From a23456f1a7ff590847093dcffd6ab451b2967405 Mon Sep 17 00:00:00 2001 From: Melvin Date: Sat, 17 Jan 2015 17:54:35 +0530 Subject: [PATCH] remove venv --- examples/shortenmyurl/venv/bin/activate | 80 - examples/shortenmyurl/venv/bin/activate.csh | 42 - examples/shortenmyurl/venv/bin/activate.fish | 74 - .../shortenmyurl/venv/bin/activate_this.py | 34 - examples/shortenmyurl/venv/bin/easy_install | 11 - .../shortenmyurl/venv/bin/easy_install-2.7 | 11 - examples/shortenmyurl/venv/bin/gunicorn | 11 - .../shortenmyurl/venv/bin/gunicorn_django | 11 - .../shortenmyurl/venv/bin/gunicorn_paster | 11 - examples/shortenmyurl/venv/bin/pip | 11 - examples/shortenmyurl/venv/bin/pip2 | 11 - examples/shortenmyurl/venv/bin/pip2.7 | 11 - examples/shortenmyurl/venv/bin/python | Bin 3349512 -> 0 bytes examples/shortenmyurl/venv/bin/python2 | 1 - examples/shortenmyurl/venv/bin/python2.7 | 1 - examples/shortenmyurl/venv/include/python2.7 | 1 - .../venv/lib/python2.7/UserDict.py | 1 - .../venv/lib/python2.7/_abcoll.py | 1 - .../venv/lib/python2.7/_weakrefset.py | 1 - .../shortenmyurl/venv/lib/python2.7/abc.py | 1 - .../shortenmyurl/venv/lib/python2.7/codecs.py | 1 - .../venv/lib/python2.7/copy_reg.py | 1 - .../venv/lib/python2.7/distutils/__init__.py | 101 - .../lib/python2.7/distutils/distutils.cfg | 6 - .../shortenmyurl/venv/lib/python2.7/encodings | 1 - .../venv/lib/python2.7/fnmatch.py | 1 - .../venv/lib/python2.7/genericpath.py | 1 - .../venv/lib/python2.7/lib-dynload | 1 - .../venv/lib/python2.7/linecache.py | 1 - .../shortenmyurl/venv/lib/python2.7/locale.py | 1 - .../lib/python2.7/no-global-site-packages.txt | 0 .../shortenmyurl/venv/lib/python2.7/ntpath.py | 1 - .../venv/lib/python2.7/orig-prefix.txt | 1 - .../shortenmyurl/venv/lib/python2.7/os.py | 1 - .../venv/lib/python2.7/posixpath.py | 1 - .../shortenmyurl/venv/lib/python2.7/re.py | 1 - .../site-packages/_markerlib/__init__.py | 16 - .../site-packages/_markerlib/markers.py | 119 - .../python2.7/site-packages/easy_install.py | 5 - .../python2.7/site-packages/flask/__init__.py | 50 - .../python2.7/site-packages/flask/_compat.py | 73 - .../lib/python2.7/site-packages/flask/app.py | 1842 ------ .../site-packages/flask/blueprints.py | 401 -- .../python2.7/site-packages/flask/config.py | 168 - .../lib/python2.7/site-packages/flask/ctx.py | 394 -- .../site-packages/flask/debughelpers.py | 87 - .../site-packages/flask/ext/__init__.py | 29 - .../python2.7/site-packages/flask/exthook.py | 120 - .../python2.7/site-packages/flask/globals.py | 44 - .../python2.7/site-packages/flask/helpers.py | 849 --- .../lib/python2.7/site-packages/flask/json.py | 243 - .../python2.7/site-packages/flask/logging.py | 45 - .../python2.7/site-packages/flask/module.py | 42 - .../python2.7/site-packages/flask/sessions.py | 332 -- .../python2.7/site-packages/flask/signals.py | 55 - .../site-packages/flask/templating.py | 143 - .../python2.7/site-packages/flask/testing.py | 124 - .../site-packages/flask/testsuite/__init__.py | 246 - .../site-packages/flask/testsuite/appctx.py | 101 - .../site-packages/flask/testsuite/basic.py | 1254 ---- .../flask/testsuite/blueprints.py | 790 --- .../site-packages/flask/testsuite/config.py | 299 - .../flask/testsuite/deprecations.py | 24 - .../site-packages/flask/testsuite/examples.py | 38 - .../site-packages/flask/testsuite/ext.py | 134 - .../site-packages/flask/testsuite/helpers.py | 593 -- .../flask/testsuite/regression.py | 116 - .../site-packages/flask/testsuite/reqctx.py | 185 - .../site-packages/flask/testsuite/signals.py | 153 - .../flask/testsuite/static/index.html | 1 - .../flask/testsuite/subclassing.py | 46 - .../flask/testsuite/templates/_macro.html | 1 - .../testsuite/templates/context_template.html | 1 - .../templates/escaping_template.html | 6 - .../flask/testsuite/templates/mail.txt | 1 - .../testsuite/templates/nested/nested.txt | 1 - .../testsuite/templates/simple_template.html | 1 - .../testsuite/templates/template_filter.html | 1 - .../testsuite/templates/template_test.html | 3 - .../flask/testsuite/templating.py | 302 - .../test_apps/blueprintapp/__init__.py | 7 - .../test_apps/blueprintapp/apps/__init__.py | 0 .../blueprintapp/apps/admin/__init__.py | 15 - .../apps/admin/static/css/test.css | 1 - .../blueprintapp/apps/admin/static/test.txt | 1 - .../apps/admin/templates/admin/index.html | 1 - .../blueprintapp/apps/frontend/__init__.py | 8 - .../frontend/templates/frontend/index.html | 1 - .../testsuite/test_apps/config_module_app.py | 4 - .../test_apps/config_package_app/__init__.py | 4 - .../test_apps/flask_broken/__init__.py | 2 - .../testsuite/test_apps/flask_broken/b.py | 0 .../flask_newext_package/__init__.py | 1 - .../flask_newext_package/submodule.py | 2 - .../test_apps/flask_newext_simple.py | 1 - .../testsuite/test_apps/flaskext/__init__.py | 0 .../flaskext/oldext_package/__init__.py | 1 - .../flaskext/oldext_package/submodule.py | 2 - .../test_apps/flaskext/oldext_simple.py | 1 - .../flask/testsuite/test_apps/importerror.py | 2 - .../lib/python2.5/site-packages/site_app.py | 3 - .../site-packages/site_package/__init__.py | 3 - .../flask/testsuite/test_apps/main_app.py | 4 - .../testsuite/test_apps/moduleapp/__init__.py | 7 - .../test_apps/moduleapp/apps/__init__.py | 0 .../moduleapp/apps/admin/__init__.py | 14 - .../moduleapp/apps/admin/static/css/test.css | 1 - .../moduleapp/apps/admin/static/test.txt | 1 - .../moduleapp/apps/admin/templates/index.html | 1 - .../moduleapp/apps/frontend/__init__.py | 9 - .../apps/frontend/templates/index.html | 1 - .../path/installed_package/__init__.py | 3 - .../test_apps/subdomaintestmodule/__init__.py | 4 - .../subdomaintestmodule/static/hello.txt | 1 - .../site-packages/flask/testsuite/testing.py | 242 - .../site-packages/flask/testsuite/views.py | 169 - .../python2.7/site-packages/flask/views.py | 149 - .../python2.7/site-packages/flask/wrappers.py | 184 - .../python2.7/site-packages/flask_heroku.py | 105 - .../gunicorn-19.1.1.dist-info/DESCRIPTION.rst | 196 - .../gunicorn-19.1.1.dist-info/METADATA | 227 - .../gunicorn-19.1.1.dist-info/RECORD | 93 - .../gunicorn-19.1.1.dist-info/WHEEL | 6 - .../entry_points.txt | 10 - .../gunicorn-19.1.1.dist-info/metadata.json | 1 - .../gunicorn-19.1.1.dist-info/top_level.txt | 1 - .../site-packages/gunicorn/__init__.py | 8 - .../site-packages/gunicorn/app/__init__.py | 4 - .../site-packages/gunicorn/app/base.py | 185 - .../site-packages/gunicorn/app/django_wsgi.py | 119 - .../site-packages/gunicorn/app/djangoapp.py | 160 - .../site-packages/gunicorn/app/pasterapp.py | 214 - .../site-packages/gunicorn/app/wsgiapp.py | 78 - .../site-packages/gunicorn/arbiter.py | 571 -- .../site-packages/gunicorn/argparse_compat.py | 2362 -------- .../site-packages/gunicorn/config.py | 1653 ------ .../python2.7/site-packages/gunicorn/debug.py | 70 - .../site-packages/gunicorn/errors.py | 21 - .../site-packages/gunicorn/glogging.py | 367 -- .../site-packages/gunicorn/http/__init__.py | 9 - .../site-packages/gunicorn/http/_sendfile.py | 68 - .../site-packages/gunicorn/http/body.py | 259 - .../site-packages/gunicorn/http/errors.py | 109 - .../site-packages/gunicorn/http/message.py | 338 -- .../site-packages/gunicorn/http/parser.py | 51 - .../site-packages/gunicorn/http/unreader.py | 80 - .../site-packages/gunicorn/http/wsgi.py | 422 -- .../gunicorn/instrument/__init__.py | 0 .../gunicorn/instrument/statsd.py | 125 - .../gunicorn/management/__init__.py | 1 - .../gunicorn/management/commands/__init__.py | 1 - .../management/commands/run_gunicorn.py | 113 - .../site-packages/gunicorn/pidfile.py | 84 - .../site-packages/gunicorn/reloader.py | 53 - .../python2.7/site-packages/gunicorn/six.py | 474 -- .../python2.7/site-packages/gunicorn/sock.py | 224 - .../python2.7/site-packages/gunicorn/util.py | 534 -- .../gunicorn/workers/__init__.py | 20 - .../gunicorn/workers/_gaiohttp.py | 128 - .../site-packages/gunicorn/workers/async.py | 136 - .../site-packages/gunicorn/workers/base.py | 217 - .../gunicorn/workers/gaiohttp.py | 17 - .../gunicorn/workers/geventlet.py | 89 - .../site-packages/gunicorn/workers/ggevent.py | 236 - .../site-packages/gunicorn/workers/gthread.py | 344 -- .../gunicorn/workers/gtornado.py | 121 - .../site-packages/gunicorn/workers/sync.py | 167 - .../gunicorn/workers/workertmp.py | 56 - .../lib/python2.7/site-packages/hashids.py | 242 - .../python2.7/site-packages/itsdangerous.py | 872 --- .../site-packages/jinja2/__init__.py | 69 - .../python2.7/site-packages/jinja2/_compat.py | 150 - .../site-packages/jinja2/_stringdefs.py | 132 - .../python2.7/site-packages/jinja2/bccache.py | 344 -- .../site-packages/jinja2/compiler.py | 1640 ------ .../site-packages/jinja2/constants.py | 32 - .../python2.7/site-packages/jinja2/debug.py | 337 -- .../site-packages/jinja2/defaults.py | 43 - .../site-packages/jinja2/exceptions.py | 146 - .../lib/python2.7/site-packages/jinja2/ext.py | 636 --- .../python2.7/site-packages/jinja2/filters.py | 987 ---- .../python2.7/site-packages/jinja2/lexer.py | 733 --- .../python2.7/site-packages/jinja2/loaders.py | 471 -- .../python2.7/site-packages/jinja2/meta.py | 103 - .../python2.7/site-packages/jinja2/nodes.py | 914 --- .../site-packages/jinja2/optimizer.py | 68 - .../python2.7/site-packages/jinja2/parser.py | 895 --- .../python2.7/site-packages/jinja2/runtime.py | 581 -- .../python2.7/site-packages/jinja2/sandbox.py | 368 -- .../python2.7/site-packages/jinja2/tests.py | 149 - .../jinja2/testsuite/__init__.py | 156 - .../site-packages/jinja2/testsuite/api.py | 261 - .../jinja2/testsuite/bytecode_cache.py | 37 - .../jinja2/testsuite/core_tags.py | 305 - .../site-packages/jinja2/testsuite/debug.py | 58 - .../jinja2/testsuite/doctests.py | 29 - .../site-packages/jinja2/testsuite/ext.py | 459 -- .../site-packages/jinja2/testsuite/filters.py | 515 -- .../site-packages/jinja2/testsuite/imports.py | 141 - .../jinja2/testsuite/inheritance.py | 250 - .../jinja2/testsuite/lexnparse.py | 593 -- .../site-packages/jinja2/testsuite/loader.py | 226 - .../jinja2/testsuite/regression.py | 279 - .../jinja2/testsuite/res/__init__.py | 0 .../testsuite/res/templates/broken.html | 3 - .../testsuite/res/templates/foo/test.html | 1 - .../testsuite/res/templates/syntaxerror.html | 4 - .../jinja2/testsuite/res/templates/test.html | 1 - .../jinja2/testsuite/security.py | 166 - .../site-packages/jinja2/testsuite/tests.py | 93 - .../site-packages/jinja2/testsuite/utils.py | 82 - .../python2.7/site-packages/jinja2/utils.py | 520 -- .../python2.7/site-packages/jinja2/visitor.py | 87 - .../site-packages/markupsafe/__init__.py | 298 - .../site-packages/markupsafe/_compat.py | 26 - .../site-packages/markupsafe/_constants.py | 267 - .../site-packages/markupsafe/_native.py | 46 - .../site-packages/markupsafe/_speedups.c | 239 - .../site-packages/markupsafe/tests.py | 179 - .../pip-1.5.6.dist-info/DESCRIPTION.rst | 71 - .../pip-1.5.6.dist-info/METADATA | 98 - .../site-packages/pip-1.5.6.dist-info/RECORD | 374 -- .../site-packages/pip-1.5.6.dist-info/WHEEL | 6 - .../pip-1.5.6.dist-info/entry_points.txt | 5 - .../pip-1.5.6.dist-info/metadata.json | 1 - .../pip-1.5.6.dist-info/top_level.txt | 1 - .../python2.7/site-packages/pip/__init__.py | 277 - .../python2.7/site-packages/pip/__main__.py | 7 - .../site-packages/pip/_vendor/__init__.py | 8 - .../pip/_vendor/_markerlib/__init__.py | 16 - .../pip/_vendor/_markerlib/markers.py | 119 - .../pip/_vendor/colorama/__init__.py | 7 - .../pip/_vendor/colorama/ansi.py | 50 - .../pip/_vendor/colorama/ansitowin32.py | 190 - .../pip/_vendor/colorama/initialise.py | 56 - .../pip/_vendor/colorama/win32.py | 137 - .../pip/_vendor/colorama/winterm.py | 120 - .../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/_vendor/distlib/compat.py | 1064 ---- .../pip/_vendor/distlib/database.py | 1301 ----- .../pip/_vendor/distlib/index.py | 488 -- .../pip/_vendor/distlib/locators.py | 1194 ---- .../pip/_vendor/distlib/manifest.py | 364 -- .../pip/_vendor/distlib/markers.py | 190 - .../pip/_vendor/distlib/metadata.py | 1026 ---- .../pip/_vendor/distlib/resources.py | 317 -- .../pip/_vendor/distlib/scripts.py | 323 -- .../site-packages/pip/_vendor/distlib/t32.exe | Bin 91136 -> 0 bytes .../site-packages/pip/_vendor/distlib/t64.exe | Bin 94720 -> 0 bytes .../site-packages/pip/_vendor/distlib/util.py | 1575 ------ .../pip/_vendor/distlib/version.py | 721 --- .../site-packages/pip/_vendor/distlib/w32.exe | Bin 87040 -> 0 bytes .../site-packages/pip/_vendor/distlib/w64.exe | Bin 91648 -> 0 bytes .../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/_vendor/html5lib/trie/py.py | 67 - .../pip/_vendor/html5lib/utils.py | 82 - .../pip/_vendor/pkg_resources.py | 2762 --------- .../site-packages/pip/_vendor/re-vendor.py | 34 - .../pip/_vendor/requests/__init__.py | 77 - .../pip/_vendor/requests/adapters.py | 388 -- .../site-packages/pip/_vendor/requests/api.py | 120 - .../pip/_vendor/requests/auth.py | 193 - .../pip/_vendor/requests/cacert.pem | 5026 ----------------- .../pip/_vendor/requests/certs.py | 24 - .../pip/_vendor/requests/compat.py | 115 - .../pip/_vendor/requests/cookies.py | 454 -- .../pip/_vendor/requests/exceptions.py | 75 - .../pip/_vendor/requests/hooks.py | 45 - .../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/_vendor/requests/utils.py | 673 --- .../site-packages/pip/_vendor/six.py | 646 --- .../pip/backwardcompat/__init__.py | 138 - .../site-packages/pip/basecommand.py | 201 - .../python2.7/site-packages/pip/baseparser.py | 224 - .../python2.7/site-packages/pip/cmdoptions.py | 371 -- .../site-packages/pip/commands/__init__.py | 88 - .../site-packages/pip/commands/bundle.py | 42 - .../site-packages/pip/commands/completion.py | 59 - .../site-packages/pip/commands/freeze.py | 114 - .../site-packages/pip/commands/help.py | 33 - .../site-packages/pip/commands/install.py | 314 - .../site-packages/pip/commands/list.py | 162 - .../site-packages/pip/commands/search.py | 132 - .../site-packages/pip/commands/show.py | 80 - .../site-packages/pip/commands/uninstall.py | 59 - .../site-packages/pip/commands/unzip.py | 7 - .../site-packages/pip/commands/wheel.py | 195 - .../site-packages/pip/commands/zip.py | 351 -- .../python2.7/site-packages/pip/download.py | 644 --- .../python2.7/site-packages/pip/exceptions.py | 46 - .../lib/python2.7/site-packages/pip/index.py | 990 ---- .../python2.7/site-packages/pip/locations.py | 172 - .../lib/python2.7/site-packages/pip/log.py | 276 - .../python2.7/site-packages/pip/pep425tags.py | 102 - .../lib/python2.7/site-packages/pip/req.py | 1931 ------- .../lib/python2.7/site-packages/pip/runner.py | 18 - .../site-packages/pip/status_codes.py | 6 - .../lib/python2.7/site-packages/pip/util.py | 720 --- .../site-packages/pip/vcs/__init__.py | 251 - .../python2.7/site-packages/pip/vcs/bazaar.py | 131 - .../python2.7/site-packages/pip/vcs/git.py | 194 - .../site-packages/pip/vcs/mercurial.py | 151 - .../site-packages/pip/vcs/subversion.py | 273 - .../lib/python2.7/site-packages/pip/wheel.py | 560 -- .../python2.7/site-packages/pkg_resources.py | 2843 ---------- .../python2.7/site-packages/redis/__init__.py | 34 - .../python2.7/site-packages/redis/_compat.py | 79 - .../python2.7/site-packages/redis/client.py | 2651 --------- .../site-packages/redis/connection.py | 1017 ---- .../site-packages/redis/exceptions.py | 71 - .../lib/python2.7/site-packages/redis/lock.py | 272 - .../python2.7/site-packages/redis/sentinel.py | 294 - .../python2.7/site-packages/redis/utils.py | 33 - .../setuptools-3.6.dist-info/DESCRIPTION.rst | 1922 ------- .../setuptools-3.6.dist-info/METADATA | 1953 ------- .../setuptools-3.6.dist-info/RECORD | 151 - .../setuptools-3.6.dist-info/WHEEL | 6 - .../dependency_links.txt | 2 - .../setuptools-3.6.dist-info/entry_points.txt | 63 - .../setuptools-3.6.dist-info/pydist.json | 1 - .../requires.txt.orig | 7 - .../setuptools-3.6.dist-info/top_level.txt | 4 - .../setuptools-3.6.dist-info/zip-safe | 1 - .../site-packages/setuptools/__init__.py | 154 - .../site-packages/setuptools/archive_util.py | 210 - .../site-packages/setuptools/cli-32.exe | Bin 65536 -> 0 bytes .../site-packages/setuptools/cli-64.exe | Bin 74752 -> 0 bytes .../site-packages/setuptools/cli-arm-32.exe | Bin 69120 -> 0 bytes .../site-packages/setuptools/cli.exe | Bin 65536 -> 0 bytes .../setuptools/command/__init__.py | 17 - .../site-packages/setuptools/command/alias.py | 76 - .../setuptools/command/bdist_egg.py | 462 -- .../setuptools/command/bdist_rpm.py | 42 - .../setuptools/command/bdist_wininst.py | 20 - .../setuptools/command/build_ext.py | 289 - .../setuptools/command/build_py.py | 221 - .../setuptools/command/develop.py | 167 - .../setuptools/command/easy_install.py | 1949 ------- .../setuptools/command/egg_info.py | 392 -- .../setuptools/command/install.py | 121 - .../setuptools/command/install_egg_info.py | 125 - .../setuptools/command/install_lib.py | 63 - .../setuptools/command/install_scripts.py | 52 - .../setuptools/command/launcher manifest.xml | 15 - .../setuptools/command/register.py | 9 - .../setuptools/command/rotate.py | 58 - .../setuptools/command/saveopts.py | 24 - .../site-packages/setuptools/command/sdist.py | 244 - .../setuptools/command/setopt.py | 145 - .../site-packages/setuptools/command/test.py | 179 - .../setuptools/command/upload_docs.py | 193 - .../site-packages/setuptools/compat.py | 83 - .../site-packages/setuptools/depends.py | 246 - .../site-packages/setuptools/dist.py | 818 --- .../site-packages/setuptools/extension.py | 53 - .../site-packages/setuptools/gui-32.exe | Bin 65536 -> 0 bytes .../site-packages/setuptools/gui-64.exe | Bin 75264 -> 0 bytes .../site-packages/setuptools/gui-arm-32.exe | Bin 69120 -> 0 bytes .../site-packages/setuptools/gui.exe | Bin 65536 -> 0 bytes .../site-packages/setuptools/lib2to3_ex.py | 58 - .../site-packages/setuptools/package_index.py | 1058 ---- .../site-packages/setuptools/py26compat.py | 19 - .../site-packages/setuptools/py27compat.py | 15 - .../site-packages/setuptools/py31compat.py | 52 - .../site-packages/setuptools/sandbox.py | 322 -- .../setuptools/script template (dev).py | 11 - .../setuptools/script template.py | 4 - .../site-packages/setuptools/site-patch.py | 76 - .../site-packages/setuptools/ssl_support.py | 234 - .../site-packages/setuptools/svn_utils.py | 583 -- .../setuptools/tests/__init__.py | 352 -- .../site-packages/setuptools/tests/doctest.py | 2683 --------- .../setuptools/tests/py26compat.py | 14 - .../setuptools/tests/script-with-bom.py | 3 - .../site-packages/setuptools/tests/server.py | 82 - .../setuptools/tests/test_bdist_egg.py | 72 - .../setuptools/tests/test_build_ext.py | 19 - .../setuptools/tests/test_develop.py | 124 - .../setuptools/tests/test_dist_info.py | 83 - .../setuptools/tests/test_easy_install.py | 462 -- .../setuptools/tests/test_egg_info.py | 173 - .../setuptools/tests/test_find_packages.py | 156 - .../setuptools/tests/test_markerlib.py | 68 - .../setuptools/tests/test_packageindex.py | 203 - .../setuptools/tests/test_resources.py | 620 -- .../setuptools/tests/test_sandbox.py | 79 - .../setuptools/tests/test_sdist.py | 535 -- .../setuptools/tests/test_svn.py | 245 - .../setuptools/tests/test_test.py | 126 - .../setuptools/tests/test_upload_docs.py | 72 - .../site-packages/setuptools/version.py | 1 - .../site-packages/werkzeug/__init__.py | 154 - .../site-packages/werkzeug/_compat.py | 202 - .../site-packages/werkzeug/_internal.py | 412 -- .../werkzeug/contrib/__init__.py | 16 - .../site-packages/werkzeug/contrib/atom.py | 347 -- .../site-packages/werkzeug/contrib/cache.py | 679 --- .../site-packages/werkzeug/contrib/fixers.py | 244 - .../site-packages/werkzeug/contrib/iterio.py | 346 -- .../werkzeug/contrib/jsrouting.py | 262 - .../site-packages/werkzeug/contrib/limiter.py | 40 - .../site-packages/werkzeug/contrib/lint.py | 334 -- .../werkzeug/contrib/profiler.py | 142 - .../werkzeug/contrib/securecookie.py | 321 -- .../werkzeug/contrib/sessions.py | 348 -- .../werkzeug/contrib/testtools.py | 71 - .../werkzeug/contrib/wrappers.py | 278 - .../site-packages/werkzeug/datastructures.py | 2621 --------- .../site-packages/werkzeug/debug/__init__.py | 185 - .../site-packages/werkzeug/debug/console.py | 211 - .../site-packages/werkzeug/debug/repr.py | 280 - .../werkzeug/debug/shared/FONT_LICENSE | 96 - .../werkzeug/debug/shared/console.png | Bin 507 -> 0 bytes .../werkzeug/debug/shared/debugger.js | 201 - .../werkzeug/debug/shared/jquery.js | 167 - .../werkzeug/debug/shared/less.png | Bin 191 -> 0 bytes .../werkzeug/debug/shared/more.png | Bin 200 -> 0 bytes .../werkzeug/debug/shared/source.png | Bin 818 -> 0 bytes .../werkzeug/debug/shared/style.css | 113 - .../werkzeug/debug/shared/ubuntu.ttf | Bin 70220 -> 0 bytes .../site-packages/werkzeug/debug/tbtools.py | 508 -- .../site-packages/werkzeug/exceptions.py | 588 -- .../site-packages/werkzeug/formparser.py | 523 -- .../python2.7/site-packages/werkzeug/http.py | 980 ---- .../python2.7/site-packages/werkzeug/local.py | 409 -- .../site-packages/werkzeug/posixemulation.py | 105 - .../site-packages/werkzeug/routing.py | 1631 ------ .../site-packages/werkzeug/script.py | 316 -- .../site-packages/werkzeug/security.py | 248 - .../site-packages/werkzeug/serving.py | 749 --- .../python2.7/site-packages/werkzeug/test.py | 880 --- .../site-packages/werkzeug/testapp.py | 230 - .../werkzeug/testsuite/__init__.py | 267 - .../werkzeug/testsuite/compat.py | 40 - .../werkzeug/testsuite/contrib/__init__.py | 19 - .../werkzeug/testsuite/contrib/cache.py | 257 - .../werkzeug/testsuite/contrib/fixers.py | 193 - .../werkzeug/testsuite/contrib/iterio.py | 184 - .../testsuite/contrib/securecookie.py | 64 - .../werkzeug/testsuite/contrib/sessions.py | 91 - .../werkzeug/testsuite/contrib/wrappers.py | 97 - .../werkzeug/testsuite/datastructures.py | 810 --- .../site-packages/werkzeug/testsuite/debug.py | 172 - .../werkzeug/testsuite/exceptions.py | 85 - .../werkzeug/testsuite/formparser.py | 411 -- .../site-packages/werkzeug/testsuite/http.py | 449 -- .../werkzeug/testsuite/internal.py | 81 - .../site-packages/werkzeug/testsuite/local.py | 159 - .../werkzeug/testsuite/multipart/collect.py | 56 - .../multipart/firefox3-2png1txt/file1.png | Bin 523 -> 0 bytes .../multipart/firefox3-2png1txt/file2.png | Bin 703 -> 0 bytes .../multipart/firefox3-2png1txt/request.txt | Bin 1739 -> 0 bytes .../multipart/firefox3-2png1txt/text.txt | 1 - .../multipart/firefox3-2pnglongtext/file1.png | Bin 781 -> 0 bytes .../multipart/firefox3-2pnglongtext/file2.png | Bin 733 -> 0 bytes .../firefox3-2pnglongtext/request.txt | Bin 2042 -> 0 bytes .../multipart/firefox3-2pnglongtext/text.txt | 3 - .../multipart/ie6-2png1txt/file1.png | Bin 523 -> 0 bytes .../multipart/ie6-2png1txt/file2.png | Bin 703 -> 0 bytes .../multipart/ie6-2png1txt/request.txt | Bin 1798 -> 0 bytes .../testsuite/multipart/ie6-2png1txt/text.txt | 1 - .../multipart/ie7_full_path_request.txt | Bin 30044 -> 0 bytes .../multipart/opera8-2png1txt/file1.png | Bin 582 -> 0 bytes .../multipart/opera8-2png1txt/file2.png | Bin 733 -> 0 bytes .../multipart/opera8-2png1txt/request.txt | Bin 1740 -> 0 bytes .../multipart/opera8-2png1txt/text.txt | 1 - .../multipart/webkit3-2png1txt/file1.png | Bin 1002 -> 0 bytes .../multipart/webkit3-2png1txt/file2.png | Bin 952 -> 0 bytes .../multipart/webkit3-2png1txt/request.txt | Bin 2408 -> 0 bytes .../multipart/webkit3-2png1txt/text.txt | 1 - .../werkzeug/testsuite/res/test.txt | 1 - .../werkzeug/testsuite/routing.py | 689 --- .../werkzeug/testsuite/security.py | 105 - .../werkzeug/testsuite/serving.py | 117 - .../site-packages/werkzeug/testsuite/test.py | 444 -- .../site-packages/werkzeug/testsuite/urls.py | 322 -- .../site-packages/werkzeug/testsuite/utils.py | 284 - .../werkzeug/testsuite/wrappers.py | 840 --- .../site-packages/werkzeug/testsuite/wsgi.py | 352 -- .../python2.7/site-packages/werkzeug/urls.py | 916 --- .../site-packages/werkzeug/useragents.py | 190 - .../python2.7/site-packages/werkzeug/utils.py | 613 -- .../site-packages/werkzeug/wrappers.py | 1808 ------ .../python2.7/site-packages/werkzeug/wsgi.py | 1047 ---- .../shortenmyurl/venv/lib/python2.7/site.py | 758 --- .../shortenmyurl/venv/lib/python2.7/sre.py | 1 - .../venv/lib/python2.7/sre_compile.py | 1 - .../venv/lib/python2.7/sre_constants.py | 1 - .../venv/lib/python2.7/sre_parse.py | 1 - .../shortenmyurl/venv/lib/python2.7/stat.py | 1 - .../shortenmyurl/venv/lib/python2.7/types.py | 1 - .../venv/lib/python2.7/warnings.py | 1 - examples/shortenmyurl/venv/local/bin | 1 - examples/shortenmyurl/venv/local/include | 1 - examples/shortenmyurl/venv/local/lib | 1 - 602 files changed, 151282 deletions(-) delete mode 100644 examples/shortenmyurl/venv/bin/activate delete mode 100644 examples/shortenmyurl/venv/bin/activate.csh delete mode 100644 examples/shortenmyurl/venv/bin/activate.fish delete mode 100644 examples/shortenmyurl/venv/bin/activate_this.py delete mode 100755 examples/shortenmyurl/venv/bin/easy_install delete mode 100755 examples/shortenmyurl/venv/bin/easy_install-2.7 delete mode 100755 examples/shortenmyurl/venv/bin/gunicorn delete mode 100755 examples/shortenmyurl/venv/bin/gunicorn_django delete mode 100755 examples/shortenmyurl/venv/bin/gunicorn_paster delete mode 100755 examples/shortenmyurl/venv/bin/pip delete mode 100755 examples/shortenmyurl/venv/bin/pip2 delete mode 100755 examples/shortenmyurl/venv/bin/pip2.7 delete mode 100755 examples/shortenmyurl/venv/bin/python delete mode 120000 examples/shortenmyurl/venv/bin/python2 delete mode 120000 examples/shortenmyurl/venv/bin/python2.7 delete mode 120000 examples/shortenmyurl/venv/include/python2.7 delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/UserDict.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/_abcoll.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/_weakrefset.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/abc.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/codecs.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/copy_reg.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/distutils/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/distutils/distutils.cfg delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/encodings delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/fnmatch.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/genericpath.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/lib-dynload delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/linecache.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/locale.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/no-global-site-packages.txt delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/ntpath.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/orig-prefix.txt delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/os.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/posixpath.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/re.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/_markerlib/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/_markerlib/markers.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/easy_install.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/_compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/app.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/blueprints.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/config.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/ctx.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/debughelpers.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/ext/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/exthook.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/globals.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/helpers.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/json.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/logging.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/module.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/sessions.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/signals.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/templating.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testing.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/appctx.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/basic.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/blueprints.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/config.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/deprecations.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/examples.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/ext.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/helpers.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/regression.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/reqctx.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/signals.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/static/index.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/subclassing.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/templates/_macro.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/templates/context_template.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/templates/escaping_template.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/templates/mail.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/templates/nested/nested.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/templates/simple_template.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/templates/template_filter.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/templates/template_test.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/templating.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/blueprintapp/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/blueprintapp/apps/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/blueprintapp/apps/admin/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/blueprintapp/apps/admin/static/css/test.css delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/blueprintapp/apps/admin/static/test.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/blueprintapp/apps/admin/templates/admin/index.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/blueprintapp/apps/frontend/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/blueprintapp/apps/frontend/templates/frontend/index.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/config_module_app.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/config_package_app/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/flask_broken/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/flask_broken/b.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/flask_newext_package/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/flask_newext_package/submodule.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/flask_newext_simple.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/flaskext/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/flaskext/oldext_package/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/flaskext/oldext_package/submodule.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/flaskext/oldext_simple.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/importerror.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/lib/python2.5/site-packages/site_app.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/lib/python2.5/site-packages/site_package/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/main_app.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/moduleapp/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/moduleapp/apps/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/moduleapp/apps/admin/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/moduleapp/apps/admin/static/css/test.css delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/moduleapp/apps/admin/static/test.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/moduleapp/apps/admin/templates/index.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/moduleapp/apps/frontend/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/moduleapp/apps/frontend/templates/index.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/path/installed_package/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/subdomaintestmodule/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/test_apps/subdomaintestmodule/static/hello.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/testing.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/testsuite/views.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/views.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask/wrappers.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/flask_heroku.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn-19.1.1.dist-info/DESCRIPTION.rst delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn-19.1.1.dist-info/METADATA delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn-19.1.1.dist-info/RECORD delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn-19.1.1.dist-info/WHEEL delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn-19.1.1.dist-info/entry_points.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn-19.1.1.dist-info/metadata.json delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn-19.1.1.dist-info/top_level.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/app/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/app/base.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/app/django_wsgi.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/app/djangoapp.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/app/pasterapp.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/arbiter.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/argparse_compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/config.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/debug.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/errors.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/glogging.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/http/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/http/_sendfile.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/http/body.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/http/errors.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/http/message.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/http/parser.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/http/unreader.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/http/wsgi.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/instrument/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/instrument/statsd.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/management/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/management/commands/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/management/commands/run_gunicorn.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/pidfile.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/reloader.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/six.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/sock.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/util.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/workers/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/workers/_gaiohttp.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/workers/async.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/workers/base.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/workers/gaiohttp.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/workers/geventlet.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/workers/ggevent.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/workers/gthread.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/workers/gtornado.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/workers/sync.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/gunicorn/workers/workertmp.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/hashids.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/itsdangerous.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/_compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/_stringdefs.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/bccache.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/compiler.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/constants.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/debug.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/defaults.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/exceptions.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/ext.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/filters.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/lexer.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/loaders.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/meta.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/nodes.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/optimizer.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/parser.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/runtime.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/sandbox.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/tests.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/api.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/bytecode_cache.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/core_tags.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/debug.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/doctests.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/ext.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/filters.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/imports.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/inheritance.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/lexnparse.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/loader.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/regression.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/broken.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/foo/test.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/syntaxerror.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/test.html delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/security.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/tests.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/utils.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/utils.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/visitor.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_constants.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_native.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_speedups.c delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/tests.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/DESCRIPTION.rst delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/METADATA delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/RECORD delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/WHEEL delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/entry_points.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/metadata.json delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/top_level.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/__main__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/_markerlib/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/_markerlib/markers.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/ansi.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/ansitowin32.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/initialise.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/win32.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/winterm.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/misc.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/shutil.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/sysconfig.cfg delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/sysconfig.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/tarfile.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/database.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/index.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/locators.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/manifest.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/markers.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/metadata.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/resources.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/scripts.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/t32.exe delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/t64.exe delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/util.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/version.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/w32.exe delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/w64.exe delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/wheel.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/constants.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/_base.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/alphabeticalattributes.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/inject_meta_charset.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/lint.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/optionaltags.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/sanitizer.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/whitespace.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/html5parser.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/ihatexml.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/inputstream.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/sanitizer.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/serializer/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/serializer/htmlserializer.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/tokenizer.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/treeadapters/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/treeadapters/sax.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/treebuilders/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/treebuilders/_base.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/treebuilders/dom.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/treebuilders/etree.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/treebuilders/etree_lxml.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/treewalkers/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/treewalkers/_base.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/treewalkers/dom.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/treewalkers/etree.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/treewalkers/genshistream.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/treewalkers/lxmletree.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/treewalkers/pulldom.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/trie/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/trie/_base.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/trie/datrie.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/trie/py.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/utils.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/pkg_resources.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/re-vendor.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/adapters.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/api.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/auth.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/cacert.pem delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/certs.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/cookies.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/exceptions.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/hooks.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/models.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/big5freq.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/big5prober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/chardetect.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/chardistribution.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/charsetgroupprober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/charsetprober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/codingstatemachine.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/constants.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/cp949prober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/escprober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/escsm.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/eucjpprober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/euckrfreq.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/euckrprober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/euctwfreq.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/euctwprober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/gb2312freq.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/gb2312prober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/hebrewprober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/jisfreq.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/jpcntx.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/langbulgarianmodel.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/langcyrillicmodel.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/langgreekmodel.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/langhebrewmodel.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/langhungarianmodel.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/langthaimodel.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/latin1prober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/mbcharsetprober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/mbcsgroupprober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/mbcssm.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/sbcharsetprober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/sbcsgroupprober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/sjisprober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/universaldetector.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/chardet/utf8prober.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/_collections.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/connection.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/connectionpool.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/contrib/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/contrib/ntlmpool.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/contrib/pyopenssl.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/exceptions.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/fields.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/filepost.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/packages/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/packages/ordered_dict.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/packages/six.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/poolmanager.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/request.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/response.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/util/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/util/connection.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/util/request.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/util/response.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/util/timeout.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/util/url.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/sessions.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/status_codes.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/structures.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/requests/utils.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/six.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/backwardcompat/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/basecommand.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/baseparser.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/cmdoptions.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/commands/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/commands/bundle.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/commands/completion.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/commands/freeze.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/commands/help.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/commands/install.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/commands/list.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/commands/search.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/commands/show.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/commands/uninstall.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/commands/unzip.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/commands/wheel.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/commands/zip.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/download.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/exceptions.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/index.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/locations.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/log.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/pep425tags.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/req.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/runner.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/status_codes.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/util.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/vcs/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/vcs/bazaar.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/vcs/git.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/vcs/mercurial.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/vcs/subversion.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/wheel.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/pkg_resources.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/redis/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/redis/_compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/redis/client.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/redis/connection.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/redis/exceptions.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/redis/lock.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/redis/sentinel.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/redis/utils.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools-3.6.dist-info/DESCRIPTION.rst delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools-3.6.dist-info/METADATA delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools-3.6.dist-info/RECORD delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools-3.6.dist-info/WHEEL delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools-3.6.dist-info/dependency_links.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools-3.6.dist-info/entry_points.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools-3.6.dist-info/pydist.json delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools-3.6.dist-info/requires.txt.orig delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools-3.6.dist-info/top_level.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools-3.6.dist-info/zip-safe delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/archive_util.py delete mode 100755 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/cli-32.exe delete mode 100755 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/cli-64.exe delete mode 100755 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/cli-arm-32.exe delete mode 100755 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/cli.exe delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/alias.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/bdist_egg.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/bdist_rpm.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/bdist_wininst.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/build_ext.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/build_py.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/develop.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/easy_install.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/egg_info.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/install.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/install_egg_info.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/install_lib.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/install_scripts.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/launcher manifest.xml delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/register.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/rotate.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/saveopts.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/sdist.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/setopt.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/test.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/command/upload_docs.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/depends.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/dist.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/extension.py delete mode 100755 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/gui-32.exe delete mode 100755 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/gui-64.exe delete mode 100755 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/gui-arm-32.exe delete mode 100755 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/gui.exe delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/lib2to3_ex.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/package_index.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/py26compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/py27compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/py31compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/sandbox.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/script template (dev).py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/script template.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/site-patch.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/ssl_support.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/svn_utils.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/doctest.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/py26compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/script-with-bom.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/server.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_bdist_egg.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_build_ext.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_develop.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_dist_info.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_easy_install.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_egg_info.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_find_packages.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_markerlib.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_packageindex.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_resources.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_sandbox.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_sdist.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_svn.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_test.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/tests/test_upload_docs.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/setuptools/version.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/_compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/_internal.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/contrib/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/contrib/atom.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/contrib/cache.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/contrib/fixers.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/contrib/iterio.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/contrib/jsrouting.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/contrib/limiter.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/contrib/lint.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/contrib/profiler.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/contrib/securecookie.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/contrib/sessions.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/contrib/testtools.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/contrib/wrappers.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/datastructures.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/debug/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/debug/console.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/debug/repr.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/debug/shared/FONT_LICENSE delete mode 100755 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/debug/shared/console.png delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/debug/shared/debugger.js delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/debug/shared/jquery.js delete mode 100755 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/debug/shared/less.png delete mode 100755 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/debug/shared/more.png delete mode 100755 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/debug/shared/source.png delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/debug/shared/style.css delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/debug/shared/ubuntu.ttf delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/debug/tbtools.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/exceptions.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/formparser.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/http.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/local.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/posixemulation.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/routing.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/script.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/security.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/serving.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/test.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testapp.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/compat.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/__init__.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/cache.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/fixers.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/iterio.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/securecookie.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/sessions.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/wrappers.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/datastructures.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/debug.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/exceptions.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/formparser.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/http.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/internal.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/local.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/collect.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2png1txt/file1.png delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2png1txt/file2.png delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2png1txt/request.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2png1txt/text.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2pnglongtext/file1.png delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2pnglongtext/file2.png delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2pnglongtext/request.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2pnglongtext/text.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/ie6-2png1txt/file1.png delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/ie6-2png1txt/file2.png delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/ie6-2png1txt/request.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/ie6-2png1txt/text.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/ie7_full_path_request.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/opera8-2png1txt/file1.png delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/opera8-2png1txt/file2.png delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/opera8-2png1txt/request.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/opera8-2png1txt/text.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/webkit3-2png1txt/file1.png delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/webkit3-2png1txt/file2.png delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/webkit3-2png1txt/request.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/webkit3-2png1txt/text.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/res/test.txt delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/routing.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/security.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/serving.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/test.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/urls.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/utils.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/wrappers.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/wsgi.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/urls.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/useragents.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/utils.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/wrappers.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/wsgi.py delete mode 100644 examples/shortenmyurl/venv/lib/python2.7/site.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/sre.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/sre_compile.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/sre_constants.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/sre_parse.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/stat.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/types.py delete mode 120000 examples/shortenmyurl/venv/lib/python2.7/warnings.py delete mode 120000 examples/shortenmyurl/venv/local/bin delete mode 120000 examples/shortenmyurl/venv/local/include delete mode 120000 examples/shortenmyurl/venv/local/lib diff --git a/examples/shortenmyurl/venv/bin/activate b/examples/shortenmyurl/venv/bin/activate deleted file mode 100644 index 151c2545..00000000 --- a/examples/shortenmyurl/venv/bin/activate +++ /dev/null @@ -1,80 +0,0 @@ -# This file must be used with "source bin/activate" *from bash* -# you cannot run it directly - -deactivate () { - unset pydoc - - # reset old environment variables - if [ -n "$_OLD_VIRTUAL_PATH" ] ; then - PATH="$_OLD_VIRTUAL_PATH" - export PATH - unset _OLD_VIRTUAL_PATH - fi - if [ -n "$_OLD_VIRTUAL_PYTHONHOME" ] ; then - PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME" - export PYTHONHOME - unset _OLD_VIRTUAL_PYTHONHOME - fi - - # This should detect bash and zsh, which have a hash command that must - # be called to get it to forget past commands. Without forgetting - # past commands the $PATH changes we made may not be respected - if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then - hash -r 2>/dev/null - fi - - if [ -n "$_OLD_VIRTUAL_PS1" ] ; then - PS1="$_OLD_VIRTUAL_PS1" - export PS1 - unset _OLD_VIRTUAL_PS1 - fi - - unset VIRTUAL_ENV - if [ ! "$1" = "nondestructive" ] ; then - # Self destruct! - unset -f deactivate - fi -} - -# unset irrelevant variables -deactivate nondestructive - -VIRTUAL_ENV="/home/melvin/development/shortenmyurl/venv" -export VIRTUAL_ENV - -_OLD_VIRTUAL_PATH="$PATH" -PATH="$VIRTUAL_ENV/bin:$PATH" -export PATH - -# unset PYTHONHOME if set -# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) -# could use `if (set -u; : $PYTHONHOME) ;` in bash -if [ -n "$PYTHONHOME" ] ; then - _OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME" - unset PYTHONHOME -fi - -if [ -z "$VIRTUAL_ENV_DISABLE_PROMPT" ] ; then - _OLD_VIRTUAL_PS1="$PS1" - if [ "x" != x ] ; then - PS1="$PS1" - else - if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then - # special case for Aspen magic directories - # see http://www.zetadev.com/software/aspen/ - PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1" - else - PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1" - fi - fi - export PS1 -fi - -alias pydoc="python -m pydoc" - -# This should detect bash and zsh, which have a hash command that must -# be called to get it to forget past commands. Without forgetting -# past commands the $PATH changes we made may not be respected -if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then - hash -r 2>/dev/null -fi diff --git a/examples/shortenmyurl/venv/bin/activate.csh b/examples/shortenmyurl/venv/bin/activate.csh deleted file mode 100644 index cbfafbbb..00000000 --- a/examples/shortenmyurl/venv/bin/activate.csh +++ /dev/null @@ -1,42 +0,0 @@ -# This file must be used with "source bin/activate.csh" *from csh*. -# You cannot run it directly. -# Created by Davide Di Blasi . - -alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc' - -# Unset irrelevant variables. -deactivate nondestructive - -setenv VIRTUAL_ENV "/home/melvin/development/shortenmyurl/venv" - -set _OLD_VIRTUAL_PATH="$PATH" -setenv PATH "$VIRTUAL_ENV/bin:$PATH" - - - -if ("" != "") then - set env_name = "" -else - if (`basename "$VIRTUAL_ENV"` == "__") then - # special case for Aspen magic directories - # see http://www.zetadev.com/software/aspen/ - set env_name = `basename \`dirname "$VIRTUAL_ENV"\`` - else - set env_name = `basename "$VIRTUAL_ENV"` - endif -endif - -# Could be in a non-interactive environment, -# in which case, $prompt is undefined and we wouldn't -# care about the prompt anyway. -if ( $?prompt ) then - set _OLD_VIRTUAL_PROMPT="$prompt" - set prompt = "[$env_name] $prompt" -endif - -unset env_name - -alias pydoc python -m pydoc - -rehash - diff --git a/examples/shortenmyurl/venv/bin/activate.fish b/examples/shortenmyurl/venv/bin/activate.fish deleted file mode 100644 index 9dfa7f54..00000000 --- a/examples/shortenmyurl/venv/bin/activate.fish +++ /dev/null @@ -1,74 +0,0 @@ -# This file must be used with "source bin/activate.fish" *from fish* (http://fishshell.com) -# you cannot run it directly - -function deactivate -d "Exit virtualenv and return to normal shell environment" - # reset old environment variables - if test -n "$_OLD_VIRTUAL_PATH" - set -gx PATH $_OLD_VIRTUAL_PATH - set -e _OLD_VIRTUAL_PATH - end - if test -n "$_OLD_VIRTUAL_PYTHONHOME" - set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME - set -e _OLD_VIRTUAL_PYTHONHOME - end - - if test -n "$_OLD_FISH_PROMPT_OVERRIDE" - # set an empty local fish_function_path, so fish_prompt doesn't automatically reload - set -l fish_function_path - # erase the virtualenv's fish_prompt function, and restore the original - functions -e fish_prompt - functions -c _old_fish_prompt fish_prompt - functions -e _old_fish_prompt - set -e _OLD_FISH_PROMPT_OVERRIDE - end - - set -e VIRTUAL_ENV - if test "$argv[1]" != "nondestructive" - # Self destruct! - functions -e deactivate - end -end - -# unset irrelevant variables -deactivate nondestructive - -set -gx VIRTUAL_ENV "/home/melvin/development/shortenmyurl/venv" - -set -gx _OLD_VIRTUAL_PATH $PATH -set -gx PATH "$VIRTUAL_ENV/bin" $PATH - -# unset PYTHONHOME if set -if set -q PYTHONHOME - set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME - set -e PYTHONHOME -end - -if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" - # fish uses a function instead of an env var to generate the prompt. - - # copy the current fish_prompt function as the function _old_fish_prompt - functions -c fish_prompt _old_fish_prompt - - # with the original prompt function copied, we can override with our own. - function fish_prompt - # Prompt override? - if test -n "" - printf "%s%s" "" (set_color normal) - _old_fish_prompt - return - end - # ...Otherwise, prepend env - set -l _checkbase (basename "$VIRTUAL_ENV") - if test $_checkbase = "__" - # special case for Aspen magic directories - # see http://www.zetadev.com/software/aspen/ - printf "%s[%s]%s " (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal) - _old_fish_prompt - else - printf "%s(%s)%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal) - _old_fish_prompt - end - end - - set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" -end diff --git a/examples/shortenmyurl/venv/bin/activate_this.py b/examples/shortenmyurl/venv/bin/activate_this.py deleted file mode 100644 index ea12c28a..00000000 --- a/examples/shortenmyurl/venv/bin/activate_this.py +++ /dev/null @@ -1,34 +0,0 @@ -"""By using execfile(this_file, dict(__file__=this_file)) you will -activate this virtualenv environment. - -This can be used when you must use an existing Python interpreter, not -the virtualenv bin/python -""" - -try: - __file__ -except NameError: - raise AssertionError( - "You must run this like execfile('path/to/activate_this.py', dict(__file__='path/to/activate_this.py'))") -import sys -import os - -old_os_path = os.environ['PATH'] -os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + os.pathsep + old_os_path -base = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -if sys.platform == 'win32': - site_packages = os.path.join(base, 'Lib', 'site-packages') -else: - site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages') -prev_sys_path = list(sys.path) -import site -site.addsitedir(site_packages) -sys.real_prefix = sys.prefix -sys.prefix = base -# Move the added items to the front of the path: -new_sys_path = [] -for item in list(sys.path): - if item not in prev_sys_path: - new_sys_path.append(item) - sys.path.remove(item) -sys.path[:0] = new_sys_path diff --git a/examples/shortenmyurl/venv/bin/easy_install b/examples/shortenmyurl/venv/bin/easy_install deleted file mode 100755 index aee5dd8c..00000000 --- a/examples/shortenmyurl/venv/bin/easy_install +++ /dev/null @@ -1,11 +0,0 @@ -#!/home/melvin/development/shortenmyurl/venv/bin/python - -# -*- coding: utf-8 -*- -import re -import sys - -from setuptools.command.easy_install import main - -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/examples/shortenmyurl/venv/bin/easy_install-2.7 b/examples/shortenmyurl/venv/bin/easy_install-2.7 deleted file mode 100755 index aee5dd8c..00000000 --- a/examples/shortenmyurl/venv/bin/easy_install-2.7 +++ /dev/null @@ -1,11 +0,0 @@ -#!/home/melvin/development/shortenmyurl/venv/bin/python - -# -*- coding: utf-8 -*- -import re -import sys - -from setuptools.command.easy_install import main - -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/examples/shortenmyurl/venv/bin/gunicorn b/examples/shortenmyurl/venv/bin/gunicorn deleted file mode 100755 index 7e753db4..00000000 --- a/examples/shortenmyurl/venv/bin/gunicorn +++ /dev/null @@ -1,11 +0,0 @@ -#!/home/melvin/development/shortenmyurl/venv/bin/python - -# -*- coding: utf-8 -*- -import re -import sys - -from gunicorn.app.wsgiapp import run - -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(run()) diff --git a/examples/shortenmyurl/venv/bin/gunicorn_django b/examples/shortenmyurl/venv/bin/gunicorn_django deleted file mode 100755 index f31dc8c9..00000000 --- a/examples/shortenmyurl/venv/bin/gunicorn_django +++ /dev/null @@ -1,11 +0,0 @@ -#!/home/melvin/development/shortenmyurl/venv/bin/python - -# -*- coding: utf-8 -*- -import re -import sys - -from gunicorn.app.djangoapp import run - -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(run()) diff --git a/examples/shortenmyurl/venv/bin/gunicorn_paster b/examples/shortenmyurl/venv/bin/gunicorn_paster deleted file mode 100755 index 79fd1f64..00000000 --- a/examples/shortenmyurl/venv/bin/gunicorn_paster +++ /dev/null @@ -1,11 +0,0 @@ -#!/home/melvin/development/shortenmyurl/venv/bin/python - -# -*- coding: utf-8 -*- -import re -import sys - -from gunicorn.app.pasterapp import run - -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(run()) diff --git a/examples/shortenmyurl/venv/bin/pip b/examples/shortenmyurl/venv/bin/pip deleted file mode 100755 index 264f59f4..00000000 --- a/examples/shortenmyurl/venv/bin/pip +++ /dev/null @@ -1,11 +0,0 @@ -#!/home/melvin/development/shortenmyurl/venv/bin/python - -# -*- coding: utf-8 -*- -import re -import sys - -from pip import main - -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/examples/shortenmyurl/venv/bin/pip2 b/examples/shortenmyurl/venv/bin/pip2 deleted file mode 100755 index 264f59f4..00000000 --- a/examples/shortenmyurl/venv/bin/pip2 +++ /dev/null @@ -1,11 +0,0 @@ -#!/home/melvin/development/shortenmyurl/venv/bin/python - -# -*- coding: utf-8 -*- -import re -import sys - -from pip import main - -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/examples/shortenmyurl/venv/bin/pip2.7 b/examples/shortenmyurl/venv/bin/pip2.7 deleted file mode 100755 index 264f59f4..00000000 --- a/examples/shortenmyurl/venv/bin/pip2.7 +++ /dev/null @@ -1,11 +0,0 @@ -#!/home/melvin/development/shortenmyurl/venv/bin/python - -# -*- coding: utf-8 -*- -import re -import sys - -from pip import main - -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/examples/shortenmyurl/venv/bin/python b/examples/shortenmyurl/venv/bin/python deleted file mode 100755 index 40a80f11f550bbb8ae048b92d7acfee624648154..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3349512 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רUQFv&iCdXf|-tte?#xDn=z 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%0DO{W-%^U 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

r|ZdPYqTMuvf#jn&Z7`*!DmY9wccXef5% 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

$S(PWtmtz_8n&>G` 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 - - Results in something like this: - - .. sourcecode:: html - -
    - ... -
- - As you can see it automatically prepends a space in front of the item - if the filter returned something unless the second parameter is false. - """ - rv = u' '.join( - u'%s="%s"' % (escape(key), escape(value)) - for key, value in iteritems(d) - if value is not None and not isinstance(value, Undefined) - ) - if autospace and rv: - rv = u' ' + rv - if _eval_ctx.autoescape: - rv = Markup(rv) - return rv - - -def do_capitalize(s): - """Capitalize a value. The first character will be uppercase, all others - lowercase. - """ - return soft_unicode(s).capitalize() - - -def do_title(s): - """Return a titlecased version of the value. I.e. words will start with - uppercase letters, all remaining characters are lowercase. - """ - rv = [] - for item in re.compile(r'([-\s]+)(?u)').split(s): - if not item: - continue - rv.append(item[0].upper() + item[1:].lower()) - return ''.join(rv) - - -def do_dictsort(value, case_sensitive=False, by='key'): - """Sort a dict and yield (key, value) pairs. Because python dicts are - unsorted you may want to use this function to order them by either - key or value: - - .. sourcecode:: jinja - - {% for item in mydict|dictsort %} - sort the dict by key, case insensitive - - {% for item in mydict|dictsort(true) %} - sort the dict by key, case sensitive - - {% for item in mydict|dictsort(false, 'value') %} - sort the dict by key, case insensitive, sorted - normally and ordered by value. - """ - if by == 'key': - pos = 0 - elif by == 'value': - pos = 1 - else: - raise FilterArgumentError('You can only sort by either ' - '"key" or "value"') - def sort_func(item): - value = item[pos] - if isinstance(value, string_types) and not case_sensitive: - value = value.lower() - return value - - return sorted(value.items(), key=sort_func) - - -@environmentfilter -def do_sort(environment, value, reverse=False, case_sensitive=False, - attribute=None): - """Sort an iterable. Per default it sorts ascending, if you pass it - true as first argument it will reverse the sorting. - - If the iterable is made of strings the third parameter can be used to - control the case sensitiveness of the comparison which is disabled by - default. - - .. sourcecode:: jinja - - {% for item in iterable|sort %} - ... - {% endfor %} - - It is also possible to sort by an attribute (for example to sort - by the date of an object) by specifying the `attribute` parameter: - - .. sourcecode:: jinja - - {% for item in iterable|sort(attribute='date') %} - ... - {% endfor %} - - .. versionchanged:: 2.6 - The `attribute` parameter was added. - """ - if not case_sensitive: - def sort_func(item): - if isinstance(item, string_types): - item = item.lower() - return item - else: - sort_func = None - if attribute is not None: - getter = make_attrgetter(environment, attribute) - def sort_func(item, processor=sort_func or (lambda x: x)): - return processor(getter(item)) - return sorted(value, key=sort_func, reverse=reverse) - - -def do_default(value, default_value=u'', boolean=False): - """If the value is undefined it will return the passed default value, - otherwise the value of the variable: - - .. sourcecode:: jinja - - {{ my_variable|default('my_variable is not defined') }} - - This will output the value of ``my_variable`` if the variable was - defined, otherwise ``'my_variable is not defined'``. If you want - to use default with variables that evaluate to false you have to - set the second parameter to `true`: - - .. sourcecode:: jinja - - {{ ''|default('the string was empty', true) }} - """ - if isinstance(value, Undefined) or (boolean and not value): - return default_value - return value - - -@evalcontextfilter -def do_join(eval_ctx, value, d=u'', attribute=None): - """Return a string which is the concatenation of the strings in the - sequence. The separator between elements is an empty string per - default, you can define it with the optional parameter: - - .. sourcecode:: jinja - - {{ [1, 2, 3]|join('|') }} - -> 1|2|3 - - {{ [1, 2, 3]|join }} - -> 123 - - It is also possible to join certain attributes of an object: - - .. sourcecode:: jinja - - {{ users|join(', ', attribute='username') }} - - .. versionadded:: 2.6 - The `attribute` parameter was added. - """ - if attribute is not None: - value = imap(make_attrgetter(eval_ctx.environment, attribute), value) - - # no automatic escaping? joining is a lot eaiser then - if not eval_ctx.autoescape: - return text_type(d).join(imap(text_type, value)) - - # if the delimiter doesn't have an html representation we check - # if any of the items has. If yes we do a coercion to Markup - if not hasattr(d, '__html__'): - value = list(value) - do_escape = False - for idx, item in enumerate(value): - if hasattr(item, '__html__'): - do_escape = True - else: - value[idx] = text_type(item) - if do_escape: - d = escape(d) - else: - d = text_type(d) - return d.join(value) - - # no html involved, to normal joining - return soft_unicode(d).join(imap(soft_unicode, value)) - - -def do_center(value, width=80): - """Centers the value in a field of a given width.""" - return text_type(value).center(width) - - -@environmentfilter -def do_first(environment, seq): - """Return the first item of a sequence.""" - try: - return next(iter(seq)) - except StopIteration: - return environment.undefined('No first item, sequence was empty.') - - -@environmentfilter -def do_last(environment, seq): - """Return the last item of a sequence.""" - try: - return next(iter(reversed(seq))) - except StopIteration: - return environment.undefined('No last item, sequence was empty.') - - -@environmentfilter -def do_random(environment, seq): - """Return a random item from the sequence.""" - try: - return choice(seq) - except IndexError: - return environment.undefined('No random item, sequence was empty.') - - -def do_filesizeformat(value, binary=False): - """Format the value like a 'human-readable' file size (i.e. 13 kB, - 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega, - Giga, etc.), if the second parameter is set to `True` the binary - prefixes are used (Mebi, Gibi). - """ - bytes = float(value) - base = binary and 1024 or 1000 - prefixes = [ - (binary and 'KiB' or 'kB'), - (binary and 'MiB' or 'MB'), - (binary and 'GiB' or 'GB'), - (binary and 'TiB' or 'TB'), - (binary and 'PiB' or 'PB'), - (binary and 'EiB' or 'EB'), - (binary and 'ZiB' or 'ZB'), - (binary and 'YiB' or 'YB') - ] - if bytes == 1: - return '1 Byte' - elif bytes < base: - return '%d Bytes' % bytes - else: - for i, prefix in enumerate(prefixes): - unit = base ** (i + 2) - if bytes < unit: - return '%.1f %s' % ((base * bytes / unit), prefix) - return '%.1f %s' % ((base * bytes / unit), prefix) - - -def do_pprint(value, verbose=False): - """Pretty print a variable. Useful for debugging. - - With Jinja 1.2 onwards you can pass it a parameter. If this parameter - is truthy the output will be more verbose (this requires `pretty`) - """ - return pformat(value, verbose=verbose) - - -@evalcontextfilter -def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False): - """Converts URLs in plain text into clickable links. - - If you pass the filter an additional integer it will shorten the urls - to that number. Also a third argument exists that makes the urls - "nofollow": - - .. sourcecode:: jinja - - {{ mytext|urlize(40, true) }} - links are shortened to 40 chars and defined with rel="nofollow" - """ - rv = urlize(value, trim_url_limit, nofollow) - if eval_ctx.autoescape: - rv = Markup(rv) - return rv - - -def do_indent(s, width=4, indentfirst=False): - """Return a copy of the passed string, each line indented by - 4 spaces. The first line is not indented. If you want to - change the number of spaces or indent the first line too - you can pass additional parameters to the filter: - - .. sourcecode:: jinja - - {{ mytext|indent(2, true) }} - indent by two spaces and indent the first line too. - """ - indention = u' ' * width - rv = (u'\n' + indention).join(s.splitlines()) - if indentfirst: - rv = indention + rv - return rv - - -def do_truncate(s, length=255, killwords=False, end='...'): - """Return a truncated copy of the string. The length is specified - with the first parameter which defaults to ``255``. If the second - parameter is ``true`` the filter will cut the text at length. Otherwise - it will discard the last word. If the text was in fact - truncated it will append an ellipsis sign (``"..."``). If you want a - different ellipsis sign than ``"..."`` you can specify it using the - third parameter. - - .. sourcecode:: jinja - - {{ "foo bar"|truncate(5) }} - -> "foo ..." - {{ "foo bar"|truncate(5, True) }} - -> "foo b..." - """ - if len(s) <= length: - return s - elif killwords: - return s[:length] + end - words = s.split(' ') - result = [] - m = 0 - for word in words: - m += len(word) + 1 - if m > length: - break - result.append(word) - result.append(end) - return u' '.join(result) - -@environmentfilter -def do_wordwrap(environment, s, width=79, break_long_words=True, - wrapstring=None): - """ - Return a copy of the string passed to the filter wrapped after - ``79`` characters. You can override this default using the first - parameter. If you set the second parameter to `false` Jinja will not - split words apart if they are longer than `width`. By default, the newlines - will be the default newlines for the environment, but this can be changed - using the wrapstring keyword argument. - - .. versionadded:: 2.7 - Added support for the `wrapstring` parameter. - """ - if not wrapstring: - wrapstring = environment.newline_sequence - import textwrap - return wrapstring.join(textwrap.wrap(s, width=width, expand_tabs=False, - replace_whitespace=False, - break_long_words=break_long_words)) - - -def do_wordcount(s): - """Count the words in that string.""" - return len(_word_re.findall(s)) - - -def do_int(value, default=0): - """Convert the value into an integer. If the - conversion doesn't work it will return ``0``. You can - override this default using the first parameter. - """ - try: - return int(value) - except (TypeError, ValueError): - # this quirk is necessary so that "42.23"|int gives 42. - try: - return int(float(value)) - except (TypeError, ValueError): - return default - - -def do_float(value, default=0.0): - """Convert the value into a floating point number. If the - conversion doesn't work it will return ``0.0``. You can - override this default using the first parameter. - """ - try: - return float(value) - except (TypeError, ValueError): - return default - - -def do_format(value, *args, **kwargs): - """ - Apply python string formatting on an object: - - .. sourcecode:: jinja - - {{ "%s - %s"|format("Hello?", "Foo!") }} - -> Hello? - Foo! - """ - if args and kwargs: - raise FilterArgumentError('can\'t handle positional and keyword ' - 'arguments at the same time') - return soft_unicode(value) % (kwargs or args) - - -def do_trim(value): - """Strip leading and trailing whitespace.""" - return soft_unicode(value).strip() - - -def do_striptags(value): - """Strip SGML/XML tags and replace adjacent whitespace by one space. - """ - if hasattr(value, '__html__'): - value = value.__html__() - return Markup(text_type(value)).striptags() - - -def do_slice(value, slices, fill_with=None): - """Slice an iterator and return a list of lists containing - those items. Useful if you want to create a div containing - three ul tags that represent columns: - - .. sourcecode:: html+jinja - -
- {%- for column in items|slice(3) %} -
    - {%- for item in column %} -
  • {{ item }}
  • - {%- endfor %} -
- {%- endfor %} -
- - If you pass it a second argument it's used to fill missing - values on the last iteration. - """ - seq = list(value) - length = len(seq) - items_per_slice = length // slices - slices_with_extra = length % slices - offset = 0 - for slice_number in range(slices): - start = offset + slice_number * items_per_slice - if slice_number < slices_with_extra: - offset += 1 - end = offset + (slice_number + 1) * items_per_slice - tmp = seq[start:end] - if fill_with is not None and slice_number >= slices_with_extra: - tmp.append(fill_with) - yield tmp - - -def do_batch(value, linecount, fill_with=None): - """ - A filter that batches items. It works pretty much like `slice` - just the other way round. It returns a list of lists with the - given number of items. If you provide a second parameter this - is used to fill up missing items. See this example: - - .. sourcecode:: html+jinja - - - {%- for row in items|batch(3, ' ') %} - - {%- for column in row %} - - {%- endfor %} - - {%- endfor %} -
{{ column }}
- """ - result = [] - tmp = [] - for item in value: - if len(tmp) == linecount: - yield tmp - tmp = [] - tmp.append(item) - if tmp: - if fill_with is not None and len(tmp) < linecount: - tmp += [fill_with] * (linecount - len(tmp)) - yield tmp - - -def do_round(value, precision=0, method='common'): - """Round the number to a given precision. The first - parameter specifies the precision (default is ``0``), the - second the rounding method: - - - ``'common'`` rounds either up or down - - ``'ceil'`` always rounds up - - ``'floor'`` always rounds down - - If you don't specify a method ``'common'`` is used. - - .. sourcecode:: jinja - - {{ 42.55|round }} - -> 43.0 - {{ 42.55|round(1, 'floor') }} - -> 42.5 - - Note that even if rounded to 0 precision, a float is returned. If - you need a real integer, pipe it through `int`: - - .. sourcecode:: jinja - - {{ 42.55|round|int }} - -> 43 - """ - if not method in ('common', 'ceil', 'floor'): - raise FilterArgumentError('method must be common, ceil or floor') - if method == 'common': - return round(value, precision) - func = getattr(math, method) - return func(value * (10 ** precision)) / (10 ** precision) - - -@environmentfilter -def do_groupby(environment, value, attribute): - """Group a sequence of objects by a common attribute. - - If you for example have a list of dicts or objects that represent persons - with `gender`, `first_name` and `last_name` attributes and you want to - group all users by genders you can do something like the following - snippet: - - .. sourcecode:: html+jinja - -
    - {% for group in persons|groupby('gender') %} -
  • {{ group.grouper }}
      - {% for person in group.list %} -
    • {{ person.first_name }} {{ person.last_name }}
    • - {% endfor %}
  • - {% endfor %} -
- - Additionally it's possible to use tuple unpacking for the grouper and - list: - - .. sourcecode:: html+jinja - -
    - {% for grouper, list in persons|groupby('gender') %} - ... - {% endfor %} -
- - As you can see the item we're grouping by is stored in the `grouper` - attribute and the `list` contains all the objects that have this grouper - in common. - - .. versionchanged:: 2.6 - It's now possible to use dotted notation to group by the child - attribute of another attribute. - """ - expr = make_attrgetter(environment, attribute) - return sorted(map(_GroupTuple, groupby(sorted(value, key=expr), expr))) - - -class _GroupTuple(tuple): - __slots__ = () - grouper = property(itemgetter(0)) - list = property(itemgetter(1)) - - def __new__(cls, xxx_todo_changeme): - (key, value) = xxx_todo_changeme - return tuple.__new__(cls, (key, list(value))) - - -@environmentfilter -def do_sum(environment, iterable, attribute=None, start=0): - """Returns the sum of a sequence of numbers plus the value of parameter - 'start' (which defaults to 0). When the sequence is empty it returns - start. - - It is also possible to sum up only certain attributes: - - .. sourcecode:: jinja - - Total: {{ items|sum(attribute='price') }} - - .. versionchanged:: 2.6 - The `attribute` parameter was added to allow suming up over - attributes. Also the `start` parameter was moved on to the right. - """ - if attribute is not None: - iterable = imap(make_attrgetter(environment, attribute), iterable) - return sum(iterable, start) - - -def do_list(value): - """Convert the value into a list. If it was a string the returned list - will be a list of characters. - """ - return list(value) - - -def do_mark_safe(value): - """Mark the value as safe which means that in an environment with automatic - escaping enabled this variable will not be escaped. - """ - return Markup(value) - - -def do_mark_unsafe(value): - """Mark a value as unsafe. This is the reverse operation for :func:`safe`.""" - return text_type(value) - - -def do_reverse(value): - """Reverse the object or return an iterator the iterates over it the other - way round. - """ - if isinstance(value, string_types): - return value[::-1] - try: - return reversed(value) - except TypeError: - try: - rv = list(value) - rv.reverse() - return rv - except TypeError: - raise FilterArgumentError('argument must be iterable') - - -@environmentfilter -def do_attr(environment, obj, name): - """Get an attribute of an object. ``foo|attr("bar")`` works like - ``foo["bar"]`` just that always an attribute is returned and items are not - looked up. - - See :ref:`Notes on subscriptions ` for more details. - """ - try: - name = str(name) - except UnicodeError: - pass - else: - try: - value = getattr(obj, name) - except AttributeError: - pass - else: - if environment.sandboxed and not \ - environment.is_safe_attribute(obj, name, value): - return environment.unsafe_undefined(obj, name) - return value - return environment.undefined(obj=obj, name=name) - - -@contextfilter -def do_map(*args, **kwargs): - """Applies a filter on a sequence of objects or looks up an attribute. - This is useful when dealing with lists of objects but you are really - only interested in a certain value of it. - - The basic usage is mapping on an attribute. Imagine you have a list - of users but you are only interested in a list of usernames: - - .. sourcecode:: jinja - - Users on this page: {{ users|map(attribute='username')|join(', ') }} - - Alternatively you can let it invoke a filter by passing the name of the - filter and the arguments afterwards. A good example would be applying a - text conversion filter on a sequence: - - .. sourcecode:: jinja - - Users on this page: {{ titles|map('lower')|join(', ') }} - - .. versionadded:: 2.7 - """ - context = args[0] - seq = args[1] - - if len(args) == 2 and 'attribute' in kwargs: - attribute = kwargs.pop('attribute') - if kwargs: - raise FilterArgumentError('Unexpected keyword argument %r' % - next(iter(kwargs))) - func = make_attrgetter(context.environment, attribute) - else: - try: - name = args[2] - args = args[3:] - except LookupError: - raise FilterArgumentError('map requires a filter argument') - func = lambda item: context.environment.call_filter( - name, item, args, kwargs, context=context) - - if seq: - for item in seq: - yield func(item) - - -@contextfilter -def do_select(*args, **kwargs): - """Filters a sequence of objects by appying a test to either the object - or the attribute and only selecting the ones with the test succeeding. - - Example usage: - - .. sourcecode:: jinja - - {{ numbers|select("odd") }} - - .. versionadded:: 2.7 - """ - return _select_or_reject(args, kwargs, lambda x: x, False) - - -@contextfilter -def do_reject(*args, **kwargs): - """Filters a sequence of objects by appying a test to either the object - or the attribute and rejecting the ones with the test succeeding. - - Example usage: - - .. sourcecode:: jinja - - {{ numbers|reject("odd") }} - - .. versionadded:: 2.7 - """ - return _select_or_reject(args, kwargs, lambda x: not x, False) - - -@contextfilter -def do_selectattr(*args, **kwargs): - """Filters a sequence of objects by appying a test to either the object - or the attribute and only selecting the ones with the test succeeding. - - Example usage: - - .. sourcecode:: jinja - - {{ users|selectattr("is_active") }} - {{ users|selectattr("email", "none") }} - - .. versionadded:: 2.7 - """ - return _select_or_reject(args, kwargs, lambda x: x, True) - - -@contextfilter -def do_rejectattr(*args, **kwargs): - """Filters a sequence of objects by appying a test to either the object - or the attribute and rejecting the ones with the test succeeding. - - .. sourcecode:: jinja - - {{ users|rejectattr("is_active") }} - {{ users|rejectattr("email", "none") }} - - .. versionadded:: 2.7 - """ - return _select_or_reject(args, kwargs, lambda x: not x, True) - - -def _select_or_reject(args, kwargs, modfunc, lookup_attr): - context = args[0] - seq = args[1] - if lookup_attr: - try: - attr = args[2] - except LookupError: - raise FilterArgumentError('Missing parameter for attribute name') - transfunc = make_attrgetter(context.environment, attr) - off = 1 - else: - off = 0 - transfunc = lambda x: x - - try: - name = args[2 + off] - args = args[3 + off:] - func = lambda item: context.environment.call_test( - name, item, args, kwargs) - except LookupError: - func = bool - - if seq: - for item in seq: - if modfunc(func(transfunc(item))): - yield item - - -FILTERS = { - 'attr': do_attr, - 'replace': do_replace, - 'upper': do_upper, - 'lower': do_lower, - 'escape': escape, - 'e': escape, - 'forceescape': do_forceescape, - 'capitalize': do_capitalize, - 'title': do_title, - 'default': do_default, - 'd': do_default, - 'join': do_join, - 'count': len, - 'dictsort': do_dictsort, - 'sort': do_sort, - 'length': len, - 'reverse': do_reverse, - 'center': do_center, - 'indent': do_indent, - 'title': do_title, - 'capitalize': do_capitalize, - 'first': do_first, - 'last': do_last, - 'map': do_map, - 'random': do_random, - 'reject': do_reject, - 'rejectattr': do_rejectattr, - 'filesizeformat': do_filesizeformat, - 'pprint': do_pprint, - 'truncate': do_truncate, - 'wordwrap': do_wordwrap, - 'wordcount': do_wordcount, - 'int': do_int, - 'float': do_float, - 'string': soft_unicode, - 'list': do_list, - 'urlize': do_urlize, - 'format': do_format, - 'trim': do_trim, - 'striptags': do_striptags, - 'select': do_select, - 'selectattr': do_selectattr, - 'slice': do_slice, - 'batch': do_batch, - 'sum': do_sum, - 'abs': abs, - 'round': do_round, - 'groupby': do_groupby, - 'safe': do_mark_safe, - 'xmlattr': do_xmlattr, - 'urlencode': do_urlencode -} diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/lexer.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/lexer.py deleted file mode 100644 index a5012850..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/lexer.py +++ /dev/null @@ -1,733 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.lexer - ~~~~~~~~~~~~ - - This module implements a Jinja / Python combination lexer. The - `Lexer` class provided by this module is used to do some preprocessing - for Jinja. - - On the one hand it filters out invalid operators like the bitshift - operators we don't allow in templates. On the other hand it separates - template code and python code in expressions. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import re - -from operator import itemgetter -from collections import deque -from jinja2.exceptions import TemplateSyntaxError -from jinja2.utils import LRUCache -from jinja2._compat import next, iteritems, implements_iterator, text_type, \ - intern - - -# cache for the lexers. Exists in order to be able to have multiple -# environments with the same lexer -_lexer_cache = LRUCache(50) - -# static regular expressions -whitespace_re = re.compile(r'\s+', re.U) -string_re = re.compile(r"('([^'\\]*(?:\\.[^'\\]*)*)'" - r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S) -integer_re = re.compile(r'\d+') - -# we use the unicode identifier rule if this python version is able -# to handle unicode identifiers, otherwise the standard ASCII one. -try: - compile('föö', '', 'eval') -except SyntaxError: - name_re = re.compile(r'\b[a-zA-Z_][a-zA-Z0-9_]*\b') -else: - from jinja2 import _stringdefs - name_re = re.compile(r'[%s][%s]*' % (_stringdefs.xid_start, - _stringdefs.xid_continue)) - -float_re = re.compile(r'(?': TOKEN_GT, - '>=': TOKEN_GTEQ, - '<': TOKEN_LT, - '<=': TOKEN_LTEQ, - '=': TOKEN_ASSIGN, - '.': TOKEN_DOT, - ':': TOKEN_COLON, - '|': TOKEN_PIPE, - ',': TOKEN_COMMA, - ';': TOKEN_SEMICOLON -} - -reverse_operators = dict([(v, k) for k, v in iteritems(operators)]) -assert len(operators) == len(reverse_operators), 'operators dropped' -operator_re = re.compile('(%s)' % '|'.join(re.escape(x) for x in - sorted(operators, key=lambda x: -len(x)))) - -ignored_tokens = frozenset([TOKEN_COMMENT_BEGIN, TOKEN_COMMENT, - TOKEN_COMMENT_END, TOKEN_WHITESPACE, - TOKEN_WHITESPACE, TOKEN_LINECOMMENT_BEGIN, - TOKEN_LINECOMMENT_END, TOKEN_LINECOMMENT]) -ignore_if_empty = frozenset([TOKEN_WHITESPACE, TOKEN_DATA, - TOKEN_COMMENT, TOKEN_LINECOMMENT]) - - -def _describe_token_type(token_type): - if token_type in reverse_operators: - return reverse_operators[token_type] - return { - TOKEN_COMMENT_BEGIN: 'begin of comment', - TOKEN_COMMENT_END: 'end of comment', - TOKEN_COMMENT: 'comment', - TOKEN_LINECOMMENT: 'comment', - TOKEN_BLOCK_BEGIN: 'begin of statement block', - TOKEN_BLOCK_END: 'end of statement block', - TOKEN_VARIABLE_BEGIN: 'begin of print statement', - TOKEN_VARIABLE_END: 'end of print statement', - TOKEN_LINESTATEMENT_BEGIN: 'begin of line statement', - TOKEN_LINESTATEMENT_END: 'end of line statement', - TOKEN_DATA: 'template data / text', - TOKEN_EOF: 'end of template' - }.get(token_type, token_type) - - -def describe_token(token): - """Returns a description of the token.""" - if token.type == 'name': - return token.value - return _describe_token_type(token.type) - - -def describe_token_expr(expr): - """Like `describe_token` but for token expressions.""" - if ':' in expr: - type, value = expr.split(':', 1) - if type == 'name': - return value - else: - type = expr - return _describe_token_type(type) - - -def count_newlines(value): - """Count the number of newline characters in the string. This is - useful for extensions that filter a stream. - """ - return len(newline_re.findall(value)) - - -def compile_rules(environment): - """Compiles all the rules from the environment into a list of rules.""" - e = re.escape - rules = [ - (len(environment.comment_start_string), 'comment', - e(environment.comment_start_string)), - (len(environment.block_start_string), 'block', - e(environment.block_start_string)), - (len(environment.variable_start_string), 'variable', - e(environment.variable_start_string)) - ] - - if environment.line_statement_prefix is not None: - rules.append((len(environment.line_statement_prefix), 'linestatement', - r'^[ \t\v]*' + e(environment.line_statement_prefix))) - if environment.line_comment_prefix is not None: - rules.append((len(environment.line_comment_prefix), 'linecomment', - r'(?:^|(?<=\S))[^\S\r\n]*' + - e(environment.line_comment_prefix))) - - return [x[1:] for x in sorted(rules, reverse=True)] - - -class Failure(object): - """Class that raises a `TemplateSyntaxError` if called. - Used by the `Lexer` to specify known errors. - """ - - def __init__(self, message, cls=TemplateSyntaxError): - self.message = message - self.error_class = cls - - def __call__(self, lineno, filename): - raise self.error_class(self.message, lineno, filename) - - -class Token(tuple): - """Token class.""" - __slots__ = () - lineno, type, value = (property(itemgetter(x)) for x in range(3)) - - def __new__(cls, lineno, type, value): - return tuple.__new__(cls, (lineno, intern(str(type)), value)) - - def __str__(self): - if self.type in reverse_operators: - return reverse_operators[self.type] - elif self.type == 'name': - return self.value - return self.type - - def test(self, expr): - """Test a token against a token expression. This can either be a - token type or ``'token_type:token_value'``. This can only test - against string values and types. - """ - # here we do a regular string equality check as test_any is usually - # passed an iterable of not interned strings. - if self.type == expr: - return True - elif ':' in expr: - return expr.split(':', 1) == [self.type, self.value] - return False - - def test_any(self, *iterable): - """Test against multiple token expressions.""" - for expr in iterable: - if self.test(expr): - return True - return False - - def __repr__(self): - return 'Token(%r, %r, %r)' % ( - self.lineno, - self.type, - self.value - ) - - -@implements_iterator -class TokenStreamIterator(object): - """The iterator for tokenstreams. Iterate over the stream - until the eof token is reached. - """ - - def __init__(self, stream): - self.stream = stream - - def __iter__(self): - return self - - def __next__(self): - token = self.stream.current - if token.type is TOKEN_EOF: - self.stream.close() - raise StopIteration() - next(self.stream) - return token - - -@implements_iterator -class TokenStream(object): - """A token stream is an iterable that yields :class:`Token`\s. The - parser however does not iterate over it but calls :meth:`next` to go - one token ahead. The current active token is stored as :attr:`current`. - """ - - def __init__(self, generator, name, filename): - self._iter = iter(generator) - self._pushed = deque() - self.name = name - self.filename = filename - self.closed = False - self.current = Token(1, TOKEN_INITIAL, '') - next(self) - - def __iter__(self): - return TokenStreamIterator(self) - - def __bool__(self): - return bool(self._pushed) or self.current.type is not TOKEN_EOF - __nonzero__ = __bool__ # py2 - - eos = property(lambda x: not x, doc="Are we at the end of the stream?") - - def push(self, token): - """Push a token back to the stream.""" - self._pushed.append(token) - - def look(self): - """Look at the next token.""" - old_token = next(self) - result = self.current - self.push(result) - self.current = old_token - return result - - def skip(self, n=1): - """Got n tokens ahead.""" - for x in range(n): - next(self) - - def next_if(self, expr): - """Perform the token test and return the token if it matched. - Otherwise the return value is `None`. - """ - if self.current.test(expr): - return next(self) - - def skip_if(self, expr): - """Like :meth:`next_if` but only returns `True` or `False`.""" - return self.next_if(expr) is not None - - def __next__(self): - """Go one token ahead and return the old one""" - rv = self.current - if self._pushed: - self.current = self._pushed.popleft() - elif self.current.type is not TOKEN_EOF: - try: - self.current = next(self._iter) - except StopIteration: - self.close() - return rv - - def close(self): - """Close the stream.""" - self.current = Token(self.current.lineno, TOKEN_EOF, '') - self._iter = None - self.closed = True - - def expect(self, expr): - """Expect a given token type and return it. This accepts the same - argument as :meth:`jinja2.lexer.Token.test`. - """ - if not self.current.test(expr): - expr = describe_token_expr(expr) - if self.current.type is TOKEN_EOF: - raise TemplateSyntaxError('unexpected end of template, ' - 'expected %r.' % expr, - self.current.lineno, - self.name, self.filename) - raise TemplateSyntaxError("expected token %r, got %r" % - (expr, describe_token(self.current)), - self.current.lineno, - self.name, self.filename) - try: - return self.current - finally: - next(self) - - -def get_lexer(environment): - """Return a lexer which is probably cached.""" - key = (environment.block_start_string, - environment.block_end_string, - environment.variable_start_string, - environment.variable_end_string, - environment.comment_start_string, - environment.comment_end_string, - environment.line_statement_prefix, - environment.line_comment_prefix, - environment.trim_blocks, - environment.lstrip_blocks, - environment.newline_sequence, - environment.keep_trailing_newline) - lexer = _lexer_cache.get(key) - if lexer is None: - lexer = Lexer(environment) - _lexer_cache[key] = lexer - return lexer - - -class Lexer(object): - """Class that implements a lexer for a given environment. Automatically - created by the environment class, usually you don't have to do that. - - Note that the lexer is not automatically bound to an environment. - Multiple environments can share the same lexer. - """ - - def __init__(self, environment): - # shortcuts - c = lambda x: re.compile(x, re.M | re.S) - e = re.escape - - # lexing rules for tags - tag_rules = [ - (whitespace_re, TOKEN_WHITESPACE, None), - (float_re, TOKEN_FLOAT, None), - (integer_re, TOKEN_INTEGER, None), - (name_re, TOKEN_NAME, None), - (string_re, TOKEN_STRING, None), - (operator_re, TOKEN_OPERATOR, None) - ] - - # assemble the root lexing rule. because "|" is ungreedy - # we have to sort by length so that the lexer continues working - # as expected when we have parsing rules like <% for block and - # <%= for variables. (if someone wants asp like syntax) - # variables are just part of the rules if variable processing - # is required. - root_tag_rules = compile_rules(environment) - - # block suffix if trimming is enabled - block_suffix_re = environment.trim_blocks and '\\n?' or '' - - # strip leading spaces if lstrip_blocks is enabled - prefix_re = {} - if environment.lstrip_blocks: - # use '{%+' to manually disable lstrip_blocks behavior - no_lstrip_re = e('+') - # detect overlap between block and variable or comment strings - block_diff = c(r'^%s(.*)' % e(environment.block_start_string)) - # make sure we don't mistake a block for a variable or a comment - m = block_diff.match(environment.comment_start_string) - no_lstrip_re += m and r'|%s' % e(m.group(1)) or '' - m = block_diff.match(environment.variable_start_string) - no_lstrip_re += m and r'|%s' % e(m.group(1)) or '' - - # detect overlap between comment and variable strings - comment_diff = c(r'^%s(.*)' % e(environment.comment_start_string)) - m = comment_diff.match(environment.variable_start_string) - no_variable_re = m and r'(?!%s)' % e(m.group(1)) or '' - - lstrip_re = r'^[ \t]*' - block_prefix_re = r'%s%s(?!%s)|%s\+?' % ( - lstrip_re, - e(environment.block_start_string), - no_lstrip_re, - e(environment.block_start_string), - ) - comment_prefix_re = r'%s%s%s|%s\+?' % ( - lstrip_re, - e(environment.comment_start_string), - no_variable_re, - e(environment.comment_start_string), - ) - prefix_re['block'] = block_prefix_re - prefix_re['comment'] = comment_prefix_re - else: - block_prefix_re = '%s' % e(environment.block_start_string) - - self.newline_sequence = environment.newline_sequence - self.keep_trailing_newline = environment.keep_trailing_newline - - # global lexing rules - self.rules = { - 'root': [ - # directives - (c('(.*?)(?:%s)' % '|'.join( - [r'(?P(?:\s*%s\-|%s)\s*raw\s*(?:\-%s\s*|%s))' % ( - e(environment.block_start_string), - block_prefix_re, - e(environment.block_end_string), - e(environment.block_end_string) - )] + [ - r'(?P<%s_begin>\s*%s\-|%s)' % (n, r, prefix_re.get(n,r)) - for n, r in root_tag_rules - ])), (TOKEN_DATA, '#bygroup'), '#bygroup'), - # data - (c('.+'), TOKEN_DATA, None) - ], - # comments - TOKEN_COMMENT_BEGIN: [ - (c(r'(.*?)((?:\-%s\s*|%s)%s)' % ( - e(environment.comment_end_string), - e(environment.comment_end_string), - block_suffix_re - )), (TOKEN_COMMENT, TOKEN_COMMENT_END), '#pop'), - (c('(.)'), (Failure('Missing end of comment tag'),), None) - ], - # blocks - TOKEN_BLOCK_BEGIN: [ - (c('(?:\-%s\s*|%s)%s' % ( - e(environment.block_end_string), - e(environment.block_end_string), - block_suffix_re - )), TOKEN_BLOCK_END, '#pop'), - ] + tag_rules, - # variables - TOKEN_VARIABLE_BEGIN: [ - (c('\-%s\s*|%s' % ( - e(environment.variable_end_string), - e(environment.variable_end_string) - )), TOKEN_VARIABLE_END, '#pop') - ] + tag_rules, - # raw block - TOKEN_RAW_BEGIN: [ - (c('(.*?)((?:\s*%s\-|%s)\s*endraw\s*(?:\-%s\s*|%s%s))' % ( - e(environment.block_start_string), - block_prefix_re, - e(environment.block_end_string), - e(environment.block_end_string), - block_suffix_re - )), (TOKEN_DATA, TOKEN_RAW_END), '#pop'), - (c('(.)'), (Failure('Missing end of raw directive'),), None) - ], - # line statements - TOKEN_LINESTATEMENT_BEGIN: [ - (c(r'\s*(\n|$)'), TOKEN_LINESTATEMENT_END, '#pop') - ] + tag_rules, - # line comments - TOKEN_LINECOMMENT_BEGIN: [ - (c(r'(.*?)()(?=\n|$)'), (TOKEN_LINECOMMENT, - TOKEN_LINECOMMENT_END), '#pop') - ] - } - - def _normalize_newlines(self, value): - """Called for strings and template data to normalize it to unicode.""" - return newline_re.sub(self.newline_sequence, value) - - def tokenize(self, source, name=None, filename=None, state=None): - """Calls tokeniter + tokenize and wraps it in a token stream. - """ - stream = self.tokeniter(source, name, filename, state) - return TokenStream(self.wrap(stream, name, filename), name, filename) - - def wrap(self, stream, name=None, filename=None): - """This is called with the stream as returned by `tokenize` and wraps - every token in a :class:`Token` and converts the value. - """ - for lineno, token, value in stream: - if token in ignored_tokens: - continue - elif token == 'linestatement_begin': - token = 'block_begin' - elif token == 'linestatement_end': - token = 'block_end' - # we are not interested in those tokens in the parser - elif token in ('raw_begin', 'raw_end'): - continue - elif token == 'data': - value = self._normalize_newlines(value) - elif token == 'keyword': - token = value - elif token == 'name': - value = str(value) - elif token == 'string': - # try to unescape string - try: - value = self._normalize_newlines(value[1:-1]) \ - .encode('ascii', 'backslashreplace') \ - .decode('unicode-escape') - except Exception as e: - msg = str(e).split(':')[-1].strip() - raise TemplateSyntaxError(msg, lineno, name, filename) - # if we can express it as bytestring (ascii only) - # we do that for support of semi broken APIs - # as datetime.datetime.strftime. On python 3 this - # call becomes a noop thanks to 2to3 - try: - value = str(value) - except UnicodeError: - pass - elif token == 'integer': - value = int(value) - elif token == 'float': - value = float(value) - elif token == 'operator': - token = operators[value] - yield Token(lineno, token, value) - - def tokeniter(self, source, name, filename=None, state=None): - """This method tokenizes the text and returns the tokens in a - generator. Use this method if you just want to tokenize a template. - """ - source = text_type(source) - lines = source.splitlines() - if self.keep_trailing_newline and source: - for newline in ('\r\n', '\r', '\n'): - if source.endswith(newline): - lines.append('') - break - source = '\n'.join(lines) - pos = 0 - lineno = 1 - stack = ['root'] - if state is not None and state != 'root': - assert state in ('variable', 'block'), 'invalid state' - stack.append(state + '_begin') - else: - state = 'root' - statetokens = self.rules[stack[-1]] - source_length = len(source) - - balancing_stack = [] - - while 1: - # tokenizer loop - for regex, tokens, new_state in statetokens: - m = regex.match(source, pos) - # if no match we try again with the next rule - if m is None: - continue - - # we only match blocks and variables if braces / parentheses - # are balanced. continue parsing with the lower rule which - # is the operator rule. do this only if the end tags look - # like operators - if balancing_stack and \ - tokens in ('variable_end', 'block_end', - 'linestatement_end'): - continue - - # tuples support more options - if isinstance(tokens, tuple): - for idx, token in enumerate(tokens): - # failure group - if token.__class__ is Failure: - raise token(lineno, filename) - # bygroup is a bit more complex, in that case we - # yield for the current token the first named - # group that matched - elif token == '#bygroup': - for key, value in iteritems(m.groupdict()): - if value is not None: - yield lineno, key, value - lineno += value.count('\n') - break - else: - raise RuntimeError('%r wanted to resolve ' - 'the token dynamically' - ' but no group matched' - % regex) - # normal group - else: - data = m.group(idx + 1) - if data or token not in ignore_if_empty: - yield lineno, token, data - lineno += data.count('\n') - - # strings as token just are yielded as it. - else: - data = m.group() - # update brace/parentheses balance - if tokens == 'operator': - if data == '{': - balancing_stack.append('}') - elif data == '(': - balancing_stack.append(')') - elif data == '[': - balancing_stack.append(']') - elif data in ('}', ')', ']'): - if not balancing_stack: - raise TemplateSyntaxError('unexpected \'%s\'' % - data, lineno, name, - filename) - expected_op = balancing_stack.pop() - if expected_op != data: - raise TemplateSyntaxError('unexpected \'%s\', ' - 'expected \'%s\'' % - (data, expected_op), - lineno, name, - filename) - # yield items - if data or tokens not in ignore_if_empty: - yield lineno, tokens, data - lineno += data.count('\n') - - # fetch new position into new variable so that we can check - # if there is a internal parsing error which would result - # in an infinite loop - pos2 = m.end() - - # handle state changes - if new_state is not None: - # remove the uppermost state - if new_state == '#pop': - stack.pop() - # resolve the new state by group checking - elif new_state == '#bygroup': - for key, value in iteritems(m.groupdict()): - if value is not None: - stack.append(key) - break - else: - raise RuntimeError('%r wanted to resolve the ' - 'new state dynamically but' - ' no group matched' % - regex) - # direct state name given - else: - stack.append(new_state) - statetokens = self.rules[stack[-1]] - # we are still at the same position and no stack change. - # this means a loop without break condition, avoid that and - # raise error - elif pos2 == pos: - raise RuntimeError('%r yielded empty string without ' - 'stack change' % regex) - # publish new function and start again - pos = pos2 - break - # if loop terminated without break we haven't found a single match - # either we are at the end of the file or we have a problem - else: - # end of text - if pos >= source_length: - return - # something went wrong - raise TemplateSyntaxError('unexpected char %r at %d' % - (source[pos], pos), lineno, - name, filename) diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/loaders.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/loaders.py deleted file mode 100644 index cc9c6836..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/loaders.py +++ /dev/null @@ -1,471 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.loaders - ~~~~~~~~~~~~~~ - - Jinja loader classes. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import os -import sys -import weakref -from types import ModuleType -from os import path -from hashlib import sha1 -from jinja2.exceptions import TemplateNotFound -from jinja2.utils import open_if_exists, internalcode -from jinja2._compat import string_types, iteritems - - -def split_template_path(template): - """Split a path into segments and perform a sanity check. If it detects - '..' in the path it will raise a `TemplateNotFound` error. - """ - pieces = [] - for piece in template.split('/'): - if path.sep in piece \ - or (path.altsep and path.altsep in piece) or \ - piece == path.pardir: - raise TemplateNotFound(template) - elif piece and piece != '.': - pieces.append(piece) - return pieces - - -class BaseLoader(object): - """Baseclass for all loaders. Subclass this and override `get_source` to - implement a custom loading mechanism. The environment provides a - `get_template` method that calls the loader's `load` method to get the - :class:`Template` object. - - A very basic example for a loader that looks up templates on the file - system could look like this:: - - from jinja2 import BaseLoader, TemplateNotFound - from os.path import join, exists, getmtime - - class MyLoader(BaseLoader): - - def __init__(self, path): - self.path = path - - def get_source(self, environment, template): - path = join(self.path, template) - if not exists(path): - raise TemplateNotFound(template) - mtime = getmtime(path) - with file(path) as f: - source = f.read().decode('utf-8') - return source, path, lambda: mtime == getmtime(path) - """ - - #: if set to `False` it indicates that the loader cannot provide access - #: to the source of templates. - #: - #: .. versionadded:: 2.4 - has_source_access = True - - def get_source(self, environment, template): - """Get the template source, filename and reload helper for a template. - It's passed the environment and template name and has to return a - tuple in the form ``(source, filename, uptodate)`` or raise a - `TemplateNotFound` error if it can't locate the template. - - The source part of the returned tuple must be the source of the - template as unicode string or a ASCII bytestring. The filename should - be the name of the file on the filesystem if it was loaded from there, - otherwise `None`. The filename is used by python for the tracebacks - if no loader extension is used. - - The last item in the tuple is the `uptodate` function. If auto - reloading is enabled it's always called to check if the template - changed. No arguments are passed so the function must store the - old state somewhere (for example in a closure). If it returns `False` - the template will be reloaded. - """ - if not self.has_source_access: - raise RuntimeError('%s cannot provide access to the source' % - self.__class__.__name__) - raise TemplateNotFound(template) - - def list_templates(self): - """Iterates over all templates. If the loader does not support that - it should raise a :exc:`TypeError` which is the default behavior. - """ - raise TypeError('this loader cannot iterate over all templates') - - @internalcode - def load(self, environment, name, globals=None): - """Loads a template. This method looks up the template in the cache - or loads one by calling :meth:`get_source`. Subclasses should not - override this method as loaders working on collections of other - loaders (such as :class:`PrefixLoader` or :class:`ChoiceLoader`) - will not call this method but `get_source` directly. - """ - code = None - if globals is None: - globals = {} - - # first we try to get the source for this template together - # with the filename and the uptodate function. - source, filename, uptodate = self.get_source(environment, name) - - # try to load the code from the bytecode cache if there is a - # bytecode cache configured. - bcc = environment.bytecode_cache - if bcc is not None: - bucket = bcc.get_bucket(environment, name, filename, source) - code = bucket.code - - # if we don't have code so far (not cached, no longer up to - # date) etc. we compile the template - if code is None: - code = environment.compile(source, name, filename) - - # if the bytecode cache is available and the bucket doesn't - # have a code so far, we give the bucket the new code and put - # it back to the bytecode cache. - if bcc is not None and bucket.code is None: - bucket.code = code - bcc.set_bucket(bucket) - - return environment.template_class.from_code(environment, code, - globals, uptodate) - - -class FileSystemLoader(BaseLoader): - """Loads templates from the file system. This loader can find templates - in folders on the file system and is the preferred way to load them. - - The loader takes the path to the templates as string, or if multiple - locations are wanted a list of them which is then looked up in the - given order: - - >>> loader = FileSystemLoader('/path/to/templates') - >>> loader = FileSystemLoader(['/path/to/templates', '/other/path']) - - Per default the template encoding is ``'utf-8'`` which can be changed - by setting the `encoding` parameter to something else. - """ - - def __init__(self, searchpath, encoding='utf-8'): - if isinstance(searchpath, string_types): - searchpath = [searchpath] - self.searchpath = list(searchpath) - self.encoding = encoding - - def get_source(self, environment, template): - pieces = split_template_path(template) - for searchpath in self.searchpath: - filename = path.join(searchpath, *pieces) - f = open_if_exists(filename) - if f is None: - continue - try: - contents = f.read().decode(self.encoding) - finally: - f.close() - - mtime = path.getmtime(filename) - def uptodate(): - try: - return path.getmtime(filename) == mtime - except OSError: - return False - return contents, filename, uptodate - raise TemplateNotFound(template) - - def list_templates(self): - found = set() - for searchpath in self.searchpath: - for dirpath, dirnames, filenames in os.walk(searchpath): - for filename in filenames: - template = os.path.join(dirpath, filename) \ - [len(searchpath):].strip(os.path.sep) \ - .replace(os.path.sep, '/') - if template[:2] == './': - template = template[2:] - if template not in found: - found.add(template) - return sorted(found) - - -class PackageLoader(BaseLoader): - """Load templates from python eggs or packages. It is constructed with - the name of the python package and the path to the templates in that - package:: - - loader = PackageLoader('mypackage', 'views') - - If the package path is not given, ``'templates'`` is assumed. - - Per default the template encoding is ``'utf-8'`` which can be changed - by setting the `encoding` parameter to something else. Due to the nature - of eggs it's only possible to reload templates if the package was loaded - from the file system and not a zip file. - """ - - def __init__(self, package_name, package_path='templates', - encoding='utf-8'): - from pkg_resources import DefaultProvider, ResourceManager, \ - get_provider - provider = get_provider(package_name) - self.encoding = encoding - self.manager = ResourceManager() - self.filesystem_bound = isinstance(provider, DefaultProvider) - self.provider = provider - self.package_path = package_path - - def get_source(self, environment, template): - pieces = split_template_path(template) - p = '/'.join((self.package_path,) + tuple(pieces)) - if not self.provider.has_resource(p): - raise TemplateNotFound(template) - - filename = uptodate = None - if self.filesystem_bound: - filename = self.provider.get_resource_filename(self.manager, p) - mtime = path.getmtime(filename) - def uptodate(): - try: - return path.getmtime(filename) == mtime - except OSError: - return False - - source = self.provider.get_resource_string(self.manager, p) - return source.decode(self.encoding), filename, uptodate - - def list_templates(self): - path = self.package_path - if path[:2] == './': - path = path[2:] - elif path == '.': - path = '' - offset = len(path) - results = [] - def _walk(path): - for filename in self.provider.resource_listdir(path): - fullname = path + '/' + filename - if self.provider.resource_isdir(fullname): - _walk(fullname) - else: - results.append(fullname[offset:].lstrip('/')) - _walk(path) - results.sort() - return results - - -class DictLoader(BaseLoader): - """Loads a template from a python dict. It's passed a dict of unicode - strings bound to template names. This loader is useful for unittesting: - - >>> loader = DictLoader({'index.html': 'source here'}) - - Because auto reloading is rarely useful this is disabled per default. - """ - - def __init__(self, mapping): - self.mapping = mapping - - def get_source(self, environment, template): - if template in self.mapping: - source = self.mapping[template] - return source, None, lambda: source == self.mapping.get(template) - raise TemplateNotFound(template) - - def list_templates(self): - return sorted(self.mapping) - - -class FunctionLoader(BaseLoader): - """A loader that is passed a function which does the loading. The - function becomes the name of the template passed and has to return either - an unicode string with the template source, a tuple in the form ``(source, - filename, uptodatefunc)`` or `None` if the template does not exist. - - >>> def load_template(name): - ... if name == 'index.html': - ... return '...' - ... - >>> loader = FunctionLoader(load_template) - - The `uptodatefunc` is a function that is called if autoreload is enabled - and has to return `True` if the template is still up to date. For more - details have a look at :meth:`BaseLoader.get_source` which has the same - return value. - """ - - def __init__(self, load_func): - self.load_func = load_func - - def get_source(self, environment, template): - rv = self.load_func(template) - if rv is None: - raise TemplateNotFound(template) - elif isinstance(rv, string_types): - return rv, None, None - return rv - - -class PrefixLoader(BaseLoader): - """A loader that is passed a dict of loaders where each loader is bound - to a prefix. The prefix is delimited from the template by a slash per - default, which can be changed by setting the `delimiter` argument to - something else:: - - loader = PrefixLoader({ - 'app1': PackageLoader('mypackage.app1'), - 'app2': PackageLoader('mypackage.app2') - }) - - By loading ``'app1/index.html'`` the file from the app1 package is loaded, - by loading ``'app2/index.html'`` the file from the second. - """ - - def __init__(self, mapping, delimiter='/'): - self.mapping = mapping - self.delimiter = delimiter - - def get_loader(self, template): - try: - prefix, name = template.split(self.delimiter, 1) - loader = self.mapping[prefix] - except (ValueError, KeyError): - raise TemplateNotFound(template) - return loader, name - - def get_source(self, environment, template): - loader, name = self.get_loader(template) - try: - return loader.get_source(environment, name) - except TemplateNotFound: - # re-raise the exception with the correct fileame here. - # (the one that includes the prefix) - raise TemplateNotFound(template) - - @internalcode - def load(self, environment, name, globals=None): - loader, local_name = self.get_loader(name) - try: - return loader.load(environment, local_name, globals) - except TemplateNotFound: - # re-raise the exception with the correct fileame here. - # (the one that includes the prefix) - raise TemplateNotFound(name) - - def list_templates(self): - result = [] - for prefix, loader in iteritems(self.mapping): - for template in loader.list_templates(): - result.append(prefix + self.delimiter + template) - return result - - -class ChoiceLoader(BaseLoader): - """This loader works like the `PrefixLoader` just that no prefix is - specified. If a template could not be found by one loader the next one - is tried. - - >>> loader = ChoiceLoader([ - ... FileSystemLoader('/path/to/user/templates'), - ... FileSystemLoader('/path/to/system/templates') - ... ]) - - This is useful if you want to allow users to override builtin templates - from a different location. - """ - - def __init__(self, loaders): - self.loaders = loaders - - def get_source(self, environment, template): - for loader in self.loaders: - try: - return loader.get_source(environment, template) - except TemplateNotFound: - pass - raise TemplateNotFound(template) - - @internalcode - def load(self, environment, name, globals=None): - for loader in self.loaders: - try: - return loader.load(environment, name, globals) - except TemplateNotFound: - pass - raise TemplateNotFound(name) - - def list_templates(self): - found = set() - for loader in self.loaders: - found.update(loader.list_templates()) - return sorted(found) - - -class _TemplateModule(ModuleType): - """Like a normal module but with support for weak references""" - - -class ModuleLoader(BaseLoader): - """This loader loads templates from precompiled templates. - - Example usage: - - >>> loader = ChoiceLoader([ - ... ModuleLoader('/path/to/compiled/templates'), - ... FileSystemLoader('/path/to/templates') - ... ]) - - Templates can be precompiled with :meth:`Environment.compile_templates`. - """ - - has_source_access = False - - def __init__(self, path): - package_name = '_jinja2_module_templates_%x' % id(self) - - # create a fake module that looks for the templates in the - # path given. - mod = _TemplateModule(package_name) - if isinstance(path, string_types): - path = [path] - else: - path = list(path) - mod.__path__ = path - - sys.modules[package_name] = weakref.proxy(mod, - lambda x: sys.modules.pop(package_name, None)) - - # the only strong reference, the sys.modules entry is weak - # so that the garbage collector can remove it once the - # loader that created it goes out of business. - self.module = mod - self.package_name = package_name - - @staticmethod - def get_template_key(name): - return 'tmpl_' + sha1(name.encode('utf-8')).hexdigest() - - @staticmethod - def get_module_filename(name): - return ModuleLoader.get_template_key(name) + '.py' - - @internalcode - def load(self, environment, name, globals=None): - key = self.get_template_key(name) - module = '%s.%s' % (self.package_name, key) - mod = getattr(self.module, module, None) - if mod is None: - try: - mod = __import__(module, None, None, ['root']) - except ImportError: - raise TemplateNotFound(name) - - # remove the entry from sys.modules, we only want the attribute - # on the module object we have stored on the loader. - sys.modules.pop(module, None) - - return environment.template_class.from_module_dict( - environment, mod.__dict__, globals) diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/meta.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/meta.py deleted file mode 100644 index 3110cff6..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/meta.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.meta - ~~~~~~~~~~~ - - This module implements various functions that exposes information about - templates that might be interesting for various kinds of applications. - - :copyright: (c) 2010 by the Jinja Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -from jinja2 import nodes -from jinja2.compiler import CodeGenerator -from jinja2._compat import string_types - - -class TrackingCodeGenerator(CodeGenerator): - """We abuse the code generator for introspection.""" - - def __init__(self, environment): - CodeGenerator.__init__(self, environment, '', - '') - self.undeclared_identifiers = set() - - def write(self, x): - """Don't write.""" - - def pull_locals(self, frame): - """Remember all undeclared identifiers.""" - self.undeclared_identifiers.update(frame.identifiers.undeclared) - - -def find_undeclared_variables(ast): - """Returns a set of all variables in the AST that will be looked up from - the context at runtime. Because at compile time it's not known which - variables will be used depending on the path the execution takes at - runtime, all variables are returned. - - >>> from jinja2 import Environment, meta - >>> env = Environment() - >>> ast = env.parse('{% set foo = 42 %}{{ bar + foo }}') - >>> meta.find_undeclared_variables(ast) - set(['bar']) - - .. admonition:: Implementation - - Internally the code generator is used for finding undeclared variables. - This is good to know because the code generator might raise a - :exc:`TemplateAssertionError` during compilation and as a matter of - fact this function can currently raise that exception as well. - """ - codegen = TrackingCodeGenerator(ast.environment) - codegen.visit(ast) - return codegen.undeclared_identifiers - - -def find_referenced_templates(ast): - """Finds all the referenced templates from the AST. This will return an - iterator over all the hardcoded template extensions, inclusions and - imports. If dynamic inheritance or inclusion is used, `None` will be - yielded. - - >>> from jinja2 import Environment, meta - >>> env = Environment() - >>> ast = env.parse('{% extends "layout.html" %}{% include helper %}') - >>> list(meta.find_referenced_templates(ast)) - ['layout.html', None] - - This function is useful for dependency tracking. For example if you want - to rebuild parts of the website after a layout template has changed. - """ - for node in ast.find_all((nodes.Extends, nodes.FromImport, nodes.Import, - nodes.Include)): - if not isinstance(node.template, nodes.Const): - # a tuple with some non consts in there - if isinstance(node.template, (nodes.Tuple, nodes.List)): - for template_name in node.template.items: - # something const, only yield the strings and ignore - # non-string consts that really just make no sense - if isinstance(template_name, nodes.Const): - if isinstance(template_name.value, string_types): - yield template_name.value - # something dynamic in there - else: - yield None - # something dynamic we don't know about here - else: - yield None - continue - # constant is a basestring, direct template name - if isinstance(node.template.value, string_types): - yield node.template.value - # a tuple or list (latter *should* not happen) made of consts, - # yield the consts that are strings. We could warn here for - # non string values - elif isinstance(node, nodes.Include) and \ - isinstance(node.template.value, (tuple, list)): - for template_name in node.template.value: - if isinstance(template_name, string_types): - yield template_name - # something else we don't care about, we could warn here - else: - yield None diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/nodes.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/nodes.py deleted file mode 100644 index c5697e6b..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/nodes.py +++ /dev/null @@ -1,914 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.nodes - ~~~~~~~~~~~~ - - This module implements additional nodes derived from the ast base node. - - It also provides some node tree helper functions like `in_lineno` and - `get_nodes` used by the parser and translator in order to normalize - python and jinja nodes. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import operator - -from collections import deque -from jinja2.utils import Markup -from jinja2._compat import next, izip, with_metaclass, text_type, \ - method_type, function_type - - -#: the types we support for context functions -_context_function_types = (function_type, method_type) - - -_binop_to_func = { - '*': operator.mul, - '/': operator.truediv, - '//': operator.floordiv, - '**': operator.pow, - '%': operator.mod, - '+': operator.add, - '-': operator.sub -} - -_uaop_to_func = { - 'not': operator.not_, - '+': operator.pos, - '-': operator.neg -} - -_cmpop_to_func = { - 'eq': operator.eq, - 'ne': operator.ne, - 'gt': operator.gt, - 'gteq': operator.ge, - 'lt': operator.lt, - 'lteq': operator.le, - 'in': lambda a, b: a in b, - 'notin': lambda a, b: a not in b -} - - -class Impossible(Exception): - """Raised if the node could not perform a requested action.""" - - -class NodeType(type): - """A metaclass for nodes that handles the field and attribute - inheritance. fields and attributes from the parent class are - automatically forwarded to the child.""" - - def __new__(cls, name, bases, d): - for attr in 'fields', 'attributes': - storage = [] - storage.extend(getattr(bases[0], attr, ())) - storage.extend(d.get(attr, ())) - assert len(bases) == 1, 'multiple inheritance not allowed' - assert len(storage) == len(set(storage)), 'layout conflict' - d[attr] = tuple(storage) - d.setdefault('abstract', False) - return type.__new__(cls, name, bases, d) - - -class EvalContext(object): - """Holds evaluation time information. Custom attributes can be attached - to it in extensions. - """ - - def __init__(self, environment, template_name=None): - self.environment = environment - if callable(environment.autoescape): - self.autoescape = environment.autoescape(template_name) - else: - self.autoescape = environment.autoescape - self.volatile = False - - def save(self): - return self.__dict__.copy() - - def revert(self, old): - self.__dict__.clear() - self.__dict__.update(old) - - -def get_eval_context(node, ctx): - if ctx is None: - if node.environment is None: - raise RuntimeError('if no eval context is passed, the ' - 'node must have an attached ' - 'environment.') - return EvalContext(node.environment) - return ctx - - -class Node(with_metaclass(NodeType, object)): - """Baseclass for all Jinja2 nodes. There are a number of nodes available - of different types. There are four major types: - - - :class:`Stmt`: statements - - :class:`Expr`: expressions - - :class:`Helper`: helper nodes - - :class:`Template`: the outermost wrapper node - - All nodes have fields and attributes. Fields may be other nodes, lists, - or arbitrary values. Fields are passed to the constructor as regular - positional arguments, attributes as keyword arguments. Each node has - two attributes: `lineno` (the line number of the node) and `environment`. - The `environment` attribute is set at the end of the parsing process for - all nodes automatically. - """ - fields = () - attributes = ('lineno', 'environment') - abstract = True - - def __init__(self, *fields, **attributes): - if self.abstract: - raise TypeError('abstract nodes are not instanciable') - if fields: - if len(fields) != len(self.fields): - if not self.fields: - raise TypeError('%r takes 0 arguments' % - self.__class__.__name__) - raise TypeError('%r takes 0 or %d argument%s' % ( - self.__class__.__name__, - len(self.fields), - len(self.fields) != 1 and 's' or '' - )) - for name, arg in izip(self.fields, fields): - setattr(self, name, arg) - for attr in self.attributes: - setattr(self, attr, attributes.pop(attr, None)) - if attributes: - raise TypeError('unknown attribute %r' % - next(iter(attributes))) - - def iter_fields(self, exclude=None, only=None): - """This method iterates over all fields that are defined and yields - ``(key, value)`` tuples. Per default all fields are returned, but - it's possible to limit that to some fields by providing the `only` - parameter or to exclude some using the `exclude` parameter. Both - should be sets or tuples of field names. - """ - for name in self.fields: - if (exclude is only is None) or \ - (exclude is not None and name not in exclude) or \ - (only is not None and name in only): - try: - yield name, getattr(self, name) - except AttributeError: - pass - - def iter_child_nodes(self, exclude=None, only=None): - """Iterates over all direct child nodes of the node. This iterates - over all fields and yields the values of they are nodes. If the value - of a field is a list all the nodes in that list are returned. - """ - for field, item in self.iter_fields(exclude, only): - if isinstance(item, list): - for n in item: - if isinstance(n, Node): - yield n - elif isinstance(item, Node): - yield item - - def find(self, node_type): - """Find the first node of a given type. If no such node exists the - return value is `None`. - """ - for result in self.find_all(node_type): - return result - - def find_all(self, node_type): - """Find all the nodes of a given type. If the type is a tuple, - the check is performed for any of the tuple items. - """ - for child in self.iter_child_nodes(): - if isinstance(child, node_type): - yield child - for result in child.find_all(node_type): - yield result - - def set_ctx(self, ctx): - """Reset the context of a node and all child nodes. Per default the - parser will all generate nodes that have a 'load' context as it's the - most common one. This method is used in the parser to set assignment - targets and other nodes to a store context. - """ - todo = deque([self]) - while todo: - node = todo.popleft() - if 'ctx' in node.fields: - node.ctx = ctx - todo.extend(node.iter_child_nodes()) - return self - - def set_lineno(self, lineno, override=False): - """Set the line numbers of the node and children.""" - todo = deque([self]) - while todo: - node = todo.popleft() - if 'lineno' in node.attributes: - if node.lineno is None or override: - node.lineno = lineno - todo.extend(node.iter_child_nodes()) - return self - - def set_environment(self, environment): - """Set the environment for all nodes.""" - todo = deque([self]) - while todo: - node = todo.popleft() - node.environment = environment - todo.extend(node.iter_child_nodes()) - return self - - def __eq__(self, other): - return type(self) is type(other) and \ - tuple(self.iter_fields()) == tuple(other.iter_fields()) - - def __ne__(self, other): - return not self.__eq__(other) - - # Restore Python 2 hashing behavior on Python 3 - __hash__ = object.__hash__ - - def __repr__(self): - return '%s(%s)' % ( - self.__class__.__name__, - ', '.join('%s=%r' % (arg, getattr(self, arg, None)) for - arg in self.fields) - ) - - -class Stmt(Node): - """Base node for all statements.""" - abstract = True - - -class Helper(Node): - """Nodes that exist in a specific context only.""" - abstract = True - - -class Template(Node): - """Node that represents a template. This must be the outermost node that - is passed to the compiler. - """ - fields = ('body',) - - -class Output(Stmt): - """A node that holds multiple expressions which are then printed out. - This is used both for the `print` statement and the regular template data. - """ - fields = ('nodes',) - - -class Extends(Stmt): - """Represents an extends statement.""" - fields = ('template',) - - -class For(Stmt): - """The for loop. `target` is the target for the iteration (usually a - :class:`Name` or :class:`Tuple`), `iter` the iterable. `body` is a list - of nodes that are used as loop-body, and `else_` a list of nodes for the - `else` block. If no else node exists it has to be an empty list. - - For filtered nodes an expression can be stored as `test`, otherwise `None`. - """ - fields = ('target', 'iter', 'body', 'else_', 'test', 'recursive') - - -class If(Stmt): - """If `test` is true, `body` is rendered, else `else_`.""" - fields = ('test', 'body', 'else_') - - -class Macro(Stmt): - """A macro definition. `name` is the name of the macro, `args` a list of - arguments and `defaults` a list of defaults if there are any. `body` is - a list of nodes for the macro body. - """ - fields = ('name', 'args', 'defaults', 'body') - - -class CallBlock(Stmt): - """Like a macro without a name but a call instead. `call` is called with - the unnamed macro as `caller` argument this node holds. - """ - fields = ('call', 'args', 'defaults', 'body') - - -class FilterBlock(Stmt): - """Node for filter sections.""" - fields = ('body', 'filter') - - -class Block(Stmt): - """A node that represents a block.""" - fields = ('name', 'body', 'scoped') - - -class Include(Stmt): - """A node that represents the include tag.""" - fields = ('template', 'with_context', 'ignore_missing') - - -class Import(Stmt): - """A node that represents the import tag.""" - fields = ('template', 'target', 'with_context') - - -class FromImport(Stmt): - """A node that represents the from import tag. It's important to not - pass unsafe names to the name attribute. The compiler translates the - attribute lookups directly into getattr calls and does *not* use the - subscript callback of the interface. As exported variables may not - start with double underscores (which the parser asserts) this is not a - problem for regular Jinja code, but if this node is used in an extension - extra care must be taken. - - The list of names may contain tuples if aliases are wanted. - """ - fields = ('template', 'names', 'with_context') - - -class ExprStmt(Stmt): - """A statement that evaluates an expression and discards the result.""" - fields = ('node',) - - -class Assign(Stmt): - """Assigns an expression to a target.""" - fields = ('target', 'node') - - -class Expr(Node): - """Baseclass for all expressions.""" - abstract = True - - def as_const(self, eval_ctx=None): - """Return the value of the expression as constant or raise - :exc:`Impossible` if this was not possible. - - An :class:`EvalContext` can be provided, if none is given - a default context is created which requires the nodes to have - an attached environment. - - .. versionchanged:: 2.4 - the `eval_ctx` parameter was added. - """ - raise Impossible() - - def can_assign(self): - """Check if it's possible to assign something to this node.""" - return False - - -class BinExpr(Expr): - """Baseclass for all binary expressions.""" - fields = ('left', 'right') - operator = None - abstract = True - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - # intercepted operators cannot be folded at compile time - if self.environment.sandboxed and \ - self.operator in self.environment.intercepted_binops: - raise Impossible() - f = _binop_to_func[self.operator] - try: - return f(self.left.as_const(eval_ctx), self.right.as_const(eval_ctx)) - except Exception: - raise Impossible() - - -class UnaryExpr(Expr): - """Baseclass for all unary expressions.""" - fields = ('node',) - operator = None - abstract = True - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - # intercepted operators cannot be folded at compile time - if self.environment.sandboxed and \ - self.operator in self.environment.intercepted_unops: - raise Impossible() - f = _uaop_to_func[self.operator] - try: - return f(self.node.as_const(eval_ctx)) - except Exception: - raise Impossible() - - -class Name(Expr): - """Looks up a name or stores a value in a name. - The `ctx` of the node can be one of the following values: - - - `store`: store a value in the name - - `load`: load that name - - `param`: like `store` but if the name was defined as function parameter. - """ - fields = ('name', 'ctx') - - def can_assign(self): - return self.name not in ('true', 'false', 'none', - 'True', 'False', 'None') - - -class Literal(Expr): - """Baseclass for literals.""" - abstract = True - - -class Const(Literal): - """All constant values. The parser will return this node for simple - constants such as ``42`` or ``"foo"`` but it can be used to store more - complex values such as lists too. Only constants with a safe - representation (objects where ``eval(repr(x)) == x`` is true). - """ - fields = ('value',) - - def as_const(self, eval_ctx=None): - return self.value - - @classmethod - def from_untrusted(cls, value, lineno=None, environment=None): - """Return a const object if the value is representable as - constant value in the generated code, otherwise it will raise - an `Impossible` exception. - """ - from .compiler import has_safe_repr - if not has_safe_repr(value): - raise Impossible() - return cls(value, lineno=lineno, environment=environment) - - -class TemplateData(Literal): - """A constant template string.""" - fields = ('data',) - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - if eval_ctx.volatile: - raise Impossible() - if eval_ctx.autoescape: - return Markup(self.data) - return self.data - - -class Tuple(Literal): - """For loop unpacking and some other things like multiple arguments - for subscripts. Like for :class:`Name` `ctx` specifies if the tuple - is used for loading the names or storing. - """ - fields = ('items', 'ctx') - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - return tuple(x.as_const(eval_ctx) for x in self.items) - - def can_assign(self): - for item in self.items: - if not item.can_assign(): - return False - return True - - -class List(Literal): - """Any list literal such as ``[1, 2, 3]``""" - fields = ('items',) - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - return [x.as_const(eval_ctx) for x in self.items] - - -class Dict(Literal): - """Any dict literal such as ``{1: 2, 3: 4}``. The items must be a list of - :class:`Pair` nodes. - """ - fields = ('items',) - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - return dict(x.as_const(eval_ctx) for x in self.items) - - -class Pair(Helper): - """A key, value pair for dicts.""" - fields = ('key', 'value') - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx) - - -class Keyword(Helper): - """A key, value pair for keyword arguments where key is a string.""" - fields = ('key', 'value') - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - return self.key, self.value.as_const(eval_ctx) - - -class CondExpr(Expr): - """A conditional expression (inline if expression). (``{{ - foo if bar else baz }}``) - """ - fields = ('test', 'expr1', 'expr2') - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - if self.test.as_const(eval_ctx): - return self.expr1.as_const(eval_ctx) - - # if we evaluate to an undefined object, we better do that at runtime - if self.expr2 is None: - raise Impossible() - - return self.expr2.as_const(eval_ctx) - - -class Filter(Expr): - """This node applies a filter on an expression. `name` is the name of - the filter, the rest of the fields are the same as for :class:`Call`. - - If the `node` of a filter is `None` the contents of the last buffer are - filtered. Buffers are created by macros and filter blocks. - """ - fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs') - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - if eval_ctx.volatile or self.node is None: - raise Impossible() - # we have to be careful here because we call filter_ below. - # if this variable would be called filter, 2to3 would wrap the - # call in a list beause it is assuming we are talking about the - # builtin filter function here which no longer returns a list in - # python 3. because of that, do not rename filter_ to filter! - filter_ = self.environment.filters.get(self.name) - if filter_ is None or getattr(filter_, 'contextfilter', False): - raise Impossible() - obj = self.node.as_const(eval_ctx) - args = [x.as_const(eval_ctx) for x in self.args] - if getattr(filter_, 'evalcontextfilter', False): - args.insert(0, eval_ctx) - elif getattr(filter_, 'environmentfilter', False): - args.insert(0, self.environment) - kwargs = dict(x.as_const(eval_ctx) for x in self.kwargs) - if self.dyn_args is not None: - try: - args.extend(self.dyn_args.as_const(eval_ctx)) - except Exception: - raise Impossible() - if self.dyn_kwargs is not None: - try: - kwargs.update(self.dyn_kwargs.as_const(eval_ctx)) - except Exception: - raise Impossible() - try: - return filter_(obj, *args, **kwargs) - except Exception: - raise Impossible() - - -class Test(Expr): - """Applies a test on an expression. `name` is the name of the test, the - rest of the fields are the same as for :class:`Call`. - """ - fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs') - - -class Call(Expr): - """Calls an expression. `args` is a list of arguments, `kwargs` a list - of keyword arguments (list of :class:`Keyword` nodes), and `dyn_args` - and `dyn_kwargs` has to be either `None` or a node that is used as - node for dynamic positional (``*args``) or keyword (``**kwargs``) - arguments. - """ - fields = ('node', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs') - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - if eval_ctx.volatile: - raise Impossible() - obj = self.node.as_const(eval_ctx) - - # don't evaluate context functions - args = [x.as_const(eval_ctx) for x in self.args] - if isinstance(obj, _context_function_types): - if getattr(obj, 'contextfunction', False): - raise Impossible() - elif getattr(obj, 'evalcontextfunction', False): - args.insert(0, eval_ctx) - elif getattr(obj, 'environmentfunction', False): - args.insert(0, self.environment) - - kwargs = dict(x.as_const(eval_ctx) for x in self.kwargs) - if self.dyn_args is not None: - try: - args.extend(self.dyn_args.as_const(eval_ctx)) - except Exception: - raise Impossible() - if self.dyn_kwargs is not None: - try: - kwargs.update(self.dyn_kwargs.as_const(eval_ctx)) - except Exception: - raise Impossible() - try: - return obj(*args, **kwargs) - except Exception: - raise Impossible() - - -class Getitem(Expr): - """Get an attribute or item from an expression and prefer the item.""" - fields = ('node', 'arg', 'ctx') - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - if self.ctx != 'load': - raise Impossible() - try: - return self.environment.getitem(self.node.as_const(eval_ctx), - self.arg.as_const(eval_ctx)) - except Exception: - raise Impossible() - - def can_assign(self): - return False - - -class Getattr(Expr): - """Get an attribute or item from an expression that is a ascii-only - bytestring and prefer the attribute. - """ - fields = ('node', 'attr', 'ctx') - - def as_const(self, eval_ctx=None): - if self.ctx != 'load': - raise Impossible() - try: - eval_ctx = get_eval_context(self, eval_ctx) - return self.environment.getattr(self.node.as_const(eval_ctx), - self.attr) - except Exception: - raise Impossible() - - def can_assign(self): - return False - - -class Slice(Expr): - """Represents a slice object. This must only be used as argument for - :class:`Subscript`. - """ - fields = ('start', 'stop', 'step') - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - def const(obj): - if obj is None: - return None - return obj.as_const(eval_ctx) - return slice(const(self.start), const(self.stop), const(self.step)) - - -class Concat(Expr): - """Concatenates the list of expressions provided after converting them to - unicode. - """ - fields = ('nodes',) - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - return ''.join(text_type(x.as_const(eval_ctx)) for x in self.nodes) - - -class Compare(Expr): - """Compares an expression with some other expressions. `ops` must be a - list of :class:`Operand`\s. - """ - fields = ('expr', 'ops') - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - result = value = self.expr.as_const(eval_ctx) - try: - for op in self.ops: - new_value = op.expr.as_const(eval_ctx) - result = _cmpop_to_func[op.op](value, new_value) - value = new_value - except Exception: - raise Impossible() - return result - - -class Operand(Helper): - """Holds an operator and an expression.""" - fields = ('op', 'expr') - -if __debug__: - Operand.__doc__ += '\nThe following operators are available: ' + \ - ', '.join(sorted('``%s``' % x for x in set(_binop_to_func) | - set(_uaop_to_func) | set(_cmpop_to_func))) - - -class Mul(BinExpr): - """Multiplies the left with the right node.""" - operator = '*' - - -class Div(BinExpr): - """Divides the left by the right node.""" - operator = '/' - - -class FloorDiv(BinExpr): - """Divides the left by the right node and truncates conver the - result into an integer by truncating. - """ - operator = '//' - - -class Add(BinExpr): - """Add the left to the right node.""" - operator = '+' - - -class Sub(BinExpr): - """Substract the right from the left node.""" - operator = '-' - - -class Mod(BinExpr): - """Left modulo right.""" - operator = '%' - - -class Pow(BinExpr): - """Left to the power of right.""" - operator = '**' - - -class And(BinExpr): - """Short circuited AND.""" - operator = 'and' - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - return self.left.as_const(eval_ctx) and self.right.as_const(eval_ctx) - - -class Or(BinExpr): - """Short circuited OR.""" - operator = 'or' - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - return self.left.as_const(eval_ctx) or self.right.as_const(eval_ctx) - - -class Not(UnaryExpr): - """Negate the expression.""" - operator = 'not' - - -class Neg(UnaryExpr): - """Make the expression negative.""" - operator = '-' - - -class Pos(UnaryExpr): - """Make the expression positive (noop for most expressions)""" - operator = '+' - - -# Helpers for extensions - - -class EnvironmentAttribute(Expr): - """Loads an attribute from the environment object. This is useful for - extensions that want to call a callback stored on the environment. - """ - fields = ('name',) - - -class ExtensionAttribute(Expr): - """Returns the attribute of an extension bound to the environment. - The identifier is the identifier of the :class:`Extension`. - - This node is usually constructed by calling the - :meth:`~jinja2.ext.Extension.attr` method on an extension. - """ - fields = ('identifier', 'name') - - -class ImportedName(Expr): - """If created with an import name the import name is returned on node - access. For example ``ImportedName('cgi.escape')`` returns the `escape` - function from the cgi module on evaluation. Imports are optimized by the - compiler so there is no need to assign them to local variables. - """ - fields = ('importname',) - - -class InternalName(Expr): - """An internal name in the compiler. You cannot create these nodes - yourself but the parser provides a - :meth:`~jinja2.parser.Parser.free_identifier` method that creates - a new identifier for you. This identifier is not available from the - template and is not threated specially by the compiler. - """ - fields = ('name',) - - def __init__(self): - raise TypeError('Can\'t create internal names. Use the ' - '`free_identifier` method on a parser.') - - -class MarkSafe(Expr): - """Mark the wrapped expression as safe (wrap it as `Markup`).""" - fields = ('expr',) - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - return Markup(self.expr.as_const(eval_ctx)) - - -class MarkSafeIfAutoescape(Expr): - """Mark the wrapped expression as safe (wrap it as `Markup`) but - only if autoescaping is active. - - .. versionadded:: 2.5 - """ - fields = ('expr',) - - def as_const(self, eval_ctx=None): - eval_ctx = get_eval_context(self, eval_ctx) - if eval_ctx.volatile: - raise Impossible() - expr = self.expr.as_const(eval_ctx) - if eval_ctx.autoescape: - return Markup(expr) - return expr - - -class ContextReference(Expr): - """Returns the current template context. It can be used like a - :class:`Name` node, with a ``'load'`` ctx and will return the - current :class:`~jinja2.runtime.Context` object. - - Here an example that assigns the current template name to a - variable named `foo`:: - - Assign(Name('foo', ctx='store'), - Getattr(ContextReference(), 'name')) - """ - - -class Continue(Stmt): - """Continue a loop.""" - - -class Break(Stmt): - """Break a loop.""" - - -class Scope(Stmt): - """An artificial scope.""" - fields = ('body',) - - -class EvalContextModifier(Stmt): - """Modifies the eval context. For each option that should be modified, - a :class:`Keyword` has to be added to the :attr:`options` list. - - Example to change the `autoescape` setting:: - - EvalContextModifier(options=[Keyword('autoescape', Const(True))]) - """ - fields = ('options',) - - -class ScopedEvalContextModifier(EvalContextModifier): - """Modifies the eval context and reverts it later. Works exactly like - :class:`EvalContextModifier` but will only modify the - :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`. - """ - fields = ('body',) - - -# make sure nobody creates custom nodes -def _failing_new(*args, **kwargs): - raise TypeError('can\'t create custom node types') -NodeType.__new__ = staticmethod(_failing_new); del _failing_new diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/optimizer.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/optimizer.py deleted file mode 100644 index 00eab115..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/optimizer.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.optimizer - ~~~~~~~~~~~~~~~~ - - The jinja optimizer is currently trying to constant fold a few expressions - and modify the AST in place so that it should be easier to evaluate it. - - Because the AST does not contain all the scoping information and the - compiler has to find that out, we cannot do all the optimizations we - want. For example loop unrolling doesn't work because unrolled loops would - have a different scoping. - - The solution would be a second syntax tree that has the scoping rules stored. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD. -""" -from jinja2 import nodes -from jinja2.visitor import NodeTransformer - - -def optimize(node, environment): - """The context hint can be used to perform an static optimization - based on the context given.""" - optimizer = Optimizer(environment) - return optimizer.visit(node) - - -class Optimizer(NodeTransformer): - - def __init__(self, environment): - self.environment = environment - - def visit_If(self, node): - """Eliminate dead code.""" - # do not optimize ifs that have a block inside so that it doesn't - # break super(). - if node.find(nodes.Block) is not None: - return self.generic_visit(node) - try: - val = self.visit(node.test).as_const() - except nodes.Impossible: - return self.generic_visit(node) - if val: - body = node.body - else: - body = node.else_ - result = [] - for node in body: - result.extend(self.visit_list(node)) - return result - - def fold(self, node): - """Do constant folding.""" - node = self.generic_visit(node) - try: - return nodes.Const.from_untrusted(node.as_const(), - lineno=node.lineno, - environment=self.environment) - except nodes.Impossible: - return node - - visit_Add = visit_Sub = visit_Mul = visit_Div = visit_FloorDiv = \ - visit_Pow = visit_Mod = visit_And = visit_Or = visit_Pos = visit_Neg = \ - visit_Not = visit_Compare = visit_Getitem = visit_Getattr = visit_Call = \ - visit_Filter = visit_Test = visit_CondExpr = fold - del fold diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/parser.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/parser.py deleted file mode 100644 index f60cd018..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/parser.py +++ /dev/null @@ -1,895 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.parser - ~~~~~~~~~~~~~ - - Implements the template parser. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -from jinja2 import nodes -from jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError -from jinja2.lexer import describe_token, describe_token_expr -from jinja2._compat import next, imap - - -#: statements that callinto -_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print', - 'macro', 'include', 'from', 'import', - 'set']) -_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq']) - - -class Parser(object): - """This is the central parsing class Jinja2 uses. It's passed to - extensions and can be used to parse expressions or statements. - """ - - def __init__(self, environment, source, name=None, filename=None, - state=None): - self.environment = environment - self.stream = environment._tokenize(source, name, filename, state) - self.name = name - self.filename = filename - self.closed = False - self.extensions = {} - for extension in environment.iter_extensions(): - for tag in extension.tags: - self.extensions[tag] = extension.parse - self._last_identifier = 0 - self._tag_stack = [] - self._end_token_stack = [] - - def fail(self, msg, lineno=None, exc=TemplateSyntaxError): - """Convenience method that raises `exc` with the message, passed - line number or last line number as well as the current name and - filename. - """ - if lineno is None: - lineno = self.stream.current.lineno - raise exc(msg, lineno, self.name, self.filename) - - def _fail_ut_eof(self, name, end_token_stack, lineno): - expected = [] - for exprs in end_token_stack: - expected.extend(imap(describe_token_expr, exprs)) - if end_token_stack: - currently_looking = ' or '.join( - "'%s'" % describe_token_expr(expr) - for expr in end_token_stack[-1]) - else: - currently_looking = None - - if name is None: - message = ['Unexpected end of template.'] - else: - message = ['Encountered unknown tag \'%s\'.' % name] - - if currently_looking: - if name is not None and name in expected: - message.append('You probably made a nesting mistake. Jinja ' - 'is expecting this tag, but currently looking ' - 'for %s.' % currently_looking) - else: - message.append('Jinja was looking for the following tags: ' - '%s.' % currently_looking) - - if self._tag_stack: - message.append('The innermost block that needs to be ' - 'closed is \'%s\'.' % self._tag_stack[-1]) - - self.fail(' '.join(message), lineno) - - def fail_unknown_tag(self, name, lineno=None): - """Called if the parser encounters an unknown tag. Tries to fail - with a human readable error message that could help to identify - the problem. - """ - return self._fail_ut_eof(name, self._end_token_stack, lineno) - - def fail_eof(self, end_tokens=None, lineno=None): - """Like fail_unknown_tag but for end of template situations.""" - stack = list(self._end_token_stack) - if end_tokens is not None: - stack.append(end_tokens) - return self._fail_ut_eof(None, stack, lineno) - - def is_tuple_end(self, extra_end_rules=None): - """Are we at the end of a tuple?""" - if self.stream.current.type in ('variable_end', 'block_end', 'rparen'): - return True - elif extra_end_rules is not None: - return self.stream.current.test_any(extra_end_rules) - return False - - def free_identifier(self, lineno=None): - """Return a new free identifier as :class:`~jinja2.nodes.InternalName`.""" - self._last_identifier += 1 - rv = object.__new__(nodes.InternalName) - nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno) - return rv - - def parse_statement(self): - """Parse a single statement.""" - token = self.stream.current - if token.type != 'name': - self.fail('tag name expected', token.lineno) - self._tag_stack.append(token.value) - pop_tag = True - try: - if token.value in _statement_keywords: - return getattr(self, 'parse_' + self.stream.current.value)() - if token.value == 'call': - return self.parse_call_block() - if token.value == 'filter': - return self.parse_filter_block() - ext = self.extensions.get(token.value) - if ext is not None: - return ext(self) - - # did not work out, remove the token we pushed by accident - # from the stack so that the unknown tag fail function can - # produce a proper error message. - self._tag_stack.pop() - pop_tag = False - self.fail_unknown_tag(token.value, token.lineno) - finally: - if pop_tag: - self._tag_stack.pop() - - def parse_statements(self, end_tokens, drop_needle=False): - """Parse multiple statements into a list until one of the end tokens - is reached. This is used to parse the body of statements as it also - parses template data if appropriate. The parser checks first if the - current token is a colon and skips it if there is one. Then it checks - for the block end and parses until if one of the `end_tokens` is - reached. Per default the active token in the stream at the end of - the call is the matched end token. If this is not wanted `drop_needle` - can be set to `True` and the end token is removed. - """ - # the first token may be a colon for python compatibility - self.stream.skip_if('colon') - - # in the future it would be possible to add whole code sections - # by adding some sort of end of statement token and parsing those here. - self.stream.expect('block_end') - result = self.subparse(end_tokens) - - # we reached the end of the template too early, the subparser - # does not check for this, so we do that now - if self.stream.current.type == 'eof': - self.fail_eof(end_tokens) - - if drop_needle: - next(self.stream) - return result - - def parse_set(self): - """Parse an assign statement.""" - lineno = next(self.stream).lineno - target = self.parse_assign_target() - self.stream.expect('assign') - expr = self.parse_tuple() - return nodes.Assign(target, expr, lineno=lineno) - - def parse_for(self): - """Parse a for loop.""" - lineno = self.stream.expect('name:for').lineno - target = self.parse_assign_target(extra_end_rules=('name:in',)) - self.stream.expect('name:in') - iter = self.parse_tuple(with_condexpr=False, - extra_end_rules=('name:recursive',)) - test = None - if self.stream.skip_if('name:if'): - test = self.parse_expression() - recursive = self.stream.skip_if('name:recursive') - body = self.parse_statements(('name:endfor', 'name:else')) - if next(self.stream).value == 'endfor': - else_ = [] - else: - else_ = self.parse_statements(('name:endfor',), drop_needle=True) - return nodes.For(target, iter, body, else_, test, - recursive, lineno=lineno) - - def parse_if(self): - """Parse an if construct.""" - node = result = nodes.If(lineno=self.stream.expect('name:if').lineno) - while 1: - node.test = self.parse_tuple(with_condexpr=False) - node.body = self.parse_statements(('name:elif', 'name:else', - 'name:endif')) - token = next(self.stream) - if token.test('name:elif'): - new_node = nodes.If(lineno=self.stream.current.lineno) - node.else_ = [new_node] - node = new_node - continue - elif token.test('name:else'): - node.else_ = self.parse_statements(('name:endif',), - drop_needle=True) - else: - node.else_ = [] - break - return result - - def parse_block(self): - node = nodes.Block(lineno=next(self.stream).lineno) - node.name = self.stream.expect('name').value - node.scoped = self.stream.skip_if('name:scoped') - - # common problem people encounter when switching from django - # to jinja. we do not support hyphens in block names, so let's - # raise a nicer error message in that case. - if self.stream.current.type == 'sub': - self.fail('Block names in Jinja have to be valid Python ' - 'identifiers and may not contain hyphens, use an ' - 'underscore instead.') - - node.body = self.parse_statements(('name:endblock',), drop_needle=True) - self.stream.skip_if('name:' + node.name) - return node - - def parse_extends(self): - node = nodes.Extends(lineno=next(self.stream).lineno) - node.template = self.parse_expression() - return node - - def parse_import_context(self, node, default): - if self.stream.current.test_any('name:with', 'name:without') and \ - self.stream.look().test('name:context'): - node.with_context = next(self.stream).value == 'with' - self.stream.skip() - else: - node.with_context = default - return node - - def parse_include(self): - node = nodes.Include(lineno=next(self.stream).lineno) - node.template = self.parse_expression() - if self.stream.current.test('name:ignore') and \ - self.stream.look().test('name:missing'): - node.ignore_missing = True - self.stream.skip(2) - else: - node.ignore_missing = False - return self.parse_import_context(node, True) - - def parse_import(self): - node = nodes.Import(lineno=next(self.stream).lineno) - node.template = self.parse_expression() - self.stream.expect('name:as') - node.target = self.parse_assign_target(name_only=True).name - return self.parse_import_context(node, False) - - def parse_from(self): - node = nodes.FromImport(lineno=next(self.stream).lineno) - node.template = self.parse_expression() - self.stream.expect('name:import') - node.names = [] - - def parse_context(): - if self.stream.current.value in ('with', 'without') and \ - self.stream.look().test('name:context'): - node.with_context = next(self.stream).value == 'with' - self.stream.skip() - return True - return False - - while 1: - if node.names: - self.stream.expect('comma') - if self.stream.current.type == 'name': - if parse_context(): - break - target = self.parse_assign_target(name_only=True) - if target.name.startswith('_'): - self.fail('names starting with an underline can not ' - 'be imported', target.lineno, - exc=TemplateAssertionError) - if self.stream.skip_if('name:as'): - alias = self.parse_assign_target(name_only=True) - node.names.append((target.name, alias.name)) - else: - node.names.append(target.name) - if parse_context() or self.stream.current.type != 'comma': - break - else: - break - if not hasattr(node, 'with_context'): - node.with_context = False - self.stream.skip_if('comma') - return node - - def parse_signature(self, node): - node.args = args = [] - node.defaults = defaults = [] - self.stream.expect('lparen') - while self.stream.current.type != 'rparen': - if args: - self.stream.expect('comma') - arg = self.parse_assign_target(name_only=True) - arg.set_ctx('param') - if self.stream.skip_if('assign'): - defaults.append(self.parse_expression()) - args.append(arg) - self.stream.expect('rparen') - - def parse_call_block(self): - node = nodes.CallBlock(lineno=next(self.stream).lineno) - if self.stream.current.type == 'lparen': - self.parse_signature(node) - else: - node.args = [] - node.defaults = [] - - node.call = self.parse_expression() - if not isinstance(node.call, nodes.Call): - self.fail('expected call', node.lineno) - node.body = self.parse_statements(('name:endcall',), drop_needle=True) - return node - - def parse_filter_block(self): - node = nodes.FilterBlock(lineno=next(self.stream).lineno) - node.filter = self.parse_filter(None, start_inline=True) - node.body = self.parse_statements(('name:endfilter',), - drop_needle=True) - return node - - def parse_macro(self): - node = nodes.Macro(lineno=next(self.stream).lineno) - node.name = self.parse_assign_target(name_only=True).name - self.parse_signature(node) - node.body = self.parse_statements(('name:endmacro',), - drop_needle=True) - return node - - def parse_print(self): - node = nodes.Output(lineno=next(self.stream).lineno) - node.nodes = [] - while self.stream.current.type != 'block_end': - if node.nodes: - self.stream.expect('comma') - node.nodes.append(self.parse_expression()) - return node - - def parse_assign_target(self, with_tuple=True, name_only=False, - extra_end_rules=None): - """Parse an assignment target. As Jinja2 allows assignments to - tuples, this function can parse all allowed assignment targets. Per - default assignments to tuples are parsed, that can be disable however - by setting `with_tuple` to `False`. If only assignments to names are - wanted `name_only` can be set to `True`. The `extra_end_rules` - parameter is forwarded to the tuple parsing function. - """ - if name_only: - token = self.stream.expect('name') - target = nodes.Name(token.value, 'store', lineno=token.lineno) - else: - if with_tuple: - target = self.parse_tuple(simplified=True, - extra_end_rules=extra_end_rules) - else: - target = self.parse_primary() - target.set_ctx('store') - if not target.can_assign(): - self.fail('can\'t assign to %r' % target.__class__. - __name__.lower(), target.lineno) - return target - - def parse_expression(self, with_condexpr=True): - """Parse an expression. Per default all expressions are parsed, if - the optional `with_condexpr` parameter is set to `False` conditional - expressions are not parsed. - """ - if with_condexpr: - return self.parse_condexpr() - return self.parse_or() - - def parse_condexpr(self): - lineno = self.stream.current.lineno - expr1 = self.parse_or() - while self.stream.skip_if('name:if'): - expr2 = self.parse_or() - if self.stream.skip_if('name:else'): - expr3 = self.parse_condexpr() - else: - expr3 = None - expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno) - lineno = self.stream.current.lineno - return expr1 - - def parse_or(self): - lineno = self.stream.current.lineno - left = self.parse_and() - while self.stream.skip_if('name:or'): - right = self.parse_and() - left = nodes.Or(left, right, lineno=lineno) - lineno = self.stream.current.lineno - return left - - def parse_and(self): - lineno = self.stream.current.lineno - left = self.parse_not() - while self.stream.skip_if('name:and'): - right = self.parse_not() - left = nodes.And(left, right, lineno=lineno) - lineno = self.stream.current.lineno - return left - - def parse_not(self): - if self.stream.current.test('name:not'): - lineno = next(self.stream).lineno - return nodes.Not(self.parse_not(), lineno=lineno) - return self.parse_compare() - - def parse_compare(self): - lineno = self.stream.current.lineno - expr = self.parse_add() - ops = [] - while 1: - token_type = self.stream.current.type - if token_type in _compare_operators: - next(self.stream) - ops.append(nodes.Operand(token_type, self.parse_add())) - elif self.stream.skip_if('name:in'): - ops.append(nodes.Operand('in', self.parse_add())) - elif self.stream.current.test('name:not') and \ - self.stream.look().test('name:in'): - self.stream.skip(2) - ops.append(nodes.Operand('notin', self.parse_add())) - else: - break - lineno = self.stream.current.lineno - if not ops: - return expr - return nodes.Compare(expr, ops, lineno=lineno) - - def parse_add(self): - lineno = self.stream.current.lineno - left = self.parse_sub() - while self.stream.current.type == 'add': - next(self.stream) - right = self.parse_sub() - left = nodes.Add(left, right, lineno=lineno) - lineno = self.stream.current.lineno - return left - - def parse_sub(self): - lineno = self.stream.current.lineno - left = self.parse_concat() - while self.stream.current.type == 'sub': - next(self.stream) - right = self.parse_concat() - left = nodes.Sub(left, right, lineno=lineno) - lineno = self.stream.current.lineno - return left - - def parse_concat(self): - lineno = self.stream.current.lineno - args = [self.parse_mul()] - while self.stream.current.type == 'tilde': - next(self.stream) - args.append(self.parse_mul()) - if len(args) == 1: - return args[0] - return nodes.Concat(args, lineno=lineno) - - def parse_mul(self): - lineno = self.stream.current.lineno - left = self.parse_div() - while self.stream.current.type == 'mul': - next(self.stream) - right = self.parse_div() - left = nodes.Mul(left, right, lineno=lineno) - lineno = self.stream.current.lineno - return left - - def parse_div(self): - lineno = self.stream.current.lineno - left = self.parse_floordiv() - while self.stream.current.type == 'div': - next(self.stream) - right = self.parse_floordiv() - left = nodes.Div(left, right, lineno=lineno) - lineno = self.stream.current.lineno - return left - - def parse_floordiv(self): - lineno = self.stream.current.lineno - left = self.parse_mod() - while self.stream.current.type == 'floordiv': - next(self.stream) - right = self.parse_mod() - left = nodes.FloorDiv(left, right, lineno=lineno) - lineno = self.stream.current.lineno - return left - - def parse_mod(self): - lineno = self.stream.current.lineno - left = self.parse_pow() - while self.stream.current.type == 'mod': - next(self.stream) - right = self.parse_pow() - left = nodes.Mod(left, right, lineno=lineno) - lineno = self.stream.current.lineno - return left - - def parse_pow(self): - lineno = self.stream.current.lineno - left = self.parse_unary() - while self.stream.current.type == 'pow': - next(self.stream) - right = self.parse_unary() - left = nodes.Pow(left, right, lineno=lineno) - lineno = self.stream.current.lineno - return left - - def parse_unary(self, with_filter=True): - token_type = self.stream.current.type - lineno = self.stream.current.lineno - if token_type == 'sub': - next(self.stream) - node = nodes.Neg(self.parse_unary(False), lineno=lineno) - elif token_type == 'add': - next(self.stream) - node = nodes.Pos(self.parse_unary(False), lineno=lineno) - else: - node = self.parse_primary() - node = self.parse_postfix(node) - if with_filter: - node = self.parse_filter_expr(node) - return node - - def parse_primary(self): - token = self.stream.current - if token.type == 'name': - if token.value in ('true', 'false', 'True', 'False'): - node = nodes.Const(token.value in ('true', 'True'), - lineno=token.lineno) - elif token.value in ('none', 'None'): - node = nodes.Const(None, lineno=token.lineno) - else: - node = nodes.Name(token.value, 'load', lineno=token.lineno) - next(self.stream) - elif token.type == 'string': - next(self.stream) - buf = [token.value] - lineno = token.lineno - while self.stream.current.type == 'string': - buf.append(self.stream.current.value) - next(self.stream) - node = nodes.Const(''.join(buf), lineno=lineno) - elif token.type in ('integer', 'float'): - next(self.stream) - node = nodes.Const(token.value, lineno=token.lineno) - elif token.type == 'lparen': - next(self.stream) - node = self.parse_tuple(explicit_parentheses=True) - self.stream.expect('rparen') - elif token.type == 'lbracket': - node = self.parse_list() - elif token.type == 'lbrace': - node = self.parse_dict() - else: - self.fail("unexpected '%s'" % describe_token(token), token.lineno) - return node - - def parse_tuple(self, simplified=False, with_condexpr=True, - extra_end_rules=None, explicit_parentheses=False): - """Works like `parse_expression` but if multiple expressions are - delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created. - This method could also return a regular expression instead of a tuple - if no commas where found. - - The default parsing mode is a full tuple. If `simplified` is `True` - only names and literals are parsed. The `no_condexpr` parameter is - forwarded to :meth:`parse_expression`. - - Because tuples do not require delimiters and may end in a bogus comma - an extra hint is needed that marks the end of a tuple. For example - for loops support tuples between `for` and `in`. In that case the - `extra_end_rules` is set to ``['name:in']``. - - `explicit_parentheses` is true if the parsing was triggered by an - expression in parentheses. This is used to figure out if an empty - tuple is a valid expression or not. - """ - lineno = self.stream.current.lineno - if simplified: - parse = self.parse_primary - elif with_condexpr: - parse = self.parse_expression - else: - parse = lambda: self.parse_expression(with_condexpr=False) - args = [] - is_tuple = False - while 1: - if args: - self.stream.expect('comma') - if self.is_tuple_end(extra_end_rules): - break - args.append(parse()) - if self.stream.current.type == 'comma': - is_tuple = True - else: - break - lineno = self.stream.current.lineno - - if not is_tuple: - if args: - return args[0] - - # if we don't have explicit parentheses, an empty tuple is - # not a valid expression. This would mean nothing (literally - # nothing) in the spot of an expression would be an empty - # tuple. - if not explicit_parentheses: - self.fail('Expected an expression, got \'%s\'' % - describe_token(self.stream.current)) - - return nodes.Tuple(args, 'load', lineno=lineno) - - def parse_list(self): - token = self.stream.expect('lbracket') - items = [] - while self.stream.current.type != 'rbracket': - if items: - self.stream.expect('comma') - if self.stream.current.type == 'rbracket': - break - items.append(self.parse_expression()) - self.stream.expect('rbracket') - return nodes.List(items, lineno=token.lineno) - - def parse_dict(self): - token = self.stream.expect('lbrace') - items = [] - while self.stream.current.type != 'rbrace': - if items: - self.stream.expect('comma') - if self.stream.current.type == 'rbrace': - break - key = self.parse_expression() - self.stream.expect('colon') - value = self.parse_expression() - items.append(nodes.Pair(key, value, lineno=key.lineno)) - self.stream.expect('rbrace') - return nodes.Dict(items, lineno=token.lineno) - - def parse_postfix(self, node): - while 1: - token_type = self.stream.current.type - if token_type == 'dot' or token_type == 'lbracket': - node = self.parse_subscript(node) - # calls are valid both after postfix expressions (getattr - # and getitem) as well as filters and tests - elif token_type == 'lparen': - node = self.parse_call(node) - else: - break - return node - - def parse_filter_expr(self, node): - while 1: - token_type = self.stream.current.type - if token_type == 'pipe': - node = self.parse_filter(node) - elif token_type == 'name' and self.stream.current.value == 'is': - node = self.parse_test(node) - # calls are valid both after postfix expressions (getattr - # and getitem) as well as filters and tests - elif token_type == 'lparen': - node = self.parse_call(node) - else: - break - return node - - def parse_subscript(self, node): - token = next(self.stream) - if token.type == 'dot': - attr_token = self.stream.current - next(self.stream) - if attr_token.type == 'name': - return nodes.Getattr(node, attr_token.value, 'load', - lineno=token.lineno) - elif attr_token.type != 'integer': - self.fail('expected name or number', attr_token.lineno) - arg = nodes.Const(attr_token.value, lineno=attr_token.lineno) - return nodes.Getitem(node, arg, 'load', lineno=token.lineno) - if token.type == 'lbracket': - args = [] - while self.stream.current.type != 'rbracket': - if args: - self.stream.expect('comma') - args.append(self.parse_subscribed()) - self.stream.expect('rbracket') - if len(args) == 1: - arg = args[0] - else: - arg = nodes.Tuple(args, 'load', lineno=token.lineno) - return nodes.Getitem(node, arg, 'load', lineno=token.lineno) - self.fail('expected subscript expression', self.lineno) - - def parse_subscribed(self): - lineno = self.stream.current.lineno - - if self.stream.current.type == 'colon': - next(self.stream) - args = [None] - else: - node = self.parse_expression() - if self.stream.current.type != 'colon': - return node - next(self.stream) - args = [node] - - if self.stream.current.type == 'colon': - args.append(None) - elif self.stream.current.type not in ('rbracket', 'comma'): - args.append(self.parse_expression()) - else: - args.append(None) - - if self.stream.current.type == 'colon': - next(self.stream) - if self.stream.current.type not in ('rbracket', 'comma'): - args.append(self.parse_expression()) - else: - args.append(None) - else: - args.append(None) - - return nodes.Slice(lineno=lineno, *args) - - def parse_call(self, node): - token = self.stream.expect('lparen') - args = [] - kwargs = [] - dyn_args = dyn_kwargs = None - require_comma = False - - def ensure(expr): - if not expr: - self.fail('invalid syntax for function call expression', - token.lineno) - - while self.stream.current.type != 'rparen': - if require_comma: - self.stream.expect('comma') - # support for trailing comma - if self.stream.current.type == 'rparen': - break - if self.stream.current.type == 'mul': - ensure(dyn_args is None and dyn_kwargs is None) - next(self.stream) - dyn_args = self.parse_expression() - elif self.stream.current.type == 'pow': - ensure(dyn_kwargs is None) - next(self.stream) - dyn_kwargs = self.parse_expression() - else: - ensure(dyn_args is None and dyn_kwargs is None) - if self.stream.current.type == 'name' and \ - self.stream.look().type == 'assign': - key = self.stream.current.value - self.stream.skip(2) - value = self.parse_expression() - kwargs.append(nodes.Keyword(key, value, - lineno=value.lineno)) - else: - ensure(not kwargs) - args.append(self.parse_expression()) - - require_comma = True - self.stream.expect('rparen') - - if node is None: - return args, kwargs, dyn_args, dyn_kwargs - return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs, - lineno=token.lineno) - - def parse_filter(self, node, start_inline=False): - while self.stream.current.type == 'pipe' or start_inline: - if not start_inline: - next(self.stream) - token = self.stream.expect('name') - name = token.value - while self.stream.current.type == 'dot': - next(self.stream) - name += '.' + self.stream.expect('name').value - if self.stream.current.type == 'lparen': - args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None) - else: - args = [] - kwargs = [] - dyn_args = dyn_kwargs = None - node = nodes.Filter(node, name, args, kwargs, dyn_args, - dyn_kwargs, lineno=token.lineno) - start_inline = False - return node - - def parse_test(self, node): - token = next(self.stream) - if self.stream.current.test('name:not'): - next(self.stream) - negated = True - else: - negated = False - name = self.stream.expect('name').value - while self.stream.current.type == 'dot': - next(self.stream) - name += '.' + self.stream.expect('name').value - dyn_args = dyn_kwargs = None - kwargs = [] - if self.stream.current.type == 'lparen': - args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None) - elif self.stream.current.type in ('name', 'string', 'integer', - 'float', 'lparen', 'lbracket', - 'lbrace') and not \ - self.stream.current.test_any('name:else', 'name:or', - 'name:and'): - if self.stream.current.test('name:is'): - self.fail('You cannot chain multiple tests with is') - args = [self.parse_expression()] - else: - args = [] - node = nodes.Test(node, name, args, kwargs, dyn_args, - dyn_kwargs, lineno=token.lineno) - if negated: - node = nodes.Not(node, lineno=token.lineno) - return node - - def subparse(self, end_tokens=None): - body = [] - data_buffer = [] - add_data = data_buffer.append - - if end_tokens is not None: - self._end_token_stack.append(end_tokens) - - def flush_data(): - if data_buffer: - lineno = data_buffer[0].lineno - body.append(nodes.Output(data_buffer[:], lineno=lineno)) - del data_buffer[:] - - try: - while self.stream: - token = self.stream.current - if token.type == 'data': - if token.value: - add_data(nodes.TemplateData(token.value, - lineno=token.lineno)) - next(self.stream) - elif token.type == 'variable_begin': - next(self.stream) - add_data(self.parse_tuple(with_condexpr=True)) - self.stream.expect('variable_end') - elif token.type == 'block_begin': - flush_data() - next(self.stream) - if end_tokens is not None and \ - self.stream.current.test_any(*end_tokens): - return body - rv = self.parse_statement() - if isinstance(rv, list): - body.extend(rv) - else: - body.append(rv) - self.stream.expect('block_end') - else: - raise AssertionError('internal parsing error') - - flush_data() - finally: - if end_tokens is not None: - self._end_token_stack.pop() - - return body - - def parse(self): - """Parse the whole template into a `Template` node.""" - result = nodes.Template(self.subparse(), lineno=1) - result.set_environment(self.environment) - return result diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/runtime.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/runtime.py deleted file mode 100644 index 7791c645..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/runtime.py +++ /dev/null @@ -1,581 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.runtime - ~~~~~~~~~~~~~~ - - Runtime helpers. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD. -""" -from itertools import chain -from jinja2.nodes import EvalContext, _context_function_types -from jinja2.utils import Markup, soft_unicode, escape, missing, concat, \ - internalcode, object_type_repr -from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \ - TemplateNotFound -from jinja2._compat import next, imap, text_type, iteritems, \ - implements_iterator, implements_to_string, string_types, PY2 - - -# these variables are exported to the template runtime -__all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup', - 'TemplateRuntimeError', 'missing', 'concat', 'escape', - 'markup_join', 'unicode_join', 'to_string', 'identity', - 'TemplateNotFound'] - -#: the name of the function that is used to convert something into -#: a string. We can just use the text type here. -to_string = text_type - -#: the identity function. Useful for certain things in the environment -identity = lambda x: x - -_last_iteration = object() - - -def markup_join(seq): - """Concatenation that escapes if necessary and converts to unicode.""" - buf = [] - iterator = imap(soft_unicode, seq) - for arg in iterator: - buf.append(arg) - if hasattr(arg, '__html__'): - return Markup(u'').join(chain(buf, iterator)) - return concat(buf) - - -def unicode_join(seq): - """Simple args to unicode conversion and concatenation.""" - return concat(imap(text_type, seq)) - - -def new_context(environment, template_name, blocks, vars=None, - shared=None, globals=None, locals=None): - """Internal helper to for context creation.""" - if vars is None: - vars = {} - if shared: - parent = vars - else: - parent = dict(globals or (), **vars) - if locals: - # if the parent is shared a copy should be created because - # we don't want to modify the dict passed - if shared: - parent = dict(parent) - for key, value in iteritems(locals): - if key[:2] == 'l_' and value is not missing: - parent[key[2:]] = value - return Context(environment, parent, template_name, blocks) - - -class TemplateReference(object): - """The `self` in templates.""" - - def __init__(self, context): - self.__context = context - - def __getitem__(self, name): - blocks = self.__context.blocks[name] - return BlockReference(name, self.__context, blocks, 0) - - def __repr__(self): - return '<%s %r>' % ( - self.__class__.__name__, - self.__context.name - ) - - -class Context(object): - """The template context holds the variables of a template. It stores the - values passed to the template and also the names the template exports. - Creating instances is neither supported nor useful as it's created - automatically at various stages of the template evaluation and should not - be created by hand. - - The context is immutable. Modifications on :attr:`parent` **must not** - happen and modifications on :attr:`vars` are allowed from generated - template code only. Template filters and global functions marked as - :func:`contextfunction`\s get the active context passed as first argument - and are allowed to access the context read-only. - - The template context supports read only dict operations (`get`, - `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`, - `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve` - method that doesn't fail with a `KeyError` but returns an - :class:`Undefined` object for missing variables. - """ - __slots__ = ('parent', 'vars', 'environment', 'eval_ctx', 'exported_vars', - 'name', 'blocks', '__weakref__') - - def __init__(self, environment, parent, name, blocks): - self.parent = parent - self.vars = {} - self.environment = environment - self.eval_ctx = EvalContext(self.environment, name) - self.exported_vars = set() - self.name = name - - # create the initial mapping of blocks. Whenever template inheritance - # takes place the runtime will update this mapping with the new blocks - # from the template. - self.blocks = dict((k, [v]) for k, v in iteritems(blocks)) - - def super(self, name, current): - """Render a parent block.""" - try: - blocks = self.blocks[name] - index = blocks.index(current) + 1 - blocks[index] - except LookupError: - return self.environment.undefined('there is no parent block ' - 'called %r.' % name, - name='super') - return BlockReference(name, self, blocks, index) - - def get(self, key, default=None): - """Returns an item from the template context, if it doesn't exist - `default` is returned. - """ - try: - return self[key] - except KeyError: - return default - - def resolve(self, key): - """Looks up a variable like `__getitem__` or `get` but returns an - :class:`Undefined` object with the name of the name looked up. - """ - if key in self.vars: - return self.vars[key] - if key in self.parent: - return self.parent[key] - return self.environment.undefined(name=key) - - def get_exported(self): - """Get a new dict with the exported variables.""" - return dict((k, self.vars[k]) for k in self.exported_vars) - - def get_all(self): - """Return a copy of the complete context as dict including the - exported variables. - """ - return dict(self.parent, **self.vars) - - @internalcode - def call(__self, __obj, *args, **kwargs): - """Call the callable with the arguments and keyword arguments - provided but inject the active context or environment as first - argument if the callable is a :func:`contextfunction` or - :func:`environmentfunction`. - """ - if __debug__: - __traceback_hide__ = True - - # Allow callable classes to take a context - fn = __obj.__call__ - for fn_type in ('contextfunction', - 'evalcontextfunction', - 'environmentfunction'): - if hasattr(fn, fn_type): - __obj = fn - break - - if isinstance(__obj, _context_function_types): - if getattr(__obj, 'contextfunction', 0): - args = (__self,) + args - elif getattr(__obj, 'evalcontextfunction', 0): - args = (__self.eval_ctx,) + args - elif getattr(__obj, 'environmentfunction', 0): - args = (__self.environment,) + args - try: - return __obj(*args, **kwargs) - except StopIteration: - return __self.environment.undefined('value was undefined because ' - 'a callable raised a ' - 'StopIteration exception') - - def derived(self, locals=None): - """Internal helper function to create a derived context.""" - context = new_context(self.environment, self.name, {}, - self.parent, True, None, locals) - context.vars.update(self.vars) - context.eval_ctx = self.eval_ctx - context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks)) - return context - - def _all(meth): - proxy = lambda self: getattr(self.get_all(), meth)() - proxy.__doc__ = getattr(dict, meth).__doc__ - proxy.__name__ = meth - return proxy - - keys = _all('keys') - values = _all('values') - items = _all('items') - - # not available on python 3 - if PY2: - iterkeys = _all('iterkeys') - itervalues = _all('itervalues') - iteritems = _all('iteritems') - del _all - - def __contains__(self, name): - return name in self.vars or name in self.parent - - def __getitem__(self, key): - """Lookup a variable or raise `KeyError` if the variable is - undefined. - """ - item = self.resolve(key) - if isinstance(item, Undefined): - raise KeyError(key) - return item - - def __repr__(self): - return '<%s %s of %r>' % ( - self.__class__.__name__, - repr(self.get_all()), - self.name - ) - - -# register the context as mapping if possible -try: - from collections import Mapping - Mapping.register(Context) -except ImportError: - pass - - -class BlockReference(object): - """One block on a template reference.""" - - def __init__(self, name, context, stack, depth): - self.name = name - self._context = context - self._stack = stack - self._depth = depth - - @property - def super(self): - """Super the block.""" - if self._depth + 1 >= len(self._stack): - return self._context.environment. \ - undefined('there is no parent block called %r.' % - self.name, name='super') - return BlockReference(self.name, self._context, self._stack, - self._depth + 1) - - @internalcode - def __call__(self): - rv = concat(self._stack[self._depth](self._context)) - if self._context.eval_ctx.autoescape: - rv = Markup(rv) - return rv - - -class LoopContext(object): - """A loop context for dynamic iteration.""" - - def __init__(self, iterable, recurse=None, depth0=0): - self._iterator = iter(iterable) - self._recurse = recurse - self._after = self._safe_next() - self.index0 = -1 - self.depth0 = depth0 - - # try to get the length of the iterable early. This must be done - # here because there are some broken iterators around where there - # __len__ is the number of iterations left (i'm looking at your - # listreverseiterator!). - try: - self._length = len(iterable) - except (TypeError, AttributeError): - self._length = None - - def cycle(self, *args): - """Cycles among the arguments with the current loop index.""" - if not args: - raise TypeError('no items for cycling given') - return args[self.index0 % len(args)] - - first = property(lambda x: x.index0 == 0) - last = property(lambda x: x._after is _last_iteration) - index = property(lambda x: x.index0 + 1) - revindex = property(lambda x: x.length - x.index0) - revindex0 = property(lambda x: x.length - x.index) - depth = property(lambda x: x.depth0 + 1) - - def __len__(self): - return self.length - - def __iter__(self): - return LoopContextIterator(self) - - def _safe_next(self): - try: - return next(self._iterator) - except StopIteration: - return _last_iteration - - @internalcode - def loop(self, iterable): - if self._recurse is None: - raise TypeError('Tried to call non recursive loop. Maybe you ' - "forgot the 'recursive' modifier.") - return self._recurse(iterable, self._recurse, self.depth0 + 1) - - # a nifty trick to enhance the error message if someone tried to call - # the the loop without or with too many arguments. - __call__ = loop - del loop - - @property - def length(self): - if self._length is None: - # if was not possible to get the length of the iterator when - # the loop context was created (ie: iterating over a generator) - # we have to convert the iterable into a sequence and use the - # length of that. - iterable = tuple(self._iterator) - self._iterator = iter(iterable) - self._length = len(iterable) + self.index0 + 1 - return self._length - - def __repr__(self): - return '<%s %r/%r>' % ( - self.__class__.__name__, - self.index, - self.length - ) - - -@implements_iterator -class LoopContextIterator(object): - """The iterator for a loop context.""" - __slots__ = ('context',) - - def __init__(self, context): - self.context = context - - def __iter__(self): - return self - - def __next__(self): - ctx = self.context - ctx.index0 += 1 - if ctx._after is _last_iteration: - raise StopIteration() - next_elem = ctx._after - ctx._after = ctx._safe_next() - return next_elem, ctx - - -class Macro(object): - """Wraps a macro function.""" - - def __init__(self, environment, func, name, arguments, defaults, - catch_kwargs, catch_varargs, caller): - self._environment = environment - self._func = func - self._argument_count = len(arguments) - self.name = name - self.arguments = arguments - self.defaults = defaults - self.catch_kwargs = catch_kwargs - self.catch_varargs = catch_varargs - self.caller = caller - - @internalcode - def __call__(self, *args, **kwargs): - # try to consume the positional arguments - arguments = list(args[:self._argument_count]) - off = len(arguments) - - # if the number of arguments consumed is not the number of - # arguments expected we start filling in keyword arguments - # and defaults. - if off != self._argument_count: - for idx, name in enumerate(self.arguments[len(arguments):]): - try: - value = kwargs.pop(name) - except KeyError: - try: - value = self.defaults[idx - self._argument_count + off] - except IndexError: - value = self._environment.undefined( - 'parameter %r was not provided' % name, name=name) - arguments.append(value) - - # it's important that the order of these arguments does not change - # if not also changed in the compiler's `function_scoping` method. - # the order is caller, keyword arguments, positional arguments! - if self.caller: - caller = kwargs.pop('caller', None) - if caller is None: - caller = self._environment.undefined('No caller defined', - name='caller') - arguments.append(caller) - if self.catch_kwargs: - arguments.append(kwargs) - elif kwargs: - raise TypeError('macro %r takes no keyword argument %r' % - (self.name, next(iter(kwargs)))) - if self.catch_varargs: - arguments.append(args[self._argument_count:]) - elif len(args) > self._argument_count: - raise TypeError('macro %r takes not more than %d argument(s)' % - (self.name, len(self.arguments))) - return self._func(*arguments) - - def __repr__(self): - return '<%s %s>' % ( - self.__class__.__name__, - self.name is None and 'anonymous' or repr(self.name) - ) - - -@implements_to_string -class Undefined(object): - """The default undefined type. This undefined type can be printed and - iterated over, but every other access will raise an :exc:`UndefinedError`: - - >>> foo = Undefined(name='foo') - >>> str(foo) - '' - >>> not foo - True - >>> foo + 42 - Traceback (most recent call last): - ... - UndefinedError: 'foo' is undefined - """ - __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name', - '_undefined_exception') - - def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError): - self._undefined_hint = hint - self._undefined_obj = obj - self._undefined_name = name - self._undefined_exception = exc - - @internalcode - def _fail_with_undefined_error(self, *args, **kwargs): - """Regular callback function for undefined objects that raises an - `UndefinedError` on call. - """ - if self._undefined_hint is None: - if self._undefined_obj is missing: - hint = '%r is undefined' % self._undefined_name - elif not isinstance(self._undefined_name, string_types): - hint = '%s has no element %r' % ( - object_type_repr(self._undefined_obj), - self._undefined_name - ) - else: - hint = '%r has no attribute %r' % ( - object_type_repr(self._undefined_obj), - self._undefined_name - ) - else: - hint = self._undefined_hint - raise self._undefined_exception(hint) - - @internalcode - def __getattr__(self, name): - if name[:2] == '__': - raise AttributeError(name) - return self._fail_with_undefined_error() - - __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \ - __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \ - __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \ - __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = __int__ = \ - __float__ = __complex__ = __pow__ = __rpow__ = \ - _fail_with_undefined_error - - def __eq__(self, other): - return type(self) is type(other) - - def __ne__(self, other): - return not self.__eq__(other) - - def __hash__(self): - return id(type(self)) - - def __str__(self): - return u'' - - def __len__(self): - return 0 - - def __iter__(self): - if 0: - yield None - - def __nonzero__(self): - return False - - def __repr__(self): - return 'Undefined' - - -@implements_to_string -class DebugUndefined(Undefined): - """An undefined that returns the debug info when printed. - - >>> foo = DebugUndefined(name='foo') - >>> str(foo) - '{{ foo }}' - >>> not foo - True - >>> foo + 42 - Traceback (most recent call last): - ... - UndefinedError: 'foo' is undefined - """ - __slots__ = () - - def __str__(self): - if self._undefined_hint is None: - if self._undefined_obj is missing: - return u'{{ %s }}' % self._undefined_name - return '{{ no such element: %s[%r] }}' % ( - object_type_repr(self._undefined_obj), - self._undefined_name - ) - return u'{{ undefined value printed: %s }}' % self._undefined_hint - - -@implements_to_string -class StrictUndefined(Undefined): - """An undefined that barks on print and iteration as well as boolean - tests and all kinds of comparisons. In other words: you can do nothing - with it except checking if it's defined using the `defined` test. - - >>> foo = StrictUndefined(name='foo') - >>> str(foo) - Traceback (most recent call last): - ... - UndefinedError: 'foo' is undefined - >>> not foo - Traceback (most recent call last): - ... - UndefinedError: 'foo' is undefined - >>> foo + 42 - Traceback (most recent call last): - ... - UndefinedError: 'foo' is undefined - """ - __slots__ = () - __iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \ - __ne__ = __bool__ = __hash__ = \ - Undefined._fail_with_undefined_error - - -# remove remaining slots attributes, after the metaclass did the magic they -# are unneeded and irritating as they contain wrong data for the subclasses. -del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__ diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/sandbox.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/sandbox.py deleted file mode 100644 index da479c1b..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/sandbox.py +++ /dev/null @@ -1,368 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.sandbox - ~~~~~~~~~~~~~~ - - Adds a sandbox layer to Jinja as it was the default behavior in the old - Jinja 1 releases. This sandbox is slightly different from Jinja 1 as the - default behavior is easier to use. - - The behavior can be changed by subclassing the environment. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD. -""" -import operator -from jinja2.environment import Environment -from jinja2.exceptions import SecurityError -from jinja2._compat import string_types, function_type, method_type, \ - traceback_type, code_type, frame_type, generator_type, PY2 - - -#: maximum number of items a range may produce -MAX_RANGE = 100000 - -#: attributes of function objects that are considered unsafe. -UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict', - 'func_defaults', 'func_globals']) - -#: unsafe method attributes. function attributes are unsafe for methods too -UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self']) - -#: unsafe generator attirbutes. -UNSAFE_GENERATOR_ATTRIBUTES = set(['gi_frame', 'gi_code']) - -# On versions > python 2 the special attributes on functions are gone, -# but they remain on methods and generators for whatever reason. -if not PY2: - UNSAFE_FUNCTION_ATTRIBUTES = set() - -import warnings - -# make sure we don't warn in python 2.6 about stuff we don't care about -warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning, - module='jinja2.sandbox') - -from collections import deque - -_mutable_set_types = (set,) -_mutable_mapping_types = (dict,) -_mutable_sequence_types = (list,) - - -# on python 2.x we can register the user collection types -try: - from UserDict import UserDict, DictMixin - from UserList import UserList - _mutable_mapping_types += (UserDict, DictMixin) - _mutable_set_types += (UserList,) -except ImportError: - pass - -# if sets is still available, register the mutable set from there as well -try: - from sets import Set - _mutable_set_types += (Set,) -except ImportError: - pass - -#: register Python 2.6 abstract base classes -try: - from collections import MutableSet, MutableMapping, MutableSequence - _mutable_set_types += (MutableSet,) - _mutable_mapping_types += (MutableMapping,) - _mutable_sequence_types += (MutableSequence,) -except ImportError: - pass - -_mutable_spec = ( - (_mutable_set_types, frozenset([ - 'add', 'clear', 'difference_update', 'discard', 'pop', 'remove', - 'symmetric_difference_update', 'update' - ])), - (_mutable_mapping_types, frozenset([ - 'clear', 'pop', 'popitem', 'setdefault', 'update' - ])), - (_mutable_sequence_types, frozenset([ - 'append', 'reverse', 'insert', 'sort', 'extend', 'remove' - ])), - (deque, frozenset([ - 'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop', - 'popleft', 'remove', 'rotate' - ])) -) - - -def safe_range(*args): - """A range that can't generate ranges with a length of more than - MAX_RANGE items. - """ - rng = range(*args) - if len(rng) > MAX_RANGE: - raise OverflowError('range too big, maximum size for range is %d' % - MAX_RANGE) - return rng - - -def unsafe(f): - """Marks a function or method as unsafe. - - :: - - @unsafe - def delete(self): - pass - """ - f.unsafe_callable = True - return f - - -def is_internal_attribute(obj, attr): - """Test if the attribute given is an internal python attribute. For - example this function returns `True` for the `func_code` attribute of - python objects. This is useful if the environment method - :meth:`~SandboxedEnvironment.is_safe_attribute` is overridden. - - >>> from jinja2.sandbox import is_internal_attribute - >>> is_internal_attribute(lambda: None, "func_code") - True - >>> is_internal_attribute((lambda x:x).func_code, 'co_code') - True - >>> is_internal_attribute(str, "upper") - False - """ - if isinstance(obj, function_type): - if attr in UNSAFE_FUNCTION_ATTRIBUTES: - return True - elif isinstance(obj, method_type): - if attr in UNSAFE_FUNCTION_ATTRIBUTES or \ - attr in UNSAFE_METHOD_ATTRIBUTES: - return True - elif isinstance(obj, type): - if attr == 'mro': - return True - elif isinstance(obj, (code_type, traceback_type, frame_type)): - return True - elif isinstance(obj, generator_type): - if attr in UNSAFE_GENERATOR_ATTRIBUTES: - return True - return attr.startswith('__') - - -def modifies_known_mutable(obj, attr): - """This function checks if an attribute on a builtin mutable object - (list, dict, set or deque) would modify it if called. It also supports - the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and - with Python 2.6 onwards the abstract base classes `MutableSet`, - `MutableMapping`, and `MutableSequence`. - - >>> modifies_known_mutable({}, "clear") - True - >>> modifies_known_mutable({}, "keys") - False - >>> modifies_known_mutable([], "append") - True - >>> modifies_known_mutable([], "index") - False - - If called with an unsupported object (such as unicode) `False` is - returned. - - >>> modifies_known_mutable("foo", "upper") - False - """ - for typespec, unsafe in _mutable_spec: - if isinstance(obj, typespec): - return attr in unsafe - return False - - -class SandboxedEnvironment(Environment): - """The sandboxed environment. It works like the regular environment but - tells the compiler to generate sandboxed code. Additionally subclasses of - this environment may override the methods that tell the runtime what - attributes or functions are safe to access. - - If the template tries to access insecure code a :exc:`SecurityError` is - raised. However also other exceptions may occour during the rendering so - the caller has to ensure that all exceptions are catched. - """ - sandboxed = True - - #: default callback table for the binary operators. A copy of this is - #: available on each instance of a sandboxed environment as - #: :attr:`binop_table` - default_binop_table = { - '+': operator.add, - '-': operator.sub, - '*': operator.mul, - '/': operator.truediv, - '//': operator.floordiv, - '**': operator.pow, - '%': operator.mod - } - - #: default callback table for the unary operators. A copy of this is - #: available on each instance of a sandboxed environment as - #: :attr:`unop_table` - default_unop_table = { - '+': operator.pos, - '-': operator.neg - } - - #: a set of binary operators that should be intercepted. Each operator - #: that is added to this set (empty by default) is delegated to the - #: :meth:`call_binop` method that will perform the operator. The default - #: operator callback is specified by :attr:`binop_table`. - #: - #: The following binary operators are interceptable: - #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**`` - #: - #: The default operation form the operator table corresponds to the - #: builtin function. Intercepted calls are always slower than the native - #: operator call, so make sure only to intercept the ones you are - #: interested in. - #: - #: .. versionadded:: 2.6 - intercepted_binops = frozenset() - - #: a set of unary operators that should be intercepted. Each operator - #: that is added to this set (empty by default) is delegated to the - #: :meth:`call_unop` method that will perform the operator. The default - #: operator callback is specified by :attr:`unop_table`. - #: - #: The following unary operators are interceptable: ``+``, ``-`` - #: - #: The default operation form the operator table corresponds to the - #: builtin function. Intercepted calls are always slower than the native - #: operator call, so make sure only to intercept the ones you are - #: interested in. - #: - #: .. versionadded:: 2.6 - intercepted_unops = frozenset() - - def intercept_unop(self, operator): - """Called during template compilation with the name of a unary - operator to check if it should be intercepted at runtime. If this - method returns `True`, :meth:`call_unop` is excuted for this unary - operator. The default implementation of :meth:`call_unop` will use - the :attr:`unop_table` dictionary to perform the operator with the - same logic as the builtin one. - - The following unary operators are interceptable: ``+`` and ``-`` - - Intercepted calls are always slower than the native operator call, - so make sure only to intercept the ones you are interested in. - - .. versionadded:: 2.6 - """ - return False - - - def __init__(self, *args, **kwargs): - Environment.__init__(self, *args, **kwargs) - self.globals['range'] = safe_range - self.binop_table = self.default_binop_table.copy() - self.unop_table = self.default_unop_table.copy() - - def is_safe_attribute(self, obj, attr, value): - """The sandboxed environment will call this method to check if the - attribute of an object is safe to access. Per default all attributes - starting with an underscore are considered private as well as the - special attributes of internal python objects as returned by the - :func:`is_internal_attribute` function. - """ - return not (attr.startswith('_') or is_internal_attribute(obj, attr)) - - def is_safe_callable(self, obj): - """Check if an object is safely callable. Per default a function is - considered safe unless the `unsafe_callable` attribute exists and is - True. Override this method to alter the behavior, but this won't - affect the `unsafe` decorator from this module. - """ - return not (getattr(obj, 'unsafe_callable', False) or - getattr(obj, 'alters_data', False)) - - def call_binop(self, context, operator, left, right): - """For intercepted binary operator calls (:meth:`intercepted_binops`) - this function is executed instead of the builtin operator. This can - be used to fine tune the behavior of certain operators. - - .. versionadded:: 2.6 - """ - return self.binop_table[operator](left, right) - - def call_unop(self, context, operator, arg): - """For intercepted unary operator calls (:meth:`intercepted_unops`) - this function is executed instead of the builtin operator. This can - be used to fine tune the behavior of certain operators. - - .. versionadded:: 2.6 - """ - return self.unop_table[operator](arg) - - def getitem(self, obj, argument): - """Subscribe an object from sandboxed code.""" - try: - return obj[argument] - except (TypeError, LookupError): - if isinstance(argument, string_types): - try: - attr = str(argument) - except Exception: - pass - else: - try: - value = getattr(obj, attr) - except AttributeError: - pass - else: - if self.is_safe_attribute(obj, argument, value): - return value - return self.unsafe_undefined(obj, argument) - return self.undefined(obj=obj, name=argument) - - def getattr(self, obj, attribute): - """Subscribe an object from sandboxed code and prefer the - attribute. The attribute passed *must* be a bytestring. - """ - try: - value = getattr(obj, attribute) - except AttributeError: - try: - return obj[attribute] - except (TypeError, LookupError): - pass - else: - if self.is_safe_attribute(obj, attribute, value): - return value - return self.unsafe_undefined(obj, attribute) - return self.undefined(obj=obj, name=attribute) - - def unsafe_undefined(self, obj, attribute): - """Return an undefined object for unsafe attributes.""" - return self.undefined('access to attribute %r of %r ' - 'object is unsafe.' % ( - attribute, - obj.__class__.__name__ - ), name=attribute, obj=obj, exc=SecurityError) - - def call(__self, __context, __obj, *args, **kwargs): - """Call an object from sandboxed code.""" - # the double prefixes are to avoid double keyword argument - # errors when proxying the call. - if not __self.is_safe_callable(__obj): - raise SecurityError('%r is not safely callable' % (__obj,)) - return __context.call(__obj, *args, **kwargs) - - -class ImmutableSandboxedEnvironment(SandboxedEnvironment): - """Works exactly like the regular `SandboxedEnvironment` but does not - permit modifications on the builtin mutable objects `list`, `set`, and - `dict` by using the :func:`modifies_known_mutable` function. - """ - - def is_safe_attribute(self, obj, attr, value): - if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value): - return False - return not modifies_known_mutable(obj, attr) diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/tests.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/tests.py deleted file mode 100644 index 48a3e061..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/tests.py +++ /dev/null @@ -1,149 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.tests - ~~~~~~~~~~~~ - - Jinja test functions. Used with the "is" operator. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import re -from jinja2.runtime import Undefined -from jinja2._compat import text_type, string_types, mapping_types - - -number_re = re.compile(r'^-?\d+(\.\d+)?$') -regex_type = type(number_re) - - -test_callable = callable - - -def test_odd(value): - """Return true if the variable is odd.""" - return value % 2 == 1 - - -def test_even(value): - """Return true if the variable is even.""" - return value % 2 == 0 - - -def test_divisibleby(value, num): - """Check if a variable is divisible by a number.""" - return value % num == 0 - - -def test_defined(value): - """Return true if the variable is defined: - - .. sourcecode:: jinja - - {% if variable is defined %} - value of variable: {{ variable }} - {% else %} - variable is not defined - {% endif %} - - See the :func:`default` filter for a simple way to set undefined - variables. - """ - return not isinstance(value, Undefined) - - -def test_undefined(value): - """Like :func:`defined` but the other way round.""" - return isinstance(value, Undefined) - - -def test_none(value): - """Return true if the variable is none.""" - return value is None - - -def test_lower(value): - """Return true if the variable is lowercased.""" - return text_type(value).islower() - - -def test_upper(value): - """Return true if the variable is uppercased.""" - return text_type(value).isupper() - - -def test_string(value): - """Return true if the object is a string.""" - return isinstance(value, string_types) - - -def test_mapping(value): - """Return true if the object is a mapping (dict etc.). - - .. versionadded:: 2.6 - """ - return isinstance(value, mapping_types) - - -def test_number(value): - """Return true if the variable is a number.""" - return isinstance(value, (int, float, complex)) - - -def test_sequence(value): - """Return true if the variable is a sequence. Sequences are variables - that are iterable. - """ - try: - len(value) - value.__getitem__ - except: - return False - return True - - -def test_sameas(value, other): - """Check if an object points to the same memory address than another - object: - - .. sourcecode:: jinja - - {% if foo.attribute is sameas false %} - the foo attribute really is the `False` singleton - {% endif %} - """ - return value is other - - -def test_iterable(value): - """Check if it's possible to iterate over an object.""" - try: - iter(value) - except TypeError: - return False - return True - - -def test_escaped(value): - """Check if the value is escaped.""" - return hasattr(value, '__html__') - - -TESTS = { - 'odd': test_odd, - 'even': test_even, - 'divisibleby': test_divisibleby, - 'defined': test_defined, - 'undefined': test_undefined, - 'none': test_none, - 'lower': test_lower, - 'upper': test_upper, - 'string': test_string, - 'mapping': test_mapping, - 'number': test_number, - 'sequence': test_sequence, - 'iterable': test_iterable, - 'callable': test_callable, - 'sameas': test_sameas, - 'escaped': test_escaped -} diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/__init__.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/__init__.py deleted file mode 100644 index 635c83e5..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/__init__.py +++ /dev/null @@ -1,156 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite - ~~~~~~~~~~~~~~~~ - - All the unittests of Jinja2. These tests can be executed by - either running run-tests.py using multiple Python versions at - the same time. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import os -import re -import sys -import unittest -from traceback import format_exception -from jinja2 import loaders -from jinja2._compat import PY2 - - -here = os.path.dirname(os.path.abspath(__file__)) - -dict_loader = loaders.DictLoader({ - 'justdict.html': 'FOO' -}) -package_loader = loaders.PackageLoader('jinja2.testsuite.res', 'templates') -filesystem_loader = loaders.FileSystemLoader(here + '/res/templates') -function_loader = loaders.FunctionLoader({'justfunction.html': 'FOO'}.get) -choice_loader = loaders.ChoiceLoader([dict_loader, package_loader]) -prefix_loader = loaders.PrefixLoader({ - 'a': filesystem_loader, - 'b': dict_loader -}) - - -class JinjaTestCase(unittest.TestCase): - - ### use only these methods for testing. If you need standard - ### unittest method, wrap them! - - def setup(self): - pass - - def teardown(self): - pass - - def setUp(self): - self.setup() - - def tearDown(self): - self.teardown() - - def assert_equal(self, a, b): - return self.assertEqual(a, b) - - def assert_raises(self, *args, **kwargs): - return self.assertRaises(*args, **kwargs) - - def assert_traceback_matches(self, callback, expected_tb): - try: - callback() - except Exception as e: - tb = format_exception(*sys.exc_info()) - if re.search(expected_tb.strip(), ''.join(tb)) is None: - raise self.fail('Traceback did not match:\n\n%s\nexpected:\n%s' - % (''.join(tb), expected_tb)) - else: - self.fail('Expected exception') - - -def find_all_tests(suite): - """Yields all the tests and their names from a given suite.""" - suites = [suite] - while suites: - s = suites.pop() - try: - suites.extend(s) - except TypeError: - yield s, '%s.%s.%s' % ( - s.__class__.__module__, - s.__class__.__name__, - s._testMethodName - ) - - -class BetterLoader(unittest.TestLoader): - """A nicer loader that solves two problems. First of all we are setting - up tests from different sources and we're doing this programmatically - which breaks the default loading logic so this is required anyways. - Secondly this loader has a nicer interpolation for test names than the - default one so you can just do ``run-tests.py ViewTestCase`` and it - will work. - """ - - def getRootSuite(self): - return suite() - - def loadTestsFromName(self, name, module=None): - root = self.getRootSuite() - if name == 'suite': - return root - - all_tests = [] - for testcase, testname in find_all_tests(root): - if testname == name or \ - testname.endswith('.' + name) or \ - ('.' + name + '.') in testname or \ - testname.startswith(name + '.'): - all_tests.append(testcase) - - if not all_tests: - raise LookupError('could not find test case for "%s"' % name) - - if len(all_tests) == 1: - return all_tests[0] - rv = unittest.TestSuite() - for test in all_tests: - rv.addTest(test) - return rv - - -def suite(): - from jinja2.testsuite import ext, filters, tests, core_tags, \ - loader, inheritance, imports, lexnparse, security, api, \ - regression, debug, utils, bytecode_cache, doctests - suite = unittest.TestSuite() - suite.addTest(ext.suite()) - suite.addTest(filters.suite()) - suite.addTest(tests.suite()) - suite.addTest(core_tags.suite()) - suite.addTest(loader.suite()) - suite.addTest(inheritance.suite()) - suite.addTest(imports.suite()) - suite.addTest(lexnparse.suite()) - suite.addTest(security.suite()) - suite.addTest(api.suite()) - suite.addTest(regression.suite()) - suite.addTest(debug.suite()) - suite.addTest(utils.suite()) - suite.addTest(bytecode_cache.suite()) - - # doctests will not run on python 3 currently. Too many issues - # with that, do not test that on that platform. - if PY2: - suite.addTest(doctests.suite()) - - return suite - - -def main(): - """Runs the testsuite as command line application.""" - try: - unittest.main(testLoader=BetterLoader(), defaultTest='suite') - except Exception as e: - print('Error: %s' % e) diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/api.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/api.py deleted file mode 100644 index 1b68bf8b..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/api.py +++ /dev/null @@ -1,261 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.api - ~~~~~~~~~~~~~~~~~~~~ - - Tests the public API and related stuff. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import unittest -import os -import tempfile -import shutil - -from jinja2.testsuite import JinjaTestCase -from jinja2._compat import next - -from jinja2 import Environment, Undefined, DebugUndefined, \ - StrictUndefined, UndefinedError, meta, \ - is_undefined, Template, DictLoader -from jinja2.utils import Cycler - -env = Environment() - - -class ExtendedAPITestCase(JinjaTestCase): - - def test_item_and_attribute(self): - from jinja2.sandbox import SandboxedEnvironment - - for env in Environment(), SandboxedEnvironment(): - # the |list is necessary for python3 - tmpl = env.from_string('{{ foo.items()|list }}') - assert tmpl.render(foo={'items': 42}) == "[('items', 42)]" - tmpl = env.from_string('{{ foo|attr("items")()|list }}') - assert tmpl.render(foo={'items': 42}) == "[('items', 42)]" - tmpl = env.from_string('{{ foo["items"] }}') - assert tmpl.render(foo={'items': 42}) == '42' - - def test_finalizer(self): - def finalize_none_empty(value): - if value is None: - value = u'' - return value - env = Environment(finalize=finalize_none_empty) - tmpl = env.from_string('{% for item in seq %}|{{ item }}{% endfor %}') - assert tmpl.render(seq=(None, 1, "foo")) == '||1|foo' - tmpl = env.from_string('<{{ none }}>') - assert tmpl.render() == '<>' - - def test_cycler(self): - items = 1, 2, 3 - c = Cycler(*items) - for item in items + items: - assert c.current == item - assert next(c) == item - next(c) - assert c.current == 2 - c.reset() - assert c.current == 1 - - def test_expressions(self): - expr = env.compile_expression("foo") - assert expr() is None - assert expr(foo=42) == 42 - expr2 = env.compile_expression("foo", undefined_to_none=False) - assert is_undefined(expr2()) - - expr = env.compile_expression("42 + foo") - assert expr(foo=42) == 84 - - def test_template_passthrough(self): - t = Template('Content') - assert env.get_template(t) is t - assert env.select_template([t]) is t - assert env.get_or_select_template([t]) is t - assert env.get_or_select_template(t) is t - - def test_autoescape_autoselect(self): - def select_autoescape(name): - if name is None or '.' not in name: - return False - return name.endswith('.html') - env = Environment(autoescape=select_autoescape, - loader=DictLoader({ - 'test.txt': '{{ foo }}', - 'test.html': '{{ foo }}' - })) - t = env.get_template('test.txt') - assert t.render(foo='') == '' - t = env.get_template('test.html') - assert t.render(foo='') == '<foo>' - t = env.from_string('{{ foo }}') - assert t.render(foo='') == '' - - -class MetaTestCase(JinjaTestCase): - - def test_find_undeclared_variables(self): - ast = env.parse('{% set foo = 42 %}{{ bar + foo }}') - x = meta.find_undeclared_variables(ast) - assert x == set(['bar']) - - ast = env.parse('{% set foo = 42 %}{{ bar + foo }}' - '{% macro meh(x) %}{{ x }}{% endmacro %}' - '{% for item in seq %}{{ muh(item) + meh(seq) }}{% endfor %}') - x = meta.find_undeclared_variables(ast) - assert x == set(['bar', 'seq', 'muh']) - - def test_find_refererenced_templates(self): - ast = env.parse('{% extends "layout.html" %}{% include helper %}') - i = meta.find_referenced_templates(ast) - assert next(i) == 'layout.html' - assert next(i) is None - assert list(i) == [] - - ast = env.parse('{% extends "layout.html" %}' - '{% from "test.html" import a, b as c %}' - '{% import "meh.html" as meh %}' - '{% include "muh.html" %}') - i = meta.find_referenced_templates(ast) - assert list(i) == ['layout.html', 'test.html', 'meh.html', 'muh.html'] - - def test_find_included_templates(self): - ast = env.parse('{% include ["foo.html", "bar.html"] %}') - i = meta.find_referenced_templates(ast) - assert list(i) == ['foo.html', 'bar.html'] - - ast = env.parse('{% include ("foo.html", "bar.html") %}') - i = meta.find_referenced_templates(ast) - assert list(i) == ['foo.html', 'bar.html'] - - ast = env.parse('{% include ["foo.html", "bar.html", foo] %}') - i = meta.find_referenced_templates(ast) - assert list(i) == ['foo.html', 'bar.html', None] - - ast = env.parse('{% include ("foo.html", "bar.html", foo) %}') - i = meta.find_referenced_templates(ast) - assert list(i) == ['foo.html', 'bar.html', None] - - -class StreamingTestCase(JinjaTestCase): - - def test_basic_streaming(self): - tmpl = env.from_string("
    {% for item in seq %}
  • {{ loop.index " - "}} - {{ item }}
  • {%- endfor %}
") - stream = tmpl.stream(seq=list(range(4))) - self.assert_equal(next(stream), '
    ') - self.assert_equal(next(stream), '
  • 1 - 0
  • ') - self.assert_equal(next(stream), '
  • 2 - 1
  • ') - self.assert_equal(next(stream), '
  • 3 - 2
  • ') - self.assert_equal(next(stream), '
  • 4 - 3
  • ') - self.assert_equal(next(stream), '
') - - def test_buffered_streaming(self): - tmpl = env.from_string("
    {% for item in seq %}
  • {{ loop.index " - "}} - {{ item }}
  • {%- endfor %}
") - stream = tmpl.stream(seq=list(range(4))) - stream.enable_buffering(size=3) - self.assert_equal(next(stream), u'
  • 1 - 0
  • 2 - 1
  • ') - self.assert_equal(next(stream), u'
  • 3 - 2
  • 4 - 3
') - - def test_streaming_behavior(self): - tmpl = env.from_string("") - stream = tmpl.stream() - assert not stream.buffered - stream.enable_buffering(20) - assert stream.buffered - stream.disable_buffering() - assert not stream.buffered - - def test_dump_stream(self): - tmp = tempfile.mkdtemp() - try: - tmpl = env.from_string(u"\u2713") - stream = tmpl.stream() - stream.dump(os.path.join(tmp, 'dump.txt'), 'utf-8') - with open(os.path.join(tmp, 'dump.txt'), 'rb') as f: - self.assertEqual(f.read(), b'\xe2\x9c\x93') - finally: - shutil.rmtree(tmp) - - -class UndefinedTestCase(JinjaTestCase): - - def test_stopiteration_is_undefined(self): - def test(): - raise StopIteration() - t = Template('A{{ test() }}B') - assert t.render(test=test) == 'AB' - t = Template('A{{ test().missingattribute }}B') - self.assert_raises(UndefinedError, t.render, test=test) - - def test_undefined_and_special_attributes(self): - try: - Undefined('Foo').__dict__ - except AttributeError: - pass - else: - assert False, "Expected actual attribute error" - - def test_default_undefined(self): - env = Environment(undefined=Undefined) - self.assert_equal(env.from_string('{{ missing }}').render(), u'') - self.assert_raises(UndefinedError, - env.from_string('{{ missing.attribute }}').render) - self.assert_equal(env.from_string('{{ missing|list }}').render(), '[]') - self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True') - self.assert_equal(env.from_string('{{ foo.missing }}').render(foo=42), '') - self.assert_equal(env.from_string('{{ not missing }}').render(), 'True') - - def test_debug_undefined(self): - env = Environment(undefined=DebugUndefined) - self.assert_equal(env.from_string('{{ missing }}').render(), '{{ missing }}') - self.assert_raises(UndefinedError, - env.from_string('{{ missing.attribute }}').render) - self.assert_equal(env.from_string('{{ missing|list }}').render(), '[]') - self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True') - self.assert_equal(env.from_string('{{ foo.missing }}').render(foo=42), - u"{{ no such element: int object['missing'] }}") - self.assert_equal(env.from_string('{{ not missing }}').render(), 'True') - - def test_strict_undefined(self): - env = Environment(undefined=StrictUndefined) - self.assert_raises(UndefinedError, env.from_string('{{ missing }}').render) - self.assert_raises(UndefinedError, env.from_string('{{ missing.attribute }}').render) - self.assert_raises(UndefinedError, env.from_string('{{ missing|list }}').render) - self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True') - self.assert_raises(UndefinedError, env.from_string('{{ foo.missing }}').render, foo=42) - self.assert_raises(UndefinedError, env.from_string('{{ not missing }}').render) - self.assert_equal(env.from_string('{{ missing|default("default", true) }}').render(), 'default') - - def test_indexing_gives_undefined(self): - t = Template("{{ var[42].foo }}") - self.assert_raises(UndefinedError, t.render, var=0) - - def test_none_gives_proper_error(self): - try: - Environment().getattr(None, 'split')() - except UndefinedError as e: - assert e.message == "'None' has no attribute 'split'" - else: - assert False, 'expected exception' - - def test_object_repr(self): - try: - Undefined(obj=42, name='upper')() - except UndefinedError as e: - assert e.message == "'int object' has no attribute 'upper'" - else: - assert False, 'expected exception' - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ExtendedAPITestCase)) - suite.addTest(unittest.makeSuite(MetaTestCase)) - suite.addTest(unittest.makeSuite(StreamingTestCase)) - suite.addTest(unittest.makeSuite(UndefinedTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/bytecode_cache.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/bytecode_cache.py deleted file mode 100644 index 9f5c635b..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/bytecode_cache.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.bytecode_cache - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Test bytecode caching - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from jinja2.testsuite import JinjaTestCase, package_loader - -from jinja2 import Environment -from jinja2.bccache import FileSystemBytecodeCache -from jinja2.exceptions import TemplateNotFound - -bytecode_cache = FileSystemBytecodeCache() -env = Environment( - loader=package_loader, - bytecode_cache=bytecode_cache, -) - - -class ByteCodeCacheTestCase(JinjaTestCase): - - def test_simple(self): - tmpl = env.get_template('test.html') - assert tmpl.render().strip() == 'BAR' - self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ByteCodeCacheTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/core_tags.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/core_tags.py deleted file mode 100644 index f1a20fd4..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/core_tags.py +++ /dev/null @@ -1,305 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.core_tags - ~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Test the core tags like for and if. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from jinja2.testsuite import JinjaTestCase - -from jinja2 import Environment, TemplateSyntaxError, UndefinedError, \ - DictLoader - -env = Environment() - - -class ForLoopTestCase(JinjaTestCase): - - def test_simple(self): - tmpl = env.from_string('{% for item in seq %}{{ item }}{% endfor %}') - assert tmpl.render(seq=list(range(10))) == '0123456789' - - def test_else(self): - tmpl = env.from_string('{% for item in seq %}XXX{% else %}...{% endfor %}') - assert tmpl.render() == '...' - - def test_empty_blocks(self): - tmpl = env.from_string('<{% for item in seq %}{% else %}{% endfor %}>') - assert tmpl.render() == '<>' - - def test_context_vars(self): - tmpl = env.from_string('''{% for item in seq -%} - {{ loop.index }}|{{ loop.index0 }}|{{ loop.revindex }}|{{ - loop.revindex0 }}|{{ loop.first }}|{{ loop.last }}|{{ - loop.length }}###{% endfor %}''') - one, two, _ = tmpl.render(seq=[0, 1]).split('###') - (one_index, one_index0, one_revindex, one_revindex0, one_first, - one_last, one_length) = one.split('|') - (two_index, two_index0, two_revindex, two_revindex0, two_first, - two_last, two_length) = two.split('|') - - assert int(one_index) == 1 and int(two_index) == 2 - assert int(one_index0) == 0 and int(two_index0) == 1 - assert int(one_revindex) == 2 and int(two_revindex) == 1 - assert int(one_revindex0) == 1 and int(two_revindex0) == 0 - assert one_first == 'True' and two_first == 'False' - assert one_last == 'False' and two_last == 'True' - assert one_length == two_length == '2' - - def test_cycling(self): - tmpl = env.from_string('''{% for item in seq %}{{ - loop.cycle('<1>', '<2>') }}{% endfor %}{% - for item in seq %}{{ loop.cycle(*through) }}{% endfor %}''') - output = tmpl.render(seq=list(range(4)), through=('<1>', '<2>')) - assert output == '<1><2>' * 4 - - def test_scope(self): - tmpl = env.from_string('{% for item in seq %}{% endfor %}{{ item }}') - output = tmpl.render(seq=list(range(10))) - assert not output - - def test_varlen(self): - def inner(): - for item in range(5): - yield item - tmpl = env.from_string('{% for item in iter %}{{ item }}{% endfor %}') - output = tmpl.render(iter=inner()) - assert output == '01234' - - def test_noniter(self): - tmpl = env.from_string('{% for item in none %}...{% endfor %}') - self.assert_raises(TypeError, tmpl.render) - - def test_recursive(self): - tmpl = env.from_string('''{% for item in seq recursive -%} - [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}] - {%- endfor %}''') - assert tmpl.render(seq=[ - dict(a=1, b=[dict(a=1), dict(a=2)]), - dict(a=2, b=[dict(a=1), dict(a=2)]), - dict(a=3, b=[dict(a='a')]) - ]) == '[1<[1][2]>][2<[1][2]>][3<[a]>]' - - def test_recursive_depth0(self): - tmpl = env.from_string('''{% for item in seq recursive -%} - [{{ loop.depth0 }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}] - {%- endfor %}''') - self.assertEqual(tmpl.render(seq=[ - dict(a=1, b=[dict(a=1), dict(a=2)]), - dict(a=2, b=[dict(a=1), dict(a=2)]), - dict(a=3, b=[dict(a='a')]) - ]), '[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]') - - def test_recursive_depth(self): - tmpl = env.from_string('''{% for item in seq recursive -%} - [{{ loop.depth }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}] - {%- endfor %}''') - self.assertEqual(tmpl.render(seq=[ - dict(a=1, b=[dict(a=1), dict(a=2)]), - dict(a=2, b=[dict(a=1), dict(a=2)]), - dict(a=3, b=[dict(a='a')]) - ]), '[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]') - - def test_looploop(self): - tmpl = env.from_string('''{% for row in table %} - {%- set rowloop = loop -%} - {% for cell in row -%} - [{{ rowloop.index }}|{{ loop.index }}] - {%- endfor %} - {%- endfor %}''') - assert tmpl.render(table=['ab', 'cd']) == '[1|1][1|2][2|1][2|2]' - - def test_reversed_bug(self): - tmpl = env.from_string('{% for i in items %}{{ i }}' - '{% if not loop.last %}' - ',{% endif %}{% endfor %}') - assert tmpl.render(items=reversed([3, 2, 1])) == '1,2,3' - - def test_loop_errors(self): - tmpl = env.from_string('''{% for item in [1] if loop.index - == 0 %}...{% endfor %}''') - self.assert_raises(UndefinedError, tmpl.render) - tmpl = env.from_string('''{% for item in [] %}...{% else - %}{{ loop }}{% endfor %}''') - assert tmpl.render() == '' - - def test_loop_filter(self): - tmpl = env.from_string('{% for item in range(10) if item ' - 'is even %}[{{ item }}]{% endfor %}') - assert tmpl.render() == '[0][2][4][6][8]' - tmpl = env.from_string(''' - {%- for item in range(10) if item is even %}[{{ - loop.index }}:{{ item }}]{% endfor %}''') - assert tmpl.render() == '[1:0][2:2][3:4][4:6][5:8]' - - def test_loop_unassignable(self): - self.assert_raises(TemplateSyntaxError, env.from_string, - '{% for loop in seq %}...{% endfor %}') - - def test_scoped_special_var(self): - t = env.from_string('{% for s in seq %}[{{ loop.first }}{% for c in s %}' - '|{{ loop.first }}{% endfor %}]{% endfor %}') - assert t.render(seq=('ab', 'cd')) == '[True|True|False][False|True|False]' - - def test_scoped_loop_var(self): - t = env.from_string('{% for x in seq %}{{ loop.first }}' - '{% for y in seq %}{% endfor %}{% endfor %}') - assert t.render(seq='ab') == 'TrueFalse' - t = env.from_string('{% for x in seq %}{% for y in seq %}' - '{{ loop.first }}{% endfor %}{% endfor %}') - assert t.render(seq='ab') == 'TrueFalseTrueFalse' - - def test_recursive_empty_loop_iter(self): - t = env.from_string(''' - {%- for item in foo recursive -%}{%- endfor -%} - ''') - assert t.render(dict(foo=[])) == '' - - def test_call_in_loop(self): - t = env.from_string(''' - {%- macro do_something() -%} - [{{ caller() }}] - {%- endmacro %} - - {%- for i in [1, 2, 3] %} - {%- call do_something() -%} - {{ i }} - {%- endcall %} - {%- endfor -%} - ''') - assert t.render() == '[1][2][3]' - - def test_scoping_bug(self): - t = env.from_string(''' - {%- for item in foo %}...{{ item }}...{% endfor %} - {%- macro item(a) %}...{{ a }}...{% endmacro %} - {{- item(2) -}} - ''') - assert t.render(foo=(1,)) == '...1......2...' - - def test_unpacking(self): - tmpl = env.from_string('{% for a, b, c in [[1, 2, 3]] %}' - '{{ a }}|{{ b }}|{{ c }}{% endfor %}') - assert tmpl.render() == '1|2|3' - - -class IfConditionTestCase(JinjaTestCase): - - def test_simple(self): - tmpl = env.from_string('''{% if true %}...{% endif %}''') - assert tmpl.render() == '...' - - def test_elif(self): - tmpl = env.from_string('''{% if false %}XXX{% elif true - %}...{% else %}XXX{% endif %}''') - assert tmpl.render() == '...' - - def test_else(self): - tmpl = env.from_string('{% if false %}XXX{% else %}...{% endif %}') - assert tmpl.render() == '...' - - def test_empty(self): - tmpl = env.from_string('[{% if true %}{% else %}{% endif %}]') - assert tmpl.render() == '[]' - - def test_complete(self): - tmpl = env.from_string('{% if a %}A{% elif b %}B{% elif c == d %}' - 'C{% else %}D{% endif %}') - assert tmpl.render(a=0, b=False, c=42, d=42.0) == 'C' - - def test_no_scope(self): - tmpl = env.from_string('{% if a %}{% set foo = 1 %}{% endif %}{{ foo }}') - assert tmpl.render(a=True) == '1' - tmpl = env.from_string('{% if true %}{% set foo = 1 %}{% endif %}{{ foo }}') - assert tmpl.render() == '1' - - -class MacrosTestCase(JinjaTestCase): - env = Environment(trim_blocks=True) - - def test_simple(self): - tmpl = self.env.from_string('''\ -{% macro say_hello(name) %}Hello {{ name }}!{% endmacro %} -{{ say_hello('Peter') }}''') - assert tmpl.render() == 'Hello Peter!' - - def test_scoping(self): - tmpl = self.env.from_string('''\ -{% macro level1(data1) %} -{% macro level2(data2) %}{{ data1 }}|{{ data2 }}{% endmacro %} -{{ level2('bar') }}{% endmacro %} -{{ level1('foo') }}''') - assert tmpl.render() == 'foo|bar' - - def test_arguments(self): - tmpl = self.env.from_string('''\ -{% macro m(a, b, c='c', d='d') %}{{ a }}|{{ b }}|{{ c }}|{{ d }}{% endmacro %} -{{ m() }}|{{ m('a') }}|{{ m('a', 'b') }}|{{ m(1, 2, 3) }}''') - assert tmpl.render() == '||c|d|a||c|d|a|b|c|d|1|2|3|d' - - def test_varargs(self): - tmpl = self.env.from_string('''\ -{% macro test() %}{{ varargs|join('|') }}{% endmacro %}\ -{{ test(1, 2, 3) }}''') - assert tmpl.render() == '1|2|3' - - def test_simple_call(self): - tmpl = self.env.from_string('''\ -{% macro test() %}[[{{ caller() }}]]{% endmacro %}\ -{% call test() %}data{% endcall %}''') - assert tmpl.render() == '[[data]]' - - def test_complex_call(self): - tmpl = self.env.from_string('''\ -{% macro test() %}[[{{ caller('data') }}]]{% endmacro %}\ -{% call(data) test() %}{{ data }}{% endcall %}''') - assert tmpl.render() == '[[data]]' - - def test_caller_undefined(self): - tmpl = self.env.from_string('''\ -{% set caller = 42 %}\ -{% macro test() %}{{ caller is not defined }}{% endmacro %}\ -{{ test() }}''') - assert tmpl.render() == 'True' - - def test_include(self): - self.env = Environment(loader=DictLoader({'include': - '{% macro test(foo) %}[{{ foo }}]{% endmacro %}'})) - tmpl = self.env.from_string('{% from "include" import test %}{{ test("foo") }}') - assert tmpl.render() == '[foo]' - - def test_macro_api(self): - tmpl = self.env.from_string('{% macro foo(a, b) %}{% endmacro %}' - '{% macro bar() %}{{ varargs }}{{ kwargs }}{% endmacro %}' - '{% macro baz() %}{{ caller() }}{% endmacro %}') - assert tmpl.module.foo.arguments == ('a', 'b') - assert tmpl.module.foo.defaults == () - assert tmpl.module.foo.name == 'foo' - assert not tmpl.module.foo.caller - assert not tmpl.module.foo.catch_kwargs - assert not tmpl.module.foo.catch_varargs - assert tmpl.module.bar.arguments == () - assert tmpl.module.bar.defaults == () - assert not tmpl.module.bar.caller - assert tmpl.module.bar.catch_kwargs - assert tmpl.module.bar.catch_varargs - assert tmpl.module.baz.caller - - def test_callself(self): - tmpl = self.env.from_string('{% macro foo(x) %}{{ x }}{% if x > 1 %}|' - '{{ foo(x - 1) }}{% endif %}{% endmacro %}' - '{{ foo(5) }}') - assert tmpl.render() == '5|4|3|2|1' - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ForLoopTestCase)) - suite.addTest(unittest.makeSuite(IfConditionTestCase)) - suite.addTest(unittest.makeSuite(MacrosTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/debug.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/debug.py deleted file mode 100644 index 2588a83e..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/debug.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.debug - ~~~~~~~~~~~~~~~~~~~~~~ - - Tests the debug system. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from jinja2.testsuite import JinjaTestCase, filesystem_loader - -from jinja2 import Environment, TemplateSyntaxError - -env = Environment(loader=filesystem_loader) - - -class DebugTestCase(JinjaTestCase): - - def test_runtime_error(self): - def test(): - tmpl.render(fail=lambda: 1 / 0) - tmpl = env.get_template('broken.html') - self.assert_traceback_matches(test, r''' - File ".*?broken.html", line 2, in (top-level template code|) - \{\{ fail\(\) \}\} - File ".*?debug.pyc?", line \d+, in - tmpl\.render\(fail=lambda: 1 / 0\) -ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero -''') - - def test_syntax_error(self): - # XXX: the .*? is necessary for python3 which does not hide - # some of the stack frames we don't want to show. Not sure - # what's up with that, but that is not that critical. Should - # be fixed though. - self.assert_traceback_matches(lambda: env.get_template('syntaxerror.html'), r'''(?sm) - File ".*?syntaxerror.html", line 4, in (template|) - \{% endif %\}.*? -(jinja2\.exceptions\.)?TemplateSyntaxError: Encountered unknown tag 'endif'. Jinja was looking for the following tags: 'endfor' or 'else'. The innermost block that needs to be closed is 'for'. - ''') - - def test_regular_syntax_error(self): - def test(): - raise TemplateSyntaxError('wtf', 42) - self.assert_traceback_matches(test, r''' - File ".*debug.pyc?", line \d+, in test - raise TemplateSyntaxError\('wtf', 42\) -(jinja2\.exceptions\.)?TemplateSyntaxError: wtf - line 42''') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(DebugTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/doctests.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/doctests.py deleted file mode 100644 index 616d3b6e..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/doctests.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.doctests - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - The doctests. Collects all tests we want to test from - the Jinja modules. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import unittest -import doctest - - -def suite(): - from jinja2 import utils, sandbox, runtime, meta, loaders, \ - ext, environment, bccache, nodes - suite = unittest.TestSuite() - suite.addTest(doctest.DocTestSuite(utils)) - suite.addTest(doctest.DocTestSuite(sandbox)) - suite.addTest(doctest.DocTestSuite(runtime)) - suite.addTest(doctest.DocTestSuite(meta)) - suite.addTest(doctest.DocTestSuite(loaders)) - suite.addTest(doctest.DocTestSuite(ext)) - suite.addTest(doctest.DocTestSuite(environment)) - suite.addTest(doctest.DocTestSuite(bccache)) - suite.addTest(doctest.DocTestSuite(nodes)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/ext.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/ext.py deleted file mode 100644 index 0f93be94..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/ext.py +++ /dev/null @@ -1,459 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.ext - ~~~~~~~~~~~~~~~~~~~~ - - Tests for the extensions. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import re -import unittest - -from jinja2.testsuite import JinjaTestCase - -from jinja2 import Environment, DictLoader, contextfunction, nodes -from jinja2.exceptions import TemplateAssertionError -from jinja2.ext import Extension -from jinja2.lexer import Token, count_newlines -from jinja2._compat import next, BytesIO, itervalues, text_type - -importable_object = 23 - -_gettext_re = re.compile(r'_\((.*?)\)(?s)') - - -i18n_templates = { - 'master.html': '{{ page_title|default(_("missing")) }}' - '{% block body %}{% endblock %}', - 'child.html': '{% extends "master.html" %}{% block body %}' - '{% trans %}watch out{% endtrans %}{% endblock %}', - 'plural.html': '{% trans user_count %}One user online{% pluralize %}' - '{{ user_count }} users online{% endtrans %}', - 'plural2.html': '{% trans user_count=get_user_count() %}{{ user_count }}s' - '{% pluralize %}{{ user_count }}p{% endtrans %}', - 'stringformat.html': '{{ _("User: %(num)s")|format(num=user_count) }}' -} - -newstyle_i18n_templates = { - 'master.html': '{{ page_title|default(_("missing")) }}' - '{% block body %}{% endblock %}', - 'child.html': '{% extends "master.html" %}{% block body %}' - '{% trans %}watch out{% endtrans %}{% endblock %}', - 'plural.html': '{% trans user_count %}One user online{% pluralize %}' - '{{ user_count }} users online{% endtrans %}', - 'stringformat.html': '{{ _("User: %(num)s", num=user_count) }}', - 'ngettext.html': '{{ ngettext("%(num)s apple", "%(num)s apples", apples) }}', - 'ngettext_long.html': '{% trans num=apples %}{{ num }} apple{% pluralize %}' - '{{ num }} apples{% endtrans %}', - 'transvars1.html': '{% trans %}User: {{ num }}{% endtrans %}', - 'transvars2.html': '{% trans num=count %}User: {{ num }}{% endtrans %}', - 'transvars3.html': '{% trans count=num %}User: {{ count }}{% endtrans %}', - 'novars.html': '{% trans %}%(hello)s{% endtrans %}', - 'vars.html': '{% trans %}{{ foo }}%(foo)s{% endtrans %}', - 'explicitvars.html': '{% trans foo="42" %}%(foo)s{% endtrans %}' -} - - -languages = { - 'de': { - 'missing': u'fehlend', - 'watch out': u'pass auf', - 'One user online': u'Ein Benutzer online', - '%(user_count)s users online': u'%(user_count)s Benutzer online', - 'User: %(num)s': u'Benutzer: %(num)s', - 'User: %(count)s': u'Benutzer: %(count)s', - '%(num)s apple': u'%(num)s Apfel', - '%(num)s apples': u'%(num)s Äpfel' - } -} - - -@contextfunction -def gettext(context, string): - language = context.get('LANGUAGE', 'en') - return languages.get(language, {}).get(string, string) - - -@contextfunction -def ngettext(context, s, p, n): - language = context.get('LANGUAGE', 'en') - if n != 1: - return languages.get(language, {}).get(p, p) - return languages.get(language, {}).get(s, s) - - -i18n_env = Environment( - loader=DictLoader(i18n_templates), - extensions=['jinja2.ext.i18n'] -) -i18n_env.globals.update({ - '_': gettext, - 'gettext': gettext, - 'ngettext': ngettext -}) - -newstyle_i18n_env = Environment( - loader=DictLoader(newstyle_i18n_templates), - extensions=['jinja2.ext.i18n'] -) -newstyle_i18n_env.install_gettext_callables(gettext, ngettext, newstyle=True) - -class TestExtension(Extension): - tags = set(['test']) - ext_attr = 42 - - def parse(self, parser): - return nodes.Output([self.call_method('_dump', [ - nodes.EnvironmentAttribute('sandboxed'), - self.attr('ext_attr'), - nodes.ImportedName(__name__ + '.importable_object'), - nodes.ContextReference() - ])]).set_lineno(next(parser.stream).lineno) - - def _dump(self, sandboxed, ext_attr, imported_object, context): - return '%s|%s|%s|%s' % ( - sandboxed, - ext_attr, - imported_object, - context.blocks - ) - - -class PreprocessorExtension(Extension): - - def preprocess(self, source, name, filename=None): - return source.replace('[[TEST]]', '({{ foo }})') - - -class StreamFilterExtension(Extension): - - def filter_stream(self, stream): - for token in stream: - if token.type == 'data': - for t in self.interpolate(token): - yield t - else: - yield token - - def interpolate(self, token): - pos = 0 - end = len(token.value) - lineno = token.lineno - while 1: - match = _gettext_re.search(token.value, pos) - if match is None: - break - value = token.value[pos:match.start()] - if value: - yield Token(lineno, 'data', value) - lineno += count_newlines(token.value) - yield Token(lineno, 'variable_begin', None) - yield Token(lineno, 'name', 'gettext') - yield Token(lineno, 'lparen', None) - yield Token(lineno, 'string', match.group(1)) - yield Token(lineno, 'rparen', None) - yield Token(lineno, 'variable_end', None) - pos = match.end() - if pos < end: - yield Token(lineno, 'data', token.value[pos:]) - - -class ExtensionsTestCase(JinjaTestCase): - - def test_extend_late(self): - env = Environment() - env.add_extension('jinja2.ext.autoescape') - t = env.from_string('{% autoescape true %}{{ "" }}{% endautoescape %}') - assert t.render() == '<test>' - - def test_loop_controls(self): - env = Environment(extensions=['jinja2.ext.loopcontrols']) - - tmpl = env.from_string(''' - {%- for item in [1, 2, 3, 4] %} - {%- if item % 2 == 0 %}{% continue %}{% endif -%} - {{ item }} - {%- endfor %}''') - assert tmpl.render() == '13' - - tmpl = env.from_string(''' - {%- for item in [1, 2, 3, 4] %} - {%- if item > 2 %}{% break %}{% endif -%} - {{ item }} - {%- endfor %}''') - assert tmpl.render() == '12' - - def test_do(self): - env = Environment(extensions=['jinja2.ext.do']) - tmpl = env.from_string(''' - {%- set items = [] %} - {%- for char in "foo" %} - {%- do items.append(loop.index0 ~ char) %} - {%- endfor %}{{ items|join(', ') }}''') - assert tmpl.render() == '0f, 1o, 2o' - - def test_with(self): - env = Environment(extensions=['jinja2.ext.with_']) - tmpl = env.from_string('''\ - {% with a=42, b=23 -%} - {{ a }} = {{ b }} - {% endwith -%} - {{ a }} = {{ b }}\ - ''') - assert [x.strip() for x in tmpl.render(a=1, b=2).splitlines()] \ - == ['42 = 23', '1 = 2'] - - def test_extension_nodes(self): - env = Environment(extensions=[TestExtension]) - tmpl = env.from_string('{% test %}') - assert tmpl.render() == 'False|42|23|{}' - - def test_identifier(self): - assert TestExtension.identifier == __name__ + '.TestExtension' - - def test_rebinding(self): - original = Environment(extensions=[TestExtension]) - overlay = original.overlay() - for env in original, overlay: - for ext in itervalues(env.extensions): - assert ext.environment is env - - def test_preprocessor_extension(self): - env = Environment(extensions=[PreprocessorExtension]) - tmpl = env.from_string('{[[TEST]]}') - assert tmpl.render(foo=42) == '{(42)}' - - def test_streamfilter_extension(self): - env = Environment(extensions=[StreamFilterExtension]) - env.globals['gettext'] = lambda x: x.upper() - tmpl = env.from_string('Foo _(bar) Baz') - out = tmpl.render() - assert out == 'Foo BAR Baz' - - def test_extension_ordering(self): - class T1(Extension): - priority = 1 - class T2(Extension): - priority = 2 - env = Environment(extensions=[T1, T2]) - ext = list(env.iter_extensions()) - assert ext[0].__class__ is T1 - assert ext[1].__class__ is T2 - - -class InternationalizationTestCase(JinjaTestCase): - - def test_trans(self): - tmpl = i18n_env.get_template('child.html') - assert tmpl.render(LANGUAGE='de') == 'fehlendpass auf' - - def test_trans_plural(self): - tmpl = i18n_env.get_template('plural.html') - assert tmpl.render(LANGUAGE='de', user_count=1) == 'Ein Benutzer online' - assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online' - - def test_trans_plural_with_functions(self): - tmpl = i18n_env.get_template('plural2.html') - def get_user_count(): - get_user_count.called += 1 - return 1 - get_user_count.called = 0 - assert tmpl.render(LANGUAGE='de', get_user_count=get_user_count) == '1s' - assert get_user_count.called == 1 - - def test_complex_plural(self): - tmpl = i18n_env.from_string('{% trans foo=42, count=2 %}{{ count }} item{% ' - 'pluralize count %}{{ count }} items{% endtrans %}') - assert tmpl.render() == '2 items' - self.assert_raises(TemplateAssertionError, i18n_env.from_string, - '{% trans foo %}...{% pluralize bar %}...{% endtrans %}') - - def test_trans_stringformatting(self): - tmpl = i18n_env.get_template('stringformat.html') - assert tmpl.render(LANGUAGE='de', user_count=5) == 'Benutzer: 5' - - def test_extract(self): - from jinja2.ext import babel_extract - source = BytesIO(''' - {{ gettext('Hello World') }} - {% trans %}Hello World{% endtrans %} - {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %} - '''.encode('ascii')) # make python 3 happy - assert list(babel_extract(source, ('gettext', 'ngettext', '_'), [], {})) == [ - (2, 'gettext', u'Hello World', []), - (3, 'gettext', u'Hello World', []), - (4, 'ngettext', (u'%(users)s user', u'%(users)s users', None), []) - ] - - def test_comment_extract(self): - from jinja2.ext import babel_extract - source = BytesIO(''' - {# trans first #} - {{ gettext('Hello World') }} - {% trans %}Hello World{% endtrans %}{# trans second #} - {#: third #} - {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %} - '''.encode('utf-8')) # make python 3 happy - assert list(babel_extract(source, ('gettext', 'ngettext', '_'), ['trans', ':'], {})) == [ - (3, 'gettext', u'Hello World', ['first']), - (4, 'gettext', u'Hello World', ['second']), - (6, 'ngettext', (u'%(users)s user', u'%(users)s users', None), ['third']) - ] - - -class NewstyleInternationalizationTestCase(JinjaTestCase): - - def test_trans(self): - tmpl = newstyle_i18n_env.get_template('child.html') - assert tmpl.render(LANGUAGE='de') == 'fehlendpass auf' - - def test_trans_plural(self): - tmpl = newstyle_i18n_env.get_template('plural.html') - assert tmpl.render(LANGUAGE='de', user_count=1) == 'Ein Benutzer online' - assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online' - - def test_complex_plural(self): - tmpl = newstyle_i18n_env.from_string('{% trans foo=42, count=2 %}{{ count }} item{% ' - 'pluralize count %}{{ count }} items{% endtrans %}') - assert tmpl.render() == '2 items' - self.assert_raises(TemplateAssertionError, i18n_env.from_string, - '{% trans foo %}...{% pluralize bar %}...{% endtrans %}') - - def test_trans_stringformatting(self): - tmpl = newstyle_i18n_env.get_template('stringformat.html') - assert tmpl.render(LANGUAGE='de', user_count=5) == 'Benutzer: 5' - - def test_newstyle_plural(self): - tmpl = newstyle_i18n_env.get_template('ngettext.html') - assert tmpl.render(LANGUAGE='de', apples=1) == '1 Apfel' - assert tmpl.render(LANGUAGE='de', apples=5) == u'5 Äpfel' - - def test_autoescape_support(self): - env = Environment(extensions=['jinja2.ext.autoescape', - 'jinja2.ext.i18n']) - env.install_gettext_callables(lambda x: u'Wert: %(name)s', - lambda s, p, n: s, newstyle=True) - t = env.from_string('{% autoescape ae %}{{ gettext("foo", name=' - '"") }}{% endautoescape %}') - assert t.render(ae=True) == 'Wert: <test>' - assert t.render(ae=False) == 'Wert: ' - - def test_num_used_twice(self): - tmpl = newstyle_i18n_env.get_template('ngettext_long.html') - assert tmpl.render(apples=5, LANGUAGE='de') == u'5 Äpfel' - - def test_num_called_num(self): - source = newstyle_i18n_env.compile(''' - {% trans num=3 %}{{ num }} apple{% pluralize - %}{{ num }} apples{% endtrans %} - ''', raw=True) - # quite hacky, but the only way to properly test that. The idea is - # that the generated code does not pass num twice (although that - # would work) for better performance. This only works on the - # newstyle gettext of course - assert re.search(r"l_ngettext, u?'\%\(num\)s apple', u?'\%\(num\)s " - r"apples', 3", source) is not None - - def test_trans_vars(self): - t1 = newstyle_i18n_env.get_template('transvars1.html') - t2 = newstyle_i18n_env.get_template('transvars2.html') - t3 = newstyle_i18n_env.get_template('transvars3.html') - assert t1.render(num=1, LANGUAGE='de') == 'Benutzer: 1' - assert t2.render(count=23, LANGUAGE='de') == 'Benutzer: 23' - assert t3.render(num=42, LANGUAGE='de') == 'Benutzer: 42' - - def test_novars_vars_escaping(self): - t = newstyle_i18n_env.get_template('novars.html') - assert t.render() == '%(hello)s' - t = newstyle_i18n_env.get_template('vars.html') - assert t.render(foo='42') == '42%(foo)s' - t = newstyle_i18n_env.get_template('explicitvars.html') - assert t.render() == '%(foo)s' - - -class AutoEscapeTestCase(JinjaTestCase): - - def test_scoped_setting(self): - env = Environment(extensions=['jinja2.ext.autoescape'], - autoescape=True) - tmpl = env.from_string(''' - {{ "" }} - {% autoescape false %} - {{ "" }} - {% endautoescape %} - {{ "" }} - ''') - assert tmpl.render().split() == \ - [u'<HelloWorld>', u'', u'<HelloWorld>'] - - env = Environment(extensions=['jinja2.ext.autoescape'], - autoescape=False) - tmpl = env.from_string(''' - {{ "" }} - {% autoescape true %} - {{ "" }} - {% endautoescape %} - {{ "" }} - ''') - assert tmpl.render().split() == \ - [u'', u'<HelloWorld>', u''] - - def test_nonvolatile(self): - env = Environment(extensions=['jinja2.ext.autoescape'], - autoescape=True) - tmpl = env.from_string('{{ {"foo": ""}|xmlattr|escape }}') - assert tmpl.render() == ' foo="<test>"' - tmpl = env.from_string('{% autoescape false %}{{ {"foo": ""}' - '|xmlattr|escape }}{% endautoescape %}') - assert tmpl.render() == ' foo="&lt;test&gt;"' - - def test_volatile(self): - env = Environment(extensions=['jinja2.ext.autoescape'], - autoescape=True) - tmpl = env.from_string('{% autoescape foo %}{{ {"foo": ""}' - '|xmlattr|escape }}{% endautoescape %}') - assert tmpl.render(foo=False) == ' foo="&lt;test&gt;"' - assert tmpl.render(foo=True) == ' foo="<test>"' - - def test_scoping(self): - env = Environment(extensions=['jinja2.ext.autoescape']) - tmpl = env.from_string('{% autoescape true %}{% set x = "" %}{{ x }}' - '{% endautoescape %}{{ x }}{{ "" }}') - assert tmpl.render(x=1) == '<x>1' - - def test_volatile_scoping(self): - env = Environment(extensions=['jinja2.ext.autoescape']) - tmplsource = ''' - {% autoescape val %} - {% macro foo(x) %} - [{{ x }}] - {% endmacro %} - {{ foo().__class__.__name__ }} - {% endautoescape %} - {{ '' }} - ''' - tmpl = env.from_string(tmplsource) - assert tmpl.render(val=True).split()[0] == 'Markup' - assert tmpl.render(val=False).split()[0] == text_type.__name__ - - # looking at the source we should see there in raw - # (and then escaped as well) - env = Environment(extensions=['jinja2.ext.autoescape']) - pysource = env.compile(tmplsource, raw=True) - assert '\\n' in pysource - - env = Environment(extensions=['jinja2.ext.autoescape'], - autoescape=True) - pysource = env.compile(tmplsource, raw=True) - assert '<testing>\\n' in pysource - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ExtensionsTestCase)) - suite.addTest(unittest.makeSuite(InternationalizationTestCase)) - suite.addTest(unittest.makeSuite(NewstyleInternationalizationTestCase)) - suite.addTest(unittest.makeSuite(AutoEscapeTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/filters.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/filters.py deleted file mode 100644 index 282dd2d8..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/filters.py +++ /dev/null @@ -1,515 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.filters - ~~~~~~~~~~~~~~~~~~~~~~~~ - - Tests for the jinja filters. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import unittest -from jinja2.testsuite import JinjaTestCase - -from jinja2 import Markup, Environment -from jinja2._compat import text_type, implements_to_string - -env = Environment() - - -class FilterTestCase(JinjaTestCase): - - def test_filter_calling(self): - rv = env.call_filter('sum', [1, 2, 3]) - self.assert_equal(rv, 6) - - def test_capitalize(self): - tmpl = env.from_string('{{ "foo bar"|capitalize }}') - assert tmpl.render() == 'Foo bar' - - def test_center(self): - tmpl = env.from_string('{{ "foo"|center(9) }}') - assert tmpl.render() == ' foo ' - - def test_default(self): - tmpl = env.from_string( - "{{ missing|default('no') }}|{{ false|default('no') }}|" - "{{ false|default('no', true) }}|{{ given|default('no') }}" - ) - assert tmpl.render(given='yes') == 'no|False|no|yes' - - def test_dictsort(self): - tmpl = env.from_string( - '{{ foo|dictsort }}|' - '{{ foo|dictsort(true) }}|' - '{{ foo|dictsort(false, "value") }}' - ) - out = tmpl.render(foo={"aa": 0, "b": 1, "c": 2, "AB": 3}) - assert out == ("[('aa', 0), ('AB', 3), ('b', 1), ('c', 2)]|" - "[('AB', 3), ('aa', 0), ('b', 1), ('c', 2)]|" - "[('aa', 0), ('b', 1), ('c', 2), ('AB', 3)]") - - def test_batch(self): - tmpl = env.from_string("{{ foo|batch(3)|list }}|" - "{{ foo|batch(3, 'X')|list }}") - out = tmpl.render(foo=list(range(10))) - assert out == ("[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]|" - "[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 'X', 'X']]") - - def test_slice(self): - tmpl = env.from_string('{{ foo|slice(3)|list }}|' - '{{ foo|slice(3, "X")|list }}') - out = tmpl.render(foo=list(range(10))) - assert out == ("[[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]|" - "[[0, 1, 2, 3], [4, 5, 6, 'X'], [7, 8, 9, 'X']]") - - def test_escape(self): - tmpl = env.from_string('''{{ '<">&'|escape }}''') - out = tmpl.render() - assert out == '<">&' - - def test_striptags(self): - tmpl = env.from_string('''{{ foo|striptags }}''') - out = tmpl.render(foo='
\n

to a webpage

' - '') - assert out == 'just a small example link to a webpage' - - def test_filesizeformat(self): - tmpl = env.from_string( - '{{ 100|filesizeformat }}|' - '{{ 1000|filesizeformat }}|' - '{{ 1000000|filesizeformat }}|' - '{{ 1000000000|filesizeformat }}|' - '{{ 1000000000000|filesizeformat }}|' - '{{ 100|filesizeformat(true) }}|' - '{{ 1000|filesizeformat(true) }}|' - '{{ 1000000|filesizeformat(true) }}|' - '{{ 1000000000|filesizeformat(true) }}|' - '{{ 1000000000000|filesizeformat(true) }}' - ) - out = tmpl.render() - self.assert_equal(out, ( - '100 Bytes|1.0 kB|1.0 MB|1.0 GB|1.0 TB|100 Bytes|' - '1000 Bytes|976.6 KiB|953.7 MiB|931.3 GiB' - )) - - def test_filesizeformat_issue59(self): - tmpl = env.from_string( - '{{ 300|filesizeformat }}|' - '{{ 3000|filesizeformat }}|' - '{{ 3000000|filesizeformat }}|' - '{{ 3000000000|filesizeformat }}|' - '{{ 3000000000000|filesizeformat }}|' - '{{ 300|filesizeformat(true) }}|' - '{{ 3000|filesizeformat(true) }}|' - '{{ 3000000|filesizeformat(true) }}' - ) - out = tmpl.render() - self.assert_equal(out, ( - '300 Bytes|3.0 kB|3.0 MB|3.0 GB|3.0 TB|300 Bytes|' - '2.9 KiB|2.9 MiB' - )) - - - def test_first(self): - tmpl = env.from_string('{{ foo|first }}') - out = tmpl.render(foo=list(range(10))) - assert out == '0' - - def test_float(self): - tmpl = env.from_string('{{ "42"|float }}|' - '{{ "ajsghasjgd"|float }}|' - '{{ "32.32"|float }}') - out = tmpl.render() - assert out == '42.0|0.0|32.32' - - def test_format(self): - tmpl = env.from_string('''{{ "%s|%s"|format("a", "b") }}''') - out = tmpl.render() - assert out == 'a|b' - - def test_indent(self): - tmpl = env.from_string('{{ foo|indent(2) }}|{{ foo|indent(2, true) }}') - text = '\n'.join([' '.join(['foo', 'bar'] * 2)] * 2) - out = tmpl.render(foo=text) - assert out == ('foo bar foo bar\n foo bar foo bar| ' - 'foo bar foo bar\n foo bar foo bar') - - def test_int(self): - tmpl = env.from_string('{{ "42"|int }}|{{ "ajsghasjgd"|int }}|' - '{{ "32.32"|int }}') - out = tmpl.render() - assert out == '42|0|32' - - def test_join(self): - tmpl = env.from_string('{{ [1, 2, 3]|join("|") }}') - out = tmpl.render() - assert out == '1|2|3' - - env2 = Environment(autoescape=True) - tmpl = env2.from_string('{{ ["", "foo"|safe]|join }}') - assert tmpl.render() == '<foo>foo' - - def test_join_attribute(self): - class User(object): - def __init__(self, username): - self.username = username - tmpl = env.from_string('''{{ users|join(', ', 'username') }}''') - assert tmpl.render(users=map(User, ['foo', 'bar'])) == 'foo, bar' - - def test_last(self): - tmpl = env.from_string('''{{ foo|last }}''') - out = tmpl.render(foo=list(range(10))) - assert out == '9' - - def test_length(self): - tmpl = env.from_string('''{{ "hello world"|length }}''') - out = tmpl.render() - assert out == '11' - - def test_lower(self): - tmpl = env.from_string('''{{ "FOO"|lower }}''') - out = tmpl.render() - assert out == 'foo' - - def test_pprint(self): - from pprint import pformat - tmpl = env.from_string('''{{ data|pprint }}''') - data = list(range(1000)) - assert tmpl.render(data=data) == pformat(data) - - def test_random(self): - tmpl = env.from_string('''{{ seq|random }}''') - seq = list(range(100)) - for _ in range(10): - assert int(tmpl.render(seq=seq)) in seq - - def test_reverse(self): - tmpl = env.from_string('{{ "foobar"|reverse|join }}|' - '{{ [1, 2, 3]|reverse|list }}') - assert tmpl.render() == 'raboof|[3, 2, 1]' - - def test_string(self): - x = [1, 2, 3, 4, 5] - tmpl = env.from_string('''{{ obj|string }}''') - assert tmpl.render(obj=x) == text_type(x) - - def test_title(self): - tmpl = env.from_string('''{{ "foo bar"|title }}''') - assert tmpl.render() == "Foo Bar" - tmpl = env.from_string('''{{ "foo's bar"|title }}''') - assert tmpl.render() == "Foo's Bar" - tmpl = env.from_string('''{{ "foo bar"|title }}''') - assert tmpl.render() == "Foo Bar" - tmpl = env.from_string('''{{ "f bar f"|title }}''') - assert tmpl.render() == "F Bar F" - tmpl = env.from_string('''{{ "foo-bar"|title }}''') - assert tmpl.render() == "Foo-Bar" - tmpl = env.from_string('''{{ "foo\tbar"|title }}''') - assert tmpl.render() == "Foo\tBar" - tmpl = env.from_string('''{{ "FOO\tBAR"|title }}''') - assert tmpl.render() == "Foo\tBar" - - def test_truncate(self): - tmpl = env.from_string( - '{{ data|truncate(15, true, ">>>") }}|' - '{{ data|truncate(15, false, ">>>") }}|' - '{{ smalldata|truncate(15) }}' - ) - out = tmpl.render(data='foobar baz bar' * 1000, - smalldata='foobar baz bar') - assert out == 'foobar baz barf>>>|foobar baz >>>|foobar baz bar' - - def test_upper(self): - tmpl = env.from_string('{{ "foo"|upper }}') - assert tmpl.render() == 'FOO' - - def test_urlize(self): - tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}') - assert tmpl.render() == 'foo '\ - 'http://www.example.com/ bar' - - def test_wordcount(self): - tmpl = env.from_string('{{ "foo bar baz"|wordcount }}') - assert tmpl.render() == '3' - - def test_block(self): - tmpl = env.from_string('{% filter lower|escape %}{% endfilter %}') - assert tmpl.render() == '<hehe>' - - def test_chaining(self): - tmpl = env.from_string('''{{ ['', '']|first|upper|escape }}''') - assert tmpl.render() == '<FOO>' - - def test_sum(self): - tmpl = env.from_string('''{{ [1, 2, 3, 4, 5, 6]|sum }}''') - assert tmpl.render() == '21' - - def test_sum_attributes(self): - tmpl = env.from_string('''{{ values|sum('value') }}''') - assert tmpl.render(values=[ - {'value': 23}, - {'value': 1}, - {'value': 18}, - ]) == '42' - - def test_sum_attributes_nested(self): - tmpl = env.from_string('''{{ values|sum('real.value') }}''') - assert tmpl.render(values=[ - {'real': {'value': 23}}, - {'real': {'value': 1}}, - {'real': {'value': 18}}, - ]) == '42' - - def test_sum_attributes_tuple(self): - tmpl = env.from_string('''{{ values.items()|sum('1') }}''') - assert tmpl.render(values={ - 'foo': 23, - 'bar': 1, - 'baz': 18, - }) == '42' - - def test_abs(self): - tmpl = env.from_string('''{{ -1|abs }}|{{ 1|abs }}''') - assert tmpl.render() == '1|1', tmpl.render() - - def test_round_positive(self): - tmpl = env.from_string('{{ 2.7|round }}|{{ 2.1|round }}|' - "{{ 2.1234|round(3, 'floor') }}|" - "{{ 2.1|round(0, 'ceil') }}") - assert tmpl.render() == '3.0|2.0|2.123|3.0', tmpl.render() - - def test_round_negative(self): - tmpl = env.from_string('{{ 21.3|round(-1)}}|' - "{{ 21.3|round(-1, 'ceil')}}|" - "{{ 21.3|round(-1, 'floor')}}") - assert tmpl.render() == '20.0|30.0|20.0',tmpl.render() - - def test_xmlattr(self): - tmpl = env.from_string("{{ {'foo': 42, 'bar': 23, 'fish': none, " - "'spam': missing, 'blub:blub': ''}|xmlattr }}") - out = tmpl.render().split() - assert len(out) == 3 - assert 'foo="42"' in out - assert 'bar="23"' in out - assert 'blub:blub="<?>"' in out - - def test_sort1(self): - tmpl = env.from_string('{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}') - assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]' - - def test_sort2(self): - tmpl = env.from_string('{{ "".join(["c", "A", "b", "D"]|sort) }}') - assert tmpl.render() == 'AbcD' - - def test_sort3(self): - tmpl = env.from_string('''{{ ['foo', 'Bar', 'blah']|sort }}''') - assert tmpl.render() == "['Bar', 'blah', 'foo']" - - def test_sort4(self): - @implements_to_string - class Magic(object): - def __init__(self, value): - self.value = value - def __str__(self): - return text_type(self.value) - tmpl = env.from_string('''{{ items|sort(attribute='value')|join }}''') - assert tmpl.render(items=map(Magic, [3, 2, 4, 1])) == '1234' - - def test_groupby(self): - tmpl = env.from_string(''' - {%- for grouper, list in [{'foo': 1, 'bar': 2}, - {'foo': 2, 'bar': 3}, - {'foo': 1, 'bar': 1}, - {'foo': 3, 'bar': 4}]|groupby('foo') -%} - {{ grouper }}{% for x in list %}: {{ x.foo }}, {{ x.bar }}{% endfor %}| - {%- endfor %}''') - assert tmpl.render().split('|') == [ - "1: 1, 2: 1, 1", - "2: 2, 3", - "3: 3, 4", - "" - ] - - def test_groupby_tuple_index(self): - tmpl = env.from_string(''' - {%- for grouper, list in [('a', 1), ('a', 2), ('b', 1)]|groupby(0) -%} - {{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}| - {%- endfor %}''') - assert tmpl.render() == 'a:1:2|b:1|' - - def test_groupby_multidot(self): - class Date(object): - def __init__(self, day, month, year): - self.day = day - self.month = month - self.year = year - class Article(object): - def __init__(self, title, *date): - self.date = Date(*date) - self.title = title - articles = [ - Article('aha', 1, 1, 1970), - Article('interesting', 2, 1, 1970), - Article('really?', 3, 1, 1970), - Article('totally not', 1, 1, 1971) - ] - tmpl = env.from_string(''' - {%- for year, list in articles|groupby('date.year') -%} - {{ year }}{% for x in list %}[{{ x.title }}]{% endfor %}| - {%- endfor %}''') - assert tmpl.render(articles=articles).split('|') == [ - '1970[aha][interesting][really?]', - '1971[totally not]', - '' - ] - - def test_filtertag(self): - tmpl = env.from_string("{% filter upper|replace('FOO', 'foo') %}" - "foobar{% endfilter %}") - assert tmpl.render() == 'fooBAR' - - def test_replace(self): - env = Environment() - tmpl = env.from_string('{{ string|replace("o", 42) }}') - assert tmpl.render(string='') == '' - env = Environment(autoescape=True) - tmpl = env.from_string('{{ string|replace("o", 42) }}') - assert tmpl.render(string='') == '<f4242>' - tmpl = env.from_string('{{ string|replace("<", 42) }}') - assert tmpl.render(string='') == '42foo>' - tmpl = env.from_string('{{ string|replace("o", ">x<") }}') - assert tmpl.render(string=Markup('foo')) == 'f>x<>x<' - - def test_forceescape(self): - tmpl = env.from_string('{{ x|forceescape }}') - assert tmpl.render(x=Markup('
')) == u'<div />' - - def test_safe(self): - env = Environment(autoescape=True) - tmpl = env.from_string('{{ "
foo
"|safe }}') - assert tmpl.render() == '
foo
' - tmpl = env.from_string('{{ "
foo
" }}') - assert tmpl.render() == '<div>foo</div>' - - def test_urlencode(self): - env = Environment(autoescape=True) - tmpl = env.from_string('{{ "Hello, world!"|urlencode }}') - assert tmpl.render() == 'Hello%2C%20world%21' - tmpl = env.from_string('{{ o|urlencode }}') - assert tmpl.render(o=u"Hello, world\u203d") == "Hello%2C%20world%E2%80%BD" - assert tmpl.render(o=(("f", 1),)) == "f=1" - assert tmpl.render(o=(('f', 1), ("z", 2))) == "f=1&z=2" - assert tmpl.render(o=((u"\u203d", 1),)) == "%E2%80%BD=1" - assert tmpl.render(o={u"\u203d": 1}) == "%E2%80%BD=1" - assert tmpl.render(o={0: 1}) == "0=1" - - def test_simple_map(self): - env = Environment() - tmpl = env.from_string('{{ ["1", "2", "3"]|map("int")|sum }}') - self.assertEqual(tmpl.render(), '6') - - def test_attribute_map(self): - class User(object): - def __init__(self, name): - self.name = name - env = Environment() - users = [ - User('john'), - User('jane'), - User('mike'), - ] - tmpl = env.from_string('{{ users|map(attribute="name")|join("|") }}') - self.assertEqual(tmpl.render(users=users), 'john|jane|mike') - - def test_empty_map(self): - env = Environment() - tmpl = env.from_string('{{ none|map("upper")|list }}') - self.assertEqual(tmpl.render(), '[]') - - def test_simple_select(self): - env = Environment() - tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|select("odd")|join("|") }}') - self.assertEqual(tmpl.render(), '1|3|5') - - def test_bool_select(self): - env = Environment() - tmpl = env.from_string('{{ [none, false, 0, 1, 2, 3, 4, 5]|select|join("|") }}') - self.assertEqual(tmpl.render(), '1|2|3|4|5') - - def test_simple_reject(self): - env = Environment() - tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|reject("odd")|join("|") }}') - self.assertEqual(tmpl.render(), '2|4') - - def test_bool_reject(self): - env = Environment() - tmpl = env.from_string('{{ [none, false, 0, 1, 2, 3, 4, 5]|reject|join("|") }}') - self.assertEqual(tmpl.render(), 'None|False|0') - - def test_simple_select_attr(self): - class User(object): - def __init__(self, name, is_active): - self.name = name - self.is_active = is_active - env = Environment() - users = [ - User('john', True), - User('jane', True), - User('mike', False), - ] - tmpl = env.from_string('{{ users|selectattr("is_active")|' - 'map(attribute="name")|join("|") }}') - self.assertEqual(tmpl.render(users=users), 'john|jane') - - def test_simple_reject_attr(self): - class User(object): - def __init__(self, name, is_active): - self.name = name - self.is_active = is_active - env = Environment() - users = [ - User('john', True), - User('jane', True), - User('mike', False), - ] - tmpl = env.from_string('{{ users|rejectattr("is_active")|' - 'map(attribute="name")|join("|") }}') - self.assertEqual(tmpl.render(users=users), 'mike') - - def test_func_select_attr(self): - class User(object): - def __init__(self, id, name): - self.id = id - self.name = name - env = Environment() - users = [ - User(1, 'john'), - User(2, 'jane'), - User(3, 'mike'), - ] - tmpl = env.from_string('{{ users|selectattr("id", "odd")|' - 'map(attribute="name")|join("|") }}') - self.assertEqual(tmpl.render(users=users), 'john|mike') - - def test_func_reject_attr(self): - class User(object): - def __init__(self, id, name): - self.id = id - self.name = name - env = Environment() - users = [ - User(1, 'john'), - User(2, 'jane'), - User(3, 'mike'), - ] - tmpl = env.from_string('{{ users|rejectattr("id", "odd")|' - 'map(attribute="name")|join("|") }}') - self.assertEqual(tmpl.render(users=users), 'jane') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(FilterTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/imports.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/imports.py deleted file mode 100644 index 3db9008d..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/imports.py +++ /dev/null @@ -1,141 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.imports - ~~~~~~~~~~~~~~~~~~~~~~~~ - - Tests the import features (with includes). - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from jinja2.testsuite import JinjaTestCase - -from jinja2 import Environment, DictLoader -from jinja2.exceptions import TemplateNotFound, TemplatesNotFound - - -test_env = Environment(loader=DictLoader(dict( - module='{% macro test() %}[{{ foo }}|{{ bar }}]{% endmacro %}', - header='[{{ foo }}|{{ 23 }}]', - o_printer='({{ o }})' -))) -test_env.globals['bar'] = 23 - - -class ImportsTestCase(JinjaTestCase): - - def test_context_imports(self): - t = test_env.from_string('{% import "module" as m %}{{ m.test() }}') - assert t.render(foo=42) == '[|23]' - t = test_env.from_string('{% import "module" as m without context %}{{ m.test() }}') - assert t.render(foo=42) == '[|23]' - t = test_env.from_string('{% import "module" as m with context %}{{ m.test() }}') - assert t.render(foo=42) == '[42|23]' - t = test_env.from_string('{% from "module" import test %}{{ test() }}') - assert t.render(foo=42) == '[|23]' - t = test_env.from_string('{% from "module" import test without context %}{{ test() }}') - assert t.render(foo=42) == '[|23]' - t = test_env.from_string('{% from "module" import test with context %}{{ test() }}') - assert t.render(foo=42) == '[42|23]' - - def test_trailing_comma(self): - test_env.from_string('{% from "foo" import bar, baz with context %}') - test_env.from_string('{% from "foo" import bar, baz, with context %}') - test_env.from_string('{% from "foo" import bar, with context %}') - test_env.from_string('{% from "foo" import bar, with, context %}') - test_env.from_string('{% from "foo" import bar, with with context %}') - - def test_exports(self): - m = test_env.from_string(''' - {% macro toplevel() %}...{% endmacro %} - {% macro __private() %}...{% endmacro %} - {% set variable = 42 %} - {% for item in [1] %} - {% macro notthere() %}{% endmacro %} - {% endfor %} - ''').module - assert m.toplevel() == '...' - assert not hasattr(m, '__missing') - assert m.variable == 42 - assert not hasattr(m, 'notthere') - - -class IncludesTestCase(JinjaTestCase): - - def test_context_include(self): - t = test_env.from_string('{% include "header" %}') - assert t.render(foo=42) == '[42|23]' - t = test_env.from_string('{% include "header" with context %}') - assert t.render(foo=42) == '[42|23]' - t = test_env.from_string('{% include "header" without context %}') - assert t.render(foo=42) == '[|23]' - - def test_choice_includes(self): - t = test_env.from_string('{% include ["missing", "header"] %}') - assert t.render(foo=42) == '[42|23]' - - t = test_env.from_string('{% include ["missing", "missing2"] ignore missing %}') - assert t.render(foo=42) == '' - - t = test_env.from_string('{% include ["missing", "missing2"] %}') - self.assert_raises(TemplateNotFound, t.render) - try: - t.render() - except TemplatesNotFound as e: - assert e.templates == ['missing', 'missing2'] - assert e.name == 'missing2' - else: - assert False, 'thou shalt raise' - - def test_includes(t, **ctx): - ctx['foo'] = 42 - assert t.render(ctx) == '[42|23]' - - t = test_env.from_string('{% include ["missing", "header"] %}') - test_includes(t) - t = test_env.from_string('{% include x %}') - test_includes(t, x=['missing', 'header']) - t = test_env.from_string('{% include [x, "header"] %}') - test_includes(t, x='missing') - t = test_env.from_string('{% include x %}') - test_includes(t, x='header') - t = test_env.from_string('{% include x %}') - test_includes(t, x='header') - t = test_env.from_string('{% include [x] %}') - test_includes(t, x='header') - - def test_include_ignoring_missing(self): - t = test_env.from_string('{% include "missing" %}') - self.assert_raises(TemplateNotFound, t.render) - for extra in '', 'with context', 'without context': - t = test_env.from_string('{% include "missing" ignore missing ' + - extra + ' %}') - assert t.render() == '' - - def test_context_include_with_overrides(self): - env = Environment(loader=DictLoader(dict( - main="{% for item in [1, 2, 3] %}{% include 'item' %}{% endfor %}", - item="{{ item }}" - ))) - assert env.get_template("main").render() == "123" - - def test_unoptimized_scopes(self): - t = test_env.from_string(""" - {% macro outer(o) %} - {% macro inner() %} - {% include "o_printer" %} - {% endmacro %} - {{ inner() }} - {% endmacro %} - {{ outer("FOO") }} - """) - assert t.render().strip() == '(FOO)' - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ImportsTestCase)) - suite.addTest(unittest.makeSuite(IncludesTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/inheritance.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/inheritance.py deleted file mode 100644 index e0f51cda..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/inheritance.py +++ /dev/null @@ -1,250 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.inheritance - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Tests the template inheritance feature. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from jinja2.testsuite import JinjaTestCase - -from jinja2 import Environment, DictLoader, TemplateError - - -LAYOUTTEMPLATE = '''\ -|{% block block1 %}block 1 from layout{% endblock %} -|{% block block2 %}block 2 from layout{% endblock %} -|{% block block3 %} -{% block block4 %}nested block 4 from layout{% endblock %} -{% endblock %}|''' - -LEVEL1TEMPLATE = '''\ -{% extends "layout" %} -{% block block1 %}block 1 from level1{% endblock %}''' - -LEVEL2TEMPLATE = '''\ -{% extends "level1" %} -{% block block2 %}{% block block5 %}nested block 5 from level2{% -endblock %}{% endblock %}''' - -LEVEL3TEMPLATE = '''\ -{% extends "level2" %} -{% block block5 %}block 5 from level3{% endblock %} -{% block block4 %}block 4 from level3{% endblock %} -''' - -LEVEL4TEMPLATE = '''\ -{% extends "level3" %} -{% block block3 %}block 3 from level4{% endblock %} -''' - -WORKINGTEMPLATE = '''\ -{% extends "layout" %} -{% block block1 %} - {% if false %} - {% block block2 %} - this should workd - {% endblock %} - {% endif %} -{% endblock %} -''' - -DOUBLEEXTENDS = '''\ -{% extends "layout" %} -{% extends "layout" %} -{% block block1 %} - {% if false %} - {% block block2 %} - this should workd - {% endblock %} - {% endif %} -{% endblock %} -''' - - -env = Environment(loader=DictLoader({ - 'layout': LAYOUTTEMPLATE, - 'level1': LEVEL1TEMPLATE, - 'level2': LEVEL2TEMPLATE, - 'level3': LEVEL3TEMPLATE, - 'level4': LEVEL4TEMPLATE, - 'working': WORKINGTEMPLATE, - 'doublee': DOUBLEEXTENDS, -}), trim_blocks=True) - - -class InheritanceTestCase(JinjaTestCase): - - def test_layout(self): - tmpl = env.get_template('layout') - assert tmpl.render() == ('|block 1 from layout|block 2 from ' - 'layout|nested block 4 from layout|') - - def test_level1(self): - tmpl = env.get_template('level1') - assert tmpl.render() == ('|block 1 from level1|block 2 from ' - 'layout|nested block 4 from layout|') - - def test_level2(self): - tmpl = env.get_template('level2') - assert tmpl.render() == ('|block 1 from level1|nested block 5 from ' - 'level2|nested block 4 from layout|') - - def test_level3(self): - tmpl = env.get_template('level3') - assert tmpl.render() == ('|block 1 from level1|block 5 from level3|' - 'block 4 from level3|') - - def test_level4(sel): - tmpl = env.get_template('level4') - assert tmpl.render() == ('|block 1 from level1|block 5 from ' - 'level3|block 3 from level4|') - - def test_super(self): - env = Environment(loader=DictLoader({ - 'a': '{% block intro %}INTRO{% endblock %}|' - 'BEFORE|{% block data %}INNER{% endblock %}|AFTER', - 'b': '{% extends "a" %}{% block data %}({{ ' - 'super() }}){% endblock %}', - 'c': '{% extends "b" %}{% block intro %}--{{ ' - 'super() }}--{% endblock %}\n{% block data ' - '%}[{{ super() }}]{% endblock %}' - })) - tmpl = env.get_template('c') - assert tmpl.render() == '--INTRO--|BEFORE|[(INNER)]|AFTER' - - def test_working(self): - tmpl = env.get_template('working') - - def test_reuse_blocks(self): - tmpl = env.from_string('{{ self.foo() }}|{% block foo %}42' - '{% endblock %}|{{ self.foo() }}') - assert tmpl.render() == '42|42|42' - - def test_preserve_blocks(self): - env = Environment(loader=DictLoader({ - 'a': '{% if false %}{% block x %}A{% endblock %}{% endif %}{{ self.x() }}', - 'b': '{% extends "a" %}{% block x %}B{{ super() }}{% endblock %}' - })) - tmpl = env.get_template('b') - assert tmpl.render() == 'BA' - - def test_dynamic_inheritance(self): - env = Environment(loader=DictLoader({ - 'master1': 'MASTER1{% block x %}{% endblock %}', - 'master2': 'MASTER2{% block x %}{% endblock %}', - 'child': '{% extends master %}{% block x %}CHILD{% endblock %}' - })) - tmpl = env.get_template('child') - for m in range(1, 3): - assert tmpl.render(master='master%d' % m) == 'MASTER%dCHILD' % m - - def test_multi_inheritance(self): - env = Environment(loader=DictLoader({ - 'master1': 'MASTER1{% block x %}{% endblock %}', - 'master2': 'MASTER2{% block x %}{% endblock %}', - 'child': '''{% if master %}{% extends master %}{% else %}{% extends - 'master1' %}{% endif %}{% block x %}CHILD{% endblock %}''' - })) - tmpl = env.get_template('child') - assert tmpl.render(master='master2') == 'MASTER2CHILD' - assert tmpl.render(master='master1') == 'MASTER1CHILD' - assert tmpl.render() == 'MASTER1CHILD' - - def test_scoped_block(self): - env = Environment(loader=DictLoader({ - 'master.html': '{% for item in seq %}[{% block item scoped %}' - '{% endblock %}]{% endfor %}' - })) - t = env.from_string('{% extends "master.html" %}{% block item %}' - '{{ item }}{% endblock %}') - assert t.render(seq=list(range(5))) == '[0][1][2][3][4]' - - def test_super_in_scoped_block(self): - env = Environment(loader=DictLoader({ - 'master.html': '{% for item in seq %}[{% block item scoped %}' - '{{ item }}{% endblock %}]{% endfor %}' - })) - t = env.from_string('{% extends "master.html" %}{% block item %}' - '{{ super() }}|{{ item * 2 }}{% endblock %}') - assert t.render(seq=list(range(5))) == '[0|0][1|2][2|4][3|6][4|8]' - - def test_scoped_block_after_inheritance(self): - env = Environment(loader=DictLoader({ - 'layout.html': ''' - {% block useless %}{% endblock %} - ''', - 'index.html': ''' - {%- extends 'layout.html' %} - {% from 'helpers.html' import foo with context %} - {% block useless %} - {% for x in [1, 2, 3] %} - {% block testing scoped %} - {{ foo(x) }} - {% endblock %} - {% endfor %} - {% endblock %} - ''', - 'helpers.html': ''' - {% macro foo(x) %}{{ the_foo + x }}{% endmacro %} - ''' - })) - rv = env.get_template('index.html').render(the_foo=42).split() - assert rv == ['43', '44', '45'] - - -class BugFixTestCase(JinjaTestCase): - - def test_fixed_macro_scoping_bug(self): - assert Environment(loader=DictLoader({ - 'test.html': '''\ - {% extends 'details.html' %} - - {% macro my_macro() %} - my_macro - {% endmacro %} - - {% block inner_box %} - {{ my_macro() }} - {% endblock %} - ''', - 'details.html': '''\ - {% extends 'standard.html' %} - - {% macro my_macro() %} - my_macro - {% endmacro %} - - {% block content %} - {% block outer_box %} - outer_box - {% block inner_box %} - inner_box - {% endblock %} - {% endblock %} - {% endblock %} - ''', - 'standard.html': ''' - {% block content %} {% endblock %} - ''' - })).get_template("test.html").render().split() == [u'outer_box', u'my_macro'] - - def test_double_extends(self): - """Ensures that a template with more than 1 {% extends ... %} usage - raises a ``TemplateError``. - """ - try: - tmpl = env.get_template('doublee') - except Exception as e: - assert isinstance(e, TemplateError) - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(InheritanceTestCase)) - suite.addTest(unittest.makeSuite(BugFixTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/lexnparse.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/lexnparse.py deleted file mode 100644 index bd1c94cd..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/lexnparse.py +++ /dev/null @@ -1,593 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.lexnparse - ~~~~~~~~~~~~~~~~~~~~~~~~~~ - - All the unittests regarding lexing, parsing and syntax. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from jinja2.testsuite import JinjaTestCase - -from jinja2 import Environment, Template, TemplateSyntaxError, \ - UndefinedError, nodes -from jinja2._compat import next, iteritems, text_type, PY2 -from jinja2.lexer import Token, TokenStream, TOKEN_EOF, \ - TOKEN_BLOCK_BEGIN, TOKEN_BLOCK_END - -env = Environment() - - -# how does a string look like in jinja syntax? -if PY2: - def jinja_string_repr(string): - return repr(string)[1:] -else: - jinja_string_repr = repr - - -class TokenStreamTestCase(JinjaTestCase): - test_tokens = [Token(1, TOKEN_BLOCK_BEGIN, ''), - Token(2, TOKEN_BLOCK_END, ''), - ] - - def test_simple(self): - ts = TokenStream(self.test_tokens, "foo", "bar") - assert ts.current.type is TOKEN_BLOCK_BEGIN - assert bool(ts) - assert not bool(ts.eos) - next(ts) - assert ts.current.type is TOKEN_BLOCK_END - assert bool(ts) - assert not bool(ts.eos) - next(ts) - assert ts.current.type is TOKEN_EOF - assert not bool(ts) - assert bool(ts.eos) - - def test_iter(self): - token_types = [t.type for t in TokenStream(self.test_tokens, "foo", "bar")] - assert token_types == ['block_begin', 'block_end', ] - - -class LexerTestCase(JinjaTestCase): - - def test_raw1(self): - tmpl = env.from_string('{% raw %}foo{% endraw %}|' - '{%raw%}{{ bar }}|{% baz %}{% endraw %}') - assert tmpl.render() == 'foo|{{ bar }}|{% baz %}' - - def test_raw2(self): - tmpl = env.from_string('1 {%- raw -%} 2 {%- endraw -%} 3') - assert tmpl.render() == '123' - - def test_balancing(self): - env = Environment('{%', '%}', '${', '}') - tmpl = env.from_string('''{% for item in seq - %}${{'foo': item}|upper}{% endfor %}''') - assert tmpl.render(seq=list(range(3))) == "{'FOO': 0}{'FOO': 1}{'FOO': 2}" - - def test_comments(self): - env = Environment('', '{', '}') - tmpl = env.from_string('''\ -
    - -
  • {item}
  • - -
''') - assert tmpl.render(seq=list(range(3))) == ("
    \n
  • 0
  • \n " - "
  • 1
  • \n
  • 2
  • \n
") - - def test_string_escapes(self): - for char in u'\0', u'\u2668', u'\xe4', u'\t', u'\r', u'\n': - tmpl = env.from_string('{{ %s }}' % jinja_string_repr(char)) - assert tmpl.render() == char - assert env.from_string('{{ "\N{HOT SPRINGS}" }}').render() == u'\u2668' - - def test_bytefallback(self): - from pprint import pformat - tmpl = env.from_string(u'''{{ 'foo'|pprint }}|{{ 'bär'|pprint }}''') - assert tmpl.render() == pformat('foo') + '|' + pformat(u'bär') - - def test_operators(self): - from jinja2.lexer import operators - for test, expect in iteritems(operators): - if test in '([{}])': - continue - stream = env.lexer.tokenize('{{ %s }}' % test) - next(stream) - assert stream.current.type == expect - - def test_normalizing(self): - for seq in '\r', '\r\n', '\n': - env = Environment(newline_sequence=seq) - tmpl = env.from_string('1\n2\r\n3\n4\n') - result = tmpl.render() - assert result.replace(seq, 'X') == '1X2X3X4' - - def test_trailing_newline(self): - for keep in [True, False]: - env = Environment(keep_trailing_newline=keep) - for template,expected in [ - ('', {}), - ('no\nnewline', {}), - ('with\nnewline\n', {False: 'with\nnewline'}), - ('with\nseveral\n\n\n', {False: 'with\nseveral\n\n'}), - ]: - tmpl = env.from_string(template) - expect = expected.get(keep, template) - result = tmpl.render() - assert result == expect, (keep, template, result, expect) - -class ParserTestCase(JinjaTestCase): - - def test_php_syntax(self): - env = Environment('', '', '') - tmpl = env.from_string('''\ -\ - - -''') - assert tmpl.render(seq=list(range(5))) == '01234' - - def test_erb_syntax(self): - env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>') - tmpl = env.from_string('''\ -<%# I'm a comment, I'm not interesting %>\ -<% for item in seq -%> - <%= item %> -<%- endfor %>''') - assert tmpl.render(seq=list(range(5))) == '01234' - - def test_comment_syntax(self): - env = Environment('', '${', '}', '') - tmpl = env.from_string('''\ -\ - - ${item} -''') - assert tmpl.render(seq=list(range(5))) == '01234' - - def test_balancing(self): - tmpl = env.from_string('''{{{'foo':'bar'}.foo}}''') - assert tmpl.render() == 'bar' - - def test_start_comment(self): - tmpl = env.from_string('''{# foo comment -and bar comment #} -{% macro blub() %}foo{% endmacro %} -{{ blub() }}''') - assert tmpl.render().strip() == 'foo' - - def test_line_syntax(self): - env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%') - tmpl = env.from_string('''\ -<%# regular comment %> -% for item in seq: - ${item} -% endfor''') - assert [int(x.strip()) for x in tmpl.render(seq=list(range(5))).split()] == \ - list(range(5)) - - env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##') - tmpl = env.from_string('''\ -<%# regular comment %> -% for item in seq: - ${item} ## the rest of the stuff -% endfor''') - assert [int(x.strip()) for x in tmpl.render(seq=list(range(5))).split()] == \ - list(range(5)) - - def test_line_syntax_priority(self): - # XXX: why is the whitespace there in front of the newline? - env = Environment('{%', '%}', '${', '}', '/*', '*/', '##', '#') - tmpl = env.from_string('''\ -/* ignore me. - I'm a multiline comment */ -## for item in seq: -* ${item} # this is just extra stuff -## endfor''') - assert tmpl.render(seq=[1, 2]).strip() == '* 1\n* 2' - env = Environment('{%', '%}', '${', '}', '/*', '*/', '#', '##') - tmpl = env.from_string('''\ -/* ignore me. - I'm a multiline comment */ -# for item in seq: -* ${item} ## this is just extra stuff - ## extra stuff i just want to ignore -# endfor''') - assert tmpl.render(seq=[1, 2]).strip() == '* 1\n\n* 2' - - def test_error_messages(self): - def assert_error(code, expected): - try: - Template(code) - except TemplateSyntaxError as e: - assert str(e) == expected, 'unexpected error message' - else: - assert False, 'that was supposed to be an error' - - assert_error('{% for item in seq %}...{% endif %}', - "Encountered unknown tag 'endif'. Jinja was looking " - "for the following tags: 'endfor' or 'else'. The " - "innermost block that needs to be closed is 'for'.") - assert_error('{% if foo %}{% for item in seq %}...{% endfor %}{% endfor %}', - "Encountered unknown tag 'endfor'. Jinja was looking for " - "the following tags: 'elif' or 'else' or 'endif'. The " - "innermost block that needs to be closed is 'if'.") - assert_error('{% if foo %}', - "Unexpected end of template. Jinja was looking for the " - "following tags: 'elif' or 'else' or 'endif'. The " - "innermost block that needs to be closed is 'if'.") - assert_error('{% for item in seq %}', - "Unexpected end of template. Jinja was looking for the " - "following tags: 'endfor' or 'else'. The innermost block " - "that needs to be closed is 'for'.") - assert_error('{% block foo-bar-baz %}', - "Block names in Jinja have to be valid Python identifiers " - "and may not contain hyphens, use an underscore instead.") - assert_error('{% unknown_tag %}', - "Encountered unknown tag 'unknown_tag'.") - - -class SyntaxTestCase(JinjaTestCase): - - def test_call(self): - env = Environment() - env.globals['foo'] = lambda a, b, c, e, g: a + b + c + e + g - tmpl = env.from_string("{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}") - assert tmpl.render() == 'abdfh' - - def test_slicing(self): - tmpl = env.from_string('{{ [1, 2, 3][:] }}|{{ [1, 2, 3][::-1] }}') - assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]' - - def test_attr(self): - tmpl = env.from_string("{{ foo.bar }}|{{ foo['bar'] }}") - assert tmpl.render(foo={'bar': 42}) == '42|42' - - def test_subscript(self): - tmpl = env.from_string("{{ foo[0] }}|{{ foo[-1] }}") - assert tmpl.render(foo=[0, 1, 2]) == '0|2' - - def test_tuple(self): - tmpl = env.from_string('{{ () }}|{{ (1,) }}|{{ (1, 2) }}') - assert tmpl.render() == '()|(1,)|(1, 2)' - - def test_math(self): - tmpl = env.from_string('{{ (1 + 1 * 2) - 3 / 2 }}|{{ 2**3 }}') - assert tmpl.render() == '1.5|8' - - def test_div(self): - tmpl = env.from_string('{{ 3 // 2 }}|{{ 3 / 2 }}|{{ 3 % 2 }}') - assert tmpl.render() == '1|1.5|1' - - def test_unary(self): - tmpl = env.from_string('{{ +3 }}|{{ -3 }}') - assert tmpl.render() == '3|-3' - - def test_concat(self): - tmpl = env.from_string("{{ [1, 2] ~ 'foo' }}") - assert tmpl.render() == '[1, 2]foo' - - def test_compare(self): - tmpl = env.from_string('{{ 1 > 0 }}|{{ 1 >= 1 }}|{{ 2 < 3 }}|' - '{{ 2 == 2 }}|{{ 1 <= 1 }}') - assert tmpl.render() == 'True|True|True|True|True' - - def test_inop(self): - tmpl = env.from_string('{{ 1 in [1, 2, 3] }}|{{ 1 not in [1, 2, 3] }}') - assert tmpl.render() == 'True|False' - - def test_literals(self): - tmpl = env.from_string('{{ [] }}|{{ {} }}|{{ () }}') - assert tmpl.render().lower() == '[]|{}|()' - - def test_bool(self): - tmpl = env.from_string('{{ true and false }}|{{ false ' - 'or true }}|{{ not false }}') - assert tmpl.render() == 'False|True|True' - - def test_grouping(self): - tmpl = env.from_string('{{ (true and false) or (false and true) and not false }}') - assert tmpl.render() == 'False' - - def test_django_attr(self): - tmpl = env.from_string('{{ [1, 2, 3].0 }}|{{ [[1]].0.0 }}') - assert tmpl.render() == '1|1' - - def test_conditional_expression(self): - tmpl = env.from_string('''{{ 0 if true else 1 }}''') - assert tmpl.render() == '0' - - def test_short_conditional_expression(self): - tmpl = env.from_string('<{{ 1 if false }}>') - assert tmpl.render() == '<>' - - tmpl = env.from_string('<{{ (1 if false).bar }}>') - self.assert_raises(UndefinedError, tmpl.render) - - def test_filter_priority(self): - tmpl = env.from_string('{{ "foo"|upper + "bar"|upper }}') - assert tmpl.render() == 'FOOBAR' - - def test_function_calls(self): - tests = [ - (True, '*foo, bar'), - (True, '*foo, *bar'), - (True, '*foo, bar=42'), - (True, '**foo, *bar'), - (True, '**foo, bar'), - (False, 'foo, bar'), - (False, 'foo, bar=42'), - (False, 'foo, bar=23, *args'), - (False, 'a, b=c, *d, **e'), - (False, '*foo, **bar') - ] - for should_fail, sig in tests: - if should_fail: - self.assert_raises(TemplateSyntaxError, - env.from_string, '{{ foo(%s) }}' % sig) - else: - env.from_string('foo(%s)' % sig) - - def test_tuple_expr(self): - for tmpl in [ - '{{ () }}', - '{{ (1, 2) }}', - '{{ (1, 2,) }}', - '{{ 1, }}', - '{{ 1, 2 }}', - '{% for foo, bar in seq %}...{% endfor %}', - '{% for x in foo, bar %}...{% endfor %}', - '{% for x in foo, %}...{% endfor %}' - ]: - assert env.from_string(tmpl) - - def test_trailing_comma(self): - tmpl = env.from_string('{{ (1, 2,) }}|{{ [1, 2,] }}|{{ {1: 2,} }}') - assert tmpl.render().lower() == '(1, 2)|[1, 2]|{1: 2}' - - def test_block_end_name(self): - env.from_string('{% block foo %}...{% endblock foo %}') - self.assert_raises(TemplateSyntaxError, env.from_string, - '{% block x %}{% endblock y %}') - - def test_constant_casing(self): - for const in True, False, None: - tmpl = env.from_string('{{ %s }}|{{ %s }}|{{ %s }}' % ( - str(const), str(const).lower(), str(const).upper() - )) - assert tmpl.render() == '%s|%s|' % (const, const) - - def test_test_chaining(self): - self.assert_raises(TemplateSyntaxError, env.from_string, - '{{ foo is string is sequence }}') - assert env.from_string('{{ 42 is string or 42 is number }}' - ).render() == 'True' - - def test_string_concatenation(self): - tmpl = env.from_string('{{ "foo" "bar" "baz" }}') - assert tmpl.render() == 'foobarbaz' - - def test_notin(self): - bar = range(100) - tmpl = env.from_string('''{{ not 42 in bar }}''') - assert tmpl.render(bar=bar) == text_type(not 42 in bar) - - def test_implicit_subscribed_tuple(self): - class Foo(object): - def __getitem__(self, x): - return x - t = env.from_string('{{ foo[1, 2] }}') - assert t.render(foo=Foo()) == u'(1, 2)' - - def test_raw2(self): - tmpl = env.from_string('{% raw %}{{ FOO }} and {% BAR %}{% endraw %}') - assert tmpl.render() == '{{ FOO }} and {% BAR %}' - - def test_const(self): - tmpl = env.from_string('{{ true }}|{{ false }}|{{ none }}|' - '{{ none is defined }}|{{ missing is defined }}') - assert tmpl.render() == 'True|False|None|True|False' - - def test_neg_filter_priority(self): - node = env.parse('{{ -1|foo }}') - assert isinstance(node.body[0].nodes[0], nodes.Filter) - assert isinstance(node.body[0].nodes[0].node, nodes.Neg) - - def test_const_assign(self): - constass1 = '''{% set true = 42 %}''' - constass2 = '''{% for none in seq %}{% endfor %}''' - for tmpl in constass1, constass2: - self.assert_raises(TemplateSyntaxError, env.from_string, tmpl) - - def test_localset(self): - tmpl = env.from_string('''{% set foo = 0 %}\ -{% for item in [1, 2] %}{% set foo = 1 %}{% endfor %}\ -{{ foo }}''') - assert tmpl.render() == '0' - - def test_parse_unary(self): - tmpl = env.from_string('{{ -foo["bar"] }}') - assert tmpl.render(foo={'bar': 42}) == '-42' - tmpl = env.from_string('{{ -foo["bar"]|abs }}') - assert tmpl.render(foo={'bar': 42}) == '42' - - -class LstripBlocksTestCase(JinjaTestCase): - - def test_lstrip(self): - env = Environment(lstrip_blocks=True, trim_blocks=False) - tmpl = env.from_string(''' {% if True %}\n {% endif %}''') - assert tmpl.render() == "\n" - - def test_lstrip_trim(self): - env = Environment(lstrip_blocks=True, trim_blocks=True) - tmpl = env.from_string(''' {% if True %}\n {% endif %}''') - assert tmpl.render() == "" - - def test_no_lstrip(self): - env = Environment(lstrip_blocks=True, trim_blocks=False) - tmpl = env.from_string(''' {%+ if True %}\n {%+ endif %}''') - assert tmpl.render() == " \n " - - def test_lstrip_endline(self): - env = Environment(lstrip_blocks=True, trim_blocks=False) - tmpl = env.from_string(''' hello{% if True %}\n goodbye{% endif %}''') - assert tmpl.render() == " hello\n goodbye" - - def test_lstrip_inline(self): - env = Environment(lstrip_blocks=True, trim_blocks=False) - tmpl = env.from_string(''' {% if True %}hello {% endif %}''') - assert tmpl.render() == 'hello ' - - def test_lstrip_nested(self): - env = Environment(lstrip_blocks=True, trim_blocks=False) - tmpl = env.from_string(''' {% if True %}a {% if True %}b {% endif %}c {% endif %}''') - assert tmpl.render() == 'a b c ' - - def test_lstrip_left_chars(self): - env = Environment(lstrip_blocks=True, trim_blocks=False) - tmpl = env.from_string(''' abc {% if True %} - hello{% endif %}''') - assert tmpl.render() == ' abc \n hello' - - def test_lstrip_embeded_strings(self): - env = Environment(lstrip_blocks=True, trim_blocks=False) - tmpl = env.from_string(''' {% set x = " {% str %} " %}{{ x }}''') - assert tmpl.render() == ' {% str %} ' - - def test_lstrip_preserve_leading_newlines(self): - env = Environment(lstrip_blocks=True, trim_blocks=False) - tmpl = env.from_string('''\n\n\n{% set hello = 1 %}''') - assert tmpl.render() == '\n\n\n' - - def test_lstrip_comment(self): - env = Environment(lstrip_blocks=True, trim_blocks=False) - tmpl = env.from_string(''' {# if True #} -hello - {#endif#}''') - assert tmpl.render() == '\nhello\n' - - def test_lstrip_angle_bracket_simple(self): - env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##', - lstrip_blocks=True, trim_blocks=True) - tmpl = env.from_string(''' <% if True %>hello <% endif %>''') - assert tmpl.render() == 'hello ' - - def test_lstrip_angle_bracket_comment(self): - env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##', - lstrip_blocks=True, trim_blocks=True) - tmpl = env.from_string(''' <%# if True %>hello <%# endif %>''') - assert tmpl.render() == 'hello ' - - def test_lstrip_angle_bracket(self): - env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##', - lstrip_blocks=True, trim_blocks=True) - tmpl = env.from_string('''\ - <%# regular comment %> - <% for item in seq %> -${item} ## the rest of the stuff - <% endfor %>''') - assert tmpl.render(seq=range(5)) == \ - ''.join('%s\n' % x for x in range(5)) - - def test_lstrip_angle_bracket_compact(self): - env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##', - lstrip_blocks=True, trim_blocks=True) - tmpl = env.from_string('''\ - <%#regular comment%> - <%for item in seq%> -${item} ## the rest of the stuff - <%endfor%>''') - assert tmpl.render(seq=range(5)) == \ - ''.join('%s\n' % x for x in range(5)) - - def test_php_syntax_with_manual(self): - env = Environment('', '', '', - lstrip_blocks=True, trim_blocks=True) - tmpl = env.from_string('''\ - - - - ''') - assert tmpl.render(seq=range(5)) == '01234' - - def test_php_syntax(self): - env = Environment('', '', '', - lstrip_blocks=True, trim_blocks=True) - tmpl = env.from_string('''\ - - - - ''') - assert tmpl.render(seq=range(5)) == ''.join(' %s\n' % x for x in range(5)) - - def test_php_syntax_compact(self): - env = Environment('', '', '', - lstrip_blocks=True, trim_blocks=True) - tmpl = env.from_string('''\ - - - - ''') - assert tmpl.render(seq=range(5)) == ''.join(' %s\n' % x for x in range(5)) - - def test_erb_syntax(self): - env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>', - lstrip_blocks=True, trim_blocks=True) - #env.from_string('') - #for n,r in env.lexer.rules.iteritems(): - # print n - #print env.lexer.rules['root'][0][0].pattern - #print "'%s'" % tmpl.render(seq=range(5)) - tmpl = env.from_string('''\ -<%# I'm a comment, I'm not interesting %> - <% for item in seq %> - <%= item %> - <% endfor %> -''') - assert tmpl.render(seq=range(5)) == ''.join(' %s\n' % x for x in range(5)) - - def test_erb_syntax_with_manual(self): - env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>', - lstrip_blocks=True, trim_blocks=True) - tmpl = env.from_string('''\ -<%# I'm a comment, I'm not interesting %> - <% for item in seq -%> - <%= item %> - <%- endfor %>''') - assert tmpl.render(seq=range(5)) == '01234' - - def test_erb_syntax_no_lstrip(self): - env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>', - lstrip_blocks=True, trim_blocks=True) - tmpl = env.from_string('''\ -<%# I'm a comment, I'm not interesting %> - <%+ for item in seq -%> - <%= item %> - <%- endfor %>''') - assert tmpl.render(seq=range(5)) == ' 01234' - - def test_comment_syntax(self): - env = Environment('', '${', '}', '', - lstrip_blocks=True, trim_blocks=True) - tmpl = env.from_string('''\ -\ - - ${item} -''') - assert tmpl.render(seq=range(5)) == '01234' - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TokenStreamTestCase)) - suite.addTest(unittest.makeSuite(LexerTestCase)) - suite.addTest(unittest.makeSuite(ParserTestCase)) - suite.addTest(unittest.makeSuite(SyntaxTestCase)) - suite.addTest(unittest.makeSuite(LstripBlocksTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/loader.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/loader.py deleted file mode 100644 index a7350aab..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/loader.py +++ /dev/null @@ -1,226 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.loader - ~~~~~~~~~~~~~~~~~~~~~~~ - - Test the loaders. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import os -import sys -import tempfile -import shutil -import unittest - -from jinja2.testsuite import JinjaTestCase, dict_loader, \ - package_loader, filesystem_loader, function_loader, \ - choice_loader, prefix_loader - -from jinja2 import Environment, loaders -from jinja2._compat import PYPY, PY2 -from jinja2.loaders import split_template_path -from jinja2.exceptions import TemplateNotFound - - -class LoaderTestCase(JinjaTestCase): - - def test_dict_loader(self): - env = Environment(loader=dict_loader) - tmpl = env.get_template('justdict.html') - assert tmpl.render().strip() == 'FOO' - self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') - - def test_package_loader(self): - env = Environment(loader=package_loader) - tmpl = env.get_template('test.html') - assert tmpl.render().strip() == 'BAR' - self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') - - def test_filesystem_loader(self): - env = Environment(loader=filesystem_loader) - tmpl = env.get_template('test.html') - assert tmpl.render().strip() == 'BAR' - tmpl = env.get_template('foo/test.html') - assert tmpl.render().strip() == 'FOO' - self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') - - def test_choice_loader(self): - env = Environment(loader=choice_loader) - tmpl = env.get_template('justdict.html') - assert tmpl.render().strip() == 'FOO' - tmpl = env.get_template('test.html') - assert tmpl.render().strip() == 'BAR' - self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') - - def test_function_loader(self): - env = Environment(loader=function_loader) - tmpl = env.get_template('justfunction.html') - assert tmpl.render().strip() == 'FOO' - self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') - - def test_prefix_loader(self): - env = Environment(loader=prefix_loader) - tmpl = env.get_template('a/test.html') - assert tmpl.render().strip() == 'BAR' - tmpl = env.get_template('b/justdict.html') - assert tmpl.render().strip() == 'FOO' - self.assert_raises(TemplateNotFound, env.get_template, 'missing') - - def test_caching(self): - changed = False - class TestLoader(loaders.BaseLoader): - def get_source(self, environment, template): - return u'foo', None, lambda: not changed - env = Environment(loader=TestLoader(), cache_size=-1) - tmpl = env.get_template('template') - assert tmpl is env.get_template('template') - changed = True - assert tmpl is not env.get_template('template') - changed = False - - env = Environment(loader=TestLoader(), cache_size=0) - assert env.get_template('template') \ - is not env.get_template('template') - - env = Environment(loader=TestLoader(), cache_size=2) - t1 = env.get_template('one') - t2 = env.get_template('two') - assert t2 is env.get_template('two') - assert t1 is env.get_template('one') - t3 = env.get_template('three') - assert 'one' in env.cache - assert 'two' not in env.cache - assert 'three' in env.cache - - def test_dict_loader_cache_invalidates(self): - mapping = {'foo': "one"} - env = Environment(loader=loaders.DictLoader(mapping)) - assert env.get_template('foo').render() == "one" - mapping['foo'] = "two" - assert env.get_template('foo').render() == "two" - - def test_split_template_path(self): - assert split_template_path('foo/bar') == ['foo', 'bar'] - assert split_template_path('./foo/bar') == ['foo', 'bar'] - self.assert_raises(TemplateNotFound, split_template_path, '../foo') - - -class ModuleLoaderTestCase(JinjaTestCase): - archive = None - - def compile_down(self, zip='deflated', py_compile=False): - super(ModuleLoaderTestCase, self).setup() - log = [] - self.reg_env = Environment(loader=prefix_loader) - if zip is not None: - self.archive = tempfile.mkstemp(suffix='.zip')[1] - else: - self.archive = tempfile.mkdtemp() - self.reg_env.compile_templates(self.archive, zip=zip, - log_function=log.append, - py_compile=py_compile) - self.mod_env = Environment(loader=loaders.ModuleLoader(self.archive)) - return ''.join(log) - - def teardown(self): - super(ModuleLoaderTestCase, self).teardown() - if hasattr(self, 'mod_env'): - if os.path.isfile(self.archive): - os.remove(self.archive) - else: - shutil.rmtree(self.archive) - self.archive = None - - def test_log(self): - log = self.compile_down() - assert 'Compiled "a/foo/test.html" as ' \ - 'tmpl_a790caf9d669e39ea4d280d597ec891c4ef0404a' in log - assert 'Finished compiling templates' in log - assert 'Could not compile "a/syntaxerror.html": ' \ - 'Encountered unknown tag \'endif\'' in log - - def _test_common(self): - tmpl1 = self.reg_env.get_template('a/test.html') - tmpl2 = self.mod_env.get_template('a/test.html') - assert tmpl1.render() == tmpl2.render() - - tmpl1 = self.reg_env.get_template('b/justdict.html') - tmpl2 = self.mod_env.get_template('b/justdict.html') - assert tmpl1.render() == tmpl2.render() - - def test_deflated_zip_compile(self): - self.compile_down(zip='deflated') - self._test_common() - - def test_stored_zip_compile(self): - self.compile_down(zip='stored') - self._test_common() - - def test_filesystem_compile(self): - self.compile_down(zip=None) - self._test_common() - - def test_weak_references(self): - self.compile_down() - tmpl = self.mod_env.get_template('a/test.html') - key = loaders.ModuleLoader.get_template_key('a/test.html') - name = self.mod_env.loader.module.__name__ - - assert hasattr(self.mod_env.loader.module, key) - assert name in sys.modules - - # unset all, ensure the module is gone from sys.modules - self.mod_env = tmpl = None - - try: - import gc - gc.collect() - except: - pass - - assert name not in sys.modules - - # This test only makes sense on non-pypy python 2 - if PY2 and not PYPY: - def test_byte_compilation(self): - log = self.compile_down(py_compile=True) - assert 'Byte-compiled "a/test.html"' in log - tmpl1 = self.mod_env.get_template('a/test.html') - mod = self.mod_env.loader.module. \ - tmpl_3c4ddf650c1a73df961a6d3d2ce2752f1b8fd490 - assert mod.__file__.endswith('.pyc') - - def test_choice_loader(self): - log = self.compile_down() - - self.mod_env.loader = loaders.ChoiceLoader([ - self.mod_env.loader, - loaders.DictLoader({'DICT_SOURCE': 'DICT_TEMPLATE'}) - ]) - - tmpl1 = self.mod_env.get_template('a/test.html') - self.assert_equal(tmpl1.render(), 'BAR') - tmpl2 = self.mod_env.get_template('DICT_SOURCE') - self.assert_equal(tmpl2.render(), 'DICT_TEMPLATE') - - def test_prefix_loader(self): - log = self.compile_down() - - self.mod_env.loader = loaders.PrefixLoader({ - 'MOD': self.mod_env.loader, - 'DICT': loaders.DictLoader({'test.html': 'DICT_TEMPLATE'}) - }) - - tmpl1 = self.mod_env.get_template('MOD/a/test.html') - self.assert_equal(tmpl1.render(), 'BAR') - tmpl2 = self.mod_env.get_template('DICT/test.html') - self.assert_equal(tmpl2.render(), 'DICT_TEMPLATE') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(LoaderTestCase)) - suite.addTest(unittest.makeSuite(ModuleLoaderTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/regression.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/regression.py deleted file mode 100644 index c5f7d5c6..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/regression.py +++ /dev/null @@ -1,279 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.regression - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Tests corner cases and bugs. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from jinja2.testsuite import JinjaTestCase - -from jinja2 import Template, Environment, DictLoader, TemplateSyntaxError, \ - TemplateNotFound, PrefixLoader -from jinja2._compat import text_type - -env = Environment() - - -class CornerTestCase(JinjaTestCase): - - def test_assigned_scoping(self): - t = env.from_string(''' - {%- for item in (1, 2, 3, 4) -%} - [{{ item }}] - {%- endfor %} - {{- item -}} - ''') - assert t.render(item=42) == '[1][2][3][4]42' - - t = env.from_string(''' - {%- for item in (1, 2, 3, 4) -%} - [{{ item }}] - {%- endfor %} - {%- set item = 42 %} - {{- item -}} - ''') - assert t.render() == '[1][2][3][4]42' - - t = env.from_string(''' - {%- set item = 42 %} - {%- for item in (1, 2, 3, 4) -%} - [{{ item }}] - {%- endfor %} - {{- item -}} - ''') - assert t.render() == '[1][2][3][4]42' - - def test_closure_scoping(self): - t = env.from_string(''' - {%- set wrapper = "" %} - {%- for item in (1, 2, 3, 4) %} - {%- macro wrapper() %}[{{ item }}]{% endmacro %} - {{- wrapper() }} - {%- endfor %} - {{- wrapper -}} - ''') - assert t.render() == '[1][2][3][4]' - - t = env.from_string(''' - {%- for item in (1, 2, 3, 4) %} - {%- macro wrapper() %}[{{ item }}]{% endmacro %} - {{- wrapper() }} - {%- endfor %} - {%- set wrapper = "" %} - {{- wrapper -}} - ''') - assert t.render() == '[1][2][3][4]' - - t = env.from_string(''' - {%- for item in (1, 2, 3, 4) %} - {%- macro wrapper() %}[{{ item }}]{% endmacro %} - {{- wrapper() }} - {%- endfor %} - {{- wrapper -}} - ''') - assert t.render(wrapper=23) == '[1][2][3][4]23' - - -class BugTestCase(JinjaTestCase): - - def test_keyword_folding(self): - env = Environment() - env.filters['testing'] = lambda value, some: value + some - assert env.from_string("{{ 'test'|testing(some='stuff') }}") \ - .render() == 'teststuff' - - def test_extends_output_bugs(self): - env = Environment(loader=DictLoader({ - 'parent.html': '(({% block title %}{% endblock %}))' - })) - - t = env.from_string('{% if expr %}{% extends "parent.html" %}{% endif %}' - '[[{% block title %}title{% endblock %}]]' - '{% for item in [1, 2, 3] %}({{ item }}){% endfor %}') - assert t.render(expr=False) == '[[title]](1)(2)(3)' - assert t.render(expr=True) == '((title))' - - def test_urlize_filter_escaping(self): - tmpl = env.from_string('{{ "http://www.example.org/http://www.example.org/<foo' - - def test_loop_call_loop(self): - tmpl = env.from_string(''' - - {% macro test() %} - {{ caller() }} - {% endmacro %} - - {% for num1 in range(5) %} - {% call test() %} - {% for num2 in range(10) %} - {{ loop.index }} - {% endfor %} - {% endcall %} - {% endfor %} - - ''') - - assert tmpl.render().split() == [text_type(x) for x in range(1, 11)] * 5 - - def test_weird_inline_comment(self): - env = Environment(line_statement_prefix='%') - self.assert_raises(TemplateSyntaxError, env.from_string, - '% for item in seq {# missing #}\n...% endfor') - - def test_old_macro_loop_scoping_bug(self): - tmpl = env.from_string('{% for i in (1, 2) %}{{ i }}{% endfor %}' - '{% macro i() %}3{% endmacro %}{{ i() }}') - assert tmpl.render() == '123' - - def test_partial_conditional_assignments(self): - tmpl = env.from_string('{% if b %}{% set a = 42 %}{% endif %}{{ a }}') - assert tmpl.render(a=23) == '23' - assert tmpl.render(b=True) == '42' - - def test_stacked_locals_scoping_bug(self): - env = Environment(line_statement_prefix='#') - t = env.from_string('''\ -# for j in [1, 2]: -# set x = 1 -# for i in [1, 2]: -# print x -# if i % 2 == 0: -# set x = x + 1 -# endif -# endfor -# endfor -# if a -# print 'A' -# elif b -# print 'B' -# elif c == d -# print 'C' -# else -# print 'D' -# endif - ''') - assert t.render(a=0, b=False, c=42, d=42.0) == '1111C' - - def test_stacked_locals_scoping_bug_twoframe(self): - t = Template(''' - {% set x = 1 %} - {% for item in foo %} - {% if item == 1 %} - {% set x = 2 %} - {% endif %} - {% endfor %} - {{ x }} - ''') - rv = t.render(foo=[1]).strip() - assert rv == u'1' - - def test_call_with_args(self): - t = Template("""{% macro dump_users(users) -%} -
    - {%- for user in users -%} -
  • {{ user.username|e }}

    {{ caller(user) }}
  • - {%- endfor -%} -
- {%- endmacro -%} - - {% call(user) dump_users(list_of_user) -%} -
-
Realname
-
{{ user.realname|e }}
-
Description
-
{{ user.description }}
-
- {% endcall %}""") - - assert [x.strip() for x in t.render(list_of_user=[{ - 'username':'apo', - 'realname':'something else', - 'description':'test' - }]).splitlines()] == [ - u'
  • apo

    ', - u'
    Realname
    ', - u'
    something else
    ', - u'
    Description
    ', - u'
    test
    ', - u'
    ', - u'
' - ] - - def test_empty_if_condition_fails(self): - self.assert_raises(TemplateSyntaxError, Template, '{% if %}....{% endif %}') - self.assert_raises(TemplateSyntaxError, Template, '{% if foo %}...{% elif %}...{% endif %}') - self.assert_raises(TemplateSyntaxError, Template, '{% for x in %}..{% endfor %}') - - def test_recursive_loop_bug(self): - tpl1 = Template(""" - {% for p in foo recursive%} - {{p.bar}} - {% for f in p.fields recursive%} - {{f.baz}} - {{p.bar}} - {% if f.rec %} - {{ loop(f.sub) }} - {% endif %} - {% endfor %} - {% endfor %} - """) - - tpl2 = Template(""" - {% for p in foo%} - {{p.bar}} - {% for f in p.fields recursive%} - {{f.baz}} - {{p.bar}} - {% if f.rec %} - {{ loop(f.sub) }} - {% endif %} - {% endfor %} - {% endfor %} - """) - - def test_else_loop_bug(self): - t = Template(''' - {% for x in y %} - {{ loop.index0 }} - {% else %} - {% for i in range(3) %}{{ i }}{% endfor %} - {% endfor %} - ''') - self.assertEqual(t.render(y=[]).strip(), '012') - - def test_correct_prefix_loader_name(self): - env = Environment(loader=PrefixLoader({ - 'foo': DictLoader({}) - })) - try: - env.get_template('foo/bar.html') - except TemplateNotFound as e: - assert e.name == 'foo/bar.html' - else: - assert False, 'expected error here' - - def test_contextfunction_callable_classes(self): - from jinja2.utils import contextfunction - class CallableClass(object): - @contextfunction - def __call__(self, ctx): - return ctx.resolve('hello') - - tpl = Template("""{{ callableclass() }}""") - output = tpl.render(callableclass = CallableClass(), hello = 'TEST') - expected = 'TEST' - - self.assert_equal(output, expected) - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(CornerTestCase)) - suite.addTest(unittest.makeSuite(BugTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/__init__.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/broken.html b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/broken.html deleted file mode 100644 index 77669fae..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/broken.html +++ /dev/null @@ -1,3 +0,0 @@ -Before -{{ fail() }} -After diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/foo/test.html b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/foo/test.html deleted file mode 100644 index b7d6715e..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/foo/test.html +++ /dev/null @@ -1 +0,0 @@ -FOO diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/syntaxerror.html b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/syntaxerror.html deleted file mode 100644 index f21b8179..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/syntaxerror.html +++ /dev/null @@ -1,4 +0,0 @@ -Foo -{% for item in broken %} - ... -{% endif %} diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/test.html b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/test.html deleted file mode 100644 index ba578e48..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/res/templates/test.html +++ /dev/null @@ -1 +0,0 @@ -BAR diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/security.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/security.py deleted file mode 100644 index 246d0f07..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/security.py +++ /dev/null @@ -1,166 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.security - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - Checks the sandbox and other security features. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from jinja2.testsuite import JinjaTestCase - -from jinja2 import Environment -from jinja2.sandbox import SandboxedEnvironment, \ - ImmutableSandboxedEnvironment, unsafe -from jinja2 import Markup, escape -from jinja2.exceptions import SecurityError, TemplateSyntaxError, \ - TemplateRuntimeError -from jinja2._compat import text_type - - -class PrivateStuff(object): - - def bar(self): - return 23 - - @unsafe - def foo(self): - return 42 - - def __repr__(self): - return 'PrivateStuff' - - -class PublicStuff(object): - bar = lambda self: 23 - _foo = lambda self: 42 - - def __repr__(self): - return 'PublicStuff' - - -class SandboxTestCase(JinjaTestCase): - - def test_unsafe(self): - env = SandboxedEnvironment() - self.assert_raises(SecurityError, env.from_string("{{ foo.foo() }}").render, - foo=PrivateStuff()) - self.assert_equal(env.from_string("{{ foo.bar() }}").render(foo=PrivateStuff()), '23') - - self.assert_raises(SecurityError, env.from_string("{{ foo._foo() }}").render, - foo=PublicStuff()) - self.assert_equal(env.from_string("{{ foo.bar() }}").render(foo=PublicStuff()), '23') - self.assert_equal(env.from_string("{{ foo.__class__ }}").render(foo=42), '') - self.assert_equal(env.from_string("{{ foo.func_code }}").render(foo=lambda:None), '') - # security error comes from __class__ already. - self.assert_raises(SecurityError, env.from_string( - "{{ foo.__class__.__subclasses__() }}").render, foo=42) - - def test_immutable_environment(self): - env = ImmutableSandboxedEnvironment() - self.assert_raises(SecurityError, env.from_string( - '{{ [].append(23) }}').render) - self.assert_raises(SecurityError, env.from_string( - '{{ {1:2}.clear() }}').render) - - def test_restricted(self): - env = SandboxedEnvironment() - self.assert_raises(TemplateSyntaxError, env.from_string, - "{% for item.attribute in seq %}...{% endfor %}") - self.assert_raises(TemplateSyntaxError, env.from_string, - "{% for foo, bar.baz in seq %}...{% endfor %}") - - def test_markup_operations(self): - # adding two strings should escape the unsafe one - unsafe = '' - safe = Markup('username') - assert unsafe + safe == text_type(escape(unsafe)) + text_type(safe) - - # string interpolations are safe to use too - assert Markup('%s') % '' == \ - '<bad user>' - assert Markup('%(username)s') % { - 'username': '' - } == '<bad user>' - - # an escaped object is markup too - assert type(Markup('foo') + 'bar') is Markup - - # and it implements __html__ by returning itself - x = Markup("foo") - assert x.__html__() is x - - # it also knows how to treat __html__ objects - class Foo(object): - def __html__(self): - return 'awesome' - def __unicode__(self): - return 'awesome' - assert Markup(Foo()) == 'awesome' - assert Markup('%s') % Foo() == \ - 'awesome' - - # escaping and unescaping - assert escape('"<>&\'') == '"<>&'' - assert Markup("Foo & Bar").striptags() == "Foo & Bar" - assert Markup("<test>").unescape() == "" - - def test_template_data(self): - env = Environment(autoescape=True) - t = env.from_string('{% macro say_hello(name) %}' - '

Hello {{ name }}!

{% endmacro %}' - '{{ say_hello("foo") }}') - escaped_out = '

Hello <blink>foo</blink>!

' - assert t.render() == escaped_out - assert text_type(t.module) == escaped_out - assert escape(t.module) == escaped_out - assert t.module.say_hello('foo') == escaped_out - assert escape(t.module.say_hello('foo')) == escaped_out - - def test_attr_filter(self): - env = SandboxedEnvironment() - tmpl = env.from_string('{{ cls|attr("__subclasses__")() }}') - self.assert_raises(SecurityError, tmpl.render, cls=int) - - def test_binary_operator_intercepting(self): - def disable_op(left, right): - raise TemplateRuntimeError('that operator so does not work') - for expr, ctx, rv in ('1 + 2', {}, '3'), ('a + 2', {'a': 2}, '4'): - env = SandboxedEnvironment() - env.binop_table['+'] = disable_op - t = env.from_string('{{ %s }}' % expr) - assert t.render(ctx) == rv - env.intercepted_binops = frozenset(['+']) - t = env.from_string('{{ %s }}' % expr) - try: - t.render(ctx) - except TemplateRuntimeError as e: - pass - else: - self.fail('expected runtime error') - - def test_unary_operator_intercepting(self): - def disable_op(arg): - raise TemplateRuntimeError('that operator so does not work') - for expr, ctx, rv in ('-1', {}, '-1'), ('-a', {'a': 2}, '-2'): - env = SandboxedEnvironment() - env.unop_table['-'] = disable_op - t = env.from_string('{{ %s }}' % expr) - assert t.render(ctx) == rv - env.intercepted_unops = frozenset(['-']) - t = env.from_string('{{ %s }}' % expr) - try: - t.render(ctx) - except TemplateRuntimeError as e: - pass - else: - self.fail('expected runtime error') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(SandboxTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/tests.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/tests.py deleted file mode 100644 index 3ece7a8f..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/tests.py +++ /dev/null @@ -1,93 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.tests - ~~~~~~~~~~~~~~~~~~~~~~ - - Who tests the tests? - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import unittest -from jinja2.testsuite import JinjaTestCase - -from jinja2 import Markup, Environment - -env = Environment() - - -class TestsTestCase(JinjaTestCase): - - def test_defined(self): - tmpl = env.from_string('{{ missing is defined }}|{{ true is defined }}') - assert tmpl.render() == 'False|True' - - def test_even(self): - tmpl = env.from_string('''{{ 1 is even }}|{{ 2 is even }}''') - assert tmpl.render() == 'False|True' - - def test_odd(self): - tmpl = env.from_string('''{{ 1 is odd }}|{{ 2 is odd }}''') - assert tmpl.render() == 'True|False' - - def test_lower(self): - tmpl = env.from_string('''{{ "foo" is lower }}|{{ "FOO" is lower }}''') - assert tmpl.render() == 'True|False' - - def test_typechecks(self): - tmpl = env.from_string(''' - {{ 42 is undefined }} - {{ 42 is defined }} - {{ 42 is none }} - {{ none is none }} - {{ 42 is number }} - {{ 42 is string }} - {{ "foo" is string }} - {{ "foo" is sequence }} - {{ [1] is sequence }} - {{ range is callable }} - {{ 42 is callable }} - {{ range(5) is iterable }} - {{ {} is mapping }} - {{ mydict is mapping }} - {{ [] is mapping }} - ''') - class MyDict(dict): - pass - assert tmpl.render(mydict=MyDict()).split() == [ - 'False', 'True', 'False', 'True', 'True', 'False', - 'True', 'True', 'True', 'True', 'False', 'True', - 'True', 'True', 'False' - ] - - def test_sequence(self): - tmpl = env.from_string( - '{{ [1, 2, 3] is sequence }}|' - '{{ "foo" is sequence }}|' - '{{ 42 is sequence }}' - ) - assert tmpl.render() == 'True|True|False' - - def test_upper(self): - tmpl = env.from_string('{{ "FOO" is upper }}|{{ "foo" is upper }}') - assert tmpl.render() == 'True|False' - - def test_sameas(self): - tmpl = env.from_string('{{ foo is sameas false }}|' - '{{ 0 is sameas false }}') - assert tmpl.render(foo=False) == 'True|False' - - def test_no_paren_for_arg1(self): - tmpl = env.from_string('{{ foo is sameas none }}') - assert tmpl.render(foo=None) == 'True' - - def test_escaped(self): - env = Environment(autoescape=True) - tmpl = env.from_string('{{ x is escaped }}|{{ y is escaped }}') - assert tmpl.render(x='foo', y=Markup('foo')) == 'False|True' - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TestsTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/utils.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/utils.py deleted file mode 100644 index cab9b09a..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/testsuite/utils.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.utils - ~~~~~~~~~~~~~~~~~~~~~~ - - Tests utilities jinja uses. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import gc -import unittest - -import pickle - -from jinja2.testsuite import JinjaTestCase - -from jinja2.utils import LRUCache, escape, object_type_repr - - -class LRUCacheTestCase(JinjaTestCase): - - def test_simple(self): - d = LRUCache(3) - d["a"] = 1 - d["b"] = 2 - d["c"] = 3 - d["a"] - d["d"] = 4 - assert len(d) == 3 - assert 'a' in d and 'c' in d and 'd' in d and 'b' not in d - - def test_pickleable(self): - cache = LRUCache(2) - cache["foo"] = 42 - cache["bar"] = 23 - cache["foo"] - - for protocol in range(3): - copy = pickle.loads(pickle.dumps(cache, protocol)) - assert copy.capacity == cache.capacity - assert copy._mapping == cache._mapping - assert copy._queue == cache._queue - - -class HelpersTestCase(JinjaTestCase): - - def test_object_type_repr(self): - class X(object): - pass - self.assert_equal(object_type_repr(42), 'int object') - self.assert_equal(object_type_repr([]), 'list object') - self.assert_equal(object_type_repr(X()), - 'jinja2.testsuite.utils.X object') - self.assert_equal(object_type_repr(None), 'None') - self.assert_equal(object_type_repr(Ellipsis), 'Ellipsis') - - -class MarkupLeakTestCase(JinjaTestCase): - - def test_markup_leaks(self): - counts = set() - for count in range(20): - for item in range(1000): - escape("foo") - escape("") - escape(u"foo") - escape(u"") - counts.add(len(gc.get_objects())) - assert len(counts) == 1, 'ouch, c extension seems to leak objects' - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(LRUCacheTestCase)) - suite.addTest(unittest.makeSuite(HelpersTestCase)) - - # this test only tests the c extension - if not hasattr(escape, 'func_code'): - suite.addTest(unittest.makeSuite(MarkupLeakTestCase)) - - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/utils.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/utils.py deleted file mode 100644 index ddc47da0..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/utils.py +++ /dev/null @@ -1,520 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.utils - ~~~~~~~~~~~~ - - Utility functions. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import re -import errno -from collections import deque -from jinja2._compat import text_type, string_types, implements_iterator, \ - allocate_lock, url_quote - - -_word_split_re = re.compile(r'(\s+)') -_punctuation_re = re.compile( - '^(?P(?:%s)*)(?P.*?)(?P(?:%s)*)$' % ( - '|'.join(map(re.escape, ('(', '<', '<'))), - '|'.join(map(re.escape, ('.', ',', ')', '>', '\n', '>'))) - ) -) -_simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$') -_striptags_re = re.compile(r'(|<[^>]*>)') -_entity_re = re.compile(r'&([^;]+);') -_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' -_digits = '0123456789' - -# special singleton representing missing values for the runtime -missing = type('MissingType', (), {'__repr__': lambda x: 'missing'})() - -# internal code -internal_code = set() - -concat = u''.join - - -def contextfunction(f): - """This decorator can be used to mark a function or method context callable. - A context callable is passed the active :class:`Context` as first argument when - called from the template. This is useful if a function wants to get access - to the context or functions provided on the context object. For example - a function that returns a sorted list of template variables the current - template exports could look like this:: - - @contextfunction - def get_exported_names(context): - return sorted(context.exported_vars) - """ - f.contextfunction = True - return f - - -def evalcontextfunction(f): - """This decorator can be used to mark a function or method as an eval - context callable. This is similar to the :func:`contextfunction` - but instead of passing the context, an evaluation context object is - passed. For more information about the eval context, see - :ref:`eval-context`. - - .. versionadded:: 2.4 - """ - f.evalcontextfunction = True - return f - - -def environmentfunction(f): - """This decorator can be used to mark a function or method as environment - callable. This decorator works exactly like the :func:`contextfunction` - decorator just that the first argument is the active :class:`Environment` - and not context. - """ - f.environmentfunction = True - return f - - -def internalcode(f): - """Marks the function as internally used""" - internal_code.add(f.__code__) - return f - - -def is_undefined(obj): - """Check if the object passed is undefined. This does nothing more than - performing an instance check against :class:`Undefined` but looks nicer. - This can be used for custom filters or tests that want to react to - undefined variables. For example a custom default filter can look like - this:: - - def default(var, default=''): - if is_undefined(var): - return default - return var - """ - from jinja2.runtime import Undefined - return isinstance(obj, Undefined) - - -def consume(iterable): - """Consumes an iterable without doing anything with it.""" - for event in iterable: - pass - - -def clear_caches(): - """Jinja2 keeps internal caches for environments and lexers. These are - used so that Jinja2 doesn't have to recreate environments and lexers all - the time. Normally you don't have to care about that but if you are - messuring memory consumption you may want to clean the caches. - """ - from jinja2.environment import _spontaneous_environments - from jinja2.lexer import _lexer_cache - _spontaneous_environments.clear() - _lexer_cache.clear() - - -def import_string(import_name, silent=False): - """Imports an object based on a string. This is useful if you want to - use import paths as endpoints or something similar. An import path can - be specified either in dotted notation (``xml.sax.saxutils.escape``) - or with a colon as object delimiter (``xml.sax.saxutils:escape``). - - If the `silent` is True the return value will be `None` if the import - fails. - - :return: imported object - """ - try: - if ':' in import_name: - module, obj = import_name.split(':', 1) - elif '.' in import_name: - items = import_name.split('.') - module = '.'.join(items[:-1]) - obj = items[-1] - else: - return __import__(import_name) - return getattr(__import__(module, None, None, [obj]), obj) - except (ImportError, AttributeError): - if not silent: - raise - - -def open_if_exists(filename, mode='rb'): - """Returns a file descriptor for the filename if that file exists, - otherwise `None`. - """ - try: - return open(filename, mode) - except IOError as e: - if e.errno not in (errno.ENOENT, errno.EISDIR): - raise - - -def object_type_repr(obj): - """Returns the name of the object's type. For some recognized - singletons the name of the object is returned instead. (For - example for `None` and `Ellipsis`). - """ - if obj is None: - return 'None' - elif obj is Ellipsis: - return 'Ellipsis' - # __builtin__ in 2.x, builtins in 3.x - if obj.__class__.__module__ in ('__builtin__', 'builtins'): - name = obj.__class__.__name__ - else: - name = obj.__class__.__module__ + '.' + obj.__class__.__name__ - return '%s object' % name - - -def pformat(obj, verbose=False): - """Prettyprint an object. Either use the `pretty` library or the - builtin `pprint`. - """ - try: - from pretty import pretty - return pretty(obj, verbose=verbose) - except ImportError: - from pprint import pformat - return pformat(obj) - - -def urlize(text, trim_url_limit=None, nofollow=False): - """Converts any URLs in text into clickable links. Works on http://, - https:// and www. links. Links can have trailing punctuation (periods, - commas, close-parens) and leading punctuation (opening parens) and - it'll still do the right thing. - - If trim_url_limit is not None, the URLs in link text will be limited - to trim_url_limit characters. - - If nofollow is True, the URLs in link text will get a rel="nofollow" - attribute. - """ - trim_url = lambda x, limit=trim_url_limit: limit is not None \ - and (x[:limit] + (len(x) >=limit and '...' - or '')) or x - words = _word_split_re.split(text_type(escape(text))) - nofollow_attr = nofollow and ' rel="nofollow"' or '' - for i, word in enumerate(words): - match = _punctuation_re.match(word) - if match: - lead, middle, trail = match.groups() - if middle.startswith('www.') or ( - '@' not in middle and - not middle.startswith('http://') and - not middle.startswith('https://') and - len(middle) > 0 and - middle[0] in _letters + _digits and ( - middle.endswith('.org') or - middle.endswith('.net') or - middle.endswith('.com') - )): - middle = '%s' % (middle, - nofollow_attr, trim_url(middle)) - if middle.startswith('http://') or \ - middle.startswith('https://'): - middle = '%s' % (middle, - nofollow_attr, trim_url(middle)) - if '@' in middle and not middle.startswith('www.') and \ - not ':' in middle and _simple_email_re.match(middle): - middle = '%s' % (middle, middle) - if lead + middle + trail != word: - words[i] = lead + middle + trail - return u''.join(words) - - -def generate_lorem_ipsum(n=5, html=True, min=20, max=100): - """Generate some lorem impsum for the template.""" - from jinja2.constants import LOREM_IPSUM_WORDS - from random import choice, randrange - words = LOREM_IPSUM_WORDS.split() - result = [] - - for _ in range(n): - next_capitalized = True - last_comma = last_fullstop = 0 - word = None - last = None - p = [] - - # each paragraph contains out of 20 to 100 words. - for idx, _ in enumerate(range(randrange(min, max))): - while True: - word = choice(words) - if word != last: - last = word - break - if next_capitalized: - word = word.capitalize() - next_capitalized = False - # add commas - if idx - randrange(3, 8) > last_comma: - last_comma = idx - last_fullstop += 2 - word += ',' - # add end of sentences - if idx - randrange(10, 20) > last_fullstop: - last_comma = last_fullstop = idx - word += '.' - next_capitalized = True - p.append(word) - - # ensure that the paragraph ends with a dot. - p = u' '.join(p) - if p.endswith(','): - p = p[:-1] + '.' - elif not p.endswith('.'): - p += '.' - result.append(p) - - if not html: - return u'\n\n'.join(result) - return Markup(u'\n'.join(u'

%s

' % escape(x) for x in result)) - - -def unicode_urlencode(obj, charset='utf-8'): - """URL escapes a single bytestring or unicode string with the - given charset if applicable to URL safe quoting under all rules - that need to be considered under all supported Python versions. - - If non strings are provided they are converted to their unicode - representation first. - """ - if not isinstance(obj, string_types): - obj = text_type(obj) - if isinstance(obj, text_type): - obj = obj.encode(charset) - return text_type(url_quote(obj)) - - -class LRUCache(object): - """A simple LRU Cache implementation.""" - - # this is fast for small capacities (something below 1000) but doesn't - # scale. But as long as it's only used as storage for templates this - # won't do any harm. - - def __init__(self, capacity): - self.capacity = capacity - self._mapping = {} - self._queue = deque() - self._postinit() - - def _postinit(self): - # alias all queue methods for faster lookup - self._popleft = self._queue.popleft - self._pop = self._queue.pop - self._remove = self._queue.remove - self._wlock = allocate_lock() - self._append = self._queue.append - - def __getstate__(self): - return { - 'capacity': self.capacity, - '_mapping': self._mapping, - '_queue': self._queue - } - - def __setstate__(self, d): - self.__dict__.update(d) - self._postinit() - - def __getnewargs__(self): - return (self.capacity,) - - def copy(self): - """Return a shallow copy of the instance.""" - rv = self.__class__(self.capacity) - rv._mapping.update(self._mapping) - rv._queue = deque(self._queue) - return rv - - def get(self, key, default=None): - """Return an item from the cache dict or `default`""" - try: - return self[key] - except KeyError: - return default - - def setdefault(self, key, default=None): - """Set `default` if the key is not in the cache otherwise - leave unchanged. Return the value of this key. - """ - self._wlock.acquire() - try: - try: - return self[key] - except KeyError: - self[key] = default - return default - finally: - self._wlock.release() - - def clear(self): - """Clear the cache.""" - self._wlock.acquire() - try: - self._mapping.clear() - self._queue.clear() - finally: - self._wlock.release() - - def __contains__(self, key): - """Check if a key exists in this cache.""" - return key in self._mapping - - def __len__(self): - """Return the current size of the cache.""" - return len(self._mapping) - - def __repr__(self): - return '<%s %r>' % ( - self.__class__.__name__, - self._mapping - ) - - def __getitem__(self, key): - """Get an item from the cache. Moves the item up so that it has the - highest priority then. - - Raise a `KeyError` if it does not exist. - """ - self._wlock.acquire() - try: - rv = self._mapping[key] - if self._queue[-1] != key: - try: - self._remove(key) - except ValueError: - # if something removed the key from the container - # when we read, ignore the ValueError that we would - # get otherwise. - pass - self._append(key) - return rv - finally: - self._wlock.release() - - def __setitem__(self, key, value): - """Sets the value for an item. Moves the item up so that it - has the highest priority then. - """ - self._wlock.acquire() - try: - if key in self._mapping: - self._remove(key) - elif len(self._mapping) == self.capacity: - del self._mapping[self._popleft()] - self._append(key) - self._mapping[key] = value - finally: - self._wlock.release() - - def __delitem__(self, key): - """Remove an item from the cache dict. - Raise a `KeyError` if it does not exist. - """ - self._wlock.acquire() - try: - del self._mapping[key] - try: - self._remove(key) - except ValueError: - # __getitem__ is not locked, it might happen - pass - finally: - self._wlock.release() - - def items(self): - """Return a list of items.""" - result = [(key, self._mapping[key]) for key in list(self._queue)] - result.reverse() - return result - - def iteritems(self): - """Iterate over all items.""" - return iter(self.items()) - - def values(self): - """Return a list of all values.""" - return [x[1] for x in self.items()] - - def itervalue(self): - """Iterate over all values.""" - return iter(self.values()) - - def keys(self): - """Return a list of all keys ordered by most recent usage.""" - return list(self) - - def iterkeys(self): - """Iterate over all keys in the cache dict, ordered by - the most recent usage. - """ - return reversed(tuple(self._queue)) - - __iter__ = iterkeys - - def __reversed__(self): - """Iterate over the values in the cache dict, oldest items - coming first. - """ - return iter(tuple(self._queue)) - - __copy__ = copy - - -# register the LRU cache as mutable mapping if possible -try: - from collections import MutableMapping - MutableMapping.register(LRUCache) -except ImportError: - pass - - -@implements_iterator -class Cycler(object): - """A cycle helper for templates.""" - - def __init__(self, *items): - if not items: - raise RuntimeError('at least one item has to be provided') - self.items = items - self.reset() - - def reset(self): - """Resets the cycle.""" - self.pos = 0 - - @property - def current(self): - """Returns the current item.""" - return self.items[self.pos] - - def __next__(self): - """Goes one item ahead and returns it.""" - rv = self.current - self.pos = (self.pos + 1) % len(self.items) - return rv - - -class Joiner(object): - """A joining helper for templates.""" - - def __init__(self, sep=u', '): - self.sep = sep - self.used = False - - def __call__(self): - if not self.used: - self.used = True - return u'' - return self.sep - - -# Imported here because that's where it was in the past -from markupsafe import Markup, escape, soft_unicode diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/visitor.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/visitor.py deleted file mode 100644 index 413e7c30..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/jinja2/visitor.py +++ /dev/null @@ -1,87 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.visitor - ~~~~~~~~~~~~~~ - - This module implements a visitor for the nodes. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD. -""" -from jinja2.nodes import Node - - -class NodeVisitor(object): - """Walks the abstract syntax tree and call visitor functions for every - node found. The visitor functions may return values which will be - forwarded by the `visit` method. - - Per default the visitor functions for the nodes are ``'visit_'`` + - class name of the node. So a `TryFinally` node visit function would - be `visit_TryFinally`. This behavior can be changed by overriding - the `get_visitor` function. If no visitor function exists for a node - (return value `None`) the `generic_visit` visitor is used instead. - """ - - def get_visitor(self, node): - """Return the visitor function for this node or `None` if no visitor - exists for this node. In that case the generic visit function is - used instead. - """ - method = 'visit_' + node.__class__.__name__ - return getattr(self, method, None) - - def visit(self, node, *args, **kwargs): - """Visit a node.""" - f = self.get_visitor(node) - if f is not None: - return f(node, *args, **kwargs) - return self.generic_visit(node, *args, **kwargs) - - def generic_visit(self, node, *args, **kwargs): - """Called if no explicit visitor function exists for a node.""" - for node in node.iter_child_nodes(): - self.visit(node, *args, **kwargs) - - -class NodeTransformer(NodeVisitor): - """Walks the abstract syntax tree and allows modifications of nodes. - - The `NodeTransformer` will walk the AST and use the return value of the - visitor functions to replace or remove the old node. If the return - value of the visitor function is `None` the node will be removed - from the previous location otherwise it's replaced with the return - value. The return value may be the original node in which case no - replacement takes place. - """ - - def generic_visit(self, node, *args, **kwargs): - for field, old_value in node.iter_fields(): - if isinstance(old_value, list): - new_values = [] - for value in old_value: - if isinstance(value, Node): - value = self.visit(value, *args, **kwargs) - if value is None: - continue - elif not isinstance(value, Node): - new_values.extend(value) - continue - new_values.append(value) - old_value[:] = new_values - elif isinstance(old_value, Node): - new_node = self.visit(old_value, *args, **kwargs) - if new_node is None: - delattr(node, field) - else: - setattr(node, field, new_node) - return node - - def visit_list(self, node, *args, **kwargs): - """As transformers may return lists in some places this method - can be used to enforce a list as return value. - """ - rv = self.visit(node, *args, **kwargs) - if not isinstance(rv, list): - rv = [rv] - return rv diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/__init__.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/__init__.py deleted file mode 100644 index 27554015..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/__init__.py +++ /dev/null @@ -1,298 +0,0 @@ -# -*- coding: utf-8 -*- -""" - markupsafe - ~~~~~~~~~~ - - Implements a Markup string. - - :copyright: (c) 2010 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import re -import string -from collections import Mapping -from markupsafe._compat import text_type, string_types, int_types, \ - unichr, iteritems, PY2 - - -__all__ = ['Markup', 'soft_unicode', 'escape', 'escape_silent'] - - -_striptags_re = re.compile(r'(|<[^>]*>)') -_entity_re = re.compile(r'&([^;]+);') - - -class Markup(text_type): - r"""Marks a string as being safe for inclusion in HTML/XML output without - needing to be escaped. This implements the `__html__` interface a couple - of frameworks and web applications use. :class:`Markup` is a direct - subclass of `unicode` and provides all the methods of `unicode` just that - it escapes arguments passed and always returns `Markup`. - - The `escape` function returns markup objects so that double escaping can't - happen. - - The constructor of the :class:`Markup` class can be used for three - different things: When passed an unicode object it's assumed to be safe, - when passed an object with an HTML representation (has an `__html__` - method) that representation is used, otherwise the object passed is - converted into a unicode string and then assumed to be safe: - - >>> Markup("Hello World!") - Markup(u'Hello World!') - >>> class Foo(object): - ... def __html__(self): - ... return 'foo' - ... - >>> Markup(Foo()) - Markup(u'foo') - - If you want object passed being always treated as unsafe you can use the - :meth:`escape` classmethod to create a :class:`Markup` object: - - >>> Markup.escape("Hello World!") - Markup(u'Hello <em>World</em>!') - - Operations on a markup string are markup aware which means that all - arguments are passed through the :func:`escape` function: - - >>> em = Markup("%s") - >>> em % "foo & bar" - Markup(u'foo & bar') - >>> strong = Markup("%(text)s") - >>> strong % {'text': 'hacker here'} - Markup(u'<blink>hacker here</blink>') - >>> Markup("Hello ") + "" - Markup(u'Hello <foo>') - """ - __slots__ = () - - def __new__(cls, base=u'', encoding=None, errors='strict'): - if hasattr(base, '__html__'): - base = base.__html__() - if encoding is None: - return text_type.__new__(cls, base) - return text_type.__new__(cls, base, encoding, errors) - - def __html__(self): - return self - - def __add__(self, other): - if isinstance(other, string_types) or hasattr(other, '__html__'): - return self.__class__(super(Markup, self).__add__(self.escape(other))) - return NotImplemented - - def __radd__(self, other): - if hasattr(other, '__html__') or isinstance(other, string_types): - return self.escape(other).__add__(self) - return NotImplemented - - def __mul__(self, num): - if isinstance(num, int_types): - return self.__class__(text_type.__mul__(self, num)) - return NotImplemented - __rmul__ = __mul__ - - def __mod__(self, arg): - if isinstance(arg, tuple): - arg = tuple(_MarkupEscapeHelper(x, self.escape) for x in arg) - else: - arg = _MarkupEscapeHelper(arg, self.escape) - return self.__class__(text_type.__mod__(self, arg)) - - def __repr__(self): - return '%s(%s)' % ( - self.__class__.__name__, - text_type.__repr__(self) - ) - - def join(self, seq): - return self.__class__(text_type.join(self, map(self.escape, seq))) - join.__doc__ = text_type.join.__doc__ - - def split(self, *args, **kwargs): - return list(map(self.__class__, text_type.split(self, *args, **kwargs))) - split.__doc__ = text_type.split.__doc__ - - def rsplit(self, *args, **kwargs): - return list(map(self.__class__, text_type.rsplit(self, *args, **kwargs))) - rsplit.__doc__ = text_type.rsplit.__doc__ - - def splitlines(self, *args, **kwargs): - return list(map(self.__class__, text_type.splitlines( - self, *args, **kwargs))) - splitlines.__doc__ = text_type.splitlines.__doc__ - - def unescape(self): - r"""Unescape markup again into an text_type string. This also resolves - known HTML4 and XHTML entities: - - >>> Markup("Main » About").unescape() - u'Main \xbb About' - """ - from markupsafe._constants import HTML_ENTITIES - def handle_match(m): - name = m.group(1) - if name in HTML_ENTITIES: - return unichr(HTML_ENTITIES[name]) - try: - if name[:2] in ('#x', '#X'): - return unichr(int(name[2:], 16)) - elif name.startswith('#'): - return unichr(int(name[1:])) - except ValueError: - pass - return u'' - return _entity_re.sub(handle_match, text_type(self)) - - def striptags(self): - r"""Unescape markup into an text_type string and strip all tags. This - also resolves known HTML4 and XHTML entities. Whitespace is - normalized to one: - - >>> Markup("Main » About").striptags() - u'Main \xbb About' - """ - stripped = u' '.join(_striptags_re.sub('', self).split()) - return Markup(stripped).unescape() - - @classmethod - def escape(cls, s): - """Escape the string. Works like :func:`escape` with the difference - that for subclasses of :class:`Markup` this function would return the - correct subclass. - """ - rv = escape(s) - if rv.__class__ is not cls: - return cls(rv) - return rv - - def make_simple_escaping_wrapper(name): - orig = getattr(text_type, name) - def func(self, *args, **kwargs): - args = _escape_argspec(list(args), enumerate(args), self.escape) - _escape_argspec(kwargs, iteritems(kwargs), self.escape) - return self.__class__(orig(self, *args, **kwargs)) - func.__name__ = orig.__name__ - func.__doc__ = orig.__doc__ - return func - - for method in '__getitem__', 'capitalize', \ - 'title', 'lower', 'upper', 'replace', 'ljust', \ - 'rjust', 'lstrip', 'rstrip', 'center', 'strip', \ - 'translate', 'expandtabs', 'swapcase', 'zfill': - locals()[method] = make_simple_escaping_wrapper(method) - - # new in python 2.5 - if hasattr(text_type, 'partition'): - def partition(self, sep): - return tuple(map(self.__class__, - text_type.partition(self, self.escape(sep)))) - def rpartition(self, sep): - return tuple(map(self.__class__, - text_type.rpartition(self, self.escape(sep)))) - - # new in python 2.6 - if hasattr(text_type, 'format'): - def format(*args, **kwargs): - self, args = args[0], args[1:] - formatter = EscapeFormatter(self.escape) - kwargs = _MagicFormatMapping(args, kwargs) - return self.__class__(formatter.vformat(self, args, kwargs)) - - def __html_format__(self, format_spec): - if format_spec: - raise ValueError('Unsupported format specification ' - 'for Markup.') - return self - - # not in python 3 - if hasattr(text_type, '__getslice__'): - __getslice__ = make_simple_escaping_wrapper('__getslice__') - - del method, make_simple_escaping_wrapper - - -class _MagicFormatMapping(Mapping): - """This class implements a dummy wrapper to fix a bug in the Python - standard library for string formatting. - - See http://bugs.python.org/issue13598 for information about why - this is necessary. - """ - - def __init__(self, args, kwargs): - self._args = args - self._kwargs = kwargs - self._last_index = 0 - - def __getitem__(self, key): - if key == '': - idx = self._last_index - self._last_index += 1 - try: - return self._args[idx] - except LookupError: - pass - key = str(idx) - return self._kwargs[key] - - def __iter__(self): - return iter(self._kwargs) - - def __len__(self): - return len(self._kwargs) - - -if hasattr(text_type, 'format'): - class EscapeFormatter(string.Formatter): - - def __init__(self, escape): - self.escape = escape - - def format_field(self, value, format_spec): - if hasattr(value, '__html_format__'): - rv = value.__html_format__(format_spec) - elif hasattr(value, '__html__'): - if format_spec: - raise ValueError('No format specification allowed ' - 'when formatting an object with ' - 'its __html__ method.') - rv = value.__html__() - else: - rv = string.Formatter.format_field(self, value, format_spec) - return text_type(self.escape(rv)) - - -def _escape_argspec(obj, iterable, escape): - """Helper for various string-wrapped functions.""" - for key, value in iterable: - if hasattr(value, '__html__') or isinstance(value, string_types): - obj[key] = escape(value) - return obj - - -class _MarkupEscapeHelper(object): - """Helper for Markup.__mod__""" - - def __init__(self, obj, escape): - self.obj = obj - self.escape = escape - - __getitem__ = lambda s, x: _MarkupEscapeHelper(s.obj[x], s.escape) - __unicode__ = __str__ = lambda s: text_type(s.escape(s.obj)) - __repr__ = lambda s: str(s.escape(repr(s.obj))) - __int__ = lambda s: int(s.obj) - __float__ = lambda s: float(s.obj) - - -# we have to import it down here as the speedups and native -# modules imports the markup type which is define above. -try: - from markupsafe._speedups import escape, escape_silent, soft_unicode -except ImportError: - from markupsafe._native import escape, escape_silent, soft_unicode - -if not PY2: - soft_str = soft_unicode - __all__.append('soft_str') diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_compat.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_compat.py deleted file mode 100644 index 62e5632a..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_compat.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -""" - markupsafe._compat - ~~~~~~~~~~~~~~~~~~ - - Compatibility module for different Python versions. - - :copyright: (c) 2013 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import sys - -PY2 = sys.version_info[0] == 2 - -if not PY2: - text_type = str - string_types = (str,) - unichr = chr - int_types = (int,) - iteritems = lambda x: iter(x.items()) -else: - text_type = unicode - string_types = (str, unicode) - unichr = unichr - int_types = (int, long) - iteritems = lambda x: x.iteritems() diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_constants.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_constants.py deleted file mode 100644 index 919bf03c..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_constants.py +++ /dev/null @@ -1,267 +0,0 @@ -# -*- coding: utf-8 -*- -""" - markupsafe._constants - ~~~~~~~~~~~~~~~~~~~~~ - - Highlevel implementation of the Markup string. - - :copyright: (c) 2010 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" - - -HTML_ENTITIES = { - 'AElig': 198, - 'Aacute': 193, - 'Acirc': 194, - 'Agrave': 192, - 'Alpha': 913, - 'Aring': 197, - 'Atilde': 195, - 'Auml': 196, - 'Beta': 914, - 'Ccedil': 199, - 'Chi': 935, - 'Dagger': 8225, - 'Delta': 916, - 'ETH': 208, - 'Eacute': 201, - 'Ecirc': 202, - 'Egrave': 200, - 'Epsilon': 917, - 'Eta': 919, - 'Euml': 203, - 'Gamma': 915, - 'Iacute': 205, - 'Icirc': 206, - 'Igrave': 204, - 'Iota': 921, - 'Iuml': 207, - 'Kappa': 922, - 'Lambda': 923, - 'Mu': 924, - 'Ntilde': 209, - 'Nu': 925, - 'OElig': 338, - 'Oacute': 211, - 'Ocirc': 212, - 'Ograve': 210, - 'Omega': 937, - 'Omicron': 927, - 'Oslash': 216, - 'Otilde': 213, - 'Ouml': 214, - 'Phi': 934, - 'Pi': 928, - 'Prime': 8243, - 'Psi': 936, - 'Rho': 929, - 'Scaron': 352, - 'Sigma': 931, - 'THORN': 222, - 'Tau': 932, - 'Theta': 920, - 'Uacute': 218, - 'Ucirc': 219, - 'Ugrave': 217, - 'Upsilon': 933, - 'Uuml': 220, - 'Xi': 926, - 'Yacute': 221, - 'Yuml': 376, - 'Zeta': 918, - 'aacute': 225, - 'acirc': 226, - 'acute': 180, - 'aelig': 230, - 'agrave': 224, - 'alefsym': 8501, - 'alpha': 945, - 'amp': 38, - 'and': 8743, - 'ang': 8736, - 'apos': 39, - 'aring': 229, - 'asymp': 8776, - 'atilde': 227, - 'auml': 228, - 'bdquo': 8222, - 'beta': 946, - 'brvbar': 166, - 'bull': 8226, - 'cap': 8745, - 'ccedil': 231, - 'cedil': 184, - 'cent': 162, - 'chi': 967, - 'circ': 710, - 'clubs': 9827, - 'cong': 8773, - 'copy': 169, - 'crarr': 8629, - 'cup': 8746, - 'curren': 164, - 'dArr': 8659, - 'dagger': 8224, - 'darr': 8595, - 'deg': 176, - 'delta': 948, - 'diams': 9830, - 'divide': 247, - 'eacute': 233, - 'ecirc': 234, - 'egrave': 232, - 'empty': 8709, - 'emsp': 8195, - 'ensp': 8194, - 'epsilon': 949, - 'equiv': 8801, - 'eta': 951, - 'eth': 240, - 'euml': 235, - 'euro': 8364, - 'exist': 8707, - 'fnof': 402, - 'forall': 8704, - 'frac12': 189, - 'frac14': 188, - 'frac34': 190, - 'frasl': 8260, - 'gamma': 947, - 'ge': 8805, - 'gt': 62, - 'hArr': 8660, - 'harr': 8596, - 'hearts': 9829, - 'hellip': 8230, - 'iacute': 237, - 'icirc': 238, - 'iexcl': 161, - 'igrave': 236, - 'image': 8465, - 'infin': 8734, - 'int': 8747, - 'iota': 953, - 'iquest': 191, - 'isin': 8712, - 'iuml': 239, - 'kappa': 954, - 'lArr': 8656, - 'lambda': 955, - 'lang': 9001, - 'laquo': 171, - 'larr': 8592, - 'lceil': 8968, - 'ldquo': 8220, - 'le': 8804, - 'lfloor': 8970, - 'lowast': 8727, - 'loz': 9674, - 'lrm': 8206, - 'lsaquo': 8249, - 'lsquo': 8216, - 'lt': 60, - 'macr': 175, - 'mdash': 8212, - 'micro': 181, - 'middot': 183, - 'minus': 8722, - 'mu': 956, - 'nabla': 8711, - 'nbsp': 160, - 'ndash': 8211, - 'ne': 8800, - 'ni': 8715, - 'not': 172, - 'notin': 8713, - 'nsub': 8836, - 'ntilde': 241, - 'nu': 957, - 'oacute': 243, - 'ocirc': 244, - 'oelig': 339, - 'ograve': 242, - 'oline': 8254, - 'omega': 969, - 'omicron': 959, - 'oplus': 8853, - 'or': 8744, - 'ordf': 170, - 'ordm': 186, - 'oslash': 248, - 'otilde': 245, - 'otimes': 8855, - 'ouml': 246, - 'para': 182, - 'part': 8706, - 'permil': 8240, - 'perp': 8869, - 'phi': 966, - 'pi': 960, - 'piv': 982, - 'plusmn': 177, - 'pound': 163, - 'prime': 8242, - 'prod': 8719, - 'prop': 8733, - 'psi': 968, - 'quot': 34, - 'rArr': 8658, - 'radic': 8730, - 'rang': 9002, - 'raquo': 187, - 'rarr': 8594, - 'rceil': 8969, - 'rdquo': 8221, - 'real': 8476, - 'reg': 174, - 'rfloor': 8971, - 'rho': 961, - 'rlm': 8207, - 'rsaquo': 8250, - 'rsquo': 8217, - 'sbquo': 8218, - 'scaron': 353, - 'sdot': 8901, - 'sect': 167, - 'shy': 173, - 'sigma': 963, - 'sigmaf': 962, - 'sim': 8764, - 'spades': 9824, - 'sub': 8834, - 'sube': 8838, - 'sum': 8721, - 'sup': 8835, - 'sup1': 185, - 'sup2': 178, - 'sup3': 179, - 'supe': 8839, - 'szlig': 223, - 'tau': 964, - 'there4': 8756, - 'theta': 952, - 'thetasym': 977, - 'thinsp': 8201, - 'thorn': 254, - 'tilde': 732, - 'times': 215, - 'trade': 8482, - 'uArr': 8657, - 'uacute': 250, - 'uarr': 8593, - 'ucirc': 251, - 'ugrave': 249, - 'uml': 168, - 'upsih': 978, - 'upsilon': 965, - 'uuml': 252, - 'weierp': 8472, - 'xi': 958, - 'yacute': 253, - 'yen': 165, - 'yuml': 255, - 'zeta': 950, - 'zwj': 8205, - 'zwnj': 8204 -} diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_native.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_native.py deleted file mode 100644 index 5e83f10a..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_native.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: utf-8 -*- -""" - markupsafe._native - ~~~~~~~~~~~~~~~~~~ - - Native Python implementation the C module is not compiled. - - :copyright: (c) 2010 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -from markupsafe import Markup -from markupsafe._compat import text_type - - -def escape(s): - """Convert the characters &, <, >, ' and " in string s to HTML-safe - sequences. Use this if you need to display text that might contain - such characters in HTML. Marks return value as markup string. - """ - if hasattr(s, '__html__'): - return s.__html__() - return Markup(text_type(s) - .replace('&', '&') - .replace('>', '>') - .replace('<', '<') - .replace("'", ''') - .replace('"', '"') - ) - - -def escape_silent(s): - """Like :func:`escape` but converts `None` into an empty - markup string. - """ - if s is None: - return Markup() - return escape(s) - - -def soft_unicode(s): - """Make a string unicode if it isn't already. That way a markup - string is not converted back to unicode. - """ - if not isinstance(s, text_type): - s = text_type(s) - return s diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_speedups.c b/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_speedups.c deleted file mode 100644 index f349febf..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/_speedups.c +++ /dev/null @@ -1,239 +0,0 @@ -/** - * markupsafe._speedups - * ~~~~~~~~~~~~~~~~~~~~ - * - * This module implements functions for automatic escaping in C for better - * performance. - * - * :copyright: (c) 2010 by Armin Ronacher. - * :license: BSD. - */ - -#include - -#define ESCAPED_CHARS_TABLE_SIZE 63 -#define UNICHR(x) (PyUnicode_AS_UNICODE((PyUnicodeObject*)PyUnicode_DecodeASCII(x, strlen(x), NULL))); - -#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) -typedef int Py_ssize_t; -#define PY_SSIZE_T_MAX INT_MAX -#define PY_SSIZE_T_MIN INT_MIN -#endif - - -static PyObject* markup; -static Py_ssize_t escaped_chars_delta_len[ESCAPED_CHARS_TABLE_SIZE]; -static Py_UNICODE *escaped_chars_repl[ESCAPED_CHARS_TABLE_SIZE]; - -static int -init_constants(void) -{ - PyObject *module; - /* happing of characters to replace */ - escaped_chars_repl['"'] = UNICHR("""); - escaped_chars_repl['\''] = UNICHR("'"); - escaped_chars_repl['&'] = UNICHR("&"); - escaped_chars_repl['<'] = UNICHR("<"); - escaped_chars_repl['>'] = UNICHR(">"); - - /* lengths of those characters when replaced - 1 */ - memset(escaped_chars_delta_len, 0, sizeof (escaped_chars_delta_len)); - escaped_chars_delta_len['"'] = escaped_chars_delta_len['\''] = \ - escaped_chars_delta_len['&'] = 4; - escaped_chars_delta_len['<'] = escaped_chars_delta_len['>'] = 3; - - /* import markup type so that we can mark the return value */ - module = PyImport_ImportModule("markupsafe"); - if (!module) - return 0; - markup = PyObject_GetAttrString(module, "Markup"); - Py_DECREF(module); - - return 1; -} - -static PyObject* -escape_unicode(PyUnicodeObject *in) -{ - PyUnicodeObject *out; - Py_UNICODE *inp = PyUnicode_AS_UNICODE(in); - const Py_UNICODE *inp_end = PyUnicode_AS_UNICODE(in) + PyUnicode_GET_SIZE(in); - Py_UNICODE *next_escp; - Py_UNICODE *outp; - Py_ssize_t delta=0, erepl=0, delta_len=0; - - /* First we need to figure out how long the escaped string will be */ - while (*(inp) || inp < inp_end) { - if (*inp < ESCAPED_CHARS_TABLE_SIZE) { - delta += escaped_chars_delta_len[*inp]; - erepl += !!escaped_chars_delta_len[*inp]; - } - ++inp; - } - - /* Do we need to escape anything at all? */ - if (!erepl) { - Py_INCREF(in); - return (PyObject*)in; - } - - out = (PyUnicodeObject*)PyUnicode_FromUnicode(NULL, PyUnicode_GET_SIZE(in) + delta); - if (!out) - return NULL; - - outp = PyUnicode_AS_UNICODE(out); - inp = PyUnicode_AS_UNICODE(in); - while (erepl-- > 0) { - /* look for the next substitution */ - next_escp = inp; - while (next_escp < inp_end) { - if (*next_escp < ESCAPED_CHARS_TABLE_SIZE && - (delta_len = escaped_chars_delta_len[*next_escp])) { - ++delta_len; - break; - } - ++next_escp; - } - - if (next_escp > inp) { - /* copy unescaped chars between inp and next_escp */ - Py_UNICODE_COPY(outp, inp, next_escp-inp); - outp += next_escp - inp; - } - - /* escape 'next_escp' */ - Py_UNICODE_COPY(outp, escaped_chars_repl[*next_escp], delta_len); - outp += delta_len; - - inp = next_escp + 1; - } - if (inp < inp_end) - Py_UNICODE_COPY(outp, inp, PyUnicode_GET_SIZE(in) - (inp - PyUnicode_AS_UNICODE(in))); - - return (PyObject*)out; -} - - -static PyObject* -escape(PyObject *self, PyObject *text) -{ - PyObject *s = NULL, *rv = NULL, *html; - - /* we don't have to escape integers, bools or floats */ - if (PyLong_CheckExact(text) || -#if PY_MAJOR_VERSION < 3 - PyInt_CheckExact(text) || -#endif - PyFloat_CheckExact(text) || PyBool_Check(text) || - text == Py_None) - return PyObject_CallFunctionObjArgs(markup, text, NULL); - - /* if the object has an __html__ method that performs the escaping */ - html = PyObject_GetAttrString(text, "__html__"); - if (html) { - rv = PyObject_CallObject(html, NULL); - Py_DECREF(html); - return rv; - } - - /* otherwise make the object unicode if it isn't, then escape */ - PyErr_Clear(); - if (!PyUnicode_Check(text)) { -#if PY_MAJOR_VERSION < 3 - PyObject *unicode = PyObject_Unicode(text); -#else - PyObject *unicode = PyObject_Str(text); -#endif - if (!unicode) - return NULL; - s = escape_unicode((PyUnicodeObject*)unicode); - Py_DECREF(unicode); - } - else - s = escape_unicode((PyUnicodeObject*)text); - - /* convert the unicode string into a markup object. */ - rv = PyObject_CallFunctionObjArgs(markup, (PyObject*)s, NULL); - Py_DECREF(s); - return rv; -} - - -static PyObject* -escape_silent(PyObject *self, PyObject *text) -{ - if (text != Py_None) - return escape(self, text); - return PyObject_CallFunctionObjArgs(markup, NULL); -} - - -static PyObject* -soft_unicode(PyObject *self, PyObject *s) -{ - if (!PyUnicode_Check(s)) -#if PY_MAJOR_VERSION < 3 - return PyObject_Unicode(s); -#else - return PyObject_Str(s); -#endif - Py_INCREF(s); - return s; -} - - -static PyMethodDef module_methods[] = { - {"escape", (PyCFunction)escape, METH_O, - "escape(s) -> markup\n\n" - "Convert the characters &, <, >, ', and \" in string s to HTML-safe\n" - "sequences. Use this if you need to display text that might contain\n" - "such characters in HTML. Marks return value as markup string."}, - {"escape_silent", (PyCFunction)escape_silent, METH_O, - "escape_silent(s) -> markup\n\n" - "Like escape but converts None to an empty string."}, - {"soft_unicode", (PyCFunction)soft_unicode, METH_O, - "soft_unicode(object) -> string\n\n" - "Make a string unicode if it isn't already. That way a markup\n" - "string is not converted back to unicode."}, - {NULL, NULL, 0, NULL} /* Sentinel */ -}; - - -#if PY_MAJOR_VERSION < 3 - -#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ -#define PyMODINIT_FUNC void -#endif -PyMODINIT_FUNC -init_speedups(void) -{ - if (!init_constants()) - return; - - Py_InitModule3("markupsafe._speedups", module_methods, ""); -} - -#else /* Python 3.x module initialization */ - -static struct PyModuleDef module_definition = { - PyModuleDef_HEAD_INIT, - "markupsafe._speedups", - NULL, - -1, - module_methods, - NULL, - NULL, - NULL, - NULL -}; - -PyMODINIT_FUNC -PyInit__speedups(void) -{ - if (!init_constants()) - return NULL; - - return PyModule_Create(&module_definition); -} - -#endif diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/tests.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/tests.py deleted file mode 100644 index 63699362..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/markupsafe/tests.py +++ /dev/null @@ -1,179 +0,0 @@ -# -*- coding: utf-8 -*- -import gc -import sys -import unittest -from markupsafe import Markup, escape, escape_silent -from markupsafe._compat import text_type - - -class MarkupTestCase(unittest.TestCase): - - def test_adding(self): - # adding two strings should escape the unsafe one - unsafe = '' - safe = Markup('username') - assert unsafe + safe == text_type(escape(unsafe)) + text_type(safe) - - def test_string_interpolation(self): - # string interpolations are safe to use too - assert Markup('%s') % '' == \ - '<bad user>' - assert Markup('%(username)s') % { - 'username': '' - } == '<bad user>' - - assert Markup('%i') % 3.14 == '3' - assert Markup('%.2f') % 3.14 == '3.14' - - def test_type_behavior(self): - # an escaped object is markup too - assert type(Markup('foo') + 'bar') is Markup - - # and it implements __html__ by returning itself - x = Markup("foo") - assert x.__html__() is x - - def test_html_interop(self): - # it also knows how to treat __html__ objects - class Foo(object): - def __html__(self): - return 'awesome' - def __unicode__(self): - return 'awesome' - __str__ = __unicode__ - assert Markup(Foo()) == 'awesome' - assert Markup('%s') % Foo() == \ - 'awesome' - - def test_tuple_interpol(self): - self.assertEqual(Markup('%s:%s') % ( - '', - '', - ), Markup(u'<foo>:<bar>')) - - def test_dict_interpol(self): - self.assertEqual(Markup('%(foo)s') % { - 'foo': '', - }, Markup(u'<foo>')) - self.assertEqual(Markup('%(foo)s:%(bar)s') % { - 'foo': '', - 'bar': '', - }, Markup(u'<foo>:<bar>')) - - def test_escaping(self): - # escaping and unescaping - assert escape('"<>&\'') == '"<>&'' - assert Markup("Foo & Bar").striptags() == "Foo & Bar" - assert Markup("<test>").unescape() == "" - - def test_formatting(self): - for actual, expected in ( - (Markup('%i') % 3.14, '3'), - (Markup('%.2f') % 3.14159, '3.14'), - (Markup('%s %s %s') % ('<', 123, '>'), '< 123 >'), - (Markup('{awesome}').format(awesome=''), - '<awesome>'), - (Markup('{0[1][bar]}').format([0, {'bar': ''}]), - '<bar/>'), - (Markup('{0[1][bar]}').format([0, {'bar': Markup('')}]), - '')): - assert actual == expected, "%r should be %r!" % (actual, expected) - - # This is new in 2.7 - if sys.version_info >= (2, 7): - def test_formatting_empty(self): - formatted = Markup('{}').format(0) - assert formatted == Markup('0') - - def test_custom_formatting(self): - class HasHTMLOnly(object): - def __html__(self): - return Markup('') - - class HasHTMLAndFormat(object): - def __html__(self): - return Markup('') - def __html_format__(self, spec): - return Markup('') - - assert Markup('{0}').format(HasHTMLOnly()) == Markup('') - assert Markup('{0}').format(HasHTMLAndFormat()) == Markup('') - - def test_complex_custom_formatting(self): - class User(object): - def __init__(self, id, username): - self.id = id - self.username = username - def __html_format__(self, format_spec): - if format_spec == 'link': - return Markup('{1}').format( - self.id, - self.__html__(), - ) - elif format_spec: - raise ValueError('Invalid format spec') - return self.__html__() - def __html__(self): - return Markup('{0}').format(self.username) - - user = User(1, 'foo') - assert Markup('

User: {0:link}').format(user) == \ - Markup('

User: foo') - - def test_all_set(self): - import markupsafe as markup - for item in markup.__all__: - getattr(markup, item) - - def test_escape_silent(self): - assert escape_silent(None) == Markup() - assert escape(None) == Markup(None) - assert escape_silent('') == Markup(u'<foo>') - - def test_splitting(self): - self.assertEqual(Markup('a b').split(), [ - Markup('a'), - Markup('b') - ]) - self.assertEqual(Markup('a b').rsplit(), [ - Markup('a'), - Markup('b') - ]) - self.assertEqual(Markup('a\nb').splitlines(), [ - Markup('a'), - Markup('b') - ]) - - def test_mul(self): - self.assertEqual(Markup('a') * 3, Markup('aaa')) - - -class MarkupLeakTestCase(unittest.TestCase): - - def test_markup_leaks(self): - counts = set() - for count in range(20): - for item in range(1000): - escape("foo") - escape("") - escape(u"foo") - escape(u"") - counts.add(len(gc.get_objects())) - assert len(counts) == 1, 'ouch, c extension seems to leak objects' - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(MarkupTestCase)) - - # this test only tests the c extension - if not hasattr(escape, 'func_code'): - suite.addTest(unittest.makeSuite(MarkupLeakTestCase)) - - return suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') - -# vim:sts=4:sw=4:et: diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/DESCRIPTION.rst b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/DESCRIPTION.rst deleted file mode 100644 index 2e2d679f..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/DESCRIPTION.rst +++ /dev/null @@ -1,71 +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. - -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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/METADATA b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/METADATA deleted file mode 100644 index 12ecc519..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/METADATA +++ /dev/null @@ -1,98 +0,0 @@ -Metadata-Version: 2.0 -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 -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 -Provides-Extra: testing -Requires-Dist: pytest; extra == 'testing' -Requires-Dist: virtualenv (>=1.10); extra == 'testing' -Requires-Dist: scripttest (>=1.3); extra == 'testing' -Requires-Dist: mock; extra == 'testing' - - -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/ - - diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/RECORD b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/RECORD deleted file mode 100644 index 347a3d18..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/RECORD +++ /dev/null @@ -1,374 +0,0 @@ -pip/__init__.py,sha256=j6Zp28eSA6gvpf2Vm7gb4ybz5Y_OKfXxY3a146aRH6g,9450 -pip/__main__.py,sha256=9JBJhprGRLUy1fEvAdufs0tsjKFAvFAY_nTde6GDkHk,116 -pip/basecommand.py,sha256=N_nE7BCcoMA7t2nRNTiJB8T__1XqI74SJI2G72VaM2E,6578 -pip/baseparser.py,sha256=DZKWTOA1OeD5mLyBUx183Jx-M16cqWOXPZZuJN4-4j8,8162 -pip/cmdoptions.py,sha256=C0JuSfhGIgrp2hMoVDYVPekPlPiG0wIFcIIFDbrsatg,9507 -pip/download.py,sha256=jnZvTGYutxPtgJvF0URMnsBGkTABNrfgFevu5QmscfE,22580 -pip/exceptions.py,sha256=wAoboA4PdhGN7xH-ayf_dcDFPYZe9XAivAlZJbOgCN4,1086 -pip/index.py,sha256=CLPb0crVhOQ3aZpl4feUKpf1pVR6qLhBiJTa71PoIkM,40403 -pip/locations.py,sha256=YyFyCLYADKgT5x-Ctj_LeZl5bEzkbBXuR2Iv8IbVqDA,6202 -pip/log.py,sha256=1fW7cVRIRBhfqWz4JH2HhJRHzVQ4PJTRbolRj3S33f8,9455 -pip/pep425tags.py,sha256=jb5Rq395Gz_Uv8kn3L9Im1HX7EhEj8nqyYX0nXulzWo,2969 -pip/req.py,sha256=DMGDl2N30fmLzh4VzhqQyix-bifSRKNhp2c_OS_gza8,83557 -pip/runner.py,sha256=VkcZKNikprpDOSl2Y3m0FaQbdGuYsoHkxdhjtL0N3oA,431 -pip/status_codes.py,sha256=sEFHUaUJbqv8iArL3HAtcztWZmGOFX01hTesSytDEh0,116 -pip/util.py,sha256=GTnXa80tWauVlIvSQiYeNw12ly5X4hMPmDbRVQ79hwk,24172 -pip/wheel.py,sha256=PwTueHq1c30KvZF3-0wlTTUiR8hxBpE3THxN1bc0eS8,20618 -pip/_vendor/__init__.py,sha256=f-xO4dF7jRP89yrL4h26_nULYgYTzgnTgUFlkDasJrc,266 -pip/_vendor/pkg_resources.py,sha256=0y2CkvxQcHCBVOmTCNvdMN8hTPPUogThjhkCxegggII,100025 -pip/_vendor/re-vendor.py,sha256=PcdZ40d0ohMsdJmA4t0AeAWbPXi1tFsvAwA5KE5FGeY,773 -pip/_vendor/six.py,sha256=whAS1kvmixxh-pKqb5qQ05-fHMnGjuKyU6m7_wa09O4,23462 -pip/_vendor/_markerlib/__init__.py,sha256=2hgtRuYDOrimZF9-ENCkrP8gnJ59HZEtlk-zoTEvn1Y,564 -pip/_vendor/_markerlib/markers.py,sha256=YuFp0-osufFIoqnzG3L0Z2fDCx4Vln3VUDeXJ2DA_1I,3979 -pip/_vendor/colorama/__init__.py,sha256=eABG0aR8L-8JfIiftmvixrDZvqHawB7KIIxiRdKsi1k,217 -pip/_vendor/colorama/ansi.py,sha256=spKO9jqXAB9POAj6M3bZLrdCf-W9wUVeDCqF664WSGs,1039 -pip/_vendor/colorama/ansitowin32.py,sha256=C0mA80tFRvkdHVTHzvyrCzsI0CNQ1gY9ng6deCxkbGY,6664 -pip/_vendor/colorama/initialise.py,sha256=sL44vQFKG5BAoFgoIxfhH0wG2NnLBw9mtnWFVtXkHGs,1297 -pip/_vendor/colorama/win32.py,sha256=tMAHgaTSySAt5BI5hBoID6oshHIYnJBlUqDsOoHbV0w,4911 -pip/_vendor/colorama/winterm.py,sha256=RhWJPcGA_T1knfS-84AXpQ0C7cn8XWE6iQkqy1GPsmk,4206 -pip/_vendor/distlib/__init__.py,sha256=kTBiZ-2Ndb1k7wb8yCvl7iRBCDTnvaOR15qf32RgvsY,581 -pip/_vendor/distlib/compat.py,sha256=pVILHBDu1P72lO1lEgPFpwRWGs4Cj2-eo_xOPLKjprk,38875 -pip/_vendor/distlib/database.py,sha256=reYrKl6tqHs3eOrMrdXX4W0OGlBqathuqSzCy-696MI,49138 -pip/_vendor/distlib/index.py,sha256=D-Zz8pQ6Gtr4t7HlFebU36P9inMPSfExmit061S8DUk,19476 -pip/_vendor/distlib/locators.py,sha256=Vi88LbYqF981rmCc8dbD9qnmt5MeJzv7qiAlvgrK3vs,46946 -pip/_vendor/distlib/manifest.py,sha256=I-JG2bVBN3Zmf4gpt9MFjgsukcIt0rMrz95jQ1kwbgE,13497 -pip/_vendor/distlib/markers.py,sha256=iRrVWwpyVwjkKJSX8NEQ92_MRMwpROcfNGKCD-Ch1QM,6282 -pip/_vendor/distlib/metadata.py,sha256=IS0Q8hNbQWEhaLtItUlLxYC3j9zVtFD76DgXbHxcRZE,36815 -pip/_vendor/distlib/resources.py,sha256=H9QmD7R_8t-iLxZne9EnjAHAdSEbJ22PYotEppOGxts,9432 -pip/_vendor/distlib/scripts.py,sha256=0bIHpJFwyvymJ4CEnm1-x3AcJZbYTEkhBAKuas295Ic,12307 -pip/_vendor/distlib/t32.exe,sha256=snr0x6iR5Yd7ZndiuvGMuuQGg8VklUc5538uQcOeVYQ,91136 -pip/_vendor/distlib/t64.exe,sha256=71TYxgPfviERRKhyYaXPx2pl4o4ugs5zNWuIMLlm7ss,94720 -pip/_vendor/distlib/util.py,sha256=UBy5ki-nyb0nJyM_-TlXSfni_cEOI4r6LzglMMB_1zc,51230 -pip/_vendor/distlib/version.py,sha256=FgTBNWH7dDY12fqTFy6nATw21wV8kKJw5G19aFouwDE,22996 -pip/_vendor/distlib/w32.exe,sha256=QoyveFPxLH-db4j2YDzb-VmP7DmGT1vHwPOLGpzc3uw,87040 -pip/_vendor/distlib/w64.exe,sha256=haGpLW73-UaPHkjhKaQVPTBJCZ9Lg1rMBZdhpi7f_V8,91648 -pip/_vendor/distlib/wheel.py,sha256=TUMl4Pzri_jglkvr2jZ4GJfWAumG3VNzT2CaW7oBXQQ,38259 -pip/_vendor/distlib/_backport/__init__.py,sha256=bqS_dTOH6uW9iGgd0uzfpPjo6vZ4xpPZ7kyfZJ2vNaw,274 -pip/_vendor/distlib/_backport/misc.py,sha256=KWecINdbFNOxSOP1fGF680CJnaC6S4fBRgEtaYTw0ig,971 -pip/_vendor/distlib/_backport/shutil.py,sha256=AUi8718iRoJ9K26mRi-rywtt8Gx7ykvrvbUbZszjfYE,25650 -pip/_vendor/distlib/_backport/sysconfig.cfg,sha256=swZKxq9RY5e9r3PXCrlvQPMsvOdiWZBTHLEbqS8LJLU,2617 -pip/_vendor/distlib/_backport/sysconfig.py,sha256=7WdYP0wbw8izH1eAEGNA-HXUyJrhzIAGK_LniUs4UNI,26958 -pip/_vendor/distlib/_backport/tarfile.py,sha256=bjyTNONZb-YEXrHFLExOSuagtSOoPaONP2UUoxwkAqE,92627 -pip/_vendor/html5lib/__init__.py,sha256=6fwIe3NEcpx7aLb1bBXUpsDgJFE9PnbpRADB7i2QhBw,714 -pip/_vendor/html5lib/constants.py,sha256=w_Lrxu8h6qE4KATYy0SL5hiJ5ebuB28SlCcdXUHf6to,87346 -pip/_vendor/html5lib/html5parser.py,sha256=qMHEOEahKSZzLHHkqLRVbuIJYgAteVR-nmkjMp59Tvw,117029 -pip/_vendor/html5lib/ihatexml.py,sha256=MT12cVXAKaW-ALUkUeN175HpUP73xK8wAIpPzQ8cgfI,16581 -pip/_vendor/html5lib/inputstream.py,sha256=qa-xwqbm-w250UR-uVzooXPSHFI4Ho6drLhPl7VWvHI,30636 -pip/_vendor/html5lib/sanitizer.py,sha256=sg7g5CXF9tfvykIoSVAvA8647MgScy3ncZC7IYH-8SA,16428 -pip/_vendor/html5lib/tokenizer.py,sha256=6Uf8sDUkvNn661bcBSBYUCTfXzSs9EyCTiPcj5PAjYI,76929 -pip/_vendor/html5lib/utils.py,sha256=T-BFeUVGJDjVCRbNoqar2qxn8jEoCOOJXE1nH0nDHEQ,2545 -pip/_vendor/html5lib/filters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -pip/_vendor/html5lib/filters/_base.py,sha256=z-IU9ZAYjpsVsqmVt7kuWC63jR11hDMr6CVrvuao8W0,286 -pip/_vendor/html5lib/filters/alphabeticalattributes.py,sha256=fpRLbz6TCe5yXEkGmyMlJ80FekWsTR-sHk3Ano0U9LQ,624 -pip/_vendor/html5lib/filters/inject_meta_charset.py,sha256=xllv1I7unxhcyZTf3LTsv30wh2mAkT7wmTZx7zIhpuY,2746 -pip/_vendor/html5lib/filters/lint.py,sha256=6rlGRUTxD5KWwEVoXVHI_PeyUHN6Vw2v_ovg0YiHsDA,4306 -pip/_vendor/html5lib/filters/optionaltags.py,sha256=4ozLwBgMRaxe7iqxefLQpDhp3irK7YHo9LgSGsvZYMw,10500 -pip/_vendor/html5lib/filters/sanitizer.py,sha256=MvGUs_v2taWPgGhjxswRSUiHfxrqMUhsNPz-eSeUYUQ,352 -pip/_vendor/html5lib/filters/whitespace.py,sha256=LbOUcC0zQ9z703KNZrArOr0kVBO7OMXjKjucDW32LU4,1142 -pip/_vendor/html5lib/serializer/__init__.py,sha256=xFXFP-inaTNlbnau5c5DGrH_O8yPm-C6HWbJxpiSqFE,490 -pip/_vendor/html5lib/serializer/htmlserializer.py,sha256=bSXUuFJB6s-ODOl0nzFN0UA6xlQRU-BwYamPeJvsNSE,12909 -pip/_vendor/html5lib/treeadapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -pip/_vendor/html5lib/treeadapters/sax.py,sha256=3of4vvaUYIAic7pngebwJV24hpOS7Zg9ggJa_WQegy4,1661 -pip/_vendor/html5lib/treebuilders/__init__.py,sha256=Xz4X6B5DA1R-5GyRa44j0sJwfl6dUNyb0NBu9-7sK3U,3405 -pip/_vendor/html5lib/treebuilders/_base.py,sha256=Xf0FZVcVwIQS6tEseJdj5wKbYucbNCnbAsnsG4lONis,13711 -pip/_vendor/html5lib/treebuilders/dom.py,sha256=ylkIlwEV2NsIWBpwEtfqF0LVoCGg4oXazEWs4-486jk,8469 -pip/_vendor/html5lib/treebuilders/etree.py,sha256=etbO6yQlyV46rWlj9mSyVqQOWrgoHgyJ01Tut4lWZkk,12621 -pip/_vendor/html5lib/treebuilders/etree_lxml.py,sha256=z3Bnfm2MstEEb_lbaAeicl5l-ab6MSQa5Q1ZZreK7Pc,14031 -pip/_vendor/html5lib/treewalkers/__init__.py,sha256=44g-xYZEoYxzkMu6CepBTLm4m-g9iy7Vm_IG8PWAbhY,2323 -pip/_vendor/html5lib/treewalkers/_base.py,sha256=hnL6zMgGJoGqEJYKVKveDmfpz1d2xriyuuau6479xq4,6919 -pip/_vendor/html5lib/treewalkers/dom.py,sha256=mAg05wBWN2k-CGPoo0KNxa55QAlHciNccp8AezCa8j8,1457 -pip/_vendor/html5lib/treewalkers/etree.py,sha256=waFU6dxcV5y4SEMyxZpQ9M4I5pKpMmCtUSN1GbuCVcE,4625 -pip/_vendor/html5lib/treewalkers/genshistream.py,sha256=IbBFrlgi-59-K7P1zm0d7ZFIknBN4c5E57PHJDkx39s,2278 -pip/_vendor/html5lib/treewalkers/lxmletree.py,sha256=vWfXWK3GOSrq2trQm2aPmIRWPhVuYDZ3g9Fu8hUeBQg,6215 -pip/_vendor/html5lib/treewalkers/pulldom.py,sha256=9W6i8yWtUzayV6EwX-okVacttHaqpQZwdBCc2S3XeQ4,2302 -pip/_vendor/html5lib/trie/__init__.py,sha256=mec5zyJ5wIKRM8819gIcIsYQwncg91rEmPwGH1dG3Ho,212 -pip/_vendor/html5lib/trie/_base.py,sha256=WGY8SGptFmx4O0aKLJ54zrIQOoyuvhS0ngA36vAcIcc,927 -pip/_vendor/html5lib/trie/datrie.py,sha256=EQpqSfkZRuTbE-DuhW7xMdVDxdZNZ0CfmnYfHA_3zxM,1178 -pip/_vendor/html5lib/trie/py.py,sha256=wXmQLrZRf4MyWNyg0m3h81m9InhLR7GJ002mIIZh-8o,1775 -pip/_vendor/requests/__init__.py,sha256=Rl423kV-MBTFDiTtEOJiP9CuaubFSi8rHaqzq1KBN0w,1856 -pip/_vendor/requests/adapters.py,sha256=fp4t_woMNJPv8vikcrLbkkDxhJHJMZ3h8MlgtKvpuE8,14608 -pip/_vendor/requests/api.py,sha256=4xrabBN80yaqHxsomHVQD09v2VndgCz1cSsEnRvGGL0,4344 -pip/_vendor/requests/auth.py,sha256=x2bFqHK3Lkbm7qPUyh_dAqYLTDTotBi-1za9EpCdA0U,6123 -pip/_vendor/requests/cacert.pem,sha256=ak7q_q8ozHdQ9ff27U-E1vCNrLisFRQSMy9zJkdpQlM,308434 -pip/_vendor/requests/certs.py,sha256=wSaqhSNoB0igp6Da-hWw0jtXICKXBbL8aS9swthlt50,544 -pip/_vendor/requests/compat.py,sha256=JGrJPV2YGatzwrexl9kSt8Z8QtmFboRZH9ywsLK_MMA,2556 -pip/_vendor/requests/cookies.py,sha256=BjMKtrI8TXQD5oQVeToYtkRBF149eI85UhWsBGwsJac,16686 -pip/_vendor/requests/exceptions.py,sha256=z-3QpicafKtIh85bMEaClL2OpNPdsc6TP_83KcsVh8Y,1877 -pip/_vendor/requests/hooks.py,sha256=9vNiuiRHRd5Qy6BX_0p1H3NsUzDo1M_HaFR2AFL41Tg,820 -pip/_vendor/requests/models.py,sha256=OYZOkemxZPpeTp5cvhdx-gAnl9bW82wdnGIr4uoVH20,26436 -pip/_vendor/requests/sessions.py,sha256=kwPPNj1M3D6yfHPcygUERvfqWaSx8odBijhqKTqRX_Q,22290 -pip/_vendor/requests/status_codes.py,sha256=LYpqLv4AEKuTPby-QSvgl_gI7fcVlUDqSBcndIwX-Qg,3136 -pip/_vendor/requests/structures.py,sha256=d7f7ZXZZzgZtvrBQBZA1boJYX_QlP1YqL-_xtpzImGw,3541 -pip/_vendor/requests/utils.py,sha256=MxSUha_2szwhfLKmGg5bolxt6lA6OghSvVZ4xMZwQhM,19973 -pip/_vendor/requests/packages/__init__.py,sha256=aXkbNCjM_WhryRBocE4AaA_p7-CTxL5LOutY7XzKm4s,62 -pip/_vendor/requests/packages/chardet/__init__.py,sha256=8-39Dg2qEuod5DNN7RMdn2ZYOO9zFU3fFfaE80iDWGc,1295 -pip/_vendor/requests/packages/chardet/big5freq.py,sha256=D8oTdz-GM7Jg8TsaWJDm65vM_OLHC3xub6qUJ3rOgsQ,82594 -pip/_vendor/requests/packages/chardet/big5prober.py,sha256=XX96C--6WKYW36mL-z7pJSAtc169Z8ZImByCP4pEN9A,1684 -pip/_vendor/requests/packages/chardet/chardetect.py,sha256=8g-dRSA97bSE6M25Tqe1roKKtl3XHSMnqi6vTzpHNV0,1141 -pip/_vendor/requests/packages/chardet/chardistribution.py,sha256=cUARQFr1oTLXeJCDQrDRkUP778AvSMzhSCnG8VLCV58,9226 -pip/_vendor/requests/packages/chardet/charsetgroupprober.py,sha256=0lKk7VE516fgMw119tNefFqLOxKfIE9WfdkpIT69OKU,3791 -pip/_vendor/requests/packages/chardet/charsetprober.py,sha256=Z48o2KiOj23FNqYH8FqzhH5m1qdm3rI8DcTm2Yqtklg,1902 -pip/_vendor/requests/packages/chardet/codingstatemachine.py,sha256=E85rYhHVMw9xDEJVgiQhp0OnLGr6i2r8_7QOWMKTH08,2318 -pip/_vendor/requests/packages/chardet/compat.py,sha256=5mm6yrHwef1JEG5OxkPJlSq5lkjLVpEGh3iPgFBkpkM,1157 -pip/_vendor/requests/packages/chardet/constants.py,sha256=-UnY8U7EP7z9fTyd09yq35BEkSFEAUAiv9ohd1DW1s4,1335 -pip/_vendor/requests/packages/chardet/cp949prober.py,sha256=FMvdLyB7fejPXRsTbca7LK1P3RUvvssmjUNyaEfz8zY,1782 -pip/_vendor/requests/packages/chardet/escprober.py,sha256=q5TcQKeVq31WxrW7Sv8yjpZkjEoaHO8S92EJZ9hodys,3187 -pip/_vendor/requests/packages/chardet/escsm.py,sha256=7iljEKN8lXTh8JFXPUSwlibMno6R6ksq4evLxbkzfro,7839 -pip/_vendor/requests/packages/chardet/eucjpprober.py,sha256=5IpfSEjAb7h3hcGMd6dkU80O900C2N6xku28rdYFKuc,3678 -pip/_vendor/requests/packages/chardet/euckrfreq.py,sha256=T5saK5mImySG5ygQPtsp6o2uKulouCwYm2ElOyFkJqU,45978 -pip/_vendor/requests/packages/chardet/euckrprober.py,sha256=Wo7dnZ5Erw_nB4H-m5alMiOxOuJUmGHlwCSaGqExDZA,1675 -pip/_vendor/requests/packages/chardet/euctwfreq.py,sha256=G_I0BW9i1w0ONeeUwIYqV7_U09buIHdqh-wNHVaql7I,34872 -pip/_vendor/requests/packages/chardet/euctwprober.py,sha256=upS2P6GuT5ujOxXYw-RJLcT7A4PTuo27KGUKU4UZpIQ,1676 -pip/_vendor/requests/packages/chardet/gb2312freq.py,sha256=M2gFdo_qQ_BslStEchrPW5CrPEZEacC0uyDLw4ok-kY,36011 -pip/_vendor/requests/packages/chardet/gb2312prober.py,sha256=VWnjoRa83Y6V6oczMaxyUr0uy48iCnC2nzk9zfEIRHc,1681 -pip/_vendor/requests/packages/chardet/hebrewprober.py,sha256=8pdoUfsVXf_L4BnJde_BewS6H2yInV5688eu0nFhLHY,13359 -pip/_vendor/requests/packages/chardet/jisfreq.py,sha256=ZcL4R5ekHHbP2KCYGakVMBsiKqZZZAABzhwi-uRkOps,47315 -pip/_vendor/requests/packages/chardet/jpcntx.py,sha256=9fJ9oS0BUarcdZNySwmzVRuT03sYdClSmFwXDj3yVNg,19104 -pip/_vendor/requests/packages/chardet/langbulgarianmodel.py,sha256=ZyPsA796MSVhYdfWhMCgKWckupAKAnKqWcE3Cl3ej6o,12784 -pip/_vendor/requests/packages/chardet/langcyrillicmodel.py,sha256=fkcd5OvogUp-GrNDWAZPgkYsSRCD2omotAEvqjlmLKE,17725 -pip/_vendor/requests/packages/chardet/langgreekmodel.py,sha256=QHMy31CH_ot67UCtmurCEKqKx2WwoaKrw2YCYYBK2Lw,12628 -pip/_vendor/requests/packages/chardet/langhebrewmodel.py,sha256=4ASl5vzKJPng4H278VHKtRYC03TpQpenlHTcsmZH1rE,11318 -pip/_vendor/requests/packages/chardet/langhungarianmodel.py,sha256=SXwuUzh49_cBeMXhshRHdrhlkz0T8_pZWV_pdqBKNFk,12536 -pip/_vendor/requests/packages/chardet/langthaimodel.py,sha256=-k7djh3dGKngAGnt3WfuoJN7acDcWcmHAPojhaUd7q4,11275 -pip/_vendor/requests/packages/chardet/latin1prober.py,sha256=g67gqZ2z89LUOlR7BZEAh4-p5a1yGWss9nWy8FCNm8Q,5241 -pip/_vendor/requests/packages/chardet/mbcharsetprober.py,sha256=9rOCjDVsmSMp6e7q2syqak22j7lrbUZhJhMee2gbVL0,3268 -pip/_vendor/requests/packages/chardet/mbcsgroupprober.py,sha256=SHRzNPLpDXfMJLA8phCHVU0WgqbgDCNxDQMolGX_7yk,1967 -pip/_vendor/requests/packages/chardet/mbcssm.py,sha256=UuiA4Ic8vEc0XpTKDneqZyiH2TwGuFVZxOxWJep3X_4,19608 -pip/_vendor/requests/packages/chardet/sbcharsetprober.py,sha256=Xq0lODqJnDgxglBiQI4BqTFiPbn63-0a5XNA5-hVu7U,4793 -pip/_vendor/requests/packages/chardet/sbcsgroupprober.py,sha256=8hLyH8RAG-aohBo7o_KciWVgRo42ZE_zEtuNG1JMRYI,3291 -pip/_vendor/requests/packages/chardet/sjisprober.py,sha256=1RjpQ2LU2gvoEB_4O839xDQVchWx2fG_C7_vXh52P5I,3734 -pip/_vendor/requests/packages/chardet/universaldetector.py,sha256=GkZdwNyNfbFWC8I1uqnzyhOUF7favWCqCOKqdQlx6gQ,6831 -pip/_vendor/requests/packages/chardet/utf8prober.py,sha256=7tdNZGrJY7jZUBD483GGMkiP0Tx8Fp-cGvWHoAsilHg,2652 -pip/_vendor/requests/packages/urllib3/__init__.py,sha256=sLIKv9dGJjDloiVXUBBjXDWWq8bM66kcvTH2SU_WZKg,1701 -pip/_vendor/requests/packages/urllib3/_collections.py,sha256=Oh1gxPZRqtOSy3pTV0pWQ949t9sjRAFMautsHiHP_pY,6557 -pip/_vendor/requests/packages/urllib3/connection.py,sha256=eug-y4_dOa-x9bxDlURwpqlZuQDhl9Tjre5D1S5bijE,6533 -pip/_vendor/requests/packages/urllib3/connectionpool.py,sha256=8eDsWYJzKYOyXMiP4CJqtLeychOw3iD_P20Ov-dbGUs,26904 -pip/_vendor/requests/packages/urllib3/exceptions.py,sha256=T-ILeqVPpEvrOYAq8XEyTF0X8XRWcFVGT2gMrF00km0,3364 -pip/_vendor/requests/packages/urllib3/fields.py,sha256=UuTJzGxUc9H1LPYZnD3f8GW308Vx_znb5pt4yimORsI,5976 -pip/_vendor/requests/packages/urllib3/filepost.py,sha256=tWPY33HnFM_RPpEU9PHv9D34n67w8ZRt80ZSsWIv0Kk,2512 -pip/_vendor/requests/packages/urllib3/poolmanager.py,sha256=bMYHdNaVI5O4YrJHr1T6tE2RYHEMzM2_K0cTy7uzX2M,8977 -pip/_vendor/requests/packages/urllib3/request.py,sha256=cXTcrr9d50Rt213ZXLgCf53KNWxe4LQ8lxSV1HBYa9E,5808 -pip/_vendor/requests/packages/urllib3/response.py,sha256=ff9-9sZkghNWCyeoECvImHspITTum7KOM20J2ia4SAw,10347 -pip/_vendor/requests/packages/urllib3/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -pip/_vendor/requests/packages/urllib3/contrib/ntlmpool.py,sha256=VJ-GjxpYITxSj4UDKX0iqvHwaatyg2RA3PaTym5Wp6w,4741 -pip/_vendor/requests/packages/urllib3/contrib/pyopenssl.py,sha256=D1cbFXSoWj4ahM0azQdvIDFkvNnzMLxOvo1wnMrPo8M,15086 -pip/_vendor/requests/packages/urllib3/packages/__init__.py,sha256=EKCTAOjZtPR_HC50e7X8hS5j4bkFkN87XZOT-Wdpfus,74 -pip/_vendor/requests/packages/urllib3/packages/ordered_dict.py,sha256=HtHphtStJlorzQqoIat8zUH0lqLns416gfSO9y_aSAQ,8936 -pip/_vendor/requests/packages/urllib3/packages/six.py,sha256=U-rO-WBrFS8PxHeamSl6okKCjqPF18NhiZb0qPZ67XM,11628 -pip/_vendor/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py,sha256=cOWMIn1orgJoA35p6pSzO_-Dc6iOX9Dhl6D2sL9b_2o,460 -pip/_vendor/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.py,sha256=fK28k37hL7-D79v9iM2fHgNK9Q1Pw0M7qVRL4rkfFjQ,3778 -pip/_vendor/requests/packages/urllib3/util/__init__.py,sha256=nI42Lb9ShOOOl_uRDyJfZP_nxHCR4wTFJXmDa_GEe7c,622 -pip/_vendor/requests/packages/urllib3/util/connection.py,sha256=Df5MeJaIpPigbIxEa87ojZ7qxXm1-V9dhnc2m7S6lNA,1348 -pip/_vendor/requests/packages/urllib3/util/request.py,sha256=-mIHA_M2aZwEmW5PpNfxEi9B47YDmFcoTW5FvQ7prf4,1924 -pip/_vendor/requests/packages/urllib3/util/response.py,sha256=EVO-5Q1Wc9K61i3RIhPB83CXfnvZpphL_NNp0SLznzI,354 -pip/_vendor/requests/packages/urllib3/util/ssl_.py,sha256=0SJbyE9KURi8IjmOwo8sqmmit4sRkXf9eg_ODWOhSD0,4235 -pip/_vendor/requests/packages/urllib3/util/timeout.py,sha256=WGx3s4593QcpwyHLY1FpFZgGPiTdL26A2nJhsZa9Rj8,9236 -pip/_vendor/requests/packages/urllib3/util/url.py,sha256=ftfW-i1XtyFZEOEKfXLkKNmM7APmgNHbtcGWYr-6xdI,4273 -pip/backwardcompat/__init__.py,sha256=AcP5dr3nL-4AGxSwsFIEUcf9ki0ROUFwfc0IrIeHaJI,3756 -pip/commands/__init__.py,sha256=N_4io-oGcWF9-raDN5TYXbGlJFsx5po36HZmwgLso6I,2236 -pip/commands/bundle.py,sha256=tK8LU3Khjkrz65y3brNP71QOBkQCb9mlv9x8s1W02T4,1787 -pip/commands/completion.py,sha256=LnJgUrpGGO4x2Y8VdwhKda4kGZWMFO28P4jYzYT5Q8k,1838 -pip/commands/freeze.py,sha256=Hyx1gzMaTFwTMcP98fwNCRVvvrWenX9j1RBziLCIo0A,4664 -pip/commands/help.py,sha256=ETLg8xfv8uFwS3KvxmsCE-I56S15jUTvfkwaPAA18pE,927 -pip/commands/install.py,sha256=PPFxd9RyUpVxfkumnztooBdrUkMguDI6eRHS0IrePUE,12694 -pip/commands/list.py,sha256=FHf7H35AajbCuymiG2z8xAGNSx8W5CNZKj6Hh2QGo38,6814 -pip/commands/search.py,sha256=_4Mza0qEb6P1aDA2OROYd-KuOJg0NrITOtQoiCDJF5Q,4736 -pip/commands/show.py,sha256=ipjEcTrk-hgvFysSKJ5E9PSPXZGTuE3NIXLYvXnsdNk,2767 -pip/commands/uninstall.py,sha256=MF4zSLfMxnH3E8T673ORNWz0Bsc4C6LEI5KImpAQrck,2203 -pip/commands/unzip.py,sha256=_PeTWKOd_iRxPt_7njQ8jGFpjX006vobn593tcIyeUc,185 -pip/commands/wheel.py,sha256=gyzZ4dQ0Ua8cP2H3ihvuNbv2z87ov-1Irxpu3m2MQqo,7320 -pip/commands/zip.py,sha256=KECCb3oCHxJqDT3kUEnlf0udp31Ckoe8oyEKdS7EKNQ,14821 -pip/vcs/__init__.py,sha256=kS31hLmJ6BgKnBu8kvXKQlJEwoj1MxYE7wfRuFL-daM,8748 -pip/vcs/bazaar.py,sha256=qUIuIqDJqwZ_nP6WR52YwvYVy1lvIUmvaT-IdxDYUHo,4943 -pip/vcs/git.py,sha256=ib3TqDwJyfjBnSRFKVe_HhNdwkmfcOZfJHbqt2RUOVg,7898 -pip/vcs/mercurial.py,sha256=71ESfgxotPPPZjiH6sMTBWcj5TS8kjgJxVnWrRb3bwo,5820 -pip/vcs/subversion.py,sha256=P31K7o83JdcipIyuEVlnpSp5KZqakb4OJ1PKT-FB7C8,10640 -pip-1.5.6.dist-info/DESCRIPTION.rst,sha256=n5sT7bxCOnG9ej7TtEjjARQZ_n2ECqWFDiJK88BM0u0,1422 -pip-1.5.6.dist-info/entry_points.txt,sha256=1-e4WB_Fe8mWHrMi1YQo_s5knbh0lu_uRmd8Wb6MJfY,68 -pip-1.5.6.dist-info/METADATA,sha256=lUBJx4V5mJY0jPlxYlu1x4YUNML-AN4dn4Dv-EFX8-Y,2499 -pip-1.5.6.dist-info/metadata.json,sha256=QZKMcKbHx-PWAvCvO0LdJX7JZjzx_yoKl2TTi1yKEKE,1361 -pip-1.5.6.dist-info/RECORD,, -pip-1.5.6.dist-info/top_level.txt,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -pip-1.5.6.dist-info/WHEEL,sha256=6lxp_S3wZGmTBtGMVmNNLyvKFcp7HqQw2Wn4YYk-Suo,110 -/home/melvin/development/shortenmyurl/venv/bin/pip,sha256=MBm3NnrkNUwibxjJPDZTc_oixeYAFa26QSFeRIoqeac,242 -/home/melvin/development/shortenmyurl/venv/bin/pip2,sha256=MBm3NnrkNUwibxjJPDZTc_oixeYAFa26QSFeRIoqeac,242 -/home/melvin/development/shortenmyurl/venv/bin/pip2.7,sha256=MBm3NnrkNUwibxjJPDZTc_oixeYAFa26QSFeRIoqeac,242 -pip/_vendor/requests/compat.pyc,, -pip/_vendor/requests/certs.pyc,, -pip/_vendor/requests/adapters.pyc,, -pip/__init__.pyc,, -pip/_vendor/html5lib/treewalkers/genshistream.pyc,, -pip/_vendor/requests/packages/chardet/latin1prober.pyc,, -pip/_vendor/distlib/_backport/__init__.pyc,, -pip/vcs/bazaar.pyc,, -pip/_vendor/distlib/metadata.pyc,, -pip/_vendor/html5lib/treebuilders/__init__.pyc,, -pip/_vendor/html5lib/filters/alphabeticalattributes.pyc,, -pip/_vendor/requests/packages/chardet/escprober.pyc,, -pip/_vendor/distlib/util.pyc,, -pip/_vendor/requests/packages/chardet/langbulgarianmodel.pyc,, -pip/commands/completion.pyc,, -pip/_vendor/html5lib/html5parser.pyc,, -pip/_vendor/html5lib/filters/lint.pyc,, -pip/pep425tags.pyc,, -pip/_vendor/requests/packages/chardet/__init__.pyc,, -pip/_vendor/html5lib/filters/whitespace.pyc,, -pip/_vendor/requests/packages/chardet/euckrprober.pyc,, -pip/_vendor/html5lib/treebuilders/etree_lxml.pyc,, -pip/_vendor/distlib/database.pyc,, -pip/_vendor/html5lib/treeadapters/sax.pyc,, -pip/commands/wheel.pyc,, -pip/_vendor/requests/auth.pyc,, -pip/_vendor/html5lib/treewalkers/pulldom.pyc,, -pip/_vendor/html5lib/ihatexml.pyc,, -pip/_vendor/html5lib/treewalkers/_base.pyc,, -pip/commands/list.pyc,, -pip/_vendor/distlib/scripts.pyc,, -pip/_vendor/html5lib/filters/sanitizer.pyc,, -pip/vcs/git.pyc,, -pip/cmdoptions.pyc,, -pip/_vendor/requests/packages/urllib3/util/ssl_.pyc,, -pip/_vendor/requests/packages/urllib3/poolmanager.pyc,, -pip/_vendor/html5lib/inputstream.pyc,, -pip/_vendor/html5lib/sanitizer.pyc,, -pip/_vendor/colorama/win32.pyc,, -pip/util.pyc,, -pip/_vendor/distlib/resources.pyc,, -pip/_vendor/requests/packages/chardet/hebrewprober.pyc,, -pip/_vendor/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.pyc,, -pip/_vendor/requests/packages/urllib3/packages/six.pyc,, -pip/_vendor/html5lib/trie/__init__.pyc,, -pip/_vendor/html5lib/__init__.pyc,, -pip/_vendor/requests/packages/chardet/charsetgroupprober.pyc,, -pip/_vendor/requests/packages/urllib3/packages/__init__.pyc,, -pip/_vendor/distlib/_backport/misc.pyc,, -pip/_vendor/requests/packages/chardet/gb2312freq.pyc,, -pip/_vendor/requests/packages/chardet/codingstatemachine.pyc,, -pip/runner.pyc,, -pip/_vendor/requests/packages/urllib3/util/url.pyc,, -pip/_vendor/requests/packages/urllib3/packages/ssl_match_hostname/__init__.pyc,, -pip/_vendor/requests/packages/chardet/langgreekmodel.pyc,, -pip/_vendor/requests/packages/__init__.pyc,, -pip/commands/show.pyc,, -pip/_vendor/requests/packages/urllib3/request.pyc,, -pip/_vendor/_markerlib/__init__.pyc,, -pip/_vendor/requests/packages/chardet/jpcntx.pyc,, -pip/_vendor/colorama/initialise.pyc,, -pip/_vendor/html5lib/treebuilders/_base.pyc,, -pip/commands/zip.pyc,, -pip/commands/help.pyc,, -pip/_vendor/requests/utils.pyc,, -pip/_vendor/colorama/__init__.pyc,, -pip/_vendor/distlib/version.pyc,, -pip/commands/uninstall.pyc,, -pip/_vendor/distlib/index.pyc,, -pip/commands/freeze.pyc,, -pip/_vendor/requests/sessions.pyc,, -pip/_vendor/html5lib/treewalkers/__init__.pyc,, -pip/_vendor/requests/packages/chardet/big5prober.pyc,, -pip/_vendor/requests/packages/chardet/langthaimodel.pyc,, -pip/_vendor/distlib/_backport/tarfile.pyc,, -pip/_vendor/requests/packages/urllib3/util/response.pyc,, -pip/_vendor/requests/packages/chardet/mbcsgroupprober.pyc,, -pip/_vendor/html5lib/filters/__init__.pyc,, -pip/baseparser.pyc,, -pip/status_codes.pyc,, -pip/_vendor/distlib/__init__.pyc,, -pip/commands/search.pyc,, -pip/_vendor/requests/packages/chardet/langhungarianmodel.pyc,, -pip/_vendor/html5lib/utils.pyc,, -pip/_vendor/html5lib/trie/datrie.pyc,, -pip/_vendor/requests/structures.pyc,, -pip/_vendor/requests/packages/chardet/euckrfreq.pyc,, -pip/_vendor/requests/packages/urllib3/fields.pyc,, -pip/_vendor/requests/packages/urllib3/contrib/ntlmpool.pyc,, -pip/vcs/__init__.pyc,, -pip/_vendor/html5lib/trie/py.pyc,, -pip/download.pyc,, -pip/commands/unzip.pyc,, -pip/commands/__init__.pyc,, -pip/_vendor/requests/packages/urllib3/__init__.pyc,, -pip/_vendor/distlib/compat.pyc,, -pip/_vendor/distlib/wheel.pyc,, -pip/_vendor/requests/packages/chardet/euctwprober.pyc,, -pip/_vendor/requests/packages/chardet/escsm.pyc,, -pip/_vendor/requests/status_codes.pyc,, -pip/_vendor/requests/exceptions.pyc,, -pip/_vendor/distlib/markers.pyc,, -pip/index.pyc,, -pip/_vendor/requests/packages/chardet/cp949prober.pyc,, -pip/_vendor/requests/api.pyc,, -pip/_vendor/requests/packages/urllib3/filepost.pyc,, -pip/_vendor/requests/packages/chardet/big5freq.pyc,, -pip/_vendor/html5lib/treebuilders/etree.pyc,, -pip/_vendor/html5lib/treebuilders/dom.pyc,, -pip/_vendor/requests/packages/chardet/mbcssm.pyc,, -pip/_vendor/distlib/_backport/shutil.pyc,, -pip/__main__.pyc,, -pip/backwardcompat/__init__.pyc,, -pip/_vendor/html5lib/tokenizer.pyc,, -pip/_vendor/requests/models.pyc,, -pip/_vendor/requests/packages/chardet/utf8prober.pyc,, -pip/_vendor/requests/packages/chardet/langhebrewmodel.pyc,, -pip/_vendor/requests/packages/chardet/compat.pyc,, -pip/_vendor/six.pyc,, -pip/_vendor/requests/packages/chardet/langcyrillicmodel.pyc,, -pip/_vendor/requests/packages/chardet/constants.pyc,, -pip/_vendor/requests/packages/urllib3/packages/ordered_dict.pyc,, -pip/_vendor/requests/packages/chardet/eucjpprober.pyc,, -pip/_vendor/html5lib/treewalkers/etree.pyc,, -pip/_vendor/requests/hooks.pyc,, -pip/_vendor/requests/packages/urllib3/connectionpool.pyc,, -pip/_vendor/requests/packages/chardet/mbcharsetprober.pyc,, -pip/locations.pyc,, -pip/_vendor/requests/packages/chardet/jisfreq.pyc,, -pip/_vendor/requests/packages/chardet/sbcsgroupprober.pyc,, -pip/vcs/subversion.pyc,, -pip/_vendor/requests/packages/urllib3/util/connection.pyc,, -pip/exceptions.pyc,, -pip/basecommand.pyc,, -pip/_vendor/distlib/locators.pyc,, -pip/_vendor/html5lib/filters/_base.pyc,, -pip/_vendor/re-vendor.pyc,, -pip/_vendor/requests/packages/urllib3/contrib/__init__.pyc,, -pip/_vendor/requests/packages/chardet/euctwfreq.pyc,, -pip/_vendor/requests/packages/chardet/chardistribution.pyc,, -pip/_vendor/distlib/_backport/sysconfig.pyc,, -pip/_vendor/requests/packages/chardet/sbcharsetprober.pyc,, -pip/_vendor/colorama/ansitowin32.pyc,, -pip/_vendor/requests/packages/chardet/sjisprober.pyc,, -pip/log.pyc,, -pip/_vendor/requests/packages/urllib3/util/timeout.pyc,, -pip/_vendor/html5lib/treewalkers/dom.pyc,, -pip/_vendor/_markerlib/markers.pyc,, -pip/_vendor/requests/cookies.pyc,, -pip/_vendor/requests/packages/urllib3/_collections.pyc,, -pip/_vendor/requests/packages/urllib3/util/request.pyc,, -pip/_vendor/pkg_resources.pyc,, -pip/_vendor/requests/packages/urllib3/util/__init__.pyc,, -pip/_vendor/distlib/manifest.pyc,, -pip/_vendor/html5lib/serializer/htmlserializer.pyc,, -pip/_vendor/html5lib/serializer/__init__.pyc,, -pip/_vendor/html5lib/trie/_base.pyc,, -pip/_vendor/requests/packages/urllib3/response.pyc,, -pip/_vendor/html5lib/treeadapters/__init__.pyc,, -pip/_vendor/html5lib/filters/inject_meta_charset.pyc,, -pip/_vendor/requests/packages/chardet/charsetprober.pyc,, -pip/commands/bundle.pyc,, -pip/vcs/mercurial.pyc,, -pip/_vendor/requests/packages/urllib3/exceptions.pyc,, -pip/_vendor/__init__.pyc,, -pip/_vendor/requests/packages/chardet/universaldetector.pyc,, -pip/_vendor/html5lib/constants.pyc,, -pip/_vendor/html5lib/treewalkers/lxmletree.pyc,, -pip/_vendor/colorama/ansi.pyc,, -pip/commands/install.pyc,, -pip/_vendor/requests/packages/chardet/gb2312prober.pyc,, -pip/_vendor/requests/packages/urllib3/contrib/pyopenssl.pyc,, -pip/wheel.pyc,, -pip/req.pyc,, -pip/_vendor/requests/__init__.pyc,, -pip/_vendor/requests/packages/chardet/chardetect.pyc,, -pip/_vendor/html5lib/filters/optionaltags.pyc,, -pip/_vendor/requests/packages/urllib3/connection.pyc,, -pip/_vendor/colorama/winterm.pyc,, diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/WHEEL b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/WHEEL deleted file mode 100644 index f19235cb..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.23.0) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/entry_points.txt b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/entry_points.txt deleted file mode 100644 index a237b5e4..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/entry_points.txt +++ /dev/null @@ -1,5 +0,0 @@ -[console_scripts] -pip = pip:main -pip3 = pip:main -pip3.4 = pip:main - diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/metadata.json b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/metadata.json deleted file mode 100644 index 2a13d372..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/metadata.json +++ /dev/null @@ -1 +0,0 @@ -{"version": "1.5.6", "license": "MIT", "summary": "A tool for installing and managing Python packages.", "test_requires": [{"requires": ["pytest", "virtualenv (>=1.10)", "scripttest (>=1.3)", "mock"]}], "generator": "bdist_wheel (0.23.0)", "document_names": {"description": "DESCRIPTION.rst"}, "run_requires": [{"extra": "testing", "requires": ["pytest", "virtualenv (>=1.10)", "scripttest (>=1.3)", "mock"]}], "exports": {"console_scripts": {"pip": "pip:main", "pip3": "pip:main", "pip3.4": "pip:main"}}, "name": "pip", "classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Topic :: Software Development :: Build Tools", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.1", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3"], "metadata_version": "2.0", "keywords": "easy_install distutils setuptools egg virtualenv", "extras": ["testing"], "commands": {"wrap_console": {"pip": "pip:main", "pip3": "pip:main", "pip3.4": "pip:main"}}, "contacts": [{"email": "python-virtualenv@groups.google.com", "name": "The pip developers", "role": "author"}], "project_urls": {"Home": "https://pip.pypa.io/"}} \ No newline at end of file diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/top_level.txt b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/top_level.txt deleted file mode 100644 index a1b589e3..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip-1.5.6.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/__init__.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/__init__.py deleted file mode 100644 index bb4a588a..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/__main__.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/__main__.py deleted file mode 100644 index 5ca37463..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/__init__.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/__init__.py deleted file mode 100644 index f233ca0d..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/_markerlib/__init__.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/_markerlib/__init__.py deleted file mode 100644 index 197781a0..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/_markerlib/markers.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/_markerlib/markers.py deleted file mode 100644 index fa837061..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/__init__.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/__init__.py deleted file mode 100644 index 0856986f..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/ansi.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/ansi.py deleted file mode 100644 index 5dfe374c..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/ansitowin32.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/ansitowin32.py deleted file mode 100644 index 0053a775..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/initialise.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/initialise.py deleted file mode 100644 index cba3676d..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/win32.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/win32.py deleted file mode 100644 index 5203e791..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/winterm.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/colorama/winterm.py deleted file mode 100644 index 27088115..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/__init__.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/__init__.py deleted file mode 100644 index f9081bb8..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/__init__.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/__init__.py deleted file mode 100644 index f7dbf4c9..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/misc.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/misc.py deleted file mode 100644 index cfb318d3..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/shutil.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/shutil.py deleted file mode 100644 index 9e2e234d..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/sysconfig.cfg b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/sysconfig.cfg deleted file mode 100644 index 1746bd01..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/sysconfig.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/sysconfig.py deleted file mode 100644 index 1d313267..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/tarfile.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/_backport/tarfile.py deleted file mode 100644 index 0580fb79..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/compat.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/compat.py deleted file mode 100644 index 63af3742..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/database.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/database.py deleted file mode 100644 index 0f013ec5..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/index.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/index.py deleted file mode 100644 index 83004b13..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/locators.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/locators.py deleted file mode 100644 index 07bc1fd4..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/manifest.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/manifest.py deleted file mode 100644 index c6b98c59..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/metadata.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/metadata.py deleted file mode 100644 index 8441d8fe..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/resources.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/resources.py deleted file mode 100644 index 567840e7..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/scripts.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/scripts.py deleted file mode 100644 index 36850b2a..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/t32.exe b/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/util.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/util.py deleted file mode 100644 index 29ec519a..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/version.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/version.py deleted file mode 100644 index f0e62c4e..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/w32.exe b/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/w64.exe b/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/wheel.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/distlib/wheel.py deleted file mode 100644 index d67d4bc5..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/__init__.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/__init__.py deleted file mode 100644 index ff5c7755..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/constants.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/constants.py deleted file mode 100644 index e7089846..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/__init__.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/_base.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/_base.py deleted file mode 100644 index c7dbaed0..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/alphabeticalattributes.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/alphabeticalattributes.py deleted file mode 100644 index fed6996c..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/inject_meta_charset.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/inject_meta_charset.py deleted file mode 100644 index ca33b70b..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/lint.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/lint.py deleted file mode 100644 index 7cc99a4b..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/optionaltags.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/optionaltags.py deleted file mode 100644 index fefe0b30..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/sanitizer.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/sanitizer.py deleted file mode 100644 index b206b54e..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/whitespace.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/whitespace.py deleted file mode 100644 index dfc60eeb..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/html5parser.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/html5parser.py deleted file mode 100644 index b28f46f2..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/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 
-  
-
-
- The debugger caught an exception in your WSGI application. You can now - look at the traceback which led to the error. - If you enable JavaScript you can also use additional features such as code - execution (if the evalex feature is enabled), automatic pasting of the - exceptions and much more. -
-''' + FOOTER + ''' - -''' - -CONSOLE_HTML = HEADER + u'''\ -

Interactive Console

-
-In this console you can execute Python expressions in the context of the -application. The initial namespace was created by the debugger automatically. -
-
The Console requires JavaScript.
-''' + FOOTER - -SUMMARY_HTML = u'''\ -
- %(title)s -
    %(frames)s
- %(description)s -
-''' - -FRAME_HTML = u'''\ -
-

File "%(filename)s", - line %(lineno)s, - in %(function_name)s

-
%(current_line)s
-
-''' - -SOURCE_TABLE_HTML = u'%s
' - -SOURCE_LINE_HTML = u'''\ - - %(lineno)s - %(code)s - -''' - - -def render_console_html(secret): - return CONSOLE_HTML % { - 'evalex': 'true', - 'console': 'true', - 'title': 'Console', - 'secret': secret, - 'traceback_id': -1 - } - - -def get_current_traceback(ignore_system_exceptions=False, - show_hidden_frames=False, skip=0): - """Get the current exception info as `Traceback` object. Per default - calling this method will reraise system exceptions such as generator exit, - system exit or others. This behavior can be disabled by passing `False` - to the function as first parameter. - """ - exc_type, exc_value, tb = sys.exc_info() - if ignore_system_exceptions and exc_type in system_exceptions: - raise - for x in range_type(skip): - if tb.tb_next is None: - break - tb = tb.tb_next - tb = Traceback(exc_type, exc_value, tb) - if not show_hidden_frames: - tb.filter_hidden_frames() - return tb - - -class Line(object): - """Helper for the source renderer.""" - __slots__ = ('lineno', 'code', 'in_frame', 'current') - - def __init__(self, lineno, code): - self.lineno = lineno - self.code = code - self.in_frame = False - self.current = False - - def classes(self): - rv = ['line'] - if self.in_frame: - rv.append('in-frame') - if self.current: - rv.append('current') - return rv - classes = property(classes) - - def render(self): - return SOURCE_LINE_HTML % { - 'classes': u' '.join(self.classes), - 'lineno': self.lineno, - 'code': escape(self.code) - } - - -class Traceback(object): - """Wraps a traceback.""" - - def __init__(self, exc_type, exc_value, tb): - self.exc_type = exc_type - self.exc_value = exc_value - if not isinstance(exc_type, str): - exception_type = exc_type.__name__ - if exc_type.__module__ not in ('__builtin__', 'exceptions'): - exception_type = exc_type.__module__ + '.' + exception_type - else: - exception_type = exc_type - self.exception_type = exception_type - - # we only add frames to the list that are not hidden. This follows - # the the magic variables as defined by paste.exceptions.collector - self.frames = [] - while tb: - self.frames.append(Frame(exc_type, exc_value, tb)) - tb = tb.tb_next - - def filter_hidden_frames(self): - """Remove the frames according to the paste spec.""" - if not self.frames: - return - - new_frames = [] - hidden = False - for frame in self.frames: - hide = frame.hide - if hide in ('before', 'before_and_this'): - new_frames = [] - hidden = False - if hide == 'before_and_this': - continue - elif hide in ('reset', 'reset_and_this'): - hidden = False - if hide == 'reset_and_this': - continue - elif hide in ('after', 'after_and_this'): - hidden = True - if hide == 'after_and_this': - continue - elif hide or hidden: - continue - new_frames.append(frame) - - # if we only have one frame and that frame is from the codeop - # module, remove it. - if len(new_frames) == 1 and self.frames[0].module == 'codeop': - del self.frames[:] - - # if the last frame is missing something went terrible wrong :( - elif self.frames[-1] in new_frames: - self.frames[:] = new_frames - - def is_syntax_error(self): - """Is it a syntax error?""" - return isinstance(self.exc_value, SyntaxError) - is_syntax_error = property(is_syntax_error) - - def exception(self): - """String representation of the exception.""" - buf = traceback.format_exception_only(self.exc_type, self.exc_value) - rv = ''.join(buf).strip() - return rv.decode('utf-8', 'replace') if PY2 else rv - exception = property(exception) - - def log(self, logfile=None): - """Log the ASCII traceback into a file object.""" - if logfile is None: - logfile = sys.stderr - tb = self.plaintext.rstrip() + u'\n' - if PY2: - tb.encode('utf-8', 'replace') - logfile.write(tb) - - def paste(self): - """Create a paste and return the paste id.""" - data = json.dumps({ - 'description': 'Werkzeug Internal Server Error', - 'public': False, - 'files': { - 'traceback.txt': { - 'content': self.plaintext - } - } - }).encode('utf-8') - try: - from urllib2 import urlopen - except ImportError: - from urllib.request import urlopen - rv = urlopen('https://api.github.com/gists', data=data) - resp = json.loads(rv.read().decode('utf-8')) - rv.close() - return { - 'url': resp['html_url'], - 'id': resp['id'] - } - - def render_summary(self, include_title=True): - """Render the traceback for the interactive console.""" - title = '' - frames = [] - classes = ['traceback'] - if not self.frames: - classes.append('noframe-traceback') - - if include_title: - if self.is_syntax_error: - title = u'Syntax Error' - else: - title = u'Traceback (most recent call last):' - - for frame in self.frames: - frames.append(u'%s' % ( - frame.info and u' title="%s"' % escape(frame.info) or u'', - frame.render() - )) - - if self.is_syntax_error: - description_wrapper = u'
%s
' - else: - description_wrapper = u'
%s
' - - return SUMMARY_HTML % { - 'classes': u' '.join(classes), - 'title': title and u'

%s

' % title or u'', - 'frames': u'\n'.join(frames), - 'description': description_wrapper % escape(self.exception) - } - - def render_full(self, evalex=False, secret=None): - """Render the Full HTML page with the traceback info.""" - exc = escape(self.exception) - return PAGE_HTML % { - 'evalex': evalex and 'true' or 'false', - 'console': 'false', - 'title': exc, - 'exception': exc, - 'exception_type': escape(self.exception_type), - 'summary': self.render_summary(include_title=False), - 'plaintext': self.plaintext, - 'plaintext_cs': re.sub('-{2,}', '-', self.plaintext), - 'traceback_id': self.id, - 'secret': secret - } - - def generate_plaintext_traceback(self): - """Like the plaintext attribute but returns a generator""" - yield u'Traceback (most recent call last):' - for frame in self.frames: - yield u' File "%s", line %s, in %s' % ( - frame.filename, - frame.lineno, - frame.function_name - ) - yield u' ' + frame.current_line.strip() - yield self.exception - - def plaintext(self): - return u'\n'.join(self.generate_plaintext_traceback()) - plaintext = cached_property(plaintext) - - id = property(lambda x: id(x)) - - -class Frame(object): - """A single frame in a traceback.""" - - def __init__(self, exc_type, exc_value, tb): - self.lineno = tb.tb_lineno - self.function_name = tb.tb_frame.f_code.co_name - self.locals = tb.tb_frame.f_locals - self.globals = tb.tb_frame.f_globals - - fn = inspect.getsourcefile(tb) or inspect.getfile(tb) - if fn[-4:] in ('.pyo', '.pyc'): - fn = fn[:-1] - # if it's a file on the file system resolve the real filename. - if os.path.isfile(fn): - fn = os.path.realpath(fn) - self.filename = fn - self.module = self.globals.get('__name__') - self.loader = self.globals.get('__loader__') - self.code = tb.tb_frame.f_code - - # support for paste's traceback extensions - self.hide = self.locals.get('__traceback_hide__', False) - info = self.locals.get('__traceback_info__') - if info is not None: - try: - info = text_type(info) - except UnicodeError: - info = str(info).decode('utf-8', 'replace') - self.info = info - - def render(self): - """Render a single frame in a traceback.""" - return FRAME_HTML % { - 'id': self.id, - 'filename': escape(self.filename), - 'lineno': self.lineno, - 'function_name': escape(self.function_name), - 'current_line': escape(self.current_line.strip()) - } - - def get_annotated_lines(self): - """Helper function that returns lines with extra information.""" - lines = [Line(idx + 1, x) for idx, x in enumerate(self.sourcelines)] - - # find function definition and mark lines - if hasattr(self.code, 'co_firstlineno'): - lineno = self.code.co_firstlineno - 1 - while lineno > 0: - if _funcdef_re.match(lines[lineno].code): - break - lineno -= 1 - try: - offset = len(inspect.getblock([x.code + '\n' for x - in lines[lineno:]])) - except TokenError: - offset = 0 - for line in lines[lineno:lineno + offset]: - line.in_frame = True - - # mark current line - try: - lines[self.lineno - 1].current = True - except IndexError: - pass - - return lines - - def render_source(self): - """Render the sourcecode.""" - return SOURCE_TABLE_HTML % u'\n'.join(line.render() for line in - self.get_annotated_lines()) - - def eval(self, code, mode='single'): - """Evaluate code in the context of the frame.""" - if isinstance(code, string_types): - if PY2 and isinstance(code, unicode): - code = UTF8_COOKIE + code.encode('utf-8') - code = compile(code, '', mode) - return eval(code, self.globals, self.locals) - - @cached_property - def sourcelines(self): - """The sourcecode of the file as list of unicode strings.""" - # get sourcecode from loader or file - source = None - if self.loader is not None: - try: - if hasattr(self.loader, 'get_source'): - source = self.loader.get_source(self.module) - elif hasattr(self.loader, 'get_source_by_code'): - source = self.loader.get_source_by_code(self.code) - except Exception: - # we munch the exception so that we don't cause troubles - # if the loader is broken. - pass - - if source is None: - try: - f = open(self.filename) - except IOError: - return [] - try: - source = f.read() - finally: - f.close() - - # already unicode? return right away - if isinstance(source, text_type): - return source.splitlines() - - # yes. it should be ascii, but we don't want to reject too many - # characters in the debugger if something breaks - charset = 'utf-8' - if source.startswith(UTF8_COOKIE): - source = source[3:] - else: - for idx, match in enumerate(_line_re.finditer(source)): - match = _line_re.search(match.group()) - if match is not None: - charset = match.group(1) - break - if idx > 1: - break - - # on broken cookies we fall back to utf-8 too - try: - codecs.lookup(charset) - except LookupError: - charset = 'utf-8' - - return source.decode(charset, 'replace').splitlines() - - @property - def current_line(self): - try: - return self.sourcelines[self.lineno - 1] - except IndexError: - return u'' - - @cached_property - def console(self): - return Console(self.globals, self.locals) - - id = property(lambda x: id(x)) diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/exceptions.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/exceptions.py deleted file mode 100644 index 35c262be..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/exceptions.py +++ /dev/null @@ -1,588 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.exceptions - ~~~~~~~~~~~~~~~~~~~ - - This module implements a number of Python exceptions you can raise from - within your views to trigger a standard non-200 response. - - - Usage Example - ------------- - - :: - - from werkzeug.wrappers import BaseRequest - from werkzeug.wsgi import responder - from werkzeug.exceptions import HTTPException, NotFound - - def view(request): - raise NotFound() - - @responder - def application(environ, start_response): - request = BaseRequest(environ) - try: - return view(request) - except HTTPException as e: - return e - - - As you can see from this example those exceptions are callable WSGI - applications. Because of Python 2.4 compatibility those do not extend - from the response objects but only from the python exception class. - - As a matter of fact they are not Werkzeug response objects. However you - can get a response object by calling ``get_response()`` on a HTTP - exception. - - Keep in mind that you have to pass an environment to ``get_response()`` - because some errors fetch additional information from the WSGI - environment. - - If you want to hook in a different exception page to say, a 404 status - code, you can add a second except for a specific subclass of an error:: - - @responder - def application(environ, start_response): - request = BaseRequest(environ) - try: - return view(request) - except NotFound, e: - return not_found(request) - except HTTPException, e: - return e - - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -import sys - -# Because of bootstrapping reasons we need to manually patch ourselves -# onto our parent module. -import werkzeug -werkzeug.exceptions = sys.modules[__name__] - -from werkzeug._internal import _get_environ -from werkzeug._compat import iteritems, integer_types, text_type, \ - implements_to_string - -from werkzeug.wrappers import Response - - -@implements_to_string -class HTTPException(Exception): - """ - Baseclass for all HTTP exceptions. This exception can be called as WSGI - application to render a default error page or you can catch the subclasses - of it independently and render nicer error messages. - """ - - code = None - description = None - - def __init__(self, description=None, response=None): - Exception.__init__(self) - if description is not None: - self.description = description - self.response = response - - @classmethod - def wrap(cls, exception, name=None): - """This method returns a new subclass of the exception provided that - also is a subclass of `BadRequest`. - """ - class newcls(cls, exception): - def __init__(self, arg=None, *args, **kwargs): - cls.__init__(self, *args, **kwargs) - exception.__init__(self, arg) - newcls.__module__ = sys._getframe(1).f_globals.get('__name__') - newcls.__name__ = name or cls.__name__ + exception.__name__ - return newcls - - @property - def name(self): - """The status name.""" - return HTTP_STATUS_CODES.get(self.code, 'Unknown Error') - - def get_description(self, environ=None): - """Get the description.""" - return u'

%s

' % escape(self.description) - - def get_body(self, environ=None): - """Get the HTML body.""" - return text_type(( - u'\n' - u'%(code)s %(name)s\n' - u'

%(name)s

\n' - u'%(description)s\n' - ) % { - 'code': self.code, - 'name': escape(self.name), - 'description': self.get_description(environ) - }) - - def get_headers(self, environ=None): - """Get a list of headers.""" - return [('Content-Type', 'text/html')] - - def get_response(self, environ=None): - """Get a response object. If one was passed to the exception - it's returned directly. - - :param environ: the optional environ for the request. This - can be used to modify the response depending - on how the request looked like. - :return: a :class:`Response` object or a subclass thereof. - """ - if self.response is not None: - return self.response - if environ is not None: - environ = _get_environ(environ) - headers = self.get_headers(environ) - return Response(self.get_body(environ), self.code, headers) - - def __call__(self, environ, start_response): - """Call the exception as WSGI application. - - :param environ: the WSGI environment. - :param start_response: the response callable provided by the WSGI - server. - """ - response = self.get_response(environ) - return response(environ, start_response) - - def __str__(self): - return '%d: %s' % (self.code, self.name) - - def __repr__(self): - return '<%s \'%s\'>' % (self.__class__.__name__, self) - - -class BadRequest(HTTPException): - """*400* `Bad Request` - - Raise if the browser sends something to the application the application - or server cannot handle. - """ - code = 400 - description = ( - 'The browser (or proxy) sent a request that this server could ' - 'not understand.' - ) - - -class ClientDisconnected(BadRequest): - """Internal exception that is raised if Werkzeug detects a disconnected - client. Since the client is already gone at that point attempting to - send the error message to the client might not work and might ultimately - result in another exception in the server. Mainly this is here so that - it is silenced by default as far as Werkzeug is concerned. - - Since disconnections cannot be reliably detected and are unspecified - by WSGI to a large extend this might or might not be raised if a client - is gone. - - .. versionadded:: 0.8 - """ - - -class SecurityError(BadRequest): - """Raised if something triggers a security error. This is otherwise - exactly like a bad request error. - - .. versionadded:: 0.9 - """ - - -class Unauthorized(HTTPException): - """*401* `Unauthorized` - - Raise if the user is not authorized. Also used if you want to use HTTP - basic auth. - """ - code = 401 - description = ( - 'The server could not verify that you are authorized to access ' - 'the URL requested. You either supplied the wrong credentials (e.g. ' - 'a bad password), or your browser doesn\'t understand how to supply ' - 'the credentials required.' - ) - - -class Forbidden(HTTPException): - """*403* `Forbidden` - - Raise if the user doesn't have the permission for the requested resource - but was authenticated. - """ - code = 403 - description = ( - 'You don\'t have the permission to access the requested resource. ' - 'It is either read-protected or not readable by the server.' - ) - - -class NotFound(HTTPException): - """*404* `Not Found` - - Raise if a resource does not exist and never existed. - """ - code = 404 - description = ( - 'The requested URL was not found on the server. ' - 'If you entered the URL manually please check your spelling and ' - 'try again.' - ) - - -class MethodNotAllowed(HTTPException): - """*405* `Method Not Allowed` - - Raise if the server used a method the resource does not handle. For - example `POST` if the resource is view only. Especially useful for REST. - - The first argument for this exception should be a list of allowed methods. - Strictly speaking the response would be invalid if you don't provide valid - methods in the header which you can do with that list. - """ - code = 405 - description = 'The method is not allowed for the requested URL.' - - def __init__(self, valid_methods=None, description=None): - """Takes an optional list of valid http methods - starting with werkzeug 0.3 the list will be mandatory.""" - HTTPException.__init__(self, description) - self.valid_methods = valid_methods - - def get_headers(self, environ): - headers = HTTPException.get_headers(self, environ) - if self.valid_methods: - headers.append(('Allow', ', '.join(self.valid_methods))) - return headers - - -class NotAcceptable(HTTPException): - """*406* `Not Acceptable` - - Raise if the server can't return any content conforming to the - `Accept` headers of the client. - """ - code = 406 - - description = ( - 'The resource identified by the request is only capable of ' - 'generating response entities which have content characteristics ' - 'not acceptable according to the accept headers sent in the ' - 'request.' - ) - - -class RequestTimeout(HTTPException): - """*408* `Request Timeout` - - Raise to signalize a timeout. - """ - code = 408 - description = ( - 'The server closed the network connection because the browser ' - 'didn\'t finish the request within the specified time.' - ) - - -class Conflict(HTTPException): - """*409* `Conflict` - - Raise to signal that a request cannot be completed because it conflicts - with the current state on the server. - - .. versionadded:: 0.7 - """ - code = 409 - description = ( - 'A conflict happened while processing the request. The resource ' - 'might have been modified while the request was being processed.' - ) - - -class Gone(HTTPException): - """*410* `Gone` - - Raise if a resource existed previously and went away without new location. - """ - code = 410 - description = ( - 'The requested URL is no longer available on this server and ' - 'there is no forwarding address.

If you followed a link ' - 'from a foreign page, please contact the author of this page.' - ) - - -class LengthRequired(HTTPException): - """*411* `Length Required` - - Raise if the browser submitted data but no ``Content-Length`` header which - is required for the kind of processing the server does. - """ - code = 411 - description = ( - 'A request with this method requires a valid Content-' - 'Length header.' - ) - - -class PreconditionFailed(HTTPException): - """*412* `Precondition Failed` - - Status code used in combination with ``If-Match``, ``If-None-Match``, or - ``If-Unmodified-Since``. - """ - code = 412 - description = ( - 'The precondition on the request for the URL failed positive ' - 'evaluation.' - ) - - -class RequestEntityTooLarge(HTTPException): - """*413* `Request Entity Too Large` - - The status code one should return if the data submitted exceeded a given - limit. - """ - code = 413 - description = ( - 'The data value transmitted exceeds the capacity limit.' - ) - - -class RequestURITooLarge(HTTPException): - """*414* `Request URI Too Large` - - Like *413* but for too long URLs. - """ - code = 414 - description = ( - 'The length of the requested URL exceeds the capacity limit ' - 'for this server. The request cannot be processed.' - ) - - -class UnsupportedMediaType(HTTPException): - """*415* `Unsupported Media Type` - - The status code returned if the server is unable to handle the media type - the client transmitted. - """ - code = 415 - description = ( - 'The server does not support the media type transmitted in ' - 'the request.' - ) - - -class RequestedRangeNotSatisfiable(HTTPException): - """*416* `Requested Range Not Satisfiable` - - The client asked for a part of the file that lies beyond the end - of the file. - - .. versionadded:: 0.7 - """ - code = 416 - description = ( - 'The server cannot provide the requested range.' - ) - - -class ExpectationFailed(HTTPException): - """*417* `Expectation Failed` - - The server cannot meet the requirements of the Expect request-header. - - .. versionadded:: 0.7 - """ - code = 417 - description = ( - 'The server could not meet the requirements of the Expect header' - ) - - -class ImATeapot(HTTPException): - """*418* `I'm a teapot` - - The server should return this if it is a teapot and someone attempted - to brew coffee with it. - - .. versionadded:: 0.7 - """ - code = 418 - description = ( - 'This server is a teapot, not a coffee machine' - ) - - -class UnprocessableEntity(HTTPException): - """*422* `Unprocessable Entity` - - Used if the request is well formed, but the instructions are otherwise - incorrect. - """ - code = 422 - description = ( - 'The request was well-formed but was unable to be followed ' - 'due to semantic errors.' - ) - - -class PreconditionRequired(HTTPException): - """*428* `Precondition Required` - - The server requires this request to be conditional, typically to prevent - the lost update problem, which is a race condition between two or more - clients attempting to update a resource through PUT or DELETE. By requiring - each client to include a conditional header ("If-Match" or "If-Unmodified- - Since") with the proper value retained from a recent GET request, the - server ensures that each client has at least seen the previous revision of - the resource. - """ - code = 428 - description = ( - 'This request is required to be conditional; try using "If-Match" ' - 'or "If-Unmodified-Since".' - ) - - -class TooManyRequests(HTTPException): - """*429* `Too Many Requests` - - The server is limiting the rate at which this user receives responses, and - this request exceeds that rate. (The server may use any convenient method - to identify users and their request rates). The server may include a - "Retry-After" header to indicate how long the user should wait before - retrying. - """ - code = 429 - description = ( - 'This user has exceeded an allotted request count. Try again later.' - ) - - -class RequestHeaderFieldsTooLarge(HTTPException): - """*431* `Request Header Fields Too Large` - - The server refuses to process the request because the header fields are too - large. One or more individual fields may be too large, or the set of all - headers is too large. - """ - code = 431 - description = ( - 'One or more header fields exceeds the maximum size.' - ) - - -class InternalServerError(HTTPException): - """*500* `Internal Server Error` - - Raise if an internal server error occurred. This is a good fallback if an - unknown error occurred in the dispatcher. - """ - code = 500 - description = ( - 'The server encountered an internal error and was unable to ' - 'complete your request. Either the server is overloaded or there ' - 'is an error in the application.' - ) - - -class NotImplemented(HTTPException): - """*501* `Not Implemented` - - Raise if the application does not support the action requested by the - browser. - """ - code = 501 - description = ( - 'The server does not support the action requested by the ' - 'browser.' - ) - - -class BadGateway(HTTPException): - """*502* `Bad Gateway` - - If you do proxying in your application you should return this status code - if you received an invalid response from the upstream server it accessed - in attempting to fulfill the request. - """ - code = 502 - description = ( - 'The proxy server received an invalid response from an upstream ' - 'server.' - ) - - -class ServiceUnavailable(HTTPException): - """*503* `Service Unavailable` - - Status code you should return if a service is temporarily unavailable. - """ - code = 503 - description = ( - 'The server is temporarily unable to service your request due to ' - 'maintenance downtime or capacity problems. Please try again ' - 'later.' - ) - - -default_exceptions = {} -__all__ = ['HTTPException'] - -def _find_exceptions(): - for name, obj in iteritems(globals()): - try: - if getattr(obj, 'code', None) is not None: - default_exceptions[obj.code] = obj - __all__.append(obj.__name__) - except TypeError: # pragma: no cover - continue -_find_exceptions() -del _find_exceptions - - -class Aborter(object): - """ - When passed a dict of code -> exception items it can be used as - callable that raises exceptions. If the first argument to the - callable is an integer it will be looked up in the mapping, if it's - a WSGI application it will be raised in a proxy exception. - - The rest of the arguments are forwarded to the exception constructor. - """ - - def __init__(self, mapping=None, extra=None): - if mapping is None: - mapping = default_exceptions - self.mapping = dict(mapping) - if extra is not None: - self.mapping.update(extra) - - def __call__(self, code, *args, **kwargs): - if not args and not kwargs and not isinstance(code, integer_types): - raise HTTPException(response=code) - if code not in self.mapping: - raise LookupError('no exception for %r' % code) - raise self.mapping[code](*args, **kwargs) - -abort = Aborter() - - -#: an exception that is used internally to signal both a key error and a -#: bad request. Used by a lot of the datastructures. -BadRequestKeyError = BadRequest.wrap(KeyError) - - -# imported here because of circular dependencies of werkzeug.utils -from werkzeug.utils import escape -from werkzeug.http import HTTP_STATUS_CODES diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/formparser.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/formparser.py deleted file mode 100644 index b349c962..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/formparser.py +++ /dev/null @@ -1,523 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.formparser - ~~~~~~~~~~~~~~~~~~~ - - This module implements the form parsing. It supports url-encoded forms - as well as non-nested multipart uploads. - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -import re -import codecs -from io import BytesIO -from tempfile import TemporaryFile -from itertools import chain, repeat, tee -from functools import update_wrapper - -from werkzeug._compat import to_native, text_type -from werkzeug.urls import url_decode_stream -from werkzeug.wsgi import make_line_iter, \ - get_input_stream, get_content_length -from werkzeug.datastructures import Headers, FileStorage, MultiDict -from werkzeug.http import parse_options_header - - -#: an iterator that yields empty strings -_empty_string_iter = repeat('') - -#: a regular expression for multipart boundaries -_multipart_boundary_re = re.compile('^[ -~]{0,200}[!-~]$') - -#: supported http encodings that are also available in python we support -#: for multipart messages. -_supported_multipart_encodings = frozenset(['base64', 'quoted-printable']) - - -def default_stream_factory(total_content_length, filename, content_type, - content_length=None): - """The stream factory that is used per default.""" - if total_content_length > 1024 * 500: - return TemporaryFile('wb+') - return BytesIO() - - -def parse_form_data(environ, stream_factory=None, charset='utf-8', - errors='replace', max_form_memory_size=None, - max_content_length=None, cls=None, - silent=True): - """Parse the form data in the environ and return it as tuple in the form - ``(stream, form, files)``. You should only call this method if the - transport method is `POST`, `PUT`, or `PATCH`. - - If the mimetype of the data transmitted is `multipart/form-data` the - files multidict will be filled with `FileStorage` objects. If the - mimetype is unknown the input stream is wrapped and returned as first - argument, else the stream is empty. - - This is a shortcut for the common usage of :class:`FormDataParser`. - - Have a look at :ref:`dealing-with-request-data` for more details. - - .. versionadded:: 0.5 - The `max_form_memory_size`, `max_content_length` and - `cls` parameters were added. - - .. versionadded:: 0.5.1 - The optional `silent` flag was added. - - :param environ: the WSGI environment to be used for parsing. - :param stream_factory: An optional callable that returns a new read and - writeable file descriptor. This callable works - the same as :meth:`~BaseResponse._get_file_stream`. - :param charset: The character set for URL and url encoded form data. - :param errors: The encoding error behavior. - :param max_form_memory_size: the maximum number of bytes to be accepted for - in-memory stored form data. If the data - exceeds the value specified an - :exc:`~exceptions.RequestEntityTooLarge` - exception is raised. - :param max_content_length: If this is provided and the transmitted data - is longer than this value an - :exc:`~exceptions.RequestEntityTooLarge` - exception is raised. - :param cls: an optional dict class to use. If this is not specified - or `None` the default :class:`MultiDict` is used. - :param silent: If set to False parsing errors will not be caught. - :return: A tuple in the form ``(stream, form, files)``. - """ - return FormDataParser(stream_factory, charset, errors, - max_form_memory_size, max_content_length, - cls, silent).parse_from_environ(environ) - - -def exhaust_stream(f): - """Helper decorator for methods that exhausts the stream on return.""" - def wrapper(self, stream, *args, **kwargs): - try: - return f(self, stream, *args, **kwargs) - finally: - exhaust = getattr(stream, 'exhaust', None) - if exhaust is not None: - exhaust() - else: - while 1: - chunk = stream.read(1024 * 64) - if not chunk: - break - return update_wrapper(wrapper, f) - - -class FormDataParser(object): - """This class implements parsing of form data for Werkzeug. By itself - it can parse multipart and url encoded form data. It can be subclassed - and extended but for most mimetypes it is a better idea to use the - untouched stream and expose it as separate attributes on a request - object. - - .. versionadded:: 0.8 - - :param stream_factory: An optional callable that returns a new read and - writeable file descriptor. This callable works - the same as :meth:`~BaseResponse._get_file_stream`. - :param charset: The character set for URL and url encoded form data. - :param errors: The encoding error behavior. - :param max_form_memory_size: the maximum number of bytes to be accepted for - in-memory stored form data. If the data - exceeds the value specified an - :exc:`~exceptions.RequestEntityTooLarge` - exception is raised. - :param max_content_length: If this is provided and the transmitted data - is longer than this value an - :exc:`~exceptions.RequestEntityTooLarge` - exception is raised. - :param cls: an optional dict class to use. If this is not specified - or `None` the default :class:`MultiDict` is used. - :param silent: If set to False parsing errors will not be caught. - """ - - def __init__(self, stream_factory=None, charset='utf-8', - errors='replace', max_form_memory_size=None, - max_content_length=None, cls=None, - silent=True): - if stream_factory is None: - stream_factory = default_stream_factory - self.stream_factory = stream_factory - self.charset = charset - self.errors = errors - self.max_form_memory_size = max_form_memory_size - self.max_content_length = max_content_length - if cls is None: - cls = MultiDict - self.cls = cls - self.silent = silent - - def get_parse_func(self, mimetype, options): - return self.parse_functions.get(mimetype) - - def parse_from_environ(self, environ): - """Parses the information from the environment as form data. - - :param environ: the WSGI environment to be used for parsing. - :return: A tuple in the form ``(stream, form, files)``. - """ - content_type = environ.get('CONTENT_TYPE', '') - content_length = get_content_length(environ) - mimetype, options = parse_options_header(content_type) - return self.parse(get_input_stream(environ), mimetype, - content_length, options) - - def parse(self, stream, mimetype, content_length, options=None): - """Parses the information from the given stream, mimetype, - content length and mimetype parameters. - - :param stream: an input stream - :param mimetype: the mimetype of the data - :param content_length: the content length of the incoming data - :param options: optional mimetype parameters (used for - the multipart boundary for instance) - :return: A tuple in the form ``(stream, form, files)``. - """ - if self.max_content_length is not None and \ - content_length is not None and \ - content_length > self.max_content_length: - raise exceptions.RequestEntityTooLarge() - if options is None: - options = {} - - parse_func = self.get_parse_func(mimetype, options) - if parse_func is not None: - try: - return parse_func(self, stream, mimetype, - content_length, options) - except ValueError: - if not self.silent: - raise - - return stream, self.cls(), self.cls() - - @exhaust_stream - def _parse_multipart(self, stream, mimetype, content_length, options): - parser = MultiPartParser(self.stream_factory, self.charset, self.errors, - max_form_memory_size=self.max_form_memory_size, - cls=self.cls) - boundary = options.get('boundary') - if boundary is None: - raise ValueError('Missing boundary') - if isinstance(boundary, text_type): - boundary = boundary.encode('ascii') - form, files = parser.parse(stream, boundary, content_length) - return stream, form, files - - @exhaust_stream - def _parse_urlencoded(self, stream, mimetype, content_length, options): - if self.max_form_memory_size is not None and \ - content_length is not None and \ - content_length > self.max_form_memory_size: - raise exceptions.RequestEntityTooLarge() - form = url_decode_stream(stream, self.charset, - errors=self.errors, cls=self.cls) - return stream, form, self.cls() - - #: mapping of mimetypes to parsing functions - parse_functions = { - 'multipart/form-data': _parse_multipart, - 'application/x-www-form-urlencoded': _parse_urlencoded, - 'application/x-url-encoded': _parse_urlencoded - } - - -def is_valid_multipart_boundary(boundary): - """Checks if the string given is a valid multipart boundary.""" - return _multipart_boundary_re.match(boundary) is not None - - -def _line_parse(line): - """Removes line ending characters and returns a tuple (`stripped_line`, - `is_terminated`). - """ - if line[-2:] in ['\r\n', b'\r\n']: - return line[:-2], True - elif line[-1:] in ['\r', '\n', b'\r', b'\n']: - return line[:-1], True - return line, False - - -def parse_multipart_headers(iterable): - """Parses multipart headers from an iterable that yields lines (including - the trailing newline symbol). The iterable has to be newline terminated. - - The iterable will stop at the line where the headers ended so it can be - further consumed. - - :param iterable: iterable of strings that are newline terminated - """ - result = [] - for line in iterable: - line = to_native(line) - line, line_terminated = _line_parse(line) - if not line_terminated: - raise ValueError('unexpected end of line in multipart header') - if not line: - break - elif line[0] in ' \t' and result: - key, value = result[-1] - result[-1] = (key, value + '\n ' + line[1:]) - else: - parts = line.split(':', 1) - if len(parts) == 2: - result.append((parts[0].strip(), parts[1].strip())) - - # we link the list to the headers, no need to create a copy, the - # list was not shared anyways. - return Headers(result) - - -_begin_form = 'begin_form' -_begin_file = 'begin_file' -_cont = 'cont' -_end = 'end' - - -class MultiPartParser(object): - - def __init__(self, stream_factory=None, charset='utf-8', errors='replace', - max_form_memory_size=None, cls=None, buffer_size=64 * 1024): - self.stream_factory = stream_factory - self.charset = charset - self.errors = errors - self.max_form_memory_size = max_form_memory_size - if stream_factory is None: - stream_factory = default_stream_factory - if cls is None: - cls = MultiDict - self.cls = cls - - # make sure the buffer size is divisible by four so that we can base64 - # decode chunk by chunk - assert buffer_size % 4 == 0, 'buffer size has to be divisible by 4' - # also the buffer size has to be at least 1024 bytes long or long headers - # will freak out the system - assert buffer_size >= 1024, 'buffer size has to be at least 1KB' - - self.buffer_size = buffer_size - - def _fix_ie_filename(self, filename): - """Internet Explorer 6 transmits the full file name if a file is - uploaded. This function strips the full path if it thinks the - filename is Windows-like absolute. - """ - if filename[1:3] == ':\\' or filename[:2] == '\\\\': - return filename.split('\\')[-1] - return filename - - def _find_terminator(self, iterator): - """The terminator might have some additional newlines before it. - There is at least one application that sends additional newlines - before headers (the python setuptools package). - """ - for line in iterator: - if not line: - break - line = line.strip() - if line: - return line - return b'' - - def fail(self, message): - raise ValueError(message) - - def get_part_encoding(self, headers): - transfer_encoding = headers.get('content-transfer-encoding') - if transfer_encoding is not None and \ - transfer_encoding in _supported_multipart_encodings: - return transfer_encoding - - def get_part_charset(self, headers): - # Figure out input charset for current part - content_type = headers.get('content-type') - if content_type: - mimetype, ct_params = parse_options_header(content_type) - return ct_params.get('charset', self.charset) - return self.charset - - def start_file_streaming(self, filename, headers, total_content_length): - if isinstance(filename, bytes): - filename = filename.decode(self.charset, self.errors) - filename = self._fix_ie_filename(filename) - content_type = headers.get('content-type') - try: - content_length = int(headers['content-length']) - except (KeyError, ValueError): - content_length = 0 - container = self.stream_factory(total_content_length, content_type, - filename, content_length) - return filename, container - - def in_memory_threshold_reached(self, bytes): - raise exceptions.RequestEntityTooLarge() - - def validate_boundary(self, boundary): - if not boundary: - self.fail('Missing boundary') - if not is_valid_multipart_boundary(boundary): - self.fail('Invalid boundary: %s' % boundary) - if len(boundary) > self.buffer_size: # pragma: no cover - # this should never happen because we check for a minimum size - # of 1024 and boundaries may not be longer than 200. The only - # situation when this happens is for non debug builds where - # the assert is skipped. - self.fail('Boundary longer than buffer size') - - def parse_lines(self, file, boundary, content_length): - """Generate parts of - ``('begin_form', (headers, name))`` - ``('begin_file', (headers, name, filename))`` - ``('cont', bytestring)`` - ``('end', None)`` - - Always obeys the grammar - parts = ( begin_form cont* end | - begin_file cont* end )* - """ - next_part = b'--' + boundary - last_part = next_part + b'--' - - iterator = chain(make_line_iter(file, limit=content_length, - buffer_size=self.buffer_size), - _empty_string_iter) - - terminator = self._find_terminator(iterator) - - if terminator == last_part: - return - elif terminator != next_part: - self.fail('Expected boundary at start of multipart data') - - while terminator != last_part: - headers = parse_multipart_headers(iterator) - - disposition = headers.get('content-disposition') - if disposition is None: - self.fail('Missing Content-Disposition header') - disposition, extra = parse_options_header(disposition) - transfer_encoding = self.get_part_encoding(headers) - name = extra.get('name') - filename = extra.get('filename') - - # if no content type is given we stream into memory. A list is - # used as a temporary container. - if filename is None: - yield _begin_form, (headers, name) - - # otherwise we parse the rest of the headers and ask the stream - # factory for something we can write in. - else: - yield _begin_file, (headers, name, filename) - - buf = b'' - for line in iterator: - if not line: - self.fail('unexpected end of stream') - - if line[:2] == b'--': - terminator = line.rstrip() - if terminator in (next_part, last_part): - break - - if transfer_encoding is not None: - if transfer_encoding == 'base64': - transfer_encoding = 'base64_codec' - try: - line = codecs.decode(line, transfer_encoding) - except Exception: - self.fail('could not decode transfer encoded chunk') - - # we have something in the buffer from the last iteration. - # this is usually a newline delimiter. - if buf: - yield _cont, buf - buf = b'' - - # If the line ends with windows CRLF we write everything except - # the last two bytes. In all other cases however we write - # everything except the last byte. If it was a newline, that's - # fine, otherwise it does not matter because we will write it - # the next iteration. this ensures we do not write the - # final newline into the stream. That way we do not have to - # truncate the stream. However we do have to make sure that - # if something else than a newline is in there we write it - # out. - if line[-2:] == b'\r\n': - buf = b'\r\n' - cutoff = -2 - else: - buf = line[-1:] - cutoff = -1 - yield _cont, line[:cutoff] - - else: # pragma: no cover - raise ValueError('unexpected end of part') - - # if we have a leftover in the buffer that is not a newline - # character we have to flush it, otherwise we will chop of - # certain values. - if buf not in (b'', b'\r', b'\n', b'\r\n'): - yield _cont, buf - - yield _end, None - - def parse_parts(self, file, boundary, content_length): - """Generate ``('file', (name, val))`` and - ``('form', (name, val))`` parts. - """ - in_memory = 0 - - for ellt, ell in self.parse_lines(file, boundary, content_length): - if ellt == _begin_file: - headers, name, filename = ell - is_file = True - guard_memory = False - filename, container = self.start_file_streaming( - filename, headers, content_length) - _write = container.write - - elif ellt == _begin_form: - headers, name = ell - is_file = False - container = [] - _write = container.append - guard_memory = self.max_form_memory_size is not None - - elif ellt == _cont: - _write(ell) - # if we write into memory and there is a memory size limit we - # count the number of bytes in memory and raise an exception if - # there is too much data in memory. - if guard_memory: - in_memory += len(ell) - if in_memory > self.max_form_memory_size: - self.in_memory_threshold_reached(in_memory) - - elif ellt == _end: - if is_file: - container.seek(0) - yield ('file', - (name, FileStorage(container, filename, name, - headers=headers))) - else: - part_charset = self.get_part_charset(headers) - yield ('form', - (name, b''.join(container).decode( - part_charset, self.errors))) - - def parse(self, file, boundary, content_length): - formstream, filestream = tee( - self.parse_parts(file, boundary, content_length), 2) - form = (p[1] for p in formstream if p[0] == 'form') - files = (p[1] for p in filestream if p[0] == 'file') - return self.cls(form), self.cls(files) - - -from werkzeug import exceptions diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/http.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/http.py deleted file mode 100644 index 27f7ae7b..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/http.py +++ /dev/null @@ -1,980 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.http - ~~~~~~~~~~~~~ - - Werkzeug comes with a bunch of utilities that help Werkzeug to deal with - HTTP data. Most of the classes and functions provided by this module are - used by the wrappers, but they are useful on their own, too, especially if - the response and request objects are not used. - - This covers some of the more HTTP centric features of WSGI, some other - utilities such as cookie handling are documented in the `werkzeug.utils` - module. - - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -import re -from time import time, gmtime -try: - from email.utils import parsedate_tz -except ImportError: # pragma: no cover - from email.Utils import parsedate_tz -try: - from urllib2 import parse_http_list as _parse_list_header -except ImportError: # pragma: no cover - from urllib.request import parse_http_list as _parse_list_header -from datetime import datetime, timedelta -from hashlib import md5 -import base64 - -from werkzeug._internal import _cookie_quote, _make_cookie_domain, \ - _cookie_parse_impl -from werkzeug._compat import to_unicode, iteritems, text_type, \ - string_types, try_coerce_native, to_bytes, PY2, \ - integer_types - - -# incorrect -_cookie_charset = 'latin1' -_accept_re = re.compile(r'([^\s;,]+)(?:[^,]*?;\s*q=(\d*(?:\.\d+)?))?') -_token_chars = frozenset("!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" - '^_`abcdefghijklmnopqrstuvwxyz|~') -_etag_re = re.compile(r'([Ww]/)?(?:"(.*?)"|(.*?))(?:\s*,\s*|$)') -_unsafe_header_chars = set('()<>@,;:\"/[]?={} \t') -_quoted_string_re = r'"[^"\\]*(?:\\.[^"\\]*)*"' -_option_header_piece_re = re.compile(r';\s*(%s|[^\s;=]+)\s*(?:=\s*(%s|[^;]+))?\s*' % - (_quoted_string_re, _quoted_string_re)) - -_entity_headers = frozenset([ - 'allow', 'content-encoding', 'content-language', 'content-length', - 'content-location', 'content-md5', 'content-range', 'content-type', - 'expires', 'last-modified' -]) -_hop_by_hop_headers = frozenset([ - 'connection', 'keep-alive', 'proxy-authenticate', - 'proxy-authorization', 'te', 'trailer', 'transfer-encoding', - 'upgrade' -]) - - -HTTP_STATUS_CODES = { - 100: 'Continue', - 101: 'Switching Protocols', - 102: 'Processing', - 200: 'OK', - 201: 'Created', - 202: 'Accepted', - 203: 'Non Authoritative Information', - 204: 'No Content', - 205: 'Reset Content', - 206: 'Partial Content', - 207: 'Multi Status', - 226: 'IM Used', # see RFC 3229 - 300: 'Multiple Choices', - 301: 'Moved Permanently', - 302: 'Found', - 303: 'See Other', - 304: 'Not Modified', - 305: 'Use Proxy', - 307: 'Temporary Redirect', - 400: 'Bad Request', - 401: 'Unauthorized', - 402: 'Payment Required', # unused - 403: 'Forbidden', - 404: 'Not Found', - 405: 'Method Not Allowed', - 406: 'Not Acceptable', - 407: 'Proxy Authentication Required', - 408: 'Request Timeout', - 409: 'Conflict', - 410: 'Gone', - 411: 'Length Required', - 412: 'Precondition Failed', - 413: 'Request Entity Too Large', - 414: 'Request URI Too Long', - 415: 'Unsupported Media Type', - 416: 'Requested Range Not Satisfiable', - 417: 'Expectation Failed', - 418: 'I\'m a teapot', # see RFC 2324 - 422: 'Unprocessable Entity', - 423: 'Locked', - 424: 'Failed Dependency', - 426: 'Upgrade Required', - 428: 'Precondition Required', # see RFC 6585 - 429: 'Too Many Requests', - 431: 'Request Header Fields Too Large', - 449: 'Retry With', # proprietary MS extension - 500: 'Internal Server Error', - 501: 'Not Implemented', - 502: 'Bad Gateway', - 503: 'Service Unavailable', - 504: 'Gateway Timeout', - 505: 'HTTP Version Not Supported', - 507: 'Insufficient Storage', - 510: 'Not Extended' -} - - -def wsgi_to_bytes(data): - """coerce wsgi unicode represented bytes to real ones - - """ - if isinstance(data, bytes): - return data - return data.encode('latin1') #XXX: utf8 fallback? - - -def bytes_to_wsgi(data): - assert isinstance(data, bytes), 'data must be bytes' - if isinstance(data, str): - return data - else: - return data.decode('latin1') - - -def quote_header_value(value, extra_chars='', allow_token=True): - """Quote a header value if necessary. - - .. versionadded:: 0.5 - - :param value: the value to quote. - :param extra_chars: a list of extra characters to skip quoting. - :param allow_token: if this is enabled token values are returned - unchanged. - """ - if isinstance(value, bytes): - value = bytes_to_wsgi(value) - value = str(value) - if allow_token: - token_chars = _token_chars | set(extra_chars) - if set(value).issubset(token_chars): - return value - return '"%s"' % value.replace('\\', '\\\\').replace('"', '\\"') - - -def unquote_header_value(value, is_filename=False): - r"""Unquotes a header value. (Reversal of :func:`quote_header_value`). - This does not use the real unquoting but what browsers are actually - using for quoting. - - .. versionadded:: 0.5 - - :param value: the header value to unquote. - """ - if value and value[0] == value[-1] == '"': - # this is not the real unquoting, but fixing this so that the - # RFC is met will result in bugs with internet explorer and - # probably some other browsers as well. IE for example is - # uploading files with "C:\foo\bar.txt" as filename - value = value[1:-1] - - # if this is a filename and the starting characters look like - # a UNC path, then just return the value without quotes. Using the - # replace sequence below on a UNC path has the effect of turning - # the leading double slash into a single slash and then - # _fix_ie_filename() doesn't work correctly. See #458. - if not is_filename or value[:2] != '\\\\': - return value.replace('\\\\', '\\').replace('\\"', '"') - return value - - -def dump_options_header(header, options): - """The reverse function to :func:`parse_options_header`. - - :param header: the header to dump - :param options: a dict of options to append. - """ - segments = [] - if header is not None: - segments.append(header) - for key, value in iteritems(options): - if value is None: - segments.append(key) - else: - segments.append('%s=%s' % (key, quote_header_value(value))) - return '; '.join(segments) - - -def dump_header(iterable, allow_token=True): - """Dump an HTTP header again. This is the reversal of - :func:`parse_list_header`, :func:`parse_set_header` and - :func:`parse_dict_header`. This also quotes strings that include an - equals sign unless you pass it as dict of key, value pairs. - - >>> dump_header({'foo': 'bar baz'}) - 'foo="bar baz"' - >>> dump_header(('foo', 'bar baz')) - 'foo, "bar baz"' - - :param iterable: the iterable or dict of values to quote. - :param allow_token: if set to `False` tokens as values are disallowed. - See :func:`quote_header_value` for more details. - """ - if isinstance(iterable, dict): - items = [] - for key, value in iteritems(iterable): - if value is None: - items.append(key) - else: - items.append('%s=%s' % ( - key, - quote_header_value(value, allow_token=allow_token) - )) - else: - items = [quote_header_value(x, allow_token=allow_token) - for x in iterable] - return ', '.join(items) - - -def parse_list_header(value): - """Parse lists as described by RFC 2068 Section 2. - - In particular, parse comma-separated lists where the elements of - the list may include quoted-strings. A quoted-string could - contain a comma. A non-quoted string could have quotes in the - middle. Quotes are removed automatically after parsing. - - It basically works like :func:`parse_set_header` just that items - may appear multiple times and case sensitivity is preserved. - - The return value is a standard :class:`list`: - - >>> parse_list_header('token, "quoted value"') - ['token', 'quoted value'] - - To create a header from the :class:`list` again, use the - :func:`dump_header` function. - - :param value: a string with a list header. - :return: :class:`list` - """ - result = [] - for item in _parse_list_header(value): - if item[:1] == item[-1:] == '"': - item = unquote_header_value(item[1:-1]) - result.append(item) - return result - - -def parse_dict_header(value, cls=dict): - """Parse lists of key, value pairs as described by RFC 2068 Section 2 and - convert them into a python dict (or any other mapping object created from - the type with a dict like interface provided by the `cls` arugment): - - >>> d = parse_dict_header('foo="is a fish", bar="as well"') - >>> type(d) is dict - True - >>> sorted(d.items()) - [('bar', 'as well'), ('foo', 'is a fish')] - - If there is no value for a key it will be `None`: - - >>> parse_dict_header('key_without_value') - {'key_without_value': None} - - To create a header from the :class:`dict` again, use the - :func:`dump_header` function. - - .. versionchanged:: 0.9 - Added support for `cls` argument. - - :param value: a string with a dict header. - :param cls: callable to use for storage of parsed results. - :return: an instance of `cls` - """ - result = cls() - if not isinstance(value, text_type): - #XXX: validate - value = bytes_to_wsgi(value) - for item in _parse_list_header(value): - if '=' not in item: - result[item] = None - continue - name, value = item.split('=', 1) - if value[:1] == value[-1:] == '"': - value = unquote_header_value(value[1:-1]) - result[name] = value - return result - - -def parse_options_header(value): - """Parse a ``Content-Type`` like header into a tuple with the content - type and the options: - - >>> parse_options_header('text/html; charset=utf8') - ('text/html', {'charset': 'utf8'}) - - This should not be used to parse ``Cache-Control`` like headers that use - a slightly different format. For these headers use the - :func:`parse_dict_header` function. - - .. versionadded:: 0.5 - - :param value: the header to parse. - :return: (str, options) - """ - def _tokenize(string): - for match in _option_header_piece_re.finditer(string): - key, value = match.groups() - key = unquote_header_value(key) - if value is not None: - value = unquote_header_value(value, key == 'filename') - yield key, value - - if not value: - return '', {} - - parts = _tokenize(';' + value) - name = next(parts)[0] - extra = dict(parts) - return name, extra - - -def parse_accept_header(value, cls=None): - """Parses an HTTP Accept-* header. This does not implement a complete - valid algorithm but one that supports at least value and quality - extraction. - - Returns a new :class:`Accept` object (basically a list of ``(value, quality)`` - tuples sorted by the quality with some additional accessor methods). - - The second parameter can be a subclass of :class:`Accept` that is created - with the parsed values and returned. - - :param value: the accept header string to be parsed. - :param cls: the wrapper class for the return value (can be - :class:`Accept` or a subclass thereof) - :return: an instance of `cls`. - """ - if cls is None: - cls = Accept - - if not value: - return cls(None) - - result = [] - for match in _accept_re.finditer(value): - quality = match.group(2) - if not quality: - quality = 1 - else: - quality = max(min(float(quality), 1), 0) - result.append((match.group(1), quality)) - return cls(result) - - -def parse_cache_control_header(value, on_update=None, cls=None): - """Parse a cache control header. The RFC differs between response and - request cache control, this method does not. It's your responsibility - to not use the wrong control statements. - - .. versionadded:: 0.5 - The `cls` was added. If not specified an immutable - :class:`~werkzeug.datastructures.RequestCacheControl` is returned. - - :param value: a cache control header to be parsed. - :param on_update: an optional callable that is called every time a value - on the :class:`~werkzeug.datastructures.CacheControl` - object is changed. - :param cls: the class for the returned object. By default - :class:`~werkzeug.datastructures.RequestCacheControl` is used. - :return: a `cls` object. - """ - if cls is None: - cls = RequestCacheControl - if not value: - return cls(None, on_update) - return cls(parse_dict_header(value), on_update) - - -def parse_set_header(value, on_update=None): - """Parse a set-like header and return a - :class:`~werkzeug.datastructures.HeaderSet` object: - - >>> hs = parse_set_header('token, "quoted value"') - - The return value is an object that treats the items case-insensitively - and keeps the order of the items: - - >>> 'TOKEN' in hs - True - >>> hs.index('quoted value') - 1 - >>> hs - HeaderSet(['token', 'quoted value']) - - To create a header from the :class:`HeaderSet` again, use the - :func:`dump_header` function. - - :param value: a set header to be parsed. - :param on_update: an optional callable that is called every time a - value on the :class:`~werkzeug.datastructures.HeaderSet` - object is changed. - :return: a :class:`~werkzeug.datastructures.HeaderSet` - """ - if not value: - return HeaderSet(None, on_update) - return HeaderSet(parse_list_header(value), on_update) - - -def parse_authorization_header(value): - """Parse an HTTP basic/digest authorization header transmitted by the web - browser. The return value is either `None` if the header was invalid or - not given, otherwise an :class:`~werkzeug.datastructures.Authorization` - object. - - :param value: the authorization header to parse. - :return: a :class:`~werkzeug.datastructures.Authorization` object or `None`. - """ - if not value: - return - value = wsgi_to_bytes(value) - try: - auth_type, auth_info = value.split(None, 1) - auth_type = auth_type.lower() - except ValueError: - return - if auth_type == b'basic': - try: - username, password = base64.b64decode(auth_info).split(b':', 1) - except Exception as e: - return - return Authorization('basic', {'username': bytes_to_wsgi(username), - 'password': bytes_to_wsgi(password)}) - elif auth_type == b'digest': - auth_map = parse_dict_header(auth_info) - for key in 'username', 'realm', 'nonce', 'uri', 'response': - if not key in auth_map: - return - if 'qop' in auth_map: - if not auth_map.get('nc') or not auth_map.get('cnonce'): - return - return Authorization('digest', auth_map) - - -def parse_www_authenticate_header(value, on_update=None): - """Parse an HTTP WWW-Authenticate header into a - :class:`~werkzeug.datastructures.WWWAuthenticate` object. - - :param value: a WWW-Authenticate header to parse. - :param on_update: an optional callable that is called every time a value - on the :class:`~werkzeug.datastructures.WWWAuthenticate` - object is changed. - :return: a :class:`~werkzeug.datastructures.WWWAuthenticate` object. - """ - if not value: - return WWWAuthenticate(on_update=on_update) - try: - auth_type, auth_info = value.split(None, 1) - auth_type = auth_type.lower() - except (ValueError, AttributeError): - return WWWAuthenticate(value.strip().lower(), on_update=on_update) - return WWWAuthenticate(auth_type, parse_dict_header(auth_info), - on_update) - - -def parse_if_range_header(value): - """Parses an if-range header which can be an etag or a date. Returns - a :class:`~werkzeug.datastructures.IfRange` object. - - .. versionadded:: 0.7 - """ - if not value: - return IfRange() - date = parse_date(value) - if date is not None: - return IfRange(date=date) - # drop weakness information - return IfRange(unquote_etag(value)[0]) - - -def parse_range_header(value, make_inclusive=True): - """Parses a range header into a :class:`~werkzeug.datastructures.Range` - object. If the header is missing or malformed `None` is returned. - `ranges` is a list of ``(start, stop)`` tuples where the ranges are - non-inclusive. - - .. versionadded:: 0.7 - """ - if not value or '=' not in value: - return None - - ranges = [] - last_end = 0 - units, rng = value.split('=', 1) - units = units.strip().lower() - - for item in rng.split(','): - item = item.strip() - if '-' not in item: - return None - if item.startswith('-'): - if last_end < 0: - return None - begin = int(item) - end = None - last_end = -1 - elif '-' in item: - begin, end = item.split('-', 1) - begin = int(begin) - if begin < last_end or last_end < 0: - return None - if end: - end = int(end) + 1 - if begin >= end: - return None - else: - end = None - last_end = end - ranges.append((begin, end)) - - return Range(units, ranges) - - -def parse_content_range_header(value, on_update=None): - """Parses a range header into a - :class:`~werkzeug.datastructures.ContentRange` object or `None` if - parsing is not possible. - - .. versionadded:: 0.7 - - :param value: a content range header to be parsed. - :param on_update: an optional callable that is called every time a value - on the :class:`~werkzeug.datastructures.ContentRange` - object is changed. - """ - if value is None: - return None - try: - units, rangedef = (value or '').strip().split(None, 1) - except ValueError: - return None - - if '/' not in rangedef: - return None - rng, length = rangedef.split('/', 1) - if length == '*': - length = None - elif length.isdigit(): - length = int(length) - else: - return None - - if rng == '*': - return ContentRange(units, None, None, length, on_update=on_update) - elif '-' not in rng: - return None - - start, stop = rng.split('-', 1) - try: - start = int(start) - stop = int(stop) + 1 - except ValueError: - return None - - if is_byte_range_valid(start, stop, length): - return ContentRange(units, start, stop, length, on_update=on_update) - - -def quote_etag(etag, weak=False): - """Quote an etag. - - :param etag: the etag to quote. - :param weak: set to `True` to tag it "weak". - """ - if '"' in etag: - raise ValueError('invalid etag') - etag = '"%s"' % etag - if weak: - etag = 'w/' + etag - return etag - - -def unquote_etag(etag): - """Unquote a single etag: - - >>> unquote_etag('w/"bar"') - ('bar', True) - >>> unquote_etag('"bar"') - ('bar', False) - - :param etag: the etag identifier to unquote. - :return: a ``(etag, weak)`` tuple. - """ - if not etag: - return None, None - etag = etag.strip() - weak = False - if etag[:2] in ('w/', 'W/'): - weak = True - etag = etag[2:] - if etag[:1] == etag[-1:] == '"': - etag = etag[1:-1] - return etag, weak - - -def parse_etags(value): - """Parse an etag header. - - :param value: the tag header to parse - :return: an :class:`~werkzeug.datastructures.ETags` object. - """ - if not value: - return ETags() - strong = [] - weak = [] - end = len(value) - pos = 0 - while pos < end: - match = _etag_re.match(value, pos) - if match is None: - break - is_weak, quoted, raw = match.groups() - if raw == '*': - return ETags(star_tag=True) - elif quoted: - raw = quoted - if is_weak: - weak.append(raw) - else: - strong.append(raw) - pos = match.end() - return ETags(strong, weak) - - -def generate_etag(data): - """Generate an etag for some data.""" - return md5(data).hexdigest() - - -def parse_date(value): - """Parse one of the following date formats into a datetime object: - - .. sourcecode:: text - - Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 - Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 - Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format - - If parsing fails the return value is `None`. - - :param value: a string with a supported date format. - :return: a :class:`datetime.datetime` object. - """ - if value: - t = parsedate_tz(value.strip()) - if t is not None: - try: - year = t[0] - # unfortunately that function does not tell us if two digit - # years were part of the string, or if they were prefixed - # with two zeroes. So what we do is to assume that 69-99 - # refer to 1900, and everything below to 2000 - if year >= 0 and year <= 68: - year += 2000 - elif year >= 69 and year <= 99: - year += 1900 - return datetime(*((year,) + t[1:7])) - \ - timedelta(seconds=t[-1] or 0) - except (ValueError, OverflowError): - return None - - -def _dump_date(d, delim): - """Used for `http_date` and `cookie_date`.""" - if d is None: - d = gmtime() - elif isinstance(d, datetime): - d = d.utctimetuple() - elif isinstance(d, (integer_types, float)): - d = gmtime(d) - return '%s, %02d%s%s%s%s %02d:%02d:%02d GMT' % ( - ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')[d.tm_wday], - d.tm_mday, delim, - ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec')[d.tm_mon - 1], - delim, str(d.tm_year), d.tm_hour, d.tm_min, d.tm_sec - ) - - -def cookie_date(expires=None): - """Formats the time to ensure compatibility with Netscape's cookie - standard. - - Accepts a floating point number expressed in seconds since the epoch in, a - datetime object or a timetuple. All times in UTC. The :func:`parse_date` - function can be used to parse such a date. - - Outputs a string in the format ``Wdy, DD-Mon-YYYY HH:MM:SS GMT``. - - :param expires: If provided that date is used, otherwise the current. - """ - return _dump_date(expires, '-') - - -def http_date(timestamp=None): - """Formats the time to match the RFC1123 date format. - - Accepts a floating point number expressed in seconds since the epoch in, a - datetime object or a timetuple. All times in UTC. The :func:`parse_date` - function can be used to parse such a date. - - Outputs a string in the format ``Wdy, DD Mon YYYY HH:MM:SS GMT``. - - :param timestamp: If provided that date is used, otherwise the current. - """ - return _dump_date(timestamp, ' ') - - -def is_resource_modified(environ, etag=None, data=None, last_modified=None): - """Convenience method for conditional requests. - - :param environ: the WSGI environment of the request to be checked. - :param etag: the etag for the response for comparison. - :param data: or alternatively the data of the response to automatically - generate an etag using :func:`generate_etag`. - :param last_modified: an optional date of the last modification. - :return: `True` if the resource was modified, otherwise `False`. - """ - if etag is None and data is not None: - etag = generate_etag(data) - elif data is not None: - raise TypeError('both data and etag given') - if environ['REQUEST_METHOD'] not in ('GET', 'HEAD'): - return False - - unmodified = False - if isinstance(last_modified, string_types): - last_modified = parse_date(last_modified) - - # ensure that microsecond is zero because the HTTP spec does not transmit - # that either and we might have some false positives. See issue #39 - if last_modified is not None: - last_modified = last_modified.replace(microsecond=0) - - modified_since = parse_date(environ.get('HTTP_IF_MODIFIED_SINCE')) - - if modified_since and last_modified and last_modified <= modified_since: - unmodified = True - if etag: - if_none_match = parse_etags(environ.get('HTTP_IF_NONE_MATCH')) - if if_none_match: - unmodified = if_none_match.contains_raw(etag) - - return not unmodified - - -def remove_entity_headers(headers, allowed=('expires', 'content-location')): - """Remove all entity headers from a list or :class:`Headers` object. This - operation works in-place. `Expires` and `Content-Location` headers are - by default not removed. The reason for this is :rfc:`2616` section - 10.3.5 which specifies some entity headers that should be sent. - - .. versionchanged:: 0.5 - added `allowed` parameter. - - :param headers: a list or :class:`Headers` object. - :param allowed: a list of headers that should still be allowed even though - they are entity headers. - """ - allowed = set(x.lower() for x in allowed) - headers[:] = [(key, value) for key, value in headers if - not is_entity_header(key) or key.lower() in allowed] - - -def remove_hop_by_hop_headers(headers): - """Remove all HTTP/1.1 "Hop-by-Hop" headers from a list or - :class:`Headers` object. This operation works in-place. - - .. versionadded:: 0.5 - - :param headers: a list or :class:`Headers` object. - """ - headers[:] = [(key, value) for key, value in headers if - not is_hop_by_hop_header(key)] - - -def is_entity_header(header): - """Check if a header is an entity header. - - .. versionadded:: 0.5 - - :param header: the header to test. - :return: `True` if it's an entity header, `False` otherwise. - """ - return header.lower() in _entity_headers - - -def is_hop_by_hop_header(header): - """Check if a header is an HTTP/1.1 "Hop-by-Hop" header. - - .. versionadded:: 0.5 - - :param header: the header to test. - :return: `True` if it's an entity header, `False` otherwise. - """ - return header.lower() in _hop_by_hop_headers - - -def parse_cookie(header, charset='utf-8', errors='replace', cls=None): - """Parse a cookie. Either from a string or WSGI environ. - - Per default encoding errors are ignored. If you want a different behavior - you can set `errors` to ``'replace'`` or ``'strict'``. In strict mode a - :exc:`HTTPUnicodeError` is raised. - - .. versionchanged:: 0.5 - This function now returns a :class:`TypeConversionDict` instead of a - regular dict. The `cls` parameter was added. - - :param header: the header to be used to parse the cookie. Alternatively - this can be a WSGI environment. - :param charset: the charset for the cookie values. - :param errors: the error behavior for the charset decoding. - :param cls: an optional dict class to use. If this is not specified - or `None` the default :class:`TypeConversionDict` is - used. - """ - if isinstance(header, dict): - header = header.get('HTTP_COOKIE', '') - elif header is None: - header = '' - - # If the value is an unicode string it's mangled through latin1. This - # is done because on PEP 3333 on Python 3 all headers are assumed latin1 - # which however is incorrect for cookies, which are sent in page encoding. - # As a result we - if isinstance(header, text_type): - header = header.encode('latin1', 'replace') - - if cls is None: - cls = TypeConversionDict - - def _parse_pairs(): - for key, val in _cookie_parse_impl(header): - key = to_unicode(key, charset, errors, allow_none_charset=True) - val = to_unicode(val, charset, errors, allow_none_charset=True) - yield try_coerce_native(key), val - - return cls(_parse_pairs()) - - -def dump_cookie(key, value='', max_age=None, expires=None, path='/', - domain=None, secure=False, httponly=False, - charset='utf-8', sync_expires=True): - """Creates a new Set-Cookie header without the ``Set-Cookie`` prefix - The parameters are the same as in the cookie Morsel object in the - Python standard library but it accepts unicode data, too. - - On Python 3 the return value of this function will be a unicode - string, on Python 2 it will be a native string. In both cases the - return value is usually restricted to ascii as the vast majority of - values are properly escaped, but that is no guarantee. If a unicode - string is returned it's tunneled through latin1 as required by - PEP 3333. - - The return value is not ASCII safe if the key contains unicode - characters. This is technically against the specification but - happens in the wild. It's strongly recommended to not use - non-ASCII values for the keys. - - :param max_age: should be a number of seconds, or `None` (default) if - the cookie should last only as long as the client's - browser session. Additionally `timedelta` objects - are accepted, too. - :param expires: should be a `datetime` object or unix timestamp. - :param path: limits the cookie to a given path, per default it will - span the whole domain. - :param domain: Use this if you want to set a cross-domain cookie. For - example, ``domain=".example.com"`` will set a cookie - that is readable by the domain ``www.example.com``, - ``foo.example.com`` etc. Otherwise, a cookie will only - be readable by the domain that set it. - :param secure: The cookie will only be available via HTTPS - :param httponly: disallow JavaScript to access the cookie. This is an - extension to the cookie standard and probably not - supported by all browsers. - :param charset: the encoding for unicode values. - :param sync_expires: automatically set expires if max_age is defined - but expires not. - """ - key = to_bytes(key, charset) - value = to_bytes(value, charset) - - if path is not None: - path = iri_to_uri(path, charset) - domain = _make_cookie_domain(domain) - if isinstance(max_age, timedelta): - max_age = (max_age.days * 60 * 60 * 24) + max_age.seconds - if expires is not None: - if not isinstance(expires, string_types): - expires = cookie_date(expires) - elif max_age is not None and sync_expires: - expires = to_bytes(cookie_date(time() + max_age)) - - buf = [key + b'=' + _cookie_quote(value)] - - # XXX: In theory all of these parameters that are not marked with `None` - # should be quoted. Because stdlib did not quote it before I did not - # want to introduce quoting there now. - for k, v, q in ((b'Domain', domain, True), - (b'Expires', expires, False,), - (b'Max-Age', max_age, False), - (b'Secure', secure, None), - (b'HttpOnly', httponly, None), - (b'Path', path, False)): - if q is None: - if v: - buf.append(k) - continue - - if v is None: - continue - - tmp = bytearray(k) - if not isinstance(v, (bytes, bytearray)): - v = to_bytes(text_type(v), charset) - if q: - v = _cookie_quote(v) - tmp += b'=' + v - buf.append(bytes(tmp)) - - # The return value will be an incorrectly encoded latin1 header on - # Python 3 for consistency with the headers object and a bytestring - # on Python 2 because that's how the API makes more sense. - rv = b'; '.join(buf) - if not PY2: - rv = rv.decode('latin1') - return rv - - -def is_byte_range_valid(start, stop, length): - """Checks if a given byte content range is valid for the given length. - - .. versionadded:: 0.7 - """ - if (start is None) != (stop is None): - return False - elif start is None: - return length is None or length >= 0 - elif length is None: - return 0 <= start < stop - elif start >= stop: - return False - return 0 <= start < length - - -# circular dependency fun -from werkzeug.datastructures import Accept, HeaderSet, ETags, Authorization, \ - WWWAuthenticate, TypeConversionDict, IfRange, Range, ContentRange, \ - RequestCacheControl - - -# DEPRECATED -# backwards compatible imports -from werkzeug.datastructures import MIMEAccept, CharsetAccept, \ - LanguageAccept, Headers -from werkzeug.urls import iri_to_uri diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/local.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/local.py deleted file mode 100644 index 04ad6203..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/local.py +++ /dev/null @@ -1,409 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.local - ~~~~~~~~~~~~~~ - - This module implements context-local objects. - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -from functools import update_wrapper -from werkzeug.wsgi import ClosingIterator -from werkzeug._compat import PY2, implements_bool - -# since each thread has its own greenlet we can just use those as identifiers -# for the context. If greenlets are not available we fall back to the -# current thread ident depending on where it is. -try: - from greenlet import getcurrent as get_ident -except ImportError: - try: - from thread import get_ident - except ImportError: - from _thread import get_ident - - -def release_local(local): - """Releases the contents of the local for the current context. - This makes it possible to use locals without a manager. - - Example:: - - >>> loc = Local() - >>> loc.foo = 42 - >>> release_local(loc) - >>> hasattr(loc, 'foo') - False - - With this function one can release :class:`Local` objects as well - as :class:`LocalStack` objects. However it is not possible to - release data held by proxies that way, one always has to retain - a reference to the underlying local object in order to be able - to release it. - - .. versionadded:: 0.6.1 - """ - local.__release_local__() - - -class Local(object): - __slots__ = ('__storage__', '__ident_func__') - - def __init__(self): - object.__setattr__(self, '__storage__', {}) - object.__setattr__(self, '__ident_func__', get_ident) - - def __iter__(self): - return iter(self.__storage__.items()) - - def __call__(self, proxy): - """Create a proxy for a name.""" - return LocalProxy(self, proxy) - - def __release_local__(self): - self.__storage__.pop(self.__ident_func__(), None) - - def __getattr__(self, name): - try: - return self.__storage__[self.__ident_func__()][name] - except KeyError: - raise AttributeError(name) - - def __setattr__(self, name, value): - ident = self.__ident_func__() - storage = self.__storage__ - try: - storage[ident][name] = value - except KeyError: - storage[ident] = {name: value} - - def __delattr__(self, name): - try: - del self.__storage__[self.__ident_func__()][name] - except KeyError: - raise AttributeError(name) - - -class LocalStack(object): - """This class works similar to a :class:`Local` but keeps a stack - of objects instead. This is best explained with an example:: - - >>> ls = LocalStack() - >>> ls.push(42) - >>> ls.top - 42 - >>> ls.push(23) - >>> ls.top - 23 - >>> ls.pop() - 23 - >>> ls.top - 42 - - They can be force released by using a :class:`LocalManager` or with - the :func:`release_local` function but the correct way is to pop the - item from the stack after using. When the stack is empty it will - no longer be bound to the current context (and as such released). - - By calling the stack without arguments it returns a proxy that resolves to - the topmost item on the stack. - - .. versionadded:: 0.6.1 - """ - - def __init__(self): - self._local = Local() - - def __release_local__(self): - self._local.__release_local__() - - def _get__ident_func__(self): - return self._local.__ident_func__ - def _set__ident_func__(self, value): - object.__setattr__(self._local, '__ident_func__', value) - __ident_func__ = property(_get__ident_func__, _set__ident_func__) - del _get__ident_func__, _set__ident_func__ - - def __call__(self): - def _lookup(): - rv = self.top - if rv is None: - raise RuntimeError('object unbound') - return rv - return LocalProxy(_lookup) - - def push(self, obj): - """Pushes a new item to the stack""" - rv = getattr(self._local, 'stack', None) - if rv is None: - self._local.stack = rv = [] - rv.append(obj) - return rv - - def pop(self): - """Removes the topmost item from the stack, will return the - old value or `None` if the stack was already empty. - """ - stack = getattr(self._local, 'stack', None) - if stack is None: - return None - elif len(stack) == 1: - release_local(self._local) - return stack[-1] - else: - return stack.pop() - - @property - def top(self): - """The topmost item on the stack. If the stack is empty, - `None` is returned. - """ - try: - return self._local.stack[-1] - except (AttributeError, IndexError): - return None - - -class LocalManager(object): - """Local objects cannot manage themselves. For that you need a local - manager. You can pass a local manager multiple locals or add them later - by appending them to `manager.locals`. Everytime the manager cleans up - it, will clean up all the data left in the locals for this context. - - The `ident_func` parameter can be added to override the default ident - function for the wrapped locals. - - .. versionchanged:: 0.6.1 - Instead of a manager the :func:`release_local` function can be used - as well. - - .. versionchanged:: 0.7 - `ident_func` was added. - """ - - def __init__(self, locals=None, ident_func=None): - if locals is None: - self.locals = [] - elif isinstance(locals, Local): - self.locals = [locals] - else: - self.locals = list(locals) - if ident_func is not None: - self.ident_func = ident_func - for local in self.locals: - object.__setattr__(local, '__ident_func__', ident_func) - else: - self.ident_func = get_ident - - def get_ident(self): - """Return the context identifier the local objects use internally for - this context. You cannot override this method to change the behavior - but use it to link other context local objects (such as SQLAlchemy's - scoped sessions) to the Werkzeug locals. - - .. versionchanged:: 0.7 - Yu can pass a different ident function to the local manager that - will then be propagated to all the locals passed to the - constructor. - """ - return self.ident_func() - - def cleanup(self): - """Manually clean up the data in the locals for this context. Call - this at the end of the request or use `make_middleware()`. - """ - for local in self.locals: - release_local(local) - - def make_middleware(self, app): - """Wrap a WSGI application so that cleaning up happens after - request end. - """ - def application(environ, start_response): - return ClosingIterator(app(environ, start_response), self.cleanup) - return application - - def middleware(self, func): - """Like `make_middleware` but for decorating functions. - - Example usage:: - - @manager.middleware - def application(environ, start_response): - ... - - The difference to `make_middleware` is that the function passed - will have all the arguments copied from the inner application - (name, docstring, module). - """ - return update_wrapper(self.make_middleware(func), func) - - def __repr__(self): - return '<%s storages: %d>' % ( - self.__class__.__name__, - len(self.locals) - ) - - -@implements_bool -class LocalProxy(object): - """Acts as a proxy for a werkzeug local. Forwards all operations to - a proxied object. The only operations not supported for forwarding - are right handed operands and any kind of assignment. - - Example usage:: - - from werkzeug.local import Local - l = Local() - - # these are proxies - request = l('request') - user = l('user') - - - from werkzeug.local import LocalStack - _response_local = LocalStack() - - # this is a proxy - response = _response_local() - - Whenever something is bound to l.user / l.request the proxy objects - will forward all operations. If no object is bound a :exc:`RuntimeError` - will be raised. - - To create proxies to :class:`Local` or :class:`LocalStack` objects, - call the object as shown above. If you want to have a proxy to an - object looked up by a function, you can (as of Werkzeug 0.6.1) pass - a function to the :class:`LocalProxy` constructor:: - - session = LocalProxy(lambda: get_current_request().session) - - .. versionchanged:: 0.6.1 - The class can be instanciated with a callable as well now. - """ - __slots__ = ('__local', '__dict__', '__name__') - - def __init__(self, local, name=None): - object.__setattr__(self, '_LocalProxy__local', local) - object.__setattr__(self, '__name__', name) - - def _get_current_object(self): - """Return the current object. This is useful if you want the real - object behind the proxy at a time for performance reasons or because - you want to pass the object into a different context. - """ - if not hasattr(self.__local, '__release_local__'): - return self.__local() - try: - return getattr(self.__local, self.__name__) - except AttributeError: - raise RuntimeError('no object bound to %s' % self.__name__) - - @property - def __dict__(self): - try: - return self._get_current_object().__dict__ - except RuntimeError: - raise AttributeError('__dict__') - - def __repr__(self): - try: - obj = self._get_current_object() - except RuntimeError: - return '<%s unbound>' % self.__class__.__name__ - return repr(obj) - - def __bool__(self): - try: - return bool(self._get_current_object()) - except RuntimeError: - return False - - def __unicode__(self): - try: - return unicode(self._get_current_object()) - except RuntimeError: - return repr(self) - - def __dir__(self): - try: - return dir(self._get_current_object()) - except RuntimeError: - return [] - - def __getattr__(self, name): - if name == '__members__': - return dir(self._get_current_object()) - return getattr(self._get_current_object(), name) - - def __setitem__(self, key, value): - self._get_current_object()[key] = value - - def __delitem__(self, key): - del self._get_current_object()[key] - - if PY2: - __getslice__ = lambda x, i, j: x._get_current_object()[i:j] - - def __setslice__(self, i, j, seq): - self._get_current_object()[i:j] = seq - - def __delslice__(self, i, j): - del self._get_current_object()[i:j] - - __setattr__ = lambda x, n, v: setattr(x._get_current_object(), n, v) - __delattr__ = lambda x, n: delattr(x._get_current_object(), n) - __str__ = lambda x: str(x._get_current_object()) - __lt__ = lambda x, o: x._get_current_object() < o - __le__ = lambda x, o: x._get_current_object() <= o - __eq__ = lambda x, o: x._get_current_object() == o - __ne__ = lambda x, o: x._get_current_object() != o - __gt__ = lambda x, o: x._get_current_object() > o - __ge__ = lambda x, o: x._get_current_object() >= o - __cmp__ = lambda x, o: cmp(x._get_current_object(), o) - __hash__ = lambda x: hash(x._get_current_object()) - __call__ = lambda x, *a, **kw: x._get_current_object()(*a, **kw) - __len__ = lambda x: len(x._get_current_object()) - __getitem__ = lambda x, i: x._get_current_object()[i] - __iter__ = lambda x: iter(x._get_current_object()) - __contains__ = lambda x, i: i in x._get_current_object() - __add__ = lambda x, o: x._get_current_object() + o - __sub__ = lambda x, o: x._get_current_object() - o - __mul__ = lambda x, o: x._get_current_object() * o - __floordiv__ = lambda x, o: x._get_current_object() // o - __mod__ = lambda x, o: x._get_current_object() % o - __divmod__ = lambda x, o: x._get_current_object().__divmod__(o) - __pow__ = lambda x, o: x._get_current_object() ** o - __lshift__ = lambda x, o: x._get_current_object() << o - __rshift__ = lambda x, o: x._get_current_object() >> o - __and__ = lambda x, o: x._get_current_object() & o - __xor__ = lambda x, o: x._get_current_object() ^ o - __or__ = lambda x, o: x._get_current_object() | o - __div__ = lambda x, o: x._get_current_object().__div__(o) - __truediv__ = lambda x, o: x._get_current_object().__truediv__(o) - __neg__ = lambda x: -(x._get_current_object()) - __pos__ = lambda x: +(x._get_current_object()) - __abs__ = lambda x: abs(x._get_current_object()) - __invert__ = lambda x: ~(x._get_current_object()) - __complex__ = lambda x: complex(x._get_current_object()) - __int__ = lambda x: int(x._get_current_object()) - __long__ = lambda x: long(x._get_current_object()) - __float__ = lambda x: float(x._get_current_object()) - __oct__ = lambda x: oct(x._get_current_object()) - __hex__ = lambda x: hex(x._get_current_object()) - __index__ = lambda x: x._get_current_object().__index__() - __coerce__ = lambda x, o: x._get_current_object().__coerce__(x, o) - __enter__ = lambda x: x._get_current_object().__enter__() - __exit__ = lambda x, *a, **kw: x._get_current_object().__exit__(*a, **kw) - __radd__ = lambda x, o: o + x._get_current_object() - __rsub__ = lambda x, o: o - x._get_current_object() - __rmul__ = lambda x, o: o * x._get_current_object() - __rdiv__ = lambda x, o: o / x._get_current_object() - if PY2: - __rtruediv__ = lambda x, o: x._get_current_object().__rtruediv__(o) - else: - __rtruediv__ = __rdiv__ - __rfloordiv__ = lambda x, o: o // x._get_current_object() - __rmod__ = lambda x, o: o % x._get_current_object() - __rdivmod__ = lambda x, o: x._get_current_object().__rdivmod__(o) diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/posixemulation.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/posixemulation.py deleted file mode 100644 index b728d5ba..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/posixemulation.py +++ /dev/null @@ -1,105 +0,0 @@ -# -*- coding: utf-8 -*- -r""" - werkzeug.posixemulation - ~~~~~~~~~~~~~~~~~~~~~~~ - - Provides a POSIX emulation for some features that are relevant to - web applications. The main purpose is to simplify support for - systems such as Windows NT that are not 100% POSIX compatible. - - Currently this only implements a :func:`rename` function that - follows POSIX semantics. Eg: if the target file already exists it - will be replaced without asking. - - This module was introduced in 0.6.1 and is not a public interface. - It might become one in later versions of Werkzeug. - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -import sys -import os -import errno -import time -import random - - -can_rename_open_file = False -if os.name == 'nt': # pragma: no cover - _rename = lambda src, dst: False - _rename_atomic = lambda src, dst: False - - try: - import ctypes - - _MOVEFILE_REPLACE_EXISTING = 0x1 - _MOVEFILE_WRITE_THROUGH = 0x8 - _MoveFileEx = ctypes.windll.kernel32.MoveFileExW - - def _rename(src, dst): - if not isinstance(src, unicode): - src = unicode(src, sys.getfilesystemencoding()) - if not isinstance(dst, unicode): - dst = unicode(dst, sys.getfilesystemencoding()) - if _rename_atomic(src, dst): - return True - retry = 0 - rv = False - while not rv and retry < 100: - rv = _MoveFileEx(src, dst, _MOVEFILE_REPLACE_EXISTING | - _MOVEFILE_WRITE_THROUGH) - if not rv: - time.sleep(0.001) - retry += 1 - return rv - - # new in Vista and Windows Server 2008 - _CreateTransaction = ctypes.windll.ktmw32.CreateTransaction - _CommitTransaction = ctypes.windll.ktmw32.CommitTransaction - _MoveFileTransacted = ctypes.windll.kernel32.MoveFileTransactedW - _CloseHandle = ctypes.windll.kernel32.CloseHandle - can_rename_open_file = True - - def _rename_atomic(src, dst): - ta = _CreateTransaction(None, 0, 0, 0, 0, 1000, 'Werkzeug rename') - if ta == -1: - return False - try: - retry = 0 - rv = False - while not rv and retry < 100: - rv = _MoveFileTransacted(src, dst, None, None, - _MOVEFILE_REPLACE_EXISTING | - _MOVEFILE_WRITE_THROUGH, ta) - if rv: - rv = _CommitTransaction(ta) - break - else: - time.sleep(0.001) - retry += 1 - return rv - finally: - _CloseHandle(ta) - except Exception: - pass - - def rename(src, dst): - # Try atomic or pseudo-atomic rename - if _rename(src, dst): - return - # Fall back to "move away and replace" - try: - os.rename(src, dst) - except OSError as e: - if e.errno != errno.EEXIST: - raise - old = "%s-%08x" % (dst, random.randint(0, sys.maxint)) - os.rename(dst, old) - os.rename(src, dst) - try: - os.unlink(old) - except Exception: - pass -else: - rename = os.rename - can_rename_open_file = True diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/routing.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/routing.py deleted file mode 100644 index f8acf72d..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/routing.py +++ /dev/null @@ -1,1631 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.routing - ~~~~~~~~~~~~~~~~ - - When it comes to combining multiple controller or view functions (however - you want to call them) you need a dispatcher. A simple way would be - applying regular expression tests on the ``PATH_INFO`` and calling - registered callback functions that return the value then. - - This module implements a much more powerful system than simple regular - expression matching because it can also convert values in the URLs and - build URLs. - - Here a simple example that creates an URL map for an application with - two subdomains (www and kb) and some URL rules: - - >>> m = Map([ - ... # Static URLs - ... Rule('/', endpoint='static/index'), - ... Rule('/about', endpoint='static/about'), - ... Rule('/help', endpoint='static/help'), - ... # Knowledge Base - ... Subdomain('kb', [ - ... Rule('/', endpoint='kb/index'), - ... Rule('/browse/', endpoint='kb/browse'), - ... Rule('/browse//', endpoint='kb/browse'), - ... Rule('/browse//', endpoint='kb/browse') - ... ]) - ... ], default_subdomain='www') - - If the application doesn't use subdomains it's perfectly fine to not set - the default subdomain and not use the `Subdomain` rule factory. The endpoint - in the rules can be anything, for example import paths or unique - identifiers. The WSGI application can use those endpoints to get the - handler for that URL. It doesn't have to be a string at all but it's - recommended. - - Now it's possible to create a URL adapter for one of the subdomains and - build URLs: - - >>> c = m.bind('example.com') - >>> c.build("kb/browse", dict(id=42)) - 'http://kb.example.com/browse/42/' - >>> c.build("kb/browse", dict()) - 'http://kb.example.com/browse/' - >>> c.build("kb/browse", dict(id=42, page=3)) - 'http://kb.example.com/browse/42/3' - >>> c.build("static/about") - '/about' - >>> c.build("static/index", force_external=True) - 'http://www.example.com/' - - >>> c = m.bind('example.com', subdomain='kb') - >>> c.build("static/about") - 'http://www.example.com/about' - - The first argument to bind is the server name *without* the subdomain. - Per default it will assume that the script is mounted on the root, but - often that's not the case so you can provide the real mount point as - second argument: - - >>> c = m.bind('example.com', '/applications/example') - - The third argument can be the subdomain, if not given the default - subdomain is used. For more details about binding have a look at the - documentation of the `MapAdapter`. - - And here is how you can match URLs: - - >>> c = m.bind('example.com') - >>> c.match("/") - ('static/index', {}) - >>> c.match("/about") - ('static/about', {}) - >>> c = m.bind('example.com', '/', 'kb') - >>> c.match("/") - ('kb/index', {}) - >>> c.match("/browse/42/23") - ('kb/browse', {'id': 42, 'page': 23}) - - If matching fails you get a `NotFound` exception, if the rule thinks - it's a good idea to redirect (for example because the URL was defined - to have a slash at the end but the request was missing that slash) it - will raise a `RequestRedirect` exception. Both are subclasses of the - `HTTPException` so you can use those errors as responses in the - application. - - If matching succeeded but the URL rule was incompatible to the given - method (for example there were only rules for `GET` and `HEAD` and - routing system tried to match a `POST` request) a `MethodNotAllowed` - method is raised. - - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -import re -import posixpath -from pprint import pformat - -from werkzeug.urls import url_encode, url_quote, url_join -from werkzeug.utils import redirect, format_string -from werkzeug.exceptions import HTTPException, NotFound, MethodNotAllowed -from werkzeug._internal import _get_environ, _encode_idna -from werkzeug._compat import itervalues, iteritems, to_unicode, to_bytes, \ - text_type, string_types, native_string_result, \ - implements_to_string, wsgi_decoding_dance -from werkzeug.datastructures import ImmutableDict, MultiDict - - -_rule_re = re.compile(r''' - (?P[^<]*) # static rule data - < - (?: - (?P[a-zA-Z_][a-zA-Z0-9_]*) # converter name - (?:\((?P.*?)\))? # converter arguments - \: # variable delimiter - )? - (?P[a-zA-Z_][a-zA-Z0-9_]*) # variable name - > -''', re.VERBOSE) -_simple_rule_re = re.compile(r'<([^>]+)>') -_converter_args_re = re.compile(r''' - ((?P\w+)\s*=\s*)? - (?P - True|False| - \d+.\d+| - \d+.| - \d+| - \w+| - [urUR]?(?P"[^"]*?"|'[^']*') - )\s*, -''', re.VERBOSE | re.UNICODE) - - -_PYTHON_CONSTANTS = { - 'None': None, - 'True': True, - 'False': False -} - - -def _pythonize(value): - if value in _PYTHON_CONSTANTS: - return _PYTHON_CONSTANTS[value] - for convert in int, float: - try: - return convert(value) - except ValueError: - pass - if value[:1] == value[-1:] and value[0] in '"\'': - value = value[1:-1] - return text_type(value) - - -def parse_converter_args(argstr): - argstr += ',' - args = [] - kwargs = {} - - for item in _converter_args_re.finditer(argstr): - value = item.group('stringval') - if value is None: - value = item.group('value') - value = _pythonize(value) - if not item.group('name'): - args.append(value) - else: - name = item.group('name') - kwargs[name] = value - - return tuple(args), kwargs - - -def parse_rule(rule): - """Parse a rule and return it as generator. Each iteration yields tuples - in the form ``(converter, arguments, variable)``. If the converter is - `None` it's a static url part, otherwise it's a dynamic one. - - :internal: - """ - pos = 0 - end = len(rule) - do_match = _rule_re.match - used_names = set() - while pos < end: - m = do_match(rule, pos) - if m is None: - break - data = m.groupdict() - if data['static']: - yield None, None, data['static'] - variable = data['variable'] - converter = data['converter'] or 'default' - if variable in used_names: - raise ValueError('variable name %r used twice.' % variable) - used_names.add(variable) - yield converter, data['args'] or None, variable - pos = m.end() - if pos < end: - remaining = rule[pos:] - if '>' in remaining or '<' in remaining: - raise ValueError('malformed url rule: %r' % rule) - yield None, None, remaining - - -class RoutingException(Exception): - """Special exceptions that require the application to redirect, notifying - about missing urls, etc. - - :internal: - """ - - -class RequestRedirect(HTTPException, RoutingException): - """Raise if the map requests a redirect. This is for example the case if - `strict_slashes` are activated and an url that requires a trailing slash. - - The attribute `new_url` contains the absolute destination url. - """ - code = 301 - - def __init__(self, new_url): - RoutingException.__init__(self, new_url) - self.new_url = new_url - - def get_response(self, environ): - return redirect(self.new_url, self.code) - - -class RequestSlash(RoutingException): - """Internal exception.""" - - -class RequestAliasRedirect(RoutingException): - """This rule is an alias and wants to redirect to the canonical URL.""" - - def __init__(self, matched_values): - self.matched_values = matched_values - - -class BuildError(RoutingException, LookupError): - """Raised if the build system cannot find a URL for an endpoint with the - values provided. - """ - - def __init__(self, endpoint, values, method): - LookupError.__init__(self, endpoint, values, method) - self.endpoint = endpoint - self.values = values - self.method = method - - -class ValidationError(ValueError): - """Validation error. If a rule converter raises this exception the rule - does not match the current URL and the next URL is tried. - """ - - -class RuleFactory(object): - """As soon as you have more complex URL setups it's a good idea to use rule - factories to avoid repetitive tasks. Some of them are builtin, others can - be added by subclassing `RuleFactory` and overriding `get_rules`. - """ - - def get_rules(self, map): - """Subclasses of `RuleFactory` have to override this method and return - an iterable of rules.""" - raise NotImplementedError() - - -class Subdomain(RuleFactory): - """All URLs provided by this factory have the subdomain set to a - specific domain. For example if you want to use the subdomain for - the current language this can be a good setup:: - - url_map = Map([ - Rule('/', endpoint='#select_language'), - Subdomain('', [ - Rule('/', endpoint='index'), - Rule('/about', endpoint='about'), - Rule('/help', endpoint='help') - ]) - ]) - - All the rules except for the ``'#select_language'`` endpoint will now - listen on a two letter long subdomain that holds the language code - for the current request. - """ - - def __init__(self, subdomain, rules): - self.subdomain = subdomain - self.rules = rules - - def get_rules(self, map): - for rulefactory in self.rules: - for rule in rulefactory.get_rules(map): - rule = rule.empty() - rule.subdomain = self.subdomain - yield rule - - -class Submount(RuleFactory): - """Like `Subdomain` but prefixes the URL rule with a given string:: - - url_map = Map([ - Rule('/', endpoint='index'), - Submount('/blog', [ - Rule('/', endpoint='blog/index'), - Rule('/entry/', endpoint='blog/show') - ]) - ]) - - Now the rule ``'blog/show'`` matches ``/blog/entry/``. - """ - - def __init__(self, path, rules): - self.path = path.rstrip('/') - self.rules = rules - - def get_rules(self, map): - for rulefactory in self.rules: - for rule in rulefactory.get_rules(map): - rule = rule.empty() - rule.rule = self.path + rule.rule - yield rule - - -class EndpointPrefix(RuleFactory): - """Prefixes all endpoints (which must be strings for this factory) with - another string. This can be useful for sub applications:: - - url_map = Map([ - Rule('/', endpoint='index'), - EndpointPrefix('blog/', [Submount('/blog', [ - Rule('/', endpoint='index'), - Rule('/entry/', endpoint='show') - ])]) - ]) - """ - - def __init__(self, prefix, rules): - self.prefix = prefix - self.rules = rules - - def get_rules(self, map): - for rulefactory in self.rules: - for rule in rulefactory.get_rules(map): - rule = rule.empty() - rule.endpoint = self.prefix + rule.endpoint - yield rule - - -class RuleTemplate(object): - """Returns copies of the rules wrapped and expands string templates in - the endpoint, rule, defaults or subdomain sections. - - Here a small example for such a rule template:: - - from werkzeug.routing import Map, Rule, RuleTemplate - - resource = RuleTemplate([ - Rule('/$name/', endpoint='$name.list'), - Rule('/$name/', endpoint='$name.show') - ]) - - url_map = Map([resource(name='user'), resource(name='page')]) - - When a rule template is called the keyword arguments are used to - replace the placeholders in all the string parameters. - """ - - def __init__(self, rules): - self.rules = list(rules) - - def __call__(self, *args, **kwargs): - return RuleTemplateFactory(self.rules, dict(*args, **kwargs)) - - -class RuleTemplateFactory(RuleFactory): - """A factory that fills in template variables into rules. Used by - `RuleTemplate` internally. - - :internal: - """ - - def __init__(self, rules, context): - self.rules = rules - self.context = context - - def get_rules(self, map): - for rulefactory in self.rules: - for rule in rulefactory.get_rules(map): - new_defaults = subdomain = None - if rule.defaults: - new_defaults = {} - for key, value in iteritems(rule.defaults): - if isinstance(value, string_types): - value = format_string(value, self.context) - new_defaults[key] = value - if rule.subdomain is not None: - subdomain = format_string(rule.subdomain, self.context) - new_endpoint = rule.endpoint - if isinstance(new_endpoint, string_types): - new_endpoint = format_string(new_endpoint, self.context) - yield Rule( - format_string(rule.rule, self.context), - new_defaults, - subdomain, - rule.methods, - rule.build_only, - new_endpoint, - rule.strict_slashes - ) - - -@implements_to_string -class Rule(RuleFactory): - """A Rule represents one URL pattern. There are some options for `Rule` - that change the way it behaves and are passed to the `Rule` constructor. - Note that besides the rule-string all arguments *must* be keyword arguments - in order to not break the application on Werkzeug upgrades. - - `string` - Rule strings basically are just normal URL paths with placeholders in - the format ```` where the converter and the - arguments are optional. If no converter is defined the `default` - converter is used which means `string` in the normal configuration. - - URL rules that end with a slash are branch URLs, others are leaves. - If you have `strict_slashes` enabled (which is the default), all - branch URLs that are matched without a trailing slash will trigger a - redirect to the same URL with the missing slash appended. - - The converters are defined on the `Map`. - - `endpoint` - The endpoint for this rule. This can be anything. A reference to a - function, a string, a number etc. The preferred way is using a string - because the endpoint is used for URL generation. - - `defaults` - An optional dict with defaults for other rules with the same endpoint. - This is a bit tricky but useful if you want to have unique URLs:: - - url_map = Map([ - Rule('/all/', defaults={'page': 1}, endpoint='all_entries'), - Rule('/all/page/', endpoint='all_entries') - ]) - - If a user now visits ``http://example.com/all/page/1`` he will be - redirected to ``http://example.com/all/``. If `redirect_defaults` is - disabled on the `Map` instance this will only affect the URL - generation. - - `subdomain` - The subdomain rule string for this rule. If not specified the rule - only matches for the `default_subdomain` of the map. If the map is - not bound to a subdomain this feature is disabled. - - Can be useful if you want to have user profiles on different subdomains - and all subdomains are forwarded to your application:: - - url_map = Map([ - Rule('/', subdomain='', endpoint='user/homepage'), - Rule('/stats', subdomain='', endpoint='user/stats') - ]) - - `methods` - A sequence of http methods this rule applies to. If not specified, all - methods are allowed. For example this can be useful if you want different - endpoints for `POST` and `GET`. If methods are defined and the path - matches but the method matched against is not in this list or in the - list of another rule for that path the error raised is of the type - `MethodNotAllowed` rather than `NotFound`. If `GET` is present in the - list of methods and `HEAD` is not, `HEAD` is added automatically. - - .. versionchanged:: 0.6.1 - `HEAD` is now automatically added to the methods if `GET` is - present. The reason for this is that existing code often did not - work properly in servers not rewriting `HEAD` to `GET` - automatically and it was not documented how `HEAD` should be - treated. This was considered a bug in Werkzeug because of that. - - `strict_slashes` - Override the `Map` setting for `strict_slashes` only for this rule. If - not specified the `Map` setting is used. - - `build_only` - Set this to True and the rule will never match but will create a URL - that can be build. This is useful if you have resources on a subdomain - or folder that are not handled by the WSGI application (like static data) - - `redirect_to` - If given this must be either a string or callable. In case of a - callable it's called with the url adapter that triggered the match and - the values of the URL as keyword arguments and has to return the target - for the redirect, otherwise it has to be a string with placeholders in - rule syntax:: - - def foo_with_slug(adapter, id): - # ask the database for the slug for the old id. this of - # course has nothing to do with werkzeug. - return 'foo/' + Foo.get_slug_for_id(id) - - url_map = Map([ - Rule('/foo/', endpoint='foo'), - Rule('/some/old/url/', redirect_to='foo/'), - Rule('/other/old/url/', redirect_to=foo_with_slug) - ]) - - When the rule is matched the routing system will raise a - `RequestRedirect` exception with the target for the redirect. - - Keep in mind that the URL will be joined against the URL root of the - script so don't use a leading slash on the target URL unless you - really mean root of that domain. - - `alias` - If enabled this rule serves as an alias for another rule with the same - endpoint and arguments. - - `host` - If provided and the URL map has host matching enabled this can be - used to provide a match rule for the whole host. This also means - that the subdomain feature is disabled. - - .. versionadded:: 0.7 - The `alias` and `host` parameters were added. - """ - - def __init__(self, string, defaults=None, subdomain=None, methods=None, - build_only=False, endpoint=None, strict_slashes=None, - redirect_to=None, alias=False, host=None): - if not string.startswith('/'): - raise ValueError('urls must start with a leading slash') - self.rule = string - self.is_leaf = not string.endswith('/') - - self.map = None - self.strict_slashes = strict_slashes - self.subdomain = subdomain - self.host = host - self.defaults = defaults - self.build_only = build_only - self.alias = alias - if methods is None: - self.methods = None - else: - self.methods = set([x.upper() for x in methods]) - if 'HEAD' not in self.methods and 'GET' in self.methods: - self.methods.add('HEAD') - self.endpoint = endpoint - self.redirect_to = redirect_to - - if defaults: - self.arguments = set(map(str, defaults)) - else: - self.arguments = set() - self._trace = self._converters = self._regex = self._weights = None - - def empty(self): - """Return an unbound copy of this rule. This can be useful if you - want to reuse an already bound URL for another map.""" - defaults = None - if self.defaults: - defaults = dict(self.defaults) - return Rule(self.rule, defaults, self.subdomain, self.methods, - self.build_only, self.endpoint, self.strict_slashes, - self.redirect_to, self.alias, self.host) - - def get_rules(self, map): - yield self - - def refresh(self): - """Rebinds and refreshes the URL. Call this if you modified the - rule in place. - - :internal: - """ - self.bind(self.map, rebind=True) - - def bind(self, map, rebind=False): - """Bind the url to a map and create a regular expression based on - the information from the rule itself and the defaults from the map. - - :internal: - """ - if self.map is not None and not rebind: - raise RuntimeError('url rule %r already bound to map %r' % - (self, self.map)) - self.map = map - if self.strict_slashes is None: - self.strict_slashes = map.strict_slashes - if self.subdomain is None: - self.subdomain = map.default_subdomain - self.compile() - - def get_converter(self, variable_name, converter_name, args, kwargs): - """Looks up the converter for the given parameter. - - .. versionadded:: 0.9 - """ - if not converter_name in self.map.converters: - raise LookupError('the converter %r does not exist' % converter_name) - return self.map.converters[converter_name](self.map, *args, **kwargs) - - def compile(self): - """Compiles the regular expression and stores it.""" - assert self.map is not None, 'rule not bound' - - if self.map.host_matching: - domain_rule = self.host or '' - else: - domain_rule = self.subdomain or '' - - self._trace = [] - self._converters = {} - self._weights = [] - regex_parts = [] - - def _build_regex(rule): - for converter, arguments, variable in parse_rule(rule): - if converter is None: - regex_parts.append(re.escape(variable)) - self._trace.append((False, variable)) - for part in variable.split('/'): - if part: - self._weights.append((0, -len(part))) - else: - if arguments: - c_args, c_kwargs = parse_converter_args(arguments) - else: - c_args = () - c_kwargs = {} - convobj = self.get_converter( - variable, converter, c_args, c_kwargs) - regex_parts.append('(?P<%s>%s)' % (variable, convobj.regex)) - self._converters[variable] = convobj - self._trace.append((True, variable)) - self._weights.append((1, convobj.weight)) - self.arguments.add(str(variable)) - - _build_regex(domain_rule) - regex_parts.append('\\|') - self._trace.append((False, '|')) - _build_regex(self.is_leaf and self.rule or self.rule.rstrip('/')) - if not self.is_leaf: - self._trace.append((False, '/')) - - if self.build_only: - return - regex = r'^%s%s$' % ( - u''.join(regex_parts), - (not self.is_leaf or not self.strict_slashes) and - '(?/?)' or '' - ) - self._regex = re.compile(regex, re.UNICODE) - - def match(self, path): - """Check if the rule matches a given path. Path is a string in the - form ``"subdomain|/path(method)"`` and is assembled by the map. If - the map is doing host matching the subdomain part will be the host - instead. - - If the rule matches a dict with the converted values is returned, - otherwise the return value is `None`. - - :internal: - """ - if not self.build_only: - m = self._regex.search(path) - if m is not None: - groups = m.groupdict() - # we have a folder like part of the url without a trailing - # slash and strict slashes enabled. raise an exception that - # tells the map to redirect to the same url but with a - # trailing slash - if self.strict_slashes and not self.is_leaf and \ - not groups.pop('__suffix__'): - raise RequestSlash() - # if we are not in strict slashes mode we have to remove - # a __suffix__ - elif not self.strict_slashes: - del groups['__suffix__'] - - result = {} - for name, value in iteritems(groups): - try: - value = self._converters[name].to_python(value) - except ValidationError: - return - result[str(name)] = value - if self.defaults: - result.update(self.defaults) - - if self.alias and self.map.redirect_defaults: - raise RequestAliasRedirect(result) - - return result - - def build(self, values, append_unknown=True): - """Assembles the relative url for that rule and the subdomain. - If building doesn't work for some reasons `None` is returned. - - :internal: - """ - tmp = [] - add = tmp.append - processed = set(self.arguments) - for is_dynamic, data in self._trace: - if is_dynamic: - try: - add(self._converters[data].to_url(values[data])) - except ValidationError: - return - processed.add(data) - else: - add(url_quote(to_bytes(data, self.map.charset), safe='/:|+')) - domain_part, url = (u''.join(tmp)).split(u'|', 1) - - if append_unknown: - query_vars = MultiDict(values) - for key in processed: - if key in query_vars: - del query_vars[key] - - if query_vars: - url += u'?' + url_encode(query_vars, charset=self.map.charset, - sort=self.map.sort_parameters, - key=self.map.sort_key) - - return domain_part, url - - def provides_defaults_for(self, rule): - """Check if this rule has defaults for a given rule. - - :internal: - """ - return not self.build_only and self.defaults and \ - self.endpoint == rule.endpoint and self != rule and \ - self.arguments == rule.arguments - - def suitable_for(self, values, method=None): - """Check if the dict of values has enough data for url generation. - - :internal: - """ - # if a method was given explicitly and that method is not supported - # by this rule, this rule is not suitable. - if method is not None and self.methods is not None \ - and method not in self.methods: - return False - - defaults = self.defaults or () - - # all arguments required must be either in the defaults dict or - # the value dictionary otherwise it's not suitable - for key in self.arguments: - if key not in defaults and key not in values: - return False - - # in case defaults are given we ensure taht either the value was - # skipped or the value is the same as the default value. - if defaults: - for key, value in iteritems(defaults): - if key in values and value != values[key]: - return False - - return True - - def match_compare_key(self): - """The match compare key for sorting. - - Current implementation: - - 1. rules without any arguments come first for performance - reasons only as we expect them to match faster and some - common ones usually don't have any arguments (index pages etc.) - 2. The more complex rules come first so the second argument is the - negative length of the number of weights. - 3. lastly we order by the actual weights. - - :internal: - """ - return bool(self.arguments), -len(self._weights), self._weights - - def build_compare_key(self): - """The build compare key for sorting. - - :internal: - """ - return self.alias and 1 or 0, -len(self.arguments), \ - -len(self.defaults or ()) - - def __eq__(self, other): - return self.__class__ is other.__class__ and \ - self._trace == other._trace - - def __ne__(self, other): - return not self.__eq__(other) - - def __str__(self): - return self.rule - - @native_string_result - def __repr__(self): - if self.map is None: - return u'<%s (unbound)>' % self.__class__.__name__ - tmp = [] - for is_dynamic, data in self._trace: - if is_dynamic: - tmp.append(u'<%s>' % data) - else: - tmp.append(data) - return u'<%s %s%s -> %s>' % ( - self.__class__.__name__, - repr((u''.join(tmp)).lstrip(u'|')).lstrip(u'u'), - self.methods is not None and u' (%s)' % - u', '.join(self.methods) or u'', - self.endpoint - ) - - -class BaseConverter(object): - """Base class for all converters.""" - regex = '[^/]+' - weight = 100 - - def __init__(self, map): - self.map = map - - def to_python(self, value): - return value - - def to_url(self, value): - return url_quote(value, charset=self.map.charset) - - -class UnicodeConverter(BaseConverter): - """This converter is the default converter and accepts any string but - only one path segment. Thus the string can not include a slash. - - This is the default validator. - - Example:: - - Rule('/pages/'), - Rule('/') - - :param map: the :class:`Map`. - :param minlength: the minimum length of the string. Must be greater - or equal 1. - :param maxlength: the maximum length of the string. - :param length: the exact length of the string. - """ - - def __init__(self, map, minlength=1, maxlength=None, length=None): - BaseConverter.__init__(self, map) - if length is not None: - length = '{%d}' % int(length) - else: - if maxlength is None: - maxlength = '' - else: - maxlength = int(maxlength) - length = '{%s,%s}' % ( - int(minlength), - maxlength - ) - self.regex = '[^/]' + length - - -class AnyConverter(BaseConverter): - """Matches one of the items provided. Items can either be Python - identifiers or strings:: - - Rule('/') - - :param map: the :class:`Map`. - :param items: this function accepts the possible items as positional - arguments. - """ - - def __init__(self, map, *items): - BaseConverter.__init__(self, map) - self.regex = '(?:%s)' % '|'.join([re.escape(x) for x in items]) - - -class PathConverter(BaseConverter): - """Like the default :class:`UnicodeConverter`, but it also matches - slashes. This is useful for wikis and similar applications:: - - Rule('/') - Rule('//edit') - - :param map: the :class:`Map`. - """ - regex = '[^/].*?' - weight = 200 - - -class NumberConverter(BaseConverter): - """Baseclass for `IntegerConverter` and `FloatConverter`. - - :internal: - """ - weight = 50 - - def __init__(self, map, fixed_digits=0, min=None, max=None): - BaseConverter.__init__(self, map) - self.fixed_digits = fixed_digits - self.min = min - self.max = max - - def to_python(self, value): - if (self.fixed_digits and len(value) != self.fixed_digits): - raise ValidationError() - value = self.num_convert(value) - if (self.min is not None and value < self.min) or \ - (self.max is not None and value > self.max): - raise ValidationError() - return value - - def to_url(self, value): - value = self.num_convert(value) - if self.fixed_digits: - value = ('%%0%sd' % self.fixed_digits) % value - return str(value) - - -class IntegerConverter(NumberConverter): - """This converter only accepts integer values:: - - Rule('/page/') - - This converter does not support negative values. - - :param map: the :class:`Map`. - :param fixed_digits: the number of fixed digits in the URL. If you set - this to ``4`` for example, the application will - only match if the url looks like ``/0001/``. The - default is variable length. - :param min: the minimal value. - :param max: the maximal value. - """ - regex = r'\d+' - num_convert = int - - -class FloatConverter(NumberConverter): - """This converter only accepts floating point values:: - - Rule('/probability/') - - This converter does not support negative values. - - :param map: the :class:`Map`. - :param min: the minimal value. - :param max: the maximal value. - """ - regex = r'\d+\.\d+' - num_convert = float - - def __init__(self, map, min=None, max=None): - NumberConverter.__init__(self, map, 0, min, max) - - -#: the default converter mapping for the map. -DEFAULT_CONVERTERS = { - 'default': UnicodeConverter, - 'string': UnicodeConverter, - 'any': AnyConverter, - 'path': PathConverter, - 'int': IntegerConverter, - 'float': FloatConverter -} - - -class Map(object): - """The map class stores all the URL rules and some configuration - parameters. Some of the configuration values are only stored on the - `Map` instance since those affect all rules, others are just defaults - and can be overridden for each rule. Note that you have to specify all - arguments besides the `rules` as keyword arguments! - - :param rules: sequence of url rules for this map. - :param default_subdomain: The default subdomain for rules without a - subdomain defined. - :param charset: charset of the url. defaults to ``"utf-8"`` - :param strict_slashes: Take care of trailing slashes. - :param redirect_defaults: This will redirect to the default rule if it - wasn't visited that way. This helps creating - unique URLs. - :param converters: A dict of converters that adds additional converters - to the list of converters. If you redefine one - converter this will override the original one. - :param sort_parameters: If set to `True` the url parameters are sorted. - See `url_encode` for more details. - :param sort_key: The sort key function for `url_encode`. - :param encoding_errors: the error method to use for decoding - :param host_matching: if set to `True` it enables the host matching - feature and disables the subdomain one. If - enabled the `host` parameter to rules is used - instead of the `subdomain` one. - - .. versionadded:: 0.5 - `sort_parameters` and `sort_key` was added. - - .. versionadded:: 0.7 - `encoding_errors` and `host_matching` was added. - """ - - #: .. versionadded:: 0.6 - #: a dict of default converters to be used. - default_converters = ImmutableDict(DEFAULT_CONVERTERS) - - def __init__(self, rules=None, default_subdomain='', charset='utf-8', - strict_slashes=True, redirect_defaults=True, - converters=None, sort_parameters=False, sort_key=None, - encoding_errors='replace', host_matching=False): - self._rules = [] - self._rules_by_endpoint = {} - self._remap = True - - self.default_subdomain = default_subdomain - self.charset = charset - self.encoding_errors = encoding_errors - self.strict_slashes = strict_slashes - self.redirect_defaults = redirect_defaults - self.host_matching = host_matching - - self.converters = self.default_converters.copy() - if converters: - self.converters.update(converters) - - self.sort_parameters = sort_parameters - self.sort_key = sort_key - - for rulefactory in rules or (): - self.add(rulefactory) - - def is_endpoint_expecting(self, endpoint, *arguments): - """Iterate over all rules and check if the endpoint expects - the arguments provided. This is for example useful if you have - some URLs that expect a language code and others that do not and - you want to wrap the builder a bit so that the current language - code is automatically added if not provided but endpoints expect - it. - - :param endpoint: the endpoint to check. - :param arguments: this function accepts one or more arguments - as positional arguments. Each one of them is - checked. - """ - self.update() - arguments = set(arguments) - for rule in self._rules_by_endpoint[endpoint]: - if arguments.issubset(rule.arguments): - return True - return False - - def iter_rules(self, endpoint=None): - """Iterate over all rules or the rules of an endpoint. - - :param endpoint: if provided only the rules for that endpoint - are returned. - :return: an iterator - """ - self.update() - if endpoint is not None: - return iter(self._rules_by_endpoint[endpoint]) - return iter(self._rules) - - def add(self, rulefactory): - """Add a new rule or factory to the map and bind it. Requires that the - rule is not bound to another map. - - :param rulefactory: a :class:`Rule` or :class:`RuleFactory` - """ - for rule in rulefactory.get_rules(self): - rule.bind(self) - self._rules.append(rule) - self._rules_by_endpoint.setdefault(rule.endpoint, []).append(rule) - self._remap = True - - def bind(self, server_name, script_name=None, subdomain=None, - url_scheme='http', default_method='GET', path_info=None, - query_args=None): - """Return a new :class:`MapAdapter` with the details specified to the - call. Note that `script_name` will default to ``'/'`` if not further - specified or `None`. The `server_name` at least is a requirement - because the HTTP RFC requires absolute URLs for redirects and so all - redirect exceptions raised by Werkzeug will contain the full canonical - URL. - - If no path_info is passed to :meth:`match` it will use the default path - info passed to bind. While this doesn't really make sense for - manual bind calls, it's useful if you bind a map to a WSGI - environment which already contains the path info. - - `subdomain` will default to the `default_subdomain` for this map if - no defined. If there is no `default_subdomain` you cannot use the - subdomain feature. - - .. versionadded:: 0.7 - `query_args` added - - .. versionadded:: 0.8 - `query_args` can now also be a string. - """ - server_name = server_name.lower() - if self.host_matching: - if subdomain is not None: - raise RuntimeError('host matching enabled and a ' - 'subdomain was provided') - elif subdomain is None: - subdomain = self.default_subdomain - if script_name is None: - script_name = '/' - server_name = _encode_idna(server_name) - return MapAdapter(self, server_name, script_name, subdomain, - url_scheme, path_info, default_method, query_args) - - def bind_to_environ(self, environ, server_name=None, subdomain=None): - """Like :meth:`bind` but you can pass it an WSGI environment and it - will fetch the information from that dictionary. Note that because of - limitations in the protocol there is no way to get the current - subdomain and real `server_name` from the environment. If you don't - provide it, Werkzeug will use `SERVER_NAME` and `SERVER_PORT` (or - `HTTP_HOST` if provided) as used `server_name` with disabled subdomain - feature. - - If `subdomain` is `None` but an environment and a server name is - provided it will calculate the current subdomain automatically. - Example: `server_name` is ``'example.com'`` and the `SERVER_NAME` - in the wsgi `environ` is ``'staging.dev.example.com'`` the calculated - subdomain will be ``'staging.dev'``. - - If the object passed as environ has an environ attribute, the value of - this attribute is used instead. This allows you to pass request - objects. Additionally `PATH_INFO` added as a default of the - :class:`MapAdapter` so that you don't have to pass the path info to - the match method. - - .. versionchanged:: 0.5 - previously this method accepted a bogus `calculate_subdomain` - parameter that did not have any effect. It was removed because - of that. - - .. versionchanged:: 0.8 - This will no longer raise a ValueError when an unexpected server - name was passed. - - :param environ: a WSGI environment. - :param server_name: an optional server name hint (see above). - :param subdomain: optionally the current subdomain (see above). - """ - environ = _get_environ(environ) - if server_name is None: - if 'HTTP_HOST' in environ: - server_name = environ['HTTP_HOST'] - else: - server_name = environ['SERVER_NAME'] - if (environ['wsgi.url_scheme'], environ['SERVER_PORT']) not \ - in (('https', '443'), ('http', '80')): - server_name += ':' + environ['SERVER_PORT'] - elif subdomain is None and not self.host_matching: - server_name = server_name.lower() - if 'HTTP_HOST' in environ: - wsgi_server_name = environ.get('HTTP_HOST') - else: - wsgi_server_name = environ.get('SERVER_NAME') - if (environ['wsgi.url_scheme'], environ['SERVER_PORT']) not \ - in (('https', '443'), ('http', '80')): - wsgi_server_name += ':' + environ['SERVER_PORT'] - wsgi_server_name = wsgi_server_name.lower() - cur_server_name = wsgi_server_name.split('.') - real_server_name = server_name.split('.') - offset = -len(real_server_name) - if cur_server_name[offset:] != real_server_name: - # This can happen even with valid configs if the server was - # accesssed directly by IP address under some situations. - # Instead of raising an exception like in Werkzeug 0.7 or - # earlier we go by an invalid subdomain which will result - # in a 404 error on matching. - subdomain = '' - else: - subdomain = '.'.join(filter(None, cur_server_name[:offset])) - - def _get_wsgi_string(name): - val = environ.get(name) - if val is not None: - return wsgi_decoding_dance(val, self.charset) - - script_name = _get_wsgi_string('SCRIPT_NAME') - path_info = _get_wsgi_string('PATH_INFO') - query_args = _get_wsgi_string('QUERY_STRING') - return Map.bind(self, server_name, script_name, - subdomain, environ['wsgi.url_scheme'], - environ['REQUEST_METHOD'], path_info, - query_args=query_args) - - def update(self): - """Called before matching and building to keep the compiled rules - in the correct order after things changed. - """ - if self._remap: - self._rules.sort(key=lambda x: x.match_compare_key()) - for rules in itervalues(self._rules_by_endpoint): - rules.sort(key=lambda x: x.build_compare_key()) - self._remap = False - - def __repr__(self): - rules = self.iter_rules() - return '%s(%s)' % (self.__class__.__name__, pformat(list(rules))) - - -class MapAdapter(object): - """Returned by :meth:`Map.bind` or :meth:`Map.bind_to_environ` and does - the URL matching and building based on runtime information. - """ - - def __init__(self, map, server_name, script_name, subdomain, - url_scheme, path_info, default_method, query_args=None): - self.map = map - self.server_name = to_unicode(server_name) - script_name = to_unicode(script_name) - if not script_name.endswith(u'/'): - script_name += u'/' - self.script_name = script_name - self.subdomain = to_unicode(subdomain) - self.url_scheme = to_unicode(url_scheme) - self.path_info = to_unicode(path_info) - self.default_method = to_unicode(default_method) - self.query_args = query_args - - def dispatch(self, view_func, path_info=None, method=None, - catch_http_exceptions=False): - """Does the complete dispatching process. `view_func` is called with - the endpoint and a dict with the values for the view. It should - look up the view function, call it, and return a response object - or WSGI application. http exceptions are not caught by default - so that applications can display nicer error messages by just - catching them by hand. If you want to stick with the default - error messages you can pass it ``catch_http_exceptions=True`` and - it will catch the http exceptions. - - Here a small example for the dispatch usage:: - - from werkzeug.wrappers import Request, Response - from werkzeug.wsgi import responder - from werkzeug.routing import Map, Rule - - def on_index(request): - return Response('Hello from the index') - - url_map = Map([Rule('/', endpoint='index')]) - views = {'index': on_index} - - @responder - def application(environ, start_response): - request = Request(environ) - urls = url_map.bind_to_environ(environ) - return urls.dispatch(lambda e, v: views[e](request, **v), - catch_http_exceptions=True) - - Keep in mind that this method might return exception objects, too, so - use :class:`Response.force_type` to get a response object. - - :param view_func: a function that is called with the endpoint as - first argument and the value dict as second. Has - to dispatch to the actual view function with this - information. (see above) - :param path_info: the path info to use for matching. Overrides the - path info specified on binding. - :param method: the HTTP method used for matching. Overrides the - method specified on binding. - :param catch_http_exceptions: set to `True` to catch any of the - werkzeug :class:`HTTPException`\s. - """ - try: - try: - endpoint, args = self.match(path_info, method) - except RequestRedirect as e: - return e - return view_func(endpoint, args) - except HTTPException as e: - if catch_http_exceptions: - return e - raise - - def match(self, path_info=None, method=None, return_rule=False, - query_args=None): - """The usage is simple: you just pass the match method the current - path info as well as the method (which defaults to `GET`). The - following things can then happen: - - - you receive a `NotFound` exception that indicates that no URL is - matching. A `NotFound` exception is also a WSGI application you - can call to get a default page not found page (happens to be the - same object as `werkzeug.exceptions.NotFound`) - - - you receive a `MethodNotAllowed` exception that indicates that there - is a match for this URL but not for the current request method. - This is useful for RESTful applications. - - - you receive a `RequestRedirect` exception with a `new_url` - attribute. This exception is used to notify you about a request - Werkzeug requests from your WSGI application. This is for example the - case if you request ``/foo`` although the correct URL is ``/foo/`` - You can use the `RequestRedirect` instance as response-like object - similar to all other subclasses of `HTTPException`. - - - you get a tuple in the form ``(endpoint, arguments)`` if there is - a match (unless `return_rule` is True, in which case you get a tuple - in the form ``(rule, arguments)``) - - If the path info is not passed to the match method the default path - info of the map is used (defaults to the root URL if not defined - explicitly). - - All of the exceptions raised are subclasses of `HTTPException` so they - can be used as WSGI responses. The will all render generic error or - redirect pages. - - Here is a small example for matching: - - >>> m = Map([ - ... Rule('/', endpoint='index'), - ... Rule('/downloads/', endpoint='downloads/index'), - ... Rule('/downloads/', endpoint='downloads/show') - ... ]) - >>> urls = m.bind("example.com", "/") - >>> urls.match("/", "GET") - ('index', {}) - >>> urls.match("/downloads/42") - ('downloads/show', {'id': 42}) - - And here is what happens on redirect and missing URLs: - - >>> urls.match("/downloads") - Traceback (most recent call last): - ... - RequestRedirect: http://example.com/downloads/ - >>> urls.match("/missing") - Traceback (most recent call last): - ... - NotFound: 404 Not Found - - :param path_info: the path info to use for matching. Overrides the - path info specified on binding. - :param method: the HTTP method used for matching. Overrides the - method specified on binding. - :param return_rule: return the rule that matched instead of just the - endpoint (defaults to `False`). - :param query_args: optional query arguments that are used for - automatic redirects as string or dictionary. It's - currently not possible to use the query arguments - for URL matching. - - .. versionadded:: 0.6 - `return_rule` was added. - - .. versionadded:: 0.7 - `query_args` was added. - - .. versionchanged:: 0.8 - `query_args` can now also be a string. - """ - self.map.update() - if path_info is None: - path_info = self.path_info - else: - path_info = to_unicode(path_info, self.map.charset) - if query_args is None: - query_args = self.query_args - method = (method or self.default_method).upper() - - path = u'%s|/%s' % (self.map.host_matching and self.server_name or - self.subdomain, path_info.lstrip('/')) - - have_match_for = set() - for rule in self.map._rules: - try: - rv = rule.match(path) - except RequestSlash: - raise RequestRedirect(self.make_redirect_url( - url_quote(path_info, self.map.charset, - safe='/:|+') + '/', query_args)) - except RequestAliasRedirect as e: - raise RequestRedirect(self.make_alias_redirect_url( - path, rule.endpoint, e.matched_values, method, query_args)) - if rv is None: - continue - if rule.methods is not None and method not in rule.methods: - have_match_for.update(rule.methods) - continue - - if self.map.redirect_defaults: - redirect_url = self.get_default_redirect(rule, method, rv, - query_args) - if redirect_url is not None: - raise RequestRedirect(redirect_url) - - if rule.redirect_to is not None: - if isinstance(rule.redirect_to, string_types): - def _handle_match(match): - value = rv[match.group(1)] - return rule._converters[match.group(1)].to_url(value) - redirect_url = _simple_rule_re.sub(_handle_match, - rule.redirect_to) - else: - redirect_url = rule.redirect_to(self, **rv) - raise RequestRedirect(str(url_join('%s://%s%s%s' % ( - self.url_scheme, - self.subdomain and self.subdomain + '.' or '', - self.server_name, - self.script_name - ), redirect_url))) - - if return_rule: - return rule, rv - else: - return rule.endpoint, rv - - if have_match_for: - raise MethodNotAllowed(valid_methods=list(have_match_for)) - raise NotFound() - - def test(self, path_info=None, method=None): - """Test if a rule would match. Works like `match` but returns `True` - if the URL matches, or `False` if it does not exist. - - :param path_info: the path info to use for matching. Overrides the - path info specified on binding. - :param method: the HTTP method used for matching. Overrides the - method specified on binding. - """ - try: - self.match(path_info, method) - except RequestRedirect: - pass - except HTTPException: - return False - return True - - def allowed_methods(self, path_info=None): - """Returns the valid methods that match for a given path. - - .. versionadded:: 0.7 - """ - try: - self.match(path_info, method='--') - except MethodNotAllowed as e: - return e.valid_methods - except HTTPException as e: - pass - return [] - - def get_host(self, domain_part): - """Figures out the full host name for the given domain part. The - domain part is a subdomain in case host matching is disabled or - a full host name. - """ - if self.map.host_matching: - if domain_part is None: - return self.server_name - return to_unicode(domain_part, 'ascii') - subdomain = domain_part - if subdomain is None: - subdomain = self.subdomain - else: - subdomain = to_unicode(subdomain, 'ascii') - return (subdomain and subdomain + u'.' or u'') + self.server_name - - def get_default_redirect(self, rule, method, values, query_args): - """A helper that returns the URL to redirect to if it finds one. - This is used for default redirecting only. - - :internal: - """ - assert self.map.redirect_defaults - for r in self.map._rules_by_endpoint[rule.endpoint]: - # every rule that comes after this one, including ourself - # has a lower priority for the defaults. We order the ones - # with the highest priority up for building. - if r is rule: - break - if r.provides_defaults_for(rule) and \ - r.suitable_for(values, method): - values.update(r.defaults) - domain_part, path = r.build(values) - return self.make_redirect_url( - path, query_args, domain_part=domain_part) - - def encode_query_args(self, query_args): - if not isinstance(query_args, string_types): - query_args = url_encode(query_args, self.map.charset) - return query_args - - def make_redirect_url(self, path_info, query_args=None, domain_part=None): - """Creates a redirect URL. - - :internal: - """ - suffix = '' - if query_args: - suffix = '?' + self.encode_query_args(query_args) - return str('%s://%s/%s%s' % ( - self.url_scheme, - self.get_host(domain_part), - posixpath.join(self.script_name[:-1].lstrip('/'), - path_info.lstrip('/')), - suffix - )) - - def make_alias_redirect_url(self, path, endpoint, values, method, query_args): - """Internally called to make an alias redirect URL.""" - url = self.build(endpoint, values, method, append_unknown=False, - force_external=True) - if query_args: - url += '?' + self.encode_query_args(query_args) - assert url != path, 'detected invalid alias setting. No canonical ' \ - 'URL found' - return url - - def _partial_build(self, endpoint, values, method, append_unknown): - """Helper for :meth:`build`. Returns subdomain and path for the - rule that accepts this endpoint, values and method. - - :internal: - """ - # in case the method is none, try with the default method first - if method is None: - rv = self._partial_build(endpoint, values, self.default_method, - append_unknown) - if rv is not None: - return rv - - # default method did not match or a specific method is passed, - # check all and go with first result. - for rule in self.map._rules_by_endpoint.get(endpoint, ()): - if rule.suitable_for(values, method): - rv = rule.build(values, append_unknown) - if rv is not None: - return rv - - def build(self, endpoint, values=None, method=None, force_external=False, - append_unknown=True): - """Building URLs works pretty much the other way round. Instead of - `match` you call `build` and pass it the endpoint and a dict of - arguments for the placeholders. - - The `build` function also accepts an argument called `force_external` - which, if you set it to `True` will force external URLs. Per default - external URLs (include the server name) will only be used if the - target URL is on a different subdomain. - - >>> m = Map([ - ... Rule('/', endpoint='index'), - ... Rule('/downloads/', endpoint='downloads/index'), - ... Rule('/downloads/', endpoint='downloads/show') - ... ]) - >>> urls = m.bind("example.com", "/") - >>> urls.build("index", {}) - '/' - >>> urls.build("downloads/show", {'id': 42}) - '/downloads/42' - >>> urls.build("downloads/show", {'id': 42}, force_external=True) - 'http://example.com/downloads/42' - - Because URLs cannot contain non ASCII data you will always get - bytestrings back. Non ASCII characters are urlencoded with the - charset defined on the map instance. - - Additional values are converted to unicode and appended to the URL as - URL querystring parameters: - - >>> urls.build("index", {'q': 'My Searchstring'}) - '/?q=My+Searchstring' - - If a rule does not exist when building a `BuildError` exception is - raised. - - The build method accepts an argument called `method` which allows you - to specify the method you want to have an URL built for if you have - different methods for the same endpoint specified. - - .. versionadded:: 0.6 - the `append_unknown` parameter was added. - - :param endpoint: the endpoint of the URL to build. - :param values: the values for the URL to build. Unhandled values are - appended to the URL as query parameters. - :param method: the HTTP method for the rule if there are different - URLs for different methods on the same endpoint. - :param force_external: enforce full canonical external URLs. - :param append_unknown: unknown parameters are appended to the generated - URL as query string argument. Disable this - if you want the builder to ignore those. - """ - self.map.update() - if values: - if isinstance(values, MultiDict): - valueiter = values.iteritems(multi=True) - else: - valueiter = iteritems(values) - values = dict((k, v) for k, v in valueiter if v is not None) - else: - values = {} - - rv = self._partial_build(endpoint, values, method, append_unknown) - if rv is None: - raise BuildError(endpoint, values, method) - domain_part, path = rv - - host = self.get_host(domain_part) - - # shortcut this. - if not force_external and ( - (self.map.host_matching and host == self.server_name) or - (not self.map.host_matching and domain_part == self.subdomain)): - return str(url_join(self.script_name, './' + path.lstrip('/'))) - return str('%s://%s%s/%s' % ( - self.url_scheme, - host, - self.script_name[:-1], - path.lstrip('/') - )) diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/script.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/script.py deleted file mode 100644 index 25827def..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/script.py +++ /dev/null @@ -1,316 +0,0 @@ -# -*- coding: utf-8 -*- -r''' - werkzeug.script - ~~~~~~~~~~~~~~~ - - .. admonition:: Deprecated Functionality - - ``werkzeug.script`` is deprecated without replacement functionality. - Python's command line support improved greatly with :mod:`argparse` - and a bunch of alternative modules. - - Most of the time you have recurring tasks while writing an application - such as starting up an interactive python interpreter with some prefilled - imports, starting the development server, initializing the database or - something similar. - - For that purpose werkzeug provides the `werkzeug.script` module which - helps you writing such scripts. - - - Basic Usage - ----------- - - The following snippet is roughly the same in every werkzeug script:: - - #!/usr/bin/env python - # -*- coding: utf-8 -*- - from werkzeug import script - - # actions go here - - if __name__ == '__main__': - script.run() - - Starting this script now does nothing because no actions are defined. - An action is a function in the same module starting with ``"action_"`` - which takes a number of arguments where every argument has a default. The - type of the default value specifies the type of the argument. - - Arguments can then be passed by position or using ``--name=value`` from - the shell. - - Because a runserver and shell command is pretty common there are two - factory functions that create such commands:: - - def make_app(): - from yourapplication import YourApplication - return YourApplication(...) - - action_runserver = script.make_runserver(make_app, use_reloader=True) - action_shell = script.make_shell(lambda: {'app': make_app()}) - - - Using The Scripts - ----------------- - - The script from above can be used like this from the shell now: - - .. sourcecode:: text - - $ ./manage.py --help - $ ./manage.py runserver localhost 8080 --debugger --no-reloader - $ ./manage.py runserver -p 4000 - $ ./manage.py shell - - As you can see it's possible to pass parameters as positional arguments - or as named parameters, pretty much like Python function calls. - - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -''' -from __future__ import print_function - -import sys -import inspect -import getopt -from os.path import basename -from werkzeug._compat import iteritems - - -argument_types = { - bool: 'boolean', - str: 'string', - int: 'integer', - float: 'float' -} - - -converters = { - 'boolean': lambda x: x.lower() in ('1', 'true', 'yes', 'on'), - 'string': str, - 'integer': int, - 'float': float -} - - -def run(namespace=None, action_prefix='action_', args=None): - """Run the script. Participating actions are looked up in the caller's - namespace if no namespace is given, otherwise in the dict provided. - Only items that start with action_prefix are processed as actions. If - you want to use all items in the namespace provided as actions set - action_prefix to an empty string. - - :param namespace: An optional dict where the functions are looked up in. - By default the local namespace of the caller is used. - :param action_prefix: The prefix for the functions. Everything else - is ignored. - :param args: the arguments for the function. If not specified - :data:`sys.argv` without the first argument is used. - """ - if namespace is None: - namespace = sys._getframe(1).f_locals - actions = find_actions(namespace, action_prefix) - - if args is None: - args = sys.argv[1:] - if not args or args[0] in ('-h', '--help'): - return print_usage(actions) - elif args[0] not in actions: - fail('Unknown action \'%s\'' % args[0]) - - arguments = {} - types = {} - key_to_arg = {} - long_options = [] - formatstring = '' - func, doc, arg_def = actions[args.pop(0)] - for idx, (arg, shortcut, default, option_type) in enumerate(arg_def): - real_arg = arg.replace('-', '_') - if shortcut: - formatstring += shortcut - if not isinstance(default, bool): - formatstring += ':' - key_to_arg['-' + shortcut] = real_arg - long_options.append(isinstance(default, bool) and arg or arg + '=') - key_to_arg['--' + arg] = real_arg - key_to_arg[idx] = real_arg - types[real_arg] = option_type - arguments[real_arg] = default - - try: - optlist, posargs = getopt.gnu_getopt(args, formatstring, long_options) - except getopt.GetoptError as e: - fail(str(e)) - - specified_arguments = set() - for key, value in enumerate(posargs): - try: - arg = key_to_arg[key] - except IndexError: - fail('Too many parameters') - specified_arguments.add(arg) - try: - arguments[arg] = converters[types[arg]](value) - except ValueError: - fail('Invalid value for argument %s (%s): %s' % (key, arg, value)) - - for key, value in optlist: - arg = key_to_arg[key] - if arg in specified_arguments: - fail('Argument \'%s\' is specified twice' % arg) - if types[arg] == 'boolean': - if arg.startswith('no_'): - value = 'no' - else: - value = 'yes' - try: - arguments[arg] = converters[types[arg]](value) - except ValueError: - fail('Invalid value for \'%s\': %s' % (key, value)) - - newargs = {} - for k, v in iteritems(arguments): - newargs[k.startswith('no_') and k[3:] or k] = v - arguments = newargs - return func(**arguments) - - -def fail(message, code=-1): - """Fail with an error.""" - print('Error: %s' % message, file=sys.stderr) - sys.exit(code) - - -def find_actions(namespace, action_prefix): - """Find all the actions in the namespace.""" - actions = {} - for key, value in iteritems(namespace): - if key.startswith(action_prefix): - actions[key[len(action_prefix):]] = analyse_action(value) - return actions - - -def print_usage(actions): - """Print the usage information. (Help screen)""" - actions = actions.items() - actions.sort() - print('usage: %s []' % basename(sys.argv[0])) - print(' %s --help' % basename(sys.argv[0])) - print() - print('actions:') - for name, (func, doc, arguments) in actions: - print(' %s:' % name) - for line in doc.splitlines(): - print(' %s' % line) - if arguments: - print() - for arg, shortcut, default, argtype in arguments: - if isinstance(default, bool): - print(' %s' % ( - (shortcut and '-%s, ' % shortcut or '') + '--' + arg - )) - else: - print(' %-30s%-10s%s' % ( - (shortcut and '-%s, ' % shortcut or '') + '--' + arg, - argtype, default - )) - print() - - -def analyse_action(func): - """Analyse a function.""" - description = inspect.getdoc(func) or 'undocumented action' - arguments = [] - args, varargs, kwargs, defaults = inspect.getargspec(func) - if varargs or kwargs: - raise TypeError('variable length arguments for action not allowed.') - if len(args) != len(defaults or ()): - raise TypeError('not all arguments have proper definitions') - - for idx, (arg, definition) in enumerate(zip(args, defaults or ())): - if arg.startswith('_'): - raise TypeError('arguments may not start with an underscore') - if not isinstance(definition, tuple): - shortcut = None - default = definition - else: - shortcut, default = definition - argument_type = argument_types[type(default)] - if isinstance(default, bool) and default is True: - arg = 'no-' + arg - arguments.append((arg.replace('_', '-'), shortcut, - default, argument_type)) - return func, description, arguments - - -def make_shell(init_func=None, banner=None, use_ipython=True): - """Returns an action callback that spawns a new interactive - python shell. - - :param init_func: an optional initialization function that is - called before the shell is started. The return - value of this function is the initial namespace. - :param banner: the banner that is displayed before the shell. If - not specified a generic banner is used instead. - :param use_ipython: if set to `True` ipython is used if available. - """ - if banner is None: - banner = 'Interactive Werkzeug Shell' - if init_func is None: - init_func = dict - def action(ipython=use_ipython): - """Start a new interactive python session.""" - namespace = init_func() - if ipython: - try: - try: - from IPython.frontend.terminal.embed import InteractiveShellEmbed - sh = InteractiveShellEmbed(banner1=banner) - except ImportError: - from IPython.Shell import IPShellEmbed - sh = IPShellEmbed(banner=banner) - except ImportError: - pass - else: - sh(global_ns={}, local_ns=namespace) - return - from code import interact - interact(banner, local=namespace) - return action - - -def make_runserver(app_factory, hostname='localhost', port=5000, - use_reloader=False, use_debugger=False, use_evalex=True, - threaded=False, processes=1, static_files=None, - extra_files=None, ssl_context=None): - """Returns an action callback that spawns a new development server. - - .. versionadded:: 0.5 - `static_files` and `extra_files` was added. - - ..versionadded:: 0.6.1 - `ssl_context` was added. - - :param app_factory: a function that returns a new WSGI application. - :param hostname: the default hostname the server should listen on. - :param port: the default port of the server. - :param use_reloader: the default setting for the reloader. - :param use_evalex: the default setting for the evalex flag of the debugger. - :param threaded: the default threading setting. - :param processes: the default number of processes to start. - :param static_files: optional dict of static files. - :param extra_files: optional list of extra files to track for reloading. - :param ssl_context: optional SSL context for running server in HTTPS mode. - """ - def action(hostname=('h', hostname), port=('p', port), - reloader=use_reloader, debugger=use_debugger, - evalex=use_evalex, threaded=threaded, processes=processes): - """Start a new development server.""" - from werkzeug.serving import run_simple - app = app_factory() - run_simple(hostname, port, app, reloader, debugger, evalex, - extra_files, 1, threaded, processes, - static_files=static_files, ssl_context=ssl_context) - return action diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/security.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/security.py deleted file mode 100644 index dc0262fa..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/security.py +++ /dev/null @@ -1,248 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.security - ~~~~~~~~~~~~~~~~~ - - Security related helpers such as secure password hashing tools. - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -import os -import hmac -import hashlib -import posixpath -import codecs -from struct import Struct -from random import SystemRandom -from operator import xor -from itertools import starmap - -from werkzeug._compat import range_type, PY2, text_type, izip, to_bytes, \ - string_types, to_native - - -SALT_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' -DEFAULT_PBKDF2_ITERATIONS = 1000 - - -_pack_int = Struct('>I').pack -_builtin_safe_str_cmp = getattr(hmac, 'compare_digest', None) -_sys_rng = SystemRandom() -_os_alt_seps = list(sep for sep in [os.path.sep, os.path.altsep] - if sep not in (None, '/')) - - -def _find_hashlib_algorithms(): - algos = getattr(hashlib, 'algorithms', None) - if algos is None: - algos = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512') - rv = {} - for algo in algos: - func = getattr(hashlib, algo, None) - if func is not None: - rv[algo] = func - return rv -_hash_funcs = _find_hashlib_algorithms() - - -def pbkdf2_hex(data, salt, iterations=DEFAULT_PBKDF2_ITERATIONS, - keylen=None, hashfunc=None): - """Like :func:`pbkdf2_bin` but returns a hex encoded string. - - .. versionadded:: 0.9 - - :param data: the data to derive. - :param salt: the salt for the derivation. - :param iterations: the number of iterations. - :param keylen: the length of the resulting key. If not provided - the digest size will be used. - :param hashfunc: the hash function to use. This can either be the - string name of a known hash function or a function - from the hashlib module. Defaults to sha1. - """ - rv = pbkdf2_bin(data, salt, iterations, keylen, hashfunc) - return to_native(codecs.encode(rv, 'hex_codec')) - - -def pbkdf2_bin(data, salt, iterations=DEFAULT_PBKDF2_ITERATIONS, - keylen=None, hashfunc=None): - """Returns a binary digest for the PBKDF2 hash algorithm of `data` - with the given `salt`. It iterates `iterations` time and produces a - key of `keylen` bytes. By default SHA-1 is used as hash function, - a different hashlib `hashfunc` can be provided. - - .. versionadded:: 0.9 - - :param data: the data to derive. - :param salt: the salt for the derivation. - :param iterations: the number of iterations. - :param keylen: the length of the resulting key. If not provided - the digest size will be used. - :param hashfunc: the hash function to use. This can either be the - string name of a known hash function or a function - from the hashlib module. Defaults to sha1. - """ - if isinstance(hashfunc, string_types): - hashfunc = _hash_funcs[hashfunc] - elif not hashfunc: - hashfunc = hashlib.sha1 - salt = to_bytes(salt) - mac = hmac.HMAC(to_bytes(data), None, hashfunc) - if not keylen: - keylen = mac.digest_size - def _pseudorandom(x, mac=mac): - h = mac.copy() - h.update(x) - return bytearray(h.digest()) - buf = bytearray() - for block in range_type(1, -(-keylen // mac.digest_size) + 1): - rv = u = _pseudorandom(salt + _pack_int(block)) - for i in range_type(iterations - 1): - u = _pseudorandom(bytes(u)) - rv = bytearray(starmap(xor, izip(rv, u))) - buf.extend(rv) - return bytes(buf[:keylen]) - - -def safe_str_cmp(a, b): - """This function compares strings in somewhat constant time. This - requires that the length of at least one string is known in advance. - - Returns `True` if the two strings are equal or `False` if they are not. - - .. versionadded:: 0.7 - """ - if isinstance(a, text_type): - a = a.encode('utf-8') - if isinstance(b, text_type): - b = b.encode('utf-8') - - if _builtin_safe_str_cmp is not None: - return _builtin_safe_str_cmp(a, b) - - if len(a) != len(b): - return False - - rv = 0 - if PY2: - for x, y in izip(a, b): - rv |= ord(x) ^ ord(y) - else: - for x, y in izip(a, b): - rv |= x ^ y - - return rv == 0 - - -def gen_salt(length): - """Generate a random string of SALT_CHARS with specified ``length``.""" - if length <= 0: - raise ValueError('requested salt of length <= 0') - return ''.join(_sys_rng.choice(SALT_CHARS) for _ in range_type(length)) - - -def _hash_internal(method, salt, password): - """Internal password hash helper. Supports plaintext without salt, - unsalted and salted passwords. In case salted passwords are used - hmac is used. - """ - if method == 'plain': - return password, method - - if isinstance(password, text_type): - password = password.encode('utf-8') - - if method.startswith('pbkdf2:'): - args = method[7:].split(':') - if len(args) not in (1, 2): - raise ValueError('Invalid number of arguments for PBKDF2') - method = args.pop(0) - iterations = args and int(args[0] or 0) or DEFAULT_PBKDF2_ITERATIONS - is_pbkdf2 = True - actual_method = 'pbkdf2:%s:%d' % (method, iterations) - else: - is_pbkdf2 = False - actual_method = method - - hash_func = _hash_funcs.get(method) - if hash_func is None: - raise TypeError('invalid method %r' % method) - - if is_pbkdf2: - if not salt: - raise ValueError('Salt is required for PBKDF2') - rv = pbkdf2_hex(password, salt, iterations, - hashfunc=hash_func) - elif salt: - if isinstance(salt, text_type): - salt = salt.encode('utf-8') - rv = hmac.HMAC(salt, password, hash_func).hexdigest() - else: - h = hash_func() - h.update(password) - rv = h.hexdigest() - return rv, actual_method - - -def generate_password_hash(password, method='pbkdf2:sha1', salt_length=8): - """Hash a password with the given method and salt with with a string of - the given length. The format of the string returned includes the method - that was used so that :func:`check_password_hash` can check the hash. - - The format for the hashed string looks like this:: - - method$salt$hash - - This method can **not** generate unsalted passwords but it is possible - to set the method to plain to enforce plaintext passwords. If a salt - is used, hmac is used internally to salt the password. - - If PBKDF2 is wanted it can be enabled by setting the method to - ``pbkdf2:method:iterations`` where iterations is optional:: - - pbkdf2:sha1:2000$salt$hash - pbkdf2:sha1$salt$hash - - :param password: the password to hash - :param method: the hash method to use (one that hashlib supports), can - optionally be in the format ``pbpdf2:[:iterations]`` - to enable PBKDF2. - :param salt_length: the length of the salt in letters - """ - salt = method != 'plain' and gen_salt(salt_length) or '' - h, actual_method = _hash_internal(method, salt, password) - return '%s$%s$%s' % (actual_method, salt, h) - - -def check_password_hash(pwhash, password): - """check a password against a given salted and hashed password value. - In order to support unsalted legacy passwords this method supports - plain text passwords, md5 and sha1 hashes (both salted and unsalted). - - Returns `True` if the password matched, `False` otherwise. - - :param pwhash: a hashed string like returned by - :func:`generate_password_hash` - :param password: the plaintext password to compare against the hash - """ - if pwhash.count('$') < 2: - return False - method, salt, hashval = pwhash.split('$', 2) - return safe_str_cmp(_hash_internal(method, salt, password)[0], hashval) - - -def safe_join(directory, filename): - """Safely join `directory` and `filename`. If this cannot be done, - this function returns ``None``. - - :param directory: the base directory. - :param filename: the untrusted filename relative to that directory. - """ - filename = posixpath.normpath(filename) - for sep in _os_alt_seps: - if sep in filename: - return None - if os.path.isabs(filename) or filename.startswith('../'): - return None - return os.path.join(directory, filename) diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/serving.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/serving.py deleted file mode 100644 index 79b7ee23..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/serving.py +++ /dev/null @@ -1,749 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.serving - ~~~~~~~~~~~~~~~~ - - There are many ways to serve a WSGI application. While you're developing - it you usually don't want a full blown webserver like Apache but a simple - standalone one. From Python 2.5 onwards there is the `wsgiref`_ server in - the standard library. If you're using older versions of Python you can - download the package from the cheeseshop. - - However there are some caveats. Sourcecode won't reload itself when - changed and each time you kill the server using ``^C`` you get an - `KeyboardInterrupt` error. While the latter is easy to solve the first - one can be a pain in the ass in some situations. - - The easiest way is creating a small ``start-myproject.py`` that runs the - application:: - - #!/usr/bin/env python - # -*- coding: utf-8 -*- - from myproject import make_app - from werkzeug.serving import run_simple - - app = make_app(...) - run_simple('localhost', 8080, app, use_reloader=True) - - You can also pass it a `extra_files` keyword argument with a list of - additional files (like configuration files) you want to observe. - - For bigger applications you should consider using `werkzeug.script` - instead of a simple start file. - - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -from __future__ import with_statement - -import os -import socket -import sys -import time -import signal -import subprocess - -try: - import thread -except ImportError: - import _thread as thread - -try: - from SocketServer import ThreadingMixIn, ForkingMixIn - from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler -except ImportError: - from socketserver import ThreadingMixIn, ForkingMixIn - from http.server import HTTPServer, BaseHTTPRequestHandler - -import werkzeug -from werkzeug._internal import _log -from werkzeug._compat import iteritems, PY2, reraise, text_type, \ - wsgi_encoding_dance -from werkzeug.urls import url_parse, url_unquote -from werkzeug.exceptions import InternalServerError, BadRequest - - -class WSGIRequestHandler(BaseHTTPRequestHandler, object): - """A request handler that implements WSGI dispatching.""" - - @property - def server_version(self): - return 'Werkzeug/' + werkzeug.__version__ - - def make_environ(self): - request_url = url_parse(self.path) - - def shutdown_server(): - self.server.shutdown_signal = True - - url_scheme = self.server.ssl_context is None and 'http' or 'https' - path_info = url_unquote(request_url.path) - - environ = { - 'wsgi.version': (1, 0), - 'wsgi.url_scheme': url_scheme, - 'wsgi.input': self.rfile, - 'wsgi.errors': sys.stderr, - 'wsgi.multithread': self.server.multithread, - 'wsgi.multiprocess': self.server.multiprocess, - 'wsgi.run_once': False, - 'werkzeug.server.shutdown': - shutdown_server, - 'SERVER_SOFTWARE': self.server_version, - 'REQUEST_METHOD': self.command, - 'SCRIPT_NAME': '', - 'PATH_INFO': wsgi_encoding_dance(path_info), - 'QUERY_STRING': wsgi_encoding_dance(request_url.query), - 'CONTENT_TYPE': self.headers.get('Content-Type', ''), - 'CONTENT_LENGTH': self.headers.get('Content-Length', ''), - 'REMOTE_ADDR': self.client_address[0], - 'REMOTE_PORT': self.client_address[1], - 'SERVER_NAME': self.server.server_address[0], - 'SERVER_PORT': str(self.server.server_address[1]), - 'SERVER_PROTOCOL': self.request_version - } - - for key, value in self.headers.items(): - key = 'HTTP_' + key.upper().replace('-', '_') - if key not in ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'): - environ[key] = value - - if request_url.netloc: - environ['HTTP_HOST'] = request_url.netloc - - return environ - - def run_wsgi(self): - if self.headers.get('Expect', '').lower().strip() == '100-continue': - self.wfile.write(b'HTTP/1.1 100 Continue\r\n\r\n') - - environ = self.make_environ() - headers_set = [] - headers_sent = [] - - def write(data): - assert headers_set, 'write() before start_response' - if not headers_sent: - status, response_headers = headers_sent[:] = headers_set - try: - code, msg = status.split(None, 1) - except ValueError: - code, msg = status, "" - self.send_response(int(code), msg) - header_keys = set() - for key, value in response_headers: - self.send_header(key, value) - key = key.lower() - header_keys.add(key) - if 'content-length' not in header_keys: - self.close_connection = True - self.send_header('Connection', 'close') - if 'server' not in header_keys: - self.send_header('Server', self.version_string()) - if 'date' not in header_keys: - self.send_header('Date', self.date_time_string()) - self.end_headers() - - assert type(data) is bytes, 'applications must write bytes' - self.wfile.write(data) - self.wfile.flush() - - def start_response(status, response_headers, exc_info=None): - if exc_info: - try: - if headers_sent: - reraise(*exc_info) - finally: - exc_info = None - elif headers_set: - raise AssertionError('Headers already set') - headers_set[:] = [status, response_headers] - return write - - def execute(app): - application_iter = app(environ, start_response) - try: - for data in application_iter: - write(data) - if not headers_sent: - write(b'') - finally: - if hasattr(application_iter, 'close'): - application_iter.close() - application_iter = None - - try: - execute(self.server.app) - except (socket.error, socket.timeout) as e: - self.connection_dropped(e, environ) - except Exception: - if self.server.passthrough_errors: - raise - from werkzeug.debug.tbtools import get_current_traceback - traceback = get_current_traceback(ignore_system_exceptions=True) - try: - # if we haven't yet sent the headers but they are set - # we roll back to be able to set them again. - if not headers_sent: - del headers_set[:] - execute(InternalServerError()) - except Exception: - pass - self.server.log('error', 'Error on request:\n%s', - traceback.plaintext) - - def handle(self): - """Handles a request ignoring dropped connections.""" - rv = None - try: - rv = BaseHTTPRequestHandler.handle(self) - except (socket.error, socket.timeout) as e: - self.connection_dropped(e) - except Exception: - if self.server.ssl_context is None or not is_ssl_error(): - raise - if self.server.shutdown_signal: - self.initiate_shutdown() - return rv - - def initiate_shutdown(self): - """A horrible, horrible way to kill the server for Python 2.6 and - later. It's the best we can do. - """ - # Windows does not provide SIGKILL, go with SIGTERM then. - sig = getattr(signal, 'SIGKILL', signal.SIGTERM) - # reloader active - if os.environ.get('WERKZEUG_RUN_MAIN') == 'true': - os.kill(os.getpid(), sig) - # python 2.7 - self.server._BaseServer__shutdown_request = True - # python 2.6 - self.server._BaseServer__serving = False - - def connection_dropped(self, error, environ=None): - """Called if the connection was closed by the client. By default - nothing happens. - """ - - def handle_one_request(self): - """Handle a single HTTP request.""" - self.raw_requestline = self.rfile.readline() - if not self.raw_requestline: - self.close_connection = 1 - elif self.parse_request(): - return self.run_wsgi() - - def send_response(self, code, message=None): - """Send the response header and log the response code.""" - self.log_request(code) - if message is None: - message = code in self.responses and self.responses[code][0] or '' - if self.request_version != 'HTTP/0.9': - hdr = "%s %d %s\r\n" % (self.protocol_version, code, message) - self.wfile.write(hdr.encode('ascii')) - - def version_string(self): - return BaseHTTPRequestHandler.version_string(self).strip() - - def address_string(self): - return self.client_address[0] - - def log_request(self, code='-', size='-'): - self.log('info', '"%s" %s %s', self.requestline, code, size) - - def log_error(self, *args): - self.log('error', *args) - - def log_message(self, format, *args): - self.log('info', format, *args) - - def log(self, type, message, *args): - _log(type, '%s - - [%s] %s\n' % (self.address_string(), - self.log_date_time_string(), - message % args)) - - -#: backwards compatible name if someone is subclassing it -BaseRequestHandler = WSGIRequestHandler - - -def generate_adhoc_ssl_pair(cn=None): - from random import random - from OpenSSL import crypto - - # pretty damn sure that this is not actually accepted by anyone - if cn is None: - cn = '*' - - cert = crypto.X509() - cert.set_serial_number(int(random() * sys.maxint)) - cert.gmtime_adj_notBefore(0) - cert.gmtime_adj_notAfter(60 * 60 * 24 * 365) - - subject = cert.get_subject() - subject.CN = cn - subject.O = 'Dummy Certificate' - - issuer = cert.get_issuer() - issuer.CN = 'Untrusted Authority' - issuer.O = 'Self-Signed' - - pkey = crypto.PKey() - pkey.generate_key(crypto.TYPE_RSA, 768) - cert.set_pubkey(pkey) - cert.sign(pkey, 'md5') - - return cert, pkey - - -def make_ssl_devcert(base_path, host=None, cn=None): - """Creates an SSL key for development. This should be used instead of - the ``'adhoc'`` key which generates a new cert on each server start. - It accepts a path for where it should store the key and cert and - either a host or CN. If a host is given it will use the CN - ``*.host/CN=host``. - - For more information see :func:`run_simple`. - - .. versionadded:: 0.9 - - :param base_path: the path to the certificate and key. The extension - ``.crt`` is added for the certificate, ``.key`` is - added for the key. - :param host: the name of the host. This can be used as an alternative - for the `cn`. - :param cn: the `CN` to use. - """ - from OpenSSL import crypto - if host is not None: - cn = '*.%s/CN=%s' % (host, host) - cert, pkey = generate_adhoc_ssl_pair(cn=cn) - - cert_file = base_path + '.crt' - pkey_file = base_path + '.key' - - with open(cert_file, 'w') as f: - f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) - with open(pkey_file, 'w') as f: - f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)) - - return cert_file, pkey_file - - -def generate_adhoc_ssl_context(): - """Generates an adhoc SSL context for the development server.""" - from OpenSSL import SSL - cert, pkey = generate_adhoc_ssl_pair() - ctx = SSL.Context(SSL.SSLv23_METHOD) - ctx.use_privatekey(pkey) - ctx.use_certificate(cert) - return ctx - - -def load_ssl_context(cert_file, pkey_file): - """Loads an SSL context from a certificate and private key file.""" - from OpenSSL import SSL - ctx = SSL.Context(SSL.SSLv23_METHOD) - ctx.use_certificate_file(cert_file) - ctx.use_privatekey_file(pkey_file) - return ctx - - -def is_ssl_error(error=None): - """Checks if the given error (or the current one) is an SSL error.""" - if error is None: - error = sys.exc_info()[1] - from OpenSSL import SSL - return isinstance(error, SSL.Error) - - -class _SSLConnectionFix(object): - """Wrapper around SSL connection to provide a working makefile().""" - - def __init__(self, con): - self._con = con - - def makefile(self, mode, bufsize): - return socket._fileobject(self._con, mode, bufsize) - - def __getattr__(self, attrib): - return getattr(self._con, attrib) - - def shutdown(self, arg=None): - try: - self._con.shutdown() - except Exception: - pass - - -def select_ip_version(host, port): - """Returns AF_INET4 or AF_INET6 depending on where to connect to.""" - # disabled due to problems with current ipv6 implementations - # and various operating systems. Probably this code also is - # not supposed to work, but I can't come up with any other - # ways to implement this. - ##try: - ## info = socket.getaddrinfo(host, port, socket.AF_UNSPEC, - ## socket.SOCK_STREAM, 0, - ## socket.AI_PASSIVE) - ## if info: - ## return info[0][0] - ##except socket.gaierror: - ## pass - if ':' in host and hasattr(socket, 'AF_INET6'): - return socket.AF_INET6 - return socket.AF_INET - - -class BaseWSGIServer(HTTPServer, object): - """Simple single-threaded, single-process WSGI server.""" - multithread = False - multiprocess = False - request_queue_size = 128 - - def __init__(self, host, port, app, handler=None, - passthrough_errors=False, ssl_context=None): - if handler is None: - handler = WSGIRequestHandler - self.address_family = select_ip_version(host, port) - HTTPServer.__init__(self, (host, int(port)), handler) - self.app = app - self.passthrough_errors = passthrough_errors - self.shutdown_signal = False - - if ssl_context is not None: - try: - from OpenSSL import tsafe - except ImportError: - raise TypeError('SSL is not available if the OpenSSL ' - 'library is not installed.') - if isinstance(ssl_context, tuple): - ssl_context = load_ssl_context(*ssl_context) - if ssl_context == 'adhoc': - ssl_context = generate_adhoc_ssl_context() - self.socket = tsafe.Connection(ssl_context, self.socket) - self.ssl_context = ssl_context - else: - self.ssl_context = None - - def log(self, type, message, *args): - _log(type, message, *args) - - def serve_forever(self): - self.shutdown_signal = False - try: - HTTPServer.serve_forever(self) - except KeyboardInterrupt: - pass - - def handle_error(self, request, client_address): - if self.passthrough_errors: - raise - else: - return HTTPServer.handle_error(self, request, client_address) - - def get_request(self): - con, info = self.socket.accept() - if self.ssl_context is not None: - con = _SSLConnectionFix(con) - return con, info - - -class ThreadedWSGIServer(ThreadingMixIn, BaseWSGIServer): - """A WSGI server that does threading.""" - multithread = True - - -class ForkingWSGIServer(ForkingMixIn, BaseWSGIServer): - """A WSGI server that does forking.""" - multiprocess = True - - def __init__(self, host, port, app, processes=40, handler=None, - passthrough_errors=False, ssl_context=None): - BaseWSGIServer.__init__(self, host, port, app, handler, - passthrough_errors, ssl_context) - self.max_children = processes - - -def make_server(host, port, app=None, threaded=False, processes=1, - request_handler=None, passthrough_errors=False, - ssl_context=None): - """Create a new server instance that is either threaded, or forks - or just processes one request after another. - """ - if threaded and processes > 1: - raise ValueError("cannot have a multithreaded and " - "multi process server.") - elif threaded: - return ThreadedWSGIServer(host, port, app, request_handler, - passthrough_errors, ssl_context) - elif processes > 1: - return ForkingWSGIServer(host, port, app, processes, request_handler, - passthrough_errors, ssl_context) - else: - return BaseWSGIServer(host, port, app, request_handler, - passthrough_errors, ssl_context) - - -def _iter_module_files(): - # The list call is necessary on Python 3 in case the module - # dictionary modifies during iteration. - for module in list(sys.modules.values()): - filename = getattr(module, '__file__', None) - if filename: - old = None - while not os.path.isfile(filename): - old = filename - filename = os.path.dirname(filename) - if filename == old: - break - else: - if filename[-4:] in ('.pyc', '.pyo'): - filename = filename[:-1] - yield filename - - -def _reloader_stat_loop(extra_files=None, interval=1): - """When this function is run from the main thread, it will force other - threads to exit when any modules currently loaded change. - - Copyright notice. This function is based on the autoreload.py from - the CherryPy trac which originated from WSGIKit which is now dead. - - :param extra_files: a list of additional files it should watch. - """ - from itertools import chain - mtimes = {} - while 1: - for filename in chain(_iter_module_files(), extra_files or ()): - try: - mtime = os.stat(filename).st_mtime - except OSError: - continue - - old_time = mtimes.get(filename) - if old_time is None: - mtimes[filename] = mtime - continue - elif mtime > old_time: - _log('info', ' * Detected change in %r, reloading' % filename) - sys.exit(3) - time.sleep(interval) - - -def _reloader_inotify(extra_files=None, interval=None): - # Mutated by inotify loop when changes occur. - changed = [False] - - # Setup inotify watches - from pyinotify import WatchManager, Notifier - - # this API changed at one point, support both - try: - from pyinotify import EventsCodes as ec - ec.IN_ATTRIB - except (ImportError, AttributeError): - import pyinotify as ec - - wm = WatchManager() - mask = ec.IN_DELETE_SELF | ec.IN_MOVE_SELF | ec.IN_MODIFY | ec.IN_ATTRIB - - def signal_changed(event): - if changed[0]: - return - _log('info', ' * Detected change in %r, reloading' % event.path) - changed[:] = [True] - - for fname in extra_files or (): - wm.add_watch(fname, mask, signal_changed) - - # ... And now we wait... - notif = Notifier(wm) - try: - while not changed[0]: - # always reiterate through sys.modules, adding them - for fname in _iter_module_files(): - wm.add_watch(fname, mask, signal_changed) - notif.process_events() - if notif.check_events(timeout=interval): - notif.read_events() - # TODO Set timeout to something small and check parent liveliness - finally: - notif.stop() - sys.exit(3) - - -# currently we always use the stat loop reloader for the simple reason -# that the inotify one does not respond to added files properly. Also -# it's quite buggy and the API is a mess. -reloader_loop = _reloader_stat_loop - - -def restart_with_reloader(): - """Spawn a new Python interpreter with the same arguments as this one, - but running the reloader thread. - """ - while 1: - _log('info', ' * Restarting with reloader') - args = [sys.executable] + sys.argv - new_environ = os.environ.copy() - new_environ['WERKZEUG_RUN_MAIN'] = 'true' - - # a weird bug on windows. sometimes unicode strings end up in the - # environment and subprocess.call does not like this, encode them - # to latin1 and continue. - if os.name == 'nt' and PY2: - for key, value in iteritems(new_environ): - if isinstance(value, text_type): - new_environ[key] = value.encode('iso-8859-1') - - exit_code = subprocess.call(args, env=new_environ) - if exit_code != 3: - return exit_code - - -def run_with_reloader(main_func, extra_files=None, interval=1): - """Run the given function in an independent python interpreter.""" - import signal - signal.signal(signal.SIGTERM, lambda *args: sys.exit(0)) - if os.environ.get('WERKZEUG_RUN_MAIN') == 'true': - thread.start_new_thread(main_func, ()) - try: - reloader_loop(extra_files, interval) - except KeyboardInterrupt: - return - try: - sys.exit(restart_with_reloader()) - except KeyboardInterrupt: - pass - - -def run_simple(hostname, port, application, use_reloader=False, - use_debugger=False, use_evalex=True, - extra_files=None, reloader_interval=1, threaded=False, - processes=1, request_handler=None, static_files=None, - passthrough_errors=False, ssl_context=None): - """Start an application using wsgiref and with an optional reloader. This - wraps `wsgiref` to fix the wrong default reporting of the multithreaded - WSGI variable and adds optional multithreading and fork support. - - This function has a command-line interface too:: - - python -m werkzeug.serving --help - - .. versionadded:: 0.5 - `static_files` was added to simplify serving of static files as well - as `passthrough_errors`. - - .. versionadded:: 0.6 - support for SSL was added. - - .. versionadded:: 0.8 - Added support for automatically loading a SSL context from certificate - file and private key. - - .. versionadded:: 0.9 - Added command-line interface. - - :param hostname: The host for the application. eg: ``'localhost'`` - :param port: The port for the server. eg: ``8080`` - :param application: the WSGI application to execute - :param use_reloader: should the server automatically restart the python - process if modules were changed? - :param use_debugger: should the werkzeug debugging system be used? - :param use_evalex: should the exception evaluation feature be enabled? - :param extra_files: a list of files the reloader should watch - additionally to the modules. For example configuration - files. - :param reloader_interval: the interval for the reloader in seconds. - :param threaded: should the process handle each request in a separate - thread? - :param processes: if greater than 1 then handle each request in a new process - up to this maximum number of concurrent processes. - :param request_handler: optional parameter that can be used to replace - the default one. You can use this to replace it - with a different - :class:`~BaseHTTPServer.BaseHTTPRequestHandler` - subclass. - :param static_files: a dict of paths for static files. This works exactly - like :class:`SharedDataMiddleware`, it's actually - just wrapping the application in that middleware before - serving. - :param passthrough_errors: set this to `True` to disable the error catching. - This means that the server will die on errors but - it can be useful to hook debuggers in (pdb etc.) - :param ssl_context: an SSL context for the connection. Either an OpenSSL - context, a tuple in the form ``(cert_file, pkey_file)``, - the string ``'adhoc'`` if the server should - automatically create one, or `None` to disable SSL - (which is the default). - """ - if use_debugger: - from werkzeug.debug import DebuggedApplication - application = DebuggedApplication(application, use_evalex) - if static_files: - from werkzeug.wsgi import SharedDataMiddleware - application = SharedDataMiddleware(application, static_files) - - def inner(): - make_server(hostname, port, application, threaded, - processes, request_handler, - passthrough_errors, ssl_context).serve_forever() - - if os.environ.get('WERKZEUG_RUN_MAIN') != 'true': - display_hostname = hostname != '*' and hostname or 'localhost' - if ':' in display_hostname: - display_hostname = '[%s]' % display_hostname - _log('info', ' * Running on %s://%s:%d/', ssl_context is None - and 'http' or 'https', display_hostname, port) - if use_reloader: - # Create and destroy a socket so that any exceptions are raised before - # we spawn a separate Python interpreter and lose this ability. - address_family = select_ip_version(hostname, port) - test_socket = socket.socket(address_family, socket.SOCK_STREAM) - test_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - test_socket.bind((hostname, port)) - test_socket.close() - run_with_reloader(inner, extra_files, reloader_interval) - else: - inner() - -def main(): - '''A simple command-line interface for :py:func:`run_simple`.''' - - # in contrast to argparse, this works at least under Python < 2.7 - import optparse - from werkzeug.utils import import_string - - parser = optparse.OptionParser(usage='Usage: %prog [options] app_module:app_object') - parser.add_option('-b', '--bind', dest='address', - help='The hostname:port the app should listen on.') - parser.add_option('-d', '--debug', dest='use_debugger', - action='store_true', default=False, - help='Use Werkzeug\'s debugger.') - parser.add_option('-r', '--reload', dest='use_reloader', - action='store_true', default=False, - help='Reload Python process if modules change.') - options, args = parser.parse_args() - - hostname, port = None, None - if options.address: - address = options.address.split(':') - hostname = address[0] - if len(address) > 1: - port = address[1] - - if len(args) != 1: - sys.stdout.write('No application supplied, or too much. See --help\n') - sys.exit(1) - app = import_string(args[0]) - - run_simple( - hostname=(hostname or '127.0.0.1'), port=int(port or 5000), - application=app, use_reloader=options.use_reloader, - use_debugger=options.use_debugger - ) - -if __name__ == '__main__': - main() diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/test.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/test.py deleted file mode 100644 index ed2d2ece..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/test.py +++ /dev/null @@ -1,880 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.test - ~~~~~~~~~~~~~ - - This module implements a client to WSGI applications for testing. - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -import sys -import mimetypes -from time import time -from random import random -from itertools import chain -from tempfile import TemporaryFile -from io import BytesIO - -try: - from urllib2 import Request as U2Request -except ImportError: - from urllib.request import Request as U2Request -try: - from http.cookiejar import CookieJar -except ImportError: # Py2 - from cookielib import CookieJar - -from werkzeug._compat import iterlists, iteritems, itervalues, to_bytes, \ - string_types, text_type, reraise, wsgi_encoding_dance, \ - make_literal_wrapper -from werkzeug._internal import _empty_stream, _get_environ -from werkzeug.wrappers import BaseRequest -from werkzeug.urls import url_encode, url_fix, iri_to_uri, url_unquote, \ - url_unparse, url_parse -from werkzeug.wsgi import get_host, get_current_url, ClosingIterator -from werkzeug.utils import dump_cookie -from werkzeug.datastructures import FileMultiDict, MultiDict, \ - CombinedMultiDict, Headers, FileStorage - - -def stream_encode_multipart(values, use_tempfile=True, threshold=1024 * 500, - boundary=None, charset='utf-8'): - """Encode a dict of values (either strings or file descriptors or - :class:`FileStorage` objects.) into a multipart encoded string stored - in a file descriptor. - """ - if boundary is None: - boundary = '---------------WerkzeugFormPart_%s%s' % (time(), random()) - _closure = [BytesIO(), 0, False] - - if use_tempfile: - def write_binary(string): - stream, total_length, on_disk = _closure - if on_disk: - stream.write(string) - else: - length = len(string) - if length + _closure[1] <= threshold: - stream.write(string) - else: - new_stream = TemporaryFile('wb+') - new_stream.write(stream.getvalue()) - new_stream.write(string) - _closure[0] = new_stream - _closure[2] = True - _closure[1] = total_length + length - else: - write_binary = _closure[0].write - - def write(string): - write_binary(string.encode(charset)) - - if not isinstance(values, MultiDict): - values = MultiDict(values) - - for key, values in iterlists(values): - for value in values: - write('--%s\r\nContent-Disposition: form-data; name="%s"' % - (boundary, key)) - reader = getattr(value, 'read', None) - if reader is not None: - filename = getattr(value, 'filename', - getattr(value, 'name', None)) - content_type = getattr(value, 'content_type', None) - if content_type is None: - content_type = filename and \ - mimetypes.guess_type(filename)[0] or \ - 'application/octet-stream' - if filename is not None: - write('; filename="%s"\r\n' % filename) - else: - write('\r\n') - write('Content-Type: %s\r\n\r\n' % content_type) - while 1: - chunk = reader(16384) - if not chunk: - break - write_binary(chunk) - else: - if not isinstance(value, string_types): - value = str(value) - else: - value = to_bytes(value, charset) - write('\r\n\r\n') - write_binary(value) - write('\r\n') - write('--%s--\r\n' % boundary) - - length = int(_closure[0].tell()) - _closure[0].seek(0) - return _closure[0], length, boundary - - -def encode_multipart(values, boundary=None, charset='utf-8'): - """Like `stream_encode_multipart` but returns a tuple in the form - (``boundary``, ``data``) where data is a bytestring. - """ - stream, length, boundary = stream_encode_multipart( - values, use_tempfile=False, boundary=boundary, charset=charset) - return boundary, stream.read() - - -def File(fd, filename=None, mimetype=None): - """Backwards compat.""" - from warnings import warn - warn(DeprecationWarning('werkzeug.test.File is deprecated, use the ' - 'EnvironBuilder or FileStorage instead')) - return FileStorage(fd, filename=filename, content_type=mimetype) - - -class _TestCookieHeaders(object): - """A headers adapter for cookielib - """ - - def __init__(self, headers): - self.headers = headers - - def getheaders(self, name): - headers = [] - name = name.lower() - for k, v in self.headers: - if k.lower() == name: - headers.append(v) - return headers - - def get_all(self, name, default=None): - rv = [] - for k, v in self.headers: - if k.lower() == name.lower(): - rv.append(v) - return rv or default or [] - - -class _TestCookieResponse(object): - """Something that looks like a httplib.HTTPResponse, but is actually just an - adapter for our test responses to make them available for cookielib. - """ - - def __init__(self, headers): - self.headers = _TestCookieHeaders(headers) - - def info(self): - return self.headers - - -class _TestCookieJar(CookieJar): - """A cookielib.CookieJar modified to inject and read cookie headers from - and to wsgi environments, and wsgi application responses. - """ - - def inject_wsgi(self, environ): - """Inject the cookies as client headers into the server's wsgi - environment. - """ - cvals = [] - for cookie in self: - cvals.append('%s=%s' % (cookie.name, cookie.value)) - if cvals: - environ['HTTP_COOKIE'] = '; '.join(cvals) - - def extract_wsgi(self, environ, headers): - """Extract the server's set-cookie headers as cookies into the - cookie jar. - """ - self.extract_cookies( - _TestCookieResponse(headers), - U2Request(get_current_url(environ)), - ) - - -def _iter_data(data): - """Iterates over a dict or multidict yielding all keys and values. - This is used to iterate over the data passed to the - :class:`EnvironBuilder`. - """ - if isinstance(data, MultiDict): - for key, values in iterlists(data): - for value in values: - yield key, value - else: - for key, values in iteritems(data): - if isinstance(values, list): - for value in values: - yield key, value - else: - yield key, values - - -class EnvironBuilder(object): - """This class can be used to conveniently create a WSGI environment - for testing purposes. It can be used to quickly create WSGI environments - or request objects from arbitrary data. - - The signature of this class is also used in some other places as of - Werkzeug 0.5 (:func:`create_environ`, :meth:`BaseResponse.from_values`, - :meth:`Client.open`). Because of this most of the functionality is - available through the constructor alone. - - Files and regular form data can be manipulated independently of each - other with the :attr:`form` and :attr:`files` attributes, but are - passed with the same argument to the constructor: `data`. - - `data` can be any of these values: - - - a `str`: If it's a string it is converted into a :attr:`input_stream`, - the :attr:`content_length` is set and you have to provide a - :attr:`content_type`. - - a `dict`: If it's a dict the keys have to be strings and the values - any of the following objects: - - - a :class:`file`-like object. These are converted into - :class:`FileStorage` objects automatically. - - a tuple. The :meth:`~FileMultiDict.add_file` method is called - with the tuple items as positional arguments. - - .. versionadded:: 0.6 - `path` and `base_url` can now be unicode strings that are encoded using - the :func:`iri_to_uri` function. - - :param path: the path of the request. In the WSGI environment this will - end up as `PATH_INFO`. If the `query_string` is not defined - and there is a question mark in the `path` everything after - it is used as query string. - :param base_url: the base URL is a URL that is used to extract the WSGI - URL scheme, host (server name + server port) and the - script root (`SCRIPT_NAME`). - :param query_string: an optional string or dict with URL parameters. - :param method: the HTTP method to use, defaults to `GET`. - :param input_stream: an optional input stream. Do not specify this and - `data`. As soon as an input stream is set you can't - modify :attr:`args` and :attr:`files` unless you - set the :attr:`input_stream` to `None` again. - :param content_type: The content type for the request. As of 0.5 you - don't have to provide this when specifying files - and form data via `data`. - :param content_length: The content length for the request. You don't - have to specify this when providing data via - `data`. - :param errors_stream: an optional error stream that is used for - `wsgi.errors`. Defaults to :data:`stderr`. - :param multithread: controls `wsgi.multithread`. Defaults to `False`. - :param multiprocess: controls `wsgi.multiprocess`. Defaults to `False`. - :param run_once: controls `wsgi.run_once`. Defaults to `False`. - :param headers: an optional list or :class:`Headers` object of headers. - :param data: a string or dict of form data. See explanation above. - :param environ_base: an optional dict of environment defaults. - :param environ_overrides: an optional dict of environment overrides. - :param charset: the charset used to encode unicode data. - """ - - #: the server protocol to use. defaults to HTTP/1.1 - server_protocol = 'HTTP/1.1' - - #: the wsgi version to use. defaults to (1, 0) - wsgi_version = (1, 0) - - #: the default request class for :meth:`get_request` - request_class = BaseRequest - - def __init__(self, path='/', base_url=None, query_string=None, - method='GET', input_stream=None, content_type=None, - content_length=None, errors_stream=None, multithread=False, - multiprocess=False, run_once=False, headers=None, data=None, - environ_base=None, environ_overrides=None, charset='utf-8'): - path_s = make_literal_wrapper(path) - if query_string is None and path_s('?') in path: - path, query_string = path.split(path_s('?'), 1) - self.charset = charset - self.path = iri_to_uri(path) - if base_url is not None: - base_url = url_fix(iri_to_uri(base_url, charset), charset) - self.base_url = base_url - if isinstance(query_string, (bytes, text_type)): - self.query_string = query_string - else: - if query_string is None: - query_string = MultiDict() - elif not isinstance(query_string, MultiDict): - query_string = MultiDict(query_string) - self.args = query_string - self.method = method - if headers is None: - headers = Headers() - elif not isinstance(headers, Headers): - headers = Headers(headers) - self.headers = headers - if content_type is not None: - self.content_type = content_type - if errors_stream is None: - errors_stream = sys.stderr - self.errors_stream = errors_stream - self.multithread = multithread - self.multiprocess = multiprocess - self.run_once = run_once - self.environ_base = environ_base - self.environ_overrides = environ_overrides - self.input_stream = input_stream - self.content_length = content_length - self.closed = False - - if data: - if input_stream is not None: - raise TypeError('can\'t provide input stream and data') - if isinstance(data, text_type): - data = data.encode(self.charset) - if isinstance(data, bytes): - self.input_stream = BytesIO(data) - if self.content_length is None: - self.content_length = len(data) - else: - for key, value in _iter_data(data): - if isinstance(value, (tuple, dict)) or \ - hasattr(value, 'read'): - self._add_file_from_data(key, value) - else: - self.form.setlistdefault(key).append(value) - - def _add_file_from_data(self, key, value): - """Called in the EnvironBuilder to add files from the data dict.""" - if isinstance(value, tuple): - self.files.add_file(key, *value) - elif isinstance(value, dict): - from warnings import warn - warn(DeprecationWarning('it\'s no longer possible to pass dicts ' - 'as `data`. Use tuples or FileStorage ' - 'objects instead'), stacklevel=2) - value = dict(value) - mimetype = value.pop('mimetype', None) - if mimetype is not None: - value['content_type'] = mimetype - self.files.add_file(key, **value) - else: - self.files.add_file(key, value) - - def _get_base_url(self): - return url_unparse((self.url_scheme, self.host, - self.script_root, '', '')).rstrip('/') + '/' - - def _set_base_url(self, value): - if value is None: - scheme = 'http' - netloc = 'localhost' - script_root = '' - else: - scheme, netloc, script_root, qs, anchor = url_parse(value) - if qs or anchor: - raise ValueError('base url must not contain a query string ' - 'or fragment') - self.script_root = script_root.rstrip('/') - self.host = netloc - self.url_scheme = scheme - - base_url = property(_get_base_url, _set_base_url, doc=''' - The base URL is a URL that is used to extract the WSGI - URL scheme, host (server name + server port) and the - script root (`SCRIPT_NAME`).''') - del _get_base_url, _set_base_url - - def _get_content_type(self): - ct = self.headers.get('Content-Type') - if ct is None and not self._input_stream: - if self.method in ('POST', 'PUT', 'PATCH'): - if self._files: - return 'multipart/form-data' - return 'application/x-www-form-urlencoded' - return None - return ct - - def _set_content_type(self, value): - if value is None: - self.headers.pop('Content-Type', None) - else: - self.headers['Content-Type'] = value - - content_type = property(_get_content_type, _set_content_type, doc=''' - The content type for the request. Reflected from and to the - :attr:`headers`. Do not set if you set :attr:`files` or - :attr:`form` for auto detection.''') - del _get_content_type, _set_content_type - - def _get_content_length(self): - return self.headers.get('Content-Length', type=int) - - def _set_content_length(self, value): - if value is None: - self.headers.pop('Content-Length', None) - else: - self.headers['Content-Length'] = str(value) - - content_length = property(_get_content_length, _set_content_length, doc=''' - The content length as integer. Reflected from and to the - :attr:`headers`. Do not set if you set :attr:`files` or - :attr:`form` for auto detection.''') - del _get_content_length, _set_content_length - - def form_property(name, storage, doc): - key = '_' + name - def getter(self): - if self._input_stream is not None: - raise AttributeError('an input stream is defined') - rv = getattr(self, key) - if rv is None: - rv = storage() - setattr(self, key, rv) - return rv - def setter(self, value): - self._input_stream = None - setattr(self, key, value) - return property(getter, setter, doc) - - form = form_property('form', MultiDict, doc=''' - A :class:`MultiDict` of form values.''') - files = form_property('files', FileMultiDict, doc=''' - A :class:`FileMultiDict` of uploaded files. You can use the - :meth:`~FileMultiDict.add_file` method to add new files to the - dict.''') - del form_property - - def _get_input_stream(self): - return self._input_stream - - def _set_input_stream(self, value): - self._input_stream = value - self._form = self._files = None - - input_stream = property(_get_input_stream, _set_input_stream, doc=''' - An optional input stream. If you set this it will clear - :attr:`form` and :attr:`files`.''') - del _get_input_stream, _set_input_stream - - def _get_query_string(self): - if self._query_string is None: - if self._args is not None: - return url_encode(self._args, charset=self.charset) - return '' - return self._query_string - - def _set_query_string(self, value): - self._query_string = value - self._args = None - - query_string = property(_get_query_string, _set_query_string, doc=''' - The query string. If you set this to a string :attr:`args` will - no longer be available.''') - del _get_query_string, _set_query_string - - def _get_args(self): - if self._query_string is not None: - raise AttributeError('a query string is defined') - if self._args is None: - self._args = MultiDict() - return self._args - - def _set_args(self, value): - self._query_string = None - self._args = value - - args = property(_get_args, _set_args, doc=''' - The URL arguments as :class:`MultiDict`.''') - del _get_args, _set_args - - @property - def server_name(self): - """The server name (read-only, use :attr:`host` to set)""" - return self.host.split(':', 1)[0] - - @property - def server_port(self): - """The server port as integer (read-only, use :attr:`host` to set)""" - pieces = self.host.split(':', 1) - if len(pieces) == 2 and pieces[1].isdigit(): - return int(pieces[1]) - elif self.url_scheme == 'https': - return 443 - return 80 - - def __del__(self): - try: - self.close() - except Exception: - pass - - def close(self): - """Closes all files. If you put real :class:`file` objects into the - :attr:`files` dict you can call this method to automatically close - them all in one go. - """ - if self.closed: - return - try: - files = itervalues(self.files) - except AttributeError: - files = () - for f in files: - try: - f.close() - except Exception: - pass - self.closed = True - - def get_environ(self): - """Return the built environ.""" - input_stream = self.input_stream - content_length = self.content_length - content_type = self.content_type - - if input_stream is not None: - start_pos = input_stream.tell() - input_stream.seek(0, 2) - end_pos = input_stream.tell() - input_stream.seek(start_pos) - content_length = end_pos - start_pos - elif content_type == 'multipart/form-data': - values = CombinedMultiDict([self.form, self.files]) - input_stream, content_length, boundary = \ - stream_encode_multipart(values, charset=self.charset) - content_type += '; boundary="%s"' % boundary - elif content_type == 'application/x-www-form-urlencoded': - #py2v3 review - values = url_encode(self.form, charset=self.charset) - values = values.encode('ascii') - content_length = len(values) - input_stream = BytesIO(values) - else: - input_stream = _empty_stream - - result = {} - if self.environ_base: - result.update(self.environ_base) - - def _path_encode(x): - return wsgi_encoding_dance(url_unquote(x, self.charset), self.charset) - - qs = wsgi_encoding_dance(self.query_string) - - result.update({ - 'REQUEST_METHOD': self.method, - 'SCRIPT_NAME': _path_encode(self.script_root), - 'PATH_INFO': _path_encode(self.path), - 'QUERY_STRING': qs, - 'SERVER_NAME': self.server_name, - 'SERVER_PORT': str(self.server_port), - 'HTTP_HOST': self.host, - 'SERVER_PROTOCOL': self.server_protocol, - 'CONTENT_TYPE': content_type or '', - 'CONTENT_LENGTH': str(content_length or '0'), - 'wsgi.version': self.wsgi_version, - 'wsgi.url_scheme': self.url_scheme, - 'wsgi.input': input_stream, - 'wsgi.errors': self.errors_stream, - 'wsgi.multithread': self.multithread, - 'wsgi.multiprocess': self.multiprocess, - 'wsgi.run_once': self.run_once - }) - for key, value in self.headers.to_wsgi_list(): - result['HTTP_%s' % key.upper().replace('-', '_')] = value - if self.environ_overrides: - result.update(self.environ_overrides) - return result - - def get_request(self, cls=None): - """Returns a request with the data. If the request class is not - specified :attr:`request_class` is used. - - :param cls: The request wrapper to use. - """ - if cls is None: - cls = self.request_class - return cls(self.get_environ()) - - -class ClientRedirectError(Exception): - """ - If a redirect loop is detected when using follow_redirects=True with - the :cls:`Client`, then this exception is raised. - """ - - -class Client(object): - """This class allows to send requests to a wrapped application. - - The response wrapper can be a class or factory function that takes - three arguments: app_iter, status and headers. The default response - wrapper just returns a tuple. - - Example:: - - class ClientResponse(BaseResponse): - ... - - client = Client(MyApplication(), response_wrapper=ClientResponse) - - The use_cookies parameter indicates whether cookies should be stored and - sent for subsequent requests. This is True by default, but passing False - will disable this behaviour. - - If you want to request some subdomain of your application you may set - `allow_subdomain_redirects` to `True` as if not no external redirects - are allowed. - - .. versionadded:: 0.5 - `use_cookies` is new in this version. Older versions did not provide - builtin cookie support. - """ - - def __init__(self, application, response_wrapper=None, use_cookies=True, - allow_subdomain_redirects=False): - self.application = application - self.response_wrapper = response_wrapper - if use_cookies: - self.cookie_jar = _TestCookieJar() - else: - self.cookie_jar = None - self.allow_subdomain_redirects = allow_subdomain_redirects - - def set_cookie(self, server_name, key, value='', max_age=None, - expires=None, path='/', domain=None, secure=None, - httponly=False, charset='utf-8'): - """Sets a cookie in the client's cookie jar. The server name - is required and has to match the one that is also passed to - the open call. - """ - assert self.cookie_jar is not None, 'cookies disabled' - header = dump_cookie(key, value, max_age, expires, path, domain, - secure, httponly, charset) - environ = create_environ(path, base_url='http://' + server_name) - headers = [('Set-Cookie', header)] - self.cookie_jar.extract_wsgi(environ, headers) - - def delete_cookie(self, server_name, key, path='/', domain=None): - """Deletes a cookie in the test client.""" - self.set_cookie(server_name, key, expires=0, max_age=0, - path=path, domain=domain) - - def run_wsgi_app(self, environ, buffered=False): - """Runs the wrapped WSGI app with the given environment.""" - if self.cookie_jar is not None: - self.cookie_jar.inject_wsgi(environ) - rv = run_wsgi_app(self.application, environ, buffered=buffered) - if self.cookie_jar is not None: - self.cookie_jar.extract_wsgi(environ, rv[2]) - return rv - - def resolve_redirect(self, response, new_location, environ, buffered=False): - """Resolves a single redirect and triggers the request again - directly on this redirect client. - """ - scheme, netloc, script_root, qs, anchor = url_parse(new_location) - base_url = url_unparse((scheme, netloc, '', '', '')).rstrip('/') + '/' - - cur_server_name = netloc.split(':', 1)[0].split('.') - real_server_name = get_host(environ).rsplit(':', 1)[0].split('.') - - if self.allow_subdomain_redirects: - allowed = cur_server_name[-len(real_server_name):] == real_server_name - else: - allowed = cur_server_name == real_server_name - - if not allowed: - raise RuntimeError('%r does not support redirect to ' - 'external targets' % self.__class__) - - # For redirect handling we temporarily disable the response - # wrapper. This is not threadsafe but not a real concern - # since the test client must not be shared anyways. - old_response_wrapper = self.response_wrapper - self.response_wrapper = None - try: - return self.open(path=script_root, base_url=base_url, - query_string=qs, as_tuple=True, - buffered=buffered) - finally: - self.response_wrapper = old_response_wrapper - - def open(self, *args, **kwargs): - """Takes the same arguments as the :class:`EnvironBuilder` class with - some additions: You can provide a :class:`EnvironBuilder` or a WSGI - environment as only argument instead of the :class:`EnvironBuilder` - arguments and two optional keyword arguments (`as_tuple`, `buffered`) - that change the type of the return value or the way the application is - executed. - - .. versionchanged:: 0.5 - If a dict is provided as file in the dict for the `data` parameter - the content type has to be called `content_type` now instead of - `mimetype`. This change was made for consistency with - :class:`werkzeug.FileWrapper`. - - The `follow_redirects` parameter was added to :func:`open`. - - Additional parameters: - - :param as_tuple: Returns a tuple in the form ``(environ, result)`` - :param buffered: Set this to True to buffer the application run. - This will automatically close the application for - you as well. - :param follow_redirects: Set this to True if the `Client` should - follow HTTP redirects. - """ - as_tuple = kwargs.pop('as_tuple', False) - buffered = kwargs.pop('buffered', False) - follow_redirects = kwargs.pop('follow_redirects', False) - environ = None - if not kwargs and len(args) == 1: - if isinstance(args[0], EnvironBuilder): - environ = args[0].get_environ() - elif isinstance(args[0], dict): - environ = args[0] - if environ is None: - builder = EnvironBuilder(*args, **kwargs) - try: - environ = builder.get_environ() - finally: - builder.close() - - response = self.run_wsgi_app(environ, buffered=buffered) - - # handle redirects - redirect_chain = [] - while 1: - status_code = int(response[1].split(None, 1)[0]) - if status_code not in (301, 302, 303, 305, 307) \ - or not follow_redirects: - break - new_location = response[2]['location'] - new_redirect_entry = (new_location, status_code) - if new_redirect_entry in redirect_chain: - raise ClientRedirectError('loop detected') - redirect_chain.append(new_redirect_entry) - environ, response = self.resolve_redirect(response, new_location, - environ, buffered=buffered) - - if self.response_wrapper is not None: - response = self.response_wrapper(*response) - if as_tuple: - return environ, response - return response - - def get(self, *args, **kw): - """Like open but method is enforced to GET.""" - kw['method'] = 'GET' - return self.open(*args, **kw) - - def patch(self, *args, **kw): - """Like open but method is enforced to PATCH.""" - kw['method'] = 'PATCH' - return self.open(*args, **kw) - - def post(self, *args, **kw): - """Like open but method is enforced to POST.""" - kw['method'] = 'POST' - return self.open(*args, **kw) - - def head(self, *args, **kw): - """Like open but method is enforced to HEAD.""" - kw['method'] = 'HEAD' - return self.open(*args, **kw) - - def put(self, *args, **kw): - """Like open but method is enforced to PUT.""" - kw['method'] = 'PUT' - return self.open(*args, **kw) - - def delete(self, *args, **kw): - """Like open but method is enforced to DELETE.""" - kw['method'] = 'DELETE' - return self.open(*args, **kw) - - def options(self, *args, **kw): - """Like open but method is enforced to OPTIONS.""" - kw['method'] = 'OPTIONS' - return self.open(*args, **kw) - - def trace(self, *args, **kw): - """Like open but method is enforced to TRACE.""" - kw['method'] = 'TRACE' - return self.open(*args, **kw) - - def __repr__(self): - return '<%s %r>' % ( - self.__class__.__name__, - self.application - ) - - -def create_environ(*args, **kwargs): - """Create a new WSGI environ dict based on the values passed. The first - parameter should be the path of the request which defaults to '/'. The - second one can either be an absolute path (in that case the host is - localhost:80) or a full path to the request with scheme, netloc port and - the path to the script. - - This accepts the same arguments as the :class:`EnvironBuilder` - constructor. - - .. versionchanged:: 0.5 - This function is now a thin wrapper over :class:`EnvironBuilder` which - was added in 0.5. The `headers`, `environ_base`, `environ_overrides` - and `charset` parameters were added. - """ - builder = EnvironBuilder(*args, **kwargs) - try: - return builder.get_environ() - finally: - builder.close() - - -def run_wsgi_app(app, environ, buffered=False): - """Return a tuple in the form (app_iter, status, headers) of the - application output. This works best if you pass it an application that - returns an iterator all the time. - - Sometimes applications may use the `write()` callable returned - by the `start_response` function. This tries to resolve such edge - cases automatically. But if you don't get the expected output you - should set `buffered` to `True` which enforces buffering. - - If passed an invalid WSGI application the behavior of this function is - undefined. Never pass non-conforming WSGI applications to this function. - - :param app: the application to execute. - :param buffered: set to `True` to enforce buffering. - :return: tuple in the form ``(app_iter, status, headers)`` - """ - environ = _get_environ(environ) - response = [] - buffer = [] - - def start_response(status, headers, exc_info=None): - if exc_info is not None: - reraise(*exc_info) - response[:] = [status, headers] - return buffer.append - - app_iter = app(environ, start_response) - - # when buffering we emit the close call early and convert the - # application iterator into a regular list - if buffered: - close_func = getattr(app_iter, 'close', None) - try: - app_iter = list(app_iter) - finally: - if close_func is not None: - close_func() - - # otherwise we iterate the application iter until we have - # a response, chain the already received data with the already - # collected data and wrap it in a new `ClosingIterator` if - # we have a close callable. - else: - while not response: - buffer.append(next(app_iter)) - if buffer: - close_func = getattr(app_iter, 'close', None) - app_iter = chain(buffer, app_iter) - if close_func is not None: - app_iter = ClosingIterator(app_iter, close_func) - - return app_iter, response[0], Headers(response[1]) diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testapp.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testapp.py deleted file mode 100644 index 4f1e31c1..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testapp.py +++ /dev/null @@ -1,230 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testapp - ~~~~~~~~~~~~~~~~ - - Provide a small test application that can be used to test a WSGI server - and check it for WSGI compliance. - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -import os -import sys -import werkzeug -from textwrap import wrap -from werkzeug.wrappers import BaseRequest as Request, BaseResponse as Response -from werkzeug.utils import escape -import base64 - -logo = Response(base64.b64decode( -'''R0lGODlhoACgAOMIAAEDACwpAEpCAGdgAJaKAM28AOnVAP3rAP///////// -//////////////////////yH5BAEKAAgALAAAAACgAKAAAAT+EMlJq704680R+F0ojmRpnuj0rWnrv -nB8rbRs33gu0bzu/0AObxgsGn3D5HHJbCUFyqZ0ukkSDlAidctNFg7gbI9LZlrBaHGtzAae0eloe25 -7w9EDOX2fst/xenyCIn5/gFqDiVVDV4aGeYiKkhSFjnCQY5OTlZaXgZp8nJ2ekaB0SQOjqphrpnOiq -ncEn65UsLGytLVmQ6m4sQazpbtLqL/HwpnER8bHyLrLOc3Oz8PRONPU1crXN9na263dMt/g4SzjMeX -m5yDpLqgG7OzJ4u8lT/P69ej3JPn69kHzN2OIAHkB9RUYSFCFQYQJFTIkCDBiwoXWGnowaLEjRm7+G -p9A7Hhx4rUkAUaSLJlxHMqVMD/aSycSZkyTplCqtGnRAM5NQ1Ly5OmzZc6gO4d6DGAUKA+hSocWYAo -SlM6oUWX2O/o0KdaVU5vuSQLAa0ADwQgMEMB2AIECZhVSnTno6spgbtXmHcBUrQACcc2FrTrWS8wAf -78cMFBgwIBgbN+qvTt3ayikRBk7BoyGAGABAdYyfdzRQGV3l4coxrqQ84GpUBmrdR3xNIDUPAKDBSA -ADIGDhhqTZIWaDcrVX8EsbNzbkvCOxG8bN5w8ly9H8jyTJHC6DFndQydbguh2e/ctZJFXRxMAqqPVA -tQH5E64SPr1f0zz7sQYjAHg0In+JQ11+N2B0XXBeeYZgBZFx4tqBToiTCPv0YBgQv8JqA6BEf6RhXx -w1ENhRBnWV8ctEX4Ul2zc3aVGcQNC2KElyTDYyYUWvShdjDyMOGMuFjqnII45aogPhz/CodUHFwaDx -lTgsaOjNyhGWJQd+lFoAGk8ObghI0kawg+EV5blH3dr+digkYuAGSaQZFHFz2P/cTaLmhF52QeSb45 -Jwxd+uSVGHlqOZpOeJpCFZ5J+rkAkFjQ0N1tah7JJSZUFNsrkeJUJMIBi8jyaEKIhKPomnC91Uo+NB -yyaJ5umnnpInIFh4t6ZSpGaAVmizqjpByDegYl8tPE0phCYrhcMWSv+uAqHfgH88ak5UXZmlKLVJhd -dj78s1Fxnzo6yUCrV6rrDOkluG+QzCAUTbCwf9SrmMLzK6p+OPHx7DF+bsfMRq7Ec61Av9i6GLw23r -idnZ+/OO0a99pbIrJkproCQMA17OPG6suq3cca5ruDfXCCDoS7BEdvmJn5otdqscn+uogRHHXs8cbh -EIfYaDY1AkrC0cqwcZpnM6ludx72x0p7Fo/hZAcpJDjax0UdHavMKAbiKltMWCF3xxh9k25N/Viud8 -ba78iCvUkt+V6BpwMlErmcgc502x+u1nSxJSJP9Mi52awD1V4yB/QHONsnU3L+A/zR4VL/indx/y64 -gqcj+qgTeweM86f0Qy1QVbvmWH1D9h+alqg254QD8HJXHvjQaGOqEqC22M54PcftZVKVSQG9jhkv7C -JyTyDoAJfPdu8v7DRZAxsP/ky9MJ3OL36DJfCFPASC3/aXlfLOOON9vGZZHydGf8LnxYJuuVIbl83y -Az5n/RPz07E+9+zw2A2ahz4HxHo9Kt79HTMx1Q7ma7zAzHgHqYH0SoZWyTuOLMiHwSfZDAQTn0ajk9 -YQqodnUYjByQZhZak9Wu4gYQsMyEpIOAOQKze8CmEF45KuAHTvIDOfHJNipwoHMuGHBnJElUoDmAyX -c2Qm/R8Ah/iILCCJOEokGowdhDYc/yoL+vpRGwyVSCWFYZNljkhEirGXsalWcAgOdeAdoXcktF2udb -qbUhjWyMQxYO01o6KYKOr6iK3fE4MaS+DsvBsGOBaMb0Y6IxADaJhFICaOLmiWTlDAnY1KzDG4ambL -cWBA8mUzjJsN2KjSaSXGqMCVXYpYkj33mcIApyhQf6YqgeNAmNvuC0t4CsDbSshZJkCS1eNisKqlyG -cF8G2JeiDX6tO6Mv0SmjCa3MFb0bJaGPMU0X7c8XcpvMaOQmCajwSeY9G0WqbBmKv34DsMIEztU6Y2 -KiDlFdt6jnCSqx7Dmt6XnqSKaFFHNO5+FmODxMCWBEaco77lNDGXBM0ECYB/+s7nKFdwSF5hgXumQe -EZ7amRg39RHy3zIjyRCykQh8Zo2iviRKyTDn/zx6EefptJj2Cw+Ep2FSc01U5ry4KLPYsTyWnVGnvb -UpyGlhjBUljyjHhWpf8OFaXwhp9O4T1gU9UeyPPa8A2l0p1kNqPXEVRm1AOs1oAGZU596t6SOR2mcB -Oco1srWtkaVrMUzIErrKri85keKqRQYX9VX0/eAUK1hrSu6HMEX3Qh2sCh0q0D2CtnUqS4hj62sE/z -aDs2Sg7MBS6xnQeooc2R2tC9YrKpEi9pLXfYXp20tDCpSP8rKlrD4axprb9u1Df5hSbz9QU0cRpfgn -kiIzwKucd0wsEHlLpe5yHXuc6FrNelOl7pY2+11kTWx7VpRu97dXA3DO1vbkhcb4zyvERYajQgAADs -='''), mimetype='image/png') - - -TEMPLATE = u'''\ - -WSGI Information - -

- -

WSGI Information

-

- This page displays all available information about the WSGI server and - the underlying Python interpreter. -

Python Interpreter

- - - - - - -
Python Version - %(python_version)s -
Platform - %(platform)s [%(os)s] -
API Version - %(api_version)s -
Byteorder - %(byteorder)s -
Werkzeug Version - %(werkzeug_version)s -
-

WSGI Environment

- %(wsgi_env)s
-

Installed Eggs

-

- The following python packages were installed on the system as - Python eggs: -

    %(python_eggs)s
-

System Path

-

- The following paths are the current contents of the load path. The - following entries are looked up for Python packages. Note that not - all items in this path are folders. Gray and underlined items are - entries pointing to invalid resources or used by custom import hooks - such as the zip importer. -

- Items with a bright background were expanded for display from a relative - path. If you encounter such paths in the output you might want to check - your setup as relative paths are usually problematic in multithreaded - environments. -

    %(sys_path)s
-
-''' - - -def iter_sys_path(): - if os.name == 'posix': - def strip(x): - prefix = os.path.expanduser('~') - if x.startswith(prefix): - x = '~' + x[len(prefix):] - return x - else: - strip = lambda x: x - - cwd = os.path.abspath(os.getcwd()) - for item in sys.path: - path = os.path.join(cwd, item or os.path.curdir) - yield strip(os.path.normpath(path)), \ - not os.path.isdir(path), path != item - - -def render_testapp(req): - try: - import pkg_resources - except ImportError: - eggs = () - else: - eggs = sorted(pkg_resources.working_set, - key=lambda x: x.project_name.lower()) - python_eggs = [] - for egg in eggs: - try: - version = egg.version - except (ValueError, AttributeError): - version = 'unknown' - python_eggs.append('
  • %s [%s]' % ( - escape(egg.project_name), - escape(version) - )) - - wsgi_env = [] - sorted_environ = sorted(req.environ.items(), - key=lambda x: repr(x[0]).lower()) - for key, value in sorted_environ: - wsgi_env.append('%s%s' % ( - escape(str(key)), - ' '.join(wrap(escape(repr(value)))) - )) - - sys_path = [] - for item, virtual, expanded in iter_sys_path(): - class_ = [] - if virtual: - class_.append('virtual') - if expanded: - class_.append('exp') - sys_path.append('%s' % ( - class_ and ' class="%s"' % ' '.join(class_) or '', - escape(item) - )) - - return (TEMPLATE % { - 'python_version': '
    '.join(escape(sys.version).splitlines()), - 'platform': escape(sys.platform), - 'os': escape(os.name), - 'api_version': sys.api_version, - 'byteorder': sys.byteorder, - 'werkzeug_version': werkzeug.__version__, - 'python_eggs': '\n'.join(python_eggs), - 'wsgi_env': '\n'.join(wsgi_env), - 'sys_path': '\n'.join(sys_path) - }).encode('utf-8') - - -def test_app(environ, start_response): - """Simple test application that dumps the environment. You can use - it to check if Werkzeug is working properly: - - .. sourcecode:: pycon - - >>> from werkzeug.serving import run_simple - >>> from werkzeug.testapp import test_app - >>> run_simple('localhost', 3000, test_app) - * Running on http://localhost:3000/ - - The application displays important information from the WSGI environment, - the Python interpreter and the installed libraries. - """ - req = Request(environ, populate_request=False) - if req.args.get('resource') == 'logo': - response = logo - else: - response = Response(render_testapp(req), mimetype='text/html') - return response(environ, start_response) - - -if __name__ == '__main__': - from werkzeug.serving import run_simple - run_simple('localhost', 5000, test_app, use_reloader=True) diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/__init__.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/__init__.py deleted file mode 100644 index 691ccddf..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/__init__.py +++ /dev/null @@ -1,267 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite - ~~~~~~~~~~~~~~~~~~ - - Contains all test Werkzeug tests. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" - -from __future__ import with_statement - -import re -import sys -import unittest -import shutil -import tempfile -import atexit - -from werkzeug.utils import find_modules -from werkzeug._compat import text_type, integer_types, reraise - - -def get_temporary_directory(): - directory = tempfile.mkdtemp() - @atexit.register - def remove_directory(): - try: - shutil.rmtree(directory) - except EnvironmentError: - pass - return directory - - -def iter_suites(package): - """Yields all testsuites.""" - for module in find_modules(package, include_packages=True): - mod = __import__(module, fromlist=['*']) - if hasattr(mod, 'suite'): - yield mod.suite() - - -def find_all_tests(suite): - """Yields all the tests and their names from a given suite.""" - suites = [suite] - while suites: - s = suites.pop() - try: - suites.extend(s) - except TypeError: - yield s, '%s.%s.%s' % ( - s.__class__.__module__, - s.__class__.__name__, - s._testMethodName - ) - - -class WerkzeugTestCase(unittest.TestCase): - """Baseclass for all the tests that Werkzeug uses. Use these - methods for testing instead of the camelcased ones in the - baseclass for consistency. - """ - - def setup(self): - pass - - def teardown(self): - pass - - def setUp(self): - self.setup() - - def tearDown(self): - unittest.TestCase.tearDown(self) - self.teardown() - - def assert_line_equal(self, x, y): - assert x == y, "lines not equal\n a = %r\n b = %r" % (x, y) - - def assert_equal(self, x, y, msg=None): - return self.assertEqual(x, y, msg) - - def assert_not_equal(self, x, y): - return self.assertNotEqual(x, y) - - def assert_raises(self, exc_type, callable=None, *args, **kwargs): - catcher = _ExceptionCatcher(self, exc_type) - if callable is None: - return catcher - with catcher: - callable(*args, **kwargs) - - if sys.version_info[:2] == (2, 6): - def assertIsNone(self, x): - assert x is None, "%r is not None" % (x,) - - def assertIsNotNone(self, x): - assert x is not None, "%r is None" % (x, ) - - def assertIn(self, x, y): - assert x in y, "%r not in %r" % (x, y) - - def assertNotIn(self, x, y): - assert x not in y, "%r in %r" % (x, y) - - def assertIsInstance(self, x, y): - assert isinstance(x, y), "not isinstance(%r, %r)" % (x, y) - - def assertIs(self, x, y): - assert x is y, "%r is not %r" % (x, y) - - def assertIsNot(self, x, y): - assert x is not y, "%r is %r" % (x, y) - - def assertSequenceEqual(self, x, y): - self.assertEqual(x, y) - - def assertRaisesRegex(self, exc_type, regex, *args, **kwargs): - catcher = _ExceptionCatcher(self, exc_type) - if not args: - return catcher - elif callable(args[0]): - with catcher: - args[0](*args[1:], **kwargs) - if args[0] is not None: - assert re.search(args[0], catcher.exc_value[0]) - else: - raise NotImplementedError() - - elif sys.version_info[0] == 2: - def assertRaisesRegex(self, *args, **kwargs): - return self.assertRaisesRegexp(*args, **kwargs) - - def assert_is_none(self, x): - self.assertIsNone(x) - - def assert_is_not_none(self, x): - self.assertIsNotNone(x) - - def assert_in(self, x, y): - self.assertIn(x, y) - - def assert_is_instance(self, x, y): - self.assertIsInstance(x, y) - - def assert_not_in(self, x, y): - self.assertNotIn(x, y) - - def assert_is(self, x, y): - self.assertIs(x, y) - - def assert_is_not(self, x, y): - self.assertIsNot(x, y) - - def assert_true(self, x): - self.assertTrue(x) - - def assert_false(self, x): - self.assertFalse(x) - - def assert_raises_regex(self, *args, **kwargs): - return self.assertRaisesRegex(*args, **kwargs) - - def assert_sequence_equal(self, x, y): - self.assertSequenceEqual(x, y) - - def assert_strict_equal(self, x, y): - '''Stricter version of assert_equal that doesn't do implicit conversion - between unicode and strings''' - self.assert_equal(x, y) - assert issubclass(type(x), type(y)) or issubclass(type(y), type(x)), \ - '%s != %s' % (type(x), type(y)) - if isinstance(x, (bytes, text_type, integer_types)) or x is None: - return - elif isinstance(x, dict) or isinstance(y, dict): - x = sorted(x.items()) - y = sorted(y.items()) - elif isinstance(x, set) or isinstance(y, set): - x = sorted(x) - y = sorted(y) - rx, ry = repr(x), repr(y) - if rx != ry: - rx = rx[:200] + (rx[200:] and '...') - ry = ry[:200] + (ry[200:] and '...') - raise AssertionError(rx, ry) - assert repr(x) == repr(y), repr((x, y))[:200] - - -class _ExceptionCatcher(object): - - def __init__(self, test_case, exc_type): - self.test_case = test_case - self.exc_type = exc_type - self.exc_value = None - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, tb): - exception_name = self.exc_type.__name__ - if exc_type is None: - self.test_case.fail('Expected exception of type %r' % - exception_name) - elif not issubclass(exc_type, self.exc_type): - reraise(exc_type, exc_value, tb) - self.exc_value = exc_value - return True - - -class BetterLoader(unittest.TestLoader): - """A nicer loader that solves two problems. First of all we are setting - up tests from different sources and we're doing this programmatically - which breaks the default loading logic so this is required anyways. - Secondly this loader has a nicer interpolation for test names than the - default one so you can just do ``run-tests.py ViewTestCase`` and it - will work. - """ - - def getRootSuite(self): - return suite() - - def loadTestsFromName(self, name, module=None): - root = self.getRootSuite() - if name == 'suite': - return root - - all_tests = [] - for testcase, testname in find_all_tests(root): - if testname == name or \ - testname.endswith('.' + name) or \ - ('.' + name + '.') in testname or \ - testname.startswith(name + '.'): - all_tests.append(testcase) - - if not all_tests: - raise LookupError('could not find test case for "%s"' % name) - - if len(all_tests) == 1: - return all_tests[0] - rv = unittest.TestSuite() - for test in all_tests: - rv.addTest(test) - return rv - - -def suite(): - """A testsuite that has all the Flask tests. You can use this - function to integrate the Flask tests into your own testsuite - in case you want to test that monkeypatches to Flask do not - break it. - """ - suite = unittest.TestSuite() - for other_suite in iter_suites(__name__): - suite.addTest(other_suite) - return suite - - -def main(): - """Runs the testsuite as command line application.""" - try: - unittest.main(testLoader=BetterLoader(), defaultTest='suite') - except Exception: - import sys - import traceback - traceback.print_exc() - sys.exit(1) diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/compat.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/compat.py deleted file mode 100644 index 2f7c807e..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/compat.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.compat - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - Ensure that old stuff does not break on update. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import unittest -import warnings -from werkzeug.testsuite import WerkzeugTestCase - -from werkzeug.wrappers import Response -from werkzeug.test import create_environ - - -class CompatTestCase(WerkzeugTestCase): - - def test_old_imports(self): - from werkzeug.utils import Headers, MultiDict, CombinedMultiDict, \ - Headers, EnvironHeaders - from werkzeug.http import Accept, MIMEAccept, CharsetAccept, \ - LanguageAccept, ETags, HeaderSet, WWWAuthenticate, \ - Authorization - - def test_exposed_werkzeug_mod(self): - import werkzeug - for key in werkzeug.__all__: - # deprecated, skip it - if key in ('templates', 'Template'): - continue - getattr(werkzeug, key) - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(CompatTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/__init__.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/__init__.py deleted file mode 100644 index c2bfc3f8..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.contrib - ~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Tests the contrib modules. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import unittest -from werkzeug.testsuite import iter_suites - - -def suite(): - suite = unittest.TestSuite() - for other_suite in iter_suites(__name__): - suite.addTest(other_suite) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/cache.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/cache.py deleted file mode 100644 index e6081552..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/cache.py +++ /dev/null @@ -1,257 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.cache - ~~~~~~~~~~~~~~~~~~~~~~~~ - - Tests the cache system - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import os -import time -import unittest -import tempfile -import shutil - -from werkzeug.testsuite import WerkzeugTestCase -from werkzeug.contrib import cache - -try: - import redis - try: - from redis.exceptions import ConnectionError as RedisConnectionError - cache.RedisCache(key_prefix='werkzeug-test-case:')._client.set('test','connection') - except RedisConnectionError: - redis = None -except ImportError: - redis = None -try: - import pylibmc as memcache -except ImportError: - try: - from google.appengine.api import memcache - except ImportError: - try: - import memcache - except ImportError: - memcache = None - - -class SimpleCacheTestCase(WerkzeugTestCase): - - def test_get_dict(self): - c = cache.SimpleCache() - c.set('a', 'a') - c.set('b', 'b') - d = c.get_dict('a', 'b') - assert 'a' in d - assert 'a' == d['a'] - assert 'b' in d - assert 'b' == d['b'] - - def test_set_many(self): - c = cache.SimpleCache() - c.set_many({0: 0, 1: 1, 2: 4}) - assert c.get(2) == 4 - c.set_many((i, i*i) for i in range(3)) - assert c.get(2) == 4 - - -class FileSystemCacheTestCase(WerkzeugTestCase): - - def test_set_get(self): - tmp_dir = tempfile.mkdtemp() - try: - c = cache.FileSystemCache(cache_dir=tmp_dir) - for i in range(3): - c.set(str(i), i * i) - for i in range(3): - result = c.get(str(i)) - assert result == i * i - finally: - shutil.rmtree(tmp_dir) - - def test_filesystemcache_prune(self): - THRESHOLD = 13 - tmp_dir = tempfile.mkdtemp() - c = cache.FileSystemCache(cache_dir=tmp_dir, threshold=THRESHOLD) - for i in range(2 * THRESHOLD): - c.set(str(i), i) - cache_files = os.listdir(tmp_dir) - shutil.rmtree(tmp_dir) - assert len(cache_files) <= THRESHOLD - - - def test_filesystemcache_clear(self): - tmp_dir = tempfile.mkdtemp() - c = cache.FileSystemCache(cache_dir=tmp_dir) - c.set('foo', 'bar') - cache_files = os.listdir(tmp_dir) - assert len(cache_files) == 1 - c.clear() - cache_files = os.listdir(tmp_dir) - assert len(cache_files) == 0 - shutil.rmtree(tmp_dir) - - -class RedisCacheTestCase(WerkzeugTestCase): - - def make_cache(self): - return cache.RedisCache(key_prefix='werkzeug-test-case:') - - def teardown(self): - self.make_cache().clear() - - def test_compat(self): - c = self.make_cache() - c._client.set(c.key_prefix + 'foo', b'Awesome') - self.assert_equal(c.get('foo'), b'Awesome') - c._client.set(c.key_prefix + 'foo', b'42') - self.assert_equal(c.get('foo'), 42) - - def test_get_set(self): - c = self.make_cache() - c.set('foo', ['bar']) - assert c.get('foo') == ['bar'] - - def test_get_many(self): - c = self.make_cache() - c.set('foo', ['bar']) - c.set('spam', 'eggs') - assert c.get_many('foo', 'spam') == [['bar'], 'eggs'] - - def test_set_many(self): - c = self.make_cache() - c.set_many({'foo': 'bar', 'spam': ['eggs']}) - assert c.get('foo') == 'bar' - assert c.get('spam') == ['eggs'] - - def test_expire(self): - c = self.make_cache() - c.set('foo', 'bar', 1) - time.sleep(2) - assert c.get('foo') is None - - def test_add(self): - c = self.make_cache() - # sanity check that add() works like set() - c.add('foo', 'bar') - assert c.get('foo') == 'bar' - c.add('foo', 'qux') - assert c.get('foo') == 'bar' - - def test_delete(self): - c = self.make_cache() - c.add('foo', 'bar') - assert c.get('foo') == 'bar' - c.delete('foo') - assert c.get('foo') is None - - def test_delete_many(self): - c = self.make_cache() - c.add('foo', 'bar') - c.add('spam', 'eggs') - c.delete_many('foo', 'spam') - assert c.get('foo') is None - assert c.get('spam') is None - - def test_inc_dec(self): - c = self.make_cache() - c.set('foo', 1) - self.assert_equal(c.inc('foo'), 2) - self.assert_equal(c.dec('foo'), 1) - c.delete('foo') - - def test_true_false(self): - c = self.make_cache() - c.set('foo', True) - assert c.get('foo') == True - c.set('bar', False) - assert c.get('bar') == False - - -class MemcachedCacheTestCase(WerkzeugTestCase): - - def make_cache(self): - return cache.MemcachedCache(key_prefix='werkzeug-test-case:') - - def teardown(self): - self.make_cache().clear() - - def test_compat(self): - c = self.make_cache() - c._client.set(c.key_prefix + b'foo', 'bar') - self.assert_equal(c.get('foo'), 'bar') - - def test_get_set(self): - c = self.make_cache() - c.set('foo', 'bar') - self.assert_equal(c.get('foo'), 'bar') - - def test_get_many(self): - c = self.make_cache() - c.set('foo', 'bar') - c.set('spam', 'eggs') - self.assert_equal(c.get_many('foo', 'spam'), ['bar', 'eggs']) - - def test_set_many(self): - c = self.make_cache() - c.set_many({'foo': 'bar', 'spam': 'eggs'}) - self.assert_equal(c.get('foo'), 'bar') - self.assert_equal(c.get('spam'), 'eggs') - - def test_expire(self): - c = self.make_cache() - c.set('foo', 'bar', 1) - time.sleep(2) - self.assert_is_none(c.get('foo')) - - def test_add(self): - c = self.make_cache() - c.add('foo', 'bar') - self.assert_equal(c.get('foo'), 'bar') - c.add('foo', 'baz') - self.assert_equal(c.get('foo'), 'bar') - - def test_delete(self): - c = self.make_cache() - c.add('foo', 'bar') - self.assert_equal(c.get('foo'), 'bar') - c.delete('foo') - self.assert_is_none(c.get('foo')) - - def test_delete_many(self): - c = self.make_cache() - c.add('foo', 'bar') - c.add('spam', 'eggs') - c.delete_many('foo', 'spam') - self.assert_is_none(c.get('foo')) - self.assert_is_none(c.get('spam')) - - def test_inc_dec(self): - c = self.make_cache() - c.set('foo', 1) - # XXX: Is this an intended difference? - c.inc('foo') - self.assert_equal(c.get('foo'), 2) - c.dec('foo') - self.assert_equal(c.get('foo'), 1) - - def test_true_false(self): - c = self.make_cache() - c.set('foo', True) - self.assert_equal(c.get('foo'), True) - c.set('bar', False) - self.assert_equal(c.get('bar'), False) - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(SimpleCacheTestCase)) - suite.addTest(unittest.makeSuite(FileSystemCacheTestCase)) - if redis is not None: - suite.addTest(unittest.makeSuite(RedisCacheTestCase)) - if memcache is not None: - suite.addTest(unittest.makeSuite(MemcachedCacheTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/fixers.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/fixers.py deleted file mode 100644 index 91a21898..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/fixers.py +++ /dev/null @@ -1,193 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.fixers - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - Server / Browser fixers. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from werkzeug.testsuite import WerkzeugTestCase -from werkzeug.datastructures import ResponseCacheControl -from werkzeug.http import parse_cache_control_header - -from werkzeug.test import create_environ, Client -from werkzeug.wrappers import Request, Response -from werkzeug.contrib import fixers -from werkzeug.utils import redirect - - -@Request.application -def path_check_app(request): - return Response('PATH_INFO: %s\nSCRIPT_NAME: %s' % ( - request.environ.get('PATH_INFO', ''), - request.environ.get('SCRIPT_NAME', '') - )) - - -class ServerFixerTestCase(WerkzeugTestCase): - - def test_cgi_root_fix(self): - app = fixers.CGIRootFix(path_check_app) - response = Response.from_app(app, dict(create_environ(), - SCRIPT_NAME='/foo', - PATH_INFO='/bar', - SERVER_SOFTWARE='lighttpd/1.4.27' - )) - self.assert_equal(response.get_data(), - b'PATH_INFO: /foo/bar\nSCRIPT_NAME: ') - - def test_cgi_root_fix_custom_app_root(self): - app = fixers.CGIRootFix(path_check_app, app_root='/baz/poop/') - response = Response.from_app(app, dict(create_environ(), - SCRIPT_NAME='/foo', - PATH_INFO='/bar' - )) - self.assert_equal(response.get_data(), b'PATH_INFO: /foo/bar\nSCRIPT_NAME: baz/poop') - - def test_path_info_from_request_uri_fix(self): - app = fixers.PathInfoFromRequestUriFix(path_check_app) - for key in 'REQUEST_URI', 'REQUEST_URL', 'UNENCODED_URL': - env = dict(create_environ(), SCRIPT_NAME='/test', PATH_INFO='/?????') - env[key] = '/test/foo%25bar?drop=this' - response = Response.from_app(app, env) - self.assert_equal(response.get_data(), b'PATH_INFO: /foo%bar\nSCRIPT_NAME: /test') - - def test_proxy_fix(self): - @Request.application - def app(request): - return Response('%s|%s' % ( - request.remote_addr, - # do not use request.host as this fixes too :) - request.environ['HTTP_HOST'] - )) - app = fixers.ProxyFix(app, num_proxies=2) - environ = dict(create_environ(), - HTTP_X_FORWARDED_PROTO="https", - HTTP_X_FORWARDED_HOST='example.com', - HTTP_X_FORWARDED_FOR='1.2.3.4, 5.6.7.8', - REMOTE_ADDR='127.0.0.1', - HTTP_HOST='fake' - ) - - response = Response.from_app(app, environ) - - self.assert_equal(response.get_data(), b'1.2.3.4|example.com') - - # And we must check that if it is a redirection it is - # correctly done: - - redirect_app = redirect('/foo/bar.hml') - response = Response.from_app(redirect_app, environ) - - wsgi_headers = response.get_wsgi_headers(environ) - assert wsgi_headers['Location'] == 'https://example.com/foo/bar.hml' - - def test_proxy_fix_weird_enum(self): - @fixers.ProxyFix - @Request.application - def app(request): - return Response(request.remote_addr) - environ = dict(create_environ(), - HTTP_X_FORWARDED_FOR=',', - REMOTE_ADDR='127.0.0.1', - ) - - response = Response.from_app(app, environ) - self.assert_strict_equal(response.get_data(), b'127.0.0.1') - - def test_header_rewriter_fix(self): - @Request.application - def application(request): - return Response("", headers=[ - ('X-Foo', 'bar') - ]) - application = fixers.HeaderRewriterFix(application, ('X-Foo',), (('X-Bar', '42'),)) - response = Response.from_app(application, create_environ()) - assert response.headers['Content-Type'] == 'text/plain; charset=utf-8' - assert 'X-Foo' not in response.headers - assert response.headers['X-Bar'] == '42' - - -class BrowserFixerTestCase(WerkzeugTestCase): - - def test_ie_fixes(self): - @fixers.InternetExplorerFix - @Request.application - def application(request): - response = Response('binary data here', mimetype='application/vnd.ms-excel') - response.headers['Vary'] = 'Cookie' - response.headers['Content-Disposition'] = 'attachment; filename=foo.xls' - return response - - c = Client(application, Response) - response = c.get('/', headers=[ - ('User-Agent', 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)') - ]) - - # IE gets no vary - self.assert_equal(response.get_data(), b'binary data here') - assert 'vary' not in response.headers - assert response.headers['content-disposition'] == 'attachment; filename=foo.xls' - assert response.headers['content-type'] == 'application/vnd.ms-excel' - - # other browsers do - c = Client(application, Response) - response = c.get('/') - self.assert_equal(response.get_data(), b'binary data here') - assert 'vary' in response.headers - - cc = ResponseCacheControl() - cc.no_cache = True - - @fixers.InternetExplorerFix - @Request.application - def application(request): - response = Response('binary data here', mimetype='application/vnd.ms-excel') - response.headers['Pragma'] = ', '.join(pragma) - response.headers['Cache-Control'] = cc.to_header() - response.headers['Content-Disposition'] = 'attachment; filename=foo.xls' - return response - - - # IE has no pragma or cache control - pragma = ('no-cache',) - c = Client(application, Response) - response = c.get('/', headers=[ - ('User-Agent', 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)') - ]) - self.assert_equal(response.get_data(), b'binary data here') - assert 'pragma' not in response.headers - assert 'cache-control' not in response.headers - assert response.headers['content-disposition'] == 'attachment; filename=foo.xls' - - # IE has simplified pragma - pragma = ('no-cache', 'x-foo') - cc.proxy_revalidate = True - response = c.get('/', headers=[ - ('User-Agent', 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)') - ]) - self.assert_equal(response.get_data(), b'binary data here') - assert response.headers['pragma'] == 'x-foo' - assert response.headers['cache-control'] == 'proxy-revalidate' - assert response.headers['content-disposition'] == 'attachment; filename=foo.xls' - - # regular browsers get everything - response = c.get('/') - self.assert_equal(response.get_data(), b'binary data here') - assert response.headers['pragma'] == 'no-cache, x-foo' - cc = parse_cache_control_header(response.headers['cache-control'], - cls=ResponseCacheControl) - assert cc.no_cache - assert cc.proxy_revalidate - assert response.headers['content-disposition'] == 'attachment; filename=foo.xls' - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ServerFixerTestCase)) - suite.addTest(unittest.makeSuite(BrowserFixerTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/iterio.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/iterio.py deleted file mode 100644 index 49c8ad0a..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/iterio.py +++ /dev/null @@ -1,184 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.iterio - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - Tests the iterio object. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import unittest -from functools import partial - -from werkzeug.testsuite import WerkzeugTestCase -from werkzeug.contrib.iterio import IterIO, greenlet - - -class IterOTestSuite(WerkzeugTestCase): - - def test_basic_native(self): - io = IterIO(["Hello", "World", "1", "2", "3"]) - self.assert_equal(io.tell(), 0) - self.assert_equal(io.read(2), "He") - self.assert_equal(io.tell(), 2) - self.assert_equal(io.read(3), "llo") - self.assert_equal(io.tell(), 5) - io.seek(0) - self.assert_equal(io.read(5), "Hello") - self.assert_equal(io.tell(), 5) - self.assert_equal(io._buf, "Hello") - self.assert_equal(io.read(), "World123") - self.assert_equal(io.tell(), 13) - io.close() - assert io.closed - - io = IterIO(["Hello\n", "World!"]) - self.assert_equal(io.readline(), 'Hello\n') - self.assert_equal(io._buf, 'Hello\n') - self.assert_equal(io.read(), 'World!') - self.assert_equal(io._buf, 'Hello\nWorld!') - self.assert_equal(io.tell(), 12) - io.seek(0) - self.assert_equal(io.readlines(), ['Hello\n', 'World!']) - - io = IterIO(["foo\n", "bar"]) - io.seek(-4, 2) - self.assert_equal(io.read(4), '\nbar') - - self.assert_raises(IOError, io.seek, 2, 100) - io.close() - self.assert_raises(ValueError, io.read) - - def test_basic_bytes(self): - io = IterIO([b"Hello", b"World", b"1", b"2", b"3"]) - self.assert_equal(io.tell(), 0) - self.assert_equal(io.read(2), b"He") - self.assert_equal(io.tell(), 2) - self.assert_equal(io.read(3), b"llo") - self.assert_equal(io.tell(), 5) - io.seek(0) - self.assert_equal(io.read(5), b"Hello") - self.assert_equal(io.tell(), 5) - self.assert_equal(io._buf, b"Hello") - self.assert_equal(io.read(), b"World123") - self.assert_equal(io.tell(), 13) - io.close() - assert io.closed - - io = IterIO([b"Hello\n", b"World!"]) - self.assert_equal(io.readline(), b'Hello\n') - self.assert_equal(io._buf, b'Hello\n') - self.assert_equal(io.read(), b'World!') - self.assert_equal(io._buf, b'Hello\nWorld!') - self.assert_equal(io.tell(), 12) - io.seek(0) - self.assert_equal(io.readlines(), [b'Hello\n', b'World!']) - - io = IterIO([b"foo\n", b"bar"]) - io.seek(-4, 2) - self.assert_equal(io.read(4), b'\nbar') - - self.assert_raises(IOError, io.seek, 2, 100) - io.close() - self.assert_raises(ValueError, io.read) - - def test_basic_unicode(self): - io = IterIO([u"Hello", u"World", u"1", u"2", u"3"]) - self.assert_equal(io.tell(), 0) - self.assert_equal(io.read(2), u"He") - self.assert_equal(io.tell(), 2) - self.assert_equal(io.read(3), u"llo") - self.assert_equal(io.tell(), 5) - io.seek(0) - self.assert_equal(io.read(5), u"Hello") - self.assert_equal(io.tell(), 5) - self.assert_equal(io._buf, u"Hello") - self.assert_equal(io.read(), u"World123") - self.assert_equal(io.tell(), 13) - io.close() - assert io.closed - - io = IterIO([u"Hello\n", u"World!"]) - self.assert_equal(io.readline(), u'Hello\n') - self.assert_equal(io._buf, u'Hello\n') - self.assert_equal(io.read(), u'World!') - self.assert_equal(io._buf, u'Hello\nWorld!') - self.assert_equal(io.tell(), 12) - io.seek(0) - self.assert_equal(io.readlines(), [u'Hello\n', u'World!']) - - io = IterIO([u"foo\n", u"bar"]) - io.seek(-4, 2) - self.assert_equal(io.read(4), u'\nbar') - - self.assert_raises(IOError, io.seek, 2, 100) - io.close() - self.assert_raises(ValueError, io.read) - - def test_sentinel_cases(self): - io = IterIO([]) - self.assert_strict_equal(io.read(), '') - io = IterIO([], b'') - self.assert_strict_equal(io.read(), b'') - io = IterIO([], u'') - self.assert_strict_equal(io.read(), u'') - - io = IterIO([]) - self.assert_strict_equal(io.read(), '') - io = IterIO([b'']) - self.assert_strict_equal(io.read(), b'') - io = IterIO([u'']) - self.assert_strict_equal(io.read(), u'') - - io = IterIO([]) - self.assert_strict_equal(io.readline(), '') - io = IterIO([], b'') - self.assert_strict_equal(io.readline(), b'') - io = IterIO([], u'') - self.assert_strict_equal(io.readline(), u'') - - io = IterIO([]) - self.assert_strict_equal(io.readline(), '') - io = IterIO([b'']) - self.assert_strict_equal(io.readline(), b'') - io = IterIO([u'']) - self.assert_strict_equal(io.readline(), u'') - - -class IterITestSuite(WerkzeugTestCase): - - def test_basic(self): - def producer(out): - out.write('1\n') - out.write('2\n') - out.flush() - out.write('3\n') - iterable = IterIO(producer) - self.assert_equal(next(iterable), '1\n2\n') - self.assert_equal(next(iterable), '3\n') - self.assert_raises(StopIteration, next, iterable) - - def test_sentinel_cases(self): - def producer_dummy_flush(out): - out.flush() - iterable = IterIO(producer_dummy_flush) - self.assert_strict_equal(next(iterable), '') - - def producer_empty(out): - pass - iterable = IterIO(producer_empty) - self.assert_raises(StopIteration, next, iterable) - - iterable = IterIO(producer_dummy_flush, b'') - self.assert_strict_equal(next(iterable), b'') - iterable = IterIO(producer_dummy_flush, u'') - self.assert_strict_equal(next(iterable), u'') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(IterOTestSuite)) - if greenlet is not None: - suite.addTest(unittest.makeSuite(IterITestSuite)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/securecookie.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/securecookie.py deleted file mode 100644 index 883989b7..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/securecookie.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.securecookie - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Tests the secure cookie. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from werkzeug.testsuite import WerkzeugTestCase - -from werkzeug.utils import parse_cookie -from werkzeug.wrappers import Request, Response -from werkzeug.contrib.securecookie import SecureCookie - - -class SecureCookieTestCase(WerkzeugTestCase): - - def test_basic_support(self): - c = SecureCookie(secret_key=b'foo') - assert c.new - assert not c.modified - assert not c.should_save - c['x'] = 42 - assert c.modified - assert c.should_save - s = c.serialize() - - c2 = SecureCookie.unserialize(s, b'foo') - assert c is not c2 - assert not c2.new - assert not c2.modified - assert not c2.should_save - self.assert_equal(c2, c) - - c3 = SecureCookie.unserialize(s, b'wrong foo') - assert not c3.modified - assert not c3.new - self.assert_equal(c3, {}) - - def test_wrapper_support(self): - req = Request.from_values() - resp = Response() - c = SecureCookie.load_cookie(req, secret_key=b'foo') - assert c.new - c['foo'] = 42 - self.assert_equal(c.secret_key, b'foo') - c.save_cookie(resp) - - req = Request.from_values(headers={ - 'Cookie': 'session="%s"' % parse_cookie(resp.headers['set-cookie'])['session'] - }) - c2 = SecureCookie.load_cookie(req, secret_key=b'foo') - assert not c2.new - self.assert_equal(c2, c) - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(SecureCookieTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/sessions.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/sessions.py deleted file mode 100644 index 070b5f70..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/sessions.py +++ /dev/null @@ -1,91 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.sessions - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Added tests for the sessions. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import os -import unittest -import shutil -from tempfile import mkdtemp, gettempdir - -from werkzeug.testsuite import WerkzeugTestCase -from werkzeug.contrib.sessions import FilesystemSessionStore - - - -class SessionTestCase(WerkzeugTestCase): - - def setup(self): - self.session_folder = mkdtemp() - - def teardown(self): - shutil.rmtree(self.session_folder) - - def test_default_tempdir(self): - store = FilesystemSessionStore() - assert store.path == gettempdir() - - def test_basic_fs_sessions(self): - store = FilesystemSessionStore(self.session_folder) - x = store.new() - assert x.new - assert not x.modified - x['foo'] = [1, 2, 3] - assert x.modified - store.save(x) - - x2 = store.get(x.sid) - assert not x2.new - assert not x2.modified - assert x2 is not x - assert x2 == x - x2['test'] = 3 - assert x2.modified - assert not x2.new - store.save(x2) - - x = store.get(x.sid) - store.delete(x) - x2 = store.get(x.sid) - # the session is not new when it was used previously. - assert not x2.new - - def test_non_urandom(self): - urandom = os.urandom - del os.urandom - try: - store = FilesystemSessionStore(self.session_folder) - store.new() - finally: - os.urandom = urandom - - - def test_renewing_fs_session(self): - store = FilesystemSessionStore(self.session_folder, renew_missing=True) - x = store.new() - store.save(x) - store.delete(x) - x2 = store.get(x.sid) - assert x2.new - - def test_fs_session_lising(self): - store = FilesystemSessionStore(self.session_folder, renew_missing=True) - sessions = set() - for x in range(10): - sess = store.new() - store.save(sess) - sessions.add(sess.sid) - - listed_sessions = set(store.list()) - assert sessions == listed_sessions - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(SessionTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/wrappers.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/wrappers.py deleted file mode 100644 index 798f1eca..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/contrib/wrappers.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.contrib.wrappers - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Added tests for the sessions. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" - -from __future__ import with_statement - -import unittest - -from werkzeug.testsuite import WerkzeugTestCase - -from werkzeug.contrib import wrappers -from werkzeug import routing -from werkzeug.wrappers import Request, Response - - -class WrappersTestCase(WerkzeugTestCase): - - def test_reverse_slash_behavior(self): - class MyRequest(wrappers.ReverseSlashBehaviorRequestMixin, Request): - pass - req = MyRequest.from_values('/foo/bar', 'http://example.com/test') - assert req.url == 'http://example.com/test/foo/bar' - assert req.path == 'foo/bar' - assert req.script_root == '/test/' - - # make sure the routing system works with the slashes in - # reverse order as well. - map = routing.Map([routing.Rule('/foo/bar', endpoint='foo')]) - adapter = map.bind_to_environ(req.environ) - assert adapter.match() == ('foo', {}) - adapter = map.bind(req.host, req.script_root) - assert adapter.match(req.path) == ('foo', {}) - - def test_dynamic_charset_request_mixin(self): - class MyRequest(wrappers.DynamicCharsetRequestMixin, Request): - pass - env = {'CONTENT_TYPE': 'text/html'} - req = MyRequest(env) - assert req.charset == 'latin1' - - env = {'CONTENT_TYPE': 'text/html; charset=utf-8'} - req = MyRequest(env) - assert req.charset == 'utf-8' - - env = {'CONTENT_TYPE': 'application/octet-stream'} - req = MyRequest(env) - assert req.charset == 'latin1' - assert req.url_charset == 'latin1' - - MyRequest.url_charset = 'utf-8' - env = {'CONTENT_TYPE': 'application/octet-stream'} - req = MyRequest(env) - assert req.charset == 'latin1' - assert req.url_charset == 'utf-8' - - def return_ascii(x): - return "ascii" - env = {'CONTENT_TYPE': 'text/plain; charset=x-weird-charset'} - req = MyRequest(env) - req.unknown_charset = return_ascii - assert req.charset == 'ascii' - assert req.url_charset == 'utf-8' - - def test_dynamic_charset_response_mixin(self): - class MyResponse(wrappers.DynamicCharsetResponseMixin, Response): - default_charset = 'utf-7' - resp = MyResponse(mimetype='text/html') - assert resp.charset == 'utf-7' - resp.charset = 'utf-8' - assert resp.charset == 'utf-8' - assert resp.mimetype == 'text/html' - assert resp.mimetype_params == {'charset': 'utf-8'} - resp.mimetype_params['charset'] = 'iso-8859-15' - assert resp.charset == 'iso-8859-15' - resp.set_data(u'Hällo Wörld') - assert b''.join(resp.iter_encoded()) == \ - u'Hällo Wörld'.encode('iso-8859-15') - del resp.headers['content-type'] - try: - resp.charset = 'utf-8' - except TypeError as e: - pass - else: - assert False, 'expected type error on charset setting without ct' - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(WrappersTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/datastructures.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/datastructures.py deleted file mode 100644 index f74fc6b8..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/datastructures.py +++ /dev/null @@ -1,810 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.datastructures - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Tests the functionality of the provided Werkzeug - datastructures. - - TODO: - - - FileMultiDict - - Immutable types undertested - - Split up dict tests - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" - -from __future__ import with_statement - -import unittest -import pickle -from contextlib import contextmanager -from copy import copy, deepcopy - -from werkzeug import datastructures -from werkzeug._compat import iterkeys, itervalues, iteritems, iterlists, \ - iterlistvalues, text_type, PY2 -from werkzeug.testsuite import WerkzeugTestCase -from werkzeug.exceptions import BadRequestKeyError - - -class NativeItermethodsTestCase(WerkzeugTestCase): - def test_basic(self): - @datastructures.native_itermethods(['keys', 'values', 'items']) - class StupidDict(object): - def keys(self, multi=1): - return iter(['a', 'b', 'c'] * multi) - - def values(self, multi=1): - return iter([1, 2, 3] * multi) - - def items(self, multi=1): - return iter(zip(iterkeys(self, multi=multi), - itervalues(self, multi=multi))) - - d = StupidDict() - expected_keys = ['a', 'b', 'c'] - expected_values = [1, 2, 3] - expected_items = list(zip(expected_keys, expected_values)) - - self.assert_equal(list(iterkeys(d)), expected_keys) - self.assert_equal(list(itervalues(d)), expected_values) - self.assert_equal(list(iteritems(d)), expected_items) - - self.assert_equal(list(iterkeys(d, 2)), expected_keys * 2) - self.assert_equal(list(itervalues(d, 2)), expected_values * 2) - self.assert_equal(list(iteritems(d, 2)), expected_items * 2) - - -class MutableMultiDictBaseTestCase(WerkzeugTestCase): - storage_class = None - - def test_pickle(self): - cls = self.storage_class - - for protocol in range(pickle.HIGHEST_PROTOCOL + 1): - d = cls() - d.setlist(b'foo', [1, 2, 3, 4]) - d.setlist(b'bar', b'foo bar baz'.split()) - s = pickle.dumps(d, protocol) - ud = pickle.loads(s) - self.assert_equal(type(ud), type(d)) - self.assert_equal(ud, d) - self.assert_equal(pickle.loads( - s.replace(b'werkzeug.datastructures', b'werkzeug')), d) - ud[b'newkey'] = b'bla' - self.assert_not_equal(ud, d) - - def test_basic_interface(self): - md = self.storage_class() - assert isinstance(md, dict) - - mapping = [('a', 1), ('b', 2), ('a', 2), ('d', 3), - ('a', 1), ('a', 3), ('d', 4), ('c', 3)] - md = self.storage_class(mapping) - - # simple getitem gives the first value - self.assert_equal(md['a'], 1) - self.assert_equal(md['c'], 3) - with self.assert_raises(KeyError): - md['e'] - self.assert_equal(md.get('a'), 1) - - # list getitem - self.assert_equal(md.getlist('a'), [1, 2, 1, 3]) - self.assert_equal(md.getlist('d'), [3, 4]) - # do not raise if key not found - self.assert_equal(md.getlist('x'), []) - - # simple setitem overwrites all values - md['a'] = 42 - self.assert_equal(md.getlist('a'), [42]) - - # list setitem - md.setlist('a', [1, 2, 3]) - self.assert_equal(md['a'], 1) - self.assert_equal(md.getlist('a'), [1, 2, 3]) - - # verify that it does not change original lists - l1 = [1, 2, 3] - md.setlist('a', l1) - del l1[:] - self.assert_equal(md['a'], 1) - - # setdefault, setlistdefault - self.assert_equal(md.setdefault('u', 23), 23) - self.assert_equal(md.getlist('u'), [23]) - del md['u'] - - md.setlist('u', [-1, -2]) - - # delitem - del md['u'] - with self.assert_raises(KeyError): - md['u'] - del md['d'] - self.assert_equal(md.getlist('d'), []) - - # keys, values, items, lists - self.assert_equal(list(sorted(md.keys())), ['a', 'b', 'c']) - self.assert_equal(list(sorted(iterkeys(md))), ['a', 'b', 'c']) - - self.assert_equal(list(sorted(itervalues(md))), [1, 2, 3]) - self.assert_equal(list(sorted(itervalues(md))), [1, 2, 3]) - - self.assert_equal(list(sorted(md.items())), - [('a', 1), ('b', 2), ('c', 3)]) - self.assert_equal(list(sorted(md.items(multi=True))), - [('a', 1), ('a', 2), ('a', 3), ('b', 2), ('c', 3)]) - self.assert_equal(list(sorted(iteritems(md))), - [('a', 1), ('b', 2), ('c', 3)]) - self.assert_equal(list(sorted(iteritems(md, multi=True))), - [('a', 1), ('a', 2), ('a', 3), ('b', 2), ('c', 3)]) - - self.assert_equal(list(sorted(md.lists())), - [('a', [1, 2, 3]), ('b', [2]), ('c', [3])]) - self.assert_equal(list(sorted(iterlists(md))), - [('a', [1, 2, 3]), ('b', [2]), ('c', [3])]) - - # copy method - c = md.copy() - self.assert_equal(c['a'], 1) - self.assert_equal(c.getlist('a'), [1, 2, 3]) - - # copy method 2 - c = copy(md) - self.assert_equal(c['a'], 1) - self.assert_equal(c.getlist('a'), [1, 2, 3]) - - # deepcopy method - c = md.deepcopy() - self.assert_equal(c['a'], 1) - self.assert_equal(c.getlist('a'), [1, 2, 3]) - - # deepcopy method 2 - c = deepcopy(md) - self.assert_equal(c['a'], 1) - self.assert_equal(c.getlist('a'), [1, 2, 3]) - - # update with a multidict - od = self.storage_class([('a', 4), ('a', 5), ('y', 0)]) - md.update(od) - self.assert_equal(md.getlist('a'), [1, 2, 3, 4, 5]) - self.assert_equal(md.getlist('y'), [0]) - - # update with a regular dict - md = c - od = {'a': 4, 'y': 0} - md.update(od) - self.assert_equal(md.getlist('a'), [1, 2, 3, 4]) - self.assert_equal(md.getlist('y'), [0]) - - # pop, poplist, popitem, popitemlist - self.assert_equal(md.pop('y'), 0) - assert 'y' not in md - self.assert_equal(md.poplist('a'), [1, 2, 3, 4]) - assert 'a' not in md - self.assert_equal(md.poplist('missing'), []) - - # remaining: b=2, c=3 - popped = md.popitem() - assert popped in [('b', 2), ('c', 3)] - popped = md.popitemlist() - assert popped in [('b', [2]), ('c', [3])] - - # type conversion - md = self.storage_class({'a': '4', 'b': ['2', '3']}) - self.assert_equal(md.get('a', type=int), 4) - self.assert_equal(md.getlist('b', type=int), [2, 3]) - - # repr - md = self.storage_class([('a', 1), ('a', 2), ('b', 3)]) - assert "('a', 1)" in repr(md) - assert "('a', 2)" in repr(md) - assert "('b', 3)" in repr(md) - - # add and getlist - md.add('c', '42') - md.add('c', '23') - self.assert_equal(md.getlist('c'), ['42', '23']) - md.add('c', 'blah') - self.assert_equal(md.getlist('c', type=int), [42, 23]) - - # setdefault - md = self.storage_class() - md.setdefault('x', []).append(42) - md.setdefault('x', []).append(23) - self.assert_equal(md['x'], [42, 23]) - - # to dict - md = self.storage_class() - md['foo'] = 42 - md.add('bar', 1) - md.add('bar', 2) - self.assert_equal(md.to_dict(), {'foo': 42, 'bar': 1}) - self.assert_equal(md.to_dict(flat=False), {'foo': [42], 'bar': [1, 2]}) - - # popitem from empty dict - with self.assert_raises(KeyError): - self.storage_class().popitem() - - with self.assert_raises(KeyError): - self.storage_class().popitemlist() - - # key errors are of a special type - with self.assert_raises(BadRequestKeyError): - self.storage_class()[42] - - # setlist works - md = self.storage_class() - md['foo'] = 42 - md.setlist('foo', [1, 2]) - self.assert_equal(md.getlist('foo'), [1, 2]) - - -class ImmutableDictBaseTestCase(WerkzeugTestCase): - storage_class = None - - def test_follows_dict_interface(self): - cls = self.storage_class - - data = {'foo': 1, 'bar': 2, 'baz': 3} - d = cls(data) - - self.assert_equal(d['foo'], 1) - self.assert_equal(d['bar'], 2) - self.assert_equal(d['baz'], 3) - self.assert_equal(sorted(d.keys()), ['bar', 'baz', 'foo']) - self.assert_true('foo' in d) - self.assert_true('foox' not in d) - self.assert_equal(len(d), 3) - - def test_copies_are_mutable(self): - cls = self.storage_class - immutable = cls({'a': 1}) - with self.assert_raises(TypeError): - immutable.pop('a') - - mutable = immutable.copy() - mutable.pop('a') - self.assert_true('a' in immutable) - self.assert_true(mutable is not immutable) - self.assert_true(copy(immutable) is immutable) - - def test_dict_is_hashable(self): - cls = self.storage_class - immutable = cls({'a': 1, 'b': 2}) - immutable2 = cls({'a': 2, 'b': 2}) - x = set([immutable]) - self.assert_true(immutable in x) - self.assert_true(immutable2 not in x) - x.discard(immutable) - self.assert_true(immutable not in x) - self.assert_true(immutable2 not in x) - x.add(immutable2) - self.assert_true(immutable not in x) - self.assert_true(immutable2 in x) - x.add(immutable) - self.assert_true(immutable in x) - self.assert_true(immutable2 in x) - - -class ImmutableTypeConversionDictTestCase(ImmutableDictBaseTestCase): - storage_class = datastructures.ImmutableTypeConversionDict - - -class ImmutableMultiDictTestCase(ImmutableDictBaseTestCase): - storage_class = datastructures.ImmutableMultiDict - - def test_multidict_is_hashable(self): - cls = self.storage_class - immutable = cls({'a': [1, 2], 'b': 2}) - immutable2 = cls({'a': [1], 'b': 2}) - x = set([immutable]) - self.assert_true(immutable in x) - self.assert_true(immutable2 not in x) - x.discard(immutable) - self.assert_true(immutable not in x) - self.assert_true(immutable2 not in x) - x.add(immutable2) - self.assert_true(immutable not in x) - self.assert_true(immutable2 in x) - x.add(immutable) - self.assert_true(immutable in x) - self.assert_true(immutable2 in x) - - -class ImmutableDictTestCase(ImmutableDictBaseTestCase): - storage_class = datastructures.ImmutableDict - - -class ImmutableOrderedMultiDictTestCase(ImmutableDictBaseTestCase): - storage_class = datastructures.ImmutableOrderedMultiDict - - def test_ordered_multidict_is_hashable(self): - a = self.storage_class([('a', 1), ('b', 1), ('a', 2)]) - b = self.storage_class([('a', 1), ('a', 2), ('b', 1)]) - self.assert_not_equal(hash(a), hash(b)) - - -class MultiDictTestCase(MutableMultiDictBaseTestCase): - storage_class = datastructures.MultiDict - - def test_multidict_pop(self): - make_d = lambda: self.storage_class({'foo': [1, 2, 3, 4]}) - d = make_d() - self.assert_equal(d.pop('foo'), 1) - assert not d - d = make_d() - self.assert_equal(d.pop('foo', 32), 1) - assert not d - d = make_d() - self.assert_equal(d.pop('foos', 32), 32) - assert d - - with self.assert_raises(KeyError): - d.pop('foos') - - def test_setlistdefault(self): - md = self.storage_class() - self.assert_equal(md.setlistdefault('u', [-1, -2]), [-1, -2]) - self.assert_equal(md.getlist('u'), [-1, -2]) - self.assert_equal(md['u'], -1) - - def test_iter_interfaces(self): - mapping = [('a', 1), ('b', 2), ('a', 2), ('d', 3), - ('a', 1), ('a', 3), ('d', 4), ('c', 3)] - md = self.storage_class(mapping) - self.assert_equal(list(zip(md.keys(), md.listvalues())), - list(md.lists())) - self.assert_equal(list(zip(md, iterlistvalues(md))), - list(iterlists(md))) - self.assert_equal(list(zip(iterkeys(md), iterlistvalues(md))), - list(iterlists(md))) - - -class OrderedMultiDictTestCase(MutableMultiDictBaseTestCase): - storage_class = datastructures.OrderedMultiDict - - def test_ordered_interface(self): - cls = self.storage_class - - d = cls() - assert not d - d.add('foo', 'bar') - self.assert_equal(len(d), 1) - d.add('foo', 'baz') - self.assert_equal(len(d), 1) - self.assert_equal(list(iteritems(d)), [('foo', 'bar')]) - self.assert_equal(list(d), ['foo']) - self.assert_equal(list(iteritems(d, multi=True)), - [('foo', 'bar'), ('foo', 'baz')]) - del d['foo'] - assert not d - self.assert_equal(len(d), 0) - self.assert_equal(list(d), []) - - d.update([('foo', 1), ('foo', 2), ('bar', 42)]) - d.add('foo', 3) - self.assert_equal(d.getlist('foo'), [1, 2, 3]) - self.assert_equal(d.getlist('bar'), [42]) - self.assert_equal(list(iteritems(d)), [('foo', 1), ('bar', 42)]) - - expected = ['foo', 'bar'] - - self.assert_sequence_equal(list(d.keys()), expected) - self.assert_sequence_equal(list(d), expected) - self.assert_sequence_equal(list(iterkeys(d)), expected) - - self.assert_equal(list(iteritems(d, multi=True)), - [('foo', 1), ('foo', 2), ('bar', 42), ('foo', 3)]) - self.assert_equal(len(d), 2) - - self.assert_equal(d.pop('foo'), 1) - assert d.pop('blafasel', None) is None - self.assert_equal(d.pop('blafasel', 42), 42) - self.assert_equal(len(d), 1) - self.assert_equal(d.poplist('bar'), [42]) - assert not d - - d.get('missingkey') is None - - d.add('foo', 42) - d.add('foo', 23) - d.add('bar', 2) - d.add('foo', 42) - self.assert_equal(d, datastructures.MultiDict(d)) - id = self.storage_class(d) - self.assert_equal(d, id) - d.add('foo', 2) - assert d != id - - d.update({'blah': [1, 2, 3]}) - self.assert_equal(d['blah'], 1) - self.assert_equal(d.getlist('blah'), [1, 2, 3]) - - # setlist works - d = self.storage_class() - d['foo'] = 42 - d.setlist('foo', [1, 2]) - self.assert_equal(d.getlist('foo'), [1, 2]) - - with self.assert_raises(BadRequestKeyError): - d.pop('missing') - with self.assert_raises(BadRequestKeyError): - d['missing'] - - # popping - d = self.storage_class() - d.add('foo', 23) - d.add('foo', 42) - d.add('foo', 1) - self.assert_equal(d.popitem(), ('foo', 23)) - with self.assert_raises(BadRequestKeyError): - d.popitem() - assert not d - - d.add('foo', 23) - d.add('foo', 42) - d.add('foo', 1) - self.assert_equal(d.popitemlist(), ('foo', [23, 42, 1])) - - with self.assert_raises(BadRequestKeyError): - d.popitemlist() - - def test_iterables(self): - a = datastructures.MultiDict((("key_a", "value_a"),)) - b = datastructures.MultiDict((("key_b", "value_b"),)) - ab = datastructures.CombinedMultiDict((a,b)) - - self.assert_equal(sorted(ab.lists()), [('key_a', ['value_a']), ('key_b', ['value_b'])]) - self.assert_equal(sorted(ab.listvalues()), [['value_a'], ['value_b']]) - self.assert_equal(sorted(ab.keys()), ["key_a", "key_b"]) - - self.assert_equal(sorted(iterlists(ab)), [('key_a', ['value_a']), ('key_b', ['value_b'])]) - self.assert_equal(sorted(iterlistvalues(ab)), [['value_a'], ['value_b']]) - self.assert_equal(sorted(iterkeys(ab)), ["key_a", "key_b"]) - - -class CombinedMultiDictTestCase(WerkzeugTestCase): - storage_class = datastructures.CombinedMultiDict - - def test_basic_interface(self): - d1 = datastructures.MultiDict([('foo', '1')]) - d2 = datastructures.MultiDict([('bar', '2'), ('bar', '3')]) - d = self.storage_class([d1, d2]) - - # lookup - self.assert_equal(d['foo'], '1') - self.assert_equal(d['bar'], '2') - self.assert_equal(d.getlist('bar'), ['2', '3']) - - self.assert_equal(sorted(d.items()), - [('bar', '2'), ('foo', '1')]) - self.assert_equal(sorted(d.items(multi=True)), - [('bar', '2'), ('bar', '3'), ('foo', '1')]) - assert 'missingkey' not in d - assert 'foo' in d - - # type lookup - self.assert_equal(d.get('foo', type=int), 1) - self.assert_equal(d.getlist('bar', type=int), [2, 3]) - - # get key errors for missing stuff - with self.assert_raises(KeyError): - d['missing'] - - # make sure that they are immutable - with self.assert_raises(TypeError): - d['foo'] = 'blub' - - # copies are immutable - d = d.copy() - with self.assert_raises(TypeError): - d['foo'] = 'blub' - - # make sure lists merges - md1 = datastructures.MultiDict((("foo", "bar"),)) - md2 = datastructures.MultiDict((("foo", "blafasel"),)) - x = self.storage_class((md1, md2)) - self.assert_equal(list(iterlists(x)), [('foo', ['bar', 'blafasel'])]) - - -class HeadersTestCase(WerkzeugTestCase): - storage_class = datastructures.Headers - - def test_basic_interface(self): - headers = self.storage_class() - headers.add('Content-Type', 'text/plain') - headers.add('X-Foo', 'bar') - assert 'x-Foo' in headers - assert 'Content-type' in headers - - headers['Content-Type'] = 'foo/bar' - self.assert_equal(headers['Content-Type'], 'foo/bar') - self.assert_equal(len(headers.getlist('Content-Type')), 1) - - # list conversion - self.assert_equal(headers.to_wsgi_list(), [ - ('Content-Type', 'foo/bar'), - ('X-Foo', 'bar') - ]) - self.assert_equal(str(headers), ( - "Content-Type: foo/bar\r\n" - "X-Foo: bar\r\n" - "\r\n")) - self.assert_equal(str(self.storage_class()), "\r\n") - - # extended add - headers.add('Content-Disposition', 'attachment', filename='foo') - self.assert_equal(headers['Content-Disposition'], - 'attachment; filename=foo') - - headers.add('x', 'y', z='"') - self.assert_equal(headers['x'], r'y; z="\""') - - def test_defaults_and_conversion(self): - # defaults - headers = self.storage_class([ - ('Content-Type', 'text/plain'), - ('X-Foo', 'bar'), - ('X-Bar', '1'), - ('X-Bar', '2') - ]) - self.assert_equal(headers.getlist('x-bar'), ['1', '2']) - self.assert_equal(headers.get('x-Bar'), '1') - self.assert_equal(headers.get('Content-Type'), 'text/plain') - - self.assert_equal(headers.setdefault('X-Foo', 'nope'), 'bar') - self.assert_equal(headers.setdefault('X-Bar', 'nope'), '1') - self.assert_equal(headers.setdefault('X-Baz', 'quux'), 'quux') - self.assert_equal(headers.setdefault('X-Baz', 'nope'), 'quux') - headers.pop('X-Baz') - - # type conversion - self.assert_equal(headers.get('x-bar', type=int), 1) - self.assert_equal(headers.getlist('x-bar', type=int), [1, 2]) - - # list like operations - self.assert_equal(headers[0], ('Content-Type', 'text/plain')) - self.assert_equal(headers[:1], self.storage_class([('Content-Type', 'text/plain')])) - del headers[:2] - del headers[-1] - self.assert_equal(headers, self.storage_class([('X-Bar', '1')])) - - def test_copying(self): - a = self.storage_class([('foo', 'bar')]) - b = a.copy() - a.add('foo', 'baz') - self.assert_equal(a.getlist('foo'), ['bar', 'baz']) - self.assert_equal(b.getlist('foo'), ['bar']) - - def test_popping(self): - headers = self.storage_class([('a', 1)]) - self.assert_equal(headers.pop('a'), 1) - self.assert_equal(headers.pop('b', 2), 2) - - with self.assert_raises(KeyError): - headers.pop('c') - - def test_set_arguments(self): - a = self.storage_class() - a.set('Content-Disposition', 'useless') - a.set('Content-Disposition', 'attachment', filename='foo') - self.assert_equal(a['Content-Disposition'], 'attachment; filename=foo') - - def test_reject_newlines(self): - h = self.storage_class() - - for variation in 'foo\nbar', 'foo\r\nbar', 'foo\rbar': - with self.assert_raises(ValueError): - h['foo'] = variation - with self.assert_raises(ValueError): - h.add('foo', variation) - with self.assert_raises(ValueError): - h.add('foo', 'test', option=variation) - with self.assert_raises(ValueError): - h.set('foo', variation) - with self.assert_raises(ValueError): - h.set('foo', 'test', option=variation) - - def test_slicing(self): - # there's nothing wrong with these being native strings - # Headers doesn't care about the data types - h = self.storage_class() - h.set('X-Foo-Poo', 'bleh') - h.set('Content-Type', 'application/whocares') - h.set('X-Forwarded-For', '192.168.0.123') - h[:] = [(k, v) for k, v in h if k.startswith(u'X-')] - self.assert_equal(list(h), [ - ('X-Foo-Poo', 'bleh'), - ('X-Forwarded-For', '192.168.0.123') - ]) - - def test_bytes_operations(self): - h = self.storage_class() - h.set('X-Foo-Poo', 'bleh') - h.set('X-Whoops', b'\xff') - - self.assert_equal(h.get('x-foo-poo', as_bytes=True), b'bleh') - self.assert_equal(h.get('x-whoops', as_bytes=True), b'\xff') - - def test_to_wsgi_list(self): - h = self.storage_class() - h.set(u'Key', u'Value') - for key, value in h.to_wsgi_list(): - if PY2: - self.assert_strict_equal(key, b'Key') - self.assert_strict_equal(value, b'Value') - else: - self.assert_strict_equal(key, u'Key') - self.assert_strict_equal(value, u'Value') - - - -class EnvironHeadersTestCase(WerkzeugTestCase): - storage_class = datastructures.EnvironHeaders - - def test_basic_interface(self): - # this happens in multiple WSGI servers because they - # use a vary naive way to convert the headers; - broken_env = { - 'HTTP_CONTENT_TYPE': 'text/html', - 'CONTENT_TYPE': 'text/html', - 'HTTP_CONTENT_LENGTH': '0', - 'CONTENT_LENGTH': '0', - 'HTTP_ACCEPT': '*', - 'wsgi.version': (1, 0) - } - headers = self.storage_class(broken_env) - assert headers - self.assert_equal(len(headers), 3) - self.assert_equal(sorted(headers), [ - ('Accept', '*'), - ('Content-Length', '0'), - ('Content-Type', 'text/html') - ]) - assert not self.storage_class({'wsgi.version': (1, 0)}) - self.assert_equal(len(self.storage_class({'wsgi.version': (1, 0)})), 0) - - def test_return_type_is_unicode(self): - # environ contains native strings; we return unicode - headers = self.storage_class({ - 'HTTP_FOO': '\xe2\x9c\x93', - 'CONTENT_TYPE': 'text/plain', - }) - self.assert_equal(headers['Foo'], u"\xe2\x9c\x93") - assert isinstance(headers['Foo'], text_type) - assert isinstance(headers['Content-Type'], text_type) - iter_output = dict(iter(headers)) - self.assert_equal(iter_output['Foo'], u"\xe2\x9c\x93") - assert isinstance(iter_output['Foo'], text_type) - assert isinstance(iter_output['Content-Type'], text_type) - - def test_bytes_operations(self): - foo_val = '\xff' - h = self.storage_class({ - 'HTTP_X_FOO': foo_val - }) - - self.assert_equal(h.get('x-foo', as_bytes=True), b'\xff') - self.assert_equal(h.get('x-foo'), u'\xff') - - -class HeaderSetTestCase(WerkzeugTestCase): - storage_class = datastructures.HeaderSet - - def test_basic_interface(self): - hs = self.storage_class() - hs.add('foo') - hs.add('bar') - assert 'Bar' in hs - self.assert_equal(hs.find('foo'), 0) - self.assert_equal(hs.find('BAR'), 1) - assert hs.find('baz') < 0 - hs.discard('missing') - hs.discard('foo') - assert hs.find('foo') < 0 - self.assert_equal(hs.find('bar'), 0) - - with self.assert_raises(IndexError): - hs.index('missing') - - self.assert_equal(hs.index('bar'), 0) - assert hs - hs.clear() - assert not hs - - -class ImmutableListTestCase(WerkzeugTestCase): - storage_class = datastructures.ImmutableList - - def test_list_hashable(self): - t = (1, 2, 3, 4) - l = self.storage_class(t) - self.assert_equal(hash(t), hash(l)) - self.assert_not_equal(t, l) - - -def make_call_asserter(assert_equal_func, func=None): - """Utility to assert a certain number of function calls. - - >>> assert_calls, func = make_call_asserter(self.assert_equal) - >>> with assert_calls(2): - func() - func() - """ - - calls = [0] - - @contextmanager - def asserter(count, msg=None): - calls[0] = 0 - yield - assert_equal_func(calls[0], count, msg) - - def wrapped(*args, **kwargs): - calls[0] += 1 - if func is not None: - return func(*args, **kwargs) - - return asserter, wrapped - - -class CallbackDictTestCase(WerkzeugTestCase): - storage_class = datastructures.CallbackDict - - def test_callback_dict_reads(self): - assert_calls, func = make_call_asserter(self.assert_equal) - initial = {'a': 'foo', 'b': 'bar'} - dct = self.storage_class(initial=initial, on_update=func) - with assert_calls(0, 'callback triggered by read-only method'): - # read-only methods - dct['a'] - dct.get('a') - self.assert_raises(KeyError, lambda: dct['x']) - 'a' in dct - list(iter(dct)) - dct.copy() - with assert_calls(0, 'callback triggered without modification'): - # methods that may write but don't - dct.pop('z', None) - dct.setdefault('a') - - def test_callback_dict_writes(self): - assert_calls, func = make_call_asserter(self.assert_equal) - initial = {'a': 'foo', 'b': 'bar'} - dct = self.storage_class(initial=initial, on_update=func) - with assert_calls(8, 'callback not triggered by write method'): - # always-write methods - dct['z'] = 123 - dct['z'] = 123 # must trigger again - del dct['z'] - dct.pop('b', None) - dct.setdefault('x') - dct.popitem() - dct.update([]) - dct.clear() - with assert_calls(0, 'callback triggered by failed del'): - self.assert_raises(KeyError, lambda: dct.__delitem__('x')) - with assert_calls(0, 'callback triggered by failed pop'): - self.assert_raises(KeyError, lambda: dct.pop('x')) - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(MultiDictTestCase)) - suite.addTest(unittest.makeSuite(OrderedMultiDictTestCase)) - suite.addTest(unittest.makeSuite(CombinedMultiDictTestCase)) - suite.addTest(unittest.makeSuite(ImmutableTypeConversionDictTestCase)) - suite.addTest(unittest.makeSuite(ImmutableMultiDictTestCase)) - suite.addTest(unittest.makeSuite(ImmutableDictTestCase)) - suite.addTest(unittest.makeSuite(ImmutableOrderedMultiDictTestCase)) - suite.addTest(unittest.makeSuite(HeadersTestCase)) - suite.addTest(unittest.makeSuite(EnvironHeadersTestCase)) - suite.addTest(unittest.makeSuite(HeaderSetTestCase)) - suite.addTest(unittest.makeSuite(NativeItermethodsTestCase)) - suite.addTest(unittest.makeSuite(CallbackDictTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/debug.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/debug.py deleted file mode 100644 index 58d25535..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/debug.py +++ /dev/null @@ -1,172 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.debug - ~~~~~~~~~~~~~~~~~~~~~~~~ - - Tests some debug utilities. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import unittest -import sys -import re - -from werkzeug.testsuite import WerkzeugTestCase -from werkzeug.debug.repr import debug_repr, DebugReprGenerator, \ - dump, helper -from werkzeug.debug.console import HTMLStringO -from werkzeug._compat import PY2 - - -class DebugReprTestCase(WerkzeugTestCase): - - def test_basic_repr(self): - self.assert_equal(debug_repr([]), u'[]') - self.assert_equal(debug_repr([1, 2]), - u'[1, 2]') - self.assert_equal(debug_repr([1, 'test']), - u'[1, \'test\']') - self.assert_equal(debug_repr([None]), - u'[None]') - - def test_sequence_repr(self): - self.assert_equal(debug_repr(list(range(20))), ( - u'[0, 1, ' - u'2, 3, ' - u'4, 5, ' - u'6, 7, ' - u'8, ' - u'9, 10, ' - u'11, 12, ' - u'13, 14, ' - u'15, 16, ' - u'17, 18, ' - u'19]' - )) - - def test_mapping_repr(self): - self.assert_equal(debug_repr({}), u'{}') - self.assert_equal(debug_repr({'foo': 42}), - u'{\'foo\'' - u': 42' - u'}') - self.assert_equal(debug_repr(dict(zip(range(10), [None] * 10))), - u'{0: None, 1: None, 2: None, 3: None, 4: None, 5: None, 6: None, 7: None, 8: None, 9: None}') - self.assert_equal( - debug_repr((1, 'zwei', u'drei')), - u'(1, \'' - u'zwei\', %s\'drei\')' % ('u' if PY2 else '')) - - def test_custom_repr(self): - class Foo(object): - def __repr__(self): - return '' - self.assert_equal(debug_repr(Foo()), - '<Foo 42>') - - def test_list_subclass_repr(self): - class MyList(list): - pass - self.assert_equal( - debug_repr(MyList([1, 2])), - u'werkzeug.testsuite.debug.MyList([' - u'1, 2])') - - def test_regex_repr(self): - self.assert_equal(debug_repr(re.compile(r'foo\d')), - u're.compile(r\'foo\\d\')') - #XXX: no raw string here cause of a syntax bug in py3.3 - self.assert_equal(debug_repr(re.compile(u'foo\\d')), - u're.compile(%sr\'foo\\d\')' % - ('u' if PY2 else '')) - - def test_set_repr(self): - self.assert_equal(debug_repr(frozenset('x')), - u'frozenset([\'x\'])') - self.assert_equal(debug_repr(set('x')), - u'set([\'x\'])') - - def test_recursive_repr(self): - a = [1] - a.append(a) - self.assert_equal(debug_repr(a), - u'[1, [...]]') - - def test_broken_repr(self): - class Foo(object): - def __repr__(self): - raise Exception('broken!') - - self.assert_equal( - debug_repr(Foo()), - u'<broken repr (Exception: ' - u'broken!)>') - - -class Foo(object): - x = 42 - y = 23 - - def __init__(self): - self.z = 15 - - -class DebugHelpersTestCase(WerkzeugTestCase): - - def test_object_dumping(self): - drg = DebugReprGenerator() - out = drg.dump_object(Foo()) - assert re.search('Details for werkzeug.testsuite.debug.Foo object at', out) - assert re.search('x.*42(?s)', out) - assert re.search('y.*23(?s)', out) - assert re.search('z.*15(?s)', out) - - out = drg.dump_object({'x': 42, 'y': 23}) - assert re.search('Contents of', out) - assert re.search('x.*42(?s)', out) - assert re.search('y.*23(?s)', out) - - out = drg.dump_object({'x': 42, 'y': 23, 23: 11}) - assert not re.search('Contents of', out) - - out = drg.dump_locals({'x': 42, 'y': 23}) - assert re.search('Local variables in frame', out) - assert re.search('x.*42(?s)', out) - assert re.search('y.*23(?s)', out) - - def test_debug_dump(self): - old = sys.stdout - sys.stdout = HTMLStringO() - try: - dump([1, 2, 3]) - x = sys.stdout.reset() - dump() - y = sys.stdout.reset() - finally: - sys.stdout = old - - self.assert_in('Details for list object at', x) - self.assert_in('1', x) - self.assert_in('Local variables in frame', y) - self.assert_in('x', y) - self.assert_in('old', y) - - def test_debug_help(self): - old = sys.stdout - sys.stdout = HTMLStringO() - try: - helper([1, 2, 3]) - x = sys.stdout.reset() - finally: - sys.stdout = old - - self.assert_in('Help on list object', x) - self.assert_in('__delitem__', x) - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(DebugReprTestCase)) - suite.addTest(unittest.makeSuite(DebugHelpersTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/exceptions.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/exceptions.py deleted file mode 100644 index 05ba9298..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/exceptions.py +++ /dev/null @@ -1,85 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.exceptions - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - The tests for the exception classes. - - TODO: - - - This is undertested. HTML is never checked - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from werkzeug.testsuite import WerkzeugTestCase - -from werkzeug import exceptions -from werkzeug.wrappers import Response -from werkzeug._compat import text_type - - -class ExceptionsTestCase(WerkzeugTestCase): - - def test_proxy_exception(self): - orig_resp = Response('Hello World') - try: - exceptions.abort(orig_resp) - except exceptions.HTTPException as e: - resp = e.get_response({}) - else: - self.fail('exception not raised') - self.assert_true(resp is orig_resp) - self.assert_equal(resp.get_data(), b'Hello World') - - def test_aborter(self): - abort = exceptions.abort - self.assert_raises(exceptions.BadRequest, abort, 400) - self.assert_raises(exceptions.Unauthorized, abort, 401) - self.assert_raises(exceptions.Forbidden, abort, 403) - self.assert_raises(exceptions.NotFound, abort, 404) - self.assert_raises(exceptions.MethodNotAllowed, abort, 405, ['GET', 'HEAD']) - self.assert_raises(exceptions.NotAcceptable, abort, 406) - self.assert_raises(exceptions.RequestTimeout, abort, 408) - self.assert_raises(exceptions.Gone, abort, 410) - self.assert_raises(exceptions.LengthRequired, abort, 411) - self.assert_raises(exceptions.PreconditionFailed, abort, 412) - self.assert_raises(exceptions.RequestEntityTooLarge, abort, 413) - self.assert_raises(exceptions.RequestURITooLarge, abort, 414) - self.assert_raises(exceptions.UnsupportedMediaType, abort, 415) - self.assert_raises(exceptions.UnprocessableEntity, abort, 422) - self.assert_raises(exceptions.InternalServerError, abort, 500) - self.assert_raises(exceptions.NotImplemented, abort, 501) - self.assert_raises(exceptions.BadGateway, abort, 502) - self.assert_raises(exceptions.ServiceUnavailable, abort, 503) - - myabort = exceptions.Aborter({1: exceptions.NotFound}) - self.assert_raises(LookupError, myabort, 404) - self.assert_raises(exceptions.NotFound, myabort, 1) - - myabort = exceptions.Aborter(extra={1: exceptions.NotFound}) - self.assert_raises(exceptions.NotFound, myabort, 404) - self.assert_raises(exceptions.NotFound, myabort, 1) - - def test_exception_repr(self): - exc = exceptions.NotFound() - self.assert_equal(text_type(exc), '404: Not Found') - self.assert_equal(repr(exc), "") - - exc = exceptions.NotFound('Not There') - self.assert_equal(text_type(exc), '404: Not Found') - self.assert_equal(repr(exc), "") - - def test_special_exceptions(self): - exc = exceptions.MethodNotAllowed(['GET', 'HEAD', 'POST']) - h = dict(exc.get_headers({})) - self.assert_equal(h['Allow'], 'GET, HEAD, POST') - self.assert_true('The method is not allowed' in exc.get_description()) - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ExceptionsTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/formparser.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/formparser.py deleted file mode 100644 index 850364f2..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/formparser.py +++ /dev/null @@ -1,411 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.formparser - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Tests the form parsing facilities. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" - -from __future__ import with_statement - -import unittest -from os.path import join, dirname - -from werkzeug.testsuite import WerkzeugTestCase - -from werkzeug import formparser -from werkzeug.test import create_environ, Client -from werkzeug.wrappers import Request, Response -from werkzeug.exceptions import RequestEntityTooLarge -from werkzeug.datastructures import MultiDict -from werkzeug.formparser import parse_form_data -from werkzeug._compat import BytesIO - - -@Request.application -def form_data_consumer(request): - result_object = request.args['object'] - if result_object == 'text': - return Response(repr(request.form['text'])) - f = request.files[result_object] - return Response(b'\n'.join(( - repr(f.filename).encode('ascii'), - repr(f.name).encode('ascii'), - repr(f.content_type).encode('ascii'), - f.stream.read() - ))) - - -def get_contents(filename): - with open(filename, 'rb') as f: - return f.read() - - -class FormParserTestCase(WerkzeugTestCase): - - def test_limiting(self): - data = b'foo=Hello+World&bar=baz' - req = Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='application/x-www-form-urlencoded', - method='POST') - req.max_content_length = 400 - self.assert_strict_equal(req.form['foo'], u'Hello World') - - req = Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='application/x-www-form-urlencoded', - method='POST') - req.max_form_memory_size = 7 - self.assert_raises(RequestEntityTooLarge, lambda: req.form['foo']) - - req = Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='application/x-www-form-urlencoded', - method='POST') - req.max_form_memory_size = 400 - self.assert_strict_equal(req.form['foo'], u'Hello World') - - data = (b'--foo\r\nContent-Disposition: form-field; name=foo\r\n\r\n' - b'Hello World\r\n' - b'--foo\r\nContent-Disposition: form-field; name=bar\r\n\r\n' - b'bar=baz\r\n--foo--') - req = Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='multipart/form-data; boundary=foo', - method='POST') - req.max_content_length = 4 - self.assert_raises(RequestEntityTooLarge, lambda: req.form['foo']) - - req = Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='multipart/form-data; boundary=foo', - method='POST') - req.max_content_length = 400 - self.assert_strict_equal(req.form['foo'], u'Hello World') - - req = Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='multipart/form-data; boundary=foo', - method='POST') - req.max_form_memory_size = 7 - self.assert_raises(RequestEntityTooLarge, lambda: req.form['foo']) - - req = Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='multipart/form-data; boundary=foo', - method='POST') - req.max_form_memory_size = 400 - self.assert_strict_equal(req.form['foo'], u'Hello World') - - def test_missing_multipart_boundary(self): - data = (b'--foo\r\nContent-Disposition: form-field; name=foo\r\n\r\n' - b'Hello World\r\n' - b'--foo\r\nContent-Disposition: form-field; name=bar\r\n\r\n' - b'bar=baz\r\n--foo--') - req = Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='multipart/form-data', - method='POST') - self.assert_equal(req.form, {}) - - def test_parse_form_data_put_without_content(self): - # A PUT without a Content-Type header returns empty data - - # Both rfc1945 and rfc2616 (1.0 and 1.1) say "Any HTTP/[1.0/1.1] message - # containing an entity-body SHOULD include a Content-Type header field - # defining the media type of that body." In the case where either - # headers are omitted, parse_form_data should still work. - env = create_environ('/foo', 'http://example.org/', method='PUT') - del env['CONTENT_TYPE'] - del env['CONTENT_LENGTH'] - - stream, form, files = formparser.parse_form_data(env) - self.assert_strict_equal(stream.read(), b'') - self.assert_strict_equal(len(form), 0) - self.assert_strict_equal(len(files), 0) - - def test_parse_form_data_get_without_content(self): - env = create_environ('/foo', 'http://example.org/', method='GET') - del env['CONTENT_TYPE'] - del env['CONTENT_LENGTH'] - - stream, form, files = formparser.parse_form_data(env) - self.assert_strict_equal(stream.read(), b'') - self.assert_strict_equal(len(form), 0) - self.assert_strict_equal(len(files), 0) - - def test_large_file(self): - data = b'x' * (1024 * 600) - req = Request.from_values(data={'foo': (BytesIO(data), 'test.txt')}, - method='POST') - # make sure we have a real file here, because we expect to be - # on the disk. > 1024 * 500 - self.assert_true(hasattr(req.files['foo'].stream, u'fileno')) - # close file to prevent fds from leaking - req.files['foo'].close() - - def test_streaming_parse(self): - data = b'x' * (1024 * 600) - class StreamMPP(formparser.MultiPartParser): - def parse(self, file, boundary, content_length): - i = iter(self.parse_lines(file, boundary, content_length)) - one = next(i) - two = next(i) - return self.cls(()), {'one': one, 'two': two} - class StreamFDP(formparser.FormDataParser): - def _sf_parse_multipart(self, stream, mimetype, - content_length, options): - form, files = StreamMPP( - self.stream_factory, self.charset, self.errors, - max_form_memory_size=self.max_form_memory_size, - cls=self.cls).parse(stream, options.get('boundary').encode('ascii'), - content_length) - return stream, form, files - parse_functions = {} - parse_functions.update(formparser.FormDataParser.parse_functions) - parse_functions['multipart/form-data'] = _sf_parse_multipart - class StreamReq(Request): - form_data_parser_class = StreamFDP - req = StreamReq.from_values(data={'foo': (BytesIO(data), 'test.txt')}, - method='POST') - self.assert_strict_equal('begin_file', req.files['one'][0]) - self.assert_strict_equal(('foo', 'test.txt'), req.files['one'][1][1:]) - self.assert_strict_equal('cont', req.files['two'][0]) - self.assert_strict_equal(data, req.files['two'][1]) - - -class MultiPartTestCase(WerkzeugTestCase): - - def test_basic(self): - resources = join(dirname(__file__), 'multipart') - client = Client(form_data_consumer, Response) - - repository = [ - ('firefox3-2png1txt', '---------------------------186454651713519341951581030105', [ - (u'anchor.png', 'file1', 'image/png', 'file1.png'), - (u'application_edit.png', 'file2', 'image/png', 'file2.png') - ], u'example text'), - ('firefox3-2pnglongtext', '---------------------------14904044739787191031754711748', [ - (u'accept.png', 'file1', 'image/png', 'file1.png'), - (u'add.png', 'file2', 'image/png', 'file2.png') - ], u'--long text\r\n--with boundary\r\n--lookalikes--'), - ('opera8-2png1txt', '----------zEO9jQKmLc2Cq88c23Dx19', [ - (u'arrow_branch.png', 'file1', 'image/png', 'file1.png'), - (u'award_star_bronze_1.png', 'file2', 'image/png', 'file2.png') - ], u'blafasel öäü'), - ('webkit3-2png1txt', '----WebKitFormBoundaryjdSFhcARk8fyGNy6', [ - (u'gtk-apply.png', 'file1', 'image/png', 'file1.png'), - (u'gtk-no.png', 'file2', 'image/png', 'file2.png') - ], u'this is another text with ümläüts'), - ('ie6-2png1txt', '---------------------------7d91b03a20128', [ - (u'file1.png', 'file1', 'image/x-png', 'file1.png'), - (u'file2.png', 'file2', 'image/x-png', 'file2.png') - ], u'ie6 sucks :-/') - ] - - for name, boundary, files, text in repository: - folder = join(resources, name) - data = get_contents(join(folder, 'request.txt')) - for filename, field, content_type, fsname in files: - response = client.post('/?object=' + field, data=data, content_type= - 'multipart/form-data; boundary="%s"' % boundary, - content_length=len(data)) - lines = response.get_data().split(b'\n', 3) - self.assert_strict_equal(lines[0], repr(filename).encode('ascii')) - self.assert_strict_equal(lines[1], repr(field).encode('ascii')) - self.assert_strict_equal(lines[2], repr(content_type).encode('ascii')) - self.assert_strict_equal(lines[3], get_contents(join(folder, fsname))) - response = client.post('/?object=text', data=data, content_type= - 'multipart/form-data; boundary="%s"' % boundary, - content_length=len(data)) - self.assert_strict_equal(response.get_data(), repr(text).encode('utf-8')) - - def test_ie7_unc_path(self): - client = Client(form_data_consumer, Response) - data_file = join(dirname(__file__), 'multipart', 'ie7_full_path_request.txt') - data = get_contents(data_file) - boundary = '---------------------------7da36d1b4a0164' - response = client.post('/?object=cb_file_upload_multiple', data=data, content_type= - 'multipart/form-data; boundary="%s"' % boundary, content_length=len(data)) - lines = response.get_data().split(b'\n', 3) - self.assert_strict_equal(lines[0], - repr(u'Sellersburg Town Council Meeting 02-22-2010doc.doc').encode('ascii')) - - def test_end_of_file(self): - # This test looks innocent but it was actually timeing out in - # the Werkzeug 0.5 release version (#394) - data = ( - b'--foo\r\n' - b'Content-Disposition: form-data; name="test"; filename="test.txt"\r\n' - b'Content-Type: text/plain\r\n\r\n' - b'file contents and no end' - ) - data = Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='multipart/form-data; boundary=foo', - method='POST') - self.assert_true(not data.files) - self.assert_true(not data.form) - - def test_broken(self): - data = ( - '--foo\r\n' - 'Content-Disposition: form-data; name="test"; filename="test.txt"\r\n' - 'Content-Transfer-Encoding: base64\r\n' - 'Content-Type: text/plain\r\n\r\n' - 'broken base 64' - '--foo--' - ) - _, form, files = formparser.parse_form_data(create_environ(data=data, - method='POST', content_type='multipart/form-data; boundary=foo')) - self.assert_true(not files) - self.assert_true(not form) - - self.assert_raises(ValueError, formparser.parse_form_data, - create_environ(data=data, method='POST', - content_type='multipart/form-data; boundary=foo'), - silent=False) - - def test_file_no_content_type(self): - data = ( - b'--foo\r\n' - b'Content-Disposition: form-data; name="test"; filename="test.txt"\r\n\r\n' - b'file contents\r\n--foo--' - ) - data = Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='multipart/form-data; boundary=foo', - method='POST') - self.assert_equal(data.files['test'].filename, 'test.txt') - self.assert_strict_equal(data.files['test'].read(), b'file contents') - - def test_extra_newline(self): - # this test looks innocent but it was actually timeing out in - # the Werkzeug 0.5 release version (#394) - data = ( - b'\r\n\r\n--foo\r\n' - b'Content-Disposition: form-data; name="foo"\r\n\r\n' - b'a string\r\n' - b'--foo--' - ) - data = Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='multipart/form-data; boundary=foo', - method='POST') - self.assert_true(not data.files) - self.assert_strict_equal(data.form['foo'], u'a string') - - def test_headers(self): - data = (b'--foo\r\n' - b'Content-Disposition: form-data; name="foo"; filename="foo.txt"\r\n' - b'X-Custom-Header: blah\r\n' - b'Content-Type: text/plain; charset=utf-8\r\n\r\n' - b'file contents, just the contents\r\n' - b'--foo--') - req = Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='multipart/form-data; boundary=foo', - method='POST') - foo = req.files['foo'] - self.assert_strict_equal(foo.mimetype, 'text/plain') - self.assert_strict_equal(foo.mimetype_params, {'charset': 'utf-8'}) - self.assert_strict_equal(foo.headers['content-type'], foo.content_type) - self.assert_strict_equal(foo.content_type, 'text/plain; charset=utf-8') - self.assert_strict_equal(foo.headers['x-custom-header'], 'blah') - - def test_nonstandard_line_endings(self): - for nl in b'\n', b'\r', b'\r\n': - data = nl.join(( - b'--foo', - b'Content-Disposition: form-data; name=foo', - b'', - b'this is just bar', - b'--foo', - b'Content-Disposition: form-data; name=bar', - b'', - b'blafasel', - b'--foo--' - )) - req = Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='multipart/form-data; ' - 'boundary=foo', method='POST') - self.assert_strict_equal(req.form['foo'], u'this is just bar') - self.assert_strict_equal(req.form['bar'], u'blafasel') - - def test_failures(self): - def parse_multipart(stream, boundary, content_length): - parser = formparser.MultiPartParser(content_length) - return parser.parse(stream, boundary, content_length) - self.assert_raises(ValueError, parse_multipart, BytesIO(), b'broken ', 0) - - data = b'--foo\r\n\r\nHello World\r\n--foo--' - self.assert_raises(ValueError, parse_multipart, BytesIO(data), b'foo', len(data)) - - data = b'--foo\r\nContent-Disposition: form-field; name=foo\r\n' \ - b'Content-Transfer-Encoding: base64\r\n\r\nHello World\r\n--foo--' - self.assert_raises(ValueError, parse_multipart, BytesIO(data), b'foo', len(data)) - - data = b'--foo\r\nContent-Disposition: form-field; name=foo\r\n\r\nHello World\r\n' - self.assert_raises(ValueError, parse_multipart, BytesIO(data), b'foo', len(data)) - - x = formparser.parse_multipart_headers(['foo: bar\r\n', ' x test\r\n']) - self.assert_strict_equal(x['foo'], 'bar\n x test') - self.assert_raises(ValueError, formparser.parse_multipart_headers, - ['foo: bar\r\n', ' x test']) - - def test_bad_newline_bad_newline_assumption(self): - class ISORequest(Request): - charset = 'latin1' - contents = b'U2vlbmUgbORu' - data = b'--foo\r\nContent-Disposition: form-data; name="test"\r\n' \ - b'Content-Transfer-Encoding: base64\r\n\r\n' + \ - contents + b'\r\n--foo--' - req = ISORequest.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='multipart/form-data; boundary=foo', - method='POST') - self.assert_strict_equal(req.form['test'], u'Sk\xe5ne l\xe4n') - - def test_empty_multipart(self): - environ = {} - data = b'--boundary--' - environ['REQUEST_METHOD'] = 'POST' - environ['CONTENT_TYPE'] = 'multipart/form-data; boundary=boundary' - environ['CONTENT_LENGTH'] = str(len(data)) - environ['wsgi.input'] = BytesIO(data) - stream, form, files = parse_form_data(environ, silent=False) - rv = stream.read() - self.assert_equal(rv, b'') - self.assert_equal(form, MultiDict()) - self.assert_equal(files, MultiDict()) - - -class InternalFunctionsTestCase(WerkzeugTestCase): - - def test_line_parser(self): - assert formparser._line_parse('foo') == ('foo', False) - assert formparser._line_parse('foo\r\n') == ('foo', True) - assert formparser._line_parse('foo\r') == ('foo', True) - assert formparser._line_parse('foo\n') == ('foo', True) - - def test_find_terminator(self): - lineiter = iter(b'\n\n\nfoo\nbar\nbaz'.splitlines(True)) - find_terminator = formparser.MultiPartParser()._find_terminator - line = find_terminator(lineiter) - self.assert_equal(line, b'foo') - self.assert_equal(list(lineiter), [b'bar\n', b'baz']) - self.assert_equal(find_terminator([]), b'') - self.assert_equal(find_terminator([b'']), b'') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(FormParserTestCase)) - suite.addTest(unittest.makeSuite(MultiPartTestCase)) - suite.addTest(unittest.makeSuite(InternalFunctionsTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/http.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/http.py deleted file mode 100644 index 610debb4..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/http.py +++ /dev/null @@ -1,449 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.http - ~~~~~~~~~~~~~~~~~~~~~~~ - - HTTP parsing utilities. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import unittest -from datetime import datetime - -from werkzeug.testsuite import WerkzeugTestCase -from werkzeug._compat import itervalues, wsgi_encoding_dance - -from werkzeug import http, datastructures -from werkzeug.test import create_environ - - -class HTTPUtilityTestCase(WerkzeugTestCase): - - def test_accept(self): - a = http.parse_accept_header('en-us,ru;q=0.5') - self.assert_equal(list(itervalues(a)), ['en-us', 'ru']) - self.assert_equal(a.best, 'en-us') - self.assert_equal(a.find('ru'), 1) - self.assert_raises(ValueError, a.index, 'de') - self.assert_equal(a.to_header(), 'en-us,ru;q=0.5') - - def test_mime_accept(self): - a = http.parse_accept_header('text/xml,application/xml,' - 'application/xhtml+xml,' - 'text/html;q=0.9,text/plain;q=0.8,' - 'image/png,*/*;q=0.5', - datastructures.MIMEAccept) - self.assert_raises(ValueError, lambda: a['missing']) - self.assert_equal(a['image/png'], 1) - self.assert_equal(a['text/plain'], 0.8) - self.assert_equal(a['foo/bar'], 0.5) - self.assert_equal(a[a.find('foo/bar')], ('*/*', 0.5)) - - def test_accept_matches(self): - a = http.parse_accept_header('text/xml,application/xml,application/xhtml+xml,' - 'text/html;q=0.9,text/plain;q=0.8,' - 'image/png', datastructures.MIMEAccept) - self.assert_equal(a.best_match(['text/html', 'application/xhtml+xml']), - 'application/xhtml+xml') - self.assert_equal(a.best_match(['text/html']), 'text/html') - self.assert_true(a.best_match(['foo/bar']) is None) - self.assert_equal(a.best_match(['foo/bar', 'bar/foo'], - default='foo/bar'), 'foo/bar') - self.assert_equal(a.best_match(['application/xml', 'text/xml']), 'application/xml') - - def test_charset_accept(self): - a = http.parse_accept_header('ISO-8859-1,utf-8;q=0.7,*;q=0.7', - datastructures.CharsetAccept) - self.assert_equal(a['iso-8859-1'], a['iso8859-1']) - self.assert_equal(a['iso-8859-1'], 1) - self.assert_equal(a['UTF8'], 0.7) - self.assert_equal(a['ebcdic'], 0.7) - - def test_language_accept(self): - a = http.parse_accept_header('de-AT,de;q=0.8,en;q=0.5', - datastructures.LanguageAccept) - self.assert_equal(a.best, 'de-AT') - self.assert_true('de_AT' in a) - self.assert_true('en' in a) - self.assert_equal(a['de-at'], 1) - self.assert_equal(a['en'], 0.5) - - def test_set_header(self): - hs = http.parse_set_header('foo, Bar, "Blah baz", Hehe') - self.assert_true('blah baz' in hs) - self.assert_true('foobar' not in hs) - self.assert_true('foo' in hs) - self.assert_equal(list(hs), ['foo', 'Bar', 'Blah baz', 'Hehe']) - hs.add('Foo') - self.assert_equal(hs.to_header(), 'foo, Bar, "Blah baz", Hehe') - - def test_list_header(self): - hl = http.parse_list_header('foo baz, blah') - self.assert_equal(hl, ['foo baz', 'blah']) - - def test_dict_header(self): - d = http.parse_dict_header('foo="bar baz", blah=42') - self.assert_equal(d, {'foo': 'bar baz', 'blah': '42'}) - - def test_cache_control_header(self): - cc = http.parse_cache_control_header('max-age=0, no-cache') - assert cc.max_age == 0 - assert cc.no_cache - cc = http.parse_cache_control_header('private, community="UCI"', None, - datastructures.ResponseCacheControl) - assert cc.private - assert cc['community'] == 'UCI' - - c = datastructures.ResponseCacheControl() - assert c.no_cache is None - assert c.private is None - c.no_cache = True - assert c.no_cache == '*' - c.private = True - assert c.private == '*' - del c.private - assert c.private is None - assert c.to_header() == 'no-cache' - - def test_authorization_header(self): - a = http.parse_authorization_header('Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==') - assert a.type == 'basic' - assert a.username == 'Aladdin' - assert a.password == 'open sesame' - - a = http.parse_authorization_header('''Digest username="Mufasa", - realm="testrealm@host.invalid", - nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", - uri="/dir/index.html", - qop=auth, - nc=00000001, - cnonce="0a4f113b", - response="6629fae49393a05397450978507c4ef1", - opaque="5ccc069c403ebaf9f0171e9517f40e41"''') - assert a.type == 'digest' - assert a.username == 'Mufasa' - assert a.realm == 'testrealm@host.invalid' - assert a.nonce == 'dcd98b7102dd2f0e8b11d0f600bfb0c093' - assert a.uri == '/dir/index.html' - assert 'auth' in a.qop - assert a.nc == '00000001' - assert a.cnonce == '0a4f113b' - assert a.response == '6629fae49393a05397450978507c4ef1' - assert a.opaque == '5ccc069c403ebaf9f0171e9517f40e41' - - a = http.parse_authorization_header('''Digest username="Mufasa", - realm="testrealm@host.invalid", - nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", - uri="/dir/index.html", - response="e257afa1414a3340d93d30955171dd0e", - opaque="5ccc069c403ebaf9f0171e9517f40e41"''') - assert a.type == 'digest' - assert a.username == 'Mufasa' - assert a.realm == 'testrealm@host.invalid' - assert a.nonce == 'dcd98b7102dd2f0e8b11d0f600bfb0c093' - assert a.uri == '/dir/index.html' - assert a.response == 'e257afa1414a3340d93d30955171dd0e' - assert a.opaque == '5ccc069c403ebaf9f0171e9517f40e41' - - assert http.parse_authorization_header('') is None - assert http.parse_authorization_header(None) is None - assert http.parse_authorization_header('foo') is None - - def test_www_authenticate_header(self): - wa = http.parse_www_authenticate_header('Basic realm="WallyWorld"') - assert wa.type == 'basic' - assert wa.realm == 'WallyWorld' - wa.realm = 'Foo Bar' - assert wa.to_header() == 'Basic realm="Foo Bar"' - - wa = http.parse_www_authenticate_header('''Digest - realm="testrealm@host.com", - qop="auth,auth-int", - nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", - opaque="5ccc069c403ebaf9f0171e9517f40e41"''') - assert wa.type == 'digest' - assert wa.realm == 'testrealm@host.com' - assert 'auth' in wa.qop - assert 'auth-int' in wa.qop - assert wa.nonce == 'dcd98b7102dd2f0e8b11d0f600bfb0c093' - assert wa.opaque == '5ccc069c403ebaf9f0171e9517f40e41' - - wa = http.parse_www_authenticate_header('broken') - assert wa.type == 'broken' - - assert not http.parse_www_authenticate_header('').type - assert not http.parse_www_authenticate_header('') - - def test_etags(self): - assert http.quote_etag('foo') == '"foo"' - assert http.quote_etag('foo', True) == 'w/"foo"' - assert http.unquote_etag('"foo"') == ('foo', False) - assert http.unquote_etag('w/"foo"') == ('foo', True) - es = http.parse_etags('"foo", "bar", w/"baz", blar') - assert sorted(es) == ['bar', 'blar', 'foo'] - assert 'foo' in es - assert 'baz' not in es - assert es.contains_weak('baz') - assert 'blar' in es - assert es.contains_raw('w/"baz"') - assert es.contains_raw('"foo"') - assert sorted(es.to_header().split(', ')) == ['"bar"', '"blar"', '"foo"', 'w/"baz"'] - - def test_etags_nonzero(self): - etags = http.parse_etags('w/"foo"') - self.assert_true(bool(etags)) - self.assert_true(etags.contains_raw('w/"foo"')) - - def test_parse_date(self): - assert http.parse_date('Sun, 06 Nov 1994 08:49:37 GMT ') == datetime(1994, 11, 6, 8, 49, 37) - assert http.parse_date('Sunday, 06-Nov-94 08:49:37 GMT') == datetime(1994, 11, 6, 8, 49, 37) - assert http.parse_date(' Sun Nov 6 08:49:37 1994') == datetime(1994, 11, 6, 8, 49, 37) - assert http.parse_date('foo') is None - - def test_parse_date_overflows(self): - assert http.parse_date(' Sun 02 Feb 1343 08:49:37 GMT') == datetime(1343, 2, 2, 8, 49, 37) - assert http.parse_date('Thu, 01 Jan 1970 00:00:00 GMT') == datetime(1970, 1, 1, 0, 0) - assert http.parse_date('Thu, 33 Jan 1970 00:00:00 GMT') is None - - def test_remove_entity_headers(self): - now = http.http_date() - headers1 = [('Date', now), ('Content-Type', 'text/html'), ('Content-Length', '0')] - headers2 = datastructures.Headers(headers1) - - http.remove_entity_headers(headers1) - assert headers1 == [('Date', now)] - - http.remove_entity_headers(headers2) - self.assert_equal(headers2, datastructures.Headers([(u'Date', now)])) - - def test_remove_hop_by_hop_headers(self): - headers1 = [('Connection', 'closed'), ('Foo', 'bar'), - ('Keep-Alive', 'wtf')] - headers2 = datastructures.Headers(headers1) - - http.remove_hop_by_hop_headers(headers1) - assert headers1 == [('Foo', 'bar')] - - http.remove_hop_by_hop_headers(headers2) - assert headers2 == datastructures.Headers([('Foo', 'bar')]) - - def test_parse_options_header(self): - assert http.parse_options_header(r'something; foo="other\"thing"') == \ - ('something', {'foo': 'other"thing'}) - assert http.parse_options_header(r'something; foo="other\"thing"; meh=42') == \ - ('something', {'foo': 'other"thing', 'meh': '42'}) - assert http.parse_options_header(r'something; foo="other\"thing"; meh=42; bleh') == \ - ('something', {'foo': 'other"thing', 'meh': '42', 'bleh': None}) - assert http.parse_options_header('something; foo="other;thing"; meh=42; bleh') == \ - ('something', {'foo': 'other;thing', 'meh': '42', 'bleh': None}) - assert http.parse_options_header('something; foo="otherthing"; meh=; bleh') == \ - ('something', {'foo': 'otherthing', 'meh': None, 'bleh': None}) - - - - def test_dump_options_header(self): - assert http.dump_options_header('foo', {'bar': 42}) == \ - 'foo; bar=42' - assert http.dump_options_header('foo', {'bar': 42, 'fizz': None}) in \ - ('foo; bar=42; fizz', 'foo; fizz; bar=42') - - def test_dump_header(self): - assert http.dump_header([1, 2, 3]) == '1, 2, 3' - assert http.dump_header([1, 2, 3], allow_token=False) == '"1", "2", "3"' - assert http.dump_header({'foo': 'bar'}, allow_token=False) == 'foo="bar"' - assert http.dump_header({'foo': 'bar'}) == 'foo=bar' - - def test_is_resource_modified(self): - env = create_environ() - - # ignore POST - env['REQUEST_METHOD'] = 'POST' - assert not http.is_resource_modified(env, etag='testing') - env['REQUEST_METHOD'] = 'GET' - - # etagify from data - self.assert_raises(TypeError, http.is_resource_modified, env, - data='42', etag='23') - env['HTTP_IF_NONE_MATCH'] = http.generate_etag(b'awesome') - assert not http.is_resource_modified(env, data=b'awesome') - - env['HTTP_IF_MODIFIED_SINCE'] = http.http_date(datetime(2008, 1, 1, 12, 30)) - assert not http.is_resource_modified(env, - last_modified=datetime(2008, 1, 1, 12, 00)) - assert http.is_resource_modified(env, - last_modified=datetime(2008, 1, 1, 13, 00)) - - def test_date_formatting(self): - assert http.cookie_date(0) == 'Thu, 01-Jan-1970 00:00:00 GMT' - assert http.cookie_date(datetime(1970, 1, 1)) == 'Thu, 01-Jan-1970 00:00:00 GMT' - assert http.http_date(0) == 'Thu, 01 Jan 1970 00:00:00 GMT' - assert http.http_date(datetime(1970, 1, 1)) == 'Thu, 01 Jan 1970 00:00:00 GMT' - - def test_cookies(self): - self.assert_strict_equal( - dict(http.parse_cookie('dismiss-top=6; CP=null*; PHPSESSID=0a539d42abc001cd' - 'c762809248d4beed; a=42; b="\\\";"')), - { - 'CP': u'null*', - 'PHPSESSID': u'0a539d42abc001cdc762809248d4beed', - 'a': u'42', - 'dismiss-top': u'6', - 'b': u'\";' - } - ) - self.assert_strict_equal( - set(http.dump_cookie('foo', 'bar baz blub', 360, httponly=True, - sync_expires=False).split(u'; ')), - set([u'HttpOnly', u'Max-Age=360', u'Path=/', u'foo="bar baz blub"']) - ) - self.assert_strict_equal(dict(http.parse_cookie('fo234{=bar; blub=Blah')), - {'fo234{': u'bar', 'blub': u'Blah'}) - - def test_cookie_quoting(self): - val = http.dump_cookie("foo", "?foo") - self.assert_strict_equal(val, 'foo="?foo"; Path=/') - self.assert_strict_equal(dict(http.parse_cookie(val)), {'foo': u'?foo'}) - - self.assert_strict_equal(dict(http.parse_cookie(r'foo="foo\054bar"')), - {'foo': u'foo,bar'}) - - def test_cookie_domain_resolving(self): - val = http.dump_cookie('foo', 'bar', domain=u'\N{SNOWMAN}.com') - self.assert_strict_equal(val, 'foo=bar; Domain=xn--n3h.com; Path=/') - - def test_cookie_unicode_dumping(self): - val = http.dump_cookie('foo', u'\N{SNOWMAN}') - h = datastructures.Headers() - h.add('Set-Cookie', val) - self.assert_equal(h['Set-Cookie'], 'foo="\\342\\230\\203"; Path=/') - - cookies = http.parse_cookie(h['Set-Cookie']) - self.assert_equal(cookies['foo'], u'\N{SNOWMAN}') - - def test_cookie_unicode_keys(self): - # Yes, this is technically against the spec but happens - val = http.dump_cookie(u'fö', u'fö') - self.assert_equal(val, wsgi_encoding_dance(u'fö="f\\303\\266"; Path=/', 'utf-8')) - cookies = http.parse_cookie(val) - self.assert_equal(cookies[u'fö'], u'fö') - - def test_cookie_unicode_parsing(self): - # This is actually a correct test. This is what is being submitted - # by firefox if you set an unicode cookie and we get the cookie sent - # in on Python 3 under PEP 3333. - cookies = http.parse_cookie(u'fö=fö') - self.assert_equal(cookies[u'fö'], u'fö') - - def test_cookie_domain_encoding(self): - val = http.dump_cookie('foo', 'bar', domain=u'\N{SNOWMAN}.com') - self.assert_strict_equal(val, 'foo=bar; Domain=xn--n3h.com; Path=/') - - val = http.dump_cookie('foo', 'bar', domain=u'.\N{SNOWMAN}.com') - self.assert_strict_equal(val, 'foo=bar; Domain=.xn--n3h.com; Path=/') - - val = http.dump_cookie('foo', 'bar', domain=u'.foo.com') - self.assert_strict_equal(val, 'foo=bar; Domain=.foo.com; Path=/') - - -class RangeTestCase(WerkzeugTestCase): - - def test_if_range_parsing(self): - rv = http.parse_if_range_header('"Test"') - assert rv.etag == 'Test' - assert rv.date is None - assert rv.to_header() == '"Test"' - - # weak information is dropped - rv = http.parse_if_range_header('w/"Test"') - assert rv.etag == 'Test' - assert rv.date is None - assert rv.to_header() == '"Test"' - - # broken etags are supported too - rv = http.parse_if_range_header('bullshit') - assert rv.etag == 'bullshit' - assert rv.date is None - assert rv.to_header() == '"bullshit"' - - rv = http.parse_if_range_header('Thu, 01 Jan 1970 00:00:00 GMT') - assert rv.etag is None - assert rv.date == datetime(1970, 1, 1) - assert rv.to_header() == 'Thu, 01 Jan 1970 00:00:00 GMT' - - for x in '', None: - rv = http.parse_if_range_header(x) - assert rv.etag is None - assert rv.date is None - assert rv.to_header() == '' - - def test_range_parsing(): - rv = http.parse_range_header('bytes=52') - assert rv is None - - rv = http.parse_range_header('bytes=52-') - assert rv.units == 'bytes' - assert rv.ranges == [(52, None)] - assert rv.to_header() == 'bytes=52-' - - rv = http.parse_range_header('bytes=52-99') - assert rv.units == 'bytes' - assert rv.ranges == [(52, 100)] - assert rv.to_header() == 'bytes=52-99' - - rv = http.parse_range_header('bytes=52-99,-1000') - assert rv.units == 'bytes' - assert rv.ranges == [(52, 100), (-1000, None)] - assert rv.to_header() == 'bytes=52-99,-1000' - - rv = http.parse_range_header('bytes = 1 - 100') - assert rv.units == 'bytes' - assert rv.ranges == [(1, 101)] - assert rv.to_header() == 'bytes=1-100' - - rv = http.parse_range_header('AWesomes=0-999') - assert rv.units == 'awesomes' - assert rv.ranges == [(0, 1000)] - assert rv.to_header() == 'awesomes=0-999' - - def test_content_range_parsing(): - rv = http.parse_content_range_header('bytes 0-98/*') - assert rv.units == 'bytes' - assert rv.start == 0 - assert rv.stop == 99 - assert rv.length is None - assert rv.to_header() == 'bytes 0-98/*' - - rv = http.parse_content_range_header('bytes 0-98/*asdfsa') - assert rv is None - - rv = http.parse_content_range_header('bytes 0-99/100') - assert rv.to_header() == 'bytes 0-99/100' - rv.start = None - rv.stop = None - assert rv.units == 'bytes' - assert rv.to_header() == 'bytes */100' - - rv = http.parse_content_range_header('bytes */100') - assert rv.start is None - assert rv.stop is None - assert rv.length == 100 - assert rv.units == 'bytes' - - -class RegressionTestCase(WerkzeugTestCase): - - def test_best_match_works(self): - # was a bug in 0.6 - rv = http.parse_accept_header('foo=,application/xml,application/xhtml+xml,' - 'text/html;q=0.9,text/plain;q=0.8,' - 'image/png,*/*;q=0.5', - datastructures.MIMEAccept).best_match(['foo/bar']) - self.assert_equal(rv, 'foo/bar') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(HTTPUtilityTestCase)) - suite.addTest(unittest.makeSuite(RegressionTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/internal.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/internal.py deleted file mode 100644 index 3e0da0ca..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/internal.py +++ /dev/null @@ -1,81 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.internal - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Internal tests. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from datetime import datetime -from warnings import filterwarnings, resetwarnings - -from werkzeug.testsuite import WerkzeugTestCase -from werkzeug.wrappers import Request, Response - -from werkzeug import _internal as internal -from werkzeug.test import create_environ - - -class InternalTestCase(WerkzeugTestCase): - - def test_date_to_unix(self): - assert internal._date_to_unix(datetime(1970, 1, 1)) == 0 - assert internal._date_to_unix(datetime(1970, 1, 1, 1, 0, 0)) == 3600 - assert internal._date_to_unix(datetime(1970, 1, 1, 1, 1, 1)) == 3661 - x = datetime(2010, 2, 15, 16, 15, 39) - assert internal._date_to_unix(x) == 1266250539 - - def test_easteregg(self): - req = Request.from_values('/?macgybarchakku') - resp = Response.force_type(internal._easteregg(None), req) - assert b'About Werkzeug' in resp.get_data() - assert b'the Swiss Army knife of Python web development' in resp.get_data() - - def test_wrapper_internals(self): - req = Request.from_values(data={'foo': 'bar'}, method='POST') - req._load_form_data() - assert req.form.to_dict() == {'foo': 'bar'} - - # second call does not break - req._load_form_data() - assert req.form.to_dict() == {'foo': 'bar'} - - # check reprs - assert repr(req) == "" - resp = Response() - assert repr(resp) == '' - resp.set_data('Hello World!') - assert repr(resp) == '' - resp.response = iter(['Test']) - assert repr(resp) == '' - - # unicode data does not set content length - response = Response([u'Hällo Wörld']) - headers = response.get_wsgi_headers(create_environ()) - assert u'Content-Length' not in headers - - response = Response([u'Hällo Wörld'.encode('utf-8')]) - headers = response.get_wsgi_headers(create_environ()) - assert u'Content-Length' in headers - - # check for internal warnings - filterwarnings('error', category=Warning) - response = Response() - environ = create_environ() - response.response = 'What the...?' - self.assert_raises(Warning, lambda: list(response.iter_encoded())) - self.assert_raises(Warning, lambda: list(response.get_app_iter(environ))) - response.direct_passthrough = True - self.assert_raises(Warning, lambda: list(response.iter_encoded())) - self.assert_raises(Warning, lambda: list(response.get_app_iter(environ))) - resetwarnings() - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(InternalTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/local.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/local.py deleted file mode 100644 index af01319a..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/local.py +++ /dev/null @@ -1,159 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.local - ~~~~~~~~~~~~~~~~~~~~~~~~ - - Local and local proxy tests. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import time -import unittest -from threading import Thread - -from werkzeug.testsuite import WerkzeugTestCase - -from werkzeug import local - - -class LocalTestCase(WerkzeugTestCase): - - def test_basic_local(self): - l = local.Local() - l.foo = 0 - values = [] - def value_setter(idx): - time.sleep(0.01 * idx) - l.foo = idx - time.sleep(0.02) - values.append(l.foo) - threads = [Thread(target=value_setter, args=(x,)) - for x in [1, 2, 3]] - for thread in threads: - thread.start() - time.sleep(0.2) - assert sorted(values) == [1, 2, 3] - - def delfoo(): - del l.foo - delfoo() - self.assert_raises(AttributeError, lambda: l.foo) - self.assert_raises(AttributeError, delfoo) - - local.release_local(l) - - def test_local_release(self): - loc = local.Local() - loc.foo = 42 - local.release_local(loc) - assert not hasattr(loc, 'foo') - - ls = local.LocalStack() - ls.push(42) - local.release_local(ls) - assert ls.top is None - - def test_local_proxy(self): - foo = [] - ls = local.LocalProxy(lambda: foo) - ls.append(42) - ls.append(23) - ls[1:] = [1, 2, 3] - assert foo == [42, 1, 2, 3] - assert repr(foo) == repr(ls) - assert foo[0] == 42 - foo += [1] - assert list(foo) == [42, 1, 2, 3, 1] - - def test_local_proxy_operations_math(self): - foo = 2 - ls = local.LocalProxy(lambda: foo) - assert ls + 1 == 3 - assert 1 + ls == 3 - assert ls - 1 == 1 - assert 1 - ls == -1 - assert ls * 1 == 2 - assert 1 * ls == 2 - assert ls / 1 == 2 - assert 1.0 / ls == 0.5 - assert ls // 1.0 == 2.0 - assert 1.0 // ls == 0.0 - assert ls % 2 == 0 - assert 2 % ls == 0 - - def test_local_proxy_operations_strings(self): - foo = "foo" - ls = local.LocalProxy(lambda: foo) - assert ls + "bar" == "foobar" - assert "bar" + ls == "barfoo" - assert ls * 2 == "foofoo" - - foo = "foo %s" - assert ls % ("bar",) == "foo bar" - - def test_local_stack(self): - ident = local.get_ident() - - ls = local.LocalStack() - assert ident not in ls._local.__storage__ - assert ls.top is None - ls.push(42) - assert ident in ls._local.__storage__ - assert ls.top == 42 - ls.push(23) - assert ls.top == 23 - ls.pop() - assert ls.top == 42 - ls.pop() - assert ls.top is None - assert ls.pop() is None - assert ls.pop() is None - - proxy = ls() - ls.push([1, 2]) - assert proxy == [1, 2] - ls.push((1, 2)) - assert proxy == (1, 2) - ls.pop() - ls.pop() - assert repr(proxy) == '' - - assert ident not in ls._local.__storage__ - - def test_local_proxies_with_callables(self): - foo = 42 - ls = local.LocalProxy(lambda: foo) - assert ls == 42 - foo = [23] - ls.append(42) - assert ls == [23, 42] - assert foo == [23, 42] - - def test_custom_idents(self): - ident = 0 - loc = local.Local() - stack = local.LocalStack() - mgr = local.LocalManager([loc, stack], ident_func=lambda: ident) - - loc.foo = 42 - stack.push({'foo': 42}) - ident = 1 - loc.foo = 23 - stack.push({'foo': 23}) - ident = 0 - assert loc.foo == 42 - assert stack.top['foo'] == 42 - stack.pop() - assert stack.top is None - ident = 1 - assert loc.foo == 23 - assert stack.top['foo'] == 23 - stack.pop() - assert stack.top is None - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(LocalTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/collect.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/collect.py deleted file mode 100644 index daa0e09e..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/collect.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -""" -Hacky helper application to collect form data. -""" -from werkzeug.serving import run_simple -from werkzeug.wrappers import Request, Response - - -def copy_stream(request): - from os import mkdir - from time import time - folder = 'request-%d' % time() - mkdir(folder) - environ = request.environ - f = open(folder + '/request.txt', 'wb+') - f.write(environ['wsgi.input'].read(int(environ['CONTENT_LENGTH']))) - f.flush() - f.seek(0) - environ['wsgi.input'] = f - request.stat_folder = folder - - -def stats(request): - copy_stream(request) - f1 = request.files['file1'] - f2 = request.files['file2'] - text = request.form['text'] - f1.save(request.stat_folder + '/file1.bin') - f2.save(request.stat_folder + '/file2.bin') - open(request.stat_folder + '/text.txt', 'w').write(text.encode('utf-8')) - return Response('Done.') - - -def upload_file(request): - return Response(''' -

    Upload File

    -
    -
    -
    -
    - -
    - ''', mimetype='text/html') - - -def application(environ, start_responseonse): - request = Request(environ) - if request.method == 'POST': - response = stats(request) - else: - response = upload_file(request) - return response(environ, start_responseonse) - - -if __name__ == '__main__': - run_simple('localhost', 5000, application, use_debugger=True) diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2png1txt/file1.png b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2png1txt/file1.png deleted file mode 100644 index 9b3422c61e5d23434d085834b82eed7a7363976e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 523 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 diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2png1txt/text.txt b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2png1txt/text.txt deleted file mode 100644 index c87634d5..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2png1txt/text.txt +++ /dev/null @@ -1 +0,0 @@ -example text \ No newline at end of file diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2pnglongtext/file1.png b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2pnglongtext/file1.png deleted file mode 100644 index 89c8129a490b329f3165f32fa0781701aab417ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 781 zcmV+o1M>WdP)4-QibtN)VXQDpczE`xXAkUjh%RI>;okxb7K@0kpyQ1k_Y(|Oe7$m(^ zNYX>mI||sUbmn+c3<&FnE=4u#()KBS^SH8e)Qs5i!#lY=$-1gbH6VluzU=m=EP78&5vQ z-?+fFP-G2l&l_QzYealK$;1Rl?FkzXR&Jv@fBPNjCr#AYRyJ7UJQ0v#?)7Ott=>3`#-pV!7>9}>Q1jL)H6h&gkP@3nI=+F3nA~M>u#(n* z8T!#8oEw&-mED4!h4s!N@Jo3S7N&Q6%6l3}nlcd~X@>;uelvPsSkXIgg~e+^T1zSf z3SNj(5%jK~i8@b;C9VHk(~TedF+gQSL8D5xnVSSWAVY>J9b+m>@{iq7_KE}go~11+5s4;8hc+i0Xa zI1j@EX5!S+Me6HNqKzU5YQwL;-W5$p%ZMKMeR<%zp69-~?<4?8|C8S?bklXr4v&Ov zb&06v2|-x?qB`90yn>Qi%Sh2^G4n)$ZdyvTPf9}1)_buUT7>`e2G&2VU@~Bb(o+Mz zi4)>IxlSY${Dj4k={-9RzU^W5g9|2V5RZ2ZulL9s2xQbZ@r6eP9Ra5u(s|C0Nj#&4>wTSkb?%#=9?@ z^oxDy-O@tyN{L@by(WWvQ3%CyEu8x{+#Jb4-h&K9Owi)2pgg+heWDyked|3R$$kL@A z#sp1v-r+=G4B8D6DqsDH0@7OztA7aT9qc1Py{()w`m``?Y0&gi2=ROcc-9+nU^I6< zT=e_Y=vSnG@?3Ue{BW5ONFttcE!R-R_W4O01|0-|K-YNXLo2`4Qv z`r1LxR6#yf3FB%T95gJnaKKivA~Z}S9A(ZxEDK}O3T04USJ P00000NkvXXu0mjf^IS-S diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2pnglongtext/request.txt b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2pnglongtext/request.txt deleted file mode 100644 index 489290b6730d72648b7a748c5c2984aa7af3c2a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2042 zcmdPZ#RCjYEDcNyOiav;EzK>=4J{1~j1A3AP0S4q%}p$Lxt#O!N>cMmbX_uw3-XII zOEUBGtQ6Ani*j{S5=#=T74i~uQ*D*fGILT5m8=y&G(;pZIXShUM6Vz(T?t`GNM%8) zl|p82VtT4RP==R_m#Z_t&z+Y`ii?4Pf!EW+B?w3hfG`Iekd*)YKM_c=q&xaLGBB(^ zVb0q163CY%U#85)$Dm{M7IGS!BGfoZ;{i(`nz>7|oj zdj}`V9RF)wcCIXknKQ*jv8g4XT2w{IdKT}|Jv!c(@9w>1mVCpf+o&k+n1`nB<||pn zez~u%Ji9i)0w?5owg>HY|MZD=BSU5a@7NFe*W{%KUc3SWO(#Xy`D$p2VZB= za{gDFZ8d$4J^q{cvcp2BRMjXbeUaVWec@YHE1aM0b=u~n;#~K(*^b=5rtMzzGA75Z z^R|Z ztvI%6(NxPB%%S&!1AN4t3_}^dhA7_2ZZ@cxTCic#oq5V0JDjAFntB8cFH7dMncisO ziZ`6%|3qg7|5Fudf4gJ%cO2LnkiwgLUOI7hwo8re$s;W8Z#kv;!}1oJEoi(JePmq< zL%001g|jq{+_)7W@^9l$+1&Gb2Mq#y_9dvZxFsp8O}Mk%?AP?&iC*DM zn0ihpBf`;p0pHs=;}u#-+1x9)v#|Yikb0wC9%!rBeydif^zze)s_hNiZn90`lWRXz z$Yhny_h$XBiFvj>t0vvBI+CItzoUPz)MoeQ_A{~}ea{@N=P+NLz~jX(&UfzE;-z{L z?OloipRZ|}D&F}vL1?yz)xO4#8Fx~FVRWrQ^4CSBInvV>PrchTxAp5er4Qbff?~_c zYfe>5dCW2rRLpE=d0S^(6(4cYI=}U3wo{b177JHgN08u`b@Mx|{JS)m7cS4@a9i-S zl~pTl#@Z7bE(R}cd9i-~$N10O=@-^Kt=x4b8JM0KJYD@<);T3K@p9qGsJgmT%c@4G zSv4hP0P|@+BA-r9lxY7Oy-lCBc}ZKO#tKc<2#x%kIbB_Tx2F|ncb)r|r#E-kS!Uh2 z!u+CJ7v9cTVr{{Hm^tmyl}oO#UI#4dRpQ7xyng>ZQD67d9dbWvDZ_bLpY z|0mzqE4f^HhOfURr?hj$Gfu~de~YZ{eAv@8DeAPx#SFvGE{%CnUR(UVoX%gX-Y6B- z^8Yj2HT$&*MhWegf|>Vq3O};l>8B#{r{(Cxm$ue?``#vgYvxwV66i1I+3H*oOHa` z%;V~F;nA9fF^tlGLyfJ%Lo=c$I-6;Cak7}{Nu`}qn5%W{fVAuv@3TAZ%ym1;(pC6x z;rG4VfAdRC?zGs;eoPS*`CJq6=kSS3OXZHS_?F#!=#s#5i&sc1{%Xr!g=Wbr&-cXoja&3b~#Ooe4 zu42QD$%kZ5uho$837eO8gg5BtVx~nYFS3?g4CGYTHT-qU@mz?bT`1?{ENK}Noh=0i z!Zs?I_^8OFo^#N1lqhog$vpE#q(Wj{ZbRi^hTiRhk+GVA79}!%JAAHxnR({Uyb`0` zpOvOA^yFN=bw2O>d|T(a!5dGcJk@*_za5zGWF6g3%QI+PK1lC;SCU#$0;~!_Sv)5{ oFI@q|2XV?XOEMIa@=Nnl5{oJ!viaGGIhon1#k#tb6bK;Q0IR$;-v9sr diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2pnglongtext/text.txt b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2pnglongtext/text.txt deleted file mode 100644 index 3bf804d5..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/firefox3-2pnglongtext/text.txt +++ /dev/null @@ -1,3 +0,0 @@ ---long text ---with boundary ---lookalikes-- \ No newline at end of file diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/ie6-2png1txt/file1.png b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/ie6-2png1txt/file1.png deleted file mode 100644 index 9b3422c61e5d23434d085834b82eed7a7363976e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 523 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 diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/ie6-2png1txt/text.txt b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/ie6-2png1txt/text.txt deleted file mode 100644 index 7c465b7a..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/ie6-2png1txt/text.txt +++ /dev/null @@ -1 +0,0 @@ -ie6 sucks :-/ \ No newline at end of file diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/ie7_full_path_request.txt b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/ie7_full_path_request.txt deleted file mode 100644 index acc4e2e1858f5888b7a9f64d47aae363145ffc90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30044 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 cM*|n+_b-i~S8HN)#RH5YnYUGP-mK>R8bw z2t8C_N?y`%B@?pVvm%P1(=O${na{Vw7Aotm+uS~f8Ro~wbIxHo`d;S7O>X_I!*}m4(;rQL3lRx0{4$S^45y5Zuub!<^(wd zDg1Ydq7a)PBNSH(^bYo1I&!_cv8F)Tfk3iCfaGzKcdABUEYJ~V4lNs7(L31l-D~h- zlLeyC;Rle^b>Pb0!o4OezZxjWAc9)nJe_NP=QDRgIAC4B#i)@%!f@-iPyu79xm3 z&=Ei~gdfA((>G@?t|CClgk~>+;;$k`$HzXCdi?6@>wW;(eSTM7w8{L??AcXUU@Ta{ zLrZBBKD>>5#ZOj$V zV$6R8et`Hsp^Y06t?}x?-BN{Jo+A{GLpF=}{yzmtYh)C=wic&;1MX^#S<^tIK8mw$ z9j5mS;s?n^1>U{8t&EN(863h(*qFLQ=;hn-R;7@>ex(0vvZCi*>q5p75xCt@M#zpM z*Z|q?@X7EteIjT$hYlRP@ApxiZy$PlmbH;D0hOKL_{*WZ;MR^|Dic+L1tK5@y>d4> zXDufE6I)H=Wxil#C-axq0i?$W%}gE53ocb3M9Ce~cq*pr4r68}P%}Rp!|ZI1=W3eKQ{(8&6eg2G=4KE}@YE!+_s=wG z)yj?Wi=|CWjtmfUw}tvT?>o~yi1Cr^9Fogm)I5&s5bN!p#FzaA_^&C@GMJ`fX;)}= z5K#fB0E~v<&l+~pTpQ_Hbc_JlkpsFSk>9$Ch@B!-R)IDix^hJgZHdi`3)**;A=W+} zt0nUFG38I&2bR2ge6xJwHJ&|-TDl&zbzpIUHhXn+ZJGP%0^v7ruA^itSBHJ0F6=jD>(Vqjq4_4IHF0@4B?%)tgEpWXX$^2@=JQ}@f$o;)eBWtvya_cwX@tTQ=kb3c{m+~33dOy=3Xa}O`~ z>wjKk^0bNi4l$(;rwf7(MlJG(Z(lY~*I%dPaH1tmzwyy}CAZ_p?Iu_KdG+db z9m9>gTe~DWQp%3z436btzBLMyM$o zn9fq-i%SxVfXO;PuPQa(aNrU)Q$8eNw@&u;2niHv*l+%RZ)LJ^n`eE>tX4y2L9s9I zl`_RWFD(ic5OEO+j1Hg4d{Hao@*=S?m#sWrr#2M?>T>;BC~$Vkkw4ttva-i#et)-j z`B9T*=ZN&;_qKE1KQ21AcUngPNA0&B7SpXiWMw-zB$_3fI~0yRFg11j&b{dT{0P=# ziH;pXM;|doOc8OZ+aRDAqQns*cR}i+)b=Rh+%ux*lg`w$)HVFDTi7ctxc1|#gLi{k zW9KQ0^gEk%|M+Lm>Y1G)vU{7@@;c^sS-p{$9hTU2ZO)Tj_MQ6?`$<>UdwX}U?demM zlsV*mW5zD$7f)}03|l&3U)_@b*_#$UkA3ZQOh|CY-2k@}eabf&Zod0)@`G8eQier4 zpUj^3-vj67%U4xT+d5I7aq8R$KTa>)^Wa)vqLy%I6RVN}+ukB`%XD3}zrxYJk5l(0 zq^f_OevNU-agMV-vS+#VLgigf%3iL}TK1YRIZZ9V*xqon@QgDikDfd5gjH~waXk-a zpP0|g-?7Vm%_C>4_|W!+hu`G%JOgf!##isAI!0Wg3j!gf{`eVK31)~|uk}|_H$^-%# zS1|OnJvc8_b}2^sWmHKI!;Oi|yObv0-__MIS1BZ{(M)bvkt=U*=h<%VTjf&~ui442 zR{iwV@Tvc8_Gx>nYBtwAGM#7J9koktOKC!3qgi!nN$$+wFPI*h=dW9wq8;AezcbnS z_hNau-V=XpSb~%^e)cX|w))M#kNJN-`CtCGc=L??Ha9%IYl5GAKCYcnrsGn_T+R_0 rU~oakh*tTnB(-8)c*)^C#N=sRU0yB#ZkE?q diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/opera8-2png1txt/text.txt b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/opera8-2png1txt/text.txt deleted file mode 100644 index ca01cb00..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/opera8-2png1txt/text.txt +++ /dev/null @@ -1 +0,0 @@ -blafasel öäü \ No newline at end of file diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/webkit3-2png1txt/file1.png b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/webkit3-2png1txt/file1.png deleted file mode 100644 index afca0732a75933c67a30ff16d2c9b4c3abf1cf1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1002 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 BEyDl+ diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/webkit3-2png1txt/text.txt b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/webkit3-2png1txt/text.txt deleted file mode 100644 index baa13008..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/multipart/webkit3-2png1txt/text.txt +++ /dev/null @@ -1 +0,0 @@ -this is another text with ümläüts \ No newline at end of file diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/res/test.txt b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/res/test.txt deleted file mode 100644 index a8efdcc3..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/res/test.txt +++ /dev/null @@ -1 +0,0 @@ -FOUND diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/routing.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/routing.py deleted file mode 100644 index 7766f2c7..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/routing.py +++ /dev/null @@ -1,689 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.routing - ~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Routing tests. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from werkzeug.testsuite import WerkzeugTestCase - -from werkzeug import routing as r -from werkzeug.wrappers import Response -from werkzeug.datastructures import ImmutableDict -from werkzeug.test import create_environ - - -class RoutingTestCase(WerkzeugTestCase): - - def test_basic_routing(self): - map = r.Map([ - r.Rule('/', endpoint='index'), - r.Rule('/foo', endpoint='foo'), - r.Rule('/bar/', endpoint='bar') - ]) - adapter = map.bind('example.org', '/') - assert adapter.match('/') == ('index', {}) - assert adapter.match('/foo') == ('foo', {}) - assert adapter.match('/bar/') == ('bar', {}) - self.assert_raises(r.RequestRedirect, lambda: adapter.match('/bar')) - self.assert_raises(r.NotFound, lambda: adapter.match('/blub')) - - adapter = map.bind('example.org', '/test') - try: - adapter.match('/bar') - except r.RequestRedirect as e: - assert e.new_url == 'http://example.org/test/bar/' - else: - self.fail('Expected request redirect') - - adapter = map.bind('example.org', '/') - try: - adapter.match('/bar') - except r.RequestRedirect as e: - assert e.new_url == 'http://example.org/bar/' - else: - self.fail('Expected request redirect') - - adapter = map.bind('example.org', '/') - try: - adapter.match('/bar', query_args={'aha': 'muhaha'}) - except r.RequestRedirect as e: - assert e.new_url == 'http://example.org/bar/?aha=muhaha' - else: - self.fail('Expected request redirect') - - adapter = map.bind('example.org', '/') - try: - adapter.match('/bar', query_args='aha=muhaha') - except r.RequestRedirect as e: - assert e.new_url == 'http://example.org/bar/?aha=muhaha' - else: - self.fail('Expected request redirect') - - adapter = map.bind_to_environ(create_environ('/bar?foo=bar', - 'http://example.org/')) - try: - adapter.match() - except r.RequestRedirect as e: - assert e.new_url == 'http://example.org/bar/?foo=bar' - else: - self.fail('Expected request redirect') - - def test_environ_defaults(self): - environ = create_environ("/foo") - self.assert_strict_equal(environ["PATH_INFO"], '/foo') - m = r.Map([r.Rule("/foo", endpoint="foo"), r.Rule("/bar", endpoint="bar")]) - a = m.bind_to_environ(environ) - self.assert_strict_equal(a.match("/foo"), ('foo', {})) - self.assert_strict_equal(a.match(), ('foo', {})) - self.assert_strict_equal(a.match("/bar"), ('bar', {})) - self.assert_raises(r.NotFound, a.match, "/bars") - - def test_environ_nonascii_pathinfo(self): - environ = create_environ(u'/лошадь') - m = r.Map([ - r.Rule(u'/', endpoint='index'), - r.Rule(u'/лошадь', endpoint='horse') - ]) - a = m.bind_to_environ(environ) - self.assert_strict_equal(a.match(u'/'), ('index', {})) - self.assert_strict_equal(a.match(u'/лошадь'), ('horse', {})) - self.assert_raises(r.NotFound, a.match, u'/барсук') - - def test_basic_building(self): - map = r.Map([ - r.Rule('/', endpoint='index'), - r.Rule('/foo', endpoint='foo'), - r.Rule('/bar/', endpoint='bar'), - r.Rule('/bar/', endpoint='bari'), - r.Rule('/bar/', endpoint='barf'), - r.Rule('/bar/', endpoint='barp'), - r.Rule('/hehe', endpoint='blah', subdomain='blah') - ]) - adapter = map.bind('example.org', '/', subdomain='blah') - - assert adapter.build('index', {}) == 'http://example.org/' - assert adapter.build('foo', {}) == 'http://example.org/foo' - assert adapter.build('bar', {'baz': 'blub'}) == 'http://example.org/bar/blub' - assert adapter.build('bari', {'bazi': 50}) == 'http://example.org/bar/50' - assert adapter.build('barf', {'bazf': 0.815}) == 'http://example.org/bar/0.815' - assert adapter.build('barp', {'bazp': 'la/di'}) == 'http://example.org/bar/la/di' - assert adapter.build('blah', {}) == '/hehe' - self.assert_raises(r.BuildError, lambda: adapter.build('urks')) - - adapter = map.bind('example.org', '/test', subdomain='blah') - assert adapter.build('index', {}) == 'http://example.org/test/' - assert adapter.build('foo', {}) == 'http://example.org/test/foo' - assert adapter.build('bar', {'baz': 'blub'}) == 'http://example.org/test/bar/blub' - assert adapter.build('bari', {'bazi': 50}) == 'http://example.org/test/bar/50' - assert adapter.build('barf', {'bazf': 0.815}) == 'http://example.org/test/bar/0.815' - assert adapter.build('barp', {'bazp': 'la/di'}) == 'http://example.org/test/bar/la/di' - assert adapter.build('blah', {}) == '/test/hehe' - - def test_defaults(self): - map = r.Map([ - r.Rule('/foo/', defaults={'page': 1}, endpoint='foo'), - r.Rule('/foo/', endpoint='foo') - ]) - adapter = map.bind('example.org', '/') - - assert adapter.match('/foo/') == ('foo', {'page': 1}) - self.assert_raises(r.RequestRedirect, lambda: adapter.match('/foo/1')) - assert adapter.match('/foo/2') == ('foo', {'page': 2}) - assert adapter.build('foo', {}) == '/foo/' - assert adapter.build('foo', {'page': 1}) == '/foo/' - assert adapter.build('foo', {'page': 2}) == '/foo/2' - - def test_greedy(self): - map = r.Map([ - r.Rule('/foo', endpoint='foo'), - r.Rule('/', endpoint='bar'), - r.Rule('//', endpoint='bar') - ]) - adapter = map.bind('example.org', '/') - - assert adapter.match('/foo') == ('foo', {}) - assert adapter.match('/blub') == ('bar', {'bar': 'blub'}) - assert adapter.match('/he/he') == ('bar', {'bar': 'he', 'blub': 'he'}) - - assert adapter.build('foo', {}) == '/foo' - assert adapter.build('bar', {'bar': 'blub'}) == '/blub' - assert adapter.build('bar', {'bar': 'blub', 'blub': 'bar'}) == '/blub/bar' - - def test_path(self): - map = r.Map([ - r.Rule('/', defaults={'name': 'FrontPage'}, endpoint='page'), - r.Rule('/Special', endpoint='special'), - r.Rule('/', endpoint='year'), - r.Rule('/', endpoint='page'), - r.Rule('//edit', endpoint='editpage'), - r.Rule('//silly/', endpoint='sillypage'), - r.Rule('//silly//edit', endpoint='editsillypage'), - r.Rule('/Talk:', endpoint='talk'), - r.Rule('/User:', endpoint='user'), - r.Rule('/User:/', endpoint='userpage'), - r.Rule('/Files/', endpoint='files'), - ]) - adapter = map.bind('example.org', '/') - - assert adapter.match('/') == ('page', {'name':'FrontPage'}) - self.assert_raises(r.RequestRedirect, lambda: adapter.match('/FrontPage')) - assert adapter.match('/Special') == ('special', {}) - assert adapter.match('/2007') == ('year', {'year':2007}) - assert adapter.match('/Some/Page') == ('page', {'name':'Some/Page'}) - assert adapter.match('/Some/Page/edit') == ('editpage', {'name':'Some/Page'}) - assert adapter.match('/Foo/silly/bar') == ('sillypage', {'name':'Foo', 'name2':'bar'}) - assert adapter.match('/Foo/silly/bar/edit') == ('editsillypage', {'name':'Foo', 'name2':'bar'}) - assert adapter.match('/Talk:Foo/Bar') == ('talk', {'name':'Foo/Bar'}) - assert adapter.match('/User:thomas') == ('user', {'username':'thomas'}) - assert adapter.match('/User:thomas/projects/werkzeug') == \ - ('userpage', {'username':'thomas', 'name':'projects/werkzeug'}) - assert adapter.match('/Files/downloads/werkzeug/0.2.zip') == \ - ('files', {'file':'downloads/werkzeug/0.2.zip'}) - - def test_dispatch(self): - env = create_environ('/') - map = r.Map([ - r.Rule('/', endpoint='root'), - r.Rule('/foo/', endpoint='foo') - ]) - adapter = map.bind_to_environ(env) - - raise_this = None - def view_func(endpoint, values): - if raise_this is not None: - raise raise_this - return Response(repr((endpoint, values))) - dispatch = lambda p, q=False: Response.force_type(adapter.dispatch(view_func, p, - catch_http_exceptions=q), env) - - assert dispatch('/').data == b"('root', {})" - assert dispatch('/foo').status_code == 301 - raise_this = r.NotFound() - self.assert_raises(r.NotFound, lambda: dispatch('/bar')) - assert dispatch('/bar', True).status_code == 404 - - def test_http_host_before_server_name(self): - env = { - 'HTTP_HOST': 'wiki.example.com', - 'SERVER_NAME': 'web0.example.com', - 'SERVER_PORT': '80', - 'SCRIPT_NAME': '', - 'PATH_INFO': '', - 'REQUEST_METHOD': 'GET', - 'wsgi.url_scheme': 'http' - } - map = r.Map([r.Rule('/', endpoint='index', subdomain='wiki')]) - adapter = map.bind_to_environ(env, server_name='example.com') - assert adapter.match('/') == ('index', {}) - assert adapter.build('index', force_external=True) == 'http://wiki.example.com/' - assert adapter.build('index') == '/' - - env['HTTP_HOST'] = 'admin.example.com' - adapter = map.bind_to_environ(env, server_name='example.com') - assert adapter.build('index') == 'http://wiki.example.com/' - - def test_adapter_url_parameter_sorting(self): - map = r.Map([r.Rule('/', endpoint='index')], sort_parameters=True, - sort_key=lambda x: x[1]) - adapter = map.bind('localhost', '/') - assert adapter.build('index', {'x': 20, 'y': 10, 'z': 30}, - force_external=True) == 'http://localhost/?y=10&x=20&z=30' - - def test_request_direct_charset_bug(self): - map = r.Map([r.Rule(u'/öäü/')]) - adapter = map.bind('localhost', '/') - try: - adapter.match(u'/öäü') - except r.RequestRedirect as e: - assert e.new_url == 'http://localhost/%C3%B6%C3%A4%C3%BC/' - else: - self.fail('expected request redirect exception') - - def test_request_redirect_default(self): - map = r.Map([r.Rule(u'/foo', defaults={'bar': 42}), - r.Rule(u'/foo/')]) - adapter = map.bind('localhost', '/') - try: - adapter.match(u'/foo/42') - except r.RequestRedirect as e: - assert e.new_url == 'http://localhost/foo' - else: - self.fail('expected request redirect exception') - - def test_request_redirect_default_subdomain(self): - map = r.Map([r.Rule(u'/foo', defaults={'bar': 42}, subdomain='test'), - r.Rule(u'/foo/', subdomain='other')]) - adapter = map.bind('localhost', '/', subdomain='other') - try: - adapter.match(u'/foo/42') - except r.RequestRedirect as e: - assert e.new_url == 'http://test.localhost/foo' - else: - self.fail('expected request redirect exception') - - def test_adapter_match_return_rule(self): - rule = r.Rule('/foo/', endpoint='foo') - map = r.Map([rule]) - adapter = map.bind('localhost', '/') - assert adapter.match('/foo/', return_rule=True) == (rule, {}) - - def test_server_name_interpolation(self): - server_name = 'example.invalid' - map = r.Map([r.Rule('/', endpoint='index'), - r.Rule('/', endpoint='alt', subdomain='alt')]) - - env = create_environ('/', 'http://%s/' % server_name) - adapter = map.bind_to_environ(env, server_name=server_name) - assert adapter.match() == ('index', {}) - - env = create_environ('/', 'http://alt.%s/' % server_name) - adapter = map.bind_to_environ(env, server_name=server_name) - assert adapter.match() == ('alt', {}) - - env = create_environ('/', 'http://%s/' % server_name) - adapter = map.bind_to_environ(env, server_name='foo') - assert adapter.subdomain == '' - - def test_rule_emptying(self): - rule = r.Rule('/foo', {'meh': 'muh'}, 'x', ['POST'], - False, 'x', True, None) - rule2 = rule.empty() - assert rule.__dict__ == rule2.__dict__ - rule.methods.add('GET') - assert rule.__dict__ != rule2.__dict__ - rule.methods.discard('GET') - rule.defaults['meh'] = 'aha' - assert rule.__dict__ != rule2.__dict__ - - def test_rule_templates(self): - testcase = r.RuleTemplate( - [ r.Submount('/test/$app', - [ r.Rule('/foo/', endpoint='handle_foo') - , r.Rule('/bar/', endpoint='handle_bar') - , r.Rule('/baz/', endpoint='handle_baz') - ]), - r.EndpointPrefix('${app}', - [ r.Rule('/${app}-blah', endpoint='bar') - , r.Rule('/${app}-meh', endpoint='baz') - ]), - r.Subdomain('$app', - [ r.Rule('/blah', endpoint='x_bar') - , r.Rule('/meh', endpoint='x_baz') - ]) - ]) - - url_map = r.Map( - [ testcase(app='test1') - , testcase(app='test2') - , testcase(app='test3') - , testcase(app='test4') - ]) - - out = sorted([(x.rule, x.subdomain, x.endpoint) - for x in url_map.iter_rules()]) - - assert out == ([ - ('/blah', 'test1', 'x_bar'), - ('/blah', 'test2', 'x_bar'), - ('/blah', 'test3', 'x_bar'), - ('/blah', 'test4', 'x_bar'), - ('/meh', 'test1', 'x_baz'), - ('/meh', 'test2', 'x_baz'), - ('/meh', 'test3', 'x_baz'), - ('/meh', 'test4', 'x_baz'), - ('/test/test1/bar/', '', 'handle_bar'), - ('/test/test1/baz/', '', 'handle_baz'), - ('/test/test1/foo/', '', 'handle_foo'), - ('/test/test2/bar/', '', 'handle_bar'), - ('/test/test2/baz/', '', 'handle_baz'), - ('/test/test2/foo/', '', 'handle_foo'), - ('/test/test3/bar/', '', 'handle_bar'), - ('/test/test3/baz/', '', 'handle_baz'), - ('/test/test3/foo/', '', 'handle_foo'), - ('/test/test4/bar/', '', 'handle_bar'), - ('/test/test4/baz/', '', 'handle_baz'), - ('/test/test4/foo/', '', 'handle_foo'), - ('/test1-blah', '', 'test1bar'), - ('/test1-meh', '', 'test1baz'), - ('/test2-blah', '', 'test2bar'), - ('/test2-meh', '', 'test2baz'), - ('/test3-blah', '', 'test3bar'), - ('/test3-meh', '', 'test3baz'), - ('/test4-blah', '', 'test4bar'), - ('/test4-meh', '', 'test4baz') - ]) - - def test_non_string_parts(self): - m = r.Map([ - r.Rule('/', endpoint='foo') - ]) - a = m.bind('example.com') - self.assert_equal(a.build('foo', {'foo': 42}), '/42') - - def test_complex_routing_rules(self): - m = r.Map([ - r.Rule('/', endpoint='index'), - r.Rule('/', endpoint='an_int'), - r.Rule('/', endpoint='a_string'), - r.Rule('/foo/', endpoint='nested'), - r.Rule('/foobar/', endpoint='nestedbar'), - r.Rule('/foo//', endpoint='nested_show'), - r.Rule('/foo//edit', endpoint='nested_edit'), - r.Rule('/users/', endpoint='users', defaults={'page': 1}), - r.Rule('/users/page/', endpoint='users'), - r.Rule('/foox', endpoint='foox'), - r.Rule('//', endpoint='barx_path_path') - ]) - a = m.bind('example.com') - - assert a.match('/') == ('index', {}) - assert a.match('/42') == ('an_int', {'blub': 42}) - assert a.match('/blub') == ('a_string', {'blub': 'blub'}) - assert a.match('/foo/') == ('nested', {}) - assert a.match('/foobar/') == ('nestedbar', {}) - assert a.match('/foo/1/2/3/') == ('nested_show', {'testing': '1/2/3'}) - assert a.match('/foo/1/2/3/edit') == ('nested_edit', {'testing': '1/2/3'}) - assert a.match('/users/') == ('users', {'page': 1}) - assert a.match('/users/page/2') == ('users', {'page': 2}) - assert a.match('/foox') == ('foox', {}) - assert a.match('/1/2/3') == ('barx_path_path', {'bar': '1', 'blub': '2/3'}) - - assert a.build('index') == '/' - assert a.build('an_int', {'blub': 42}) == '/42' - assert a.build('a_string', {'blub': 'test'}) == '/test' - assert a.build('nested') == '/foo/' - assert a.build('nestedbar') == '/foobar/' - assert a.build('nested_show', {'testing': '1/2/3'}) == '/foo/1/2/3/' - assert a.build('nested_edit', {'testing': '1/2/3'}) == '/foo/1/2/3/edit' - assert a.build('users', {'page': 1}) == '/users/' - assert a.build('users', {'page': 2}) == '/users/page/2' - assert a.build('foox') == '/foox' - assert a.build('barx_path_path', {'bar': '1', 'blub': '2/3'}) == '/1/2/3' - - def test_default_converters(self): - class MyMap(r.Map): - default_converters = r.Map.default_converters.copy() - default_converters['foo'] = r.UnicodeConverter - assert isinstance(r.Map.default_converters, ImmutableDict) - m = MyMap([ - r.Rule('/a/', endpoint='a'), - r.Rule('/b/', endpoint='b'), - r.Rule('/c/', endpoint='c') - ], converters={'bar': r.UnicodeConverter}) - a = m.bind('example.org', '/') - assert a.match('/a/1') == ('a', {'a': '1'}) - assert a.match('/b/2') == ('b', {'b': '2'}) - assert a.match('/c/3') == ('c', {'c': '3'}) - assert 'foo' not in r.Map.default_converters - - def test_build_append_unknown(self): - map = r.Map([ - r.Rule('/bar/', endpoint='barf') - ]) - adapter = map.bind('example.org', '/', subdomain='blah') - assert adapter.build('barf', {'bazf': 0.815, 'bif' : 1.0}) == \ - 'http://example.org/bar/0.815?bif=1.0' - assert adapter.build('barf', {'bazf': 0.815, 'bif' : 1.0}, - append_unknown=False) == 'http://example.org/bar/0.815' - - def test_method_fallback(self): - map = r.Map([ - r.Rule('/', endpoint='index', methods=['GET']), - r.Rule('/', endpoint='hello_name', methods=['GET']), - r.Rule('/select', endpoint='hello_select', methods=['POST']), - r.Rule('/search_get', endpoint='search', methods=['GET']), - r.Rule('/search_post', endpoint='search', methods=['POST']) - ]) - adapter = map.bind('example.com') - assert adapter.build('index') == '/' - assert adapter.build('index', method='GET') == '/' - assert adapter.build('hello_name', {'name': 'foo'}) == '/foo' - assert adapter.build('hello_select') == '/select' - assert adapter.build('hello_select', method='POST') == '/select' - assert adapter.build('search') == '/search_get' - assert adapter.build('search', method='GET') == '/search_get' - assert adapter.build('search', method='POST') == '/search_post' - - def test_implicit_head(self): - url_map = r.Map([ - r.Rule('/get', methods=['GET'], endpoint='a'), - r.Rule('/post', methods=['POST'], endpoint='b') - ]) - adapter = url_map.bind('example.org') - assert adapter.match('/get', method='HEAD') == ('a', {}) - self.assert_raises(r.MethodNotAllowed, adapter.match, - '/post', method='HEAD') - - def test_protocol_joining_bug(self): - m = r.Map([r.Rule('/', endpoint='x')]) - a = m.bind('example.org') - assert a.build('x', {'foo': 'x:y'}) == '/x:y' - assert a.build('x', {'foo': 'x:y'}, force_external=True) == \ - 'http://example.org/x:y' - - def test_allowed_methods_querying(self): - m = r.Map([r.Rule('/', methods=['GET', 'HEAD']), - r.Rule('/foo', methods=['POST'])]) - a = m.bind('example.org') - assert sorted(a.allowed_methods('/foo')) == ['GET', 'HEAD', 'POST'] - - def test_external_building_with_port(self): - map = r.Map([ - r.Rule('/', endpoint='index'), - ]) - adapter = map.bind('example.org:5000', '/') - built_url = adapter.build('index', {}, force_external=True) - assert built_url == 'http://example.org:5000/', built_url - - def test_external_building_with_port_bind_to_environ(self): - map = r.Map([ - r.Rule('/', endpoint='index'), - ]) - adapter = map.bind_to_environ( - create_environ('/', 'http://example.org:5000/'), - server_name="example.org:5000" - ) - built_url = adapter.build('index', {}, force_external=True) - assert built_url == 'http://example.org:5000/', built_url - - def test_external_building_with_port_bind_to_environ_wrong_servername(self): - map = r.Map([ - r.Rule('/', endpoint='index'), - ]) - environ = create_environ('/', 'http://example.org:5000/') - adapter = map.bind_to_environ(environ, server_name="example.org") - assert adapter.subdomain == '' - - def test_converter_parser(self): - args, kwargs = r.parse_converter_args(u'test, a=1, b=3.0') - - assert args == ('test',) - assert kwargs == {'a': 1, 'b': 3.0 } - - args, kwargs = r.parse_converter_args('') - assert not args and not kwargs - - args, kwargs = r.parse_converter_args('a, b, c,') - assert args == ('a', 'b', 'c') - assert not kwargs - - args, kwargs = r.parse_converter_args('True, False, None') - assert args == (True, False, None) - - args, kwargs = r.parse_converter_args('"foo", u"bar"') - assert args == ('foo', 'bar') - - def test_alias_redirects(self): - m = r.Map([ - r.Rule('/', endpoint='index'), - r.Rule('/index.html', endpoint='index', alias=True), - r.Rule('/users/', defaults={'page': 1}, endpoint='users'), - r.Rule('/users/index.html', defaults={'page': 1}, alias=True, - endpoint='users'), - r.Rule('/users/page/', endpoint='users'), - r.Rule('/users/page-.html', alias=True, endpoint='users'), - ]) - a = m.bind('example.com') - - def ensure_redirect(path, new_url, args=None): - try: - a.match(path, query_args=args) - except r.RequestRedirect as e: - assert e.new_url == 'http://example.com' + new_url - else: - assert False, 'expected redirect' - - ensure_redirect('/index.html', '/') - ensure_redirect('/users/index.html', '/users/') - ensure_redirect('/users/page-2.html', '/users/page/2') - ensure_redirect('/users/page-1.html', '/users/') - ensure_redirect('/users/page-1.html', '/users/?foo=bar', {'foo': 'bar'}) - - assert a.build('index') == '/' - assert a.build('users', {'page': 1}) == '/users/' - assert a.build('users', {'page': 2}) == '/users/page/2' - - def test_double_defaults(self): - for prefix in '', '/aaa': - m = r.Map([ - r.Rule(prefix + '/', defaults={'foo': 1, 'bar': False}, endpoint='x'), - r.Rule(prefix + '/', defaults={'bar': False}, endpoint='x'), - r.Rule(prefix + '/bar/', defaults={'foo': 1, 'bar': True}, endpoint='x'), - r.Rule(prefix + '/bar/', defaults={'bar': True}, endpoint='x') - ]) - a = m.bind('example.com') - - assert a.match(prefix + '/') == ('x', {'foo': 1, 'bar': False}) - assert a.match(prefix + '/2') == ('x', {'foo': 2, 'bar': False}) - assert a.match(prefix + '/bar/') == ('x', {'foo': 1, 'bar': True}) - assert a.match(prefix + '/bar/2') == ('x', {'foo': 2, 'bar': True}) - - assert a.build('x', {'foo': 1, 'bar': False}) == prefix + '/' - assert a.build('x', {'foo': 2, 'bar': False}) == prefix + '/2' - assert a.build('x', {'bar': False}) == prefix + '/' - assert a.build('x', {'foo': 1, 'bar': True}) == prefix + '/bar/' - assert a.build('x', {'foo': 2, 'bar': True}) == prefix + '/bar/2' - assert a.build('x', {'bar': True}) == prefix + '/bar/' - - def test_host_matching(self): - m = r.Map([ - r.Rule('/', endpoint='index', host='www.'), - r.Rule('/', endpoint='files', host='files.'), - r.Rule('/foo/', defaults={'page': 1}, host='www.', endpoint='x'), - r.Rule('/', host='files.', endpoint='x') - ], host_matching=True) - - a = m.bind('www.example.com') - assert a.match('/') == ('index', {'domain': 'example.com'}) - assert a.match('/foo/') == ('x', {'domain': 'example.com', 'page': 1}) - try: - a.match('/foo') - except r.RequestRedirect as e: - assert e.new_url == 'http://www.example.com/foo/' - else: - assert False, 'expected redirect' - - a = m.bind('files.example.com') - assert a.match('/') == ('files', {'domain': 'example.com'}) - assert a.match('/2') == ('x', {'domain': 'example.com', 'page': 2}) - try: - a.match('/1') - except r.RequestRedirect as e: - assert e.new_url == 'http://www.example.com/foo/' - else: - assert False, 'expected redirect' - - def test_server_name_casing(self): - m = r.Map([ - r.Rule('/', endpoint='index', subdomain='foo') - ]) - - env = create_environ() - env['SERVER_NAME'] = env['HTTP_HOST'] = 'FOO.EXAMPLE.COM' - a = m.bind_to_environ(env, server_name='example.com') - assert a.match('/') == ('index', {}) - - env = create_environ() - env['SERVER_NAME'] = '127.0.0.1' - env['SERVER_PORT'] = '5000' - del env['HTTP_HOST'] - a = m.bind_to_environ(env, server_name='example.com') - try: - a.match() - except r.NotFound: - pass - else: - assert False, 'Expected not found exception' - - def test_redirect_request_exception_code(self): - exc = r.RequestRedirect('http://www.google.com/') - exc.code = 307 - env = create_environ() - self.assert_strict_equal(exc.get_response(env).status_code, exc.code) - - def test_redirect_path_quoting(self): - url_map = r.Map([ - r.Rule('/', defaults={'page': 1}, endpoint='category'), - r.Rule('//page/', endpoint='category') - ]) - - adapter = url_map.bind('example.com') - try: - adapter.match('/foo bar/page/1') - except r.RequestRedirect as e: - response = e.get_response({}) - self.assert_strict_equal(response.headers['location'], - u'http://example.com/foo%20bar') - else: - self.fail('Expected redirect') - - def test_unicode_rules(self): - m = r.Map([ - r.Rule(u'/войти/', endpoint='enter'), - r.Rule(u'/foo+bar/', endpoint='foobar') - ]) - a = m.bind(u'☃.example.com') - try: - a.match(u'/войти') - except r.RequestRedirect as e: - self.assert_strict_equal(e.new_url, 'http://xn--n3h.example.com/' - '%D0%B2%D0%BE%D0%B9%D1%82%D0%B8/') - endpoint, values = a.match(u'/войти/') - self.assert_strict_equal(endpoint, 'enter') - self.assert_strict_equal(values, {}) - - try: - a.match(u'/foo+bar') - except r.RequestRedirect as e: - self.assert_strict_equal(e.new_url, 'http://xn--n3h.example.com/' - 'foo+bar/') - endpoint, values = a.match(u'/foo+bar/') - self.assert_strict_equal(endpoint, 'foobar') - self.assert_strict_equal(values, {}) - - url = a.build('enter', {}, force_external=True) - self.assert_strict_equal(url, 'http://xn--n3h.example.com/%D0%B2%D0%BE%D0%B9%D1%82%D0%B8/') - - url = a.build('foobar', {}, force_external=True) - self.assert_strict_equal(url, 'http://xn--n3h.example.com/foo+bar/') - - def test_map_repr(self): - m = r.Map([ - r.Rule(u'/wat', endpoint='enter'), - r.Rule(u'/woop', endpoint='foobar') - ]) - rv = repr(m) - self.assert_strict_equal(rv, - "Map([ foobar>, enter>])") - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(RoutingTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/security.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/security.py deleted file mode 100644 index 6ee2684e..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/security.py +++ /dev/null @@ -1,105 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.security - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Tests the security helpers. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import os -import unittest - -from werkzeug.testsuite import WerkzeugTestCase - -from werkzeug.security import check_password_hash, generate_password_hash, \ - safe_join, pbkdf2_hex, safe_str_cmp - - -class SecurityTestCase(WerkzeugTestCase): - - def test_safe_str_cmp(self): - assert safe_str_cmp('a', 'a') is True - assert safe_str_cmp(b'a', u'a') is True - assert safe_str_cmp('a', 'b') is False - assert safe_str_cmp(b'aaa', 'aa') is False - assert safe_str_cmp(b'aaa', 'bbb') is False - assert safe_str_cmp(b'aaa', u'aaa') is True - - def test_password_hashing(self): - hash0 = generate_password_hash('default') - assert check_password_hash(hash0, 'default') - assert hash0.startswith('pbkdf2:sha1:1000$') - - hash1 = generate_password_hash('default', 'sha1') - hash2 = generate_password_hash(u'default', method='sha1') - assert hash1 != hash2 - assert check_password_hash(hash1, 'default') - assert check_password_hash(hash2, 'default') - assert hash1.startswith('sha1$') - assert hash2.startswith('sha1$') - - fakehash = generate_password_hash('default', method='plain') - assert fakehash == 'plain$$default' - assert check_password_hash(fakehash, 'default') - - mhash = generate_password_hash(u'default', method='md5') - assert mhash.startswith('md5$') - assert check_password_hash(mhash, 'default') - - legacy = 'md5$$c21f969b5f03d33d43e04f8f136e7682' - assert check_password_hash(legacy, 'default') - - legacy = u'md5$$c21f969b5f03d33d43e04f8f136e7682' - assert check_password_hash(legacy, 'default') - - def test_safe_join(self): - assert safe_join('foo', 'bar/baz') == os.path.join('foo', 'bar/baz') - assert safe_join('foo', '../bar/baz') is None - if os.name == 'nt': - assert safe_join('foo', 'foo\\bar') is None - - def test_pbkdf2(self): - def check(data, salt, iterations, keylen, expected): - rv = pbkdf2_hex(data, salt, iterations, keylen) - self.assert_equal(rv, expected) - - # From RFC 6070 - check('password', 'salt', 1, None, - '0c60c80f961f0e71f3a9b524af6012062fe037a6') - check('password', 'salt', 1, 20, - '0c60c80f961f0e71f3a9b524af6012062fe037a6') - check('password', 'salt', 2, 20, - 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957') - check('password', 'salt', 4096, 20, - '4b007901b765489abead49d926f721d065a429c1') - check('passwordPASSWORDpassword', 'saltSALTsaltSALTsaltSALTsaltSALTsalt', - 4096, 25, '3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038') - check('pass\x00word', 'sa\x00lt', 4096, 16, - '56fa6aa75548099dcc37d7f03425e0c3') - # This one is from the RFC but it just takes for ages - ##check('password', 'salt', 16777216, 20, - ## 'eefe3d61cd4da4e4e9945b3d6ba2158c2634e984') - - # From Crypt-PBKDF2 - check('password', 'ATHENA.MIT.EDUraeburn', 1, 16, - 'cdedb5281bb2f801565a1122b2563515') - check('password', 'ATHENA.MIT.EDUraeburn', 1, 32, - 'cdedb5281bb2f801565a1122b25635150ad1f7a04bb9f3a333ecc0e2e1f70837') - check('password', 'ATHENA.MIT.EDUraeburn', 2, 16, - '01dbee7f4a9e243e988b62c73cda935d') - check('password', 'ATHENA.MIT.EDUraeburn', 2, 32, - '01dbee7f4a9e243e988b62c73cda935da05378b93244ec8f48a99e61ad799d86') - check('password', 'ATHENA.MIT.EDUraeburn', 1200, 32, - '5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddbc5e5142f708a31e2e62b1e13') - check('X' * 64, 'pass phrase equals block size', 1200, 32, - '139c30c0966bc32ba55fdbf212530ac9c5ec59f1a452f5cc9ad940fea0598ed1') - check('X' * 65, 'pass phrase exceeds block size', 1200, 32, - '9ccad6d468770cd51b10e6a68721be611a8b4d282601db3b36be9246915ec82a') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(SecurityTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/serving.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/serving.py deleted file mode 100644 index e478de26..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/serving.py +++ /dev/null @@ -1,117 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.serving - ~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Added serving tests. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import sys -import time -try: - import httplib -except ImportError: - from http import client as httplib -try: - from urllib2 import urlopen, HTTPError -except ImportError: # pragma: no cover - from urllib.request import urlopen - from urllib.error import HTTPError - -import unittest -from functools import update_wrapper - -from werkzeug.testsuite import WerkzeugTestCase - -from werkzeug import __version__ as version, serving -from werkzeug.testapp import test_app -from werkzeug._compat import StringIO -from threading import Thread - - - -real_make_server = serving.make_server - - -def silencestderr(f): - def new_func(*args, **kwargs): - old_stderr = sys.stderr - sys.stderr = StringIO() - try: - return f(*args, **kwargs) - finally: - sys.stderr = old_stderr - return update_wrapper(new_func, f) - - -def run_dev_server(application): - servers = [] - - def tracking_make_server(*args, **kwargs): - srv = real_make_server(*args, **kwargs) - servers.append(srv) - return srv - serving.make_server = tracking_make_server - try: - t = Thread(target=serving.run_simple, - args=('localhost', 0, application)) - t.setDaemon(True) - t.start() - time.sleep(0.25) - finally: - serving.make_server = real_make_server - if not servers: - return None, None - server, = servers - ip, port = server.socket.getsockname()[:2] - if ':' in ip: - ip = '[%s]' % ip - return server, '%s:%d' % (ip, port) - - -class ServingTestCase(WerkzeugTestCase): - - @silencestderr - def test_serving(self): - server, addr = run_dev_server(test_app) - rv = urlopen('http://%s/?foo=bar&baz=blah' % addr).read() - self.assert_in(b'WSGI Information', rv) - self.assert_in(b'foo=bar&baz=blah', rv) - self.assert_in(b'Werkzeug/' + version.encode('ascii'), rv) - - @silencestderr - def test_broken_app(self): - def broken_app(environ, start_response): - 1 // 0 - server, addr = run_dev_server(broken_app) - try: - urlopen('http://%s/?foo=bar&baz=blah' % addr).read() - except HTTPError as e: - # In Python3 a 500 response causes an exception - rv = e.read() - assert b'Internal Server Error' in rv - else: - assert False, 'expected internal server error' - - @silencestderr - def test_absolute_requests(self): - def asserting_app(environ, start_response): - assert environ['HTTP_HOST'] == 'surelynotexisting.example.com:1337' - assert environ['PATH_INFO'] == '/index.htm' - assert environ['SERVER_PORT'] == addr.split(':')[1] - start_response('200 OK', [('Content-Type', 'text/html')]) - return [b'YES'] - - server, addr = run_dev_server(asserting_app) - conn = httplib.HTTPConnection(addr) - conn.request('GET', 'http://surelynotexisting.example.com:1337/index.htm') - res = conn.getresponse() - assert res.read() == b'YES' - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ServingTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/test.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/test.py deleted file mode 100644 index ae151fb9..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/test.py +++ /dev/null @@ -1,444 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.test - ~~~~~~~~~~~~~~~~~~~~~~~ - - Tests the testing tools. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" - -from __future__ import with_statement - -import sys -import unittest -from io import BytesIO -from werkzeug._compat import iteritems, to_bytes - -from werkzeug.testsuite import WerkzeugTestCase - -from werkzeug.wrappers import Request, Response, BaseResponse -from werkzeug.test import Client, EnvironBuilder, create_environ, \ - ClientRedirectError, stream_encode_multipart, run_wsgi_app -from werkzeug.utils import redirect -from werkzeug.formparser import parse_form_data -from werkzeug.datastructures import MultiDict, FileStorage - - -def cookie_app(environ, start_response): - """A WSGI application which sets a cookie, and returns as a ersponse any - cookie which exists. - """ - response = Response(environ.get('HTTP_COOKIE', 'No Cookie'), - mimetype='text/plain') - response.set_cookie('test', 'test') - return response(environ, start_response) - - -def redirect_loop_app(environ, start_response): - response = redirect('http://localhost/some/redirect/') - return response(environ, start_response) - - -def redirect_with_get_app(environ, start_response): - req = Request(environ) - if req.url not in ('http://localhost/', - 'http://localhost/first/request', - 'http://localhost/some/redirect/'): - assert False, 'redirect_demo_app() did not expect URL "%s"' % req.url - if '/some/redirect' not in req.url: - response = redirect('http://localhost/some/redirect/') - else: - response = Response('current url: %s' % req.url) - return response(environ, start_response) - - -def redirect_with_post_app(environ, start_response): - req = Request(environ) - if req.url == 'http://localhost/some/redirect/': - assert req.method == 'GET', 'request should be GET' - assert not req.form, 'request should not have data' - response = Response('current url: %s' % req.url) - else: - response = redirect('http://localhost/some/redirect/') - return response(environ, start_response) - - -def external_redirect_demo_app(environ, start_response): - response = redirect('http://example.com/') - return response(environ, start_response) - - -def external_subdomain_redirect_demo_app(environ, start_response): - if 'test.example.com' in environ['HTTP_HOST']: - response = Response('redirected successfully to subdomain') - else: - response = redirect('http://test.example.com/login') - return response(environ, start_response) - - -def multi_value_post_app(environ, start_response): - req = Request(environ) - assert req.form['field'] == 'val1', req.form['field'] - assert req.form.getlist('field') == ['val1', 'val2'], req.form.getlist('field') - response = Response('ok') - return response(environ, start_response) - - -class TestTestCase(WerkzeugTestCase): - - def test_cookie_forging(self): - c = Client(cookie_app) - c.set_cookie('localhost', 'foo', 'bar') - appiter, code, headers = c.open() - self.assert_strict_equal(list(appiter), [b'foo=bar']) - - def test_set_cookie_app(self): - c = Client(cookie_app) - appiter, code, headers = c.open() - self.assert_in('Set-Cookie', dict(headers)) - - def test_cookiejar_stores_cookie(self): - c = Client(cookie_app) - appiter, code, headers = c.open() - self.assert_in('test', c.cookie_jar._cookies['localhost.local']['/']) - - def test_no_initial_cookie(self): - c = Client(cookie_app) - appiter, code, headers = c.open() - self.assert_strict_equal(b''.join(appiter), b'No Cookie') - - def test_resent_cookie(self): - c = Client(cookie_app) - c.open() - appiter, code, headers = c.open() - self.assert_strict_equal(b''.join(appiter), b'test=test') - - def test_disable_cookies(self): - c = Client(cookie_app, use_cookies=False) - c.open() - appiter, code, headers = c.open() - self.assert_strict_equal(b''.join(appiter), b'No Cookie') - - def test_cookie_for_different_path(self): - c = Client(cookie_app) - c.open('/path1') - appiter, code, headers = c.open('/path2') - self.assert_strict_equal(b''.join(appiter), b'test=test') - - def test_environ_builder_basics(self): - b = EnvironBuilder() - self.assert_is_none(b.content_type) - b.method = 'POST' - self.assert_equal(b.content_type, 'application/x-www-form-urlencoded') - b.files.add_file('test', BytesIO(b'test contents'), 'test.txt') - self.assert_equal(b.files['test'].content_type, 'text/plain') - self.assert_equal(b.content_type, 'multipart/form-data') - b.form['test'] = 'normal value' - - req = b.get_request() - b.close() - - self.assert_strict_equal(req.url, u'http://localhost/') - self.assert_strict_equal(req.method, 'POST') - self.assert_strict_equal(req.form['test'], u'normal value') - self.assert_equal(req.files['test'].content_type, 'text/plain') - self.assert_strict_equal(req.files['test'].filename, u'test.txt') - self.assert_strict_equal(req.files['test'].read(), b'test contents') - - def test_environ_builder_headers(self): - b = EnvironBuilder(environ_base={'HTTP_USER_AGENT': 'Foo/0.1'}, - environ_overrides={'wsgi.version': (1, 1)}) - b.headers['X-Suck-My-Dick'] = 'very well sir' - env = b.get_environ() - self.assert_strict_equal(env['HTTP_USER_AGENT'], 'Foo/0.1') - self.assert_strict_equal(env['HTTP_X_SUCK_MY_DICK'], 'very well sir') - self.assert_strict_equal(env['wsgi.version'], (1, 1)) - - b.headers['User-Agent'] = 'Bar/1.0' - env = b.get_environ() - self.assert_strict_equal(env['HTTP_USER_AGENT'], 'Bar/1.0') - - def test_environ_builder_headers_content_type(self): - b = EnvironBuilder(headers={'Content-Type': 'text/plain'}) - env = b.get_environ() - self.assert_equal(env['CONTENT_TYPE'], 'text/plain') - b = EnvironBuilder(content_type='text/html', - headers={'Content-Type': 'text/plain'}) - env = b.get_environ() - self.assert_equal(env['CONTENT_TYPE'], 'text/html') - - def test_environ_builder_paths(self): - b = EnvironBuilder(path='/foo', base_url='http://example.com/') - self.assert_strict_equal(b.base_url, 'http://example.com/') - self.assert_strict_equal(b.path, '/foo') - self.assert_strict_equal(b.script_root, '') - self.assert_strict_equal(b.host, 'example.com') - - b = EnvironBuilder(path='/foo', base_url='http://example.com/bar') - self.assert_strict_equal(b.base_url, 'http://example.com/bar/') - self.assert_strict_equal(b.path, '/foo') - self.assert_strict_equal(b.script_root, '/bar') - self.assert_strict_equal(b.host, 'example.com') - - b.host = 'localhost' - self.assert_strict_equal(b.base_url, 'http://localhost/bar/') - b.base_url = 'http://localhost:8080/' - self.assert_strict_equal(b.host, 'localhost:8080') - self.assert_strict_equal(b.server_name, 'localhost') - self.assert_strict_equal(b.server_port, 8080) - - b.host = 'foo.invalid' - b.url_scheme = 'https' - b.script_root = '/test' - env = b.get_environ() - self.assert_strict_equal(env['SERVER_NAME'], 'foo.invalid') - self.assert_strict_equal(env['SERVER_PORT'], '443') - self.assert_strict_equal(env['SCRIPT_NAME'], '/test') - self.assert_strict_equal(env['PATH_INFO'], '/foo') - self.assert_strict_equal(env['HTTP_HOST'], 'foo.invalid') - self.assert_strict_equal(env['wsgi.url_scheme'], 'https') - self.assert_strict_equal(b.base_url, 'https://foo.invalid/test/') - - def test_environ_builder_content_type(self): - builder = EnvironBuilder() - self.assert_is_none(builder.content_type) - builder.method = 'POST' - self.assert_equal(builder.content_type, 'application/x-www-form-urlencoded') - builder.form['foo'] = 'bar' - self.assert_equal(builder.content_type, 'application/x-www-form-urlencoded') - builder.files.add_file('blafasel', BytesIO(b'foo'), 'test.txt') - self.assert_equal(builder.content_type, 'multipart/form-data') - req = builder.get_request() - self.assert_strict_equal(req.form['foo'], u'bar') - self.assert_strict_equal(req.files['blafasel'].read(), b'foo') - - def test_environ_builder_stream_switch(self): - d = MultiDict(dict(foo=u'bar', blub=u'blah', hu=u'hum')) - for use_tempfile in False, True: - stream, length, boundary = stream_encode_multipart( - d, use_tempfile, threshold=150) - self.assert_true(isinstance(stream, BytesIO) != use_tempfile) - - form = parse_form_data({'wsgi.input': stream, 'CONTENT_LENGTH': str(length), - 'CONTENT_TYPE': 'multipart/form-data; boundary="%s"' % - boundary})[1] - self.assert_strict_equal(form, d) - stream.close() - - def test_environ_builder_unicode_file_mix(self): - for use_tempfile in False, True: - f = FileStorage(BytesIO(u'\N{SNOWMAN}'.encode('utf-8')), - 'snowman.txt') - d = MultiDict(dict(f=f, s=u'\N{SNOWMAN}')) - stream, length, boundary = stream_encode_multipart( - d, use_tempfile, threshold=150) - self.assert_true(isinstance(stream, BytesIO) != use_tempfile) - - _, form, files = parse_form_data({ - 'wsgi.input': stream, - 'CONTENT_LENGTH': str(length), - 'CONTENT_TYPE': 'multipart/form-data; boundary="%s"' % - boundary - }) - self.assert_strict_equal(form['s'], u'\N{SNOWMAN}') - self.assert_strict_equal(files['f'].name, 'f') - self.assert_strict_equal(files['f'].filename, u'snowman.txt') - self.assert_strict_equal(files['f'].read(), - u'\N{SNOWMAN}'.encode('utf-8')) - stream.close() - - def test_create_environ(self): - env = create_environ('/foo?bar=baz', 'http://example.org/') - expected = { - 'wsgi.multiprocess': False, - 'wsgi.version': (1, 0), - 'wsgi.run_once': False, - 'wsgi.errors': sys.stderr, - 'wsgi.multithread': False, - 'wsgi.url_scheme': 'http', - 'SCRIPT_NAME': '', - 'CONTENT_TYPE': '', - 'CONTENT_LENGTH': '0', - 'SERVER_NAME': 'example.org', - 'REQUEST_METHOD': 'GET', - 'HTTP_HOST': 'example.org', - 'PATH_INFO': '/foo', - 'SERVER_PORT': '80', - 'SERVER_PROTOCOL': 'HTTP/1.1', - 'QUERY_STRING': 'bar=baz' - } - for key, value in iteritems(expected): - self.assert_equal(env[key], value) - self.assert_strict_equal(env['wsgi.input'].read(0), b'') - self.assert_strict_equal(create_environ('/foo', 'http://example.com/')['SCRIPT_NAME'], '') - - def test_file_closing(self): - closed = [] - class SpecialInput(object): - def read(self): - return '' - def close(self): - closed.append(self) - - env = create_environ(data={'foo': SpecialInput()}) - self.assert_strict_equal(len(closed), 1) - builder = EnvironBuilder() - builder.files.add_file('blah', SpecialInput()) - builder.close() - self.assert_strict_equal(len(closed), 2) - - def test_follow_redirect(self): - env = create_environ('/', base_url='http://localhost') - c = Client(redirect_with_get_app) - appiter, code, headers = c.open(environ_overrides=env, follow_redirects=True) - self.assert_strict_equal(code, '200 OK') - self.assert_strict_equal(b''.join(appiter), b'current url: http://localhost/some/redirect/') - - # Test that the :cls:`Client` is aware of user defined response wrappers - c = Client(redirect_with_get_app, response_wrapper=BaseResponse) - resp = c.get('/', follow_redirects=True) - self.assert_strict_equal(resp.status_code, 200) - self.assert_strict_equal(resp.data, b'current url: http://localhost/some/redirect/') - - # test with URL other than '/' to make sure redirected URL's are correct - c = Client(redirect_with_get_app, response_wrapper=BaseResponse) - resp = c.get('/first/request', follow_redirects=True) - self.assert_strict_equal(resp.status_code, 200) - self.assert_strict_equal(resp.data, b'current url: http://localhost/some/redirect/') - - def test_follow_external_redirect(self): - env = create_environ('/', base_url='http://localhost') - c = Client(external_redirect_demo_app) - self.assert_raises(RuntimeError, lambda: - c.get(environ_overrides=env, follow_redirects=True)) - - def test_follow_external_redirect_on_same_subdomain(self): - env = create_environ('/', base_url='http://example.com') - c = Client(external_subdomain_redirect_demo_app, allow_subdomain_redirects=True) - c.get(environ_overrides=env, follow_redirects=True) - - # check that this does not work for real external domains - env = create_environ('/', base_url='http://localhost') - self.assert_raises(RuntimeError, lambda: - c.get(environ_overrides=env, follow_redirects=True)) - - # check that subdomain redirects fail if no `allow_subdomain_redirects` is applied - c = Client(external_subdomain_redirect_demo_app) - self.assert_raises(RuntimeError, lambda: - c.get(environ_overrides=env, follow_redirects=True)) - - def test_follow_redirect_loop(self): - c = Client(redirect_loop_app, response_wrapper=BaseResponse) - with self.assert_raises(ClientRedirectError): - resp = c.get('/', follow_redirects=True) - - def test_follow_redirect_with_post(self): - c = Client(redirect_with_post_app, response_wrapper=BaseResponse) - resp = c.post('/', follow_redirects=True, data='foo=blub+hehe&blah=42') - self.assert_strict_equal(resp.status_code, 200) - self.assert_strict_equal(resp.data, b'current url: http://localhost/some/redirect/') - - def test_path_info_script_name_unquoting(self): - def test_app(environ, start_response): - start_response('200 OK', [('Content-Type', 'text/plain')]) - return [environ['PATH_INFO'] + '\n' + environ['SCRIPT_NAME']] - c = Client(test_app, response_wrapper=BaseResponse) - resp = c.get('/foo%40bar') - self.assert_strict_equal(resp.data, b'/foo@bar\n') - c = Client(test_app, response_wrapper=BaseResponse) - resp = c.get('/foo%40bar', 'http://localhost/bar%40baz') - self.assert_strict_equal(resp.data, b'/foo@bar\n/bar@baz') - - def test_multi_value_submit(self): - c = Client(multi_value_post_app, response_wrapper=BaseResponse) - data = { - 'field': ['val1','val2'] - } - resp = c.post('/', data=data) - self.assert_strict_equal(resp.status_code, 200) - c = Client(multi_value_post_app, response_wrapper=BaseResponse) - data = MultiDict({ - 'field': ['val1', 'val2'] - }) - resp = c.post('/', data=data) - self.assert_strict_equal(resp.status_code, 200) - - def test_iri_support(self): - b = EnvironBuilder(u'/föö-bar', base_url=u'http://☃.net/') - self.assert_strict_equal(b.path, '/f%C3%B6%C3%B6-bar') - self.assert_strict_equal(b.base_url, 'http://xn--n3h.net/') - - def test_run_wsgi_apps(self): - def simple_app(environ, start_response): - start_response('200 OK', [('Content-Type', 'text/html')]) - return ['Hello World!'] - app_iter, status, headers = run_wsgi_app(simple_app, {}) - self.assert_strict_equal(status, '200 OK') - self.assert_strict_equal(list(headers), [('Content-Type', 'text/html')]) - self.assert_strict_equal(app_iter, ['Hello World!']) - - def yielding_app(environ, start_response): - start_response('200 OK', [('Content-Type', 'text/html')]) - yield 'Hello ' - yield 'World!' - app_iter, status, headers = run_wsgi_app(yielding_app, {}) - self.assert_strict_equal(status, '200 OK') - self.assert_strict_equal(list(headers), [('Content-Type', 'text/html')]) - self.assert_strict_equal(list(app_iter), ['Hello ', 'World!']) - - def test_multiple_cookies(self): - @Request.application - def test_app(request): - response = Response(repr(sorted(request.cookies.items()))) - response.set_cookie(u'test1', b'foo') - response.set_cookie(u'test2', b'bar') - return response - client = Client(test_app, Response) - resp = client.get('/') - self.assert_strict_equal(resp.data, b'[]') - resp = client.get('/') - self.assert_strict_equal(resp.data, - to_bytes(repr([('test1', u'foo'), ('test2', u'bar')]), 'ascii')) - - def test_correct_open_invocation_on_redirect(self): - class MyClient(Client): - counter = 0 - def open(self, *args, **kwargs): - self.counter += 1 - env = kwargs.setdefault('environ_overrides', {}) - env['werkzeug._foo'] = self.counter - return Client.open(self, *args, **kwargs) - - @Request.application - def test_app(request): - return Response(str(request.environ['werkzeug._foo'])) - - c = MyClient(test_app, response_wrapper=Response) - self.assert_strict_equal(c.get('/').data, b'1') - self.assert_strict_equal(c.get('/').data, b'2') - self.assert_strict_equal(c.get('/').data, b'3') - - def test_correct_encoding(self): - req = Request.from_values(u'/\N{SNOWMAN}', u'http://example.com/foo') - self.assert_strict_equal(req.script_root, u'/foo') - self.assert_strict_equal(req.path, u'/\N{SNOWMAN}') - - def test_full_url_requests_with_args(self): - base = 'http://example.com/' - - @Request.application - def test_app(request): - return Response(request.args['x']) - client = Client(test_app, Response) - resp = client.get('/?x=42', base) - self.assert_strict_equal(resp.data, b'42') - resp = client.get('http://www.example.com/?x=23', base) - self.assert_strict_equal(resp.data, b'23') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TestTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/urls.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/urls.py deleted file mode 100644 index 300fef10..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/urls.py +++ /dev/null @@ -1,322 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.urls - ~~~~~~~~~~~~~~~~~~~~~~~ - - URL helper tests. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from werkzeug.testsuite import WerkzeugTestCase - -from werkzeug.datastructures import OrderedMultiDict -from werkzeug import urls -from werkzeug._compat import text_type, NativeStringIO, BytesIO - - -class URLsTestCase(WerkzeugTestCase): - - def test_replace(self): - url = urls.url_parse('http://de.wikipedia.org/wiki/Troll') - self.assert_strict_equal(url.replace(query='foo=bar'), - urls.url_parse('http://de.wikipedia.org/wiki/Troll?foo=bar')) - self.assert_strict_equal(url.replace(scheme='https'), - urls.url_parse('https://de.wikipedia.org/wiki/Troll')) - - def test_quoting(self): - self.assert_strict_equal(urls.url_quote(u'\xf6\xe4\xfc'), '%C3%B6%C3%A4%C3%BC') - self.assert_strict_equal(urls.url_unquote(urls.url_quote(u'#%="\xf6')), u'#%="\xf6') - self.assert_strict_equal(urls.url_quote_plus('foo bar'), 'foo+bar') - self.assert_strict_equal(urls.url_unquote_plus('foo+bar'), u'foo bar') - self.assert_strict_equal(urls.url_quote_plus('foo+bar'), 'foo%2Bbar') - self.assert_strict_equal(urls.url_unquote_plus('foo%2Bbar'), u'foo+bar') - self.assert_strict_equal(urls.url_encode({b'a': None, b'b': b'foo bar'}), 'b=foo+bar') - self.assert_strict_equal(urls.url_encode({u'a': None, u'b': u'foo bar'}), 'b=foo+bar') - self.assert_strict_equal(urls.url_fix(u'http://de.wikipedia.org/wiki/Elf (Begriffsklärung)'), - 'http://de.wikipedia.org/wiki/Elf%20(Begriffskl%C3%A4rung)') - self.assert_strict_equal(urls.url_quote_plus(42), '42') - self.assert_strict_equal(urls.url_quote(b'\xff'), '%FF') - - def test_bytes_unquoting(self): - self.assert_strict_equal(urls.url_unquote(urls.url_quote( - u'#%="\xf6', charset='latin1'), charset=None), b'#%="\xf6') - - def test_url_decoding(self): - x = urls.url_decode(b'foo=42&bar=23&uni=H%C3%A4nsel') - self.assert_strict_equal(x['foo'], u'42') - self.assert_strict_equal(x['bar'], u'23') - self.assert_strict_equal(x['uni'], u'Hänsel') - - x = urls.url_decode(b'foo=42;bar=23;uni=H%C3%A4nsel', separator=b';') - self.assert_strict_equal(x['foo'], u'42') - self.assert_strict_equal(x['bar'], u'23') - self.assert_strict_equal(x['uni'], u'Hänsel') - - x = urls.url_decode(b'%C3%9Ch=H%C3%A4nsel', decode_keys=True) - self.assert_strict_equal(x[u'Üh'], u'Hänsel') - - def test_url_bytes_decoding(self): - x = urls.url_decode(b'foo=42&bar=23&uni=H%C3%A4nsel', charset=None) - self.assert_strict_equal(x[b'foo'], b'42') - self.assert_strict_equal(x[b'bar'], b'23') - self.assert_strict_equal(x[b'uni'], u'Hänsel'.encode('utf-8')) - - def test_streamed_url_decoding(self): - item1 = u'a' * 100000 - item2 = u'b' * 400 - string = ('a=%s&b=%s&c=%s' % (item1, item2, item2)).encode('ascii') - gen = urls.url_decode_stream(BytesIO(string), limit=len(string), - return_iterator=True) - self.assert_strict_equal(next(gen), ('a', item1)) - self.assert_strict_equal(next(gen), ('b', item2)) - self.assert_strict_equal(next(gen), ('c', item2)) - self.assert_raises(StopIteration, lambda: next(gen)) - - def test_stream_decoding_string_fails(self): - self.assert_raises(TypeError, urls.url_decode_stream, 'testing') - - def test_url_encoding(self): - self.assert_strict_equal(urls.url_encode({'foo': 'bar 45'}), 'foo=bar+45') - d = {'foo': 1, 'bar': 23, 'blah': u'Hänsel'} - self.assert_strict_equal(urls.url_encode(d, sort=True), 'bar=23&blah=H%C3%A4nsel&foo=1') - self.assert_strict_equal(urls.url_encode(d, sort=True, separator=u';'), 'bar=23;blah=H%C3%A4nsel;foo=1') - - def test_sorted_url_encode(self): - self.assert_strict_equal(urls.url_encode({u"a": 42, u"b": 23, 1: 1, 2: 2}, - sort=True, key=lambda i: text_type(i[0])), '1=1&2=2&a=42&b=23') - self.assert_strict_equal(urls.url_encode({u'A': 1, u'a': 2, u'B': 3, 'b': 4}, sort=True, - key=lambda x: x[0].lower() + x[0]), 'A=1&a=2&B=3&b=4') - - def test_streamed_url_encoding(self): - out = NativeStringIO() - urls.url_encode_stream({'foo': 'bar 45'}, out) - self.assert_strict_equal(out.getvalue(), 'foo=bar+45') - - d = {'foo': 1, 'bar': 23, 'blah': u'Hänsel'} - out = NativeStringIO() - urls.url_encode_stream(d, out, sort=True) - self.assert_strict_equal(out.getvalue(), 'bar=23&blah=H%C3%A4nsel&foo=1') - out = NativeStringIO() - urls.url_encode_stream(d, out, sort=True, separator=u';') - self.assert_strict_equal(out.getvalue(), 'bar=23;blah=H%C3%A4nsel;foo=1') - - gen = urls.url_encode_stream(d, sort=True) - self.assert_strict_equal(next(gen), 'bar=23') - self.assert_strict_equal(next(gen), 'blah=H%C3%A4nsel') - self.assert_strict_equal(next(gen), 'foo=1') - self.assert_raises(StopIteration, lambda: next(gen)) - - def test_url_fixing(self): - x = urls.url_fix(u'http://de.wikipedia.org/wiki/Elf (Begriffskl\xe4rung)') - self.assert_line_equal(x, 'http://de.wikipedia.org/wiki/Elf%20(Begriffskl%C3%A4rung)') - - x = urls.url_fix("http://just.a.test/$-_.+!*'(),") - self.assert_equal(x, "http://just.a.test/$-_.+!*'(),") - - def test_url_fixing_qs(self): - x = urls.url_fix(b'http://example.com/?foo=%2f%2f') - self.assert_line_equal(x, 'http://example.com/?foo=%2f%2f') - - x = urls.url_fix('http://acronyms.thefreedictionary.com/Algebraic+Methods+of+Solving+the+Schr%C3%B6dinger+Equation') - self.assert_equal(x, 'http://acronyms.thefreedictionary.com/Algebraic+Methods+of+Solving+the+Schr%C3%B6dinger+Equation') - - def test_iri_support(self): - self.assert_strict_equal(urls.uri_to_iri('http://xn--n3h.net/'), - u'http://\u2603.net/') - self.assert_strict_equal( - urls.uri_to_iri(b'http://%C3%BCser:p%C3%A4ssword@xn--n3h.net/p%C3%A5th'), - u'http://\xfcser:p\xe4ssword@\u2603.net/p\xe5th') - self.assert_strict_equal(urls.iri_to_uri(u'http://☃.net/'), 'http://xn--n3h.net/') - self.assert_strict_equal( - urls.iri_to_uri(u'http://üser:pässword@☃.net/påth'), - 'http://%C3%BCser:p%C3%A4ssword@xn--n3h.net/p%C3%A5th') - - self.assert_strict_equal(urls.uri_to_iri('http://test.com/%3Fmeh?foo=%26%2F'), - u'http://test.com/%3Fmeh?foo=%26%2F') - - # this should work as well, might break on 2.4 because of a broken - # idna codec - self.assert_strict_equal(urls.uri_to_iri(b'/foo'), u'/foo') - self.assert_strict_equal(urls.iri_to_uri(u'/foo'), '/foo') - - self.assert_strict_equal(urls.iri_to_uri(u'http://föö.com:8080/bam/baz'), - 'http://xn--f-1gaa.com:8080/bam/baz') - - def test_iri_safe_conversion(self): - self.assert_strict_equal(urls.iri_to_uri(u'magnet:?foo=bar'), - 'magnet:?foo=bar') - self.assert_strict_equal(urls.iri_to_uri(u'itms-service://?foo=bar'), - 'itms-service:?foo=bar') - self.assert_strict_equal(urls.iri_to_uri(u'itms-service://?foo=bar', - safe_conversion=True), - 'itms-service://?foo=bar') - - def test_iri_safe_quoting(self): - uri = 'http://xn--f-1gaa.com/%2F%25?q=%C3%B6&x=%3D%25#%25' - iri = u'http://föö.com/%2F%25?q=ö&x=%3D%25#%25' - self.assert_strict_equal(urls.uri_to_iri(uri), iri) - self.assert_strict_equal(urls.iri_to_uri(urls.uri_to_iri(uri)), uri) - - def test_ordered_multidict_encoding(self): - d = OrderedMultiDict() - d.add('foo', 1) - d.add('foo', 2) - d.add('foo', 3) - d.add('bar', 0) - d.add('foo', 4) - self.assert_equal(urls.url_encode(d), 'foo=1&foo=2&foo=3&bar=0&foo=4') - - def test_multidict_encoding(self): - d = OrderedMultiDict() - d.add('2013-10-10T23:26:05.657975+0000', '2013-10-10T23:26:05.657975+0000') - self.assert_equal(urls.url_encode(d), '2013-10-10T23%3A26%3A05.657975%2B0000=2013-10-10T23%3A26%3A05.657975%2B0000') - - def test_href(self): - x = urls.Href('http://www.example.com/') - self.assert_strict_equal(x(u'foo'), 'http://www.example.com/foo') - self.assert_strict_equal(x.foo(u'bar'), 'http://www.example.com/foo/bar') - self.assert_strict_equal(x.foo(u'bar', x=42), 'http://www.example.com/foo/bar?x=42') - self.assert_strict_equal(x.foo(u'bar', class_=42), 'http://www.example.com/foo/bar?class=42') - self.assert_strict_equal(x.foo(u'bar', {u'class': 42}), 'http://www.example.com/foo/bar?class=42') - self.assert_raises(AttributeError, lambda: x.__blah__) - - x = urls.Href('blah') - self.assert_strict_equal(x.foo(u'bar'), 'blah/foo/bar') - - self.assert_raises(TypeError, x.foo, {u"foo": 23}, x=42) - - x = urls.Href('') - self.assert_strict_equal(x('foo'), 'foo') - - def test_href_url_join(self): - x = urls.Href(u'test') - self.assert_line_equal(x(u'foo:bar'), u'test/foo:bar') - self.assert_line_equal(x(u'http://example.com/'), u'test/http://example.com/') - self.assert_line_equal(x.a(), u'test/a') - - def test_href_past_root(self): - base_href = urls.Href('http://www.blagga.com/1/2/3') - self.assert_strict_equal(base_href('../foo'), 'http://www.blagga.com/1/2/foo') - self.assert_strict_equal(base_href('../../foo'), 'http://www.blagga.com/1/foo') - self.assert_strict_equal(base_href('../../../foo'), 'http://www.blagga.com/foo') - self.assert_strict_equal(base_href('../../../../foo'), 'http://www.blagga.com/foo') - self.assert_strict_equal(base_href('../../../../../foo'), 'http://www.blagga.com/foo') - self.assert_strict_equal(base_href('../../../../../../foo'), 'http://www.blagga.com/foo') - - def test_url_unquote_plus_unicode(self): - # was broken in 0.6 - self.assert_strict_equal(urls.url_unquote_plus(u'\x6d'), u'\x6d') - self.assert_is(type(urls.url_unquote_plus(u'\x6d')), text_type) - - def test_quoting_of_local_urls(self): - rv = urls.iri_to_uri(u'/foo\x8f') - self.assert_strict_equal(rv, '/foo%C2%8F') - self.assert_is(type(rv), str) - - def test_url_attributes(self): - rv = urls.url_parse('http://foo%3a:bar%3a@[::1]:80/123?x=y#frag') - self.assert_strict_equal(rv.scheme, 'http') - self.assert_strict_equal(rv.auth, 'foo%3a:bar%3a') - self.assert_strict_equal(rv.username, u'foo:') - self.assert_strict_equal(rv.password, u'bar:') - self.assert_strict_equal(rv.raw_username, 'foo%3a') - self.assert_strict_equal(rv.raw_password, 'bar%3a') - self.assert_strict_equal(rv.host, '::1') - self.assert_equal(rv.port, 80) - self.assert_strict_equal(rv.path, '/123') - self.assert_strict_equal(rv.query, 'x=y') - self.assert_strict_equal(rv.fragment, 'frag') - - rv = urls.url_parse(u'http://\N{SNOWMAN}.com/') - self.assert_strict_equal(rv.host, u'\N{SNOWMAN}.com') - self.assert_strict_equal(rv.ascii_host, 'xn--n3h.com') - - def test_url_attributes_bytes(self): - rv = urls.url_parse(b'http://foo%3a:bar%3a@[::1]:80/123?x=y#frag') - self.assert_strict_equal(rv.scheme, b'http') - self.assert_strict_equal(rv.auth, b'foo%3a:bar%3a') - self.assert_strict_equal(rv.username, u'foo:') - self.assert_strict_equal(rv.password, u'bar:') - self.assert_strict_equal(rv.raw_username, b'foo%3a') - self.assert_strict_equal(rv.raw_password, b'bar%3a') - self.assert_strict_equal(rv.host, b'::1') - self.assert_equal(rv.port, 80) - self.assert_strict_equal(rv.path, b'/123') - self.assert_strict_equal(rv.query, b'x=y') - self.assert_strict_equal(rv.fragment, b'frag') - - def test_url_joining(self): - self.assert_strict_equal(urls.url_join('/foo', '/bar'), '/bar') - self.assert_strict_equal(urls.url_join('http://example.com/foo', '/bar'), - 'http://example.com/bar') - self.assert_strict_equal(urls.url_join('file:///tmp/', 'test.html'), - 'file:///tmp/test.html') - self.assert_strict_equal(urls.url_join('file:///tmp/x', 'test.html'), - 'file:///tmp/test.html') - self.assert_strict_equal(urls.url_join('file:///tmp/x', '../../../x.html'), - 'file:///x.html') - - def test_partial_unencoded_decode(self): - ref = u'foo=정상처리'.encode('euc-kr') - x = urls.url_decode(ref, charset='euc-kr') - self.assert_strict_equal(x['foo'], u'정상처리') - - def test_iri_to_uri_idempotence_ascii_only(self): - uri = u'http://www.idempoten.ce' - uri = urls.iri_to_uri(uri) - self.assert_equal(urls.iri_to_uri(uri), uri) - - def test_iri_to_uri_idempotence_non_ascii(self): - uri = u'http://\N{SNOWMAN}/\N{SNOWMAN}' - uri = urls.iri_to_uri(uri) - self.assert_equal(urls.iri_to_uri(uri), uri) - - def test_uri_to_iri_idempotence_ascii_only(self): - uri = 'http://www.idempoten.ce' - uri = urls.uri_to_iri(uri) - self.assert_equal(urls.uri_to_iri(uri), uri) - - def test_uri_to_iri_idempotence_non_ascii(self): - uri = 'http://xn--n3h/%E2%98%83' - uri = urls.uri_to_iri(uri) - self.assert_equal(urls.uri_to_iri(uri), uri) - - def test_iri_to_uri_to_iri(self): - iri = u'http://föö.com/' - uri = urls.iri_to_uri(iri) - self.assert_equal(urls.uri_to_iri(uri), iri) - - def test_uri_to_iri_to_uri(self): - uri = 'http://xn--f-rgao.com/%C3%9E' - iri = urls.uri_to_iri(uri) - self.assert_equal(urls.iri_to_uri(iri), uri) - - def test_uri_iri_normalization(self): - uri = 'http://xn--f-rgao.com/%E2%98%90/fred?utf8=%E2%9C%93' - iri = u'http://föñ.com/\N{BALLOT BOX}/fred?utf8=\u2713' - - tests = [ - u'http://föñ.com/\N{BALLOT BOX}/fred?utf8=\u2713', - u'http://xn--f-rgao.com/\u2610/fred?utf8=\N{CHECK MARK}', - b'http://xn--f-rgao.com/%E2%98%90/fred?utf8=%E2%9C%93', - u'http://xn--f-rgao.com/%E2%98%90/fred?utf8=%E2%9C%93', - u'http://föñ.com/\u2610/fred?utf8=%E2%9C%93', - b'http://xn--f-rgao.com/\xe2\x98\x90/fred?utf8=\xe2\x9c\x93', - ] - - for test in tests: - self.assert_equal(urls.uri_to_iri(test), iri) - self.assert_equal(urls.iri_to_uri(test), uri) - self.assert_equal(urls.uri_to_iri(urls.iri_to_uri(test)), iri) - self.assert_equal(urls.iri_to_uri(urls.uri_to_iri(test)), uri) - self.assert_equal(urls.uri_to_iri(urls.uri_to_iri(test)), iri) - self.assert_equal(urls.iri_to_uri(urls.iri_to_uri(test)), uri) - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(URLsTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/utils.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/utils.py deleted file mode 100644 index 8b1c0f43..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/utils.py +++ /dev/null @@ -1,284 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.utils - ~~~~~~~~~~~~~~~~~~~~~~~~ - - General utilities. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" - -from __future__ import with_statement - -import unittest -from datetime import datetime -from functools import partial - -from werkzeug.testsuite import WerkzeugTestCase - -from werkzeug import utils -from werkzeug.datastructures import Headers -from werkzeug.http import parse_date, http_date -from werkzeug.wrappers import BaseResponse -from werkzeug.test import Client, run_wsgi_app -from werkzeug._compat import text_type, implements_iterator - - -class GeneralUtilityTestCase(WerkzeugTestCase): - - def test_redirect(self): - resp = utils.redirect(u'/füübär') - self.assert_in(b'/f%C3%BC%C3%BCb%C3%A4r', resp.get_data()) - self.assert_equal(resp.headers['Location'], '/f%C3%BC%C3%BCb%C3%A4r') - self.assert_equal(resp.status_code, 302) - - resp = utils.redirect(u'http://☃.net/', 307) - self.assert_in(b'http://xn--n3h.net/', resp.get_data()) - self.assert_equal(resp.headers['Location'], 'http://xn--n3h.net/') - self.assert_equal(resp.status_code, 307) - - resp = utils.redirect('http://example.com/', 305) - self.assert_equal(resp.headers['Location'], 'http://example.com/') - self.assert_equal(resp.status_code, 305) - - def test_redirect_no_unicode_header_keys(self): - # Make sure all headers are native keys. This was a bug at one point - # due to an incorrect conversion. - resp = utils.redirect('http://example.com/', 305) - for key, value in resp.headers.items(): - self.assert_equal(type(key), str) - self.assert_equal(type(value), text_type) - self.assert_equal(resp.headers['Location'], 'http://example.com/') - self.assert_equal(resp.status_code, 305) - - def test_redirect_xss(self): - location = 'http://example.com/?xss=">' - resp = utils.redirect(location) - self.assert_not_in(b'', resp.get_data()) - - location = 'http://example.com/?xss="onmouseover="alert(1)' - resp = utils.redirect(location) - self.assert_not_in(b'href="http://example.com/?xss="onmouseover="alert(1)"', resp.get_data()) - - def test_cached_property(self): - foo = [] - class A(object): - def prop(self): - foo.append(42) - return 42 - prop = utils.cached_property(prop) - - a = A() - p = a.prop - q = a.prop - self.assert_true(p == q == 42) - self.assert_equal(foo, [42]) - - foo = [] - class A(object): - def _prop(self): - foo.append(42) - return 42 - prop = utils.cached_property(_prop, name='prop') - del _prop - - a = A() - p = a.prop - q = a.prop - self.assert_true(p == q == 42) - self.assert_equal(foo, [42]) - - def test_environ_property(self): - class A(object): - environ = {'string': 'abc', 'number': '42'} - - string = utils.environ_property('string') - missing = utils.environ_property('missing', 'spam') - read_only = utils.environ_property('number') - number = utils.environ_property('number', load_func=int) - broken_number = utils.environ_property('broken_number', load_func=int) - date = utils.environ_property('date', None, parse_date, http_date, - read_only=False) - foo = utils.environ_property('foo') - - a = A() - self.assert_equal(a.string, 'abc') - self.assert_equal(a.missing, 'spam') - def test_assign(): - a.read_only = 'something' - self.assert_raises(AttributeError, test_assign) - self.assert_equal(a.number, 42) - self.assert_equal(a.broken_number, None) - self.assert_is_none(a.date) - a.date = datetime(2008, 1, 22, 10, 0, 0, 0) - self.assert_equal(a.environ['date'], 'Tue, 22 Jan 2008 10:00:00 GMT') - - def test_escape(self): - class Foo(str): - def __html__(self): - return text_type(self) - self.assert_equal(utils.escape(None), '') - self.assert_equal(utils.escape(42), '42') - self.assert_equal(utils.escape('<>'), '<>') - self.assert_equal(utils.escape('"foo"'), '"foo"') - self.assert_equal(utils.escape(Foo('')), '') - - def test_unescape(self): - self.assert_equal(utils.unescape('<ä>'), u'<ä>') - - def test_run_wsgi_app(self): - def foo(environ, start_response): - start_response('200 OK', [('Content-Type', 'text/plain')]) - yield '1' - yield '2' - yield '3' - - app_iter, status, headers = run_wsgi_app(foo, {}) - self.assert_equal(status, '200 OK') - self.assert_equal(list(headers), [('Content-Type', 'text/plain')]) - self.assert_equal(next(app_iter), '1') - self.assert_equal(next(app_iter), '2') - self.assert_equal(next(app_iter), '3') - self.assert_raises(StopIteration, partial(next, app_iter)) - - got_close = [] - @implements_iterator - class CloseIter(object): - def __init__(self): - self.iterated = False - def __iter__(self): - return self - def close(self): - got_close.append(None) - def __next__(self): - if self.iterated: - raise StopIteration() - self.iterated = True - return 'bar' - - def bar(environ, start_response): - start_response('200 OK', [('Content-Type', 'text/plain')]) - return CloseIter() - - app_iter, status, headers = run_wsgi_app(bar, {}) - self.assert_equal(status, '200 OK') - self.assert_equal(list(headers), [('Content-Type', 'text/plain')]) - self.assert_equal(next(app_iter), 'bar') - self.assert_raises(StopIteration, partial(next, app_iter)) - app_iter.close() - - self.assert_equal(run_wsgi_app(bar, {}, True)[0], ['bar']) - - self.assert_equal(len(got_close), 2) - - def test_import_string(self): - import cgi - from werkzeug.debug import DebuggedApplication - self.assert_is(utils.import_string('cgi.escape'), cgi.escape) - self.assert_is(utils.import_string(u'cgi.escape'), cgi.escape) - self.assert_is(utils.import_string('cgi:escape'), cgi.escape) - self.assert_is_none(utils.import_string('XXXXXXXXXXXX', True)) - self.assert_is_none(utils.import_string('cgi.XXXXXXXXXXXX', True)) - self.assert_is(utils.import_string(u'cgi.escape'), cgi.escape) - self.assert_is(utils.import_string(u'werkzeug.debug.DebuggedApplication'), DebuggedApplication) - self.assert_raises(ImportError, utils.import_string, 'XXXXXXXXXXXXXXXX') - self.assert_raises(ImportError, utils.import_string, 'cgi.XXXXXXXXXX') - - def test_find_modules(self): - self.assert_equal(list(utils.find_modules('werkzeug.debug')), \ - ['werkzeug.debug.console', 'werkzeug.debug.repr', - 'werkzeug.debug.tbtools']) - - def test_html_builder(self): - html = utils.html - xhtml = utils.xhtml - self.assert_equal(html.p('Hello World'), '

    Hello World

    ') - self.assert_equal(html.a('Test', href='#'), '
    Test') - self.assert_equal(html.br(), '
    ') - self.assert_equal(xhtml.br(), '
    ') - self.assert_equal(html.img(src='foo'), '') - self.assert_equal(xhtml.img(src='foo'), '') - self.assert_equal(html.html( - html.head( - html.title('foo'), - html.script(type='text/javascript') - ) - ), 'foo') - self.assert_equal(html(''), '<foo>') - self.assert_equal(html.input(disabled=True), '') - self.assert_equal(xhtml.input(disabled=True), '') - self.assert_equal(html.input(disabled=''), '') - self.assert_equal(xhtml.input(disabled=''), '') - self.assert_equal(html.input(disabled=None), '') - self.assert_equal(xhtml.input(disabled=None), '') - self.assert_equal(html.script('alert("Hello World");'), '') - self.assert_equal(xhtml.script('alert("Hello World");'), '') - - def test_validate_arguments(self): - take_none = lambda: None - take_two = lambda a, b: None - take_two_one_default = lambda a, b=0: None - - self.assert_equal(utils.validate_arguments(take_two, (1, 2,), {}), ((1, 2), {})) - self.assert_equal(utils.validate_arguments(take_two, (1,), {'b': 2}), ((1, 2), {})) - self.assert_equal(utils.validate_arguments(take_two_one_default, (1,), {}), ((1, 0), {})) - self.assert_equal(utils.validate_arguments(take_two_one_default, (1, 2), {}), ((1, 2), {})) - - self.assert_raises(utils.ArgumentValidationError, - utils.validate_arguments, take_two, (), {}) - - self.assert_equal(utils.validate_arguments(take_none, (1, 2,), {'c': 3}), ((), {})) - self.assert_raises(utils.ArgumentValidationError, - utils.validate_arguments, take_none, (1,), {}, drop_extra=False) - self.assert_raises(utils.ArgumentValidationError, - utils.validate_arguments, take_none, (), {'a': 1}, drop_extra=False) - - def test_header_set_duplication_bug(self): - headers = Headers([ - ('Content-Type', 'text/html'), - ('Foo', 'bar'), - ('Blub', 'blah') - ]) - headers['blub'] = 'hehe' - headers['blafasel'] = 'humm' - self.assert_equal(headers, Headers([ - ('Content-Type', 'text/html'), - ('Foo', 'bar'), - ('blub', 'hehe'), - ('blafasel', 'humm') - ])) - - def test_append_slash_redirect(self): - def app(env, sr): - return utils.append_slash_redirect(env)(env, sr) - client = Client(app, BaseResponse) - response = client.get('foo', base_url='http://example.org/app') - self.assert_equal(response.status_code, 301) - self.assert_equal(response.headers['Location'], 'http://example.org/app/foo/') - - def test_cached_property_doc(self): - @utils.cached_property - def foo(): - """testing""" - return 42 - self.assert_equal(foo.__doc__, 'testing') - self.assert_equal(foo.__name__, 'foo') - self.assert_equal(foo.__module__, __name__) - - def test_secure_filename(self): - self.assert_equal(utils.secure_filename('My cool movie.mov'), - 'My_cool_movie.mov') - self.assert_equal(utils.secure_filename('../../../etc/passwd'), - 'etc_passwd') - self.assert_equal(utils.secure_filename(u'i contain cool \xfcml\xe4uts.txt'), - 'i_contain_cool_umlauts.txt') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(GeneralUtilityTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/wrappers.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/wrappers.py deleted file mode 100644 index 8f9e41c0..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/wrappers.py +++ /dev/null @@ -1,840 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.wrappers - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Tests for the response and request objects. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import unittest -import pickle -from io import BytesIO -from datetime import datetime -from werkzeug._compat import iteritems - -from werkzeug.testsuite import WerkzeugTestCase - -from werkzeug import wrappers -from werkzeug.exceptions import SecurityError -from werkzeug.wsgi import LimitedStream -from werkzeug.datastructures import MultiDict, ImmutableOrderedMultiDict, \ - ImmutableList, ImmutableTypeConversionDict, CharsetAccept, \ - MIMEAccept, LanguageAccept, Accept, CombinedMultiDict -from werkzeug.test import Client, create_environ, run_wsgi_app -from werkzeug._compat import implements_iterator, text_type - - -class RequestTestResponse(wrappers.BaseResponse): - """Subclass of the normal response class we use to test response - and base classes. Has some methods to test if things in the - response match. - """ - - def __init__(self, response, status, headers): - wrappers.BaseResponse.__init__(self, response, status, headers) - self.body_data = pickle.loads(self.get_data()) - - def __getitem__(self, key): - return self.body_data[key] - - -def request_demo_app(environ, start_response): - request = wrappers.BaseRequest(environ) - assert 'werkzeug.request' in environ - start_response('200 OK', [('Content-Type', 'text/plain')]) - return [pickle.dumps({ - 'args': request.args, - 'args_as_list': list(request.args.lists()), - 'form': request.form, - 'form_as_list': list(request.form.lists()), - 'environ': prepare_environ_pickle(request.environ), - 'data': request.get_data() - })] - - -def prepare_environ_pickle(environ): - result = {} - for key, value in iteritems(environ): - try: - pickle.dumps((key, value)) - except Exception: - continue - result[key] = value - return result - - -class WrappersTestCase(WerkzeugTestCase): - - def assert_environ(self, environ, method): - self.assert_strict_equal(environ['REQUEST_METHOD'], method) - self.assert_strict_equal(environ['PATH_INFO'], '/') - self.assert_strict_equal(environ['SCRIPT_NAME'], '') - self.assert_strict_equal(environ['SERVER_NAME'], 'localhost') - self.assert_strict_equal(environ['wsgi.version'], (1, 0)) - self.assert_strict_equal(environ['wsgi.url_scheme'], 'http') - - def test_base_request(self): - client = Client(request_demo_app, RequestTestResponse) - - # get requests - response = client.get('/?foo=bar&foo=hehe') - self.assert_strict_equal(response['args'], MultiDict([('foo', u'bar'), ('foo', u'hehe')])) - self.assert_strict_equal(response['args_as_list'], [('foo', [u'bar', u'hehe'])]) - self.assert_strict_equal(response['form'], MultiDict()) - self.assert_strict_equal(response['form_as_list'], []) - self.assert_strict_equal(response['data'], b'') - self.assert_environ(response['environ'], 'GET') - - # post requests with form data - response = client.post('/?blub=blah', data='foo=blub+hehe&blah=42', - content_type='application/x-www-form-urlencoded') - self.assert_strict_equal(response['args'], MultiDict([('blub', u'blah')])) - self.assert_strict_equal(response['args_as_list'], [('blub', [u'blah'])]) - self.assert_strict_equal(response['form'], MultiDict([('foo', u'blub hehe'), ('blah', u'42')])) - self.assert_strict_equal(response['data'], b'') - # currently we do not guarantee that the values are ordered correctly - # for post data. - ## self.assert_strict_equal(response['form_as_list'], [('foo', ['blub hehe']), ('blah', ['42'])]) - self.assert_environ(response['environ'], 'POST') - - # patch requests with form data - response = client.patch('/?blub=blah', data='foo=blub+hehe&blah=42', - content_type='application/x-www-form-urlencoded') - self.assert_strict_equal(response['args'], MultiDict([('blub', u'blah')])) - self.assert_strict_equal(response['args_as_list'], [('blub', [u'blah'])]) - self.assert_strict_equal(response['form'], - MultiDict([('foo', u'blub hehe'), ('blah', u'42')])) - self.assert_strict_equal(response['data'], b'') - self.assert_environ(response['environ'], 'PATCH') - - # post requests with json data - json = b'{"foo": "bar", "blub": "blah"}' - response = client.post('/?a=b', data=json, content_type='application/json') - self.assert_strict_equal(response['data'], json) - self.assert_strict_equal(response['args'], MultiDict([('a', u'b')])) - self.assert_strict_equal(response['form'], MultiDict()) - - def test_query_string_is_bytes(self): - req = wrappers.Request.from_values(u'/?foo=%2f') - self.assert_strict_equal(req.query_string, b'foo=%2f') - - def test_access_route(self): - req = wrappers.Request.from_values(headers={ - 'X-Forwarded-For': '192.168.1.2, 192.168.1.1' - }) - req.environ['REMOTE_ADDR'] = '192.168.1.3' - self.assert_equal(req.access_route, ['192.168.1.2', '192.168.1.1']) - self.assert_strict_equal(req.remote_addr, '192.168.1.3') - - req = wrappers.Request.from_values() - req.environ['REMOTE_ADDR'] = '192.168.1.3' - self.assert_strict_equal(list(req.access_route), ['192.168.1.3']) - - def test_url_request_descriptors(self): - req = wrappers.Request.from_values('/bar?foo=baz', 'http://example.com/test') - self.assert_strict_equal(req.path, u'/bar') - self.assert_strict_equal(req.full_path, u'/bar?foo=baz') - self.assert_strict_equal(req.script_root, u'/test') - self.assert_strict_equal(req.url, u'http://example.com/test/bar?foo=baz') - self.assert_strict_equal(req.base_url, u'http://example.com/test/bar') - self.assert_strict_equal(req.url_root, u'http://example.com/test/') - self.assert_strict_equal(req.host_url, u'http://example.com/') - self.assert_strict_equal(req.host, 'example.com') - self.assert_strict_equal(req.scheme, 'http') - - req = wrappers.Request.from_values('/bar?foo=baz', 'https://example.com/test') - self.assert_strict_equal(req.scheme, 'https') - - def test_url_request_descriptors_query_quoting(self): - next = 'http%3A%2F%2Fwww.example.com%2F%3Fnext%3D%2F' - req = wrappers.Request.from_values('/bar?next=' + next, 'http://example.com/') - self.assert_equal(req.path, u'/bar') - self.assert_strict_equal(req.full_path, u'/bar?next=' + next) - self.assert_strict_equal(req.url, u'http://example.com/bar?next=' + next) - - def test_url_request_descriptors_hosts(self): - req = wrappers.Request.from_values('/bar?foo=baz', 'http://example.com/test') - req.trusted_hosts = ['example.com'] - self.assert_strict_equal(req.path, u'/bar') - self.assert_strict_equal(req.full_path, u'/bar?foo=baz') - self.assert_strict_equal(req.script_root, u'/test') - self.assert_strict_equal(req.url, u'http://example.com/test/bar?foo=baz') - self.assert_strict_equal(req.base_url, u'http://example.com/test/bar') - self.assert_strict_equal(req.url_root, u'http://example.com/test/') - self.assert_strict_equal(req.host_url, u'http://example.com/') - self.assert_strict_equal(req.host, 'example.com') - self.assert_strict_equal(req.scheme, 'http') - - req = wrappers.Request.from_values('/bar?foo=baz', 'https://example.com/test') - self.assert_strict_equal(req.scheme, 'https') - - req = wrappers.Request.from_values('/bar?foo=baz', 'http://example.com/test') - req.trusted_hosts = ['example.org'] - self.assert_raises(SecurityError, lambda: req.url) - self.assert_raises(SecurityError, lambda: req.base_url) - self.assert_raises(SecurityError, lambda: req.url_root) - self.assert_raises(SecurityError, lambda: req.host_url) - self.assert_raises(SecurityError, lambda: req.host) - - def test_authorization_mixin(self): - request = wrappers.Request.from_values(headers={ - 'Authorization': 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' - }) - a = request.authorization - self.assert_strict_equal(a.type, 'basic') - self.assert_strict_equal(a.username, 'Aladdin') - self.assert_strict_equal(a.password, 'open sesame') - - def test_stream_only_mixing(self): - request = wrappers.PlainRequest.from_values( - data=b'foo=blub+hehe', - content_type='application/x-www-form-urlencoded' - ) - self.assert_equal(list(request.files.items()), []) - self.assert_equal(list(request.form.items()), []) - self.assert_raises(AttributeError, lambda: request.data) - self.assert_strict_equal(request.stream.read(), b'foo=blub+hehe') - - def test_base_response(self): - # unicode - response = wrappers.BaseResponse(u'öäü') - self.assert_strict_equal(response.get_data(), u'öäü'.encode('utf-8')) - - # writing - response = wrappers.Response('foo') - response.stream.write('bar') - self.assert_strict_equal(response.get_data(), b'foobar') - - # set cookie - response = wrappers.BaseResponse() - response.set_cookie('foo', 'bar', 60, 0, '/blub', 'example.org') - self.assert_strict_equal(response.headers.to_wsgi_list(), [ - ('Content-Type', 'text/plain; charset=utf-8'), - ('Set-Cookie', 'foo=bar; Domain=example.org; Expires=Thu, ' - '01-Jan-1970 00:00:00 GMT; Max-Age=60; Path=/blub') - ]) - - # delete cookie - response = wrappers.BaseResponse() - response.delete_cookie('foo') - self.assert_strict_equal(response.headers.to_wsgi_list(), [ - ('Content-Type', 'text/plain; charset=utf-8'), - ('Set-Cookie', 'foo=; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Path=/') - ]) - - # close call forwarding - closed = [] - @implements_iterator - class Iterable(object): - def __next__(self): - raise StopIteration() - def __iter__(self): - return self - def close(self): - closed.append(True) - response = wrappers.BaseResponse(Iterable()) - response.call_on_close(lambda: closed.append(True)) - app_iter, status, headers = run_wsgi_app(response, - create_environ(), - buffered=True) - self.assert_strict_equal(status, '200 OK') - self.assert_strict_equal(''.join(app_iter), '') - self.assert_strict_equal(len(closed), 2) - - # with statement - del closed[:] - response = wrappers.BaseResponse(Iterable()) - with response: - pass - self.assert_equal(len(closed), 1) - - def test_response_status_codes(self): - response = wrappers.BaseResponse() - response.status_code = 404 - self.assert_strict_equal(response.status, '404 NOT FOUND') - response.status = '200 OK' - self.assert_strict_equal(response.status_code, 200) - response.status = '999 WTF' - self.assert_strict_equal(response.status_code, 999) - response.status_code = 588 - self.assert_strict_equal(response.status_code, 588) - self.assert_strict_equal(response.status, '588 UNKNOWN') - response.status = 'wtf' - self.assert_strict_equal(response.status_code, 0) - self.assert_strict_equal(response.status, '0 wtf') - - def test_type_forcing(self): - def wsgi_application(environ, start_response): - start_response('200 OK', [('Content-Type', 'text/html')]) - return ['Hello World!'] - base_response = wrappers.BaseResponse('Hello World!', content_type='text/html') - - class SpecialResponse(wrappers.Response): - def foo(self): - return 42 - - # good enough for this simple application, but don't ever use that in - # real world examples! - fake_env = {} - - for orig_resp in wsgi_application, base_response: - response = SpecialResponse.force_type(orig_resp, fake_env) - assert response.__class__ is SpecialResponse - self.assert_strict_equal(response.foo(), 42) - self.assert_strict_equal(response.get_data(), b'Hello World!') - self.assert_equal(response.content_type, 'text/html') - - # without env, no arbitrary conversion - self.assert_raises(TypeError, SpecialResponse.force_type, wsgi_application) - - def test_accept_mixin(self): - request = wrappers.Request({ - 'HTTP_ACCEPT': 'text/xml,application/xml,application/xhtml+xml,' - 'text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5', - 'HTTP_ACCEPT_CHARSET': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', - 'HTTP_ACCEPT_ENCODING': 'gzip,deflate', - 'HTTP_ACCEPT_LANGUAGE': 'en-us,en;q=0.5' - }) - self.assert_equal(request.accept_mimetypes, MIMEAccept([ - ('text/xml', 1), ('image/png', 1), ('application/xml', 1), - ('application/xhtml+xml', 1), ('text/html', 0.9), - ('text/plain', 0.8), ('*/*', 0.5) - ])) - self.assert_strict_equal(request.accept_charsets, CharsetAccept([ - ('ISO-8859-1', 1), ('utf-8', 0.7), ('*', 0.7) - ])) - self.assert_strict_equal(request.accept_encodings, Accept([ - ('gzip', 1), ('deflate', 1)])) - self.assert_strict_equal(request.accept_languages, LanguageAccept([ - ('en-us', 1), ('en', 0.5)])) - - request = wrappers.Request({'HTTP_ACCEPT': ''}) - self.assert_strict_equal(request.accept_mimetypes, MIMEAccept()) - - def test_etag_request_mixin(self): - request = wrappers.Request({ - 'HTTP_CACHE_CONTROL': 'no-store, no-cache', - 'HTTP_IF_MATCH': 'w/"foo", bar, "baz"', - 'HTTP_IF_NONE_MATCH': 'w/"foo", bar, "baz"', - 'HTTP_IF_MODIFIED_SINCE': 'Tue, 22 Jan 2008 11:18:44 GMT', - 'HTTP_IF_UNMODIFIED_SINCE': 'Tue, 22 Jan 2008 11:18:44 GMT' - }) - assert request.cache_control.no_store - assert request.cache_control.no_cache - - for etags in request.if_match, request.if_none_match: - assert etags('bar') - assert etags.contains_raw('w/"foo"') - assert etags.contains_weak('foo') - assert not etags.contains('foo') - - self.assert_equal(request.if_modified_since, datetime(2008, 1, 22, 11, 18, 44)) - self.assert_equal(request.if_unmodified_since, datetime(2008, 1, 22, 11, 18, 44)) - - def test_user_agent_mixin(self): - user_agents = [ - ('Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.11) ' - 'Gecko/20071127 Firefox/2.0.0.11', 'firefox', 'macos', '2.0.0.11', - 'en-US'), - ('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; de-DE) Opera 8.54', - 'opera', 'windows', '8.54', 'de-DE'), - ('Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420 ' - '(KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3', - 'safari', 'iphone', '419.3', 'en'), - ('Bot Googlebot/2.1 ( http://www.googlebot.com/bot.html)', - 'google', None, '2.1', None) - ] - for ua, browser, platform, version, lang in user_agents: - request = wrappers.Request({'HTTP_USER_AGENT': ua}) - self.assert_strict_equal(request.user_agent.browser, browser) - self.assert_strict_equal(request.user_agent.platform, platform) - self.assert_strict_equal(request.user_agent.version, version) - self.assert_strict_equal(request.user_agent.language, lang) - assert bool(request.user_agent) - self.assert_strict_equal(request.user_agent.to_header(), ua) - self.assert_strict_equal(str(request.user_agent), ua) - - request = wrappers.Request({'HTTP_USER_AGENT': 'foo'}) - assert not request.user_agent - - def test_stream_wrapping(self): - class LowercasingStream(object): - def __init__(self, stream): - self._stream = stream - def read(self, size=-1): - return self._stream.read(size).lower() - def readline(self, size=-1): - return self._stream.readline(size).lower() - - data = b'foo=Hello+World' - req = wrappers.Request.from_values('/', method='POST', data=data, - content_type='application/x-www-form-urlencoded') - req.stream = LowercasingStream(req.stream) - self.assert_equal(req.form['foo'], 'hello world') - - def test_data_descriptor_triggers_parsing(self): - data = b'foo=Hello+World' - req = wrappers.Request.from_values('/', method='POST', data=data, - content_type='application/x-www-form-urlencoded') - - self.assert_equal(req.data, b'') - self.assert_equal(req.form['foo'], u'Hello World') - - def test_get_data_method_parsing_caching_behavior(self): - data = b'foo=Hello+World' - req = wrappers.Request.from_values('/', method='POST', data=data, - content_type='application/x-www-form-urlencoded') - - # get_data() caches, so form stays available - self.assert_equal(req.get_data(), data) - self.assert_equal(req.form['foo'], u'Hello World') - self.assert_equal(req.get_data(), data) - - # here we access the form data first, caching is bypassed - req = wrappers.Request.from_values('/', method='POST', data=data, - content_type='application/x-www-form-urlencoded') - self.assert_equal(req.form['foo'], u'Hello World') - self.assert_equal(req.get_data(), b'') - - # Another case is uncached get data which trashes everything - req = wrappers.Request.from_values('/', method='POST', data=data, - content_type='application/x-www-form-urlencoded') - self.assert_equal(req.get_data(cache=False), data) - self.assert_equal(req.get_data(cache=False), b'') - self.assert_equal(req.form, {}) - - # Or we can implicitly start the form parser which is similar to - # the old .data behavior - req = wrappers.Request.from_values('/', method='POST', data=data, - content_type='application/x-www-form-urlencoded') - self.assert_equal(req.get_data(parse_form_data=True), b'') - self.assert_equal(req.form['foo'], u'Hello World') - - def test_etag_response_mixin(self): - response = wrappers.Response('Hello World') - self.assert_equal(response.get_etag(), (None, None)) - response.add_etag() - self.assert_equal(response.get_etag(), ('b10a8db164e0754105b7a99be72e3fe5', False)) - assert not response.cache_control - response.cache_control.must_revalidate = True - response.cache_control.max_age = 60 - response.headers['Content-Length'] = len(response.get_data()) - assert response.headers['Cache-Control'] in ('must-revalidate, max-age=60', - 'max-age=60, must-revalidate') - - assert 'date' not in response.headers - env = create_environ() - env.update({ - 'REQUEST_METHOD': 'GET', - 'HTTP_IF_NONE_MATCH': response.get_etag()[0] - }) - response.make_conditional(env) - assert 'date' in response.headers - - # after the thing is invoked by the server as wsgi application - # (we're emulating this here), there must not be any entity - # headers left and the status code would have to be 304 - resp = wrappers.Response.from_app(response, env) - self.assert_equal(resp.status_code, 304) - assert not 'content-length' in resp.headers - - # make sure date is not overriden - response = wrappers.Response('Hello World') - response.date = 1337 - d = response.date - response.make_conditional(env) - self.assert_equal(response.date, d) - - # make sure content length is only set if missing - response = wrappers.Response('Hello World') - response.content_length = 999 - response.make_conditional(env) - self.assert_equal(response.content_length, 999) - - def test_etag_response_mixin_freezing(self): - class WithFreeze(wrappers.ETagResponseMixin, wrappers.BaseResponse): - pass - class WithoutFreeze(wrappers.BaseResponse, wrappers.ETagResponseMixin): - pass - - response = WithFreeze('Hello World') - response.freeze() - self.assert_strict_equal(response.get_etag(), - (text_type(wrappers.generate_etag(b'Hello World')), False)) - response = WithoutFreeze('Hello World') - response.freeze() - self.assert_equal(response.get_etag(), (None, None)) - response = wrappers.Response('Hello World') - response.freeze() - self.assert_equal(response.get_etag(), (None, None)) - - def test_authenticate_mixin(self): - resp = wrappers.Response() - resp.www_authenticate.type = 'basic' - resp.www_authenticate.realm = 'Testing' - self.assert_strict_equal(resp.headers['WWW-Authenticate'], u'Basic realm="Testing"') - resp.www_authenticate.realm = None - resp.www_authenticate.type = None - assert 'WWW-Authenticate' not in resp.headers - - def test_response_stream_mixin(self): - response = wrappers.Response() - response.stream.write('Hello ') - response.stream.write('World!') - self.assert_equal(response.response, ['Hello ', 'World!']) - self.assert_equal(response.get_data(), b'Hello World!') - - def test_common_response_descriptors_mixin(self): - response = wrappers.Response() - response.mimetype = 'text/html' - self.assert_equal(response.mimetype, 'text/html') - self.assert_equal(response.content_type, 'text/html; charset=utf-8') - self.assert_equal(response.mimetype_params, {'charset': 'utf-8'}) - response.mimetype_params['x-foo'] = 'yep' - del response.mimetype_params['charset'] - self.assert_equal(response.content_type, 'text/html; x-foo=yep') - - now = datetime.utcnow().replace(microsecond=0) - - assert response.content_length is None - response.content_length = '42' - self.assert_equal(response.content_length, 42) - - for attr in 'date', 'age', 'expires': - assert getattr(response, attr) is None - setattr(response, attr, now) - self.assert_equal(getattr(response, attr), now) - - assert response.retry_after is None - response.retry_after = now - self.assert_equal(response.retry_after, now) - - assert not response.vary - response.vary.add('Cookie') - response.vary.add('Content-Language') - assert 'cookie' in response.vary - self.assert_equal(response.vary.to_header(), 'Cookie, Content-Language') - response.headers['Vary'] = 'Content-Encoding' - self.assert_equal(response.vary.as_set(), set(['content-encoding'])) - - response.allow.update(['GET', 'POST']) - self.assert_equal(response.headers['Allow'], 'GET, POST') - - response.content_language.add('en-US') - response.content_language.add('fr') - self.assert_equal(response.headers['Content-Language'], 'en-US, fr') - - def test_common_request_descriptors_mixin(self): - request = wrappers.Request.from_values(content_type='text/html; charset=utf-8', - content_length='23', - headers={ - 'Referer': 'http://www.example.com/', - 'Date': 'Sat, 28 Feb 2009 19:04:35 GMT', - 'Max-Forwards': '10', - 'Pragma': 'no-cache', - 'Content-Encoding': 'gzip', - 'Content-MD5': '9a3bc6dbc47a70db25b84c6e5867a072' - }) - - self.assert_equal(request.content_type, 'text/html; charset=utf-8') - self.assert_equal(request.mimetype, 'text/html') - self.assert_equal(request.mimetype_params, {'charset': 'utf-8'}) - self.assert_equal(request.content_length, 23) - self.assert_equal(request.referrer, 'http://www.example.com/') - self.assert_equal(request.date, datetime(2009, 2, 28, 19, 4, 35)) - self.assert_equal(request.max_forwards, 10) - self.assert_true('no-cache' in request.pragma) - self.assert_equal(request.content_encoding, 'gzip') - self.assert_equal(request.content_md5, '9a3bc6dbc47a70db25b84c6e5867a072') - - def test_shallow_mode(self): - request = wrappers.Request({'QUERY_STRING': 'foo=bar'}, shallow=True) - self.assert_equal(request.args['foo'], 'bar') - self.assert_raises(RuntimeError, lambda: request.form['foo']) - - def test_form_parsing_failed(self): - data = ( - b'--blah\r\n' - ) - data = wrappers.Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='multipart/form-data; boundary=foo', - method='POST') - assert not data.files - assert not data.form - - def test_file_closing(self): - data = (b'--foo\r\n' - b'Content-Disposition: form-data; name="foo"; filename="foo.txt"\r\n' - b'Content-Type: text/plain; charset=utf-8\r\n\r\n' - b'file contents, just the contents\r\n' - b'--foo--') - req = wrappers.Request.from_values( - input_stream=BytesIO(data), - content_length=len(data), - content_type='multipart/form-data; boundary=foo', - method='POST' - ) - foo = req.files['foo'] - self.assert_equal(foo.mimetype, 'text/plain') - self.assert_equal(foo.filename, 'foo.txt') - - self.assert_equal(foo.closed, False) - req.close() - self.assert_equal(foo.closed, True) - - def test_file_closing_with(self): - data = (b'--foo\r\n' - b'Content-Disposition: form-data; name="foo"; filename="foo.txt"\r\n' - b'Content-Type: text/plain; charset=utf-8\r\n\r\n' - b'file contents, just the contents\r\n' - b'--foo--') - req = wrappers.Request.from_values( - input_stream=BytesIO(data), - content_length=len(data), - content_type='multipart/form-data; boundary=foo', - method='POST' - ) - with req: - foo = req.files['foo'] - self.assert_equal(foo.mimetype, 'text/plain') - self.assert_equal(foo.filename, 'foo.txt') - - self.assert_equal(foo.closed, True) - - def test_url_charset_reflection(self): - req = wrappers.Request.from_values() - req.charset = 'utf-7' - self.assert_equal(req.url_charset, 'utf-7') - - def test_response_streamed(self): - r = wrappers.Response() - assert not r.is_streamed - r = wrappers.Response("Hello World") - assert not r.is_streamed - r = wrappers.Response(["foo", "bar"]) - assert not r.is_streamed - def gen(): - if 0: - yield None - r = wrappers.Response(gen()) - assert r.is_streamed - - def test_response_iter_wrapping(self): - def uppercasing(iterator): - for item in iterator: - yield item.upper() - def generator(): - yield 'foo' - yield 'bar' - req = wrappers.Request.from_values() - resp = wrappers.Response(generator()) - del resp.headers['Content-Length'] - resp.response = uppercasing(resp.iter_encoded()) - actual_resp = wrappers.Response.from_app(resp, req.environ, buffered=True) - self.assertEqual(actual_resp.get_data(), b'FOOBAR') - - def test_response_freeze(self): - def generate(): - yield "foo" - yield "bar" - resp = wrappers.Response(generate()) - resp.freeze() - self.assert_equal(resp.response, [b'foo', b'bar']) - self.assert_equal(resp.headers['content-length'], '6') - - def test_other_method_payload(self): - data = b'Hello World' - req = wrappers.Request.from_values(input_stream=BytesIO(data), - content_length=len(data), - content_type='text/plain', - method='WHAT_THE_FUCK') - self.assert_equal(req.get_data(), data) - self.assert_is_instance(req.stream, LimitedStream) - - def test_urlfication(self): - resp = wrappers.Response() - resp.headers['Location'] = u'http://üser:pässword@☃.net/påth' - resp.headers['Content-Location'] = u'http://☃.net/' - headers = resp.get_wsgi_headers(create_environ()) - self.assert_equal(headers['location'], \ - 'http://%C3%BCser:p%C3%A4ssword@xn--n3h.net/p%C3%A5th') - self.assert_equal(headers['content-location'], 'http://xn--n3h.net/') - - def test_new_response_iterator_behavior(self): - req = wrappers.Request.from_values() - resp = wrappers.Response(u'Hello Wörld!') - - def get_content_length(resp): - headers = resp.get_wsgi_headers(req.environ) - return headers.get('content-length', type=int) - - def generate_items(): - yield "Hello " - yield u"Wörld!" - - # werkzeug encodes when set to `data` now, which happens - # if a string is passed to the response object. - self.assert_equal(resp.response, [u'Hello Wörld!'.encode('utf-8')]) - self.assert_equal(resp.get_data(), u'Hello Wörld!'.encode('utf-8')) - self.assert_equal(get_content_length(resp), 13) - assert not resp.is_streamed - assert resp.is_sequence - - # try the same for manual assignment - resp.set_data(u'Wörd') - self.assert_equal(resp.response, [u'Wörd'.encode('utf-8')]) - self.assert_equal(resp.get_data(), u'Wörd'.encode('utf-8')) - self.assert_equal(get_content_length(resp), 5) - assert not resp.is_streamed - assert resp.is_sequence - - # automatic generator sequence conversion - resp.response = generate_items() - assert resp.is_streamed - assert not resp.is_sequence - self.assert_equal(resp.get_data(), u'Hello Wörld!'.encode('utf-8')) - self.assert_equal(resp.response, [b'Hello ', u'Wörld!'.encode('utf-8')]) - assert not resp.is_streamed - assert resp.is_sequence - - # automatic generator sequence conversion - resp.response = generate_items() - resp.implicit_sequence_conversion = False - assert resp.is_streamed - assert not resp.is_sequence - self.assert_raises(RuntimeError, lambda: resp.get_data()) - resp.make_sequence() - self.assert_equal(resp.get_data(), u'Hello Wörld!'.encode('utf-8')) - self.assert_equal(resp.response, [b'Hello ', u'Wörld!'.encode('utf-8')]) - assert not resp.is_streamed - assert resp.is_sequence - - # stream makes it a list no matter how the conversion is set - for val in True, False: - resp.implicit_sequence_conversion = val - resp.response = ("foo", "bar") - assert resp.is_sequence - resp.stream.write('baz') - self.assert_equal(resp.response, ['foo', 'bar', 'baz']) - - def test_form_data_ordering(self): - class MyRequest(wrappers.Request): - parameter_storage_class = ImmutableOrderedMultiDict - - req = MyRequest.from_values('/?foo=1&bar=0&foo=3') - self.assert_equal(list(req.args), ['foo', 'bar']) - self.assert_equal(list(req.args.items(multi=True)), [ - ('foo', '1'), - ('bar', '0'), - ('foo', '3') - ]) - self.assert_is_instance(req.args, ImmutableOrderedMultiDict) - self.assert_is_instance(req.values, CombinedMultiDict) - self.assert_equal(req.values['foo'], '1') - self.assert_equal(req.values.getlist('foo'), ['1', '3']) - - def test_storage_classes(self): - class MyRequest(wrappers.Request): - dict_storage_class = dict - list_storage_class = list - parameter_storage_class = dict - req = MyRequest.from_values('/?foo=baz', headers={ - 'Cookie': 'foo=bar' - }) - assert type(req.cookies) is dict - self.assert_equal(req.cookies, {'foo': 'bar'}) - assert type(req.access_route) is list - - assert type(req.args) is dict - assert type(req.values) is CombinedMultiDict - self.assert_equal(req.values['foo'], u'baz') - - req = wrappers.Request.from_values(headers={ - 'Cookie': 'foo=bar' - }) - assert type(req.cookies) is ImmutableTypeConversionDict - self.assert_equal(req.cookies, {'foo': 'bar'}) - assert type(req.access_route) is ImmutableList - - MyRequest.list_storage_class = tuple - req = MyRequest.from_values() - assert type(req.access_route) is tuple - - def test_response_headers_passthrough(self): - headers = wrappers.Headers() - resp = wrappers.Response(headers=headers) - assert resp.headers is headers - - def test_response_304_no_content_length(self): - resp = wrappers.Response('Test', status=304) - env = create_environ() - assert 'content-length' not in resp.get_wsgi_headers(env) - - def test_ranges(self): - # basic range stuff - req = wrappers.Request.from_values() - assert req.range is None - req = wrappers.Request.from_values(headers={'Range': 'bytes=0-499'}) - self.assert_equal(req.range.ranges, [(0, 500)]) - - resp = wrappers.Response() - resp.content_range = req.range.make_content_range(1000) - self.assert_equal(resp.content_range.units, 'bytes') - self.assert_equal(resp.content_range.start, 0) - self.assert_equal(resp.content_range.stop, 500) - self.assert_equal(resp.content_range.length, 1000) - self.assert_equal(resp.headers['Content-Range'], 'bytes 0-499/1000') - - resp.content_range.unset() - assert 'Content-Range' not in resp.headers - - resp.headers['Content-Range'] = 'bytes 0-499/1000' - self.assert_equal(resp.content_range.units, 'bytes') - self.assert_equal(resp.content_range.start, 0) - self.assert_equal(resp.content_range.stop, 500) - self.assert_equal(resp.content_range.length, 1000) - - def test_auto_content_length(self): - resp = wrappers.Response('Hello World!') - self.assert_equal(resp.content_length, 12) - - resp = wrappers.Response(['Hello World!']) - assert resp.content_length is None - self.assert_equal(resp.get_wsgi_headers({})['Content-Length'], '12') - - def test_disabled_auto_content_length(self): - class MyResponse(wrappers.Response): - automatically_set_content_length = False - resp = MyResponse('Hello World!') - self.assert_is_none(resp.content_length) - - resp = MyResponse(['Hello World!']) - self.assert_is_none(resp.content_length) - self.assert_not_in('Content-Length', resp.get_wsgi_headers({})) - - def test_location_header_autocorrect(self): - env = create_environ() - class MyResponse(wrappers.Response): - autocorrect_location_header = False - resp = MyResponse('Hello World!') - resp.headers['Location'] = '/test' - self.assert_equal(resp.get_wsgi_headers(env)['Location'], '/test') - - resp = wrappers.Response('Hello World!') - resp.headers['Location'] = '/test' - self.assert_equal(resp.get_wsgi_headers(env)['Location'], 'http://localhost/test') - - def test_modified_url_encoding(self): - class ModifiedRequest(wrappers.Request): - url_charset = 'euc-kr' - - req = ModifiedRequest.from_values(u'/?foo=정상처리'.encode('euc-kr')) - self.assert_strict_equal(req.args['foo'], u'정상처리') - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(WrappersTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/wsgi.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/wsgi.py deleted file mode 100644 index ee991fbb..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/testsuite/wsgi.py +++ /dev/null @@ -1,352 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.testsuite.wsgi - ~~~~~~~~~~~~~~~~~~~~~~~ - - Tests the WSGI utilities. - - :copyright: (c) 2014 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import unittest -from os import path -from contextlib import closing - -from werkzeug.testsuite import WerkzeugTestCase, get_temporary_directory - -from werkzeug.wrappers import BaseResponse -from werkzeug.exceptions import BadRequest, ClientDisconnected -from werkzeug.test import Client, create_environ, run_wsgi_app -from werkzeug import wsgi -from werkzeug._compat import StringIO, BytesIO, NativeStringIO, to_native - - -class WSGIUtilsTestCase(WerkzeugTestCase): - - def test_shareddatamiddleware_get_file_loader(self): - app = wsgi.SharedDataMiddleware(None, {}) - assert callable(app.get_file_loader('foo')) - - def test_shared_data_middleware(self): - def null_application(environ, start_response): - start_response('404 NOT FOUND', [('Content-Type', 'text/plain')]) - yield b'NOT FOUND' - - test_dir = get_temporary_directory() - with open(path.join(test_dir, to_native(u'äöü', 'utf-8')), 'w') as test_file: - test_file.write(u'FOUND') - - app = wsgi.SharedDataMiddleware(null_application, { - '/': path.join(path.dirname(__file__), 'res'), - '/sources': path.join(path.dirname(__file__), 'res'), - '/pkg': ('werkzeug.debug', 'shared'), - '/foo': test_dir - }) - - for p in '/test.txt', '/sources/test.txt', '/foo/äöü': - app_iter, status, headers = run_wsgi_app(app, create_environ(p)) - self.assert_equal(status, '200 OK') - with closing(app_iter) as app_iter: - data = b''.join(app_iter).strip() - self.assert_equal(data, b'FOUND') - - app_iter, status, headers = run_wsgi_app( - app, create_environ('/pkg/debugger.js')) - with closing(app_iter) as app_iter: - contents = b''.join(app_iter) - self.assert_in(b'$(function() {', contents) - - app_iter, status, headers = run_wsgi_app( - app, create_environ('/missing')) - self.assert_equal(status, '404 NOT FOUND') - self.assert_equal(b''.join(app_iter).strip(), b'NOT FOUND') - - - def test_get_host(self): - env = {'HTTP_X_FORWARDED_HOST': 'example.org', - 'SERVER_NAME': 'bullshit', 'HOST_NAME': 'ignore me dammit'} - self.assert_equal(wsgi.get_host(env), 'example.org') - self.assert_equal( - wsgi.get_host(create_environ('/', 'http://example.org')), - 'example.org') - - def test_get_host_multiple_forwarded(self): - env = {'HTTP_X_FORWARDED_HOST': 'example.com, example.org', - 'SERVER_NAME': 'bullshit', 'HOST_NAME': 'ignore me dammit'} - self.assert_equal(wsgi.get_host(env), 'example.com') - self.assert_equal( - wsgi.get_host(create_environ('/', 'http://example.com')), - 'example.com') - - def test_get_host_validation(self): - env = {'HTTP_X_FORWARDED_HOST': 'example.org', - 'SERVER_NAME': 'bullshit', 'HOST_NAME': 'ignore me dammit'} - self.assert_equal(wsgi.get_host(env, trusted_hosts=['.example.org']), - 'example.org') - self.assert_raises(BadRequest, wsgi.get_host, env, - trusted_hosts=['example.com']) - - def test_responder(self): - def foo(environ, start_response): - return BaseResponse(b'Test') - client = Client(wsgi.responder(foo), BaseResponse) - response = client.get('/') - self.assert_equal(response.status_code, 200) - self.assert_equal(response.data, b'Test') - - def test_pop_path_info(self): - original_env = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/a/b///c'} - - # regular path info popping - def assert_tuple(script_name, path_info): - self.assert_equal(env.get('SCRIPT_NAME'), script_name) - self.assert_equal(env.get('PATH_INFO'), path_info) - env = original_env.copy() - pop = lambda: wsgi.pop_path_info(env) - - assert_tuple('/foo', '/a/b///c') - self.assert_equal(pop(), 'a') - assert_tuple('/foo/a', '/b///c') - self.assert_equal(pop(), 'b') - assert_tuple('/foo/a/b', '///c') - self.assert_equal(pop(), 'c') - assert_tuple('/foo/a/b///c', '') - self.assert_is_none(pop()) - - def test_peek_path_info(self): - env = { - 'SCRIPT_NAME': '/foo', - 'PATH_INFO': '/aaa/b///c' - } - - self.assert_equal(wsgi.peek_path_info(env), 'aaa') - self.assert_equal(wsgi.peek_path_info(env), 'aaa') - self.assert_equal(wsgi.peek_path_info(env, charset=None), b'aaa') - self.assert_equal(wsgi.peek_path_info(env, charset=None), b'aaa') - - def test_path_info_and_script_name_fetching(self): - env = create_environ(u'/\N{SNOWMAN}', u'http://example.com/\N{COMET}/') - self.assert_equal(wsgi.get_path_info(env), u'/\N{SNOWMAN}') - self.assert_equal(wsgi.get_path_info(env, charset=None), u'/\N{SNOWMAN}'.encode('utf-8')) - self.assert_equal(wsgi.get_script_name(env), u'/\N{COMET}') - self.assert_equal(wsgi.get_script_name(env, charset=None), u'/\N{COMET}'.encode('utf-8')) - - def test_query_string_fetching(self): - env = create_environ(u'/?\N{SNOWMAN}=\N{COMET}') - qs = wsgi.get_query_string(env) - self.assert_strict_equal(qs, '%E2%98%83=%E2%98%84') - - def test_limited_stream(self): - class RaisingLimitedStream(wsgi.LimitedStream): - def on_exhausted(self): - raise BadRequest('input stream exhausted') - - io = BytesIO(b'123456') - stream = RaisingLimitedStream(io, 3) - self.assert_strict_equal(stream.read(), b'123') - self.assert_raises(BadRequest, stream.read) - - io = BytesIO(b'123456') - stream = RaisingLimitedStream(io, 3) - self.assert_strict_equal(stream.tell(), 0) - self.assert_strict_equal(stream.read(1), b'1') - self.assert_strict_equal(stream.tell(), 1) - self.assert_strict_equal(stream.read(1), b'2') - self.assert_strict_equal(stream.tell(), 2) - self.assert_strict_equal(stream.read(1), b'3') - self.assert_strict_equal(stream.tell(), 3) - self.assert_raises(BadRequest, stream.read) - - io = BytesIO(b'123456\nabcdefg') - stream = wsgi.LimitedStream(io, 9) - self.assert_strict_equal(stream.readline(), b'123456\n') - self.assert_strict_equal(stream.readline(), b'ab') - - io = BytesIO(b'123456\nabcdefg') - stream = wsgi.LimitedStream(io, 9) - self.assert_strict_equal(stream.readlines(), [b'123456\n', b'ab']) - - io = BytesIO(b'123456\nabcdefg') - stream = wsgi.LimitedStream(io, 9) - self.assert_strict_equal(stream.readlines(2), [b'12']) - self.assert_strict_equal(stream.readlines(2), [b'34']) - self.assert_strict_equal(stream.readlines(), [b'56\n', b'ab']) - - io = BytesIO(b'123456\nabcdefg') - stream = wsgi.LimitedStream(io, 9) - self.assert_strict_equal(stream.readline(100), b'123456\n') - - io = BytesIO(b'123456\nabcdefg') - stream = wsgi.LimitedStream(io, 9) - self.assert_strict_equal(stream.readlines(100), [b'123456\n', b'ab']) - - io = BytesIO(b'123456') - stream = wsgi.LimitedStream(io, 3) - self.assert_strict_equal(stream.read(1), b'1') - self.assert_strict_equal(stream.read(1), b'2') - self.assert_strict_equal(stream.read(), b'3') - self.assert_strict_equal(stream.read(), b'') - - io = BytesIO(b'123456') - stream = wsgi.LimitedStream(io, 3) - self.assert_strict_equal(stream.read(-1), b'123') - - io = BytesIO(b'123456') - stream = wsgi.LimitedStream(io, 0) - self.assert_strict_equal(stream.read(-1), b'') - - io = StringIO(u'123456') - stream = wsgi.LimitedStream(io, 0) - self.assert_strict_equal(stream.read(-1), u'') - - io = StringIO(u'123\n456\n') - stream = wsgi.LimitedStream(io, 8) - self.assert_strict_equal(list(stream), [u'123\n', u'456\n']) - - def test_limited_stream_disconnection(self): - io = BytesIO(b'A bit of content') - - # disconnect detection on out of bytes - stream = wsgi.LimitedStream(io, 255) - with self.assert_raises(ClientDisconnected): - stream.read() - - # disconnect detection because file close - io = BytesIO(b'x' * 255) - io.close() - stream = wsgi.LimitedStream(io, 255) - with self.assert_raises(ClientDisconnected): - stream.read() - - def test_path_info_extraction(self): - x = wsgi.extract_path_info('http://example.com/app', '/app/hello') - self.assert_equal(x, u'/hello') - x = wsgi.extract_path_info('http://example.com/app', - 'https://example.com/app/hello') - self.assert_equal(x, u'/hello') - x = wsgi.extract_path_info('http://example.com/app/', - 'https://example.com/app/hello') - self.assert_equal(x, u'/hello') - x = wsgi.extract_path_info('http://example.com/app/', - 'https://example.com/app') - self.assert_equal(x, u'/') - x = wsgi.extract_path_info(u'http://☃.net/', u'/fööbär') - self.assert_equal(x, u'/fööbär') - x = wsgi.extract_path_info(u'http://☃.net/x', u'http://☃.net/x/fööbär') - self.assert_equal(x, u'/fööbär') - - env = create_environ(u'/fööbär', u'http://☃.net/x/') - x = wsgi.extract_path_info(env, u'http://☃.net/x/fööbär') - self.assert_equal(x, u'/fööbär') - - x = wsgi.extract_path_info('http://example.com/app/', - 'https://example.com/a/hello') - self.assert_is_none(x) - x = wsgi.extract_path_info('http://example.com/app/', - 'https://example.com/app/hello', - collapse_http_schemes=False) - self.assert_is_none(x) - - def test_get_host_fallback(self): - self.assert_equal(wsgi.get_host({ - 'SERVER_NAME': 'foobar.example.com', - 'wsgi.url_scheme': 'http', - 'SERVER_PORT': '80' - }), 'foobar.example.com') - self.assert_equal(wsgi.get_host({ - 'SERVER_NAME': 'foobar.example.com', - 'wsgi.url_scheme': 'http', - 'SERVER_PORT': '81' - }), 'foobar.example.com:81') - - def test_get_current_url_unicode(self): - env = create_environ() - env['QUERY_STRING'] = 'foo=bar&baz=blah&meh=\xcf' - rv = wsgi.get_current_url(env) - self.assert_strict_equal(rv, - u'http://localhost/?foo=bar&baz=blah&meh=\ufffd') - - def test_multi_part_line_breaks(self): - data = 'abcdef\r\nghijkl\r\nmnopqrstuvwxyz\r\nABCDEFGHIJK' - test_stream = NativeStringIO(data) - lines = list(wsgi.make_line_iter(test_stream, limit=len(data), - buffer_size=16)) - self.assert_equal(lines, ['abcdef\r\n', 'ghijkl\r\n', - 'mnopqrstuvwxyz\r\n', 'ABCDEFGHIJK']) - - data = 'abc\r\nThis line is broken by the buffer length.' \ - '\r\nFoo bar baz' - test_stream = NativeStringIO(data) - lines = list(wsgi.make_line_iter(test_stream, limit=len(data), - buffer_size=24)) - self.assert_equal(lines, ['abc\r\n', 'This line is broken by the ' - 'buffer length.\r\n', 'Foo bar baz']) - - def test_multi_part_line_breaks_bytes(self): - data = b'abcdef\r\nghijkl\r\nmnopqrstuvwxyz\r\nABCDEFGHIJK' - test_stream = BytesIO(data) - lines = list(wsgi.make_line_iter(test_stream, limit=len(data), - buffer_size=16)) - self.assert_equal(lines, [b'abcdef\r\n', b'ghijkl\r\n', - b'mnopqrstuvwxyz\r\n', b'ABCDEFGHIJK']) - - data = b'abc\r\nThis line is broken by the buffer length.' \ - b'\r\nFoo bar baz' - test_stream = BytesIO(data) - lines = list(wsgi.make_line_iter(test_stream, limit=len(data), - buffer_size=24)) - self.assert_equal(lines, [b'abc\r\n', b'This line is broken by the ' - b'buffer length.\r\n', b'Foo bar baz']) - - def test_multi_part_line_breaks_problematic(self): - data = 'abc\rdef\r\nghi' - for x in range(1, 10): - test_stream = NativeStringIO(data) - lines = list(wsgi.make_line_iter(test_stream, limit=len(data), - buffer_size=4)) - self.assert_equal(lines, ['abc\r', 'def\r\n', 'ghi']) - - def test_iter_functions_support_iterators(self): - data = ['abcdef\r\nghi', 'jkl\r\nmnopqrstuvwxyz\r', '\nABCDEFGHIJK'] - lines = list(wsgi.make_line_iter(data)) - self.assert_equal(lines, ['abcdef\r\n', 'ghijkl\r\n', - 'mnopqrstuvwxyz\r\n', 'ABCDEFGHIJK']) - - def test_make_chunk_iter(self): - data = [u'abcdefXghi', u'jklXmnopqrstuvwxyzX', u'ABCDEFGHIJK'] - rv = list(wsgi.make_chunk_iter(data, 'X')) - self.assert_equal(rv, [u'abcdef', u'ghijkl', u'mnopqrstuvwxyz', - u'ABCDEFGHIJK']) - - data = u'abcdefXghijklXmnopqrstuvwxyzXABCDEFGHIJK' - test_stream = StringIO(data) - rv = list(wsgi.make_chunk_iter(test_stream, 'X', limit=len(data), - buffer_size=4)) - self.assert_equal(rv, [u'abcdef', u'ghijkl', u'mnopqrstuvwxyz', - u'ABCDEFGHIJK']) - - def test_make_chunk_iter_bytes(self): - data = [b'abcdefXghi', b'jklXmnopqrstuvwxyzX', b'ABCDEFGHIJK'] - rv = list(wsgi.make_chunk_iter(data, 'X')) - self.assert_equal(rv, [b'abcdef', b'ghijkl', b'mnopqrstuvwxyz', - b'ABCDEFGHIJK']) - - data = b'abcdefXghijklXmnopqrstuvwxyzXABCDEFGHIJK' - test_stream = BytesIO(data) - rv = list(wsgi.make_chunk_iter(test_stream, 'X', limit=len(data), - buffer_size=4)) - self.assert_equal(rv, [b'abcdef', b'ghijkl', b'mnopqrstuvwxyz', - b'ABCDEFGHIJK']) - - def test_lines_longer_buffer_size(self): - data = '1234567890\n1234567890\n' - for bufsize in range(1, 15): - lines = list(wsgi.make_line_iter(NativeStringIO(data), limit=len(data), - buffer_size=4)) - self.assert_equal(lines, ['1234567890\n', '1234567890\n']) - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(WSGIUtilsTestCase)) - return suite diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/urls.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/urls.py deleted file mode 100644 index 42c54797..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/urls.py +++ /dev/null @@ -1,916 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.urls - ~~~~~~~~~~~~~ - - This module implements various URL related functions. - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -import re -from werkzeug._compat import text_type, PY2, to_unicode, \ - to_native, implements_to_string, try_coerce_native, \ - normalize_string_tuple, make_literal_wrapper, \ - fix_tuple_repr -from werkzeug._internal import _encode_idna, _decode_idna -from werkzeug.datastructures import MultiDict, iter_multi_items -from collections import namedtuple - - -# A regular expression for what a valid schema looks like -_scheme_re = re.compile(r'^[a-zA-Z0-9+-.]+$') - -# Characters that are safe in any part of an URL. -_always_safe = (b'abcdefghijklmnopqrstuvwxyz' - b'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-+') - -_hexdigits = '0123456789ABCDEFabcdef' -_hextobyte = dict( - ((a + b).encode(), int(a + b, 16)) - for a in _hexdigits for b in _hexdigits -) - - -_URLTuple = fix_tuple_repr(namedtuple('_URLTuple', - ['scheme', 'netloc', 'path', 'query', 'fragment'])) - - -class _URLMixin(object): - __slots__ = () - - def replace(self, **kwargs): - """Return an URL with the same values, except for those parameters - given new values by whichever keyword arguments are specified.""" - return self._replace(**kwargs) - - @property - def host(self): - """The host part of the URL if available, otherwise `None`. The - host is either the hostname or the IP address mentioned in the - URL. It will not contain the port. - """ - return self._split_host()[0] - - @property - def ascii_host(self): - """Works exactly like :attr:`host` but will return a result that - is restricted to ASCII. If it finds a netloc that is not ASCII - it will attempt to idna decode it. This is useful for socket - operations when the URL might include internationalized characters. - """ - rv = self.host - if rv is not None and isinstance(rv, text_type): - rv = _encode_idna(rv) - return to_native(rv, 'ascii', 'ignore') - - @property - def port(self): - """The port in the URL as an integer if it was present, `None` - otherwise. This does not fill in default ports. - """ - try: - rv = int(to_native(self._split_host()[1])) - if 0 <= rv <= 65535: - return rv - except (ValueError, TypeError): - pass - - @property - def auth(self): - """The authentication part in the URL if available, `None` - otherwise. - """ - return self._split_netloc()[0] - - @property - def username(self): - """The username if it was part of the URL, `None` otherwise. - This undergoes URL decoding and will always be a unicode string. - """ - rv = self._split_auth()[0] - if rv is not None: - return _url_unquote_legacy(rv) - - @property - def raw_username(self): - """The username if it was part of the URL, `None` otherwise. - Unlike :attr:`username` this one is not being decoded. - """ - return self._split_auth()[0] - - @property - def password(self): - """The password if it was part of the URL, `None` otherwise. - This undergoes URL decoding and will always be a unicode string. - """ - rv = self._split_auth()[1] - if rv is not None: - return _url_unquote_legacy(rv) - - @property - def raw_password(self): - """The password if it was part of the URL, `None` otherwise. - Unlike :attr:`password` this one is not being decoded. - """ - return self._split_auth()[1] - - def decode_query(self, *args, **kwargs): - """Decodes the query part of the URL. Ths is a shortcut for - calling :func:`url_decode` on the query argument. The arguments and - keyword arguments are forwarded to :func:`url_decode` unchanged. - """ - return url_decode(self.query, *args, **kwargs) - - def join(self, *args, **kwargs): - """Joins this URL with another one. This is just a convenience - function for calling into :meth:`url_join` and then parsing the - return value again. - """ - return url_parse(url_join(self, *args, **kwargs)) - - def to_url(self): - """Returns a URL string or bytes depending on the type of the - information stored. This is just a convenience function - for calling :meth:`url_unparse` for this URL. - """ - return url_unparse(self) - - def decode_netloc(self): - """Decodes the netloc part into a string.""" - rv = _decode_idna(self.host or '') - - if ':' in rv: - rv = '[%s]' % rv - port = self.port - if port is not None: - rv = '%s:%d' % (rv, port) - auth = ':'.join(filter(None, [ - _url_unquote_legacy(self.raw_username or '', '/:%@'), - _url_unquote_legacy(self.raw_password or '', '/:%@'), - ])) - if auth: - rv = '%s@%s' % (auth, rv) - return rv - - def to_uri_tuple(self): - """Returns a :class:`BytesURL` tuple that holds a URI. This will - encode all the information in the URL properly to ASCII using the - rules a web browser would follow. - - It's usually more interesting to directly call :meth:`iri_to_uri` which - will return a string. - """ - return url_parse(iri_to_uri(self).encode('ascii')) - - def to_iri_tuple(self): - """Returns a :class:`URL` tuple that holds a IRI. This will try - to decode as much information as possible in the URL without - losing information similar to how a web browser does it for the - URL bar. - - It's usually more interesting to directly call :meth:`uri_to_iri` which - will return a string. - """ - return url_parse(uri_to_iri(self)) - - def _split_netloc(self): - if self._at in self.netloc: - return self.netloc.split(self._at, 1) - return None, self.netloc - - def _split_auth(self): - auth = self._split_netloc()[0] - if not auth: - return None, None - if self._colon not in auth: - return auth, None - return auth.split(self._colon, 1) - - def _split_host(self): - rv = self._split_netloc()[1] - if not rv: - return None, None - - if not rv.startswith(self._lbracket): - if self._colon in rv: - return rv.split(self._colon, 1) - return rv, None - - idx = rv.find(self._rbracket) - if idx < 0: - return rv, None - - host = rv[1:idx] - rest = rv[idx + 1:] - if rest.startswith(self._colon): - return host, rest[1:] - return host, None - - -@implements_to_string -class URL(_URLTuple, _URLMixin): - """Represents a parsed URL. This behaves like a regular tuple but - also has some extra attributes that give further insight into the - URL. - """ - __slots__ = () - _at = '@' - _colon = ':' - _lbracket = '[' - _rbracket = ']' - - def __str__(self): - return self.to_url() - - def encode_netloc(self): - """Encodes the netloc part to an ASCII safe URL as bytes.""" - rv = self.ascii_host or '' - if ':' in rv: - rv = '[%s]' % rv - port = self.port - if port is not None: - rv = '%s:%d' % (rv, port) - auth = ':'.join(filter(None, [ - url_quote(self.raw_username or '', 'utf-8', 'strict', '/:%'), - url_quote(self.raw_password or '', 'utf-8', 'strict', '/:%'), - ])) - if auth: - rv = '%s@%s' % (auth, rv) - return rv.encode('ascii') - - def encode(self, charset='utf-8', errors='replace'): - """Encodes the URL to a tuple made out of bytes. The charset is - only being used for the path, query and fragment. - """ - return BytesURL( - self.scheme.encode('ascii'), - self.encode_netloc(), - self.path.encode(charset, errors), - self.query.encode(charset, errors), - self.fragment.encode(charset, errors) - ) - - -class BytesURL(_URLTuple, _URLMixin): - """Represents a parsed URL in bytes.""" - __slots__ = () - _at = b'@' - _colon = b':' - _lbracket = b'[' - _rbracket = b']' - - def __str__(self): - return self.to_url().decode('utf-8', 'replace') - - def encode_netloc(self): - """Returns the netloc unchanged as bytes.""" - return self.netloc - - def decode(self, charset='utf-8', errors='replace'): - """Decodes the URL to a tuple made out of strings. The charset is - only being used for the path, query and fragment. - """ - return URL( - self.scheme.decode('ascii'), - self.decode_netloc(), - self.path.decode(charset, errors), - self.query.decode(charset, errors), - self.fragment.decode(charset, errors) - ) - - -def _unquote_to_bytes(string, unsafe=''): - if isinstance(string, text_type): - string = string.encode('utf-8') - if isinstance(unsafe, text_type): - unsafe = unsafe.encode('utf-8') - unsafe = frozenset(bytearray(unsafe)) - bits = iter(string.split(b'%')) - result = bytearray(next(bits, b'')) - for item in bits: - try: - char = _hextobyte[item[:2]] - if char in unsafe: - raise KeyError() - result.append(char) - result.extend(item[2:]) - except KeyError: - result.extend(b'%') - result.extend(item) - return bytes(result) - - -def _url_encode_impl(obj, charset, encode_keys, sort, key): - iterable = iter_multi_items(obj) - if sort: - iterable = sorted(iterable, key=key) - for key, value in iterable: - if value is None: - continue - if not isinstance(key, bytes): - key = text_type(key).encode(charset) - if not isinstance(value, bytes): - value = text_type(value).encode(charset) - yield url_quote_plus(key) + '=' + url_quote_plus(value) - - -def _url_unquote_legacy(value, unsafe=''): - try: - return url_unquote(value, charset='utf-8', - errors='strict', unsafe=unsafe) - except UnicodeError: - return url_unquote(value, charset='latin1', unsafe=unsafe) - - -def url_parse(url, scheme=None, allow_fragments=True): - """Parses a URL from a string into a :class:`URL` tuple. If the URL - is lacking a scheme it can be provided as second argument. Otherwise, - it is ignored. Optionally fragments can be stripped from the URL - by setting `allow_fragments` to `False`. - - The inverse of this function is :func:`url_unparse`. - - :param url: the URL to parse. - :param scheme: the default schema to use if the URL is schemaless. - :param allow_fragments: if set to `False` a fragment will be removed - from the URL. - """ - s = make_literal_wrapper(url) - is_text_based = isinstance(url, text_type) - - if scheme is None: - scheme = s('') - netloc = query = fragment = s('') - i = url.find(s(':')) - if i > 0 and _scheme_re.match(to_native(url[:i], errors='replace')): - # make sure "iri" is not actually a port number (in which case - # "scheme" is really part of the path) - rest = url[i + 1:] - if not rest or any(c not in s('0123456789') for c in rest): - # not a port number - scheme, url = url[:i].lower(), rest - - if url[:2] == s('//'): - delim = len(url) - for c in s('/?#'): - wdelim = url.find(c, 2) - if wdelim >= 0: - delim = min(delim, wdelim) - netloc, url = url[2:delim], url[delim:] - if (s('[') in netloc and s(']') not in netloc) or \ - (s(']') in netloc and s('[') not in netloc): - raise ValueError('Invalid IPv6 URL') - - if allow_fragments and s('#') in url: - url, fragment = url.split(s('#'), 1) - if s('?') in url: - url, query = url.split(s('?'), 1) - - result_type = is_text_based and URL or BytesURL - return result_type(scheme, netloc, url, query, fragment) - - -def url_quote(string, charset='utf-8', errors='strict', safe='/:', unsafe=''): - """URL encode a single string with a given encoding. - - :param s: the string to quote. - :param charset: the charset to be used. - :param safe: an optional sequence of safe characters. - :param unsafe: an optional sequence of unsafe characters. - - .. versionadded:: 0.9.2 - The `unsafe` parameter was added. - """ - if not isinstance(string, (text_type, bytes, bytearray)): - string = text_type(string) - if isinstance(string, text_type): - string = string.encode(charset, errors) - if isinstance(safe, text_type): - safe = safe.encode(charset, errors) - if isinstance(unsafe, text_type): - unsafe = unsafe.encode(charset, errors) - safe = frozenset(bytearray(safe) + _always_safe) - frozenset(bytearray(unsafe)) - rv = bytearray() - for char in bytearray(string): - if char in safe: - rv.append(char) - else: - rv.extend(('%%%02X' % char).encode('ascii')) - return to_native(bytes(rv)) - - -def url_quote_plus(string, charset='utf-8', errors='strict', safe=''): - """URL encode a single string with the given encoding and convert - whitespace to "+". - - :param s: The string to quote. - :param charset: The charset to be used. - :param safe: An optional sequence of safe characters. - """ - return url_quote(string, charset, errors, safe + ' ', '+').replace(' ', '+') - - -def url_unparse(components): - """The reverse operation to :meth:`url_parse`. This accepts arbitrary - as well as :class:`URL` tuples and returns a URL as a string. - - :param components: the parsed URL as tuple which should be converted - into a URL string. - """ - scheme, netloc, path, query, fragment = \ - normalize_string_tuple(components) - s = make_literal_wrapper(scheme) - url = s('') - - # We generally treat file:///x and file:/x the same which is also - # what browsers seem to do. This also allows us to ignore a schema - # register for netloc utilization or having to differenciate between - # empty and missing netloc. - if netloc or (scheme and path.startswith(s('/'))): - if path and path[:1] != s('/'): - path = s('/') + path - url = s('//') + (netloc or s('')) + path - elif path: - url += path - if scheme: - url = scheme + s(':') + url - if query: - url = url + s('?') + query - if fragment: - url = url + s('#') + fragment - return url - - -def url_unquote(string, charset='utf-8', errors='replace', unsafe=''): - """URL decode a single string with a given encoding. If the charset - is set to `None` no unicode decoding is performed and raw bytes - are returned. - - :param s: the string to unquote. - :param charset: the charset of the query string. If set to `None` - no unicode decoding will take place. - :param errors: the error handling for the charset decoding. - """ - rv = _unquote_to_bytes(string, unsafe) - if charset is not None: - rv = rv.decode(charset, errors) - return rv - - -def url_unquote_plus(s, charset='utf-8', errors='replace'): - """URL decode a single string with the given `charset` and decode "+" to - whitespace. - - Per default encoding errors are ignored. If you want a different behavior - you can set `errors` to ``'replace'`` or ``'strict'``. In strict mode a - :exc:`HTTPUnicodeError` is raised. - - :param s: The string to unquote. - :param charset: the charset of the query string. If set to `None` - no unicode decoding will take place. - :param errors: The error handling for the `charset` decoding. - """ - if isinstance(s, text_type): - s = s.replace(u'+', u' ') - else: - s = s.replace(b'+', b' ') - return url_unquote(s, charset, errors) - - -def url_fix(s, charset='utf-8'): - r"""Sometimes you get an URL by a user that just isn't a real URL because - it contains unsafe characters like ' ' and so on. This function can fix - some of the problems in a similar way browsers handle data entered by the - user: - - >>> url_fix(u'http://de.wikipedia.org/wiki/Elf (Begriffskl\xe4rung)') - 'http://de.wikipedia.org/wiki/Elf%20(Begriffskl%C3%A4rung)' - - :param s: the string with the URL to fix. - :param charset: The target charset for the URL if the url was given as - unicode string. - """ - scheme, netloc, path, qs, anchor = url_parse(to_unicode(s, charset, 'replace')) - path = url_quote(path, charset, safe='/%+$!*\'(),') - qs = url_quote_plus(qs, charset, safe=':&%=+$!*\'(),') - return to_native(url_unparse((scheme, netloc, path, qs, anchor))) - - -def uri_to_iri(uri, charset='utf-8', errors='replace'): - r""" - Converts a URI in a given charset to a IRI. - - Examples for URI versus IRI: - - >>> uri_to_iri(b'http://xn--n3h.net/') - u'http://\u2603.net/' - >>> uri_to_iri(b'http://%C3%BCser:p%C3%A4ssword@xn--n3h.net/p%C3%A5th') - u'http://\xfcser:p\xe4ssword@\u2603.net/p\xe5th' - - Query strings are left unchanged: - - >>> uri_to_iri('/?foo=24&x=%26%2f') - u'/?foo=24&x=%26%2f' - - .. versionadded:: 0.6 - - :param uri: The URI to convert. - :param charset: The charset of the URI. - :param errors: The error handling on decode. - """ - if isinstance(uri, tuple): - uri = url_unparse(uri) - uri = url_parse(to_unicode(uri, charset)) - path = url_unquote(uri.path, charset, errors, '%/;?') - query = url_unquote(uri.query, charset, errors, '%;/?:@&=+,$') - fragment = url_unquote(uri.fragment, charset, errors, '%;/?:@&=+,$') - return url_unparse((uri.scheme, uri.decode_netloc(), - path, query, fragment)) - - -def iri_to_uri(iri, charset='utf-8', errors='strict', safe_conversion=False): - r""" - Converts any unicode based IRI to an acceptable ASCII URI. Werkzeug always - uses utf-8 URLs internally because this is what browsers and HTTP do as - well. In some places where it accepts an URL it also accepts a unicode IRI - and converts it into a URI. - - Examples for IRI versus URI: - - >>> iri_to_uri(u'http://☃.net/') - 'http://xn--n3h.net/' - >>> iri_to_uri(u'http://üser:pässword@☃.net/påth') - 'http://%C3%BCser:p%C3%A4ssword@xn--n3h.net/p%C3%A5th' - - There is a general problem with IRI and URI conversion with some - protocols that appear in the wild that are in violation of the URI - specification. In places where Werkzeug goes through a forced IRI to - URI conversion it will set the `safe_conversion` flag which will - not perform a conversion if the end result is already ASCII. This - can mean that the return value is not an entirely correct URI but - it will not destroy such invalid URLs in the process. - - As an example consider the following two IRIs:: - - magnet:?xt=uri:whatever - itms-services://?action=download-manifest - - The internal representation after parsing of those URLs is the same - and there is no way to reconstruct the original one. If safe - conversion is enabled however this function becomes a noop for both of - those strings as they both can be considered URIs. - - .. versionadded:: 0.6 - - .. versionchanged:: 0.9.6 - The `safe_conversion` parameter was added. - - :param iri: The IRI to convert. - :param charset: The charset for the URI. - :param safe_conversion: indicates if a safe conversion should take place. - For more information see the explanation above. - """ - if isinstance(iri, tuple): - iri = url_unparse(iri) - - if safe_conversion: - try: - native_iri = to_native(iri) - ascii_iri = to_native(iri).encode('ascii') - if ascii_iri.split() == [ascii_iri]: - return native_iri - except UnicodeError: - pass - - iri = url_parse(to_unicode(iri, charset, errors)) - - netloc = iri.encode_netloc().decode('ascii') - path = url_quote(iri.path, charset, errors, '/:~+%') - query = url_quote(iri.query, charset, errors, '%&[]:;$*()+,!?*/=') - fragment = url_quote(iri.fragment, charset, errors, '=%&[]:;$()+,!?*/') - - return to_native(url_unparse((iri.scheme, netloc, - path, query, fragment))) - - -def url_decode(s, charset='utf-8', decode_keys=False, include_empty=True, - errors='replace', separator='&', cls=None): - """ - Parse a querystring and return it as :class:`MultiDict`. There is a - difference in key decoding on different Python versions. On Python 3 - keys will always be fully decoded whereas on Python 2, keys will - remain bytestrings if they fit into ASCII. On 2.x keys can be forced - to be unicode by setting `decode_keys` to `True`. - - If the charset is set to `None` no unicode decoding will happen and - raw bytes will be returned. - - Per default a missing value for a key will default to an empty key. If - you don't want that behavior you can set `include_empty` to `False`. - - Per default encoding errors are ignored. If you want a different behavior - you can set `errors` to ``'replace'`` or ``'strict'``. In strict mode a - `HTTPUnicodeError` is raised. - - .. versionchanged:: 0.5 - In previous versions ";" and "&" could be used for url decoding. - This changed in 0.5 where only "&" is supported. If you want to - use ";" instead a different `separator` can be provided. - - The `cls` parameter was added. - - :param s: a string with the query string to decode. - :param charset: the charset of the query string. If set to `None` - no unicode decoding will take place. - :param decode_keys: Used on Python 2.x to control whether keys should - be forced to be unicode objects. If set to `True` - then keys will be unicode in all cases. Otherwise, - they remain `str` if they fit into ASCII. - :param include_empty: Set to `False` if you don't want empty values to - appear in the dict. - :param errors: the decoding error behavior. - :param separator: the pair separator to be used, defaults to ``&`` - :param cls: an optional dict class to use. If this is not specified - or `None` the default :class:`MultiDict` is used. - """ - if cls is None: - cls = MultiDict - if isinstance(s, text_type) and not isinstance(separator, text_type): - separator = separator.decode(charset or 'ascii') - elif isinstance(s, bytes) and not isinstance(separator, bytes): - separator = separator.encode(charset or 'ascii') - return cls(_url_decode_impl(s.split(separator), charset, decode_keys, - include_empty, errors)) - - -def url_decode_stream(stream, charset='utf-8', decode_keys=False, - include_empty=True, errors='replace', separator='&', - cls=None, limit=None, return_iterator=False): - """Works like :func:`url_decode` but decodes a stream. The behavior - of stream and limit follows functions like - :func:`~werkzeug.wsgi.make_line_iter`. The generator of pairs is - directly fed to the `cls` so you can consume the data while it's - parsed. - - .. versionadded:: 0.8 - - :param stream: a stream with the encoded querystring - :param charset: the charset of the query string. If set to `None` - no unicode decoding will take place. - :param decode_keys: Used on Python 2.x to control whether keys should - be forced to be unicode objects. If set to `True`, - keys will be unicode in all cases. Otherwise, they - remain `str` if they fit into ASCII. - :param include_empty: Set to `False` if you don't want empty values to - appear in the dict. - :param errors: the decoding error behavior. - :param separator: the pair separator to be used, defaults to ``&`` - :param cls: an optional dict class to use. If this is not specified - or `None` the default :class:`MultiDict` is used. - :param limit: the content length of the URL data. Not necessary if - a limited stream is provided. - :param return_iterator: if set to `True` the `cls` argument is ignored - and an iterator over all decoded pairs is - returned - """ - from werkzeug.wsgi import make_chunk_iter - if return_iterator: - cls = lambda x: x - elif cls is None: - cls = MultiDict - pair_iter = make_chunk_iter(stream, separator, limit) - return cls(_url_decode_impl(pair_iter, charset, decode_keys, - include_empty, errors)) - - -def _url_decode_impl(pair_iter, charset, decode_keys, include_empty, errors): - for pair in pair_iter: - if not pair: - continue - s = make_literal_wrapper(pair) - equal = s('=') - if equal in pair: - key, value = pair.split(equal, 1) - else: - if not include_empty: - continue - key = pair - value = s('') - key = url_unquote_plus(key, charset, errors) - if charset is not None and PY2 and not decode_keys: - key = try_coerce_native(key) - yield key, url_unquote_plus(value, charset, errors) - - -def url_encode(obj, charset='utf-8', encode_keys=False, sort=False, key=None, - separator=b'&'): - """URL encode a dict/`MultiDict`. If a value is `None` it will not appear - in the result string. Per default only values are encoded into the target - charset strings. If `encode_keys` is set to ``True`` unicode keys are - supported too. - - If `sort` is set to `True` the items are sorted by `key` or the default - sorting algorithm. - - .. versionadded:: 0.5 - `sort`, `key`, and `separator` were added. - - :param obj: the object to encode into a query string. - :param charset: the charset of the query string. - :param encode_keys: set to `True` if you have unicode keys. (Ignored on - Python 3.x) - :param sort: set to `True` if you want parameters to be sorted by `key`. - :param separator: the separator to be used for the pairs. - :param key: an optional function to be used for sorting. For more details - check out the :func:`sorted` documentation. - """ - separator = to_native(separator, 'ascii') - return separator.join(_url_encode_impl(obj, charset, encode_keys, sort, key)) - - -def url_encode_stream(obj, stream=None, charset='utf-8', encode_keys=False, - sort=False, key=None, separator=b'&'): - """Like :meth:`url_encode` but writes the results to a stream - object. If the stream is `None` a generator over all encoded - pairs is returned. - - .. versionadded:: 0.8 - - :param obj: the object to encode into a query string. - :param stream: a stream to write the encoded object into or `None` if - an iterator over the encoded pairs should be returned. In - that case the separator argument is ignored. - :param charset: the charset of the query string. - :param encode_keys: set to `True` if you have unicode keys. (Ignored on - Python 3.x) - :param sort: set to `True` if you want parameters to be sorted by `key`. - :param separator: the separator to be used for the pairs. - :param key: an optional function to be used for sorting. For more details - check out the :func:`sorted` documentation. - """ - separator = to_native(separator, 'ascii') - gen = _url_encode_impl(obj, charset, encode_keys, sort, key) - if stream is None: - return gen - for idx, chunk in enumerate(gen): - if idx: - stream.write(separator) - stream.write(chunk) - - -def url_join(base, url, allow_fragments=True): - """Join a base URL and a possibly relative URL to form an absolute - interpretation of the latter. - - :param base: the base URL for the join operation. - :param url: the URL to join. - :param allow_fragments: indicates whether fragments should be allowed. - """ - if isinstance(base, tuple): - base = url_unparse(base) - if isinstance(url, tuple): - url = url_unparse(url) - - base, url = normalize_string_tuple((base, url)) - s = make_literal_wrapper(base) - - if not base: - return url - if not url: - return base - - bscheme, bnetloc, bpath, bquery, bfragment = \ - url_parse(base, allow_fragments=allow_fragments) - scheme, netloc, path, query, fragment = \ - url_parse(url, bscheme, allow_fragments) - if scheme != bscheme: - return url - if netloc: - return url_unparse((scheme, netloc, path, query, fragment)) - netloc = bnetloc - - if path[:1] == s('/'): - segments = path.split(s('/')) - elif not path: - segments = bpath.split(s('/')) - if not query: - query = bquery - else: - segments = bpath.split(s('/'))[:-1] + path.split(s('/')) - - # If the rightmost part is "./" we want to keep the slash but - # remove the dot. - if segments[-1] == s('.'): - segments[-1] = s('') - - # Resolve ".." and "." - segments = [segment for segment in segments if segment != s('.')] - while 1: - i = 1 - n = len(segments) - 1 - while i < n: - if segments[i] == s('..') and \ - segments[i - 1] not in (s(''), s('..')): - del segments[i - 1:i + 1] - break - i += 1 - else: - break - - # Remove trailing ".." if the URL is absolute - unwanted_marker = [s(''), s('..')] - while segments[:2] == unwanted_marker: - del segments[1] - - path = s('/').join(segments) - return url_unparse((scheme, netloc, path, query, fragment)) - - -class Href(object): - """Implements a callable that constructs URLs with the given base. The - function can be called with any number of positional and keyword - arguments which than are used to assemble the URL. Works with URLs - and posix paths. - - Positional arguments are appended as individual segments to - the path of the URL: - - >>> href = Href('/foo') - >>> href('bar', 23) - '/foo/bar/23' - >>> href('foo', bar=23) - '/foo/foo?bar=23' - - If any of the arguments (positional or keyword) evaluates to `None` it - will be skipped. If no keyword arguments are given the last argument - can be a :class:`dict` or :class:`MultiDict` (or any other dict subclass), - otherwise the keyword arguments are used for the query parameters, cutting - off the first trailing underscore of the parameter name: - - >>> href(is_=42) - '/foo?is=42' - >>> href({'foo': 'bar'}) - '/foo?foo=bar' - - Combining of both methods is not allowed: - - >>> href({'foo': 'bar'}, bar=42) - Traceback (most recent call last): - ... - TypeError: keyword arguments and query-dicts can't be combined - - Accessing attributes on the href object creates a new href object with - the attribute name as prefix: - - >>> bar_href = href.bar - >>> bar_href("blub") - '/foo/bar/blub' - - If `sort` is set to `True` the items are sorted by `key` or the default - sorting algorithm: - - >>> href = Href("/", sort=True) - >>> href(a=1, b=2, c=3) - '/?a=1&b=2&c=3' - - .. versionadded:: 0.5 - `sort` and `key` were added. - """ - - def __init__(self, base='./', charset='utf-8', sort=False, key=None): - if not base: - base = './' - self.base = base - self.charset = charset - self.sort = sort - self.key = key - - def __getattr__(self, name): - if name[:2] == '__': - raise AttributeError(name) - base = self.base - if base[-1:] != '/': - base += '/' - return Href(url_join(base, name), self.charset, self.sort, self.key) - - def __call__(self, *path, **query): - if path and isinstance(path[-1], dict): - if query: - raise TypeError('keyword arguments and query-dicts ' - 'can\'t be combined') - query, path = path[-1], path[:-1] - elif query: - query = dict([(k.endswith('_') and k[:-1] or k, v) - for k, v in query.items()]) - path = '/'.join([to_unicode(url_quote(x, self.charset), 'ascii') - for x in path if x is not None]).lstrip('/') - rv = self.base - if path: - if not rv.endswith('/'): - rv += '/' - rv = url_join(rv, './' + path) - if query: - rv += '?' + to_unicode(url_encode(query, self.charset, sort=self.sort, - key=self.key), 'ascii') - return to_native(rv) diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/useragents.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/useragents.py deleted file mode 100644 index f791c3cc..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/useragents.py +++ /dev/null @@ -1,190 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.useragents - ~~~~~~~~~~~~~~~~~~~ - - This module provides a helper to inspect user agent strings. This module - is far from complete but should work for most of the currently available - browsers. - - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -import re - - -class UserAgentParser(object): - """A simple user agent parser. Used by the `UserAgent`.""" - - platforms = ( - ('iphone|ios', 'iphone'), - ('ipad', 'ipad'), - (r'darwin|mac|os\s*x', 'macos'), - ('win', 'windows'), - (r'android', 'android'), - (r'x11|lin(\b|ux)?', 'linux'), - ('(sun|i86)os', 'solaris'), - (r'nintendo\s+wii', 'wii'), - ('irix', 'irix'), - ('hp-?ux', 'hpux'), - ('aix', 'aix'), - ('sco|unix_sv', 'sco'), - ('bsd', 'bsd'), - ('amiga', 'amiga'), - ('blackberry|playbook', 'blackberry') - ) - browsers = ( - ('googlebot', 'google'), - ('msnbot', 'msn'), - ('yahoo', 'yahoo'), - ('ask jeeves', 'ask'), - (r'aol|america\s+online\s+browser', 'aol'), - ('opera', 'opera'), - ('chrome', 'chrome'), - ('firefox|firebird|phoenix|iceweasel', 'firefox'), - ('galeon', 'galeon'), - ('safari', 'safari'), - ('webkit', 'webkit'), - ('camino', 'camino'), - ('konqueror', 'konqueror'), - ('k-meleon', 'kmeleon'), - ('netscape', 'netscape'), - (r'msie|microsoft\s+internet\s+explorer', 'msie'), - ('lynx', 'lynx'), - ('links', 'links'), - ('seamonkey|mozilla', 'seamonkey') - ) - - _browser_version_re = r'(?:%s)[/\sa-z(]*(\d+[.\da-z]+)?(?i)' - _language_re = re.compile( - r'(?:;\s*|\s+)(\b\w{2}\b(?:-\b\w{2}\b)?)\s*;|' - r'(?:\(|\[|;)\s*(\b\w{2}\b(?:-\b\w{2}\b)?)\s*(?:\]|\)|;)' - ) - - def __init__(self): - self.platforms = [(b, re.compile(a, re.I)) for a, b in self.platforms] - self.browsers = [(b, re.compile(self._browser_version_re % a)) - for a, b in self.browsers] - - def __call__(self, user_agent): - for platform, regex in self.platforms: - match = regex.search(user_agent) - if match is not None: - break - else: - platform = None - for browser, regex in self.browsers: - match = regex.search(user_agent) - if match is not None: - version = match.group(1) - break - else: - browser = version = None - match = self._language_re.search(user_agent) - if match is not None: - language = match.group(1) or match.group(2) - else: - language = None - return platform, browser, version, language - - -class UserAgent(object): - """Represents a user agent. Pass it a WSGI environment or a user agent - string and you can inspect some of the details from the user agent - string via the attributes. The following attributes exist: - - .. attribute:: string - - the raw user agent string - - .. attribute:: platform - - the browser platform. The following platforms are currently - recognized: - - - `aix` - - `amiga` - - `android` - - `bsd` - - `hpux` - - `iphone` - - `ipad` - - `irix` - - `linux` - - `macos` - - `sco` - - `solaris` - - `wii` - - `windows` - - .. attribute:: browser - - the name of the browser. The following browsers are currently - recognized: - - - `aol` * - - `ask` * - - `camino` - - `chrome` - - `firefox` - - `galeon` - - `google` * - - `kmeleon` - - `konqueror` - - `links` - - `lynx` - - `msie` - - `msn` - - `netscape` - - `opera` - - `safari` - - `seamonkey` - - `webkit` - - `yahoo` * - - (Browsers maked with a star (``*``) are crawlers.) - - .. attribute:: version - - the version of the browser - - .. attribute:: language - - the language of the browser - """ - - _parser = UserAgentParser() - - def __init__(self, environ_or_string): - if isinstance(environ_or_string, dict): - environ_or_string = environ_or_string.get('HTTP_USER_AGENT', '') - self.string = environ_or_string - self.platform, self.browser, self.version, self.language = \ - self._parser(environ_or_string) - - def to_header(self): - return self.string - - def __str__(self): - return self.string - - def __nonzero__(self): - return bool(self.browser) - - __bool__ = __nonzero__ - - def __repr__(self): - return '<%s %r/%s>' % ( - self.__class__.__name__, - self.browser, - self.version - ) - - -# conceptionally this belongs in this module but because we want to lazily -# load the user agent module (which happens in wrappers.py) we have to import -# it afterwards. The class itself has the module set to this module so -# pickle, inspect and similar modules treat the object as if it was really -# implemented here. -from werkzeug.wrappers import UserAgentMixin diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/utils.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/utils.py deleted file mode 100644 index af5f9fe2..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/utils.py +++ /dev/null @@ -1,613 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.utils - ~~~~~~~~~~~~~~ - - This module implements various utilities for WSGI applications. Most of - them are used by the request and response wrappers but especially for - middleware development it makes sense to use them without the wrappers. - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -import re -import os -import sys -import pkgutil -try: - from html.entities import name2codepoint -except ImportError: - from htmlentitydefs import name2codepoint - -from werkzeug._compat import unichr, text_type, string_types, iteritems, \ - reraise, PY2 -from werkzeug._internal import _DictAccessorProperty, \ - _parse_signature, _missing - - -_format_re = re.compile(r'\$(?:(%s)|\{(%s)\})' % (('[a-zA-Z_][a-zA-Z0-9_]*',) * 2)) -_entity_re = re.compile(r'&([^;]+);') -_filename_ascii_strip_re = re.compile(r'[^A-Za-z0-9_.-]') -_windows_device_files = ('CON', 'AUX', 'COM1', 'COM2', 'COM3', 'COM4', 'LPT1', - 'LPT2', 'LPT3', 'PRN', 'NUL') - - -class cached_property(object): - """A decorator that converts a function into a lazy property. The - function wrapped is called the first time to retrieve the result - and then that calculated result is used the next time you access - the value:: - - class Foo(object): - - @cached_property - def foo(self): - # calculate something important here - return 42 - - The class has to have a `__dict__` in order for this property to - work. - """ - - # implementation detail: this property is implemented as non-data - # descriptor. non-data descriptors are only invoked if there is - # no entry with the same name in the instance's __dict__. - # this allows us to completely get rid of the access function call - # overhead. If one choses to invoke __get__ by hand the property - # will still work as expected because the lookup logic is replicated - # in __get__ for manual invocation. - - def __init__(self, func, name=None, doc=None): - self.__name__ = name or func.__name__ - self.__module__ = func.__module__ - self.__doc__ = doc or func.__doc__ - self.func = func - - def __get__(self, obj, type=None): - if obj is None: - return self - value = obj.__dict__.get(self.__name__, _missing) - if value is _missing: - value = self.func(obj) - obj.__dict__[self.__name__] = value - return value - - -class environ_property(_DictAccessorProperty): - """Maps request attributes to environment variables. This works not only - for the Werzeug request object, but also any other class with an - environ attribute: - - >>> class Test(object): - ... environ = {'key': 'value'} - ... test = environ_property('key') - >>> var = Test() - >>> var.test - 'value' - - If you pass it a second value it's used as default if the key does not - exist, the third one can be a converter that takes a value and converts - it. If it raises :exc:`ValueError` or :exc:`TypeError` the default value - is used. If no default value is provided `None` is used. - - Per default the property is read only. You have to explicitly enable it - by passing ``read_only=False`` to the constructor. - """ - - read_only = True - - def lookup(self, obj): - return obj.environ - - -class header_property(_DictAccessorProperty): - """Like `environ_property` but for headers.""" - - def lookup(self, obj): - return obj.headers - - -class HTMLBuilder(object): - """Helper object for HTML generation. - - Per default there are two instances of that class. The `html` one, and - the `xhtml` one for those two dialects. The class uses keyword parameters - and positional parameters to generate small snippets of HTML. - - Keyword parameters are converted to XML/SGML attributes, positional - arguments are used as children. Because Python accepts positional - arguments before keyword arguments it's a good idea to use a list with the - star-syntax for some children: - - >>> html.p(class_='foo', *[html.a('foo', href='foo.html'), ' ', - ... html.a('bar', href='bar.html')]) - u'

    foo bar

    ' - - This class works around some browser limitations and can not be used for - arbitrary SGML/XML generation. For that purpose lxml and similar - libraries exist. - - Calling the builder escapes the string passed: - - >>> html.p(html("")) - u'

    <foo>

    ' - """ - - _entity_re = re.compile(r'&([^;]+);') - _entities = name2codepoint.copy() - _entities['apos'] = 39 - _empty_elements = set([ - 'area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame', - 'hr', 'img', 'input', 'keygen', 'isindex', 'link', 'meta', 'param', - 'source', 'wbr' - ]) - _boolean_attributes = set([ - 'selected', 'checked', 'compact', 'declare', 'defer', 'disabled', - 'ismap', 'multiple', 'nohref', 'noresize', 'noshade', 'nowrap' - ]) - _plaintext_elements = set(['textarea']) - _c_like_cdata = set(['script', 'style']) - - def __init__(self, dialect): - self._dialect = dialect - - def __call__(self, s): - return escape(s) - - def __getattr__(self, tag): - if tag[:2] == '__': - raise AttributeError(tag) - def proxy(*children, **arguments): - buffer = '<' + tag - for key, value in iteritems(arguments): - if value is None: - continue - if key[-1] == '_': - key = key[:-1] - if key in self._boolean_attributes: - if not value: - continue - if self._dialect == 'xhtml': - value = '="' + key + '"' - else: - value = '' - else: - value = '="' + escape(value) + '"' - buffer += ' ' + key + value - if not children and tag in self._empty_elements: - if self._dialect == 'xhtml': - buffer += ' />' - else: - buffer += '>' - return buffer - buffer += '>' - - children_as_string = ''.join([text_type(x) for x in children - if x is not None]) - - if children_as_string: - if tag in self._plaintext_elements: - children_as_string = escape(children_as_string) - elif tag in self._c_like_cdata and self._dialect == 'xhtml': - children_as_string = '/**/' - buffer += children_as_string + '' - return buffer - return proxy - - def __repr__(self): - return '<%s for %r>' % ( - self.__class__.__name__, - self._dialect - ) - - -html = HTMLBuilder('html') -xhtml = HTMLBuilder('xhtml') - - -def get_content_type(mimetype, charset): - """Return the full content type string with charset for a mimetype. - - If the mimetype represents text the charset will be appended as charset - parameter, otherwise the mimetype is returned unchanged. - - :param mimetype: the mimetype to be used as content type. - :param charset: the charset to be appended in case it was a text mimetype. - :return: the content type. - """ - if mimetype.startswith('text/') or \ - mimetype == 'application/xml' or \ - (mimetype.startswith('application/') and - mimetype.endswith('+xml')): - mimetype += '; charset=' + charset - return mimetype - - -def format_string(string, context): - """String-template format a string: - - >>> format_string('$foo and ${foo}s', dict(foo=42)) - '42 and 42s' - - This does not do any attribute lookup etc. For more advanced string - formattings have a look at the `werkzeug.template` module. - - :param string: the format string. - :param context: a dict with the variables to insert. - """ - def lookup_arg(match): - x = context[match.group(1) or match.group(2)] - if not isinstance(x, string_types): - x = type(string)(x) - return x - return _format_re.sub(lookup_arg, string) - - -def secure_filename(filename): - r"""Pass it a filename and it will return a secure version of it. This - filename can then safely be stored on a regular file system and passed - to :func:`os.path.join`. The filename returned is an ASCII only string - for maximum portability. - - On windows system the function also makes sure that the file is not - named after one of the special device files. - - >>> secure_filename("My cool movie.mov") - 'My_cool_movie.mov' - >>> secure_filename("../../../etc/passwd") - 'etc_passwd' - >>> secure_filename(u'i contain cool \xfcml\xe4uts.txt') - 'i_contain_cool_umlauts.txt' - - The function might return an empty filename. It's your responsibility - to ensure that the filename is unique and that you generate random - filename if the function returned an empty one. - - .. versionadded:: 0.5 - - :param filename: the filename to secure - """ - if isinstance(filename, text_type): - from unicodedata import normalize - filename = normalize('NFKD', filename).encode('ascii', 'ignore') - if not PY2: - filename = filename.decode('ascii') - for sep in os.path.sep, os.path.altsep: - if sep: - filename = filename.replace(sep, ' ') - filename = str(_filename_ascii_strip_re.sub('', '_'.join( - filename.split()))).strip('._') - - # on nt a couple of special files are present in each folder. We - # have to ensure that the target file is not such a filename. In - # this case we prepend an underline - if os.name == 'nt' and filename and \ - filename.split('.')[0].upper() in _windows_device_files: - filename = '_' + filename - - return filename - - -def escape(s, quote=None): - """Replace special characters "&", "<", ">" and (") to HTML-safe sequences. - - There is a special handling for `None` which escapes to an empty string. - - .. versionchanged:: 0.9 - `quote` is now implicitly on. - - :param s: the string to escape. - :param quote: ignored. - """ - if s is None: - return '' - elif hasattr(s, '__html__'): - return text_type(s.__html__()) - elif not isinstance(s, string_types): - s = text_type(s) - if quote is not None: - from warnings import warn - warn(DeprecationWarning('quote parameter is implicit now'), stacklevel=2) - s = s.replace('&', '&').replace('<', '<') \ - .replace('>', '>').replace('"', """) - return s - - -def unescape(s): - """The reverse function of `escape`. This unescapes all the HTML - entities, not only the XML entities inserted by `escape`. - - :param s: the string to unescape. - """ - def handle_match(m): - name = m.group(1) - if name in HTMLBuilder._entities: - return unichr(HTMLBuilder._entities[name]) - try: - if name[:2] in ('#x', '#X'): - return unichr(int(name[2:], 16)) - elif name.startswith('#'): - return unichr(int(name[1:])) - except ValueError: - pass - return u'' - return _entity_re.sub(handle_match, s) - - -def redirect(location, code=302): - """Return a response object (a WSGI application) that, if called, - redirects the client to the target location. Supported codes are 301, - 302, 303, 305, and 307. 300 is not supported because it's not a real - redirect and 304 because it's the answer for a request with a request - with defined If-Modified-Since headers. - - .. versionadded:: 0.6 - The location can now be a unicode string that is encoded using - the :func:`iri_to_uri` function. - - :param location: the location the response should redirect to. - :param code: the redirect status code. defaults to 302. - """ - from werkzeug.wrappers import Response - display_location = escape(location) - if isinstance(location, text_type): - # Safe conversion is necessary here as we might redirect - # to a broken URI scheme (for instance itms-services). - from werkzeug.urls import iri_to_uri - location = iri_to_uri(location, safe_conversion=True) - response = Response( - '\n' - 'Redirecting...\n' - '

    Redirecting...

    \n' - '

    You should be redirected automatically to target URL: ' - '%s. If not click the link.' % - (escape(location), display_location), code, mimetype='text/html') - response.headers['Location'] = location - return response - - -def append_slash_redirect(environ, code=301): - """Redirect to the same URL but with a slash appended. The behavior - of this function is undefined if the path ends with a slash already. - - :param environ: the WSGI environment for the request that triggers - the redirect. - :param code: the status code for the redirect. - """ - new_path = environ['PATH_INFO'].strip('/') + '/' - query_string = environ.get('QUERY_STRING') - if query_string: - new_path += '?' + query_string - return redirect(new_path, code) - - -def import_string(import_name, silent=False): - """Imports an object based on a string. This is useful if you want to - use import paths as endpoints or something similar. An import path can - be specified either in dotted notation (``xml.sax.saxutils.escape``) - or with a colon as object delimiter (``xml.sax.saxutils:escape``). - - If `silent` is True the return value will be `None` if the import fails. - - :param import_name: the dotted name for the object to import. - :param silent: if set to `True` import errors are ignored and - `None` is returned instead. - :return: imported object - """ - #XXX: py3 review needed - assert isinstance(import_name, string_types) - # force the import name to automatically convert to strings - import_name = str(import_name) - try: - if ':' in import_name: - module, obj = import_name.split(':', 1) - elif '.' in import_name: - module, obj = import_name.rsplit('.', 1) - else: - return __import__(import_name) - # __import__ is not able to handle unicode strings in the fromlist - # if the module is a package - if PY2 and isinstance(obj, unicode): - obj = obj.encode('utf-8') - try: - return getattr(__import__(module, None, None, [obj]), obj) - except (ImportError, AttributeError): - # support importing modules not yet set up by the parent module - # (or package for that matter) - modname = module + '.' + obj - __import__(modname) - return sys.modules[modname] - except ImportError as e: - if not silent: - reraise( - ImportStringError, - ImportStringError(import_name, e), - sys.exc_info()[2]) - - -def find_modules(import_path, include_packages=False, recursive=False): - """Find all the modules below a package. This can be useful to - automatically import all views / controllers so that their metaclasses / - function decorators have a chance to register themselves on the - application. - - Packages are not returned unless `include_packages` is `True`. This can - also recursively list modules but in that case it will import all the - packages to get the correct load path of that module. - - :param import_name: the dotted name for the package to find child modules. - :param include_packages: set to `True` if packages should be returned, too. - :param recursive: set to `True` if recursion should happen. - :return: generator - """ - module = import_string(import_path) - path = getattr(module, '__path__', None) - if path is None: - raise ValueError('%r is not a package' % import_path) - basename = module.__name__ + '.' - for importer, modname, ispkg in pkgutil.iter_modules(path): - modname = basename + modname - if ispkg: - if include_packages: - yield modname - if recursive: - for item in find_modules(modname, include_packages, True): - yield item - else: - yield modname - - -def validate_arguments(func, args, kwargs, drop_extra=True): - """Check if the function accepts the arguments and keyword arguments. - Returns a new ``(args, kwargs)`` tuple that can safely be passed to - the function without causing a `TypeError` because the function signature - is incompatible. If `drop_extra` is set to `True` (which is the default) - any extra positional or keyword arguments are dropped automatically. - - The exception raised provides three attributes: - - `missing` - A set of argument names that the function expected but where - missing. - - `extra` - A dict of keyword arguments that the function can not handle but - where provided. - - `extra_positional` - A list of values that where given by positional argument but the - function cannot accept. - - This can be useful for decorators that forward user submitted data to - a view function:: - - from werkzeug.utils import ArgumentValidationError, validate_arguments - - def sanitize(f): - def proxy(request): - data = request.values.to_dict() - try: - args, kwargs = validate_arguments(f, (request,), data) - except ArgumentValidationError: - raise BadRequest('The browser failed to transmit all ' - 'the data expected.') - return f(*args, **kwargs) - return proxy - - :param func: the function the validation is performed against. - :param args: a tuple of positional arguments. - :param kwargs: a dict of keyword arguments. - :param drop_extra: set to `False` if you don't want extra arguments - to be silently dropped. - :return: tuple in the form ``(args, kwargs)``. - """ - parser = _parse_signature(func) - args, kwargs, missing, extra, extra_positional = parser(args, kwargs)[:5] - if missing: - raise ArgumentValidationError(tuple(missing)) - elif (extra or extra_positional) and not drop_extra: - raise ArgumentValidationError(None, extra, extra_positional) - return tuple(args), kwargs - - -def bind_arguments(func, args, kwargs): - """Bind the arguments provided into a dict. When passed a function, - a tuple of arguments and a dict of keyword arguments `bind_arguments` - returns a dict of names as the function would see it. This can be useful - to implement a cache decorator that uses the function arguments to build - the cache key based on the values of the arguments. - - :param func: the function the arguments should be bound for. - :param args: tuple of positional arguments. - :param kwargs: a dict of keyword arguments. - :return: a :class:`dict` of bound keyword arguments. - """ - args, kwargs, missing, extra, extra_positional, \ - arg_spec, vararg_var, kwarg_var = _parse_signature(func)(args, kwargs) - values = {} - for (name, has_default, default), value in zip(arg_spec, args): - values[name] = value - if vararg_var is not None: - values[vararg_var] = tuple(extra_positional) - elif extra_positional: - raise TypeError('too many positional arguments') - if kwarg_var is not None: - multikw = set(extra) & set([x[0] for x in arg_spec]) - if multikw: - raise TypeError('got multiple values for keyword argument ' + - repr(next(iter(multikw)))) - values[kwarg_var] = extra - elif extra: - raise TypeError('got unexpected keyword argument ' + - repr(next(iter(extra)))) - return values - - -class ArgumentValidationError(ValueError): - """Raised if :func:`validate_arguments` fails to validate""" - - def __init__(self, missing=None, extra=None, extra_positional=None): - self.missing = set(missing or ()) - self.extra = extra or {} - self.extra_positional = extra_positional or [] - ValueError.__init__(self, 'function arguments invalid. (' - '%d missing, %d additional)' % ( - len(self.missing), - len(self.extra) + len(self.extra_positional) - )) - - -class ImportStringError(ImportError): - """Provides information about a failed :func:`import_string` attempt.""" - - #: String in dotted notation that failed to be imported. - import_name = None - #: Wrapped exception. - exception = None - - def __init__(self, import_name, exception): - self.import_name = import_name - self.exception = exception - - msg = ( - 'import_string() failed for %r. Possible reasons are:\n\n' - '- missing __init__.py in a package;\n' - '- package or module path not included in sys.path;\n' - '- duplicated package or module name taking precedence in ' - 'sys.path;\n' - '- missing module, class, function or variable;\n\n' - 'Debugged import:\n\n%s\n\n' - 'Original exception:\n\n%s: %s') - - name = '' - tracked = [] - for part in import_name.replace(':', '.').split('.'): - name += (name and '.') + part - imported = import_string(name, silent=True) - if imported: - tracked.append((name, getattr(imported, '__file__', None))) - else: - track = ['- %r found in %r.' % (n, i) for n, i in tracked] - track.append('- %r not found.' % name) - msg = msg % (import_name, '\n'.join(track), - exception.__class__.__name__, str(exception)) - break - - ImportError.__init__(self, msg) - - def __repr__(self): - return '<%s(%r, %r)>' % (self.__class__.__name__, self.import_name, - self.exception) - - -# circular dependencies -from werkzeug.http import quote_header_value, unquote_header_value, \ - cookie_date - -# DEPRECATED -# these objects were previously in this module as well. we import -# them here for backwards compatibility with old pickles. -from werkzeug.datastructures import MultiDict, CombinedMultiDict, \ - Headers, EnvironHeaders -from werkzeug.http import parse_cookie, dump_cookie diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/wrappers.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/wrappers.py deleted file mode 100644 index edfb74cf..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/wrappers.py +++ /dev/null @@ -1,1808 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.wrappers - ~~~~~~~~~~~~~~~~~ - - The wrappers are simple request and response objects which you can - subclass to do whatever you want them to do. The request object contains - the information transmitted by the client (webbrowser) and the response - object contains all the information sent back to the browser. - - An important detail is that the request object is created with the WSGI - environ and will act as high-level proxy whereas the response object is an - actual WSGI application. - - Like everything else in Werkzeug these objects will work correctly with - unicode data. Incoming form data parsed by the response object will be - decoded into an unicode object if possible and if it makes sense. - - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -from functools import update_wrapper -from datetime import datetime, timedelta - -from werkzeug.http import HTTP_STATUS_CODES, \ - parse_accept_header, parse_cache_control_header, parse_etags, \ - parse_date, generate_etag, is_resource_modified, unquote_etag, \ - quote_etag, parse_set_header, parse_authorization_header, \ - parse_www_authenticate_header, remove_entity_headers, \ - parse_options_header, dump_options_header, http_date, \ - parse_if_range_header, parse_cookie, dump_cookie, \ - parse_range_header, parse_content_range_header, dump_header -from werkzeug.urls import url_decode, iri_to_uri, url_join -from werkzeug.formparser import FormDataParser, default_stream_factory -from werkzeug.utils import cached_property, environ_property, \ - header_property, get_content_type -from werkzeug.wsgi import get_current_url, get_host, \ - ClosingIterator, get_input_stream, get_content_length -from werkzeug.datastructures import MultiDict, CombinedMultiDict, Headers, \ - EnvironHeaders, ImmutableMultiDict, ImmutableTypeConversionDict, \ - ImmutableList, MIMEAccept, CharsetAccept, LanguageAccept, \ - ResponseCacheControl, RequestCacheControl, CallbackDict, \ - ContentRange, iter_multi_items -from werkzeug._internal import _get_environ -from werkzeug._compat import to_bytes, string_types, text_type, \ - integer_types, wsgi_decoding_dance, wsgi_get_bytes, \ - to_unicode, to_native, BytesIO - - -def _run_wsgi_app(*args): - """This function replaces itself to ensure that the test module is not - imported unless required. DO NOT USE! - """ - global _run_wsgi_app - from werkzeug.test import run_wsgi_app as _run_wsgi_app - return _run_wsgi_app(*args) - - -def _warn_if_string(iterable): - """Helper for the response objects to check if the iterable returned - to the WSGI server is not a string. - """ - if isinstance(iterable, string_types): - from warnings import warn - warn(Warning('response iterable was set to a string. This appears ' - 'to work but means that the server will send the ' - 'data to the client char, by char. This is almost ' - 'never intended behavior, use response.data to assign ' - 'strings to the response object.'), stacklevel=2) - - -def _assert_not_shallow(request): - if request.shallow: - raise RuntimeError('A shallow request tried to consume ' - 'form data. If you really want to do ' - 'that, set `shallow` to False.') - - -def _iter_encoded(iterable, charset): - for item in iterable: - if isinstance(item, text_type): - yield item.encode(charset) - else: - yield item - - -class BaseRequest(object): - """Very basic request object. This does not implement advanced stuff like - entity tag parsing or cache controls. The request object is created with - the WSGI environment as first argument and will add itself to the WSGI - environment as ``'werkzeug.request'`` unless it's created with - `populate_request` set to False. - - There are a couple of mixins available that add additional functionality - to the request object, there is also a class called `Request` which - subclasses `BaseRequest` and all the important mixins. - - It's a good idea to create a custom subclass of the :class:`BaseRequest` - and add missing functionality either via mixins or direct implementation. - Here an example for such subclasses:: - - from werkzeug.wrappers import BaseRequest, ETagRequestMixin - - class Request(BaseRequest, ETagRequestMixin): - pass - - Request objects are **read only**. As of 0.5 modifications are not - allowed in any place. Unlike the lower level parsing functions the - request object will use immutable objects everywhere possible. - - Per default the request object will assume all the text data is `utf-8` - encoded. Please refer to `the unicode chapter `_ for more - details about customizing the behavior. - - Per default the request object will be added to the WSGI - environment as `werkzeug.request` to support the debugging system. - If you don't want that, set `populate_request` to `False`. - - If `shallow` is `True` the environment is initialized as shallow - object around the environ. Every operation that would modify the - environ in any way (such as consuming form data) raises an exception - unless the `shallow` attribute is explicitly set to `False`. This - is useful for middlewares where you don't want to consume the form - data by accident. A shallow request is not populated to the WSGI - environment. - - .. versionchanged:: 0.5 - read-only mode was enforced by using immutables classes for all - data. - """ - - #: the charset for the request, defaults to utf-8 - charset = 'utf-8' - - #: the error handling procedure for errors, defaults to 'replace' - encoding_errors = 'replace' - - #: the maximum content length. This is forwarded to the form data - #: parsing function (:func:`parse_form_data`). When set and the - #: :attr:`form` or :attr:`files` attribute is accessed and the - #: parsing fails because more than the specified value is transmitted - #: a :exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception is raised. - #: - #: Have a look at :ref:`dealing-with-request-data` for more details. - #: - #: .. versionadded:: 0.5 - max_content_length = None - - #: the maximum form field size. This is forwarded to the form data - #: parsing function (:func:`parse_form_data`). When set and the - #: :attr:`form` or :attr:`files` attribute is accessed and the - #: data in memory for post data is longer than the specified value a - #: :exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception is raised. - #: - #: Have a look at :ref:`dealing-with-request-data` for more details. - #: - #: .. versionadded:: 0.5 - max_form_memory_size = None - - #: the class to use for `args` and `form`. The default is an - #: :class:`~werkzeug.datastructures.ImmutableMultiDict` which supports - #: multiple values per key. alternatively it makes sense to use an - #: :class:`~werkzeug.datastructures.ImmutableOrderedMultiDict` which - #: preserves order or a :class:`~werkzeug.datastructures.ImmutableDict` - #: which is the fastest but only remembers the last key. It is also - #: possible to use mutable structures, but this is not recommended. - #: - #: .. versionadded:: 0.6 - parameter_storage_class = ImmutableMultiDict - - #: the type to be used for list values from the incoming WSGI environment. - #: By default an :class:`~werkzeug.datastructures.ImmutableList` is used - #: (for example for :attr:`access_list`). - #: - #: .. versionadded:: 0.6 - list_storage_class = ImmutableList - - #: the type to be used for dict values from the incoming WSGI environment. - #: By default an - #: :class:`~werkzeug.datastructures.ImmutableTypeConversionDict` is used - #: (for example for :attr:`cookies`). - #: - #: .. versionadded:: 0.6 - dict_storage_class = ImmutableTypeConversionDict - - #: The form data parser that shoud be used. Can be replaced to customize - #: the form date parsing. - form_data_parser_class = FormDataParser - - #: Optionally a list of hosts that is trusted by this request. By default - #: all hosts are trusted which means that whatever the client sends the - #: host is will be accepted. This is the recommended setup as a webserver - #: should manually be set up to not route invalid hosts to the application. - #: - #: .. versionadded:: 0.9 - trusted_hosts = None - - #: Indicates weather the data descriptor should be allowed to read and - #: buffer up the input stream. By default it's enabled. - #: - #: .. versionadded:: 0.9 - disable_data_descriptor = False - - def __init__(self, environ, populate_request=True, shallow=False): - self.environ = environ - if populate_request and not shallow: - self.environ['werkzeug.request'] = self - self.shallow = shallow - - def __repr__(self): - # make sure the __repr__ even works if the request was created - # from an invalid WSGI environment. If we display the request - # in a debug session we don't want the repr to blow up. - args = [] - try: - args.append("'%s'" % self.url) - args.append('[%s]' % self.method) - except Exception: - args.append('(invalid WSGI environ)') - - return '<%s %s>' % ( - self.__class__.__name__, - ' '.join(args) - ) - - @property - def url_charset(self): - """The charset that is assumed for URLs. Defaults to the value - of :attr:`charset`. - - .. versionadded:: 0.6 - """ - return self.charset - - @classmethod - def from_values(cls, *args, **kwargs): - """Create a new request object based on the values provided. If - environ is given missing values are filled from there. This method is - useful for small scripts when you need to simulate a request from an URL. - Do not use this method for unittesting, there is a full featured client - object (:class:`Client`) that allows to create multipart requests, - support for cookies etc. - - This accepts the same options as the - :class:`~werkzeug.test.EnvironBuilder`. - - .. versionchanged:: 0.5 - This method now accepts the same arguments as - :class:`~werkzeug.test.EnvironBuilder`. Because of this the - `environ` parameter is now called `environ_overrides`. - - :return: request object - """ - from werkzeug.test import EnvironBuilder - charset = kwargs.pop('charset', cls.charset) - kwargs['charset'] = charset - builder = EnvironBuilder(*args, **kwargs) - try: - return builder.get_request(cls) - finally: - builder.close() - - @classmethod - def application(cls, f): - """Decorate a function as responder that accepts the request as first - argument. This works like the :func:`responder` decorator but the - function is passed the request object as first argument and the - request object will be closed automatically:: - - @Request.application - def my_wsgi_app(request): - return Response('Hello World!') - - :param f: the WSGI callable to decorate - :return: a new WSGI callable - """ - #: return a callable that wraps the -2nd argument with the request - #: and calls the function with all the arguments up to that one and - #: the request. The return value is then called with the latest - #: two arguments. This makes it possible to use this decorator for - #: both methods and standalone WSGI functions. - def application(*args): - request = cls(args[-2]) - with request: - return f(*args[:-2] + (request,))(*args[-2:]) - return update_wrapper(application, f) - - def _get_file_stream(self, total_content_length, content_type, filename=None, - content_length=None): - """Called to get a stream for the file upload. - - This must provide a file-like class with `read()`, `readline()` - and `seek()` methods that is both writeable and readable. - - The default implementation returns a temporary file if the total - content length is higher than 500KB. Because many browsers do not - provide a content length for the files only the total content - length matters. - - :param total_content_length: the total content length of all the - data in the request combined. This value - is guaranteed to be there. - :param content_type: the mimetype of the uploaded file. - :param filename: the filename of the uploaded file. May be `None`. - :param content_length: the length of this file. This value is usually - not provided because webbrowsers do not provide - this value. - """ - return default_stream_factory(total_content_length, content_type, - filename, content_length) - - @property - def want_form_data_parsed(self): - """Returns True if the request method carries content. As of - Werkzeug 0.9 this will be the case if a content type is transmitted. - - .. versionadded:: 0.8 - """ - return bool(self.environ.get('CONTENT_TYPE')) - - def make_form_data_parser(self): - """Creates the form data parser. Instanciates the - :attr:`form_data_parser_class` with some parameters. - - .. versionadded:: 0.8 - """ - return self.form_data_parser_class(self._get_file_stream, - self.charset, - self.encoding_errors, - self.max_form_memory_size, - self.max_content_length, - self.parameter_storage_class) - - def _load_form_data(self): - """Method used internally to retrieve submitted data. After calling - this sets `form` and `files` on the request object to multi dicts - filled with the incoming form data. As a matter of fact the input - stream will be empty afterwards. You can also call this method to - force the parsing of the form data. - - .. versionadded:: 0.8 - """ - # abort early if we have already consumed the stream - if 'form' in self.__dict__: - return - - _assert_not_shallow(self) - - if self.want_form_data_parsed: - content_type = self.environ.get('CONTENT_TYPE', '') - content_length = get_content_length(self.environ) - mimetype, options = parse_options_header(content_type) - parser = self.make_form_data_parser() - data = parser.parse(self._get_stream_for_parsing(), - mimetype, content_length, options) - else: - data = (self.stream, self.parameter_storage_class(), - self.parameter_storage_class()) - - # inject the values into the instance dict so that we bypass - # our cached_property non-data descriptor. - d = self.__dict__ - d['stream'], d['form'], d['files'] = data - - def _get_stream_for_parsing(self): - """This is the same as accessing :attr:`stream` with the difference - that if it finds cached data from calling :meth:`get_data` first it - will create a new stream out of the cached data. - - .. versionadded:: 0.9.3 - """ - cached_data = getattr(self, '_cached_data', None) - if cached_data is not None: - return BytesIO(cached_data) - return self.stream - - def close(self): - """Closes associated resources of this request object. This - closes all file handles explicitly. You can also use the request - object in a with statement with will automatically close it. - - .. versionadded:: 0.9 - """ - files = self.__dict__.get('files') - for key, value in iter_multi_items(files or ()): - value.close() - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, tb): - self.close() - - @cached_property - def stream(self): - """The stream to read incoming data from. Unlike :attr:`input_stream` - this stream is properly guarded that you can't accidentally read past - the length of the input. Werkzeug will internally always refer to - this stream to read data which makes it possible to wrap this - object with a stream that does filtering. - - .. versionchanged:: 0.9 - This stream is now always available but might be consumed by the - form parser later on. Previously the stream was only set if no - parsing happened. - """ - _assert_not_shallow(self) - return get_input_stream(self.environ) - - input_stream = environ_property('wsgi.input', 'The WSGI input stream.\n' - 'In general it\'s a bad idea to use this one because you can easily ' - 'read past the boundary. Use the :attr:`stream` instead.') - - @cached_property - def args(self): - """The parsed URL parameters. By default an - :class:`~werkzeug.datastructures.ImmutableMultiDict` - is returned from this function. This can be changed by setting - :attr:`parameter_storage_class` to a different type. This might - be necessary if the order of the form data is important. - """ - return url_decode(wsgi_get_bytes(self.environ.get('QUERY_STRING', '')), - self.url_charset, errors=self.encoding_errors, - cls=self.parameter_storage_class) - - @cached_property - def data(self): - if self.disable_data_descriptor: - raise AttributeError('data descriptor is disabled') - # XXX: this should eventually be deprecated. - - # We trigger form data parsing first which means that the descriptor - # will not cache the data that would otherwise be .form or .files - # data. This restores the behavior that was there in Werkzeug - # before 0.9. New code should use :meth:`get_data` explicitly as - # this will make behavior explicit. - return self.get_data(parse_form_data=True) - - def get_data(self, cache=True, as_text=False, parse_form_data=False): - """This reads the buffered incoming data from the client into one - bytestring. By default this is cached but that behavior can be - changed by setting `cache` to `False`. - - Usually it's a bad idea to call this method without checking the - content length first as a client could send dozens of megabytes or more - to cause memory problems on the server. - - Note that if the form data was already parsed this method will not - return anything as form data parsing does not cache the data like - this method does. To implicitly invoke form data parsing function - set `parse_form_data` to `True`. When this is done the return value - of this method will be an empty string if the form parser handles - the data. This generally is not necessary as if the whole data is - cached (which is the default) the form parser will used the cached - data to parse the form data. Please be generally aware of checking - the content length first in any case before calling this method - to avoid exhausting server memory. - - If `as_text` is set to `True` the return value will be a decoded - unicode string. - - .. versionadded:: 0.9 - """ - rv = getattr(self, '_cached_data', None) - if rv is None: - if parse_form_data: - self._load_form_data() - rv = self.stream.read() - if cache: - self._cached_data = rv - if as_text: - rv = rv.decode(self.charset, self.encoding_errors) - return rv - - @cached_property - def form(self): - """The form parameters. By default an - :class:`~werkzeug.datastructures.ImmutableMultiDict` - is returned from this function. This can be changed by setting - :attr:`parameter_storage_class` to a different type. This might - be necessary if the order of the form data is important. - """ - self._load_form_data() - return self.form - - @cached_property - def values(self): - """Combined multi dict for :attr:`args` and :attr:`form`.""" - args = [] - for d in self.args, self.form: - if not isinstance(d, MultiDict): - d = MultiDict(d) - args.append(d) - return CombinedMultiDict(args) - - @cached_property - def files(self): - """:class:`~werkzeug.datastructures.MultiDict` object containing - all uploaded files. Each key in :attr:`files` is the name from the - ````. Each value in :attr:`files` is a - Werkzeug :class:`~werkzeug.datastructures.FileStorage` object. - - Note that :attr:`files` will only contain data if the request method was - POST, PUT or PATCH and the ``

    `` that posted to the request had - ``enctype="multipart/form-data"``. It will be empty otherwise. - - See the :class:`~werkzeug.datastructures.MultiDict` / - :class:`~werkzeug.datastructures.FileStorage` documentation for - more details about the used data structure. - """ - self._load_form_data() - return self.files - - @cached_property - def cookies(self): - """Read only access to the retrieved cookie values as dictionary.""" - return parse_cookie(self.environ, self.charset, - self.encoding_errors, - cls=self.dict_storage_class) - - @cached_property - def headers(self): - """The headers from the WSGI environ as immutable - :class:`~werkzeug.datastructures.EnvironHeaders`. - """ - return EnvironHeaders(self.environ) - - @cached_property - def path(self): - """Requested path as unicode. This works a bit like the regular path - info in the WSGI environment but will always include a leading slash, - even if the URL root is accessed. - """ - raw_path = wsgi_decoding_dance(self.environ.get('PATH_INFO') or '', - self.charset, self.encoding_errors) - return '/' + raw_path.lstrip('/') - - @cached_property - def full_path(self): - """Requested path as unicode, including the query string.""" - return self.path + u'?' + to_unicode(self.query_string, self.url_charset) - - @cached_property - def script_root(self): - """The root path of the script without the trailing slash.""" - raw_path = wsgi_decoding_dance(self.environ.get('SCRIPT_NAME') or '', - self.charset, self.encoding_errors) - return raw_path.rstrip('/') - - @cached_property - def url(self): - """The reconstructed current URL as IRI.""" - return get_current_url(self.environ, - trusted_hosts=self.trusted_hosts) - - @cached_property - def base_url(self): - """Like :attr:`url` but without the querystring""" - return get_current_url(self.environ, strip_querystring=True, - trusted_hosts=self.trusted_hosts) - - @cached_property - def url_root(self): - """The full URL root (with hostname), this is the application - root as IRI. - """ - return get_current_url(self.environ, True, - trusted_hosts=self.trusted_hosts) - - @cached_property - def host_url(self): - """Just the host with scheme as IRI.""" - return get_current_url(self.environ, host_only=True, - trusted_hosts=self.trusted_hosts) - - @cached_property - def host(self): - """Just the host including the port if available.""" - return get_host(self.environ, trusted_hosts=self.trusted_hosts) - - query_string = environ_property('QUERY_STRING', '', read_only=True, - load_func=wsgi_get_bytes, doc= - '''The URL parameters as raw bytestring.''') - method = environ_property('REQUEST_METHOD', 'GET', read_only=True, doc= - '''The transmission method. (For example ``'GET'`` or ``'POST'``).''') - - @cached_property - def access_route(self): - """If a forwarded header exists this is a list of all ip addresses - from the client ip to the last proxy server. - """ - if 'HTTP_X_FORWARDED_FOR' in self.environ: - addr = self.environ['HTTP_X_FORWARDED_FOR'].split(',') - return self.list_storage_class([x.strip() for x in addr]) - elif 'REMOTE_ADDR' in self.environ: - return self.list_storage_class([self.environ['REMOTE_ADDR']]) - return self.list_storage_class() - - @property - def remote_addr(self): - """The remote address of the client.""" - return self.environ.get('REMOTE_ADDR') - - remote_user = environ_property('REMOTE_USER', doc=''' - If the server supports user authentication, and the script is - protected, this attribute contains the username the user has - authenticated as.''') - - scheme = environ_property('wsgi.url_scheme', doc=''' - URL scheme (http or https). - - .. versionadded:: 0.7''') - - is_xhr = property(lambda x: x.environ.get('HTTP_X_REQUESTED_WITH', '') - .lower() == 'xmlhttprequest', doc=''' - True if the request was triggered via a JavaScript XMLHttpRequest. - This only works with libraries that support the `X-Requested-With` - header and set it to "XMLHttpRequest". Libraries that do that are - prototype, jQuery and Mochikit and probably some more.''') - is_secure = property(lambda x: x.environ['wsgi.url_scheme'] == 'https', - doc='`True` if the request is secure.') - is_multithread = environ_property('wsgi.multithread', doc=''' - boolean that is `True` if the application is served by - a multithreaded WSGI server.''') - is_multiprocess = environ_property('wsgi.multiprocess', doc=''' - boolean that is `True` if the application is served by - a WSGI server that spawns multiple processes.''') - is_run_once = environ_property('wsgi.run_once', doc=''' - boolean that is `True` if the application will be executed only - once in a process lifetime. This is the case for CGI for example, - but it's not guaranteed that the exeuction only happens one time.''') - - -class BaseResponse(object): - """Base response class. The most important fact about a response object - is that it's a regular WSGI application. It's initialized with a couple - of response parameters (headers, body, status code etc.) and will start a - valid WSGI response when called with the environ and start response - callable. - - Because it's a WSGI application itself processing usually ends before the - actual response is sent to the server. This helps debugging systems - because they can catch all the exceptions before responses are started. - - Here a small example WSGI application that takes advantage of the - response objects:: - - from werkzeug.wrappers import BaseResponse as Response - - def index(): - return Response('Index page') - - def application(environ, start_response): - path = environ.get('PATH_INFO') or '/' - if path == '/': - response = index() - else: - response = Response('Not Found', status=404) - return response(environ, start_response) - - Like :class:`BaseRequest` which object is lacking a lot of functionality - implemented in mixins. This gives you a better control about the actual - API of your response objects, so you can create subclasses and add custom - functionality. A full featured response object is available as - :class:`Response` which implements a couple of useful mixins. - - To enforce a new type of already existing responses you can use the - :meth:`force_type` method. This is useful if you're working with different - subclasses of response objects and you want to post process them with a - know interface. - - Per default the request object will assume all the text data is `utf-8` - encoded. Please refer to `the unicode chapter `_ for more - details about customizing the behavior. - - Response can be any kind of iterable or string. If it's a string it's - considered being an iterable with one item which is the string passed. - Headers can be a list of tuples or a - :class:`~werkzeug.datastructures.Headers` object. - - Special note for `mimetype` and `content_type`: For most mime types - `mimetype` and `content_type` work the same, the difference affects - only 'text' mimetypes. If the mimetype passed with `mimetype` is a - mimetype starting with `text/`, the charset parameter of the response - object is appended to it. In contrast the `content_type` parameter is - always added as header unmodified. - - .. versionchanged:: 0.5 - the `direct_passthrough` parameter was added. - - :param response: a string or response iterable. - :param status: a string with a status or an integer with the status code. - :param headers: a list of headers or a - :class:`~werkzeug.datastructures.Headers` object. - :param mimetype: the mimetype for the request. See notice above. - :param content_type: the content type for the request. See notice above. - :param direct_passthrough: if set to `True` :meth:`iter_encoded` is not - called before iteration which makes it - possible to pass special iterators though - unchanged (see :func:`wrap_file` for more - details.) - """ - - #: the charset of the response. - charset = 'utf-8' - - #: the default status if none is provided. - default_status = 200 - - #: the default mimetype if none is provided. - default_mimetype = 'text/plain' - - #: if set to `False` accessing properties on the response object will - #: not try to consume the response iterator and convert it into a list. - #: - #: .. versionadded:: 0.6.2 - #: - #: That attribute was previously called `implicit_seqence_conversion`. - #: (Notice the typo). If you did use this feature, you have to adapt - #: your code to the name change. - implicit_sequence_conversion = True - - #: Should this response object correct the location header to be RFC - #: conformant? This is true by default. - #: - #: .. versionadded:: 0.8 - autocorrect_location_header = True - - #: Should this response object automatically set the content-length - #: header if possible? This is true by default. - #: - #: .. versionadded:: 0.8 - automatically_set_content_length = True - - def __init__(self, response=None, status=None, headers=None, - mimetype=None, content_type=None, direct_passthrough=False): - if isinstance(headers, Headers): - self.headers = headers - elif not headers: - self.headers = Headers() - else: - self.headers = Headers(headers) - - if content_type is None: - if mimetype is None and 'content-type' not in self.headers: - mimetype = self.default_mimetype - if mimetype is not None: - mimetype = get_content_type(mimetype, self.charset) - content_type = mimetype - if content_type is not None: - self.headers['Content-Type'] = content_type - if status is None: - status = self.default_status - if isinstance(status, integer_types): - self.status_code = status - else: - self.status = status - - self.direct_passthrough = direct_passthrough - self._on_close = [] - - # we set the response after the headers so that if a class changes - # the charset attribute, the data is set in the correct charset. - if response is None: - self.response = [] - elif isinstance(response, (text_type, bytes, bytearray)): - self.set_data(response) - else: - self.response = response - - def call_on_close(self, func): - """Adds a function to the internal list of functions that should - be called as part of closing down the response. Since 0.7 this - function also returns the function that was passed so that this - can be used as a decorator. - - .. versionadded:: 0.6 - """ - self._on_close.append(func) - return func - - def __repr__(self): - if self.is_sequence: - body_info = '%d bytes' % sum(map(len, self.iter_encoded())) - else: - body_info = self.is_streamed and 'streamed' or 'likely-streamed' - return '<%s %s [%s]>' % ( - self.__class__.__name__, - body_info, - self.status - ) - - @classmethod - def force_type(cls, response, environ=None): - """Enforce that the WSGI response is a response object of the current - type. Werkzeug will use the :class:`BaseResponse` internally in many - situations like the exceptions. If you call :meth:`get_response` on an - exception you will get back a regular :class:`BaseResponse` object, even - if you are using a custom subclass. - - This method can enforce a given response type, and it will also - convert arbitrary WSGI callables into response objects if an environ - is provided:: - - # convert a Werkzeug response object into an instance of the - # MyResponseClass subclass. - response = MyResponseClass.force_type(response) - - # convert any WSGI application into a response object - response = MyResponseClass.force_type(response, environ) - - This is especially useful if you want to post-process responses in - the main dispatcher and use functionality provided by your subclass. - - Keep in mind that this will modify response objects in place if - possible! - - :param response: a response object or wsgi application. - :param environ: a WSGI environment object. - :return: a response object. - """ - if not isinstance(response, BaseResponse): - if environ is None: - raise TypeError('cannot convert WSGI application into ' - 'response objects without an environ') - response = BaseResponse(*_run_wsgi_app(response, environ)) - response.__class__ = cls - return response - - @classmethod - def from_app(cls, app, environ, buffered=False): - """Create a new response object from an application output. This - works best if you pass it an application that returns a generator all - the time. Sometimes applications may use the `write()` callable - returned by the `start_response` function. This tries to resolve such - edge cases automatically. But if you don't get the expected output - you should set `buffered` to `True` which enforces buffering. - - :param app: the WSGI application to execute. - :param environ: the WSGI environment to execute against. - :param buffered: set to `True` to enforce buffering. - :return: a response object. - """ - return cls(*_run_wsgi_app(app, environ, buffered)) - - def _get_status_code(self): - return self._status_code - def _set_status_code(self, code): - self._status_code = code - try: - self._status = '%d %s' % (code, HTTP_STATUS_CODES[code].upper()) - except KeyError: - self._status = '%d UNKNOWN' % code - status_code = property(_get_status_code, _set_status_code, - doc='The HTTP Status code as number') - del _get_status_code, _set_status_code - - def _get_status(self): - return self._status - def _set_status(self, value): - self._status = to_native(value) - try: - self._status_code = int(self._status.split(None, 1)[0]) - except ValueError: - self._status_code = 0 - self._status = '0 %s' % self._status - status = property(_get_status, _set_status, doc='The HTTP Status code') - del _get_status, _set_status - - def get_data(self, as_text=False): - """The string representation of the request body. Whenever you call - this property the request iterable is encoded and flattened. This - can lead to unwanted behavior if you stream big data. - - This behavior can be disabled by setting - :attr:`implicit_sequence_conversion` to `False`. - - If `as_text` is set to `True` the return value will be a decoded - unicode string. - - .. versionadded:: 0.9 - """ - self._ensure_sequence() - rv = b''.join(self.iter_encoded()) - if as_text: - rv = rv.decode(self.charset) - return rv - - def set_data(self, value): - """Sets a new string as response. The value set must either by a - unicode or bytestring. If a unicode string is set it's encoded - automatically to the charset of the response (utf-8 by default). - - .. versionadded:: 0.9 - """ - # if an unicode string is set, it's encoded directly so that we - # can set the content length - if isinstance(value, text_type): - value = value.encode(self.charset) - else: - value = bytes(value) - self.response = [value] - if self.automatically_set_content_length: - self.headers['Content-Length'] = str(len(value)) - - data = property(get_data, set_data, doc=''' - A descriptor that calls :meth:`get_data` and :meth:`set_data`. This - should not be used and will eventually get deprecated. - ''') - - def calculate_content_length(self): - """Returns the content length if available or `None` otherwise.""" - try: - self._ensure_sequence() - except RuntimeError: - return None - return sum(len(x) for x in self.response) - - def _ensure_sequence(self, mutable=False): - """This method can be called by methods that need a sequence. If - `mutable` is true, it will also ensure that the response sequence - is a standard Python list. - - .. versionadded:: 0.6 - """ - if self.is_sequence: - # if we need a mutable object, we ensure it's a list. - if mutable and not isinstance(self.response, list): - self.response = list(self.response) - return - if self.direct_passthrough: - raise RuntimeError('Attempted implicit sequence conversion ' - 'but the response object is in direct ' - 'passthrough mode.') - if not self.implicit_sequence_conversion: - raise RuntimeError('The response object required the iterable ' - 'to be a sequence, but the implicit ' - 'conversion was disabled. Call ' - 'make_sequence() yourself.') - self.make_sequence() - - def make_sequence(self): - """Converts the response iterator in a list. By default this happens - automatically if required. If `implicit_sequence_conversion` is - disabled, this method is not automatically called and some properties - might raise exceptions. This also encodes all the items. - - .. versionadded:: 0.6 - """ - if not self.is_sequence: - # if we consume an iterable we have to ensure that the close - # method of the iterable is called if available when we tear - # down the response - close = getattr(self.response, 'close', None) - self.response = list(self.iter_encoded()) - if close is not None: - self.call_on_close(close) - - def iter_encoded(self): - """Iter the response encoded with the encoding of the response. - If the response object is invoked as WSGI application the return - value of this method is used as application iterator unless - :attr:`direct_passthrough` was activated. - """ - if __debug__: - _warn_if_string(self.response) - # Encode in a separate function so that self.response is fetched - # early. This allows us to wrap the response with the return - # value from get_app_iter or iter_encoded. - return _iter_encoded(self.response, self.charset) - - def set_cookie(self, key, value='', max_age=None, expires=None, - path='/', domain=None, secure=None, httponly=False): - """Sets a cookie. The parameters are the same as in the cookie `Morsel` - object in the Python standard library but it accepts unicode data, too. - - :param key: the key (name) of the cookie to be set. - :param value: the value of the cookie. - :param max_age: should be a number of seconds, or `None` (default) if - the cookie should last only as long as the client's - browser session. - :param expires: should be a `datetime` object or UNIX timestamp. - :param domain: if you want to set a cross-domain cookie. For example, - ``domain=".example.com"`` will set a cookie that is - readable by the domain ``www.example.com``, - ``foo.example.com`` etc. Otherwise, a cookie will only - be readable by the domain that set it. - :param path: limits the cookie to a given path, per default it will - span the whole domain. - """ - self.headers.add('Set-Cookie', dump_cookie(key, value, max_age, - expires, path, domain, secure, httponly, - self.charset)) - - def delete_cookie(self, key, path='/', domain=None): - """Delete a cookie. Fails silently if key doesn't exist. - - :param key: the key (name) of the cookie to be deleted. - :param path: if the cookie that should be deleted was limited to a - path, the path has to be defined here. - :param domain: if the cookie that should be deleted was limited to a - domain, that domain has to be defined here. - """ - self.set_cookie(key, expires=0, max_age=0, path=path, domain=domain) - - @property - def is_streamed(self): - """If the response is streamed (the response is not an iterable with - a length information) this property is `True`. In this case streamed - means that there is no information about the number of iterations. - This is usually `True` if a generator is passed to the response object. - - This is useful for checking before applying some sort of post - filtering that should not take place for streamed responses. - """ - try: - len(self.response) - except (TypeError, AttributeError): - return True - return False - - @property - def is_sequence(self): - """If the iterator is buffered, this property will be `True`. A - response object will consider an iterator to be buffered if the - response attribute is a list or tuple. - - .. versionadded:: 0.6 - """ - return isinstance(self.response, (tuple, list)) - - def close(self): - """Close the wrapped response if possible. You can also use the object - in a with statement which will automatically close it. - - .. versionadded:: 0.9 - Can now be used in a with statement. - """ - if hasattr(self.response, 'close'): - self.response.close() - for func in self._on_close: - func() - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, tb): - self.close() - - def freeze(self): - """Call this method if you want to make your response object ready for - being pickled. This buffers the generator if there is one. It will - also set the `Content-Length` header to the length of the body. - - .. versionchanged:: 0.6 - The `Content-Length` header is now set. - """ - # we explicitly set the length to a list of the *encoded* response - # iterator. Even if the implicit sequence conversion is disabled. - self.response = list(self.iter_encoded()) - self.headers['Content-Length'] = str(sum(map(len, self.response))) - - def get_wsgi_headers(self, environ): - """This is automatically called right before the response is started - and returns headers modified for the given environment. It returns a - copy of the headers from the response with some modifications applied - if necessary. - - For example the location header (if present) is joined with the root - URL of the environment. Also the content length is automatically set - to zero here for certain status codes. - - .. versionchanged:: 0.6 - Previously that function was called `fix_headers` and modified - the response object in place. Also since 0.6, IRIs in location - and content-location headers are handled properly. - - Also starting with 0.6, Werkzeug will attempt to set the content - length if it is able to figure it out on its own. This is the - case if all the strings in the response iterable are already - encoded and the iterable is buffered. - - :param environ: the WSGI environment of the request. - :return: returns a new :class:`~werkzeug.datastructures.Headers` - object. - """ - headers = Headers(self.headers) - location = None - content_location = None - content_length = None - status = self.status_code - - # iterate over the headers to find all values in one go. Because - # get_wsgi_headers is used each response that gives us a tiny - # speedup. - for key, value in headers: - ikey = key.lower() - if ikey == u'location': - location = value - elif ikey == u'content-location': - content_location = value - elif ikey == u'content-length': - content_length = value - - # make sure the location header is an absolute URL - if location is not None: - old_location = location - if isinstance(location, text_type): - # Safe conversion is necessary here as we might redirect - # to a broken URI scheme (for instance itms-services). - location = iri_to_uri(location, safe_conversion=True) - - if self.autocorrect_location_header: - current_url = get_current_url(environ, root_only=True) - if isinstance(current_url, text_type): - current_url = iri_to_uri(current_url) - location = url_join(current_url, location) - if location != old_location: - headers['Location'] = location - - # make sure the content location is a URL - if content_location is not None and \ - isinstance(content_location, text_type): - headers['Content-Location'] = iri_to_uri(content_location) - - # remove entity headers and set content length to zero if needed. - # Also update content_length accordingly so that the automatic - # content length detection does not trigger in the following - # code. - if 100 <= status < 200 or status == 204: - headers['Content-Length'] = content_length = u'0' - elif status == 304: - remove_entity_headers(headers) - - # if we can determine the content length automatically, we - # should try to do that. But only if this does not involve - # flattening the iterator or encoding of unicode strings in - # the response. We however should not do that if we have a 304 - # response. - if self.automatically_set_content_length and \ - self.is_sequence and content_length is None and status != 304: - try: - content_length = sum(len(to_bytes(x, 'ascii')) - for x in self.response) - except UnicodeError: - # aha, something non-bytestringy in there, too bad, we - # can't safely figure out the length of the response. - pass - else: - headers['Content-Length'] = str(content_length) - - return headers - - def get_app_iter(self, environ): - """Returns the application iterator for the given environ. Depending - on the request method and the current status code the return value - might be an empty response rather than the one from the response. - - If the request method is `HEAD` or the status code is in a range - where the HTTP specification requires an empty response, an empty - iterable is returned. - - .. versionadded:: 0.6 - - :param environ: the WSGI environment of the request. - :return: a response iterable. - """ - status = self.status_code - if environ['REQUEST_METHOD'] == 'HEAD' or \ - 100 <= status < 200 or status in (204, 304): - iterable = () - elif self.direct_passthrough: - if __debug__: - _warn_if_string(self.response) - return self.response - else: - iterable = self.iter_encoded() - return ClosingIterator(iterable, self.close) - - def get_wsgi_response(self, environ): - """Returns the final WSGI response as tuple. The first item in - the tuple is the application iterator, the second the status and - the third the list of headers. The response returned is created - specially for the given environment. For example if the request - method in the WSGI environment is ``'HEAD'`` the response will - be empty and only the headers and status code will be present. - - .. versionadded:: 0.6 - - :param environ: the WSGI environment of the request. - :return: an ``(app_iter, status, headers)`` tuple. - """ - headers = self.get_wsgi_headers(environ) - app_iter = self.get_app_iter(environ) - return app_iter, self.status, headers.to_wsgi_list() - - def __call__(self, environ, start_response): - """Process this response as WSGI application. - - :param environ: the WSGI environment. - :param start_response: the response callable provided by the WSGI - server. - :return: an application iterator - """ - app_iter, status, headers = self.get_wsgi_response(environ) - start_response(status, headers) - return app_iter - - -class AcceptMixin(object): - """A mixin for classes with an :attr:`~BaseResponse.environ` attribute - to get all the HTTP accept headers as - :class:`~werkzeug.datastructures.Accept` objects (or subclasses - thereof). - """ - - @cached_property - def accept_mimetypes(self): - """List of mimetypes this client supports as - :class:`~werkzeug.datastructures.MIMEAccept` object. - """ - return parse_accept_header(self.environ.get('HTTP_ACCEPT'), MIMEAccept) - - @cached_property - def accept_charsets(self): - """List of charsets this client supports as - :class:`~werkzeug.datastructures.CharsetAccept` object. - """ - return parse_accept_header(self.environ.get('HTTP_ACCEPT_CHARSET'), - CharsetAccept) - - @cached_property - def accept_encodings(self): - """List of encodings this client accepts. Encodings in a HTTP term - are compression encodings such as gzip. For charsets have a look at - :attr:`accept_charset`. - """ - return parse_accept_header(self.environ.get('HTTP_ACCEPT_ENCODING')) - - @cached_property - def accept_languages(self): - """List of languages this client accepts as - :class:`~werkzeug.datastructures.LanguageAccept` object. - - .. versionchanged 0.5 - In previous versions this was a regular - :class:`~werkzeug.datastructures.Accept` object. - """ - return parse_accept_header(self.environ.get('HTTP_ACCEPT_LANGUAGE'), - LanguageAccept) - - -class ETagRequestMixin(object): - """Add entity tag and cache descriptors to a request object or object with - a WSGI environment available as :attr:`~BaseRequest.environ`. This not - only provides access to etags but also to the cache control header. - """ - - @cached_property - def cache_control(self): - """A :class:`~werkzeug.datastructures.RequestCacheControl` object - for the incoming cache control headers. - """ - cache_control = self.environ.get('HTTP_CACHE_CONTROL') - return parse_cache_control_header(cache_control, None, - RequestCacheControl) - - @cached_property - def if_match(self): - """An object containing all the etags in the `If-Match` header. - - :rtype: :class:`~werkzeug.datastructures.ETags` - """ - return parse_etags(self.environ.get('HTTP_IF_MATCH')) - - @cached_property - def if_none_match(self): - """An object containing all the etags in the `If-None-Match` header. - - :rtype: :class:`~werkzeug.datastructures.ETags` - """ - return parse_etags(self.environ.get('HTTP_IF_NONE_MATCH')) - - @cached_property - def if_modified_since(self): - """The parsed `If-Modified-Since` header as datetime object.""" - return parse_date(self.environ.get('HTTP_IF_MODIFIED_SINCE')) - - @cached_property - def if_unmodified_since(self): - """The parsed `If-Unmodified-Since` header as datetime object.""" - return parse_date(self.environ.get('HTTP_IF_UNMODIFIED_SINCE')) - - @cached_property - def if_range(self): - """The parsed `If-Range` header. - - .. versionadded:: 0.7 - - :rtype: :class:`~werkzeug.datastructures.IfRange` - """ - return parse_if_range_header(self.environ.get('HTTP_IF_RANGE')) - - @cached_property - def range(self): - """The parsed `Range` header. - - .. versionadded:: 0.7 - - :rtype: :class:`~werkzeug.datastructures.Range` - """ - return parse_range_header(self.environ.get('HTTP_RANGE')) - - -class UserAgentMixin(object): - """Adds a `user_agent` attribute to the request object which contains the - parsed user agent of the browser that triggered the request as a - :class:`~werkzeug.useragents.UserAgent` object. - """ - - @cached_property - def user_agent(self): - """The current user agent.""" - from werkzeug.useragents import UserAgent - return UserAgent(self.environ) - - -class AuthorizationMixin(object): - """Adds an :attr:`authorization` property that represents the parsed - value of the `Authorization` header as - :class:`~werkzeug.datastructures.Authorization` object. - """ - - @cached_property - def authorization(self): - """The `Authorization` object in parsed form.""" - header = self.environ.get('HTTP_AUTHORIZATION') - return parse_authorization_header(header) - - -class StreamOnlyMixin(object): - """If mixed in before the request object this will change the bahavior - of it to disable handling of form parsing. This disables the - :attr:`files`, :attr:`form` attributes and will just provide a - :attr:`stream` attribute that however is always available. - - .. versionadded:: 0.9 - """ - - disable_data_descriptor = True - want_form_data_parsed = False - - -class ETagResponseMixin(object): - """Adds extra functionality to a response object for etag and cache - handling. This mixin requires an object with at least a `headers` - object that implements a dict like interface similar to - :class:`~werkzeug.datastructures.Headers`. - - If you want the :meth:`freeze` method to automatically add an etag, you - have to mixin this method before the response base class. The default - response class does not do that. - """ - - @property - def cache_control(self): - """The Cache-Control general-header field is used to specify - directives that MUST be obeyed by all caching mechanisms along the - request/response chain. - """ - def on_update(cache_control): - if not cache_control and 'cache-control' in self.headers: - del self.headers['cache-control'] - elif cache_control: - self.headers['Cache-Control'] = cache_control.to_header() - return parse_cache_control_header(self.headers.get('cache-control'), - on_update, - ResponseCacheControl) - - def make_conditional(self, request_or_environ): - """Make the response conditional to the request. This method works - best if an etag was defined for the response already. The `add_etag` - method can be used to do that. If called without etag just the date - header is set. - - This does nothing if the request method in the request or environ is - anything but GET or HEAD. - - It does not remove the body of the response because that's something - the :meth:`__call__` function does for us automatically. - - Returns self so that you can do ``return resp.make_conditional(req)`` - but modifies the object in-place. - - :param request_or_environ: a request object or WSGI environment to be - used to make the response conditional - against. - """ - environ = _get_environ(request_or_environ) - if environ['REQUEST_METHOD'] in ('GET', 'HEAD'): - # if the date is not in the headers, add it now. We however - # will not override an already existing header. Unfortunately - # this header will be overriden by many WSGI servers including - # wsgiref. - if 'date' not in self.headers: - self.headers['Date'] = http_date() - if 'content-length' not in self.headers: - length = self.calculate_content_length() - if length is not None: - self.headers['Content-Length'] = length - if not is_resource_modified(environ, self.headers.get('etag'), None, - self.headers.get('last-modified')): - self.status_code = 304 - return self - - def add_etag(self, overwrite=False, weak=False): - """Add an etag for the current response if there is none yet.""" - if overwrite or 'etag' not in self.headers: - self.set_etag(generate_etag(self.get_data()), weak) - - def set_etag(self, etag, weak=False): - """Set the etag, and override the old one if there was one.""" - self.headers['ETag'] = quote_etag(etag, weak) - - def get_etag(self): - """Return a tuple in the form ``(etag, is_weak)``. If there is no - ETag the return value is ``(None, None)``. - """ - return unquote_etag(self.headers.get('ETag')) - - def freeze(self, no_etag=False): - """Call this method if you want to make your response object ready for - pickeling. This buffers the generator if there is one. This also - sets the etag unless `no_etag` is set to `True`. - """ - if not no_etag: - self.add_etag() - super(ETagResponseMixin, self).freeze() - - accept_ranges = header_property('Accept-Ranges', doc=''' - The `Accept-Ranges` header. Even though the name would indicate - that multiple values are supported, it must be one string token only. - - The values ``'bytes'`` and ``'none'`` are common. - - .. versionadded:: 0.7''') - - def _get_content_range(self): - def on_update(rng): - if not rng: - del self.headers['content-range'] - else: - self.headers['Content-Range'] = rng.to_header() - rv = parse_content_range_header(self.headers.get('content-range'), - on_update) - # always provide a content range object to make the descriptor - # more user friendly. It provides an unset() method that can be - # used to remove the header quickly. - if rv is None: - rv = ContentRange(None, None, None, on_update=on_update) - return rv - def _set_content_range(self, value): - if not value: - del self.headers['content-range'] - elif isinstance(value, string_types): - self.headers['Content-Range'] = value - else: - self.headers['Content-Range'] = value.to_header() - content_range = property(_get_content_range, _set_content_range, doc=''' - The `Content-Range` header as - :class:`~werkzeug.datastructures.ContentRange` object. Even if the - header is not set it wil provide such an object for easier - manipulation. - - .. versionadded:: 0.7''') - del _get_content_range, _set_content_range - - -class ResponseStream(object): - """A file descriptor like object used by the :class:`ResponseStreamMixin` to - represent the body of the stream. It directly pushes into the response - iterable of the response object. - """ - - mode = 'wb+' - - def __init__(self, response): - self.response = response - self.closed = False - - def write(self, value): - if self.closed: - raise ValueError('I/O operation on closed file') - self.response._ensure_sequence(mutable=True) - self.response.response.append(value) - - def writelines(self, seq): - for item in seq: - self.write(item) - - def close(self): - self.closed = True - - def flush(self): - if self.closed: - raise ValueError('I/O operation on closed file') - - def isatty(self): - if self.closed: - raise ValueError('I/O operation on closed file') - return False - - @property - def encoding(self): - return self.response.charset - - -class ResponseStreamMixin(object): - """Mixin for :class:`BaseRequest` subclasses. Classes that inherit from - this mixin will automatically get a :attr:`stream` property that provides - a write-only interface to the response iterable. - """ - - @cached_property - def stream(self): - """The response iterable as write-only stream.""" - return ResponseStream(self) - - -class CommonRequestDescriptorsMixin(object): - """A mixin for :class:`BaseRequest` subclasses. Request objects that - mix this class in will automatically get descriptors for a couple of - HTTP headers with automatic type conversion. - - .. versionadded:: 0.5 - """ - - content_type = environ_property('CONTENT_TYPE', doc=''' - The Content-Type entity-header field indicates the media type of - the entity-body sent to the recipient or, in the case of the HEAD - method, the media type that would have been sent had the request - been a GET.''') - - @cached_property - def content_length(self): - """The Content-Length entity-header field indicates the size of the - entity-body in bytes or, in the case of the HEAD method, the size of - the entity-body that would have been sent had the request been a - GET. - """ - return get_content_length(self.environ) - - content_encoding = environ_property('HTTP_CONTENT_ENCODING', doc=''' - The Content-Encoding entity-header field is used as a modifier to the - media-type. When present, its value indicates what additional content - codings have been applied to the entity-body, and thus what decoding - mechanisms must be applied in order to obtain the media-type - referenced by the Content-Type header field. - - .. versionadded:: 0.9''') - content_md5 = environ_property('HTTP_CONTENT_MD5', doc=''' - The Content-MD5 entity-header field, as defined in RFC 1864, is an - MD5 digest of the entity-body for the purpose of providing an - end-to-end message integrity check (MIC) of the entity-body. (Note: - a MIC is good for detecting accidental modification of the - entity-body in transit, but is not proof against malicious attacks.) - - .. versionadded:: 0.9''') - referrer = environ_property('HTTP_REFERER', doc=''' - The Referer[sic] request-header field allows the client to specify, - for the server's benefit, the address (URI) of the resource from which - the Request-URI was obtained (the "referrer", although the header - field is misspelled).''') - date = environ_property('HTTP_DATE', None, parse_date, doc=''' - The Date general-header field represents the date and time at which - the message was originated, having the same semantics as orig-date - in RFC 822.''') - max_forwards = environ_property('HTTP_MAX_FORWARDS', None, int, doc=''' - The Max-Forwards request-header field provides a mechanism with the - TRACE and OPTIONS methods to limit the number of proxies or gateways - that can forward the request to the next inbound server.''') - - def _parse_content_type(self): - if not hasattr(self, '_parsed_content_type'): - self._parsed_content_type = \ - parse_options_header(self.environ.get('CONTENT_TYPE', '')) - - @property - def mimetype(self): - """Like :attr:`content_type` but without parameters (eg, without - charset, type etc.). For example if the content - type is ``text/html; charset=utf-8`` the mimetype would be - ``'text/html'``. - """ - self._parse_content_type() - return self._parsed_content_type[0] - - @property - def mimetype_params(self): - """The mimetype parameters as dict. For example if the content - type is ``text/html; charset=utf-8`` the params would be - ``{'charset': 'utf-8'}``. - """ - self._parse_content_type() - return self._parsed_content_type[1] - - @cached_property - def pragma(self): - """The Pragma general-header field is used to include - implementation-specific directives that might apply to any recipient - along the request/response chain. All pragma directives specify - optional behavior from the viewpoint of the protocol; however, some - systems MAY require that behavior be consistent with the directives. - """ - return parse_set_header(self.environ.get('HTTP_PRAGMA', '')) - - -class CommonResponseDescriptorsMixin(object): - """A mixin for :class:`BaseResponse` subclasses. Response objects that - mix this class in will automatically get descriptors for a couple of - HTTP headers with automatic type conversion. - """ - - def _get_mimetype(self): - ct = self.headers.get('content-type') - if ct: - return ct.split(';')[0].strip() - - def _set_mimetype(self, value): - self.headers['Content-Type'] = get_content_type(value, self.charset) - - def _get_mimetype_params(self): - def on_update(d): - self.headers['Content-Type'] = \ - dump_options_header(self.mimetype, d) - d = parse_options_header(self.headers.get('content-type', ''))[1] - return CallbackDict(d, on_update) - - mimetype = property(_get_mimetype, _set_mimetype, doc=''' - The mimetype (content type without charset etc.)''') - mimetype_params = property(_get_mimetype_params, doc=''' - The mimetype parameters as dict. For example if the content - type is ``text/html; charset=utf-8`` the params would be - ``{'charset': 'utf-8'}``. - - .. versionadded:: 0.5 - ''') - location = header_property('Location', doc=''' - The Location response-header field is used to redirect the recipient - to a location other than the Request-URI for completion of the request - or identification of a new resource.''') - age = header_property('Age', None, parse_date, http_date, doc=''' - The Age response-header field conveys the sender's estimate of the - amount of time since the response (or its revalidation) was - generated at the origin server. - - Age values are non-negative decimal integers, representing time in - seconds.''') - content_type = header_property('Content-Type', doc=''' - The Content-Type entity-header field indicates the media type of the - entity-body sent to the recipient or, in the case of the HEAD method, - the media type that would have been sent had the request been a GET. - ''') - content_length = header_property('Content-Length', None, int, str, doc=''' - The Content-Length entity-header field indicates the size of the - entity-body, in decimal number of OCTETs, sent to the recipient or, - in the case of the HEAD method, the size of the entity-body that would - have been sent had the request been a GET.''') - content_location = header_property('Content-Location', doc=''' - The Content-Location entity-header field MAY be used to supply the - resource location for the entity enclosed in the message when that - entity is accessible from a location separate from the requested - resource's URI.''') - content_encoding = header_property('Content-Encoding', doc=''' - The Content-Encoding entity-header field is used as a modifier to the - media-type. When present, its value indicates what additional content - codings have been applied to the entity-body, and thus what decoding - mechanisms must be applied in order to obtain the media-type - referenced by the Content-Type header field.''') - content_md5 = header_property('Content-MD5', doc=''' - The Content-MD5 entity-header field, as defined in RFC 1864, is an - MD5 digest of the entity-body for the purpose of providing an - end-to-end message integrity check (MIC) of the entity-body. (Note: - a MIC is good for detecting accidental modification of the - entity-body in transit, but is not proof against malicious attacks.) - ''') - date = header_property('Date', None, parse_date, http_date, doc=''' - The Date general-header field represents the date and time at which - the message was originated, having the same semantics as orig-date - in RFC 822.''') - expires = header_property('Expires', None, parse_date, http_date, doc=''' - The Expires entity-header field gives the date/time after which the - response is considered stale. A stale cache entry may not normally be - returned by a cache.''') - last_modified = header_property('Last-Modified', None, parse_date, - http_date, doc=''' - The Last-Modified entity-header field indicates the date and time at - which the origin server believes the variant was last modified.''') - - def _get_retry_after(self): - value = self.headers.get('retry-after') - if value is None: - return - elif value.isdigit(): - return datetime.utcnow() + timedelta(seconds=int(value)) - return parse_date(value) - def _set_retry_after(self, value): - if value is None: - if 'retry-after' in self.headers: - del self.headers['retry-after'] - return - elif isinstance(value, datetime): - value = http_date(value) - else: - value = str(value) - self.headers['Retry-After'] = value - - retry_after = property(_get_retry_after, _set_retry_after, doc=''' - The Retry-After response-header field can be used with a 503 (Service - Unavailable) response to indicate how long the service is expected - to be unavailable to the requesting client. - - Time in seconds until expiration or date.''') - - def _set_property(name, doc=None): - def fget(self): - def on_update(header_set): - if not header_set and name in self.headers: - del self.headers[name] - elif header_set: - self.headers[name] = header_set.to_header() - return parse_set_header(self.headers.get(name), on_update) - def fset(self, value): - if not value: - del self.headers[name] - elif isinstance(value, string_types): - self.headers[name] = value - else: - self.headers[name] = dump_header(value) - return property(fget, fset, doc=doc) - - vary = _set_property('Vary', doc=''' - The Vary field value indicates the set of request-header fields that - fully determines, while the response is fresh, whether a cache is - permitted to use the response to reply to a subsequent request - without revalidation.''') - content_language = _set_property('Content-Language', doc=''' - The Content-Language entity-header field describes the natural - language(s) of the intended audience for the enclosed entity. Note - that this might not be equivalent to all the languages used within - the entity-body.''') - allow = _set_property('Allow', doc=''' - The Allow entity-header field lists the set of methods supported - by the resource identified by the Request-URI. The purpose of this - field is strictly to inform the recipient of valid methods - associated with the resource. An Allow header field MUST be - present in a 405 (Method Not Allowed) response.''') - - del _set_property, _get_mimetype, _set_mimetype, _get_retry_after, \ - _set_retry_after - - -class WWWAuthenticateMixin(object): - """Adds a :attr:`www_authenticate` property to a response object.""" - - @property - def www_authenticate(self): - """The `WWW-Authenticate` header in a parsed form.""" - def on_update(www_auth): - if not www_auth and 'www-authenticate' in self.headers: - del self.headers['www-authenticate'] - elif www_auth: - self.headers['WWW-Authenticate'] = www_auth.to_header() - header = self.headers.get('www-authenticate') - return parse_www_authenticate_header(header, on_update) - - -class Request(BaseRequest, AcceptMixin, ETagRequestMixin, - UserAgentMixin, AuthorizationMixin, - CommonRequestDescriptorsMixin): - """Full featured request object implementing the following mixins: - - - :class:`AcceptMixin` for accept header parsing - - :class:`ETagRequestMixin` for etag and cache control handling - - :class:`UserAgentMixin` for user agent introspection - - :class:`AuthorizationMixin` for http auth handling - - :class:`CommonRequestDescriptorsMixin` for common headers - """ - - -class PlainRequest(StreamOnlyMixin, Request): - """A request object without special form parsing capabilities. - - .. versionadded:: 0.9 - """ - - -class Response(BaseResponse, ETagResponseMixin, ResponseStreamMixin, - CommonResponseDescriptorsMixin, - WWWAuthenticateMixin): - """Full featured response object implementing the following mixins: - - - :class:`ETagResponseMixin` for etag and cache control handling - - :class:`ResponseStreamMixin` to add support for the `stream` property - - :class:`CommonResponseDescriptorsMixin` for various HTTP descriptors - - :class:`WWWAuthenticateMixin` for HTTP authentication support - """ diff --git a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/wsgi.py b/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/wsgi.py deleted file mode 100644 index 03042b57..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site-packages/werkzeug/wsgi.py +++ /dev/null @@ -1,1047 +0,0 @@ -# -*- coding: utf-8 -*- -""" - werkzeug.wsgi - ~~~~~~~~~~~~~ - - This module implements WSGI related helpers. - - :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" -import re -import os -import sys -import posixpath -import mimetypes -from itertools import chain -from zlib import adler32 -from time import time, mktime -from datetime import datetime -from functools import partial, update_wrapper - -from werkzeug._compat import iteritems, text_type, string_types, \ - implements_iterator, make_literal_wrapper, to_unicode, to_bytes, \ - wsgi_get_bytes, try_coerce_native, PY2 -from werkzeug._internal import _empty_stream, _encode_idna -from werkzeug.http import is_resource_modified, http_date -from werkzeug.urls import uri_to_iri, url_quote, url_parse, url_join - - -def responder(f): - """Marks a function as responder. Decorate a function with it and it - will automatically call the return value as WSGI application. - - Example:: - - @responder - def application(environ, start_response): - return Response('Hello World!') - """ - return update_wrapper(lambda *a: f(*a)(*a[-2:]), f) - - -def get_current_url(environ, root_only=False, strip_querystring=False, - host_only=False, trusted_hosts=None): - """A handy helper function that recreates the full URL as IRI for the - current request or parts of it. Here an example: - - >>> from werkzeug.test import create_environ - >>> env = create_environ("/?param=foo", "http://localhost/script") - >>> get_current_url(env) - 'http://localhost/script/?param=foo' - >>> get_current_url(env, root_only=True) - 'http://localhost/script/' - >>> get_current_url(env, host_only=True) - 'http://localhost/' - >>> get_current_url(env, strip_querystring=True) - 'http://localhost/script/' - - This optionally it verifies that the host is in a list of trusted hosts. - If the host is not in there it will raise a - :exc:`~werkzeug.exceptions.SecurityError`. - - Note that the string returned might contain unicode characters as the - representation is an IRI not an URI. If you need an ASCII only - representation you can use the :func:`~werkzeug.urls.iri_to_uri` - function: - - >>> from werkzeug.urls import iri_to_uri - >>> iri_to_uri(get_current_url(env)) - 'http://localhost/script/?param=foo' - - :param environ: the WSGI environment to get the current URL from. - :param root_only: set `True` if you only want the root URL. - :param strip_querystring: set to `True` if you don't want the querystring. - :param host_only: set to `True` if the host URL should be returned. - :param trusted_hosts: a list of trusted hosts, see :func:`host_is_trusted` - for more information. - """ - tmp = [environ['wsgi.url_scheme'], '://', get_host(environ, trusted_hosts)] - cat = tmp.append - if host_only: - return uri_to_iri(''.join(tmp) + '/') - cat(url_quote(wsgi_get_bytes(environ.get('SCRIPT_NAME', ''))).rstrip('/')) - cat('/') - if not root_only: - cat(url_quote(wsgi_get_bytes(environ.get('PATH_INFO', '')).lstrip(b'/'))) - if not strip_querystring: - qs = get_query_string(environ) - if qs: - cat('?' + qs) - return uri_to_iri(''.join(tmp)) - - -def host_is_trusted(hostname, trusted_list): - """Checks if a host is trusted against a list. This also takes care - of port normalization. - - .. versionadded:: 0.9 - - :param hostname: the hostname to check - :param trusted_list: a list of hostnames to check against. If a - hostname starts with a dot it will match against - all subdomains as well. - """ - if not hostname: - return False - - if isinstance(trusted_list, string_types): - trusted_list = [trusted_list] - - def _normalize(hostname): - if ':' in hostname: - hostname = hostname.rsplit(':', 1)[0] - return _encode_idna(hostname) - - hostname = _normalize(hostname) - for ref in trusted_list: - if ref.startswith('.'): - ref = ref[1:] - suffix_match = True - else: - suffix_match = False - ref = _normalize(ref) - if ref == hostname: - return True - if suffix_match and hostname.endswith('.' + ref): - return True - return False - - -def get_host(environ, trusted_hosts=None): - """Return the real host for the given WSGI environment. This takes care - of the `X-Forwarded-Host` header. Optionally it verifies that the host - is in a list of trusted hosts. If the host is not in there it will raise - a :exc:`~werkzeug.exceptions.SecurityError`. - - :param environ: the WSGI environment to get the host of. - :param trusted_hosts: a list of trusted hosts, see :func:`host_is_trusted` - for more information. - """ - if 'HTTP_X_FORWARDED_HOST' in environ: - rv = environ['HTTP_X_FORWARDED_HOST'].split(',')[0].strip() - elif 'HTTP_HOST' in environ: - rv = environ['HTTP_HOST'] - else: - rv = environ['SERVER_NAME'] - if (environ['wsgi.url_scheme'], environ['SERVER_PORT']) not \ - in (('https', '443'), ('http', '80')): - rv += ':' + environ['SERVER_PORT'] - if trusted_hosts is not None: - if not host_is_trusted(rv, trusted_hosts): - from werkzeug.exceptions import SecurityError - raise SecurityError('Host "%s" is not trusted' % rv) - return rv - - -def get_content_length(environ): - """Returns the content length from the WSGI environment as - integer. If it's not available `None` is returned. - - .. versionadded:: 0.9 - - :param environ: the WSGI environ to fetch the content length from. - """ - content_length = environ.get('CONTENT_LENGTH') - if content_length is not None: - try: - return max(0, int(content_length)) - except (ValueError, TypeError): - pass - - -def get_input_stream(environ, safe_fallback=True): - """Returns the input stream from the WSGI environment and wraps it - in the most sensible way possible. The stream returned is not the - raw WSGI stream in most cases but one that is safe to read from - without taking into account the content length. - - .. versionadded:: 0.9 - - :param environ: the WSGI environ to fetch the stream from. - :param safe: indicates weather the function should use an empty - stream as safe fallback or just return the original - WSGI input stream if it can't wrap it safely. The - default is to return an empty string in those cases. - """ - stream = environ['wsgi.input'] - content_length = get_content_length(environ) - - # A wsgi extension that tells us if the input is terminated. In - # that case we return the stream unchanged as we know we can savely - # read it until the end. - if environ.get('wsgi.input_terminated'): - return stream - - # If we don't have a content length we fall back to an empty stream - # in case of a safe fallback, otherwise we return the stream unchanged. - # The non-safe fallback is not recommended but might be useful in - # some situations. - if content_length is None: - return safe_fallback and _empty_stream or stream - - # Otherwise limit the stream to the content length - return LimitedStream(stream, content_length) - - -def get_query_string(environ): - """Returns the `QUERY_STRING` from the WSGI environment. This also takes - care about the WSGI decoding dance on Python 3 environments as a - native string. The string returned will be restricted to ASCII - characters. - - .. versionadded:: 0.9 - - :param environ: the WSGI environment object to get the query string from. - """ - qs = wsgi_get_bytes(environ.get('QUERY_STRING', '')) - # QUERY_STRING really should be ascii safe but some browsers - # will send us some unicode stuff (I am looking at you IE). - # In that case we want to urllib quote it badly. - return try_coerce_native(url_quote(qs, safe=':&%=+$!*\'(),')) - - -def get_path_info(environ, charset='utf-8', errors='replace'): - """Returns the `PATH_INFO` from the WSGI environment and properly - decodes it. This also takes care about the WSGI decoding dance - on Python 3 environments. if the `charset` is set to `None` a - bytestring is returned. - - .. versionadded:: 0.9 - - :param environ: the WSGI environment object to get the path from. - :param charset: the charset for the path info, or `None` if no - decoding should be performed. - :param errors: the decoding error handling. - """ - path = wsgi_get_bytes(environ.get('PATH_INFO', '')) - return to_unicode(path, charset, errors, allow_none_charset=True) - - -def get_script_name(environ, charset='utf-8', errors='replace'): - """Returns the `SCRIPT_NAME` from the WSGI environment and properly - decodes it. This also takes care about the WSGI decoding dance - on Python 3 environments. if the `charset` is set to `None` a - bytestring is returned. - - .. versionadded:: 0.9 - - :param environ: the WSGI environment object to get the path from. - :param charset: the charset for the path, or `None` if no - decoding should be performed. - :param errors: the decoding error handling. - """ - path = wsgi_get_bytes(environ.get('SCRIPT_NAME', '')) - return to_unicode(path, charset, errors, allow_none_charset=True) - - -def pop_path_info(environ, charset='utf-8', errors='replace'): - """Removes and returns the next segment of `PATH_INFO`, pushing it onto - `SCRIPT_NAME`. Returns `None` if there is nothing left on `PATH_INFO`. - - If the `charset` is set to `None` a bytestring is returned. - - If there are empty segments (``'/foo//bar``) these are ignored but - properly pushed to the `SCRIPT_NAME`: - - >>> env = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/a/b'} - >>> pop_path_info(env) - 'a' - >>> env['SCRIPT_NAME'] - '/foo/a' - >>> pop_path_info(env) - 'b' - >>> env['SCRIPT_NAME'] - '/foo/a/b' - - .. versionadded:: 0.5 - - .. versionchanged:: 0.9 - The path is now decoded and a charset and encoding - parameter can be provided. - - :param environ: the WSGI environment that is modified. - """ - path = environ.get('PATH_INFO') - if not path: - return None - - script_name = environ.get('SCRIPT_NAME', '') - - # shift multiple leading slashes over - old_path = path - path = path.lstrip('/') - if path != old_path: - script_name += '/' * (len(old_path) - len(path)) - - if '/' not in path: - environ['PATH_INFO'] = '' - environ['SCRIPT_NAME'] = script_name + path - rv = wsgi_get_bytes(path) - else: - segment, path = path.split('/', 1) - environ['PATH_INFO'] = '/' + path - environ['SCRIPT_NAME'] = script_name + segment - rv = wsgi_get_bytes(segment) - - return to_unicode(rv, charset, errors, allow_none_charset=True) - - -def peek_path_info(environ, charset='utf-8', errors='replace'): - """Returns the next segment on the `PATH_INFO` or `None` if there - is none. Works like :func:`pop_path_info` without modifying the - environment: - - >>> env = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/a/b'} - >>> peek_path_info(env) - 'a' - >>> peek_path_info(env) - 'a' - - If the `charset` is set to `None` a bytestring is returned. - - .. versionadded:: 0.5 - - .. versionchanged:: 0.9 - The path is now decoded and a charset and encoding - parameter can be provided. - - :param environ: the WSGI environment that is checked. - """ - segments = environ.get('PATH_INFO', '').lstrip('/').split('/', 1) - if segments: - return to_unicode(wsgi_get_bytes(segments[0]), - charset, errors, allow_none_charset=True) - - -def extract_path_info(environ_or_baseurl, path_or_url, charset='utf-8', - errors='replace', collapse_http_schemes=True): - """Extracts the path info from the given URL (or WSGI environment) and - path. The path info returned is a unicode string, not a bytestring - suitable for a WSGI environment. The URLs might also be IRIs. - - If the path info could not be determined, `None` is returned. - - Some examples: - - >>> extract_path_info('http://example.com/app', '/app/hello') - u'/hello' - >>> extract_path_info('http://example.com/app', - ... 'https://example.com/app/hello') - u'/hello' - >>> extract_path_info('http://example.com/app', - ... 'https://example.com/app/hello', - ... collapse_http_schemes=False) is None - True - - Instead of providing a base URL you can also pass a WSGI environment. - - .. versionadded:: 0.6 - - :param environ_or_baseurl: a WSGI environment dict, a base URL or - base IRI. This is the root of the - application. - :param path_or_url: an absolute path from the server root, a - relative path (in which case it's the path info) - or a full URL. Also accepts IRIs and unicode - parameters. - :param charset: the charset for byte data in URLs - :param errors: the error handling on decode - :param collapse_http_schemes: if set to `False` the algorithm does - not assume that http and https on the - same server point to the same - resource. - """ - def _normalize_netloc(scheme, netloc): - parts = netloc.split(u'@', 1)[-1].split(u':', 1) - if len(parts) == 2: - netloc, port = parts - if (scheme == u'http' and port == u'80') or \ - (scheme == u'https' and port == u'443'): - port = None - else: - netloc = parts[0] - port = None - if port is not None: - netloc += u':' + port - return netloc - - # make sure whatever we are working on is a IRI and parse it - path = uri_to_iri(path_or_url, charset, errors) - if isinstance(environ_or_baseurl, dict): - environ_or_baseurl = get_current_url(environ_or_baseurl, - root_only=True) - base_iri = uri_to_iri(environ_or_baseurl, charset, errors) - base_scheme, base_netloc, base_path = url_parse(base_iri)[:3] - cur_scheme, cur_netloc, cur_path, = \ - url_parse(url_join(base_iri, path))[:3] - - # normalize the network location - base_netloc = _normalize_netloc(base_scheme, base_netloc) - cur_netloc = _normalize_netloc(cur_scheme, cur_netloc) - - # is that IRI even on a known HTTP scheme? - if collapse_http_schemes: - for scheme in base_scheme, cur_scheme: - if scheme not in (u'http', u'https'): - return None - else: - if not (base_scheme in (u'http', u'https') and - base_scheme == cur_scheme): - return None - - # are the netlocs compatible? - if base_netloc != cur_netloc: - return None - - # are we below the application path? - base_path = base_path.rstrip(u'/') - if not cur_path.startswith(base_path): - return None - - return u'/' + cur_path[len(base_path):].lstrip(u'/') - - -class SharedDataMiddleware(object): - """A WSGI middleware that provides static content for development - environments or simple server setups. Usage is quite simple:: - - import os - from werkzeug.wsgi import SharedDataMiddleware - - app = SharedDataMiddleware(app, { - '/shared': os.path.join(os.path.dirname(__file__), 'shared') - }) - - The contents of the folder ``./shared`` will now be available on - ``http://example.com/shared/``. This is pretty useful during development - because a standalone media server is not required. One can also mount - files on the root folder and still continue to use the application because - the shared data middleware forwards all unhandled requests to the - application, even if the requests are below one of the shared folders. - - If `pkg_resources` is available you can also tell the middleware to serve - files from package data:: - - app = SharedDataMiddleware(app, { - '/shared': ('myapplication', 'shared_files') - }) - - This will then serve the ``shared_files`` folder in the `myapplication` - Python package. - - The optional `disallow` parameter can be a list of :func:`~fnmatch.fnmatch` - rules for files that are not accessible from the web. If `cache` is set to - `False` no caching headers are sent. - - Currently the middleware does not support non ASCII filenames. If the - encoding on the file system happens to be the encoding of the URI it may - work but this could also be by accident. We strongly suggest using ASCII - only file names for static files. - - The middleware will guess the mimetype using the Python `mimetype` - module. If it's unable to figure out the charset it will fall back - to `fallback_mimetype`. - - .. versionchanged:: 0.5 - The cache timeout is configurable now. - - .. versionadded:: 0.6 - The `fallback_mimetype` parameter was added. - - :param app: the application to wrap. If you don't want to wrap an - application you can pass it :exc:`NotFound`. - :param exports: a dict of exported files and folders. - :param disallow: a list of :func:`~fnmatch.fnmatch` rules. - :param fallback_mimetype: the fallback mimetype for unknown files. - :param cache: enable or disable caching headers. - :Param cache_timeout: the cache timeout in seconds for the headers. - """ - - def __init__(self, app, exports, disallow=None, cache=True, - cache_timeout=60 * 60 * 12, fallback_mimetype='text/plain'): - self.app = app - self.exports = {} - self.cache = cache - self.cache_timeout = cache_timeout - for key, value in iteritems(exports): - if isinstance(value, tuple): - loader = self.get_package_loader(*value) - elif isinstance(value, string_types): - if os.path.isfile(value): - loader = self.get_file_loader(value) - else: - loader = self.get_directory_loader(value) - else: - raise TypeError('unknown def %r' % value) - self.exports[key] = loader - if disallow is not None: - from fnmatch import fnmatch - self.is_allowed = lambda x: not fnmatch(x, disallow) - self.fallback_mimetype = fallback_mimetype - - def is_allowed(self, filename): - """Subclasses can override this method to disallow the access to - certain files. However by providing `disallow` in the constructor - this method is overwritten. - """ - return True - - def _opener(self, filename): - return lambda: ( - open(filename, 'rb'), - datetime.utcfromtimestamp(os.path.getmtime(filename)), - int(os.path.getsize(filename)) - ) - - def get_file_loader(self, filename): - return lambda x: (os.path.basename(filename), self._opener(filename)) - - def get_package_loader(self, package, package_path): - from pkg_resources import DefaultProvider, ResourceManager, \ - get_provider - loadtime = datetime.utcnow() - provider = get_provider(package) - manager = ResourceManager() - filesystem_bound = isinstance(provider, DefaultProvider) - def loader(path): - if path is None: - return None, None - path = posixpath.join(package_path, path) - if not provider.has_resource(path): - return None, None - basename = posixpath.basename(path) - if filesystem_bound: - return basename, self._opener( - provider.get_resource_filename(manager, path)) - return basename, lambda: ( - provider.get_resource_stream(manager, path), - loadtime, - 0 - ) - return loader - - def get_directory_loader(self, directory): - def loader(path): - if path is not None: - path = os.path.join(directory, path) - else: - path = directory - if os.path.isfile(path): - return os.path.basename(path), self._opener(path) - return None, None - return loader - - def generate_etag(self, mtime, file_size, real_filename): - if not isinstance(real_filename, bytes): - real_filename = real_filename.encode(sys.getfilesystemencoding()) - return 'wzsdm-%d-%s-%s' % ( - mktime(mtime.timetuple()), - file_size, - adler32(real_filename) & 0xffffffff - ) - - def __call__(self, environ, start_response): - cleaned_path = get_path_info(environ) - if PY2: - cleaned_path = cleaned_path.encode(sys.getfilesystemencoding()) - # sanitize the path for non unix systems - cleaned_path = cleaned_path.strip('/') - for sep in os.sep, os.altsep: - if sep and sep != '/': - cleaned_path = cleaned_path.replace(sep, '/') - path = '/'.join([''] + [x for x in cleaned_path.split('/') - if x and x != '..']) - file_loader = None - for search_path, loader in iteritems(self.exports): - if search_path == path: - real_filename, file_loader = loader(None) - if file_loader is not None: - break - if not search_path.endswith('/'): - search_path += '/' - if path.startswith(search_path): - real_filename, file_loader = loader(path[len(search_path):]) - if file_loader is not None: - break - if file_loader is None or not self.is_allowed(real_filename): - return self.app(environ, start_response) - - guessed_type = mimetypes.guess_type(real_filename) - mime_type = guessed_type[0] or self.fallback_mimetype - f, mtime, file_size = file_loader() - - headers = [('Date', http_date())] - if self.cache: - timeout = self.cache_timeout - etag = self.generate_etag(mtime, file_size, real_filename) - headers += [ - ('Etag', '"%s"' % etag), - ('Cache-Control', 'max-age=%d, public' % timeout) - ] - if not is_resource_modified(environ, etag, last_modified=mtime): - f.close() - start_response('304 Not Modified', headers) - return [] - headers.append(('Expires', http_date(time() + timeout))) - else: - headers.append(('Cache-Control', 'public')) - - headers.extend(( - ('Content-Type', mime_type), - ('Content-Length', str(file_size)), - ('Last-Modified', http_date(mtime)) - )) - start_response('200 OK', headers) - return wrap_file(environ, f) - - -class DispatcherMiddleware(object): - """Allows one to mount middlewares or applications in a WSGI application. - This is useful if you want to combine multiple WSGI applications:: - - app = DispatcherMiddleware(app, { - '/app2': app2, - '/app3': app3 - }) - """ - - def __init__(self, app, mounts=None): - self.app = app - self.mounts = mounts or {} - - def __call__(self, environ, start_response): - script = environ.get('PATH_INFO', '') - path_info = '' - while '/' in script: - if script in self.mounts: - app = self.mounts[script] - break - items = script.split('/') - script = '/'.join(items[:-1]) - path_info = '/%s%s' % (items[-1], path_info) - else: - app = self.mounts.get(script, self.app) - original_script_name = environ.get('SCRIPT_NAME', '') - environ['SCRIPT_NAME'] = original_script_name + script - environ['PATH_INFO'] = path_info - return app(environ, start_response) - - -@implements_iterator -class ClosingIterator(object): - """The WSGI specification requires that all middlewares and gateways - respect the `close` callback of an iterator. Because it is useful to add - another close action to a returned iterator and adding a custom iterator - is a boring task this class can be used for that:: - - return ClosingIterator(app(environ, start_response), [cleanup_session, - cleanup_locals]) - - If there is just one close function it can be passed instead of the list. - - A closing iterator is not needed if the application uses response objects - and finishes the processing if the response is started:: - - try: - return response(environ, start_response) - finally: - cleanup_session() - cleanup_locals() - """ - - def __init__(self, iterable, callbacks=None): - iterator = iter(iterable) - self._next = partial(next, iterator) - if callbacks is None: - callbacks = [] - elif callable(callbacks): - callbacks = [callbacks] - else: - callbacks = list(callbacks) - iterable_close = getattr(iterator, 'close', None) - if iterable_close: - callbacks.insert(0, iterable_close) - self._callbacks = callbacks - - def __iter__(self): - return self - - def __next__(self): - return self._next() - - def close(self): - for callback in self._callbacks: - callback() - - -def wrap_file(environ, file, buffer_size=8192): - """Wraps a file. This uses the WSGI server's file wrapper if available - or otherwise the generic :class:`FileWrapper`. - - .. versionadded:: 0.5 - - If the file wrapper from the WSGI server is used it's important to not - iterate over it from inside the application but to pass it through - unchanged. If you want to pass out a file wrapper inside a response - object you have to set :attr:`~BaseResponse.direct_passthrough` to `True`. - - More information about file wrappers are available in :pep:`333`. - - :param file: a :class:`file`-like object with a :meth:`~file.read` method. - :param buffer_size: number of bytes for one iteration. - """ - return environ.get('wsgi.file_wrapper', FileWrapper)(file, buffer_size) - - -@implements_iterator -class FileWrapper(object): - """This class can be used to convert a :class:`file`-like object into - an iterable. It yields `buffer_size` blocks until the file is fully - read. - - You should not use this class directly but rather use the - :func:`wrap_file` function that uses the WSGI server's file wrapper - support if it's available. - - .. versionadded:: 0.5 - - If you're using this object together with a :class:`BaseResponse` you have - to use the `direct_passthrough` mode. - - :param file: a :class:`file`-like object with a :meth:`~file.read` method. - :param buffer_size: number of bytes for one iteration. - """ - - def __init__(self, file, buffer_size=8192): - self.file = file - self.buffer_size = buffer_size - - def close(self): - if hasattr(self.file, 'close'): - self.file.close() - - def __iter__(self): - return self - - def __next__(self): - data = self.file.read(self.buffer_size) - if data: - return data - raise StopIteration() - - -def _make_chunk_iter(stream, limit, buffer_size): - """Helper for the line and chunk iter functions.""" - if isinstance(stream, (bytes, bytearray, text_type)): - raise TypeError('Passed a string or byte object instead of ' - 'true iterator or stream.') - if not hasattr(stream, 'read'): - for item in stream: - if item: - yield item - return - if not isinstance(stream, LimitedStream) and limit is not None: - stream = LimitedStream(stream, limit) - _read = stream.read - while 1: - item = _read(buffer_size) - if not item: - break - yield item - - -def make_line_iter(stream, limit=None, buffer_size=10 * 1024): - """Safely iterates line-based over an input stream. If the input stream - is not a :class:`LimitedStream` the `limit` parameter is mandatory. - - This uses the stream's :meth:`~file.read` method internally as opposite - to the :meth:`~file.readline` method that is unsafe and can only be used - in violation of the WSGI specification. The same problem applies to the - `__iter__` function of the input stream which calls :meth:`~file.readline` - without arguments. - - If you need line-by-line processing it's strongly recommended to iterate - over the input stream using this helper function. - - .. versionchanged:: 0.8 - This function now ensures that the limit was reached. - - .. versionadded:: 0.9 - added support for iterators as input stream. - - :param stream: the stream or iterate to iterate over. - :param limit: the limit in bytes for the stream. (Usually - content length. Not necessary if the `stream` - is a :class:`LimitedStream`. - :param buffer_size: The optional buffer size. - """ - _iter = _make_chunk_iter(stream, limit, buffer_size) - - first_item = next(_iter, '') - if not first_item: - return - - s = make_literal_wrapper(first_item) - empty = s('') - cr = s('\r') - lf = s('\n') - crlf = s('\r\n') - - _iter = chain((first_item,), _iter) - - def _iter_basic_lines(): - _join = empty.join - buffer = [] - while 1: - new_data = next(_iter, '') - if not new_data: - break - new_buf = [] - for item in chain(buffer, new_data.splitlines(True)): - new_buf.append(item) - if item and item[-1:] in crlf: - yield _join(new_buf) - new_buf = [] - buffer = new_buf - if buffer: - yield _join(buffer) - - # This hackery is necessary to merge 'foo\r' and '\n' into one item - # of 'foo\r\n' if we were unlucky and we hit a chunk boundary. - previous = empty - for item in _iter_basic_lines(): - if item == lf and previous[-1:] == cr: - previous += item - item = empty - if previous: - yield previous - previous = item - if previous: - yield previous - - -def make_chunk_iter(stream, separator, limit=None, buffer_size=10 * 1024): - """Works like :func:`make_line_iter` but accepts a separator - which divides chunks. If you want newline based processing - you should use :func:`make_line_iter` instead as it - supports arbitrary newline markers. - - .. versionadded:: 0.8 - - .. versionadded:: 0.9 - added support for iterators as input stream. - - :param stream: the stream or iterate to iterate over. - :param separator: the separator that divides chunks. - :param limit: the limit in bytes for the stream. (Usually - content length. Not necessary if the `stream` - is otherwise already limited). - :param buffer_size: The optional buffer size. - """ - _iter = _make_chunk_iter(stream, limit, buffer_size) - - first_item = next(_iter, '') - if not first_item: - return - - _iter = chain((first_item,), _iter) - if isinstance(first_item, text_type): - separator = to_unicode(separator) - _split = re.compile(r'(%s)' % re.escape(separator)).split - _join = u''.join - else: - separator = to_bytes(separator) - _split = re.compile(b'(' + re.escape(separator) + b')').split - _join = b''.join - - buffer = [] - while 1: - new_data = next(_iter, '') - if not new_data: - break - chunks = _split(new_data) - new_buf = [] - for item in chain(buffer, chunks): - if item == separator: - yield _join(new_buf) - new_buf = [] - else: - new_buf.append(item) - buffer = new_buf - if buffer: - yield _join(buffer) - - -@implements_iterator -class LimitedStream(object): - """Wraps a stream so that it doesn't read more than n bytes. If the - stream is exhausted and the caller tries to get more bytes from it - :func:`on_exhausted` is called which by default returns an empty - string. The return value of that function is forwarded - to the reader function. So if it returns an empty string - :meth:`read` will return an empty string as well. - - The limit however must never be higher than what the stream can - output. Otherwise :meth:`readlines` will try to read past the - limit. - - .. admonition:: Note on WSGI compliance - - calls to :meth:`readline` and :meth:`readlines` are not - WSGI compliant because it passes a size argument to the - readline methods. Unfortunately the WSGI PEP is not safely - implementable without a size argument to :meth:`readline` - because there is no EOF marker in the stream. As a result - of that the use of :meth:`readline` is discouraged. - - For the same reason iterating over the :class:`LimitedStream` - is not portable. It internally calls :meth:`readline`. - - We strongly suggest using :meth:`read` only or using the - :func:`make_line_iter` which safely iterates line-based - over a WSGI input stream. - - :param stream: the stream to wrap. - :param limit: the limit for the stream, must not be longer than - what the string can provide if the stream does not - end with `EOF` (like `wsgi.input`) - """ - - def __init__(self, stream, limit): - self._read = stream.read - self._readline = stream.readline - self._pos = 0 - self.limit = limit - - def __iter__(self): - return self - - @property - def is_exhausted(self): - """If the stream is exhausted this attribute is `True`.""" - return self._pos >= self.limit - - def on_exhausted(self): - """This is called when the stream tries to read past the limit. - The return value of this function is returned from the reading - function. - """ - # Read null bytes from the stream so that we get the - # correct end of stream marker. - return self._read(0) - - def on_disconnect(self): - """What should happen if a disconnect is detected? The return - value of this function is returned from read functions in case - the client went away. By default a - :exc:`~werkzeug.exceptions.ClientDisconnected` exception is raised. - """ - from werkzeug.exceptions import ClientDisconnected - raise ClientDisconnected() - - def exhaust(self, chunk_size=1024 * 64): - """Exhaust the stream. This consumes all the data left until the - limit is reached. - - :param chunk_size: the size for a chunk. It will read the chunk - until the stream is exhausted and throw away - the results. - """ - to_read = self.limit - self._pos - chunk = chunk_size - while to_read > 0: - chunk = min(to_read, chunk) - self.read(chunk) - to_read -= chunk - - def read(self, size=None): - """Read `size` bytes or if size is not provided everything is read. - - :param size: the number of bytes read. - """ - if self._pos >= self.limit: - return self.on_exhausted() - if size is None or size == -1: # -1 is for consistence with file - size = self.limit - to_read = min(self.limit - self._pos, size) - try: - read = self._read(to_read) - except (IOError, ValueError): - return self.on_disconnect() - if to_read and len(read) != to_read: - return self.on_disconnect() - self._pos += len(read) - return read - - def readline(self, size=None): - """Reads one line from the stream.""" - if self._pos >= self.limit: - return self.on_exhausted() - if size is None: - size = self.limit - self._pos - else: - size = min(size, self.limit - self._pos) - try: - line = self._readline(size) - except (ValueError, IOError): - return self.on_disconnect() - if size and not line: - return self.on_disconnect() - self._pos += len(line) - return line - - def readlines(self, size=None): - """Reads a file into a list of strings. It calls :meth:`readline` - until the file is read to the end. It does support the optional - `size` argument if the underlaying stream supports it for - `readline`. - """ - last_pos = self._pos - result = [] - if size is not None: - end = min(self.limit, last_pos + size) - else: - end = self.limit - while 1: - if size is not None: - size -= last_pos - self._pos - if self._pos >= end: - break - result.append(self.readline(size)) - if size is not None: - last_pos = self._pos - return result - - def tell(self): - """Returns the position of the stream. - - .. versionadded:: 0.9 - """ - return self._pos - - def __next__(self): - line = self.readline() - if not line: - raise StopIteration() - return line diff --git a/examples/shortenmyurl/venv/lib/python2.7/site.py b/examples/shortenmyurl/venv/lib/python2.7/site.py deleted file mode 100644 index 871a11ce..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/site.py +++ /dev/null @@ -1,758 +0,0 @@ -"""Append module search paths for third-party packages to sys.path. - -**************************************************************** -* This module is automatically imported during initialization. * -**************************************************************** - -In earlier versions of Python (up to 1.5a3), scripts or modules that -needed to use site-specific modules would place ``import site'' -somewhere near the top of their code. Because of the automatic -import, this is no longer necessary (but code that does it still -works). - -This will append site-specific paths to the module search path. On -Unix, it starts with sys.prefix and sys.exec_prefix (if different) and -appends lib/python/site-packages as well as lib/site-python. -It also supports the Debian convention of -lib/python/dist-packages. On other platforms (mainly Mac and -Windows), it uses just sys.prefix (and sys.exec_prefix, if different, -but this is unlikely). The resulting directories, if they exist, are -appended to sys.path, and also inspected for path configuration files. - -FOR DEBIAN, this sys.path is augmented with directories in /usr/local. -Local addons go into /usr/local/lib/python/site-packages -(resp. /usr/local/lib/site-python), Debian addons install into -/usr/{lib,share}/python/dist-packages. - -A path configuration file is a file whose name has the form -.pth; its contents are additional directories (one per line) -to be added to sys.path. Non-existing directories (or -non-directories) are never added to sys.path; no directory is added to -sys.path more than once. Blank lines and lines beginning with -'#' are skipped. Lines starting with 'import' are executed. - -For example, suppose sys.prefix and sys.exec_prefix are set to -/usr/local and there is a directory /usr/local/lib/python2.X/site-packages -with three subdirectories, foo, bar and spam, and two path -configuration files, foo.pth and bar.pth. Assume foo.pth contains the -following: - - # foo package configuration - foo - bar - bletch - -and bar.pth contains: - - # bar package configuration - bar - -Then the following directories are added to sys.path, in this order: - - /usr/local/lib/python2.X/site-packages/bar - /usr/local/lib/python2.X/site-packages/foo - -Note that bletch is omitted because it doesn't exist; bar precedes foo -because bar.pth comes alphabetically before foo.pth; and spam is -omitted because it is not mentioned in either path configuration file. - -After these path manipulations, an attempt is made to import a module -named sitecustomize, which can perform arbitrary additional -site-specific customizations. If this import fails with an -ImportError exception, it is silently ignored. - -""" - -import sys -import os -try: - import __builtin__ as builtins -except ImportError: - import builtins -try: - set -except NameError: - from sets import Set as set - -# Prefixes for site-packages; add additional prefixes like /usr/local here -PREFIXES = [sys.prefix, sys.exec_prefix] -# Enable per user site-packages directory -# set it to False to disable the feature or True to force the feature -ENABLE_USER_SITE = None -# for distutils.commands.install -USER_SITE = None -USER_BASE = None - -_is_64bit = (getattr(sys, 'maxsize', None) or getattr(sys, 'maxint')) > 2**32 -_is_pypy = hasattr(sys, 'pypy_version_info') -_is_jython = sys.platform[:4] == 'java' -if _is_jython: - ModuleType = type(os) - -def makepath(*paths): - dir = os.path.join(*paths) - if _is_jython and (dir == '__classpath__' or - dir.startswith('__pyclasspath__')): - return dir, dir - dir = os.path.abspath(dir) - return dir, os.path.normcase(dir) - -def abs__file__(): - """Set all module' __file__ attribute to an absolute path""" - for m in sys.modules.values(): - if ((_is_jython and not isinstance(m, ModuleType)) or - hasattr(m, '__loader__')): - # only modules need the abspath in Jython. and don't mess - # with a PEP 302-supplied __file__ - continue - f = getattr(m, '__file__', None) - if f is None: - continue - m.__file__ = os.path.abspath(f) - -def removeduppaths(): - """ Remove duplicate entries from sys.path along with making them - absolute""" - # This ensures that the initial path provided by the interpreter contains - # only absolute pathnames, even if we're running from the build directory. - L = [] - known_paths = set() - for dir in sys.path: - # Filter out duplicate paths (on case-insensitive file systems also - # if they only differ in case); turn relative paths into absolute - # paths. - dir, dircase = makepath(dir) - if not dircase in known_paths: - L.append(dir) - known_paths.add(dircase) - sys.path[:] = L - return known_paths - -# XXX This should not be part of site.py, since it is needed even when -# using the -S option for Python. See http://www.python.org/sf/586680 -def addbuilddir(): - """Append ./build/lib. in case we're running in the build dir - (especially for Guido :-)""" - from distutils.util import get_platform - s = "build/lib.%s-%.3s" % (get_platform(), sys.version) - if hasattr(sys, 'gettotalrefcount'): - s += '-pydebug' - s = os.path.join(os.path.dirname(sys.path[-1]), s) - sys.path.append(s) - -def _init_pathinfo(): - """Return a set containing all existing directory entries from sys.path""" - d = set() - for dir in sys.path: - try: - if os.path.isdir(dir): - dir, dircase = makepath(dir) - d.add(dircase) - except TypeError: - continue - return d - -def addpackage(sitedir, name, known_paths): - """Add a new path to known_paths by combining sitedir and 'name' or execute - sitedir if it starts with 'import'""" - if known_paths is None: - _init_pathinfo() - reset = 1 - else: - reset = 0 - fullname = os.path.join(sitedir, name) - try: - f = open(fullname, "rU") - except IOError: - return - try: - for line in f: - if line.startswith("#"): - continue - if line.startswith("import"): - exec(line) - continue - line = line.rstrip() - dir, dircase = makepath(sitedir, line) - if not dircase in known_paths and os.path.exists(dir): - sys.path.append(dir) - known_paths.add(dircase) - finally: - f.close() - if reset: - known_paths = None - return known_paths - -def addsitedir(sitedir, known_paths=None): - """Add 'sitedir' argument to sys.path if missing and handle .pth files in - 'sitedir'""" - if known_paths is None: - known_paths = _init_pathinfo() - reset = 1 - else: - reset = 0 - sitedir, sitedircase = makepath(sitedir) - if not sitedircase in known_paths: - sys.path.append(sitedir) # Add path component - try: - names = os.listdir(sitedir) - except os.error: - return - names.sort() - for name in names: - if name.endswith(os.extsep + "pth"): - addpackage(sitedir, name, known_paths) - if reset: - known_paths = None - return known_paths - -def addsitepackages(known_paths, sys_prefix=sys.prefix, exec_prefix=sys.exec_prefix): - """Add site-packages (and possibly site-python) to sys.path""" - prefixes = [os.path.join(sys_prefix, "local"), sys_prefix] - if exec_prefix != sys_prefix: - prefixes.append(os.path.join(exec_prefix, "local")) - - for prefix in prefixes: - if prefix: - if sys.platform in ('os2emx', 'riscos') or _is_jython: - sitedirs = [os.path.join(prefix, "Lib", "site-packages")] - elif _is_pypy: - sitedirs = [os.path.join(prefix, 'site-packages')] - elif sys.platform == 'darwin' and prefix == sys_prefix: - - if prefix.startswith("/System/Library/Frameworks/"): # Apple's Python - - sitedirs = [os.path.join("/Library/Python", sys.version[:3], "site-packages"), - os.path.join(prefix, "Extras", "lib", "python")] - - else: # any other Python distros on OSX work this way - sitedirs = [os.path.join(prefix, "lib", - "python" + sys.version[:3], "site-packages")] - - elif os.sep == '/': - sitedirs = [os.path.join(prefix, - "lib", - "python" + sys.version[:3], - "site-packages"), - os.path.join(prefix, "lib", "site-python"), - os.path.join(prefix, "python" + sys.version[:3], "lib-dynload")] - lib64_dir = os.path.join(prefix, "lib64", "python" + sys.version[:3], "site-packages") - if (os.path.exists(lib64_dir) and - os.path.realpath(lib64_dir) not in [os.path.realpath(p) for p in sitedirs]): - if _is_64bit: - sitedirs.insert(0, lib64_dir) - else: - sitedirs.append(lib64_dir) - try: - # sys.getobjects only available in --with-pydebug build - sys.getobjects - sitedirs.insert(0, os.path.join(sitedirs[0], 'debug')) - except AttributeError: - pass - # Debian-specific dist-packages directories: - if sys.version[0] == '2': - sitedirs.append(os.path.join(prefix, "lib", - "python" + sys.version[:3], - "dist-packages")) - else: - sitedirs.append(os.path.join(prefix, "lib", - "python" + sys.version[0], - "dist-packages")) - sitedirs.append(os.path.join(prefix, "local/lib", - "python" + sys.version[:3], - "dist-packages")) - sitedirs.append(os.path.join(prefix, "lib", "dist-python")) - else: - sitedirs = [prefix, os.path.join(prefix, "lib", "site-packages")] - if sys.platform == 'darwin': - # for framework builds *only* we add the standard Apple - # locations. Currently only per-user, but /Library and - # /Network/Library could be added too - if 'Python.framework' in prefix: - home = os.environ.get('HOME') - if home: - sitedirs.append( - os.path.join(home, - 'Library', - 'Python', - sys.version[:3], - 'site-packages')) - for sitedir in sitedirs: - if os.path.isdir(sitedir): - addsitedir(sitedir, known_paths) - return None - -def check_enableusersite(): - """Check if user site directory is safe for inclusion - - The function tests for the command line flag (including environment var), - process uid/gid equal to effective uid/gid. - - None: Disabled for security reasons - False: Disabled by user (command line option) - True: Safe and enabled - """ - if hasattr(sys, 'flags') and getattr(sys.flags, 'no_user_site', False): - return False - - if hasattr(os, "getuid") and hasattr(os, "geteuid"): - # check process uid == effective uid - if os.geteuid() != os.getuid(): - return None - if hasattr(os, "getgid") and hasattr(os, "getegid"): - # check process gid == effective gid - if os.getegid() != os.getgid(): - return None - - return True - -def addusersitepackages(known_paths): - """Add a per user site-package to sys.path - - Each user has its own python directory with site-packages in the - home directory. - - USER_BASE is the root directory for all Python versions - - USER_SITE is the user specific site-packages directory - - USER_SITE/.. can be used for data. - """ - global USER_BASE, USER_SITE, ENABLE_USER_SITE - env_base = os.environ.get("PYTHONUSERBASE", None) - - def joinuser(*args): - return os.path.expanduser(os.path.join(*args)) - - #if sys.platform in ('os2emx', 'riscos'): - # # Don't know what to put here - # USER_BASE = '' - # USER_SITE = '' - if os.name == "nt": - base = os.environ.get("APPDATA") or "~" - if env_base: - USER_BASE = env_base - else: - USER_BASE = joinuser(base, "Python") - USER_SITE = os.path.join(USER_BASE, - "Python" + sys.version[0] + sys.version[2], - "site-packages") - else: - if env_base: - USER_BASE = env_base - else: - USER_BASE = joinuser("~", ".local") - USER_SITE = os.path.join(USER_BASE, "lib", - "python" + sys.version[:3], - "site-packages") - - if ENABLE_USER_SITE and os.path.isdir(USER_SITE): - addsitedir(USER_SITE, known_paths) - if ENABLE_USER_SITE: - for dist_libdir in ("lib", "local/lib"): - user_site = os.path.join(USER_BASE, dist_libdir, - "python" + sys.version[:3], - "dist-packages") - if os.path.isdir(user_site): - addsitedir(user_site, known_paths) - return known_paths - - - -def setBEGINLIBPATH(): - """The OS/2 EMX port has optional extension modules that do double duty - as DLLs (and must use the .DLL file extension) for other extensions. - The library search path needs to be amended so these will be found - during module import. Use BEGINLIBPATH so that these are at the start - of the library search path. - - """ - dllpath = os.path.join(sys.prefix, "Lib", "lib-dynload") - libpath = os.environ['BEGINLIBPATH'].split(';') - if libpath[-1]: - libpath.append(dllpath) - else: - libpath[-1] = dllpath - os.environ['BEGINLIBPATH'] = ';'.join(libpath) - - -def setquit(): - """Define new built-ins 'quit' and 'exit'. - These are simply strings that display a hint on how to exit. - - """ - if os.sep == ':': - eof = 'Cmd-Q' - elif os.sep == '\\': - eof = 'Ctrl-Z plus Return' - else: - eof = 'Ctrl-D (i.e. EOF)' - - class Quitter(object): - def __init__(self, name): - self.name = name - def __repr__(self): - return 'Use %s() or %s to exit' % (self.name, eof) - def __call__(self, code=None): - # Shells like IDLE catch the SystemExit, but listen when their - # stdin wrapper is closed. - try: - sys.stdin.close() - except: - pass - raise SystemExit(code) - builtins.quit = Quitter('quit') - builtins.exit = Quitter('exit') - - -class _Printer(object): - """interactive prompt objects for printing the license text, a list of - contributors and the copyright notice.""" - - MAXLINES = 23 - - def __init__(self, name, data, files=(), dirs=()): - self.__name = name - self.__data = data - self.__files = files - self.__dirs = dirs - self.__lines = None - - def __setup(self): - if self.__lines: - return - data = None - for dir in self.__dirs: - for filename in self.__files: - filename = os.path.join(dir, filename) - try: - fp = open(filename, "rU") - data = fp.read() - fp.close() - break - except IOError: - pass - if data: - break - if not data: - data = self.__data - self.__lines = data.split('\n') - self.__linecnt = len(self.__lines) - - def __repr__(self): - self.__setup() - if len(self.__lines) <= self.MAXLINES: - return "\n".join(self.__lines) - else: - return "Type %s() to see the full %s text" % ((self.__name,)*2) - - def __call__(self): - self.__setup() - prompt = 'Hit Return for more, or q (and Return) to quit: ' - lineno = 0 - while 1: - try: - for i in range(lineno, lineno + self.MAXLINES): - print(self.__lines[i]) - except IndexError: - break - else: - lineno += self.MAXLINES - key = None - while key is None: - try: - key = raw_input(prompt) - except NameError: - key = input(prompt) - if key not in ('', 'q'): - key = None - if key == 'q': - break - -def setcopyright(): - """Set 'copyright' and 'credits' in __builtin__""" - builtins.copyright = _Printer("copyright", sys.copyright) - if _is_jython: - builtins.credits = _Printer( - "credits", - "Jython is maintained by the Jython developers (www.jython.org).") - elif _is_pypy: - builtins.credits = _Printer( - "credits", - "PyPy is maintained by the PyPy developers: http://pypy.org/") - else: - builtins.credits = _Printer("credits", """\ - Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands - for supporting Python development. See www.python.org for more information.""") - here = os.path.dirname(os.__file__) - builtins.license = _Printer( - "license", "See http://www.python.org/%.3s/license.html" % sys.version, - ["LICENSE.txt", "LICENSE"], - [os.path.join(here, os.pardir), here, os.curdir]) - - -class _Helper(object): - """Define the built-in 'help'. - This is a wrapper around pydoc.help (with a twist). - - """ - - def __repr__(self): - return "Type help() for interactive help, " \ - "or help(object) for help about object." - def __call__(self, *args, **kwds): - import pydoc - return pydoc.help(*args, **kwds) - -def sethelper(): - builtins.help = _Helper() - -def aliasmbcs(): - """On Windows, some default encodings are not provided by Python, - while they are always available as "mbcs" in each locale. Make - them usable by aliasing to "mbcs" in such a case.""" - if sys.platform == 'win32': - import locale, codecs - enc = locale.getdefaultlocale()[1] - if enc.startswith('cp'): # "cp***" ? - try: - codecs.lookup(enc) - except LookupError: - import encodings - encodings._cache[enc] = encodings._unknown - encodings.aliases.aliases[enc] = 'mbcs' - -def setencoding(): - """Set the string encoding used by the Unicode implementation. The - default is 'ascii', but if you're willing to experiment, you can - change this.""" - encoding = "ascii" # Default value set by _PyUnicode_Init() - if 0: - # Enable to support locale aware default string encodings. - import locale - loc = locale.getdefaultlocale() - if loc[1]: - encoding = loc[1] - if 0: - # Enable to switch off string to Unicode coercion and implicit - # Unicode to string conversion. - encoding = "undefined" - if encoding != "ascii": - # On Non-Unicode builds this will raise an AttributeError... - sys.setdefaultencoding(encoding) # Needs Python Unicode build ! - - -def execsitecustomize(): - """Run custom site specific code, if available.""" - try: - import sitecustomize - except ImportError: - pass - -def virtual_install_main_packages(): - f = open(os.path.join(os.path.dirname(__file__), 'orig-prefix.txt')) - sys.real_prefix = f.read().strip() - f.close() - pos = 2 - hardcoded_relative_dirs = [] - if sys.path[0] == '': - pos += 1 - if _is_jython: - paths = [os.path.join(sys.real_prefix, 'Lib')] - elif _is_pypy: - if sys.version_info > (3, 2): - cpyver = '%d' % sys.version_info[0] - elif sys.pypy_version_info >= (1, 5): - cpyver = '%d.%d' % sys.version_info[:2] - else: - cpyver = '%d.%d.%d' % sys.version_info[:3] - paths = [os.path.join(sys.real_prefix, 'lib_pypy'), - os.path.join(sys.real_prefix, 'lib-python', cpyver)] - if sys.pypy_version_info < (1, 9): - paths.insert(1, os.path.join(sys.real_prefix, - 'lib-python', 'modified-%s' % cpyver)) - hardcoded_relative_dirs = paths[:] # for the special 'darwin' case below - # - # This is hardcoded in the Python executable, but relative to sys.prefix: - for path in paths[:]: - plat_path = os.path.join(path, 'plat-%s' % sys.platform) - if os.path.exists(plat_path): - paths.append(plat_path) - elif sys.platform == 'win32': - paths = [os.path.join(sys.real_prefix, 'Lib'), os.path.join(sys.real_prefix, 'DLLs')] - else: - paths = [os.path.join(sys.real_prefix, 'lib', 'python'+sys.version[:3])] - hardcoded_relative_dirs = paths[:] # for the special 'darwin' case below - lib64_path = os.path.join(sys.real_prefix, 'lib64', 'python'+sys.version[:3]) - if os.path.exists(lib64_path): - if _is_64bit: - paths.insert(0, lib64_path) - else: - paths.append(lib64_path) - # This is hardcoded in the Python executable, but relative to - # sys.prefix. Debian change: we need to add the multiarch triplet - # here, which is where the real stuff lives. As per PEP 421, in - # Python 3.3+, this lives in sys.implementation, while in Python 2.7 - # it lives in sys. - try: - arch = getattr(sys, 'implementation', sys)._multiarch - except AttributeError: - # This is a non-multiarch aware Python. Fallback to the old way. - arch = sys.platform - plat_path = os.path.join(sys.real_prefix, 'lib', - 'python'+sys.version[:3], - 'plat-%s' % arch) - if os.path.exists(plat_path): - paths.append(plat_path) - # This is hardcoded in the Python executable, but - # relative to sys.prefix, so we have to fix up: - for path in list(paths): - tk_dir = os.path.join(path, 'lib-tk') - if os.path.exists(tk_dir): - paths.append(tk_dir) - - # These are hardcoded in the Apple's Python executable, - # but relative to sys.prefix, so we have to fix them up: - if sys.platform == 'darwin': - hardcoded_paths = [os.path.join(relative_dir, module) - for relative_dir in hardcoded_relative_dirs - for module in ('plat-darwin', 'plat-mac', 'plat-mac/lib-scriptpackages')] - - for path in hardcoded_paths: - if os.path.exists(path): - paths.append(path) - - sys.path.extend(paths) - -def force_global_eggs_after_local_site_packages(): - """ - Force easy_installed eggs in the global environment to get placed - in sys.path after all packages inside the virtualenv. This - maintains the "least surprise" result that packages in the - virtualenv always mask global packages, never the other way - around. - - """ - egginsert = getattr(sys, '__egginsert', 0) - for i, path in enumerate(sys.path): - if i > egginsert and path.startswith(sys.prefix): - egginsert = i - sys.__egginsert = egginsert + 1 - -def virtual_addsitepackages(known_paths): - force_global_eggs_after_local_site_packages() - return addsitepackages(known_paths, sys_prefix=sys.real_prefix) - -def fixclasspath(): - """Adjust the special classpath sys.path entries for Jython. These - entries should follow the base virtualenv lib directories. - """ - paths = [] - classpaths = [] - for path in sys.path: - if path == '__classpath__' or path.startswith('__pyclasspath__'): - classpaths.append(path) - else: - paths.append(path) - sys.path = paths - sys.path.extend(classpaths) - -def execusercustomize(): - """Run custom user specific code, if available.""" - try: - import usercustomize - except ImportError: - pass - - -def main(): - global ENABLE_USER_SITE - virtual_install_main_packages() - abs__file__() - paths_in_sys = removeduppaths() - if (os.name == "posix" and sys.path and - os.path.basename(sys.path[-1]) == "Modules"): - addbuilddir() - if _is_jython: - fixclasspath() - GLOBAL_SITE_PACKAGES = not os.path.exists(os.path.join(os.path.dirname(__file__), 'no-global-site-packages.txt')) - if not GLOBAL_SITE_PACKAGES: - ENABLE_USER_SITE = False - if ENABLE_USER_SITE is None: - ENABLE_USER_SITE = check_enableusersite() - paths_in_sys = addsitepackages(paths_in_sys) - paths_in_sys = addusersitepackages(paths_in_sys) - if GLOBAL_SITE_PACKAGES: - paths_in_sys = virtual_addsitepackages(paths_in_sys) - if sys.platform == 'os2emx': - setBEGINLIBPATH() - setquit() - setcopyright() - sethelper() - aliasmbcs() - setencoding() - execsitecustomize() - if ENABLE_USER_SITE: - execusercustomize() - # Remove sys.setdefaultencoding() so that users cannot change the - # encoding after initialization. The test for presence is needed when - # this module is run as a script, because this code is executed twice. - if hasattr(sys, "setdefaultencoding"): - del sys.setdefaultencoding - -main() - -def _script(): - help = """\ - %s [--user-base] [--user-site] - - Without arguments print some useful information - With arguments print the value of USER_BASE and/or USER_SITE separated - by '%s'. - - Exit codes with --user-base or --user-site: - 0 - user site directory is enabled - 1 - user site directory is disabled by user - 2 - uses site directory is disabled by super user - or for security reasons - >2 - unknown error - """ - args = sys.argv[1:] - if not args: - print("sys.path = [") - for dir in sys.path: - print(" %r," % (dir,)) - print("]") - def exists(path): - if os.path.isdir(path): - return "exists" - else: - return "doesn't exist" - print("USER_BASE: %r (%s)" % (USER_BASE, exists(USER_BASE))) - print("USER_SITE: %r (%s)" % (USER_SITE, exists(USER_BASE))) - print("ENABLE_USER_SITE: %r" % ENABLE_USER_SITE) - sys.exit(0) - - buffer = [] - if '--user-base' in args: - buffer.append(USER_BASE) - if '--user-site' in args: - buffer.append(USER_SITE) - - if buffer: - print(os.pathsep.join(buffer)) - if ENABLE_USER_SITE: - sys.exit(0) - elif ENABLE_USER_SITE is False: - sys.exit(1) - elif ENABLE_USER_SITE is None: - sys.exit(2) - else: - sys.exit(3) - else: - import textwrap - print(textwrap.dedent(help % (sys.argv[0], os.pathsep))) - sys.exit(10) - -if __name__ == '__main__': - _script() diff --git a/examples/shortenmyurl/venv/lib/python2.7/sre.py b/examples/shortenmyurl/venv/lib/python2.7/sre.py deleted file mode 120000 index 27f81b93..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/sre.py +++ /dev/null @@ -1 +0,0 @@ -/usr/lib/python2.7/sre.py \ No newline at end of file diff --git a/examples/shortenmyurl/venv/lib/python2.7/sre_compile.py b/examples/shortenmyurl/venv/lib/python2.7/sre_compile.py deleted file mode 120000 index dce5da4c..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/sre_compile.py +++ /dev/null @@ -1 +0,0 @@ -/usr/lib/python2.7/sre_compile.py \ No newline at end of file diff --git a/examples/shortenmyurl/venv/lib/python2.7/sre_constants.py b/examples/shortenmyurl/venv/lib/python2.7/sre_constants.py deleted file mode 120000 index b9c9797e..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/sre_constants.py +++ /dev/null @@ -1 +0,0 @@ -/usr/lib/python2.7/sre_constants.py \ No newline at end of file diff --git a/examples/shortenmyurl/venv/lib/python2.7/sre_parse.py b/examples/shortenmyurl/venv/lib/python2.7/sre_parse.py deleted file mode 120000 index f33a572f..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/sre_parse.py +++ /dev/null @@ -1 +0,0 @@ -/usr/lib/python2.7/sre_parse.py \ No newline at end of file diff --git a/examples/shortenmyurl/venv/lib/python2.7/stat.py b/examples/shortenmyurl/venv/lib/python2.7/stat.py deleted file mode 120000 index c1d654c1..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/stat.py +++ /dev/null @@ -1 +0,0 @@ -/usr/lib/python2.7/stat.py \ No newline at end of file diff --git a/examples/shortenmyurl/venv/lib/python2.7/types.py b/examples/shortenmyurl/venv/lib/python2.7/types.py deleted file mode 120000 index 55464783..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/types.py +++ /dev/null @@ -1 +0,0 @@ -/usr/lib/python2.7/types.py \ No newline at end of file diff --git a/examples/shortenmyurl/venv/lib/python2.7/warnings.py b/examples/shortenmyurl/venv/lib/python2.7/warnings.py deleted file mode 120000 index a9c47309..00000000 --- a/examples/shortenmyurl/venv/lib/python2.7/warnings.py +++ /dev/null @@ -1 +0,0 @@ -/usr/lib/python2.7/warnings.py \ No newline at end of file diff --git a/examples/shortenmyurl/venv/local/bin b/examples/shortenmyurl/venv/local/bin deleted file mode 120000 index 839a13d3..00000000 --- a/examples/shortenmyurl/venv/local/bin +++ /dev/null @@ -1 +0,0 @@ -/home/melvin/development/shortenmyurl/venv/bin \ No newline at end of file diff --git a/examples/shortenmyurl/venv/local/include b/examples/shortenmyurl/venv/local/include deleted file mode 120000 index 96c9e34c..00000000 --- a/examples/shortenmyurl/venv/local/include +++ /dev/null @@ -1 +0,0 @@ -/home/melvin/development/shortenmyurl/venv/include \ No newline at end of file diff --git a/examples/shortenmyurl/venv/local/lib b/examples/shortenmyurl/venv/local/lib deleted file mode 120000 index 25b85963..00000000 --- a/examples/shortenmyurl/venv/local/lib +++ /dev/null @@ -1 +0,0 @@ -/home/melvin/development/shortenmyurl/venv/lib \ No newline at end of file
  • just a small \n ' - 'example link