Repository: wistbean/learn_python3_spider
Branch: master
Commit: aef4159f8542
Files: 2270
Total size: 23.1 MB
Directory structure:
gitextract_cqvzh202/
├── .gitattributes
├── CloudCreat
├── GaoKao_Score/
│ ├── 2006-2016浙江高考录取分数线.html
│ ├── 2006-2016海南高考录取分数线.html
│ ├── 2006-2017上海高考录取分数线.html
│ ├── 2006-2017安徽高考录取分数线.html
│ ├── 2006-2017山东高考录取分数线.html
│ ├── 2006-2017山西高考录取分数线.html
│ ├── 2006-2017新疆高考录取分数线.html
│ ├── 2006-2017河南高考录取分数线.html
│ ├── 2006-2017福建高考录取分数线.html
│ ├── 2006-2017重庆高考录取分数线.html
│ ├── 2006-2017黑龙江高考录取分数线.html
│ ├── 2006-2018云南高考录取分数线.html
│ ├── 2006-2018内蒙古高考录取分数线.html
│ ├── 2006-2018北京高考录取分数线.html
│ ├── 2006-2018吉林高考录取分数线.html
│ ├── 2006-2018四川高考录取分数线.html
│ ├── 2006-2018天津高考录取分数线.html
│ ├── 2006-2018宁夏高考录取分数线.html
│ ├── 2006-2018广东高考录取分数线.html
│ ├── 2006-2018广西高考录取分数线.html
│ ├── 2006-2018江西高考分数线.html
│ ├── 2006-2018河北高考录取分数线.html
│ ├── 2006-2018湖北高考录取分数线.html
│ ├── 2006-2018湖南高考录取分数线.html
│ ├── 2006-2018甘肃高考录取分数线.html
│ ├── 2006-2018西藏高考录取分数线.html
│ ├── 2006-2018贵州高考录取分数线.html
│ ├── 2006-2018辽宁高考录取分数线.html
│ ├── 2006-2018陕西高考录取分数线.html
│ ├── 2006-2018青海高考录取分数线.html
│ ├── 2010-2017江苏高考录取分数线.html
│ ├── 文科(一本)全国高考录取分数平均值比较.html
│ └── 理科(一本)全国高考录取分数平均值比较.html
├── LICENSE
├── README.md
├── biaoqingbao/
│ ├── biaoqingbao.py
│ └── search.py
├── dangdang_top_500.py
├── douban_top_250_books.py
├── douban_top_250_books_mul_process.py
├── fuck_bilibili_captcha.py
├── ikun_basketball.py
├── meizitu.py
├── qiushibaike/
│ ├── qiushibaike/
│ │ ├── __init__.py
│ │ ├── items.py
│ │ ├── middlewares.py
│ │ ├── pipelines.py
│ │ ├── settings.py
│ │ └── spiders/
│ │ ├── __init__.py
│ │ └── qiushibaike_spider.py
│ └── scrapy.cfg
├── stackoverflow/
│ ├── .idea/
│ │ ├── inspectionProfiles/
│ │ │ └── profiles_settings.xml
│ │ ├── misc.xml
│ │ ├── modules.xml
│ │ ├── stackoverflow.iml
│ │ ├── vcs.xml
│ │ └── workspace.xml
│ ├── scrapy.cfg
│ ├── stackoverflow/
│ │ ├── __init__.py
│ │ ├── items.py
│ │ ├── middlewares/
│ │ │ ├── StackoverflowDownloaderMiddleware.py
│ │ │ └── __init__.py
│ │ ├── middlewares.py
│ │ ├── pipelines.py
│ │ ├── requirement.txt
│ │ ├── settings.py
│ │ └── spiders/
│ │ ├── __init__.py
│ │ └── stackoverflow-python-spider.py
│ └── venv/
│ ├── bin/
│ │ ├── activate
│ │ ├── activate.csh
│ │ ├── activate.fish
│ │ ├── automat-visualize
│ │ ├── cftp
│ │ ├── ckeygen
│ │ ├── conch
│ │ ├── easy_install
│ │ ├── easy_install-3.6
│ │ ├── mailmail
│ │ ├── pip
│ │ ├── pip3
│ │ ├── pip3.6
│ │ ├── pyhtmlizer
│ │ ├── python
│ │ ├── python3
│ │ ├── scrapy
│ │ ├── tkconch
│ │ ├── trial
│ │ ├── twist
│ │ └── twistd
│ ├── lib/
│ │ └── python3.6/
│ │ └── site-packages/
│ │ ├── .libs_cffi_backend/
│ │ │ └── libffi-10449faf.so.5.0.6
│ │ ├── Automat-0.8.0.dist-info/
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ ├── entry_points.txt
│ │ │ └── top_level.txt
│ │ ├── OpenSSL/
│ │ │ ├── SSL.py
│ │ │ ├── __init__.py
│ │ │ ├── _util.py
│ │ │ ├── crypto.py
│ │ │ ├── debug.py
│ │ │ ├── rand.py
│ │ │ ├── tsafe.py
│ │ │ └── version.py
│ │ ├── PyDispatcher-2.0.5-py3.6.egg-info/
│ │ │ ├── PKG-INFO
│ │ │ ├── SOURCES.txt
│ │ │ ├── dependency_links.txt
│ │ │ ├── installed-files.txt
│ │ │ └── top_level.txt
│ │ ├── PyHamcrest-1.9.0.dist-info/
│ │ │ ├── DESCRIPTION.rst
│ │ │ ├── INSTALLER
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ ├── metadata.json
│ │ │ ├── pbr.json
│ │ │ └── top_level.txt
│ │ ├── Scrapy-1.7.4.dist-info/
│ │ │ ├── AUTHORS
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ ├── entry_points.txt
│ │ │ └── top_level.txt
│ │ ├── Twisted-19.7.0.dist-info/
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ ├── entry_points.txt
│ │ │ └── top_level.txt
│ │ ├── attr/
│ │ │ ├── __init__.py
│ │ │ ├── __init__.pyi
│ │ │ ├── _compat.py
│ │ │ ├── _config.py
│ │ │ ├── _funcs.py
│ │ │ ├── _make.py
│ │ │ ├── _version_info.py
│ │ │ ├── _version_info.pyi
│ │ │ ├── converters.py
│ │ │ ├── converters.pyi
│ │ │ ├── exceptions.py
│ │ │ ├── exceptions.pyi
│ │ │ ├── filters.py
│ │ │ ├── filters.pyi
│ │ │ ├── py.typed
│ │ │ ├── validators.py
│ │ │ └── validators.pyi
│ │ ├── attrs-19.3.0.dist-info/
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ └── top_level.txt
│ │ ├── automat/
│ │ │ ├── __init__.py
│ │ │ ├── _core.py
│ │ │ ├── _discover.py
│ │ │ ├── _introspection.py
│ │ │ ├── _methodical.py
│ │ │ ├── _test/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_core.py
│ │ │ │ ├── test_discover.py
│ │ │ │ ├── test_methodical.py
│ │ │ │ ├── test_trace.py
│ │ │ │ └── test_visualize.py
│ │ │ └── _visualize.py
│ │ ├── bson/
│ │ │ ├── __init__.py
│ │ │ ├── binary.py
│ │ │ ├── code.py
│ │ │ ├── codec_options.py
│ │ │ ├── dbref.py
│ │ │ ├── decimal128.py
│ │ │ ├── errors.py
│ │ │ ├── int64.py
│ │ │ ├── json_util.py
│ │ │ ├── max_key.py
│ │ │ ├── min_key.py
│ │ │ ├── objectid.py
│ │ │ ├── py3compat.py
│ │ │ ├── raw_bson.py
│ │ │ ├── regex.py
│ │ │ ├── son.py
│ │ │ ├── timestamp.py
│ │ │ └── tz_util.py
│ │ ├── cffi/
│ │ │ ├── __init__.py
│ │ │ ├── _cffi_errors.h
│ │ │ ├── _cffi_include.h
│ │ │ ├── _embedding.h
│ │ │ ├── api.py
│ │ │ ├── backend_ctypes.py
│ │ │ ├── cffi_opcode.py
│ │ │ ├── commontypes.py
│ │ │ ├── cparser.py
│ │ │ ├── error.py
│ │ │ ├── ffiplatform.py
│ │ │ ├── lock.py
│ │ │ ├── model.py
│ │ │ ├── parse_c_type.h
│ │ │ ├── pkgconfig.py
│ │ │ ├── recompiler.py
│ │ │ ├── setuptools_ext.py
│ │ │ ├── vengine_cpy.py
│ │ │ ├── vengine_gen.py
│ │ │ └── verifier.py
│ │ ├── cffi-1.13.1.dist-info/
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ ├── entry_points.txt
│ │ │ └── top_level.txt
│ │ ├── constantly/
│ │ │ ├── __init__.py
│ │ │ ├── _constants.py
│ │ │ └── _version.py
│ │ ├── constantly-15.1.0.dist-info/
│ │ │ ├── DESCRIPTION.rst
│ │ │ ├── INSTALLER
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ ├── metadata.json
│ │ │ ├── pbr.json
│ │ │ └── top_level.txt
│ │ ├── cryptography/
│ │ │ ├── __about__.py
│ │ │ ├── __init__.py
│ │ │ ├── exceptions.py
│ │ │ ├── fernet.py
│ │ │ ├── hazmat/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _der.py
│ │ │ │ ├── _oid.py
│ │ │ │ ├── backends/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── interfaces.py
│ │ │ │ │ └── openssl/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── aead.py
│ │ │ │ │ ├── backend.py
│ │ │ │ │ ├── ciphers.py
│ │ │ │ │ ├── cmac.py
│ │ │ │ │ ├── decode_asn1.py
│ │ │ │ │ ├── dh.py
│ │ │ │ │ ├── dsa.py
│ │ │ │ │ ├── ec.py
│ │ │ │ │ ├── ed25519.py
│ │ │ │ │ ├── ed448.py
│ │ │ │ │ ├── encode_asn1.py
│ │ │ │ │ ├── hashes.py
│ │ │ │ │ ├── hmac.py
│ │ │ │ │ ├── ocsp.py
│ │ │ │ │ ├── poly1305.py
│ │ │ │ │ ├── rsa.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ ├── x25519.py
│ │ │ │ │ ├── x448.py
│ │ │ │ │ └── x509.py
│ │ │ │ ├── bindings/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── openssl/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── _conditional.py
│ │ │ │ │ └── binding.py
│ │ │ │ └── primitives/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── asymmetric/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── dh.py
│ │ │ │ │ ├── dsa.py
│ │ │ │ │ ├── ec.py
│ │ │ │ │ ├── ed25519.py
│ │ │ │ │ ├── ed448.py
│ │ │ │ │ ├── padding.py
│ │ │ │ │ ├── rsa.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ ├── x25519.py
│ │ │ │ │ └── x448.py
│ │ │ │ ├── ciphers/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── aead.py
│ │ │ │ │ ├── algorithms.py
│ │ │ │ │ ├── base.py
│ │ │ │ │ └── modes.py
│ │ │ │ ├── cmac.py
│ │ │ │ ├── constant_time.py
│ │ │ │ ├── hashes.py
│ │ │ │ ├── hmac.py
│ │ │ │ ├── kdf/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── concatkdf.py
│ │ │ │ │ ├── hkdf.py
│ │ │ │ │ ├── kbkdf.py
│ │ │ │ │ ├── pbkdf2.py
│ │ │ │ │ ├── scrypt.py
│ │ │ │ │ └── x963kdf.py
│ │ │ │ ├── keywrap.py
│ │ │ │ ├── padding.py
│ │ │ │ ├── poly1305.py
│ │ │ │ ├── serialization/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── pkcs12.py
│ │ │ │ │ └── ssh.py
│ │ │ │ └── twofactor/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── hotp.py
│ │ │ │ ├── totp.py
│ │ │ │ └── utils.py
│ │ │ ├── utils.py
│ │ │ └── x509/
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── certificate_transparency.py
│ │ │ ├── extensions.py
│ │ │ ├── general_name.py
│ │ │ ├── name.py
│ │ │ ├── ocsp.py
│ │ │ └── oid.py
│ │ ├── cryptography-2.8.dist-info/
│ │ │ ├── AUTHORS.rst
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── LICENSE.APACHE
│ │ │ ├── LICENSE.BSD
│ │ │ ├── LICENSE.PSF
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ └── top_level.txt
│ │ ├── cssselect/
│ │ │ ├── __init__.py
│ │ │ ├── parser.py
│ │ │ └── xpath.py
│ │ ├── cssselect-1.1.0.dist-info/
│ │ │ ├── AUTHORS
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ └── top_level.txt
│ │ ├── easy-install.pth
│ │ ├── exampleproj/
│ │ │ ├── __init__.py
│ │ │ └── _version.py
│ │ ├── gridfs/
│ │ │ ├── __init__.py
│ │ │ ├── errors.py
│ │ │ └── grid_file.py
│ │ ├── hamcrest/
│ │ │ ├── __init__.py
│ │ │ ├── core/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── assert_that.py
│ │ │ │ ├── base_description.py
│ │ │ │ ├── base_matcher.py
│ │ │ │ ├── compat.py
│ │ │ │ ├── core/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── allof.py
│ │ │ │ │ ├── anyof.py
│ │ │ │ │ ├── described_as.py
│ │ │ │ │ ├── is_.py
│ │ │ │ │ ├── isanything.py
│ │ │ │ │ ├── isequal.py
│ │ │ │ │ ├── isinstanceof.py
│ │ │ │ │ ├── isnone.py
│ │ │ │ │ ├── isnot.py
│ │ │ │ │ ├── issame.py
│ │ │ │ │ └── raises.py
│ │ │ │ ├── description.py
│ │ │ │ ├── helpers/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── hasmethod.py
│ │ │ │ │ └── wrap_matcher.py
│ │ │ │ ├── matcher.py
│ │ │ │ ├── selfdescribing.py
│ │ │ │ ├── selfdescribingvalue.py
│ │ │ │ └── string_description.py
│ │ │ └── library/
│ │ │ ├── __init__.py
│ │ │ ├── collection/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── is_empty.py
│ │ │ │ ├── isdict_containing.py
│ │ │ │ ├── isdict_containingentries.py
│ │ │ │ ├── isdict_containingkey.py
│ │ │ │ ├── isdict_containingvalue.py
│ │ │ │ ├── isin.py
│ │ │ │ ├── issequence_containing.py
│ │ │ │ ├── issequence_containinginanyorder.py
│ │ │ │ ├── issequence_containinginorder.py
│ │ │ │ └── issequence_onlycontaining.py
│ │ │ ├── integration/
│ │ │ │ ├── __init__.py
│ │ │ │ └── match_equality.py
│ │ │ ├── number/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── iscloseto.py
│ │ │ │ └── ordering_comparison.py
│ │ │ ├── object/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── haslength.py
│ │ │ │ ├── hasproperty.py
│ │ │ │ └── hasstring.py
│ │ │ └── text/
│ │ │ ├── __init__.py
│ │ │ ├── isequal_ignoring_case.py
│ │ │ ├── isequal_ignoring_whitespace.py
│ │ │ ├── stringcontains.py
│ │ │ ├── stringcontainsinorder.py
│ │ │ ├── stringendswith.py
│ │ │ ├── stringmatches.py
│ │ │ ├── stringstartswith.py
│ │ │ └── substringmatcher.py
│ │ ├── hyperlink/
│ │ │ ├── __init__.py
│ │ │ ├── _url.py
│ │ │ └── test/
│ │ │ ├── __init__.py
│ │ │ ├── common.py
│ │ │ ├── test_common.py
│ │ │ ├── test_decoded_url.py
│ │ │ ├── test_parse.py
│ │ │ ├── test_scheme_registration.py
│ │ │ └── test_url.py
│ │ ├── hyperlink-19.0.0.dist-info/
│ │ │ ├── DESCRIPTION.rst
│ │ │ ├── INSTALLER
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ ├── metadata.json
│ │ │ └── top_level.txt
│ │ ├── idna/
│ │ │ ├── __init__.py
│ │ │ ├── codec.py
│ │ │ ├── compat.py
│ │ │ ├── core.py
│ │ │ ├── idnadata.py
│ │ │ ├── intranges.py
│ │ │ ├── package_data.py
│ │ │ └── uts46data.py
│ │ ├── idna-2.8.dist-info/
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.rst
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ └── top_level.txt
│ │ ├── incremental/
│ │ │ ├── __init__.py
│ │ │ ├── _version.py
│ │ │ ├── tests/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_update.py
│ │ │ │ └── test_version.py
│ │ │ └── update.py
│ │ ├── incremental-17.5.0.dist-info/
│ │ │ ├── DESCRIPTION.rst
│ │ │ ├── INSTALLER
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ ├── entry_points.txt
│ │ │ ├── metadata.json
│ │ │ └── top_level.txt
│ │ ├── lxml/
│ │ │ ├── ElementInclude.py
│ │ │ ├── __init__.py
│ │ │ ├── _elementpath.py
│ │ │ ├── builder.py
│ │ │ ├── cssselect.py
│ │ │ ├── doctestcompare.py
│ │ │ ├── etree.h
│ │ │ ├── etree_api.h
│ │ │ ├── html/
│ │ │ │ ├── ElementSoup.py
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _diffcommand.py
│ │ │ │ ├── _html5builder.py
│ │ │ │ ├── _setmixin.py
│ │ │ │ ├── builder.py
│ │ │ │ ├── clean.py
│ │ │ │ ├── defs.py
│ │ │ │ ├── diff.py
│ │ │ │ ├── formfill.py
│ │ │ │ ├── html5parser.py
│ │ │ │ ├── soupparser.py
│ │ │ │ └── usedoctest.py
│ │ │ ├── includes/
│ │ │ │ ├── __init__.pxd
│ │ │ │ ├── __init__.py
│ │ │ │ ├── c14n.pxd
│ │ │ │ ├── config.pxd
│ │ │ │ ├── dtdvalid.pxd
│ │ │ │ ├── etree_defs.h
│ │ │ │ ├── etreepublic.pxd
│ │ │ │ ├── htmlparser.pxd
│ │ │ │ ├── libexslt/
│ │ │ │ │ ├── exslt.h
│ │ │ │ │ ├── exsltconfig.h
│ │ │ │ │ └── exsltexports.h
│ │ │ │ ├── libxml/
│ │ │ │ │ ├── DOCBparser.h
│ │ │ │ │ ├── HTMLparser.h
│ │ │ │ │ ├── HTMLtree.h
│ │ │ │ │ ├── SAX.h
│ │ │ │ │ ├── SAX2.h
│ │ │ │ │ ├── c14n.h
│ │ │ │ │ ├── catalog.h
│ │ │ │ │ ├── chvalid.h
│ │ │ │ │ ├── debugXML.h
│ │ │ │ │ ├── dict.h
│ │ │ │ │ ├── encoding.h
│ │ │ │ │ ├── entities.h
│ │ │ │ │ ├── globals.h
│ │ │ │ │ ├── hash.h
│ │ │ │ │ ├── list.h
│ │ │ │ │ ├── nanoftp.h
│ │ │ │ │ ├── nanohttp.h
│ │ │ │ │ ├── parser.h
│ │ │ │ │ ├── parserInternals.h
│ │ │ │ │ ├── relaxng.h
│ │ │ │ │ ├── schemasInternals.h
│ │ │ │ │ ├── schematron.h
│ │ │ │ │ ├── threads.h
│ │ │ │ │ ├── tree.h
│ │ │ │ │ ├── uri.h
│ │ │ │ │ ├── valid.h
│ │ │ │ │ ├── xinclude.h
│ │ │ │ │ ├── xlink.h
│ │ │ │ │ ├── xmlIO.h
│ │ │ │ │ ├── xmlautomata.h
│ │ │ │ │ ├── xmlerror.h
│ │ │ │ │ ├── xmlexports.h
│ │ │ │ │ ├── xmlmemory.h
│ │ │ │ │ ├── xmlmodule.h
│ │ │ │ │ ├── xmlreader.h
│ │ │ │ │ ├── xmlregexp.h
│ │ │ │ │ ├── xmlsave.h
│ │ │ │ │ ├── xmlschemas.h
│ │ │ │ │ ├── xmlschemastypes.h
│ │ │ │ │ ├── xmlstring.h
│ │ │ │ │ ├── xmlunicode.h
│ │ │ │ │ ├── xmlversion.h
│ │ │ │ │ ├── xmlwriter.h
│ │ │ │ │ ├── xpath.h
│ │ │ │ │ ├── xpathInternals.h
│ │ │ │ │ └── xpointer.h
│ │ │ │ ├── libxslt/
│ │ │ │ │ ├── attributes.h
│ │ │ │ │ ├── documents.h
│ │ │ │ │ ├── extensions.h
│ │ │ │ │ ├── extra.h
│ │ │ │ │ ├── functions.h
│ │ │ │ │ ├── imports.h
│ │ │ │ │ ├── keys.h
│ │ │ │ │ ├── namespaces.h
│ │ │ │ │ ├── numbersInternals.h
│ │ │ │ │ ├── pattern.h
│ │ │ │ │ ├── preproc.h
│ │ │ │ │ ├── security.h
│ │ │ │ │ ├── templates.h
│ │ │ │ │ ├── transform.h
│ │ │ │ │ ├── variables.h
│ │ │ │ │ ├── xslt.h
│ │ │ │ │ ├── xsltInternals.h
│ │ │ │ │ ├── xsltconfig.h
│ │ │ │ │ ├── xsltexports.h
│ │ │ │ │ ├── xsltlocale.h
│ │ │ │ │ └── xsltutils.h
│ │ │ │ ├── lxml-version.h
│ │ │ │ ├── relaxng.pxd
│ │ │ │ ├── schematron.pxd
│ │ │ │ ├── tree.pxd
│ │ │ │ ├── uri.pxd
│ │ │ │ ├── xinclude.pxd
│ │ │ │ ├── xmlerror.pxd
│ │ │ │ ├── xmlparser.pxd
│ │ │ │ ├── xmlschema.pxd
│ │ │ │ ├── xpath.pxd
│ │ │ │ └── xslt.pxd
│ │ │ ├── isoschematron/
│ │ │ │ ├── __init__.py
│ │ │ │ └── resources/
│ │ │ │ ├── rng/
│ │ │ │ │ └── iso-schematron.rng
│ │ │ │ └── xsl/
│ │ │ │ ├── RNG2Schtrn.xsl
│ │ │ │ ├── XSD2Schtrn.xsl
│ │ │ │ └── iso-schematron-xslt1/
│ │ │ │ ├── iso_abstract_expand.xsl
│ │ │ │ ├── iso_dsdl_include.xsl
│ │ │ │ ├── iso_schematron_message.xsl
│ │ │ │ ├── iso_schematron_skeleton_for_xslt1.xsl
│ │ │ │ ├── iso_svrl_for_xslt1.xsl
│ │ │ │ └── readme.txt
│ │ │ ├── lxml.etree.h
│ │ │ ├── lxml.etree_api.h
│ │ │ ├── pyclasslookup.py
│ │ │ ├── sax.py
│ │ │ └── usedoctest.py
│ │ ├── lxml-4.4.1.dist-info/
│ │ │ ├── INSTALLER
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ └── top_level.txt
│ │ ├── parsel/
│ │ │ ├── __init__.py
│ │ │ ├── csstranslator.py
│ │ │ ├── selector.py
│ │ │ ├── utils.py
│ │ │ └── xpathfuncs.py
│ │ ├── parsel-1.5.2.dist-info/
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ └── top_level.txt
│ │ ├── pip-19.0.3-py3.6.egg/
│ │ │ ├── EGG-INFO/
│ │ │ │ ├── PKG-INFO
│ │ │ │ ├── SOURCES.txt
│ │ │ │ ├── dependency_links.txt
│ │ │ │ ├── entry_points.txt
│ │ │ │ ├── not-zip-safe
│ │ │ │ └── top_level.txt
│ │ │ └── pip/
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── _internal/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── build_env.py
│ │ │ │ ├── cache.py
│ │ │ │ ├── cli/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── autocompletion.py
│ │ │ │ │ ├── base_command.py
│ │ │ │ │ ├── cmdoptions.py
│ │ │ │ │ ├── main_parser.py
│ │ │ │ │ ├── parser.py
│ │ │ │ │ └── status_codes.py
│ │ │ │ ├── commands/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── completion.py
│ │ │ │ │ ├── configuration.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── hash.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── install.py
│ │ │ │ │ ├── list.py
│ │ │ │ │ ├── search.py
│ │ │ │ │ ├── show.py
│ │ │ │ │ ├── uninstall.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── configuration.py
│ │ │ │ ├── download.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── index.py
│ │ │ │ ├── locations.py
│ │ │ │ ├── models/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── candidate.py
│ │ │ │ │ ├── format_control.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ └── link.py
│ │ │ │ ├── operations/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ └── prepare.py
│ │ │ │ ├── pep425tags.py
│ │ │ │ ├── pyproject.py
│ │ │ │ ├── req/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── constructors.py
│ │ │ │ │ ├── req_file.py
│ │ │ │ │ ├── req_install.py
│ │ │ │ │ ├── req_set.py
│ │ │ │ │ ├── req_tracker.py
│ │ │ │ │ └── req_uninstall.py
│ │ │ │ ├── resolve.py
│ │ │ │ ├── utils/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── appdirs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── deprecation.py
│ │ │ │ │ ├── encoding.py
│ │ │ │ │ ├── filesystem.py
│ │ │ │ │ ├── glibc.py
│ │ │ │ │ ├── hashes.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── misc.py
│ │ │ │ │ ├── models.py
│ │ │ │ │ ├── outdated.py
│ │ │ │ │ ├── packaging.py
│ │ │ │ │ ├── setuptools_build.py
│ │ │ │ │ ├── temp_dir.py
│ │ │ │ │ ├── typing.py
│ │ │ │ │ └── ui.py
│ │ │ │ ├── vcs/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── bazaar.py
│ │ │ │ │ ├── git.py
│ │ │ │ │ ├── mercurial.py
│ │ │ │ │ └── subversion.py
│ │ │ │ └── wheel.py
│ │ │ └── _vendor/
│ │ │ ├── __init__.py
│ │ │ ├── appdirs.py
│ │ │ ├── cachecontrol/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _cmd.py
│ │ │ │ ├── adapter.py
│ │ │ │ ├── cache.py
│ │ │ │ ├── caches/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── file_cache.py
│ │ │ │ │ └── redis_cache.py
│ │ │ │ ├── compat.py
│ │ │ │ ├── controller.py
│ │ │ │ ├── filewrapper.py
│ │ │ │ ├── heuristics.py
│ │ │ │ ├── serialize.py
│ │ │ │ └── wrapper.py
│ │ │ ├── certifi/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ ├── cacert.pem
│ │ │ │ └── core.py
│ │ │ ├── chardet/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── big5freq.py
│ │ │ │ ├── big5prober.py
│ │ │ │ ├── chardistribution.py
│ │ │ │ ├── charsetgroupprober.py
│ │ │ │ ├── charsetprober.py
│ │ │ │ ├── cli/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── chardetect.py
│ │ │ │ ├── codingstatemachine.py
│ │ │ │ ├── compat.py
│ │ │ │ ├── cp949prober.py
│ │ │ │ ├── enums.py
│ │ │ │ ├── escprober.py
│ │ │ │ ├── escsm.py
│ │ │ │ ├── eucjpprober.py
│ │ │ │ ├── euckrfreq.py
│ │ │ │ ├── euckrprober.py
│ │ │ │ ├── euctwfreq.py
│ │ │ │ ├── euctwprober.py
│ │ │ │ ├── gb2312freq.py
│ │ │ │ ├── gb2312prober.py
│ │ │ │ ├── hebrewprober.py
│ │ │ │ ├── jisfreq.py
│ │ │ │ ├── jpcntx.py
│ │ │ │ ├── langbulgarianmodel.py
│ │ │ │ ├── langcyrillicmodel.py
│ │ │ │ ├── langgreekmodel.py
│ │ │ │ ├── langhebrewmodel.py
│ │ │ │ ├── langhungarianmodel.py
│ │ │ │ ├── langthaimodel.py
│ │ │ │ ├── langturkishmodel.py
│ │ │ │ ├── latin1prober.py
│ │ │ │ ├── mbcharsetprober.py
│ │ │ │ ├── mbcsgroupprober.py
│ │ │ │ ├── mbcssm.py
│ │ │ │ ├── sbcharsetprober.py
│ │ │ │ ├── sbcsgroupprober.py
│ │ │ │ ├── sjisprober.py
│ │ │ │ ├── universaldetector.py
│ │ │ │ ├── utf8prober.py
│ │ │ │ └── version.py
│ │ │ ├── colorama/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── ansi.py
│ │ │ │ ├── ansitowin32.py
│ │ │ │ ├── initialise.py
│ │ │ │ ├── win32.py
│ │ │ │ └── winterm.py
│ │ │ ├── distlib/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _backport/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── misc.py
│ │ │ │ │ ├── shutil.py
│ │ │ │ │ ├── sysconfig.cfg
│ │ │ │ │ ├── sysconfig.py
│ │ │ │ │ └── tarfile.py
│ │ │ │ ├── compat.py
│ │ │ │ ├── database.py
│ │ │ │ ├── index.py
│ │ │ │ ├── locators.py
│ │ │ │ ├── manifest.py
│ │ │ │ ├── markers.py
│ │ │ │ ├── metadata.py
│ │ │ │ ├── resources.py
│ │ │ │ ├── scripts.py
│ │ │ │ ├── util.py
│ │ │ │ ├── version.py
│ │ │ │ └── wheel.py
│ │ │ ├── distro.py
│ │ │ ├── html5lib/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _ihatexml.py
│ │ │ │ ├── _inputstream.py
│ │ │ │ ├── _tokenizer.py
│ │ │ │ ├── _trie/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── _base.py
│ │ │ │ │ ├── datrie.py
│ │ │ │ │ └── py.py
│ │ │ │ ├── _utils.py
│ │ │ │ ├── constants.py
│ │ │ │ ├── filters/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── alphabeticalattributes.py
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── inject_meta_charset.py
│ │ │ │ │ ├── lint.py
│ │ │ │ │ ├── optionaltags.py
│ │ │ │ │ ├── sanitizer.py
│ │ │ │ │ └── whitespace.py
│ │ │ │ ├── html5parser.py
│ │ │ │ ├── serializer.py
│ │ │ │ ├── treeadapters/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── genshi.py
│ │ │ │ │ └── sax.py
│ │ │ │ ├── treebuilders/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── dom.py
│ │ │ │ │ ├── etree.py
│ │ │ │ │ └── etree_lxml.py
│ │ │ │ └── treewalkers/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ ├── dom.py
│ │ │ │ ├── etree.py
│ │ │ │ ├── etree_lxml.py
│ │ │ │ └── genshi.py
│ │ │ ├── idna/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── codec.py
│ │ │ │ ├── compat.py
│ │ │ │ ├── core.py
│ │ │ │ ├── idnadata.py
│ │ │ │ ├── intranges.py
│ │ │ │ ├── package_data.py
│ │ │ │ └── uts46data.py
│ │ │ ├── ipaddress.py
│ │ │ ├── lockfile/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── linklockfile.py
│ │ │ │ ├── mkdirlockfile.py
│ │ │ │ ├── pidlockfile.py
│ │ │ │ ├── sqlitelockfile.py
│ │ │ │ └── symlinklockfile.py
│ │ │ ├── msgpack/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _version.py
│ │ │ │ ├── exceptions.py
│ │ │ │ └── fallback.py
│ │ │ ├── packaging/
│ │ │ │ ├── __about__.py
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _compat.py
│ │ │ │ ├── _structures.py
│ │ │ │ ├── markers.py
│ │ │ │ ├── requirements.py
│ │ │ │ ├── specifiers.py
│ │ │ │ ├── utils.py
│ │ │ │ └── version.py
│ │ │ ├── pep517/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _in_process.py
│ │ │ │ ├── build.py
│ │ │ │ ├── check.py
│ │ │ │ ├── colorlog.py
│ │ │ │ ├── compat.py
│ │ │ │ ├── envbuild.py
│ │ │ │ └── wrappers.py
│ │ │ ├── pkg_resources/
│ │ │ │ ├── __init__.py
│ │ │ │ └── py31compat.py
│ │ │ ├── progress/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── bar.py
│ │ │ │ ├── counter.py
│ │ │ │ ├── helpers.py
│ │ │ │ └── spinner.py
│ │ │ ├── pyparsing.py
│ │ │ ├── pytoml/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── core.py
│ │ │ │ ├── parser.py
│ │ │ │ ├── test.py
│ │ │ │ ├── utils.py
│ │ │ │ └── writer.py
│ │ │ ├── requests/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __version__.py
│ │ │ │ ├── _internal_utils.py
│ │ │ │ ├── adapters.py
│ │ │ │ ├── api.py
│ │ │ │ ├── auth.py
│ │ │ │ ├── certs.py
│ │ │ │ ├── compat.py
│ │ │ │ ├── cookies.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── help.py
│ │ │ │ ├── hooks.py
│ │ │ │ ├── models.py
│ │ │ │ ├── packages.py
│ │ │ │ ├── sessions.py
│ │ │ │ ├── status_codes.py
│ │ │ │ ├── structures.py
│ │ │ │ └── utils.py
│ │ │ ├── retrying.py
│ │ │ ├── six.py
│ │ │ ├── urllib3/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _collections.py
│ │ │ │ ├── connection.py
│ │ │ │ ├── connectionpool.py
│ │ │ │ ├── contrib/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── _appengine_environ.py
│ │ │ │ │ ├── _securetransport/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── bindings.py
│ │ │ │ │ │ └── low_level.py
│ │ │ │ │ ├── appengine.py
│ │ │ │ │ ├── ntlmpool.py
│ │ │ │ │ ├── pyopenssl.py
│ │ │ │ │ ├── securetransport.py
│ │ │ │ │ └── socks.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── fields.py
│ │ │ │ ├── filepost.py
│ │ │ │ ├── packages/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── backports/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── makefile.py
│ │ │ │ │ ├── six.py
│ │ │ │ │ └── ssl_match_hostname/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── _implementation.py
│ │ │ │ ├── poolmanager.py
│ │ │ │ ├── request.py
│ │ │ │ ├── response.py
│ │ │ │ └── util/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── connection.py
│ │ │ │ ├── queue.py
│ │ │ │ ├── request.py
│ │ │ │ ├── response.py
│ │ │ │ ├── retry.py
│ │ │ │ ├── ssl_.py
│ │ │ │ ├── timeout.py
│ │ │ │ ├── url.py
│ │ │ │ └── wait.py
│ │ │ └── webencodings/
│ │ │ ├── __init__.py
│ │ │ ├── labels.py
│ │ │ ├── mklabels.py
│ │ │ ├── tests.py
│ │ │ └── x_user_defined.py
│ │ ├── pyOpenSSL-19.0.0.dist-info/
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ └── top_level.txt
│ │ ├── pyasn1/
│ │ │ ├── __init__.py
│ │ │ ├── codec/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── ber/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── decoder.py
│ │ │ │ │ ├── encoder.py
│ │ │ │ │ └── eoo.py
│ │ │ │ ├── cer/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── decoder.py
│ │ │ │ │ └── encoder.py
│ │ │ │ ├── der/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── decoder.py
│ │ │ │ │ └── encoder.py
│ │ │ │ └── native/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── decoder.py
│ │ │ │ └── encoder.py
│ │ │ ├── compat/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── binary.py
│ │ │ │ ├── calling.py
│ │ │ │ ├── dateandtime.py
│ │ │ │ ├── integer.py
│ │ │ │ ├── octets.py
│ │ │ │ └── string.py
│ │ │ ├── debug.py
│ │ │ ├── error.py
│ │ │ └── type/
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── char.py
│ │ │ ├── constraint.py
│ │ │ ├── error.py
│ │ │ ├── namedtype.py
│ │ │ ├── namedval.py
│ │ │ ├── opentype.py
│ │ │ ├── tag.py
│ │ │ ├── tagmap.py
│ │ │ ├── univ.py
│ │ │ └── useful.py
│ │ ├── pyasn1-0.4.7.dist-info/
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.rst
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ ├── top_level.txt
│ │ │ └── zip-safe
│ │ ├── pyasn1_modules/
│ │ │ ├── __init__.py
│ │ │ ├── pem.py
│ │ │ ├── rfc1155.py
│ │ │ ├── rfc1157.py
│ │ │ ├── rfc1901.py
│ │ │ ├── rfc1902.py
│ │ │ ├── rfc1905.py
│ │ │ ├── rfc2251.py
│ │ │ ├── rfc2314.py
│ │ │ ├── rfc2315.py
│ │ │ ├── rfc2437.py
│ │ │ ├── rfc2459.py
│ │ │ ├── rfc2511.py
│ │ │ ├── rfc2560.py
│ │ │ ├── rfc2634.py
│ │ │ ├── rfc2985.py
│ │ │ ├── rfc2986.py
│ │ │ ├── rfc3161.py
│ │ │ ├── rfc3274.py
│ │ │ ├── rfc3279.py
│ │ │ ├── rfc3280.py
│ │ │ ├── rfc3281.py
│ │ │ ├── rfc3412.py
│ │ │ ├── rfc3414.py
│ │ │ ├── rfc3447.py
│ │ │ ├── rfc3560.py
│ │ │ ├── rfc3565.py
│ │ │ ├── rfc3709.py
│ │ │ ├── rfc3770.py
│ │ │ ├── rfc3779.py
│ │ │ ├── rfc3852.py
│ │ │ ├── rfc4055.py
│ │ │ ├── rfc4073.py
│ │ │ ├── rfc4108.py
│ │ │ ├── rfc4210.py
│ │ │ ├── rfc4211.py
│ │ │ ├── rfc5035.py
│ │ │ ├── rfc5083.py
│ │ │ ├── rfc5084.py
│ │ │ ├── rfc5208.py
│ │ │ ├── rfc5280.py
│ │ │ ├── rfc5480.py
│ │ │ ├── rfc5649.py
│ │ │ ├── rfc5652.py
│ │ │ ├── rfc5751.py
│ │ │ ├── rfc5914.py
│ │ │ ├── rfc5915.py
│ │ │ ├── rfc5934.py
│ │ │ ├── rfc5940.py
│ │ │ ├── rfc5958.py
│ │ │ ├── rfc5990.py
│ │ │ ├── rfc6010.py
│ │ │ ├── rfc6019.py
│ │ │ ├── rfc6031.py
│ │ │ ├── rfc6032.py
│ │ │ ├── rfc6210.py
│ │ │ ├── rfc6211.py
│ │ │ ├── rfc6402.py
│ │ │ ├── rfc7030.py
│ │ │ ├── rfc7191.py
│ │ │ ├── rfc7292.py
│ │ │ ├── rfc7296.py
│ │ │ ├── rfc7773.py
│ │ │ ├── rfc7894.py
│ │ │ ├── rfc7906.py
│ │ │ ├── rfc7914.py
│ │ │ ├── rfc8017.py
│ │ │ ├── rfc8018.py
│ │ │ ├── rfc8103.py
│ │ │ ├── rfc8209.py
│ │ │ ├── rfc8226.py
│ │ │ ├── rfc8358.py
│ │ │ ├── rfc8360.py
│ │ │ ├── rfc8398.py
│ │ │ ├── rfc8410.py
│ │ │ ├── rfc8418.py
│ │ │ ├── rfc8419.py
│ │ │ ├── rfc8479.py
│ │ │ ├── rfc8494.py
│ │ │ ├── rfc8520.py
│ │ │ ├── rfc8619.py
│ │ │ └── rfc8649.py
│ │ ├── pyasn1_modules-0.2.7.dist-info/
│ │ │ ├── DESCRIPTION.rst
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ ├── metadata.json
│ │ │ ├── top_level.txt
│ │ │ └── zip-safe
│ │ ├── pycparser/
│ │ │ ├── __init__.py
│ │ │ ├── _ast_gen.py
│ │ │ ├── _build_tables.py
│ │ │ ├── _c_ast.cfg
│ │ │ ├── ast_transforms.py
│ │ │ ├── c_ast.py
│ │ │ ├── c_generator.py
│ │ │ ├── c_lexer.py
│ │ │ ├── c_parser.py
│ │ │ ├── lextab.py
│ │ │ ├── ply/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── cpp.py
│ │ │ │ ├── ctokens.py
│ │ │ │ ├── lex.py
│ │ │ │ ├── yacc.py
│ │ │ │ └── ygen.py
│ │ │ ├── plyparser.py
│ │ │ └── yacctab.py
│ │ ├── pycparser-2.19-py3.6.egg-info/
│ │ │ ├── PKG-INFO
│ │ │ ├── SOURCES.txt
│ │ │ ├── dependency_links.txt
│ │ │ ├── installed-files.txt
│ │ │ └── top_level.txt
│ │ ├── pydispatch/
│ │ │ ├── __init__.py
│ │ │ ├── dispatcher.py
│ │ │ ├── errors.py
│ │ │ ├── robust.py
│ │ │ ├── robustapply.py
│ │ │ └── saferef.py
│ │ ├── pymongo/
│ │ │ ├── __init__.py
│ │ │ ├── aggregation.py
│ │ │ ├── auth.py
│ │ │ ├── bulk.py
│ │ │ ├── change_stream.py
│ │ │ ├── client_options.py
│ │ │ ├── client_session.py
│ │ │ ├── collation.py
│ │ │ ├── collection.py
│ │ │ ├── command_cursor.py
│ │ │ ├── common.py
│ │ │ ├── compression_support.py
│ │ │ ├── cursor.py
│ │ │ ├── cursor_manager.py
│ │ │ ├── database.py
│ │ │ ├── driver_info.py
│ │ │ ├── encryption.py
│ │ │ ├── encryption_options.py
│ │ │ ├── errors.py
│ │ │ ├── helpers.py
│ │ │ ├── ismaster.py
│ │ │ ├── max_staleness_selectors.py
│ │ │ ├── message.py
│ │ │ ├── mongo_client.py
│ │ │ ├── mongo_replica_set_client.py
│ │ │ ├── monitor.py
│ │ │ ├── monitoring.py
│ │ │ ├── monotonic.py
│ │ │ ├── network.py
│ │ │ ├── operations.py
│ │ │ ├── periodic_executor.py
│ │ │ ├── pool.py
│ │ │ ├── read_concern.py
│ │ │ ├── read_preferences.py
│ │ │ ├── response.py
│ │ │ ├── results.py
│ │ │ ├── saslprep.py
│ │ │ ├── server.py
│ │ │ ├── server_description.py
│ │ │ ├── server_selectors.py
│ │ │ ├── server_type.py
│ │ │ ├── settings.py
│ │ │ ├── son_manipulator.py
│ │ │ ├── srv_resolver.py
│ │ │ ├── ssl_context.py
│ │ │ ├── ssl_match_hostname.py
│ │ │ ├── ssl_support.py
│ │ │ ├── thread_util.py
│ │ │ ├── topology.py
│ │ │ ├── topology_description.py
│ │ │ ├── uri_parser.py
│ │ │ └── write_concern.py
│ │ ├── pymongo-3.9.0.dist-info/
│ │ │ ├── INSTALLER
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ └── top_level.txt
│ │ ├── queuelib/
│ │ │ ├── __init__.py
│ │ │ ├── pqueue.py
│ │ │ ├── queue.py
│ │ │ ├── rrqueue.py
│ │ │ └── tests/
│ │ │ ├── __init__.py
│ │ │ ├── test_pqueue.py
│ │ │ ├── test_queue.py
│ │ │ └── test_rrqueue.py
│ │ ├── queuelib-1.5.0.dist-info/
│ │ │ ├── DESCRIPTION.rst
│ │ │ ├── INSTALLER
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ ├── metadata.json
│ │ │ └── top_level.txt
│ │ ├── redis/
│ │ │ ├── __init__.py
│ │ │ ├── _compat.py
│ │ │ ├── client.py
│ │ │ ├── connection.py
│ │ │ ├── exceptions.py
│ │ │ ├── lock.py
│ │ │ ├── sentinel.py
│ │ │ └── utils.py
│ │ ├── redis-3.3.11.dist-info/
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ └── top_level.txt
│ │ ├── scrapy/
│ │ │ ├── VERSION
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── _monkeypatches.py
│ │ │ ├── cmdline.py
│ │ │ ├── commands/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── bench.py
│ │ │ │ ├── check.py
│ │ │ │ ├── crawl.py
│ │ │ │ ├── edit.py
│ │ │ │ ├── fetch.py
│ │ │ │ ├── genspider.py
│ │ │ │ ├── list.py
│ │ │ │ ├── parse.py
│ │ │ │ ├── runspider.py
│ │ │ │ ├── settings.py
│ │ │ │ ├── shell.py
│ │ │ │ ├── startproject.py
│ │ │ │ ├── version.py
│ │ │ │ └── view.py
│ │ │ ├── contracts/
│ │ │ │ ├── __init__.py
│ │ │ │ └── default.py
│ │ │ ├── core/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── downloader/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── contextfactory.py
│ │ │ │ │ ├── handlers/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── datauri.py
│ │ │ │ │ │ ├── file.py
│ │ │ │ │ │ ├── ftp.py
│ │ │ │ │ │ ├── http.py
│ │ │ │ │ │ ├── http10.py
│ │ │ │ │ │ ├── http11.py
│ │ │ │ │ │ └── s3.py
│ │ │ │ │ ├── middleware.py
│ │ │ │ │ ├── tls.py
│ │ │ │ │ └── webclient.py
│ │ │ │ ├── engine.py
│ │ │ │ ├── scheduler.py
│ │ │ │ ├── scraper.py
│ │ │ │ └── spidermw.py
│ │ │ ├── crawler.py
│ │ │ ├── downloadermiddlewares/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── ajaxcrawl.py
│ │ │ │ ├── chunked.py
│ │ │ │ ├── cookies.py
│ │ │ │ ├── decompression.py
│ │ │ │ ├── defaultheaders.py
│ │ │ │ ├── downloadtimeout.py
│ │ │ │ ├── httpauth.py
│ │ │ │ ├── httpcache.py
│ │ │ │ ├── httpcompression.py
│ │ │ │ ├── httpproxy.py
│ │ │ │ ├── redirect.py
│ │ │ │ ├── retry.py
│ │ │ │ ├── robotstxt.py
│ │ │ │ ├── stats.py
│ │ │ │ └── useragent.py
│ │ │ ├── dupefilters.py
│ │ │ ├── exceptions.py
│ │ │ ├── exporters.py
│ │ │ ├── extension.py
│ │ │ ├── extensions/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── closespider.py
│ │ │ │ ├── corestats.py
│ │ │ │ ├── debug.py
│ │ │ │ ├── feedexport.py
│ │ │ │ ├── httpcache.py
│ │ │ │ ├── logstats.py
│ │ │ │ ├── memdebug.py
│ │ │ │ ├── memusage.py
│ │ │ │ ├── spiderstate.py
│ │ │ │ ├── statsmailer.py
│ │ │ │ ├── telnet.py
│ │ │ │ └── throttle.py
│ │ │ ├── http/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── common.py
│ │ │ │ ├── cookies.py
│ │ │ │ ├── headers.py
│ │ │ │ ├── request/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── form.py
│ │ │ │ │ ├── json_request.py
│ │ │ │ │ └── rpc.py
│ │ │ │ └── response/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── html.py
│ │ │ │ ├── text.py
│ │ │ │ └── xml.py
│ │ │ ├── interfaces.py
│ │ │ ├── item.py
│ │ │ ├── link.py
│ │ │ ├── linkextractors/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── htmlparser.py
│ │ │ │ ├── lxmlhtml.py
│ │ │ │ ├── regex.py
│ │ │ │ └── sgml.py
│ │ │ ├── loader/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── common.py
│ │ │ │ └── processors.py
│ │ │ ├── logformatter.py
│ │ │ ├── mail.py
│ │ │ ├── middleware.py
│ │ │ ├── mime.types
│ │ │ ├── pipelines/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── files.py
│ │ │ │ ├── images.py
│ │ │ │ └── media.py
│ │ │ ├── pqueues.py
│ │ │ ├── resolver.py
│ │ │ ├── responsetypes.py
│ │ │ ├── selector/
│ │ │ │ ├── __init__.py
│ │ │ │ └── unified.py
│ │ │ ├── settings/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── default_settings.py
│ │ │ │ └── deprecated.py
│ │ │ ├── shell.py
│ │ │ ├── signalmanager.py
│ │ │ ├── signals.py
│ │ │ ├── spiderloader.py
│ │ │ ├── spidermiddlewares/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── depth.py
│ │ │ │ ├── httperror.py
│ │ │ │ ├── offsite.py
│ │ │ │ ├── referer.py
│ │ │ │ └── urllength.py
│ │ │ ├── spiders/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── crawl.py
│ │ │ │ ├── feed.py
│ │ │ │ ├── init.py
│ │ │ │ └── sitemap.py
│ │ │ ├── squeues.py
│ │ │ ├── statscollectors.py
│ │ │ ├── templates/
│ │ │ │ ├── project/
│ │ │ │ │ ├── module/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── items.py.tmpl
│ │ │ │ │ │ ├── middlewares.py.tmpl
│ │ │ │ │ │ ├── pipelines.py.tmpl
│ │ │ │ │ │ ├── settings.py.tmpl
│ │ │ │ │ │ └── spiders/
│ │ │ │ │ │ └── __init__.py
│ │ │ │ │ └── scrapy.cfg
│ │ │ │ └── spiders/
│ │ │ │ ├── basic.tmpl
│ │ │ │ ├── crawl.tmpl
│ │ │ │ ├── csvfeed.tmpl
│ │ │ │ └── xmlfeed.tmpl
│ │ │ ├── utils/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── benchserver.py
│ │ │ │ ├── boto.py
│ │ │ │ ├── conf.py
│ │ │ │ ├── console.py
│ │ │ │ ├── datatypes.py
│ │ │ │ ├── decorators.py
│ │ │ │ ├── defer.py
│ │ │ │ ├── deprecate.py
│ │ │ │ ├── display.py
│ │ │ │ ├── engine.py
│ │ │ │ ├── ftp.py
│ │ │ │ ├── gz.py
│ │ │ │ ├── http.py
│ │ │ │ ├── httpobj.py
│ │ │ │ ├── iterators.py
│ │ │ │ ├── job.py
│ │ │ │ ├── log.py
│ │ │ │ ├── markup.py
│ │ │ │ ├── misc.py
│ │ │ │ ├── multipart.py
│ │ │ │ ├── ossignal.py
│ │ │ │ ├── project.py
│ │ │ │ ├── python.py
│ │ │ │ ├── reactor.py
│ │ │ │ ├── reqser.py
│ │ │ │ ├── request.py
│ │ │ │ ├── response.py
│ │ │ │ ├── serialize.py
│ │ │ │ ├── signal.py
│ │ │ │ ├── sitemap.py
│ │ │ │ ├── spider.py
│ │ │ │ ├── template.py
│ │ │ │ ├── test.py
│ │ │ │ ├── testproc.py
│ │ │ │ ├── testsite.py
│ │ │ │ ├── trackref.py
│ │ │ │ ├── url.py
│ │ │ │ └── versions.py
│ │ │ └── xlib/
│ │ │ ├── __init__.py
│ │ │ ├── pydispatch.py
│ │ │ └── tx.py
│ │ ├── scrapy_redis/
│ │ │ ├── __init__.py
│ │ │ ├── connection.py
│ │ │ ├── defaults.py
│ │ │ ├── dupefilter.py
│ │ │ ├── picklecompat.py
│ │ │ ├── pipelines.py
│ │ │ ├── queue.py
│ │ │ ├── scheduler.py
│ │ │ ├── spiders.py
│ │ │ └── utils.py
│ │ ├── scrapy_redis-0.6.8.dist-info/
│ │ │ ├── DESCRIPTION.rst
│ │ │ ├── INSTALLER
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ ├── metadata.json
│ │ │ └── top_level.txt
│ │ ├── service_identity/
│ │ │ ├── __init__.py
│ │ │ ├── _common.py
│ │ │ ├── _compat.py
│ │ │ ├── cryptography.py
│ │ │ ├── exceptions.py
│ │ │ └── pyopenssl.py
│ │ ├── service_identity-18.1.0.dist-info/
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ └── top_level.txt
│ │ ├── setuptools-40.8.0-py3.6.egg
│ │ ├── setuptools.pth
│ │ ├── six-1.12.0.dist-info/
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ └── top_level.txt
│ │ ├── six.py
│ │ ├── twisted/
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── _threads/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _convenience.py
│ │ │ │ ├── _ithreads.py
│ │ │ │ ├── _memory.py
│ │ │ │ ├── _pool.py
│ │ │ │ ├── _team.py
│ │ │ │ ├── _threadworker.py
│ │ │ │ └── test/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_convenience.py
│ │ │ │ ├── test_memory.py
│ │ │ │ ├── test_team.py
│ │ │ │ └── test_threadworker.py
│ │ │ ├── _version.py
│ │ │ ├── application/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── app.py
│ │ │ │ ├── internet.py
│ │ │ │ ├── reactors.py
│ │ │ │ ├── runner/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── _exit.py
│ │ │ │ │ ├── _pidfile.py
│ │ │ │ │ ├── _runner.py
│ │ │ │ │ └── test/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_exit.py
│ │ │ │ │ ├── test_pidfile.py
│ │ │ │ │ └── test_runner.py
│ │ │ │ ├── service.py
│ │ │ │ ├── strports.py
│ │ │ │ ├── test/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_internet.py
│ │ │ │ │ └── test_service.py
│ │ │ │ └── twist/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _options.py
│ │ │ │ ├── _twist.py
│ │ │ │ └── test/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_options.py
│ │ │ │ └── test_twist.py
│ │ │ ├── conch/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── avatar.py
│ │ │ │ ├── checkers.py
│ │ │ │ ├── client/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── agent.py
│ │ │ │ │ ├── connect.py
│ │ │ │ │ ├── default.py
│ │ │ │ │ ├── direct.py
│ │ │ │ │ ├── knownhosts.py
│ │ │ │ │ └── options.py
│ │ │ │ ├── endpoints.py
│ │ │ │ ├── error.py
│ │ │ │ ├── insults/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── helper.py
│ │ │ │ │ ├── insults.py
│ │ │ │ │ ├── text.py
│ │ │ │ │ └── window.py
│ │ │ │ ├── interfaces.py
│ │ │ │ ├── ls.py
│ │ │ │ ├── manhole.py
│ │ │ │ ├── manhole_ssh.py
│ │ │ │ ├── manhole_tap.py
│ │ │ │ ├── mixin.py
│ │ │ │ ├── openssh_compat/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── factory.py
│ │ │ │ │ └── primes.py
│ │ │ │ ├── recvline.py
│ │ │ │ ├── scripts/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── cftp.py
│ │ │ │ │ ├── ckeygen.py
│ │ │ │ │ ├── conch.py
│ │ │ │ │ └── tkconch.py
│ │ │ │ ├── ssh/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── _kex.py
│ │ │ │ │ ├── address.py
│ │ │ │ │ ├── agent.py
│ │ │ │ │ ├── channel.py
│ │ │ │ │ ├── common.py
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── factory.py
│ │ │ │ │ ├── filetransfer.py
│ │ │ │ │ ├── forwarding.py
│ │ │ │ │ ├── keys.py
│ │ │ │ │ ├── service.py
│ │ │ │ │ ├── session.py
│ │ │ │ │ ├── sexpy.py
│ │ │ │ │ ├── transport.py
│ │ │ │ │ └── userauth.py
│ │ │ │ ├── stdio.py
│ │ │ │ ├── tap.py
│ │ │ │ ├── telnet.py
│ │ │ │ ├── test/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── keydata.py
│ │ │ │ │ ├── loopback.py
│ │ │ │ │ ├── test_address.py
│ │ │ │ │ ├── test_agent.py
│ │ │ │ │ ├── test_cftp.py
│ │ │ │ │ ├── test_channel.py
│ │ │ │ │ ├── test_checkers.py
│ │ │ │ │ ├── test_ckeygen.py
│ │ │ │ │ ├── test_conch.py
│ │ │ │ │ ├── test_connection.py
│ │ │ │ │ ├── test_default.py
│ │ │ │ │ ├── test_endpoints.py
│ │ │ │ │ ├── test_filetransfer.py
│ │ │ │ │ ├── test_forwarding.py
│ │ │ │ │ ├── test_helper.py
│ │ │ │ │ ├── test_insults.py
│ │ │ │ │ ├── test_keys.py
│ │ │ │ │ ├── test_knownhosts.py
│ │ │ │ │ ├── test_manhole.py
│ │ │ │ │ ├── test_manhole_tap.py
│ │ │ │ │ ├── test_mixin.py
│ │ │ │ │ ├── test_openssh_compat.py
│ │ │ │ │ ├── test_recvline.py
│ │ │ │ │ ├── test_scripts.py
│ │ │ │ │ ├── test_session.py
│ │ │ │ │ ├── test_ssh.py
│ │ │ │ │ ├── test_tap.py
│ │ │ │ │ ├── test_telnet.py
│ │ │ │ │ ├── test_text.py
│ │ │ │ │ ├── test_transport.py
│ │ │ │ │ ├── test_unix.py
│ │ │ │ │ ├── test_userauth.py
│ │ │ │ │ └── test_window.py
│ │ │ │ ├── ttymodes.py
│ │ │ │ ├── ui/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── ansi.py
│ │ │ │ │ └── tkvt100.py
│ │ │ │ └── unix.py
│ │ │ ├── copyright.py
│ │ │ ├── cred/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _digest.py
│ │ │ │ ├── checkers.py
│ │ │ │ ├── credentials.py
│ │ │ │ ├── error.py
│ │ │ │ ├── portal.py
│ │ │ │ ├── strcred.py
│ │ │ │ └── test/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_cramauth.py
│ │ │ │ ├── test_cred.py
│ │ │ │ ├── test_digestauth.py
│ │ │ │ ├── test_simpleauth.py
│ │ │ │ └── test_strcred.py
│ │ │ ├── enterprise/
│ │ │ │ ├── __init__.py
│ │ │ │ └── adbapi.py
│ │ │ ├── internet/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _baseprocess.py
│ │ │ │ ├── _dumbwin32proc.py
│ │ │ │ ├── _glibbase.py
│ │ │ │ ├── _idna.py
│ │ │ │ ├── _newtls.py
│ │ │ │ ├── _pollingfile.py
│ │ │ │ ├── _posixserialport.py
│ │ │ │ ├── _posixstdio.py
│ │ │ │ ├── _producer_helpers.py
│ │ │ │ ├── _resolver.py
│ │ │ │ ├── _signals.py
│ │ │ │ ├── _sslverify.py
│ │ │ │ ├── _threadedselect.py
│ │ │ │ ├── _win32serialport.py
│ │ │ │ ├── _win32stdio.py
│ │ │ │ ├── abstract.py
│ │ │ │ ├── address.py
│ │ │ │ ├── asyncioreactor.py
│ │ │ │ ├── base.py
│ │ │ │ ├── cfreactor.py
│ │ │ │ ├── default.py
│ │ │ │ ├── defer.py
│ │ │ │ ├── endpoints.py
│ │ │ │ ├── epollreactor.py
│ │ │ │ ├── error.py
│ │ │ │ ├── fdesc.py
│ │ │ │ ├── gireactor.py
│ │ │ │ ├── glib2reactor.py
│ │ │ │ ├── gtk2reactor.py
│ │ │ │ ├── gtk3reactor.py
│ │ │ │ ├── inotify.py
│ │ │ │ ├── interfaces.py
│ │ │ │ ├── iocpreactor/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── abstract.py
│ │ │ │ │ ├── const.py
│ │ │ │ │ ├── interfaces.py
│ │ │ │ │ ├── notes.txt
│ │ │ │ │ ├── reactor.py
│ │ │ │ │ ├── setup.py
│ │ │ │ │ ├── tcp.py
│ │ │ │ │ └── udp.py
│ │ │ │ ├── kqreactor.py
│ │ │ │ ├── main.py
│ │ │ │ ├── pollreactor.py
│ │ │ │ ├── posixbase.py
│ │ │ │ ├── process.py
│ │ │ │ ├── protocol.py
│ │ │ │ ├── pyuisupport.py
│ │ │ │ ├── reactor.py
│ │ │ │ ├── selectreactor.py
│ │ │ │ ├── serialport.py
│ │ │ │ ├── ssl.py
│ │ │ │ ├── stdio.py
│ │ │ │ ├── task.py
│ │ │ │ ├── tcp.py
│ │ │ │ ├── test/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── _awaittests.py.3only
│ │ │ │ │ ├── _posixifaces.py
│ │ │ │ │ ├── _win32ifaces.py
│ │ │ │ │ ├── _yieldfromtests.py.3only
│ │ │ │ │ ├── connectionmixins.py
│ │ │ │ │ ├── fake_CAs/
│ │ │ │ │ │ ├── chain.pem
│ │ │ │ │ │ ├── not-a-certificate
│ │ │ │ │ │ ├── thing1.pem
│ │ │ │ │ │ ├── thing2-duplicate.pem
│ │ │ │ │ │ └── thing2.pem
│ │ │ │ │ ├── fakeendpoint.py
│ │ │ │ │ ├── modulehelpers.py
│ │ │ │ │ ├── process_cli.py
│ │ │ │ │ ├── process_connectionlost.py
│ │ │ │ │ ├── process_gireactornocompat.py
│ │ │ │ │ ├── process_helper.py
│ │ │ │ │ ├── reactormixins.py
│ │ │ │ │ ├── test_abstract.py
│ │ │ │ │ ├── test_address.py
│ │ │ │ │ ├── test_asyncioreactor.py
│ │ │ │ │ ├── test_base.py
│ │ │ │ │ ├── test_baseprocess.py
│ │ │ │ │ ├── test_core.py
│ │ │ │ │ ├── test_coroutines.py
│ │ │ │ │ ├── test_default.py
│ │ │ │ │ ├── test_endpoints.py
│ │ │ │ │ ├── test_epollreactor.py
│ │ │ │ │ ├── test_error.py
│ │ │ │ │ ├── test_fdset.py
│ │ │ │ │ ├── test_filedescriptor.py
│ │ │ │ │ ├── test_gireactor.py
│ │ │ │ │ ├── test_glibbase.py
│ │ │ │ │ ├── test_inlinecb.py
│ │ │ │ │ ├── test_inotify.py
│ │ │ │ │ ├── test_iocp.py
│ │ │ │ │ ├── test_kqueuereactor.py
│ │ │ │ │ ├── test_main.py
│ │ │ │ │ ├── test_newtls.py
│ │ │ │ │ ├── test_pollingfile.py
│ │ │ │ │ ├── test_posixbase.py
│ │ │ │ │ ├── test_posixprocess.py
│ │ │ │ │ ├── test_process.py
│ │ │ │ │ ├── test_protocol.py
│ │ │ │ │ ├── test_resolver.py
│ │ │ │ │ ├── test_serialport.py
│ │ │ │ │ ├── test_sigchld.py
│ │ │ │ │ ├── test_socket.py
│ │ │ │ │ ├── test_stdio.py
│ │ │ │ │ ├── test_tcp.py
│ │ │ │ │ ├── test_testing.py
│ │ │ │ │ ├── test_threads.py
│ │ │ │ │ ├── test_time.py
│ │ │ │ │ ├── test_tls.py
│ │ │ │ │ ├── test_udp.py
│ │ │ │ │ ├── test_udp_internals.py
│ │ │ │ │ ├── test_unix.py
│ │ │ │ │ ├── test_win32events.py
│ │ │ │ │ └── test_win32serialport.py
│ │ │ │ ├── testing.py
│ │ │ │ ├── threads.py
│ │ │ │ ├── tksupport.py
│ │ │ │ ├── udp.py
│ │ │ │ ├── unix.py
│ │ │ │ ├── utils.py
│ │ │ │ ├── win32eventreactor.py
│ │ │ │ ├── wxreactor.py
│ │ │ │ └── wxsupport.py
│ │ │ ├── logger/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _buffer.py
│ │ │ │ ├── _capture.py
│ │ │ │ ├── _file.py
│ │ │ │ ├── _filter.py
│ │ │ │ ├── _flatten.py
│ │ │ │ ├── _format.py
│ │ │ │ ├── _global.py
│ │ │ │ ├── _io.py
│ │ │ │ ├── _json.py
│ │ │ │ ├── _legacy.py
│ │ │ │ ├── _levels.py
│ │ │ │ ├── _logger.py
│ │ │ │ ├── _observer.py
│ │ │ │ ├── _stdlib.py
│ │ │ │ ├── _util.py
│ │ │ │ └── test/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_buffer.py
│ │ │ │ ├── test_capture.py
│ │ │ │ ├── test_file.py
│ │ │ │ ├── test_filter.py
│ │ │ │ ├── test_flatten.py
│ │ │ │ ├── test_format.py
│ │ │ │ ├── test_global.py
│ │ │ │ ├── test_io.py
│ │ │ │ ├── test_json.py
│ │ │ │ ├── test_legacy.py
│ │ │ │ ├── test_levels.py
│ │ │ │ ├── test_logger.py
│ │ │ │ ├── test_observer.py
│ │ │ │ ├── test_stdlib.py
│ │ │ │ └── test_util.py
│ │ │ ├── mail/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _cred.py
│ │ │ │ ├── _except.py
│ │ │ │ ├── imap4.py
│ │ │ │ ├── interfaces.py
│ │ │ │ ├── pop3.py
│ │ │ │ ├── pop3client.py
│ │ │ │ ├── protocols.py
│ │ │ │ ├── relay.py
│ │ │ │ ├── scripts/
│ │ │ │ │ └── mailmail.py
│ │ │ │ ├── smtp.py
│ │ │ │ └── test/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── pop3testserver.py
│ │ │ │ ├── rfc822.message
│ │ │ │ ├── test_imap.py
│ │ │ │ ├── test_mailmail.py
│ │ │ │ ├── test_pop3.py
│ │ │ │ ├── test_pop3client.py
│ │ │ │ └── test_smtp.py
│ │ │ ├── names/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _rfc1982.py
│ │ │ │ ├── authority.py
│ │ │ │ ├── cache.py
│ │ │ │ ├── client.py
│ │ │ │ ├── common.py
│ │ │ │ ├── dns.py
│ │ │ │ ├── error.py
│ │ │ │ ├── hosts.py
│ │ │ │ ├── resolve.py
│ │ │ │ ├── root.py
│ │ │ │ ├── secondary.py
│ │ │ │ ├── server.py
│ │ │ │ ├── srvconnect.py
│ │ │ │ ├── tap.py
│ │ │ │ └── test/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_cache.py
│ │ │ │ ├── test_client.py
│ │ │ │ ├── test_common.py
│ │ │ │ ├── test_dns.py
│ │ │ │ ├── test_examples.py
│ │ │ │ ├── test_hosts.py
│ │ │ │ ├── test_names.py
│ │ │ │ ├── test_resolve.py
│ │ │ │ ├── test_rfc1982.py
│ │ │ │ ├── test_rootresolve.py
│ │ │ │ ├── test_server.py
│ │ │ │ ├── test_srvconnect.py
│ │ │ │ ├── test_tap.py
│ │ │ │ └── test_util.py
│ │ │ ├── pair/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── ethernet.py
│ │ │ │ ├── ip.py
│ │ │ │ ├── raw.py
│ │ │ │ ├── rawudp.py
│ │ │ │ ├── test/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_ethernet.py
│ │ │ │ │ ├── test_ip.py
│ │ │ │ │ ├── test_rawudp.py
│ │ │ │ │ └── test_tuntap.py
│ │ │ │ ├── testing.py
│ │ │ │ └── tuntap.py
│ │ │ ├── persisted/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aot.py
│ │ │ │ ├── crefutil.py
│ │ │ │ ├── dirdbm.py
│ │ │ │ ├── sob.py
│ │ │ │ ├── styles.py
│ │ │ │ └── test/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_styles.py
│ │ │ ├── plugin.py
│ │ │ ├── plugins/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── cred_anonymous.py
│ │ │ │ ├── cred_file.py
│ │ │ │ ├── cred_memory.py
│ │ │ │ ├── cred_sshkeys.py
│ │ │ │ ├── cred_unix.py
│ │ │ │ ├── twisted_conch.py
│ │ │ │ ├── twisted_core.py
│ │ │ │ ├── twisted_ftp.py
│ │ │ │ ├── twisted_inet.py
│ │ │ │ ├── twisted_names.py
│ │ │ │ ├── twisted_portforward.py
│ │ │ │ ├── twisted_reactors.py
│ │ │ │ ├── twisted_runner.py
│ │ │ │ ├── twisted_socks.py
│ │ │ │ ├── twisted_trial.py
│ │ │ │ ├── twisted_web.py
│ │ │ │ └── twisted_words.py
│ │ │ ├── positioning/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _sentence.py
│ │ │ │ ├── base.py
│ │ │ │ ├── ipositioning.py
│ │ │ │ ├── nmea.py
│ │ │ │ └── test/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── receiver.py
│ │ │ │ ├── test_base.py
│ │ │ │ ├── test_nmea.py
│ │ │ │ └── test_sentence.py
│ │ │ ├── protocols/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── amp.py
│ │ │ │ ├── basic.py
│ │ │ │ ├── dict.py
│ │ │ │ ├── finger.py
│ │ │ │ ├── ftp.py
│ │ │ │ ├── haproxy/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── _exceptions.py
│ │ │ │ │ ├── _info.py
│ │ │ │ │ ├── _interfaces.py
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _v1parser.py
│ │ │ │ │ ├── _v2parser.py
│ │ │ │ │ ├── _wrapper.py
│ │ │ │ │ └── test/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_parser.py
│ │ │ │ │ ├── test_v1parser.py
│ │ │ │ │ ├── test_v2parser.py
│ │ │ │ │ └── test_wrapper.py
│ │ │ │ ├── htb.py
│ │ │ │ ├── ident.py
│ │ │ │ ├── loopback.py
│ │ │ │ ├── memcache.py
│ │ │ │ ├── pcp.py
│ │ │ │ ├── policies.py
│ │ │ │ ├── portforward.py
│ │ │ │ ├── postfix.py
│ │ │ │ ├── sip.py
│ │ │ │ ├── socks.py
│ │ │ │ ├── stateful.py
│ │ │ │ ├── test/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_basic.py
│ │ │ │ │ └── test_tls.py
│ │ │ │ ├── tls.py
│ │ │ │ └── wire.py
│ │ │ ├── python/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _appdirs.py
│ │ │ │ ├── _inotify.py
│ │ │ │ ├── _oldstyle.py
│ │ │ │ ├── _pydoctortemplates/
│ │ │ │ │ ├── common.html
│ │ │ │ │ ├── index.html
│ │ │ │ │ └── summary.html
│ │ │ │ ├── _release.py
│ │ │ │ ├── _setup.py
│ │ │ │ ├── _shellcomp.py
│ │ │ │ ├── _textattributes.py
│ │ │ │ ├── _tzhelper.py
│ │ │ │ ├── _url.py
│ │ │ │ ├── compat.py
│ │ │ │ ├── components.py
│ │ │ │ ├── constants.py
│ │ │ │ ├── context.py
│ │ │ │ ├── deprecate.py
│ │ │ │ ├── failure.py
│ │ │ │ ├── fakepwd.py
│ │ │ │ ├── filepath.py
│ │ │ │ ├── formmethod.py
│ │ │ │ ├── htmlizer.py
│ │ │ │ ├── lockfile.py
│ │ │ │ ├── log.py
│ │ │ │ ├── logfile.py
│ │ │ │ ├── modules.py
│ │ │ │ ├── monkey.py
│ │ │ │ ├── procutils.py
│ │ │ │ ├── randbytes.py
│ │ │ │ ├── rebuild.py
│ │ │ │ ├── reflect.py
│ │ │ │ ├── release.py
│ │ │ │ ├── roots.py
│ │ │ │ ├── runtime.py
│ │ │ │ ├── sendmsg.py
│ │ │ │ ├── shortcut.py
│ │ │ │ ├── syslog.py
│ │ │ │ ├── systemd.py
│ │ │ │ ├── test/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── _deprecatetests.py.3only
│ │ │ │ │ ├── deprecatedattributes.py
│ │ │ │ │ ├── modules_helpers.py
│ │ │ │ │ ├── pullpipe.py
│ │ │ │ │ ├── test_appdirs.py
│ │ │ │ │ ├── test_components.py
│ │ │ │ │ ├── test_constants.py
│ │ │ │ │ ├── test_deprecate.py
│ │ │ │ │ ├── test_dist3.py
│ │ │ │ │ ├── test_fakepwd.py
│ │ │ │ │ ├── test_htmlizer.py
│ │ │ │ │ ├── test_inotify.py
│ │ │ │ │ ├── test_release.py
│ │ │ │ │ ├── test_runtime.py
│ │ │ │ │ ├── test_sendmsg.py
│ │ │ │ │ ├── test_setup.py
│ │ │ │ │ ├── test_shellcomp.py
│ │ │ │ │ ├── test_syslog.py
│ │ │ │ │ ├── test_systemd.py
│ │ │ │ │ ├── test_textattributes.py
│ │ │ │ │ ├── test_tzhelper.py
│ │ │ │ │ ├── test_url.py
│ │ │ │ │ ├── test_urlpath.py
│ │ │ │ │ ├── test_util.py
│ │ │ │ │ ├── test_versions.py
│ │ │ │ │ ├── test_zippath.py
│ │ │ │ │ └── test_zipstream.py
│ │ │ │ ├── text.py
│ │ │ │ ├── threadable.py
│ │ │ │ ├── threadpool.py
│ │ │ │ ├── twisted-completion.zsh
│ │ │ │ ├── url.py
│ │ │ │ ├── urlpath.py
│ │ │ │ ├── usage.py
│ │ │ │ ├── util.py
│ │ │ │ ├── versions.py
│ │ │ │ ├── win32.py
│ │ │ │ ├── zippath.py
│ │ │ │ └── zipstream.py
│ │ │ ├── runner/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── inetd.py
│ │ │ │ ├── inetdconf.py
│ │ │ │ ├── inetdtap.py
│ │ │ │ ├── procmon.py
│ │ │ │ ├── procmontap.py
│ │ │ │ └── test/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_inetdconf.py
│ │ │ │ ├── test_procmon.py
│ │ │ │ └── test_procmontap.py
│ │ │ ├── scripts/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _twistd_unix.py
│ │ │ │ ├── _twistw.py
│ │ │ │ ├── htmlizer.py
│ │ │ │ ├── test/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_scripts.py
│ │ │ │ ├── trial.py
│ │ │ │ └── twistd.py
│ │ │ ├── spread/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── banana.py
│ │ │ │ ├── flavors.py
│ │ │ │ ├── interfaces.py
│ │ │ │ ├── jelly.py
│ │ │ │ ├── pb.py
│ │ │ │ ├── publish.py
│ │ │ │ ├── test/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_banana.py
│ │ │ │ │ ├── test_jelly.py
│ │ │ │ │ ├── test_pb.py
│ │ │ │ │ └── test_pbfailure.py
│ │ │ │ └── util.py
│ │ │ ├── tap/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── ftp.py
│ │ │ │ ├── portforward.py
│ │ │ │ └── socks.py
│ │ │ ├── test/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── cert.pem.no_trailing_newline
│ │ │ │ ├── crash_test_dummy.py
│ │ │ │ ├── iosim.py
│ │ │ │ ├── key.pem.no_trailing_newline
│ │ │ │ ├── mock_win32process.py
│ │ │ │ ├── myrebuilder1.py
│ │ │ │ ├── myrebuilder2.py
│ │ │ │ ├── plugin_basic.py
│ │ │ │ ├── plugin_extra1.py
│ │ │ │ ├── plugin_extra2.py
│ │ │ │ ├── process_cmdline.py
│ │ │ │ ├── process_echoer.py
│ │ │ │ ├── process_fds.py
│ │ │ │ ├── process_getargv.py
│ │ │ │ ├── process_getenv.py
│ │ │ │ ├── process_linger.py
│ │ │ │ ├── process_reader.py
│ │ │ │ ├── process_signal.py
│ │ │ │ ├── process_stdinreader.py
│ │ │ │ ├── process_tester.py
│ │ │ │ ├── process_tty.py
│ │ │ │ ├── process_twisted.py
│ │ │ │ ├── proto_helpers.py
│ │ │ │ ├── reflect_helper_IE.py
│ │ │ │ ├── reflect_helper_VE.py
│ │ │ │ ├── reflect_helper_ZDE.py
│ │ │ │ ├── server.pem
│ │ │ │ ├── ssl_helpers.py
│ │ │ │ ├── stdio_test_consumer.py
│ │ │ │ ├── stdio_test_halfclose.py
│ │ │ │ ├── stdio_test_hostpeer.py
│ │ │ │ ├── stdio_test_lastwrite.py
│ │ │ │ ├── stdio_test_loseconn.py
│ │ │ │ ├── stdio_test_producer.py
│ │ │ │ ├── stdio_test_write.py
│ │ │ │ ├── stdio_test_writeseq.py
│ │ │ │ ├── test_abstract.py
│ │ │ │ ├── test_adbapi.py
│ │ │ │ ├── test_amp.py
│ │ │ │ ├── test_application.py
│ │ │ │ ├── test_compat.py
│ │ │ │ ├── test_context.py
│ │ │ │ ├── test_cooperator.py
│ │ │ │ ├── test_defer.py
│ │ │ │ ├── test_defer.py.3only
│ │ │ │ ├── test_defgen.py
│ │ │ │ ├── test_dict.py
│ │ │ │ ├── test_dirdbm.py
│ │ │ │ ├── test_error.py
│ │ │ │ ├── test_factories.py
│ │ │ │ ├── test_failure.py
│ │ │ │ ├── test_fdesc.py
│ │ │ │ ├── test_finger.py
│ │ │ │ ├── test_formmethod.py
│ │ │ │ ├── test_ftp.py
│ │ │ │ ├── test_ftp_options.py
│ │ │ │ ├── test_htb.py
│ │ │ │ ├── test_ident.py
│ │ │ │ ├── test_internet.py
│ │ │ │ ├── test_iosim.py
│ │ │ │ ├── test_iutils.py
│ │ │ │ ├── test_lockfile.py
│ │ │ │ ├── test_log.py
│ │ │ │ ├── test_logfile.py
│ │ │ │ ├── test_loopback.py
│ │ │ │ ├── test_main.py
│ │ │ │ ├── test_memcache.py
│ │ │ │ ├── test_modules.py
│ │ │ │ ├── test_monkey.py
│ │ │ │ ├── test_nooldstyle.py
│ │ │ │ ├── test_paths.py
│ │ │ │ ├── test_pcp.py
│ │ │ │ ├── test_persisted.py
│ │ │ │ ├── test_plugin.py
│ │ │ │ ├── test_policies.py
│ │ │ │ ├── test_postfix.py
│ │ │ │ ├── test_process.py
│ │ │ │ ├── test_protocols.py
│ │ │ │ ├── test_randbytes.py
│ │ │ │ ├── test_rebuild.py
│ │ │ │ ├── test_reflect.py
│ │ │ │ ├── test_roots.py
│ │ │ │ ├── test_shortcut.py
│ │ │ │ ├── test_sip.py
│ │ │ │ ├── test_sob.py
│ │ │ │ ├── test_socks.py
│ │ │ │ ├── test_ssl.py
│ │ │ │ ├── test_sslverify.py
│ │ │ │ ├── test_stateful.py
│ │ │ │ ├── test_stdio.py
│ │ │ │ ├── test_strerror.py
│ │ │ │ ├── test_strports.py
│ │ │ │ ├── test_task.py
│ │ │ │ ├── test_tcp.py
│ │ │ │ ├── test_tcp_internals.py
│ │ │ │ ├── test_text.py
│ │ │ │ ├── test_threadable.py
│ │ │ │ ├── test_threadpool.py
│ │ │ │ ├── test_threads.py
│ │ │ │ ├── test_tpfile.py
│ │ │ │ ├── test_twistd.py
│ │ │ │ ├── test_twisted.py
│ │ │ │ ├── test_udp.py
│ │ │ │ ├── test_unix.py
│ │ │ │ ├── test_usage.py
│ │ │ │ └── testutils.py
│ │ │ ├── trial/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ ├── _asyncrunner.py
│ │ │ │ ├── _asynctest.py
│ │ │ │ ├── _dist/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── distreporter.py
│ │ │ │ │ ├── disttrial.py
│ │ │ │ │ ├── managercommands.py
│ │ │ │ │ ├── options.py
│ │ │ │ │ ├── test/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── test_distreporter.py
│ │ │ │ │ │ ├── test_disttrial.py
│ │ │ │ │ │ ├── test_options.py
│ │ │ │ │ │ ├── test_worker.py
│ │ │ │ │ │ ├── test_workerreporter.py
│ │ │ │ │ │ └── test_workertrial.py
│ │ │ │ │ ├── worker.py
│ │ │ │ │ ├── workercommands.py
│ │ │ │ │ ├── workerreporter.py
│ │ │ │ │ └── workertrial.py
│ │ │ │ ├── _synctest.py
│ │ │ │ ├── itrial.py
│ │ │ │ ├── reporter.py
│ │ │ │ ├── runner.py
│ │ │ │ ├── test/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── detests.py
│ │ │ │ │ ├── erroneous.py
│ │ │ │ │ ├── mockcustomsuite.py
│ │ │ │ │ ├── mockcustomsuite2.py
│ │ │ │ │ ├── mockcustomsuite3.py
│ │ │ │ │ ├── mockdoctest.py
│ │ │ │ │ ├── moduleself.py
│ │ │ │ │ ├── moduletest.py
│ │ │ │ │ ├── novars.py
│ │ │ │ │ ├── ordertests.py
│ │ │ │ │ ├── packages.py
│ │ │ │ │ ├── sample.py
│ │ │ │ │ ├── scripttest.py
│ │ │ │ │ ├── skipping.py
│ │ │ │ │ ├── suppression.py
│ │ │ │ │ ├── test_assertions.py
│ │ │ │ │ ├── test_asyncassertions.py
│ │ │ │ │ ├── test_deferred.py
│ │ │ │ │ ├── test_doctest.py
│ │ │ │ │ ├── test_keyboard.py
│ │ │ │ │ ├── test_loader.py
│ │ │ │ │ ├── test_log.py
│ │ │ │ │ ├── test_output.py
│ │ │ │ │ ├── test_plugins.py
│ │ │ │ │ ├── test_pyunitcompat.py
│ │ │ │ │ ├── test_reporter.py
│ │ │ │ │ ├── test_runner.py
│ │ │ │ │ ├── test_script.py
│ │ │ │ │ ├── test_suppression.py
│ │ │ │ │ ├── test_testcase.py
│ │ │ │ │ ├── test_tests.py
│ │ │ │ │ ├── test_util.py
│ │ │ │ │ ├── test_warning.py
│ │ │ │ │ └── weird.py
│ │ │ │ ├── unittest.py
│ │ │ │ └── util.py
│ │ │ ├── web/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _auth/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── basic.py
│ │ │ │ │ ├── digest.py
│ │ │ │ │ └── wrapper.py
│ │ │ │ ├── _element.py
│ │ │ │ ├── _flatten.py
│ │ │ │ ├── _http2.py
│ │ │ │ ├── _newclient.py
│ │ │ │ ├── _responses.py
│ │ │ │ ├── _stan.py
│ │ │ │ ├── client.py
│ │ │ │ ├── demo.py
│ │ │ │ ├── distrib.py
│ │ │ │ ├── domhelpers.py
│ │ │ │ ├── error.py
│ │ │ │ ├── guard.py
│ │ │ │ ├── html.py
│ │ │ │ ├── http.py
│ │ │ │ ├── http_headers.py
│ │ │ │ ├── iweb.py
│ │ │ │ ├── microdom.py
│ │ │ │ ├── proxy.py
│ │ │ │ ├── resource.py
│ │ │ │ ├── rewrite.py
│ │ │ │ ├── script.py
│ │ │ │ ├── server.py
│ │ │ │ ├── static.py
│ │ │ │ ├── sux.py
│ │ │ │ ├── tap.py
│ │ │ │ ├── template.py
│ │ │ │ ├── test/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── _util.py
│ │ │ │ │ ├── injectionhelpers.py
│ │ │ │ │ ├── requesthelper.py
│ │ │ │ │ ├── test_agent.py
│ │ │ │ │ ├── test_cgi.py
│ │ │ │ │ ├── test_client.py
│ │ │ │ │ ├── test_distrib.py
│ │ │ │ │ ├── test_domhelpers.py
│ │ │ │ │ ├── test_error.py
│ │ │ │ │ ├── test_flatten.py
│ │ │ │ │ ├── test_html.py
│ │ │ │ │ ├── test_http.py
│ │ │ │ │ ├── test_http2.py
│ │ │ │ │ ├── test_http_headers.py
│ │ │ │ │ ├── test_httpauth.py
│ │ │ │ │ ├── test_newclient.py
│ │ │ │ │ ├── test_proxy.py
│ │ │ │ │ ├── test_resource.py
│ │ │ │ │ ├── test_script.py
│ │ │ │ │ ├── test_stan.py
│ │ │ │ │ ├── test_static.py
│ │ │ │ │ ├── test_tap.py
│ │ │ │ │ ├── test_template.py
│ │ │ │ │ ├── test_util.py
│ │ │ │ │ ├── test_vhost.py
│ │ │ │ │ ├── test_web.py
│ │ │ │ │ ├── test_web__responses.py
│ │ │ │ │ ├── test_webclient.py
│ │ │ │ │ ├── test_wsgi.py
│ │ │ │ │ ├── test_xml.py
│ │ │ │ │ └── test_xmlrpc.py
│ │ │ │ ├── twcgi.py
│ │ │ │ ├── util.py
│ │ │ │ ├── vhost.py
│ │ │ │ ├── wsgi.py
│ │ │ │ └── xmlrpc.py
│ │ │ └── words/
│ │ │ ├── __init__.py
│ │ │ ├── ewords.py
│ │ │ ├── im/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── baseaccount.py
│ │ │ │ ├── basechat.py
│ │ │ │ ├── basesupport.py
│ │ │ │ ├── instancemessenger.glade
│ │ │ │ ├── interfaces.py
│ │ │ │ ├── ircsupport.py
│ │ │ │ ├── locals.py
│ │ │ │ └── pbsupport.py
│ │ │ ├── iwords.py
│ │ │ ├── protocols/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── irc.py
│ │ │ │ └── jabber/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── client.py
│ │ │ │ ├── component.py
│ │ │ │ ├── error.py
│ │ │ │ ├── ijabber.py
│ │ │ │ ├── jid.py
│ │ │ │ ├── jstrports.py
│ │ │ │ ├── sasl.py
│ │ │ │ ├── sasl_mechanisms.py
│ │ │ │ ├── xmlstream.py
│ │ │ │ └── xmpp_stringprep.py
│ │ │ ├── service.py
│ │ │ ├── tap.py
│ │ │ ├── test/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_basechat.py
│ │ │ │ ├── test_basesupport.py
│ │ │ │ ├── test_domish.py
│ │ │ │ ├── test_irc.py
│ │ │ │ ├── test_irc_service.py
│ │ │ │ ├── test_ircsupport.py
│ │ │ │ ├── test_jabberclient.py
│ │ │ │ ├── test_jabbercomponent.py
│ │ │ │ ├── test_jabbererror.py
│ │ │ │ ├── test_jabberjid.py
│ │ │ │ ├── test_jabberjstrports.py
│ │ │ │ ├── test_jabbersasl.py
│ │ │ │ ├── test_jabbersaslmechanisms.py
│ │ │ │ ├── test_jabberxmlstream.py
│ │ │ │ ├── test_jabberxmppstringprep.py
│ │ │ │ ├── test_service.py
│ │ │ │ ├── test_tap.py
│ │ │ │ ├── test_xishutil.py
│ │ │ │ ├── test_xmlstream.py
│ │ │ │ ├── test_xmpproutertap.py
│ │ │ │ └── test_xpath.py
│ │ │ ├── xish/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── domish.py
│ │ │ │ ├── utility.py
│ │ │ │ ├── xmlstream.py
│ │ │ │ ├── xpath.py
│ │ │ │ ├── xpathparser.g
│ │ │ │ └── xpathparser.py
│ │ │ └── xmpproutertap.py
│ │ ├── w3lib/
│ │ │ ├── __init__.py
│ │ │ ├── encoding.py
│ │ │ ├── form.py
│ │ │ ├── html.py
│ │ │ ├── http.py
│ │ │ ├── url.py
│ │ │ └── util.py
│ │ ├── w3lib-1.21.0.dist-info/
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── WHEEL
│ │ │ └── top_level.txt
│ │ ├── zope/
│ │ │ └── interface/
│ │ │ ├── __init__.py
│ │ │ ├── _compat.py
│ │ │ ├── _flatten.py
│ │ │ ├── _zope_interface_coptimizations.c
│ │ │ ├── adapter.py
│ │ │ ├── advice.py
│ │ │ ├── common/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── idatetime.py
│ │ │ │ ├── interfaces.py
│ │ │ │ ├── mapping.py
│ │ │ │ ├── sequence.py
│ │ │ │ └── tests/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── basemapping.py
│ │ │ │ ├── test_idatetime.py
│ │ │ │ └── test_import_interfaces.py
│ │ │ ├── declarations.py
│ │ │ ├── document.py
│ │ │ ├── exceptions.py
│ │ │ ├── interface.py
│ │ │ ├── interfaces.py
│ │ │ ├── registry.py
│ │ │ ├── ro.py
│ │ │ ├── tests/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── advisory_testing.py
│ │ │ │ ├── dummy.py
│ │ │ │ ├── idummy.py
│ │ │ │ ├── ifoo.py
│ │ │ │ ├── ifoo_other.py
│ │ │ │ ├── m1.py
│ │ │ │ ├── m2.py
│ │ │ │ ├── odd.py
│ │ │ │ ├── test_adapter.py
│ │ │ │ ├── test_advice.py
│ │ │ │ ├── test_declarations.py
│ │ │ │ ├── test_document.py
│ │ │ │ ├── test_element.py
│ │ │ │ ├── test_exceptions.py
│ │ │ │ ├── test_interface.py
│ │ │ │ ├── test_interfaces.py
│ │ │ │ ├── test_odd_declarations.py
│ │ │ │ ├── test_registry.py
│ │ │ │ ├── test_ro.py
│ │ │ │ ├── test_sorting.py
│ │ │ │ └── test_verify.py
│ │ │ └── verify.py
│ │ ├── zope.interface-4.6.0-py3.6-nspkg.pth
│ │ └── zope.interface-4.6.0.dist-info/
│ │ ├── INSTALLER
│ │ ├── LICENSE.txt
│ │ ├── METADATA
│ │ ├── RECORD
│ │ ├── WHEEL
│ │ ├── namespace_packages.txt
│ │ └── top_level.txt
│ └── pyvenv.cfg
├── wechat_moment.py
└── wechat_public_account.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
*.js linguist-language=python
*.css linguist-language=python
*.html linguist-language=python
================================================
FILE: CloudCreat
================================================
# coding: utf-8
from wordcloud import WordCloud
import cv2
import jieba
import matplotlib.pyplot as plt
with open('test.txt', 'r') as f:
text = f.read()
cut_text = " ".join(jieba.cut(text))
color_mask = cv2.imread('back.jpeg')
cloud = WordCloud(
# 设置字体,不指定就会出现乱码
font_path="/Users/caichenyang/Desktop/爬虫尝试/Baoli.ttc",
# font_path=path.join(d,'simsun.ttc'),
# 设置背景色
background_color='white',
# 词云形状
mask=color_mask,
# 允许最大词汇
max_words=120,
# 最大号字体
max_font_size=2000
)
wCloud = cloud.generate(cut_text)
wCloud.to_file('cloud.jpg')
plt.imshow(wCloud, interpolation='bilinear')
plt.axis('off')
plt.show()
================================================
FILE: GaoKao_Score/2006-2016浙江高考录取分数线.html
================================================
.*?
.*?class="star">.*?class="tuijian">(.*?).*?class="publisher_info">.*?target="_blank">(.*?).*?class="biaosheng">.*?(.*?).*?(.*?).*?', re.S)
items = re.findall(pattern, html)
for item in items:
yield {
'range': item[0],
'image': item[1],
'title': item[2],
'recommend': item[3],
'author': item[4],
'times': item[5],
'price': item[6]
}
def write_item_to_file(item):
print('开始写入数据 ====> ' + str(item))
with open('book.txt', 'a', encoding='UTF-8') as f:
f.write(json.dumps(item, ensure_ascii=False) + '\n')
def main(page):
url = 'http://bang.dangdang.com/books/fivestars/01.00.00.00.00.00-recent30-0-0-1-' + str(page)
html = request_dandan(url)
items = parse_result(html) # 解析过滤我们想要的信息
for item in items:
write_item_to_file(item)
if __name__ == "__main__":
for i in range(1, 26):
main(i)
================================================
FILE: douban_top_250_books.py
================================================
import requests
from bs4 import BeautifulSoup
import xlwt
def request_douban(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/88.0.4324.146 Safari/537.36',
}
try:
response = requests.get(url=url, headers=headers)
if response.status_code == 200:
return response.text
except requests.RequestException:
return None
book = xlwt.Workbook(encoding='utf-8', style_compression=0)
sheet = book.add_sheet('豆瓣电影Top250', cell_overwrite_ok=True)
sheet.write(0, 0, '名称')
sheet.write(0, 1, '图片')
sheet.write(0, 2, '排名')
sheet.write(0, 3, '评分')
sheet.write(0, 4, '作者')
sheet.write(0, 5, '简介')
n = 1
def save_to_excel(soup):
list = soup.find(class_='grid_view').find_all('li')
for item in list:
item_name = item.find(class_='title').string
item_img = item.find('a').find('img').get('src')
item_index = item.find(class_='').string
item_score = item.find(class_='rating_num').string
item_author = item.find('p').text
if item.find(class_='inq') is not None:
item_intr = item.find(class_='inq').string
else:
item_intr = 'NOT AVAILABLE'
# print('爬取电影:' + item_index + ' | ' + item_name +' | ' + item_img +' | ' + item_score +' | ' + item_author +' | ' + item_intr )
print('爬取电影:' + item_index + ' | ' + item_name + ' | ' + item_score + ' | ' + item_intr)
global n
sheet.write(n, 0, item_name)
sheet.write(n, 1, item_img)
sheet.write(n, 2, item_index)
sheet.write(n, 3, item_score)
sheet.write(n, 4, item_author)
sheet.write(n, 5, item_intr)
n = n + 1
def main(page):
url = 'https://movie.douban.com/top250?start=' + str(page * 25) + '&filter='
html = request_douban(url)
soup = BeautifulSoup(html, 'lxml')
save_to_excel(soup)
if __name__ == '__main__':
for i in range(0, 10):
main(i)
book.save(u'豆瓣最受欢迎的250部电影.xlsx')
================================================
FILE: douban_top_250_books_mul_process.py
================================================
import requests
from bs4 import BeautifulSoup
import xlwt
import multiprocessing
import time
import sys
def request_douban(url):
try:
response = requests.get(url,headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'})
if response.status_code == 200:
return response.text
except requests.RequestException:
return None
def main(url):
sys.setrecursionlimit(1000000)
data = []
html = request_douban(url)
# soup = BeautifulSoup(html, 'lxml')
soup = BeautifulSoup(html, 'html.parser')
list = soup.find(class_='grid_view').find_all('li')
for item in list:
item_name = item.find(class_='title').string
item_img = item.find('a').find('img').get('src')
item_index = item.find(class_='').string
item_score = item.find(class_='rating_num').string
item_author = item.find('p').text
item_intr = ''
if (item.find(class_='inq') != None):
item_intr = item.find(class_='inq').string
print('爬取电影:' + item_index + ' | ' + item_name + ' | ' + item_score + ' | ' + item_intr)
item = {
'item_index': item_index,
'item_name': item_name,
'item_score': item_score,
'item_intr': item_intr,
'item_img': item_img,
'item_author': item_author
}
data.append(item)
return data
if __name__ == '__main__':
startTime = time.time()
data = []
urls = []
pool = multiprocessing.Pool(multiprocessing.cpu_count()-1)
for i in range(0, 10):
url = 'https://movie.douban.com/top250?start=' + str(i * 25) + '&filter='
urls.append(url)
pool.map(main, urls)
for pageItem in pool.map(main, urls):
data.extend(pageItem)
book = xlwt.Workbook(encoding='utf-8', style_compression=0)
sheet = book.add_sheet('豆瓣电影Top250-test', cell_overwrite_ok=True)
sheet.write(0, 0, '名称')
sheet.write(0, 1, '图片')
sheet.write(0, 2, '排名')
sheet.write(0, 3, '评分')
sheet.write(0, 4, '作者')
sheet.write(0, 5, '简介')
for index,item in enumerate(data):
sheet.write(index+1, 0, item['item_name'])
sheet.write(index+1, 1, item['item_img'])
sheet.write(index+1, 2, item['item_index'])
sheet.write(index+1, 3, item['item_score'])
sheet.write(index+1, 4, item['item_author'])
sheet.write(index+1, 5, item['item_intr'])
book.save(u'豆瓣最受欢迎的250部电影-mul.xlsx')
endTime = time.time()
dtime = endTime - startTime
print("程序运行时间:%s s" % dtime) # 4.036666631698608 s
================================================
FILE: fuck_bilibili_captcha.py
================================================
import time
import requests
from PIL import Image
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup
import re
from io import BytesIO
driver = webdriver.Chrome('/usr/lib/chromium-browser/chromedriver')
WAIT = WebDriverWait(driver, 10)
url = 'https://passport.bilibili.com/login'
def mergy_Image(image_file, location_list):
"""
将原始图片进行合成
:param image_file: 图片文件
:param location_list: 图片位置
:return: 合成新的图片
"""
# 存放上下部分的各个小块
upper_half_list = []
down_half_list = []
image = Image.open(image_file)
# 通过 y 的位置来判断是上半部分还是下半部分,然后切割
for location in location_list:
if location['y'] == -58:
# 间距为10,y:58-116
im = image.crop((abs(location['x']), 58, abs(location['x'])+10, 116))
upper_half_list.append(im)
if location['y'] == 0:
# 间距为10,y:0-58
im = image.crop((abs(location['x']), 0, abs(location['x']) + 10, 58))
down_half_list.append(im)
# 创建一张大小一样的图片
new_image = Image.new('RGB', (260, 116))
# 粘贴好上半部分 y坐标是从上到下(0-116)
offset = 0
for im in upper_half_list:
new_image.paste(im, (offset, 0))
offset += 10
# 粘贴好下半部分
offset = 0
for im in down_half_list:
new_image.paste(im, (offset, 58))
offset += 10
return new_image
def get_distance(bg_Image, fullbg_Image):
# 阈值
threshold = 200
print(bg_Image.size[0])
print(bg_Image.size[1])
for i in range(60, bg_Image.size[0]):
for j in range(bg_Image.size[1]):
bg_pix = bg_Image.getpixel((i, j))
fullbg_pix = fullbg_Image.getpixel((i, j))
r = abs(bg_pix[0] - fullbg_pix[0])
g = abs(bg_pix[1] - fullbg_pix[1])
b = abs(bg_pix[2] - fullbg_pix[2])
if r + g + b > threshold:
return i
def get_path(distance):
result = []
current = 0
mid = distance * 4 / 5
t = 0.2
v = 0
while current < (distance - 10):
if current < mid:
a = 2
else:
a = -3
v0 = v
v = v0 + a * t
s = v0 * t + 0.5 * a * t * t
current += s
result.append(round(s))
return result
def start_drag(driver, distance):
# 被妖怪吃掉了
# knob = WAIT.until(EC.presence_of_element_located((By.CSS_SELECTOR, "#gc-box > div > div.gt_slider > div.gt_slider_knob.gt_show")))
# ActionChains(driver).click_and_hold(knob).perform()
# ActionChains(driver).move_by_offset(xoffset=distance, yoffset=0.1).perform()
# time.sleep(0.5)
# ActionChains(driver).release(knob).perform()
# 被妖怪吃掉了
# ActionChains(driver).drag_and_drop_by_offset(knob, distance-10, 0).perform()
knob = WAIT.until(EC.presence_of_element_located((By.CSS_SELECTOR, "#gc-box > div > div.gt_slider > div.gt_slider_knob.gt_show")))
result = get_path(distance)
ActionChains(driver).click_and_hold(knob).perform()
for x in result:
ActionChains(driver).move_by_offset(xoffset=x, yoffset=0).perform()
time.sleep(0.5)
ActionChains(driver).release(knob).perform()
def recognize_code(driver):
"""
识别滑动验证码
:param driver: selenium驱动
:return:
"""
bs = BeautifulSoup(driver.page_source,'lxml')
# 找到背景图片和缺口图片的div
bg_div = bs.find_all(class_='gt_cut_bg_slice')
fullbg_div = bs.find_all(class_='gt_cut_fullbg_slice')
# 获取缺口背景图片url
bg_url = re.findall('background-image:\surl\("(.*?)"\)',bg_div[0].get('style'))
# 获取背景图片url
fullbg_url = re.findall('background-image:\surl\("(.*?)"\)',fullbg_div[0].get('style'))
# 存放每个合成缺口背景图片的位置
bg_location_list = []
# 存放每个合成背景图片的位置
fullbg_location_list = []
for bg in bg_div:
location = {}
location['x'] = int(re.findall('background-position:\s(.*?)px\s(.*?)px;', bg.get('style'))[0][0])
location['y'] = int(re.findall('background-position:\s(.*?)px\s(.*?)px;', bg.get('style'))[0][1])
bg_location_list.append(location)
for fullbg in fullbg_div:
location = {}
location['x'] = int(re.findall('background-position:\s(.*?)px\s(.*?)px;', fullbg.get('style'))[0][0])
location['y'] = int(re.findall('background-position:\s(.*?)px\s(.*?)px;', fullbg.get('style'))[0][1])
fullbg_location_list.append(location)
print(bg_location_list)
print(fullbg_location_list)
# 将图片格式存为 jpg 格式
bg_url = bg_url[0].replace('webp', 'jpg')
fullbg_url = fullbg_url[0].replace('webp', 'jpg')
# print(bg_url)
# print(fullbg_url)
# 下载图片
bg_image = requests.get(bg_url).content
fullbg_image = requests.get(fullbg_url).content
print('完成图片下载')
# 写入图片
bg_image_file = BytesIO(bg_image)
fullbg_image_file = BytesIO(fullbg_image)
# 合成图片
bg_Image = mergy_Image(bg_image_file, bg_location_list)
fullbg_Image = mergy_Image(fullbg_image_file, fullbg_location_list)
# bg_Image.show()
# fullbg_Image.show()
# 计算缺口偏移距离
distance = get_distance(bg_Image, fullbg_Image)
print('得到距离:%s' % str(distance))
start_drag(driver, distance)
if __name__ == '__main__':
# 获取滑块按钮
driver.get(url)
slider = WAIT.until(EC.element_to_be_clickable(
(By.CSS_SELECTOR, "#gc-box > div > div.gt_slider > div.gt_slider_knob.gt_show")))
recognize_code(driver)
# driver.close()
================================================
FILE: ikun_basketball.py
================================================
# coding=utf-8
# 最新版的selenium(4.x.x)已经不支持PhantomJS。如要用PhantomJS,可用旧版本selenium。如pip install selenium==3.8.0。
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup
import xlwt
# browser = webdriver.PhantomJS()
browser = webdriver.Chrome()
WAIT = WebDriverWait(browser, 10)
browser.set_window_size(1400, 900)
book = xlwt.Workbook(encoding='utf-8', style_compression=0)
sheet = book.add_sheet('蔡徐坤篮球', cell_overwrite_ok=True)
sheet.write(0, 0, '名称')
sheet.write(0, 1, '地址')
sheet.write(0, 2, '描述')
sheet.write(0, 3, '观看次数')
sheet.write(0, 4, '弹幕数')
sheet.write(0, 5, '发布时间')
n = 1
def search():
try:
print('开始访问b站....')
browser.get("https://www.bilibili.com/")
# 被那个破登录遮住了
# index = WAIT.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#primary_menu > ul > li.home > a")))
# index.click()
input = WAIT.until(EC.presence_of_element_located((By.CSS_SELECTOR, "#nav_searchform > input")))
submit = WAIT.until(EC.element_to_be_clickable(
(By.XPATH, '/html/body/div[2]/div/div[1]/div[1]/div/div[2]/div/form/div/button')))
input.send_keys('蔡徐坤 篮球')
submit.click()
# 跳转到新的窗口
print('跳转到新窗口')
all_h = browser.window_handles
browser.switch_to.window(all_h[1])
get_source()
total = WAIT.until(EC.presence_of_element_located((By.CSS_SELECTOR,
"#all-list > div.flow-loader > div.page-wrap > div > ul > li.page-item.last > button")))
return int(total.text)
except TimeoutException:
return search()
def next_page(page_num):
try:
print('获取下一页数据')
next_btn = WAIT.until(EC.element_to_be_clickable((By.CSS_SELECTOR,
'#all-list > div.flow-loader > div.page-wrap > div > ul > li.page-item.next > button')))
next_btn.click()
WAIT.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR,
'#all-list > div.flow-loader > div.page-wrap > div > ul > li.page-item.active > button'),
str(page_num)))
get_source()
except TimeoutException:
browser.refresh()
return next_page(page_num)
def save_to_excel(soup):
list = soup.find(class_='video-list clearfix').find_all(class_='video-item matrix')
for item in list:
item_title = item.find('a').get('title')
item_link = item.find('a').get('href')
item_dec = item.find(class_='des hide').text
item_view = item.find(class_='so-icon watch-num').text
item_biubiu = item.find(class_='so-icon hide').text
item_date = item.find(class_='so-icon time').text
print('爬取:' + item_title)
global n
sheet.write(n, 0, item_title)
sheet.write(n, 1, item_link)
sheet.write(n, 2, item_dec)
sheet.write(n, 3, item_view)
sheet.write(n, 4, item_biubiu)
sheet.write(n, 5, item_date)
n = n + 1
def get_source():
WAIT.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, '#all-list > div.flow-loader > div.filter-wrap')))
html = browser.page_source
soup = BeautifulSoup(html, 'lxml')
print('到这')
save_to_excel(soup)
def main():
try:
total = search()
print(total)
for i in range(2, int(total + 1)):
next_page(i)
finally:
browser.close()
if __name__ == '__main__':
main()
book.save('蔡徐坤篮球.xlsx')
================================================
FILE: meizitu.py
================================================
# encoding = utf-8
import concurrent
import os
from concurrent.futures import ThreadPoolExecutor
import requests
from bs4 import BeautifulSoup
def header(referer):
headers = {
'Host': 'i.meizitu.net',
'Pragma': 'no-cache',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36',
'Accept': 'image/webp,image/apng,image/*,*/*;q=0.8',
'Referer': '{}'.format(referer),
}
return headers
def request_page(url):
try:
response = requests.get(url)
if response.status_code == 200:
return response.text
except requests.RequestException:
return None
def get_page_urls():
for i in range(1, 2):
baseurl = 'https://www.mzitu.com/page/{}'.format(i)
html = request_page(baseurl)
soup = BeautifulSoup(html, 'lxml')
elements = soup.find(class_='postlist').find_all('li')
urls = []
for item in elements:
url = item.find('span').find('a').get('href')
print('页面链接:%s' % url)
urls.append(url)
return urls
def download_Pic(title, image_list):
# 新建文件夹
os.mkdir(title)
j = 1
# 下载图片
for item in image_list:
filename = '%s/%s.jpg' % (title, str(j))
print('downloading....%s : NO.%s' % (title, str(j)))
with open(filename, 'wb') as f:
img = requests.get(item, headers=header(item)).content
f.write(img)
j += 1
def download(url):
html = request_page(url)
soup = BeautifulSoup(html, 'lxml')
total = soup.find(class_='pagenavi').find_all('a')[-2].find('span').string
title = soup.find('h2').string
image_list = []
for i in range(int(total)):
html = request_page(url + '/%s' % (i + 1))
soup = BeautifulSoup(html, 'lxml')
img_url = soup.find('img').get('src')
image_list.append(img_url)
download_Pic(title, image_list)
def download_all_images(list_page_urls):
# 获取每一个详情妹纸
# works = len(list_page_urls)
with concurrent.futures.ProcessPoolExecutor(max_workers=5) as exector:
for url in list_page_urls:
exector.submit(download, url)
if __name__ == '__main__':
# 获取每一页的链接和名称
list_page_urls = get_page_urls()
download_all_images(list_page_urls)
================================================
FILE: qiushibaike/qiushibaike/__init__.py
================================================
================================================
FILE: qiushibaike/qiushibaike/items.py
================================================
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class QiushibaikeItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
author = scrapy.Field()
content = scrapy.Field()
_id = scrapy.Field()
================================================
FILE: qiushibaike/qiushibaike/middlewares.py
================================================
# -*- coding: utf-8 -*-
# Define here the models for your spider middleware
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/spider-middleware.html
from scrapy import signals
class QiushibaikeSpiderMiddleware(object):
# Not all methods need to be defined. If a method is not defined,
# scrapy acts as if the spider middleware does not modify the
# passed objects.
@classmethod
def from_crawler(cls, crawler):
# This method is used by Scrapy to create your spiders.
s = cls()
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
return s
def process_spider_input(self, response, spider):
# Called for each response that goes through the spider
# middleware and into the spider.
# Should return None or raise an exception.
return None
def process_spider_output(self, response, result, spider):
# Called with the results returned from the Spider, after
# it has processed the response.
# Must return an iterable of Request, dict or Item objects.
for i in result:
yield i
def process_spider_exception(self, response, exception, spider):
# Called when a spider or process_spider_input() method
# (from other spider middleware) raises an exception.
# Should return either None or an iterable of Response, dict
# or Item objects.
pass
def process_start_requests(self, start_requests, spider):
# Called with the start requests of the spider, and works
# similarly to the process_spider_output() method, except
# that it doesn’t have a response associated.
# Must return only requests (not items).
for r in start_requests:
yield r
def spider_opened(self, spider):
spider.logger.info('Spider opened: %s' % spider.name)
class QiushibaikeDownloaderMiddleware(object):
# Not all methods need to be defined. If a method is not defined,
# scrapy acts as if the downloader middleware does not modify the
# passed objects.
@classmethod
def from_crawler(cls, crawler):
# This method is used by Scrapy to create your spiders.
s = cls()
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
return s
def process_request(self, request, spider):
# Called for each request that goes through the downloader
# middleware.
# Must either:
# - return None: continue processing this request
# - or return a Response object
# - or return a Request object
# - or raise IgnoreRequest: process_exception() methods of
# installed downloader middleware will be called
return None
def process_response(self, request, response, spider):
# Called with the response returned from the downloader.
# Must either;
# - return a Response object
# - return a Request object
# - or raise IgnoreRequest
return response
def process_exception(self, request, exception, spider):
# Called when a download handler or a process_request()
# (from other downloader middleware) raises an exception.
# Must either:
# - return None: continue processing this exception
# - return a Response object: stops process_exception() chain
# - return a Request object: stops process_exception() chain
pass
def spider_opened(self, spider):
spider.logger.info('Spider opened: %s' % spider.name)
================================================
FILE: qiushibaike/qiushibaike/pipelines.py
================================================
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
import pymongo
class QiushibaikePipeline(object):
def __init__(self):
self.connection = pymongo.MongoClient('localhost', 27017)
self.db = self.connection.scrapy
self.collection = self.db.qiushibaike
def process_item(self, item, spider):
if not self.connection or not item:
return
self.collection.save(item)
def __del__(self):
if self.connection:
self.connection.close()
================================================
FILE: qiushibaike/qiushibaike/settings.py
================================================
# -*- coding: utf-8 -*-
# Scrapy settings for qiushibaike project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
# https://doc.scrapy.org/en/latest/topics/settings.html
# https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
# https://doc.scrapy.org/en/latest/topics/spider-middleware.html
BOT_NAME = 'qiushibaike'
SPIDER_MODULES = ['qiushibaike.spiders']
NEWSPIDER_MODULE = 'qiushibaike.spiders'
FEED_EXPORT_ENCODING = 'utf-8'
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/73.0.3683.86 Chrome/73.0.3683.86 Safari/537.36'
# Obey robots.txt rules
ROBOTSTXT_OBEY = True
# Configure maximum concurrent requests performed by Scrapy (default: 16)
#CONCURRENT_REQUESTS = 32
# Configure a delay for requests for the same website (default: 0)
# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
#DOWNLOAD_DELAY = 3
# The download delay setting will honor only one of:
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#CONCURRENT_REQUESTS_PER_IP = 16
# Disable cookies (enabled by default)
#COOKIES_ENABLED = False
# Disable Telnet Console (enabled by default)
#TELNETCONSOLE_ENABLED = False
# Override the default request headers:
#DEFAULT_REQUEST_HEADERS = {
# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
# 'Accept-Language': 'en',
#}
# Enable or disable spider middlewares
# See https://doc.scrapy.org/en/latest/topics/spider-middleware.html
#SPIDER_MIDDLEWARES = {
# 'qiushibaike.middlewares.QiushibaikeSpiderMiddleware': 543,
#}
# Enable or disable downloader middlewares
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
#DOWNLOADER_MIDDLEWARES = {
# 'qiushibaike.middlewares.QiushibaikeDownloaderMiddleware': 543,
#}
# Enable or disable extensions
# See https://doc.scrapy.org/en/latest/topics/extensions.html
#EXTENSIONS = {
# 'scrapy.extensions.telnet.TelnetConsole': None,
#}
# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'qiushibaike.pipelines.QiushibaikePipeline': 300,
}
# Enable and configure the AutoThrottle extension (disabled by default)
# See https://doc.scrapy.org/en/latest/topics/autothrottle.html
#AUTOTHROTTLE_ENABLED = True
# The initial download delay
#AUTOTHROTTLE_START_DELAY = 5
# The maximum download delay to be set in case of high latencies
#AUTOTHROTTLE_MAX_DELAY = 60
# The average number of requests Scrapy should be sending in parallel to
# each remote server
#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# Enable showing throttling stats for every response received:
#AUTOTHROTTLE_DEBUG = False
# Enable and configure HTTP caching (disabled by default)
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
#HTTPCACHE_ENABLED = True
#HTTPCACHE_EXPIRATION_SECS = 0
#HTTPCACHE_DIR = 'httpcache'
#HTTPCACHE_IGNORE_HTTP_CODES = []
#HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
================================================
FILE: qiushibaike/qiushibaike/spiders/__init__.py
================================================
# This package will contain the spiders of your Scrapy project
#
# Please refer to the documentation for information on how to create and manage
# your spiders.
================================================
FILE: qiushibaike/qiushibaike/spiders/qiushibaike_spider.py
================================================
# -*- coding: utf-8 -*-
import random
import scrapy
from qiushibaike.items import QiushibaikeItem
class QiushiSpider(scrapy.Spider):
# 这里定义一个唯一的名称,用来标识糗事的爬虫,在项目中不能和别的爬虫名称一样,等会会用到这个名称
name = "qiushibaike"
def start_requests(self):
urls = [
'https://www.qiushibaike.com/text/page/1/',
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response):
content_left_div = response.xpath('//*[@id="content-left"]')
content_list_div = content_left_div.xpath('./div')
for content_div in content_list_div:
item = QiushibaikeItem()
item['author'] = content_div.xpath('./div/a[2]/h2/text()').get()
item['content'] = content_div.xpath('./a/div/span/text()').getall()
item['_id'] = content_div.attrib['id']
yield item
next_page = response.xpath('//*[@id="content-left"]/ul/li[last()]/a').attrib['href']
if next_page is not None:
yield response.follow(next_page, callback=self.parse)
================================================
FILE: qiushibaike/scrapy.cfg
================================================
# Automatically created by: scrapy startproject
#
# For more information about the [deploy] section see:
# https://scrapyd.readthedocs.io/en/latest/deploy.html
[settings]
default = qiushibaike.settings
[deploy]
#url = http://localhost:6800/
project = qiushibaike
================================================
FILE: stackoverflow/.idea/inspectionProfiles/profiles_settings.xml
================================================
================================================
FILE: stackoverflow/.idea/misc.xml
================================================
================================================
FILE: stackoverflow/.idea/modules.xml
================================================
================================================
FILE: stackoverflow/.idea/stackoverflow.iml
================================================
================================================
FILE: stackoverflow/.idea/vcs.xml
================================================
================================================
FILE: stackoverflow/.idea/workspace.xml
================================================
1571212815240
1571212815240
================================================
FILE: stackoverflow/scrapy.cfg
================================================
# Automatically created by: scrapy startproject
#
# For more information about the [deploy] section see:
# https://scrapyd.readthedocs.io/en/latest/deploy.html
[settings]
default = stackoverflow.settings
[deploy]
#url = http://localhost:6800/
project = stackoverflow
================================================
FILE: stackoverflow/stackoverflow/__init__.py
================================================
================================================
FILE: stackoverflow/stackoverflow/items.py
================================================
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class StackoverflowPythonItem(scrapy.Item):
_id = scrapy.Field()
questions = scrapy.Field()
votes = scrapy.Field()
answers = scrapy.Field()
views = scrapy.Field()
links = scrapy.Field()
================================================
FILE: stackoverflow/stackoverflow/middlewares/StackoverflowDownloaderMiddleware.py
================================================
from scrapy.downloadermiddlewares.httpproxy import HttpProxyMiddleware
class HttpProxy(HttpProxyMiddleware):
@staticmethod
def proxy_shadowsocks():
proxy = "http://127.0.0.1:1080"
return proxy
================================================
FILE: stackoverflow/stackoverflow/middlewares/__init__.py
================================================
================================================
FILE: stackoverflow/stackoverflow/middlewares.py
================================================
# -*- coding: utf-8 -*-
# Define here the models for your spider middleware
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/spider-middleware.html
from scrapy import signals
class StackoverflowSpiderMiddleware(object):
# Not all methods need to be defined. If a method is not defined,
# scrapy acts as if the spider middleware does not modify the
# passed objects.
@classmethod
def from_crawler(cls, crawler):
# This method is used by Scrapy to create your spiders.
s = cls()
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
return s
def process_spider_input(self, response, spider):
# Called for each response that goes through the spider
# middleware and into the spider.
# Should return None or raise an exception.
return None
def process_spider_output(self, response, result, spider):
# Called with the results returned from the Spider, after
# it has processed the response.
# Must return an iterable of Request, dict or Item objects.
for i in result:
yield i
def process_spider_exception(self, response, exception, spider):
# Called when a spider or process_spider_input() method
# (from other spider middleware) raises an exception.
# Should return either None or an iterable of Response, dict
# or Item objects.
pass
def process_start_requests(self, start_requests, spider):
# Called with the start requests of the spider, and works
# similarly to the process_spider_output() method, except
# that it doesn’t have a response associated.
# Must return only requests (not items).
for r in start_requests:
yield r
def spider_opened(self, spider):
spider.logger.info('Spider opened: %s' % spider.name)
class StackoverflowDownloaderMiddleware(object):
# Not all methods need to be defined. If a method is not defined,
# scrapy acts as if the downloader middleware does not modify the
# passed objects.
@classmethod
def from_crawler(cls, crawler):
# This method is used by Scrapy to create your spiders.
s = cls()
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
return s
def process_request(self, request, spider):
# Called for each request that goes through the downloader
# middleware.
# Must either:
# - return None: continue processing this request
# - or return a Response object
# - or return a Request object
# - or raise IgnoreRequest: process_exception() methods of
# installed downloader middleware will be called
return None
def process_response(self, request, response, spider):
# Called with the response returned from the downloader.
# Must either;
# - return a Response object
# - return a Request object
# - or raise IgnoreRequest
return response
def process_exception(self, request, exception, spider):
# Called when a download handler or a process_request()
# (from other downloader middleware) raises an exception.
# Must either:
# - return None: continue processing this exception
# - return a Response object: stops process_exception() chain
# - return a Request object: stops process_exception() chain
pass
def spider_opened(self, spider):
spider.logger.info('Spider opened: %s' % spider.name)
================================================
FILE: stackoverflow/stackoverflow/pipelines.py
================================================
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
import pymongo
class StackoverflowPipeline(object):
def __init__(self):
self.connection = pymongo.MongoClient('68.183.180.71', 27017)
self.db = self.connection.scrapy
self.collection = self.db.stackoverflow
def process_item(self, item, spider):
if not self.connection or not item:
return
self.collection.save(item)
def __del__(self):
if self.connection:
self.connection.close()
================================================
FILE: stackoverflow/stackoverflow/requirement.txt
================================================
pymongo==3.9.0
redis==3.3.11
Scrapy==1.7.4
scrapy-redis==0.6.8
lxml==4.4.1
parsel==1.5.2
================================================
FILE: stackoverflow/stackoverflow/settings.py
================================================
# -*- coding: utf-8 -*-
# Scrapy settings for stackoverflow project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
# https://doc.scrapy.org/en/latest/topics/settings.html
# https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
# https://doc.scrapy.org/en/latest/topics/spider-middleware.html
BOT_NAME = 'stackoverflow'
SPIDER_MODULES = ['stackoverflow.spiders']
NEWSPIDER_MODULE = 'stackoverflow.spiders'
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/73.0.3683.86 Chrome/73.0.3683.86 Safari/537.36'
# Obey robots.txt rules
ROBOTSTXT_OBEY = True
# Configure maximum concurrent requests performed by Scrapy (default: 16)
#CONCURRENT_REQUESTS = 32
# Configure a delay for requests for the same website (default: 0)
# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 1
# The download delay setting will honor only one of:
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#CONCURRENT_REQUESTS_PER_IP = 16
# Disable cookies (enabled by default)
#COOKIES_ENABLED = False
# Disable Telnet Console (enabled by default)
#TELNETCONSOLE_ENABLED = False
# Override the default request headers:
#DEFAULT_REQUEST_HEADERS = {
# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
# 'Accept-Language': 'en',
#}
# Enable or disable spider middlewares
# See https://doc.scrapy.org/en/latest/topics/spider-middleware.html
#SPIDER_MIDDLEWARES = {
# 'stackoverflow.middlewares.StackoverflowSpiderMiddleware': 543,
#}
# Enable or disable downloader middlewares
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
'stackoverflow.middlewares.StackoverflowDownloaderMiddleware.HttpProxy': 543,
}
# Enable or disable extensions
# See https://doc.scrapy.org/en/latest/topics/extensions.html
#EXTENSIONS = {
# 'scrapy.extensions.telnet.TelnetConsole': None,
#}
# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'stackoverflow.pipelines.StackoverflowPipeline': 300,
}
# Enable and configure the AutoThrottle extension (disabled by default)
# See https://doc.scrapy.org/en/latest/topics/autothrottle.html
#AUTOTHROTTLE_ENABLED = True
# The initial download delay
#AUTOTHROTTLE_START_DELAY = 5
# The maximum download delay to be set in case of high latencies
#AUTOTHROTTLE_MAX_DELAY = 60
# The average number of requests Scrapy should be sending in parallel to
# each remote server
#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# Enable showing throttling stats for every response received:
#AUTOTHROTTLE_DEBUG = False
# Enable and configure HTTP caching (disabled by default)
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
#HTTPCACHE_ENABLED = True
#HTTPCACHE_EXPIRATION_SECS = 0
#HTTPCACHE_DIR = 'httpcache'
#HTTPCACHE_IGNORE_HTTP_CODES = []
#HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
# 调度器改为 scrapy_redis
SCHEDULER = 'scrapy_redis.scheduler.Scheduler'
# redis 去重
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# redis服务器地址
REDIS_HOST = '68.183.180.0'
REDIS_PORT = 6379
================================================
FILE: stackoverflow/stackoverflow/spiders/__init__.py
================================================
# This package will contain the spiders of your Scrapy project
#
# Please refer to the documentation for information on how to create and manage
# your spiders.
================================================
FILE: stackoverflow/stackoverflow/spiders/stackoverflow-python-spider.py
================================================
import scrapy
from stackoverflow.items import StackoverflowPythonItem
class StackoverflowPythonSpider(scrapy.Spider):
name = "stackoverflow-python"
def start_requests(self):
urls = []
_url = 'https://stackoverflow.com/questions/tagged/python?tab=votes&page={}&pagesize=15'
for page in range(1, 84322):
urls.append(_url.format(page))
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response):
question_list = response.xpath('//*[@id="questions"]')
for question in question_list.xpath('./div'):
item = StackoverflowPythonItem()
item['_id'] = question.attrib['id']
item['questions'] = question.xpath('div[2]/h3/a/text()').extract()
item['votes'] = question.xpath(
'div[1]/div[1]/div[1]/div[1]/span/strong/text()').extract()
item['answers'] = question.xpath(
'div[1]/div[1]/div[2]/strong/text()').extract()
item['views'] = question.xpath('div[1]/div[2]/@title').extract()
item['links'] = question.xpath('div[2]/h3/a/@href').extract()
yield item
================================================
FILE: stackoverflow/venv/bin/activate
================================================
# This file must be used with "source bin/activate" *from bash*
# you cannot run it directly
deactivate () {
# reset old environment variables
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
PATH="${_OLD_VIRTUAL_PATH:-}"
export PATH
unset _OLD_VIRTUAL_PATH
fi
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
export PYTHONHOME
unset _OLD_VIRTUAL_PYTHONHOME
fi
# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
hash -r
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/wistbean/githubproject/learn_python3_spider/stackoverflow/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(venv) " != x ] ; then
PS1="(venv) ${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
# 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
fi
================================================
FILE: stackoverflow/venv/bin/activate.csh
================================================
# This file must be used with "source bin/activate.csh" *from csh*.
# You cannot run it directly.
# Created by Davide Di Blasi .
# Ported to Python 3.3 venv by Andrew Svetlov
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'
# Unset irrelevant variables.
deactivate nondestructive
setenv VIRTUAL_ENV "/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv"
set _OLD_VIRTUAL_PATH="$PATH"
setenv PATH "$VIRTUAL_ENV/bin:$PATH"
set _OLD_VIRTUAL_PROMPT="$prompt"
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
if ("venv" != "") then
set env_name = "venv"
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
set prompt = "[$env_name] $prompt"
unset env_name
endif
alias pydoc python -m pydoc
rehash
================================================
FILE: stackoverflow/venv/bin/activate.fish
================================================
# This file must be used with ". bin/activate.fish" *from fish* (http://fishshell.org)
# 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"
functions -e fish_prompt
set -e _OLD_FISH_PROMPT_OVERRIDE
functions -c _old_fish_prompt fish_prompt
functions -e _old_fish_prompt
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/wistbean/githubproject/learn_python3_spider/stackoverflow/venv"
set -gx _OLD_VIRTUAL_PATH $PATH
set -gx PATH "$VIRTUAL_ENV/bin" $PATH
# unset PYTHONHOME if set
if set -q PYTHONHOME
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
set -e PYTHONHOME
end
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
# fish uses a function instead of an env var to generate the prompt.
# save the current fish_prompt function as the function _old_fish_prompt
functions -c fish_prompt _old_fish_prompt
# with the original prompt function renamed, we can override with our own.
function fish_prompt
# Save the return status of the last command
set -l old_status $status
# Prompt override?
if test -n "(venv) "
printf "%s%s" "(venv) " (set_color normal)
else
# ...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)
else
printf "%s(%s)%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal)
end
end
# Restore the return status of the previous command.
echo "exit $old_status" | .
_old_fish_prompt
end
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
end
================================================
FILE: stackoverflow/venv/bin/automat-visualize
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from automat._visualize import tool
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(tool())
================================================
FILE: stackoverflow/venv/bin/cftp
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from twisted.conch.scripts.cftp import run
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(run())
================================================
FILE: stackoverflow/venv/bin/ckeygen
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from twisted.conch.scripts.ckeygen import run
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(run())
================================================
FILE: stackoverflow/venv/bin/conch
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from twisted.conch.scripts.conch import run
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(run())
================================================
FILE: stackoverflow/venv/bin/easy_install
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'setuptools==40.8.0','console_scripts','easy_install'
__requires__ = 'setuptools==40.8.0'
import re
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(
load_entry_point('setuptools==40.8.0', 'console_scripts', 'easy_install')()
)
================================================
FILE: stackoverflow/venv/bin/easy_install-3.6
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'setuptools==40.8.0','console_scripts','easy_install-3.6'
__requires__ = 'setuptools==40.8.0'
import re
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(
load_entry_point('setuptools==40.8.0', 'console_scripts', 'easy_install-3.6')()
)
================================================
FILE: stackoverflow/venv/bin/mailmail
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from twisted.mail.scripts.mailmail import run
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(run())
================================================
FILE: stackoverflow/venv/bin/pip
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'pip==19.0.3','console_scripts','pip'
__requires__ = 'pip==19.0.3'
import re
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(
load_entry_point('pip==19.0.3', 'console_scripts', 'pip')()
)
================================================
FILE: stackoverflow/venv/bin/pip3
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'pip==19.0.3','console_scripts','pip3'
__requires__ = 'pip==19.0.3'
import re
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(
load_entry_point('pip==19.0.3', 'console_scripts', 'pip3')()
)
================================================
FILE: stackoverflow/venv/bin/pip3.6
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'pip==19.0.3','console_scripts','pip3.6'
__requires__ = 'pip==19.0.3'
import re
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(
load_entry_point('pip==19.0.3', 'console_scripts', 'pip3.6')()
)
================================================
FILE: stackoverflow/venv/bin/pyhtmlizer
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from twisted.scripts.htmlizer import run
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(run())
================================================
FILE: stackoverflow/venv/bin/scrapy
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from scrapy.cmdline import execute
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(execute())
================================================
FILE: stackoverflow/venv/bin/tkconch
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from twisted.conch.scripts.tkconch import run
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(run())
================================================
FILE: stackoverflow/venv/bin/trial
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from twisted.scripts.trial import run
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(run())
================================================
FILE: stackoverflow/venv/bin/twist
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from twisted.application.twist._twist import Twist
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(Twist.main())
================================================
FILE: stackoverflow/venv/bin/twistd
================================================
#!/home/wistbean/githubproject/learn_python3_spider/stackoverflow/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from twisted.scripts.twistd import run
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(run())
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Automat-0.8.0.dist-info/INSTALLER
================================================
pip
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Automat-0.8.0.dist-info/LICENSE
================================================
Copyright (c) 2014
Rackspace
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.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Automat-0.8.0.dist-info/METADATA
================================================
Metadata-Version: 2.1
Name: Automat
Version: 0.8.0
Summary: Self-service finite-state machines for the programmer on the go.
Home-page: https://github.com/glyph/Automat
Author: Glyph
Author-email: glyph@twistedmatrix.com
License: MIT
Keywords: fsm finite state machine automata
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Requires-Dist: attrs (>=16.1.0)
Requires-Dist: six
Provides-Extra: visualize
Requires-Dist: graphviz (>0.5.1) ; extra == 'visualize'
Requires-Dist: Twisted (>=16.1.1) ; extra == 'visualize'
Automat
=======
.. image:: https://readthedocs.org/projects/automat/badge/?version=latest
:target: http://automat.readthedocs.io/en/latest/
:alt: Documentation Status
.. image:: https://travis-ci.org/glyph/automat.svg?branch=master
:target: https://travis-ci.org/glyph/automat
:alt: Build Status
.. image:: https://coveralls.io/repos/glyph/automat/badge.png
:target: https://coveralls.io/r/glyph/automat
:alt: Coverage Status
Self-service finite-state machines for the programmer on the go.
----------------------------------------------------------------
Automat is a library for concise, idiomatic Python expression of finite-state
automata (particularly deterministic finite-state transducers).
Read more here, or on `Read the Docs `_\ , or watch the following videos for an overview and presentation
Overview and presentation by **Glyph Lefkowitz** at the first talk of the first Pyninsula meetup, on February 21st, 2017:
.. image:: https://img.youtube.com/vi/0wOZBpD1VVk/0.jpg
:target: https://www.youtube.com/watch?v=0wOZBpD1VVk
:alt: Glyph Lefkowitz - Automat - Pyninsula #0
Presentation by **Clinton Roy** at PyCon Australia, on August 6th 2017:
.. image:: https://img.youtube.com/vi/TedUKXhu9kE/0.jpg
:target: https://www.youtube.com/watch?v=TedUKXhu9kE
:alt: Clinton Roy - State Machines - Pycon Australia 2017
Why use state machines?
^^^^^^^^^^^^^^^^^^^^^^^
Sometimes you have to create an object whose behavior varies with its state,
but still wishes to present a consistent interface to its callers.
For example, let's say you're writing the software for a coffee machine. It
has a lid that can be opened or closed, a chamber for water, a chamber for
coffee beans, and a button for "brew".
There are a number of possible states for the coffee machine. It might or
might not have water. It might or might not have beans. The lid might be open
or closed. The "brew" button should only actually attempt to brew coffee in
one of these configurations, and the "open lid" button should only work if the
coffee is not, in fact, brewing.
With diligence and attention to detail, you can implement this correctly using
a collection of attributes on an object; ``has_water``\ , ``has_beans``\ ,
``is_lid_open`` and so on. However, you have to keep all these attributes
consistent. As the coffee maker becomes more complex - perhaps you add an
additional chamber for flavorings so you can make hazelnut coffee, for
example - you have to keep adding more and more checks and more and more
reasoning about which combinations of states are allowed.
Rather than adding tedious 'if' checks to every single method to make sure that
each of these flags are exactly what you expect, you can use a state machine to
ensure that if your code runs at all, it will be run with all the required
values initialized, because they have to be called in the order you declare
them.
You can read about state machines and their advantages for Python programmers
in considerably more detail
`in this excellent series of articles from ClusterHQ `_.
What makes Automat different?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
There are
`dozens of libraries on PyPI implementing state machines `_.
So it behooves me to say why yet another one would be a good idea.
Automat is designed around this principle: while organizing your code around
state machines is a good idea, your callers don't, and shouldn't have to, care
that you've done so. In Python, the "input" to a stateful system is a method
call; the "output" may be a method call, if you need to invoke a side effect,
or a return value, if you are just performing a computation in memory. Most
other state-machine libraries require you to explicitly create an input object,
provide that object to a generic "input" method, and then receive results,
sometimes in terms of that library's interfaces and sometimes in terms of
classes you define yourself.
For example, a snippet of the coffee-machine example above might be implemented
as follows in naive Python:
.. code-block:: python
class CoffeeMachine(object):
def brew_button(self):
if self.has_water and self.has_beans and not self.is_lid_open:
self.heat_the_heating_element()
# ...
With Automat, you'd create a class with a ``MethodicalMachine`` attribute:
.. code-block:: python
from automat import MethodicalMachine
class CoffeeBrewer(object):
_machine = MethodicalMachine()
and then you would break the above logic into two pieces - the ``brew_button``
*input*\ , declared like so:
.. code-block:: python
@_machine.input()
def brew_button(self):
"The user pressed the 'brew' button."
It wouldn't do any good to declare a method *body* on this, however, because
input methods don't actually execute their bodies when called; doing actual
work is the *output*\ 's job:
.. code-block:: python
@_machine.output()
def _heat_the_heating_element(self):
"Heat up the heating element, which should cause coffee to happen."
self._heating_element.turn_on()
As well as a couple of *states* - and for simplicity's sake let's say that the
only two states are ``have_beans`` and ``dont_have_beans``\ :
.. code-block:: python
@_machine.state()
def have_beans(self):
"In this state, you have some beans."
@_machine.state(initial=True)
def dont_have_beans(self):
"In this state, you don't have any beans."
``dont_have_beans`` is the ``initial`` state because ``CoffeeBrewer`` starts without beans
in it.
(And another input to put some beans in:)
.. code-block:: python
@_machine.input()
def put_in_beans(self):
"The user put in some beans."
Finally, you hook everything together with the ``upon`` method of the functions
decorated with ``_machine.state``\ :
.. code-block:: python
# When we don't have beans, upon putting in beans, we will then have beans
# (and produce no output)
dont_have_beans.upon(put_in_beans, enter=have_beans, outputs=[])
# When we have beans, upon pressing the brew button, we will then not have
# beans any more (as they have been entered into the brewing chamber) and
# our output will be heating the heating element.
have_beans.upon(brew_button, enter=dont_have_beans,
outputs=[_heat_the_heating_element])
To *users* of this coffee machine class though, it still looks like a POPO
(Plain Old Python Object):
.. code-block:: python
>>> coffee_machine = CoffeeMachine()
>>> coffee_machine.put_in_beans()
>>> coffee_machine.brew_button()
All of the *inputs* are provided by calling them like methods, all of the
*outputs* are automatically invoked when they are produced according to the
outputs specified to ``upon`` and all of the states are simply opaque tokens -
although the fact that they're defined as methods like inputs and outputs
allows you to put docstrings on them easily to document them.
How do I get the current state of a state machine?
--------------------------------------------------
Don't do that.
One major reason for having a state machine is that you want the callers of the
state machine to just provide the appropriate input to the machine at the
appropriate time, and *not have to check themselves* what state the machine is
in. So if you are tempted to write some code like this:
.. code-block:: python
if connection_state_machine.state == "CONNECTED":
connection_state_machine.send_message()
else:
print("not connected")
Instead, just make your calling code do this:
.. code-block:: python
connection_state_machine.send_message()
and then change your state machine to look like this:
.. code-block:: python
@_machine.state()
def connected(self):
"connected"
@_machine.state()
def not_connected(self):
"not connected"
@_machine.input()
def send_message(self):
"send a message"
@_machine.output()
def _actually_send_message(self):
self._transport.send(b"message")
@_machine.output()
def _report_sending_failure(self):
print("not connected")
connected.upon(send_message, enter=connected, [_actually_send_message])
not_connected.upon(send_message, enter=not_connected, [_report_sending_failure])
so that the responsibility for knowing which state the state machine is in
remains within the state machine itself.
Input for Inputs and Output for Outputs
---------------------------------------
Quite often you want to be able to pass parameters to your methods, as well as
inspecting their results. For example, when you brew the coffee, you might
expect a cup of coffee to result, and you would like to see what kind of coffee
it is. And if you were to put delicious hand-roasted small-batch artisanal
beans into the machine, you would expect a *better* cup of coffee than if you
were to use mass-produced beans. You would do this in plain old Python by
adding a parameter, so that's how you do it in Automat as well.
.. code-block:: python
@_machine.input()
def put_in_beans(self, beans):
"The user put in some beans."
However, one important difference here is that *we can't add any
implementation code to the input method*. Inputs are purely a declaration of
the interface; the behavior must all come from outputs. Therefore, the change
in the state of the coffee machine must be represented as an output. We can
add an output method like this:
.. code-block:: python
@_machine.output()
def _save_beans(self, beans):
"The beans are now in the machine; save them."
self._beans = beans
and then connect it to the ``put_in_beans`` by changing the transition from
``dont_have_beans`` to ``have_beans`` like so:
.. code-block:: python
dont_have_beans.upon(put_in_beans, enter=have_beans,
outputs=[_save_beans])
Now, when you call:
.. code-block:: python
coffee_machine.put_in_beans("real good beans")
the machine will remember the beans for later.
So how do we get the beans back out again? One of our outputs needs to have a
return value. It would make sense if our ``brew_button`` method returned the cup
of coffee that it made, so we should add an output. So, in addition to heating
the heating element, let's add a return value that describes the coffee. First
a new output:
.. code-block:: python
@_machine.output()
def _describe_coffee(self):
return "A cup of coffee made with {}.".format(self._beans)
Note that we don't need to check first whether ``self._beans`` exists or not,
because we can only reach this output method if the state machine says we've
gone through a set of states that sets this attribute.
Now, we need to hook up ``_describe_coffee`` to the process of brewing, so change
the brewing transition to:
.. code-block:: python
have_beans.upon(brew_button, enter=dont_have_beans,
outputs=[_heat_the_heating_element,
_describe_coffee])
Now, we can call it:
.. code-block:: python
>>> coffee_machine.brew_button()
[None, 'A cup of coffee made with real good beans.']
Except... wait a second, what's that ``None`` doing there?
Since every input can produce multiple outputs, in automat, the default return
value from every input invocation is a ``list``. In this case, we have both
``_heat_the_heating_element`` and ``_describe_coffee`` outputs, so we're seeing
both of their return values. However, this can be customized, with the
``collector`` argument to ``upon``\ ; the ``collector`` is a callable which takes an
iterable of all the outputs' return values and "collects" a single return value
to return to the caller of the state machine.
In this case, we only care about the last output, so we can adjust the call to
``upon`` like this:
.. code-block:: python
have_beans.upon(brew_button, enter=dont_have_beans,
outputs=[_heat_the_heating_element,
_describe_coffee],
collector=lambda iterable: list(iterable)[-1]
)
And now, we'll get just the return value we want:
.. code-block:: python
>>> coffee_machine.brew_button()
'A cup of coffee made with real good beans.'
If I can't get the state of the state machine, how can I save it to (a database, an API response, a file on disk...)
--------------------------------------------------------------------------------------------------------------------
There are APIs for serializing the state machine.
First, you have to decide on a persistent representation of each state, via the
``serialized=`` argument to the ``MethodicalMachine.state()`` decorator.
Let's take this very simple "light switch" state machine, which can be on or
off, and flipped to reverse its state:
.. code-block:: python
class LightSwitch(object):
_machine = MethodicalMachine()
@_machine.state(serialized="on")
def on_state(self):
"the switch is on"
@_machine.state(serialized="off", initial=True)
def off_state(self):
"the switch is off"
@_machine.input()
def flip(self):
"flip the switch"
on_state.upon(flip, enter=off_state, outputs=[])
off_state.upon(flip, enter=on_state, outputs=[])
In this case, we've chosen a serialized representation for each state via the
``serialized`` argument. The on state is represented by the string ``"on"``\ , and
the off state is represented by the string ``"off"``.
Now, let's just add an input that lets us tell if the switch is on or not.
.. code-block:: python
@_machine.input()
def query_power(self):
"return True if powered, False otherwise"
@_machine.output()
def _is_powered(self):
return True
@_machine.output()
def _not_powered(self):
return False
on_state.upon(query_power, enter=on_state, outputs=[_is_powered],
collector=next)
off_state.upon(query_power, enter=off_state, outputs=[_not_powered],
collector=next)
To save the state, we have the ``MethodicalMachine.serializer()`` method. A
method decorated with ``@serializer()`` gets an extra argument injected at the
beginning of its argument list: the serialized identifier for the state. In
this case, either ``"on"`` or ``"off"``. Since state machine output methods can
also affect other state on the object, a serializer method is expected to
return *all* relevant state for serialization.
For our simple light switch, such a method might look like this:
.. code-block:: python
@_machine.serializer()
def save(self, state):
return {"is-it-on": state}
Serializers can be public methods, and they can return whatever you like. If
necessary, you can have different serializers - just multiple methods decorated
with ``@_machine.serializer()`` - for different formats; return one data-structure
for JSON, one for XML, one for a database row, and so on.
When it comes time to unserialize, though, you generally want a private method,
because an unserializer has to take a not-fully-initialized instance and
populate it with state. It is expected to *return* the serialized machine
state token that was passed to the serializer, but it can take whatever
arguments you like. Of course, in order to return that, it probably has to
take it somewhere in its arguments, so it will generally take whatever a paired
serializer has returned as an argument.
So our unserializer would look like this:
.. code-block:: python
@_machine.unserializer()
def _restore(self, blob):
return blob["is-it-on"]
Generally you will want a classmethod deserialization constructor which you
write yourself to call this, so that you know how to create an instance of your
own object, like so:
.. code-block:: python
@classmethod
def from_blob(cls, blob):
self = cls()
self._restore(blob)
return self
Saving and loading our ``LightSwitch`` along with its state-machine state can now
be accomplished as follows:
.. code-block:: python
>>> switch1 = LightSwitch()
>>> switch1.query_power()
False
>>> switch1.flip()
[]
>>> switch1.query_power()
True
>>> blob = switch1.save()
>>> switch2 = LightSwitch.from_blob(blob)
>>> switch2.query_power()
True
More comprehensive (tested, working) examples are present in ``docs/examples``.
Go forth and machine all the state!
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Automat-0.8.0.dist-info/RECORD
================================================
../../../bin/automat-visualize,sha256=VjaldkbEc5rfj7J6UEu5q63H4NX3pe_kve9ePk9txE0,283
Automat-0.8.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
Automat-0.8.0.dist-info/LICENSE,sha256=siATAWeNCpN9k4VDgnyhNgcS6zTiPejuPzv_-9TA43Y,1053
Automat-0.8.0.dist-info/METADATA,sha256=IMGy5LioGR1j8VhvNYvnWPCGalDNx0WlqYU0ShTjOMc,17919
Automat-0.8.0.dist-info/RECORD,,
Automat-0.8.0.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110
Automat-0.8.0.dist-info/entry_points.txt,sha256=i4tDM5qwy3v1KIN7ETS2XRVcHkThhkq7ZFTPuyP6BpA,63
Automat-0.8.0.dist-info/top_level.txt,sha256=vg4zAOyhP_3YCmpKZLNgFw1uMF3lC_b6TKsdz7jBSpI,8
automat/__init__.py,sha256=ec8PILBwt35xyzsstU9kx8p5ADi6KX9d1rBLZsocN_Y,169
automat/__pycache__/__init__.cpython-36.pyc,,
automat/__pycache__/_core.cpython-36.pyc,,
automat/__pycache__/_discover.cpython-36.pyc,,
automat/__pycache__/_introspection.cpython-36.pyc,,
automat/__pycache__/_methodical.cpython-36.pyc,,
automat/__pycache__/_visualize.cpython-36.pyc,,
automat/_core.py,sha256=IEtZHq3wsBZPX_VfMHMFy_uNjx1kfE11Qq-nmIXZe28,4819
automat/_discover.py,sha256=ye7NHLZkrwYsPmBpTIyJuJ-VRCmwkOUpA0is-A81z04,4367
automat/_introspection.py,sha256=i5UEGdj8lp2BnHnGeAyIwEyoN2gU1nXYg-ZPNX7oBbM,1274
automat/_methodical.py,sha256=AEWagTYaAF8PCXsYoQRYeRn07Jg5fdKDFuAlPvGYHUM,15932
automat/_test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
automat/_test/__pycache__/__init__.cpython-36.pyc,,
automat/_test/__pycache__/test_core.cpython-36.pyc,,
automat/_test/__pycache__/test_discover.cpython-36.pyc,,
automat/_test/__pycache__/test_methodical.cpython-36.pyc,,
automat/_test/__pycache__/test_trace.cpython-36.pyc,,
automat/_test/__pycache__/test_visualize.cpython-36.pyc,,
automat/_test/test_core.py,sha256=CDmGBQNi9Pr7ZktfBcOhBvwI7wjLLYRtWZ0P5baXONY,2833
automat/_test/test_discover.py,sha256=O9ndAdRAC8uO0uDhioz3e45EsJCF19jQZESj0RBC7ZM,21846
automat/_test/test_methodical.py,sha256=t1CAKtT1fs-FoKMQxXl4ky6_6pgpG7lGDbyQrb_vIeo,18856
automat/_test/test_trace.py,sha256=Mx1B8QgaE7QFk6blTie2j-Vx95hTV-zySnlxLalt8ek,3279
automat/_test/test_visualize.py,sha256=8ErNYxovTiDyZkYkoP1BcyEazU_s0YQ3NHdfH9OihAg,13744
automat/_visualize.py,sha256=jY8HkzaGdMoXB7LavvaneW4GdtBN6PRShl7-4OXDvss,6335
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Automat-0.8.0.dist-info/WHEEL
================================================
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.6)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Automat-0.8.0.dist-info/entry_points.txt
================================================
[console_scripts]
automat-visualize = automat._visualize:tool
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Automat-0.8.0.dist-info/top_level.txt
================================================
automat
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/OpenSSL/SSL.py
================================================
import os
import socket
from sys import platform
from functools import wraps, partial
from itertools import count, chain
from weakref import WeakValueDictionary
from errno import errorcode
from cryptography.utils import deprecated
from six import (
binary_type as _binary_type, integer_types as integer_types, int2byte,
indexbytes)
from OpenSSL._util import (
UNSPECIFIED as _UNSPECIFIED,
exception_from_error_queue as _exception_from_error_queue,
ffi as _ffi,
lib as _lib,
make_assert as _make_assert,
native as _native,
path_string as _path_string,
text_to_bytes_and_warn as _text_to_bytes_and_warn,
no_zero_allocator as _no_zero_allocator,
)
from OpenSSL.crypto import (
FILETYPE_PEM, _PassphraseHelper, PKey, X509Name, X509, X509Store)
__all__ = [
'OPENSSL_VERSION_NUMBER',
'SSLEAY_VERSION',
'SSLEAY_CFLAGS',
'SSLEAY_PLATFORM',
'SSLEAY_DIR',
'SSLEAY_BUILT_ON',
'SENT_SHUTDOWN',
'RECEIVED_SHUTDOWN',
'SSLv2_METHOD',
'SSLv3_METHOD',
'SSLv23_METHOD',
'TLSv1_METHOD',
'TLSv1_1_METHOD',
'TLSv1_2_METHOD',
'OP_NO_SSLv2',
'OP_NO_SSLv3',
'OP_NO_TLSv1',
'OP_NO_TLSv1_1',
'OP_NO_TLSv1_2',
'MODE_RELEASE_BUFFERS',
'OP_SINGLE_DH_USE',
'OP_SINGLE_ECDH_USE',
'OP_EPHEMERAL_RSA',
'OP_MICROSOFT_SESS_ID_BUG',
'OP_NETSCAPE_CHALLENGE_BUG',
'OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG',
'OP_SSLREF2_REUSE_CERT_TYPE_BUG',
'OP_MICROSOFT_BIG_SSLV3_BUFFER',
'OP_MSIE_SSLV2_RSA_PADDING',
'OP_SSLEAY_080_CLIENT_DH_BUG',
'OP_TLS_D5_BUG',
'OP_TLS_BLOCK_PADDING_BUG',
'OP_DONT_INSERT_EMPTY_FRAGMENTS',
'OP_CIPHER_SERVER_PREFERENCE',
'OP_TLS_ROLLBACK_BUG',
'OP_PKCS1_CHECK_1',
'OP_PKCS1_CHECK_2',
'OP_NETSCAPE_CA_DN_BUG',
'OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG',
'OP_NO_COMPRESSION',
'OP_NO_QUERY_MTU',
'OP_COOKIE_EXCHANGE',
'OP_NO_TICKET',
'OP_ALL',
'VERIFY_PEER',
'VERIFY_FAIL_IF_NO_PEER_CERT',
'VERIFY_CLIENT_ONCE',
'VERIFY_NONE',
'SESS_CACHE_OFF',
'SESS_CACHE_CLIENT',
'SESS_CACHE_SERVER',
'SESS_CACHE_BOTH',
'SESS_CACHE_NO_AUTO_CLEAR',
'SESS_CACHE_NO_INTERNAL_LOOKUP',
'SESS_CACHE_NO_INTERNAL_STORE',
'SESS_CACHE_NO_INTERNAL',
'SSL_ST_CONNECT',
'SSL_ST_ACCEPT',
'SSL_ST_MASK',
'SSL_CB_LOOP',
'SSL_CB_EXIT',
'SSL_CB_READ',
'SSL_CB_WRITE',
'SSL_CB_ALERT',
'SSL_CB_READ_ALERT',
'SSL_CB_WRITE_ALERT',
'SSL_CB_ACCEPT_LOOP',
'SSL_CB_ACCEPT_EXIT',
'SSL_CB_CONNECT_LOOP',
'SSL_CB_CONNECT_EXIT',
'SSL_CB_HANDSHAKE_START',
'SSL_CB_HANDSHAKE_DONE',
'Error',
'WantReadError',
'WantWriteError',
'WantX509LookupError',
'ZeroReturnError',
'SysCallError',
'SSLeay_version',
'Session',
'Context',
'Connection'
]
try:
_buffer = buffer
except NameError:
class _buffer(object):
pass
OPENSSL_VERSION_NUMBER = _lib.OPENSSL_VERSION_NUMBER
SSLEAY_VERSION = _lib.SSLEAY_VERSION
SSLEAY_CFLAGS = _lib.SSLEAY_CFLAGS
SSLEAY_PLATFORM = _lib.SSLEAY_PLATFORM
SSLEAY_DIR = _lib.SSLEAY_DIR
SSLEAY_BUILT_ON = _lib.SSLEAY_BUILT_ON
SENT_SHUTDOWN = _lib.SSL_SENT_SHUTDOWN
RECEIVED_SHUTDOWN = _lib.SSL_RECEIVED_SHUTDOWN
SSLv2_METHOD = 1
SSLv3_METHOD = 2
SSLv23_METHOD = 3
TLSv1_METHOD = 4
TLSv1_1_METHOD = 5
TLSv1_2_METHOD = 6
OP_NO_SSLv2 = _lib.SSL_OP_NO_SSLv2
OP_NO_SSLv3 = _lib.SSL_OP_NO_SSLv3
OP_NO_TLSv1 = _lib.SSL_OP_NO_TLSv1
OP_NO_TLSv1_1 = _lib.SSL_OP_NO_TLSv1_1
OP_NO_TLSv1_2 = _lib.SSL_OP_NO_TLSv1_2
MODE_RELEASE_BUFFERS = _lib.SSL_MODE_RELEASE_BUFFERS
OP_SINGLE_DH_USE = _lib.SSL_OP_SINGLE_DH_USE
OP_SINGLE_ECDH_USE = _lib.SSL_OP_SINGLE_ECDH_USE
OP_EPHEMERAL_RSA = _lib.SSL_OP_EPHEMERAL_RSA
OP_MICROSOFT_SESS_ID_BUG = _lib.SSL_OP_MICROSOFT_SESS_ID_BUG
OP_NETSCAPE_CHALLENGE_BUG = _lib.SSL_OP_NETSCAPE_CHALLENGE_BUG
OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = (
_lib.SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
)
OP_SSLREF2_REUSE_CERT_TYPE_BUG = _lib.SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
OP_MICROSOFT_BIG_SSLV3_BUFFER = _lib.SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
OP_MSIE_SSLV2_RSA_PADDING = _lib.SSL_OP_MSIE_SSLV2_RSA_PADDING
OP_SSLEAY_080_CLIENT_DH_BUG = _lib.SSL_OP_SSLEAY_080_CLIENT_DH_BUG
OP_TLS_D5_BUG = _lib.SSL_OP_TLS_D5_BUG
OP_TLS_BLOCK_PADDING_BUG = _lib.SSL_OP_TLS_BLOCK_PADDING_BUG
OP_DONT_INSERT_EMPTY_FRAGMENTS = _lib.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
OP_CIPHER_SERVER_PREFERENCE = _lib.SSL_OP_CIPHER_SERVER_PREFERENCE
OP_TLS_ROLLBACK_BUG = _lib.SSL_OP_TLS_ROLLBACK_BUG
OP_PKCS1_CHECK_1 = _lib.SSL_OP_PKCS1_CHECK_1
OP_PKCS1_CHECK_2 = _lib.SSL_OP_PKCS1_CHECK_2
OP_NETSCAPE_CA_DN_BUG = _lib.SSL_OP_NETSCAPE_CA_DN_BUG
OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = (
_lib.SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
)
OP_NO_COMPRESSION = _lib.SSL_OP_NO_COMPRESSION
OP_NO_QUERY_MTU = _lib.SSL_OP_NO_QUERY_MTU
OP_COOKIE_EXCHANGE = _lib.SSL_OP_COOKIE_EXCHANGE
OP_NO_TICKET = _lib.SSL_OP_NO_TICKET
OP_ALL = _lib.SSL_OP_ALL
VERIFY_PEER = _lib.SSL_VERIFY_PEER
VERIFY_FAIL_IF_NO_PEER_CERT = _lib.SSL_VERIFY_FAIL_IF_NO_PEER_CERT
VERIFY_CLIENT_ONCE = _lib.SSL_VERIFY_CLIENT_ONCE
VERIFY_NONE = _lib.SSL_VERIFY_NONE
SESS_CACHE_OFF = _lib.SSL_SESS_CACHE_OFF
SESS_CACHE_CLIENT = _lib.SSL_SESS_CACHE_CLIENT
SESS_CACHE_SERVER = _lib.SSL_SESS_CACHE_SERVER
SESS_CACHE_BOTH = _lib.SSL_SESS_CACHE_BOTH
SESS_CACHE_NO_AUTO_CLEAR = _lib.SSL_SESS_CACHE_NO_AUTO_CLEAR
SESS_CACHE_NO_INTERNAL_LOOKUP = _lib.SSL_SESS_CACHE_NO_INTERNAL_LOOKUP
SESS_CACHE_NO_INTERNAL_STORE = _lib.SSL_SESS_CACHE_NO_INTERNAL_STORE
SESS_CACHE_NO_INTERNAL = _lib.SSL_SESS_CACHE_NO_INTERNAL
SSL_ST_CONNECT = _lib.SSL_ST_CONNECT
SSL_ST_ACCEPT = _lib.SSL_ST_ACCEPT
SSL_ST_MASK = _lib.SSL_ST_MASK
if _lib.Cryptography_HAS_SSL_ST:
SSL_ST_INIT = _lib.SSL_ST_INIT
SSL_ST_BEFORE = _lib.SSL_ST_BEFORE
SSL_ST_OK = _lib.SSL_ST_OK
SSL_ST_RENEGOTIATE = _lib.SSL_ST_RENEGOTIATE
__all__.extend([
'SSL_ST_INIT',
'SSL_ST_BEFORE',
'SSL_ST_OK',
'SSL_ST_RENEGOTIATE',
])
SSL_CB_LOOP = _lib.SSL_CB_LOOP
SSL_CB_EXIT = _lib.SSL_CB_EXIT
SSL_CB_READ = _lib.SSL_CB_READ
SSL_CB_WRITE = _lib.SSL_CB_WRITE
SSL_CB_ALERT = _lib.SSL_CB_ALERT
SSL_CB_READ_ALERT = _lib.SSL_CB_READ_ALERT
SSL_CB_WRITE_ALERT = _lib.SSL_CB_WRITE_ALERT
SSL_CB_ACCEPT_LOOP = _lib.SSL_CB_ACCEPT_LOOP
SSL_CB_ACCEPT_EXIT = _lib.SSL_CB_ACCEPT_EXIT
SSL_CB_CONNECT_LOOP = _lib.SSL_CB_CONNECT_LOOP
SSL_CB_CONNECT_EXIT = _lib.SSL_CB_CONNECT_EXIT
SSL_CB_HANDSHAKE_START = _lib.SSL_CB_HANDSHAKE_START
SSL_CB_HANDSHAKE_DONE = _lib.SSL_CB_HANDSHAKE_DONE
# Taken from https://golang.org/src/crypto/x509/root_linux.go
_CERTIFICATE_FILE_LOCATIONS = [
"/etc/ssl/certs/ca-certificates.crt", # Debian/Ubuntu/Gentoo etc.
"/etc/pki/tls/certs/ca-bundle.crt", # Fedora/RHEL 6
"/etc/ssl/ca-bundle.pem", # OpenSUSE
"/etc/pki/tls/cacert.pem", # OpenELEC
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", # CentOS/RHEL 7
]
_CERTIFICATE_PATH_LOCATIONS = [
"/etc/ssl/certs", # SLES10/SLES11
]
# These values are compared to output from cffi's ffi.string so they must be
# byte strings.
_CRYPTOGRAPHY_MANYLINUX1_CA_DIR = b"/opt/pyca/cryptography/openssl/certs"
_CRYPTOGRAPHY_MANYLINUX1_CA_FILE = b"/opt/pyca/cryptography/openssl/cert.pem"
class Error(Exception):
"""
An error occurred in an `OpenSSL.SSL` API.
"""
_raise_current_error = partial(_exception_from_error_queue, Error)
_openssl_assert = _make_assert(Error)
class WantReadError(Error):
pass
class WantWriteError(Error):
pass
class WantX509LookupError(Error):
pass
class ZeroReturnError(Error):
pass
class SysCallError(Error):
pass
class _CallbackExceptionHelper(object):
"""
A base class for wrapper classes that allow for intelligent exception
handling in OpenSSL callbacks.
:ivar list _problems: Any exceptions that occurred while executing in a
context where they could not be raised in the normal way. Typically
this is because OpenSSL has called into some Python code and requires a
return value. The exceptions are saved to be raised later when it is
possible to do so.
"""
def __init__(self):
self._problems = []
def raise_if_problem(self):
"""
Raise an exception from the OpenSSL error queue or that was previously
captured whe running a callback.
"""
if self._problems:
try:
_raise_current_error()
except Error:
pass
raise self._problems.pop(0)
class _VerifyHelper(_CallbackExceptionHelper):
"""
Wrap a callback such that it can be used as a certificate verification
callback.
"""
def __init__(self, callback):
_CallbackExceptionHelper.__init__(self)
@wraps(callback)
def wrapper(ok, store_ctx):
x509 = _lib.X509_STORE_CTX_get_current_cert(store_ctx)
_lib.X509_up_ref(x509)
cert = X509._from_raw_x509_ptr(x509)
error_number = _lib.X509_STORE_CTX_get_error(store_ctx)
error_depth = _lib.X509_STORE_CTX_get_error_depth(store_ctx)
index = _lib.SSL_get_ex_data_X509_STORE_CTX_idx()
ssl = _lib.X509_STORE_CTX_get_ex_data(store_ctx, index)
connection = Connection._reverse_mapping[ssl]
try:
result = callback(
connection, cert, error_number, error_depth, ok
)
except Exception as e:
self._problems.append(e)
return 0
else:
if result:
_lib.X509_STORE_CTX_set_error(store_ctx, _lib.X509_V_OK)
return 1
else:
return 0
self.callback = _ffi.callback(
"int (*)(int, X509_STORE_CTX *)", wrapper)
class _NpnAdvertiseHelper(_CallbackExceptionHelper):
"""
Wrap a callback such that it can be used as an NPN advertisement callback.
"""
def __init__(self, callback):
_CallbackExceptionHelper.__init__(self)
@wraps(callback)
def wrapper(ssl, out, outlen, arg):
try:
conn = Connection._reverse_mapping[ssl]
protos = callback(conn)
# Join the protocols into a Python bytestring, length-prefixing
# each element.
protostr = b''.join(
chain.from_iterable((int2byte(len(p)), p) for p in protos)
)
# Save our callback arguments on the connection object. This is
# done to make sure that they don't get freed before OpenSSL
# uses them. Then, return them appropriately in the output
# parameters.
conn._npn_advertise_callback_args = [
_ffi.new("unsigned int *", len(protostr)),
_ffi.new("unsigned char[]", protostr),
]
outlen[0] = conn._npn_advertise_callback_args[0][0]
out[0] = conn._npn_advertise_callback_args[1]
return 0
except Exception as e:
self._problems.append(e)
return 2 # SSL_TLSEXT_ERR_ALERT_FATAL
self.callback = _ffi.callback(
"int (*)(SSL *, const unsigned char **, unsigned int *, void *)",
wrapper
)
class _NpnSelectHelper(_CallbackExceptionHelper):
"""
Wrap a callback such that it can be used as an NPN selection callback.
"""
def __init__(self, callback):
_CallbackExceptionHelper.__init__(self)
@wraps(callback)
def wrapper(ssl, out, outlen, in_, inlen, arg):
try:
conn = Connection._reverse_mapping[ssl]
# The string passed to us is actually made up of multiple
# length-prefixed bytestrings. We need to split that into a
# list.
instr = _ffi.buffer(in_, inlen)[:]
protolist = []
while instr:
length = indexbytes(instr, 0)
proto = instr[1:length + 1]
protolist.append(proto)
instr = instr[length + 1:]
# Call the callback
outstr = callback(conn, protolist)
# Save our callback arguments on the connection object. This is
# done to make sure that they don't get freed before OpenSSL
# uses them. Then, return them appropriately in the output
# parameters.
conn._npn_select_callback_args = [
_ffi.new("unsigned char *", len(outstr)),
_ffi.new("unsigned char[]", outstr),
]
outlen[0] = conn._npn_select_callback_args[0][0]
out[0] = conn._npn_select_callback_args[1]
return 0
except Exception as e:
self._problems.append(e)
return 2 # SSL_TLSEXT_ERR_ALERT_FATAL
self.callback = _ffi.callback(
("int (*)(SSL *, unsigned char **, unsigned char *, "
"const unsigned char *, unsigned int, void *)"),
wrapper
)
class _ALPNSelectHelper(_CallbackExceptionHelper):
"""
Wrap a callback such that it can be used as an ALPN selection callback.
"""
def __init__(self, callback):
_CallbackExceptionHelper.__init__(self)
@wraps(callback)
def wrapper(ssl, out, outlen, in_, inlen, arg):
try:
conn = Connection._reverse_mapping[ssl]
# The string passed to us is made up of multiple
# length-prefixed bytestrings. We need to split that into a
# list.
instr = _ffi.buffer(in_, inlen)[:]
protolist = []
while instr:
encoded_len = indexbytes(instr, 0)
proto = instr[1:encoded_len + 1]
protolist.append(proto)
instr = instr[encoded_len + 1:]
# Call the callback
outstr = callback(conn, protolist)
if not isinstance(outstr, _binary_type):
raise TypeError("ALPN callback must return a bytestring.")
# Save our callback arguments on the connection object to make
# sure that they don't get freed before OpenSSL can use them.
# Then, return them in the appropriate output parameters.
conn._alpn_select_callback_args = [
_ffi.new("unsigned char *", len(outstr)),
_ffi.new("unsigned char[]", outstr),
]
outlen[0] = conn._alpn_select_callback_args[0][0]
out[0] = conn._alpn_select_callback_args[1]
return 0
except Exception as e:
self._problems.append(e)
return 2 # SSL_TLSEXT_ERR_ALERT_FATAL
self.callback = _ffi.callback(
("int (*)(SSL *, unsigned char **, unsigned char *, "
"const unsigned char *, unsigned int, void *)"),
wrapper
)
class _OCSPServerCallbackHelper(_CallbackExceptionHelper):
"""
Wrap a callback such that it can be used as an OCSP callback for the server
side.
Annoyingly, OpenSSL defines one OCSP callback but uses it in two different
ways. For servers, that callback is expected to retrieve some OCSP data and
hand it to OpenSSL, and may return only SSL_TLSEXT_ERR_OK,
SSL_TLSEXT_ERR_FATAL, and SSL_TLSEXT_ERR_NOACK. For clients, that callback
is expected to check the OCSP data, and returns a negative value on error,
0 if the response is not acceptable, or positive if it is. These are
mutually exclusive return code behaviours, and they mean that we need two
helpers so that we always return an appropriate error code if the user's
code throws an exception.
Given that we have to have two helpers anyway, these helpers are a bit more
helpery than most: specifically, they hide a few more of the OpenSSL
functions so that the user has an easier time writing these callbacks.
This helper implements the server side.
"""
def __init__(self, callback):
_CallbackExceptionHelper.__init__(self)
@wraps(callback)
def wrapper(ssl, cdata):
try:
conn = Connection._reverse_mapping[ssl]
# Extract the data if any was provided.
if cdata != _ffi.NULL:
data = _ffi.from_handle(cdata)
else:
data = None
# Call the callback.
ocsp_data = callback(conn, data)
if not isinstance(ocsp_data, _binary_type):
raise TypeError("OCSP callback must return a bytestring.")
# If the OCSP data was provided, we will pass it to OpenSSL.
# However, we have an early exit here: if no OCSP data was
# provided we will just exit out and tell OpenSSL that there
# is nothing to do.
if not ocsp_data:
return 3 # SSL_TLSEXT_ERR_NOACK
# OpenSSL takes ownership of this data and expects it to have
# been allocated by OPENSSL_malloc.
ocsp_data_length = len(ocsp_data)
data_ptr = _lib.OPENSSL_malloc(ocsp_data_length)
_ffi.buffer(data_ptr, ocsp_data_length)[:] = ocsp_data
_lib.SSL_set_tlsext_status_ocsp_resp(
ssl, data_ptr, ocsp_data_length
)
return 0
except Exception as e:
self._problems.append(e)
return 2 # SSL_TLSEXT_ERR_ALERT_FATAL
self.callback = _ffi.callback("int (*)(SSL *, void *)", wrapper)
class _OCSPClientCallbackHelper(_CallbackExceptionHelper):
"""
Wrap a callback such that it can be used as an OCSP callback for the client
side.
Annoyingly, OpenSSL defines one OCSP callback but uses it in two different
ways. For servers, that callback is expected to retrieve some OCSP data and
hand it to OpenSSL, and may return only SSL_TLSEXT_ERR_OK,
SSL_TLSEXT_ERR_FATAL, and SSL_TLSEXT_ERR_NOACK. For clients, that callback
is expected to check the OCSP data, and returns a negative value on error,
0 if the response is not acceptable, or positive if it is. These are
mutually exclusive return code behaviours, and they mean that we need two
helpers so that we always return an appropriate error code if the user's
code throws an exception.
Given that we have to have two helpers anyway, these helpers are a bit more
helpery than most: specifically, they hide a few more of the OpenSSL
functions so that the user has an easier time writing these callbacks.
This helper implements the client side.
"""
def __init__(self, callback):
_CallbackExceptionHelper.__init__(self)
@wraps(callback)
def wrapper(ssl, cdata):
try:
conn = Connection._reverse_mapping[ssl]
# Extract the data if any was provided.
if cdata != _ffi.NULL:
data = _ffi.from_handle(cdata)
else:
data = None
# Get the OCSP data.
ocsp_ptr = _ffi.new("unsigned char **")
ocsp_len = _lib.SSL_get_tlsext_status_ocsp_resp(ssl, ocsp_ptr)
if ocsp_len < 0:
# No OCSP data.
ocsp_data = b''
else:
# Copy the OCSP data, then pass it to the callback.
ocsp_data = _ffi.buffer(ocsp_ptr[0], ocsp_len)[:]
valid = callback(conn, ocsp_data, data)
# Return 1 on success or 0 on error.
return int(bool(valid))
except Exception as e:
self._problems.append(e)
# Return negative value if an exception is hit.
return -1
self.callback = _ffi.callback("int (*)(SSL *, void *)", wrapper)
def _asFileDescriptor(obj):
fd = None
if not isinstance(obj, integer_types):
meth = getattr(obj, "fileno", None)
if meth is not None:
obj = meth()
if isinstance(obj, integer_types):
fd = obj
if not isinstance(fd, integer_types):
raise TypeError("argument must be an int, or have a fileno() method.")
elif fd < 0:
raise ValueError(
"file descriptor cannot be a negative integer (%i)" % (fd,))
return fd
def SSLeay_version(type):
"""
Return a string describing the version of OpenSSL in use.
:param type: One of the :const:`SSLEAY_` constants defined in this module.
"""
return _ffi.string(_lib.SSLeay_version(type))
def _make_requires(flag, error):
"""
Builds a decorator that ensures that functions that rely on OpenSSL
functions that are not present in this build raise NotImplementedError,
rather than AttributeError coming out of cryptography.
:param flag: A cryptography flag that guards the functions, e.g.
``Cryptography_HAS_NEXTPROTONEG``.
:param error: The string to be used in the exception if the flag is false.
"""
def _requires_decorator(func):
if not flag:
@wraps(func)
def explode(*args, **kwargs):
raise NotImplementedError(error)
return explode
else:
return func
return _requires_decorator
_requires_npn = _make_requires(
_lib.Cryptography_HAS_NEXTPROTONEG, "NPN not available"
)
_requires_alpn = _make_requires(
_lib.Cryptography_HAS_ALPN, "ALPN not available"
)
_requires_sni = _make_requires(
_lib.Cryptography_HAS_TLSEXT_HOSTNAME, "SNI not available"
)
class Session(object):
"""
A class representing an SSL session. A session defines certain connection
parameters which may be re-used to speed up the setup of subsequent
connections.
.. versionadded:: 0.14
"""
pass
class Context(object):
"""
:class:`OpenSSL.SSL.Context` instances define the parameters for setting
up new SSL connections.
:param method: One of SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, or
TLSv1_METHOD.
"""
_methods = {
SSLv2_METHOD: "SSLv2_method",
SSLv3_METHOD: "SSLv3_method",
SSLv23_METHOD: "SSLv23_method",
TLSv1_METHOD: "TLSv1_method",
TLSv1_1_METHOD: "TLSv1_1_method",
TLSv1_2_METHOD: "TLSv1_2_method",
}
_methods = dict(
(identifier, getattr(_lib, name))
for (identifier, name) in _methods.items()
if getattr(_lib, name, None) is not None)
def __init__(self, method):
if not isinstance(method, integer_types):
raise TypeError("method must be an integer")
try:
method_func = self._methods[method]
except KeyError:
raise ValueError("No such protocol")
method_obj = method_func()
_openssl_assert(method_obj != _ffi.NULL)
context = _lib.SSL_CTX_new(method_obj)
_openssl_assert(context != _ffi.NULL)
context = _ffi.gc(context, _lib.SSL_CTX_free)
# If SSL_CTX_set_ecdh_auto is available then set it so the ECDH curve
# will be auto-selected. This function was added in 1.0.2 and made a
# noop in 1.1.0+ (where it is set automatically).
try:
res = _lib.SSL_CTX_set_ecdh_auto(context, 1)
_openssl_assert(res == 1)
except AttributeError:
pass
self._context = context
self._passphrase_helper = None
self._passphrase_callback = None
self._passphrase_userdata = None
self._verify_helper = None
self._verify_callback = None
self._info_callback = None
self._tlsext_servername_callback = None
self._app_data = None
self._npn_advertise_helper = None
self._npn_advertise_callback = None
self._npn_select_helper = None
self._npn_select_callback = None
self._alpn_select_helper = None
self._alpn_select_callback = None
self._ocsp_helper = None
self._ocsp_callback = None
self._ocsp_data = None
self.set_mode(_lib.SSL_MODE_ENABLE_PARTIAL_WRITE)
def load_verify_locations(self, cafile, capath=None):
"""
Let SSL know where we can find trusted certificates for the certificate
chain. Note that the certificates have to be in PEM format.
If capath is passed, it must be a directory prepared using the
``c_rehash`` tool included with OpenSSL. Either, but not both, of
*pemfile* or *capath* may be :data:`None`.
:param cafile: In which file we can find the certificates (``bytes`` or
``unicode``).
:param capath: In which directory we can find the certificates
(``bytes`` or ``unicode``).
:return: None
"""
if cafile is None:
cafile = _ffi.NULL
else:
cafile = _path_string(cafile)
if capath is None:
capath = _ffi.NULL
else:
capath = _path_string(capath)
load_result = _lib.SSL_CTX_load_verify_locations(
self._context, cafile, capath
)
if not load_result:
_raise_current_error()
def _wrap_callback(self, callback):
@wraps(callback)
def wrapper(size, verify, userdata):
return callback(size, verify, self._passphrase_userdata)
return _PassphraseHelper(
FILETYPE_PEM, wrapper, more_args=True, truncate=True)
def set_passwd_cb(self, callback, userdata=None):
"""
Set the passphrase callback. This function will be called
when a private key with a passphrase is loaded.
:param callback: The Python callback to use. This must accept three
positional arguments. First, an integer giving the maximum length
of the passphrase it may return. If the returned passphrase is
longer than this, it will be truncated. Second, a boolean value
which will be true if the user should be prompted for the
passphrase twice and the callback should verify that the two values
supplied are equal. Third, the value given as the *userdata*
parameter to :meth:`set_passwd_cb`. The *callback* must return
a byte string. If an error occurs, *callback* should return a false
value (e.g. an empty string).
:param userdata: (optional) A Python object which will be given as
argument to the callback
:return: None
"""
if not callable(callback):
raise TypeError("callback must be callable")
self._passphrase_helper = self._wrap_callback(callback)
self._passphrase_callback = self._passphrase_helper.callback
_lib.SSL_CTX_set_default_passwd_cb(
self._context, self._passphrase_callback)
self._passphrase_userdata = userdata
def set_default_verify_paths(self):
"""
Specify that the platform provided CA certificates are to be used for
verification purposes. This method has some caveats related to the
binary wheels that cryptography (pyOpenSSL's primary dependency) ships:
* macOS will only load certificates using this method if the user has
the ``openssl@1.1`` `Homebrew `_ formula installed
in the default location.
* Windows will not work.
* manylinux1 cryptography wheels will work on most common Linux
distributions in pyOpenSSL 17.1.0 and above. pyOpenSSL detects the
manylinux1 wheel and attempts to load roots via a fallback path.
:return: None
"""
# SSL_CTX_set_default_verify_paths will attempt to load certs from
# both a cafile and capath that are set at compile time. However,
# it will first check environment variables and, if present, load
# those paths instead
set_result = _lib.SSL_CTX_set_default_verify_paths(self._context)
_openssl_assert(set_result == 1)
# After attempting to set default_verify_paths we need to know whether
# to go down the fallback path.
# First we'll check to see if any env vars have been set. If so,
# we won't try to do anything else because the user has set the path
# themselves.
dir_env_var = _ffi.string(
_lib.X509_get_default_cert_dir_env()
).decode("ascii")
file_env_var = _ffi.string(
_lib.X509_get_default_cert_file_env()
).decode("ascii")
if not self._check_env_vars_set(dir_env_var, file_env_var):
default_dir = _ffi.string(_lib.X509_get_default_cert_dir())
default_file = _ffi.string(_lib.X509_get_default_cert_file())
# Now we check to see if the default_dir and default_file are set
# to the exact values we use in our manylinux1 builds. If they are
# then we know to load the fallbacks
if (
default_dir == _CRYPTOGRAPHY_MANYLINUX1_CA_DIR and
default_file == _CRYPTOGRAPHY_MANYLINUX1_CA_FILE
):
# This is manylinux1, let's load our fallback paths
self._fallback_default_verify_paths(
_CERTIFICATE_FILE_LOCATIONS,
_CERTIFICATE_PATH_LOCATIONS
)
def _check_env_vars_set(self, dir_env_var, file_env_var):
"""
Check to see if the default cert dir/file environment vars are present.
:return: bool
"""
return (
os.environ.get(file_env_var) is not None or
os.environ.get(dir_env_var) is not None
)
def _fallback_default_verify_paths(self, file_path, dir_path):
"""
Default verify paths are based on the compiled version of OpenSSL.
However, when pyca/cryptography is compiled as a manylinux1 wheel
that compiled location can potentially be wrong. So, like Go, we
will try a predefined set of paths and attempt to load roots
from there.
:return: None
"""
for cafile in file_path:
if os.path.isfile(cafile):
self.load_verify_locations(cafile)
break
for capath in dir_path:
if os.path.isdir(capath):
self.load_verify_locations(None, capath)
break
def use_certificate_chain_file(self, certfile):
"""
Load a certificate chain from a file.
:param certfile: The name of the certificate chain file (``bytes`` or
``unicode``). Must be PEM encoded.
:return: None
"""
certfile = _path_string(certfile)
result = _lib.SSL_CTX_use_certificate_chain_file(
self._context, certfile
)
if not result:
_raise_current_error()
def use_certificate_file(self, certfile, filetype=FILETYPE_PEM):
"""
Load a certificate from a file
:param certfile: The name of the certificate file (``bytes`` or
``unicode``).
:param filetype: (optional) The encoding of the file, which is either
:const:`FILETYPE_PEM` or :const:`FILETYPE_ASN1`. The default is
:const:`FILETYPE_PEM`.
:return: None
"""
certfile = _path_string(certfile)
if not isinstance(filetype, integer_types):
raise TypeError("filetype must be an integer")
use_result = _lib.SSL_CTX_use_certificate_file(
self._context, certfile, filetype
)
if not use_result:
_raise_current_error()
def use_certificate(self, cert):
"""
Load a certificate from a X509 object
:param cert: The X509 object
:return: None
"""
if not isinstance(cert, X509):
raise TypeError("cert must be an X509 instance")
use_result = _lib.SSL_CTX_use_certificate(self._context, cert._x509)
if not use_result:
_raise_current_error()
def add_extra_chain_cert(self, certobj):
"""
Add certificate to chain
:param certobj: The X509 certificate object to add to the chain
:return: None
"""
if not isinstance(certobj, X509):
raise TypeError("certobj must be an X509 instance")
copy = _lib.X509_dup(certobj._x509)
add_result = _lib.SSL_CTX_add_extra_chain_cert(self._context, copy)
if not add_result:
# TODO: This is untested.
_lib.X509_free(copy)
_raise_current_error()
def _raise_passphrase_exception(self):
if self._passphrase_helper is not None:
self._passphrase_helper.raise_if_problem(Error)
_raise_current_error()
def use_privatekey_file(self, keyfile, filetype=_UNSPECIFIED):
"""
Load a private key from a file
:param keyfile: The name of the key file (``bytes`` or ``unicode``)
:param filetype: (optional) The encoding of the file, which is either
:const:`FILETYPE_PEM` or :const:`FILETYPE_ASN1`. The default is
:const:`FILETYPE_PEM`.
:return: None
"""
keyfile = _path_string(keyfile)
if filetype is _UNSPECIFIED:
filetype = FILETYPE_PEM
elif not isinstance(filetype, integer_types):
raise TypeError("filetype must be an integer")
use_result = _lib.SSL_CTX_use_PrivateKey_file(
self._context, keyfile, filetype)
if not use_result:
self._raise_passphrase_exception()
def use_privatekey(self, pkey):
"""
Load a private key from a PKey object
:param pkey: The PKey object
:return: None
"""
if not isinstance(pkey, PKey):
raise TypeError("pkey must be a PKey instance")
use_result = _lib.SSL_CTX_use_PrivateKey(self._context, pkey._pkey)
if not use_result:
self._raise_passphrase_exception()
def check_privatekey(self):
"""
Check if the private key (loaded with :meth:`use_privatekey`) matches
the certificate (loaded with :meth:`use_certificate`)
:return: :data:`None` (raises :exc:`Error` if something's wrong)
"""
if not _lib.SSL_CTX_check_private_key(self._context):
_raise_current_error()
def load_client_ca(self, cafile):
"""
Load the trusted certificates that will be sent to the client. Does
not actually imply any of the certificates are trusted; that must be
configured separately.
:param bytes cafile: The path to a certificates file in PEM format.
:return: None
"""
ca_list = _lib.SSL_load_client_CA_file(
_text_to_bytes_and_warn("cafile", cafile)
)
_openssl_assert(ca_list != _ffi.NULL)
_lib.SSL_CTX_set_client_CA_list(self._context, ca_list)
def set_session_id(self, buf):
"""
Set the session id to *buf* within which a session can be reused for
this Context object. This is needed when doing session resumption,
because there is no way for a stored session to know which Context
object it is associated with.
:param bytes buf: The session id.
:returns: None
"""
buf = _text_to_bytes_and_warn("buf", buf)
_openssl_assert(
_lib.SSL_CTX_set_session_id_context(
self._context,
buf,
len(buf),
) == 1
)
def set_session_cache_mode(self, mode):
"""
Set the behavior of the session cache used by all connections using
this Context. The previously set mode is returned. See
:const:`SESS_CACHE_*` for details about particular modes.
:param mode: One or more of the SESS_CACHE_* flags (combine using
bitwise or)
:returns: The previously set caching mode.
.. versionadded:: 0.14
"""
if not isinstance(mode, integer_types):
raise TypeError("mode must be an integer")
return _lib.SSL_CTX_set_session_cache_mode(self._context, mode)
def get_session_cache_mode(self):
"""
Get the current session cache mode.
:returns: The currently used cache mode.
.. versionadded:: 0.14
"""
return _lib.SSL_CTX_get_session_cache_mode(self._context)
def set_verify(self, mode, callback):
"""
et the verification flags for this Context object to *mode* and specify
that *callback* should be used for verification callbacks.
:param mode: The verify mode, this should be one of
:const:`VERIFY_NONE` and :const:`VERIFY_PEER`. If
:const:`VERIFY_PEER` is used, *mode* can be OR:ed with
:const:`VERIFY_FAIL_IF_NO_PEER_CERT` and
:const:`VERIFY_CLIENT_ONCE` to further control the behaviour.
:param callback: The Python callback to use. This should take five
arguments: A Connection object, an X509 object, and three integer
variables, which are in turn potential error number, error depth
and return code. *callback* should return True if verification
passes and False otherwise.
:return: None
See SSL_CTX_set_verify(3SSL) for further details.
"""
if not isinstance(mode, integer_types):
raise TypeError("mode must be an integer")
if not callable(callback):
raise TypeError("callback must be callable")
self._verify_helper = _VerifyHelper(callback)
self._verify_callback = self._verify_helper.callback
_lib.SSL_CTX_set_verify(self._context, mode, self._verify_callback)
def set_verify_depth(self, depth):
"""
Set the maximum depth for the certificate chain verification that shall
be allowed for this Context object.
:param depth: An integer specifying the verify depth
:return: None
"""
if not isinstance(depth, integer_types):
raise TypeError("depth must be an integer")
_lib.SSL_CTX_set_verify_depth(self._context, depth)
def get_verify_mode(self):
"""
Retrieve the Context object's verify mode, as set by
:meth:`set_verify`.
:return: The verify mode
"""
return _lib.SSL_CTX_get_verify_mode(self._context)
def get_verify_depth(self):
"""
Retrieve the Context object's verify depth, as set by
:meth:`set_verify_depth`.
:return: The verify depth
"""
return _lib.SSL_CTX_get_verify_depth(self._context)
def load_tmp_dh(self, dhfile):
"""
Load parameters for Ephemeral Diffie-Hellman
:param dhfile: The file to load EDH parameters from (``bytes`` or
``unicode``).
:return: None
"""
dhfile = _path_string(dhfile)
bio = _lib.BIO_new_file(dhfile, b"r")
if bio == _ffi.NULL:
_raise_current_error()
bio = _ffi.gc(bio, _lib.BIO_free)
dh = _lib.PEM_read_bio_DHparams(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
dh = _ffi.gc(dh, _lib.DH_free)
_lib.SSL_CTX_set_tmp_dh(self._context, dh)
def set_tmp_ecdh(self, curve):
"""
Select a curve to use for ECDHE key exchange.
:param curve: A curve object to use as returned by either
:meth:`OpenSSL.crypto.get_elliptic_curve` or
:meth:`OpenSSL.crypto.get_elliptic_curves`.
:return: None
"""
_lib.SSL_CTX_set_tmp_ecdh(self._context, curve._to_EC_KEY())
def set_cipher_list(self, cipher_list):
"""
Set the list of ciphers to be used in this context.
See the OpenSSL manual for more information (e.g.
:manpage:`ciphers(1)`).
:param bytes cipher_list: An OpenSSL cipher string.
:return: None
"""
cipher_list = _text_to_bytes_and_warn("cipher_list", cipher_list)
if not isinstance(cipher_list, bytes):
raise TypeError("cipher_list must be a byte string.")
_openssl_assert(
_lib.SSL_CTX_set_cipher_list(self._context, cipher_list) == 1
)
# In OpenSSL 1.1.1 setting the cipher list will always return TLS 1.3
# ciphers even if you pass an invalid cipher. Applications (like
# Twisted) have tests that depend on an error being raised if an
# invalid cipher string is passed, but without the following check
# for the TLS 1.3 specific cipher suites it would never error.
tmpconn = Connection(self, None)
_openssl_assert(
tmpconn.get_cipher_list() != [
'TLS_AES_256_GCM_SHA384',
'TLS_CHACHA20_POLY1305_SHA256',
'TLS_AES_128_GCM_SHA256'
]
)
def set_client_ca_list(self, certificate_authorities):
"""
Set the list of preferred client certificate signers for this server
context.
This list of certificate authorities will be sent to the client when
the server requests a client certificate.
:param certificate_authorities: a sequence of X509Names.
:return: None
.. versionadded:: 0.10
"""
name_stack = _lib.sk_X509_NAME_new_null()
_openssl_assert(name_stack != _ffi.NULL)
try:
for ca_name in certificate_authorities:
if not isinstance(ca_name, X509Name):
raise TypeError(
"client CAs must be X509Name objects, not %s "
"objects" % (
type(ca_name).__name__,
)
)
copy = _lib.X509_NAME_dup(ca_name._name)
_openssl_assert(copy != _ffi.NULL)
push_result = _lib.sk_X509_NAME_push(name_stack, copy)
if not push_result:
_lib.X509_NAME_free(copy)
_raise_current_error()
except Exception:
_lib.sk_X509_NAME_free(name_stack)
raise
_lib.SSL_CTX_set_client_CA_list(self._context, name_stack)
def add_client_ca(self, certificate_authority):
"""
Add the CA certificate to the list of preferred signers for this
context.
The list of certificate authorities will be sent to the client when the
server requests a client certificate.
:param certificate_authority: certificate authority's X509 certificate.
:return: None
.. versionadded:: 0.10
"""
if not isinstance(certificate_authority, X509):
raise TypeError("certificate_authority must be an X509 instance")
add_result = _lib.SSL_CTX_add_client_CA(
self._context, certificate_authority._x509)
_openssl_assert(add_result == 1)
def set_timeout(self, timeout):
"""
Set the timeout for newly created sessions for this Context object to
*timeout*. The default value is 300 seconds. See the OpenSSL manual
for more information (e.g. :manpage:`SSL_CTX_set_timeout(3)`).
:param timeout: The timeout in (whole) seconds
:return: The previous session timeout
"""
if not isinstance(timeout, integer_types):
raise TypeError("timeout must be an integer")
return _lib.SSL_CTX_set_timeout(self._context, timeout)
def get_timeout(self):
"""
Retrieve session timeout, as set by :meth:`set_timeout`. The default
is 300 seconds.
:return: The session timeout
"""
return _lib.SSL_CTX_get_timeout(self._context)
def set_info_callback(self, callback):
"""
Set the information callback to *callback*. This function will be
called from time to time during SSL handshakes.
:param callback: The Python callback to use. This should take three
arguments: a Connection object and two integers. The first integer
specifies where in the SSL handshake the function was called, and
the other the return code from a (possibly failed) internal
function call.
:return: None
"""
@wraps(callback)
def wrapper(ssl, where, return_code):
callback(Connection._reverse_mapping[ssl], where, return_code)
self._info_callback = _ffi.callback(
"void (*)(const SSL *, int, int)", wrapper)
_lib.SSL_CTX_set_info_callback(self._context, self._info_callback)
def get_app_data(self):
"""
Get the application data (supplied via :meth:`set_app_data()`)
:return: The application data
"""
return self._app_data
def set_app_data(self, data):
"""
Set the application data (will be returned from get_app_data())
:param data: Any Python object
:return: None
"""
self._app_data = data
def get_cert_store(self):
"""
Get the certificate store for the context. This can be used to add
"trusted" certificates without using the
:meth:`load_verify_locations` method.
:return: A X509Store object or None if it does not have one.
"""
store = _lib.SSL_CTX_get_cert_store(self._context)
if store == _ffi.NULL:
# TODO: This is untested.
return None
pystore = X509Store.__new__(X509Store)
pystore._store = store
return pystore
def set_options(self, options):
"""
Add options. Options set before are not cleared!
This method should be used with the :const:`OP_*` constants.
:param options: The options to add.
:return: The new option bitmask.
"""
if not isinstance(options, integer_types):
raise TypeError("options must be an integer")
return _lib.SSL_CTX_set_options(self._context, options)
def set_mode(self, mode):
"""
Add modes via bitmask. Modes set before are not cleared! This method
should be used with the :const:`MODE_*` constants.
:param mode: The mode to add.
:return: The new mode bitmask.
"""
if not isinstance(mode, integer_types):
raise TypeError("mode must be an integer")
return _lib.SSL_CTX_set_mode(self._context, mode)
@_requires_sni
def set_tlsext_servername_callback(self, callback):
"""
Specify a callback function to be called when clients specify a server
name.
:param callback: The callback function. It will be invoked with one
argument, the Connection instance.
.. versionadded:: 0.13
"""
@wraps(callback)
def wrapper(ssl, alert, arg):
callback(Connection._reverse_mapping[ssl])
return 0
self._tlsext_servername_callback = _ffi.callback(
"int (*)(SSL *, int *, void *)", wrapper)
_lib.SSL_CTX_set_tlsext_servername_callback(
self._context, self._tlsext_servername_callback)
def set_tlsext_use_srtp(self, profiles):
"""
Enable support for negotiating SRTP keying material.
:param bytes profiles: A colon delimited list of protection profile
names, like ``b'SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32'``.
:return: None
"""
if not isinstance(profiles, bytes):
raise TypeError("profiles must be a byte string.")
_openssl_assert(
_lib.SSL_CTX_set_tlsext_use_srtp(self._context, profiles) == 0
)
@_requires_npn
def set_npn_advertise_callback(self, callback):
"""
Specify a callback function that will be called when offering `Next
Protocol Negotiation
`_ as a server.
:param callback: The callback function. It will be invoked with one
argument, the :class:`Connection` instance. It should return a
list of bytestrings representing the advertised protocols, like
``[b'http/1.1', b'spdy/2']``.
.. versionadded:: 0.15
"""
self._npn_advertise_helper = _NpnAdvertiseHelper(callback)
self._npn_advertise_callback = self._npn_advertise_helper.callback
_lib.SSL_CTX_set_next_protos_advertised_cb(
self._context, self._npn_advertise_callback, _ffi.NULL)
@_requires_npn
def set_npn_select_callback(self, callback):
"""
Specify a callback function that will be called when a server offers
Next Protocol Negotiation options.
:param callback: The callback function. It will be invoked with two
arguments: the Connection, and a list of offered protocols as
bytestrings, e.g. ``[b'http/1.1', b'spdy/2']``. It should return
one of those bytestrings, the chosen protocol.
.. versionadded:: 0.15
"""
self._npn_select_helper = _NpnSelectHelper(callback)
self._npn_select_callback = self._npn_select_helper.callback
_lib.SSL_CTX_set_next_proto_select_cb(
self._context, self._npn_select_callback, _ffi.NULL)
@_requires_alpn
def set_alpn_protos(self, protos):
"""
Specify the protocols that the client is prepared to speak after the
TLS connection has been negotiated using Application Layer Protocol
Negotiation.
:param protos: A list of the protocols to be offered to the server.
This list should be a Python list of bytestrings representing the
protocols to offer, e.g. ``[b'http/1.1', b'spdy/2']``.
"""
# Take the list of protocols and join them together, prefixing them
# with their lengths.
protostr = b''.join(
chain.from_iterable((int2byte(len(p)), p) for p in protos)
)
# Build a C string from the list. We don't need to save this off
# because OpenSSL immediately copies the data out.
input_str = _ffi.new("unsigned char[]", protostr)
_lib.SSL_CTX_set_alpn_protos(self._context, input_str, len(protostr))
@_requires_alpn
def set_alpn_select_callback(self, callback):
"""
Specify a callback function that will be called on the server when a
client offers protocols using ALPN.
:param callback: The callback function. It will be invoked with two
arguments: the Connection, and a list of offered protocols as
bytestrings, e.g ``[b'http/1.1', b'spdy/2']``. It should return
one of those bytestrings, the chosen protocol.
"""
self._alpn_select_helper = _ALPNSelectHelper(callback)
self._alpn_select_callback = self._alpn_select_helper.callback
_lib.SSL_CTX_set_alpn_select_cb(
self._context, self._alpn_select_callback, _ffi.NULL)
def _set_ocsp_callback(self, helper, data):
"""
This internal helper does the common work for
``set_ocsp_server_callback`` and ``set_ocsp_client_callback``, which is
almost all of it.
"""
self._ocsp_helper = helper
self._ocsp_callback = helper.callback
if data is None:
self._ocsp_data = _ffi.NULL
else:
self._ocsp_data = _ffi.new_handle(data)
rc = _lib.SSL_CTX_set_tlsext_status_cb(
self._context, self._ocsp_callback
)
_openssl_assert(rc == 1)
rc = _lib.SSL_CTX_set_tlsext_status_arg(self._context, self._ocsp_data)
_openssl_assert(rc == 1)
def set_ocsp_server_callback(self, callback, data=None):
"""
Set a callback to provide OCSP data to be stapled to the TLS handshake
on the server side.
:param callback: The callback function. It will be invoked with two
arguments: the Connection, and the optional arbitrary data you have
provided. The callback must return a bytestring that contains the
OCSP data to staple to the handshake. If no OCSP data is available
for this connection, return the empty bytestring.
:param data: Some opaque data that will be passed into the callback
function when called. This can be used to avoid needing to do
complex data lookups or to keep track of what context is being
used. This parameter is optional.
"""
helper = _OCSPServerCallbackHelper(callback)
self._set_ocsp_callback(helper, data)
def set_ocsp_client_callback(self, callback, data=None):
"""
Set a callback to validate OCSP data stapled to the TLS handshake on
the client side.
:param callback: The callback function. It will be invoked with three
arguments: the Connection, a bytestring containing the stapled OCSP
assertion, and the optional arbitrary data you have provided. The
callback must return a boolean that indicates the result of
validating the OCSP data: ``True`` if the OCSP data is valid and
the certificate can be trusted, or ``False`` if either the OCSP
data is invalid or the certificate has been revoked.
:param data: Some opaque data that will be passed into the callback
function when called. This can be used to avoid needing to do
complex data lookups or to keep track of what context is being
used. This parameter is optional.
"""
helper = _OCSPClientCallbackHelper(callback)
self._set_ocsp_callback(helper, data)
ContextType = deprecated(
Context, __name__,
"ContextType has been deprecated, use Context instead", DeprecationWarning
)
class Connection(object):
"""
"""
_reverse_mapping = WeakValueDictionary()
def __init__(self, context, socket=None):
"""
Create a new Connection object, using the given OpenSSL.SSL.Context
instance and socket.
:param context: An SSL Context to use for this connection
:param socket: The socket to use for transport layer
"""
if not isinstance(context, Context):
raise TypeError("context must be a Context instance")
ssl = _lib.SSL_new(context._context)
self._ssl = _ffi.gc(ssl, _lib.SSL_free)
# We set SSL_MODE_AUTO_RETRY to handle situations where OpenSSL returns
# an SSL_ERROR_WANT_READ when processing a non-application data packet
# even though there is still data on the underlying transport.
# See https://github.com/openssl/openssl/issues/6234 for more details.
_lib.SSL_set_mode(self._ssl, _lib.SSL_MODE_AUTO_RETRY)
self._context = context
self._app_data = None
# References to strings used for Next Protocol Negotiation. OpenSSL's
# header files suggest that these might get copied at some point, but
# doesn't specify when, so we store them here to make sure they don't
# get freed before OpenSSL uses them.
self._npn_advertise_callback_args = None
self._npn_select_callback_args = None
# References to strings used for Application Layer Protocol
# Negotiation. These strings get copied at some point but it's well
# after the callback returns, so we have to hang them somewhere to
# avoid them getting freed.
self._alpn_select_callback_args = None
self._reverse_mapping[self._ssl] = self
if socket is None:
self._socket = None
# Don't set up any gc for these, SSL_free will take care of them.
self._into_ssl = _lib.BIO_new(_lib.BIO_s_mem())
_openssl_assert(self._into_ssl != _ffi.NULL)
self._from_ssl = _lib.BIO_new(_lib.BIO_s_mem())
_openssl_assert(self._from_ssl != _ffi.NULL)
_lib.SSL_set_bio(self._ssl, self._into_ssl, self._from_ssl)
else:
self._into_ssl = None
self._from_ssl = None
self._socket = socket
set_result = _lib.SSL_set_fd(
self._ssl, _asFileDescriptor(self._socket))
_openssl_assert(set_result == 1)
def __getattr__(self, name):
"""
Look up attributes on the wrapped socket object if they are not found
on the Connection object.
"""
if self._socket is None:
raise AttributeError("'%s' object has no attribute '%s'" % (
self.__class__.__name__, name
))
else:
return getattr(self._socket, name)
def _raise_ssl_error(self, ssl, result):
if self._context._verify_helper is not None:
self._context._verify_helper.raise_if_problem()
if self._context._npn_advertise_helper is not None:
self._context._npn_advertise_helper.raise_if_problem()
if self._context._npn_select_helper is not None:
self._context._npn_select_helper.raise_if_problem()
if self._context._alpn_select_helper is not None:
self._context._alpn_select_helper.raise_if_problem()
if self._context._ocsp_helper is not None:
self._context._ocsp_helper.raise_if_problem()
error = _lib.SSL_get_error(ssl, result)
if error == _lib.SSL_ERROR_WANT_READ:
raise WantReadError()
elif error == _lib.SSL_ERROR_WANT_WRITE:
raise WantWriteError()
elif error == _lib.SSL_ERROR_ZERO_RETURN:
raise ZeroReturnError()
elif error == _lib.SSL_ERROR_WANT_X509_LOOKUP:
# TODO: This is untested.
raise WantX509LookupError()
elif error == _lib.SSL_ERROR_SYSCALL:
if _lib.ERR_peek_error() == 0:
if result < 0:
if platform == "win32":
errno = _ffi.getwinerror()[0]
else:
errno = _ffi.errno
if errno != 0:
raise SysCallError(errno, errorcode.get(errno))
raise SysCallError(-1, "Unexpected EOF")
else:
# TODO: This is untested.
_raise_current_error()
elif error == _lib.SSL_ERROR_NONE:
pass
else:
_raise_current_error()
def get_context(self):
"""
Retrieve the :class:`Context` object associated with this
:class:`Connection`.
"""
return self._context
def set_context(self, context):
"""
Switch this connection to a new session context.
:param context: A :class:`Context` instance giving the new session
context to use.
"""
if not isinstance(context, Context):
raise TypeError("context must be a Context instance")
_lib.SSL_set_SSL_CTX(self._ssl, context._context)
self._context = context
@_requires_sni
def get_servername(self):
"""
Retrieve the servername extension value if provided in the client hello
message, or None if there wasn't one.
:return: A byte string giving the server name or :data:`None`.
.. versionadded:: 0.13
"""
name = _lib.SSL_get_servername(
self._ssl, _lib.TLSEXT_NAMETYPE_host_name
)
if name == _ffi.NULL:
return None
return _ffi.string(name)
@_requires_sni
def set_tlsext_host_name(self, name):
"""
Set the value of the servername extension to send in the client hello.
:param name: A byte string giving the name.
.. versionadded:: 0.13
"""
if not isinstance(name, bytes):
raise TypeError("name must be a byte string")
elif b"\0" in name:
raise TypeError("name must not contain NUL byte")
# XXX I guess this can fail sometimes?
_lib.SSL_set_tlsext_host_name(self._ssl, name)
def pending(self):
"""
Get the number of bytes that can be safely read from the SSL buffer
(**not** the underlying transport buffer).
:return: The number of bytes available in the receive buffer.
"""
return _lib.SSL_pending(self._ssl)
def send(self, buf, flags=0):
"""
Send data on the connection. NOTE: If you get one of the WantRead,
WantWrite or WantX509Lookup exceptions on this, you have to call the
method again with the SAME buffer.
:param buf: The string, buffer or memoryview to send
:param flags: (optional) Included for compatibility with the socket
API, the value is ignored
:return: The number of bytes written
"""
# Backward compatibility
buf = _text_to_bytes_and_warn("buf", buf)
if isinstance(buf, memoryview):
buf = buf.tobytes()
if isinstance(buf, _buffer):
buf = str(buf)
if not isinstance(buf, bytes):
raise TypeError("data must be a memoryview, buffer or byte string")
if len(buf) > 2147483647:
raise ValueError("Cannot send more than 2**31-1 bytes at once.")
result = _lib.SSL_write(self._ssl, buf, len(buf))
self._raise_ssl_error(self._ssl, result)
return result
write = send
def sendall(self, buf, flags=0):
"""
Send "all" data on the connection. This calls send() repeatedly until
all data is sent. If an error occurs, it's impossible to tell how much
data has been sent.
:param buf: The string, buffer or memoryview to send
:param flags: (optional) Included for compatibility with the socket
API, the value is ignored
:return: The number of bytes written
"""
buf = _text_to_bytes_and_warn("buf", buf)
if isinstance(buf, memoryview):
buf = buf.tobytes()
if isinstance(buf, _buffer):
buf = str(buf)
if not isinstance(buf, bytes):
raise TypeError("buf must be a memoryview, buffer or byte string")
left_to_send = len(buf)
total_sent = 0
data = _ffi.new("char[]", buf)
while left_to_send:
# SSL_write's num arg is an int,
# so we cannot send more than 2**31-1 bytes at once.
result = _lib.SSL_write(
self._ssl,
data + total_sent,
min(left_to_send, 2147483647)
)
self._raise_ssl_error(self._ssl, result)
total_sent += result
left_to_send -= result
def recv(self, bufsiz, flags=None):
"""
Receive data on the connection.
:param bufsiz: The maximum number of bytes to read
:param flags: (optional) The only supported flag is ``MSG_PEEK``,
all other flags are ignored.
:return: The string read from the Connection
"""
buf = _no_zero_allocator("char[]", bufsiz)
if flags is not None and flags & socket.MSG_PEEK:
result = _lib.SSL_peek(self._ssl, buf, bufsiz)
else:
result = _lib.SSL_read(self._ssl, buf, bufsiz)
self._raise_ssl_error(self._ssl, result)
return _ffi.buffer(buf, result)[:]
read = recv
def recv_into(self, buffer, nbytes=None, flags=None):
"""
Receive data on the connection and copy it directly into the provided
buffer, rather than creating a new string.
:param buffer: The buffer to copy into.
:param nbytes: (optional) The maximum number of bytes to read into the
buffer. If not present, defaults to the size of the buffer. If
larger than the size of the buffer, is reduced to the size of the
buffer.
:param flags: (optional) The only supported flag is ``MSG_PEEK``,
all other flags are ignored.
:return: The number of bytes read into the buffer.
"""
if nbytes is None:
nbytes = len(buffer)
else:
nbytes = min(nbytes, len(buffer))
# We need to create a temporary buffer. This is annoying, it would be
# better if we could pass memoryviews straight into the SSL_read call,
# but right now we can't. Revisit this if CFFI gets that ability.
buf = _no_zero_allocator("char[]", nbytes)
if flags is not None and flags & socket.MSG_PEEK:
result = _lib.SSL_peek(self._ssl, buf, nbytes)
else:
result = _lib.SSL_read(self._ssl, buf, nbytes)
self._raise_ssl_error(self._ssl, result)
# This strange line is all to avoid a memory copy. The buffer protocol
# should allow us to assign a CFFI buffer to the LHS of this line, but
# on CPython 3.3+ that segfaults. As a workaround, we can temporarily
# wrap it in a memoryview.
buffer[:result] = memoryview(_ffi.buffer(buf, result))
return result
def _handle_bio_errors(self, bio, result):
if _lib.BIO_should_retry(bio):
if _lib.BIO_should_read(bio):
raise WantReadError()
elif _lib.BIO_should_write(bio):
# TODO: This is untested.
raise WantWriteError()
elif _lib.BIO_should_io_special(bio):
# TODO: This is untested. I think io_special means the socket
# BIO has a not-yet connected socket.
raise ValueError("BIO_should_io_special")
else:
# TODO: This is untested.
raise ValueError("unknown bio failure")
else:
# TODO: This is untested.
_raise_current_error()
def bio_read(self, bufsiz):
"""
If the Connection was created with a memory BIO, this method can be
used to read bytes from the write end of that memory BIO. Many
Connection methods will add bytes which must be read in this manner or
the buffer will eventually fill up and the Connection will be able to
take no further actions.
:param bufsiz: The maximum number of bytes to read
:return: The string read.
"""
if self._from_ssl is None:
raise TypeError("Connection sock was not None")
if not isinstance(bufsiz, integer_types):
raise TypeError("bufsiz must be an integer")
buf = _no_zero_allocator("char[]", bufsiz)
result = _lib.BIO_read(self._from_ssl, buf, bufsiz)
if result <= 0:
self._handle_bio_errors(self._from_ssl, result)
return _ffi.buffer(buf, result)[:]
def bio_write(self, buf):
"""
If the Connection was created with a memory BIO, this method can be
used to add bytes to the read end of that memory BIO. The Connection
can then read the bytes (for example, in response to a call to
:meth:`recv`).
:param buf: The string to put into the memory BIO.
:return: The number of bytes written
"""
buf = _text_to_bytes_and_warn("buf", buf)
if self._into_ssl is None:
raise TypeError("Connection sock was not None")
result = _lib.BIO_write(self._into_ssl, buf, len(buf))
if result <= 0:
self._handle_bio_errors(self._into_ssl, result)
return result
def renegotiate(self):
"""
Renegotiate the session.
:return: True if the renegotiation can be started, False otherwise
:rtype: bool
"""
if not self.renegotiate_pending():
_openssl_assert(_lib.SSL_renegotiate(self._ssl) == 1)
return True
return False
def do_handshake(self):
"""
Perform an SSL handshake (usually called after :meth:`renegotiate` or
one of :meth:`set_accept_state` or :meth:`set_accept_state`). This can
raise the same exceptions as :meth:`send` and :meth:`recv`.
:return: None.
"""
result = _lib.SSL_do_handshake(self._ssl)
self._raise_ssl_error(self._ssl, result)
def renegotiate_pending(self):
"""
Check if there's a renegotiation in progress, it will return False once
a renegotiation is finished.
:return: Whether there's a renegotiation in progress
:rtype: bool
"""
return _lib.SSL_renegotiate_pending(self._ssl) == 1
def total_renegotiations(self):
"""
Find out the total number of renegotiations.
:return: The number of renegotiations.
:rtype: int
"""
return _lib.SSL_total_renegotiations(self._ssl)
def connect(self, addr):
"""
Call the :meth:`connect` method of the underlying socket and set up SSL
on the socket, using the :class:`Context` object supplied to this
:class:`Connection` object at creation.
:param addr: A remote address
:return: What the socket's connect method returns
"""
_lib.SSL_set_connect_state(self._ssl)
return self._socket.connect(addr)
def connect_ex(self, addr):
"""
Call the :meth:`connect_ex` method of the underlying socket and set up
SSL on the socket, using the Context object supplied to this Connection
object at creation. Note that if the :meth:`connect_ex` method of the
socket doesn't return 0, SSL won't be initialized.
:param addr: A remove address
:return: What the socket's connect_ex method returns
"""
connect_ex = self._socket.connect_ex
self.set_connect_state()
return connect_ex(addr)
def accept(self):
"""
Call the :meth:`accept` method of the underlying socket and set up SSL
on the returned socket, using the Context object supplied to this
:class:`Connection` object at creation.
:return: A *(conn, addr)* pair where *conn* is the new
:class:`Connection` object created, and *address* is as returned by
the socket's :meth:`accept`.
"""
client, addr = self._socket.accept()
conn = Connection(self._context, client)
conn.set_accept_state()
return (conn, addr)
def bio_shutdown(self):
"""
If the Connection was created with a memory BIO, this method can be
used to indicate that *end of file* has been reached on the read end of
that memory BIO.
:return: None
"""
if self._from_ssl is None:
raise TypeError("Connection sock was not None")
_lib.BIO_set_mem_eof_return(self._into_ssl, 0)
def shutdown(self):
"""
Send the shutdown message to the Connection.
:return: True if the shutdown completed successfully (i.e. both sides
have sent closure alerts), False otherwise (in which case you
call :meth:`recv` or :meth:`send` when the connection becomes
readable/writeable).
"""
result = _lib.SSL_shutdown(self._ssl)
if result < 0:
self._raise_ssl_error(self._ssl, result)
elif result > 0:
return True
else:
return False
def get_cipher_list(self):
"""
Retrieve the list of ciphers used by the Connection object.
:return: A list of native cipher strings.
"""
ciphers = []
for i in count():
result = _lib.SSL_get_cipher_list(self._ssl, i)
if result == _ffi.NULL:
break
ciphers.append(_native(_ffi.string(result)))
return ciphers
def get_client_ca_list(self):
"""
Get CAs whose certificates are suggested for client authentication.
:return: If this is a server connection, the list of certificate
authorities that will be sent or has been sent to the client, as
controlled by this :class:`Connection`'s :class:`Context`.
If this is a client connection, the list will be empty until the
connection with the server is established.
.. versionadded:: 0.10
"""
ca_names = _lib.SSL_get_client_CA_list(self._ssl)
if ca_names == _ffi.NULL:
# TODO: This is untested.
return []
result = []
for i in range(_lib.sk_X509_NAME_num(ca_names)):
name = _lib.sk_X509_NAME_value(ca_names, i)
copy = _lib.X509_NAME_dup(name)
_openssl_assert(copy != _ffi.NULL)
pyname = X509Name.__new__(X509Name)
pyname._name = _ffi.gc(copy, _lib.X509_NAME_free)
result.append(pyname)
return result
def makefile(self, *args, **kwargs):
"""
The makefile() method is not implemented, since there is no dup
semantics for SSL connections
:raise: NotImplementedError
"""
raise NotImplementedError(
"Cannot make file object of OpenSSL.SSL.Connection")
def get_app_data(self):
"""
Retrieve application data as set by :meth:`set_app_data`.
:return: The application data
"""
return self._app_data
def set_app_data(self, data):
"""
Set application data
:param data: The application data
:return: None
"""
self._app_data = data
def get_shutdown(self):
"""
Get the shutdown state of the Connection.
:return: The shutdown state, a bitvector of SENT_SHUTDOWN,
RECEIVED_SHUTDOWN.
"""
return _lib.SSL_get_shutdown(self._ssl)
def set_shutdown(self, state):
"""
Set the shutdown state of the Connection.
:param state: bitvector of SENT_SHUTDOWN, RECEIVED_SHUTDOWN.
:return: None
"""
if not isinstance(state, integer_types):
raise TypeError("state must be an integer")
_lib.SSL_set_shutdown(self._ssl, state)
def get_state_string(self):
"""
Retrieve a verbose string detailing the state of the Connection.
:return: A string representing the state
:rtype: bytes
"""
return _ffi.string(_lib.SSL_state_string_long(self._ssl))
def server_random(self):
"""
Retrieve the random value used with the server hello message.
:return: A string representing the state
"""
session = _lib.SSL_get_session(self._ssl)
if session == _ffi.NULL:
return None
length = _lib.SSL_get_server_random(self._ssl, _ffi.NULL, 0)
assert length > 0
outp = _no_zero_allocator("unsigned char[]", length)
_lib.SSL_get_server_random(self._ssl, outp, length)
return _ffi.buffer(outp, length)[:]
def client_random(self):
"""
Retrieve the random value used with the client hello message.
:return: A string representing the state
"""
session = _lib.SSL_get_session(self._ssl)
if session == _ffi.NULL:
return None
length = _lib.SSL_get_client_random(self._ssl, _ffi.NULL, 0)
assert length > 0
outp = _no_zero_allocator("unsigned char[]", length)
_lib.SSL_get_client_random(self._ssl, outp, length)
return _ffi.buffer(outp, length)[:]
def master_key(self):
"""
Retrieve the value of the master key for this session.
:return: A string representing the state
"""
session = _lib.SSL_get_session(self._ssl)
if session == _ffi.NULL:
return None
length = _lib.SSL_SESSION_get_master_key(session, _ffi.NULL, 0)
assert length > 0
outp = _no_zero_allocator("unsigned char[]", length)
_lib.SSL_SESSION_get_master_key(session, outp, length)
return _ffi.buffer(outp, length)[:]
def export_keying_material(self, label, olen, context=None):
"""
Obtain keying material for application use.
:param: label - a disambiguating label string as described in RFC 5705
:param: olen - the length of the exported key material in bytes
:param: context - a per-association context value
:return: the exported key material bytes or None
"""
outp = _no_zero_allocator("unsigned char[]", olen)
context_buf = _ffi.NULL
context_len = 0
use_context = 0
if context is not None:
context_buf = context
context_len = len(context)
use_context = 1
success = _lib.SSL_export_keying_material(self._ssl, outp, olen,
label, len(label),
context_buf, context_len,
use_context)
_openssl_assert(success == 1)
return _ffi.buffer(outp, olen)[:]
def sock_shutdown(self, *args, **kwargs):
"""
Call the :meth:`shutdown` method of the underlying socket.
See :manpage:`shutdown(2)`.
:return: What the socket's shutdown() method returns
"""
return self._socket.shutdown(*args, **kwargs)
def get_certificate(self):
"""
Retrieve the local certificate (if any)
:return: The local certificate
"""
cert = _lib.SSL_get_certificate(self._ssl)
if cert != _ffi.NULL:
_lib.X509_up_ref(cert)
return X509._from_raw_x509_ptr(cert)
return None
def get_peer_certificate(self):
"""
Retrieve the other side's certificate (if any)
:return: The peer's certificate
"""
cert = _lib.SSL_get_peer_certificate(self._ssl)
if cert != _ffi.NULL:
return X509._from_raw_x509_ptr(cert)
return None
def get_peer_cert_chain(self):
"""
Retrieve the other side's certificate (if any)
:return: A list of X509 instances giving the peer's certificate chain,
or None if it does not have one.
"""
cert_stack = _lib.SSL_get_peer_cert_chain(self._ssl)
if cert_stack == _ffi.NULL:
return None
result = []
for i in range(_lib.sk_X509_num(cert_stack)):
# TODO could incref instead of dup here
cert = _lib.X509_dup(_lib.sk_X509_value(cert_stack, i))
pycert = X509._from_raw_x509_ptr(cert)
result.append(pycert)
return result
def want_read(self):
"""
Checks if more data has to be read from the transport layer to complete
an operation.
:return: True iff more data has to be read
"""
return _lib.SSL_want_read(self._ssl)
def want_write(self):
"""
Checks if there is data to write to the transport layer to complete an
operation.
:return: True iff there is data to write
"""
return _lib.SSL_want_write(self._ssl)
def set_accept_state(self):
"""
Set the connection to work in server mode. The handshake will be
handled automatically by read/write.
:return: None
"""
_lib.SSL_set_accept_state(self._ssl)
def set_connect_state(self):
"""
Set the connection to work in client mode. The handshake will be
handled automatically by read/write.
:return: None
"""
_lib.SSL_set_connect_state(self._ssl)
def get_session(self):
"""
Returns the Session currently used.
:return: An instance of :class:`OpenSSL.SSL.Session` or
:obj:`None` if no session exists.
.. versionadded:: 0.14
"""
session = _lib.SSL_get1_session(self._ssl)
if session == _ffi.NULL:
return None
pysession = Session.__new__(Session)
pysession._session = _ffi.gc(session, _lib.SSL_SESSION_free)
return pysession
def set_session(self, session):
"""
Set the session to be used when the TLS/SSL connection is established.
:param session: A Session instance representing the session to use.
:returns: None
.. versionadded:: 0.14
"""
if not isinstance(session, Session):
raise TypeError("session must be a Session instance")
result = _lib.SSL_set_session(self._ssl, session._session)
if not result:
_raise_current_error()
def _get_finished_message(self, function):
"""
Helper to implement :meth:`get_finished` and
:meth:`get_peer_finished`.
:param function: Either :data:`SSL_get_finished`: or
:data:`SSL_get_peer_finished`.
:return: :data:`None` if the desired message has not yet been
received, otherwise the contents of the message.
:rtype: :class:`bytes` or :class:`NoneType`
"""
# The OpenSSL documentation says nothing about what might happen if the
# count argument given is zero. Specifically, it doesn't say whether
# the output buffer may be NULL in that case or not. Inspection of the
# implementation reveals that it calls memcpy() unconditionally.
# Section 7.1.4, paragraph 1 of the C standard suggests that
# memcpy(NULL, source, 0) is not guaranteed to produce defined (let
# alone desirable) behavior (though it probably does on just about
# every implementation...)
#
# Allocate a tiny buffer to pass in (instead of just passing NULL as
# one might expect) for the initial call so as to be safe against this
# potentially undefined behavior.
empty = _ffi.new("char[]", 0)
size = function(self._ssl, empty, 0)
if size == 0:
# No Finished message so far.
return None
buf = _no_zero_allocator("char[]", size)
function(self._ssl, buf, size)
return _ffi.buffer(buf, size)[:]
def get_finished(self):
"""
Obtain the latest TLS Finished message that we sent.
:return: The contents of the message or :obj:`None` if the TLS
handshake has not yet completed.
:rtype: :class:`bytes` or :class:`NoneType`
.. versionadded:: 0.15
"""
return self._get_finished_message(_lib.SSL_get_finished)
def get_peer_finished(self):
"""
Obtain the latest TLS Finished message that we received from the peer.
:return: The contents of the message or :obj:`None` if the TLS
handshake has not yet completed.
:rtype: :class:`bytes` or :class:`NoneType`
.. versionadded:: 0.15
"""
return self._get_finished_message(_lib.SSL_get_peer_finished)
def get_cipher_name(self):
"""
Obtain the name of the currently used cipher.
:returns: The name of the currently used cipher or :obj:`None`
if no connection has been established.
:rtype: :class:`unicode` or :class:`NoneType`
.. versionadded:: 0.15
"""
cipher = _lib.SSL_get_current_cipher(self._ssl)
if cipher == _ffi.NULL:
return None
else:
name = _ffi.string(_lib.SSL_CIPHER_get_name(cipher))
return name.decode("utf-8")
def get_cipher_bits(self):
"""
Obtain the number of secret bits of the currently used cipher.
:returns: The number of secret bits of the currently used cipher
or :obj:`None` if no connection has been established.
:rtype: :class:`int` or :class:`NoneType`
.. versionadded:: 0.15
"""
cipher = _lib.SSL_get_current_cipher(self._ssl)
if cipher == _ffi.NULL:
return None
else:
return _lib.SSL_CIPHER_get_bits(cipher, _ffi.NULL)
def get_cipher_version(self):
"""
Obtain the protocol version of the currently used cipher.
:returns: The protocol name of the currently used cipher
or :obj:`None` if no connection has been established.
:rtype: :class:`unicode` or :class:`NoneType`
.. versionadded:: 0.15
"""
cipher = _lib.SSL_get_current_cipher(self._ssl)
if cipher == _ffi.NULL:
return None
else:
version = _ffi.string(_lib.SSL_CIPHER_get_version(cipher))
return version.decode("utf-8")
def get_protocol_version_name(self):
"""
Retrieve the protocol version of the current connection.
:returns: The TLS version of the current connection, for example
the value for TLS 1.2 would be ``TLSv1.2``or ``Unknown``
for connections that were not successfully established.
:rtype: :class:`unicode`
"""
version = _ffi.string(_lib.SSL_get_version(self._ssl))
return version.decode("utf-8")
def get_protocol_version(self):
"""
Retrieve the SSL or TLS protocol version of the current connection.
:returns: The TLS version of the current connection. For example,
it will return ``0x769`` for connections made over TLS version 1.
:rtype: :class:`int`
"""
version = _lib.SSL_version(self._ssl)
return version
@_requires_npn
def get_next_proto_negotiated(self):
"""
Get the protocol that was negotiated by NPN.
:returns: A bytestring of the protocol name. If no protocol has been
negotiated yet, returns an empty string.
.. versionadded:: 0.15
"""
data = _ffi.new("unsigned char **")
data_len = _ffi.new("unsigned int *")
_lib.SSL_get0_next_proto_negotiated(self._ssl, data, data_len)
return _ffi.buffer(data[0], data_len[0])[:]
@_requires_alpn
def set_alpn_protos(self, protos):
"""
Specify the client's ALPN protocol list.
These protocols are offered to the server during protocol negotiation.
:param protos: A list of the protocols to be offered to the server.
This list should be a Python list of bytestrings representing the
protocols to offer, e.g. ``[b'http/1.1', b'spdy/2']``.
"""
# Take the list of protocols and join them together, prefixing them
# with their lengths.
protostr = b''.join(
chain.from_iterable((int2byte(len(p)), p) for p in protos)
)
# Build a C string from the list. We don't need to save this off
# because OpenSSL immediately copies the data out.
input_str = _ffi.new("unsigned char[]", protostr)
_lib.SSL_set_alpn_protos(self._ssl, input_str, len(protostr))
@_requires_alpn
def get_alpn_proto_negotiated(self):
"""
Get the protocol that was negotiated by ALPN.
:returns: A bytestring of the protocol name. If no protocol has been
negotiated yet, returns an empty string.
"""
data = _ffi.new("unsigned char **")
data_len = _ffi.new("unsigned int *")
_lib.SSL_get0_alpn_selected(self._ssl, data, data_len)
if not data_len:
return b''
return _ffi.buffer(data[0], data_len[0])[:]
def request_ocsp(self):
"""
Called to request that the server sends stapled OCSP data, if
available. If this is not called on the client side then the server
will not send OCSP data. Should be used in conjunction with
:meth:`Context.set_ocsp_client_callback`.
"""
rc = _lib.SSL_set_tlsext_status_type(
self._ssl, _lib.TLSEXT_STATUSTYPE_ocsp
)
_openssl_assert(rc == 1)
ConnectionType = deprecated(
Connection, __name__,
"ConnectionType has been deprecated, use Connection instead",
DeprecationWarning
)
# This is similar to the initialization calls at the end of OpenSSL/crypto.py
# but is exercised mostly by the Context initializer.
_lib.SSL_library_init()
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/OpenSSL/__init__.py
================================================
# Copyright (C) AB Strakt
# See LICENSE for details.
"""
pyOpenSSL - A simple wrapper around the OpenSSL library
"""
from OpenSSL import crypto, SSL
from OpenSSL.version import (
__author__, __copyright__, __email__, __license__, __summary__, __title__,
__uri__, __version__,
)
__all__ = [
"SSL", "crypto",
"__author__", "__copyright__", "__email__", "__license__", "__summary__",
"__title__", "__uri__", "__version__",
]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/OpenSSL/_util.py
================================================
import sys
import warnings
from six import PY3, binary_type, text_type
from cryptography.hazmat.bindings.openssl.binding import Binding
binding = Binding()
binding.init_static_locks()
ffi = binding.ffi
lib = binding.lib
# This is a special CFFI allocator that does not bother to zero its memory
# after allocation. This has vastly better performance on large allocations and
# so should be used whenever we don't need the memory zeroed out.
no_zero_allocator = ffi.new_allocator(should_clear_after_alloc=False)
def text(charp):
"""
Get a native string type representing of the given CFFI ``char*`` object.
:param charp: A C-style string represented using CFFI.
:return: :class:`str`
"""
if not charp:
return ""
return native(ffi.string(charp))
def exception_from_error_queue(exception_type):
"""
Convert an OpenSSL library failure into a Python exception.
When a call to the native OpenSSL library fails, this is usually signalled
by the return value, and an error code is stored in an error queue
associated with the current thread. The err library provides functions to
obtain these error codes and textual error messages.
"""
errors = []
while True:
error = lib.ERR_get_error()
if error == 0:
break
errors.append((
text(lib.ERR_lib_error_string(error)),
text(lib.ERR_func_error_string(error)),
text(lib.ERR_reason_error_string(error))))
raise exception_type(errors)
def make_assert(error):
"""
Create an assert function that uses :func:`exception_from_error_queue` to
raise an exception wrapped by *error*.
"""
def openssl_assert(ok):
"""
If *ok* is not True, retrieve the error from OpenSSL and raise it.
"""
if ok is not True:
exception_from_error_queue(error)
return openssl_assert
def native(s):
"""
Convert :py:class:`bytes` or :py:class:`unicode` to the native
:py:class:`str` type, using UTF-8 encoding if conversion is necessary.
:raise UnicodeError: The input string is not UTF-8 decodeable.
:raise TypeError: The input is neither :py:class:`bytes` nor
:py:class:`unicode`.
"""
if not isinstance(s, (binary_type, text_type)):
raise TypeError("%r is neither bytes nor unicode" % s)
if PY3:
if isinstance(s, binary_type):
return s.decode("utf-8")
else:
if isinstance(s, text_type):
return s.encode("utf-8")
return s
def path_string(s):
"""
Convert a Python string to a :py:class:`bytes` string identifying the same
path and which can be passed into an OpenSSL API accepting a filename.
:param s: An instance of :py:class:`bytes` or :py:class:`unicode`.
:return: An instance of :py:class:`bytes`.
"""
if isinstance(s, binary_type):
return s
elif isinstance(s, text_type):
return s.encode(sys.getfilesystemencoding())
else:
raise TypeError("Path must be represented as bytes or unicode string")
if PY3:
def byte_string(s):
return s.encode("charmap")
else:
def byte_string(s):
return s
# A marker object to observe whether some optional arguments are passed any
# value or not.
UNSPECIFIED = object()
_TEXT_WARNING = (
text_type.__name__ + " for {0} is no longer accepted, use bytes"
)
def text_to_bytes_and_warn(label, obj):
"""
If ``obj`` is text, emit a warning that it should be bytes instead and try
to convert it to bytes automatically.
:param str label: The name of the parameter from which ``obj`` was taken
(so a developer can easily find the source of the problem and correct
it).
:return: If ``obj`` is the text string type, a ``bytes`` object giving the
UTF-8 encoding of that text is returned. Otherwise, ``obj`` itself is
returned.
"""
if isinstance(obj, text_type):
warnings.warn(
_TEXT_WARNING.format(label),
category=DeprecationWarning,
stacklevel=3
)
return obj.encode('utf-8')
return obj
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/OpenSSL/crypto.py
================================================
import datetime
from base64 import b16encode
from functools import partial
from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
from six import (
integer_types as _integer_types,
text_type as _text_type,
PY3 as _PY3)
from cryptography import x509
from cryptography.hazmat.primitives.asymmetric import dsa, rsa
from cryptography.utils import deprecated
from OpenSSL._util import (
ffi as _ffi,
lib as _lib,
exception_from_error_queue as _exception_from_error_queue,
byte_string as _byte_string,
native as _native,
UNSPECIFIED as _UNSPECIFIED,
text_to_bytes_and_warn as _text_to_bytes_and_warn,
make_assert as _make_assert,
)
__all__ = [
'FILETYPE_PEM',
'FILETYPE_ASN1',
'FILETYPE_TEXT',
'TYPE_RSA',
'TYPE_DSA',
'Error',
'PKey',
'get_elliptic_curves',
'get_elliptic_curve',
'X509Name',
'X509Extension',
'X509Req',
'X509',
'X509StoreFlags',
'X509Store',
'X509StoreContextError',
'X509StoreContext',
'load_certificate',
'dump_certificate',
'dump_publickey',
'dump_privatekey',
'Revoked',
'CRL',
'PKCS7',
'PKCS12',
'NetscapeSPKI',
'load_publickey',
'load_privatekey',
'dump_certificate_request',
'load_certificate_request',
'sign',
'verify',
'dump_crl',
'load_crl',
'load_pkcs7_data',
'load_pkcs12'
]
FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
# TODO This was an API mistake. OpenSSL has no such constant.
FILETYPE_TEXT = 2 ** 16 - 1
TYPE_RSA = _lib.EVP_PKEY_RSA
TYPE_DSA = _lib.EVP_PKEY_DSA
TYPE_DH = _lib.EVP_PKEY_DH
TYPE_EC = _lib.EVP_PKEY_EC
class Error(Exception):
"""
An error occurred in an `OpenSSL.crypto` API.
"""
_raise_current_error = partial(_exception_from_error_queue, Error)
_openssl_assert = _make_assert(Error)
def _get_backend():
"""
Importing the backend from cryptography has the side effect of activating
the osrandom engine. This mutates the global state of OpenSSL in the
process and causes issues for various programs that use subinterpreters or
embed Python. By putting the import in this function we can avoid
triggering this side effect unless _get_backend is called.
"""
from cryptography.hazmat.backends.openssl.backend import backend
return backend
def _untested_error(where):
"""
An OpenSSL API failed somehow. Additionally, the failure which was
encountered isn't one that's exercised by the test suite so future behavior
of pyOpenSSL is now somewhat less predictable.
"""
raise RuntimeError("Unknown %s failure" % (where,))
def _new_mem_buf(buffer=None):
"""
Allocate a new OpenSSL memory BIO.
Arrange for the garbage collector to clean it up automatically.
:param buffer: None or some bytes to use to put into the BIO so that they
can be read out.
"""
if buffer is None:
bio = _lib.BIO_new(_lib.BIO_s_mem())
free = _lib.BIO_free
else:
data = _ffi.new("char[]", buffer)
bio = _lib.BIO_new_mem_buf(data, len(buffer))
# Keep the memory alive as long as the bio is alive!
def free(bio, ref=data):
return _lib.BIO_free(bio)
_openssl_assert(bio != _ffi.NULL)
bio = _ffi.gc(bio, free)
return bio
def _bio_to_string(bio):
"""
Copy the contents of an OpenSSL BIO object into a Python byte string.
"""
result_buffer = _ffi.new('char**')
buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
return _ffi.buffer(result_buffer[0], buffer_length)[:]
def _set_asn1_time(boundary, when):
"""
The the time value of an ASN1 time object.
@param boundary: An ASN1_TIME pointer (or an object safely
castable to that type) which will have its value set.
@param when: A string representation of the desired time value.
@raise TypeError: If C{when} is not a L{bytes} string.
@raise ValueError: If C{when} does not represent a time in the required
format.
@raise RuntimeError: If the time value cannot be set for some other
(unspecified) reason.
"""
if not isinstance(when, bytes):
raise TypeError("when must be a byte string")
set_result = _lib.ASN1_TIME_set_string(boundary, when)
if set_result == 0:
raise ValueError("Invalid string")
def _get_asn1_time(timestamp):
"""
Retrieve the time value of an ASN1 time object.
@param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
that type) from which the time value will be retrieved.
@return: The time value from C{timestamp} as a L{bytes} string in a certain
format. Or C{None} if the object contains no time value.
"""
string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
if _lib.ASN1_STRING_length(string_timestamp) == 0:
return None
elif (
_lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME
):
return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
else:
generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
_lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
if generalized_timestamp[0] == _ffi.NULL:
# This may happen:
# - if timestamp was not an ASN1_TIME
# - if allocating memory for the ASN1_GENERALIZEDTIME failed
# - if a copy of the time data from timestamp cannot be made for
# the newly allocated ASN1_GENERALIZEDTIME
#
# These are difficult to test. cffi enforces the ASN1_TIME type.
# Memory allocation failures are a pain to trigger
# deterministically.
_untested_error("ASN1_TIME_to_generalizedtime")
else:
string_timestamp = _ffi.cast(
"ASN1_STRING*", generalized_timestamp[0])
string_data = _lib.ASN1_STRING_data(string_timestamp)
string_result = _ffi.string(string_data)
_lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
return string_result
class _X509NameInvalidator(object):
def __init__(self):
self._names = []
def add(self, name):
self._names.append(name)
def clear(self):
for name in self._names:
# Breaks the object, but also prevents UAF!
del name._name
class PKey(object):
"""
A class representing an DSA or RSA public key or key pair.
"""
_only_public = False
_initialized = True
def __init__(self):
pkey = _lib.EVP_PKEY_new()
self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
self._initialized = False
def to_cryptography_key(self):
"""
Export as a ``cryptography`` key.
:rtype: One of ``cryptography``'s `key interfaces`_.
.. _key interfaces: https://cryptography.io/en/latest/hazmat/\
primitives/asymmetric/rsa/#key-interfaces
.. versionadded:: 16.1.0
"""
backend = _get_backend()
if self._only_public:
return backend._evp_pkey_to_public_key(self._pkey)
else:
return backend._evp_pkey_to_private_key(self._pkey)
@classmethod
def from_cryptography_key(cls, crypto_key):
"""
Construct based on a ``cryptography`` *crypto_key*.
:param crypto_key: A ``cryptography`` key.
:type crypto_key: One of ``cryptography``'s `key interfaces`_.
:rtype: PKey
.. versionadded:: 16.1.0
"""
pkey = cls()
if not isinstance(crypto_key, (rsa.RSAPublicKey, rsa.RSAPrivateKey,
dsa.DSAPublicKey, dsa.DSAPrivateKey)):
raise TypeError("Unsupported key type")
pkey._pkey = crypto_key._evp_pkey
if isinstance(crypto_key, (rsa.RSAPublicKey, dsa.DSAPublicKey)):
pkey._only_public = True
pkey._initialized = True
return pkey
def generate_key(self, type, bits):
"""
Generate a key pair of the given type, with the given number of bits.
This generates a key "into" the this object.
:param type: The key type.
:type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
:param bits: The number of bits.
:type bits: :py:data:`int` ``>= 0``
:raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
of the appropriate type.
:raises ValueError: If the number of bits isn't an integer of
the appropriate size.
:return: ``None``
"""
if not isinstance(type, int):
raise TypeError("type must be an integer")
if not isinstance(bits, int):
raise TypeError("bits must be an integer")
if type == TYPE_RSA:
if bits <= 0:
raise ValueError("Invalid number of bits")
# TODO Check error return
exponent = _lib.BN_new()
exponent = _ffi.gc(exponent, _lib.BN_free)
_lib.BN_set_word(exponent, _lib.RSA_F4)
rsa = _lib.RSA_new()
result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
_openssl_assert(result == 1)
result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
_openssl_assert(result == 1)
elif type == TYPE_DSA:
dsa = _lib.DSA_new()
_openssl_assert(dsa != _ffi.NULL)
dsa = _ffi.gc(dsa, _lib.DSA_free)
res = _lib.DSA_generate_parameters_ex(
dsa, bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL
)
_openssl_assert(res == 1)
_openssl_assert(_lib.DSA_generate_key(dsa) == 1)
_openssl_assert(_lib.EVP_PKEY_set1_DSA(self._pkey, dsa) == 1)
else:
raise Error("No such key type")
self._initialized = True
def check(self):
"""
Check the consistency of an RSA private key.
This is the Python equivalent of OpenSSL's ``RSA_check_key``.
:return: ``True`` if key is consistent.
:raise OpenSSL.crypto.Error: if the key is inconsistent.
:raise TypeError: if the key is of a type which cannot be checked.
Only RSA keys can currently be checked.
"""
if self._only_public:
raise TypeError("public key only")
if _lib.EVP_PKEY_type(self.type()) != _lib.EVP_PKEY_RSA:
raise TypeError("key type unsupported")
rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
rsa = _ffi.gc(rsa, _lib.RSA_free)
result = _lib.RSA_check_key(rsa)
if result:
return True
_raise_current_error()
def type(self):
"""
Returns the type of the key
:return: The type of the key.
"""
return _lib.EVP_PKEY_id(self._pkey)
def bits(self):
"""
Returns the number of bits of the key
:return: The number of bits of the key.
"""
return _lib.EVP_PKEY_bits(self._pkey)
PKeyType = deprecated(
PKey, __name__,
"PKeyType has been deprecated, use PKey instead",
DeprecationWarning
)
class _EllipticCurve(object):
"""
A representation of a supported elliptic curve.
@cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
instances each of which represents one curve supported by the system.
@type _curves: :py:type:`NoneType` or :py:type:`set`
"""
_curves = None
if _PY3:
# This only necessary on Python 3. Morever, it is broken on Python 2.
def __ne__(self, other):
"""
Implement cooperation with the right-hand side argument of ``!=``.
Python 3 seems to have dropped this cooperation in this very narrow
circumstance.
"""
if isinstance(other, _EllipticCurve):
return super(_EllipticCurve, self).__ne__(other)
return NotImplemented
@classmethod
def _load_elliptic_curves(cls, lib):
"""
Get the curves supported by OpenSSL.
:param lib: The OpenSSL library binding object.
:return: A :py:type:`set` of ``cls`` instances giving the names of the
elliptic curves the underlying library supports.
"""
num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
# The return value on this call should be num_curves again. We
# could check it to make sure but if it *isn't* then.. what could
# we do? Abort the whole process, I suppose...? -exarkun
lib.EC_get_builtin_curves(builtin_curves, num_curves)
return set(
cls.from_nid(lib, c.nid)
for c in builtin_curves)
@classmethod
def _get_elliptic_curves(cls, lib):
"""
Get, cache, and return the curves supported by OpenSSL.
:param lib: The OpenSSL library binding object.
:return: A :py:type:`set` of ``cls`` instances giving the names of the
elliptic curves the underlying library supports.
"""
if cls._curves is None:
cls._curves = cls._load_elliptic_curves(lib)
return cls._curves
@classmethod
def from_nid(cls, lib, nid):
"""
Instantiate a new :py:class:`_EllipticCurve` associated with the given
OpenSSL NID.
:param lib: The OpenSSL library binding object.
:param nid: The OpenSSL NID the resulting curve object will represent.
This must be a curve NID (and not, for example, a hash NID) or
subsequent operations will fail in unpredictable ways.
:type nid: :py:class:`int`
:return: The curve object.
"""
return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
def __init__(self, lib, nid, name):
"""
:param _lib: The :py:mod:`cryptography` binding instance used to
interface with OpenSSL.
:param _nid: The OpenSSL NID identifying the curve this object
represents.
:type _nid: :py:class:`int`
:param name: The OpenSSL short name identifying the curve this object
represents.
:type name: :py:class:`unicode`
"""
self._lib = lib
self._nid = nid
self.name = name
def __repr__(self):
return "" % (self.name,)
def _to_EC_KEY(self):
"""
Create a new OpenSSL EC_KEY structure initialized to use this curve.
The structure is automatically garbage collected when the Python object
is garbage collected.
"""
key = self._lib.EC_KEY_new_by_curve_name(self._nid)
return _ffi.gc(key, _lib.EC_KEY_free)
def get_elliptic_curves():
"""
Return a set of objects representing the elliptic curves supported in the
OpenSSL build in use.
The curve objects have a :py:class:`unicode` ``name`` attribute by which
they identify themselves.
The curve objects are useful as values for the argument accepted by
:py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
used for ECDHE key exchange.
"""
return _EllipticCurve._get_elliptic_curves(_lib)
def get_elliptic_curve(name):
"""
Return a single curve object selected by name.
See :py:func:`get_elliptic_curves` for information about curve objects.
:param name: The OpenSSL short name identifying the curve object to
retrieve.
:type name: :py:class:`unicode`
If the named curve is not supported then :py:class:`ValueError` is raised.
"""
for curve in get_elliptic_curves():
if curve.name == name:
return curve
raise ValueError("unknown curve name", name)
class X509Name(object):
"""
An X.509 Distinguished Name.
:ivar countryName: The country of the entity.
:ivar C: Alias for :py:attr:`countryName`.
:ivar stateOrProvinceName: The state or province of the entity.
:ivar ST: Alias for :py:attr:`stateOrProvinceName`.
:ivar localityName: The locality of the entity.
:ivar L: Alias for :py:attr:`localityName`.
:ivar organizationName: The organization name of the entity.
:ivar O: Alias for :py:attr:`organizationName`.
:ivar organizationalUnitName: The organizational unit of the entity.
:ivar OU: Alias for :py:attr:`organizationalUnitName`
:ivar commonName: The common name of the entity.
:ivar CN: Alias for :py:attr:`commonName`.
:ivar emailAddress: The e-mail address of the entity.
"""
def __init__(self, name):
"""
Create a new X509Name, copying the given X509Name instance.
:param name: The name to copy.
:type name: :py:class:`X509Name`
"""
name = _lib.X509_NAME_dup(name._name)
self._name = _ffi.gc(name, _lib.X509_NAME_free)
def __setattr__(self, name, value):
if name.startswith('_'):
return super(X509Name, self).__setattr__(name, value)
# Note: we really do not want str subclasses here, so we do not use
# isinstance.
if type(name) is not str:
raise TypeError("attribute name must be string, not '%.200s'" % (
type(value).__name__,))
nid = _lib.OBJ_txt2nid(_byte_string(name))
if nid == _lib.NID_undef:
try:
_raise_current_error()
except Error:
pass
raise AttributeError("No such attribute")
# If there's an old entry for this NID, remove it
for i in range(_lib.X509_NAME_entry_count(self._name)):
ent = _lib.X509_NAME_get_entry(self._name, i)
ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
ent_nid = _lib.OBJ_obj2nid(ent_obj)
if nid == ent_nid:
ent = _lib.X509_NAME_delete_entry(self._name, i)
_lib.X509_NAME_ENTRY_free(ent)
break
if isinstance(value, _text_type):
value = value.encode('utf-8')
add_result = _lib.X509_NAME_add_entry_by_NID(
self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
if not add_result:
_raise_current_error()
def __getattr__(self, name):
"""
Find attribute. An X509Name object has the following attributes:
countryName (alias C), stateOrProvince (alias ST), locality (alias L),
organization (alias O), organizationalUnit (alias OU), commonName
(alias CN) and more...
"""
nid = _lib.OBJ_txt2nid(_byte_string(name))
if nid == _lib.NID_undef:
# This is a bit weird. OBJ_txt2nid indicated failure, but it seems
# a lower level function, a2d_ASN1_OBJECT, also feels the need to
# push something onto the error queue. If we don't clean that up
# now, someone else will bump into it later and be quite confused.
# See lp#314814.
try:
_raise_current_error()
except Error:
pass
return super(X509Name, self).__getattr__(name)
entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
if entry_index == -1:
return None
entry = _lib.X509_NAME_get_entry(self._name, entry_index)
data = _lib.X509_NAME_ENTRY_get_data(entry)
result_buffer = _ffi.new("unsigned char**")
data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
_openssl_assert(data_length >= 0)
try:
result = _ffi.buffer(
result_buffer[0], data_length
)[:].decode('utf-8')
finally:
# XXX untested
_lib.OPENSSL_free(result_buffer[0])
return result
def _cmp(op):
def f(self, other):
if not isinstance(other, X509Name):
return NotImplemented
result = _lib.X509_NAME_cmp(self._name, other._name)
return op(result, 0)
return f
__eq__ = _cmp(__eq__)
__ne__ = _cmp(__ne__)
__lt__ = _cmp(__lt__)
__le__ = _cmp(__le__)
__gt__ = _cmp(__gt__)
__ge__ = _cmp(__ge__)
def __repr__(self):
"""
String representation of an X509Name
"""
result_buffer = _ffi.new("char[]", 512)
format_result = _lib.X509_NAME_oneline(
self._name, result_buffer, len(result_buffer))
_openssl_assert(format_result != _ffi.NULL)
return "" % (
_native(_ffi.string(result_buffer)),)
def hash(self):
"""
Return an integer representation of the first four bytes of the
MD5 digest of the DER representation of the name.
This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
:return: The (integer) hash of this name.
:rtype: :py:class:`int`
"""
return _lib.X509_NAME_hash(self._name)
def der(self):
"""
Return the DER encoding of this name.
:return: The DER encoded form of this name.
:rtype: :py:class:`bytes`
"""
result_buffer = _ffi.new('unsigned char**')
encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
_openssl_assert(encode_result >= 0)
string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
_lib.OPENSSL_free(result_buffer[0])
return string_result
def get_components(self):
"""
Returns the components of this name, as a sequence of 2-tuples.
:return: The components of this name.
:rtype: :py:class:`list` of ``name, value`` tuples.
"""
result = []
for i in range(_lib.X509_NAME_entry_count(self._name)):
ent = _lib.X509_NAME_get_entry(self._name, i)
fname = _lib.X509_NAME_ENTRY_get_object(ent)
fval = _lib.X509_NAME_ENTRY_get_data(ent)
nid = _lib.OBJ_obj2nid(fname)
name = _lib.OBJ_nid2sn(nid)
# ffi.string does not handle strings containing NULL bytes
# (which may have been generated by old, broken software)
value = _ffi.buffer(_lib.ASN1_STRING_data(fval),
_lib.ASN1_STRING_length(fval))[:]
result.append((_ffi.string(name), value))
return result
X509NameType = deprecated(
X509Name, __name__,
"X509NameType has been deprecated, use X509Name instead",
DeprecationWarning
)
class X509Extension(object):
"""
An X.509 v3 certificate extension.
"""
def __init__(self, type_name, critical, value, subject=None, issuer=None):
"""
Initializes an X509 extension.
:param type_name: The name of the type of extension_ to create.
:type type_name: :py:data:`bytes`
:param bool critical: A flag indicating whether this is a critical
extension.
:param value: The value of the extension.
:type value: :py:data:`bytes`
:param subject: Optional X509 certificate to use as subject.
:type subject: :py:class:`X509`
:param issuer: Optional X509 certificate to use as issuer.
:type issuer: :py:class:`X509`
.. _extension: https://www.openssl.org/docs/manmaster/man5/
x509v3_config.html#STANDARD-EXTENSIONS
"""
ctx = _ffi.new("X509V3_CTX*")
# A context is necessary for any extension which uses the r2i
# conversion method. That is, X509V3_EXT_nconf may segfault if passed
# a NULL ctx. Start off by initializing most of the fields to NULL.
_lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
# We have no configuration database - but perhaps we should (some
# extensions may require it).
_lib.X509V3_set_ctx_nodb(ctx)
# Initialize the subject and issuer, if appropriate. ctx is a local,
# and as far as I can tell none of the X509V3_* APIs invoked here steal
# any references, so no need to mess with reference counts or
# duplicates.
if issuer is not None:
if not isinstance(issuer, X509):
raise TypeError("issuer must be an X509 instance")
ctx.issuer_cert = issuer._x509
if subject is not None:
if not isinstance(subject, X509):
raise TypeError("subject must be an X509 instance")
ctx.subject_cert = subject._x509
if critical:
# There are other OpenSSL APIs which would let us pass in critical
# separately, but they're harder to use, and since value is already
# a pile of crappy junk smuggling a ton of utterly important
# structured data, what's the point of trying to avoid nasty stuff
# with strings? (However, X509V3_EXT_i2d in particular seems like
# it would be a better API to invoke. I do not know where to get
# the ext_struc it desires for its last parameter, though.)
value = b"critical," + value
extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
if extension == _ffi.NULL:
_raise_current_error()
self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
@property
def _nid(self):
return _lib.OBJ_obj2nid(
_lib.X509_EXTENSION_get_object(self._extension)
)
_prefixes = {
_lib.GEN_EMAIL: "email",
_lib.GEN_DNS: "DNS",
_lib.GEN_URI: "URI",
}
def _subjectAltNameString(self):
names = _ffi.cast(
"GENERAL_NAMES*", _lib.X509V3_EXT_d2i(self._extension)
)
names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
parts = []
for i in range(_lib.sk_GENERAL_NAME_num(names)):
name = _lib.sk_GENERAL_NAME_value(names, i)
try:
label = self._prefixes[name.type]
except KeyError:
bio = _new_mem_buf()
_lib.GENERAL_NAME_print(bio, name)
parts.append(_native(_bio_to_string(bio)))
else:
value = _native(
_ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
parts.append(label + ":" + value)
return ", ".join(parts)
def __str__(self):
"""
:return: a nice text representation of the extension
"""
if _lib.NID_subject_alt_name == self._nid:
return self._subjectAltNameString()
bio = _new_mem_buf()
print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
_openssl_assert(print_result != 0)
return _native(_bio_to_string(bio))
def get_critical(self):
"""
Returns the critical field of this X.509 extension.
:return: The critical field.
"""
return _lib.X509_EXTENSION_get_critical(self._extension)
def get_short_name(self):
"""
Returns the short type name of this X.509 extension.
The result is a byte string such as :py:const:`b"basicConstraints"`.
:return: The short type name.
:rtype: :py:data:`bytes`
.. versionadded:: 0.12
"""
obj = _lib.X509_EXTENSION_get_object(self._extension)
nid = _lib.OBJ_obj2nid(obj)
return _ffi.string(_lib.OBJ_nid2sn(nid))
def get_data(self):
"""
Returns the data of the X509 extension, encoded as ASN.1.
:return: The ASN.1 encoded data of this X509 extension.
:rtype: :py:data:`bytes`
.. versionadded:: 0.12
"""
octet_result = _lib.X509_EXTENSION_get_data(self._extension)
string_result = _ffi.cast('ASN1_STRING*', octet_result)
char_result = _lib.ASN1_STRING_data(string_result)
result_length = _lib.ASN1_STRING_length(string_result)
return _ffi.buffer(char_result, result_length)[:]
X509ExtensionType = deprecated(
X509Extension, __name__,
"X509ExtensionType has been deprecated, use X509Extension instead",
DeprecationWarning
)
class X509Req(object):
"""
An X.509 certificate signing requests.
"""
def __init__(self):
req = _lib.X509_REQ_new()
self._req = _ffi.gc(req, _lib.X509_REQ_free)
# Default to version 0.
self.set_version(0)
def to_cryptography(self):
"""
Export as a ``cryptography`` certificate signing request.
:rtype: ``cryptography.x509.CertificateSigningRequest``
.. versionadded:: 17.1.0
"""
from cryptography.hazmat.backends.openssl.x509 import (
_CertificateSigningRequest
)
backend = _get_backend()
return _CertificateSigningRequest(backend, self._req)
@classmethod
def from_cryptography(cls, crypto_req):
"""
Construct based on a ``cryptography`` *crypto_req*.
:param crypto_req: A ``cryptography`` X.509 certificate signing request
:type crypto_req: ``cryptography.x509.CertificateSigningRequest``
:rtype: X509Req
.. versionadded:: 17.1.0
"""
if not isinstance(crypto_req, x509.CertificateSigningRequest):
raise TypeError("Must be a certificate signing request")
req = cls()
req._req = crypto_req._x509_req
return req
def set_pubkey(self, pkey):
"""
Set the public key of the certificate signing request.
:param pkey: The public key to use.
:type pkey: :py:class:`PKey`
:return: ``None``
"""
set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
_openssl_assert(set_result == 1)
def get_pubkey(self):
"""
Get the public key of the certificate signing request.
:return: The public key.
:rtype: :py:class:`PKey`
"""
pkey = PKey.__new__(PKey)
pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
_openssl_assert(pkey._pkey != _ffi.NULL)
pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
pkey._only_public = True
return pkey
def set_version(self, version):
"""
Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
request.
:param int version: The version number.
:return: ``None``
"""
set_result = _lib.X509_REQ_set_version(self._req, version)
_openssl_assert(set_result == 1)
def get_version(self):
"""
Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
request.
:return: The value of the version subfield.
:rtype: :py:class:`int`
"""
return _lib.X509_REQ_get_version(self._req)
def get_subject(self):
"""
Return the subject of this certificate signing request.
This creates a new :class:`X509Name` that wraps the underlying subject
name field on the certificate signing request. Modifying it will modify
the underlying signing request, and will have the effect of modifying
any other :class:`X509Name` that refers to this subject.
:return: The subject of this certificate signing request.
:rtype: :class:`X509Name`
"""
name = X509Name.__new__(X509Name)
name._name = _lib.X509_REQ_get_subject_name(self._req)
_openssl_assert(name._name != _ffi.NULL)
# The name is owned by the X509Req structure. As long as the X509Name
# Python object is alive, keep the X509Req Python object alive.
name._owner = self
return name
def add_extensions(self, extensions):
"""
Add extensions to the certificate signing request.
:param extensions: The X.509 extensions to add.
:type extensions: iterable of :py:class:`X509Extension`
:return: ``None``
"""
stack = _lib.sk_X509_EXTENSION_new_null()
_openssl_assert(stack != _ffi.NULL)
stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
for ext in extensions:
if not isinstance(ext, X509Extension):
raise ValueError("One of the elements is not an X509Extension")
# TODO push can fail (here and elsewhere)
_lib.sk_X509_EXTENSION_push(stack, ext._extension)
add_result = _lib.X509_REQ_add_extensions(self._req, stack)
_openssl_assert(add_result == 1)
def get_extensions(self):
"""
Get X.509 extensions in the certificate signing request.
:return: The X.509 extensions in this request.
:rtype: :py:class:`list` of :py:class:`X509Extension` objects.
.. versionadded:: 0.15
"""
exts = []
native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
ext = X509Extension.__new__(X509Extension)
ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
exts.append(ext)
return exts
def sign(self, pkey, digest):
"""
Sign the certificate signing request with this key and digest type.
:param pkey: The key pair to sign with.
:type pkey: :py:class:`PKey`
:param digest: The name of the message digest to use for the signature,
e.g. :py:data:`b"sha256"`.
:type digest: :py:class:`bytes`
:return: ``None``
"""
if pkey._only_public:
raise ValueError("Key has only public part")
if not pkey._initialized:
raise ValueError("Key is uninitialized")
digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
if digest_obj == _ffi.NULL:
raise ValueError("No such digest method")
sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
_openssl_assert(sign_result > 0)
def verify(self, pkey):
"""
Verifies the signature on this certificate signing request.
:param PKey key: A public key.
:return: ``True`` if the signature is correct.
:rtype: bool
:raises OpenSSL.crypto.Error: If the signature is invalid or there is a
problem verifying the signature.
"""
if not isinstance(pkey, PKey):
raise TypeError("pkey must be a PKey instance")
result = _lib.X509_REQ_verify(self._req, pkey._pkey)
if result <= 0:
_raise_current_error()
return result
X509ReqType = deprecated(
X509Req, __name__,
"X509ReqType has been deprecated, use X509Req instead",
DeprecationWarning
)
class X509(object):
"""
An X.509 certificate.
"""
def __init__(self):
x509 = _lib.X509_new()
_openssl_assert(x509 != _ffi.NULL)
self._x509 = _ffi.gc(x509, _lib.X509_free)
self._issuer_invalidator = _X509NameInvalidator()
self._subject_invalidator = _X509NameInvalidator()
@classmethod
def _from_raw_x509_ptr(cls, x509):
cert = cls.__new__(cls)
cert._x509 = _ffi.gc(x509, _lib.X509_free)
cert._issuer_invalidator = _X509NameInvalidator()
cert._subject_invalidator = _X509NameInvalidator()
return cert
def to_cryptography(self):
"""
Export as a ``cryptography`` certificate.
:rtype: ``cryptography.x509.Certificate``
.. versionadded:: 17.1.0
"""
from cryptography.hazmat.backends.openssl.x509 import _Certificate
backend = _get_backend()
return _Certificate(backend, self._x509)
@classmethod
def from_cryptography(cls, crypto_cert):
"""
Construct based on a ``cryptography`` *crypto_cert*.
:param crypto_key: A ``cryptography`` X.509 certificate.
:type crypto_key: ``cryptography.x509.Certificate``
:rtype: X509
.. versionadded:: 17.1.0
"""
if not isinstance(crypto_cert, x509.Certificate):
raise TypeError("Must be a certificate")
cert = cls()
cert._x509 = crypto_cert._x509
return cert
def set_version(self, version):
"""
Set the version number of the certificate. Note that the
version value is zero-based, eg. a value of 0 is V1.
:param version: The version number of the certificate.
:type version: :py:class:`int`
:return: ``None``
"""
if not isinstance(version, int):
raise TypeError("version must be an integer")
_lib.X509_set_version(self._x509, version)
def get_version(self):
"""
Return the version number of the certificate.
:return: The version number of the certificate.
:rtype: :py:class:`int`
"""
return _lib.X509_get_version(self._x509)
def get_pubkey(self):
"""
Get the public key of the certificate.
:return: The public key.
:rtype: :py:class:`PKey`
"""
pkey = PKey.__new__(PKey)
pkey._pkey = _lib.X509_get_pubkey(self._x509)
if pkey._pkey == _ffi.NULL:
_raise_current_error()
pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
pkey._only_public = True
return pkey
def set_pubkey(self, pkey):
"""
Set the public key of the certificate.
:param pkey: The public key.
:type pkey: :py:class:`PKey`
:return: :py:data:`None`
"""
if not isinstance(pkey, PKey):
raise TypeError("pkey must be a PKey instance")
set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
_openssl_assert(set_result == 1)
def sign(self, pkey, digest):
"""
Sign the certificate with this key and digest type.
:param pkey: The key to sign with.
:type pkey: :py:class:`PKey`
:param digest: The name of the message digest to use.
:type digest: :py:class:`bytes`
:return: :py:data:`None`
"""
if not isinstance(pkey, PKey):
raise TypeError("pkey must be a PKey instance")
if pkey._only_public:
raise ValueError("Key only has public part")
if not pkey._initialized:
raise ValueError("Key is uninitialized")
evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
if evp_md == _ffi.NULL:
raise ValueError("No such digest method")
sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
_openssl_assert(sign_result > 0)
def get_signature_algorithm(self):
"""
Return the signature algorithm used in the certificate.
:return: The name of the algorithm.
:rtype: :py:class:`bytes`
:raises ValueError: If the signature algorithm is undefined.
.. versionadded:: 0.13
"""
algor = _lib.X509_get0_tbs_sigalg(self._x509)
nid = _lib.OBJ_obj2nid(algor.algorithm)
if nid == _lib.NID_undef:
raise ValueError("Undefined signature algorithm")
return _ffi.string(_lib.OBJ_nid2ln(nid))
def digest(self, digest_name):
"""
Return the digest of the X509 object.
:param digest_name: The name of the digest algorithm to use.
:type digest_name: :py:class:`bytes`
:return: The digest of the object, formatted as
:py:const:`b":"`-delimited hex pairs.
:rtype: :py:class:`bytes`
"""
digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
if digest == _ffi.NULL:
raise ValueError("No such digest method")
result_buffer = _ffi.new("unsigned char[]", _lib.EVP_MAX_MD_SIZE)
result_length = _ffi.new("unsigned int[]", 1)
result_length[0] = len(result_buffer)
digest_result = _lib.X509_digest(
self._x509, digest, result_buffer, result_length)
_openssl_assert(digest_result == 1)
return b":".join([
b16encode(ch).upper() for ch
in _ffi.buffer(result_buffer, result_length[0])])
def subject_name_hash(self):
"""
Return the hash of the X509 subject.
:return: The hash of the subject.
:rtype: :py:class:`bytes`
"""
return _lib.X509_subject_name_hash(self._x509)
def set_serial_number(self, serial):
"""
Set the serial number of the certificate.
:param serial: The new serial number.
:type serial: :py:class:`int`
:return: :py:data`None`
"""
if not isinstance(serial, _integer_types):
raise TypeError("serial must be an integer")
hex_serial = hex(serial)[2:]
if not isinstance(hex_serial, bytes):
hex_serial = hex_serial.encode('ascii')
bignum_serial = _ffi.new("BIGNUM**")
# BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
# it. If bignum is still NULL after this call, then the return value
# is actually the result. I hope. -exarkun
small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
if bignum_serial[0] == _ffi.NULL:
set_result = _lib.ASN1_INTEGER_set(
_lib.X509_get_serialNumber(self._x509), small_serial)
if set_result:
# TODO Not tested
_raise_current_error()
else:
asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
_lib.BN_free(bignum_serial[0])
if asn1_serial == _ffi.NULL:
# TODO Not tested
_raise_current_error()
asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
_openssl_assert(set_result == 1)
def get_serial_number(self):
"""
Return the serial number of this certificate.
:return: The serial number.
:rtype: int
"""
asn1_serial = _lib.X509_get_serialNumber(self._x509)
bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
try:
hex_serial = _lib.BN_bn2hex(bignum_serial)
try:
hexstring_serial = _ffi.string(hex_serial)
serial = int(hexstring_serial, 16)
return serial
finally:
_lib.OPENSSL_free(hex_serial)
finally:
_lib.BN_free(bignum_serial)
def gmtime_adj_notAfter(self, amount):
"""
Adjust the time stamp on which the certificate stops being valid.
:param int amount: The number of seconds by which to adjust the
timestamp.
:return: ``None``
"""
if not isinstance(amount, int):
raise TypeError("amount must be an integer")
notAfter = _lib.X509_get_notAfter(self._x509)
_lib.X509_gmtime_adj(notAfter, amount)
def gmtime_adj_notBefore(self, amount):
"""
Adjust the timestamp on which the certificate starts being valid.
:param amount: The number of seconds by which to adjust the timestamp.
:return: ``None``
"""
if not isinstance(amount, int):
raise TypeError("amount must be an integer")
notBefore = _lib.X509_get_notBefore(self._x509)
_lib.X509_gmtime_adj(notBefore, amount)
def has_expired(self):
"""
Check whether the certificate has expired.
:return: ``True`` if the certificate has expired, ``False`` otherwise.
:rtype: bool
"""
time_string = _native(self.get_notAfter())
not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ")
return not_after < datetime.datetime.utcnow()
def _get_boundary_time(self, which):
return _get_asn1_time(which(self._x509))
def get_notBefore(self):
"""
Get the timestamp at which the certificate starts being valid.
The timestamp is formatted as an ASN.1 TIME::
YYYYMMDDhhmmssZ
:return: A timestamp string, or ``None`` if there is none.
:rtype: bytes or NoneType
"""
return self._get_boundary_time(_lib.X509_get_notBefore)
def _set_boundary_time(self, which, when):
return _set_asn1_time(which(self._x509), when)
def set_notBefore(self, when):
"""
Set the timestamp at which the certificate starts being valid.
The timestamp is formatted as an ASN.1 TIME::
YYYYMMDDhhmmssZ
:param bytes when: A timestamp string.
:return: ``None``
"""
return self._set_boundary_time(_lib.X509_get_notBefore, when)
def get_notAfter(self):
"""
Get the timestamp at which the certificate stops being valid.
The timestamp is formatted as an ASN.1 TIME::
YYYYMMDDhhmmssZ
:return: A timestamp string, or ``None`` if there is none.
:rtype: bytes or NoneType
"""
return self._get_boundary_time(_lib.X509_get_notAfter)
def set_notAfter(self, when):
"""
Set the timestamp at which the certificate stops being valid.
The timestamp is formatted as an ASN.1 TIME::
YYYYMMDDhhmmssZ
:param bytes when: A timestamp string.
:return: ``None``
"""
return self._set_boundary_time(_lib.X509_get_notAfter, when)
def _get_name(self, which):
name = X509Name.__new__(X509Name)
name._name = which(self._x509)
_openssl_assert(name._name != _ffi.NULL)
# The name is owned by the X509 structure. As long as the X509Name
# Python object is alive, keep the X509 Python object alive.
name._owner = self
return name
def _set_name(self, which, name):
if not isinstance(name, X509Name):
raise TypeError("name must be an X509Name")
set_result = which(self._x509, name._name)
_openssl_assert(set_result == 1)
def get_issuer(self):
"""
Return the issuer of this certificate.
This creates a new :class:`X509Name` that wraps the underlying issuer
name field on the certificate. Modifying it will modify the underlying
certificate, and will have the effect of modifying any other
:class:`X509Name` that refers to this issuer.
:return: The issuer of this certificate.
:rtype: :class:`X509Name`
"""
name = self._get_name(_lib.X509_get_issuer_name)
self._issuer_invalidator.add(name)
return name
def set_issuer(self, issuer):
"""
Set the issuer of this certificate.
:param issuer: The issuer.
:type issuer: :py:class:`X509Name`
:return: ``None``
"""
self._set_name(_lib.X509_set_issuer_name, issuer)
self._issuer_invalidator.clear()
def get_subject(self):
"""
Return the subject of this certificate.
This creates a new :class:`X509Name` that wraps the underlying subject
name field on the certificate. Modifying it will modify the underlying
certificate, and will have the effect of modifying any other
:class:`X509Name` that refers to this subject.
:return: The subject of this certificate.
:rtype: :class:`X509Name`
"""
name = self._get_name(_lib.X509_get_subject_name)
self._subject_invalidator.add(name)
return name
def set_subject(self, subject):
"""
Set the subject of this certificate.
:param subject: The subject.
:type subject: :py:class:`X509Name`
:return: ``None``
"""
self._set_name(_lib.X509_set_subject_name, subject)
self._subject_invalidator.clear()
def get_extension_count(self):
"""
Get the number of extensions on this certificate.
:return: The number of extensions.
:rtype: :py:class:`int`
.. versionadded:: 0.12
"""
return _lib.X509_get_ext_count(self._x509)
def add_extensions(self, extensions):
"""
Add extensions to the certificate.
:param extensions: The extensions to add.
:type extensions: An iterable of :py:class:`X509Extension` objects.
:return: ``None``
"""
for ext in extensions:
if not isinstance(ext, X509Extension):
raise ValueError("One of the elements is not an X509Extension")
add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
if not add_result:
_raise_current_error()
def get_extension(self, index):
"""
Get a specific extension of the certificate by index.
Extensions on a certificate are kept in order. The index
parameter selects which extension will be returned.
:param int index: The index of the extension to retrieve.
:return: The extension at the specified index.
:rtype: :py:class:`X509Extension`
:raises IndexError: If the extension index was out of bounds.
.. versionadded:: 0.12
"""
ext = X509Extension.__new__(X509Extension)
ext._extension = _lib.X509_get_ext(self._x509, index)
if ext._extension == _ffi.NULL:
raise IndexError("extension index out of bounds")
extension = _lib.X509_EXTENSION_dup(ext._extension)
ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
return ext
X509Type = deprecated(
X509, __name__,
"X509Type has been deprecated, use X509 instead",
DeprecationWarning
)
class X509StoreFlags(object):
"""
Flags for X509 verification, used to change the behavior of
:class:`X509Store`.
See `OpenSSL Verification Flags`_ for details.
.. _OpenSSL Verification Flags:
https://www.openssl.org/docs/manmaster/man3/X509_VERIFY_PARAM_set_flags.html
"""
CRL_CHECK = _lib.X509_V_FLAG_CRL_CHECK
CRL_CHECK_ALL = _lib.X509_V_FLAG_CRL_CHECK_ALL
IGNORE_CRITICAL = _lib.X509_V_FLAG_IGNORE_CRITICAL
X509_STRICT = _lib.X509_V_FLAG_X509_STRICT
ALLOW_PROXY_CERTS = _lib.X509_V_FLAG_ALLOW_PROXY_CERTS
POLICY_CHECK = _lib.X509_V_FLAG_POLICY_CHECK
EXPLICIT_POLICY = _lib.X509_V_FLAG_EXPLICIT_POLICY
INHIBIT_MAP = _lib.X509_V_FLAG_INHIBIT_MAP
NOTIFY_POLICY = _lib.X509_V_FLAG_NOTIFY_POLICY
CHECK_SS_SIGNATURE = _lib.X509_V_FLAG_CHECK_SS_SIGNATURE
CB_ISSUER_CHECK = _lib.X509_V_FLAG_CB_ISSUER_CHECK
class X509Store(object):
"""
An X.509 store.
An X.509 store is used to describe a context in which to verify a
certificate. A description of a context may include a set of certificates
to trust, a set of certificate revocation lists, verification flags and
more.
An X.509 store, being only a description, cannot be used by itself to
verify a certificate. To carry out the actual verification process, see
:class:`X509StoreContext`.
"""
def __init__(self):
store = _lib.X509_STORE_new()
self._store = _ffi.gc(store, _lib.X509_STORE_free)
def add_cert(self, cert):
"""
Adds a trusted certificate to this store.
Adding a certificate with this method adds this certificate as a
*trusted* certificate.
:param X509 cert: The certificate to add to this store.
:raises TypeError: If the certificate is not an :class:`X509`.
:raises OpenSSL.crypto.Error: If OpenSSL was unhappy with your
certificate.
:return: ``None`` if the certificate was added successfully.
"""
if not isinstance(cert, X509):
raise TypeError()
# As of OpenSSL 1.1.0i adding the same cert to the store more than
# once doesn't cause an error. Accordingly, this code now silences
# the error for OpenSSL < 1.1.0i as well.
if _lib.X509_STORE_add_cert(self._store, cert._x509) == 0:
code = _lib.ERR_peek_error()
err_reason = _lib.ERR_GET_REASON(code)
_openssl_assert(
err_reason == _lib.X509_R_CERT_ALREADY_IN_HASH_TABLE
)
_lib.ERR_clear_error()
def add_crl(self, crl):
"""
Add a certificate revocation list to this store.
The certificate revocation lists added to a store will only be used if
the associated flags are configured to check certificate revocation
lists.
.. versionadded:: 16.1.0
:param CRL crl: The certificate revocation list to add to this store.
:return: ``None`` if the certificate revocation list was added
successfully.
"""
_openssl_assert(_lib.X509_STORE_add_crl(self._store, crl._crl) != 0)
def set_flags(self, flags):
"""
Set verification flags to this store.
Verification flags can be combined by oring them together.
.. note::
Setting a verification flag sometimes requires clients to add
additional information to the store, otherwise a suitable error will
be raised.
For example, in setting flags to enable CRL checking a
suitable CRL must be added to the store otherwise an error will be
raised.
.. versionadded:: 16.1.0
:param int flags: The verification flags to set on this store.
See :class:`X509StoreFlags` for available constants.
:return: ``None`` if the verification flags were successfully set.
"""
_openssl_assert(_lib.X509_STORE_set_flags(self._store, flags) != 0)
def set_time(self, vfy_time):
"""
Set the time against which the certificates are verified.
Normally the current time is used.
.. note::
For example, you can determine if a certificate was valid at a given
time.
.. versionadded:: 17.0.0
:param datetime vfy_time: The verification time to set on this store.
:return: ``None`` if the verification time was successfully set.
"""
param = _lib.X509_VERIFY_PARAM_new()
param = _ffi.gc(param, _lib.X509_VERIFY_PARAM_free)
_lib.X509_VERIFY_PARAM_set_time(param, int(vfy_time.strftime('%s')))
_openssl_assert(_lib.X509_STORE_set1_param(self._store, param) != 0)
X509StoreType = deprecated(
X509Store, __name__,
"X509StoreType has been deprecated, use X509Store instead",
DeprecationWarning
)
class X509StoreContextError(Exception):
"""
An exception raised when an error occurred while verifying a certificate
using `OpenSSL.X509StoreContext.verify_certificate`.
:ivar certificate: The certificate which caused verificate failure.
:type certificate: :class:`X509`
"""
def __init__(self, message, certificate):
super(X509StoreContextError, self).__init__(message)
self.certificate = certificate
class X509StoreContext(object):
"""
An X.509 store context.
An X.509 store context is used to carry out the actual verification process
of a certificate in a described context. For describing such a context, see
:class:`X509Store`.
:ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
instance. It is dynamically allocated and automatically garbage
collected.
:ivar _store: See the ``store`` ``__init__`` parameter.
:ivar _cert: See the ``certificate`` ``__init__`` parameter.
:param X509Store store: The certificates which will be trusted for the
purposes of any verifications.
:param X509 certificate: The certificate to be verified.
"""
def __init__(self, store, certificate):
store_ctx = _lib.X509_STORE_CTX_new()
self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
self._store = store
self._cert = certificate
# Make the store context available for use after instantiating this
# class by initializing it now. Per testing, subsequent calls to
# :meth:`_init` have no adverse affect.
self._init()
def _init(self):
"""
Set up the store context for a subsequent verification operation.
Calling this method more than once without first calling
:meth:`_cleanup` will leak memory.
"""
ret = _lib.X509_STORE_CTX_init(
self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL
)
if ret <= 0:
_raise_current_error()
def _cleanup(self):
"""
Internally cleans up the store context.
The store context can then be reused with a new call to :meth:`_init`.
"""
_lib.X509_STORE_CTX_cleanup(self._store_ctx)
def _exception_from_context(self):
"""
Convert an OpenSSL native context error failure into a Python
exception.
When a call to native OpenSSL X509_verify_cert fails, additional
information about the failure can be obtained from the store context.
"""
errors = [
_lib.X509_STORE_CTX_get_error(self._store_ctx),
_lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
_native(_ffi.string(_lib.X509_verify_cert_error_string(
_lib.X509_STORE_CTX_get_error(self._store_ctx)))),
]
# A context error should always be associated with a certificate, so we
# expect this call to never return :class:`None`.
_x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
_cert = _lib.X509_dup(_x509)
pycert = X509._from_raw_x509_ptr(_cert)
return X509StoreContextError(errors, pycert)
def set_store(self, store):
"""
Set the context's X.509 store.
.. versionadded:: 0.15
:param X509Store store: The store description which will be used for
the purposes of any *future* verifications.
"""
self._store = store
def verify_certificate(self):
"""
Verify a certificate in a context.
.. versionadded:: 0.15
:raises X509StoreContextError: If an error occurred when validating a
certificate in the context. Sets ``certificate`` attribute to
indicate which certificate caused the error.
"""
# Always re-initialize the store context in case
# :meth:`verify_certificate` is called multiple times.
#
# :meth:`_init` is called in :meth:`__init__` so _cleanup is called
# before _init to ensure memory is not leaked.
self._cleanup()
self._init()
ret = _lib.X509_verify_cert(self._store_ctx)
self._cleanup()
if ret <= 0:
raise self._exception_from_context()
def load_certificate(type, buffer):
"""
Load a certificate (X509) from the string *buffer* encoded with the
type *type*.
:param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
:param bytes buffer: The buffer the certificate is stored in
:return: The X509 object
"""
if isinstance(buffer, _text_type):
buffer = buffer.encode("ascii")
bio = _new_mem_buf(buffer)
if type == FILETYPE_PEM:
x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
elif type == FILETYPE_ASN1:
x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
else:
raise ValueError(
"type argument must be FILETYPE_PEM or FILETYPE_ASN1")
if x509 == _ffi.NULL:
_raise_current_error()
return X509._from_raw_x509_ptr(x509)
def dump_certificate(type, cert):
"""
Dump the certificate *cert* into a buffer string encoded with the type
*type*.
:param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
FILETYPE_TEXT)
:param cert: The certificate to dump
:return: The buffer with the dumped certificate in
"""
bio = _new_mem_buf()
if type == FILETYPE_PEM:
result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
elif type == FILETYPE_ASN1:
result_code = _lib.i2d_X509_bio(bio, cert._x509)
elif type == FILETYPE_TEXT:
result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
else:
raise ValueError(
"type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
"FILETYPE_TEXT")
assert result_code == 1
return _bio_to_string(bio)
def dump_publickey(type, pkey):
"""
Dump a public key to a buffer.
:param type: The file type (one of :data:`FILETYPE_PEM` or
:data:`FILETYPE_ASN1`).
:param PKey pkey: The public key to dump
:return: The buffer with the dumped key in it.
:rtype: bytes
"""
bio = _new_mem_buf()
if type == FILETYPE_PEM:
write_bio = _lib.PEM_write_bio_PUBKEY
elif type == FILETYPE_ASN1:
write_bio = _lib.i2d_PUBKEY_bio
else:
raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
result_code = write_bio(bio, pkey._pkey)
if result_code != 1: # pragma: no cover
_raise_current_error()
return _bio_to_string(bio)
def dump_privatekey(type, pkey, cipher=None, passphrase=None):
"""
Dump the private key *pkey* into a buffer string encoded with the type
*type*. Optionally (if *type* is :const:`FILETYPE_PEM`) encrypting it
using *cipher* and *passphrase*.
:param type: The file type (one of :const:`FILETYPE_PEM`,
:const:`FILETYPE_ASN1`, or :const:`FILETYPE_TEXT`)
:param PKey pkey: The PKey to dump
:param cipher: (optional) if encrypted PEM format, the cipher to use
:param passphrase: (optional) if encrypted PEM format, this can be either
the passphrase to use, or a callback for providing the passphrase.
:return: The buffer with the dumped key in
:rtype: bytes
"""
bio = _new_mem_buf()
if not isinstance(pkey, PKey):
raise TypeError("pkey must be a PKey")
if cipher is not None:
if passphrase is None:
raise TypeError(
"if a value is given for cipher "
"one must also be given for passphrase")
cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
if cipher_obj == _ffi.NULL:
raise ValueError("Invalid cipher name")
else:
cipher_obj = _ffi.NULL
helper = _PassphraseHelper(type, passphrase)
if type == FILETYPE_PEM:
result_code = _lib.PEM_write_bio_PrivateKey(
bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
helper.callback, helper.callback_args)
helper.raise_if_problem()
elif type == FILETYPE_ASN1:
result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
elif type == FILETYPE_TEXT:
if _lib.EVP_PKEY_id(pkey._pkey) != _lib.EVP_PKEY_RSA:
raise TypeError("Only RSA keys are supported for FILETYPE_TEXT")
rsa = _ffi.gc(
_lib.EVP_PKEY_get1_RSA(pkey._pkey),
_lib.RSA_free
)
result_code = _lib.RSA_print(bio, rsa, 0)
else:
raise ValueError(
"type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
"FILETYPE_TEXT")
_openssl_assert(result_code != 0)
return _bio_to_string(bio)
class Revoked(object):
"""
A certificate revocation.
"""
# https://www.openssl.org/docs/manmaster/man5/x509v3_config.html#CRL-distribution-points
# which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
# OCSP_crl_reason_str. We use the latter, just like the command line
# program.
_crl_reasons = [
b"unspecified",
b"keyCompromise",
b"CACompromise",
b"affiliationChanged",
b"superseded",
b"cessationOfOperation",
b"certificateHold",
# b"removeFromCRL",
]
def __init__(self):
revoked = _lib.X509_REVOKED_new()
self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
def set_serial(self, hex_str):
"""
Set the serial number.
The serial number is formatted as a hexadecimal number encoded in
ASCII.
:param bytes hex_str: The new serial number.
:return: ``None``
"""
bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
bignum_ptr = _ffi.new("BIGNUM**")
bignum_ptr[0] = bignum_serial
bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
if not bn_result:
raise ValueError("bad hex string")
asn1_serial = _ffi.gc(
_lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
_lib.ASN1_INTEGER_free)
_lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
def get_serial(self):
"""
Get the serial number.
The serial number is formatted as a hexadecimal number encoded in
ASCII.
:return: The serial number.
:rtype: bytes
"""
bio = _new_mem_buf()
asn1_int = _lib.X509_REVOKED_get0_serialNumber(self._revoked)
_openssl_assert(asn1_int != _ffi.NULL)
result = _lib.i2a_ASN1_INTEGER(bio, asn1_int)
_openssl_assert(result >= 0)
return _bio_to_string(bio)
def _delete_reason(self):
for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
obj = _lib.X509_EXTENSION_get_object(ext)
if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
_lib.X509_EXTENSION_free(ext)
_lib.X509_REVOKED_delete_ext(self._revoked, i)
break
def set_reason(self, reason):
"""
Set the reason of this revocation.
If :data:`reason` is ``None``, delete the reason instead.
:param reason: The reason string.
:type reason: :class:`bytes` or :class:`NoneType`
:return: ``None``
.. seealso::
:meth:`all_reasons`, which gives you a list of all supported
reasons which you might pass to this method.
"""
if reason is None:
self._delete_reason()
elif not isinstance(reason, bytes):
raise TypeError("reason must be None or a byte string")
else:
reason = reason.lower().replace(b' ', b'')
reason_code = [r.lower() for r in self._crl_reasons].index(reason)
new_reason_ext = _lib.ASN1_ENUMERATED_new()
_openssl_assert(new_reason_ext != _ffi.NULL)
new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
_openssl_assert(set_result != _ffi.NULL)
self._delete_reason()
add_result = _lib.X509_REVOKED_add1_ext_i2d(
self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
_openssl_assert(add_result == 1)
def get_reason(self):
"""
Get the reason of this revocation.
:return: The reason, or ``None`` if there is none.
:rtype: bytes or NoneType
.. seealso::
:meth:`all_reasons`, which gives you a list of all supported
reasons this method might return.
"""
for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
obj = _lib.X509_EXTENSION_get_object(ext)
if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
bio = _new_mem_buf()
print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
if not print_result:
print_result = _lib.M_ASN1_OCTET_STRING_print(
bio, _lib.X509_EXTENSION_get_data(ext)
)
_openssl_assert(print_result != 0)
return _bio_to_string(bio)
def all_reasons(self):
"""
Return a list of all the supported reason strings.
This list is a copy; modifying it does not change the supported reason
strings.
:return: A list of reason strings.
:rtype: :class:`list` of :class:`bytes`
"""
return self._crl_reasons[:]
def set_rev_date(self, when):
"""
Set the revocation timestamp.
:param bytes when: The timestamp of the revocation,
as ASN.1 TIME.
:return: ``None``
"""
dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
return _set_asn1_time(dt, when)
def get_rev_date(self):
"""
Get the revocation timestamp.
:return: The timestamp of the revocation, as ASN.1 TIME.
:rtype: bytes
"""
dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
return _get_asn1_time(dt)
class CRL(object):
"""
A certificate revocation list.
"""
def __init__(self):
crl = _lib.X509_CRL_new()
self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
def to_cryptography(self):
"""
Export as a ``cryptography`` CRL.
:rtype: ``cryptography.x509.CertificateRevocationList``
.. versionadded:: 17.1.0
"""
from cryptography.hazmat.backends.openssl.x509 import (
_CertificateRevocationList
)
backend = _get_backend()
return _CertificateRevocationList(backend, self._crl)
@classmethod
def from_cryptography(cls, crypto_crl):
"""
Construct based on a ``cryptography`` *crypto_crl*.
:param crypto_crl: A ``cryptography`` certificate revocation list
:type crypto_crl: ``cryptography.x509.CertificateRevocationList``
:rtype: CRL
.. versionadded:: 17.1.0
"""
if not isinstance(crypto_crl, x509.CertificateRevocationList):
raise TypeError("Must be a certificate revocation list")
crl = cls()
crl._crl = crypto_crl._x509_crl
return crl
def get_revoked(self):
"""
Return the revocations in this certificate revocation list.
These revocations will be provided by value, not by reference.
That means it's okay to mutate them: it won't affect this CRL.
:return: The revocations in this CRL.
:rtype: :class:`tuple` of :class:`Revocation`
"""
results = []
revoked_stack = _lib.X509_CRL_get_REVOKED(self._crl)
for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
revoked_copy = _lib.Cryptography_X509_REVOKED_dup(revoked)
pyrev = Revoked.__new__(Revoked)
pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
results.append(pyrev)
if results:
return tuple(results)
def add_revoked(self, revoked):
"""
Add a revoked (by value not reference) to the CRL structure
This revocation will be added by value, not by reference. That
means it's okay to mutate it after adding: it won't affect
this CRL.
:param Revoked revoked: The new revocation.
:return: ``None``
"""
copy = _lib.Cryptography_X509_REVOKED_dup(revoked._revoked)
_openssl_assert(copy != _ffi.NULL)
add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
_openssl_assert(add_result != 0)
def get_issuer(self):
"""
Get the CRL's issuer.
.. versionadded:: 16.1.0
:rtype: X509Name
"""
_issuer = _lib.X509_NAME_dup(_lib.X509_CRL_get_issuer(self._crl))
_openssl_assert(_issuer != _ffi.NULL)
_issuer = _ffi.gc(_issuer, _lib.X509_NAME_free)
issuer = X509Name.__new__(X509Name)
issuer._name = _issuer
return issuer
def set_version(self, version):
"""
Set the CRL version.
.. versionadded:: 16.1.0
:param int version: The version of the CRL.
:return: ``None``
"""
_openssl_assert(_lib.X509_CRL_set_version(self._crl, version) != 0)
def _set_boundary_time(self, which, when):
return _set_asn1_time(which(self._crl), when)
def set_lastUpdate(self, when):
"""
Set when the CRL was last updated.
The timestamp is formatted as an ASN.1 TIME::
YYYYMMDDhhmmssZ
.. versionadded:: 16.1.0
:param bytes when: A timestamp string.
:return: ``None``
"""
return self._set_boundary_time(_lib.X509_CRL_get_lastUpdate, when)
def set_nextUpdate(self, when):
"""
Set when the CRL will next be udpated.
The timestamp is formatted as an ASN.1 TIME::
YYYYMMDDhhmmssZ
.. versionadded:: 16.1.0
:param bytes when: A timestamp string.
:return: ``None``
"""
return self._set_boundary_time(_lib.X509_CRL_get_nextUpdate, when)
def sign(self, issuer_cert, issuer_key, digest):
"""
Sign the CRL.
Signing a CRL enables clients to associate the CRL itself with an
issuer. Before a CRL is meaningful to other OpenSSL functions, it must
be signed by an issuer.
This method implicitly sets the issuer's name based on the issuer
certificate and private key used to sign the CRL.
.. versionadded:: 16.1.0
:param X509 issuer_cert: The issuer's certificate.
:param PKey issuer_key: The issuer's private key.
:param bytes digest: The digest method to sign the CRL with.
"""
digest_obj = _lib.EVP_get_digestbyname(digest)
_openssl_assert(digest_obj != _ffi.NULL)
_lib.X509_CRL_set_issuer_name(
self._crl, _lib.X509_get_subject_name(issuer_cert._x509))
_lib.X509_CRL_sort(self._crl)
result = _lib.X509_CRL_sign(self._crl, issuer_key._pkey, digest_obj)
_openssl_assert(result != 0)
def export(self, cert, key, type=FILETYPE_PEM, days=100,
digest=_UNSPECIFIED):
"""
Export the CRL as a string.
:param X509 cert: The certificate used to sign the CRL.
:param PKey key: The key used to sign the CRL.
:param int type: The export format, either :data:`FILETYPE_PEM`,
:data:`FILETYPE_ASN1`, or :data:`FILETYPE_TEXT`.
:param int days: The number of days until the next update of this CRL.
:param bytes digest: The name of the message digest to use (eg
``b"sha2566"``).
:rtype: bytes
"""
if not isinstance(cert, X509):
raise TypeError("cert must be an X509 instance")
if not isinstance(key, PKey):
raise TypeError("key must be a PKey instance")
if not isinstance(type, int):
raise TypeError("type must be an integer")
if digest is _UNSPECIFIED:
raise TypeError("digest must be provided")
digest_obj = _lib.EVP_get_digestbyname(digest)
if digest_obj == _ffi.NULL:
raise ValueError("No such digest method")
bio = _lib.BIO_new(_lib.BIO_s_mem())
_openssl_assert(bio != _ffi.NULL)
# A scratch time object to give different values to different CRL
# fields
sometime = _lib.ASN1_TIME_new()
_openssl_assert(sometime != _ffi.NULL)
_lib.X509_gmtime_adj(sometime, 0)
_lib.X509_CRL_set_lastUpdate(self._crl, sometime)
_lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
_lib.X509_CRL_set_nextUpdate(self._crl, sometime)
_lib.X509_CRL_set_issuer_name(
self._crl, _lib.X509_get_subject_name(cert._x509)
)
sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
if not sign_result:
_raise_current_error()
return dump_crl(type, self)
CRLType = deprecated(
CRL, __name__,
"CRLType has been deprecated, use CRL instead",
DeprecationWarning
)
class PKCS7(object):
def type_is_signed(self):
"""
Check if this NID_pkcs7_signed object
:return: True if the PKCS7 is of type signed
"""
return bool(_lib.PKCS7_type_is_signed(self._pkcs7))
def type_is_enveloped(self):
"""
Check if this NID_pkcs7_enveloped object
:returns: True if the PKCS7 is of type enveloped
"""
return bool(_lib.PKCS7_type_is_enveloped(self._pkcs7))
def type_is_signedAndEnveloped(self):
"""
Check if this NID_pkcs7_signedAndEnveloped object
:returns: True if the PKCS7 is of type signedAndEnveloped
"""
return bool(_lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7))
def type_is_data(self):
"""
Check if this NID_pkcs7_data object
:return: True if the PKCS7 is of type data
"""
return bool(_lib.PKCS7_type_is_data(self._pkcs7))
def get_type_name(self):
"""
Returns the type name of the PKCS7 structure
:return: A string with the typename
"""
nid = _lib.OBJ_obj2nid(self._pkcs7.type)
string_type = _lib.OBJ_nid2sn(nid)
return _ffi.string(string_type)
PKCS7Type = deprecated(
PKCS7, __name__,
"PKCS7Type has been deprecated, use PKCS7 instead",
DeprecationWarning
)
class PKCS12(object):
"""
A PKCS #12 archive.
"""
def __init__(self):
self._pkey = None
self._cert = None
self._cacerts = None
self._friendlyname = None
def get_certificate(self):
"""
Get the certificate in the PKCS #12 structure.
:return: The certificate, or :py:const:`None` if there is none.
:rtype: :py:class:`X509` or :py:const:`None`
"""
return self._cert
def set_certificate(self, cert):
"""
Set the certificate in the PKCS #12 structure.
:param cert: The new certificate, or :py:const:`None` to unset it.
:type cert: :py:class:`X509` or :py:const:`None`
:return: ``None``
"""
if not isinstance(cert, X509):
raise TypeError("cert must be an X509 instance")
self._cert = cert
def get_privatekey(self):
"""
Get the private key in the PKCS #12 structure.
:return: The private key, or :py:const:`None` if there is none.
:rtype: :py:class:`PKey`
"""
return self._pkey
def set_privatekey(self, pkey):
"""
Set the certificate portion of the PKCS #12 structure.
:param pkey: The new private key, or :py:const:`None` to unset it.
:type pkey: :py:class:`PKey` or :py:const:`None`
:return: ``None``
"""
if not isinstance(pkey, PKey):
raise TypeError("pkey must be a PKey instance")
self._pkey = pkey
def get_ca_certificates(self):
"""
Get the CA certificates in the PKCS #12 structure.
:return: A tuple with the CA certificates in the chain, or
:py:const:`None` if there are none.
:rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
"""
if self._cacerts is not None:
return tuple(self._cacerts)
def set_ca_certificates(self, cacerts):
"""
Replace or set the CA certificates within the PKCS12 object.
:param cacerts: The new CA certificates, or :py:const:`None` to unset
them.
:type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
:return: ``None``
"""
if cacerts is None:
self._cacerts = None
else:
cacerts = list(cacerts)
for cert in cacerts:
if not isinstance(cert, X509):
raise TypeError(
"iterable must only contain X509 instances"
)
self._cacerts = cacerts
def set_friendlyname(self, name):
"""
Set the friendly name in the PKCS #12 structure.
:param name: The new friendly name, or :py:const:`None` to unset.
:type name: :py:class:`bytes` or :py:const:`None`
:return: ``None``
"""
if name is None:
self._friendlyname = None
elif not isinstance(name, bytes):
raise TypeError(
"name must be a byte string or None (not %r)" % (name,)
)
self._friendlyname = name
def get_friendlyname(self):
"""
Get the friendly name in the PKCS# 12 structure.
:returns: The friendly name, or :py:const:`None` if there is none.
:rtype: :py:class:`bytes` or :py:const:`None`
"""
return self._friendlyname
def export(self, passphrase=None, iter=2048, maciter=1):
"""
Dump a PKCS12 object as a string.
For more information, see the :c:func:`PKCS12_create` man page.
:param passphrase: The passphrase used to encrypt the structure. Unlike
some other passphrase arguments, this *must* be a string, not a
callback.
:type passphrase: :py:data:`bytes`
:param iter: Number of times to repeat the encryption step.
:type iter: :py:data:`int`
:param maciter: Number of times to repeat the MAC step.
:type maciter: :py:data:`int`
:return: The string representation of the PKCS #12 structure.
:rtype:
"""
passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
if self._cacerts is None:
cacerts = _ffi.NULL
else:
cacerts = _lib.sk_X509_new_null()
cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
for cert in self._cacerts:
_lib.sk_X509_push(cacerts, cert._x509)
if passphrase is None:
passphrase = _ffi.NULL
friendlyname = self._friendlyname
if friendlyname is None:
friendlyname = _ffi.NULL
if self._pkey is None:
pkey = _ffi.NULL
else:
pkey = self._pkey._pkey
if self._cert is None:
cert = _ffi.NULL
else:
cert = self._cert._x509
pkcs12 = _lib.PKCS12_create(
passphrase, friendlyname, pkey, cert, cacerts,
_lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
_lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
iter, maciter, 0)
if pkcs12 == _ffi.NULL:
_raise_current_error()
pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
bio = _new_mem_buf()
_lib.i2d_PKCS12_bio(bio, pkcs12)
return _bio_to_string(bio)
PKCS12Type = deprecated(
PKCS12, __name__,
"PKCS12Type has been deprecated, use PKCS12 instead",
DeprecationWarning
)
class NetscapeSPKI(object):
"""
A Netscape SPKI object.
"""
def __init__(self):
spki = _lib.NETSCAPE_SPKI_new()
self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
def sign(self, pkey, digest):
"""
Sign the certificate request with this key and digest type.
:param pkey: The private key to sign with.
:type pkey: :py:class:`PKey`
:param digest: The message digest to use.
:type digest: :py:class:`bytes`
:return: ``None``
"""
if pkey._only_public:
raise ValueError("Key has only public part")
if not pkey._initialized:
raise ValueError("Key is uninitialized")
digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
if digest_obj == _ffi.NULL:
raise ValueError("No such digest method")
sign_result = _lib.NETSCAPE_SPKI_sign(
self._spki, pkey._pkey, digest_obj
)
_openssl_assert(sign_result > 0)
def verify(self, key):
"""
Verifies a signature on a certificate request.
:param PKey key: The public key that signature is supposedly from.
:return: ``True`` if the signature is correct.
:rtype: bool
:raises OpenSSL.crypto.Error: If the signature is invalid, or there was
a problem verifying the signature.
"""
answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
if answer <= 0:
_raise_current_error()
return True
def b64_encode(self):
"""
Generate a base64 encoded representation of this SPKI object.
:return: The base64 encoded string.
:rtype: :py:class:`bytes`
"""
encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
result = _ffi.string(encoded)
_lib.OPENSSL_free(encoded)
return result
def get_pubkey(self):
"""
Get the public key of this certificate.
:return: The public key.
:rtype: :py:class:`PKey`
"""
pkey = PKey.__new__(PKey)
pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
_openssl_assert(pkey._pkey != _ffi.NULL)
pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
pkey._only_public = True
return pkey
def set_pubkey(self, pkey):
"""
Set the public key of the certificate
:param pkey: The public key
:return: ``None``
"""
set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
_openssl_assert(set_result == 1)
NetscapeSPKIType = deprecated(
NetscapeSPKI, __name__,
"NetscapeSPKIType has been deprecated, use NetscapeSPKI instead",
DeprecationWarning
)
class _PassphraseHelper(object):
def __init__(self, type, passphrase, more_args=False, truncate=False):
if type != FILETYPE_PEM and passphrase is not None:
raise ValueError(
"only FILETYPE_PEM key format supports encryption"
)
self._passphrase = passphrase
self._more_args = more_args
self._truncate = truncate
self._problems = []
@property
def callback(self):
if self._passphrase is None:
return _ffi.NULL
elif isinstance(self._passphrase, bytes):
return _ffi.NULL
elif callable(self._passphrase):
return _ffi.callback("pem_password_cb", self._read_passphrase)
else:
raise TypeError(
"Last argument must be a byte string or a callable."
)
@property
def callback_args(self):
if self._passphrase is None:
return _ffi.NULL
elif isinstance(self._passphrase, bytes):
return self._passphrase
elif callable(self._passphrase):
return _ffi.NULL
else:
raise TypeError(
"Last argument must be a byte string or a callable."
)
def raise_if_problem(self, exceptionType=Error):
if self._problems:
# Flush the OpenSSL error queue
try:
_exception_from_error_queue(exceptionType)
except exceptionType:
pass
raise self._problems.pop(0)
def _read_passphrase(self, buf, size, rwflag, userdata):
try:
if self._more_args:
result = self._passphrase(size, rwflag, userdata)
else:
result = self._passphrase(rwflag)
if not isinstance(result, bytes):
raise ValueError("String expected")
if len(result) > size:
if self._truncate:
result = result[:size]
else:
raise ValueError(
"passphrase returned by callback is too long"
)
for i in range(len(result)):
buf[i] = result[i:i + 1]
return len(result)
except Exception as e:
self._problems.append(e)
return 0
def load_publickey(type, buffer):
"""
Load a public key from a buffer.
:param type: The file type (one of :data:`FILETYPE_PEM`,
:data:`FILETYPE_ASN1`).
:param buffer: The buffer the key is stored in.
:type buffer: A Python string object, either unicode or bytestring.
:return: The PKey object.
:rtype: :class:`PKey`
"""
if isinstance(buffer, _text_type):
buffer = buffer.encode("ascii")
bio = _new_mem_buf(buffer)
if type == FILETYPE_PEM:
evp_pkey = _lib.PEM_read_bio_PUBKEY(
bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
elif type == FILETYPE_ASN1:
evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
else:
raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
if evp_pkey == _ffi.NULL:
_raise_current_error()
pkey = PKey.__new__(PKey)
pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
pkey._only_public = True
return pkey
def load_privatekey(type, buffer, passphrase=None):
"""
Load a private key (PKey) from the string *buffer* encoded with the type
*type*.
:param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
:param buffer: The buffer the key is stored in
:param passphrase: (optional) if encrypted PEM format, this can be
either the passphrase to use, or a callback for
providing the passphrase.
:return: The PKey object
"""
if isinstance(buffer, _text_type):
buffer = buffer.encode("ascii")
bio = _new_mem_buf(buffer)
helper = _PassphraseHelper(type, passphrase)
if type == FILETYPE_PEM:
evp_pkey = _lib.PEM_read_bio_PrivateKey(
bio, _ffi.NULL, helper.callback, helper.callback_args)
helper.raise_if_problem()
elif type == FILETYPE_ASN1:
evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
else:
raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
if evp_pkey == _ffi.NULL:
_raise_current_error()
pkey = PKey.__new__(PKey)
pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
return pkey
def dump_certificate_request(type, req):
"""
Dump the certificate request *req* into a buffer string encoded with the
type *type*.
:param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
:param req: The certificate request to dump
:return: The buffer with the dumped certificate request in
"""
bio = _new_mem_buf()
if type == FILETYPE_PEM:
result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
elif type == FILETYPE_ASN1:
result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
elif type == FILETYPE_TEXT:
result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
else:
raise ValueError(
"type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
"FILETYPE_TEXT"
)
_openssl_assert(result_code != 0)
return _bio_to_string(bio)
def load_certificate_request(type, buffer):
"""
Load a certificate request (X509Req) from the string *buffer* encoded with
the type *type*.
:param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
:param buffer: The buffer the certificate request is stored in
:return: The X509Req object
"""
if isinstance(buffer, _text_type):
buffer = buffer.encode("ascii")
bio = _new_mem_buf(buffer)
if type == FILETYPE_PEM:
req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
elif type == FILETYPE_ASN1:
req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
else:
raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
_openssl_assert(req != _ffi.NULL)
x509req = X509Req.__new__(X509Req)
x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
return x509req
def sign(pkey, data, digest):
"""
Sign a data string using the given key and message digest.
:param pkey: PKey to sign with
:param data: data to be signed
:param digest: message digest to use
:return: signature
.. versionadded:: 0.11
"""
data = _text_to_bytes_and_warn("data", data)
digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
if digest_obj == _ffi.NULL:
raise ValueError("No such digest method")
md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
_lib.EVP_SignInit(md_ctx, digest_obj)
_lib.EVP_SignUpdate(md_ctx, data, len(data))
length = _lib.EVP_PKEY_size(pkey._pkey)
_openssl_assert(length > 0)
signature_buffer = _ffi.new("unsigned char[]", length)
signature_length = _ffi.new("unsigned int *")
final_result = _lib.EVP_SignFinal(
md_ctx, signature_buffer, signature_length, pkey._pkey)
_openssl_assert(final_result == 1)
return _ffi.buffer(signature_buffer, signature_length[0])[:]
def verify(cert, signature, data, digest):
"""
Verify the signature for a data string.
:param cert: signing certificate (X509 object) corresponding to the
private key which generated the signature.
:param signature: signature returned by sign function
:param data: data to be verified
:param digest: message digest to use
:return: ``None`` if the signature is correct, raise exception otherwise.
.. versionadded:: 0.11
"""
data = _text_to_bytes_and_warn("data", data)
digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
if digest_obj == _ffi.NULL:
raise ValueError("No such digest method")
pkey = _lib.X509_get_pubkey(cert._x509)
_openssl_assert(pkey != _ffi.NULL)
pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
_lib.EVP_VerifyInit(md_ctx, digest_obj)
_lib.EVP_VerifyUpdate(md_ctx, data, len(data))
verify_result = _lib.EVP_VerifyFinal(
md_ctx, signature, len(signature), pkey
)
if verify_result != 1:
_raise_current_error()
def dump_crl(type, crl):
"""
Dump a certificate revocation list to a buffer.
:param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
``FILETYPE_TEXT``).
:param CRL crl: The CRL to dump.
:return: The buffer with the CRL.
:rtype: bytes
"""
bio = _new_mem_buf()
if type == FILETYPE_PEM:
ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
elif type == FILETYPE_ASN1:
ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
elif type == FILETYPE_TEXT:
ret = _lib.X509_CRL_print(bio, crl._crl)
else:
raise ValueError(
"type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
"FILETYPE_TEXT")
assert ret == 1
return _bio_to_string(bio)
def load_crl(type, buffer):
"""
Load Certificate Revocation List (CRL) data from a string *buffer*.
*buffer* encoded with the type *type*.
:param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
:param buffer: The buffer the CRL is stored in
:return: The PKey object
"""
if isinstance(buffer, _text_type):
buffer = buffer.encode("ascii")
bio = _new_mem_buf(buffer)
if type == FILETYPE_PEM:
crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
elif type == FILETYPE_ASN1:
crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
else:
raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
if crl == _ffi.NULL:
_raise_current_error()
result = CRL.__new__(CRL)
result._crl = _ffi.gc(crl, _lib.X509_CRL_free)
return result
def load_pkcs7_data(type, buffer):
"""
Load pkcs7 data from the string *buffer* encoded with the type
*type*.
:param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
:param buffer: The buffer with the pkcs7 data.
:return: The PKCS7 object
"""
if isinstance(buffer, _text_type):
buffer = buffer.encode("ascii")
bio = _new_mem_buf(buffer)
if type == FILETYPE_PEM:
pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
elif type == FILETYPE_ASN1:
pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
else:
raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
if pkcs7 == _ffi.NULL:
_raise_current_error()
pypkcs7 = PKCS7.__new__(PKCS7)
pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
return pypkcs7
def load_pkcs12(buffer, passphrase=None):
"""
Load pkcs12 data from the string *buffer*. If the pkcs12 structure is
encrypted, a *passphrase* must be included. The MAC is always
checked and thus required.
See also the man page for the C function :py:func:`PKCS12_parse`.
:param buffer: The buffer the certificate is stored in
:param passphrase: (Optional) The password to decrypt the PKCS12 lump
:returns: The PKCS12 object
"""
passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
if isinstance(buffer, _text_type):
buffer = buffer.encode("ascii")
bio = _new_mem_buf(buffer)
# Use null passphrase if passphrase is None or empty string. With PKCS#12
# password based encryption no password and a zero length password are two
# different things, but OpenSSL implementation will try both to figure out
# which one works.
if not passphrase:
passphrase = _ffi.NULL
p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
if p12 == _ffi.NULL:
_raise_current_error()
p12 = _ffi.gc(p12, _lib.PKCS12_free)
pkey = _ffi.new("EVP_PKEY**")
cert = _ffi.new("X509**")
cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
if not parse_result:
_raise_current_error()
cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
# openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
# queue for no particular reason. This error isn't interesting to anyone
# outside this function. It's not even interesting to us. Get rid of it.
try:
_raise_current_error()
except Error:
pass
if pkey[0] == _ffi.NULL:
pykey = None
else:
pykey = PKey.__new__(PKey)
pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
if cert[0] == _ffi.NULL:
pycert = None
friendlyname = None
else:
pycert = X509._from_raw_x509_ptr(cert[0])
friendlyname_length = _ffi.new("int*")
friendlyname_buffer = _lib.X509_alias_get0(
cert[0], friendlyname_length
)
friendlyname = _ffi.buffer(
friendlyname_buffer, friendlyname_length[0]
)[:]
if friendlyname_buffer == _ffi.NULL:
friendlyname = None
pycacerts = []
for i in range(_lib.sk_X509_num(cacerts)):
x509 = _lib.sk_X509_value(cacerts, i)
pycacert = X509._from_raw_x509_ptr(x509)
pycacerts.append(pycacert)
if not pycacerts:
pycacerts = None
pkcs12 = PKCS12.__new__(PKCS12)
pkcs12._pkey = pykey
pkcs12._cert = pycert
pkcs12._cacerts = pycacerts
pkcs12._friendlyname = friendlyname
return pkcs12
# There are no direct unit tests for this initialization. It is tested
# indirectly since it is necessary for functions like dump_privatekey when
# using encryption.
#
# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
# and some other similar tests may fail without this (though they may not if
# the Python runtime has already done some initialization of the underlying
# OpenSSL library (and is linked against the same one that cryptography is
# using)).
_lib.OpenSSL_add_all_algorithms()
# This is similar but exercised mainly by exception_from_error_queue. It calls
# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
_lib.SSL_load_error_strings()
# Set the default string mask to match OpenSSL upstream (since 2005) and
# RFC5280 recommendations.
_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/OpenSSL/debug.py
================================================
from __future__ import print_function
import ssl
import sys
import OpenSSL.SSL
import cffi
import cryptography
from . import version
_env_info = u"""\
pyOpenSSL: {pyopenssl}
cryptography: {cryptography}
cffi: {cffi}
cryptography's compiled against OpenSSL: {crypto_openssl_compile}
cryptography's linked OpenSSL: {crypto_openssl_link}
Pythons's OpenSSL: {python_openssl}
Python executable: {python}
Python version: {python_version}
Platform: {platform}
sys.path: {sys_path}""".format(
pyopenssl=version.__version__,
crypto_openssl_compile=OpenSSL._util.ffi.string(
OpenSSL._util.lib.OPENSSL_VERSION_TEXT,
).decode("ascii"),
crypto_openssl_link=OpenSSL.SSL.SSLeay_version(
OpenSSL.SSL.SSLEAY_VERSION
).decode("ascii"),
python_openssl=getattr(ssl, "OPENSSL_VERSION", "n/a"),
cryptography=cryptography.__version__,
cffi=cffi.__version__,
python=sys.executable,
python_version=sys.version,
platform=sys.platform,
sys_path=sys.path,
)
if __name__ == "__main__":
print(_env_info)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/OpenSSL/rand.py
================================================
"""
PRNG management routines, thin wrappers.
"""
from OpenSSL._util import lib as _lib
def add(buffer, entropy):
"""
Mix bytes from *string* into the PRNG state.
The *entropy* argument is (the lower bound of) an estimate of how much
randomness is contained in *string*, measured in bytes.
For more information, see e.g. :rfc:`1750`.
This function is only relevant if you are forking Python processes and
need to reseed the CSPRNG after fork.
:param buffer: Buffer with random data.
:param entropy: The entropy (in bytes) measurement of the buffer.
:return: :obj:`None`
"""
if not isinstance(buffer, bytes):
raise TypeError("buffer must be a byte string")
if not isinstance(entropy, int):
raise TypeError("entropy must be an integer")
_lib.RAND_add(buffer, len(buffer), entropy)
def status():
"""
Check whether the PRNG has been seeded with enough data.
:return: 1 if the PRNG is seeded enough, 0 otherwise.
"""
return _lib.RAND_status()
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/OpenSSL/tsafe.py
================================================
import warnings
from threading import RLock as _RLock
from OpenSSL import SSL as _ssl
warnings.warn(
"OpenSSL.tsafe is deprecated and will be removed",
DeprecationWarning, stacklevel=3
)
class Connection:
def __init__(self, *args):
self._ssl_conn = _ssl.Connection(*args)
self._lock = _RLock()
for f in ('get_context', 'pending', 'send', 'write', 'recv', 'read',
'renegotiate', 'bind', 'listen', 'connect', 'accept',
'setblocking', 'fileno', 'shutdown', 'close', 'get_cipher_list',
'getpeername', 'getsockname', 'getsockopt', 'setsockopt',
'makefile', 'get_app_data', 'set_app_data', 'state_string',
'sock_shutdown', 'get_peer_certificate', 'get_peer_cert_chain',
'want_read', 'want_write', 'set_connect_state',
'set_accept_state', 'connect_ex', 'sendall'):
exec("""def %s(self, *args):
self._lock.acquire()
try:
return self._ssl_conn.%s(*args)
finally:
self._lock.release()\n""" % (f, f))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/OpenSSL/version.py
================================================
# Copyright (C) AB Strakt
# Copyright (C) Jean-Paul Calderone
# See LICENSE for details.
"""
pyOpenSSL - A simple wrapper around the OpenSSL library
"""
__all__ = [
"__author__", "__copyright__", "__email__", "__license__", "__summary__",
"__title__", "__uri__", "__version__",
]
__version__ = "19.0.0"
__title__ = "pyOpenSSL"
__uri__ = "https://pyopenssl.org/"
__summary__ = "Python wrapper module around the OpenSSL library"
__author__ = "The pyOpenSSL developers"
__email__ = "cryptography-dev@python.org"
__license__ = "Apache License, Version 2.0"
__copyright__ = "Copyright 2001-2017 {0}".format(__author__)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/PyDispatcher-2.0.5-py3.6.egg-info/PKG-INFO
================================================
Metadata-Version: 1.2
Name: PyDispatcher
Version: 2.0.5
Summary: Multi-producer-multi-consumer signal dispatching mechanism
Home-page: http://pydispatcher.sourceforge.net
Author: Patrick K. O'Brien
Author-email: pydispatcher-devel@lists.sourceforge.net
Maintainer: Mike C. Fletcher
Maintainer-email: pydispatcher-devel@lists.sourceforge.net
License: BSD
Description: Dispatcher mechanism for creating event models
PyDispatcher is an enhanced version of Patrick K. O'Brien's
original dispatcher.py module. It provides the Python
programmer with a robust mechanism for event routing within
various application contexts.
Included in the package are the robustapply and saferef
modules, which provide the ability to selectively apply
arguments to callable objects and to reference instance
methods using weak-references.
Keywords: dispatcher,dispatch,pydispatch,event,signal,sender,receiver,propagate,multi-consumer,multi-producer,saferef,robustapply,apply
Platform: Any
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Intended Audience :: Developers
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/PyDispatcher-2.0.5-py3.6.egg-info/SOURCES.txt
================================================
MANIFEST.in
license.txt
setup.cfg
setup.py
PyDispatcher.egg-info/PKG-INFO
PyDispatcher.egg-info/SOURCES.txt
PyDispatcher.egg-info/dependency_links.txt
PyDispatcher.egg-info/top_level.txt
docs/index.html
docs/images/greypinstripe.png
docs/pydoc/__init__.py
docs/pydoc/builddocs.py
docs/pydoc/pydispatch.__init__.html
docs/pydoc/pydispatch.dispatcher.html
docs/pydoc/pydispatch.errors.html
docs/pydoc/pydispatch.html
docs/pydoc/pydispatch.robust.html
docs/pydoc/pydispatch.robustapply.html
docs/pydoc/pydispatch.saferef.html
docs/pydoc/pydoc2.py
docs/pydoc/weakref.html
docs/style/sitestyle.css
examples/__init__.py
examples/extra_args.py
examples/hello_messages.py
examples/simple_sample.py
pydispatch/__init__.py
pydispatch/dispatcher.py
pydispatch/errors.py
pydispatch/robust.py
pydispatch/robustapply.py
pydispatch/saferef.py
tests/__init__.py
tests/test_dispatcher.py
tests/test_robustapply.py
tests/test_saferef.py
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/PyDispatcher-2.0.5-py3.6.egg-info/dependency_links.txt
================================================
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/PyDispatcher-2.0.5-py3.6.egg-info/installed-files.txt
================================================
../pydispatch/__init__.py
../pydispatch/__pycache__/__init__.cpython-36.pyc
../pydispatch/__pycache__/dispatcher.cpython-36.pyc
../pydispatch/__pycache__/errors.cpython-36.pyc
../pydispatch/__pycache__/robust.cpython-36.pyc
../pydispatch/__pycache__/robustapply.cpython-36.pyc
../pydispatch/__pycache__/saferef.cpython-36.pyc
../pydispatch/dispatcher.py
../pydispatch/errors.py
../pydispatch/robust.py
../pydispatch/robustapply.py
../pydispatch/saferef.py
PKG-INFO
SOURCES.txt
dependency_links.txt
top_level.txt
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/PyDispatcher-2.0.5-py3.6.egg-info/top_level.txt
================================================
pydispatch
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/PyHamcrest-1.9.0.dist-info/DESCRIPTION.rst
================================================
PyHamcrest
==========
| |docs| |travis| |coveralls| |landscape| |scrutinizer| |codeclimate|
| |version| |downloads| |wheel| |supported-versions| |supported-implementations|
.. |docs| image:: https://readthedocs.org/projects/pyhamcrest/badge/?style=flat
:target: https://pyhamcrest.readthedocs.org/
:alt: Documentation Status
.. |travis| image:: http://img.shields.io/travis/hamcrest/PyHamcrest/master.png?style=flat
:alt: Travis-CI Build Status
:target: https://travis-ci.org/hamcrest/PyHamcrest
.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/hamcrest/PyHamcrest?branch=master
:alt: AppVeyor Build Status
:target: https://ci.appveyor.com/project/hamcrest/PyHamcrest
.. |coveralls| image:: http://img.shields.io/coveralls/hamcrest/PyHamcrest/master.png?style=flat
:alt: Coverage Status
:target: https://coveralls.io/r/hamcrest/PyHamcrest
.. |landscape| image:: https://landscape.io/github/hamcrest/PyHamcrest/master/landscape.svg?style=flat
:target: https://landscape.io/github/hamcrest/PyHamcrest/master
:alt: Code Quality Status
.. |codeclimate| image:: https://codeclimate.com/github/hamcrest/PyHamcrest/badges/gpa.svg
:target: https://codeclimate.com/github/hamcrest/PyHamcrest
:alt: Code Climate
.. |version| image:: http://img.shields.io/pypi/v/PyHamcrest.png?style=flat
:alt: PyPI Package latest release
:target: https://pypi.python.org/pypi/PyHamcrest
.. |downloads| image:: http://img.shields.io/pypi/dm/PyHamcrest.png?style=flat
:alt: PyPI Package monthly downloads
:target: https://pypi.python.org/pypi/PyHamcrest
.. |wheel| image:: https://pypip.in/wheel/PyHamcrest/badge.png?style=flat
:alt: PyPI Wheel
:target: https://pypi.python.org/pypi/PyHamcrest
.. |supported-versions| image:: https://pypip.in/py_versions/PyHamcrest/badge.png?style=flat
:alt: Supported versions
:target: https://pypi.python.org/pypi/PyHamcrest
.. |supported-implementations| image:: https://pypip.in/implementation/PyHamcrest/badge.png?style=flat
:alt: Supported imlementations
:target: https://pypi.python.org/pypi/PyHamcrest
.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/hamcrest/PyHamcrest/master.png?style=flat
:alt: Scrtinizer Status
:target: https://scrutinizer-ci.com/g/hamcrest/PyHamcrest/
Introduction
============
PyHamcrest is a framework for writing matcher objects, allowing you to
declaratively define "match" rules. There are a number of situations where
matchers are invaluable, such as UI validation, or data filtering, but it is in
the area of writing flexible tests that matchers are most commonly used. This
tutorial shows you how to use PyHamcrest for unit testing.
When writing tests it is sometimes difficult to get the balance right between
overspecifying the test (and making it brittle to changes), and not specifying
enough (making the test less valuable since it continues to pass even when the
thing being tested is broken). Having a tool that allows you to pick out
precisely the aspect under test and describe the values it should have, to a
controlled level of precision, helps greatly in writing tests that are "just
right." Such tests fail when the behavior of the aspect under test deviates
from the expected behavior, yet continue to pass when minor, unrelated changes
to the behaviour are made.
Installation
============
Hamcrest can be installed using the usual Python packaging tools. It depends on
distribute, but as long as you have a network connection when you install, the
installation process will take care of that for you.
My first PyHamcrest test
========================
We'll start by writing a very simple PyUnit test, but instead of using PyUnit's
``assertEqual`` method, we'll use PyHamcrest's ``assert_that`` construct and
the standard set of matchers:
.. code:: python
from hamcrest import *
import unittest
class BiscuitTest(unittest.TestCase):
def testEquals(self):
theBiscuit = Biscuit('Ginger')
myBiscuit = Biscuit('Ginger')
assert_that(theBiscuit, equal_to(myBiscuit))
if __name__ == '__main__':
unittest.main()
The ``assert_that`` function is a stylized sentence for making a test
assertion. In this example, the subject of the assertion is the object
``theBiscuit``, which is the first method parameter. The second method
parameter is a matcher for ``Biscuit`` objects, here a matcher that checks one
object is equal to another using the Python ``==`` operator. The test passes
since the ``Biscuit`` class defines an ``__eq__`` method.
If you have more than one assertion in your test you can include an identifier
for the tested value in the assertion:
.. code:: python
assert_that(theBiscuit.getChocolateChipCount(), equal_to(10), 'chocolate chips')
assert_that(theBiscuit.getHazelnutCount(), equal_to(3), 'hazelnuts')
As a convenience, assert_that can also be used to verify a boolean condition:
.. code:: python
assert_that(theBiscuit.isCooked(), 'cooked')
This is equivalent to the ``assert_`` method of unittest.TestCase, but because
it's a standalone function, it offers greater flexibility in test writing.
Predefined matchers
===================
PyHamcrest comes with a library of useful matchers:
* Object
* ``equal_to`` - match equal object
* ``has_length`` - match ``len()``
* ``has_property`` - match value of property with given name
* ``has_properties`` - match an object that has all of the given properties.
* ``has_string`` - match ``str()``
* ``instance_of`` - match object type
* ``none``, ``not_none`` - match ``None``, or not ``None``
* ``same_instance`` - match same object
* ``calling, raises`` - wrap a method call and assert that it raises an exception
* Number
* ``close_to`` - match number close to a given value
* ``greater_than``, ``greater_than_or_equal_to``, ``less_than``,
``less_than_or_equal_to`` - match numeric ordering
* Text
* ``contains_string`` - match part of a string
* ``ends_with`` - match the end of a string
* ``equal_to_ignoring_case`` - match the complete string but ignore case
* ``equal_to_ignoring_whitespace`` - match the complete string but ignore extra whitespace
* ``matches_regexp`` - match a regular expression in a string
* ``starts_with`` - match the beginning of a string
* ``string_contains_in_order`` - match parts of a string, in relative order
* Logical
* ``all_of`` - ``and`` together all matchers
* ``any_of`` - ``or`` together all matchers
* ``anything`` - match anything, useful in composite matchers when you don't care about a particular value
* ``is_not`` - negate the matcher
* Sequence
* ``contains`` - exactly match the entire sequence
* ``contains_inanyorder`` - match the entire sequence, but in any order
* ``has_item`` - match if given item appears in the sequence
* ``has_items`` - match if all given items appear in the sequence, in any order
* ``is_in`` - match if item appears in the given sequence
* ``only_contains`` - match if sequence's items appear in given list
* ``empty`` - match if the sequence is empty
* Dictionary
* ``has_entries`` - match dictionary with list of key-value pairs
* ``has_entry`` - match dictionary containing a key-value pair
* ``has_key`` - match dictionary with a key
* ``has_value`` - match dictionary with a value
* Decorator
* ``calling`` - wrap a callable in a deffered object, for subsequent matching on calling behaviour
* ``raises`` - Ensure that a deferred callable raises as expected
* ``described_as`` - give the matcher a custom failure description
* ``is_`` - decorator to improve readability - see `Syntactic sugar` below
The arguments for many of these matchers accept not just a matching value, but
another matcher, so matchers can be composed for greater flexibility. For
example, ``only_contains(less_than(5))`` will match any sequence where every
item is less than 5.
Syntactic sugar
===============
PyHamcrest strives to make your tests as readable as possible. For example, the
``is_`` matcher is a wrapper that doesn't add any extra behavior to the
underlying matcher. The following assertions are all equivalent:
.. code:: python
assert_that(theBiscuit, equal_to(myBiscuit))
assert_that(theBiscuit, is_(equal_to(myBiscuit)))
assert_that(theBiscuit, is_(myBiscuit))
The last form is allowed since ``is_(value)`` wraps most non-matcher arguments
with ``equal_to``. But if the argument is a type, it is wrapped with
``instance_of``, so the following are also equivalent:
.. code:: python
assert_that(theBiscuit, instance_of(Biscuit))
assert_that(theBiscuit, is_(instance_of(Biscuit)))
assert_that(theBiscuit, is_(Biscuit))
*Note that PyHamcrest's ``is_`` matcher is unrelated to Python's ``is``
operator. The matcher for object identity is ``same_instance``.*
Writing custom matchers
=======================
PyHamcrest comes bundled with lots of useful matchers, but you'll probably find
that you need to create your own from time to time to fit your testing needs.
This commonly occurs when you find a fragment of code that tests the same set
of properties over and over again (and in different tests), and you want to
bundle the fragment into a single assertion. By writing your own matcher you'll
eliminate code duplication and make your tests more readable!
Let's write our own matcher for testing if a calendar date falls on a Saturday.
This is the test we want to write:
.. code:: python
def testDateIsOnASaturday(self):
d = datetime.date(2008, 04, 26)
assert_that(d, is_(on_a_saturday()))
And here's the implementation:
.. code:: python
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.hasmethod import hasmethod
class IsGivenDayOfWeek(BaseMatcher):
def __init__(self, day):
self.day = day # Monday is 0, Sunday is 6
def _matches(self, item):
if not hasmethod(item, 'weekday'):
return False
return item.weekday() == self.day
def describe_to(self, description):
day_as_string = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
'Friday', 'Saturday', 'Sunday']
description.append_text('calendar date falling on ') \
.append_text(day_as_string[self.day])
def on_a_saturday():
return IsGivenDayOfWeek(5)
For our Matcher implementation we implement the ``_matches`` method - which
calls the ``weekday`` method after confirming that the argument (which may not
be a date) has such a method - and the ``describe_to`` method - which is used
to produce a failure message when a test fails. Here's an example of how the
failure message looks:
.. code:: python
assert_that(datetime.date(2008, 04, 06), is_(on_a_saturday()))
fails with the message::
AssertionError:
Expected: is calendar date falling on Saturday
got: <2008-04-06>
Let's say this matcher is saved in a module named ``isgivendayofweek``. We
could use it in our test by importing the factory function ``on_a_saturday``:
.. code:: python
from hamcrest import *
import unittest
from isgivendayofweek import on_a_saturday
class DateTest(unittest.TestCase):
def testDateIsOnASaturday(self):
d = datetime.date(2008, 04, 26)
assert_that(d, is_(on_a_saturday()))
if __name__ == '__main__':
unittest.main()
Even though the ``on_a_saturday`` function creates a new matcher each time it
is called, you should not assume this is the only usage pattern for your
matcher. Therefore you should make sure your matcher is stateless, so a single
instance can be reused between matches.
More resources
==============
* Documentation_
* Package_
* Sources_
* Hamcrest_
.. _Documentation: http://readthedocs.org/docs/pyhamcrest/en/V1.8.2/
.. _Package: http://pypi.python.org/pypi/PyHamcrest
.. _Sources: https://github.com/hamcrest/PyHamcrest
.. _Hamcrest: http://hamcrest.org
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/PyHamcrest-1.9.0.dist-info/INSTALLER
================================================
pip
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/PyHamcrest-1.9.0.dist-info/METADATA
================================================
Metadata-Version: 2.0
Name: PyHamcrest
Version: 1.9.0
Summary: Hamcrest framework for matcher objects
Home-page: https://github.com/hamcrest/PyHamcrest
Author: Chris Rose
Author-email: offline@offby1.net
License: New BSD
Download-URL: http://pypi.python.org/packages/source/P/PyHamcrest/PyHamcrest-1.9.0.tar.gz
Keywords: hamcrest matchers pyunit unit test testing unittest unittesting
Platform: All
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: Jython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Testing
Provides: hamcrest
Requires-Dist: setuptools
Requires-Dist: six
PyHamcrest
==========
| |docs| |travis| |coveralls| |landscape| |scrutinizer| |codeclimate|
| |version| |downloads| |wheel| |supported-versions| |supported-implementations|
.. |docs| image:: https://readthedocs.org/projects/pyhamcrest/badge/?style=flat
:target: https://pyhamcrest.readthedocs.org/
:alt: Documentation Status
.. |travis| image:: http://img.shields.io/travis/hamcrest/PyHamcrest/master.png?style=flat
:alt: Travis-CI Build Status
:target: https://travis-ci.org/hamcrest/PyHamcrest
.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/hamcrest/PyHamcrest?branch=master
:alt: AppVeyor Build Status
:target: https://ci.appveyor.com/project/hamcrest/PyHamcrest
.. |coveralls| image:: http://img.shields.io/coveralls/hamcrest/PyHamcrest/master.png?style=flat
:alt: Coverage Status
:target: https://coveralls.io/r/hamcrest/PyHamcrest
.. |landscape| image:: https://landscape.io/github/hamcrest/PyHamcrest/master/landscape.svg?style=flat
:target: https://landscape.io/github/hamcrest/PyHamcrest/master
:alt: Code Quality Status
.. |codeclimate| image:: https://codeclimate.com/github/hamcrest/PyHamcrest/badges/gpa.svg
:target: https://codeclimate.com/github/hamcrest/PyHamcrest
:alt: Code Climate
.. |version| image:: http://img.shields.io/pypi/v/PyHamcrest.png?style=flat
:alt: PyPI Package latest release
:target: https://pypi.python.org/pypi/PyHamcrest
.. |downloads| image:: http://img.shields.io/pypi/dm/PyHamcrest.png?style=flat
:alt: PyPI Package monthly downloads
:target: https://pypi.python.org/pypi/PyHamcrest
.. |wheel| image:: https://pypip.in/wheel/PyHamcrest/badge.png?style=flat
:alt: PyPI Wheel
:target: https://pypi.python.org/pypi/PyHamcrest
.. |supported-versions| image:: https://pypip.in/py_versions/PyHamcrest/badge.png?style=flat
:alt: Supported versions
:target: https://pypi.python.org/pypi/PyHamcrest
.. |supported-implementations| image:: https://pypip.in/implementation/PyHamcrest/badge.png?style=flat
:alt: Supported imlementations
:target: https://pypi.python.org/pypi/PyHamcrest
.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/hamcrest/PyHamcrest/master.png?style=flat
:alt: Scrtinizer Status
:target: https://scrutinizer-ci.com/g/hamcrest/PyHamcrest/
Introduction
============
PyHamcrest is a framework for writing matcher objects, allowing you to
declaratively define "match" rules. There are a number of situations where
matchers are invaluable, such as UI validation, or data filtering, but it is in
the area of writing flexible tests that matchers are most commonly used. This
tutorial shows you how to use PyHamcrest for unit testing.
When writing tests it is sometimes difficult to get the balance right between
overspecifying the test (and making it brittle to changes), and not specifying
enough (making the test less valuable since it continues to pass even when the
thing being tested is broken). Having a tool that allows you to pick out
precisely the aspect under test and describe the values it should have, to a
controlled level of precision, helps greatly in writing tests that are "just
right." Such tests fail when the behavior of the aspect under test deviates
from the expected behavior, yet continue to pass when minor, unrelated changes
to the behaviour are made.
Installation
============
Hamcrest can be installed using the usual Python packaging tools. It depends on
distribute, but as long as you have a network connection when you install, the
installation process will take care of that for you.
My first PyHamcrest test
========================
We'll start by writing a very simple PyUnit test, but instead of using PyUnit's
``assertEqual`` method, we'll use PyHamcrest's ``assert_that`` construct and
the standard set of matchers:
.. code:: python
from hamcrest import *
import unittest
class BiscuitTest(unittest.TestCase):
def testEquals(self):
theBiscuit = Biscuit('Ginger')
myBiscuit = Biscuit('Ginger')
assert_that(theBiscuit, equal_to(myBiscuit))
if __name__ == '__main__':
unittest.main()
The ``assert_that`` function is a stylized sentence for making a test
assertion. In this example, the subject of the assertion is the object
``theBiscuit``, which is the first method parameter. The second method
parameter is a matcher for ``Biscuit`` objects, here a matcher that checks one
object is equal to another using the Python ``==`` operator. The test passes
since the ``Biscuit`` class defines an ``__eq__`` method.
If you have more than one assertion in your test you can include an identifier
for the tested value in the assertion:
.. code:: python
assert_that(theBiscuit.getChocolateChipCount(), equal_to(10), 'chocolate chips')
assert_that(theBiscuit.getHazelnutCount(), equal_to(3), 'hazelnuts')
As a convenience, assert_that can also be used to verify a boolean condition:
.. code:: python
assert_that(theBiscuit.isCooked(), 'cooked')
This is equivalent to the ``assert_`` method of unittest.TestCase, but because
it's a standalone function, it offers greater flexibility in test writing.
Predefined matchers
===================
PyHamcrest comes with a library of useful matchers:
* Object
* ``equal_to`` - match equal object
* ``has_length`` - match ``len()``
* ``has_property`` - match value of property with given name
* ``has_properties`` - match an object that has all of the given properties.
* ``has_string`` - match ``str()``
* ``instance_of`` - match object type
* ``none``, ``not_none`` - match ``None``, or not ``None``
* ``same_instance`` - match same object
* ``calling, raises`` - wrap a method call and assert that it raises an exception
* Number
* ``close_to`` - match number close to a given value
* ``greater_than``, ``greater_than_or_equal_to``, ``less_than``,
``less_than_or_equal_to`` - match numeric ordering
* Text
* ``contains_string`` - match part of a string
* ``ends_with`` - match the end of a string
* ``equal_to_ignoring_case`` - match the complete string but ignore case
* ``equal_to_ignoring_whitespace`` - match the complete string but ignore extra whitespace
* ``matches_regexp`` - match a regular expression in a string
* ``starts_with`` - match the beginning of a string
* ``string_contains_in_order`` - match parts of a string, in relative order
* Logical
* ``all_of`` - ``and`` together all matchers
* ``any_of`` - ``or`` together all matchers
* ``anything`` - match anything, useful in composite matchers when you don't care about a particular value
* ``is_not`` - negate the matcher
* Sequence
* ``contains`` - exactly match the entire sequence
* ``contains_inanyorder`` - match the entire sequence, but in any order
* ``has_item`` - match if given item appears in the sequence
* ``has_items`` - match if all given items appear in the sequence, in any order
* ``is_in`` - match if item appears in the given sequence
* ``only_contains`` - match if sequence's items appear in given list
* ``empty`` - match if the sequence is empty
* Dictionary
* ``has_entries`` - match dictionary with list of key-value pairs
* ``has_entry`` - match dictionary containing a key-value pair
* ``has_key`` - match dictionary with a key
* ``has_value`` - match dictionary with a value
* Decorator
* ``calling`` - wrap a callable in a deffered object, for subsequent matching on calling behaviour
* ``raises`` - Ensure that a deferred callable raises as expected
* ``described_as`` - give the matcher a custom failure description
* ``is_`` - decorator to improve readability - see `Syntactic sugar` below
The arguments for many of these matchers accept not just a matching value, but
another matcher, so matchers can be composed for greater flexibility. For
example, ``only_contains(less_than(5))`` will match any sequence where every
item is less than 5.
Syntactic sugar
===============
PyHamcrest strives to make your tests as readable as possible. For example, the
``is_`` matcher is a wrapper that doesn't add any extra behavior to the
underlying matcher. The following assertions are all equivalent:
.. code:: python
assert_that(theBiscuit, equal_to(myBiscuit))
assert_that(theBiscuit, is_(equal_to(myBiscuit)))
assert_that(theBiscuit, is_(myBiscuit))
The last form is allowed since ``is_(value)`` wraps most non-matcher arguments
with ``equal_to``. But if the argument is a type, it is wrapped with
``instance_of``, so the following are also equivalent:
.. code:: python
assert_that(theBiscuit, instance_of(Biscuit))
assert_that(theBiscuit, is_(instance_of(Biscuit)))
assert_that(theBiscuit, is_(Biscuit))
*Note that PyHamcrest's ``is_`` matcher is unrelated to Python's ``is``
operator. The matcher for object identity is ``same_instance``.*
Writing custom matchers
=======================
PyHamcrest comes bundled with lots of useful matchers, but you'll probably find
that you need to create your own from time to time to fit your testing needs.
This commonly occurs when you find a fragment of code that tests the same set
of properties over and over again (and in different tests), and you want to
bundle the fragment into a single assertion. By writing your own matcher you'll
eliminate code duplication and make your tests more readable!
Let's write our own matcher for testing if a calendar date falls on a Saturday.
This is the test we want to write:
.. code:: python
def testDateIsOnASaturday(self):
d = datetime.date(2008, 04, 26)
assert_that(d, is_(on_a_saturday()))
And here's the implementation:
.. code:: python
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.hasmethod import hasmethod
class IsGivenDayOfWeek(BaseMatcher):
def __init__(self, day):
self.day = day # Monday is 0, Sunday is 6
def _matches(self, item):
if not hasmethod(item, 'weekday'):
return False
return item.weekday() == self.day
def describe_to(self, description):
day_as_string = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
'Friday', 'Saturday', 'Sunday']
description.append_text('calendar date falling on ') \
.append_text(day_as_string[self.day])
def on_a_saturday():
return IsGivenDayOfWeek(5)
For our Matcher implementation we implement the ``_matches`` method - which
calls the ``weekday`` method after confirming that the argument (which may not
be a date) has such a method - and the ``describe_to`` method - which is used
to produce a failure message when a test fails. Here's an example of how the
failure message looks:
.. code:: python
assert_that(datetime.date(2008, 04, 06), is_(on_a_saturday()))
fails with the message::
AssertionError:
Expected: is calendar date falling on Saturday
got: <2008-04-06>
Let's say this matcher is saved in a module named ``isgivendayofweek``. We
could use it in our test by importing the factory function ``on_a_saturday``:
.. code:: python
from hamcrest import *
import unittest
from isgivendayofweek import on_a_saturday
class DateTest(unittest.TestCase):
def testDateIsOnASaturday(self):
d = datetime.date(2008, 04, 26)
assert_that(d, is_(on_a_saturday()))
if __name__ == '__main__':
unittest.main()
Even though the ``on_a_saturday`` function creates a new matcher each time it
is called, you should not assume this is the only usage pattern for your
matcher. Therefore you should make sure your matcher is stateless, so a single
instance can be reused between matches.
More resources
==============
* Documentation_
* Package_
* Sources_
* Hamcrest_
.. _Documentation: http://readthedocs.org/docs/pyhamcrest/en/V1.8.2/
.. _Package: http://pypi.python.org/pypi/PyHamcrest
.. _Sources: https://github.com/hamcrest/PyHamcrest
.. _Hamcrest: http://hamcrest.org
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/PyHamcrest-1.9.0.dist-info/RECORD
================================================
PyHamcrest-1.9.0.dist-info/DESCRIPTION.rst,sha256=13XTDh2baR2aJ91v_lAOjEXD7Ydush_RHhk0Z3azfs8,11973
PyHamcrest-1.9.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
PyHamcrest-1.9.0.dist-info/METADATA,sha256=s0naXZHUZhft0MWcUeZVaZYlREKPOqHp3mUQrhUoC6s,13276
PyHamcrest-1.9.0.dist-info/RECORD,,
PyHamcrest-1.9.0.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110
PyHamcrest-1.9.0.dist-info/metadata.json,sha256=Jqs-ZSW5kWSnfvxDsRMwSQH6TxEqSJjBJWiQk1G-c_A,1545
PyHamcrest-1.9.0.dist-info/pbr.json,sha256=jdAcCmfO0nnMs9-YKXuwDyKnxc4qGwyUxyGulF9Pam4,47
PyHamcrest-1.9.0.dist-info/top_level.txt,sha256=mRc0yPsPQSqFgWBmZBY33u-05Xtm5M4GEve4NjYdloQ,9
hamcrest/__init__.py,sha256=Uo0mxeePyXP9_yIzBBvKqIL6tzEHqBwBO1eSHfAKies,230
hamcrest/__pycache__/__init__.cpython-36.pyc,,
hamcrest/core/__init__.py,sha256=nDkYm1E1P7XpHmR8EHu17eahlmC6uYix4HurTyJjhlE,230
hamcrest/core/__pycache__/__init__.cpython-36.pyc,,
hamcrest/core/__pycache__/assert_that.cpython-36.pyc,,
hamcrest/core/__pycache__/base_description.cpython-36.pyc,,
hamcrest/core/__pycache__/base_matcher.cpython-36.pyc,,
hamcrest/core/__pycache__/compat.cpython-36.pyc,,
hamcrest/core/__pycache__/description.cpython-36.pyc,,
hamcrest/core/__pycache__/matcher.cpython-36.pyc,,
hamcrest/core/__pycache__/selfdescribing.cpython-36.pyc,,
hamcrest/core/__pycache__/selfdescribingvalue.cpython-36.pyc,,
hamcrest/core/__pycache__/string_description.cpython-36.pyc,,
hamcrest/core/assert_that.py,sha256=mPdTQQVsjUliK3xp8l_Vn3YmMzg_h5rYhWJk2mstMc0,2428
hamcrest/core/base_description.py,sha256=auvrelro2vGh_A05TQxwbaBJStvfHiFqm0TL56luxEU,2841
hamcrest/core/base_matcher.py,sha256=eRhLv7zFBJGaz68vEsDlvKbrWwU8GRDfZc7pWBNcxwI,1193
hamcrest/core/compat.py,sha256=wUi1u_nIhgUA3kFGJDZLQ2D_cRw79E1SxPDMaI4mzG0,642
hamcrest/core/core/__init__.py,sha256=7q_pNO9cmtV3BEixiGcueNdbxRxlKEFZ1RSO-5GP58E,770
hamcrest/core/core/__pycache__/__init__.cpython-36.pyc,,
hamcrest/core/core/__pycache__/allof.cpython-36.pyc,,
hamcrest/core/core/__pycache__/anyof.cpython-36.pyc,,
hamcrest/core/core/__pycache__/described_as.cpython-36.pyc,,
hamcrest/core/core/__pycache__/is_.cpython-36.pyc,,
hamcrest/core/core/__pycache__/isanything.cpython-36.pyc,,
hamcrest/core/core/__pycache__/isequal.cpython-36.pyc,,
hamcrest/core/core/__pycache__/isinstanceof.cpython-36.pyc,,
hamcrest/core/core/__pycache__/isnone.cpython-36.pyc,,
hamcrest/core/core/__pycache__/isnot.cpython-36.pyc,,
hamcrest/core/core/__pycache__/issame.cpython-36.pyc,,
hamcrest/core/core/__pycache__/raises.cpython-36.pyc,,
hamcrest/core/core/allof.py,sha256=x2ea18Z5cioRybs1heTd3E8zYtpFbuBJg3vIU3vl9k0,1487
hamcrest/core/core/anyof.py,sha256=8j2KAsaToXbv8CA5hed4bqPR3hscODIiaFhAlAyJ2Vs,1097
hamcrest/core/core/described_as.py,sha256=kyy_qRpoebWB1bS2ReAkNDt-79iXu6HqHxOG0GT7PtQ,1623
hamcrest/core/core/is_.py,sha256=C7UCASfr4AIlaaMZnT5d34OthAZQ3rYv8OhszQjz-Eg,2547
hamcrest/core/core/isanything.py,sha256=D2QO5dbDhwlVRGLFrnxOSijTyeKN2iWLRwjpvnumkvg,798
hamcrest/core/core/isequal.py,sha256=TAwF_lWIjVokPruXN8IGS6ajzPGlThanTLPdhktKwRQ,893
hamcrest/core/core/isinstanceof.py,sha256=dnt8YKLhYwGZvDkJ0OTdLd1PN9cB9ZWCg5k8kdnEuqI,1352
hamcrest/core/core/isnone.py,sha256=51ueQKBgg0RzWVLzjFOyt6K0ejk2EbXUlUX90ORPm80,557
hamcrest/core/core/isnot.py,sha256=_z_ynAVUXEUGWoiRlynFa_yaCVh9cK9LIOznDfKVZeo,1533
hamcrest/core/core/issame.py,sha256=8FvAjud4HTuyz7O-XoJbzLtKhChCr1_5JmzMYMeQt1s,1261
hamcrest/core/core/raises.py,sha256=BZXtMlQiEqEjQMYT76HUiuQNRjTECIUmL82_FKYhAvs,3610
hamcrest/core/description.py,sha256=gbVS-ejZJ783o-WEA66bXnXc9DH5cOlQXg0FlzoVGro,1729
hamcrest/core/helpers/__init__.py,sha256=mPsycYI18LoGawOo9BfETa7yKtnM-fDjFOr43BIevUg,146
hamcrest/core/helpers/__pycache__/__init__.cpython-36.pyc,,
hamcrest/core/helpers/__pycache__/hasmethod.cpython-36.pyc,,
hamcrest/core/helpers/__pycache__/wrap_matcher.cpython-36.pyc,,
hamcrest/core/helpers/hasmethod.py,sha256=LPh_WDRuyKYII3G3fX_x2Ql-ECuPJn4tK5eWMLbetLg,325
hamcrest/core/helpers/wrap_matcher.py,sha256=IQTtw98Pp1NXcVTy9boaNh6jayvawKHhX62R3ZwnVwQ,880
hamcrest/core/matcher.py,sha256=BG6e8bIJvwFI0qkaSkt_SOuuLI0VidvoX8GQLadYssU,1851
hamcrest/core/selfdescribing.py,sha256=RzwqHRGg00AJYweGiP8JzSxoHFdBo0Q7m5axYfutfG8,574
hamcrest/core/selfdescribingvalue.py,sha256=OpGLOjdPA9FSgmLZzmkfYrDvpG261TDDiM56muROFqQ,834
hamcrest/core/string_description.py,sha256=Jp-SbuY8LAwPucL4NMrwWqRhkg6CMwYE-pH0ZDMUq8A,908
hamcrest/library/__init__.py,sha256=2atNiBCC2g3c-7jw53CltNgU4wEao1uRcheUPl1ML50,1014
hamcrest/library/__pycache__/__init__.cpython-36.pyc,,
hamcrest/library/collection/__init__.py,sha256=iJU6WCsf0R22m11fqMA9Ztb161AZAdrsKG-4Cj38lZ0,635
hamcrest/library/collection/__pycache__/__init__.cpython-36.pyc,,
hamcrest/library/collection/__pycache__/is_empty.cpython-36.pyc,,
hamcrest/library/collection/__pycache__/isdict_containing.cpython-36.pyc,,
hamcrest/library/collection/__pycache__/isdict_containingentries.cpython-36.pyc,,
hamcrest/library/collection/__pycache__/isdict_containingkey.cpython-36.pyc,,
hamcrest/library/collection/__pycache__/isdict_containingvalue.cpython-36.pyc,,
hamcrest/library/collection/__pycache__/isin.cpython-36.pyc,,
hamcrest/library/collection/__pycache__/issequence_containing.cpython-36.pyc,,
hamcrest/library/collection/__pycache__/issequence_containinginanyorder.cpython-36.pyc,,
hamcrest/library/collection/__pycache__/issequence_containinginorder.cpython-36.pyc,,
hamcrest/library/collection/__pycache__/issequence_onlycontaining.cpython-36.pyc,,
hamcrest/library/collection/is_empty.py,sha256=p3-B7DCmdbVzqiW3D1h3krdeqmu9B0mfYOaa6HehODg,913
hamcrest/library/collection/isdict_containing.py,sha256=6QxDtDp_Z2TK-6om8cHnJDh45YdmaNHAEy5n97rzf00,2056
hamcrest/library/collection/isdict_containingentries.py,sha256=xKtdFjrwLN32rUdRR4PBUSYa3yACa6jXsmlZv0D9YAU,5168
hamcrest/library/collection/isdict_containingkey.py,sha256=aiBpusjpZmkUEMZ_rUFZBB1GxIfsqluMjhXoWNScqZY,1535
hamcrest/library/collection/isdict_containingvalue.py,sha256=N7mHKgMnd7q6HsQekHH6DShNYbLiSXN9cpQgcdMIjlw,1565
hamcrest/library/collection/isin.py,sha256=bcVslW0fUq0pM_SrT9gdltTlNfeJkrVPZAlg6riV2Ys,774
hamcrest/library/collection/issequence_containing.py,sha256=ZwYMm2-Ul_JtvjcgdMjipYdz82yUbGmRNsdPAjO9RX0,3001
hamcrest/library/collection/issequence_containinginanyorder.py,sha256=Px_W2-_0XDOXiL2NTTMp16ZTZvBl4m5rXjlMoR4Ulmw,3613
hamcrest/library/collection/issequence_containinginorder.py,sha256=x7AT_kOCaPY0LmZw28ln8xLLHBtT-I3NneoCWzMJoYA,3219
hamcrest/library/collection/issequence_onlycontaining.py,sha256=Ia17P1HVgb43lZfdUEhmPyUUUWtGLix__fqXIQJTUiI,1626
hamcrest/library/integration/__init__.py,sha256=3aiupojVacPksKTXVhqRs9OwUDoUlUw-bjWItJnRg8Q,254
hamcrest/library/integration/__pycache__/__init__.cpython-36.pyc,,
hamcrest/library/integration/__pycache__/match_equality.cpython-36.pyc,,
hamcrest/library/integration/match_equality.py,sha256=0BMth20YLTqjqTLT4qMVldAe2dQV3CJ2j3zLXDIGl9c,1192
hamcrest/library/number/__init__.py,sha256=J3UoFdR9UPq9zXSKe1a9qAlpjaVst8-pnaxsvbCPj78,335
hamcrest/library/number/__pycache__/__init__.cpython-36.pyc,,
hamcrest/library/number/__pycache__/iscloseto.cpython-36.pyc,,
hamcrest/library/number/__pycache__/ordering_comparison.cpython-36.pyc,,
hamcrest/library/number/iscloseto.py,sha256=2lQTw3Xvo5MW-aePxpWVUOwyV_ydXtH6cCAIAxeopk8,2259
hamcrest/library/number/ordering_comparison.py,sha256=8XxVSOzPK29D14h4wtBZYVYKZf6IcABaQEKihEuzlhI,1700
hamcrest/library/object/__init__.py,sha256=pxzCpybBHRaIg7RJUAw7R1Po0llw8QBbVv_R1TXNBhc,319
hamcrest/library/object/__pycache__/__init__.cpython-36.pyc,,
hamcrest/library/object/__pycache__/haslength.cpython-36.pyc,,
hamcrest/library/object/__pycache__/hasproperty.cpython-36.pyc,,
hamcrest/library/object/__pycache__/hasstring.cpython-36.pyc,,
hamcrest/library/object/haslength.py,sha256=mpYVvrBZV548FwEeqlHWYofv9LPgChvnypZ4RhZDMp0,1681
hamcrest/library/object/hasproperty.py,sha256=9t8upZxjqSQp6IvGyTm4ftGvcpBeyk0dy36HgvlXZBg,5740
hamcrest/library/object/hasstring.py,sha256=_Ht1x-DwV4hk2fRuGo_KoayoLOIoWObKoA30u7HnABU,1250
hamcrest/library/text/__init__.py,sha256=3Uuy1lY2p0VEUy1SAIO6IZgDDgyx8ZsB98k-J2FA_R0,548
hamcrest/library/text/__pycache__/__init__.cpython-36.pyc,,
hamcrest/library/text/__pycache__/isequal_ignoring_case.cpython-36.pyc,,
hamcrest/library/text/__pycache__/isequal_ignoring_whitespace.cpython-36.pyc,,
hamcrest/library/text/__pycache__/stringcontains.cpython-36.pyc,,
hamcrest/library/text/__pycache__/stringcontainsinorder.cpython-36.pyc,,
hamcrest/library/text/__pycache__/stringendswith.cpython-36.pyc,,
hamcrest/library/text/__pycache__/stringmatches.cpython-36.pyc,,
hamcrest/library/text/__pycache__/stringstartswith.cpython-36.pyc,,
hamcrest/library/text/__pycache__/substringmatcher.cpython-36.pyc,,
hamcrest/library/text/isequal_ignoring_case.py,sha256=VGkR3PNDOVE1MJT9H4a3SjR2SIYNzT80VoV6NEq3aqw,1257
hamcrest/library/text/isequal_ignoring_whitespace.py,sha256=NQzswc7fk5rOhcoHO4zbYSWqn-WQdQ7Hwf0FoDHAwBM,1667
hamcrest/library/text/stringcontains.py,sha256=JbkSxdFkpRrNYJfSUghboxe1jRLfHAJvOn6PYvMx7fQ,953
hamcrest/library/text/stringcontainsinorder.py,sha256=B3qG7TG24_WyVPGJER2iqi7fzOMZN0UsBRJPtWutBkc,1705
hamcrest/library/text/stringendswith.py,sha256=JjukJWSVWgURvTstrbCGCQdQzY0PMWLul__UlDh2NGA,980
hamcrest/library/text/stringmatches.py,sha256=AEBn8NI3q-YzRUdXiAfnw1Kmse-LLxJUluDAuy_D9nU,1151
hamcrest/library/text/stringstartswith.py,sha256=oOro8G3z8nAOUyOjHHkHhUvY-lt7XRTJzDr9dYxxons,1007
hamcrest/library/text/substringmatcher.py,sha256=lSPxE7pTpTJlUkMtd28WgsM1FFm56JVZixSvAldSZXk,695
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/PyHamcrest-1.9.0.dist-info/WHEEL
================================================
Wheel-Version: 1.0
Generator: bdist_wheel (0.24.0)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/PyHamcrest-1.9.0.dist-info/metadata.json
================================================
{"license": "New BSD", "download_url": "http://pypi.python.org/packages/source/P/PyHamcrest/PyHamcrest-1.9.0.tar.gz", "name": "PyHamcrest", "provides": "hamcrest", "test_requires": [{"requires": ["hypothesis (>=1.11)", "pytest (>=2.8)", "mock", "pytest-cov"]}], "extensions": {"python.details": {"project_urls": {"Home": "https://github.com/hamcrest/PyHamcrest"}, "contacts": [{"name": "Chris Rose", "role": "author", "email": "offline@offby1.net"}], "document_names": {"description": "DESCRIPTION.rst"}}}, "run_requires": [{"requires": ["setuptools", "six"]}], "generator": "bdist_wheel (0.24.0)", "summary": "Hamcrest framework for matcher objects", "extras": [], "classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: Jython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development", "Topic :: Software Development :: Quality Assurance", "Topic :: Software Development :: Testing"], "version": "1.9.0", "metadata_version": "2.0", "keywords": ["hamcrest", "matchers", "pyunit", "unit", "test", "testing", "unittest", "unittesting"], "platform": "All"}
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/PyHamcrest-1.9.0.dist-info/pbr.json
================================================
{"is_release": false, "git_version": "d572d69"}
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/PyHamcrest-1.9.0.dist-info/top_level.txt
================================================
hamcrest
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Scrapy-1.7.4.dist-info/AUTHORS
================================================
Scrapy was brought to life by Shane Evans while hacking a scraping framework
prototype for Mydeco (mydeco.com). It soon became maintained, extended and
improved by Insophia (insophia.com), with the initial sponsorship of Mydeco to
bootstrap the project. In mid-2011, Scrapinghub became the new official
maintainer.
Here is the list of the primary authors & contributors:
* Pablo Hoffman
* Daniel Graña
* Martin Olveyra
* Gabriel García
* Michael Cetrulo
* Artem Bogomyagkov
* Damian Canabal
* Andres Moreira
* Ismael Carnales
* Matías Aguirre
* German Hoffmann
* Anibal Pacheco
* Bruno Deferrari
* Shane Evans
* Ezequiel Rivero
* Patrick Mezard
* Rolando Espinoza
* Ping Yin
* Lucian Ursu
* Shuaib Khan
* Didier Deshommes
* Vikas Dhiman
* Jochen Maes
* Darian Moody
* Jordi Lonch
* Zuhao Wan
* Steven Almeroth
* Tom Mortimer-Jones
* Chris Tilden
* Alexandr N Zamaraev
* Emanuel Schorsch
* Michal Danilak
* Natan Lao
* Hasnain Lakhani
* Pedro Faustino
* Alex Cepoi
* Ilya Baryshev
* Libor Nenadál
* Jae-Myoung Yu
* Vladislav Poluhin
* Marc Abramowitz
* Valentin-Costel Hăloiu
* Jason Yeo
* Сергей Прохоров
* Simon Ratne
* Julien Duponchelle
* Jochen Maes
* Vikas Dhiman
* Juan Picca
* Nicolás Ramírez
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Scrapy-1.7.4.dist-info/INSTALLER
================================================
pip
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Scrapy-1.7.4.dist-info/LICENSE
================================================
Copyright (c) Scrapy developers.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of Scrapy nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Scrapy-1.7.4.dist-info/METADATA
================================================
Metadata-Version: 2.1
Name: Scrapy
Version: 1.7.4
Summary: A high-level Web Crawling and Web Scraping framework
Home-page: https://scrapy.org
Author: Scrapy developers
Maintainer: Pablo Hoffman
Maintainer-email: pablo@pablohoffman.com
License: BSD
Platform: UNKNOWN
Classifier: Framework :: Scrapy
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
Requires-Dist: w3lib (>=1.17.0)
Requires-Dist: queuelib
Requires-Dist: pyOpenSSL
Requires-Dist: cssselect (>=0.9)
Requires-Dist: six (>=1.5.2)
Requires-Dist: parsel (>=1.5)
Requires-Dist: PyDispatcher (>=2.0.5)
Requires-Dist: service-identity
Requires-Dist: PyPyDispatcher (>=2.1.0) ; platform_python_implementation == "PyPy"
Requires-Dist: Twisted (>=13.1.0) ; python_version != "3.4"
Requires-Dist: lxml ; python_version != "3.4"
Requires-Dist: Twisted (<=19.2.0,>=13.1.0) ; python_version == "3.4"
Requires-Dist: lxml (<=4.3.5) ; python_version == "3.4"
======
Scrapy
======
.. image:: https://img.shields.io/pypi/v/Scrapy.svg
:target: https://pypi.python.org/pypi/Scrapy
:alt: PyPI Version
.. image:: https://img.shields.io/pypi/pyversions/Scrapy.svg
:target: https://pypi.python.org/pypi/Scrapy
:alt: Supported Python Versions
.. image:: https://img.shields.io/travis/scrapy/scrapy/master.svg
:target: https://travis-ci.org/scrapy/scrapy
:alt: Build Status
.. image:: https://img.shields.io/badge/wheel-yes-brightgreen.svg
:target: https://pypi.python.org/pypi/Scrapy
:alt: Wheel Status
.. image:: https://img.shields.io/codecov/c/github/scrapy/scrapy/master.svg
:target: https://codecov.io/github/scrapy/scrapy?branch=master
:alt: Coverage report
.. image:: https://anaconda.org/conda-forge/scrapy/badges/version.svg
:target: https://anaconda.org/conda-forge/scrapy
:alt: Conda Version
Overview
========
Scrapy is a fast high-level web crawling and web scraping framework, used to
crawl websites and extract structured data from their pages. It can be used for
a wide range of purposes, from data mining to monitoring and automated testing.
For more information including a list of features check the Scrapy homepage at:
https://scrapy.org
Requirements
============
* Python 2.7 or Python 3.4+
* Works on Linux, Windows, Mac OSX, BSD
Install
=======
The quick way::
pip install scrapy
For more details see the install section in the documentation:
https://docs.scrapy.org/en/latest/intro/install.html
Documentation
=============
Documentation is available online at https://docs.scrapy.org/ and in the ``docs``
directory.
Releases
========
You can find release notes at https://docs.scrapy.org/en/latest/news.html
Community (blog, twitter, mail list, IRC)
=========================================
See https://scrapy.org/community/
Contributing
============
See https://docs.scrapy.org/en/master/contributing.html
Code of Conduct
---------------
Please note that this project is released with a Contributor Code of Conduct
(see https://github.com/scrapy/scrapy/blob/master/CODE_OF_CONDUCT.md).
By participating in this project you agree to abide by its terms.
Please report unacceptable behavior to opensource@scrapinghub.com.
Companies using Scrapy
======================
See https://scrapy.org/companies/
Commercial Support
==================
See https://scrapy.org/support/
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Scrapy-1.7.4.dist-info/RECORD
================================================
../../../bin/scrapy,sha256=nBpGRsKtbys-Xp4iWs4bUk8T8k7OmhWXZrXiaWhKU1Q,285
Scrapy-1.7.4.dist-info/AUTHORS,sha256=wBeg3cpJ5eH5Ilhbd22N1Npk17-KVy7CwXL0uRshrYM,1273
Scrapy-1.7.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
Scrapy-1.7.4.dist-info/LICENSE,sha256=_TMa88y4d2u-fzF4IeXguRwqt8c0ZOd0JdUiBPe12YA,1517
Scrapy-1.7.4.dist-info/METADATA,sha256=Xj14ruhbCZkQFrJRpOz6IYGkmpQSzZ0UNgPoeWsjGWc,4273
Scrapy-1.7.4.dist-info/RECORD,,
Scrapy-1.7.4.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110
Scrapy-1.7.4.dist-info/entry_points.txt,sha256=WDkmo-mkyyTA0TS6pVQtxOnkG9VXzFeotzjdI7r5DO4,51
Scrapy-1.7.4.dist-info/top_level.txt,sha256=daQJ2I8J6o-AN_sw03XNdbAoaiFVV2v9xkB7FxB6dao,7
scrapy/VERSION,sha256=wKWmSTuO_WdX5f7Mb8zT38UTsZYzMffIryxNaFT5v2Y,6
scrapy/__init__.py,sha256=GtWfEXEqceruqbQHf_nbzQ_t-Gu8menXdEaj7C6qhR8,1146
scrapy/__main__.py,sha256=0pB9bs0MIwKYELCv21imsZMzlfacVRGv6q49Vnbclvw,77
scrapy/__pycache__/__init__.cpython-36.pyc,,
scrapy/__pycache__/__main__.cpython-36.pyc,,
scrapy/__pycache__/_monkeypatches.cpython-36.pyc,,
scrapy/__pycache__/cmdline.cpython-36.pyc,,
scrapy/__pycache__/crawler.cpython-36.pyc,,
scrapy/__pycache__/dupefilters.cpython-36.pyc,,
scrapy/__pycache__/exceptions.cpython-36.pyc,,
scrapy/__pycache__/exporters.cpython-36.pyc,,
scrapy/__pycache__/extension.cpython-36.pyc,,
scrapy/__pycache__/interfaces.cpython-36.pyc,,
scrapy/__pycache__/item.cpython-36.pyc,,
scrapy/__pycache__/link.cpython-36.pyc,,
scrapy/__pycache__/logformatter.cpython-36.pyc,,
scrapy/__pycache__/mail.cpython-36.pyc,,
scrapy/__pycache__/middleware.cpython-36.pyc,,
scrapy/__pycache__/pqueues.cpython-36.pyc,,
scrapy/__pycache__/resolver.cpython-36.pyc,,
scrapy/__pycache__/responsetypes.cpython-36.pyc,,
scrapy/__pycache__/shell.cpython-36.pyc,,
scrapy/__pycache__/signalmanager.cpython-36.pyc,,
scrapy/__pycache__/signals.cpython-36.pyc,,
scrapy/__pycache__/spiderloader.cpython-36.pyc,,
scrapy/__pycache__/squeues.cpython-36.pyc,,
scrapy/__pycache__/statscollectors.cpython-36.pyc,,
scrapy/_monkeypatches.py,sha256=IbS8a61u3tlJ-1KA_wdrDWGSjlO0MjYA23WGmGOPU8k,976
scrapy/cmdline.py,sha256=VwGYKBNrih2fpVZ7vqG5A68kdT3egvM_1dK3TjyVk7E,5486
scrapy/commands/__init__.py,sha256=RcI0G7rAPZ_FRycx9TDxV_vdI5ViJqNIbQyLSzgn9WI,3532
scrapy/commands/__pycache__/__init__.cpython-36.pyc,,
scrapy/commands/__pycache__/bench.cpython-36.pyc,,
scrapy/commands/__pycache__/check.cpython-36.pyc,,
scrapy/commands/__pycache__/crawl.cpython-36.pyc,,
scrapy/commands/__pycache__/edit.cpython-36.pyc,,
scrapy/commands/__pycache__/fetch.cpython-36.pyc,,
scrapy/commands/__pycache__/genspider.cpython-36.pyc,,
scrapy/commands/__pycache__/list.cpython-36.pyc,,
scrapy/commands/__pycache__/parse.cpython-36.pyc,,
scrapy/commands/__pycache__/runspider.cpython-36.pyc,,
scrapy/commands/__pycache__/settings.cpython-36.pyc,,
scrapy/commands/__pycache__/shell.cpython-36.pyc,,
scrapy/commands/__pycache__/startproject.cpython-36.pyc,,
scrapy/commands/__pycache__/version.cpython-36.pyc,,
scrapy/commands/__pycache__/view.cpython-36.pyc,,
scrapy/commands/bench.py,sha256=vm6kFt45KdJsCTNydR7BK1zki8cQfVbG9VcNVbPpIgQ,1640
scrapy/commands/check.py,sha256=TaUfMEhB2IwgCGgk4i5BHGmqdtWUfm2D4FgfXpLlBPQ,3453
scrapy/commands/crawl.py,sha256=u41-TBL-3Avw9CVGHNpflJKy83Jt-bPmOMpUGlL7jHQ,2625
scrapy/commands/edit.py,sha256=OERVroFVEvfFoDda9xQ2Hm-0Sshq79cRV9g-UQKW1R8,1051
scrapy/commands/fetch.py,sha256=m23twt8conAjm43S8nNReWcEt264O-4RqNf2IgOIDjo,2734
scrapy/commands/genspider.py,sha256=7Yx4AZEGgzP1YfKAcaQkcJhR5svI7KZ92ls61sHybOg,4915
scrapy/commands/list.py,sha256=L2C-B5m7rRNrENSOUNov_BZBdB_GF4ncJmaO7HVLOoQ,374
scrapy/commands/parse.py,sha256=lUV4En8O_rOiQ_e0lfg4WgYq_v6yYcQ_twI4Q89w07c,10296
scrapy/commands/runspider.py,sha256=UslNwaSU5kkCLO5cwprJI57t7rPO4djfak9fZCdNqgY,3668
scrapy/commands/settings.py,sha256=0hbpJmWFcJTSpP7Xl67Szk03d5WJR9hJzCxKOUlctnA,1750
scrapy/commands/shell.py,sha256=-RPATQEypBo6vGRZLY_76asJfH5jgXkLmQJnk1tiD3U,2720
scrapy/commands/startproject.py,sha256=07eNX97Om03GDWdNATbCe6ff5kblTaVC85zPLY6Lq5E,3921
scrapy/commands/version.py,sha256=4p4Aw_J-w2a5EOxwGX0QSUcuE_awKnSqLSGHZnvU2TE,1021
scrapy/commands/view.py,sha256=naXH4HTkXjdSjkaevs5JuJcTbFE8o_EeHdvvfi_MWWM,557
scrapy/contracts/__init__.py,sha256=r8HO_NAh0YjEszksbddFf64JFXhL32mSaC6VGZX8iBs,6017
scrapy/contracts/__pycache__/__init__.cpython-36.pyc,,
scrapy/contracts/__pycache__/default.cpython-36.pyc,,
scrapy/contracts/default.py,sha256=NLJkh6yhxbm10R0d_m3FbhehxL7109OhORH9b_Iu3Ag,2334
scrapy/core/__init__.py,sha256=qWrZeCfaO0rc0hg-MW2Famk13S-U5VcBqmJzRxEL8mc,51
scrapy/core/__pycache__/__init__.cpython-36.pyc,,
scrapy/core/__pycache__/engine.cpython-36.pyc,,
scrapy/core/__pycache__/scheduler.cpython-36.pyc,,
scrapy/core/__pycache__/scraper.cpython-36.pyc,,
scrapy/core/__pycache__/spidermw.cpython-36.pyc,,
scrapy/core/downloader/__init__.py,sha256=Cxa-FfH6Mz1A1Mp7PGBDpI9qWYtMea4Jt6u_DJWism4,7208
scrapy/core/downloader/__pycache__/__init__.cpython-36.pyc,,
scrapy/core/downloader/__pycache__/contextfactory.cpython-36.pyc,,
scrapy/core/downloader/__pycache__/middleware.cpython-36.pyc,,
scrapy/core/downloader/__pycache__/tls.cpython-36.pyc,,
scrapy/core/downloader/__pycache__/webclient.cpython-36.pyc,,
scrapy/core/downloader/contextfactory.py,sha256=Fvr6UnBKjEVfdnR2-LHHuvvURxI7jEoL9wdGbwN7Jy8,4480
scrapy/core/downloader/handlers/__init__.py,sha256=Kf963BJqJgqknLvuDuuPg8rOdcbQWwNdoz8kQThN1WE,2806
scrapy/core/downloader/handlers/__pycache__/__init__.cpython-36.pyc,,
scrapy/core/downloader/handlers/__pycache__/datauri.cpython-36.pyc,,
scrapy/core/downloader/handlers/__pycache__/file.cpython-36.pyc,,
scrapy/core/downloader/handlers/__pycache__/ftp.cpython-36.pyc,,
scrapy/core/downloader/handlers/__pycache__/http.cpython-36.pyc,,
scrapy/core/downloader/handlers/__pycache__/http10.cpython-36.pyc,,
scrapy/core/downloader/handlers/__pycache__/http11.cpython-36.pyc,,
scrapy/core/downloader/handlers/__pycache__/s3.cpython-36.pyc,,
scrapy/core/downloader/handlers/datauri.py,sha256=7nKvTXPCot1H8kqHYJnhj37SWgfafMi8wbCkv6k6p7s,791
scrapy/core/downloader/handlers/file.py,sha256=I9YXSEhplT4-RyAjhLGeko_Uej_A5PeZew8ze32XcDY,535
scrapy/core/downloader/handlers/ftp.py,sha256=8263S1q_4Av0T_dJ6YGvTIP5wkJ_hCt0sCjAgMQk_rA,4568
scrapy/core/downloader/handlers/http.py,sha256=HKHUa25ANNGtrxEp3PDVhMno57K0EaWm2ZeroZPMZXQ,146
scrapy/core/downloader/handlers/http10.py,sha256=BVxK2wWcmMUoSdpXf4-_3P4Ys1orVbm4dSHs_BVupIk,994
scrapy/core/downloader/handlers/http11.py,sha256=12P2EfHOFXf4SMc9iO3s7bsR9NiY3oWTFw4nDQ8MznI,21150
scrapy/core/downloader/handlers/s3.py,sha256=QKJqc4HtcKPlSQj6m7Ds936aPs8b_ELeEynCIi0B2tk,3870
scrapy/core/downloader/middleware.py,sha256=Q_hkW8G5Dh6IV6Kcb6sOeWIZpVwYT9lbQCAAcNe8Agc,3500
scrapy/core/downloader/tls.py,sha256=ckhjPgbcCBuwXGyADSK_LGE2jzpX_m11K7RniQST4Q0,3620
scrapy/core/downloader/webclient.py,sha256=0I-V6vxB3dBmVsvpuKja7moGH9imAyGJ475Cu6Err6g,5796
scrapy/core/engine.py,sha256=b_W67uhavv0W_eOOIOWfWXudw2inxT2-p_xwISrT_Ro,13114
scrapy/core/scheduler.py,sha256=AXyJdDFk42wwcQtglrVjfDLM4sJM2Ebeiop04Ka9qR4,7220
scrapy/core/scraper.py,sha256=CAXJZFV6HqHjaiT7hf7luNSZ4NmedEKIFAn1mx0PSGU,10190
scrapy/core/spidermw.py,sha256=UuP_Eip2pMKB52RzoWuOMmFzcVS3ACPF63xJaHma3VA,5409
scrapy/crawler.py,sha256=HQ-RTrk_XZhq-m0lY7NvG1vKJmSVxHETmpuLxuq0GVY,13435
scrapy/downloadermiddlewares/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
scrapy/downloadermiddlewares/__pycache__/__init__.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/ajaxcrawl.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/chunked.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/cookies.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/decompression.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/defaultheaders.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/downloadtimeout.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/httpauth.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/httpcache.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/httpcompression.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/httpproxy.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/redirect.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/retry.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/robotstxt.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/stats.cpython-36.pyc,,
scrapy/downloadermiddlewares/__pycache__/useragent.cpython-36.pyc,,
scrapy/downloadermiddlewares/ajaxcrawl.py,sha256=wZp8pcTX4diWPRUuSfi7L80i7xa_nUDAanwDKrL6_Bc,3365
scrapy/downloadermiddlewares/chunked.py,sha256=2BEDL3dYZNSrTSJEODMYRwVp_FcnxTmGYughULNafdk,773
scrapy/downloadermiddlewares/cookies.py,sha256=Nv87VOoKoriX5VM98f_Xw_vir4lt8LQNTbhwTnSrFFM,3330
scrapy/downloadermiddlewares/decompression.py,sha256=yueO97rb4GQxKEoON5qA6r7MfMVK6olMjfT2SSix0_I,2629
scrapy/downloadermiddlewares/defaultheaders.py,sha256=2Q9ExGM7fM57k7nrv6U9NIJcl_BL9Wpaa_gRY-L_3x4,568
scrapy/downloadermiddlewares/downloadtimeout.py,sha256=Pt-9xbi3obt8eEVjMD85VWcPXZc-VI0qB1uFC1pNQaY,709
scrapy/downloadermiddlewares/httpauth.py,sha256=3ALLKVZmnsGIwTzbBad8R2As7Dt2GIRUPzXO-Jrso4s,893
scrapy/downloadermiddlewares/httpcache.py,sha256=USiehBnBQncT_Q_MSzJdioAfFWi4raWXbqiSWuyh4Hc,4706
scrapy/downloadermiddlewares/httpcompression.py,sha256=GE8MgpBzItVM3tcS2a11Avs5QS3dw87MIQMmAhl865c,2605
scrapy/downloadermiddlewares/httpproxy.py,sha256=JJzzrLbmKEsXF-We2Iim4wXn-ulhekr1M69wxe1yzS0,2561
scrapy/downloadermiddlewares/redirect.py,sha256=vjcwFvCewTsOHXW7GtBBPtl4r_tMjuUJCX6UBzYBhI4,4436
scrapy/downloadermiddlewares/retry.py,sha256=eh6MIdgapC1ftJqYoypZDbCtDhFbjHc3Z0ImLXRp6L8,3746
scrapy/downloadermiddlewares/robotstxt.py,sha256=j5fsGDc0ZINZhvaeX3kyj0DwHrKhazx7wysmGmK_L7o,4490
scrapy/downloadermiddlewares/stats.py,sha256=djbnZUa9POgJbInehoJGA3NhzlXwXQeb5OqX1ngUs1I,1495
scrapy/downloadermiddlewares/useragent.py,sha256=q-IAslxHg5ryft03xcyv8xzElGGP3zZTJCYPHTa8DQE,749
scrapy/dupefilters.py,sha256=Hyf0ZSZ05VnmCHwL8JcRLAbY5OquxeaY7bhR-5BSODU,2302
scrapy/exceptions.py,sha256=HUXqpZCoQuKnZxa-5eiK-GerV2EIqoLmYTcfANCj4ek,1620
scrapy/exporters.py,sha256=xCJBbUVlF6DoBjoWN6XErnD30dtKez0hihiq5WckLeg,12541
scrapy/extension.py,sha256=BAMLf4nYbRZkLwZZ6mXkKxozBWcnQFAaslTfCW-BqFw,396
scrapy/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
scrapy/extensions/__pycache__/__init__.cpython-36.pyc,,
scrapy/extensions/__pycache__/closespider.cpython-36.pyc,,
scrapy/extensions/__pycache__/corestats.cpython-36.pyc,,
scrapy/extensions/__pycache__/debug.cpython-36.pyc,,
scrapy/extensions/__pycache__/feedexport.cpython-36.pyc,,
scrapy/extensions/__pycache__/httpcache.cpython-36.pyc,,
scrapy/extensions/__pycache__/logstats.cpython-36.pyc,,
scrapy/extensions/__pycache__/memdebug.cpython-36.pyc,,
scrapy/extensions/__pycache__/memusage.cpython-36.pyc,,
scrapy/extensions/__pycache__/spiderstate.cpython-36.pyc,,
scrapy/extensions/__pycache__/statsmailer.cpython-36.pyc,,
scrapy/extensions/__pycache__/telnet.cpython-36.pyc,,
scrapy/extensions/__pycache__/throttle.cpython-36.pyc,,
scrapy/extensions/closespider.py,sha256=TaIUui6l9ZJfLWLQ4X6jKyW_WREQenUmZttN04qESJU,2583
scrapy/extensions/corestats.py,sha256=YAdF8DoCx2HeNqjvKijEcBMhMXpNyAQ9RcOrJSheCvM,1772
scrapy/extensions/debug.py,sha256=XzJwGpW8jrRrl1g6b6pr5ABoakqHv9hU_v57RasCCYw,1890
scrapy/extensions/feedexport.py,sha256=vtXB9mB34Y1TcA_YCab4THBjIHNSuAQEeUUmyNq15GE,11047
scrapy/extensions/httpcache.py,sha256=FaM1QYyjRaeHKYgrDnEET61S0qx7tx6_CXhET2oTWF8,16924
scrapy/extensions/logstats.py,sha256=5_Ds4kqQ5kf7RbjnPpUkZAZOHNK5uvWgDOQ7PzDFiEg,1754
scrapy/extensions/memdebug.py,sha256=blguRbnQhDEXDUpsOQFfaRrRwVH6skymG-vH3jYdABs,945
scrapy/extensions/memusage.py,sha256=CkteP9viQ8A5Exb5niRVsz_DnuDsIZUmZ3u7PqqFOd4,4940
scrapy/extensions/spiderstate.py,sha256=oitUjBiG7_2d0UsXgwLF0FUJtBBOWVoQjSxI0NZcZVo,1169
scrapy/extensions/statsmailer.py,sha256=BH22wLlpo2aCOvu-RJ3sfF5HrFf-SQlw8O8_gYKnpa8,1242
scrapy/extensions/telnet.py,sha256=vTJLZvs6E0aaVRbxsSJGSbqCVS-OzhVgEvhegW0lXdM,4136
scrapy/extensions/throttle.py,sha256=pRZLfXJqu_wnFkHNkKdDA2Z5vKuFhgVOpJ8TtzaRtPo,3586
scrapy/http/__init__.py,sha256=5VPoouMGxjXuKrX42XKZQhEISVjbkWXNJqr1ID0cuVc,602
scrapy/http/__pycache__/__init__.cpython-36.pyc,,
scrapy/http/__pycache__/common.cpython-36.pyc,,
scrapy/http/__pycache__/cookies.cpython-36.pyc,,
scrapy/http/__pycache__/headers.cpython-36.pyc,,
scrapy/http/common.py,sha256=xSv2z7fQKyyAtSj98H68xIcEoZI-1W7BVDD4lWM5mFM,247
scrapy/http/cookies.py,sha256=uE3Js0R-lQZztadT3MMSRrlIouOaVQ4-uTdecUni8nk,5842
scrapy/http/headers.py,sha256=95O4zWPdUmXJFgy2wMBe2SjvWfXPqzFtn6x2r8N_5-o,2738
scrapy/http/request/__init__.py,sha256=ruK2uoGLPlocbhhccQaFFbfYvy8-pT6s1w8Wi5K4d-w,3483
scrapy/http/request/__pycache__/__init__.cpython-36.pyc,,
scrapy/http/request/__pycache__/form.cpython-36.pyc,,
scrapy/http/request/__pycache__/json_request.cpython-36.pyc,,
scrapy/http/request/__pycache__/rpc.cpython-36.pyc,,
scrapy/http/request/form.py,sha256=XJhxnWFTjD6uBloDzIgr1AEnKtFHXuwshkxipTg-cWQ,7852
scrapy/http/request/json_request.py,sha256=kLnvuqkml5L-nUHRjIT9QplTPCen4pBiNKNgSqZ6MKE,1722
scrapy/http/request/rpc.py,sha256=81jlEaaSR3kOw1y7j6HQMEqdjxR__7bdnlG6PlrMEug,1109
scrapy/http/response/__init__.py,sha256=7RgWzEdOVmmB3SEUZl3gAbVBkGOpqa1HzVikMNsyFKI,4624
scrapy/http/response/__pycache__/__init__.cpython-36.pyc,,
scrapy/http/response/__pycache__/html.cpython-36.pyc,,
scrapy/http/response/__pycache__/text.cpython-36.pyc,,
scrapy/http/response/__pycache__/xml.cpython-36.pyc,,
scrapy/http/response/html.py,sha256=OMbreqX9_9ME0fUgl1FlGay86er_-bkJQCk-L7pn_DE,299
scrapy/http/response/text.py,sha256=VlBm4EI3Qqu_VF3jhhSBt1DnhOTRgpFKm37S-PoHmvU,6459
scrapy/http/response/xml.py,sha256=W02SvIrRv6OMNwqP3m5fnQVRVlExrMDOYZyyoiuNxAI,296
scrapy/interfaces.py,sha256=DGvtWeh-AqQstCHTzhSTW7GR46OY0Q9Vyql0LVNCR-g,558
scrapy/item.py,sha256=A6K2CvBY_dGmjahs83QaVqjTl5OPSPUZrDRhxDYwWHA,2936
scrapy/link.py,sha256=Z8DIzb3SKfZFoyo9ZSaLVVYjxQYo-LxVbIjLj7-RPZ8,1456
scrapy/linkextractors/__init__.py,sha256=UxqtWN2RYU9M9rFS0s8CeDmj4D1KXE-whvI3S4PRUuY,4272
scrapy/linkextractors/__pycache__/__init__.cpython-36.pyc,,
scrapy/linkextractors/__pycache__/htmlparser.cpython-36.pyc,,
scrapy/linkextractors/__pycache__/lxmlhtml.cpython-36.pyc,,
scrapy/linkextractors/__pycache__/regex.cpython-36.pyc,,
scrapy/linkextractors/__pycache__/sgml.cpython-36.pyc,,
scrapy/linkextractors/htmlparser.py,sha256=e02ScMDkPaft4X8aPIDboo0K0L4WmSSFgjRfDiK_tOs,3098
scrapy/linkextractors/lxmlhtml.py,sha256=3aLIZYqNdHYTiFlHbpNjIpcV1byScQnLTwIKnsGHYGc,5167
scrapy/linkextractors/regex.py,sha256=cFNdKeznrceSOjmFG7CneFMsi4Qt3e40-8PqFSsoPxQ,1365
scrapy/linkextractors/sgml.py,sha256=Yud2amivbIrv0RHFxJbKKjVfk1GuNNqdqKQUd5sK6bw,6174
scrapy/loader/__init__.py,sha256=t12Ut1BxLGYYnerT9c32bm5E2HWiq6H2xU912Ehwi-w,7377
scrapy/loader/__pycache__/__init__.cpython-36.pyc,,
scrapy/loader/__pycache__/common.cpython-36.pyc,,
scrapy/loader/__pycache__/processors.cpython-36.pyc,,
scrapy/loader/common.py,sha256=w6UWdlw7XwgBY0KhHpHoCBDBSsDg6DAJpXt8jPkYjQw,467
scrapy/loader/processors.py,sha256=7yeJTlOl2HYHnv7siPpQgR5ZofepLJH18ufu-Pjb3is,3514
scrapy/logformatter.py,sha256=S_J90TIMaAWIL1J19dqOYyQVmaCoCf-hhu6TATr-TPQ,2669
scrapy/mail.py,sha256=nhEXQT_mW_KhIHe7SHc9E64jG4Ev2ByZHAJPorTIOoE,5008
scrapy/middleware.py,sha256=O5I6Y14LojjmM6b72s6xCiw2MzfcwiptK2vbmp_YJSo,2729
scrapy/mime.types,sha256=7qvGIyoPSzvg9yaUpGQ8Du29MCGWi4Em_W30NUnX8qQ,20392
scrapy/pipelines/__init__.py,sha256=weq8sXL8EXHmgxrP5jXwijVI7hSfDJPY60_tGRzwNJA,714
scrapy/pipelines/__pycache__/__init__.cpython-36.pyc,,
scrapy/pipelines/__pycache__/files.cpython-36.pyc,,
scrapy/pipelines/__pycache__/images.cpython-36.pyc,,
scrapy/pipelines/__pycache__/media.cpython-36.pyc,,
scrapy/pipelines/files.py,sha256=FuuOXlAR1uUbw8vGbGT1eJ1QvWcnT35vX_7PA43iWKE,17220
scrapy/pipelines/images.py,sha256=zYgT6LBmU7fC_9HSKb9kFT-pCxR_Qtmr6lLZk6yx0-E,6282
scrapy/pipelines/media.py,sha256=5uKBskmxqUv3iEhHSXZUth9ZWVDUPeVdGaS4CpjZnxA,7927
scrapy/pqueues.py,sha256=559g--Af_FuI7nqd-swG2pI6BhmL2mTxVnzk6wzzBPk,7020
scrapy/resolver.py,sha256=yvEwscKAwSN_k0rQcqKwZEmOoC89FGSzSD4SLgsFN-c,1114
scrapy/responsetypes.py,sha256=c-0mDpDd4AzRAWL07Njsn4YDnQeJKgaMo6SyhlSFwpo,4856
scrapy/selector/__init__.py,sha256=mqtn-787YUiKAQRNKSTrfcy7msFih5dvSfLk-Pxa0aE,56
scrapy/selector/__pycache__/__init__.cpython-36.pyc,,
scrapy/selector/__pycache__/unified.cpython-36.pyc,,
scrapy/selector/unified.py,sha256=GPGc-44XU8boqL6BW4MOKKPJLofAJJ5L46QuFMRmWbw,2751
scrapy/settings/__init__.py,sha256=ph4PLiBWcMLnJa5uk52W5cslp6VfZljM29g-yyUpiNE,15983
scrapy/settings/__pycache__/__init__.cpython-36.pyc,,
scrapy/settings/__pycache__/default_settings.cpython-36.pyc,,
scrapy/settings/__pycache__/deprecated.cpython-36.pyc,,
scrapy/settings/default_settings.py,sha256=AB8f1BJ81PvT6c0ip7VvzuvWg-77rGQ1PugrM28Jk8M,8753
scrapy/settings/deprecated.py,sha256=QnHMsOyZ6FDD1h92Tev15HKgOt4MkUM8K8uLgxnAwRQ,1451
scrapy/shell.py,sha256=mQjwfVt_57lkBZONQBBxJBd12p6JSUfUTE05w7-7GjA,7545
scrapy/signalmanager.py,sha256=S1H3hKakZt6SihB9gjucPut9d_HtfMY8QpG4H5EcN84,2475
scrapy/signals.py,sha256=rhvhVrwAeiuB1dXBgnjRVybdOOKnvfyWyLnoEynOQMY,726
scrapy/spiderloader.py,sha256=QDSTZ7hZXI9x5_kyN611NxnZllyDv7MsG9o9S5KDSZc,2993
scrapy/spidermiddlewares/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
scrapy/spidermiddlewares/__pycache__/__init__.cpython-36.pyc,,
scrapy/spidermiddlewares/__pycache__/depth.cpython-36.pyc,,
scrapy/spidermiddlewares/__pycache__/httperror.cpython-36.pyc,,
scrapy/spidermiddlewares/__pycache__/offsite.cpython-36.pyc,,
scrapy/spidermiddlewares/__pycache__/referer.cpython-36.pyc,,
scrapy/spidermiddlewares/__pycache__/urllength.cpython-36.pyc,,
scrapy/spidermiddlewares/depth.py,sha256=9PKNJhjK5ifYSAQkPm7A9a0HPgdcXy1ljNrStmN8kE4,2020
scrapy/spidermiddlewares/httperror.py,sha256=S--1Fj3kDjGRpWxKrKBDI_ZbfKyTnXY1442GXx3WeLc,1921
scrapy/spidermiddlewares/offsite.py,sha256=oj7KXRCb1yVixLCEtQfpJ_88fS4MP_l4oUyKlD3mkyE,2563
scrapy/spidermiddlewares/referer.py,sha256=-qnECc8aGubdd2MNxFH-7KqCgTFiKwuB6cnddmnRe-U,13626
scrapy/spidermiddlewares/urllength.py,sha256=ZLzHSY8GlgYElyY4L2v-XzXQ7e9ukEZ22nPfRfeeZEc,1059
scrapy/spiders/__init__.py,sha256=7prK-GN_kfDtgqme7-40Br-R7DFuR-EUnaxVKjnHbD4,3370
scrapy/spiders/__pycache__/__init__.cpython-36.pyc,,
scrapy/spiders/__pycache__/crawl.cpython-36.pyc,,
scrapy/spiders/__pycache__/feed.cpython-36.pyc,,
scrapy/spiders/__pycache__/init.cpython-36.pyc,,
scrapy/spiders/__pycache__/sitemap.cpython-36.pyc,,
scrapy/spiders/crawl.py,sha256=6-5o4H2gcpTCQ51kOMIAMedKuQ0oWlncIt-Zi0fYkZU,4382
scrapy/spiders/feed.py,sha256=uglx45zWWSCkHuMPxn-X_rBKc7qo3QU8Rz1gib4dyDo,5441
scrapy/spiders/init.py,sha256=6moM5Uc_JHkB3ktCiEALBGukUIgBGKcbvGrqaZTVP6U,1354
scrapy/spiders/sitemap.py,sha256=WOFv_p6cldLxaj4RDpdMYYXxqPFpG8aGiNp_3y_7NHs,3579
scrapy/squeues.py,sha256=dTxBInUZUvE-jODzXZsA3ZGogeH43MGdU_IzdqOp1Ok,1301
scrapy/statscollectors.py,sha256=lPGG3O2pifgY0hkPc47_BP1RxLpsC-4jLNG4BaxCC8U,2129
scrapy/templates/project/module/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
scrapy/templates/project/module/__pycache__/__init__.cpython-36.pyc,,
scrapy/templates/project/module/items.py.tmpl,sha256=PhB4ktMFPN6sxgq7NvBBc-jmNUl9IqIufiRigI86LJg,295
scrapy/templates/project/module/middlewares.py.tmpl,sha256=KiJuaxDkJ2Ec7YlEZ1kare3_P7hH6Kk4il0gUDU0bFo,3613
scrapy/templates/project/module/pipelines.py.tmpl,sha256=3d07xChH5DWvqHOhxnqFvwbNwVTIkHQKl5KwO-s8W1M,296
scrapy/templates/project/module/settings.py.tmpl,sha256=Yl1ax5pQbCQb1lBf1VePOL65SFtWNPkzTqKD9bNTZUU,3162
scrapy/templates/project/module/spiders/__init__.py,sha256=ULwecZkx3_NTphkz7y_qiazBeUoHFnCCWnKSjoDCZj0,161
scrapy/templates/project/module/spiders/__pycache__/__init__.cpython-36.pyc,,
scrapy/templates/project/scrapy.cfg,sha256=rRXe96NnAjpS8_2AtC_flgy7uleqtduLmPd-K720IG4,273
scrapy/templates/spiders/basic.tmpl,sha256=DbIobzgnP0SSwCUFdpvF79zcViqO7Hp3MKlrSEYlriI,208
scrapy/templates/spiders/crawl.tmpl,sha256=-X_oA4pShxJtcC6BsXXp3HljYeJDknBKG1uAueFmdHk,657
scrapy/templates/spiders/csvfeed.tmpl,sha256=uxN0675_-ntfDkK9OBiu0B7x7dSXmxYWj5G5fV-0vIo,571
scrapy/templates/spiders/xmlfeed.tmpl,sha256=cStRh3fgz_48X5B9tHtlqsyYbqfvBYC4cOTmzZx8nds,565
scrapy/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
scrapy/utils/__pycache__/__init__.cpython-36.pyc,,
scrapy/utils/__pycache__/benchserver.cpython-36.pyc,,
scrapy/utils/__pycache__/boto.cpython-36.pyc,,
scrapy/utils/__pycache__/conf.cpython-36.pyc,,
scrapy/utils/__pycache__/console.cpython-36.pyc,,
scrapy/utils/__pycache__/datatypes.cpython-36.pyc,,
scrapy/utils/__pycache__/decorators.cpython-36.pyc,,
scrapy/utils/__pycache__/defer.cpython-36.pyc,,
scrapy/utils/__pycache__/deprecate.cpython-36.pyc,,
scrapy/utils/__pycache__/display.cpython-36.pyc,,
scrapy/utils/__pycache__/engine.cpython-36.pyc,,
scrapy/utils/__pycache__/ftp.cpython-36.pyc,,
scrapy/utils/__pycache__/gz.cpython-36.pyc,,
scrapy/utils/__pycache__/http.cpython-36.pyc,,
scrapy/utils/__pycache__/httpobj.cpython-36.pyc,,
scrapy/utils/__pycache__/iterators.cpython-36.pyc,,
scrapy/utils/__pycache__/job.cpython-36.pyc,,
scrapy/utils/__pycache__/log.cpython-36.pyc,,
scrapy/utils/__pycache__/markup.cpython-36.pyc,,
scrapy/utils/__pycache__/misc.cpython-36.pyc,,
scrapy/utils/__pycache__/multipart.cpython-36.pyc,,
scrapy/utils/__pycache__/ossignal.cpython-36.pyc,,
scrapy/utils/__pycache__/project.cpython-36.pyc,,
scrapy/utils/__pycache__/python.cpython-36.pyc,,
scrapy/utils/__pycache__/reactor.cpython-36.pyc,,
scrapy/utils/__pycache__/reqser.cpython-36.pyc,,
scrapy/utils/__pycache__/request.cpython-36.pyc,,
scrapy/utils/__pycache__/response.cpython-36.pyc,,
scrapy/utils/__pycache__/serialize.cpython-36.pyc,,
scrapy/utils/__pycache__/signal.cpython-36.pyc,,
scrapy/utils/__pycache__/sitemap.cpython-36.pyc,,
scrapy/utils/__pycache__/spider.cpython-36.pyc,,
scrapy/utils/__pycache__/template.cpython-36.pyc,,
scrapy/utils/__pycache__/test.cpython-36.pyc,,
scrapy/utils/__pycache__/testproc.cpython-36.pyc,,
scrapy/utils/__pycache__/testsite.cpython-36.pyc,,
scrapy/utils/__pycache__/trackref.cpython-36.pyc,,
scrapy/utils/__pycache__/url.cpython-36.pyc,,
scrapy/utils/__pycache__/versions.cpython-36.pyc,,
scrapy/utils/benchserver.py,sha256=WVbn3Qq78Ul7P8LbBPNxBp5-dh7h87STziVFnEVe044,1332
scrapy/utils/boto.py,sha256=XOuDGZFSFu52k-zT8HR7Vmza6RevrrckvXhPPyyt45M,494
scrapy/utils/conf.py,sha256=sDQtbM-G1vUhUy4ye3nY4g6pdHw6cv7r-xC3_TaIzlI,4102
scrapy/utils/console.py,sha256=o_8iJo5CarNN5NgSEMnxkTTRScmsP4-iULNTMsr1ZPA,3403
scrapy/utils/datatypes.py,sha256=M9Hb_GIy2E7Zi79acxIePD8WP_ns0gI4GGzlrj_KXhU,9823
scrapy/utils/decorators.py,sha256=OR-tu3Xh2JW4tQsPFw18K7BdlY4xU64ukpqTFBQ8t0k,1273
scrapy/utils/defer.py,sha256=k8gTXwubNeHa-dJ9kF910d0NVIxOIqNdrIMg7_wjGf4,3576
scrapy/utils/deprecate.py,sha256=e9JdhwgIg4ygfYtxBMXi_Vw7oy69CHn1nHs7Mkcd3ho,6710
scrapy/utils/display.py,sha256=e1fwP0uIEZyEmrJtYRynwKfrAfVPa58sh_NS1q3s7aM,699
scrapy/utils/engine.py,sha256=DdlrtdxTAAT-lnC325WfGRrjJVfYYs_EIy2fXZl0p5w,1376
scrapy/utils/ftp.py,sha256=Nt5QYvnBC1fs2RTm3dGfr5v1JeuXebS9Ass7bqjY6ds,531
scrapy/utils/gz.py,sha256=3Hn1C_ck0nzowXo4NWau67ecp3GAySxnWOQ5IbFQn2U,2200
scrapy/utils/http.py,sha256=lNaFKDZxXqbA-5kkCn_zMYp4s3KkSW-Q1Q8OC6uy8lw,905
scrapy/utils/httpobj.py,sha256=zrs-XKmo12LCXqSzQUbkp17tx8CzjiM_a8K14M0805s,516
scrapy/utils/iterators.py,sha256=KlR9nWVdWZ61YWwtCeY8KkMEp5VrM2IgPb7VUmE0l40,5025
scrapy/utils/job.py,sha256=9aMdjUE8yXj_TUbTVzTVmyXpmT8WSSuytNJNM1L7Tx8,148
scrapy/utils/log.py,sha256=oSB5QV5etHOBwpzF0rRUJwRcmkciWW7Fkh0t18UpyTU,6558
scrapy/utils/markup.py,sha256=PTuqniHxdLO9IgjgdJA9_1P1iUR6itySyN5VHzdh4ss,400
scrapy/utils/misc.py,sha256=loIAdMP21eLM26wbKNDg_8TgTyOaek1iC9E1MvWV4mg,5030
scrapy/utils/multipart.py,sha256=sNbnG1slp7cNnI7ZJBFRMWeQodlPFTR_Hr8ZG2-vhjY,488
scrapy/utils/ossignal.py,sha256=kxrCur_rPYVipHIBlwWHUScEFgULrC3UNi7IHIox_Kg,994
scrapy/utils/project.py,sha256=ufFEQ5QSJ2uG9DEakWSdNOVC1R86NsG-pf8LstH65VI,2590
scrapy/utils/python.py,sha256=m1ZocXLJHnxbhWHUw-ut1Rif8LNqWFSaWZCXwagaXhc,11805
scrapy/utils/reactor.py,sha256=LkmKoT-YLTmIvCrBsvuPR_1Frkmj_0HAeOays4F9ztQ,1360
scrapy/utils/reqser.py,sha256=E1bvBMrP_lKufCXUp_pbRfZtdTmps7lq0QUaPHU9LlM,3213
scrapy/utils/request.py,sha256=Psnh6DX1vPjCIxVrYf19Zlrqh0FmH_xGj45qdeg9dGM,3459
scrapy/utils/response.py,sha256=lI_NJ-oYJOQuWTXHh61Bmu0eY9qh6jVqAepI7e5A9-Y,2665
scrapy/utils/serialize.py,sha256=J3T9E05j8HXqoqHuX_ZWSSqDes07iirCRl_BznHeyxg,1201
scrapy/utils/signal.py,sha256=b4fTZbiqVSxZazdGmLLBirKHHW0U7e-7XqbWHd_5a04,2969
scrapy/utils/sitemap.py,sha256=PSi3joL-4nVbBwhOqasDnOFcCQP8VA-BTtvEqX134as,1518
scrapy/utils/spider.py,sha256=VdMMl1EhmN65nA3tC-Z4uKn-wKfBaGApsbJjGZZnUJw,1911
scrapy/utils/template.py,sha256=JNCXL8NT0gGFgEK4aC0oCeUQlKOWzisdjdGNvnPJ4Q0,816
scrapy/utils/test.py,sha256=fhMskcoxNFyNeSS9EZ1cCt_StVNgyr0UmRhUxdIW-cw,3089
scrapy/utils/testproc.py,sha256=xDcuLRPWChiTL7L7wwYOT9XZjdzQUu0tDsMKyFSXzwc,1508
scrapy/utils/testsite.py,sha256=yDS8GwhSKKBuNLCswrrmD2GfsB827sTlKfuQ8iorxao,1562
scrapy/utils/trackref.py,sha256=rg82Iib9fkjqkfmFdE507VVxcOBfycG_FZZ9Hldyz08,2081
scrapy/utils/url.py,sha256=5sWMcSbQQBe53pa2v5JOPMSq2cQmzsI09OEvQdCg0W8,5119
scrapy/utils/versions.py,sha256=eMWzL4F0jIWnSxlSd-hysa9LoCSJjc9cwirxsdlWZIg,1419
scrapy/xlib/__init__.py,sha256=CbHNJHO8-CRSs6dP3WIWf1u4ruo2KyTrio-GBpxr45Y,92
scrapy/xlib/__pycache__/__init__.cpython-36.pyc,,
scrapy/xlib/__pycache__/pydispatch.cpython-36.pyc,,
scrapy/xlib/__pycache__/tx.cpython-36.pyc,,
scrapy/xlib/pydispatch.py,sha256=Z4y2vxQ5k4SrDfLfjJsR2BUGNY0Pghn9lmVqpJEXyRo,629
scrapy/xlib/tx.py,sha256=v08NnjBxl_kdLlCVSLEJcyEti-DHhw2Sklai2eCZhbY,749
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Scrapy-1.7.4.dist-info/WHEEL
================================================
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.6)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Scrapy-1.7.4.dist-info/entry_points.txt
================================================
[console_scripts]
scrapy = scrapy.cmdline:execute
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Scrapy-1.7.4.dist-info/top_level.txt
================================================
scrapy
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Twisted-19.7.0.dist-info/INSTALLER
================================================
pip
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Twisted-19.7.0.dist-info/LICENSE
================================================
Copyright (c) 2001-2019
Allen Short
Amber Hawkie Brown
Andrew Bennetts
Andy Gayton
Antoine Pitrou
Apple Computer, Inc.
Ashwini Oruganti
Benjamin Bruheim
Bob Ippolito
Canonical Limited
Christopher Armstrong
Ciena Corporation
David Reid
Divmod Inc.
Donovan Preston
Eric Mangold
Eyal Lotem
Google Inc.
Hybrid Logic Ltd.
Hynek Schlawack
Itamar Turner-Trauring
James Knight
Jason A. Mobarak
Jean-Paul Calderone
Jessica McKellar
Jonathan D. Simms
Jonathan Jacobs
Jonathan Lange
Julian Berman
Jürgen Hermann
Kevin Horn
Kevin Turner
Laurens Van Houtven
Mary Gardiner
Massachusetts Institute of Technology
Matthew Lefkowitz
Moshe Zadka
Paul Swartz
Pavel Pergamenshchik
Rackspace, US Inc.
Ralph Meijer
Richard Wall
Sean Riley
Software Freedom Conservancy
Tavendo GmbH
Thijs Triemstra
Thomas Herve
Timothy Allen
Tom Most
Tom Prince
Travis B. Hartwell
and others that have contributed code to the public domain.
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.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Twisted-19.7.0.dist-info/METADATA
================================================
Metadata-Version: 2.1
Name: Twisted
Version: 19.7.0
Summary: An asynchronous networking framework written in Python
Home-page: https://twistedmatrix.com/
Author: Twisted Matrix Laboratories
Author-email: twisted-python@twistedmatrix.com
Maintainer: Glyph Lefkowitz
Maintainer-email: glyph@twistedmatrix.com
License: MIT
Project-URL: Documentation, https://twistedmatrix.com/documents/current/
Project-URL: Source, https://github.com/twisted/twisted
Project-URL: Issues, https://twistedmatrix.com/trac/report
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Description-Content-Type: text/x-rst
Requires-Dist: zope.interface (>=4.4.2)
Requires-Dist: constantly (>=15.1)
Requires-Dist: incremental (>=16.10.1)
Requires-Dist: Automat (>=0.3.0)
Requires-Dist: hyperlink (>=17.1.1)
Requires-Dist: PyHamcrest (>=1.9.0)
Requires-Dist: attrs (>=17.4.0)
Provides-Extra: all_non_platform
Requires-Dist: pyopenssl (>=16.0.0) ; extra == 'all_non_platform'
Requires-Dist: service-identity (>=18.1.0) ; extra == 'all_non_platform'
Requires-Dist: idna (!=2.3,>=0.6) ; extra == 'all_non_platform'
Requires-Dist: pyasn1 ; extra == 'all_non_platform'
Requires-Dist: cryptography (>=2.5) ; extra == 'all_non_platform'
Requires-Dist: appdirs (>=1.4.0) ; extra == 'all_non_platform'
Requires-Dist: bcrypt (>=3.0.0) ; extra == 'all_non_platform'
Requires-Dist: soappy ; extra == 'all_non_platform'
Requires-Dist: pyserial (>=3.0) ; extra == 'all_non_platform'
Requires-Dist: h2 (<4.0,>=3.0) ; extra == 'all_non_platform'
Requires-Dist: priority (<2.0,>=1.1.0) ; extra == 'all_non_platform'
Provides-Extra: conch
Requires-Dist: pyasn1 ; extra == 'conch'
Requires-Dist: cryptography (>=2.5) ; extra == 'conch'
Requires-Dist: appdirs (>=1.4.0) ; extra == 'conch'
Requires-Dist: bcrypt (>=3.0.0) ; extra == 'conch'
Provides-Extra: dev
Requires-Dist: pyflakes (>=1.0.0) ; extra == 'dev'
Requires-Dist: twisted-dev-tools (>=0.0.2) ; extra == 'dev'
Requires-Dist: python-subunit ; extra == 'dev'
Requires-Dist: sphinx (>=1.3.1) ; extra == 'dev'
Requires-Dist: towncrier (>=17.4.0) ; extra == 'dev'
Provides-Extra: http2
Requires-Dist: h2 (<4.0,>=3.0) ; extra == 'http2'
Requires-Dist: priority (<2.0,>=1.1.0) ; extra == 'http2'
Provides-Extra: macos_platform
Requires-Dist: pyobjc-core ; extra == 'macos_platform'
Requires-Dist: pyobjc-framework-CFNetwork ; extra == 'macos_platform'
Requires-Dist: pyobjc-framework-Cocoa ; extra == 'macos_platform'
Requires-Dist: pyopenssl (>=16.0.0) ; extra == 'macos_platform'
Requires-Dist: service-identity (>=18.1.0) ; extra == 'macos_platform'
Requires-Dist: idna (!=2.3,>=0.6) ; extra == 'macos_platform'
Requires-Dist: pyasn1 ; extra == 'macos_platform'
Requires-Dist: cryptography (>=2.5) ; extra == 'macos_platform'
Requires-Dist: appdirs (>=1.4.0) ; extra == 'macos_platform'
Requires-Dist: bcrypt (>=3.0.0) ; extra == 'macos_platform'
Requires-Dist: soappy ; extra == 'macos_platform'
Requires-Dist: pyserial (>=3.0) ; extra == 'macos_platform'
Requires-Dist: h2 (<4.0,>=3.0) ; extra == 'macos_platform'
Requires-Dist: priority (<2.0,>=1.1.0) ; extra == 'macos_platform'
Provides-Extra: osx_platform
Requires-Dist: pyobjc-core ; extra == 'osx_platform'
Requires-Dist: pyobjc-framework-CFNetwork ; extra == 'osx_platform'
Requires-Dist: pyobjc-framework-Cocoa ; extra == 'osx_platform'
Requires-Dist: pyopenssl (>=16.0.0) ; extra == 'osx_platform'
Requires-Dist: service-identity (>=18.1.0) ; extra == 'osx_platform'
Requires-Dist: idna (!=2.3,>=0.6) ; extra == 'osx_platform'
Requires-Dist: pyasn1 ; extra == 'osx_platform'
Requires-Dist: cryptography (>=2.5) ; extra == 'osx_platform'
Requires-Dist: appdirs (>=1.4.0) ; extra == 'osx_platform'
Requires-Dist: bcrypt (>=3.0.0) ; extra == 'osx_platform'
Requires-Dist: soappy ; extra == 'osx_platform'
Requires-Dist: pyserial (>=3.0) ; extra == 'osx_platform'
Requires-Dist: h2 (<4.0,>=3.0) ; extra == 'osx_platform'
Requires-Dist: priority (<2.0,>=1.1.0) ; extra == 'osx_platform'
Provides-Extra: serial
Requires-Dist: pyserial (>=3.0) ; extra == 'serial'
Provides-Extra: soap
Requires-Dist: soappy ; extra == 'soap'
Provides-Extra: tls
Requires-Dist: pyopenssl (>=16.0.0) ; extra == 'tls'
Requires-Dist: service-identity (>=18.1.0) ; extra == 'tls'
Requires-Dist: idna (!=2.3,>=0.6) ; extra == 'tls'
Provides-Extra: windows_platform
Requires-Dist: pywin32 ; extra == 'windows_platform'
Requires-Dist: pyopenssl (>=16.0.0) ; extra == 'windows_platform'
Requires-Dist: service-identity (>=18.1.0) ; extra == 'windows_platform'
Requires-Dist: idna (!=2.3,>=0.6) ; extra == 'windows_platform'
Requires-Dist: pyasn1 ; extra == 'windows_platform'
Requires-Dist: cryptography (>=2.5) ; extra == 'windows_platform'
Requires-Dist: appdirs (>=1.4.0) ; extra == 'windows_platform'
Requires-Dist: bcrypt (>=3.0.0) ; extra == 'windows_platform'
Requires-Dist: soappy ; extra == 'windows_platform'
Requires-Dist: pyserial (>=3.0) ; extra == 'windows_platform'
Requires-Dist: h2 (<4.0,>=3.0) ; extra == 'windows_platform'
Requires-Dist: priority (<2.0,>=1.1.0) ; extra == 'windows_platform'
Twisted
=======
|pypi|_
|travis|_
|circleci|_
For information on what's new in Twisted 19.2.0, see the `NEWS `_ file that comes with the distribution.
What is this?
-------------
Twisted is an event-based framework for internet applications, supporting Python 2.7 and Python 3.5+.
It includes modules for many different purposes, including the following:
- ``twisted.web``: HTTP clients and servers, HTML templating, and a WSGI server
- ``twisted.conch``: SSHv2 and Telnet clients and servers and terminal emulators
- ``twisted.words``: Clients and servers for IRC, XMPP, and other IM protocols
- ``twisted.mail``: IMAPv4, POP3, SMTP clients and servers
- ``twisted.positioning``: Tools for communicating with NMEA-compatible GPS receivers
- ``twisted.names``: DNS client and tools for making your own DNS servers
- ``twisted.trial``: A unit testing framework that integrates well with Twisted-based code.
Twisted supports all major system event loops -- ``select`` (all platforms), ``poll`` (most POSIX platforms), ``epoll`` (Linux), ``kqueue`` (FreeBSD, macOS), IOCP (Windows), and various GUI event loops (GTK+2/3, Qt, wxWidgets).
Third-party reactors can plug into Twisted, and provide support for additional event loops.
Installing
----------
To install the latest version of Twisted using pip::
$ pip install twisted
Additional instructions for installing this software are in `the installation instructions `_.
Documentation and Support
-------------------------
Twisted's documentation is available from the `Twisted Matrix website `_.
This documentation contains how-tos, code examples, and an API reference.
Help is also available on the `Twisted mailing list `_.
There is also a pair of very lively IRC channels, ``#twisted`` (for general Twisted questions) and ``#twisted.web`` (for Twisted Web), on ``chat.freenode.net``.
Unit Tests
----------
Twisted has a comprehensive test suite, which can be run by ``tox``::
$ tox -l # to view all test environments
$ tox -e py27-tests # to run the tests for Python 2.7
$ tox -e py35-tests # to run the tests for Python 3.5
You can test running the test suite under the different reactors with the ``TWISTED_REACTOR`` environment variable::
$ env TWISTED_REACTOR=epoll tox -e py27-tests
Some of these tests may fail if you:
* don't have the dependencies required for a particular subsystem installed,
* have a firewall blocking some ports (or things like Multicast, which Linux NAT has shown itself to do), or
* run them as root.
Copyright
---------
All of the code in this distribution is Copyright (c) 2001-2019 Twisted Matrix Laboratories.
Twisted is made available under the MIT license.
The included `LICENSE `_ file describes this in detail.
Warranty
--------
THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE USE OF THIS SOFTWARE IS WITH YOU.
IN NO EVENT WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY, BE LIABLE TO YOU FOR ANY DAMAGES, EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
Again, see the included `LICENSE `_ file for specific legal details.
.. |pypi| image:: http://img.shields.io/pypi/v/twisted.svg
.. _pypi: https://pypi.python.org/pypi/twisted
.. |travis| image:: https://travis-ci.org/twisted/twisted.svg?branch=trunk
.. _travis: https://travis-ci.org/twisted/twisted
.. |circleci| image:: https://circleci.com/gh/twisted/twisted.svg?style=svg
.. _circleci: https://circleci.com/gh/twisted/twisted
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Twisted-19.7.0.dist-info/RECORD
================================================
../../../bin/cftp,sha256=uQ-4stYf8E120-asLychp7hW1VjLJxFL_6HNQI0aHdo,289
../../../bin/ckeygen,sha256=4GXdm-6Esn7pGzUxOvnNH_g6nl_jIsNazaBBzD_dkM4,292
../../../bin/conch,sha256=_8hQIr6ODtna6muwkpUnV333R-PyKSOVPjW0PORO3Ho,290
../../../bin/mailmail,sha256=QXut2P7LTlyKMFD6eM8uDlaXlUwnm523mrKmxiYgd4Y,292
../../../bin/pyhtmlizer,sha256=fcX6JmFsYRGMDV9hyV1PULC6x3vJhi3fNW8hwlZVLdg,287
../../../bin/tkconch,sha256=m7e0vrKcr_kYHru2A8qfTV-LynkDFJIc4uMZGh8yEMM,292
../../../bin/trial,sha256=m3QRoAfu-MXf3yMnwDsRzEayV-GGnxNl5J9Si3psuX4,284
../../../bin/twist,sha256=kJTyCYIA1VJw8qmtYnumNRt2eOljm68iOeauiljwibY,304
../../../bin/twistd,sha256=RnXH8pBHK-V3QlTXoxihOlZjhkudgOV1hJr174Z7Sw0,285
Twisted-19.7.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
Twisted-19.7.0.dist-info/LICENSE,sha256=hbeYQTuohbBswbke_oV6OfaUBxwpsE6A0j6ibuJx1hM,1926
Twisted-19.7.0.dist-info/METADATA,sha256=9lvJRkxJOpFZ8fFA81XkDN6jkCljIvfEvxHUTrWRyFo,9321
Twisted-19.7.0.dist-info/RECORD,,
Twisted-19.7.0.dist-info/WHEEL,sha256=q6ZS0x11G9XscKQI--PbS172VpPpBOOoLI4QlxtsUa0,109
Twisted-19.7.0.dist-info/entry_points.txt,sha256=UK8U0KNTSAegCW9a4j4bDwbOO5c1579QKqXzwsPPcnI,394
Twisted-19.7.0.dist-info/top_level.txt,sha256=e9eVTH2N7T_qnhIPUQhDQilKWgnW7rTHCvHGyd7xp0k,8
twisted/__init__.py,sha256=A7hcrXmwPGeAGHDPU_wyOTjgqRHAPAuLVvMI9E6xblg,256
twisted/__main__.py,sha256=-IXh5Xk046Kf8k4NqwciSb4K6q4X4RnKEMwsrbrsn9g,448
twisted/__pycache__/__init__.cpython-36.pyc,,
twisted/__pycache__/__main__.cpython-36.pyc,,
twisted/__pycache__/_version.cpython-36.pyc,,
twisted/__pycache__/copyright.cpython-36.pyc,,
twisted/__pycache__/plugin.cpython-36.pyc,,
twisted/_threads/__init__.py,sha256=XUQc4vy6dlY3VYcNQZEGPOThfz6cB6x9-ySpiv3eW8w,570
twisted/_threads/__pycache__/__init__.cpython-36.pyc,,
twisted/_threads/__pycache__/_convenience.cpython-36.pyc,,
twisted/_threads/__pycache__/_ithreads.cpython-36.pyc,,
twisted/_threads/__pycache__/_memory.cpython-36.pyc,,
twisted/_threads/__pycache__/_pool.cpython-36.pyc,,
twisted/_threads/__pycache__/_team.cpython-36.pyc,,
twisted/_threads/__pycache__/_threadworker.cpython-36.pyc,,
twisted/_threads/_convenience.py,sha256=bME26wNYCSEtoVqCOSqqwMyEhgU9_UXzFu4r-lK9fsI,969
twisted/_threads/_ithreads.py,sha256=phOeuVsKw3K-BPex6ZutkvNyij8nrYZAmhVgi5wERUo,1810
twisted/_threads/_memory.py,sha256=8V-KVBG6ngic_XNenwGAslQWsNyoeRhn4Hd5vv4ByoY,1666
twisted/_threads/_pool.py,sha256=_Nw_ltHAfF24Vy72CoxPXiNkUAfRUlLD3PFiavzy00E,2399
twisted/_threads/_team.py,sha256=60gJbzlRrx6Ga8Qse7Klpsv5Sqc4a1DYGh52Qt1GJVA,7259
twisted/_threads/_threadworker.py,sha256=GnzPGY_4nz9_aohIK4l_UnEPEg-o-0u4jCmR8emV4AE,3376
twisted/_threads/test/__init__.py,sha256=-tNWrOXAaGo9x-k49W4kk9ol44DaBbLFeBSZaHxtzKk,226
twisted/_threads/test/__pycache__/__init__.cpython-36.pyc,,
twisted/_threads/test/__pycache__/test_convenience.cpython-36.pyc,,
twisted/_threads/test/__pycache__/test_memory.cpython-36.pyc,,
twisted/_threads/test/__pycache__/test_team.cpython-36.pyc,,
twisted/_threads/test/__pycache__/test_threadworker.cpython-36.pyc,,
twisted/_threads/test/test_convenience.py,sha256=-088jkN0O_GroTglswcmnzz9iS7vUdLvOwN0nwMcJuE,1442
twisted/_threads/test/test_memory.py,sha256=H3pafUk-1CJL3kE7JM_zQKd0Dte6twFJqFD4j3ntkNY,2148
twisted/_threads/test/test_team.py,sha256=zY3BDEA5TrQgL5ka1WHOFC4A-6NNA0QU2Th8FBgi5G0,9534
twisted/_threads/test/test_threadworker.py,sha256=O5QpeGz0vLPApZV1jmnq29jfhG9y8MV8ygnh_4A_YXw,8093
twisted/_version.py,sha256=2gUxEnRoE1XvGCGzKAozLESbm4b5o6Aaa8H9hqtyLFk,260
twisted/application/__init__.py,sha256=qAl6aEqUMpJJXs69xa8mxSVpiE4E9MzMkKWX26xo8MM,129
twisted/application/__pycache__/__init__.cpython-36.pyc,,
twisted/application/__pycache__/app.cpython-36.pyc,,
twisted/application/__pycache__/internet.cpython-36.pyc,,
twisted/application/__pycache__/reactors.cpython-36.pyc,,
twisted/application/__pycache__/service.cpython-36.pyc,,
twisted/application/__pycache__/strports.cpython-36.pyc,,
twisted/application/app.py,sha256=bILSMk-3-7MLqoZf7OpbbXwZpxu9KSPAeC52WjR26Hg,23465
twisted/application/internet.py,sha256=EzTydNA6GYP6bPhkw1Bs4u_hxmGmd-RE_oQwpZszXSg,36974
twisted/application/reactors.py,sha256=p0LAxCG6gUX4L5k07rIaDhwXZu22pyxaELpoD7USe1M,2169
twisted/application/runner/__init__.py,sha256=oAOyWGGBaaPSeeHS_vHk2pvip3_-nPVZlPvIf4EkKh4,185
twisted/application/runner/__pycache__/__init__.cpython-36.pyc,,
twisted/application/runner/__pycache__/_exit.cpython-36.pyc,,
twisted/application/runner/__pycache__/_pidfile.cpython-36.pyc,,
twisted/application/runner/__pycache__/_runner.cpython-36.pyc,,
twisted/application/runner/_exit.py,sha256=injGMM6zHAa488X2m7VE_ImIKxRHR76aXIuGftbTZyQ,3984
twisted/application/runner/_pidfile.py,sha256=7PJHb2IBI5nz6280u_LpE1yoR0SbbojjJBPvIJHlECQ,6995
twisted/application/runner/_runner.py,sha256=A2wlGmCgxoWMn48mK-AkN74MeODYbfvhzGU6nxCngK0,5765
twisted/application/runner/test/__init__.py,sha256=NAk9flgxX4siFhfJm6zpSt9odTHr3mmjQeuq-SOBobo,180
twisted/application/runner/test/__pycache__/__init__.cpython-36.pyc,,
twisted/application/runner/test/__pycache__/test_exit.cpython-36.pyc,,
twisted/application/runner/test/__pycache__/test_pidfile.cpython-36.pyc,,
twisted/application/runner/test/__pycache__/test_runner.cpython-36.pyc,,
twisted/application/runner/test/test_exit.py,sha256=M3WZICqMykDZg-02VMo2p8QIuyoONkmjMDFKFfIaKMw,2489
twisted/application/runner/test/test_pidfile.py,sha256=7VHnxmHJJk-_w-77Egk6zm2u-LoN5Sc-DX_Sif-7yHo,12984
twisted/application/runner/test/test_runner.py,sha256=RZkx-HqEe0lqyTN3QX6t7y7kUbsChAfRo4R5HWKf0s0,13293
twisted/application/service.py,sha256=7JGdq40MJ_8lgOmEqu_vR7oQHaiXE2H_51hzpneTSJA,12021
twisted/application/strports.py,sha256=n8kh_673Beui-gQQu5xj7lYxgNyzXWg4IzNNO39UIjk,2233
twisted/application/test/__init__.py,sha256=QJh3C_0yH0jDm6ViNbaoefp_no7sv7FyuV32ZYWE75s,124
twisted/application/test/__pycache__/__init__.cpython-36.pyc,,
twisted/application/test/__pycache__/test_internet.cpython-36.pyc,,
twisted/application/test/__pycache__/test_service.cpython-36.pyc,,
twisted/application/test/test_internet.py,sha256=bBcMqDsAoXDy88xg5X1nkm8tMruEYBtVmkCkylyeyoI,42340
twisted/application/test/test_service.py,sha256=YPdTXv2BdRFUOyJdhKO8cPtdplxOmwi1fQjcft_Kw4M,5091
twisted/application/twist/__init__.py,sha256=YPzoFOyJSICe6QB4XZXFxNyJWsRru-RRvYizhrN9jJE,166
twisted/application/twist/__pycache__/__init__.cpython-36.pyc,,
twisted/application/twist/__pycache__/_options.cpython-36.pyc,,
twisted/application/twist/__pycache__/_twist.cpython-36.pyc,,
twisted/application/twist/_options.py,sha256=7SUx3kQpZbmXEUusRl4tJrGqv0s78GHJGjSOcWk5088,5719
twisted/application/twist/_twist.py,sha256=hmdSn31p0CPsBupdKoaa_RvTShH4gwigOyuYsJns3to,3499
twisted/application/twist/test/__init__.py,sha256=B0KIIGDdfaLWhGhs1WBlDQoABIMxwJBl5tSEQmIkoBo,178
twisted/application/twist/test/__pycache__/__init__.cpython-36.pyc,,
twisted/application/twist/test/__pycache__/test_options.cpython-36.pyc,,
twisted/application/twist/test/__pycache__/test_twist.cpython-36.pyc,,
twisted/application/twist/test/test_options.py,sha256=XP8TpbptQST3zFChhBxGJ8SKqUdloxYhEPrUznFHPMc,10906
twisted/application/twist/test/test_twist.py,sha256=SkVSPN9RcaXZMBVzx3QqnBf2Ljquvjcldb4kZo_DzqI,7618
twisted/conch/__init__.py,sha256=ePuf1Y1dXhse4EBuyIQUPsHFurM3l28cenQc9R3fL3A,198
twisted/conch/__pycache__/__init__.cpython-36.pyc,,
twisted/conch/__pycache__/avatar.cpython-36.pyc,,
twisted/conch/__pycache__/checkers.cpython-36.pyc,,
twisted/conch/__pycache__/endpoints.cpython-36.pyc,,
twisted/conch/__pycache__/error.cpython-36.pyc,,
twisted/conch/__pycache__/interfaces.cpython-36.pyc,,
twisted/conch/__pycache__/ls.cpython-36.pyc,,
twisted/conch/__pycache__/manhole.cpython-36.pyc,,
twisted/conch/__pycache__/manhole_ssh.cpython-36.pyc,,
twisted/conch/__pycache__/manhole_tap.cpython-36.pyc,,
twisted/conch/__pycache__/mixin.cpython-36.pyc,,
twisted/conch/__pycache__/recvline.cpython-36.pyc,,
twisted/conch/__pycache__/stdio.cpython-36.pyc,,
twisted/conch/__pycache__/tap.cpython-36.pyc,,
twisted/conch/__pycache__/telnet.cpython-36.pyc,,
twisted/conch/__pycache__/ttymodes.cpython-36.pyc,,
twisted/conch/__pycache__/unix.cpython-36.pyc,,
twisted/conch/avatar.py,sha256=cJqlSmAbhtnxxsBFLvQ6-kRvbnDSuf4FvnrpvZqEo_Y,1438
twisted/conch/checkers.py,sha256=UPSJAg4CXSF8Sr1e6CvPYyOcrDJjCr9LLpj3kFisD_M,19742
twisted/conch/client/__init__.py,sha256=vbi0H87oC9ZMg2pFDUwAa-W7W7XDnFnrglQ3S1TOxKM,139
twisted/conch/client/__pycache__/__init__.cpython-36.pyc,,
twisted/conch/client/__pycache__/agent.cpython-36.pyc,,
twisted/conch/client/__pycache__/connect.cpython-36.pyc,,
twisted/conch/client/__pycache__/default.cpython-36.pyc,,
twisted/conch/client/__pycache__/direct.cpython-36.pyc,,
twisted/conch/client/__pycache__/knownhosts.cpython-36.pyc,,
twisted/conch/client/__pycache__/options.cpython-36.pyc,,
twisted/conch/client/agent.py,sha256=0barVVIXiD1O_DvfBdGsRobOS2i9pH1tHXuqq_kA1jo,1730
twisted/conch/client/connect.py,sha256=mEiTeBIhhKdZZkb-qYNwZ_RC75CZ1hf9A_b0Rg7eHuw,672
twisted/conch/client/default.py,sha256=ekQY-TV_kubRLcp2YGdEi3C1OnAc1_egRVV3qlP5VAQ,11976
twisted/conch/client/direct.py,sha256=O7Jf4KPh7cyh67VqD8HokSKWQtsyG6dAnexAFY-BbpU,3264
twisted/conch/client/knownhosts.py,sha256=MiXC4BSXkxq8AsvLhPA_wcgSywBwFOCD7KYvzUocDzA,19875
twisted/conch/client/options.py,sha256=MJPpxYF36jME_VH-b54klDTdCIlS5YevnDq_ozodjtg,4145
twisted/conch/endpoints.py,sha256=jOs-YG4F9qaZubNI2xKeKbJ5oXJ0cRym6EeqmO69FM8,29743
twisted/conch/error.py,sha256=ynbrCK0fo_wdvyUhbV5GsMVvNjbNIFZHzvoT05hOEyg,2716
twisted/conch/insults/__init__.py,sha256=PALruuxw5vHDKLyzbY6XUcn73FFKhMk44dRQpFdrJvc,76
twisted/conch/insults/__pycache__/__init__.cpython-36.pyc,,
twisted/conch/insults/__pycache__/helper.cpython-36.pyc,,
twisted/conch/insults/__pycache__/insults.cpython-36.pyc,,
twisted/conch/insults/__pycache__/text.cpython-36.pyc,,
twisted/conch/insults/__pycache__/window.cpython-36.pyc,,
twisted/conch/insults/helper.py,sha256=SwL14WVDDvHl1uWesi0c0H4BD6JLjgDsY2TUsg3IFPo,14396
twisted/conch/insults/insults.py,sha256=8q8d5kxf0ah9xgxgzaSfeYDqBhbpCtsO7_k06TOl-BQ,35589
twisted/conch/insults/text.py,sha256=Cc07uGyoLNcsmtsd_uGMj0aT37zZbUamJB2J4uiXqlk,5424
twisted/conch/insults/window.py,sha256=eC-Delffu-yT-cKOvkvPpm_Ft9nRYk8QF8_zNuJo8Sg,27812
twisted/conch/interfaces.py,sha256=6pOyjMrOXPqS1TVwYuoiXSoutO4Wmq-RbiXO1E3p_tI,13636
twisted/conch/ls.py,sha256=1KtrdFww3j6bIEY2gZ0y_gi4TBy6CLQsoHUzWRcsUR8,2551
twisted/conch/manhole.py,sha256=wjpTsXUQ2QRbev_1WcJ9Z-2pbi1J5OKmHY2XoeLUpeQ,11832
twisted/conch/manhole_ssh.py,sha256=NqYFUy305e1DH1WQ3X2SFEG8UPZ6aD8CMKfiQ_4Iduk,3990
twisted/conch/manhole_tap.py,sha256=Q5Ljl6d73Shi_84GNeAmnIcZKFo_MTkhaPBZIKvW9bs,5370
twisted/conch/mixin.py,sha256=8haxUUg5oxVCUzJ71-agK4lJ_ObJ828O2U2sds8dGPM,1374
twisted/conch/openssh_compat/__init__.py,sha256=uIe8Ifysdq6wuLyqjeMXT81DKsZw56QqgxWazKZERu0,152
twisted/conch/openssh_compat/__pycache__/__init__.cpython-36.pyc,,
twisted/conch/openssh_compat/__pycache__/factory.cpython-36.pyc,,
twisted/conch/openssh_compat/__pycache__/primes.cpython-36.pyc,,
twisted/conch/openssh_compat/factory.py,sha256=csprCbaqAQV2V3jcm0jmltxDnl4nY8v3hH7ztTf3lNE,2323
twisted/conch/openssh_compat/primes.py,sha256=_RyvlWjxwymp18gcA0HaiISr8OPwXM3WmsdowkTybeg,682
twisted/conch/recvline.py,sha256=jre0-Le7dp-RplyURznthdQuhu1ZQ5JC7V2YT93EK20,11523
twisted/conch/scripts/__init__.py,sha256=UJRr3MgRq7dcUk9OBG9M0jOmMs2H746XbolCl0dZgwI,16
twisted/conch/scripts/__pycache__/__init__.cpython-36.pyc,,
twisted/conch/scripts/__pycache__/cftp.cpython-36.pyc,,
twisted/conch/scripts/__pycache__/ckeygen.cpython-36.pyc,,
twisted/conch/scripts/__pycache__/conch.cpython-36.pyc,,
twisted/conch/scripts/__pycache__/tkconch.cpython-36.pyc,,
twisted/conch/scripts/cftp.py,sha256=TF1LsKgpmK1nCM_Z-2mgdP2ArVwULAYW44zWesmStkM,31775
twisted/conch/scripts/ckeygen.py,sha256=fceeMBsu3imO-lINBtU72KDMJMsXAT9t74jI9C9Mq6I,10078
twisted/conch/scripts/conch.py,sha256=gNpQFxlMJsrockj4-14kIqkHgEbB1l-xiXK5pQdeVEA,18462
twisted/conch/scripts/tkconch.py,sha256=nuBbI7FPh-ufV-RZGqOHFtJoN1-btbzjWE9LBsNd1_s,23189
twisted/conch/ssh/__init__.py,sha256=IDSvIu8OyDtv2iyBNQlgpZCYPmRDQ1OWBYDm2FUnSXM,183
twisted/conch/ssh/__pycache__/__init__.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/_kex.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/address.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/agent.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/channel.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/common.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/connection.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/factory.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/filetransfer.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/forwarding.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/keys.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/service.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/session.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/sexpy.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/transport.cpython-36.pyc,,
twisted/conch/ssh/__pycache__/userauth.cpython-36.pyc,,
twisted/conch/ssh/_kex.py,sha256=keHgecXDjuUHu_hv21Aaq6FBasMUZqFk1BtDAZ8DhUE,7668
twisted/conch/ssh/address.py,sha256=2ZCPpaUa_Evaj_M_KjbBzllx2gf1l2DQt30rXJwL_-s,1158
twisted/conch/ssh/agent.py,sha256=YITkSpOpiaNSI6EBt4M2EKogOk0Rlj4_QJX0lznRsAs,9692
twisted/conch/ssh/channel.py,sha256=nS1uE0DmZWUvp0vESpSQoanfktxYI50WNV6Sdfyrz1U,9852
twisted/conch/ssh/common.py,sha256=B9LRnUkmWZoQOF1PRFk6b-85_NH1jRzMaE0ROPZk1KY,2059
twisted/conch/ssh/connection.py,sha256=oTD85RQqrKGjHfRBG_PFNoMAJzLc8v6FvZpPY86Vxy0,26151
twisted/conch/ssh/factory.py,sha256=X28xtqHwEpsDtVswL6ele4Wo_4-q6mLugeW03LGW1As,3820
twisted/conch/ssh/filetransfer.py,sha256=pIbW2bXLGagYFKSNKmsn9px7tLto-mS3EhTgoM90778,34723
twisted/conch/ssh/forwarding.py,sha256=L0hBefu4bo4-L-4GCX-wnoFSGmCO9evRFQsm1YcPOVk,8176
twisted/conch/ssh/keys.py,sha256=zlpe3nNB5xWmgmepeXLN_2RsdCdNmTCR1fmhDw5tIdg,54988
twisted/conch/ssh/service.py,sha256=YV99lc0ZxNZMqKFurGXe-i5m8VbeBOZjti7HlO61fvU,1456
twisted/conch/ssh/session.py,sha256=xTVxNdd2MHBP-PhACVZHBLRJPdYn6auAbHZrYPtJ5TE,11225
twisted/conch/ssh/sexpy.py,sha256=lb0LVT8frScz5WEbMklatpcH5xqSV23ayw-m3CPlJP8,1053
twisted/conch/ssh/transport.py,sha256=r1xXHsOow7lOooe0rMgfb2cjyRgFcYrgg-JqiXb3los,73499
twisted/conch/ssh/userauth.py,sha256=jM51sMI7wmOgDVqH8Mbmc0QGWknJK5T5-y0iigchLR4,27336
twisted/conch/stdio.py,sha256=daZfnkeiP4dWbrAWVS3IwRVRrXA-VWvkyL1JpXO0uco,2764
twisted/conch/tap.py,sha256=9edTigyWQ7HmwQM52PPXIQEtjK_ENzLIm2TOqbsLnaE,3183
twisted/conch/telnet.py,sha256=hqa_MuP0QsaBfjqCA5I4qoJNgT0CIevrFZhlZRRqkhk,38539
twisted/conch/test/__init__.py,sha256=HAuvSUTlRN7E22xo4FEOw_2INTlSQcW-j3maA64RIWE,14
twisted/conch/test/__pycache__/__init__.cpython-36.pyc,,
twisted/conch/test/__pycache__/keydata.cpython-36.pyc,,
twisted/conch/test/__pycache__/loopback.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_address.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_agent.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_cftp.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_channel.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_checkers.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_ckeygen.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_conch.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_connection.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_default.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_endpoints.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_filetransfer.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_forwarding.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_helper.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_insults.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_keys.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_knownhosts.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_manhole.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_manhole_tap.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_mixin.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_openssh_compat.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_recvline.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_scripts.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_session.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_ssh.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_tap.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_telnet.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_text.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_transport.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_unix.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_userauth.cpython-36.pyc,,
twisted/conch/test/__pycache__/test_window.cpython-36.pyc,,
twisted/conch/test/keydata.py,sha256=kKR2HtebOfEYUJoitfE2f5WP0tLTfiX8T1Y-LuoSzDU,34462
twisted/conch/test/loopback.py,sha256=qV37tzWIsclzzTBSMiJfZP7-QDu9uBss82vNd926vZk,757
twisted/conch/test/test_address.py,sha256=OCDd05QbekjIIAMIeTlD39FfFc74TOUScnJSB1fHtQs,1629
twisted/conch/test/test_agent.py,sha256=9c_mMNa6OesLxvEblONmufuLKgkbngt9hKYZOA4KzAY,13086
twisted/conch/test/test_cftp.py,sha256=qfSE0uqVjEUqqNGZ24lm4bE3cl4KlisT_k5gT7NQP9Q,50866
twisted/conch/test/test_channel.py,sha256=xCt_cPTjQdHtu9kMNRBY5v3ZHOZnsiVRsmQaVBNcrO8,12099
twisted/conch/test/test_checkers.py,sha256=3bQSxiqv_91SAa55bfPKEVsLYccdJGAkQP2W7R2jm2A,31498
twisted/conch/test/test_ckeygen.py,sha256=Sk0IG-BX77iJfnnwJ6WVOA-1djeDec202WXtIYkL6Es,20158
twisted/conch/test/test_conch.py,sha256=OOjekhD7uE_VVi-4ShrO8Phss8nQJTbuoyLl2jzqKb0,25140
twisted/conch/test/test_connection.py,sha256=Bo-o57TFu_HJyD7YSS7L_WPg045bzl7dpoiHfr5F8pY,28729
twisted/conch/test/test_default.py,sha256=QPDy8v9neuR_q5y2l2-eRk2m7h70ZRX4vl26giyGTJI,11584
twisted/conch/test/test_endpoints.py,sha256=zEsFSKwShr_D70T5EGPplmldNq5vhKzpwngK-U8FhZE,54561
twisted/conch/test/test_filetransfer.py,sha256=DNiffEU0csVUwrLHq0kOqRmaRoGzDAgVvKYMh88MuDg,29239
twisted/conch/test/test_forwarding.py,sha256=DUUceXTLnXBPdEiEdnsRCFr_1mYnDprxgphXXQ3vW5g,2216
twisted/conch/test/test_helper.py,sha256=Fyl1gfsQbJMwzJN1OgyId5bEVW3rB1wWJdB5KCHpeZ4,20492
twisted/conch/test/test_insults.py,sha256=8TlCDalzJMnIsXm1nqMuGbkvdzHq9TkfIiR3Jlmtjf0,32330
twisted/conch/test/test_keys.py,sha256=Cp8SAlEUXm6ExJIo4yzodsDdVLdlnzDNn6DwZnQDwhk,50732
twisted/conch/test/test_knownhosts.py,sha256=hLDWLTA5UhVFW4kHGjUdXhlviG9ORD0SS0Y8zQy2x2w,49398
twisted/conch/test/test_manhole.py,sha256=7vznZ_Cye7YcnXUpxvDEMkxug_klwNSAIfiRbfva30U,13462
twisted/conch/test/test_manhole_tap.py,sha256=MzFrW10USUMe4tR2E7MpIGU94XPQogeSEg9_p6x9bM8,4235
twisted/conch/test/test_mixin.py,sha256=4_kOBOFf8gbWXEUuPPoggf5e2XBhdrZEa-dcnDoyWM4,1055
twisted/conch/test/test_openssh_compat.py,sha256=JoSP23u_ITcTvXju4mT_C7iHG3Aad0-R_C9Y7GQxnQM,4630
twisted/conch/test/test_recvline.py,sha256=81zKYJBYoxwPdr8Mm_yUXMgR4qykVGVaIitDGtK0pUU,25406
twisted/conch/test/test_scripts.py,sha256=hpbHxsJy4mC9Zn4qH_NVYUhKWaZ85o-9oKPzPppEwq4,1887
twisted/conch/test/test_session.py,sha256=O9EcNItOWoHaSIs18gzpzzuriKvZ-aQZF2hDpFj3vE8,39464
twisted/conch/test/test_ssh.py,sha256=XGM-BvVl_kK4bW9NFerqyZUeSso2cmDkxyyxCZbPrG0,32377
twisted/conch/test/test_tap.py,sha256=UDKmRhcEtFtV3G2D7WTyObP3z9QL1yBremFGxSBY7oc,4951
twisted/conch/test/test_telnet.py,sha256=-RCx8XJzNvSeygjJVco-RxyK-VYlTnVt29vbjfRGrK8,26524
twisted/conch/test/test_text.py,sha256=QvJbWCZTTLyAd87Cti2HmZPbDt9QECENq2nrNUvr-bk,3943
twisted/conch/test/test_transport.py,sha256=8QGS8Fp7bv5WoWEcXMXuvcBH1o_qBvJDNtSepffFzCg,94204
twisted/conch/test/test_unix.py,sha256=P5M6yUwDYz9x5mbbpO2KW13D-5I4aL2lpyRZ7PMr-9M,2533
twisted/conch/test/test_userauth.py,sha256=FHck9BxouYpJB42vth9xTCrfUQ2D0TaLwt1RBPuu8m8,32604
twisted/conch/test/test_window.py,sha256=2Qzq_paXugLOlUWEel3p79g71OuAOPahtQV_1d87mnU,2115
twisted/conch/ttymodes.py,sha256=J0Z95i2ljFJi9Wrclw_h7RvudTQp5TWXY_QerE8gY8Q,2239
twisted/conch/ui/__init__.py,sha256=RizFn8MwYiNGvqshvLD3SPhUGafTcMZ-o8U9EkwSF8k,167
twisted/conch/ui/__pycache__/__init__.cpython-36.pyc,,
twisted/conch/ui/__pycache__/ansi.cpython-36.pyc,,
twisted/conch/ui/__pycache__/tkvt100.cpython-36.pyc,,
twisted/conch/ui/ansi.py,sha256=ZMh5UAKbHP55G8nKJcWzdrrQO9wWj8bBMbTRA1c2zZY,7181
twisted/conch/ui/tkvt100.py,sha256=q3a8r-97Qya7ompsc2wxVHS55uNY_FPe-5vNzOBzoZY,7052
twisted/conch/unix.py,sha256=dbOqv_-62mWg-6LwfscElkY5ZWvRZIB0AfEry4k6lEk,16307
twisted/copyright.py,sha256=_BzTp6ekKVHGxy_igsXo4e4Y7TkQiRkGFglIjK0PHkQ,1531
twisted/cred/__init__.py,sha256=W4NhTuZj7C95wT9UlvVbCa37jcHD_QJCyo5CImBK8Pg,189
twisted/cred/__pycache__/__init__.cpython-36.pyc,,
twisted/cred/__pycache__/_digest.cpython-36.pyc,,
twisted/cred/__pycache__/checkers.cpython-36.pyc,,
twisted/cred/__pycache__/credentials.cpython-36.pyc,,
twisted/cred/__pycache__/error.cpython-36.pyc,,
twisted/cred/__pycache__/portal.cpython-36.pyc,,
twisted/cred/__pycache__/strcred.cpython-36.pyc,,
twisted/cred/_digest.py,sha256=sSpPeBMKKWYmYrW_fJ-5OwRUykFMVTsUAWHyonBbQ78,4114
twisted/cred/checkers.py,sha256=cAUY_9xiu8Fmrl1uMbvrkbxgaf137IOYQE8O5dYzKfQ,9219
twisted/cred/credentials.py,sha256=Q47WuA1omb0v5NoxIenOJV2sTUu_oFk1Ogfmlc2WMqU,16220
twisted/cred/error.py,sha256=Cpk_fR1EETu-HUAX7pbZakS-gw5nT8IADPbfdPMCt3Q,1037
twisted/cred/portal.py,sha256=-oz18ZO9qFnWGmTE4bqXmFIvjqJYKJBjebVhjkTuyh4,5406
twisted/cred/strcred.py,sha256=7_LkVWPalXkU5aTeU-KhNbnQs4Ov0wkM3fhW8xwRLIY,8385
twisted/cred/test/__init__.py,sha256=dJnJovocFbB0NlnMradQkTYnlhmluUFWNL3_wFUzJek,157
twisted/cred/test/__pycache__/__init__.cpython-36.pyc,,
twisted/cred/test/__pycache__/test_cramauth.cpython-36.pyc,,
twisted/cred/test/__pycache__/test_cred.cpython-36.pyc,,
twisted/cred/test/__pycache__/test_digestauth.cpython-36.pyc,,
twisted/cred/test/__pycache__/test_simpleauth.cpython-36.pyc,,
twisted/cred/test/__pycache__/test_strcred.cpython-36.pyc,,
twisted/cred/test/test_cramauth.py,sha256=8t4EMvxjl2iJBwSFEjppRO_VOunyzd_BWT5qGsJhLyM,2878
twisted/cred/test/test_cred.py,sha256=ikCGIkSBUkzXqNmqrX3PCJ2dsmAs8FN7FfG2Br3RYXM,13589
twisted/cred/test/test_digestauth.py,sha256=hJq6Zb5ZUY8FsOLf39tFSSpZxNFJ_0wq3W-DNfTsssU,24353
twisted/cred/test/test_simpleauth.py,sha256=9RuqcmpS17hEE6le1S5i44AO4PLYhKVhDVLsa5s0AyQ,2953
twisted/cred/test/test_strcred.py,sha256=CYIaHDkPqfD3lt-w2FPQNdDXZO0Q4CdSrYiDTniV9Z8,26359
twisted/enterprise/__init__.py,sha256=GnETu2_bpAushHQriI67GNeToHIqtrGNqOjXqg-cGsY,162
twisted/enterprise/__pycache__/__init__.cpython-36.pyc,,
twisted/enterprise/__pycache__/adbapi.cpython-36.pyc,,
twisted/enterprise/adbapi.py,sha256=-sHE2s0wLHiIEmModgIc8LfxZRjpG_Ljzv0h4D-rXp4,16883
twisted/internet/__init__.py,sha256=ickB0k1GfdghN-mprceL4YNhZOqOJTSbTssukmcHhyw,521
twisted/internet/__pycache__/__init__.cpython-36.pyc,,
twisted/internet/__pycache__/_baseprocess.cpython-36.pyc,,
twisted/internet/__pycache__/_dumbwin32proc.cpython-36.pyc,,
twisted/internet/__pycache__/_glibbase.cpython-36.pyc,,
twisted/internet/__pycache__/_idna.cpython-36.pyc,,
twisted/internet/__pycache__/_newtls.cpython-36.pyc,,
twisted/internet/__pycache__/_pollingfile.cpython-36.pyc,,
twisted/internet/__pycache__/_posixserialport.cpython-36.pyc,,
twisted/internet/__pycache__/_posixstdio.cpython-36.pyc,,
twisted/internet/__pycache__/_producer_helpers.cpython-36.pyc,,
twisted/internet/__pycache__/_resolver.cpython-36.pyc,,
twisted/internet/__pycache__/_signals.cpython-36.pyc,,
twisted/internet/__pycache__/_sslverify.cpython-36.pyc,,
twisted/internet/__pycache__/_threadedselect.cpython-36.pyc,,
twisted/internet/__pycache__/_win32serialport.cpython-36.pyc,,
twisted/internet/__pycache__/_win32stdio.cpython-36.pyc,,
twisted/internet/__pycache__/abstract.cpython-36.pyc,,
twisted/internet/__pycache__/address.cpython-36.pyc,,
twisted/internet/__pycache__/asyncioreactor.cpython-36.pyc,,
twisted/internet/__pycache__/base.cpython-36.pyc,,
twisted/internet/__pycache__/cfreactor.cpython-36.pyc,,
twisted/internet/__pycache__/default.cpython-36.pyc,,
twisted/internet/__pycache__/defer.cpython-36.pyc,,
twisted/internet/__pycache__/endpoints.cpython-36.pyc,,
twisted/internet/__pycache__/epollreactor.cpython-36.pyc,,
twisted/internet/__pycache__/error.cpython-36.pyc,,
twisted/internet/__pycache__/fdesc.cpython-36.pyc,,
twisted/internet/__pycache__/gireactor.cpython-36.pyc,,
twisted/internet/__pycache__/glib2reactor.cpython-36.pyc,,
twisted/internet/__pycache__/gtk2reactor.cpython-36.pyc,,
twisted/internet/__pycache__/gtk3reactor.cpython-36.pyc,,
twisted/internet/__pycache__/inotify.cpython-36.pyc,,
twisted/internet/__pycache__/interfaces.cpython-36.pyc,,
twisted/internet/__pycache__/kqreactor.cpython-36.pyc,,
twisted/internet/__pycache__/main.cpython-36.pyc,,
twisted/internet/__pycache__/pollreactor.cpython-36.pyc,,
twisted/internet/__pycache__/posixbase.cpython-36.pyc,,
twisted/internet/__pycache__/process.cpython-36.pyc,,
twisted/internet/__pycache__/protocol.cpython-36.pyc,,
twisted/internet/__pycache__/pyuisupport.cpython-36.pyc,,
twisted/internet/__pycache__/reactor.cpython-36.pyc,,
twisted/internet/__pycache__/selectreactor.cpython-36.pyc,,
twisted/internet/__pycache__/serialport.cpython-36.pyc,,
twisted/internet/__pycache__/ssl.cpython-36.pyc,,
twisted/internet/__pycache__/stdio.cpython-36.pyc,,
twisted/internet/__pycache__/task.cpython-36.pyc,,
twisted/internet/__pycache__/tcp.cpython-36.pyc,,
twisted/internet/__pycache__/testing.cpython-36.pyc,,
twisted/internet/__pycache__/threads.cpython-36.pyc,,
twisted/internet/__pycache__/tksupport.cpython-36.pyc,,
twisted/internet/__pycache__/udp.cpython-36.pyc,,
twisted/internet/__pycache__/unix.cpython-36.pyc,,
twisted/internet/__pycache__/utils.cpython-36.pyc,,
twisted/internet/__pycache__/win32eventreactor.cpython-36.pyc,,
twisted/internet/__pycache__/wxreactor.cpython-36.pyc,,
twisted/internet/__pycache__/wxsupport.cpython-36.pyc,,
twisted/internet/_baseprocess.py,sha256=oA5Yr481sEDg4UgsRyPDdwgz7RXJmasV6-jfuiSxlbE,1913
twisted/internet/_dumbwin32proc.py,sha256=7v0Zi003NzCWLE755g8cxr5ymcV2tN7R2B0Vdqc2WiI,13107
twisted/internet/_glibbase.py,sha256=UYNKRhHRPS9Qz8xmBIdDzZvYW9_-yQIy94P12O6pqGs,12813
twisted/internet/_idna.py,sha256=gYjexNDtZN1i0h6qoM161lGgOJrJHuBa1eP53oRr2jw,1397
twisted/internet/_newtls.py,sha256=NOCNH8CX-3CplooDfnprvg9o6qkUyt8QaMwN2r8_IKY,9332
twisted/internet/_pollingfile.py,sha256=qJAGGqXSJ6WYX6EyYe9wb-7OogZ_8DckKmTWjruyJDE,8982
twisted/internet/_posixserialport.py,sha256=gg1KrS3F4k33mULmkxekoM80XE8nhrZ-_oQxq27uTm8,1995
twisted/internet/_posixstdio.py,sha256=6vMt5L3wPA0c-rsTMyqDA583yVzsiR5o6lQ5FwmHkF8,4687
twisted/internet/_producer_helpers.py,sha256=eOqBQC5NsjBWT41oxQLwkyBQBh819uACCq-fIYDWRAs,3788
twisted/internet/_resolver.py,sha256=XjW_CQC8HxeWs7RvZXLLL6F4vN111Z1JC6uTbRK-skc,8530
twisted/internet/_signals.py,sha256=632Qy-EUB5v5RmhhhyntSkziY4jbb-kr2OhRDIHIrVQ,2718
twisted/internet/_sslverify.py,sha256=0wkJdmFhwHg4bA6iLSxRUU_hUZalgL0z5eT8WdrSrPk,72643
twisted/internet/_threadedselect.py,sha256=kYBjTox4Izt0jwTay-zrijjPN1PBZsOcbF1Q2HmsKi0,11764
twisted/internet/_win32serialport.py,sha256=BG-J2A18t-OWpFgRb0O3kN4KX6YPxVBq7q2knVA9muU,4744
twisted/internet/_win32stdio.py,sha256=XEF95KvNvyAThHvO3xBBR1ZZSRxyuuAnbWexYFN35Gc,3204
twisted/internet/abstract.py,sha256=64vN7f-4wT0SjMvZWxGbL0gLCagly7K_jfTJbhhylSU,19274
twisted/internet/address.py,sha256=etExPe2zLdiMZLMMPdl4sKw-b14-z4qk-es5AjR44P0,5246
twisted/internet/asyncioreactor.py,sha256=RgqUpwhb9Oj4wuj5S1YSZDcvDD0qfnIGeQ3Dl1T7djA,10553
twisted/internet/base.py,sha256=YosxpOp73JRDyuUFe6F86Vw5jbxfKkm3UJHgcsw71tE,44807
twisted/internet/cfreactor.py,sha256=XD3vxoojc4ol__9m-l1UjI7_8x_iy1mS91qK7rrFxDE,17501
twisted/internet/default.py,sha256=Kaer40mBJZh2FNUjdwkcjLx0H4otwVjSxGJAjah1PeA,1942
twisted/internet/defer.py,sha256=7tVf05OEL9ZeHi_fbEE5NhsP0e1KCFkt4eOIObyKEi0,71538
twisted/internet/endpoints.py,sha256=5w7doQW1XUaZeYCXovxOSEZKIun6ZZs8onbe-4p1sAA,77326
twisted/internet/epollreactor.py,sha256=C88W-ZnEGxH7rLHOyyZEVdjLqA0N4yeprhpMax3gTXc,8493
twisted/internet/error.py,sha256=sGIWVe03xkrfFv3B3y6oCfxxbvchBZFJg0bU5gPoJ6I,12930
twisted/internet/fdesc.py,sha256=nVL6TE6JBUJW-Yfyh7uaWBv-NHqE_Uc1qIT2Myz30qk,3223
twisted/internet/gireactor.py,sha256=CtgJNXQymPyihhiqrWHZqT89g65hSXXZHrITwypVQjI,6123
twisted/internet/glib2reactor.py,sha256=_fHgbRRmABRTuLZ9hGia_cf5WsKYUoUfn7G3Ue6r8oY,1115
twisted/internet/gtk2reactor.py,sha256=otOVjJ41g2XqlSkv917z_XjoXtxYku1G6Qu6OrkLCXA,3614
twisted/internet/gtk3reactor.py,sha256=j_m-9nnTk267VQpfE-SVRplkJTEQGmsRz-dZMQz5kZA,2252
twisted/internet/inotify.py,sha256=X4mQASe4bdY2_hyh80JdHQYElzqYmsH7I6GMHcJhXxM,14691
twisted/internet/interfaces.py,sha256=CQTA8orAZHIXl4SLOaPklIHBbplfF7qMT6W0JT_gX2g,96841
twisted/internet/iocpreactor/__init__.py,sha256=27qHsOLp9irn3pKHUwlAOyJdu9khir4tTTPLj8djNIg,191
twisted/internet/iocpreactor/__pycache__/__init__.cpython-36.pyc,,
twisted/internet/iocpreactor/__pycache__/abstract.cpython-36.pyc,,
twisted/internet/iocpreactor/__pycache__/const.cpython-36.pyc,,
twisted/internet/iocpreactor/__pycache__/interfaces.cpython-36.pyc,,
twisted/internet/iocpreactor/__pycache__/reactor.cpython-36.pyc,,
twisted/internet/iocpreactor/__pycache__/setup.cpython-36.pyc,,
twisted/internet/iocpreactor/__pycache__/tcp.cpython-36.pyc,,
twisted/internet/iocpreactor/__pycache__/udp.cpython-36.pyc,,
twisted/internet/iocpreactor/abstract.py,sha256=I9NG1gYeV_qM2GK0OQOsnATXo4mfbGov3KsMZuFKgVU,13140
twisted/internet/iocpreactor/const.py,sha256=t66XJONPOmxAo65y--PGT3hGuCuzW0hkZSYPn3_rxM0,524
twisted/internet/iocpreactor/interfaces.py,sha256=QjNOs3GrwNkJDhXno7a6t8cmYPYYZimfzAcolyW5APM,942
twisted/internet/iocpreactor/notes.txt,sha256=M0nci0EaspffjVOb52oxwbdcCldjBd861kJYbCtOpAg,890
twisted/internet/iocpreactor/reactor.py,sha256=ljIs-BjzYA4WdWWDuAeWq_FHOis4OhIsZxviOK0tDpE,9190
twisted/internet/iocpreactor/setup.py,sha256=cDNm15Q783-ma3x24dn_AskmZKzcw_Lm6kSTsb_5kXE,588
twisted/internet/iocpreactor/tcp.py,sha256=jpM9wcpgvuVvABk8pdWFd52IFOdVEZxG4u_ug_-6wIs,20143
twisted/internet/iocpreactor/udp.py,sha256=PDN_RpvDmk3P4wr_0NbUjB0c6d3_JWE99_BqIR7QZMA,14016
twisted/internet/kqreactor.py,sha256=q6rBYkifSJRLgvHM8_DG9yUxfIMrWD8GqXR3IhFOzI0,10292
twisted/internet/main.py,sha256=Be-vOTGwAjtJp4ClfJS_YcFNi4K6OD5MRZbPAdf1z0c,1054
twisted/internet/pollreactor.py,sha256=-8iCPvvAmFdrppsUmVi0Y3YB13shYVx5Butm804ECp8,6026
twisted/internet/posixbase.py,sha256=gqF-AR9g5fuZFuTYgE_bBomw15nf6wayV7T2w2PE0LY,26357
twisted/internet/process.py,sha256=xjwiddhe5gc77KuNaoJ_wvaoJHuB0PNpD7q32ELzvG4,37757
twisted/internet/protocol.py,sha256=4H2pC8sMBybJp91_1WEHMELsdndtydqnMIwzgyNnHmA,27134
twisted/internet/pyuisupport.py,sha256=v265CibEt7gJzS295Gp8krpqWi-6LQc8jOSuKPwILWs,817
twisted/internet/reactor.py,sha256=MKC3G2suikAAo6jxm2HTVRWizJ6aIoDUp4BBlG_TZ2Q,1863
twisted/internet/selectreactor.py,sha256=_4uNzRQ1pId94vFgYAILlfMNEC81P5OFjXfY4tXCBkE,6215
twisted/internet/serialport.py,sha256=6h2KSqB_U1GfduHwNO-XWVQ7deZdIaT9izwyI_OCQf0,2317
twisted/internet/ssl.py,sha256=p_eXSk4crn1yS9659veU9y-d0npj-61xKwdrLl7Lees,8444
twisted/internet/stdio.py,sha256=kbU3W7OTnXOvsHGgis2AeX13vzIgmzrgeS3DLRxlUnY,1045
twisted/internet/task.py,sha256=YwT9EXKh8X9W4UTnwDDVVWMbRQ755HfNc5Vd5sQ-pxs,31157
twisted/internet/tcp.py,sha256=jBDVMB8PVj2QvvwAgBkRgCLFCkhYT8hmW7X-0qI70EY,54908
twisted/internet/test/__init__.py,sha256=R0XCXlTn2bvT1mHPrDoQkW4y-WEXFq_jVBO83Nax7jY,112
twisted/internet/test/__pycache__/__init__.cpython-36.pyc,,
twisted/internet/test/__pycache__/_posixifaces.cpython-36.pyc,,
twisted/internet/test/__pycache__/_win32ifaces.cpython-36.pyc,,
twisted/internet/test/__pycache__/connectionmixins.cpython-36.pyc,,
twisted/internet/test/__pycache__/fakeendpoint.cpython-36.pyc,,
twisted/internet/test/__pycache__/modulehelpers.cpython-36.pyc,,
twisted/internet/test/__pycache__/process_cli.cpython-36.pyc,,
twisted/internet/test/__pycache__/process_connectionlost.cpython-36.pyc,,
twisted/internet/test/__pycache__/process_gireactornocompat.cpython-36.pyc,,
twisted/internet/test/__pycache__/process_helper.cpython-36.pyc,,
twisted/internet/test/__pycache__/reactormixins.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_abstract.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_address.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_asyncioreactor.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_base.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_baseprocess.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_core.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_coroutines.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_default.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_endpoints.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_epollreactor.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_error.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_fdset.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_filedescriptor.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_gireactor.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_glibbase.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_inlinecb.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_inotify.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_iocp.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_kqueuereactor.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_main.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_newtls.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_pollingfile.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_posixbase.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_posixprocess.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_process.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_protocol.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_resolver.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_serialport.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_sigchld.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_socket.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_stdio.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_tcp.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_testing.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_threads.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_time.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_tls.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_udp.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_udp_internals.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_unix.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_win32events.cpython-36.pyc,,
twisted/internet/test/__pycache__/test_win32serialport.cpython-36.pyc,,
twisted/internet/test/_awaittests.py.3only,sha256=651lYVAeyzETW_iKSUSuSC5e4PhbsA-wWTtTg_j8cKY,6175
twisted/internet/test/_posixifaces.py,sha256=xL3pSciwjrgsc2vDGnDKHOvE4mdrgcl7bn8k0Ntv_VU,4689
twisted/internet/test/_win32ifaces.py,sha256=vVJB50tK-ld9Dl4twObaEmKkPVUJ33aXGoR3_D-PJdA,3883
twisted/internet/test/_yieldfromtests.py.3only,sha256=cF9nuNuy-83kpGw7EaIbqZLWyopXSCI_VWNtLl3fZUM,4333
twisted/internet/test/connectionmixins.py,sha256=Pue7N7q7eKo3YmhcnAofG6Ywqm6qlg0aM-PEVyUo8zw,20442
twisted/internet/test/fake_CAs/chain.pem,sha256=3oISrpA2Sb0kD6NysWF0imvVJL3B27li6fhvN0f8NWQ,2090
twisted/internet/test/fake_CAs/not-a-certificate,sha256=GJS9_LOIDdjtHP_M9HZVBli__V-Drd2i_sWSMUyfzlg,84
twisted/internet/test/fake_CAs/thing1.pem,sha256=RWz-DQyE72AFJo6awm6JarF4NAtDdryvmlYCL1hgkEA,1339
twisted/internet/test/fake_CAs/thing2-duplicate.pem,sha256=jl9GaNBh32s56E8BGhxhvX9g-VcLFE9bmrcYh-ONyXU,1339
twisted/internet/test/fake_CAs/thing2.pem,sha256=jl9GaNBh32s56E8BGhxhvX9g-VcLFE9bmrcYh-ONyXU,1339
twisted/internet/test/fakeendpoint.py,sha256=WyT9ss1Fc_2yeLLgJYkHuunArjULjxP_vzq1NSJUIHQ,1555
twisted/internet/test/modulehelpers.py,sha256=mA3sU_zQ42YObsSffwtei1JaiB3vZHOQwJG864Nj3pU,1726
twisted/internet/test/process_cli.py,sha256=SJl3N3-wknNAZsd7gpLVSLNHAbd8XaoGxCgyczRkbE8,664
twisted/internet/test/process_connectionlost.py,sha256=aDGj_l1QlH2pSmwWRPQbW-YSqjgy-3pVm7tEjmveRVE,119
twisted/internet/test/process_gireactornocompat.py,sha256=2p8sOZbMzmzI3XsEF5KmG7f09fkNNIL9WSBl1B_5V6o,721
twisted/internet/test/process_helper.py,sha256=rTonb5m0GZ7SEHdD--OBxitBvOurLo_KXSewArnznos,1081
twisted/internet/test/reactormixins.py,sha256=bQDbUUhazlVO9ZAsFGD10WNicNlKxC_7MdgfWznPMQo,14054
twisted/internet/test/test_abstract.py,sha256=mxQNphfzUEaFw24JSP0EXE9DeSwqqoaxPY8u4xS6jc0,2032
twisted/internet/test/test_address.py,sha256=s2SRx7zOIfNzHsdyyd-Up54C1--5yPgYK_bifGpsCzg,8598
twisted/internet/test/test_asyncioreactor.py,sha256=AvqcLlFgGKeoMAH_KT0v09v0Kz1-Q-f2JBR6jsf57tg,1331
twisted/internet/test/test_base.py,sha256=ppOqFt_1MBBG6Gyod47GTwqIhwTiM_y2cyMPfRz8ISc,13369
twisted/internet/test/test_baseprocess.py,sha256=Z9RUmCFPJ8P75H0rnY7bpXor2ziJ3SG0dWcwYk3FYAM,2613
twisted/internet/test/test_core.py,sha256=Qvk9lprgYzWgLmGppftwu8VxG6m4trqIbohsRag8Oq4,11262
twisted/internet/test/test_coroutines.py,sha256=h7mJtgpmxyufah9lGIuobxR9zWZq021YtMhDbJW9dSg,1787
twisted/internet/test/test_default.py,sha256=Nzy-gVFdIG-jSuaLy79QryRBKKj7yCJN0cb5P2c0L1s,3540
twisted/internet/test/test_endpoints.py,sha256=cAEAumCdQvM7Hzsgv0zxVKe4-nyHZvvJUxifWKVCaRs,148715
twisted/internet/test/test_epollreactor.py,sha256=d4AYzKsTlX3vltXsYeuLs1_izD_SDlLppzZu3r8mkok,7336
twisted/internet/test/test_error.py,sha256=oDVs6B66RlGVry9EUFcB3veY6F7XKbP8ollJtzl3Vls,1117
twisted/internet/test/test_fdset.py,sha256=4nb3OZQ4IkvxdctWv9D7aqHt9Q2oG2AEnk96id_je8g,13501
twisted/internet/test/test_filedescriptor.py,sha256=n5dk7wBEBkdEHkdVoP8giao8TuNozXXhuo4u7Rck_Fc,2808
twisted/internet/test/test_gireactor.py,sha256=nKg_WP2t7Px0qLG0OWwYctQPNFA6umxPB8apJS4cJec,9042
twisted/internet/test/test_glibbase.py,sha256=cy_fhIkPU1hWGR7X7HCHdxyttwsCW9znx6TfkUx3Ydw,2284
twisted/internet/test/test_inlinecb.py,sha256=EVvSMw9_P-S6ZPFsvxTl_T1dDsqoa10mrY1ZmxK6pPI,11599
twisted/internet/test/test_inotify.py,sha256=iNsOQCxh7STqv6UyFVM3CPCUcMGHHoHj5lH9bR-sV-I,16686
twisted/internet/test/test_iocp.py,sha256=ToWR8uGVP-xRi95rLrgg3XihthvR5vbiJXd0KlRaM-E,5170
twisted/internet/test/test_kqueuereactor.py,sha256=gwI-cGpRR9clo65AT2O5hJ_ywk4Aa2s3fC5dQ8N5R-o,1916
twisted/internet/test/test_main.py,sha256=GTjenqA-4z9NgFjkol_umHmFT9yJPc7_hRZm5qvhOgM,1436
twisted/internet/test/test_newtls.py,sha256=lRPyRBQB23xjyYl26xsHmk3DNvRAXrGq8MGzu0IEMnk,6693
twisted/internet/test/test_pollingfile.py,sha256=Q9lXthu2zLgpSx8-0JxxRWso3rYy2KzTMS4oYefBKIU,1278
twisted/internet/test/test_posixbase.py,sha256=yViBaItENJAHROGogmQfYLcCpr214vxRb3Xs6hn-OhE,9536
twisted/internet/test/test_posixprocess.py,sha256=MAx23Bu8oDxxLD4wsiH8r8U0dG6mwzOC4Hoaxg3F-jQ,11166
twisted/internet/test/test_process.py,sha256=N7DsHIzbIHA2fQrPeuUKyFonWLOmC3u-yUkek08xWVU,32045
twisted/internet/test/test_protocol.py,sha256=FYOzV9o1sfU0f9mX-sqmnGRBTIqMFC0AX2VHxXfTkc8,18727
twisted/internet/test/test_resolver.py,sha256=XelBnCD7C7407RoIi_pmjejNkP7lKvYopFHoXI-ulzw,20153
twisted/internet/test/test_serialport.py,sha256=61zuFJtDV9_UTAbWWHqFN1X84q5lweVB9hswsjs_b8Q,1948
twisted/internet/test/test_sigchld.py,sha256=STT-nfEsm4n1Y2NJVkHzQhbQNc-6RnZlu3sXvbL65DU,3935
twisted/internet/test/test_socket.py,sha256=mYp89LTUAPIHQ-hk0dwBV07WY-jGHaT_xT47dshgLzs,9329
twisted/internet/test/test_stdio.py,sha256=rcuJcxmqTy253faCcKn5IOb4H37FA9-zD-WmRwRvSLk,6449
twisted/internet/test/test_tcp.py,sha256=eu263u3jtvHW8NJSMiWZ1D6cRwSznVIUXzGxclWLCGo,108446
twisted/internet/test/test_testing.py,sha256=3piwz-YZPbta29JSQ35u-gjJIJIB8LvhealU1nO9vGY,16676
twisted/internet/test/test_threads.py,sha256=QHJlDT8yrt2p694J73OyYuyaQbfoE5JFGhVY11PBrBA,8582
twisted/internet/test/test_time.py,sha256=mkm9Dzb7WGfSLrGKrO2H_FWYcj9Hd2N23sutQrZM9uY,3717
twisted/internet/test/test_tls.py,sha256=6B_p8wgbLtiREd7RC7bq91d6Nq3Ttu9EnMFiMxQXbns,13459
twisted/internet/test/test_udp.py,sha256=xG2LDYVIUDAt9GKo017kkIk2rZV2uDDSMg2Z6zOuaWc,17140
twisted/internet/test/test_udp_internals.py,sha256=W3KXCY9AGz_BCwSEP86XPmNfHBRPqLwHA1rS2oeXh0Q,4909
twisted/internet/test/test_unix.py,sha256=uImznrC0H-zKauZsH8EWD_ByLYc3Qc8bZZMj0k2u_yo,35712
twisted/internet/test/test_win32events.py,sha256=9mDXR-8OVTXow8hgR9F9ygn42NoWPtQjpcLA_RWRmjE,6500
twisted/internet/test/test_win32serialport.py,sha256=5--jrNIeK1Q5268i1qFlTyj8rvAHKuos53muqidCaNE,5282
twisted/internet/testing.py,sha256=3k4bJWjcekOwK1N7mT3A-R_IWYXa89gFpgRcv_MOTLc,29106
twisted/internet/threads.py,sha256=9iwvudl1ROPFollGPXuD7vHLHzZFajNO4QR-9C_apr8,3953
twisted/internet/tksupport.py,sha256=th9iaGhbwYdurBXmOHfqjagRvi3vKMF-f30FPMne_fk,2045
twisted/internet/udp.py,sha256=HUJClZLNANFQpmaWqRRV_zM8jbEhHNY7JT3dx8L4ljI,18569
twisted/internet/unix.py,sha256=i7213Texp8VocUlaFtSp0P75XMmYFkKjJ0Se3sNoOvU,21965
twisted/internet/utils.py,sha256=38YGqBFgj4aqWuXq6Zme3sAPIYoNB42kBF0qiejJtmc,8347
twisted/internet/win32eventreactor.py,sha256=XgPo4hKF0a1hLbOVCxRWspGUoB5DtTBQVzNBtV_Dkkc,15193
twisted/internet/wxreactor.py,sha256=Bj43Qo8v0tm1SDiehiFEZO81wn2vVBdSifKGH3LZuq4,5290
twisted/internet/wxsupport.py,sha256=gNrChXmxkAVv_ANnVWYIXM7_MHYztDrZXoP8GVGIDqA,1363
twisted/logger/__init__.py,sha256=wua2tX8Am7sKMFTGoIMhFzT6b6HJRZ46sV9zEVLOzKU,3318
twisted/logger/__pycache__/__init__.cpython-36.pyc,,
twisted/logger/__pycache__/_buffer.cpython-36.pyc,,
twisted/logger/__pycache__/_capture.cpython-36.pyc,,
twisted/logger/__pycache__/_file.cpython-36.pyc,,
twisted/logger/__pycache__/_filter.cpython-36.pyc,,
twisted/logger/__pycache__/_flatten.cpython-36.pyc,,
twisted/logger/__pycache__/_format.cpython-36.pyc,,
twisted/logger/__pycache__/_global.cpython-36.pyc,,
twisted/logger/__pycache__/_io.cpython-36.pyc,,
twisted/logger/__pycache__/_json.cpython-36.pyc,,
twisted/logger/__pycache__/_legacy.cpython-36.pyc,,
twisted/logger/__pycache__/_levels.cpython-36.pyc,,
twisted/logger/__pycache__/_logger.cpython-36.pyc,,
twisted/logger/__pycache__/_observer.cpython-36.pyc,,
twisted/logger/__pycache__/_stdlib.cpython-36.pyc,,
twisted/logger/__pycache__/_util.cpython-36.pyc,,
twisted/logger/_buffer.py,sha256=Ey_2hKMColHaD4hmmSAfeWx54_y6k2NN05ZtAlSSObg,1484
twisted/logger/_capture.py,sha256=gkkka_YA9mivTlOakGk1svO39-0z-PgaIyDAM1S_bZU,459
twisted/logger/_file.py,sha256=cTcmdYkAUG6ZXvSoPUEw6DCjWM9SeHR--KzSy0uoDtg,2485
twisted/logger/_filter.py,sha256=hFxcx_Zj2MXUdNqjCtxLdFQbd8LMJdtPrUfBxB6Jfgk,6986
twisted/logger/_flatten.py,sha256=4IHEykWLzF7ETajOPemB-SPJYWsnKlcjjDmiM2tbovA,5091
twisted/logger/_format.py,sha256=oL_JqJcitW7oB_qUkKNcoJdexU0vQahK8k8otQi4kDM,12436
twisted/logger/_global.py,sha256=vulnbrNmcfWWArNLjApYasXFt0qiH97w1_Ngu3khvqk,8787
twisted/logger/_io.py,sha256=nBp4WrTrb7QS2UL4rm8tIEXgBjOHq1pay6jcSWPC2PU,4459
twisted/logger/_json.py,sha256=8mWj_DOABHynHDSvUBEBqUMVHYZ-O4deVwKJGKx0TqE,10069
twisted/logger/_legacy.py,sha256=IGc2gfq-FFYz5gJwz-XpLuhHdGrpL0CNvyWiYTNJS2U,5237
twisted/logger/_levels.py,sha256=EHzcJgMG3TyKV0hnUqX1LIExbPlvXwlEbxQmca0qfLI,3772
twisted/logger/_logger.py,sha256=htbvVZ-uTQPgu_6SdH2G_S7-0QB6Ui6mcUrYYLHrWz8,9548
twisted/logger/_observer.py,sha256=3R7RC7t1HQzzoPPLsst76vAqAc8821ofXdL9qQrlcJw,4991
twisted/logger/_stdlib.py,sha256=FjMeA8N4BzrQL4F-ldsap8nIdBvYOXfYwDPr-39L5gI,4611
twisted/logger/_util.py,sha256=tjt6KwCfV4aCTZrKgTFhunTgMKsAY19JTUIBgSmDDZM,1328
twisted/logger/test/__init__.py,sha256=cGAk-ROeAJboDWOal_3es3XGNfc2Krzid7s4tD6zC40,161
twisted/logger/test/__pycache__/__init__.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_buffer.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_capture.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_file.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_filter.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_flatten.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_format.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_global.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_io.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_json.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_legacy.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_levels.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_logger.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_observer.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_stdlib.cpython-36.pyc,,
twisted/logger/test/__pycache__/test_util.cpython-36.pyc,,
twisted/logger/test/test_buffer.py,sha256=1aktli9DYcJNP6RoSP9UEGWFOZPRkt7X-JjXIp8Yodg,1642
twisted/logger/test/test_capture.py,sha256=RY6MlSSxV3t2CQfpSL4Bw22lAntqkv3_S9rdUav2vzs,1083
twisted/logger/test/test_file.py,sha256=cheG1k5tukraq-D69-YkpyYLVuCRwDZBxSJ6Vq_7AtE,5623
twisted/logger/test/test_filter.py,sha256=eKTEDG9D3A40xean4VURrDqt1E6ahW9zMH4c4M_SPeI,12010
twisted/logger/test/test_flatten.py,sha256=ED2GgB3lbdSPquZa05sp1A8C2V-vEfIjqIeSgg_ZiMs,9137
twisted/logger/test/test_format.py,sha256=Ai0fX0tiug5XeFwKkSC0KS5A1Il0zLSONSU6SAymhiA,22563
twisted/logger/test/test_global.py,sha256=ASCp2U2HY9pxX5mVxezfDf-AlI4Sz92p_DfE1z3_TqM,12049
twisted/logger/test/test_io.py,sha256=23iLbLF5LW6NNtl1OUF1cewOhahXANuzJdYnDg8zL5c,7212
twisted/logger/test/test_json.py,sha256=7b4vPpSA_rDvU4odC18GWgHNkGQd-424eENIv-vc4WA,18584
twisted/logger/test/test_legacy.py,sha256=1UunwkcS4wNj55U4UbI_ju9Ode_AEIP9rO0hERfFchQ,14395
twisted/logger/test/test_levels.py,sha256=tOk3LKjszhlzyL1Yf9mWDli7JnP3KokbFEk8hH2KSAM,875
twisted/logger/test/test_logger.py,sha256=DpDTOl2Uunn9MndN7eqxVEU4xZ0rOV7rs8wOJ2XrjoU,7354
twisted/logger/test/test_observer.py,sha256=gJxSYGkZDddedE5bRufQP6WZqOaVwpmQIykEPemRHEo,5253
twisted/logger/test/test_stdlib.py,sha256=0jMzZ7VT2KwXKqxmzycArG9FKzmOg6wwuktMJtodgk4,8639
twisted/logger/test/test_util.py,sha256=dyGJWIINUYI2MeIPEG-NntOByrg6eQ0IeZZhrcdt2K8,2671
twisted/mail/__init__.py,sha256=TTwDhFQPpKH_2LKY6Bcc1_eBoua-VUIeuY2S1-P22JI,142
twisted/mail/__pycache__/__init__.cpython-36.pyc,,
twisted/mail/__pycache__/_cred.cpython-36.pyc,,
twisted/mail/__pycache__/_except.cpython-36.pyc,,
twisted/mail/__pycache__/imap4.cpython-36.pyc,,
twisted/mail/__pycache__/interfaces.cpython-36.pyc,,
twisted/mail/__pycache__/pop3.cpython-36.pyc,,
twisted/mail/__pycache__/pop3client.cpython-36.pyc,,
twisted/mail/__pycache__/protocols.cpython-36.pyc,,
twisted/mail/__pycache__/relay.cpython-36.pyc,,
twisted/mail/__pycache__/smtp.cpython-36.pyc,,
twisted/mail/_cred.py,sha256=V-98-Kn5dWa1_6UboZEr77FgshnyFQSdPVcFypXcnZ4,2786
twisted/mail/_except.py,sha256=2bhvABOlSg_b2rwyyNIgAI4TpaNIsz0mkSVqHv0qn9o,8763
twisted/mail/imap4.py,sha256=Oa2_Utr0ojbY-cMuaQmGLowZ8_rm4rmalTqrz2W3aug,211261
twisted/mail/interfaces.py,sha256=RpN6ZHGZ34n2O7R4__AnVXyavlFdxF0hO20HG9-_Elc,32153
twisted/mail/pop3.py,sha256=IRFvrotm_YB7E3DXGXIn0rpRz4yVBgF4jxQt6TDfYWE,54946
twisted/mail/pop3client.py,sha256=dWHzCuiijPz2mm9p0AFGCVHzZccjcf2KN5wy6aF4yBY,46706
twisted/mail/protocols.py,sha256=OdMKy9HSqLjPfma78rFtu5UaHz_SzCBCV9vFucSjOOc,12644
twisted/mail/relay.py,sha256=DoGtkPnwEL6N9nutaWn4EmV8pxBTFrz_Mnh2tWwvQsY,5361
twisted/mail/scripts/__pycache__/mailmail.cpython-36.pyc,,
twisted/mail/scripts/mailmail.py,sha256=grFSxZpUjZvcegj2OkwUkfDunUGpAYv-c75nGY2JfT0,10581
twisted/mail/smtp.py,sha256=4t5MEHp3_1oaicOO1OQBHhKb-nDdha1FVhZrAu2USQA,71612
twisted/mail/test/__init__.py,sha256=p5MeYvSnUTo_P8vZfiYhJ1KXeI-Y090YiJfedQFqvkE,24
twisted/mail/test/__pycache__/__init__.cpython-36.pyc,,
twisted/mail/test/__pycache__/pop3testserver.cpython-36.pyc,,
twisted/mail/test/__pycache__/test_imap.cpython-36.pyc,,
twisted/mail/test/__pycache__/test_mailmail.cpython-36.pyc,,
twisted/mail/test/__pycache__/test_pop3.cpython-36.pyc,,
twisted/mail/test/__pycache__/test_pop3client.cpython-36.pyc,,
twisted/mail/test/__pycache__/test_smtp.cpython-36.pyc,,
twisted/mail/test/pop3testserver.py,sha256=GC8MrFuOEWCA55VkGuZ0cl5eQ8iL7lYj12PzegNhE6w,8249
twisted/mail/test/rfc822.message,sha256=0nsnccDczctGjuZaRUBDgJ29EViOh-lRVFvgy8Mhwwg,3834
twisted/mail/test/test_imap.py,sha256=903XJQbfxHo2QOvarhxi5k5vm6-dfTVQAZV3KK8AtX4,265738
twisted/mail/test/test_mailmail.py,sha256=DzcZrQr7HS_Mpkxtt5UQpIDyX5KwgauTQEbe1tvmHus,12930
twisted/mail/test/test_pop3.py,sha256=EC0-NqaECqKBEVC0-3vartbdySYWyzTf6w4wNhp5y9E,42094
twisted/mail/test/test_pop3client.py,sha256=sLFvUs8SEvR79eLVEOLos4ebYuw3xUZvc6_rxVs-pyQ,21986
twisted/mail/test/test_smtp.py,sha256=j8TwKunZaHIhY7sfS5VtnNRKjEYbp0HRKyojAiChDvc,63927
twisted/names/__init__.py,sha256=pn-zinHevqxkH0Ww1O7gdT7u_xNISy_is4ODYmO071E,135
twisted/names/__pycache__/__init__.cpython-36.pyc,,
twisted/names/__pycache__/_rfc1982.cpython-36.pyc,,
twisted/names/__pycache__/authority.cpython-36.pyc,,
twisted/names/__pycache__/cache.cpython-36.pyc,,
twisted/names/__pycache__/client.cpython-36.pyc,,
twisted/names/__pycache__/common.cpython-36.pyc,,
twisted/names/__pycache__/dns.cpython-36.pyc,,
twisted/names/__pycache__/error.cpython-36.pyc,,
twisted/names/__pycache__/hosts.cpython-36.pyc,,
twisted/names/__pycache__/resolve.cpython-36.pyc,,
twisted/names/__pycache__/root.cpython-36.pyc,,
twisted/names/__pycache__/secondary.cpython-36.pyc,,
twisted/names/__pycache__/server.cpython-36.pyc,,
twisted/names/__pycache__/srvconnect.cpython-36.pyc,,
twisted/names/__pycache__/tap.cpython-36.pyc,,
twisted/names/_rfc1982.py,sha256=m4BrYSy8VRvdlg4io8DeMB5wzF5v6c2hePVueBnN7Ec,9113
twisted/names/authority.py,sha256=_wFwPeeSsyMvhtvlCXdOm1CZRlYEhN-nHEO5tw0EHis,16530
twisted/names/cache.py,sha256=vRGMwuE4lFhf4W2BodlwD8u8SSaMpAOYmTtl8zH1AAE,3804
twisted/names/client.py,sha256=PDqrkmpwagwzKXGLw5vsisfnCt_YQaxbYpBFWbY1nhw,24549
twisted/names/common.py,sha256=nFbHZKgxS2m9mv4oOYYTTTxa2XR-Wf0UZ3wqlpTJfCA,7860
twisted/names/dns.py,sha256=7t4GaYbIOmPx7s54BPEjlktRPQ2lPF89fxsQbJ4-RqM,96976
twisted/names/error.py,sha256=02_cTkNE6K1Gahwpxwors_qd9gr5ts3x0PghidZejMQ,2056
twisted/names/hosts.py,sha256=RQlExFaZGDTLvFhRoBH85KeeRI8Eq7UtxcpECBpMF98,4521
twisted/names/resolve.py,sha256=-zMAKlRaex2DuUXGw7-o2RxYRRrxAGNNa5o_x0Dxrdc,3361
twisted/names/root.py,sha256=-Q17Eu87jHN8V1V2xkyS5Jk-rn-11Nd5jUvxPoMZ_Uw,12448
twisted/names/secondary.py,sha256=Rzwbf-PCbzePioyR5AArHoS7ua_qXOz5GwkYNOJhmP4,6085
twisted/names/server.py,sha256=jtcUz8H2GW3a0XeUrpmkhmlF7GVJZHd8u9Rei06BDJY,22305
twisted/names/srvconnect.py,sha256=uGSBa0VzKQJgi-E4NbyB0MQgDNiX2BUSgPqJGPF5rW8,9144
twisted/names/tap.py,sha256=Jls1yZyObp10LUj9DdWFDXniWfju5JbXG8qMJYBHrCY,4832
twisted/names/test/__init__.py,sha256=d3JTIolomvO_PAkMM5Huipo6vc06Zyp3zhfeAuu_rEQ,26
twisted/names/test/__pycache__/__init__.cpython-36.pyc,,
twisted/names/test/__pycache__/test_cache.cpython-36.pyc,,
twisted/names/test/__pycache__/test_client.cpython-36.pyc,,
twisted/names/test/__pycache__/test_common.cpython-36.pyc,,
twisted/names/test/__pycache__/test_dns.cpython-36.pyc,,
twisted/names/test/__pycache__/test_examples.cpython-36.pyc,,
twisted/names/test/__pycache__/test_hosts.cpython-36.pyc,,
twisted/names/test/__pycache__/test_names.cpython-36.pyc,,
twisted/names/test/__pycache__/test_resolve.cpython-36.pyc,,
twisted/names/test/__pycache__/test_rfc1982.cpython-36.pyc,,
twisted/names/test/__pycache__/test_rootresolve.cpython-36.pyc,,
twisted/names/test/__pycache__/test_server.cpython-36.pyc,,
twisted/names/test/__pycache__/test_srvconnect.cpython-36.pyc,,
twisted/names/test/__pycache__/test_tap.cpython-36.pyc,,
twisted/names/test/__pycache__/test_util.cpython-36.pyc,,
twisted/names/test/test_cache.py,sha256=YNu7OeMpeNNFPJbzvE9a6OxDMybG_hU3xd466ZM_ztM,4916
twisted/names/test/test_client.py,sha256=nbfVm1Zep5DpKtXhKASpaqXDrH1NbsQwVYC6WcWN1wc,41764
twisted/names/test/test_common.py,sha256=3iP0IAmfWr-RKQdCmCKNvJw5k8U6DhII6BIN1zvOR7c,4206
twisted/names/test/test_dns.py,sha256=Y-8t2MAVHOijV_zNx_5aaNr4C8Ac0ALOrg7LGa7ppow,158849
twisted/names/test/test_examples.py,sha256=-VKU30q-Jkfw2ucz0so0hyyjrH1fJOpcKD1u7NcS6yY,5349
twisted/names/test/test_hosts.py,sha256=c5cs0ksd5N6s9qa0gxC-rnKd7baJVSiehvSB46EnlDg,8547
twisted/names/test/test_names.py,sha256=KLblh3uylJ30Fr8Ku83qOwoCKdIg8v9D9JkEN7lMUNE,43096
twisted/names/test/test_resolve.py,sha256=A3KYPzouCKlR5UOcUz0NATHYhey8QnVLL_398BXQaCo,1075
twisted/names/test/test_rfc1982.py,sha256=Ib4CocE0s8JAEqp_TvaZH6EjweB_QnrTuuDPmBEmkDo,13992
twisted/names/test/test_rootresolve.py,sha256=1Cp_QKpBToYSyjW8R3EdJRvbfbHcvvnVMwKeQyNAG8Q,25643
twisted/names/test/test_server.py,sha256=JQYGRbPoW6Hk5Sq9vsinlehP3KSToh2nRoZdVc3RSFA,41234
twisted/names/test/test_srvconnect.py,sha256=XSatW9AjCca_uL60AhXrPpOLlosV0AkW733r6kw-iVc,10124
twisted/names/test/test_tap.py,sha256=kLMsChF8IiCt5l0FQNZeVxoOIG7FlIupb17q6Ld3Q_U,4961
twisted/names/test/test_util.py,sha256=IGGlPKZ5Wn5L0A_Jj0MdN3_r_xghj_X4J0VLAqR8LTQ,3915
twisted/pair/__init__.py,sha256=69Cr0TdbaWqxKH2AEB9jxdRNydRnbWwx4kHzYlAFs7c,315
twisted/pair/__pycache__/__init__.cpython-36.pyc,,
twisted/pair/__pycache__/ethernet.cpython-36.pyc,,
twisted/pair/__pycache__/ip.cpython-36.pyc,,
twisted/pair/__pycache__/raw.cpython-36.pyc,,
twisted/pair/__pycache__/rawudp.cpython-36.pyc,,
twisted/pair/__pycache__/testing.cpython-36.pyc,,
twisted/pair/__pycache__/tuntap.cpython-36.pyc,,
twisted/pair/ethernet.py,sha256=ZKLmhJ9rqPsDVFFgcYqjtnyQf8gkGL-G7jnMNaXc2jo,1698
twisted/pair/ip.py,sha256=Kb5HfbLZ0wikbfIaKPLgGQHkPHcba5GlbGad3s5932k,2595
twisted/pair/raw.py,sha256=NJOSZ0D9qp78r3B_T9jivDozAGPaUagg8xtQOogtbAo,811
twisted/pair/rawudp.py,sha256=F67B2yZ0IqpW9bMNWk3-4gvQ1YtW9DZyBL6ZeWwzG8Q,1813
twisted/pair/test/__init__.py,sha256=mAc-2NR8lrqRyWN-YI4kn9LUZ7So6ae3xJ2RzldDQ1w,13
twisted/pair/test/__pycache__/__init__.cpython-36.pyc,,
twisted/pair/test/__pycache__/test_ethernet.cpython-36.pyc,,
twisted/pair/test/__pycache__/test_ip.cpython-36.pyc,,
twisted/pair/test/__pycache__/test_rawudp.cpython-36.pyc,,
twisted/pair/test/__pycache__/test_tuntap.cpython-36.pyc,,
twisted/pair/test/test_ethernet.py,sha256=iWxYX0e65w5Nq6r_cthyLSpAwvWjVW7AX-UVhfBpR_c,6653
twisted/pair/test/test_ip.py,sha256=euftwHEBKqvwaQQpta9jvKS5de49tz3oqtLC10p2xlg,15148
twisted/pair/test/test_rawudp.py,sha256=yze31pPb0eKWsfRUrHOFBIr6jC9tTgGvekw42Gk-T5M,13074
twisted/pair/test/test_tuntap.py,sha256=S2OTUrXwu1-ku_dEM6MHjmTlKpuRsajQuUgn9XJKnpo,47567
twisted/pair/testing.py,sha256=MZRPms9JY-FTQX8k91gND5MNd23Esz_RDLBLqNZodp0,17307
twisted/pair/tuntap.py,sha256=TxshMXYq2GYTWyxxjaNPpIPggigozJ0PFLkAnG-z8GA,12538
twisted/persisted/__init__.py,sha256=zyAGR02ZdUO8fNoKHf602wUApt3DvnnfD-B4iJ1QJqI,136
twisted/persisted/__pycache__/__init__.cpython-36.pyc,,
twisted/persisted/__pycache__/aot.cpython-36.pyc,,
twisted/persisted/__pycache__/crefutil.cpython-36.pyc,,
twisted/persisted/__pycache__/dirdbm.cpython-36.pyc,,
twisted/persisted/__pycache__/sob.cpython-36.pyc,,
twisted/persisted/__pycache__/styles.cpython-36.pyc,,
twisted/persisted/aot.py,sha256=9J-HHadGM8z7jDH37peHqP1WdgZ9roqmAnqycOeB-n8,18605
twisted/persisted/crefutil.py,sha256=Xp3-vK0OeOroNd2NJH1vJhiXUHsmBZ6_9r_uDK9FE8g,4375
twisted/persisted/dirdbm.py,sha256=JU8ZwO7ZF2lIhc6H-T6lCvAsgXxiydYc31JRkLqbj_8,10141
twisted/persisted/sob.py,sha256=-yhIm6Ah6UhGRTs3v6l6ZWHJMU8DorDuadg34YztWHs,5197
twisted/persisted/styles.py,sha256=wD9iJHv7hIH6GUTP9s5HuREfNzCA4yguaRHeWacFzc4,13495
twisted/persisted/test/__init__.py,sha256=C5rPf38HFfuGrl35BEIrhxgs9HtwoEMpxPvNdNHNELk,113
twisted/persisted/test/__pycache__/__init__.cpython-36.pyc,,
twisted/persisted/test/__pycache__/test_styles.cpython-36.pyc,,
twisted/persisted/test/test_styles.py,sha256=0s26icbUsYU1v4FLhTpxaT49vLuYDhr4Y6etvTru1JQ,3388
twisted/plugin.py,sha256=1ZW0wvUbQ0GYV0ry7JX2qu2LTH35b6WzfPRTG9HhwDo,8407
twisted/plugins/__init__.py,sha256=lk9vXST0ZZip_WzApTLgsFmWKA0SDJLHe5HyNBFDers,590
twisted/plugins/__pycache__/__init__.cpython-36.pyc,,
twisted/plugins/__pycache__/cred_anonymous.cpython-36.pyc,,
twisted/plugins/__pycache__/cred_file.cpython-36.pyc,,
twisted/plugins/__pycache__/cred_memory.cpython-36.pyc,,
twisted/plugins/__pycache__/cred_sshkeys.cpython-36.pyc,,
twisted/plugins/__pycache__/cred_unix.cpython-36.pyc,,
twisted/plugins/__pycache__/twisted_conch.cpython-36.pyc,,
twisted/plugins/__pycache__/twisted_core.cpython-36.pyc,,
twisted/plugins/__pycache__/twisted_ftp.cpython-36.pyc,,
twisted/plugins/__pycache__/twisted_inet.cpython-36.pyc,,
twisted/plugins/__pycache__/twisted_names.cpython-36.pyc,,
twisted/plugins/__pycache__/twisted_portforward.cpython-36.pyc,,
twisted/plugins/__pycache__/twisted_reactors.cpython-36.pyc,,
twisted/plugins/__pycache__/twisted_runner.cpython-36.pyc,,
twisted/plugins/__pycache__/twisted_socks.cpython-36.pyc,,
twisted/plugins/__pycache__/twisted_trial.cpython-36.pyc,,
twisted/plugins/__pycache__/twisted_web.cpython-36.pyc,,
twisted/plugins/__pycache__/twisted_words.cpython-36.pyc,,
twisted/plugins/cred_anonymous.py,sha256=vpl3-TdqBrPcPYEMnuDPcI0ZfWDmvxS6n0W6rt9dS-Q,1017
twisted/plugins/cred_file.py,sha256=EbDvh1Sgf5BcoTD5k9-sJey43wiJpJNmypHUVWD4TcA,1875
twisted/plugins/cred_memory.py,sha256=8rRWaV93xIOIY5sXnUCpFsvD2va0v_iqs3dDO7KAUp0,2387
twisted/plugins/cred_sshkeys.py,sha256=0bSoTYESFswyRdGxSsmr5q9LZs4JL0sAnAzXMeLeecc,1498
twisted/plugins/cred_unix.py,sha256=xUlXtGd6RPEpWrO5J1cB6Cw6URJ1cSEtdcq1Xe5vBYc,5905
twisted/plugins/twisted_conch.py,sha256=5uZ8DxMkL9ZoajHKqTCxOGEMarZIeomKgfY9JfGA2LA,519
twisted/plugins/twisted_core.py,sha256=UYnNWMLp3tMpbWjzQYDNYGyQeO6CKhrum7-Qo_wUnos,589
twisted/plugins/twisted_ftp.py,sha256=2YITyfTb3iAUnJoEfMCh0jVjnGjO6O_nHR_SAS4auGs,229
twisted/plugins/twisted_inet.py,sha256=VBtuyAPilMxsjykF4rVLyGgtr0R_Q3dXB8E-SBFztVk,260
twisted/plugins/twisted_names.py,sha256=8dMOvdQzlVu6etrsLKGFcj4LJlbg9N2FFqzTZais7bg,247
twisted/plugins/twisted_portforward.py,sha256=f3tDxoFwoJV0BfW8b1jXrYjr72GQIKcgGykaxkUBcpg,275
twisted/plugins/twisted_reactors.py,sha256=bZjUWLDKFMRW5kReCWCyPTb6zYiPCSyZ4_dJJ0vgTH0,1880
twisted/plugins/twisted_runner.py,sha256=4onfqhfRsx2XnBn7c4bWt8dxMmQyrpALUYeB9ZZ20EQ,278
twisted/plugins/twisted_socks.py,sha256=M8G4xLBbk3S-klsY0HNwWIA2xXhy4VQpjsLRM_bIvLE,247
twisted/plugins/twisted_trial.py,sha256=hpii1iu8KvcTz6basUtpz0VfZ3b6TLCINYpLjy2l78I,2084
twisted/plugins/twisted_web.py,sha256=ef7vqQPmVigdoowgJWR3zAwgPs9ANV9ezC5cEQOuaQc,312
twisted/plugins/twisted_words.py,sha256=Qf1p7QsLjl0uqGAm-MvricGjyZE-Ceq3PqjwwrJokYo,1029
twisted/positioning/__init__.py,sha256=y_fhSJlC3z4GeB-rC3z2tiprb3JxxGvlYv-GHmuhv1Q,223
twisted/positioning/__pycache__/__init__.cpython-36.pyc,,
twisted/positioning/__pycache__/_sentence.cpython-36.pyc,,
twisted/positioning/__pycache__/base.cpython-36.pyc,,
twisted/positioning/__pycache__/ipositioning.cpython-36.pyc,,
twisted/positioning/__pycache__/nmea.cpython-36.pyc,,
twisted/positioning/_sentence.py,sha256=G8vKaSb_8T-khzyGeeDht6PWtQYugU4_kQr4-VdET8A,4004
twisted/positioning/base.py,sha256=H83JCeCxX0V3GGN0sEyHiEDeuM1GyDOMAgf6ngnl4LQ,28410
twisted/positioning/ipositioning.py,sha256=hxGOOrFK0Hqj0gvNA5lTU0J6sbQr-zN4ErVh8gRnffA,3013
twisted/positioning/nmea.py,sha256=1rcMypYwWD6A468USl9lbOb80Qxla6_VVsSTTOqXPyY,35975
twisted/positioning/test/__init__.py,sha256=Ekrh30kyy4hMgeFG33jFNP-S209JCflSF7hTan4MKEo,125
twisted/positioning/test/__pycache__/__init__.cpython-36.pyc,,
twisted/positioning/test/__pycache__/receiver.cpython-36.pyc,,
twisted/positioning/test/__pycache__/test_base.cpython-36.pyc,,
twisted/positioning/test/__pycache__/test_nmea.cpython-36.pyc,,
twisted/positioning/test/__pycache__/test_sentence.cpython-36.pyc,,
twisted/positioning/test/receiver.py,sha256=eLkfrggQVEPHfpB12vC1E8T3oud5tvAYK4gEejC4wjE,1166
twisted/positioning/test/test_base.py,sha256=FbsYzs122PkztgjDKxCb44Lb626UAqOyJBwwLXQjn6g,28897
twisted/positioning/test/test_nmea.py,sha256=mTs_PNwZv-DmMJC_QIibP_kbSazNXl2DY14BaheHKAw,39925
twisted/positioning/test/test_sentence.py,sha256=REOT5BUY-vUz_FEbmWrapgel9-dmcH41fIpeNo4peJE,4770
twisted/protocols/__init__.py,sha256=11Pa7Emr3WMc3VvzbjfrTydeVl4rpQJ587BWXZD125w,391
twisted/protocols/__pycache__/__init__.cpython-36.pyc,,
twisted/protocols/__pycache__/amp.cpython-36.pyc,,
twisted/protocols/__pycache__/basic.cpython-36.pyc,,
twisted/protocols/__pycache__/dict.cpython-36.pyc,,
twisted/protocols/__pycache__/finger.cpython-36.pyc,,
twisted/protocols/__pycache__/ftp.cpython-36.pyc,,
twisted/protocols/__pycache__/htb.cpython-36.pyc,,
twisted/protocols/__pycache__/ident.cpython-36.pyc,,
twisted/protocols/__pycache__/loopback.cpython-36.pyc,,
twisted/protocols/__pycache__/memcache.cpython-36.pyc,,
twisted/protocols/__pycache__/pcp.cpython-36.pyc,,
twisted/protocols/__pycache__/policies.cpython-36.pyc,,
twisted/protocols/__pycache__/portforward.cpython-36.pyc,,
twisted/protocols/__pycache__/postfix.cpython-36.pyc,,
twisted/protocols/__pycache__/sip.cpython-36.pyc,,
twisted/protocols/__pycache__/socks.cpython-36.pyc,,
twisted/protocols/__pycache__/stateful.cpython-36.pyc,,
twisted/protocols/__pycache__/tls.cpython-36.pyc,,
twisted/protocols/__pycache__/wire.cpython-36.pyc,,
twisted/protocols/amp.py,sha256=y_Nvxa4lOQpx3D3qrWIB_XkY3AiMCG7OQPSm5lBwI1Y,97898
twisted/protocols/basic.py,sha256=aJGgFcI8hRVuqcXJrp5aPCgUx-U73SKUYhOSprEK4LQ,32061
twisted/protocols/dict.py,sha256=osi8Fjn7QALiRTtuFyDdZymRtdjxceO5CxwIaQBeqSk,10762
twisted/protocols/finger.py,sha256=MHoysns-8Wi3QfrZNIvoUQVyASQSzx-t3GzjYp9MPK0,1220
twisted/protocols/ftp.py,sha256=DzUEKyf9NmVXtOrzOZbV0IPkpR96WSvcRRW1REM8CEk,106132
twisted/protocols/haproxy/__init__.py,sha256=TyD3qy2qDa2p6zw0Q3DkPeWS5ChiAEzX0JZfAfFdtYg,251
twisted/protocols/haproxy/__pycache__/__init__.cpython-36.pyc,,
twisted/protocols/haproxy/__pycache__/_exceptions.cpython-36.pyc,,
twisted/protocols/haproxy/__pycache__/_info.cpython-36.pyc,,
twisted/protocols/haproxy/__pycache__/_interfaces.cpython-36.pyc,,
twisted/protocols/haproxy/__pycache__/_parser.cpython-36.pyc,,
twisted/protocols/haproxy/__pycache__/_v1parser.cpython-36.pyc,,
twisted/protocols/haproxy/__pycache__/_v2parser.cpython-36.pyc,,
twisted/protocols/haproxy/__pycache__/_wrapper.cpython-36.pyc,,
twisted/protocols/haproxy/_exceptions.py,sha256=SW9Zeft6X9W2HtPY9Mfh2AIbQVuoX8UNs7l4eOz0Izo,1085
twisted/protocols/haproxy/_info.py,sha256=OB180dloGeTnpjxeVBObB6P-e3VU223ZK4ImHsBNvZM,929
twisted/protocols/haproxy/_interfaces.py,sha256=bDsfV4TKelDi5vW_dig0vmh8grcM7R6KZJrb7kTnlO0,1794
twisted/protocols/haproxy/_parser.py,sha256=AT7MMzwMx8kaMbVjDjLiJSt8MiuzApbwu7LFn5vxTOI,2051
twisted/protocols/haproxy/_v1parser.py,sha256=LAM2OeeV-vC5b85ohEPk1mcUnqMOQJgnUvA0NF7kUKk,4326
twisted/protocols/haproxy/_v2parser.py,sha256=JkSl8VWd7YMw5V6JNJ6LhunnWf_DVl_jde6isu7_VF4,6307
twisted/protocols/haproxy/_wrapper.py,sha256=4lA_nXL-pdzgXJ_5DXPwrnqvfOSC9gWLuovOdlMJ6jA,3323
twisted/protocols/haproxy/test/__init__.py,sha256=gxu5b7Qz4fM2tMbIm4VeUfMY4NthR3rzZlnX1VO_JUU,183
twisted/protocols/haproxy/test/__pycache__/__init__.cpython-36.pyc,,
twisted/protocols/haproxy/test/__pycache__/test_parser.cpython-36.pyc,,
twisted/protocols/haproxy/test/__pycache__/test_v1parser.cpython-36.pyc,,
twisted/protocols/haproxy/test/__pycache__/test_v2parser.cpython-36.pyc,,
twisted/protocols/haproxy/test/__pycache__/test_wrapper.cpython-36.pyc,,
twisted/protocols/haproxy/test/test_parser.py,sha256=k7RipRqyta7A4XySeBDQQrNBTqWO3nMr7ZgTgHpYLy4,3467
twisted/protocols/haproxy/test/test_v1parser.py,sha256=4hUm8u_vbAwPrrdRouAN1bDephjikVn5yFrB3e6b1H8,4694
twisted/protocols/haproxy/test/test_v2parser.py,sha256=PuyYjAYyLho-M8iOU1znggWjEvowhFTFVemblipH-EE,11777
twisted/protocols/haproxy/test/test_wrapper.py,sha256=8vRib0ifsoeAeeefQN0y5r0lo0_sTEMpoMzKUx6W4c4,13035
twisted/protocols/htb.py,sha256=NAiAptbEWvk46eDOlvLi1NjDfgkhSAFzNdS46mPjqsM,9327
twisted/protocols/ident.py,sha256=KV78Gj7IguHGpsOzEgkgIFPAqaiUNlXoiRSGBUChZcc,7781
twisted/protocols/loopback.py,sha256=xRPWLdrukRJth5yp8TWXspLofVR_HApqfk65pE7UJ4s,11928
twisted/protocols/memcache.py,sha256=98KnhDWuVDj_FBiNiM5MAsQrQg6xCrjkIko_rxqigTM,23693
twisted/protocols/pcp.py,sha256=sZWqAcibTFdsZnep-2Ml9lZwtT86z8FL6QCr-UH7-eU,7088
twisted/protocols/policies.py,sha256=SIp1MDpyhZTf7296XGiJHP_OC2WmMFS0G3Dwo9wOWl8,21327
twisted/protocols/portforward.py,sha256=Ob19TUzNKwq5OACeTBe35ZthfaGtu0o96gAbGBMGTNo,2383
twisted/protocols/postfix.py,sha256=2erA8Ap2nKF9W6t25TXk3ozG9wsW7ynDcjkN5BLwFQE,3953
twisted/protocols/sip.py,sha256=BSc-8qrcrx7gpz0Ku1vqX_wkdrZssi9huD1nDVEsoWs,37794
twisted/protocols/socks.py,sha256=kYGCYSO_K4YcSW3eG2iij9qye45-sokhMHz6h5gSejw,7816
twisted/protocols/stateful.py,sha256=6r-k3nLKMIa4M_9x1NRn5LWJ2BUPrn4jRh1TP8Jqltw,1640
twisted/protocols/test/__init__.py,sha256=QMkwFc9QOiSDp4ZU06wLjPDi3iw0y3ysUgdjOPceMu0,118
twisted/protocols/test/__pycache__/__init__.cpython-36.pyc,,
twisted/protocols/test/__pycache__/test_basic.cpython-36.pyc,,
twisted/protocols/test/__pycache__/test_tls.cpython-36.pyc,,
twisted/protocols/test/test_basic.py,sha256=2LqruAhTDMjhjP_afc018EQ2SwxmeBY6KXjS0KMBhZY,43214
twisted/protocols/test/test_tls.py,sha256=zSTdoAeXZEyNBM8yuMD07rBJSgGsoPJFjdCp7WQ_dyA,75552
twisted/protocols/tls.py,sha256=GmaSZCckJRo1W-winsYwf_uHfOeg-2wl1CveH5PgEWU,32620
twisted/protocols/wire.py,sha256=47h5tn358eT-T_c-QULiRm8CavhH74TxdLFKx-B1mUg,2556
twisted/python/__init__.py,sha256=59IqUE-1fknNPjKnfvC46EWCIdUeqEcUxAofVFiPSSU,674
twisted/python/__pycache__/__init__.cpython-36.pyc,,
twisted/python/__pycache__/_appdirs.cpython-36.pyc,,
twisted/python/__pycache__/_inotify.cpython-36.pyc,,
twisted/python/__pycache__/_oldstyle.cpython-36.pyc,,
twisted/python/__pycache__/_release.cpython-36.pyc,,
twisted/python/__pycache__/_setup.cpython-36.pyc,,
twisted/python/__pycache__/_shellcomp.cpython-36.pyc,,
twisted/python/__pycache__/_textattributes.cpython-36.pyc,,
twisted/python/__pycache__/_tzhelper.cpython-36.pyc,,
twisted/python/__pycache__/_url.cpython-36.pyc,,
twisted/python/__pycache__/compat.cpython-36.pyc,,
twisted/python/__pycache__/components.cpython-36.pyc,,
twisted/python/__pycache__/constants.cpython-36.pyc,,
twisted/python/__pycache__/context.cpython-36.pyc,,
twisted/python/__pycache__/deprecate.cpython-36.pyc,,
twisted/python/__pycache__/failure.cpython-36.pyc,,
twisted/python/__pycache__/fakepwd.cpython-36.pyc,,
twisted/python/__pycache__/filepath.cpython-36.pyc,,
twisted/python/__pycache__/formmethod.cpython-36.pyc,,
twisted/python/__pycache__/htmlizer.cpython-36.pyc,,
twisted/python/__pycache__/lockfile.cpython-36.pyc,,
twisted/python/__pycache__/log.cpython-36.pyc,,
twisted/python/__pycache__/logfile.cpython-36.pyc,,
twisted/python/__pycache__/modules.cpython-36.pyc,,
twisted/python/__pycache__/monkey.cpython-36.pyc,,
twisted/python/__pycache__/procutils.cpython-36.pyc,,
twisted/python/__pycache__/randbytes.cpython-36.pyc,,
twisted/python/__pycache__/rebuild.cpython-36.pyc,,
twisted/python/__pycache__/reflect.cpython-36.pyc,,
twisted/python/__pycache__/release.cpython-36.pyc,,
twisted/python/__pycache__/roots.cpython-36.pyc,,
twisted/python/__pycache__/runtime.cpython-36.pyc,,
twisted/python/__pycache__/sendmsg.cpython-36.pyc,,
twisted/python/__pycache__/shortcut.cpython-36.pyc,,
twisted/python/__pycache__/syslog.cpython-36.pyc,,
twisted/python/__pycache__/systemd.cpython-36.pyc,,
twisted/python/__pycache__/text.cpython-36.pyc,,
twisted/python/__pycache__/threadable.cpython-36.pyc,,
twisted/python/__pycache__/threadpool.cpython-36.pyc,,
twisted/python/__pycache__/url.cpython-36.pyc,,
twisted/python/__pycache__/urlpath.cpython-36.pyc,,
twisted/python/__pycache__/usage.cpython-36.pyc,,
twisted/python/__pycache__/util.cpython-36.pyc,,
twisted/python/__pycache__/versions.cpython-36.pyc,,
twisted/python/__pycache__/win32.cpython-36.pyc,,
twisted/python/__pycache__/zippath.cpython-36.pyc,,
twisted/python/__pycache__/zipstream.cpython-36.pyc,,
twisted/python/_appdirs.py,sha256=bw_i8btCVr-TH62QlcP-Gdt5v6R0hoCaiZyYk2ZvVxA,788
twisted/python/_inotify.py,sha256=aYbn1L_5MM62Gl60GzlkiwOHTc6mB0lUCr1tP-FsgPU,3455
twisted/python/_oldstyle.py,sha256=ksosHBxHm691H3HwaR1ORGMNC-7q2U-IwTMpcxqugZ0,2593
twisted/python/_pydoctortemplates/common.html,sha256=KxdAlEXi-ihLekHIh0t1VGHIRNv1QzOHLdU7F3jtuTY,3341
twisted/python/_pydoctortemplates/index.html,sha256=JecyxRLyBd8Z45KbYD_rQeTeRizrXIjlNslU3uLppjM,3565
twisted/python/_pydoctortemplates/summary.html,sha256=E_LjXUI4vwx8G7_5ZwAd6LndTeYxUTCrjGUOMiUtu1Y,1980
twisted/python/_release.py,sha256=xqUE9jUSx0rKKI00hFYfz7NXA8h7b9orFpWZODYRJek,18550
twisted/python/_setup.py,sha256=0qYzsSph8fvBU-XmVsCi6tTEz41Z2eva_N25E_1c78Q,14352
twisted/python/_shellcomp.py,sha256=9mb_W8t3VkpejPSNWyrkiT5fGLdTc4V6mi3uvS7Ej7k,24830
twisted/python/_textattributes.py,sha256=5HDokoRNMdRKmmKh1yrdymoOE7qTWkeNPOm8tOUePx8,9079
twisted/python/_tzhelper.py,sha256=YFN_nX1P-QvHzMUKKXcA9eQsUf2n9MHYr2lIecLqy70,3192
twisted/python/_url.py,sha256=7-vSoeXo3oMd6xDG3GvsDb7BXpRx8tnAc6HpPUk9zLQ,253
twisted/python/compat.py,sha256=NJEtYTaa_LA3j85-TkfyusjkRgk28CqpBy_3aDCvI0k,22907
twisted/python/components.py,sha256=jf9hOzQqetZfpDgBMELxCPdM6S8ALQYpBV-a2rVK4uc,14242
twisted/python/constants.py,sha256=GuTBebugkgjf4CkvJaOxy3GLYrV72Ftz_IFexC6dn2Y,544
twisted/python/context.py,sha256=2mPa-VtpamaSkfz5433svgisrVaT7mKPhQVgQ1i0SZY,4024
twisted/python/deprecate.py,sha256=EfkGx7d9K0st0vrsiNcvOIaD5_C2fQa8aWZbBCCloXI,26948
twisted/python/failure.py,sha256=2KBV5GN7gy-umIdziF1Mri_JCLlr6sL9fzx7Exp13i4,27564
twisted/python/fakepwd.py,sha256=26yDkt13tXXNTGv2Ua3qQ2t_0FJy0sesVge86O8ulAc,6138
twisted/python/filepath.py,sha256=rtd9HVtB_NZOWq3K2iZpaCw6_R-mjVlouVV6WylGljw,58887
twisted/python/formmethod.py,sha256=xpgE8EVYQQ_bgWySJp74ZT4ecY1SBL1hY4t5Oz_pDLg,11460
twisted/python/htmlizer.py,sha256=x91-QwzLlcF8Zfw3vG8NzzCabm7SF4m8EARO1v9llDI,3541
twisted/python/lockfile.py,sha256=ZgEOdSPnK3RFXTPz9cuvieQrp2uNvGV2bow8qiqSLmE,7718
twisted/python/log.py,sha256=etGKoolsiXr__IGZN9SG8YMd-JS3hMFIpphvvIRfNak,22472
twisted/python/logfile.py,sha256=TNbhiOp692oNKnQ9SCBz3oJAlfgbIYk1R6cnYFEYWRY,10083
twisted/python/modules.py,sha256=Zret5tlILxKbI05x4Rw_b0Qw0pBxcYIMn0ssSGQLaAs,27141
twisted/python/monkey.py,sha256=dTtT6kIz1vvSmIOUKOGGGlRAmpWS9UCzRGyc09hZHmE,2227
twisted/python/procutils.py,sha256=lkI5rWeD1iNyKsp9_L0XI8Lm3I4o7W6AzsiwdoFfLDU,1419
twisted/python/randbytes.py,sha256=dpPatxms22rgQwoLzuPYGWbWJc1ogVOyUrB_eAW1Fjs,3959
twisted/python/rebuild.py,sha256=9ro6DKmvmfQzMs7RKn3Tho2kL1pjmyyAwI1Rpm8mb2k,9268
twisted/python/reflect.py,sha256=ul_gpPzj1JhozrflHEW4UdRwysBtUd_N1fjSn8Wsn84,19477
twisted/python/release.py,sha256=fOCKs0fEKqLZduuDuBijZ0MDIkGEWliJApxEaAYlkEk,1192
twisted/python/roots.py,sha256=P98gPe16GCettjsnJCNPKAyeBJTyJOkvIKDx1-JMRu4,7404
twisted/python/runtime.py,sha256=XnzEnaDzX01aFGd-T-hw7sqP_yh30m56ttPALWNB9Fo,6216
twisted/python/sendmsg.py,sha256=V9Sxc2I2OI6iXS9Fy1GYR__nH8MiWEkLcxlhO6B3m24,3420
twisted/python/shortcut.py,sha256=HIlHg7G7u9jMhC09DrLPOv8zNnvF4wkz2AjBL-GKrn8,2253
twisted/python/syslog.py,sha256=Cu67zZN15N21NESUvs9RFQ4yQTdTzzn0ZTikKEhVDjA,3730
twisted/python/systemd.py,sha256=onsuaC2aPtrUS3DNeHMdoclD3v79vcm4jFmDU_pqBGE,2834
twisted/python/test/__init__.py,sha256=V0srj7fq1Y17ZVfFgUc0n5ueVkK0InJNIT90pWlEKLI,42
twisted/python/test/__pycache__/__init__.cpython-36.pyc,,
twisted/python/test/__pycache__/deprecatedattributes.cpython-36.pyc,,
twisted/python/test/__pycache__/modules_helpers.cpython-36.pyc,,
twisted/python/test/__pycache__/pullpipe.cpython-36.pyc,,
twisted/python/test/__pycache__/test_appdirs.cpython-36.pyc,,
twisted/python/test/__pycache__/test_components.cpython-36.pyc,,
twisted/python/test/__pycache__/test_constants.cpython-36.pyc,,
twisted/python/test/__pycache__/test_deprecate.cpython-36.pyc,,
twisted/python/test/__pycache__/test_dist3.cpython-36.pyc,,
twisted/python/test/__pycache__/test_fakepwd.cpython-36.pyc,,
twisted/python/test/__pycache__/test_htmlizer.cpython-36.pyc,,
twisted/python/test/__pycache__/test_inotify.cpython-36.pyc,,
twisted/python/test/__pycache__/test_release.cpython-36.pyc,,
twisted/python/test/__pycache__/test_runtime.cpython-36.pyc,,
twisted/python/test/__pycache__/test_sendmsg.cpython-36.pyc,,
twisted/python/test/__pycache__/test_setup.cpython-36.pyc,,
twisted/python/test/__pycache__/test_shellcomp.cpython-36.pyc,,
twisted/python/test/__pycache__/test_syslog.cpython-36.pyc,,
twisted/python/test/__pycache__/test_systemd.cpython-36.pyc,,
twisted/python/test/__pycache__/test_textattributes.cpython-36.pyc,,
twisted/python/test/__pycache__/test_tzhelper.cpython-36.pyc,,
twisted/python/test/__pycache__/test_url.cpython-36.pyc,,
twisted/python/test/__pycache__/test_urlpath.cpython-36.pyc,,
twisted/python/test/__pycache__/test_util.cpython-36.pyc,,
twisted/python/test/__pycache__/test_versions.cpython-36.pyc,,
twisted/python/test/__pycache__/test_zippath.cpython-36.pyc,,
twisted/python/test/__pycache__/test_zipstream.cpython-36.pyc,,
twisted/python/test/_deprecatetests.py.3only,sha256=qSX82XTcTBq4SpzmvjFlf-fK64geLp0spny-mRM_Kms,1814
twisted/python/test/deprecatedattributes.py,sha256=oTFSMS8Xi6q4JUgh5nUlBsmH3WrPkANJcKkI8plLJ94,571
twisted/python/test/modules_helpers.py,sha256=Ugs47h2kBaWydzLUHEYJx5lBf2a4vvpZuPAU3qaH4Sc,1605
twisted/python/test/pullpipe.py,sha256=hyX-tJuVuAo3QK76Q4Z0-Ots3Jo8ia3-9HWUPexlnuM,1220
twisted/python/test/test_appdirs.py,sha256=IpWQQKEiFNFnZahLWJZvHmM3dr1RKA_JERpbNLh3wLY,1081
twisted/python/test/test_components.py,sha256=HNKATjfPnL5lIxVS1wCBGTIb4NYFPkZzo05xNpJLRY8,25974
twisted/python/test/test_constants.py,sha256=_k490Ijg6HpYx_jHTjSedSD555Ujz0FHbrvLV1xNuYs,38117
twisted/python/test/test_deprecate.py,sha256=_xNUpOwd8TAbTC39m_wVEmQrSU3DaBfDoyVb40RLoDY,38930
twisted/python/test/test_dist3.py,sha256=QoIwlgUmeEtwcfbp2BLpqIiqub97v2fAHLw77BEYKbE,1858
twisted/python/test/test_fakepwd.py,sha256=2ulp3433yk5zIYcmb96ZUd2VXc8X-Q07xGdC54_OLyQ,14107
twisted/python/test/test_htmlizer.py,sha256=mA0YLFeplomK31oADOCo8-woa8ALbgfEu1FVLGSmLGw,1266
twisted/python/test/test_inotify.py,sha256=TPSjt9OPRp4hyEk05ZUl4281yuUI_etJ5LETjEMXz6s,3639
twisted/python/test/test_release.py,sha256=sLrfF-SJYRnjwiwGtbBVICaRniIh8Q_7TB612gPm9wg,41046
twisted/python/test/test_runtime.py,sha256=W3p_U-4eBEWYb2pQPfFEelUoHP-j9H-whEYbvgZtRKo,7926
twisted/python/test/test_sendmsg.py,sha256=gmm-zG0rRwfTuy8ozGJ7xeBhDSCJezjyAHyf8djNm1s,25233
twisted/python/test/test_setup.py,sha256=EXT8DjgyTqS5_ecN150HzZi7eMGJQHLCihwwxbzA6cE,13699
twisted/python/test/test_shellcomp.py,sha256=6mHTIncdngMe5Nm42x9_oXH-H-O4BO7g3QzwdiwHQ18,21809
twisted/python/test/test_syslog.py,sha256=2f2Ik8tLD89X905NtsKczHQNw4ssMd9sDmwpI5WTZEA,4948
twisted/python/test/test_systemd.py,sha256=lC5l4suhb6cQGnXlcxUyx5ZR7MUAAq0Zrci-f9pneCs,6401
twisted/python/test/test_textattributes.py,sha256=3tIa0LITcWGQraaeuu1S3Ai1v8rnGiNnRYnpRuDvBUE,712
twisted/python/test/test_tzhelper.py,sha256=qbJVrzd42-2SmiGTXBbDYbLLuSD1i1F4IkbLuT2X124,3984
twisted/python/test/test_url.py,sha256=mwDdEvACowrPyxYNPqCR_b32s93sN7DzvpR73SqEMZM,29313
twisted/python/test/test_urlpath.py,sha256=j7qCw-4PNgHeoYmIplna8zzt5EvrnluRFH8wf0d14Gs,10328
twisted/python/test/test_util.py,sha256=x5clz1UK59zQ1pETP-mKj5L2S8WUYRUjnieY1q-jl6k,36460
twisted/python/test/test_versions.py,sha256=xCTFjXPc8r6DujRCDzavd9qkzL1hwzcxwyDcT5fOAS8,5400
twisted/python/test/test_zippath.py,sha256=LRDWmsm8shSxYiw2QOs4NFjXFef1hsCUIzxmOhCn0f0,3474
twisted/python/test/test_zipstream.py,sha256=ai-XdQAlvQ6uUAmm5ikIjIpj7WU4KhWTj50tgbN_lRg,12308
twisted/python/text.py,sha256=bI7CKqBudIqueU7lduVKsQqzTZipPdSoZoa0lR9IklI,5482
twisted/python/threadable.py,sha256=yx-911e3S7loq9svlCLbqrFtLbATJd-IrXtFyC1FzKI,3297
twisted/python/threadpool.py,sha256=SfnPhHyfbfzB8IBu2p_qyHbA5PKqfEesMhNBKqz0ctQ,9840
twisted/python/twisted-completion.zsh,sha256=DkNZis_hXXFAxUutigSn6gDRk8i70ylRrJ7ZBy-8NZo,1371
twisted/python/url.py,sha256=0vJfs6hgMrWkIR2ZgovyPASQlYHh2afVCFaQaGSLA2c,244
twisted/python/urlpath.py,sha256=GV2oT4B_QwtKVOfKjOZC5J_bIxVzblHGtP7-2aCqxXk,9084
twisted/python/usage.py,sha256=PmukwnG15RZjJwCwX4Z5moDUShWKwBVHwj1jocLVDZY,35002
twisted/python/util.py,sha256=4Pz0IZzKDqY9UFwqb-RU4HJoCUgrAO_h2-sLBMNR58o,27931
twisted/python/versions.py,sha256=VV-6OHSdnxuUPrfZ0tfb1kIxwU_nIIUA8Isedy1wYxc,322
twisted/python/win32.py,sha256=i2e7daTFnZVYWpmGjlPBH97IsXQKm5kiwX7Zy1vY2S4,4317
twisted/python/zippath.py,sha256=3iNAMvf_shM4KMaIHttR5HsBawMmHJy_h1z0emsvGPQ,9237
twisted/python/zipstream.py,sha256=yZb1fdWj1YHXrK9_sG4auyiQbZYrZsf2tsbTE65fT08,9757
twisted/runner/__init__.py,sha256=ahzGC9cYnSf0DSsEzBgV1oK-AyD_jb3jvVfEZA6mJZ0,124
twisted/runner/__pycache__/__init__.cpython-36.pyc,,
twisted/runner/__pycache__/inetd.cpython-36.pyc,,
twisted/runner/__pycache__/inetdconf.cpython-36.pyc,,
twisted/runner/__pycache__/inetdtap.cpython-36.pyc,,
twisted/runner/__pycache__/procmon.cpython-36.pyc,,
twisted/runner/__pycache__/procmontap.cpython-36.pyc,,
twisted/runner/inetd.py,sha256=EHkgH-8dYHD75CUaby9dkui4zGFToR6HhOpOxd5c7os,1962
twisted/runner/inetdconf.py,sha256=hHz7QpqQGJtg5YQ2KRj_IdmfmasiYnvw4ZXK4nRy98w,4917
twisted/runner/inetdtap.py,sha256=3EfntNfqiEBApmNjyXv10v9DZ0u4pk8EUbaf2hPEbX8,3558
twisted/runner/procmon.py,sha256=e7Rr8ANff3jDDirWYHQxTGm_F5sH24eKQBRZRulrkjg,12675
twisted/runner/procmontap.py,sha256=3S6LdXV2qIzUrWyNvHlk8ZMpc2Pri79PXjBIB0p6oEw,2298
twisted/runner/test/__init__.py,sha256=tjveH1kCFEM9rVaT_bsWV8TURsUKAgqn9p3zHZdDK40,114
twisted/runner/test/__pycache__/__init__.cpython-36.pyc,,
twisted/runner/test/__pycache__/test_inetdconf.cpython-36.pyc,,
twisted/runner/test/__pycache__/test_procmon.cpython-36.pyc,,
twisted/runner/test/__pycache__/test_procmontap.cpython-36.pyc,,
twisted/runner/test/test_inetdconf.py,sha256=r-HcBqvSvDbqcyc6viHoBdCfLrP0Pqm-ptALYU-kjFU,1785
twisted/runner/test/test_procmon.py,sha256=juFE0_OW7YLTIr9Ohe35EK84T7NVB0NXGrz4UsuqWNg,23346
twisted/runner/test/test_procmontap.py,sha256=f237F_JUHlqJQ0IDXoVBB9C_Qu2FZHJGTGOduSXWyNM,2520
twisted/scripts/__init__.py,sha256=TSubMCp4NhcXtFvbrOT9boiIzXpbSvATakl3yGBQwQY,261
twisted/scripts/__pycache__/__init__.cpython-36.pyc,,
twisted/scripts/__pycache__/_twistd_unix.cpython-36.pyc,,
twisted/scripts/__pycache__/_twistw.cpython-36.pyc,,
twisted/scripts/__pycache__/htmlizer.cpython-36.pyc,,
twisted/scripts/__pycache__/trial.cpython-36.pyc,,
twisted/scripts/__pycache__/twistd.cpython-36.pyc,,
twisted/scripts/_twistd_unix.py,sha256=oxV8dzXcxZe-kwzQLUoBT9TFrOSUmnJnaQvqh0ZL0q4,16380
twisted/scripts/_twistw.py,sha256=DR_MP8Ij2fqlYNTACS384RPuNHdOdIhrHsO0mDfUJG0,1562
twisted/scripts/htmlizer.py,sha256=HSlaUZZ5O7Lxnay2tNm-eFq6sqh7pKhvysixJdyGY_s,1868
twisted/scripts/test/__init__.py,sha256=p8A4Q5FXoU8Mch55_ANwPbv5-vTZikEVox_gvZELTHg,118
twisted/scripts/test/__pycache__/__init__.cpython-36.pyc,,
twisted/scripts/test/__pycache__/test_scripts.cpython-36.pyc,,
twisted/scripts/test/test_scripts.py,sha256=zsK4xm834A3KBsx6qUlbjfNWOiqw4iK1AmY4Ktf7dzg,4880
twisted/scripts/trial.py,sha256=vlKgrnUIuBmmMB5uAQjv1MYUARKc5EF54bVfQ-XDggY,21132
twisted/scripts/twistd.py,sha256=1UX9uFucre3pMc5VqLD-QrIfNbLgkF8FQ_Swr0D2wn4,867
twisted/spread/__init__.py,sha256=gfxmcnrYlpVRF5hdBZ3WUCItFEAc6DNSQw6D8e_f3RE,159
twisted/spread/__pycache__/__init__.cpython-36.pyc,,
twisted/spread/__pycache__/banana.cpython-36.pyc,,
twisted/spread/__pycache__/flavors.cpython-36.pyc,,
twisted/spread/__pycache__/interfaces.cpython-36.pyc,,
twisted/spread/__pycache__/jelly.cpython-36.pyc,,
twisted/spread/__pycache__/pb.cpython-36.pyc,,
twisted/spread/__pycache__/publish.cpython-36.pyc,,
twisted/spread/__pycache__/util.cpython-36.pyc,,
twisted/spread/banana.py,sha256=ofAgyONvTiJ5H5AaGhLxK8mnAo-6u7sgo00KqwMrxGY,12334
twisted/spread/flavors.py,sha256=n2_9c16yhkbpDAk6SkbN6UBVmmQ4_QU2YeUkIW_WgAQ,23455
twisted/spread/interfaces.py,sha256=A7UjlK03QoQ5KnPMUkvlpSnYqe5pdt7hUKv6MTLWa30,686
twisted/spread/jelly.py,sha256=aCq16IuReZ7btYNcO2zBGHZwfUDqWJ3YY0AEdmPVMwU,36468
twisted/spread/pb.py,sha256=BUR4Cf3snqevg95aH3yri__uN1cda5K2WNGeman8ZoU,52385
twisted/spread/publish.py,sha256=G4n2VvafpTtx7S8eEZtHC8s6naDBdwmLWNG4itifat8,4480
twisted/spread/test/__init__.py,sha256=67HyXbsJ4DIBtcMcUWJqGMHdQc2Z-NLinUz2MVUEplI,110
twisted/spread/test/__pycache__/__init__.cpython-36.pyc,,
twisted/spread/test/__pycache__/test_banana.cpython-36.pyc,,
twisted/spread/test/__pycache__/test_jelly.cpython-36.pyc,,
twisted/spread/test/__pycache__/test_pb.cpython-36.pyc,,
twisted/spread/test/__pycache__/test_pbfailure.cpython-36.pyc,,
twisted/spread/test/test_banana.py,sha256=wV0I1JtZvg1VJZEZVPvfFEUQYSNS2eL-irtqarZyb_k,15456
twisted/spread/test/test_jelly.py,sha256=tVs3Ph0cGjO6lU9uqqe6qHTVASoUuPhi5N2Oa1FwFP8,19990
twisted/spread/test/test_pb.py,sha256=dy7mom3-TD89U_qz2NdnC1RTfwBwA4glz4QwvXxniuw,63874
twisted/spread/test/test_pbfailure.py,sha256=292uqxxnW0nLSWfubBnW3INJWksGImoECepvAC_h554,15433
twisted/spread/util.py,sha256=OWm_8dRgzKEvGVWxutxhdWOkupoc1sLj0FSuwX8JW1w,6387
twisted/tap/__init__.py,sha256=cWvA7ICrsBPoK11cax2E9a3OhvuDMYXRBvj_7tKXMDI,162
twisted/tap/__pycache__/__init__.cpython-36.pyc,,
twisted/tap/__pycache__/ftp.cpython-36.pyc,,
twisted/tap/__pycache__/portforward.cpython-36.pyc,,
twisted/tap/__pycache__/socks.cpython-36.pyc,,
twisted/tap/ftp.py,sha256=JmF1-GN5eoEYen773DBg0_-hSyHnFE94q1XrsG1Lz9Y,2002
twisted/tap/portforward.py,sha256=ZMY42wPvX5yfi1A3Ug_XLEOM7F5-UWhgzq2nY2WVNa8,795
twisted/tap/socks.py,sha256=uF0OnqGl16jcW6vtT7BvRImqsxSZPeJ8GPnUCoKghrc,1292
twisted/test/__init__.py,sha256=P8kgU78nKls3dRPDEW7-PYoYrm2J_hYMiYB6eJUHNbI,477
twisted/test/__pycache__/__init__.cpython-36.pyc,,
twisted/test/__pycache__/crash_test_dummy.cpython-36.pyc,,
twisted/test/__pycache__/iosim.cpython-36.pyc,,
twisted/test/__pycache__/mock_win32process.cpython-36.pyc,,
twisted/test/__pycache__/myrebuilder1.cpython-36.pyc,,
twisted/test/__pycache__/myrebuilder2.cpython-36.pyc,,
twisted/test/__pycache__/plugin_basic.cpython-36.pyc,,
twisted/test/__pycache__/plugin_extra1.cpython-36.pyc,,
twisted/test/__pycache__/plugin_extra2.cpython-36.pyc,,
twisted/test/__pycache__/process_cmdline.cpython-36.pyc,,
twisted/test/__pycache__/process_echoer.cpython-36.pyc,,
twisted/test/__pycache__/process_fds.cpython-36.pyc,,
twisted/test/__pycache__/process_getargv.cpython-36.pyc,,
twisted/test/__pycache__/process_getenv.cpython-36.pyc,,
twisted/test/__pycache__/process_linger.cpython-36.pyc,,
twisted/test/__pycache__/process_reader.cpython-36.pyc,,
twisted/test/__pycache__/process_signal.cpython-36.pyc,,
twisted/test/__pycache__/process_stdinreader.cpython-36.pyc,,
twisted/test/__pycache__/process_tester.cpython-36.pyc,,
twisted/test/__pycache__/process_tty.cpython-36.pyc,,
twisted/test/__pycache__/process_twisted.cpython-36.pyc,,
twisted/test/__pycache__/proto_helpers.cpython-36.pyc,,
twisted/test/__pycache__/reflect_helper_IE.cpython-36.pyc,,
twisted/test/__pycache__/reflect_helper_VE.cpython-36.pyc,,
twisted/test/__pycache__/reflect_helper_ZDE.cpython-36.pyc,,
twisted/test/__pycache__/ssl_helpers.cpython-36.pyc,,
twisted/test/__pycache__/stdio_test_consumer.cpython-36.pyc,,
twisted/test/__pycache__/stdio_test_halfclose.cpython-36.pyc,,
twisted/test/__pycache__/stdio_test_hostpeer.cpython-36.pyc,,
twisted/test/__pycache__/stdio_test_lastwrite.cpython-36.pyc,,
twisted/test/__pycache__/stdio_test_loseconn.cpython-36.pyc,,
twisted/test/__pycache__/stdio_test_producer.cpython-36.pyc,,
twisted/test/__pycache__/stdio_test_write.cpython-36.pyc,,
twisted/test/__pycache__/stdio_test_writeseq.cpython-36.pyc,,
twisted/test/__pycache__/test_abstract.cpython-36.pyc,,
twisted/test/__pycache__/test_adbapi.cpython-36.pyc,,
twisted/test/__pycache__/test_amp.cpython-36.pyc,,
twisted/test/__pycache__/test_application.cpython-36.pyc,,
twisted/test/__pycache__/test_compat.cpython-36.pyc,,
twisted/test/__pycache__/test_context.cpython-36.pyc,,
twisted/test/__pycache__/test_cooperator.cpython-36.pyc,,
twisted/test/__pycache__/test_defer.cpython-36.pyc,,
twisted/test/__pycache__/test_defgen.cpython-36.pyc,,
twisted/test/__pycache__/test_dict.cpython-36.pyc,,
twisted/test/__pycache__/test_dirdbm.cpython-36.pyc,,
twisted/test/__pycache__/test_error.cpython-36.pyc,,
twisted/test/__pycache__/test_factories.cpython-36.pyc,,
twisted/test/__pycache__/test_failure.cpython-36.pyc,,
twisted/test/__pycache__/test_fdesc.cpython-36.pyc,,
twisted/test/__pycache__/test_finger.cpython-36.pyc,,
twisted/test/__pycache__/test_formmethod.cpython-36.pyc,,
twisted/test/__pycache__/test_ftp.cpython-36.pyc,,
twisted/test/__pycache__/test_ftp_options.cpython-36.pyc,,
twisted/test/__pycache__/test_htb.cpython-36.pyc,,
twisted/test/__pycache__/test_ident.cpython-36.pyc,,
twisted/test/__pycache__/test_internet.cpython-36.pyc,,
twisted/test/__pycache__/test_iosim.cpython-36.pyc,,
twisted/test/__pycache__/test_iutils.cpython-36.pyc,,
twisted/test/__pycache__/test_lockfile.cpython-36.pyc,,
twisted/test/__pycache__/test_log.cpython-36.pyc,,
twisted/test/__pycache__/test_logfile.cpython-36.pyc,,
twisted/test/__pycache__/test_loopback.cpython-36.pyc,,
twisted/test/__pycache__/test_main.cpython-36.pyc,,
twisted/test/__pycache__/test_memcache.cpython-36.pyc,,
twisted/test/__pycache__/test_modules.cpython-36.pyc,,
twisted/test/__pycache__/test_monkey.cpython-36.pyc,,
twisted/test/__pycache__/test_nooldstyle.cpython-36.pyc,,
twisted/test/__pycache__/test_paths.cpython-36.pyc,,
twisted/test/__pycache__/test_pcp.cpython-36.pyc,,
twisted/test/__pycache__/test_persisted.cpython-36.pyc,,
twisted/test/__pycache__/test_plugin.cpython-36.pyc,,
twisted/test/__pycache__/test_policies.cpython-36.pyc,,
twisted/test/__pycache__/test_postfix.cpython-36.pyc,,
twisted/test/__pycache__/test_process.cpython-36.pyc,,
twisted/test/__pycache__/test_protocols.cpython-36.pyc,,
twisted/test/__pycache__/test_randbytes.cpython-36.pyc,,
twisted/test/__pycache__/test_rebuild.cpython-36.pyc,,
twisted/test/__pycache__/test_reflect.cpython-36.pyc,,
twisted/test/__pycache__/test_roots.cpython-36.pyc,,
twisted/test/__pycache__/test_shortcut.cpython-36.pyc,,
twisted/test/__pycache__/test_sip.cpython-36.pyc,,
twisted/test/__pycache__/test_sob.cpython-36.pyc,,
twisted/test/__pycache__/test_socks.cpython-36.pyc,,
twisted/test/__pycache__/test_ssl.cpython-36.pyc,,
twisted/test/__pycache__/test_sslverify.cpython-36.pyc,,
twisted/test/__pycache__/test_stateful.cpython-36.pyc,,
twisted/test/__pycache__/test_stdio.cpython-36.pyc,,
twisted/test/__pycache__/test_strerror.cpython-36.pyc,,
twisted/test/__pycache__/test_strports.cpython-36.pyc,,
twisted/test/__pycache__/test_task.cpython-36.pyc,,
twisted/test/__pycache__/test_tcp.cpython-36.pyc,,
twisted/test/__pycache__/test_tcp_internals.cpython-36.pyc,,
twisted/test/__pycache__/test_text.cpython-36.pyc,,
twisted/test/__pycache__/test_threadable.cpython-36.pyc,,
twisted/test/__pycache__/test_threadpool.cpython-36.pyc,,
twisted/test/__pycache__/test_threads.cpython-36.pyc,,
twisted/test/__pycache__/test_tpfile.cpython-36.pyc,,
twisted/test/__pycache__/test_twistd.cpython-36.pyc,,
twisted/test/__pycache__/test_twisted.cpython-36.pyc,,
twisted/test/__pycache__/test_udp.cpython-36.pyc,,
twisted/test/__pycache__/test_unix.cpython-36.pyc,,
twisted/test/__pycache__/test_usage.cpython-36.pyc,,
twisted/test/__pycache__/testutils.cpython-36.pyc,,
twisted/test/cert.pem.no_trailing_newline,sha256=zo_jqLPMFx4ihV8QxkdwD-_wT9WIC-zRDZcH23okXgk,1414
twisted/test/crash_test_dummy.py,sha256=e_KrrGBFmaXSLCLxq59VklPym1tY8UvzcCqZ-6xHzWU,543
twisted/test/iosim.py,sha256=HTAEcEPxQePmaPoMqBKBs4nS_J062aEyyKvOKax44II,17843
twisted/test/key.pem.no_trailing_newline,sha256=6ChUJWC8C3KXcoX1BBidlFOglMqHtYS-ul9cr6UMiHk,1707
twisted/test/mock_win32process.py,sha256=EeeQqdYC2ka1pqW10xDOblWBBuYGuIZc4OSIBRY9Czk,1499
twisted/test/myrebuilder1.py,sha256=IIZN_g1GPNIFVon6tbvPJmIHId7okkkY6P3QWQxKc1E,158
twisted/test/myrebuilder2.py,sha256=jCXJikyxA9P65EeQBypSXO5EPvPJ6tFhSfG2tuleLQI,158
twisted/test/plugin_basic.py,sha256=8xNGvfT0iGqQJoQlXNgV5MZBPh7kckLiCa75WOLPmZY,943
twisted/test/plugin_extra1.py,sha256=OfoMucKmCvgMRHL3YLhwU_Xi2CL4f862-44Au-SHe7c,407
twisted/test/plugin_extra2.py,sha256=EznTfuePvwBnCDi6eeth5bbUe41eS-LjLYmy516ynRU,579
twisted/test/process_cmdline.py,sha256=BimXPJAOrI7p6yeI__pflO_Jalk5y6tlgr-n2zgkaDo,162
twisted/test/process_echoer.py,sha256=USXd05oAkfmRKITVYXjpQ9lFouVEQbyA_a9mudWELpU,214
twisted/test/process_fds.py,sha256=id3GJEGB_uv9AmOPIC-yGvLehIRQDKrTEn5UDq_VSx4,945
twisted/test/process_getargv.py,sha256=WYk6DVL_Zviy160-eNWq263-i4nXAJpezsjpxBbDpUE,283
twisted/test/process_getenv.py,sha256=3micUPcws3OHsrbz6FvudJmAULuL7QxZQaPQL3yBddA,268
twisted/test/process_linger.py,sha256=g151drgjRfbI61dKYG0KYi8F8HxXRE3muWxBuzGVp4Q,286
twisted/test/process_reader.py,sha256=UbbRXJzTl8c6e_lGvFFlGsobtZUxkZovHPTUbfowDjg,188
twisted/test/process_signal.py,sha256=3HFQ8y72n9abUQHG0m_VuHddGePPgmZbjbCkkIbCpVc,214
twisted/test/process_stdinreader.py,sha256=2SQ9WN-X_qZPBc65dUBWEHVl1TtK_vOTKGzfbMwaRa4,857
twisted/test/process_tester.py,sha256=ahvvBnJv2a0z2X4FRXRkiYVrtgaWlotD2OaHHzAgR5I,1035
twisted/test/process_tty.py,sha256=hLLXgrwy_SF-dq2_moeGQSnpRJwyjgVMW7_z9ejXXvQ,130
twisted/test/process_twisted.py,sha256=MwDbDERsvFxRFkkuL48g-VJPVkUqI6GKl4skYpy14hg,1206
twisted/test/proto_helpers.py,sha256=O8Nwlhyg-0o7YmWyGk_0acecBlfbDAYjgXA3IB9CeAs,1009
twisted/test/raiser.cpython-36m-x86_64-linux-gnu.so,sha256=kLerOiQ3s3gyR_0He4TwA10Et2QImqI--T0CLU4r9OU,99619
twisted/test/reflect_helper_IE.py,sha256=D7N7dob70tx6BCuf2mTOVON-9iclUwWtKUTfvsU3F3M,61
twisted/test/reflect_helper_VE.py,sha256=VLu_9ughD3FOfYWMKw6N521vzp6YErR-d5IGnvVINzk,82
twisted/test/reflect_helper_ZDE.py,sha256=6eJjOrxytcz6G1a-NT3rz5fpIyof7ejuk4ZqxkXTAR0,47
twisted/test/server.pem,sha256=bAB7jzd2KxoBpd5VYhzgdmuPDKH9_XV_su2nNq6-xlI,4444
twisted/test/ssl_helpers.py,sha256=ZXyuxzyOz3eoedcTplun835Gru7UI1hj_tsZGGjHH5w,1032
twisted/test/stdio_test_consumer.py,sha256=UcpBNu9jRBjjplwDMFBvISaKV1G-MoZGpmdEN3y-AB0,1216
twisted/test/stdio_test_halfclose.py,sha256=1ULDASakPelEWZTmTEiGP_2yoqADEh_uO3NAtvf9f3w,1938
twisted/test/stdio_test_hostpeer.py,sha256=S4iym1eUrhSTI9q0_NyNFsU2vOt73kM80wQXAZPYiKc,1021
twisted/test/stdio_test_lastwrite.py,sha256=ja24d-ofVHcBwS-zQfZhepBu2DEMY10ESGNOc7NPiG0,1206
twisted/test/stdio_test_loseconn.py,sha256=4MuY6FhUQjVUOxJ-Da_oz87uAESTA2eqpOFjz36PbY8,1548
twisted/test/stdio_test_producer.py,sha256=OChDgtN-lKe4wv5afQiUngvvzJN-5ovdkNwDfsSooEQ,1507
twisted/test/stdio_test_write.py,sha256=ZzHl8uDvAuN987XKwHeU7huFJeUhkH2m7llj0_lb1TM,923
twisted/test/stdio_test_writeseq.py,sha256=KjDrpNrGdy6Ao66bUHuRlxk4r1hUxbf9z-q_YQPrrJQ,915
twisted/test/test_abstract.py,sha256=u1sJ3MqObQNQirOIL9KBdEK5GmHY-hfoX9MaaNbG7JQ,3497
twisted/test/test_adbapi.py,sha256=YZY7rTrIeImJlW852LbG19mMR_gPHq0gJyOCqBhh618,26148
twisted/test/test_amp.py,sha256=YsKFvd1aaugyD_lBDG0w6IPnDCKDjtcNPFO7YNmNBck,110553
twisted/test/test_application.py,sha256=vjgnjo4Q-IQ8NPZT8DH_hgyT2m0nrniw4nLEMpe4DOI,34210
twisted/test/test_compat.py,sha256=GKXSsM1F11qkVT0pPM6CPfVc1fugOMCUSB9EuBG0PJk,28527
twisted/test/test_context.py,sha256=zsV4fhj0VCrTLbzhjOdcr2gxG3kAOYCOwRjUvIs1ap4,1515
twisted/test/test_cooperator.py,sha256=vW_NFZ5arXXHquIBUeBwqUqb8cpLUP6ftFoDi6G-EXQ,21467
twisted/test/test_defer.py,sha256=3mNCERZAqGEP63g3dlCzJ4RGc-A2bD48zRaIM6_uyi8,104143
twisted/test/test_defer.py.3only,sha256=VUYRAxF1fFS6HBFPEmgQJF5cbF0T7hXMyuZI6ZOXqLM,2500
twisted/test/test_defgen.py,sha256=FcjjeYL5N9BbAnSf0rgTD36dN-zKTq2SR3pTKfBlBr0,10701
twisted/test/test_dict.py,sha256=GCmGM7c6XlVwIsQpkPJxeAW_Nyjy_kR2C6TsqXVruCU,1442
twisted/test/test_dirdbm.py,sha256=cPN4kXEgtG20KChbnVDwGfrRUCEiuvp8fSxY8UfBTM4,6695
twisted/test/test_error.py,sha256=3qPMbLZfUo_qvJx3E0m6mbXx-DYE_uP9mhkapMDix8g,8593
twisted/test/test_factories.py,sha256=i_dbiMVIhvx7f47BQK9I_Y8vdloV-9k33-0h2iX3uQ8,4637
twisted/test/test_failure.py,sha256=5G91yYuoSJ4-pwQlPTQIF3yMowcr7XFKFmSGA1vN09Q,32814
twisted/test/test_fdesc.py,sha256=DDqHNCrc5Q_gnDLyqGKI_ReNFjR1Qv79GQLjaWysIO0,7371
twisted/test/test_finger.py,sha256=lE5o_NacakzRCt5yYkCh-z_SktcXwK4FXhI5GXg9E0s,1997
twisted/test/test_formmethod.py,sha256=9aSzdUJSAzdrUhYGe-cf7nvDPU1L3JZCDIpYlSlrjjA,3645
twisted/test/test_ftp.py,sha256=Dmre2zNP4odYzKmK6KPzutLsv3T8zVS40eKmBkXvA80,130321
twisted/test/test_ftp_options.py,sha256=eGD8-ot2TGhcMTeP79EGhpmo-HfxmH3by_KzopdHNDw,2685
twisted/test/test_htb.py,sha256=nT0xU1fTt5TawiOd53Q7mQOkbSybNXa5Hdud74KO-bs,3190
twisted/test/test_ident.py,sha256=27hHDLdWQjZj_3511PpJ9jk-GKK8gRUOtmCzRLNMspw,7015
twisted/test/test_internet.py,sha256=WBPCf4NPaNWtDB9fIJ6Efwlel8QIn5DDC4BeBc2k3D0,46803
twisted/test/test_iosim.py,sha256=ZaDyIAoVKKjmmpZCugfrT6sKp0lVcgIrfGxqjvpqHL8,9060
twisted/test/test_iutils.py,sha256=Kv3t0iIi9u9fgzluaU2SVxVPGCQbcp3gwQfpkai0Spk,14384
twisted/test/test_lockfile.py,sha256=PsCJl1pA0K-aA-SIwW_i7VyN-43xTfxtmcmkPqDNQ3k,15506
twisted/test/test_log.py,sha256=0rlzX1ua_ZSqfDNsHc2tih12QZxsodgG4Ht4ELNpLzQ,36330
twisted/test/test_logfile.py,sha256=MPFH14kANpfxPbokwn9sZU4bK984kR6D1anoFJy_r58,18227
twisted/test/test_loopback.py,sha256=PTSDXS5TFz6L1GEkdXLWBHRrp3CJ0ds2WDodMrLWtLE,14486
twisted/test/test_main.py,sha256=F3x8NqO0CxZvfnmm6H2-x5Z4UsLH0htWUe0nwO_v4Qk,2501
twisted/test/test_memcache.py,sha256=lTdDfwGIOUIYv3nWC4TOpuY2oZ8D3--d6Z78a-5Spb4,25143
twisted/test/test_modules.py,sha256=VWkroMXc5duBPTOTtJnHgJDFSHUBmK2TfaJwvfa7w88,17888
twisted/test/test_monkey.py,sha256=D37NHborDX663mPE3vnYQP2OA8Ey37YDpuHCuXu4Gu4,5637
twisted/test/test_nooldstyle.py,sha256=hwfH8G2l4KJrHqUCmH__iUjhoFW34aGVy_WOE2iXi5g,5955
twisted/test/test_paths.py,sha256=j_0l5igUqehcYqvFfBG9KU0ZZlQKnho36ysoBNHxv64,74357
twisted/test/test_pcp.py,sha256=k13lppisnl5WYCS5BD-kAbyUzM1CZBLxbQ0rG_S3a-M,12551
twisted/test/test_persisted.py,sha256=KHfsZlx2feaihD0Ja5KBq_-h56CQ2ilxWDQ32xq-JnA,14624
twisted/test/test_plugin.py,sha256=r20OZv-hMr9DjMyk9tJxDykMV_g1seLgyDfp3eVz6Ww,26113
twisted/test/test_policies.py,sha256=KtUlbJZRqmqOpQT4E20PHb3V_6gvBa45DzkFZEr3Hck,33499
twisted/test/test_postfix.py,sha256=CrDVuSkr18QQDVhJ5lCCy07Fy6RQjOaMffUKmno0nZM,4243
twisted/test/test_process.py,sha256=Y5ntI0AwGXEsxuiViOB8bdVIyyFLUO3Efw3O9fs4vJk,86120
twisted/test/test_protocols.py,sha256=ZIk1-7OhE-04Oytmr9-ScYWBi_PrsBDh-aUFiiUYqgY,7450
twisted/test/test_randbytes.py,sha256=MkUMH7zYTdJ4Ln8J9VJDLueHFcZ4HR1Qz2aNPVFHKnw,3357
twisted/test/test_rebuild.py,sha256=iscBE4IMkfOmEGkHlyjCZC8ioXjnwNi5kQwmf19eduk,8495
twisted/test/test_reflect.py,sha256=riIAjcwwIq4ZeM4rGZIaxuDFLkrKtqr315-xM-j7ANw,26085
twisted/test/test_roots.py,sha256=4TzR1qugGrfLdjwO34KO0SAweOxOMHqkJtMwkWtbmm4,1812
twisted/test/test_shortcut.py,sha256=NkA5ho-Rvhhu9Dj_JD5N6VZS4lzNWHInPe2J4Clv-L4,1991
twisted/test/test_sip.py,sha256=wFVIuH_XqHAGlenbvtswDjBFZpo3E4RnIRAxEel_AEI,25284
twisted/test/test_sob.py,sha256=ttrn_p7OpR2ikvTm8oNxgxrxnQ4xMdT7YdIc02egl58,5632
twisted/test/test_socks.py,sha256=ImzFJie1KZesqrTM1LyhhCSD_WLXB-_eRrWWpAzw31c,17738
twisted/test/test_ssl.py,sha256=kqOXu-IGJKW4HuCSdTs4U2rORO-P4SrGBby5stQfmOE,22923
twisted/test/test_sslverify.py,sha256=iAjE3Zo6FKDhCaRE_PiyIFwVOGbAJ58ZAQcvsSisAJY,116121
twisted/test/test_stateful.py,sha256=-X78ROUUyb5c6-jzJ4DIi_NYf0t8xmLegEOSqrQSxnE,2021
twisted/test/test_stdio.py,sha256=M7agWsEf2cC2tpHrtqXEVn9jQXIqYYzYEW2eQ5RoB5U,13156
twisted/test/test_strerror.py,sha256=4lT14E-7oGKDHpsAoJ4Es6WDPa9h6fK3FS92B51w3s8,5183
twisted/test/test_strports.py,sha256=oM-EGX3x5WWQIMTXYWUy7fgscvVuhoaoKdxCqHTgSLE,1797
twisted/test/test_task.py,sha256=-7MgKjHCcIclp6DmwOegRo-C5Ury2lF4i3W5xBJRbLA,39683
twisted/test/test_tcp.py,sha256=ywEI3OaF7iJfY4l7eA6ZYBuem-TIegIiF1yEg8Bpuak,66192
twisted/test/test_tcp_internals.py,sha256=DCBr5-a2W12EvX9gWBlf8vIGc8YEizQ1Uodcdu5tfqk,13255
twisted/test/test_text.py,sha256=ZDBTmtLnIGkYwL08uX0MJ4Xq-B1oPgt8rAzO1_FT62o,6456
twisted/test/test_threadable.py,sha256=85oUaY3J3Cg7Y-uvm6Wk4f5cQ-RhYi5SCLIbS8fb7ZQ,3738
twisted/test/test_threadpool.py,sha256=1qoaUY1zYLmeW4M0ZRRNfvzH0CUwAkdPjQ-5L_Q0lEk,22204
twisted/test/test_threads.py,sha256=bLzBn98GjVgBCylKpps1oLFwpJKaGV9Q_79_6jDT_uc,13268
twisted/test/test_tpfile.py,sha256=f3apHS3fbcoNspvqJ4d3Tljtv44lHU3FcWgJIoyy4Gk,1601
twisted/test/test_twistd.py,sha256=BYTWg5qB6NVwGjIkM6qWUd54U6pj308SVQPfAA1Pw_Y,74201
twisted/test/test_twisted.py,sha256=JFiWXtkK0Si6NLrh1i3iLLplxie2_zZNb6DHB-tmAjo,9214
twisted/test/test_udp.py,sha256=K6uHGFmp7pLUpIjmfjNNFtyiFQmNHyO6XVVO783b3zU,24992
twisted/test/test_unix.py,sha256=sxRkpz0NzS98bXy1ZlfN_p3J2GRk2BbLg8aGGLv5vnM,15157
twisted/test/test_usage.py,sha256=E3vSRYqzzUbjWg3CZW4bFYAK8eoAtiuUGdb9jJH9JeY,23645
twisted/test/testutils.py,sha256=VWozf8WzYsiwRA8LCR7jIaLyi9x0dE2HOHJaJQTmtwc,5321
twisted/trial/__init__.py,sha256=2ib2sy-amXD8irsLolFFjjeNur8BnaXwBWaOCASmsFU,2040
twisted/trial/__main__.py,sha256=noqg0SgiYqvgjWVTPJCyrxZDdpR-l1p666wuE4a5388,249
twisted/trial/__pycache__/__init__.cpython-36.pyc,,
twisted/trial/__pycache__/__main__.cpython-36.pyc,,
twisted/trial/__pycache__/_asyncrunner.cpython-36.pyc,,
twisted/trial/__pycache__/_asynctest.cpython-36.pyc,,
twisted/trial/__pycache__/_synctest.cpython-36.pyc,,
twisted/trial/__pycache__/itrial.cpython-36.pyc,,
twisted/trial/__pycache__/reporter.cpython-36.pyc,,
twisted/trial/__pycache__/runner.cpython-36.pyc,,
twisted/trial/__pycache__/unittest.cpython-36.pyc,,
twisted/trial/__pycache__/util.cpython-36.pyc,,
twisted/trial/_asyncrunner.py,sha256=oNL10LsWsYgfPDZhAzO9Hes-yKZa17M6PF-JyAFamuw,4530
twisted/trial/_asynctest.py,sha256=qUGroPSQz4SPywueE4vxXnk8JtkbwopGFqA6D1J9-UA,14634
twisted/trial/_dist/__init__.py,sha256=0v2hhp_DnNSlYu4-6rS6SzWwFTqcl_1DCqPrWxKdEXc,1941
twisted/trial/_dist/__pycache__/__init__.cpython-36.pyc,,
twisted/trial/_dist/__pycache__/distreporter.cpython-36.pyc,,
twisted/trial/_dist/__pycache__/disttrial.cpython-36.pyc,,
twisted/trial/_dist/__pycache__/managercommands.cpython-36.pyc,,
twisted/trial/_dist/__pycache__/options.cpython-36.pyc,,
twisted/trial/_dist/__pycache__/worker.cpython-36.pyc,,
twisted/trial/_dist/__pycache__/workercommands.cpython-36.pyc,,
twisted/trial/_dist/__pycache__/workerreporter.cpython-36.pyc,,
twisted/trial/_dist/__pycache__/workertrial.cpython-36.pyc,,
twisted/trial/_dist/distreporter.py,sha256=4oiCkv6AZOIfBfZt8qDKyKSERZtx5S7r9AA170DAeYU,2495
twisted/trial/_dist/disttrial.py,sha256=T-QHOl0r5MztVjVBbfCyGtERQQs1ixeLqkYjOvtSXEM,8711
twisted/trial/_dist/managercommands.py,sha256=FDoWQMJXMu1UIzYseCtS4t2A7yKyZFfEM_Zc3U9qs7E,1897
twisted/trial/_dist/options.py,sha256=7GLbC2y5zGM3IwimCBg7H26AOlwiPb2dkoebWQFezzE,739
twisted/trial/_dist/test/__init__.py,sha256=IOS3XedcenVmIEF2Dn-7IhLiGyeN1IG33V51Pk_iS7o,118
twisted/trial/_dist/test/__pycache__/__init__.cpython-36.pyc,,
twisted/trial/_dist/test/__pycache__/test_distreporter.cpython-36.pyc,,
twisted/trial/_dist/test/__pycache__/test_disttrial.cpython-36.pyc,,
twisted/trial/_dist/test/__pycache__/test_options.cpython-36.pyc,,
twisted/trial/_dist/test/__pycache__/test_worker.cpython-36.pyc,,
twisted/trial/_dist/test/__pycache__/test_workerreporter.cpython-36.pyc,,
twisted/trial/_dist/test/__pycache__/test_workertrial.cpython-36.pyc,,
twisted/trial/_dist/test/test_distreporter.py,sha256=wrXX0UllZZRgCAArA8gdKHipm9JLi0cFMzdgk_pn2DU,2051
twisted/trial/_dist/test/test_disttrial.py,sha256=aJ7-xg5Ew1uwyoFq5F0T_YMK5u-JfZfbdAdYGJE3a9M,16757
twisted/trial/_dist/test/test_options.py,sha256=8cMl8nKBeXvnfuRDwL6oTluwnbtJ3GR9HZl45YEiAyA,1312
twisted/trial/_dist/test/test_worker.py,sha256=Lu4I8xl0i3kgyrpBTinEAgxrpDBX43vRF9otsDrZH4c,14784
twisted/trial/_dist/test/test_workerreporter.py,sha256=lNGGrJoiWsu58wVMAY9lF6twFISQgMyoRh60HT9ww80,5390
twisted/trial/_dist/test/test_workertrial.py,sha256=StZMQYWknt0nVg2F4KaJ9ZPUNFX-JVh0-5uF6d1kHB0,5014
twisted/trial/_dist/worker.py,sha256=uuzghTilXOwfiNHjKkgYUppJNkqzo4_VBEqwKNIXkR8,9153
twisted/trial/_dist/workercommands.py,sha256=GerNCLGPNP8asXy22Cl8qAKQYJ9sKiXDo729Lc1AbbE,641
twisted/trial/_dist/workerreporter.py,sha256=ysGwtY-e6c_sSTR3IGhy7f8kqgqOQI46EnJysD2LJxk,4856
twisted/trial/_dist/workertrial.py,sha256=BQDJ2KHnHQ6MtPwOq_pU428h2zvT7k-JYVnsc1Z62VY,2859
twisted/trial/_synctest.py,sha256=HgxTQKu4jMXjUjJyC48yNX7LVw4f8nEynMi3VyDdGtk,50017
twisted/trial/itrial.py,sha256=EmbbuIA4WItHcgQKEOGhfORSTxTuWX-DrRezBrcbj9k,6857
twisted/trial/reporter.py,sha256=peShSfUXXNGxHTQyxY-1WXuTEAaEhaWrUqRDh0YaPxI,40105
twisted/trial/runner.py,sha256=mzT5AVFYlBL97jCK8CjJLZjKor9zysNV-yff7bLX7OQ,36720
twisted/trial/test/__init__.py,sha256=uWFvjebi50_v57TkFDrFhvUS5oUq8Jo5y_vRBvpP9o4,130
twisted/trial/test/__pycache__/__init__.cpython-36.pyc,,
twisted/trial/test/__pycache__/detests.cpython-36.pyc,,
twisted/trial/test/__pycache__/erroneous.cpython-36.pyc,,
twisted/trial/test/__pycache__/mockcustomsuite.cpython-36.pyc,,
twisted/trial/test/__pycache__/mockcustomsuite2.cpython-36.pyc,,
twisted/trial/test/__pycache__/mockcustomsuite3.cpython-36.pyc,,
twisted/trial/test/__pycache__/mockdoctest.cpython-36.pyc,,
twisted/trial/test/__pycache__/moduleself.cpython-36.pyc,,
twisted/trial/test/__pycache__/moduletest.cpython-36.pyc,,
twisted/trial/test/__pycache__/novars.cpython-36.pyc,,
twisted/trial/test/__pycache__/ordertests.cpython-36.pyc,,
twisted/trial/test/__pycache__/packages.cpython-36.pyc,,
twisted/trial/test/__pycache__/sample.cpython-36.pyc,,
twisted/trial/test/__pycache__/scripttest.cpython-36.pyc,,
twisted/trial/test/__pycache__/skipping.cpython-36.pyc,,
twisted/trial/test/__pycache__/suppression.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_assertions.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_asyncassertions.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_deferred.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_doctest.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_keyboard.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_loader.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_log.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_output.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_plugins.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_pyunitcompat.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_reporter.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_runner.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_script.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_suppression.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_testcase.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_tests.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_util.cpython-36.pyc,,
twisted/trial/test/__pycache__/test_warning.cpython-36.pyc,,
twisted/trial/test/__pycache__/weird.cpython-36.pyc,,
twisted/trial/test/detests.py,sha256=7uYBWdLD-Slpq6cXrgtdJyalwCvAZzhJGL0KX2jhbUA,5368
twisted/trial/test/erroneous.py,sha256=fM-kSxh_M7QfB0Oc9bIIQDX-r_29ZdJIrabqUqjxZhc,4829
twisted/trial/test/mockcustomsuite.py,sha256=pNEnsIgTTx-fp2hYS4GxkAenBER6uPot11VbkDzqQgM,535
twisted/trial/test/mockcustomsuite2.py,sha256=GPSbV-Ou5XCACyVF_DgD2SXDH3Ekvzab9rQiC0roUuQ,532
twisted/trial/test/mockcustomsuite3.py,sha256=zc_roFFRqTPwVGto3VL7_Ic15nGm4WvCEG-w5rHiYlw,675
twisted/trial/test/mockdoctest.py,sha256=f89ND666XnQnUuvIyR4begtzQWM_mBxzRWs5F9AeWvE,2645
twisted/trial/test/moduleself.py,sha256=UWx4cOBRU6OlGdjfjgEgNQPpfbp-biul5WCAtI30GD4,170
twisted/trial/test/moduletest.py,sha256=Yx-H7C4qwBgzKFkp1B_JYyq2D8CCiSEpE9qS2jwfD7A,310
twisted/trial/test/novars.py,sha256=asKIwzyfBjiDqHi8zeTzcHHdLYGBk1JQf1QvbZl25zc,189
twisted/trial/test/ordertests.py,sha256=ZZm2zhvHrEtN7hVXH49vVTOB7dEsXfuargd_8M1d0wM,867
twisted/trial/test/packages.py,sha256=lnN006Agb_-kEkNrKGus38S-ePaIl4JT8azwJFhTGRg,4927
twisted/trial/test/sample.py,sha256=nWBJwh0ZAu3tpLhV8N5RoNUI7HUQQWrkLIbVHrDDGbk,2155
twisted/trial/test/scripttest.py,sha256=1wey0lWic-hQv_NZ4YR6BS-GHFqcJaxf8CHGitkdosY,466
twisted/trial/test/skipping.py,sha256=y1Pkj2IMNGfVdrtwBEkPzRWh_zBia3srnkHySEbszPg,5356
twisted/trial/test/suppression.py,sha256=rHQuaV53Au_YXyYw0zZC4UToHp-o5_uQUB_vbmiS9GI,2497
twisted/trial/test/test_assertions.py,sha256=rIbGSAeiouJh_20HJZUib8D4u-wHN8rIVnUXIyFZYvI,46630
twisted/trial/test/test_asyncassertions.py,sha256=f-OE4xvhJ9jZmVUd74azvoUKgYcUW-BLHwRbYjIcCB8,2571
twisted/trial/test/test_deferred.py,sha256=d-iLD-GqYvAq2IvFUhmr8eVtOwGeP4X9bFg_BoqMAeY,8889
twisted/trial/test/test_doctest.py,sha256=p5fpDtW76E461ltTr5vrrz0V3Gas5nGz7lUypOvi90U,1766
twisted/trial/test/test_keyboard.py,sha256=Zc3E7yyNElQ9bI2E8wlsRj_1V5jOXFv_ylTi3FW9db8,4036
twisted/trial/test/test_loader.py,sha256=b6r0-_40GUTMZ2svo58Q_NBMXkxY3HmE5ffBb2mp4n8,26783
twisted/trial/test/test_log.py,sha256=4KbBgmQwI7IjFnZ8W8ZNdtb5RcSLoPGov7QL2Znxjmw,7969
twisted/trial/test/test_output.py,sha256=zQ94RkuSX1FOLTxlt7VqSAueSWmvpsYrGIHeTDINo8M,5299
twisted/trial/test/test_plugins.py,sha256=9KUuBPPm05bO1a7RxQP6fMRDr23S7_FKf81ssYL3GHo,1451
twisted/trial/test/test_pyunitcompat.py,sha256=HkGUKXAp9hfYOqjPY_DVWBvxpTVm-QC2qPAZXJHfUII,7670
twisted/trial/test/test_reporter.py,sha256=3vFYKFQSF5g_Gf21MN99PNiUAUdE9Xwq5-Wxp86Lpzw,57428
twisted/trial/test/test_runner.py,sha256=pRK1B-bIjTn9pCu2gSte_IVP_3i0OMitwasxQYBuptQ,34074
twisted/trial/test/test_script.py,sha256=YaO9q-4fH_9T6yhSTeEm0ciGv5ivM1DBdAlIDWa9U3I,29717
twisted/trial/test/test_suppression.py,sha256=vw8R3i_EaZgtdcGNxrzSbVI7gvLVm2baHh348g_yVvc,6089
twisted/trial/test/test_testcase.py,sha256=f2xpFykUxZoW8T5HzSiw7dc0pqOAh5ZswK4u1eC9ZOw,2043
twisted/trial/test/test_tests.py,sha256=koXRAKkmWDMXElmy87uPQCuIspyeYr4VeO4dbf1XPpc,50030
twisted/trial/test/test_util.py,sha256=faNL8ZBaOR83bcNQV7x7pNtXUofSSvj8h9gbq1m6o0s,24709
twisted/trial/test/test_warning.py,sha256=aZZSrMvdCvAf_EALAvTSBpQozfSpef_5GyelC7qpCgk,16770
twisted/trial/test/weird.py,sha256=apD_gjh7qeK_gEi9r3WErMHYvPuf0PIk_BoJZNAbvCA,721
twisted/trial/unittest.py,sha256=JQAudPGd--a9KNzsaGRCnzbQ2H_JzMSQFC-nMVJ4Xng,978
twisted/trial/util.py,sha256=FjW69s1ttgn3MHUXkv7HmhK2JXzceiE0BgTiAQnNgHw,13410
twisted/web/__init__.py,sha256=XDcQGn3KmRxndOIDTJZcSWGhxPALqHLMxbzsRhqsra4,384
twisted/web/__pycache__/__init__.cpython-36.pyc,,
twisted/web/__pycache__/_element.cpython-36.pyc,,
twisted/web/__pycache__/_flatten.cpython-36.pyc,,
twisted/web/__pycache__/_http2.cpython-36.pyc,,
twisted/web/__pycache__/_newclient.cpython-36.pyc,,
twisted/web/__pycache__/_responses.cpython-36.pyc,,
twisted/web/__pycache__/_stan.cpython-36.pyc,,
twisted/web/__pycache__/client.cpython-36.pyc,,
twisted/web/__pycache__/demo.cpython-36.pyc,,
twisted/web/__pycache__/distrib.cpython-36.pyc,,
twisted/web/__pycache__/domhelpers.cpython-36.pyc,,
twisted/web/__pycache__/error.cpython-36.pyc,,
twisted/web/__pycache__/guard.cpython-36.pyc,,
twisted/web/__pycache__/html.cpython-36.pyc,,
twisted/web/__pycache__/http.cpython-36.pyc,,
twisted/web/__pycache__/http_headers.cpython-36.pyc,,
twisted/web/__pycache__/iweb.cpython-36.pyc,,
twisted/web/__pycache__/microdom.cpython-36.pyc,,
twisted/web/__pycache__/proxy.cpython-36.pyc,,
twisted/web/__pycache__/resource.cpython-36.pyc,,
twisted/web/__pycache__/rewrite.cpython-36.pyc,,
twisted/web/__pycache__/script.cpython-36.pyc,,
twisted/web/__pycache__/server.cpython-36.pyc,,
twisted/web/__pycache__/static.cpython-36.pyc,,
twisted/web/__pycache__/sux.cpython-36.pyc,,
twisted/web/__pycache__/tap.cpython-36.pyc,,
twisted/web/__pycache__/template.cpython-36.pyc,,
twisted/web/__pycache__/twcgi.cpython-36.pyc,,
twisted/web/__pycache__/util.cpython-36.pyc,,
twisted/web/__pycache__/vhost.cpython-36.pyc,,
twisted/web/__pycache__/wsgi.cpython-36.pyc,,
twisted/web/__pycache__/xmlrpc.cpython-36.pyc,,
twisted/web/_auth/__init__.py,sha256=GD_euhqqSJj1fv_srRt5Yl5RfcExpzifR-PYLNTKIwI,190
twisted/web/_auth/__pycache__/__init__.cpython-36.pyc,,
twisted/web/_auth/__pycache__/basic.cpython-36.pyc,,
twisted/web/_auth/__pycache__/digest.cpython-36.pyc,,
twisted/web/_auth/__pycache__/wrapper.cpython-36.pyc,,
twisted/web/_auth/basic.py,sha256=S3KTEXHVdz8EFnrR3Un3kulhOO_kOUitt0D1cleHIzg,1689
twisted/web/_auth/digest.py,sha256=Cr3akmx_l73w-yZxUqB3CcF1DFNc9R41Ibpw63MIfHc,1770
twisted/web/_auth/wrapper.py,sha256=QjwuVhM9rwMcxiV1oF8u9YmH7YEy3EPC4BfzGsQy4U8,8566
twisted/web/_element.py,sha256=7vBEF4yTwCUsmeAsBCjSwYbutvNrLS4Bp-9PA0ae7mU,5947
twisted/web/_flatten.py,sha256=obSfnAN4wJ0n3DK_e1fxlj5qiVc_CwLkyMFKAI0QzdI,15912
twisted/web/_http2.py,sha256=mlomwH5LyFPIl3wZ1GE60BtIAx1mls-x54wagPni5AA,45545
twisted/web/_newclient.py,sha256=bsD00poQNKPGLeFY0pXkxZ1yaDV20Xe9sH5oc0x-KAg,63973
twisted/web/_responses.py,sha256=IuFI3g88Klz01-6AGus3FDu4ifFiSZcGpH_7xQFKv8U,3655
twisted/web/_stan.py,sha256=hr8FW8_qo-wFShnq3iGUmALNVew2k0is5YbRnuXliJ4,10790
twisted/web/client.py,sha256=wf2N3Rzn4lZ_lLc-DPc-euuiI0O7l35e1QxO2eeJLOg,76971
twisted/web/demo.py,sha256=g3JC8qhso0-sYmmRVjT_di_F2_-J09kdsM9Z5kH7u3g,554
twisted/web/distrib.py,sha256=ky8W3tDRSsVXmarhx3z7Ys9oKmho0UtNIKd0gv72LVE,11881
twisted/web/domhelpers.py,sha256=JJor6qQbzybg-D9rVX-9Q3vTvJZUDNbzp9HyaACvPc0,8645
twisted/web/error.py,sha256=z_QFN-l4gy370GEWXuue3MIliddbNa1VXroIRcfsfHA,12537
twisted/web/guard.py,sha256=2vGjNL9ZxbPxHZWuqXwJ1UFXGHfFgAxdD7kQ90I0OqU,630
twisted/web/html.py,sha256=7uKIiee9Sg6vKlV5juUTHoTSwLPVa6jXLSKTOkg6SKs,1557
twisted/web/http.py,sha256=xTllJJrr8PWDEmyvpkBNSVqsdrZo_ovErRz4fG8tEAc,104055
twisted/web/http_headers.py,sha256=L9yz-tM4HUP_xDU7fqvnNIuiEzj6yYRp6O766HDsYLA,8853
twisted/web/iweb.py,sha256=KYQqCnUp6ebvwa5BNCogYjKpdrY2p7_flVDbCa8A9rE,26778
twisted/web/microdom.py,sha256=a-LdI_UIIXFLMfFdHDVKYnAM8vTEfKhSkPAqeK_PC34,36197
twisted/web/proxy.py,sha256=u_LqSCDNuFKjs_K85LNzimWcsxrvtRuMe5ZHs3QO6lU,9837
twisted/web/resource.py,sha256=kpKqmCAWKXwNvokIGYM2pCCWM4AevSOgklRX20Oy3-8,13610
twisted/web/rewrite.py,sha256=ezcoNJcAy-ET1WmS2UF3JzTNhhNR1bGoyDK0dl_q9Fg,1852
twisted/web/script.py,sha256=pIQ-kiryhNxUjZlJUQyd2knXWjdzO_VZFm8-weXDIh0,5745
twisted/web/server.py,sha256=eDdTtMBs2fANGFR0oL5UWJLLrdRdClpIdAUJ0kbw0ic,28329
twisted/web/static.py,sha256=3iCMORPZXIwcujH1D4lwU7R-vISY-2RbBqUiC11vNHc,38007
twisted/web/sux.py,sha256=ue2_D9mzOOOPpPvJNTL-31jWbnAgsG-EimiuAIJQx2Q,20892
twisted/web/tap.py,sha256=nMnaXPp8dEHhOLDj_L6ogXyulXR387_-3hMVucoX5Vg,10331
twisted/web/template.py,sha256=IZMkl-eBtxot8sFb96C2xHBXMcHwwgvjE8egjy30pKo,17631
twisted/web/test/__init__.py,sha256=fUhYepItGqSYT0CsZLxIbU9lDRjUkJ0pGsdsr8GRp0c,108
twisted/web/test/__pycache__/__init__.cpython-36.pyc,,
twisted/web/test/__pycache__/_util.cpython-36.pyc,,
twisted/web/test/__pycache__/injectionhelpers.cpython-36.pyc,,
twisted/web/test/__pycache__/requesthelper.cpython-36.pyc,,
twisted/web/test/__pycache__/test_agent.cpython-36.pyc,,
twisted/web/test/__pycache__/test_cgi.cpython-36.pyc,,
twisted/web/test/__pycache__/test_client.cpython-36.pyc,,
twisted/web/test/__pycache__/test_distrib.cpython-36.pyc,,
twisted/web/test/__pycache__/test_domhelpers.cpython-36.pyc,,
twisted/web/test/__pycache__/test_error.cpython-36.pyc,,
twisted/web/test/__pycache__/test_flatten.cpython-36.pyc,,
twisted/web/test/__pycache__/test_html.cpython-36.pyc,,
twisted/web/test/__pycache__/test_http.cpython-36.pyc,,
twisted/web/test/__pycache__/test_http2.cpython-36.pyc,,
twisted/web/test/__pycache__/test_http_headers.cpython-36.pyc,,
twisted/web/test/__pycache__/test_httpauth.cpython-36.pyc,,
twisted/web/test/__pycache__/test_newclient.cpython-36.pyc,,
twisted/web/test/__pycache__/test_proxy.cpython-36.pyc,,
twisted/web/test/__pycache__/test_resource.cpython-36.pyc,,
twisted/web/test/__pycache__/test_script.cpython-36.pyc,,
twisted/web/test/__pycache__/test_stan.cpython-36.pyc,,
twisted/web/test/__pycache__/test_static.cpython-36.pyc,,
twisted/web/test/__pycache__/test_tap.cpython-36.pyc,,
twisted/web/test/__pycache__/test_template.cpython-36.pyc,,
twisted/web/test/__pycache__/test_util.cpython-36.pyc,,
twisted/web/test/__pycache__/test_vhost.cpython-36.pyc,,
twisted/web/test/__pycache__/test_web.cpython-36.pyc,,
twisted/web/test/__pycache__/test_web__responses.cpython-36.pyc,,
twisted/web/test/__pycache__/test_webclient.cpython-36.pyc,,
twisted/web/test/__pycache__/test_wsgi.cpython-36.pyc,,
twisted/web/test/__pycache__/test_xml.cpython-36.pyc,,
twisted/web/test/__pycache__/test_xmlrpc.cpython-36.pyc,,
twisted/web/test/_util.py,sha256=6pb3RDrdZoJ1DaELSW8PdaXUywANty8JN8j8AUwOKAM,2568
twisted/web/test/injectionhelpers.py,sha256=V2QQTamzKkOjypM7qdt2Y2iVHzQi4c83mZTesOt2_JU,5627
twisted/web/test/requesthelper.py,sha256=oP_zp0MkntT7TKvJPMIg6_7LlyQiuQ0-izoHRiYNIB0,13702
twisted/web/test/test_agent.py,sha256=ghnRnHIpSsrvi7ilIqdFU4a1MENBBzJ-PItrw6IAVQY,116623
twisted/web/test/test_cgi.py,sha256=fPZPDFG8JAOUJD2pXr7H_FOenrzy-RLdLW3FOTmM4L8,13761
twisted/web/test/test_client.py,sha256=rnMgKFRmeVFgtKTjnyAhJL2LvOI8P6WIjXJa--Juv5M,1372
twisted/web/test/test_distrib.py,sha256=SAHzSQyQa3IoYGi1dc0csEvSl69hSnBzRZGzKbfSIoI,18288
twisted/web/test/test_domhelpers.py,sha256=ir_GSEC4Y5eJUIP4mKi9GzFUdwLXvuDuBEHiUmSC2go,11103
twisted/web/test/test_error.py,sha256=a-KtTSqsH05SlDijTSPA50C7m-dgPhZH3Avc9uKs3uE,16210
twisted/web/test/test_flatten.py,sha256=TJTlohdbkYUC6OLIprKuYQrHoUh2aY86kVgzIQyp9Nk,18259
twisted/web/test/test_html.py,sha256=BBbAgc2B9f8-PmYvcyGDbhjKDUpBQTiuikNgaNpKaGo,1264
twisted/web/test/test_http.py,sha256=4IrPhkpFTHNSXbjQu9cjrOi6c-3X4LFGz6DYXIMah6k,131929
twisted/web/test/test_http2.py,sha256=LLlY0PSmFovpGoGe05bfTFrM8UetVZIhGrwCX4V_RUc,99939
twisted/web/test/test_http_headers.py,sha256=c3uv_Zbs5hDJQ64eGEErzs4iCVSnDdDCTp8sY3hbs0g,22177
twisted/web/test/test_httpauth.py,sha256=VyOB2BQqn2SEjXUsSUUc9OLHFgesUwjCvQD0U87XMSg,24128
twisted/web/test/test_newclient.py,sha256=rq4_W0WxH4NhCozadpy3gudGsD4zZTUDkdib1MMUSCY,110593
twisted/web/test/test_proxy.py,sha256=DW2jc_1elz_bPp4eU7qLK5peNTc_WM39p1TDnIMBaC8,20346
twisted/web/test/test_resource.py,sha256=EgBRDWfHTO01PNJgDbbAnUv9Pp_C5NmC2ZUOHiL-buI,9243
twisted/web/test/test_script.py,sha256=rQilL-H4VzO-NGU6_2Dv9h32VA3j4pZSPtwMW30e86E,3784
twisted/web/test/test_stan.py,sha256=5IqsRlFv_yp7HVZXFaqlFR1g79H2etwtPriydZkjaFE,5667
twisted/web/test/test_static.py,sha256=PqkZKWxhQ3GGmlMqwx2oDfrY_RlNc8ZPE5oaWLL74XU,67858
twisted/web/test/test_tap.py,sha256=w1GFPg5RbSWryvvp1wf7HleTz0EJHSoxHN3oMGpvzuc,12200
twisted/web/test/test_template.py,sha256=tVpMImaRl2wZQo1m-CPR1EfnApPSxhZedkLT4xTEsww,25977
twisted/web/test/test_util.py,sha256=pGxkGSoNPuWmunh_xqVJ8k4z97rMcZafvTgz6VOC770,12590
twisted/web/test/test_vhost.py,sha256=lF3ch-BlKMRqwug79z-y_dmFyJwQjVwLqhziruVeZz4,7398
twisted/web/test/test_web.py,sha256=CsyyQrdvYh-_r12YjuYXMS2z21hMR_bMZrXvqjfBgx8,64296
twisted/web/test/test_web__responses.py,sha256=Hsq7CDGZoxE9Iq78xaYuhZxqoN58qNuKsoaR4cgAMK0,877
twisted/web/test/test_webclient.py,sha256=Ww5dnXrDvtTsTwUAXtchL1vgKbQMrK_3Lbw4X9UtUMM,59615
twisted/web/test/test_wsgi.py,sha256=WAsGDXhOATeEIdDj-PPimPdrSoMVRKUl8EgCWVRcegw,78210
twisted/web/test/test_xml.py,sha256=zEnd97a1PSltKUfNyobziKKt7laDLWJV3jdfxJw3caw,42357
twisted/web/test/test_xmlrpc.py,sha256=6OL77o-ZcYUGS80cu5cyrbZA89DOkIB98xceNIOmQeA,30302
twisted/web/twcgi.py,sha256=_BIZTsI0soo5v7tf4gx25bqhbJhwNB8ZZCoDIdIgCr0,11343
twisted/web/util.py,sha256=Nwt-k63WLnLLhfA7vOh-10EkBboLhZehTM2oHpkFfjE,12412
twisted/web/vhost.py,sha256=9Y-li_wuLQmTJKPJWs4KOiT_WTVqhrnbfdcobtpbQnk,4463
twisted/web/wsgi.py,sha256=bjbeVJI5DrrhHlB1VFK-DVrOknosC_uRB6B4HGIMPDw,21879
twisted/web/xmlrpc.py,sha256=H5mFDI1rk1-dmj8QPijFyd34K5T7gKxTv8i-XMNFwak,20203
twisted/words/__init__.py,sha256=ffiFEwEz9RTE5rrSHV9jzhWhuomlg-tT7RQAXhlpGNI,215
twisted/words/__pycache__/__init__.cpython-36.pyc,,
twisted/words/__pycache__/ewords.cpython-36.pyc,,
twisted/words/__pycache__/iwords.cpython-36.pyc,,
twisted/words/__pycache__/service.cpython-36.pyc,,
twisted/words/__pycache__/tap.cpython-36.pyc,,
twisted/words/__pycache__/xmpproutertap.cpython-36.pyc,,
twisted/words/ewords.py,sha256=XOOQe4IRjQrj-kRj8Hu07VhjT6gCJYXmJ5MeFDhMEpE,623
twisted/words/im/__init__.py,sha256=ojtUkusjr0Xe56X-Oo4kmcmDCRCsC9C5qwZQZ_7vyPc,129
twisted/words/im/__pycache__/__init__.cpython-36.pyc,,
twisted/words/im/__pycache__/baseaccount.cpython-36.pyc,,
twisted/words/im/__pycache__/basechat.cpython-36.pyc,,
twisted/words/im/__pycache__/basesupport.cpython-36.pyc,,
twisted/words/im/__pycache__/interfaces.cpython-36.pyc,,
twisted/words/im/__pycache__/ircsupport.cpython-36.pyc,,
twisted/words/im/__pycache__/locals.cpython-36.pyc,,
twisted/words/im/__pycache__/pbsupport.cpython-36.pyc,,
twisted/words/im/baseaccount.py,sha256=s4wY-BSOVxOpuY85qyWzAV_Jcf53V48gPs7MA4ODitc,1808
twisted/words/im/basechat.py,sha256=sa3FXpKVESXmoCATOAq781KzPg-02vpk_Om42UcN1es,16454
twisted/words/im/basesupport.py,sha256=AmZMFNSPJRqriDckFSRrx2Ae2DeZUMblNdzi_yIPTpY,7842
twisted/words/im/instancemessenger.glade,sha256=Scnco66vE3ByEHRbXpG4jkjW8wBquLjVrPtTRXurkRs,77126
twisted/words/im/interfaces.py,sha256=C8hxSNUyi-BDhC7uzGQFAoQMGEb2BiqTekob5cOe-8o,8675
twisted/words/im/ircsupport.py,sha256=ZBhiItd93QgRcXZvEcSygIBi0-QJs5sWfyVAUY2bfQM,9150
twisted/words/im/locals.py,sha256=JCVxJC5thNvnoTQ9VbrGtdXtGoYDBAm4u9ZhqqL8G0I,499
twisted/words/im/pbsupport.py,sha256=964WKGL-swV-24Y_JT1-5hvfZwBxixjP-aDq5BebcJ8,9676
twisted/words/iwords.py,sha256=YtWBU_LM980pJN6_MjMToSVkZteZXYtTgM-wg5S9kPM,8528
twisted/words/protocols/__init__.py,sha256=zmeNC2QVvHipjDnBJSx2CKRWMONswC98R2IlwuAhWBw,97
twisted/words/protocols/__pycache__/__init__.cpython-36.pyc,,
twisted/words/protocols/__pycache__/irc.cpython-36.pyc,,
twisted/words/protocols/irc.py,sha256=spjIqZTWOAecb1e8iP5yTCxt5ArerCjo1gRpkxY_54I,125664
twisted/words/protocols/jabber/__init__.py,sha256=yofokZPwf09uggpzpyRuUCZf_qAkzijZZCZnDpkEN90,167
twisted/words/protocols/jabber/__pycache__/__init__.cpython-36.pyc,,
twisted/words/protocols/jabber/__pycache__/client.cpython-36.pyc,,
twisted/words/protocols/jabber/__pycache__/component.cpython-36.pyc,,
twisted/words/protocols/jabber/__pycache__/error.cpython-36.pyc,,
twisted/words/protocols/jabber/__pycache__/ijabber.cpython-36.pyc,,
twisted/words/protocols/jabber/__pycache__/jid.cpython-36.pyc,,
twisted/words/protocols/jabber/__pycache__/jstrports.cpython-36.pyc,,
twisted/words/protocols/jabber/__pycache__/sasl.cpython-36.pyc,,
twisted/words/protocols/jabber/__pycache__/sasl_mechanisms.cpython-36.pyc,,
twisted/words/protocols/jabber/__pycache__/xmlstream.cpython-36.pyc,,
twisted/words/protocols/jabber/__pycache__/xmpp_stringprep.cpython-36.pyc,,
twisted/words/protocols/jabber/client.py,sha256=L4rpVpZFzNGjaGw7nb4468ZIpPxzPdlRa6mjiJZIZ3U,14382
twisted/words/protocols/jabber/component.py,sha256=bcXoz0-mtxYrYjZy8m_BlFJhuiZk3TG5jQm_hLHx15o,15595
twisted/words/protocols/jabber/error.py,sha256=GsmBMFqyQ3dJMfMebbocmF1Dp_MFYWObsKswKoqiwLA,10802
twisted/words/protocols/jabber/ijabber.py,sha256=R2Y4N6jWJFb7Rqz5O_QelpHtbQpCA6yjGXNUWXe8xpE,5380
twisted/words/protocols/jabber/jid.py,sha256=xqT9MfeTo2YD2hqSmFJqkxmi6Fsf_3zdy423UWukFTE,7249
twisted/words/protocols/jabber/jstrports.py,sha256=RoATh0iNGE-qN1MoJKTd9TXN_51Sshoo80a7qlJQ2Nc,978
twisted/words/protocols/jabber/sasl.py,sha256=uEVeYQ9snoX4ODHQmxOQSC0-zIWEoA8Dnaki-vpxiFA,7461
twisted/words/protocols/jabber/sasl_mechanisms.py,sha256=rPBzN-_kiyIne3GDVHVyHi8tRoKoEeS2Nv2tD46un2U,8730
twisted/words/protocols/jabber/xmlstream.py,sha256=bExNRabsilWpyGLxjQeat4TJoHt7nE0OegMb4NBGLUg,36848
twisted/words/protocols/jabber/xmpp_stringprep.py,sha256=JaC22A1_c9_mR0RoxjHZ1oO_VKbRHE4h4kViPK9YcGQ,7221
twisted/words/service.py,sha256=gREUR1_Cq5kEUEDA9BnjWAM87nqYq_3JPUoIZf7VjTM,38173
twisted/words/tap.py,sha256=a0Q_SX7jt6adZYHX_sSkB16qwWqz-uLGTOYV-br54W8,2422
twisted/words/test/__init__.py,sha256=wDdSRMUVT0_hf5Fe36M3C6GiB4N1TOqgB41q9B-Ia04,14
twisted/words/test/__pycache__/__init__.cpython-36.pyc,,
twisted/words/test/__pycache__/test_basechat.cpython-36.pyc,,
twisted/words/test/__pycache__/test_basesupport.cpython-36.pyc,,
twisted/words/test/__pycache__/test_domish.cpython-36.pyc,,
twisted/words/test/__pycache__/test_irc.cpython-36.pyc,,
twisted/words/test/__pycache__/test_irc_service.cpython-36.pyc,,
twisted/words/test/__pycache__/test_ircsupport.cpython-36.pyc,,
twisted/words/test/__pycache__/test_jabberclient.cpython-36.pyc,,
twisted/words/test/__pycache__/test_jabbercomponent.cpython-36.pyc,,
twisted/words/test/__pycache__/test_jabbererror.cpython-36.pyc,,
twisted/words/test/__pycache__/test_jabberjid.cpython-36.pyc,,
twisted/words/test/__pycache__/test_jabberjstrports.cpython-36.pyc,,
twisted/words/test/__pycache__/test_jabbersasl.cpython-36.pyc,,
twisted/words/test/__pycache__/test_jabbersaslmechanisms.cpython-36.pyc,,
twisted/words/test/__pycache__/test_jabberxmlstream.cpython-36.pyc,,
twisted/words/test/__pycache__/test_jabberxmppstringprep.cpython-36.pyc,,
twisted/words/test/__pycache__/test_service.cpython-36.pyc,,
twisted/words/test/__pycache__/test_tap.cpython-36.pyc,,
twisted/words/test/__pycache__/test_xishutil.cpython-36.pyc,,
twisted/words/test/__pycache__/test_xmlstream.cpython-36.pyc,,
twisted/words/test/__pycache__/test_xmpproutertap.cpython-36.pyc,,
twisted/words/test/__pycache__/test_xpath.cpython-36.pyc,,
twisted/words/test/test_basechat.py,sha256=y01cIaQ3LrPRUbsdsiTt50w5WeRu-tQrDLHqZe9MQos,2504
twisted/words/test/test_basesupport.py,sha256=YtA2z8fxt1aP-AYSHpO3PCLNA9t-G5De5ibFH_JEEd8,3064
twisted/words/test/test_domish.py,sha256=QFHbVSG9SHOy0IJ2_Gx-hTD-KLHHGVeSMJC8IinO3xA,20172
twisted/words/test/test_irc.py,sha256=LNcjt-o8U2BSbxx6kNpBb-b5z5OTi1kbuM54pwfQIxU,103397
twisted/words/test/test_irc_service.py,sha256=X_pjwDVCfKBShdEHIiezZH4UFyoyxWaRkAWzP5yGEOM,9639
twisted/words/test/test_ircsupport.py,sha256=vhzh3PXjUynPnsf3NwZ5Nu67w-4ZBuC4u1Oiz4tBVgs,10702
twisted/words/test/test_jabberclient.py,sha256=22MQ-lfQCgrRe9r5qTmXuHluFa_pPaxSRHkONpAlj4E,16866
twisted/words/test/test_jabbercomponent.py,sha256=gw_WkkLLegqMjjWpnCJP59pSNlgBQB0Wbu7mLjpPDe0,14204
twisted/words/test/test_jabbererror.py,sha256=h97z_XCO11UhFw8Zkb2GH1y31uF6wcILTIdkTdqdsNU,11521
twisted/words/test/test_jabberjid.py,sha256=5WlXkppYf9H7y_zDOLpBaXAYo2Am2SB0SkvT4x2_LN0,7210
twisted/words/test/test_jabberjstrports.py,sha256=0SJ1Z8J27DcBHANt-7w6rgn34rlY65LNaTZcp2ysQuY,996
twisted/words/test/test_jabbersasl.py,sha256=2aTrH1bZXhmejB0ILDjcYHOrAvWN_nM6tMPaGOoBrTU,9432
twisted/words/test/test_jabbersaslmechanisms.py,sha256=uz_kmwx2T_sFGms27gZ7NGbGBPESRGy46HiWiP2o6mU,5758
twisted/words/test/test_jabberxmlstream.py,sha256=kasBxkHYAr22DwlscSsO9dNUk8xmFQQ9bphSgk0hnbA,45718
twisted/words/test/test_jabberxmppstringprep.py,sha256=9E7K3ji2kRRzTYU9NWqqjdSUyvT4iOxYJELgVZhDShk,5549
twisted/words/test/test_service.py,sha256=cH-DqZL7lV4_kTHlyF6_XzA3w9g4Zs8lbt0J2XdRqWw,28462
twisted/words/test/test_tap.py,sha256=rNN4d-kYxOe-6dUmRwHmJe1wjN74Px0v2MltP02_TB4,2180
twisted/words/test/test_xishutil.py,sha256=onFjooPZ3cM3r42-iw2H9ihBcXZ5q865C8p5JgpftgA,9396
twisted/words/test/test_xmlstream.py,sha256=YuCLqVj1s1Ccll11b7OG_bm8IaoNOlFjNZeNKeLIfJQ,6274
twisted/words/test/test_xmpproutertap.py,sha256=qROkHmUyHZ1kRwThHV9-28LOhR74lQJXM-g5NUIRMww,2398
twisted/words/test/test_xpath.py,sha256=m2Fvr_21iIKlBiWNWp-7Pf8YTJm6f9_e1t9Ga4XjMO4,11002
twisted/words/xish/__init__.py,sha256=XJs3sqZxj1QVTrrgkbVAUcpxMekKLPEKzuEXFJVwp0k,177
twisted/words/xish/__pycache__/__init__.cpython-36.pyc,,
twisted/words/xish/__pycache__/domish.cpython-36.pyc,,
twisted/words/xish/__pycache__/utility.cpython-36.pyc,,
twisted/words/xish/__pycache__/xmlstream.cpython-36.pyc,,
twisted/words/xish/__pycache__/xpath.cpython-36.pyc,,
twisted/words/xish/__pycache__/xpathparser.cpython-36.pyc,,
twisted/words/xish/domish.py,sha256=O41aNQaLjs5aAhleDGctdPOG5EU1r9QQJ_K6JHLEIlY,30564
twisted/words/xish/utility.py,sha256=bCnYogLhRc1BWprU8ewiPqiU9kCUUoDZQqcdZoXFuZI,13482
twisted/words/xish/xmlstream.py,sha256=p9zjmPIaBSDFIb8a4Cgi6ReOIeDO4GllurTclNLljJc,9189
twisted/words/xish/xpath.py,sha256=KLvSEWoNXnD7ruqsATQYIy70cMFD7uXE8B7mp6xV3bY,9556
twisted/words/xish/xpathparser.g,sha256=eJQMsCzdX76niIJm8hHiLNLLqq4G6uJl6TDx9iPx6qk,18122
twisted/words/xish/xpathparser.py,sha256=iPE2dtF79_SU2i0GDQR9jW2Gc2UP6yWeJ_EEgPLCHwk,22851
twisted/words/xmpproutertap.py,sha256=n9oc9f4xelocf6NGS0_BreuRGbe9YBMpsdKuMjPrd8E,820
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Twisted-19.7.0.dist-info/WHEEL
================================================
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.4)
Root-Is-Purelib: false
Tag: cp36-cp36m-manylinux1_x86_64
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Twisted-19.7.0.dist-info/entry_points.txt
================================================
[console_scripts]
cftp = twisted.conch.scripts.cftp:run
ckeygen = twisted.conch.scripts.ckeygen:run
conch = twisted.conch.scripts.conch:run
mailmail = twisted.mail.scripts.mailmail:run
pyhtmlizer = twisted.scripts.htmlizer:run
tkconch = twisted.conch.scripts.tkconch:run
trial = twisted.scripts.trial:run
twist = twisted.application.twist._twist:Twist.main
twistd = twisted.scripts.twistd:run
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/Twisted-19.7.0.dist-info/top_level.txt
================================================
twisted
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/__init__.py
================================================
from __future__ import absolute_import, division, print_function
from functools import partial
from . import converters, exceptions, filters, validators
from ._config import get_run_validators, set_run_validators
from ._funcs import asdict, assoc, astuple, evolve, has
from ._make import (
NOTHING,
Attribute,
Factory,
attrib,
attrs,
fields,
fields_dict,
make_class,
validate,
)
from ._version_info import VersionInfo
__version__ = "19.3.0"
__version_info__ = VersionInfo._from_version_string(__version__)
__title__ = "attrs"
__description__ = "Classes Without Boilerplate"
__url__ = "https://www.attrs.org/"
__uri__ = __url__
__doc__ = __description__ + " <" + __uri__ + ">"
__author__ = "Hynek Schlawack"
__email__ = "hs@ox.cx"
__license__ = "MIT"
__copyright__ = "Copyright (c) 2015 Hynek Schlawack"
s = attributes = attrs
ib = attr = attrib
dataclass = partial(attrs, auto_attribs=True) # happy Easter ;)
__all__ = [
"Attribute",
"Factory",
"NOTHING",
"asdict",
"assoc",
"astuple",
"attr",
"attrib",
"attributes",
"attrs",
"converters",
"evolve",
"exceptions",
"fields",
"fields_dict",
"filters",
"get_run_validators",
"has",
"ib",
"make_class",
"s",
"set_run_validators",
"validate",
"validators",
]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/__init__.pyi
================================================
from typing import (
Any,
Callable,
Dict,
Generic,
List,
Optional,
Sequence,
Mapping,
Tuple,
Type,
TypeVar,
Union,
overload,
)
# `import X as X` is required to make these public
from . import exceptions as exceptions
from . import filters as filters
from . import converters as converters
from . import validators as validators
from ._version_info import VersionInfo
__version__: str
__version_info__: VersionInfo
__title__: str
__description__: str
__url__: str
__uri__: str
__author__: str
__email__: str
__license__: str
__copyright__: str
_T = TypeVar("_T")
_C = TypeVar("_C", bound=type)
_ValidatorType = Callable[[Any, Attribute[_T], _T], Any]
_ConverterType = Callable[[Any], _T]
_FilterType = Callable[[Attribute[_T], _T], bool]
_ReprType = Callable[[Any], str]
_ReprArgType = Union[bool, _ReprType]
# FIXME: in reality, if multiple validators are passed they must be in a list or tuple,
# but those are invariant and so would prevent subtypes of _ValidatorType from working
# when passed in a list or tuple.
_ValidatorArgType = Union[_ValidatorType[_T], Sequence[_ValidatorType[_T]]]
# _make --
NOTHING: object
# NOTE: Factory lies about its return type to make this possible: `x: List[int] = Factory(list)`
# Work around mypy issue #4554 in the common case by using an overload.
@overload
def Factory(factory: Callable[[], _T]) -> _T: ...
@overload
def Factory(
factory: Union[Callable[[Any], _T], Callable[[], _T]],
takes_self: bool = ...,
) -> _T: ...
class Attribute(Generic[_T]):
name: str
default: Optional[_T]
validator: Optional[_ValidatorType[_T]]
repr: _ReprArgType
cmp: bool
eq: bool
order: bool
hash: Optional[bool]
init: bool
converter: Optional[_ConverterType[_T]]
metadata: Dict[Any, Any]
type: Optional[Type[_T]]
kw_only: bool
# NOTE: We had several choices for the annotation to use for type arg:
# 1) Type[_T]
# - Pros: Handles simple cases correctly
# - Cons: Might produce less informative errors in the case of conflicting TypeVars
# e.g. `attr.ib(default='bad', type=int)`
# 2) Callable[..., _T]
# - Pros: Better error messages than #1 for conflicting TypeVars
# - Cons: Terrible error messages for validator checks.
# e.g. attr.ib(type=int, validator=validate_str)
# -> error: Cannot infer function type argument
# 3) type (and do all of the work in the mypy plugin)
# - Pros: Simple here, and we could customize the plugin with our own errors.
# - Cons: Would need to write mypy plugin code to handle all the cases.
# We chose option #1.
# `attr` lies about its return type to make the following possible:
# attr() -> Any
# attr(8) -> int
# attr(validator=) -> Whatever the callable expects.
# This makes this type of assignments possible:
# x: int = attr(8)
#
# This form catches explicit None or no default but with no other arguments returns Any.
@overload
def attrib(
default: None = ...,
validator: None = ...,
repr: _ReprArgType = ...,
cmp: Optional[bool] = ...,
hash: Optional[bool] = ...,
init: bool = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: None = ...,
converter: None = ...,
factory: None = ...,
kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> Any: ...
# This form catches an explicit None or no default and infers the type from the other arguments.
@overload
def attrib(
default: None = ...,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: _ReprArgType = ...,
cmp: Optional[bool] = ...,
hash: Optional[bool] = ...,
init: bool = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: Optional[Type[_T]] = ...,
converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ...,
kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> _T: ...
# This form catches an explicit default argument.
@overload
def attrib(
default: _T,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: _ReprArgType = ...,
cmp: Optional[bool] = ...,
hash: Optional[bool] = ...,
init: bool = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: Optional[Type[_T]] = ...,
converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ...,
kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> _T: ...
# This form covers type=non-Type: e.g. forward references (str), Any
@overload
def attrib(
default: Optional[_T] = ...,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: _ReprArgType = ...,
cmp: Optional[bool] = ...,
hash: Optional[bool] = ...,
init: bool = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: object = ...,
converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ...,
kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> Any: ...
@overload
def attrs(
maybe_cls: _C,
these: Optional[Dict[str, Any]] = ...,
repr_ns: Optional[str] = ...,
repr: bool = ...,
cmp: Optional[bool] = ...,
hash: Optional[bool] = ...,
init: bool = ...,
slots: bool = ...,
frozen: bool = ...,
weakref_slot: bool = ...,
str: bool = ...,
auto_attribs: bool = ...,
kw_only: bool = ...,
cache_hash: bool = ...,
auto_exc: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> _C: ...
@overload
def attrs(
maybe_cls: None = ...,
these: Optional[Dict[str, Any]] = ...,
repr_ns: Optional[str] = ...,
repr: bool = ...,
cmp: Optional[bool] = ...,
hash: Optional[bool] = ...,
init: bool = ...,
slots: bool = ...,
frozen: bool = ...,
weakref_slot: bool = ...,
str: bool = ...,
auto_attribs: bool = ...,
kw_only: bool = ...,
cache_hash: bool = ...,
auto_exc: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> Callable[[_C], _C]: ...
# TODO: add support for returning NamedTuple from the mypy plugin
class _Fields(Tuple[Attribute[Any], ...]):
def __getattr__(self, name: str) -> Attribute[Any]: ...
def fields(cls: type) -> _Fields: ...
def fields_dict(cls: type) -> Dict[str, Attribute[Any]]: ...
def validate(inst: Any) -> None: ...
# TODO: add support for returning a proper attrs class from the mypy plugin
# we use Any instead of _CountingAttr so that e.g. `make_class('Foo', [attr.ib()])` is valid
def make_class(
name: str,
attrs: Union[List[str], Tuple[str, ...], Dict[str, Any]],
bases: Tuple[type, ...] = ...,
repr_ns: Optional[str] = ...,
repr: bool = ...,
cmp: Optional[bool] = ...,
hash: Optional[bool] = ...,
init: bool = ...,
slots: bool = ...,
frozen: bool = ...,
weakref_slot: bool = ...,
str: bool = ...,
auto_attribs: bool = ...,
kw_only: bool = ...,
cache_hash: bool = ...,
auto_exc: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> type: ...
# _funcs --
# TODO: add support for returning TypedDict from the mypy plugin
# FIXME: asdict/astuple do not honor their factory args. waiting on one of these:
# https://github.com/python/mypy/issues/4236
# https://github.com/python/typing/issues/253
def asdict(
inst: Any,
recurse: bool = ...,
filter: Optional[_FilterType[Any]] = ...,
dict_factory: Type[Mapping[Any, Any]] = ...,
retain_collection_types: bool = ...,
) -> Dict[str, Any]: ...
# TODO: add support for returning NamedTuple from the mypy plugin
def astuple(
inst: Any,
recurse: bool = ...,
filter: Optional[_FilterType[Any]] = ...,
tuple_factory: Type[Sequence[Any]] = ...,
retain_collection_types: bool = ...,
) -> Tuple[Any, ...]: ...
def has(cls: type) -> bool: ...
def assoc(inst: _T, **changes: Any) -> _T: ...
def evolve(inst: _T, **changes: Any) -> _T: ...
# _config --
def set_run_validators(run: bool) -> None: ...
def get_run_validators() -> bool: ...
# aliases --
s = attributes = attrs
ib = attr = attrib
dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/_compat.py
================================================
from __future__ import absolute_import, division, print_function
import platform
import sys
import types
import warnings
PY2 = sys.version_info[0] == 2
PYPY = platform.python_implementation() == "PyPy"
if PYPY or sys.version_info[:2] >= (3, 6):
ordered_dict = dict
else:
from collections import OrderedDict
ordered_dict = OrderedDict
if PY2:
from UserDict import IterableUserDict
from collections import Mapping, Sequence
# We 'bundle' isclass instead of using inspect as importing inspect is
# fairly expensive (order of 10-15 ms for a modern machine in 2016)
def isclass(klass):
return isinstance(klass, (type, types.ClassType))
# TYPE is used in exceptions, repr(int) is different on Python 2 and 3.
TYPE = "type"
def iteritems(d):
return d.iteritems()
# Python 2 is bereft of a read-only dict proxy, so we make one!
class ReadOnlyDict(IterableUserDict):
"""
Best-effort read-only dict wrapper.
"""
def __setitem__(self, key, val):
# We gently pretend we're a Python 3 mappingproxy.
raise TypeError(
"'mappingproxy' object does not support item assignment"
)
def update(self, _):
# We gently pretend we're a Python 3 mappingproxy.
raise AttributeError(
"'mappingproxy' object has no attribute 'update'"
)
def __delitem__(self, _):
# We gently pretend we're a Python 3 mappingproxy.
raise TypeError(
"'mappingproxy' object does not support item deletion"
)
def clear(self):
# We gently pretend we're a Python 3 mappingproxy.
raise AttributeError(
"'mappingproxy' object has no attribute 'clear'"
)
def pop(self, key, default=None):
# We gently pretend we're a Python 3 mappingproxy.
raise AttributeError(
"'mappingproxy' object has no attribute 'pop'"
)
def popitem(self):
# We gently pretend we're a Python 3 mappingproxy.
raise AttributeError(
"'mappingproxy' object has no attribute 'popitem'"
)
def setdefault(self, key, default=None):
# We gently pretend we're a Python 3 mappingproxy.
raise AttributeError(
"'mappingproxy' object has no attribute 'setdefault'"
)
def __repr__(self):
# Override to be identical to the Python 3 version.
return "mappingproxy(" + repr(self.data) + ")"
def metadata_proxy(d):
res = ReadOnlyDict()
res.data.update(d) # We blocked update, so we have to do it like this.
return res
def just_warn(*args, **kw): # pragma: nocover
"""
We only warn on Python 3 because we are not aware of any concrete
consequences of not setting the cell on Python 2.
"""
else: # Python 3 and later.
from collections.abc import Mapping, Sequence # noqa
def just_warn(*args, **kw):
"""
We only warn on Python 3 because we are not aware of any concrete
consequences of not setting the cell on Python 2.
"""
warnings.warn(
"Running interpreter doesn't sufficiently support code object "
"introspection. Some features like bare super() or accessing "
"__class__ will not work with slotted classes.",
RuntimeWarning,
stacklevel=2,
)
def isclass(klass):
return isinstance(klass, type)
TYPE = "class"
def iteritems(d):
return d.items()
def metadata_proxy(d):
return types.MappingProxyType(dict(d))
def make_set_closure_cell():
"""Return a function of two arguments (cell, value) which sets
the value stored in the closure cell `cell` to `value`.
"""
# pypy makes this easy. (It also supports the logic below, but
# why not do the easy/fast thing?)
if PYPY: # pragma: no cover
def set_closure_cell(cell, value):
cell.__setstate__((value,))
return set_closure_cell
# Otherwise gotta do it the hard way.
# Create a function that will set its first cellvar to `value`.
def set_first_cellvar_to(value):
x = value
return
# This function will be eliminated as dead code, but
# not before its reference to `x` forces `x` to be
# represented as a closure cell rather than a local.
def force_x_to_be_a_cell(): # pragma: no cover
return x
try:
# Extract the code object and make sure our assumptions about
# the closure behavior are correct.
if PY2:
co = set_first_cellvar_to.func_code
else:
co = set_first_cellvar_to.__code__
if co.co_cellvars != ("x",) or co.co_freevars != ():
raise AssertionError # pragma: no cover
# Convert this code object to a code object that sets the
# function's first _freevar_ (not cellvar) to the argument.
if sys.version_info >= (3, 8):
# CPython 3.8+ has an incompatible CodeType signature
# (added a posonlyargcount argument) but also added
# CodeType.replace() to do this without counting parameters.
set_first_freevar_code = co.replace(
co_cellvars=co.co_freevars, co_freevars=co.co_cellvars
)
else:
args = [co.co_argcount]
if not PY2:
args.append(co.co_kwonlyargcount)
args.extend(
[
co.co_nlocals,
co.co_stacksize,
co.co_flags,
co.co_code,
co.co_consts,
co.co_names,
co.co_varnames,
co.co_filename,
co.co_name,
co.co_firstlineno,
co.co_lnotab,
# These two arguments are reversed:
co.co_cellvars,
co.co_freevars,
]
)
set_first_freevar_code = types.CodeType(*args)
def set_closure_cell(cell, value):
# Create a function using the set_first_freevar_code,
# whose first closure cell is `cell`. Calling it will
# change the value of that cell.
setter = types.FunctionType(
set_first_freevar_code, {}, "setter", (), (cell,)
)
# And call it to set the cell.
setter(value)
# Make sure it works on this interpreter:
def make_func_with_cell():
x = None
def func():
return x # pragma: no cover
return func
if PY2:
cell = make_func_with_cell().func_closure[0]
else:
cell = make_func_with_cell().__closure__[0]
set_closure_cell(cell, 100)
if cell.cell_contents != 100:
raise AssertionError # pragma: no cover
except Exception:
return just_warn
else:
return set_closure_cell
set_closure_cell = make_set_closure_cell()
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/_config.py
================================================
from __future__ import absolute_import, division, print_function
__all__ = ["set_run_validators", "get_run_validators"]
_run_validators = True
def set_run_validators(run):
"""
Set whether or not validators are run. By default, they are run.
"""
if not isinstance(run, bool):
raise TypeError("'run' must be bool.")
global _run_validators
_run_validators = run
def get_run_validators():
"""
Return whether or not validators are run.
"""
return _run_validators
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/_funcs.py
================================================
from __future__ import absolute_import, division, print_function
import copy
from ._compat import iteritems
from ._make import NOTHING, _obj_setattr, fields
from .exceptions import AttrsAttributeNotFoundError
def asdict(
inst,
recurse=True,
filter=None,
dict_factory=dict,
retain_collection_types=False,
):
"""
Return the ``attrs`` attribute values of *inst* as a dict.
Optionally recurse into other ``attrs``-decorated classes.
:param inst: Instance of an ``attrs``-decorated class.
:param bool recurse: Recurse into classes that are also
``attrs``-decorated.
:param callable filter: A callable whose return code determines whether an
attribute or element is included (``True``) or dropped (``False``). Is
called with the `attr.Attribute` as the first argument and the
value as the second argument.
:param callable dict_factory: A callable to produce dictionaries from. For
example, to produce ordered dictionaries instead of normal Python
dictionaries, pass in ``collections.OrderedDict``.
:param bool retain_collection_types: Do not convert to ``list`` when
encountering an attribute whose type is ``tuple`` or ``set``. Only
meaningful if ``recurse`` is ``True``.
:rtype: return type of *dict_factory*
:raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
class.
.. versionadded:: 16.0.0 *dict_factory*
.. versionadded:: 16.1.0 *retain_collection_types*
"""
attrs = fields(inst.__class__)
rv = dict_factory()
for a in attrs:
v = getattr(inst, a.name)
if filter is not None and not filter(a, v):
continue
if recurse is True:
if has(v.__class__):
rv[a.name] = asdict(
v, True, filter, dict_factory, retain_collection_types
)
elif isinstance(v, (tuple, list, set)):
cf = v.__class__ if retain_collection_types is True else list
rv[a.name] = cf(
[
_asdict_anything(
i, filter, dict_factory, retain_collection_types
)
for i in v
]
)
elif isinstance(v, dict):
df = dict_factory
rv[a.name] = df(
(
_asdict_anything(
kk, filter, df, retain_collection_types
),
_asdict_anything(
vv, filter, df, retain_collection_types
),
)
for kk, vv in iteritems(v)
)
else:
rv[a.name] = v
else:
rv[a.name] = v
return rv
def _asdict_anything(val, filter, dict_factory, retain_collection_types):
"""
``asdict`` only works on attrs instances, this works on anything.
"""
if getattr(val.__class__, "__attrs_attrs__", None) is not None:
# Attrs class.
rv = asdict(val, True, filter, dict_factory, retain_collection_types)
elif isinstance(val, (tuple, list, set)):
cf = val.__class__ if retain_collection_types is True else list
rv = cf(
[
_asdict_anything(
i, filter, dict_factory, retain_collection_types
)
for i in val
]
)
elif isinstance(val, dict):
df = dict_factory
rv = df(
(
_asdict_anything(kk, filter, df, retain_collection_types),
_asdict_anything(vv, filter, df, retain_collection_types),
)
for kk, vv in iteritems(val)
)
else:
rv = val
return rv
def astuple(
inst,
recurse=True,
filter=None,
tuple_factory=tuple,
retain_collection_types=False,
):
"""
Return the ``attrs`` attribute values of *inst* as a tuple.
Optionally recurse into other ``attrs``-decorated classes.
:param inst: Instance of an ``attrs``-decorated class.
:param bool recurse: Recurse into classes that are also
``attrs``-decorated.
:param callable filter: A callable whose return code determines whether an
attribute or element is included (``True``) or dropped (``False``). Is
called with the `attr.Attribute` as the first argument and the
value as the second argument.
:param callable tuple_factory: A callable to produce tuples from. For
example, to produce lists instead of tuples.
:param bool retain_collection_types: Do not convert to ``list``
or ``dict`` when encountering an attribute which type is
``tuple``, ``dict`` or ``set``. Only meaningful if ``recurse`` is
``True``.
:rtype: return type of *tuple_factory*
:raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
class.
.. versionadded:: 16.2.0
"""
attrs = fields(inst.__class__)
rv = []
retain = retain_collection_types # Very long. :/
for a in attrs:
v = getattr(inst, a.name)
if filter is not None and not filter(a, v):
continue
if recurse is True:
if has(v.__class__):
rv.append(
astuple(
v,
recurse=True,
filter=filter,
tuple_factory=tuple_factory,
retain_collection_types=retain,
)
)
elif isinstance(v, (tuple, list, set)):
cf = v.__class__ if retain is True else list
rv.append(
cf(
[
astuple(
j,
recurse=True,
filter=filter,
tuple_factory=tuple_factory,
retain_collection_types=retain,
)
if has(j.__class__)
else j
for j in v
]
)
)
elif isinstance(v, dict):
df = v.__class__ if retain is True else dict
rv.append(
df(
(
astuple(
kk,
tuple_factory=tuple_factory,
retain_collection_types=retain,
)
if has(kk.__class__)
else kk,
astuple(
vv,
tuple_factory=tuple_factory,
retain_collection_types=retain,
)
if has(vv.__class__)
else vv,
)
for kk, vv in iteritems(v)
)
)
else:
rv.append(v)
else:
rv.append(v)
return rv if tuple_factory is list else tuple_factory(rv)
def has(cls):
"""
Check whether *cls* is a class with ``attrs`` attributes.
:param type cls: Class to introspect.
:raise TypeError: If *cls* is not a class.
:rtype: bool
"""
return getattr(cls, "__attrs_attrs__", None) is not None
def assoc(inst, **changes):
"""
Copy *inst* and apply *changes*.
:param inst: Instance of a class with ``attrs`` attributes.
:param changes: Keyword changes in the new copy.
:return: A copy of inst with *changes* incorporated.
:raise attr.exceptions.AttrsAttributeNotFoundError: If *attr_name* couldn't
be found on *cls*.
:raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
class.
.. deprecated:: 17.1.0
Use `evolve` instead.
"""
import warnings
warnings.warn(
"assoc is deprecated and will be removed after 2018/01.",
DeprecationWarning,
stacklevel=2,
)
new = copy.copy(inst)
attrs = fields(inst.__class__)
for k, v in iteritems(changes):
a = getattr(attrs, k, NOTHING)
if a is NOTHING:
raise AttrsAttributeNotFoundError(
"{k} is not an attrs attribute on {cl}.".format(
k=k, cl=new.__class__
)
)
_obj_setattr(new, k, v)
return new
def evolve(inst, **changes):
"""
Create a new instance, based on *inst* with *changes* applied.
:param inst: Instance of a class with ``attrs`` attributes.
:param changes: Keyword changes in the new copy.
:return: A copy of inst with *changes* incorporated.
:raise TypeError: If *attr_name* couldn't be found in the class
``__init__``.
:raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
class.
.. versionadded:: 17.1.0
"""
cls = inst.__class__
attrs = fields(cls)
for a in attrs:
if not a.init:
continue
attr_name = a.name # To deal with private attributes.
init_name = attr_name if attr_name[0] != "_" else attr_name[1:]
if init_name not in changes:
changes[init_name] = getattr(inst, attr_name)
return cls(**changes)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/_make.py
================================================
from __future__ import absolute_import, division, print_function
import copy
import linecache
import sys
import threading
import uuid
import warnings
from operator import itemgetter
from . import _config
from ._compat import (
PY2,
isclass,
iteritems,
metadata_proxy,
ordered_dict,
set_closure_cell,
)
from .exceptions import (
DefaultAlreadySetError,
FrozenInstanceError,
NotAnAttrsClassError,
PythonTooOldError,
UnannotatedAttributeError,
)
# This is used at least twice, so cache it here.
_obj_setattr = object.__setattr__
_init_converter_pat = "__attr_converter_{}"
_init_factory_pat = "__attr_factory_{}"
_tuple_property_pat = (
" {attr_name} = _attrs_property(_attrs_itemgetter({index}))"
)
_classvar_prefixes = ("typing.ClassVar", "t.ClassVar", "ClassVar")
# we don't use a double-underscore prefix because that triggers
# name mangling when trying to create a slot for the field
# (when slots=True)
_hash_cache_field = "_attrs_cached_hash"
_empty_metadata_singleton = metadata_proxy({})
# Unique object for unequivocal getattr() defaults.
_sentinel = object()
class _Nothing(object):
"""
Sentinel class to indicate the lack of a value when ``None`` is ambiguous.
``_Nothing`` is a singleton. There is only ever one of it.
"""
_singleton = None
def __new__(cls):
if _Nothing._singleton is None:
_Nothing._singleton = super(_Nothing, cls).__new__(cls)
return _Nothing._singleton
def __repr__(self):
return "NOTHING"
NOTHING = _Nothing()
"""
Sentinel to indicate the lack of a value when ``None`` is ambiguous.
"""
def attrib(
default=NOTHING,
validator=None,
repr=True,
cmp=None,
hash=None,
init=True,
metadata=None,
type=None,
converter=None,
factory=None,
kw_only=False,
eq=None,
order=None,
):
"""
Create a new attribute on a class.
.. warning::
Does *not* do anything unless the class is also decorated with
`attr.s`!
:param default: A value that is used if an ``attrs``-generated ``__init__``
is used and no value is passed while instantiating or the attribute is
excluded using ``init=False``.
If the value is an instance of `Factory`, its callable will be
used to construct a new value (useful for mutable data types like lists
or dicts).
If a default is not set (or set manually to ``attr.NOTHING``), a value
*must* be supplied when instantiating; otherwise a `TypeError`
will be raised.
The default can also be set using decorator notation as shown below.
:type default: Any value
:param callable factory: Syntactic sugar for
``default=attr.Factory(callable)``.
:param validator: `callable` that is called by ``attrs``-generated
``__init__`` methods after the instance has been initialized. They
receive the initialized instance, the `Attribute`, and the
passed value.
The return value is *not* inspected so the validator has to throw an
exception itself.
If a ``list`` is passed, its items are treated as validators and must
all pass.
Validators can be globally disabled and re-enabled using
`get_run_validators`.
The validator can also be set using decorator notation as shown below.
:type validator: ``callable`` or a ``list`` of ``callable``\\ s.
:param repr: Include this attribute in the generated ``__repr__``
method. If ``True``, include the attribute; if ``False``, omit it. By
default, the built-in ``repr()`` function is used. To override how the
attribute value is formatted, pass a ``callable`` that takes a single
value and returns a string. Note that the resulting string is used
as-is, i.e. it will be used directly *instead* of calling ``repr()``
(the default).
:type repr: a ``bool`` or a ``callable`` to use a custom function.
:param bool eq: If ``True`` (default), include this attribute in the
generated ``__eq__`` and ``__ne__`` methods that check two instances
for equality.
:param bool order: If ``True`` (default), include this attributes in the
generated ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods.
:param bool cmp: Setting to ``True`` is equivalent to setting ``eq=True,
order=True``. Deprecated in favor of *eq* and *order*.
:param hash: Include this attribute in the generated ``__hash__``
method. If ``None`` (default), mirror *eq*'s value. This is the
correct behavior according the Python spec. Setting this value to
anything else than ``None`` is *discouraged*.
:type hash: ``bool`` or ``None``
:param bool init: Include this attribute in the generated ``__init__``
method. It is possible to set this to ``False`` and set a default
value. In that case this attributed is unconditionally initialized
with the specified default value or factory.
:param callable converter: `callable` that is called by
``attrs``-generated ``__init__`` methods to converter attribute's value
to the desired format. It is given the passed-in value, and the
returned value will be used as the new value of the attribute. The
value is converted before being passed to the validator, if any.
:param metadata: An arbitrary mapping, to be used by third-party
components. See `extending_metadata`.
:param type: The type of the attribute. In Python 3.6 or greater, the
preferred method to specify the type is using a variable annotation
(see `PEP 526 `_).
This argument is provided for backward compatibility.
Regardless of the approach used, the type will be stored on
``Attribute.type``.
Please note that ``attrs`` doesn't do anything with this metadata by
itself. You can use it as part of your own code or for
`static type checking `.
:param kw_only: Make this attribute keyword-only (Python 3+)
in the generated ``__init__`` (if ``init`` is ``False``, this
parameter is ignored).
.. versionadded:: 15.2.0 *convert*
.. versionadded:: 16.3.0 *metadata*
.. versionchanged:: 17.1.0 *validator* can be a ``list`` now.
.. versionchanged:: 17.1.0
*hash* is ``None`` and therefore mirrors *eq* by default.
.. versionadded:: 17.3.0 *type*
.. deprecated:: 17.4.0 *convert*
.. versionadded:: 17.4.0 *converter* as a replacement for the deprecated
*convert* to achieve consistency with other noun-based arguments.
.. versionadded:: 18.1.0
``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``.
.. versionadded:: 18.2.0 *kw_only*
.. versionchanged:: 19.2.0 *convert* keyword argument removed
.. versionchanged:: 19.2.0 *repr* also accepts a custom callable.
.. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01.
.. versionadded:: 19.2.0 *eq* and *order*
"""
eq, order = _determine_eq_order(cmp, eq, order)
if hash is not None and hash is not True and hash is not False:
raise TypeError(
"Invalid value for hash. Must be True, False, or None."
)
if factory is not None:
if default is not NOTHING:
raise ValueError(
"The `default` and `factory` arguments are mutually "
"exclusive."
)
if not callable(factory):
raise ValueError("The `factory` argument must be a callable.")
default = Factory(factory)
if metadata is None:
metadata = {}
return _CountingAttr(
default=default,
validator=validator,
repr=repr,
cmp=None,
hash=hash,
init=init,
converter=converter,
metadata=metadata,
type=type,
kw_only=kw_only,
eq=eq,
order=order,
)
def _make_attr_tuple_class(cls_name, attr_names):
"""
Create a tuple subclass to hold `Attribute`s for an `attrs` class.
The subclass is a bare tuple with properties for names.
class MyClassAttributes(tuple):
__slots__ = ()
x = property(itemgetter(0))
"""
attr_class_name = "{}Attributes".format(cls_name)
attr_class_template = [
"class {}(tuple):".format(attr_class_name),
" __slots__ = ()",
]
if attr_names:
for i, attr_name in enumerate(attr_names):
attr_class_template.append(
_tuple_property_pat.format(index=i, attr_name=attr_name)
)
else:
attr_class_template.append(" pass")
globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property}
eval(compile("\n".join(attr_class_template), "", "exec"), globs)
return globs[attr_class_name]
# Tuple class for extracted attributes from a class definition.
# `base_attrs` is a subset of `attrs`.
_Attributes = _make_attr_tuple_class(
"_Attributes",
[
# all attributes to build dunder methods for
"attrs",
# attributes that have been inherited
"base_attrs",
# map inherited attributes to their originating classes
"base_attrs_map",
],
)
def _is_class_var(annot):
"""
Check whether *annot* is a typing.ClassVar.
The string comparison hack is used to avoid evaluating all string
annotations which would put attrs-based classes at a performance
disadvantage compared to plain old classes.
"""
return str(annot).startswith(_classvar_prefixes)
def _get_annotations(cls):
"""
Get annotations for *cls*.
"""
anns = getattr(cls, "__annotations__", None)
if anns is None:
return {}
# Verify that the annotations aren't merely inherited.
for base_cls in cls.__mro__[1:]:
if anns is getattr(base_cls, "__annotations__", None):
return {}
return anns
def _counter_getter(e):
"""
Key function for sorting to avoid re-creating a lambda for every class.
"""
return e[1].counter
def _transform_attrs(cls, these, auto_attribs, kw_only):
"""
Transform all `_CountingAttr`s on a class into `Attribute`s.
If *these* is passed, use that and don't look for them on the class.
Return an `_Attributes`.
"""
cd = cls.__dict__
anns = _get_annotations(cls)
if these is not None:
ca_list = [(name, ca) for name, ca in iteritems(these)]
if not isinstance(these, ordered_dict):
ca_list.sort(key=_counter_getter)
elif auto_attribs is True:
ca_names = {
name
for name, attr in cd.items()
if isinstance(attr, _CountingAttr)
}
ca_list = []
annot_names = set()
for attr_name, type in anns.items():
if _is_class_var(type):
continue
annot_names.add(attr_name)
a = cd.get(attr_name, NOTHING)
if not isinstance(a, _CountingAttr):
if a is NOTHING:
a = attrib()
else:
a = attrib(default=a)
ca_list.append((attr_name, a))
unannotated = ca_names - annot_names
if len(unannotated) > 0:
raise UnannotatedAttributeError(
"The following `attr.ib`s lack a type annotation: "
+ ", ".join(
sorted(unannotated, key=lambda n: cd.get(n).counter)
)
+ "."
)
else:
ca_list = sorted(
(
(name, attr)
for name, attr in cd.items()
if isinstance(attr, _CountingAttr)
),
key=lambda e: e[1].counter,
)
own_attrs = [
Attribute.from_counting_attr(
name=attr_name, ca=ca, type=anns.get(attr_name)
)
for attr_name, ca in ca_list
]
base_attrs = []
base_attr_map = {} # A dictionary of base attrs to their classes.
taken_attr_names = {a.name: a for a in own_attrs}
# Traverse the MRO and collect attributes.
for base_cls in cls.__mro__[1:-1]:
sub_attrs = getattr(base_cls, "__attrs_attrs__", None)
if sub_attrs is not None:
for a in sub_attrs:
prev_a = taken_attr_names.get(a.name)
# Only add an attribute if it hasn't been defined before. This
# allows for overwriting attribute definitions by subclassing.
if prev_a is None:
base_attrs.append(a)
taken_attr_names[a.name] = a
base_attr_map[a.name] = base_cls
attr_names = [a.name for a in base_attrs + own_attrs]
AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names)
if kw_only:
own_attrs = [a._assoc(kw_only=True) for a in own_attrs]
base_attrs = [a._assoc(kw_only=True) for a in base_attrs]
attrs = AttrsClass(base_attrs + own_attrs)
# Mandatory vs non-mandatory attr order only matters when they are part of
# the __init__ signature and when they aren't kw_only (which are moved to
# the end and can be mandatory or non-mandatory in any order, as they will
# be specified as keyword args anyway). Check the order of those attrs:
had_default = False
for a in (a for a in attrs if a.init is not False and a.kw_only is False):
if had_default is True and a.default is NOTHING:
raise ValueError(
"No mandatory attributes allowed after an attribute with a "
"default value or factory. Attribute in question: %r" % (a,)
)
if had_default is False and a.default is not NOTHING:
had_default = True
return _Attributes((attrs, base_attrs, base_attr_map))
def _frozen_setattrs(self, name, value):
"""
Attached to frozen classes as __setattr__.
"""
raise FrozenInstanceError()
def _frozen_delattrs(self, name):
"""
Attached to frozen classes as __delattr__.
"""
raise FrozenInstanceError()
class _ClassBuilder(object):
"""
Iteratively build *one* class.
"""
__slots__ = (
"_cls",
"_cls_dict",
"_attrs",
"_base_names",
"_attr_names",
"_slots",
"_frozen",
"_weakref_slot",
"_cache_hash",
"_has_post_init",
"_delete_attribs",
"_base_attr_map",
"_is_exc",
)
def __init__(
self,
cls,
these,
slots,
frozen,
weakref_slot,
auto_attribs,
kw_only,
cache_hash,
is_exc,
):
attrs, base_attrs, base_map = _transform_attrs(
cls, these, auto_attribs, kw_only
)
self._cls = cls
self._cls_dict = dict(cls.__dict__) if slots else {}
self._attrs = attrs
self._base_names = set(a.name for a in base_attrs)
self._base_attr_map = base_map
self._attr_names = tuple(a.name for a in attrs)
self._slots = slots
self._frozen = frozen or _has_frozen_base_class(cls)
self._weakref_slot = weakref_slot
self._cache_hash = cache_hash
self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False))
self._delete_attribs = not bool(these)
self._is_exc = is_exc
self._cls_dict["__attrs_attrs__"] = self._attrs
if frozen:
self._cls_dict["__setattr__"] = _frozen_setattrs
self._cls_dict["__delattr__"] = _frozen_delattrs
def __repr__(self):
return "<_ClassBuilder(cls={cls})>".format(cls=self._cls.__name__)
def build_class(self):
"""
Finalize class based on the accumulated configuration.
Builder cannot be used after calling this method.
"""
if self._slots is True:
return self._create_slots_class()
else:
return self._patch_original_class()
def _patch_original_class(self):
"""
Apply accumulated methods and return the class.
"""
cls = self._cls
base_names = self._base_names
# Clean class of attribute definitions (`attr.ib()`s).
if self._delete_attribs:
for name in self._attr_names:
if (
name not in base_names
and getattr(cls, name, _sentinel) is not _sentinel
):
try:
delattr(cls, name)
except AttributeError:
# This can happen if a base class defines a class
# variable and we want to set an attribute with the
# same name by using only a type annotation.
pass
# Attach our dunder methods.
for name, value in self._cls_dict.items():
setattr(cls, name, value)
# Attach __setstate__. This is necessary to clear the hash code
# cache on deserialization. See issue
# https://github.com/python-attrs/attrs/issues/482 .
# Note that this code only handles setstate for dict classes.
# For slotted classes, see similar code in _create_slots_class .
if self._cache_hash:
existing_set_state_method = getattr(cls, "__setstate__", None)
if existing_set_state_method:
raise NotImplementedError(
"Currently you cannot use hash caching if "
"you specify your own __setstate__ method."
"See https://github.com/python-attrs/attrs/issues/494 ."
)
def cache_hash_set_state(chss_self, _):
# clear hash code cache
setattr(chss_self, _hash_cache_field, None)
setattr(cls, "__setstate__", cache_hash_set_state)
return cls
def _create_slots_class(self):
"""
Build and return a new class with a `__slots__` attribute.
"""
base_names = self._base_names
cd = {
k: v
for k, v in iteritems(self._cls_dict)
if k not in tuple(self._attr_names) + ("__dict__", "__weakref__")
}
weakref_inherited = False
# Traverse the MRO to check for an existing __weakref__.
for base_cls in self._cls.__mro__[1:-1]:
if "__weakref__" in getattr(base_cls, "__dict__", ()):
weakref_inherited = True
break
names = self._attr_names
if (
self._weakref_slot
and "__weakref__" not in getattr(self._cls, "__slots__", ())
and "__weakref__" not in names
and not weakref_inherited
):
names += ("__weakref__",)
# We only add the names of attributes that aren't inherited.
# Settings __slots__ to inherited attributes wastes memory.
slot_names = [name for name in names if name not in base_names]
if self._cache_hash:
slot_names.append(_hash_cache_field)
cd["__slots__"] = tuple(slot_names)
qualname = getattr(self._cls, "__qualname__", None)
if qualname is not None:
cd["__qualname__"] = qualname
# __weakref__ is not writable.
state_attr_names = tuple(
an for an in self._attr_names if an != "__weakref__"
)
def slots_getstate(self):
"""
Automatically created by attrs.
"""
return tuple(getattr(self, name) for name in state_attr_names)
hash_caching_enabled = self._cache_hash
def slots_setstate(self, state):
"""
Automatically created by attrs.
"""
__bound_setattr = _obj_setattr.__get__(self, Attribute)
for name, value in zip(state_attr_names, state):
__bound_setattr(name, value)
# Clearing the hash code cache on deserialization is needed
# because hash codes can change from run to run. See issue
# https://github.com/python-attrs/attrs/issues/482 .
# Note that this code only handles setstate for slotted classes.
# For dict classes, see similar code in _patch_original_class .
if hash_caching_enabled:
__bound_setattr(_hash_cache_field, None)
# slots and frozen require __getstate__/__setstate__ to work
cd["__getstate__"] = slots_getstate
cd["__setstate__"] = slots_setstate
# Create new class based on old class and our methods.
cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd)
# The following is a fix for
# https://github.com/python-attrs/attrs/issues/102. On Python 3,
# if a method mentions `__class__` or uses the no-arg super(), the
# compiler will bake a reference to the class in the method itself
# as `method.__closure__`. Since we replace the class with a
# clone, we rewrite these references so it keeps working.
for item in cls.__dict__.values():
if isinstance(item, (classmethod, staticmethod)):
# Class- and staticmethods hide their functions inside.
# These might need to be rewritten as well.
closure_cells = getattr(item.__func__, "__closure__", None)
else:
closure_cells = getattr(item, "__closure__", None)
if not closure_cells: # Catch None or the empty list.
continue
for cell in closure_cells:
if cell.cell_contents is self._cls:
set_closure_cell(cell, cls)
return cls
def add_repr(self, ns):
self._cls_dict["__repr__"] = self._add_method_dunders(
_make_repr(self._attrs, ns=ns)
)
return self
def add_str(self):
repr = self._cls_dict.get("__repr__")
if repr is None:
raise ValueError(
"__str__ can only be generated if a __repr__ exists."
)
def __str__(self):
return self.__repr__()
self._cls_dict["__str__"] = self._add_method_dunders(__str__)
return self
def make_unhashable(self):
self._cls_dict["__hash__"] = None
return self
def add_hash(self):
self._cls_dict["__hash__"] = self._add_method_dunders(
_make_hash(
self._cls,
self._attrs,
frozen=self._frozen,
cache_hash=self._cache_hash,
)
)
return self
def add_init(self):
self._cls_dict["__init__"] = self._add_method_dunders(
_make_init(
self._cls,
self._attrs,
self._has_post_init,
self._frozen,
self._slots,
self._cache_hash,
self._base_attr_map,
self._is_exc,
)
)
return self
def add_eq(self):
cd = self._cls_dict
cd["__eq__"], cd["__ne__"] = (
self._add_method_dunders(meth)
for meth in _make_eq(self._cls, self._attrs)
)
return self
def add_order(self):
cd = self._cls_dict
cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = (
self._add_method_dunders(meth)
for meth in _make_order(self._cls, self._attrs)
)
return self
def _add_method_dunders(self, method):
"""
Add __module__ and __qualname__ to a *method* if possible.
"""
try:
method.__module__ = self._cls.__module__
except AttributeError:
pass
try:
method.__qualname__ = ".".join(
(self._cls.__qualname__, method.__name__)
)
except AttributeError:
pass
return method
_CMP_DEPRECATION = (
"The usage of `cmp` is deprecated and will be removed on or after "
"2021-06-01. Please use `eq` and `order` instead."
)
def _determine_eq_order(cmp, eq, order):
"""
Validate the combination of *cmp*, *eq*, and *order*. Derive the effective
values of eq and order.
"""
if cmp is not None and any((eq is not None, order is not None)):
raise ValueError("Don't mix `cmp` with `eq' and `order`.")
# cmp takes precedence due to bw-compatibility.
if cmp is not None:
warnings.warn(_CMP_DEPRECATION, DeprecationWarning, stacklevel=3)
return cmp, cmp
# If left None, equality is on and ordering mirrors equality.
if eq is None:
eq = True
if order is None:
order = eq
if eq is False and order is True:
raise ValueError("`order` can only be True if `eq` is True too.")
return eq, order
def attrs(
maybe_cls=None,
these=None,
repr_ns=None,
repr=True,
cmp=None,
hash=None,
init=True,
slots=False,
frozen=False,
weakref_slot=True,
str=False,
auto_attribs=False,
kw_only=False,
cache_hash=False,
auto_exc=False,
eq=None,
order=None,
):
r"""
A class decorator that adds `dunder
`_\ -methods according to the
specified attributes using `attr.ib` or the *these* argument.
:param these: A dictionary of name to `attr.ib` mappings. This is
useful to avoid the definition of your attributes within the class body
because you can't (e.g. if you want to add ``__repr__`` methods to
Django models) or don't want to.
If *these* is not ``None``, ``attrs`` will *not* search the class body
for attributes and will *not* remove any attributes from it.
If *these* is an ordered dict (`dict` on Python 3.6+,
`collections.OrderedDict` otherwise), the order is deduced from
the order of the attributes inside *these*. Otherwise the order
of the definition of the attributes is used.
:type these: `dict` of `str` to `attr.ib`
:param str repr_ns: When using nested classes, there's no way in Python 2
to automatically detect that. Therefore it's possible to set the
namespace explicitly for a more meaningful ``repr`` output.
:param bool repr: Create a ``__repr__`` method with a human readable
representation of ``attrs`` attributes..
:param bool str: Create a ``__str__`` method that is identical to
``__repr__``. This is usually not necessary except for
`Exception`\ s.
:param bool eq: If ``True`` or ``None`` (default), add ``__eq__`` and
``__ne__`` methods that check two instances for equality.
They compare the instances as if they were tuples of their ``attrs``
attributes, but only iff the types of both classes are *identical*!
:type eq: `bool` or `None`
:param bool order: If ``True``, add ``__lt__``, ``__le__``, ``__gt__``,
and ``__ge__`` methods that behave like *eq* above and allow instances
to be ordered. If ``None`` (default) mirror value of *eq*.
:type order: `bool` or `None`
:param cmp: Setting to ``True`` is equivalent to setting ``eq=True,
order=True``. Deprecated in favor of *eq* and *order*, has precedence
over them for backward-compatibility though. Must not be mixed with
*eq* or *order*.
:type cmp: `bool` or `None`
:param hash: If ``None`` (default), the ``__hash__`` method is generated
according how *eq* and *frozen* are set.
1. If *both* are True, ``attrs`` will generate a ``__hash__`` for you.
2. If *eq* is True and *frozen* is False, ``__hash__`` will be set to
None, marking it unhashable (which it is).
3. If *eq* is False, ``__hash__`` will be left untouched meaning the
``__hash__`` method of the base class will be used (if base class is
``object``, this means it will fall back to id-based hashing.).
Although not recommended, you can decide for yourself and force
``attrs`` to create one (e.g. if the class is immutable even though you
didn't freeze it programmatically) by passing ``True`` or not. Both of
these cases are rather special and should be used carefully.
See our documentation on `hashing`, Python's documentation on
`object.__hash__`, and the `GitHub issue that led to the default \
behavior `_ for more
details.
:type hash: ``bool`` or ``None``
:param bool init: Create a ``__init__`` method that initializes the
``attrs`` attributes. Leading underscores are stripped for the
argument name. If a ``__attrs_post_init__`` method exists on the
class, it will be called after the class is fully initialized.
:param bool slots: Create a `slotted class ` that's more
memory-efficient.
:param bool frozen: Make instances immutable after initialization. If
someone attempts to modify a frozen instance,
`attr.exceptions.FrozenInstanceError` is raised.
Please note:
1. This is achieved by installing a custom ``__setattr__`` method
on your class, so you can't implement your own.
2. True immutability is impossible in Python.
3. This *does* have a minor a runtime performance `impact
` when initializing new instances. In other words:
``__init__`` is slightly slower with ``frozen=True``.
4. If a class is frozen, you cannot modify ``self`` in
``__attrs_post_init__`` or a self-written ``__init__``. You can
circumvent that limitation by using
``object.__setattr__(self, "attribute_name", value)``.
:param bool weakref_slot: Make instances weak-referenceable. This has no
effect unless ``slots`` is also enabled.
:param bool auto_attribs: If True, collect `PEP 526`_-annotated attributes
(Python 3.6 and later only) from the class body.
In this case, you **must** annotate every field. If ``attrs``
encounters a field that is set to an `attr.ib` but lacks a type
annotation, an `attr.exceptions.UnannotatedAttributeError` is
raised. Use ``field_name: typing.Any = attr.ib(...)`` if you don't
want to set a type.
If you assign a value to those attributes (e.g. ``x: int = 42``), that
value becomes the default value like if it were passed using
``attr.ib(default=42)``. Passing an instance of `Factory` also
works as expected.
Attributes annotated as `typing.ClassVar`, and attributes that are
neither annotated nor set to an `attr.ib` are **ignored**.
.. _`PEP 526`: https://www.python.org/dev/peps/pep-0526/
:param bool kw_only: Make all attributes keyword-only (Python 3+)
in the generated ``__init__`` (if ``init`` is ``False``, this
parameter is ignored).
:param bool cache_hash: Ensure that the object's hash code is computed
only once and stored on the object. If this is set to ``True``,
hashing must be either explicitly or implicitly enabled for this
class. If the hash code is cached, avoid any reassignments of
fields involved in hash code computation or mutations of the objects
those fields point to after object creation. If such changes occur,
the behavior of the object's hash code is undefined.
:param bool auto_exc: If the class subclasses `BaseException`
(which implicitly includes any subclass of any exception), the
following happens to behave like a well-behaved Python exceptions
class:
- the values for *eq*, *order*, and *hash* are ignored and the
instances compare and hash by the instance's ids (N.B. ``attrs`` will
*not* remove existing implementations of ``__hash__`` or the equality
methods. It just won't add own ones.),
- all attributes that are either passed into ``__init__`` or have a
default value are additionally available as a tuple in the ``args``
attribute,
- the value of *str* is ignored leaving ``__str__`` to base classes.
.. versionadded:: 16.0.0 *slots*
.. versionadded:: 16.1.0 *frozen*
.. versionadded:: 16.3.0 *str*
.. versionadded:: 16.3.0 Support for ``__attrs_post_init__``.
.. versionchanged:: 17.1.0
*hash* supports ``None`` as value which is also the default now.
.. versionadded:: 17.3.0 *auto_attribs*
.. versionchanged:: 18.1.0
If *these* is passed, no attributes are deleted from the class body.
.. versionchanged:: 18.1.0 If *these* is ordered, the order is retained.
.. versionadded:: 18.2.0 *weakref_slot*
.. deprecated:: 18.2.0
``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a
`DeprecationWarning` if the classes compared are subclasses of
each other. ``__eq`` and ``__ne__`` never tried to compared subclasses
to each other.
.. versionchanged:: 19.2.0
``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider
subclasses comparable anymore.
.. versionadded:: 18.2.0 *kw_only*
.. versionadded:: 18.2.0 *cache_hash*
.. versionadded:: 19.1.0 *auto_exc*
.. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01.
.. versionadded:: 19.2.0 *eq* and *order*
"""
eq, order = _determine_eq_order(cmp, eq, order)
def wrap(cls):
if getattr(cls, "__class__", None) is None:
raise TypeError("attrs only works with new-style classes.")
is_exc = auto_exc is True and issubclass(cls, BaseException)
builder = _ClassBuilder(
cls,
these,
slots,
frozen,
weakref_slot,
auto_attribs,
kw_only,
cache_hash,
is_exc,
)
if repr is True:
builder.add_repr(repr_ns)
if str is True:
builder.add_str()
if eq is True and not is_exc:
builder.add_eq()
if order is True and not is_exc:
builder.add_order()
if hash is not True and hash is not False and hash is not None:
# Can't use `hash in` because 1 == True for example.
raise TypeError(
"Invalid value for hash. Must be True, False, or None."
)
elif hash is False or (hash is None and eq is False) or is_exc:
# Don't do anything. Should fall back to __object__'s __hash__
# which is by id.
if cache_hash:
raise TypeError(
"Invalid value for cache_hash. To use hash caching,"
" hashing must be either explicitly or implicitly "
"enabled."
)
elif hash is True or (hash is None and eq is True and frozen is True):
# Build a __hash__ if told so, or if it's safe.
builder.add_hash()
else:
# Raise TypeError on attempts to hash.
if cache_hash:
raise TypeError(
"Invalid value for cache_hash. To use hash caching,"
" hashing must be either explicitly or implicitly "
"enabled."
)
builder.make_unhashable()
if init is True:
builder.add_init()
else:
if cache_hash:
raise TypeError(
"Invalid value for cache_hash. To use hash caching,"
" init must be True."
)
return builder.build_class()
# maybe_cls's type depends on the usage of the decorator. It's a class
# if it's used as `@attrs` but ``None`` if used as `@attrs()`.
if maybe_cls is None:
return wrap
else:
return wrap(maybe_cls)
_attrs = attrs
"""
Internal alias so we can use it in functions that take an argument called
*attrs*.
"""
if PY2:
def _has_frozen_base_class(cls):
"""
Check whether *cls* has a frozen ancestor by looking at its
__setattr__.
"""
return (
getattr(cls.__setattr__, "__module__", None)
== _frozen_setattrs.__module__
and cls.__setattr__.__name__ == _frozen_setattrs.__name__
)
else:
def _has_frozen_base_class(cls):
"""
Check whether *cls* has a frozen ancestor by looking at its
__setattr__.
"""
return cls.__setattr__ == _frozen_setattrs
def _attrs_to_tuple(obj, attrs):
"""
Create a tuple of all values of *obj*'s *attrs*.
"""
return tuple(getattr(obj, a.name) for a in attrs)
def _generate_unique_filename(cls, func_name):
"""
Create a "filename" suitable for a function being generated.
"""
unique_id = uuid.uuid4()
extra = ""
count = 1
while True:
unique_filename = "".format(
func_name,
cls.__module__,
getattr(cls, "__qualname__", cls.__name__),
extra,
)
# To handle concurrency we essentially "reserve" our spot in
# the linecache with a dummy line. The caller can then
# set this value correctly.
cache_line = (1, None, (str(unique_id),), unique_filename)
if (
linecache.cache.setdefault(unique_filename, cache_line)
== cache_line
):
return unique_filename
# Looks like this spot is taken. Try again.
count += 1
extra = "-{0}".format(count)
def _make_hash(cls, attrs, frozen, cache_hash):
attrs = tuple(
a for a in attrs if a.hash is True or (a.hash is None and a.eq is True)
)
tab = " "
unique_filename = _generate_unique_filename(cls, "hash")
type_hash = hash(unique_filename)
method_lines = ["def __hash__(self):"]
def append_hash_computation_lines(prefix, indent):
"""
Generate the code for actually computing the hash code.
Below this will either be returned directly or used to compute
a value which is then cached, depending on the value of cache_hash
"""
method_lines.extend(
[indent + prefix + "hash((", indent + " %d," % (type_hash,)]
)
for a in attrs:
method_lines.append(indent + " self.%s," % a.name)
method_lines.append(indent + " ))")
if cache_hash:
method_lines.append(tab + "if self.%s is None:" % _hash_cache_field)
if frozen:
append_hash_computation_lines(
"object.__setattr__(self, '%s', " % _hash_cache_field, tab * 2
)
method_lines.append(tab * 2 + ")") # close __setattr__
else:
append_hash_computation_lines(
"self.%s = " % _hash_cache_field, tab * 2
)
method_lines.append(tab + "return self.%s" % _hash_cache_field)
else:
append_hash_computation_lines("return ", tab)
script = "\n".join(method_lines)
globs = {}
locs = {}
bytecode = compile(script, unique_filename, "exec")
eval(bytecode, globs, locs)
# In order of debuggers like PDB being able to step through the code,
# we add a fake linecache entry.
linecache.cache[unique_filename] = (
len(script),
None,
script.splitlines(True),
unique_filename,
)
return locs["__hash__"]
def _add_hash(cls, attrs):
"""
Add a hash method to *cls*.
"""
cls.__hash__ = _make_hash(cls, attrs, frozen=False, cache_hash=False)
return cls
def __ne__(self, other):
"""
Check equality and either forward a NotImplemented or return the result
negated.
"""
result = self.__eq__(other)
if result is NotImplemented:
return NotImplemented
return not result
def _make_eq(cls, attrs):
attrs = [a for a in attrs if a.eq]
unique_filename = _generate_unique_filename(cls, "eq")
lines = [
"def __eq__(self, other):",
" if other.__class__ is not self.__class__:",
" return NotImplemented",
]
# We can't just do a big self.x = other.x and... clause due to
# irregularities like nan == nan is false but (nan,) == (nan,) is true.
if attrs:
lines.append(" return (")
others = [" ) == ("]
for a in attrs:
lines.append(" self.%s," % (a.name,))
others.append(" other.%s," % (a.name,))
lines += others + [" )"]
else:
lines.append(" return True")
script = "\n".join(lines)
globs = {}
locs = {}
bytecode = compile(script, unique_filename, "exec")
eval(bytecode, globs, locs)
# In order of debuggers like PDB being able to step through the code,
# we add a fake linecache entry.
linecache.cache[unique_filename] = (
len(script),
None,
script.splitlines(True),
unique_filename,
)
return locs["__eq__"], __ne__
def _make_order(cls, attrs):
attrs = [a for a in attrs if a.order]
def attrs_to_tuple(obj):
"""
Save us some typing.
"""
return _attrs_to_tuple(obj, attrs)
def __lt__(self, other):
"""
Automatically created by attrs.
"""
if other.__class__ is self.__class__:
return attrs_to_tuple(self) < attrs_to_tuple(other)
return NotImplemented
def __le__(self, other):
"""
Automatically created by attrs.
"""
if other.__class__ is self.__class__:
return attrs_to_tuple(self) <= attrs_to_tuple(other)
return NotImplemented
def __gt__(self, other):
"""
Automatically created by attrs.
"""
if other.__class__ is self.__class__:
return attrs_to_tuple(self) > attrs_to_tuple(other)
return NotImplemented
def __ge__(self, other):
"""
Automatically created by attrs.
"""
if other.__class__ is self.__class__:
return attrs_to_tuple(self) >= attrs_to_tuple(other)
return NotImplemented
return __lt__, __le__, __gt__, __ge__
def _add_eq(cls, attrs=None):
"""
Add equality methods to *cls* with *attrs*.
"""
if attrs is None:
attrs = cls.__attrs_attrs__
cls.__eq__, cls.__ne__ = _make_eq(cls, attrs)
return cls
_already_repring = threading.local()
def _make_repr(attrs, ns):
"""
Make a repr method that includes relevant *attrs*, adding *ns* to the full
name.
"""
# Figure out which attributes to include, and which function to use to
# format them. The a.repr value can be either bool or a custom callable.
attr_names_with_reprs = tuple(
(a.name, repr if a.repr is True else a.repr)
for a in attrs
if a.repr is not False
)
def __repr__(self):
"""
Automatically created by attrs.
"""
try:
working_set = _already_repring.working_set
except AttributeError:
working_set = set()
_already_repring.working_set = working_set
if id(self) in working_set:
return "..."
real_cls = self.__class__
if ns is None:
qualname = getattr(real_cls, "__qualname__", None)
if qualname is not None:
class_name = qualname.rsplit(">.", 1)[-1]
else:
class_name = real_cls.__name__
else:
class_name = ns + "." + real_cls.__name__
# Since 'self' remains on the stack (i.e.: strongly referenced) for the
# duration of this call, it's safe to depend on id(...) stability, and
# not need to track the instance and therefore worry about properties
# like weakref- or hash-ability.
working_set.add(id(self))
try:
result = [class_name, "("]
first = True
for name, attr_repr in attr_names_with_reprs:
if first:
first = False
else:
result.append(", ")
result.extend(
(name, "=", attr_repr(getattr(self, name, NOTHING)))
)
return "".join(result) + ")"
finally:
working_set.remove(id(self))
return __repr__
def _add_repr(cls, ns=None, attrs=None):
"""
Add a repr method to *cls*.
"""
if attrs is None:
attrs = cls.__attrs_attrs__
cls.__repr__ = _make_repr(attrs, ns)
return cls
def _make_init(
cls, attrs, post_init, frozen, slots, cache_hash, base_attr_map, is_exc
):
attrs = [a for a in attrs if a.init or a.default is not NOTHING]
unique_filename = _generate_unique_filename(cls, "init")
script, globs, annotations = _attrs_to_init_script(
attrs, frozen, slots, post_init, cache_hash, base_attr_map, is_exc
)
locs = {}
bytecode = compile(script, unique_filename, "exec")
attr_dict = dict((a.name, a) for a in attrs)
globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict})
if frozen is True:
# Save the lookup overhead in __init__ if we need to circumvent
# immutability.
globs["_cached_setattr"] = _obj_setattr
eval(bytecode, globs, locs)
# In order of debuggers like PDB being able to step through the code,
# we add a fake linecache entry.
linecache.cache[unique_filename] = (
len(script),
None,
script.splitlines(True),
unique_filename,
)
__init__ = locs["__init__"]
__init__.__annotations__ = annotations
return __init__
def fields(cls):
"""
Return the tuple of ``attrs`` attributes for a class.
The tuple also allows accessing the fields by their names (see below for
examples).
:param type cls: Class to introspect.
:raise TypeError: If *cls* is not a class.
:raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
class.
:rtype: tuple (with name accessors) of `attr.Attribute`
.. versionchanged:: 16.2.0 Returned tuple allows accessing the fields
by name.
"""
if not isclass(cls):
raise TypeError("Passed object must be a class.")
attrs = getattr(cls, "__attrs_attrs__", None)
if attrs is None:
raise NotAnAttrsClassError(
"{cls!r} is not an attrs-decorated class.".format(cls=cls)
)
return attrs
def fields_dict(cls):
"""
Return an ordered dictionary of ``attrs`` attributes for a class, whose
keys are the attribute names.
:param type cls: Class to introspect.
:raise TypeError: If *cls* is not a class.
:raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
class.
:rtype: an ordered dict where keys are attribute names and values are
`attr.Attribute`\\ s. This will be a `dict` if it's
naturally ordered like on Python 3.6+ or an
:class:`~collections.OrderedDict` otherwise.
.. versionadded:: 18.1.0
"""
if not isclass(cls):
raise TypeError("Passed object must be a class.")
attrs = getattr(cls, "__attrs_attrs__", None)
if attrs is None:
raise NotAnAttrsClassError(
"{cls!r} is not an attrs-decorated class.".format(cls=cls)
)
return ordered_dict(((a.name, a) for a in attrs))
def validate(inst):
"""
Validate all attributes on *inst* that have a validator.
Leaves all exceptions through.
:param inst: Instance of a class with ``attrs`` attributes.
"""
if _config._run_validators is False:
return
for a in fields(inst.__class__):
v = a.validator
if v is not None:
v(inst, a, getattr(inst, a.name))
def _is_slot_cls(cls):
return "__slots__" in cls.__dict__
def _is_slot_attr(a_name, base_attr_map):
"""
Check if the attribute name comes from a slot class.
"""
return a_name in base_attr_map and _is_slot_cls(base_attr_map[a_name])
def _attrs_to_init_script(
attrs, frozen, slots, post_init, cache_hash, base_attr_map, is_exc
):
"""
Return a script of an initializer for *attrs* and a dict of globals.
The globals are expected by the generated script.
If *frozen* is True, we cannot set the attributes directly so we use
a cached ``object.__setattr__``.
"""
lines = []
any_slot_ancestors = any(
_is_slot_attr(a.name, base_attr_map) for a in attrs
)
if frozen is True:
if slots is True:
lines.append(
# Circumvent the __setattr__ descriptor to save one lookup per
# assignment.
# Note _setattr will be used again below if cache_hash is True
"_setattr = _cached_setattr.__get__(self, self.__class__)"
)
def fmt_setter(attr_name, value_var):
return "_setattr('%(attr_name)s', %(value_var)s)" % {
"attr_name": attr_name,
"value_var": value_var,
}
def fmt_setter_with_converter(attr_name, value_var):
conv_name = _init_converter_pat.format(attr_name)
return "_setattr('%(attr_name)s', %(conv)s(%(value_var)s))" % {
"attr_name": attr_name,
"value_var": value_var,
"conv": conv_name,
}
else:
# Dict frozen classes assign directly to __dict__.
# But only if the attribute doesn't come from an ancestor slot
# class.
# Note _inst_dict will be used again below if cache_hash is True
lines.append("_inst_dict = self.__dict__")
if any_slot_ancestors:
lines.append(
# Circumvent the __setattr__ descriptor to save one lookup
# per assignment.
"_setattr = _cached_setattr.__get__(self, self.__class__)"
)
def fmt_setter(attr_name, value_var):
if _is_slot_attr(attr_name, base_attr_map):
res = "_setattr('%(attr_name)s', %(value_var)s)" % {
"attr_name": attr_name,
"value_var": value_var,
}
else:
res = "_inst_dict['%(attr_name)s'] = %(value_var)s" % {
"attr_name": attr_name,
"value_var": value_var,
}
return res
def fmt_setter_with_converter(attr_name, value_var):
conv_name = _init_converter_pat.format(attr_name)
if _is_slot_attr(attr_name, base_attr_map):
tmpl = "_setattr('%(attr_name)s', %(c)s(%(value_var)s))"
else:
tmpl = "_inst_dict['%(attr_name)s'] = %(c)s(%(value_var)s)"
return tmpl % {
"attr_name": attr_name,
"value_var": value_var,
"c": conv_name,
}
else:
# Not frozen.
def fmt_setter(attr_name, value):
return "self.%(attr_name)s = %(value)s" % {
"attr_name": attr_name,
"value": value,
}
def fmt_setter_with_converter(attr_name, value_var):
conv_name = _init_converter_pat.format(attr_name)
return "self.%(attr_name)s = %(conv)s(%(value_var)s)" % {
"attr_name": attr_name,
"value_var": value_var,
"conv": conv_name,
}
args = []
kw_only_args = []
attrs_to_validate = []
# This is a dictionary of names to validator and converter callables.
# Injecting this into __init__ globals lets us avoid lookups.
names_for_globals = {}
annotations = {"return": None}
for a in attrs:
if a.validator:
attrs_to_validate.append(a)
attr_name = a.name
arg_name = a.name.lstrip("_")
has_factory = isinstance(a.default, Factory)
if has_factory and a.default.takes_self:
maybe_self = "self"
else:
maybe_self = ""
if a.init is False:
if has_factory:
init_factory_name = _init_factory_pat.format(a.name)
if a.converter is not None:
lines.append(
fmt_setter_with_converter(
attr_name,
init_factory_name + "({0})".format(maybe_self),
)
)
conv_name = _init_converter_pat.format(a.name)
names_for_globals[conv_name] = a.converter
else:
lines.append(
fmt_setter(
attr_name,
init_factory_name + "({0})".format(maybe_self),
)
)
names_for_globals[init_factory_name] = a.default.factory
else:
if a.converter is not None:
lines.append(
fmt_setter_with_converter(
attr_name,
"attr_dict['{attr_name}'].default".format(
attr_name=attr_name
),
)
)
conv_name = _init_converter_pat.format(a.name)
names_for_globals[conv_name] = a.converter
else:
lines.append(
fmt_setter(
attr_name,
"attr_dict['{attr_name}'].default".format(
attr_name=attr_name
),
)
)
elif a.default is not NOTHING and not has_factory:
arg = "{arg_name}=attr_dict['{attr_name}'].default".format(
arg_name=arg_name, attr_name=attr_name
)
if a.kw_only:
kw_only_args.append(arg)
else:
args.append(arg)
if a.converter is not None:
lines.append(fmt_setter_with_converter(attr_name, arg_name))
names_for_globals[
_init_converter_pat.format(a.name)
] = a.converter
else:
lines.append(fmt_setter(attr_name, arg_name))
elif has_factory:
arg = "{arg_name}=NOTHING".format(arg_name=arg_name)
if a.kw_only:
kw_only_args.append(arg)
else:
args.append(arg)
lines.append(
"if {arg_name} is not NOTHING:".format(arg_name=arg_name)
)
init_factory_name = _init_factory_pat.format(a.name)
if a.converter is not None:
lines.append(
" " + fmt_setter_with_converter(attr_name, arg_name)
)
lines.append("else:")
lines.append(
" "
+ fmt_setter_with_converter(
attr_name,
init_factory_name + "({0})".format(maybe_self),
)
)
names_for_globals[
_init_converter_pat.format(a.name)
] = a.converter
else:
lines.append(" " + fmt_setter(attr_name, arg_name))
lines.append("else:")
lines.append(
" "
+ fmt_setter(
attr_name,
init_factory_name + "({0})".format(maybe_self),
)
)
names_for_globals[init_factory_name] = a.default.factory
else:
if a.kw_only:
kw_only_args.append(arg_name)
else:
args.append(arg_name)
if a.converter is not None:
lines.append(fmt_setter_with_converter(attr_name, arg_name))
names_for_globals[
_init_converter_pat.format(a.name)
] = a.converter
else:
lines.append(fmt_setter(attr_name, arg_name))
if a.init is True and a.converter is None and a.type is not None:
annotations[arg_name] = a.type
if attrs_to_validate: # we can skip this if there are no validators.
names_for_globals["_config"] = _config
lines.append("if _config._run_validators is True:")
for a in attrs_to_validate:
val_name = "__attr_validator_{}".format(a.name)
attr_name = "__attr_{}".format(a.name)
lines.append(
" {}(self, {}, self.{})".format(val_name, attr_name, a.name)
)
names_for_globals[val_name] = a.validator
names_for_globals[attr_name] = a
if post_init:
lines.append("self.__attrs_post_init__()")
# because this is set only after __attrs_post_init is called, a crash
# will result if post-init tries to access the hash code. This seemed
# preferable to setting this beforehand, in which case alteration to
# field values during post-init combined with post-init accessing the
# hash code would result in silent bugs.
if cache_hash:
if frozen:
if slots:
# if frozen and slots, then _setattr defined above
init_hash_cache = "_setattr('%s', %s)"
else:
# if frozen and not slots, then _inst_dict defined above
init_hash_cache = "_inst_dict['%s'] = %s"
else:
init_hash_cache = "self.%s = %s"
lines.append(init_hash_cache % (_hash_cache_field, "None"))
# For exceptions we rely on BaseException.__init__ for proper
# initialization.
if is_exc:
vals = ",".join("self." + a.name for a in attrs if a.init)
lines.append("BaseException.__init__(self, %s)" % (vals,))
args = ", ".join(args)
if kw_only_args:
if PY2:
raise PythonTooOldError(
"Keyword-only arguments only work on Python 3 and later."
)
args += "{leading_comma}*, {kw_only_args}".format(
leading_comma=", " if args else "",
kw_only_args=", ".join(kw_only_args),
)
return (
"""\
def __init__(self, {args}):
{lines}
""".format(
args=args, lines="\n ".join(lines) if lines else "pass"
),
names_for_globals,
annotations,
)
class Attribute(object):
"""
*Read-only* representation of an attribute.
:attribute name: The name of the attribute.
Plus *all* arguments of `attr.ib` (except for ``factory``
which is only syntactic sugar for ``default=Factory(...)``.
For the version history of the fields, see `attr.ib`.
"""
__slots__ = (
"name",
"default",
"validator",
"repr",
"eq",
"order",
"hash",
"init",
"metadata",
"type",
"converter",
"kw_only",
)
def __init__(
self,
name,
default,
validator,
repr,
cmp, # XXX: unused, remove along with other cmp code.
hash,
init,
metadata=None,
type=None,
converter=None,
kw_only=False,
eq=None,
order=None,
):
eq, order = _determine_eq_order(cmp, eq, order)
# Cache this descriptor here to speed things up later.
bound_setattr = _obj_setattr.__get__(self, Attribute)
# Despite the big red warning, people *do* instantiate `Attribute`
# themselves.
bound_setattr("name", name)
bound_setattr("default", default)
bound_setattr("validator", validator)
bound_setattr("repr", repr)
bound_setattr("eq", eq)
bound_setattr("order", order)
bound_setattr("hash", hash)
bound_setattr("init", init)
bound_setattr("converter", converter)
bound_setattr(
"metadata",
(
metadata_proxy(metadata)
if metadata
else _empty_metadata_singleton
),
)
bound_setattr("type", type)
bound_setattr("kw_only", kw_only)
def __setattr__(self, name, value):
raise FrozenInstanceError()
@classmethod
def from_counting_attr(cls, name, ca, type=None):
# type holds the annotated value. deal with conflicts:
if type is None:
type = ca.type
elif ca.type is not None:
raise ValueError(
"Type annotation and type argument cannot both be present"
)
inst_dict = {
k: getattr(ca, k)
for k in Attribute.__slots__
if k
not in (
"name",
"validator",
"default",
"type",
) # exclude methods and deprecated alias
}
return cls(
name=name,
validator=ca._validator,
default=ca._default,
type=type,
cmp=None,
**inst_dict
)
@property
def cmp(self):
"""
Simulate the presence of a cmp attribute and warn.
"""
warnings.warn(_CMP_DEPRECATION, DeprecationWarning, stacklevel=2)
return self.eq and self.order
# Don't use attr.assoc since fields(Attribute) doesn't work
def _assoc(self, **changes):
"""
Copy *self* and apply *changes*.
"""
new = copy.copy(self)
new._setattrs(changes.items())
return new
# Don't use _add_pickle since fields(Attribute) doesn't work
def __getstate__(self):
"""
Play nice with pickle.
"""
return tuple(
getattr(self, name) if name != "metadata" else dict(self.metadata)
for name in self.__slots__
)
def __setstate__(self, state):
"""
Play nice with pickle.
"""
self._setattrs(zip(self.__slots__, state))
def _setattrs(self, name_values_pairs):
bound_setattr = _obj_setattr.__get__(self, Attribute)
for name, value in name_values_pairs:
if name != "metadata":
bound_setattr(name, value)
else:
bound_setattr(
name,
metadata_proxy(value)
if value
else _empty_metadata_singleton,
)
_a = [
Attribute(
name=name,
default=NOTHING,
validator=None,
repr=True,
cmp=None,
eq=True,
order=False,
hash=(name != "metadata"),
init=True,
)
for name in Attribute.__slots__
]
Attribute = _add_hash(
_add_eq(_add_repr(Attribute, attrs=_a), attrs=_a),
attrs=[a for a in _a if a.hash],
)
class _CountingAttr(object):
"""
Intermediate representation of attributes that uses a counter to preserve
the order in which the attributes have been defined.
*Internal* data structure of the attrs library. Running into is most
likely the result of a bug like a forgotten `@attr.s` decorator.
"""
__slots__ = (
"counter",
"_default",
"repr",
"eq",
"order",
"hash",
"init",
"metadata",
"_validator",
"converter",
"type",
"kw_only",
)
__attrs_attrs__ = tuple(
Attribute(
name=name,
default=NOTHING,
validator=None,
repr=True,
cmp=None,
hash=True,
init=True,
kw_only=False,
eq=True,
order=False,
)
for name in (
"counter",
"_default",
"repr",
"eq",
"order",
"hash",
"init",
)
) + (
Attribute(
name="metadata",
default=None,
validator=None,
repr=True,
cmp=None,
hash=False,
init=True,
kw_only=False,
eq=True,
order=False,
),
)
cls_counter = 0
def __init__(
self,
default,
validator,
repr,
cmp, # XXX: unused, remove along with cmp
hash,
init,
converter,
metadata,
type,
kw_only,
eq,
order,
):
_CountingAttr.cls_counter += 1
self.counter = _CountingAttr.cls_counter
self._default = default
# If validator is a list/tuple, wrap it using helper validator.
if validator and isinstance(validator, (list, tuple)):
self._validator = and_(*validator)
else:
self._validator = validator
self.repr = repr
self.eq = eq
self.order = order
self.hash = hash
self.init = init
self.converter = converter
self.metadata = metadata
self.type = type
self.kw_only = kw_only
def validator(self, meth):
"""
Decorator that adds *meth* to the list of validators.
Returns *meth* unchanged.
.. versionadded:: 17.1.0
"""
if self._validator is None:
self._validator = meth
else:
self._validator = and_(self._validator, meth)
return meth
def default(self, meth):
"""
Decorator that allows to set the default for an attribute.
Returns *meth* unchanged.
:raises DefaultAlreadySetError: If default has been set before.
.. versionadded:: 17.1.0
"""
if self._default is not NOTHING:
raise DefaultAlreadySetError()
self._default = Factory(meth, takes_self=True)
return meth
_CountingAttr = _add_eq(_add_repr(_CountingAttr))
@attrs(slots=True, init=False, hash=True)
class Factory(object):
"""
Stores a factory callable.
If passed as the default value to `attr.ib`, the factory is used to
generate a new value.
:param callable factory: A callable that takes either none or exactly one
mandatory positional argument depending on *takes_self*.
:param bool takes_self: Pass the partially initialized instance that is
being initialized as a positional argument.
.. versionadded:: 17.1.0 *takes_self*
"""
factory = attrib()
takes_self = attrib()
def __init__(self, factory, takes_self=False):
"""
`Factory` is part of the default machinery so if we want a default
value here, we have to implement it ourselves.
"""
self.factory = factory
self.takes_self = takes_self
def make_class(name, attrs, bases=(object,), **attributes_arguments):
"""
A quick way to create a new class called *name* with *attrs*.
:param name: The name for the new class.
:type name: str
:param attrs: A list of names or a dictionary of mappings of names to
attributes.
If *attrs* is a list or an ordered dict (`dict` on Python 3.6+,
`collections.OrderedDict` otherwise), the order is deduced from
the order of the names or attributes inside *attrs*. Otherwise the
order of the definition of the attributes is used.
:type attrs: `list` or `dict`
:param tuple bases: Classes that the new class will subclass.
:param attributes_arguments: Passed unmodified to `attr.s`.
:return: A new class with *attrs*.
:rtype: type
.. versionadded:: 17.1.0 *bases*
.. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained.
"""
if isinstance(attrs, dict):
cls_dict = attrs
elif isinstance(attrs, (list, tuple)):
cls_dict = dict((a, attrib()) for a in attrs)
else:
raise TypeError("attrs argument must be a dict or a list.")
post_init = cls_dict.pop("__attrs_post_init__", None)
type_ = type(
name,
bases,
{} if post_init is None else {"__attrs_post_init__": post_init},
)
# For pickling to work, the __module__ variable needs to be set to the
# frame where the class is created. Bypass this step in environments where
# sys._getframe is not defined (Jython for example) or sys._getframe is not
# defined for arguments greater than 0 (IronPython).
try:
type_.__module__ = sys._getframe(1).f_globals.get(
"__name__", "__main__"
)
except (AttributeError, ValueError):
pass
# We do it here for proper warnings with meaningful stacklevel.
cmp = attributes_arguments.pop("cmp", None)
attributes_arguments["eq"], attributes_arguments[
"order"
] = _determine_eq_order(
cmp, attributes_arguments.get("eq"), attributes_arguments.get("order")
)
return _attrs(these=cls_dict, **attributes_arguments)(type_)
# These are required by within this module so we define them here and merely
# import into .validators.
@attrs(slots=True, hash=True)
class _AndValidator(object):
"""
Compose many validators to a single one.
"""
_validators = attrib()
def __call__(self, inst, attr, value):
for v in self._validators:
v(inst, attr, value)
def and_(*validators):
"""
A validator that composes multiple validators into one.
When called on a value, it runs all wrapped validators.
:param validators: Arbitrary number of validators.
:type validators: callables
.. versionadded:: 17.1.0
"""
vals = []
for validator in validators:
vals.extend(
validator._validators
if isinstance(validator, _AndValidator)
else [validator]
)
return _AndValidator(tuple(vals))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/_version_info.py
================================================
from __future__ import absolute_import, division, print_function
from functools import total_ordering
from ._funcs import astuple
from ._make import attrib, attrs
@total_ordering
@attrs(eq=False, order=False, slots=True, frozen=True)
class VersionInfo(object):
"""
A version object that can be compared to tuple of length 1--4:
>>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2)
True
>>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1)
True
>>> vi = attr.VersionInfo(19, 2, 0, "final")
>>> vi < (19, 1, 1)
False
>>> vi < (19,)
False
>>> vi == (19, 2,)
True
>>> vi == (19, 2, 1)
False
.. versionadded:: 19.2
"""
year = attrib(type=int)
minor = attrib(type=int)
micro = attrib(type=int)
releaselevel = attrib(type=str)
@classmethod
def _from_version_string(cls, s):
"""
Parse *s* and return a _VersionInfo.
"""
v = s.split(".")
if len(v) == 3:
v.append("final")
return cls(
year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3]
)
def _ensure_tuple(self, other):
"""
Ensure *other* is a tuple of a valid length.
Returns a possibly transformed *other* and ourselves as a tuple of
the same length as *other*.
"""
if self.__class__ is other.__class__:
other = astuple(other)
if not isinstance(other, tuple):
raise NotImplementedError
if not (1 <= len(other) <= 4):
raise NotImplementedError
return astuple(self)[: len(other)], other
def __eq__(self, other):
try:
us, them = self._ensure_tuple(other)
except NotImplementedError:
return NotImplemented
return us == them
def __lt__(self, other):
try:
us, them = self._ensure_tuple(other)
except NotImplementedError:
return NotImplemented
# Since alphabetically "dev0" < "final" < "post1" < "post2", we don't
# have to do anything special with releaselevel for now.
return us < them
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/_version_info.pyi
================================================
class VersionInfo:
@property
def year(self) -> int: ...
@property
def minor(self) -> int: ...
@property
def micro(self) -> int: ...
@property
def releaselevel(self) -> str: ...
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/converters.py
================================================
"""
Commonly useful converters.
"""
from __future__ import absolute_import, division, print_function
from ._make import NOTHING, Factory
def optional(converter):
"""
A converter that allows an attribute to be optional. An optional attribute
is one which can be set to ``None``.
:param callable converter: the converter that is used for non-``None``
values.
.. versionadded:: 17.1.0
"""
def optional_converter(val):
if val is None:
return None
return converter(val)
return optional_converter
def default_if_none(default=NOTHING, factory=None):
"""
A converter that allows to replace ``None`` values by *default* or the
result of *factory*.
:param default: Value to be used if ``None`` is passed. Passing an instance
of `attr.Factory` is supported, however the ``takes_self`` option
is *not*.
:param callable factory: A callable that takes not parameters whose result
is used if ``None`` is passed.
:raises TypeError: If **neither** *default* or *factory* is passed.
:raises TypeError: If **both** *default* and *factory* are passed.
:raises ValueError: If an instance of `attr.Factory` is passed with
``takes_self=True``.
.. versionadded:: 18.2.0
"""
if default is NOTHING and factory is None:
raise TypeError("Must pass either `default` or `factory`.")
if default is not NOTHING and factory is not None:
raise TypeError(
"Must pass either `default` or `factory` but not both."
)
if factory is not None:
default = Factory(factory)
if isinstance(default, Factory):
if default.takes_self:
raise ValueError(
"`takes_self` is not supported by default_if_none."
)
def default_if_none_converter(val):
if val is not None:
return val
return default.factory()
else:
def default_if_none_converter(val):
if val is not None:
return val
return default
return default_if_none_converter
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/converters.pyi
================================================
from typing import TypeVar, Optional, Callable, overload
from . import _ConverterType
_T = TypeVar("_T")
def optional(
converter: _ConverterType[_T]
) -> _ConverterType[Optional[_T]]: ...
@overload
def default_if_none(default: _T) -> _ConverterType[_T]: ...
@overload
def default_if_none(*, factory: Callable[[], _T]) -> _ConverterType[_T]: ...
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/exceptions.py
================================================
from __future__ import absolute_import, division, print_function
class FrozenInstanceError(AttributeError):
"""
A frozen/immutable instance has been attempted to be modified.
It mirrors the behavior of ``namedtuples`` by using the same error message
and subclassing `AttributeError`.
.. versionadded:: 16.1.0
"""
msg = "can't set attribute"
args = [msg]
class AttrsAttributeNotFoundError(ValueError):
"""
An ``attrs`` function couldn't find an attribute that the user asked for.
.. versionadded:: 16.2.0
"""
class NotAnAttrsClassError(ValueError):
"""
A non-``attrs`` class has been passed into an ``attrs`` function.
.. versionadded:: 16.2.0
"""
class DefaultAlreadySetError(RuntimeError):
"""
A default has been set using ``attr.ib()`` and is attempted to be reset
using the decorator.
.. versionadded:: 17.1.0
"""
class UnannotatedAttributeError(RuntimeError):
"""
A class with ``auto_attribs=True`` has an ``attr.ib()`` without a type
annotation.
.. versionadded:: 17.3.0
"""
class PythonTooOldError(RuntimeError):
"""
An ``attrs`` feature requiring a more recent python version has been used.
.. versionadded:: 18.2.0
"""
class NotCallableError(TypeError):
"""
A ``attr.ib()`` requiring a callable has been set with a value
that is not callable.
.. versionadded:: 19.2.0
"""
def __init__(self, msg, value):
super(TypeError, self).__init__(msg, value)
self.msg = msg
self.value = value
def __str__(self):
return str(self.msg)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/exceptions.pyi
================================================
from typing import Any
class FrozenInstanceError(AttributeError):
msg: str = ...
class AttrsAttributeNotFoundError(ValueError): ...
class NotAnAttrsClassError(ValueError): ...
class DefaultAlreadySetError(RuntimeError): ...
class UnannotatedAttributeError(RuntimeError): ...
class PythonTooOldError(RuntimeError): ...
class NotCallableError(TypeError):
msg: str = ...
value: Any = ...
def __init__(self, msg: str, value: Any) -> None: ...
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/filters.py
================================================
"""
Commonly useful filters for `attr.asdict`.
"""
from __future__ import absolute_import, division, print_function
from ._compat import isclass
from ._make import Attribute
def _split_what(what):
"""
Returns a tuple of `frozenset`s of classes and attributes.
"""
return (
frozenset(cls for cls in what if isclass(cls)),
frozenset(cls for cls in what if isinstance(cls, Attribute)),
)
def include(*what):
"""
Whitelist *what*.
:param what: What to whitelist.
:type what: `list` of `type` or `attr.Attribute`\\ s
:rtype: `callable`
"""
cls, attrs = _split_what(what)
def include_(attribute, value):
return value.__class__ in cls or attribute in attrs
return include_
def exclude(*what):
"""
Blacklist *what*.
:param what: What to blacklist.
:type what: `list` of classes or `attr.Attribute`\\ s.
:rtype: `callable`
"""
cls, attrs = _split_what(what)
def exclude_(attribute, value):
return value.__class__ not in cls and attribute not in attrs
return exclude_
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/filters.pyi
================================================
from typing import Union, Any
from . import Attribute, _FilterType
def include(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ...
def exclude(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ...
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/py.typed
================================================
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/validators.py
================================================
"""
Commonly useful validators.
"""
from __future__ import absolute_import, division, print_function
import re
from ._make import _AndValidator, and_, attrib, attrs
from .exceptions import NotCallableError
__all__ = [
"and_",
"deep_iterable",
"deep_mapping",
"in_",
"instance_of",
"is_callable",
"matches_re",
"optional",
"provides",
]
@attrs(repr=False, slots=True, hash=True)
class _InstanceOfValidator(object):
type = attrib()
def __call__(self, inst, attr, value):
"""
We use a callable class to be able to change the ``__repr__``.
"""
if not isinstance(value, self.type):
raise TypeError(
"'{name}' must be {type!r} (got {value!r} that is a "
"{actual!r}).".format(
name=attr.name,
type=self.type,
actual=value.__class__,
value=value,
),
attr,
self.type,
value,
)
def __repr__(self):
return "".format(
type=self.type
)
def instance_of(type):
"""
A validator that raises a `TypeError` if the initializer is called
with a wrong type for this particular attribute (checks are performed using
`isinstance` therefore it's also valid to pass a tuple of types).
:param type: The type to check for.
:type type: type or tuple of types
:raises TypeError: With a human readable error message, the attribute
(of type `attr.Attribute`), the expected type, and the value it
got.
"""
return _InstanceOfValidator(type)
@attrs(repr=False, frozen=True)
class _MatchesReValidator(object):
regex = attrib()
flags = attrib()
match_func = attrib()
def __call__(self, inst, attr, value):
"""
We use a callable class to be able to change the ``__repr__``.
"""
if not self.match_func(value):
raise ValueError(
"'{name}' must match regex {regex!r}"
" ({value!r} doesn't)".format(
name=attr.name, regex=self.regex.pattern, value=value
),
attr,
self.regex,
value,
)
def __repr__(self):
return "".format(
regex=self.regex
)
def matches_re(regex, flags=0, func=None):
r"""
A validator that raises `ValueError` if the initializer is called
with a string that doesn't match *regex*.
:param str regex: a regex string to match against
:param int flags: flags that will be passed to the underlying re function
(default 0)
:param callable func: which underlying `re` function to call (options
are `re.fullmatch`, `re.search`, `re.match`, default
is ``None`` which means either `re.fullmatch` or an emulation of
it on Python 2). For performance reasons, they won't be used directly
but on a pre-`re.compile`\ ed pattern.
.. versionadded:: 19.2.0
"""
fullmatch = getattr(re, "fullmatch", None)
valid_funcs = (fullmatch, None, re.search, re.match)
if func not in valid_funcs:
raise ValueError(
"'func' must be one of %s."
% (
", ".join(
sorted(
e and e.__name__ or "None" for e in set(valid_funcs)
)
),
)
)
pattern = re.compile(regex, flags)
if func is re.match:
match_func = pattern.match
elif func is re.search:
match_func = pattern.search
else:
if fullmatch:
match_func = pattern.fullmatch
else:
pattern = re.compile(r"(?:{})\Z".format(regex), flags)
match_func = pattern.match
return _MatchesReValidator(pattern, flags, match_func)
@attrs(repr=False, slots=True, hash=True)
class _ProvidesValidator(object):
interface = attrib()
def __call__(self, inst, attr, value):
"""
We use a callable class to be able to change the ``__repr__``.
"""
if not self.interface.providedBy(value):
raise TypeError(
"'{name}' must provide {interface!r} which {value!r} "
"doesn't.".format(
name=attr.name, interface=self.interface, value=value
),
attr,
self.interface,
value,
)
def __repr__(self):
return "".format(
interface=self.interface
)
def provides(interface):
"""
A validator that raises a `TypeError` if the initializer is called
with an object that does not provide the requested *interface* (checks are
performed using ``interface.providedBy(value)`` (see `zope.interface
`_).
:param zope.interface.Interface interface: The interface to check for.
:raises TypeError: With a human readable error message, the attribute
(of type `attr.Attribute`), the expected interface, and the
value it got.
"""
return _ProvidesValidator(interface)
@attrs(repr=False, slots=True, hash=True)
class _OptionalValidator(object):
validator = attrib()
def __call__(self, inst, attr, value):
if value is None:
return
self.validator(inst, attr, value)
def __repr__(self):
return "".format(
what=repr(self.validator)
)
def optional(validator):
"""
A validator that makes an attribute optional. An optional attribute is one
which can be set to ``None`` in addition to satisfying the requirements of
the sub-validator.
:param validator: A validator (or a list of validators) that is used for
non-``None`` values.
:type validator: callable or `list` of callables.
.. versionadded:: 15.1.0
.. versionchanged:: 17.1.0 *validator* can be a list of validators.
"""
if isinstance(validator, list):
return _OptionalValidator(_AndValidator(validator))
return _OptionalValidator(validator)
@attrs(repr=False, slots=True, hash=True)
class _InValidator(object):
options = attrib()
def __call__(self, inst, attr, value):
try:
in_options = value in self.options
except TypeError: # e.g. `1 in "abc"`
in_options = False
if not in_options:
raise ValueError(
"'{name}' must be in {options!r} (got {value!r})".format(
name=attr.name, options=self.options, value=value
)
)
def __repr__(self):
return "".format(
options=self.options
)
def in_(options):
"""
A validator that raises a `ValueError` if the initializer is called
with a value that does not belong in the options provided. The check is
performed using ``value in options``.
:param options: Allowed options.
:type options: list, tuple, `enum.Enum`, ...
:raises ValueError: With a human readable error message, the attribute (of
type `attr.Attribute`), the expected options, and the value it
got.
.. versionadded:: 17.1.0
"""
return _InValidator(options)
@attrs(repr=False, slots=False, hash=True)
class _IsCallableValidator(object):
def __call__(self, inst, attr, value):
"""
We use a callable class to be able to change the ``__repr__``.
"""
if not callable(value):
message = (
"'{name}' must be callable "
"(got {value!r} that is a {actual!r})."
)
raise NotCallableError(
msg=message.format(
name=attr.name, value=value, actual=value.__class__
),
value=value,
)
def __repr__(self):
return ""
def is_callable():
"""
A validator that raises a `attr.exceptions.NotCallableError` if the
initializer is called with a value for this particular attribute
that is not callable.
.. versionadded:: 19.1.0
:raises `attr.exceptions.NotCallableError`: With a human readable error
message containing the attribute (`attr.Attribute`) name,
and the value it got.
"""
return _IsCallableValidator()
@attrs(repr=False, slots=True, hash=True)
class _DeepIterable(object):
member_validator = attrib(validator=is_callable())
iterable_validator = attrib(
default=None, validator=optional(is_callable())
)
def __call__(self, inst, attr, value):
"""
We use a callable class to be able to change the ``__repr__``.
"""
if self.iterable_validator is not None:
self.iterable_validator(inst, attr, value)
for member in value:
self.member_validator(inst, attr, member)
def __repr__(self):
iterable_identifier = (
""
if self.iterable_validator is None
else " {iterable!r}".format(iterable=self.iterable_validator)
)
return (
""
).format(
iterable_identifier=iterable_identifier,
member=self.member_validator,
)
def deep_iterable(member_validator, iterable_validator=None):
"""
A validator that performs deep validation of an iterable.
:param member_validator: Validator to apply to iterable members
:param iterable_validator: Validator to apply to iterable itself
(optional)
.. versionadded:: 19.1.0
:raises TypeError: if any sub-validators fail
"""
return _DeepIterable(member_validator, iterable_validator)
@attrs(repr=False, slots=True, hash=True)
class _DeepMapping(object):
key_validator = attrib(validator=is_callable())
value_validator = attrib(validator=is_callable())
mapping_validator = attrib(default=None, validator=optional(is_callable()))
def __call__(self, inst, attr, value):
"""
We use a callable class to be able to change the ``__repr__``.
"""
if self.mapping_validator is not None:
self.mapping_validator(inst, attr, value)
for key in value:
self.key_validator(inst, attr, key)
self.value_validator(inst, attr, value[key])
def __repr__(self):
return (
""
).format(key=self.key_validator, value=self.value_validator)
def deep_mapping(key_validator, value_validator, mapping_validator=None):
"""
A validator that performs deep validation of a dictionary.
:param key_validator: Validator to apply to dictionary keys
:param value_validator: Validator to apply to dictionary values
:param mapping_validator: Validator to apply to top-level mapping
attribute (optional)
.. versionadded:: 19.1.0
:raises TypeError: if any sub-validators fail
"""
return _DeepMapping(key_validator, value_validator, mapping_validator)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attr/validators.pyi
================================================
from typing import (
Container,
List,
Union,
TypeVar,
Type,
Any,
Optional,
Tuple,
Iterable,
Mapping,
Callable,
Match,
AnyStr,
overload,
)
from . import _ValidatorType
_T = TypeVar("_T")
_T1 = TypeVar("_T1")
_T2 = TypeVar("_T2")
_T3 = TypeVar("_T3")
_I = TypeVar("_I", bound=Iterable)
_K = TypeVar("_K")
_V = TypeVar("_V")
_M = TypeVar("_M", bound=Mapping)
# To be more precise on instance_of use some overloads.
# If there are more than 3 items in the tuple then we fall back to Any
@overload
def instance_of(type: Type[_T]) -> _ValidatorType[_T]: ...
@overload
def instance_of(type: Tuple[Type[_T]]) -> _ValidatorType[_T]: ...
@overload
def instance_of(
type: Tuple[Type[_T1], Type[_T2]]
) -> _ValidatorType[Union[_T1, _T2]]: ...
@overload
def instance_of(
type: Tuple[Type[_T1], Type[_T2], Type[_T3]]
) -> _ValidatorType[Union[_T1, _T2, _T3]]: ...
@overload
def instance_of(type: Tuple[type, ...]) -> _ValidatorType[Any]: ...
def provides(interface: Any) -> _ValidatorType[Any]: ...
def optional(
validator: Union[_ValidatorType[_T], List[_ValidatorType[_T]]]
) -> _ValidatorType[Optional[_T]]: ...
def in_(options: Container[_T]) -> _ValidatorType[_T]: ...
def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ...
def matches_re(
regex: AnyStr,
flags: int = ...,
func: Optional[
Callable[[AnyStr, AnyStr, int], Optional[Match[AnyStr]]]
] = ...,
) -> _ValidatorType[AnyStr]: ...
def deep_iterable(
member_validator: _ValidatorType[_T],
iterable_validator: Optional[_ValidatorType[_I]] = ...,
) -> _ValidatorType[_I]: ...
def deep_mapping(
key_validator: _ValidatorType[_K],
value_validator: _ValidatorType[_V],
mapping_validator: Optional[_ValidatorType[_M]] = ...,
) -> _ValidatorType[_M]: ...
def is_callable() -> _ValidatorType[_T]: ...
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attrs-19.3.0.dist-info/INSTALLER
================================================
pip
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attrs-19.3.0.dist-info/LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2015 Hynek Schlawack
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.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attrs-19.3.0.dist-info/METADATA
================================================
Metadata-Version: 2.1
Name: attrs
Version: 19.3.0
Summary: Classes Without Boilerplate
Home-page: https://www.attrs.org/
Author: Hynek Schlawack
Author-email: hs@ox.cx
Maintainer: Hynek Schlawack
Maintainer-email: hs@ox.cx
License: MIT
Project-URL: Documentation, https://www.attrs.org/
Project-URL: Bug Tracker, https://github.com/python-attrs/attrs/issues
Project-URL: Source Code, https://github.com/python-attrs/attrs
Keywords: class,attribute,boilerplate
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: English
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
Description-Content-Type: text/x-rst
Provides-Extra: azure-pipelines
Requires-Dist: coverage ; extra == 'azure-pipelines'
Requires-Dist: hypothesis ; extra == 'azure-pipelines'
Requires-Dist: pympler ; extra == 'azure-pipelines'
Requires-Dist: pytest (>=4.3.0) ; extra == 'azure-pipelines'
Requires-Dist: six ; extra == 'azure-pipelines'
Requires-Dist: zope.interface ; extra == 'azure-pipelines'
Requires-Dist: pytest-azurepipelines ; extra == 'azure-pipelines'
Provides-Extra: dev
Requires-Dist: coverage ; extra == 'dev'
Requires-Dist: hypothesis ; extra == 'dev'
Requires-Dist: pympler ; extra == 'dev'
Requires-Dist: pytest (>=4.3.0) ; extra == 'dev'
Requires-Dist: six ; extra == 'dev'
Requires-Dist: zope.interface ; extra == 'dev'
Requires-Dist: sphinx ; extra == 'dev'
Requires-Dist: pre-commit ; extra == 'dev'
Provides-Extra: docs
Requires-Dist: sphinx ; extra == 'docs'
Requires-Dist: zope.interface ; extra == 'docs'
Provides-Extra: tests
Requires-Dist: coverage ; extra == 'tests'
Requires-Dist: hypothesis ; extra == 'tests'
Requires-Dist: pympler ; extra == 'tests'
Requires-Dist: pytest (>=4.3.0) ; extra == 'tests'
Requires-Dist: six ; extra == 'tests'
Requires-Dist: zope.interface ; extra == 'tests'
.. image:: https://www.attrs.org/en/latest/_static/attrs_logo.png
:alt: attrs Logo
======================================
``attrs``: Classes Without Boilerplate
======================================
.. image:: https://readthedocs.org/projects/attrs/badge/?version=stable
:target: https://www.attrs.org/en/stable/?badge=stable
:alt: Documentation Status
.. image:: https://attrs.visualstudio.com/attrs/_apis/build/status/python-attrs.attrs?branchName=master
:target: https://attrs.visualstudio.com/attrs/_build/latest?definitionId=1&branchName=master
:alt: CI Status
.. image:: https://codecov.io/github/python-attrs/attrs/branch/master/graph/badge.svg
:target: https://codecov.io/github/python-attrs/attrs
:alt: Test Coverage
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black
:alt: Code style: black
.. teaser-begin
``attrs`` is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka `dunder `_ methods).
Its main goal is to help you to write **concise** and **correct** software without slowing down your code.
.. -spiel-end-
For that, it gives you a class decorator and a way to declaratively define the attributes on that class:
.. -code-begin-
.. code-block:: pycon
>>> import attr
>>> @attr.s
... class SomeClass(object):
... a_number = attr.ib(default=42)
... list_of_numbers = attr.ib(factory=list)
...
... def hard_math(self, another_number):
... return self.a_number + sum(self.list_of_numbers) * another_number
>>> sc = SomeClass(1, [1, 2, 3])
>>> sc
SomeClass(a_number=1, list_of_numbers=[1, 2, 3])
>>> sc.hard_math(3)
19
>>> sc == SomeClass(1, [1, 2, 3])
True
>>> sc != SomeClass(2, [3, 2, 1])
True
>>> attr.asdict(sc)
{'a_number': 1, 'list_of_numbers': [1, 2, 3]}
>>> SomeClass()
SomeClass(a_number=42, list_of_numbers=[])
>>> C = attr.make_class("C", ["a", "b"])
>>> C("foo", "bar")
C(a='foo', b='bar')
After *declaring* your attributes ``attrs`` gives you:
- a concise and explicit overview of the class's attributes,
- a nice human-readable ``__repr__``,
- a complete set of comparison methods (equality and ordering),
- an initializer,
- and much more,
*without* writing dull boilerplate code again and again and *without* runtime performance penalties.
On Python 3.6 and later, you can often even drop the calls to ``attr.ib()`` by using `type annotations `_.
This gives you the power to use actual classes with actual types in your code instead of confusing ``tuple``\ s or `confusingly behaving `_ ``namedtuple``\ s.
Which in turn encourages you to write *small classes* that do `one thing well `_.
Never again violate the `single responsibility principle `_ just because implementing ``__init__`` et al is a painful drag.
.. -testimonials-
Testimonials
============
**Amber Hawkie Brown**, Twisted Release Manager and Computer Owl:
Writing a fully-functional class using attrs takes me less time than writing this testimonial.
**Glyph Lefkowitz**, creator of `Twisted `_, `Automat `_, and other open source software, in `The One Python Library Everyone Needs `_:
I’m looking forward to is being able to program in Python-with-attrs everywhere.
It exerts a subtle, but positive, design influence in all the codebases I’ve see it used in.
**Kenneth Reitz**, creator of `Requests `_ (`on paper no less `_!):
attrs—classes for humans. I like it.
**Łukasz Langa**, creator of `Black `_, prolific Python core developer, and release manager for Python 3.8 and 3.9:
I'm increasingly digging your attr.ocity. Good job!
.. -end-
.. -project-information-
Getting Help
============
Please use the ``python-attrs`` tag on `StackOverflow `_ to get help.
Answering questions of your fellow developers is also great way to help the project!
Project Information
===================
``attrs`` is released under the `MIT `_ license,
its documentation lives at `Read the Docs `_,
the code on `GitHub `_,
and the latest release on `PyPI `_.
It’s rigorously tested on Python 2.7, 3.4+, and PyPy.
We collect information on **third-party extensions** in our `wiki `_.
Feel free to browse and add your own!
If you'd like to contribute to ``attrs`` you're most welcome and we've written `a little guide `_ to get you started!
Release Information
===================
19.3.0 (2019-10-15)
-------------------
Changes
^^^^^^^
- Fixed ``auto_attribs`` usage when default values cannot be compared directly with ``==``, such as ``numpy`` arrays.
`#585 `_
`Full changelog `_.
Credits
=======
``attrs`` is written and maintained by `Hynek Schlawack `_.
The development is kindly supported by `Variomedia AG `_.
A full list of contributors can be found in `GitHub's overview `_.
It’s the spiritual successor of `characteristic `_ and aspires to fix some of it clunkiness and unfortunate decisions.
Both were inspired by Twisted’s `FancyEqMixin `_ but both are implemented using class decorators because `subclassing is bad for you `_, m’kay?
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attrs-19.3.0.dist-info/RECORD
================================================
attr/__init__.py,sha256=ONaI-ZEGOIC7IDqH2HANgesnOxPE1m0GIRRYPPsXEHk,1349
attr/__init__.pyi,sha256=fOnMRTF00b5J23PYPF74u66UVhVzzm0KYVxzmVXHPw0,8257
attr/__pycache__/__init__.cpython-36.pyc,,
attr/__pycache__/_compat.cpython-36.pyc,,
attr/__pycache__/_config.cpython-36.pyc,,
attr/__pycache__/_funcs.cpython-36.pyc,,
attr/__pycache__/_make.cpython-36.pyc,,
attr/__pycache__/_version_info.cpython-36.pyc,,
attr/__pycache__/converters.cpython-36.pyc,,
attr/__pycache__/exceptions.cpython-36.pyc,,
attr/__pycache__/filters.cpython-36.pyc,,
attr/__pycache__/validators.cpython-36.pyc,,
attr/_compat.py,sha256=-pJtdtqgCg0K6rH_BWf3wKuTum58GD-WWPclQQ2SUaU,7326
attr/_config.py,sha256=_KvW0mQdH2PYjHc0YfIUaV_o2pVfM7ziMEYTxwmEhOA,514
attr/_funcs.py,sha256=unAJfNGSTOzxyFzkj7Rs3O1bfsQodmXyir9uZKen-vY,9696
attr/_make.py,sha256=HhjGhFEbnxPKuUb9hFmAjXoQGpekniw1IEF3_Z-vwCc,70807
attr/_version_info.py,sha256=azMi1lNelb3cJvvYUMXsXVbUANkRzbD5IEiaXVpeVr4,2162
attr/_version_info.pyi,sha256=x_M3L3WuB7r_ULXAWjx959udKQ4HLB8l-hsc1FDGNvk,209
attr/converters.py,sha256=5QJRYSXE8G7PW0289y_SPwvvZIcw-nJIuBlfYVdB4BQ,2141
attr/converters.pyi,sha256=wAhCoOT1MFV8t323rpD87O7bxQ8CYLTPiBQd-29BieI,351
attr/exceptions.py,sha256=hbhOa3b4W8_mRrbj3FsMTR4Bt5xzbJs5xaFTWn8s6h4,1635
attr/exceptions.pyi,sha256=4zuaJyl2axxWbqnZgxo_2oTpPNbyowEw3A4hqV5PmAc,458
attr/filters.py,sha256=weDxwATsa69T_0bPVjiM1fGsciAMQmwhY5G8Jm5BxuI,1098
attr/filters.pyi,sha256=xDpmKQlFdssgxGa5tsl1ADh_3zwAwAT4vUhd8h-8-Tk,214
attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
attr/validators.py,sha256=8AsxgdDgh3sGPseiUIMPGcTr6PvaDYfH3AK46tsvs8U,11460
attr/validators.pyi,sha256=vZgsJqUwrJevh4v_Hd7_RSXqDrBctE6-3AEZ7uYKodo,1868
attrs-19.3.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
attrs-19.3.0.dist-info/LICENSE,sha256=v2WaKLSSQGAvVrvfSQy-LsUJsVuY-Z17GaUsdA4yeGM,1082
attrs-19.3.0.dist-info/METADATA,sha256=WmnjYy_TftebL3pewXyGEaD4TZRrLUEHk3frEkAtqL0,9022
attrs-19.3.0.dist-info/RECORD,,
attrs-19.3.0.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110
attrs-19.3.0.dist-info/top_level.txt,sha256=tlRYMddkRlKPqJ96wP2_j9uEsmcNHgD2SbuWd4CzGVU,5
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attrs-19.3.0.dist-info/WHEEL
================================================
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.6)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/attrs-19.3.0.dist-info/top_level.txt
================================================
attr
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/automat/__init__.py
================================================
# -*- test-case-name: automat -*-
from ._methodical import MethodicalMachine
from ._core import NoTransition
__all__ = [
'MethodicalMachine',
'NoTransition',
]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/automat/_core.py
================================================
# -*- test-case-name: automat._test.test_core -*-
"""
A core state-machine abstraction.
Perhaps something that could be replaced with or integrated into machinist.
"""
from itertools import chain
_NO_STATE = ""
class NoTransition(Exception):
"""
A finite state machine in C{state} has no transition for C{symbol}.
@param state: the finite state machine's state at the time of the
illegal transition.
@param symbol: the input symbol for which no transition exists.
"""
def __init__(self, state, symbol):
self.state = state
self.symbol = symbol
super(Exception, self).__init__(
"no transition for {} in {}".format(symbol, state)
)
class Automaton(object):
"""
A declaration of a finite state machine.
Note that this is not the machine itself; it is immutable.
"""
def __init__(self):
"""
Initialize the set of transitions and the initial state.
"""
self._initialState = _NO_STATE
self._transitions = set()
@property
def initialState(self):
"""
Return this automaton's initial state.
"""
return self._initialState
@initialState.setter
def initialState(self, state):
"""
Set this automaton's initial state. Raises a ValueError if
this automaton already has an initial state.
"""
if self._initialState is not _NO_STATE:
raise ValueError(
"initial state already set to {}".format(self._initialState))
self._initialState = state
def addTransition(self, inState, inputSymbol, outState, outputSymbols):
"""
Add the given transition to the outputSymbol. Raise ValueError if
there is already a transition with the same inState and inputSymbol.
"""
# keeping self._transitions in a flat list makes addTransition
# O(n^2), but state machines don't tend to have hundreds of
# transitions.
for (anInState, anInputSymbol, anOutState, _) in self._transitions:
if (anInState == inState and anInputSymbol == inputSymbol):
raise ValueError(
"already have transition from {} via {}".format(inState, inputSymbol))
self._transitions.add(
(inState, inputSymbol, outState, tuple(outputSymbols))
)
def allTransitions(self):
"""
All transitions.
"""
return frozenset(self._transitions)
def inputAlphabet(self):
"""
The full set of symbols acceptable to this automaton.
"""
return {inputSymbol for (inState, inputSymbol, outState,
outputSymbol) in self._transitions}
def outputAlphabet(self):
"""
The full set of symbols which can be produced by this automaton.
"""
return set(
chain.from_iterable(
outputSymbols for
(inState, inputSymbol, outState, outputSymbols)
in self._transitions
)
)
def states(self):
"""
All valid states; "Q" in the mathematical description of a state
machine.
"""
return frozenset(
chain.from_iterable(
(inState, outState)
for
(inState, inputSymbol, outState, outputSymbol)
in self._transitions
)
)
def outputForInput(self, inState, inputSymbol):
"""
A 2-tuple of (outState, outputSymbols) for inputSymbol.
"""
for (anInState, anInputSymbol,
outState, outputSymbols) in self._transitions:
if (inState, inputSymbol) == (anInState, anInputSymbol):
return (outState, list(outputSymbols))
raise NoTransition(state=inState, symbol=inputSymbol)
class Transitioner(object):
"""
The combination of a current state and an L{Automaton}.
"""
def __init__(self, automaton, initialState):
self._automaton = automaton
self._state = initialState
self._tracer = None
def setTrace(self, tracer):
self._tracer = tracer
def transition(self, inputSymbol):
"""
Transition between states, returning any outputs.
"""
outState, outputSymbols = self._automaton.outputForInput(self._state,
inputSymbol)
outTracer = None
if self._tracer:
outTracer = self._tracer(self._state._name(),
inputSymbol._name(),
outState._name())
self._state = outState
return (outputSymbols, outTracer)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/automat/_discover.py
================================================
import collections
import inspect
from automat import MethodicalMachine
from twisted.python.modules import PythonModule, getModule
def isOriginalLocation(attr):
"""
Attempt to discover if this appearance of a PythonAttribute
representing a class refers to the module where that class was
defined.
"""
sourceModule = inspect.getmodule(attr.load())
if sourceModule is None:
return False
currentModule = attr
while not isinstance(currentModule, PythonModule):
currentModule = currentModule.onObject
return currentModule.name == sourceModule.__name__
def findMachinesViaWrapper(within):
"""
Recursively yield L{MethodicalMachine}s and their FQPNs within a
L{PythonModule} or a L{twisted.python.modules.PythonAttribute}
wrapper object.
Note that L{PythonModule}s may refer to packages, as well.
The discovery heuristic considers L{MethodicalMachine} instances
that are module-level attributes or class-level attributes
accessible from module scope. Machines inside nested classes will
be discovered, but those returned from functions or methods will not be.
@type within: L{PythonModule} or L{twisted.python.modules.PythonAttribute}
@param within: Where to start the search.
@return: a generator which yields FQPN, L{MethodicalMachine} pairs.
"""
queue = collections.deque([within])
visited = set()
while queue:
attr = queue.pop()
value = attr.load()
if isinstance(value, MethodicalMachine) and value not in visited:
visited.add(value)
yield attr.name, value
elif (inspect.isclass(value) and isOriginalLocation(attr) and
value not in visited):
visited.add(value)
queue.extendleft(attr.iterAttributes())
elif isinstance(attr, PythonModule) and value not in visited:
visited.add(value)
queue.extendleft(attr.iterAttributes())
queue.extendleft(attr.iterModules())
class InvalidFQPN(Exception):
"""
The given FQPN was not a dot-separated list of Python objects.
"""
class NoModule(InvalidFQPN):
"""
A prefix of the FQPN was not an importable module or package.
"""
class NoObject(InvalidFQPN):
"""
A suffix of the FQPN was not an accessible object
"""
def wrapFQPN(fqpn):
"""
Given an FQPN, retrieve the object via the global Python module
namespace and wrap it with a L{PythonModule} or a
L{twisted.python.modules.PythonAttribute}.
"""
# largely cribbed from t.p.reflect.namedAny
if not fqpn:
raise InvalidFQPN("FQPN was empty")
components = collections.deque(fqpn.split('.'))
if '' in components:
raise InvalidFQPN(
"name must be a string giving a '.'-separated list of Python "
"identifiers, not %r" % (fqpn,))
component = components.popleft()
try:
module = getModule(component)
except KeyError:
raise NoModule(component)
# find the bottom-most module
while components:
component = components.popleft()
try:
module = module[component]
except KeyError:
components.appendleft(component)
break
else:
module.load()
else:
return module
# find the bottom-most attribute
attribute = module
for component in components:
try:
attribute = next(child for child in attribute.iterAttributes()
if child.name.rsplit('.', 1)[-1] == component)
except StopIteration:
raise NoObject('{}.{}'.format(attribute.name, component))
return attribute
def findMachines(fqpn):
"""
Recursively yield L{MethodicalMachine}s and their FQPNs in and
under the a Python object specified by an FQPN.
The discovery heuristic considers L{MethodicalMachine} instances
that are module-level attributes or class-level attributes
accessible from module scope. Machines inside nested classes will
be discovered, but those returned from functions or methods will not be.
@type within: an FQPN
@param within: Where to start the search.
@return: a generator which yields FQPN, L{MethodicalMachine} pairs.
"""
return findMachinesViaWrapper(wrapFQPN(fqpn))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/automat/_introspection.py
================================================
"""
Python introspection helpers.
"""
from types import CodeType as code, FunctionType as function
def copycode(template, changes):
names = [
"argcount", "nlocals", "stacksize", "flags", "code", "consts",
"names", "varnames", "filename", "name", "firstlineno", "lnotab",
"freevars", "cellvars"
]
if hasattr(code, "co_kwonlyargcount"):
names.insert(1, "kwonlyargcount")
if hasattr(code, "co_posonlyargcount"):
# PEP 570 added "positional only arguments"
names.insert(1, "posonlyargcount")
values = [
changes.get(name, getattr(template, "co_" + name))
for name in names
]
return code(*values)
def copyfunction(template, funcchanges, codechanges):
names = [
"globals", "name", "defaults", "closure",
]
values = [
funcchanges.get(name, getattr(template, "__" + name + "__"))
for name in names
]
return function(copycode(template.__code__, codechanges), *values)
def preserveName(f):
"""
Preserve the name of the given function on the decorated function.
"""
def decorator(decorated):
return copyfunction(decorated,
dict(name=f.__name__), dict(name=f.__name__))
return decorator
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/automat/_methodical.py
================================================
# -*- test-case-name: automat._test.test_methodical -*-
import collections
from functools import wraps
from itertools import count
try:
# Python 3
from inspect import getfullargspec as getArgsSpec
except ImportError:
# Python 2
from inspect import getargspec as getArgsSpec
import attr
import six
from ._core import Transitioner, Automaton
from ._introspection import preserveName
ArgSpec = collections.namedtuple('ArgSpec', ['args', 'varargs', 'varkw',
'defaults', 'kwonlyargs',
'kwonlydefaults', 'annotations'])
def _getArgSpec(func):
"""
Normalize inspect.ArgSpec across python versions
and convert mutable attributes to immutable types.
:param Callable func: A function.
:return: The function's ArgSpec.
:rtype: ArgSpec
"""
spec = getArgsSpec(func)
return ArgSpec(
args=tuple(spec.args),
varargs=spec.varargs,
varkw=spec.varkw if six.PY3 else spec.keywords,
defaults=spec.defaults if spec.defaults else (),
kwonlyargs=tuple(spec.kwonlyargs) if six.PY3 else (),
kwonlydefaults=(
tuple(spec.kwonlydefaults.items())
if spec.kwonlydefaults else ()
) if six.PY3 else (),
annotations=tuple(spec.annotations.items()) if six.PY3 else (),
)
def _getArgNames(spec):
"""
Get the name of all arguments defined in a function signature.
The name of * and ** arguments is normalized to "*args" and "**kwargs".
:param ArgSpec spec: A function to interrogate for a signature.
:return: The set of all argument names in `func`s signature.
:rtype: Set[str]
"""
return set(
spec.args
+ spec.kwonlyargs
+ (('*args',) if spec.varargs else ())
+ (('**kwargs',) if spec.varkw else ())
+ spec.annotations
)
def _keywords_only(f):
"""
Decorate a function so all its arguments must be passed by keyword.
A useful utility for decorators that take arguments so that they don't
accidentally get passed the thing they're decorating as their first
argument.
Only works for methods right now.
"""
@wraps(f)
def g(self, **kw):
return f(self, **kw)
return g
@attr.s(frozen=True)
class MethodicalState(object):
"""
A state for a L{MethodicalMachine}.
"""
machine = attr.ib(repr=False)
method = attr.ib()
serialized = attr.ib(repr=False)
def upon(self, input, enter, outputs, collector=list):
"""
Declare a state transition within the :class:`automat.MethodicalMachine`
associated with this :class:`automat.MethodicalState`:
upon the receipt of the `input`, enter the `state`,
emitting each output in `outputs`.
:param MethodicalInput input: The input triggering a state transition.
:param MethodicalState enter: The resulting state.
:param Iterable[MethodicalOutput] outputs: The outputs to be triggered
as a result of the declared state transition.
:param Callable collector: The function to be used when collecting
output return values.
:raises TypeError: if any of the `outputs` signatures do not match
the `inputs` signature.
:raises ValueError: if the state transition from `self` via `input`
has already been defined.
"""
inputArgs = _getArgNames(input.argSpec)
for output in outputs:
outputArgs = _getArgNames(output.argSpec)
if not outputArgs.issubset(inputArgs):
raise TypeError(
"method {input} signature {inputSignature} "
"does not match output {output} "
"signature {outputSignature}".format(
input=input.method.__name__,
output=output.method.__name__,
inputSignature=getArgsSpec(input.method),
outputSignature=getArgsSpec(output.method),
))
self.machine._oneTransition(self, input, enter, outputs, collector)
def _name(self):
return self.method.__name__
def _transitionerFromInstance(oself, symbol, automaton):
"""
Get a L{Transitioner}
"""
transitioner = getattr(oself, symbol, None)
if transitioner is None:
transitioner = Transitioner(
automaton,
automaton.initialState,
)
setattr(oself, symbol, transitioner)
return transitioner
def _empty():
pass
def _docstring():
"""docstring"""
def assertNoCode(inst, attribute, f):
# The function body must be empty, i.e. "pass" or "return None", which
# both yield the same bytecode: LOAD_CONST (None), RETURN_VALUE. We also
# accept functions with only a docstring, which yields slightly different
# bytecode, because the "None" is put in a different constant slot.
# Unfortunately, this does not catch function bodies that return a
# constant value, e.g. "return 1", because their code is identical to a
# "return None". They differ in the contents of their constant table, but
# checking that would require us to parse the bytecode, find the index
# being returned, then making sure the table has a None at that index.
if f.__code__.co_code not in (_empty.__code__.co_code,
_docstring.__code__.co_code):
raise ValueError("function body must be empty")
def _filterArgs(args, kwargs, inputSpec, outputSpec):
"""
Filter out arguments that were passed to input that output won't accept.
:param tuple args: The *args that input received.
:param dict kwargs: The **kwargs that input received.
:param ArgSpec inputSpec: The input's arg spec.
:param ArgSpec outputSpec: The output's arg spec.
:return: The args and kwargs that output will accept.
:rtype: Tuple[tuple, dict]
"""
named_args = tuple(zip(inputSpec.args[1:], args))
if outputSpec.varargs:
# Only return all args if the output accepts *args.
return_args = args
else:
# Filter out arguments that don't appear
# in the output's method signature.
return_args = [v for n, v in named_args if n in outputSpec.args]
# Get any of input's default arguments that were not passed.
passed_arg_names = tuple(kwargs)
for name, value in named_args:
passed_arg_names += (name, value)
defaults = zip(inputSpec.args[::-1], inputSpec.defaults[::-1])
full_kwargs = {n: v for n, v in defaults if n not in passed_arg_names}
full_kwargs.update(kwargs)
if outputSpec.varkw:
# Only pass all kwargs if the output method accepts **kwargs.
return_kwargs = full_kwargs
else:
# Filter out names that the output method does not accept.
all_accepted_names = outputSpec.args[1:] + outputSpec.kwonlyargs
return_kwargs = {n: v for n, v in full_kwargs.items()
if n in all_accepted_names}
return return_args, return_kwargs
@attr.s(cmp=False, hash=False)
class MethodicalInput(object):
"""
An input for a L{MethodicalMachine}.
"""
automaton = attr.ib(repr=False)
method = attr.ib(validator=assertNoCode)
symbol = attr.ib(repr=False)
collectors = attr.ib(default=attr.Factory(dict), repr=False)
argSpec = attr.ib(init=False, repr=False)
@argSpec.default
def _buildArgSpec(self):
return _getArgSpec(self.method)
def __get__(self, oself, type=None):
"""
Return a function that takes no arguments and returns values returned
by output functions produced by the given L{MethodicalInput} in
C{oself}'s current state.
"""
transitioner = _transitionerFromInstance(oself, self.symbol,
self.automaton)
@preserveName(self.method)
@wraps(self.method)
def doInput(*args, **kwargs):
self.method(oself, *args, **kwargs)
previousState = transitioner._state
(outputs, outTracer) = transitioner.transition(self)
collector = self.collectors[previousState]
values = []
for output in outputs:
if outTracer:
outTracer(output._name())
a, k = _filterArgs(args, kwargs, self.argSpec, output.argSpec)
value = output(oself, *a, **k)
values.append(value)
return collector(values)
return doInput
def _name(self):
return self.method.__name__
@attr.s(frozen=True)
class MethodicalOutput(object):
"""
An output for a L{MethodicalMachine}.
"""
machine = attr.ib(repr=False)
method = attr.ib()
argSpec = attr.ib(init=False, repr=False)
@argSpec.default
def _buildArgSpec(self):
return _getArgSpec(self.method)
def __get__(self, oself, type=None):
"""
Outputs are private, so raise an exception when we attempt to get one.
"""
raise AttributeError(
"{cls}.{method} is a state-machine output method; "
"to produce this output, call an input method instead.".format(
cls=type.__name__,
method=self.method.__name__
)
)
def __call__(self, oself, *args, **kwargs):
"""
Call the underlying method.
"""
return self.method(oself, *args, **kwargs)
def _name(self):
return self.method.__name__
@attr.s(cmp=False, hash=False)
class MethodicalTracer(object):
automaton = attr.ib(repr=False)
symbol = attr.ib(repr=False)
def __get__(self, oself, type=None):
transitioner = _transitionerFromInstance(oself, self.symbol,
self.automaton)
def setTrace(tracer):
transitioner.setTrace(tracer)
return setTrace
counter = count()
def gensym():
"""
Create a unique Python identifier.
"""
return "_symbol_" + str(next(counter))
class MethodicalMachine(object):
"""
A :class:`MethodicalMachine` is an interface to an `Automaton`
that uses methods on a class.
"""
def __init__(self):
self._automaton = Automaton()
self._reducers = {}
self._symbol = gensym()
def __get__(self, oself, type=None):
"""
L{MethodicalMachine} is an implementation detail for setting up
class-level state; applications should never need to access it on an
instance.
"""
if oself is not None:
raise AttributeError(
"MethodicalMachine is an implementation detail.")
return self
@_keywords_only
def state(self, initial=False, terminal=False,
serialized=None):
"""
Declare a state, possibly an initial state or a terminal state.
This is a decorator for methods, but it will modify the method so as
not to be callable any more.
:param bool initial: is this state the initial state?
Only one state on this :class:`automat.MethodicalMachine`
may be an initial state; more than one is an error.
:param bool terminal: Is this state a terminal state?
i.e. a state that the machine can end up in?
(This is purely informational at this point.)
:param Hashable serialized: a serializable value
to be used to represent this state to external systems.
This value should be hashable;
:py:func:`unicode` is a good type to use.
"""
def decorator(stateMethod):
state = MethodicalState(machine=self,
method=stateMethod,
serialized=serialized)
if initial:
self._automaton.initialState = state
return state
return decorator
@_keywords_only
def input(self):
"""
Declare an input.
This is a decorator for methods.
"""
def decorator(inputMethod):
return MethodicalInput(automaton=self._automaton,
method=inputMethod,
symbol=self._symbol)
return decorator
@_keywords_only
def output(self):
"""
Declare an output.
This is a decorator for methods.
This method will be called when the state machine transitions to this
state as specified in the decorated `output` method.
"""
def decorator(outputMethod):
return MethodicalOutput(machine=self, method=outputMethod)
return decorator
def _oneTransition(self, startState, inputToken, endState, outputTokens,
collector):
"""
See L{MethodicalState.upon}.
"""
# FIXME: tests for all of this (some of it is wrong)
# if not isinstance(startState, MethodicalState):
# raise NotImplementedError("start state {} isn't a state"
# .format(startState))
# if not isinstance(inputToken, MethodicalInput):
# raise NotImplementedError("start state {} isn't an input"
# .format(inputToken))
# if not isinstance(endState, MethodicalState):
# raise NotImplementedError("end state {} isn't a state"
# .format(startState))
# for output in outputTokens:
# if not isinstance(endState, MethodicalState):
# raise NotImplementedError("output state {} isn't a state"
# .format(endState))
self._automaton.addTransition(startState, inputToken, endState,
tuple(outputTokens))
inputToken.collectors[startState] = collector
@_keywords_only
def serializer(self):
"""
"""
def decorator(decoratee):
@wraps(decoratee)
def serialize(oself):
transitioner = _transitionerFromInstance(oself, self._symbol,
self._automaton)
return decoratee(oself, transitioner._state.serialized)
return serialize
return decorator
@_keywords_only
def unserializer(self):
"""
"""
def decorator(decoratee):
@wraps(decoratee)
def unserialize(oself, *args, **kwargs):
state = decoratee(oself, *args, **kwargs)
mapping = {}
for eachState in self._automaton.states():
mapping[eachState.serialized] = eachState
transitioner = _transitionerFromInstance(
oself, self._symbol, self._automaton)
transitioner._state = mapping[state]
return None # it's on purpose
return unserialize
return decorator
@property
def _setTrace(self):
return MethodicalTracer(self._automaton, self._symbol)
def asDigraph(self):
"""
Generate a L{graphviz.Digraph} that represents this machine's
states and transitions.
@return: L{graphviz.Digraph} object; for more information, please
see the documentation for
U{graphviz}
"""
from ._visualize import makeDigraph
return makeDigraph(
self._automaton,
stateAsString=lambda state: state.method.__name__,
inputAsString=lambda input: input.method.__name__,
outputAsString=lambda output: output.method.__name__,
)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/automat/_test/__init__.py
================================================
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/automat/_test/test_core.py
================================================
from .._core import Automaton, NoTransition
from unittest import TestCase
class CoreTests(TestCase):
"""
Tests for Automat's (currently private, implementation detail) core.
"""
def test_NoTransition(self):
"""
A L{NoTransition} exception describes the state and input symbol
that caused it.
"""
# NoTransition requires two arguments
with self.assertRaises(TypeError):
NoTransition()
state = "current-state"
symbol = "transitionless-symbol"
noTransitionException = NoTransition(state=state, symbol=symbol)
self.assertIs(noTransitionException.symbol, symbol)
self.assertIn(state, str(noTransitionException))
self.assertIn(symbol, str(noTransitionException))
def test_noOutputForInput(self):
"""
L{Automaton.outputForInput} raises L{NoTransition} if no
transition for that input is defined.
"""
a = Automaton()
self.assertRaises(NoTransition, a.outputForInput,
"no-state", "no-symbol")
def test_oneTransition(self):
"""
L{Automaton.addTransition} adds its input symbol to
L{Automaton.inputAlphabet}, all its outputs to
L{Automaton.outputAlphabet}, and causes L{Automaton.outputForInput} to
start returning the new state and output symbols.
"""
a = Automaton()
a.addTransition("beginning", "begin", "ending", ["end"])
self.assertEqual(a.inputAlphabet(), {"begin"})
self.assertEqual(a.outputAlphabet(), {"end"})
self.assertEqual(a.outputForInput("beginning", "begin"),
("ending", ["end"]))
self.assertEqual(a.states(), {"beginning", "ending"})
def test_oneTransition_nonIterableOutputs(self):
"""
L{Automaton.addTransition} raises a TypeError when given outputs
that aren't iterable and doesn't add any transitions.
"""
a = Automaton()
nonIterableOutputs = 1
self.assertRaises(
TypeError,
a.addTransition,
"fromState", "viaSymbol", "toState", nonIterableOutputs)
self.assertFalse(a.inputAlphabet())
self.assertFalse(a.outputAlphabet())
self.assertFalse(a.states())
self.assertFalse(a.allTransitions())
def test_initialState(self):
"""
L{Automaton.initialState} is a descriptor that sets the initial
state if it's not yet set, and raises L{ValueError} if it is.
"""
a = Automaton()
a.initialState = "a state"
self.assertEqual(a.initialState, "a state")
with self.assertRaises(ValueError):
a.initialState = "another state"
# FIXME: addTransition for transition that's been added before
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/automat/_test/test_discover.py
================================================
import operator
import os
import shutil
import sys
import textwrap
import tempfile
from unittest import skipIf, TestCase
import six
def isTwistedInstalled():
try:
__import__('twisted')
except ImportError:
return False
else:
return True
class _WritesPythonModules(TestCase):
"""
A helper that enables generating Python module test fixtures.
"""
def setUp(self):
super(_WritesPythonModules, self).setUp()
from twisted.python.modules import getModule, PythonPath
from twisted.python.filepath import FilePath
self.getModule = getModule
self.PythonPath = PythonPath
self.FilePath = FilePath
self.originalSysModules = set(sys.modules.keys())
self.savedSysPath = sys.path[:]
self.pathDir = tempfile.mkdtemp()
self.makeImportable(self.pathDir)
def tearDown(self):
super(_WritesPythonModules, self).tearDown()
sys.path[:] = self.savedSysPath
modulesToDelete = six.viewkeys(sys.modules) - self.originalSysModules
for module in modulesToDelete:
del sys.modules[module]
shutil.rmtree(self.pathDir)
def makeImportable(self, path):
sys.path.append(path)
def writeSourceInto(self, source, path, moduleName):
directory = self.FilePath(path)
module = directory.child(moduleName)
# FilePath always opens a file in binary mode - but that will
# break on Python 3
with open(module.path, 'w') as f:
f.write(textwrap.dedent(source))
return self.PythonPath([directory.path])
def makeModule(self, source, path, moduleName):
pythonModuleName, _ = os.path.splitext(moduleName)
return self.writeSourceInto(source, path, moduleName)[pythonModuleName]
def attributesAsDict(self, hasIterAttributes):
return {attr.name: attr for attr in hasIterAttributes.iterAttributes()}
def loadModuleAsDict(self, module):
module.load()
return self.attributesAsDict(module)
def makeModuleAsDict(self, source, path, name):
return self.loadModuleAsDict(self.makeModule(source, path, name))
@skipIf(not isTwistedInstalled(), "Twisted is not installed.")
class OriginalLocationTests(_WritesPythonModules):
"""
Tests that L{isOriginalLocation} detects when a
L{PythonAttribute}'s FQPN refers to an object inside the module
where it was defined.
For example: A L{twisted.python.modules.PythonAttribute} with a
name of 'foo.bar' that refers to a 'bar' object defined in module
'baz' does *not* refer to bar's original location, while a
L{PythonAttribute} with a name of 'baz.bar' does.
"""
def setUp(self):
super(OriginalLocationTests, self).setUp()
from .._discover import isOriginalLocation
self.isOriginalLocation = isOriginalLocation
def test_failsWithNoModule(self):
"""
L{isOriginalLocation} returns False when the attribute refers to an
object whose source module cannot be determined.
"""
source = """\
class Fake(object):
pass
hasEmptyModule = Fake()
hasEmptyModule.__module__ = None
"""
moduleDict = self.makeModuleAsDict(source,
self.pathDir,
'empty_module_attr.py')
self.assertFalse(self.isOriginalLocation(
moduleDict['empty_module_attr.hasEmptyModule']))
def test_failsWithDifferentModule(self):
"""
L{isOriginalLocation} returns False when the attribute refers to
an object outside of the module where that object was defined.
"""
originalSource = """\
class ImportThisClass(object):
pass
importThisObject = ImportThisClass()
importThisNestingObject = ImportThisClass()
importThisNestingObject.nestedObject = ImportThisClass()
"""
importingSource = """\
from original import (ImportThisClass,
importThisObject,
importThisNestingObject)
"""
self.makeModule(originalSource, self.pathDir, 'original.py')
importingDict = self.makeModuleAsDict(importingSource,
self.pathDir,
'importing.py')
self.assertFalse(
self.isOriginalLocation(
importingDict['importing.ImportThisClass']))
self.assertFalse(
self.isOriginalLocation(
importingDict['importing.importThisObject']))
nestingObject = importingDict['importing.importThisNestingObject']
nestingObjectDict = self.attributesAsDict(nestingObject)
nestedObject = nestingObjectDict[
'importing.importThisNestingObject.nestedObject']
self.assertFalse(self.isOriginalLocation(nestedObject))
def test_succeedsWithSameModule(self):
"""
L{isOriginalLocation} returns True when the attribute refers to an
object inside the module where that object was defined.
"""
mSource = textwrap.dedent("""
class ThisClassWasDefinedHere(object):
pass
anObject = ThisClassWasDefinedHere()
aNestingObject = ThisClassWasDefinedHere()
aNestingObject.nestedObject = ThisClassWasDefinedHere()
""")
mDict = self.makeModuleAsDict(mSource, self.pathDir, 'm.py')
self.assertTrue(self.isOriginalLocation(
mDict['m.ThisClassWasDefinedHere']))
self.assertTrue(self.isOriginalLocation(mDict['m.aNestingObject']))
nestingObject = mDict['m.aNestingObject']
nestingObjectDict = self.attributesAsDict(nestingObject)
nestedObject = nestingObjectDict['m.aNestingObject.nestedObject']
self.assertTrue(self.isOriginalLocation(nestedObject))
@skipIf(not isTwistedInstalled(), "Twisted is not installed.")
class FindMachinesViaWrapperTests(_WritesPythonModules):
"""
L{findMachinesViaWrapper} recursively yields FQPN,
L{MethodicalMachine} pairs in and under a given
L{twisted.python.modules.PythonModule} or
L{twisted.python.modules.PythonAttribute}.
"""
TEST_MODULE_SOURCE = """
from automat import MethodicalMachine
class PythonClass(object):
_classMachine = MethodicalMachine()
class NestedClass(object):
_nestedClassMachine = MethodicalMachine()
ignoredAttribute = "I am ignored."
def ignoredMethod(self):
"I am also ignored."
rootLevelMachine = MethodicalMachine()
ignoredPythonObject = PythonClass()
anotherIgnoredPythonObject = "I am ignored."
"""
def setUp(self):
super(FindMachinesViaWrapperTests, self).setUp()
from .._discover import findMachinesViaWrapper
self.findMachinesViaWrapper = findMachinesViaWrapper
def test_yieldsMachine(self):
"""
When given a L{twisted.python.modules.PythonAttribute} that refers
directly to a L{MethodicalMachine}, L{findMachinesViaWrapper}
yields that machine and its FQPN.
"""
source = """\
from automat import MethodicalMachine
rootMachine = MethodicalMachine()
"""
moduleDict = self.makeModuleAsDict(source, self.pathDir, 'root.py')
rootMachine = moduleDict['root.rootMachine']
self.assertIn(('root.rootMachine', rootMachine.load()),
list(self.findMachinesViaWrapper(rootMachine)))
def test_yieldsMachineInClass(self):
"""
When given a L{twisted.python.modules.PythonAttribute} that refers
to a class that contains a L{MethodicalMachine} as a class
variable, L{findMachinesViaWrapper} yields that machine and
its FQPN.
"""
source = """\
from automat import MethodicalMachine
class PythonClass(object):
_classMachine = MethodicalMachine()
"""
moduleDict = self.makeModuleAsDict(source, self.pathDir, 'clsmod.py')
PythonClass = moduleDict['clsmod.PythonClass']
self.assertIn(('clsmod.PythonClass._classMachine',
PythonClass.load()._classMachine),
list(self.findMachinesViaWrapper(PythonClass)))
def test_yieldsMachineInNestedClass(self):
"""
When given a L{twisted.python.modules.PythonAttribute} that refers
to a nested class that contains a L{MethodicalMachine} as a
class variable, L{findMachinesViaWrapper} yields that machine
and its FQPN.
"""
source = """\
from automat import MethodicalMachine
class PythonClass(object):
class NestedClass(object):
_classMachine = MethodicalMachine()
"""
moduleDict = self.makeModuleAsDict(source,
self.pathDir,
'nestedcls.py')
PythonClass = moduleDict['nestedcls.PythonClass']
self.assertIn(('nestedcls.PythonClass.NestedClass._classMachine',
PythonClass.load().NestedClass._classMachine),
list(self.findMachinesViaWrapper(PythonClass)))
def test_yieldsMachineInModule(self):
"""
When given a L{twisted.python.modules.PythonModule} that refers to
a module that contains a L{MethodicalMachine},
L{findMachinesViaWrapper} yields that machine and its FQPN.
"""
source = """\
from automat import MethodicalMachine
rootMachine = MethodicalMachine()
"""
module = self.makeModule(source, self.pathDir, 'root.py')
rootMachine = self.loadModuleAsDict(module)['root.rootMachine'].load()
self.assertIn(('root.rootMachine', rootMachine),
list(self.findMachinesViaWrapper(module)))
def test_yieldsMachineInClassInModule(self):
"""
When given a L{twisted.python.modules.PythonModule} that refers to
the original module of a class containing a
L{MethodicalMachine}, L{findMachinesViaWrapper} yields that
machine and its FQPN.
"""
source = """\
from automat import MethodicalMachine
class PythonClass(object):
_classMachine = MethodicalMachine()
"""
module = self.makeModule(source, self.pathDir, 'clsmod.py')
PythonClass = self.loadModuleAsDict(
module)['clsmod.PythonClass'].load()
self.assertIn(('clsmod.PythonClass._classMachine',
PythonClass._classMachine),
list(self.findMachinesViaWrapper(module)))
def test_yieldsMachineInNestedClassInModule(self):
"""
When given a L{twisted.python.modules.PythonModule} that refers to
the original module of a nested class containing a
L{MethodicalMachine}, L{findMachinesViaWrapper} yields that
machine and its FQPN.
"""
source = """\
from automat import MethodicalMachine
class PythonClass(object):
class NestedClass(object):
_classMachine = MethodicalMachine()
"""
module = self.makeModule(source, self.pathDir, 'nestedcls.py')
PythonClass = self.loadModuleAsDict(
module)['nestedcls.PythonClass'].load()
self.assertIn(('nestedcls.PythonClass.NestedClass._classMachine',
PythonClass.NestedClass._classMachine),
list(self.findMachinesViaWrapper(module)))
def test_ignoresImportedClass(self):
"""
When given a L{twisted.python.modules.PythonAttribute} that refers
to a class imported from another module, any
L{MethodicalMachine}s on that class are ignored.
This behavior ensures that a machine is only discovered on a
class when visiting the module where that class was defined.
"""
originalSource = """
from automat import MethodicalMachine
class PythonClass(object):
_classMachine = MethodicalMachine()
"""
importingSource = """
from original import PythonClass
"""
self.makeModule(originalSource, self.pathDir, 'original.py')
importingModule = self.makeModule(importingSource,
self.pathDir,
'importing.py')
self.assertFalse(list(self.findMachinesViaWrapper(importingModule)))
def test_descendsIntoPackages(self):
"""
L{findMachinesViaWrapper} descends into packages to discover
machines.
"""
pythonPath = self.PythonPath([self.pathDir])
package = self.FilePath(self.pathDir).child("test_package")
package.makedirs()
package.child('__init__.py').touch()
source = """
from automat import MethodicalMachine
class PythonClass(object):
_classMachine = MethodicalMachine()
rootMachine = MethodicalMachine()
"""
self.makeModule(source, package.path, 'module.py')
test_package = pythonPath['test_package']
machines = sorted(self.findMachinesViaWrapper(test_package),
key=operator.itemgetter(0))
moduleDict = self.loadModuleAsDict(test_package['module'])
rootMachine = moduleDict['test_package.module.rootMachine'].load()
PythonClass = moduleDict['test_package.module.PythonClass'].load()
expectedMachines = sorted(
[('test_package.module.rootMachine',
rootMachine),
('test_package.module.PythonClass._classMachine',
PythonClass._classMachine)], key=operator.itemgetter(0))
self.assertEqual(expectedMachines, machines)
def test_infiniteLoop(self):
"""
L{findMachinesViaWrapper} ignores infinite loops.
Note this test can't fail - it can only run forever!
"""
source = """
class InfiniteLoop(object):
pass
InfiniteLoop.loop = InfiniteLoop
"""
module = self.makeModule(source, self.pathDir, 'loop.py')
self.assertFalse(list(self.findMachinesViaWrapper(module)))
@skipIf(not isTwistedInstalled(), "Twisted is not installed.")
class WrapFQPNTests(TestCase):
"""
Tests that ensure L{wrapFQPN} loads the
L{twisted.python.modules.PythonModule} or
L{twisted.python.modules.PythonAttribute} for a given FQPN.
"""
def setUp(self):
from twisted.python.modules import PythonModule, PythonAttribute
from .._discover import wrapFQPN, InvalidFQPN, NoModule, NoObject
self.PythonModule = PythonModule
self.PythonAttribute = PythonAttribute
self.wrapFQPN = wrapFQPN
self.InvalidFQPN = InvalidFQPN
self.NoModule = NoModule
self.NoObject = NoObject
def assertModuleWrapperRefersTo(self, moduleWrapper, module):
"""
Assert that a L{twisted.python.modules.PythonModule} refers to a
particular Python module.
"""
self.assertIsInstance(moduleWrapper, self.PythonModule)
self.assertEqual(moduleWrapper.name, module.__name__)
self.assertIs(moduleWrapper.load(), module)
def assertAttributeWrapperRefersTo(self, attributeWrapper, fqpn, obj):
"""
Assert that a L{twisted.python.modules.PythonAttribute} refers to a
particular Python object.
"""
self.assertIsInstance(attributeWrapper, self.PythonAttribute)
self.assertEqual(attributeWrapper.name, fqpn)
self.assertIs(attributeWrapper.load(), obj)
def test_failsWithEmptyFQPN(self):
"""
L{wrapFQPN} raises L{InvalidFQPN} when given an empty string.
"""
with self.assertRaises(self.InvalidFQPN):
self.wrapFQPN('')
def test_failsWithBadDotting(self):
""""
L{wrapFQPN} raises L{InvalidFQPN} when given a badly-dotted
FQPN. (e.g., x..y).
"""
for bad in ('.fails', 'fails.', 'this..fails'):
with self.assertRaises(self.InvalidFQPN):
self.wrapFQPN(bad)
def test_singleModule(self):
"""
L{wrapFQPN} returns a L{twisted.python.modules.PythonModule}
referring to the single module a dotless FQPN describes.
"""
import os
moduleWrapper = self.wrapFQPN('os')
self.assertIsInstance(moduleWrapper, self.PythonModule)
self.assertIs(moduleWrapper.load(), os)
def test_failsWithMissingSingleModuleOrPackage(self):
"""
L{wrapFQPN} raises L{NoModule} when given a dotless FQPN that does
not refer to a module or package.
"""
with self.assertRaises(self.NoModule):
self.wrapFQPN("this is not an acceptable name!")
def test_singlePackage(self):
"""
L{wrapFQPN} returns a L{twisted.python.modules.PythonModule}
referring to the single package a dotless FQPN describes.
"""
import xml
self.assertModuleWrapperRefersTo(self.wrapFQPN('xml'), xml)
def test_multiplePackages(self):
"""
L{wrapFQPN} returns a L{twisted.python.modules.PythonModule}
referring to the deepest package described by dotted FQPN.
"""
import xml.etree
self.assertModuleWrapperRefersTo(self.wrapFQPN('xml.etree'), xml.etree)
def test_multiplePackagesFinalModule(self):
"""
L{wrapFQPN} returns a L{twisted.python.modules.PythonModule}
referring to the deepest module described by dotted FQPN.
"""
import xml.etree.ElementTree
self.assertModuleWrapperRefersTo(
self.wrapFQPN('xml.etree.ElementTree'), xml.etree.ElementTree)
def test_singleModuleObject(self):
"""
L{wrapFQPN} returns a L{twisted.python.modules.PythonAttribute}
referring to the deepest object an FQPN names, traversing one module.
"""
import os
self.assertAttributeWrapperRefersTo(
self.wrapFQPN('os.path'), 'os.path', os.path)
def test_multiplePackagesObject(self):
"""
L{wrapFQPN} returns a L{twisted.python.modules.PythonAttribute}
referring to the deepest object described by an FQPN,
descending through several packages.
"""
import xml.etree.ElementTree
import automat
for fqpn, obj in [('xml.etree.ElementTree.fromstring',
xml.etree.ElementTree.fromstring),
('automat.MethodicalMachine.__doc__',
automat.MethodicalMachine.__doc__)]:
self.assertAttributeWrapperRefersTo(
self.wrapFQPN(fqpn), fqpn, obj)
def test_failsWithMultiplePackagesMissingModuleOrPackage(self):
"""
L{wrapFQPN} raises L{NoObject} when given an FQPN that contains a
missing attribute, module, or package.
"""
for bad in ('xml.etree.nope!',
'xml.etree.nope!.but.the.rest.is.believable'):
with self.assertRaises(self.NoObject):
self.wrapFQPN(bad)
@skipIf(not isTwistedInstalled(), "Twisted is not installed.")
class FindMachinesIntegrationTests(_WritesPythonModules):
"""
Integration tests to check that L{findMachines} yields all
machines discoverable at or below an FQPN.
"""
SOURCE = """
from automat import MethodicalMachine
class PythonClass(object):
_machine = MethodicalMachine()
ignored = "i am ignored"
rootLevel = MethodicalMachine()
ignored = "i am ignored"
"""
def setUp(self):
super(FindMachinesIntegrationTests, self).setUp()
from .._discover import findMachines
self.findMachines = findMachines
packageDir = self.FilePath(self.pathDir).child("test_package")
packageDir.makedirs()
self.pythonPath = self.PythonPath([self.pathDir])
self.writeSourceInto(self.SOURCE, packageDir.path, '__init__.py')
subPackageDir = packageDir.child('subpackage')
subPackageDir.makedirs()
subPackageDir.child('__init__.py').touch()
self.makeModule(self.SOURCE, subPackageDir.path, 'module.py')
self.packageDict = self.loadModuleAsDict(
self.pythonPath['test_package'])
self.moduleDict = self.loadModuleAsDict(
self.pythonPath['test_package']['subpackage']['module'])
def test_discoverAll(self):
"""
Given a top-level package FQPN, L{findMachines} discovers all
L{MethodicalMachine} instances in and below it.
"""
machines = sorted(self.findMachines('test_package'),
key=operator.itemgetter(0))
tpRootLevel = self.packageDict['test_package.rootLevel'].load()
tpPythonClass = self.packageDict['test_package.PythonClass'].load()
mRLAttr = self.moduleDict['test_package.subpackage.module.rootLevel']
mRootLevel = mRLAttr.load()
mPCAttr = self.moduleDict['test_package.subpackage.module.PythonClass']
mPythonClass = mPCAttr.load()
expectedMachines = sorted(
[('test_package.rootLevel', tpRootLevel),
('test_package.PythonClass._machine', tpPythonClass._machine),
('test_package.subpackage.module.rootLevel', mRootLevel),
('test_package.subpackage.module.PythonClass._machine',
mPythonClass._machine)],
key=operator.itemgetter(0))
self.assertEqual(expectedMachines, machines)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/automat/_test/test_methodical.py
================================================
"""
Tests for the public interface of Automat.
"""
from functools import reduce
from unittest import TestCase
from automat._methodical import ArgSpec, _getArgNames, _getArgSpec, _filterArgs
from .. import MethodicalMachine, NoTransition
from .. import _methodical
class MethodicalTests(TestCase):
"""
Tests for L{MethodicalMachine}.
"""
def test_oneTransition(self):
"""
L{MethodicalMachine} provides a way for you to declare a state machine
with inputs, outputs, and states as methods. When you have declared an
input, an output, and a state, calling the input method in that state
will produce the specified output.
"""
class Machination(object):
machine = MethodicalMachine()
@machine.input()
def anInput(self):
"an input"
@machine.output()
def anOutput(self):
"an output"
return "an-output-value"
@machine.output()
def anotherOutput(self):
"another output"
return "another-output-value"
@machine.state(initial=True)
def anState(self):
"a state"
@machine.state()
def anotherState(self):
"another state"
anState.upon(anInput, enter=anotherState, outputs=[anOutput])
anotherState.upon(anInput, enter=anotherState,
outputs=[anotherOutput])
m = Machination()
self.assertEqual(m.anInput(), ["an-output-value"])
self.assertEqual(m.anInput(), ["another-output-value"])
def test_machineItselfIsPrivate(self):
"""
L{MethodicalMachine} is an implementation detail. If you attempt to
access it on an instance of your class, you will get an exception.
However, since tools may need to access it for the purposes of, for
example, visualization, you may access it on the class itself.
"""
expectedMachine = MethodicalMachine()
class Machination(object):
machine = expectedMachine
machination = Machination()
with self.assertRaises(AttributeError) as cm:
machination.machine
self.assertIn("MethodicalMachine is an implementation detail",
str(cm.exception))
self.assertIs(Machination.machine, expectedMachine)
def test_outputsArePrivate(self):
"""
One of the benefits of using a state machine is that your output method
implementations don't need to take invalid state transitions into
account - the methods simply won't be called. This property would be
broken if client code called output methods directly, so output methods
are not directly visible under their names.
"""
class Machination(object):
machine = MethodicalMachine()
counter = 0
@machine.input()
def anInput(self):
"an input"
@machine.output()
def anOutput(self):
self.counter += 1
@machine.state(initial=True)
def state(self):
"a machine state"
state.upon(anInput, enter=state, outputs=[anOutput])
mach1 = Machination()
mach1.anInput()
self.assertEqual(mach1.counter, 1)
mach2 = Machination()
with self.assertRaises(AttributeError) as cm:
mach2.anOutput
self.assertEqual(mach2.counter, 0)
self.assertIn(
"Machination.anOutput is a state-machine output method; to "
"produce this output, call an input method instead.",
str(cm.exception)
)
def test_multipleMachines(self):
"""
Two machines may co-exist happily on the same instance; they don't
interfere with each other.
"""
class MultiMach(object):
a = MethodicalMachine()
b = MethodicalMachine()
@a.input()
def inputA(self):
"input A"
@b.input()
def inputB(self):
"input B"
@a.state(initial=True)
def initialA(self):
"initial A"
@b.state(initial=True)
def initialB(self):
"initial B"
@a.output()
def outputA(self):
return "A"
@b.output()
def outputB(self):
return "B"
initialA.upon(inputA, initialA, [outputA])
initialB.upon(inputB, initialB, [outputB])
mm = MultiMach()
self.assertEqual(mm.inputA(), ["A"])
self.assertEqual(mm.inputB(), ["B"])
def test_collectOutputs(self):
"""
Outputs can be combined with the "collector" argument to "upon".
"""
import operator
class Machine(object):
m = MethodicalMachine()
@m.input()
def input(self):
"an input"
@m.output()
def outputA(self):
return "A"
@m.output()
def outputB(self):
return "B"
@m.state(initial=True)
def state(self):
"a state"
state.upon(input, state, [outputA, outputB],
collector=lambda x: reduce(operator.add, x))
m = Machine()
self.assertEqual(m.input(), "AB")
def test_methodName(self):
"""
Input methods preserve their declared names.
"""
class Mech(object):
m = MethodicalMachine()
@m.input()
def declaredInputName(self):
"an input"
@m.state(initial=True)
def aState(self):
"state"
m = Mech()
with self.assertRaises(TypeError) as cm:
m.declaredInputName("too", "many", "arguments")
self.assertIn("declaredInputName", str(cm.exception))
def test_inputWithArguments(self):
"""
If an input takes an argument, it will pass that along to its output.
"""
class Mechanism(object):
m = MethodicalMachine()
@m.input()
def input(self, x, y=1):
"an input"
@m.state(initial=True)
def state(self):
"a state"
@m.output()
def output(self, x, y=1):
self._x = x
return x + y
state.upon(input, state, [output])
m = Mechanism()
self.assertEqual(m.input(3), [4])
self.assertEqual(m._x, 3)
def test_outputWithSubsetOfArguments(self):
"""
Inputs pass arguments that output will accept.
"""
class Mechanism(object):
m = MethodicalMachine()
@m.input()
def input(self, x, y=1):
"an input"
@m.state(initial=True)
def state(self):
"a state"
@m.output()
def outputX(self, x):
self._x = x
return x
@m.output()
def outputY(self, y):
self._y = y
return y
@m.output()
def outputNoArgs(self):
return None
state.upon(input, state, [outputX, outputY, outputNoArgs])
m = Mechanism()
# Pass x as positional argument.
self.assertEqual(m.input(3), [3, 1, None])
self.assertEqual(m._x, 3)
self.assertEqual(m._y, 1)
# Pass x as key word argument.
self.assertEqual(m.input(x=4), [4, 1, None])
self.assertEqual(m._x, 4)
self.assertEqual(m._y, 1)
# Pass y as positional argument.
self.assertEqual(m.input(6, 3), [6, 3, None])
self.assertEqual(m._x, 6)
self.assertEqual(m._y, 3)
# Pass y as key word argument.
self.assertEqual(m.input(5, y=2), [5, 2, None])
self.assertEqual(m._x, 5)
self.assertEqual(m._y, 2)
def test_inputFunctionsMustBeEmpty(self):
"""
The wrapped input function must have an empty body.
"""
# input functions are executed to assert that the signature matches,
# but their body must be empty
_methodical._empty() # chase coverage
_methodical._docstring()
class Mechanism(object):
m = MethodicalMachine()
with self.assertRaises(ValueError) as cm:
@m.input()
def input(self):
"an input"
list() # pragma: no cover
self.assertEqual(str(cm.exception), "function body must be empty")
# all three of these cases should be valid. Functions/methods with
# docstrings produce slightly different bytecode than ones without.
class MechanismWithDocstring(object):
m = MethodicalMachine()
@m.input()
def input(self):
"an input"
@m.state(initial=True)
def start(self):
"starting state"
start.upon(input, enter=start, outputs=[])
MechanismWithDocstring().input()
class MechanismWithPass(object):
m = MethodicalMachine()
@m.input()
def input(self):
pass
@m.state(initial=True)
def start(self):
"starting state"
start.upon(input, enter=start, outputs=[])
MechanismWithPass().input()
class MechanismWithDocstringAndPass(object):
m = MethodicalMachine()
@m.input()
def input(self):
"an input"
pass
@m.state(initial=True)
def start(self):
"starting state"
start.upon(input, enter=start, outputs=[])
MechanismWithDocstringAndPass().input()
class MechanismReturnsNone(object):
m = MethodicalMachine()
@m.input()
def input(self):
return None
@m.state(initial=True)
def start(self):
"starting state"
start.upon(input, enter=start, outputs=[])
MechanismReturnsNone().input()
class MechanismWithDocstringAndReturnsNone(object):
m = MethodicalMachine()
@m.input()
def input(self):
"an input"
return None
@m.state(initial=True)
def start(self):
"starting state"
start.upon(input, enter=start, outputs=[])
MechanismWithDocstringAndReturnsNone().input()
def test_inputOutputMismatch(self):
"""
All the argument lists of the outputs for a given input must match; if
one does not the call to C{upon} will raise a C{TypeError}.
"""
class Mechanism(object):
m = MethodicalMachine()
@m.input()
def nameOfInput(self, a):
"an input"
@m.output()
def outputThatMatches(self, a):
"an output that matches"
@m.output()
def outputThatDoesntMatch(self, b):
"an output that doesn't match"
@m.state()
def state(self):
"a state"
with self.assertRaises(TypeError) as cm:
state.upon(nameOfInput, state, [outputThatMatches,
outputThatDoesntMatch])
self.assertIn("nameOfInput", str(cm.exception))
self.assertIn("outputThatDoesntMatch", str(cm.exception))
def test_getArgNames(self):
"""
Type annotations should be included in the set of
"""
spec = ArgSpec(
args=('a', 'b'),
varargs=None,
varkw=None,
defaults=None,
kwonlyargs=(),
kwonlydefaults=None,
annotations=(('a', int), ('b', str)),
)
self.assertEqual(
_getArgNames(spec),
{'a', 'b', ('a', int), ('b', str)},
)
def test_filterArgs(self):
"""
filterArgs() should not filter the `args` parameter
if outputSpec accepts `*args`.
"""
inputSpec = _getArgSpec(lambda *args, **kwargs: None)
outputSpec = _getArgSpec(lambda *args, **kwargs: None)
argsIn = ()
argsOut, _ = _filterArgs(argsIn, {}, inputSpec, outputSpec)
self.assertIs(argsIn, argsOut)
def test_multipleInitialStatesFailure(self):
"""
A L{MethodicalMachine} can only have one initial state.
"""
class WillFail(object):
m = MethodicalMachine()
@m.state(initial=True)
def firstInitialState(self):
"The first initial state -- this is OK."
with self.assertRaises(ValueError):
@m.state(initial=True)
def secondInitialState(self):
"The second initial state -- results in a ValueError."
def test_multipleTransitionsFailure(self):
"""
A L{MethodicalMachine} can only have one transition per start/event
pair.
"""
class WillFail(object):
m = MethodicalMachine()
@m.state(initial=True)
def start(self):
"We start here."
@m.state()
def end(self):
"Rainbows end."
@m.input()
def event(self):
"An event."
start.upon(event, enter=end, outputs=[])
with self.assertRaises(ValueError):
start.upon(event, enter=end, outputs=[])
def test_badTransitionForCurrentState(self):
"""
Calling any input method that lacks a transition for the machine's
current state raises an informative L{NoTransition}.
"""
class OnlyOnePath(object):
m = MethodicalMachine()
@m.state(initial=True)
def start(self):
"Start state."
@m.state()
def end(self):
"End state."
@m.input()
def advance(self):
"Move from start to end."
@m.input()
def deadEnd(self):
"A transition from nowhere to nowhere."
start.upon(advance, end, [])
machine = OnlyOnePath()
with self.assertRaises(NoTransition) as cm:
machine.deadEnd()
self.assertIn("deadEnd", str(cm.exception))
self.assertIn("start", str(cm.exception))
machine.advance()
with self.assertRaises(NoTransition) as cm:
machine.deadEnd()
self.assertIn("deadEnd", str(cm.exception))
self.assertIn("end", str(cm.exception))
def test_saveState(self):
"""
L{MethodicalMachine.serializer} is a decorator that modifies its
decoratee's signature to take a "state" object as its first argument,
which is the "serialized" argument to the L{MethodicalMachine.state}
decorator.
"""
class Mechanism(object):
m = MethodicalMachine()
def __init__(self):
self.value = 1
@m.state(serialized="first-state", initial=True)
def first(self):
"First state."
@m.state(serialized="second-state")
def second(self):
"Second state."
@m.serializer()
def save(self, state):
return {
'machine-state': state,
'some-value': self.value,
}
self.assertEqual(
Mechanism().save(),
{
"machine-state": "first-state",
"some-value": 1,
}
)
def test_restoreState(self):
"""
L{MethodicalMachine.unserializer} decorates a function that becomes a
machine-state unserializer; its return value is mapped to the
C{serialized} parameter to C{state}, and the L{MethodicalMachine}
associated with that instance's state is updated to that state.
"""
class Mechanism(object):
m = MethodicalMachine()
def __init__(self):
self.value = 1
self.ranOutput = False
@m.state(serialized="first-state", initial=True)
def first(self):
"First state."
@m.state(serialized="second-state")
def second(self):
"Second state."
@m.input()
def input(self):
"an input"
@m.output()
def output(self):
self.value = 2
self.ranOutput = True
return 1
@m.output()
def output2(self):
return 2
first.upon(input, second, [output],
collector=lambda x: list(x)[0])
second.upon(input, second, [output2],
collector=lambda x: list(x)[0])
@m.serializer()
def save(self, state):
return {
'machine-state': state,
'some-value': self.value,
}
@m.unserializer()
def _restore(self, blob):
self.value = blob['some-value']
return blob['machine-state']
@classmethod
def fromBlob(cls, blob):
self = cls()
self._restore(blob)
return self
m1 = Mechanism()
m1.input()
blob = m1.save()
m2 = Mechanism.fromBlob(blob)
self.assertEqual(m2.ranOutput, False)
self.assertEqual(m2.input(), 2)
self.assertEqual(
m2.save(),
{
'machine-state': 'second-state',
'some-value': 2,
}
)
# FIXME: error for wrong types on any call to _oneTransition
# FIXME: better public API for .upon; maybe a context manager?
# FIXME: when transitions are defined, validate that we can always get to
# terminal? do we care about this?
# FIXME: implementation (and use-case/example) for passing args from in to out
# FIXME: possibly these need some kind of support from core
# FIXME: wildcard state (in all states, when input X, emit Y and go to Z)
# FIXME: wildcard input (in state X, when any input, emit Y and go to Z)
# FIXME: combined wildcards (in any state for any input, emit Y go to Z)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/automat/_test/test_trace.py
================================================
from unittest import TestCase
from .._methodical import MethodicalMachine
class SampleObject(object):
mm = MethodicalMachine()
@mm.state(initial=True)
def begin(self):
"initial state"
@mm.state()
def middle(self):
"middle state"
@mm.state()
def end(self):
"end state"
@mm.input()
def go1(self):
"sample input"
@mm.input()
def go2(self):
"sample input"
@mm.input()
def back(self):
"sample input"
@mm.output()
def out(self):
"sample output"
setTrace = mm._setTrace
begin.upon(go1, middle, [out])
middle.upon(go2, end, [out])
end.upon(back, middle, [])
middle.upon(back, begin, [])
class TraceTests(TestCase):
def test_only_inputs(self):
traces = []
def tracer(old_state, input, new_state):
traces.append((old_state, input, new_state))
return None # "I only care about inputs, not outputs"
s = SampleObject()
s.setTrace(tracer)
s.go1()
self.assertEqual(traces, [("begin", "go1", "middle"),
])
s.go2()
self.assertEqual(traces, [("begin", "go1", "middle"),
("middle", "go2", "end"),
])
s.setTrace(None)
s.back()
self.assertEqual(traces, [("begin", "go1", "middle"),
("middle", "go2", "end"),
])
s.go2()
self.assertEqual(traces, [("begin", "go1", "middle"),
("middle", "go2", "end"),
])
def test_inputs_and_outputs(self):
traces = []
def tracer(old_state, input, new_state):
traces.append((old_state, input, new_state, None))
def trace_outputs(output):
traces.append((old_state, input, new_state, output))
return trace_outputs # "I care about outputs too"
s = SampleObject()
s.setTrace(tracer)
s.go1()
self.assertEqual(traces, [("begin", "go1", "middle", None),
("begin", "go1", "middle", "out"),
])
s.go2()
self.assertEqual(traces, [("begin", "go1", "middle", None),
("begin", "go1", "middle", "out"),
("middle", "go2", "end", None),
("middle", "go2", "end", "out"),
])
s.setTrace(None)
s.back()
self.assertEqual(traces, [("begin", "go1", "middle", None),
("begin", "go1", "middle", "out"),
("middle", "go2", "end", None),
("middle", "go2", "end", "out"),
])
s.go2()
self.assertEqual(traces, [("begin", "go1", "middle", None),
("begin", "go1", "middle", "out"),
("middle", "go2", "end", None),
("middle", "go2", "end", "out"),
])
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/automat/_test/test_visualize.py
================================================
from __future__ import print_function
import functools
import os
import subprocess
from unittest import TestCase, skipIf
import attr
from .._methodical import MethodicalMachine
from .test_discover import isTwistedInstalled
def isGraphvizModuleInstalled():
"""
Is the graphviz Python module installed?
"""
try:
__import__("graphviz")
except ImportError:
return False
else:
return True
def isGraphvizInstalled():
"""
Are the graphviz tools installed?
"""
r, w = os.pipe()
os.close(w)
try:
return not subprocess.call("dot", stdin=r, shell=True)
finally:
os.close(r)
def sampleMachine():
"""
Create a sample L{MethodicalMachine} with some sample states.
"""
mm = MethodicalMachine()
class SampleObject(object):
@mm.state(initial=True)
def begin(self):
"initial state"
@mm.state()
def end(self):
"end state"
@mm.input()
def go(self):
"sample input"
@mm.output()
def out(self):
"sample output"
begin.upon(go, end, [out])
so = SampleObject()
so.go()
return mm
@skipIf(not isGraphvizModuleInstalled(), "Graphviz module is not installed.")
class ElementMakerTests(TestCase):
"""
L{elementMaker} generates HTML representing the specified element.
"""
def setUp(self):
from .._visualize import elementMaker
self.elementMaker = elementMaker
def test_sortsAttrs(self):
"""
L{elementMaker} orders HTML attributes lexicographically.
"""
expected = r''
self.assertEqual(expected,
self.elementMaker("div",
b='2',
a='1',
c='3'))
def test_quotesAttrs(self):
"""
L{elementMaker} quotes HTML attributes according to DOT's quoting rule.
See U{http://www.graphviz.org/doc/info/lang.html}, footnote 1.
"""
expected = r''
self.assertEqual(expected,
self.elementMaker("div",
b='a " quote',
a=1,
c="a string"))
def test_noAttrs(self):
"""
L{elementMaker} should render an element with no attributes.
"""
expected = r''
self.assertEqual(expected, self.elementMaker("div"))
@attr.s
class HTMLElement(object):
"""Holds an HTML element, as created by elementMaker."""
name = attr.ib()
children = attr.ib()
attributes = attr.ib()
def findElements(element, predicate):
"""
Recursively collect all elements in an L{HTMLElement} tree that
match the optional predicate.
"""
if predicate(element):
return [element]
elif isLeaf(element):
return []
return [result
for child in element.children
for result in findElements(child, predicate)]
def isLeaf(element):
"""
This HTML element is actually leaf node.
"""
return not isinstance(element, HTMLElement)
@skipIf(not isGraphvizModuleInstalled(), "Graphviz module is not installed.")
class TableMakerTests(TestCase):
"""
Tests that ensure L{tableMaker} generates HTML tables usable as
labels in DOT graphs.
For more information, read the "HTML-Like Labels" section of
U{http://www.graphviz.org/doc/info/shapes.html}.
"""
def fakeElementMaker(self, name, *children, **attributes):
return HTMLElement(name=name, children=children, attributes=attributes)
def setUp(self):
from .._visualize import tableMaker
self.inputLabel = "input label"
self.port = "the port"
self.tableMaker = functools.partial(tableMaker,
_E=self.fakeElementMaker)
def test_inputLabelRow(self):
"""
The table returned by L{tableMaker} always contains the input
symbol label in its first row, and that row contains one cell
with a port attribute set to the provided port.
"""
def hasPort(element):
return (not isLeaf(element)
and element.attributes.get("port") == self.port)
for outputLabels in ([], ["an output label"]):
table = self.tableMaker(self.inputLabel, outputLabels,
port=self.port)
self.assertGreater(len(table.children), 0)
inputLabelRow = table.children[0]
portCandidates = findElements(table, hasPort)
self.assertEqual(len(portCandidates), 1)
self.assertEqual(portCandidates[0].name, "td")
self.assertEqual(findElements(inputLabelRow, isLeaf),
[self.inputLabel])
def test_noOutputLabels(self):
"""
L{tableMaker} does not add a colspan attribute to the input
label's cell or a second row if there no output labels.
"""
table = self.tableMaker("input label", (), port=self.port)
self.assertEqual(len(table.children), 1)
(inputLabelRow,) = table.children
self.assertNotIn("colspan", inputLabelRow.attributes)
def test_withOutputLabels(self):
"""
L{tableMaker} adds a colspan attribute to the input label's cell
equal to the number of output labels and a second row that
contains the output labels.
"""
table = self.tableMaker(self.inputLabel, ("output label 1",
"output label 2"),
port=self.port)
self.assertEqual(len(table.children), 2)
inputRow, outputRow = table.children
def hasCorrectColspan(element):
return (not isLeaf(element)
and element.name == "td"
and element.attributes.get('colspan') == "2")
self.assertEqual(len(findElements(inputRow, hasCorrectColspan)),
1)
self.assertEqual(findElements(outputRow, isLeaf), ["output label 1",
"output label 2"])
@skipIf(not isGraphvizModuleInstalled(), "Graphviz module is not installed.")
@skipIf(not isGraphvizInstalled(), "Graphviz tools are not installed.")
class IntegrationTests(TestCase):
"""
Tests which make sure Graphviz can understand the output produced by
Automat.
"""
def test_validGraphviz(self):
"""
L{graphviz} emits valid graphviz data.
"""
p = subprocess.Popen("dot", stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
out, err = p.communicate("".join(sampleMachine().asDigraph())
.encode("utf-8"))
self.assertEqual(p.returncode, 0)
@skipIf(not isGraphvizModuleInstalled(), "Graphviz module is not installed.")
class SpotChecks(TestCase):
"""
Tests to make sure that the output contains salient features of the machine
being generated.
"""
def test_containsMachineFeatures(self):
"""
The output of L{graphviz} should contain the names of the states,
inputs, outputs in the state machine.
"""
gvout = "".join(sampleMachine().asDigraph())
self.assertIn("begin", gvout)
self.assertIn("end", gvout)
self.assertIn("go", gvout)
self.assertIn("out", gvout)
class RecordsDigraphActions(object):
"""
Records calls made to L{FakeDigraph}.
"""
def __init__(self):
self.reset()
def reset(self):
self.renderCalls = []
self.saveCalls = []
class FakeDigraph(object):
"""
A fake L{graphviz.Digraph}. Instantiate it with a
L{RecordsDigraphActions}.
"""
def __init__(self, recorder):
self._recorder = recorder
def render(self, **kwargs):
self._recorder.renderCalls.append(kwargs)
def save(self, **kwargs):
self._recorder.saveCalls.append(kwargs)
class FakeMethodicalMachine(object):
"""
A fake L{MethodicalMachine}. Instantiate it with a L{FakeDigraph}
"""
def __init__(self, digraph):
self._digraph = digraph
def asDigraph(self):
return self._digraph
@skipIf(not isGraphvizModuleInstalled(), "Graphviz module is not installed.")
@skipIf(not isGraphvizInstalled(), "Graphviz tools are not installed.")
@skipIf(not isTwistedInstalled(), "Twisted is not installed.")
class VisualizeToolTests(TestCase):
def setUp(self):
self.digraphRecorder = RecordsDigraphActions()
self.fakeDigraph = FakeDigraph(self.digraphRecorder)
self.fakeProgname = 'tool-test'
self.fakeSysPath = ['ignored']
self.collectedOutput = []
self.fakeFQPN = 'fake.fqpn'
def collectPrints(self, *args):
self.collectedOutput.append(' '.join(args))
def fakeFindMachines(self, fqpn):
yield fqpn, FakeMethodicalMachine(self.fakeDigraph)
def tool(self,
progname=None,
argv=None,
syspath=None,
findMachines=None,
print=None):
from .._visualize import tool
return tool(
_progname=progname or self.fakeProgname,
_argv=argv or [self.fakeFQPN],
_syspath=syspath or self.fakeSysPath,
_findMachines=findMachines or self.fakeFindMachines,
_print=print or self.collectPrints)
def test_checksCurrentDirectory(self):
"""
L{tool} adds '' to sys.path to ensure
L{automat._discover.findMachines} searches the current
directory.
"""
self.tool(argv=[self.fakeFQPN])
self.assertEqual(self.fakeSysPath[0], '')
def test_quietHidesOutput(self):
"""
Passing -q/--quiet hides all output.
"""
self.tool(argv=[self.fakeFQPN, '--quiet'])
self.assertFalse(self.collectedOutput)
self.tool(argv=[self.fakeFQPN, '-q'])
self.assertFalse(self.collectedOutput)
def test_onlySaveDot(self):
"""
Passing an empty string for --image-directory/-i disables
rendering images.
"""
for arg in ('--image-directory', '-i'):
self.digraphRecorder.reset()
self.collectedOutput = []
self.tool(argv=[self.fakeFQPN, arg, ''])
self.assertFalse(any("image" in line
for line in self.collectedOutput))
self.assertEqual(len(self.digraphRecorder.saveCalls), 1)
(call,) = self.digraphRecorder.saveCalls
self.assertEqual("{}.dot".format(self.fakeFQPN),
call['filename'])
self.assertFalse(self.digraphRecorder.renderCalls)
def test_saveOnlyImage(self):
"""
Passing an empty string for --dot-directory/-d disables saving dot
files.
"""
for arg in ('--dot-directory', '-d'):
self.digraphRecorder.reset()
self.collectedOutput = []
self.tool(argv=[self.fakeFQPN, arg, ''])
self.assertFalse(any("dot" in line
for line in self.collectedOutput))
self.assertEqual(len(self.digraphRecorder.renderCalls), 1)
(call,) = self.digraphRecorder.renderCalls
self.assertEqual("{}.dot".format(self.fakeFQPN),
call['filename'])
self.assertTrue(call['cleanup'])
self.assertFalse(self.digraphRecorder.saveCalls)
def test_saveDotAndImagesInDifferentDirectories(self):
"""
Passing different directories to --image-directory and --dot-directory
writes images and dot files to those directories.
"""
imageDirectory = 'image'
dotDirectory = 'dot'
self.tool(argv=[self.fakeFQPN,
'--image-directory', imageDirectory,
'--dot-directory', dotDirectory])
self.assertTrue(any("image" in line
for line in self.collectedOutput))
self.assertTrue(any("dot" in line
for line in self.collectedOutput))
self.assertEqual(len(self.digraphRecorder.renderCalls), 1)
(renderCall,) = self.digraphRecorder.renderCalls
self.assertEqual(renderCall["directory"], imageDirectory)
self.assertTrue(renderCall['cleanup'])
self.assertEqual(len(self.digraphRecorder.saveCalls), 1)
(saveCall,) = self.digraphRecorder.saveCalls
self.assertEqual(saveCall["directory"], dotDirectory)
def test_saveDotAndImagesInSameDirectory(self):
"""
Passing the same directory to --image-directory and --dot-directory
writes images and dot files to that one directory.
"""
directory = 'imagesAndDot'
self.tool(argv=[self.fakeFQPN,
'--image-directory', directory,
'--dot-directory', directory])
self.assertTrue(any("image and dot" in line
for line in self.collectedOutput))
self.assertEqual(len(self.digraphRecorder.renderCalls), 1)
(renderCall,) = self.digraphRecorder.renderCalls
self.assertEqual(renderCall["directory"], directory)
self.assertFalse(renderCall['cleanup'])
self.assertFalse(len(self.digraphRecorder.saveCalls))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/automat/_visualize.py
================================================
from __future__ import print_function
import argparse
import sys
import graphviz
from ._discover import findMachines
def _gvquote(s):
return '"{}"'.format(s.replace('"', r'\"'))
def _gvhtml(s):
return '<{}>'.format(s)
def elementMaker(name, *children, **attrs):
"""
Construct a string from the HTML element description.
"""
formattedAttrs = ' '.join('{}={}'.format(key, _gvquote(str(value)))
for key, value in sorted(attrs.items()))
formattedChildren = ''.join(children)
return u'<{name} {attrs}>{children}{name}>'.format(
name=name,
attrs=formattedAttrs,
children=formattedChildren)
def tableMaker(inputLabel, outputLabels, port, _E=elementMaker):
"""
Construct an HTML table to label a state transition.
"""
colspan = {}
if outputLabels:
colspan['colspan'] = str(len(outputLabels))
inputLabelCell = _E("td",
_E("font",
inputLabel,
face="menlo-italic"),
color="purple",
port=port,
**colspan)
pointSize = {"point-size": "9"}
outputLabelCells = [_E("td",
_E("font",
outputLabel,
**pointSize),
color="pink")
for outputLabel in outputLabels]
rows = [_E("tr", inputLabelCell)]
if outputLabels:
rows.append(_E("tr", *outputLabelCells))
return _E("table", *rows)
def makeDigraph(automaton, inputAsString=repr,
outputAsString=repr,
stateAsString=repr):
"""
Produce a L{graphviz.Digraph} object from an automaton.
"""
digraph = graphviz.Digraph(graph_attr={'pack': 'true',
'dpi': '100'},
node_attr={'fontname': 'Menlo'},
edge_attr={'fontname': 'Menlo'})
for state in automaton.states():
if state is automaton.initialState:
stateShape = "bold"
fontName = "Menlo-Bold"
else:
stateShape = ""
fontName = "Menlo"
digraph.node(stateAsString(state),
fontame=fontName,
shape="ellipse",
style=stateShape,
color="blue")
for n, eachTransition in enumerate(automaton.allTransitions()):
inState, inputSymbol, outState, outputSymbols = eachTransition
thisTransition = "t{}".format(n)
inputLabel = inputAsString(inputSymbol)
port = "tableport"
table = tableMaker(inputLabel, [outputAsString(outputSymbol)
for outputSymbol in outputSymbols],
port=port)
digraph.node(thisTransition,
label=_gvhtml(table), margin="0.2", shape="none")
digraph.edge(stateAsString(inState),
'{}:{}:w'.format(thisTransition, port),
arrowhead="none")
digraph.edge('{}:{}:e'.format(thisTransition, port),
stateAsString(outState))
return digraph
def tool(_progname=sys.argv[0],
_argv=sys.argv[1:],
_syspath=sys.path,
_findMachines=findMachines,
_print=print):
"""
Entry point for command line utility.
"""
DESCRIPTION = """
Visualize automat.MethodicalMachines as graphviz graphs.
"""
EPILOG = """
You must have the graphviz tool suite installed. Please visit
http://www.graphviz.org for more information.
"""
if _syspath[0]:
_syspath.insert(0, '')
argumentParser = argparse.ArgumentParser(
prog=_progname,
description=DESCRIPTION,
epilog=EPILOG)
argumentParser.add_argument('fqpn',
help="A Fully Qualified Path name"
" representing where to find machines.")
argumentParser.add_argument('--quiet', '-q',
help="suppress output",
default=False,
action="store_true")
argumentParser.add_argument('--dot-directory', '-d',
help="Where to write out .dot files.",
default=".automat_visualize")
argumentParser.add_argument('--image-directory', '-i',
help="Where to write out image files.",
default=".automat_visualize")
argumentParser.add_argument('--image-type', '-t',
help="The image format.",
choices=graphviz.FORMATS,
default='png')
argumentParser.add_argument('--view', '-v',
help="View rendered graphs with"
" default image viewer",
default=False,
action="store_true")
args = argumentParser.parse_args(_argv)
explicitlySaveDot = (args.dot_directory
and (not args.image_directory
or args.image_directory != args.dot_directory))
if args.quiet:
def _print(*args):
pass
for fqpn, machine in _findMachines(args.fqpn):
_print(fqpn, '...discovered')
digraph = machine.asDigraph()
if explicitlySaveDot:
digraph.save(filename="{}.dot".format(fqpn),
directory=args.dot_directory)
_print(fqpn, "...wrote dot into", args.dot_directory)
if args.image_directory:
deleteDot = not args.dot_directory or explicitlySaveDot
digraph.format = args.image_type
digraph.render(filename="{}.dot".format(fqpn),
directory=args.image_directory,
view=args.view,
cleanup=deleteDot)
if deleteDot:
msg = "...wrote image into"
else:
msg = "...wrote image and dot into"
_print(fqpn, msg, args.image_directory)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/__init__.py
================================================
# Copyright 2009-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""BSON (Binary JSON) encoding and decoding.
The mapping from Python types to BSON types is as follows:
======================================= ============= ===================
Python Type BSON Type Supported Direction
======================================= ============= ===================
None null both
bool boolean both
int [#int]_ int32 / int64 py -> bson
long int64 py -> bson
`bson.int64.Int64` int64 both
float number (real) both
string string py -> bson
unicode string both
list array both
dict / `SON` object both
datetime.datetime [#dt]_ [#dt2]_ date both
`bson.regex.Regex` regex both
compiled re [#re]_ regex py -> bson
`bson.binary.Binary` binary both
`bson.objectid.ObjectId` oid both
`bson.dbref.DBRef` dbref both
None undefined bson -> py
unicode code bson -> py
`bson.code.Code` code py -> bson
unicode symbol bson -> py
bytes (Python 3) [#bytes]_ binary both
======================================= ============= ===================
Note that, when using Python 2.x, to save binary data it must be wrapped as
an instance of `bson.binary.Binary`. Otherwise it will be saved as a BSON
string and retrieved as unicode. Users of Python 3.x can use the Python bytes
type.
.. [#int] A Python int will be saved as a BSON int32 or BSON int64 depending
on its size. A BSON int32 will always decode to a Python int. A BSON
int64 will always decode to a :class:`~bson.int64.Int64`.
.. [#dt] datetime.datetime instances will be rounded to the nearest
millisecond when saved
.. [#dt2] all datetime.datetime instances are treated as *naive*. clients
should always use UTC.
.. [#re] :class:`~bson.regex.Regex` instances and regular expression
objects from ``re.compile()`` are both saved as BSON regular expressions.
BSON regular expressions are decoded as :class:`~bson.regex.Regex`
instances.
.. [#bytes] The bytes type from Python 3.x is encoded as BSON binary with
subtype 0. In Python 3.x it will be decoded back to bytes. In Python 2.x
it will be decoded to an instance of :class:`~bson.binary.Binary` with
subtype 0.
"""
import calendar
import datetime
import itertools
import platform
import re
import struct
import sys
import uuid
from codecs import (utf_8_decode as _utf_8_decode,
utf_8_encode as _utf_8_encode)
from bson.binary import (Binary, OLD_UUID_SUBTYPE,
JAVA_LEGACY, CSHARP_LEGACY,
UUIDLegacy)
from bson.code import Code
from bson.codec_options import (
CodecOptions, DEFAULT_CODEC_OPTIONS, _raw_document_class)
from bson.dbref import DBRef
from bson.decimal128 import Decimal128
from bson.errors import (InvalidBSON,
InvalidDocument,
InvalidStringData)
from bson.int64 import Int64
from bson.max_key import MaxKey
from bson.min_key import MinKey
from bson.objectid import ObjectId
from bson.py3compat import (abc,
b,
PY3,
iteritems,
text_type,
string_type,
reraise)
from bson.regex import Regex
from bson.son import SON, RE_TYPE
from bson.timestamp import Timestamp
from bson.tz_util import utc
try:
from bson import _cbson
_USE_C = True
except ImportError:
_USE_C = False
EPOCH_AWARE = datetime.datetime.fromtimestamp(0, utc)
EPOCH_NAIVE = datetime.datetime.utcfromtimestamp(0)
BSONNUM = b"\x01" # Floating point
BSONSTR = b"\x02" # UTF-8 string
BSONOBJ = b"\x03" # Embedded document
BSONARR = b"\x04" # Array
BSONBIN = b"\x05" # Binary
BSONUND = b"\x06" # Undefined
BSONOID = b"\x07" # ObjectId
BSONBOO = b"\x08" # Boolean
BSONDAT = b"\x09" # UTC Datetime
BSONNUL = b"\x0A" # Null
BSONRGX = b"\x0B" # Regex
BSONREF = b"\x0C" # DBRef
BSONCOD = b"\x0D" # Javascript code
BSONSYM = b"\x0E" # Symbol
BSONCWS = b"\x0F" # Javascript code with scope
BSONINT = b"\x10" # 32bit int
BSONTIM = b"\x11" # Timestamp
BSONLON = b"\x12" # 64bit int
BSONDEC = b"\x13" # Decimal128
BSONMIN = b"\xFF" # Min key
BSONMAX = b"\x7F" # Max key
_UNPACK_FLOAT_FROM = struct.Struct("= obj_end:
raise InvalidBSON("invalid object length")
# If this is the top-level document, validate the total size too.
if position == 0 and obj_size != obj_end:
raise InvalidBSON("invalid object length")
return obj_size, end
def _get_object(data, view, position, obj_end, opts, dummy):
"""Decode a BSON subdocument to opts.document_class or bson.dbref.DBRef."""
obj_size, end = _get_object_size(data, position, obj_end)
if _raw_document_class(opts.document_class):
return (opts.document_class(data[position:end + 1], opts),
position + obj_size)
obj = _elements_to_dict(data, view, position + 4, end, opts)
position += obj_size
if "$ref" in obj:
return (DBRef(obj.pop("$ref"), obj.pop("$id", None),
obj.pop("$db", None), obj), position)
return obj, position
def _get_array(data, view, position, obj_end, opts, element_name):
"""Decode a BSON array to python list."""
size = _UNPACK_INT_FROM(data, position)[0]
end = position + size - 1
if data[end] != _OBJEND:
raise InvalidBSON("bad eoo")
position += 4
end -= 1
result = []
# Avoid doing global and attribute lookups in the loop.
append = result.append
index = data.index
getter = _ELEMENT_GETTER
decoder_map = opts.type_registry._decoder_map
while position < end:
element_type = data[position]
# Just skip the keys.
position = index(b'\x00', position) + 1
try:
value, position = getter[element_type](
data, view, position, obj_end, opts, element_name)
except KeyError:
_raise_unknown_type(element_type, element_name)
if decoder_map:
custom_decoder = decoder_map.get(type(value))
if custom_decoder is not None:
value = custom_decoder(value)
append(value)
if position != end + 1:
raise InvalidBSON('bad array length')
return result, position + 1
def _get_binary(data, view, position, obj_end, opts, dummy1):
"""Decode a BSON binary to bson.binary.Binary or python UUID."""
length, subtype = _UNPACK_LENGTH_SUBTYPE_FROM(data, position)
position += 5
if subtype == 2:
length2 = _UNPACK_INT_FROM(data, position)[0]
position += 4
if length2 != length - 4:
raise InvalidBSON("invalid binary (st 2) - lengths don't match!")
length = length2
end = position + length
if length < 0 or end > obj_end:
raise InvalidBSON('bad binary object length')
if subtype == 3:
# Java Legacy
uuid_representation = opts.uuid_representation
if uuid_representation == JAVA_LEGACY:
java = data[position:end]
value = uuid.UUID(bytes=java[0:8][::-1] + java[8:16][::-1])
# C# legacy
elif uuid_representation == CSHARP_LEGACY:
value = uuid.UUID(bytes_le=data[position:end])
# Python
else:
value = uuid.UUID(bytes=data[position:end])
return value, end
if subtype == 4:
return uuid.UUID(bytes=data[position:end]), end
# Python3 special case. Decode subtype 0 to 'bytes'.
if PY3 and subtype == 0:
value = data[position:end]
else:
value = Binary(data[position:end], subtype)
return value, end
def _get_oid(data, view, position, dummy0, dummy1, dummy2):
"""Decode a BSON ObjectId to bson.objectid.ObjectId."""
end = position + 12
return ObjectId(data[position:end]), end
def _get_boolean(data, view, position, dummy0, dummy1, dummy2):
"""Decode a BSON true/false to python True/False."""
end = position + 1
boolean_byte = data[position:end]
if boolean_byte == b'\x00':
return False, end
elif boolean_byte == b'\x01':
return True, end
raise InvalidBSON('invalid boolean value: %r' % boolean_byte)
def _get_date(data, view, position, dummy0, opts, dummy1):
"""Decode a BSON datetime to python datetime.datetime."""
return _millis_to_datetime(
_UNPACK_LONG_FROM(data, position)[0], opts), position + 8
def _get_code(data, view, position, obj_end, opts, element_name):
"""Decode a BSON code to bson.code.Code."""
code, position = _get_string(data, view, position, obj_end, opts, element_name)
return Code(code), position
def _get_code_w_scope(data, view, position, obj_end, opts, element_name):
"""Decode a BSON code_w_scope to bson.code.Code."""
code_end = position + _UNPACK_INT_FROM(data, position)[0]
code, position = _get_string(
data, view, position + 4, code_end, opts, element_name)
scope, position = _get_object(data, view, position, code_end, opts, element_name)
if position != code_end:
raise InvalidBSON('scope outside of javascript code boundaries')
return Code(code, scope), position
def _get_regex(data, view, position, dummy0, opts, dummy1):
"""Decode a BSON regex to bson.regex.Regex or a python pattern object."""
pattern, position = _get_c_string(data, view, position, opts)
bson_flags, position = _get_c_string(data, view, position, opts)
bson_re = Regex(pattern, bson_flags)
return bson_re, position
def _get_ref(data, view, position, obj_end, opts, element_name):
"""Decode (deprecated) BSON DBPointer to bson.dbref.DBRef."""
collection, position = _get_string(
data, view, position, obj_end, opts, element_name)
oid, position = _get_oid(data, view, position, obj_end, opts, element_name)
return DBRef(collection, oid), position
def _get_timestamp(data, view, position, dummy0, dummy1, dummy2):
"""Decode a BSON timestamp to bson.timestamp.Timestamp."""
inc, timestamp = _UNPACK_TIMESTAMP_FROM(data, position)
return Timestamp(timestamp, inc), position + 8
def _get_int64(data, view, position, dummy0, dummy1, dummy2):
"""Decode a BSON int64 to bson.int64.Int64."""
return Int64(_UNPACK_LONG_FROM(data, position)[0]), position + 8
def _get_decimal128(data, view, position, dummy0, dummy1, dummy2):
"""Decode a BSON decimal128 to bson.decimal128.Decimal128."""
end = position + 16
return Decimal128.from_bid(data[position:end]), end
# Each decoder function's signature is:
# - data: bytes
# - view: memoryview that references `data`
# - position: int, beginning of object in 'data' to decode
# - obj_end: int, end of object to decode in 'data' if variable-length type
# - opts: a CodecOptions
_ELEMENT_GETTER = {
_maybe_ord(BSONNUM): _get_float,
_maybe_ord(BSONSTR): _get_string,
_maybe_ord(BSONOBJ): _get_object,
_maybe_ord(BSONARR): _get_array,
_maybe_ord(BSONBIN): _get_binary,
_maybe_ord(BSONUND): lambda u, v, w, x, y, z: (None, w), # Deprecated undefined
_maybe_ord(BSONOID): _get_oid,
_maybe_ord(BSONBOO): _get_boolean,
_maybe_ord(BSONDAT): _get_date,
_maybe_ord(BSONNUL): lambda u, v, w, x, y, z: (None, w),
_maybe_ord(BSONRGX): _get_regex,
_maybe_ord(BSONREF): _get_ref, # Deprecated DBPointer
_maybe_ord(BSONCOD): _get_code,
_maybe_ord(BSONSYM): _get_string, # Deprecated symbol
_maybe_ord(BSONCWS): _get_code_w_scope,
_maybe_ord(BSONINT): _get_int,
_maybe_ord(BSONTIM): _get_timestamp,
_maybe_ord(BSONLON): _get_int64,
_maybe_ord(BSONDEC): _get_decimal128,
_maybe_ord(BSONMIN): lambda u, v, w, x, y, z: (MinKey(), w),
_maybe_ord(BSONMAX): lambda u, v, w, x, y, z: (MaxKey(), w)}
if _USE_C:
def _element_to_dict(data, view, position, obj_end, opts):
return _cbson._element_to_dict(data, position, obj_end, opts)
else:
def _element_to_dict(data, view, position, obj_end, opts):
"""Decode a single key, value pair."""
element_type = data[position]
position += 1
element_name, position = _get_c_string(data, view, position, opts)
try:
value, position = _ELEMENT_GETTER[element_type](data, view, position,
obj_end, opts,
element_name)
except KeyError:
_raise_unknown_type(element_type, element_name)
if opts.type_registry._decoder_map:
custom_decoder = opts.type_registry._decoder_map.get(type(value))
if custom_decoder is not None:
value = custom_decoder(value)
return element_name, value, position
def _raw_to_dict(data, position, obj_end, opts, result):
data, view = get_data_and_view(data)
return _elements_to_dict(data, view, position, obj_end, opts, result)
def _elements_to_dict(data, view, position, obj_end, opts, result=None):
"""Decode a BSON document into result."""
if result is None:
result = opts.document_class()
end = obj_end - 1
while position < end:
key, value, position = _element_to_dict(data, view, position, obj_end, opts)
result[key] = value
if position != obj_end:
raise InvalidBSON('bad object or element length')
return result
def _bson_to_dict(data, opts):
"""Decode a BSON string to document_class."""
data, view = get_data_and_view(data)
try:
if _raw_document_class(opts.document_class):
return opts.document_class(data, opts)
_, end = _get_object_size(data, 0, len(data))
return _elements_to_dict(data, view, 4, end, opts)
except InvalidBSON:
raise
except Exception:
# Change exception type to InvalidBSON but preserve traceback.
_, exc_value, exc_tb = sys.exc_info()
reraise(InvalidBSON, exc_value, exc_tb)
if _USE_C:
_bson_to_dict = _cbson._bson_to_dict
_PACK_FLOAT = struct.Struct(">> import collections # From Python standard library.
>>> import bson
>>> from bson.codec_options import CodecOptions
>>> data = bson.encode({'a': 1})
>>> decoded_doc = bson.decode(data)
>>> options = CodecOptions(document_class=collections.OrderedDict)
>>> decoded_doc = bson.decode(data, codec_options=options)
>>> type(decoded_doc)
:Parameters:
- `data`: the BSON to decode. Any bytes-like object that implements
the buffer protocol.
- `codec_options` (optional): An instance of
:class:`~bson.codec_options.CodecOptions`.
.. versionadded:: 3.9
"""
if not isinstance(codec_options, CodecOptions):
raise _CODEC_OPTIONS_TYPE_ERROR
return _bson_to_dict(data, codec_options)
def decode_all(data, codec_options=DEFAULT_CODEC_OPTIONS):
"""Decode BSON data to multiple documents.
`data` must be a bytes-like object implementing the buffer protocol that
provides concatenated, valid, BSON-encoded documents.
:Parameters:
- `data`: BSON data
- `codec_options` (optional): An instance of
:class:`~bson.codec_options.CodecOptions`.
.. versionchanged:: 3.9
Supports bytes-like objects that implement the buffer protocol.
.. versionchanged:: 3.0
Removed `compile_re` option: PyMongo now always represents BSON regular
expressions as :class:`~bson.regex.Regex` objects. Use
:meth:`~bson.regex.Regex.try_compile` to attempt to convert from a
BSON regular expression to a Python regular expression object.
Replaced `as_class`, `tz_aware`, and `uuid_subtype` options with
`codec_options`.
.. versionchanged:: 2.7
Added `compile_re` option. If set to False, PyMongo represented BSON
regular expressions as :class:`~bson.regex.Regex` objects instead of
attempting to compile BSON regular expressions as Python native
regular expressions, thus preventing errors for some incompatible
patterns, see `PYTHON-500`_.
.. _PYTHON-500: https://jira.mongodb.org/browse/PYTHON-500
"""
data, view = get_data_and_view(data)
if not isinstance(codec_options, CodecOptions):
raise _CODEC_OPTIONS_TYPE_ERROR
data_len = len(data)
docs = []
position = 0
end = data_len - 1
use_raw = _raw_document_class(codec_options.document_class)
try:
while position < end:
obj_size = _UNPACK_INT_FROM(data, position)[0]
if data_len - position < obj_size:
raise InvalidBSON("invalid object size")
obj_end = position + obj_size - 1
if data[obj_end] != _OBJEND:
raise InvalidBSON("bad eoo")
if use_raw:
docs.append(
codec_options.document_class(
data[position:obj_end + 1], codec_options))
else:
docs.append(_elements_to_dict(data,
view,
position + 4,
obj_end,
codec_options))
position += obj_size
return docs
except InvalidBSON:
raise
except Exception:
# Change exception type to InvalidBSON but preserve traceback.
_, exc_value, exc_tb = sys.exc_info()
reraise(InvalidBSON, exc_value, exc_tb)
if _USE_C:
decode_all = _cbson.decode_all
def _decode_selective(rawdoc, fields, codec_options):
if _raw_document_class(codec_options.document_class):
# If document_class is RawBSONDocument, use vanilla dictionary for
# decoding command response.
doc = {}
else:
# Else, use the specified document_class.
doc = codec_options.document_class()
for key, value in iteritems(rawdoc):
if key in fields:
if fields[key] == 1:
doc[key] = _bson_to_dict(rawdoc.raw, codec_options)[key]
else:
doc[key] = _decode_selective(value, fields[key], codec_options)
else:
doc[key] = value
return doc
def _decode_all_selective(data, codec_options, fields):
"""Decode BSON data to a single document while using user-provided
custom decoding logic.
`data` must be a string representing a valid, BSON-encoded document.
:Parameters:
- `data`: BSON data
- `codec_options`: An instance of
:class:`~bson.codec_options.CodecOptions` with user-specified type
decoders. If no decoders are found, this method is the same as
``decode_all``.
- `fields`: Map of document namespaces where data that needs
to be custom decoded lives or None. For example, to custom decode a
list of objects in 'field1.subfield1', the specified value should be
``{'field1': {'subfield1': 1}}``. If ``fields`` is an empty map or
None, this method is the same as ``decode_all``.
:Returns:
- `document_list`: Single-member list containing the decoded document.
.. versionadded:: 3.8
"""
if not codec_options.type_registry._decoder_map:
return decode_all(data, codec_options)
if not fields:
return decode_all(data, codec_options.with_options(type_registry=None))
# Decode documents for internal use.
from bson.raw_bson import RawBSONDocument
internal_codec_options = codec_options.with_options(
document_class=RawBSONDocument, type_registry=None)
_doc = _bson_to_dict(data, internal_codec_options)
return [_decode_selective(_doc, fields, codec_options,)]
def decode_iter(data, codec_options=DEFAULT_CODEC_OPTIONS):
"""Decode BSON data to multiple documents as a generator.
Works similarly to the decode_all function, but yields one document at a
time.
`data` must be a string of concatenated, valid, BSON-encoded
documents.
:Parameters:
- `data`: BSON data
- `codec_options` (optional): An instance of
:class:`~bson.codec_options.CodecOptions`.
.. versionchanged:: 3.0
Replaced `as_class`, `tz_aware`, and `uuid_subtype` options with
`codec_options`.
.. versionadded:: 2.8
"""
if not isinstance(codec_options, CodecOptions):
raise _CODEC_OPTIONS_TYPE_ERROR
position = 0
end = len(data) - 1
while position < end:
obj_size = _UNPACK_INT_FROM(data, position)[0]
elements = data[position:position + obj_size]
position += obj_size
yield _bson_to_dict(elements, codec_options)
def decode_file_iter(file_obj, codec_options=DEFAULT_CODEC_OPTIONS):
"""Decode bson data from a file to multiple documents as a generator.
Works similarly to the decode_all function, but reads from the file object
in chunks and parses bson in chunks, yielding one document at a time.
:Parameters:
- `file_obj`: A file object containing BSON data.
- `codec_options` (optional): An instance of
:class:`~bson.codec_options.CodecOptions`.
.. versionchanged:: 3.0
Replaced `as_class`, `tz_aware`, and `uuid_subtype` options with
`codec_options`.
.. versionadded:: 2.8
"""
while True:
# Read size of next object.
size_data = file_obj.read(4)
if not size_data:
break # Finished with file normaly.
elif len(size_data) != 4:
raise InvalidBSON("cut off in middle of objsize")
obj_size = _UNPACK_INT_FROM(size_data, 0)[0] - 4
elements = size_data + file_obj.read(obj_size)
yield _bson_to_dict(elements, codec_options)
def is_valid(bson):
"""Check that the given string represents valid :class:`BSON` data.
Raises :class:`TypeError` if `bson` is not an instance of
:class:`str` (:class:`bytes` in python 3). Returns ``True``
if `bson` is valid :class:`BSON`, ``False`` otherwise.
:Parameters:
- `bson`: the data to be validated
"""
if not isinstance(bson, bytes):
raise TypeError("BSON data must be an instance of a subclass of bytes")
try:
_bson_to_dict(bson, DEFAULT_CODEC_OPTIONS)
return True
except Exception:
return False
class BSON(bytes):
"""BSON (Binary JSON) data.
.. warning:: Using this class to encode and decode BSON adds a performance
cost. For better performance use the module level functions
:func:`encode` and :func:`decode` instead.
"""
@classmethod
def encode(cls, document, check_keys=False,
codec_options=DEFAULT_CODEC_OPTIONS):
"""Encode a document to a new :class:`BSON` instance.
A document can be any mapping type (like :class:`dict`).
Raises :class:`TypeError` if `document` is not a mapping type,
or contains keys that are not instances of
:class:`basestring` (:class:`str` in python 3). Raises
:class:`~bson.errors.InvalidDocument` if `document` cannot be
converted to :class:`BSON`.
:Parameters:
- `document`: mapping type representing a document
- `check_keys` (optional): check if keys start with '$' or
contain '.', raising :class:`~bson.errors.InvalidDocument` in
either case
- `codec_options` (optional): An instance of
:class:`~bson.codec_options.CodecOptions`.
.. versionchanged:: 3.0
Replaced `uuid_subtype` option with `codec_options`.
"""
return cls(encode(document, check_keys, codec_options))
def decode(self, codec_options=DEFAULT_CODEC_OPTIONS):
"""Decode this BSON data.
By default, returns a BSON document represented as a Python
:class:`dict`. To use a different :class:`MutableMapping` class,
configure a :class:`~bson.codec_options.CodecOptions`::
>>> import collections # From Python standard library.
>>> import bson
>>> from bson.codec_options import CodecOptions
>>> data = bson.BSON.encode({'a': 1})
>>> decoded_doc = bson.BSON(data).decode()
>>> options = CodecOptions(document_class=collections.OrderedDict)
>>> decoded_doc = bson.BSON(data).decode(codec_options=options)
>>> type(decoded_doc)
:Parameters:
- `codec_options` (optional): An instance of
:class:`~bson.codec_options.CodecOptions`.
.. versionchanged:: 3.0
Removed `compile_re` option: PyMongo now always represents BSON
regular expressions as :class:`~bson.regex.Regex` objects. Use
:meth:`~bson.regex.Regex.try_compile` to attempt to convert from a
BSON regular expression to a Python regular expression object.
Replaced `as_class`, `tz_aware`, and `uuid_subtype` options with
`codec_options`.
.. versionchanged:: 2.7
Added `compile_re` option. If set to False, PyMongo represented BSON
regular expressions as :class:`~bson.regex.Regex` objects instead of
attempting to compile BSON regular expressions as Python native
regular expressions, thus preventing errors for some incompatible
patterns, see `PYTHON-500`_.
.. _PYTHON-500: https://jira.mongodb.org/browse/PYTHON-500
"""
return decode(self, codec_options)
def has_c():
"""Is the C extension installed?
"""
return _USE_C
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/binary.py
================================================
# Copyright 2009-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from uuid import UUID
from bson.py3compat import PY3
"""Tools for representing BSON binary data.
"""
BINARY_SUBTYPE = 0
"""BSON binary subtype for binary data.
This is the default subtype for binary data.
"""
FUNCTION_SUBTYPE = 1
"""BSON binary subtype for functions.
"""
OLD_BINARY_SUBTYPE = 2
"""Old BSON binary subtype for binary data.
This is the old default subtype, the current
default is :data:`BINARY_SUBTYPE`.
"""
OLD_UUID_SUBTYPE = 3
"""Old BSON binary subtype for a UUID.
:class:`uuid.UUID` instances will automatically be encoded
by :mod:`bson` using this subtype.
.. versionadded:: 2.1
"""
UUID_SUBTYPE = 4
"""BSON binary subtype for a UUID.
This is the new BSON binary subtype for UUIDs. The
current default is :data:`OLD_UUID_SUBTYPE`.
.. versionchanged:: 2.1
Changed to subtype 4.
"""
STANDARD = UUID_SUBTYPE
"""The standard UUID representation.
:class:`uuid.UUID` instances will automatically be encoded to
and decoded from BSON binary, using RFC-4122 byte order with
binary subtype :data:`UUID_SUBTYPE`.
.. versionadded:: 3.0
"""
PYTHON_LEGACY = OLD_UUID_SUBTYPE
"""The Python legacy UUID representation.
:class:`uuid.UUID` instances will automatically be encoded to
and decoded from BSON binary, using RFC-4122 byte order with
binary subtype :data:`OLD_UUID_SUBTYPE`.
.. versionadded:: 3.0
"""
JAVA_LEGACY = 5
"""The Java legacy UUID representation.
:class:`uuid.UUID` instances will automatically be encoded to
and decoded from BSON binary subtype :data:`OLD_UUID_SUBTYPE`,
using the Java driver's legacy byte order.
.. versionchanged:: 3.6
BSON binary subtype 4 is decoded using RFC-4122 byte order.
.. versionadded:: 2.3
"""
CSHARP_LEGACY = 6
"""The C#/.net legacy UUID representation.
:class:`uuid.UUID` instances will automatically be encoded to
and decoded from BSON binary subtype :data:`OLD_UUID_SUBTYPE`,
using the C# driver's legacy byte order.
.. versionchanged:: 3.6
BSON binary subtype 4 is decoded using RFC-4122 byte order.
.. versionadded:: 2.3
"""
ALL_UUID_SUBTYPES = (OLD_UUID_SUBTYPE, UUID_SUBTYPE)
ALL_UUID_REPRESENTATIONS = (STANDARD, PYTHON_LEGACY, JAVA_LEGACY, CSHARP_LEGACY)
UUID_REPRESENTATION_NAMES = {
PYTHON_LEGACY: 'PYTHON_LEGACY',
STANDARD: 'STANDARD',
JAVA_LEGACY: 'JAVA_LEGACY',
CSHARP_LEGACY: 'CSHARP_LEGACY'}
MD5_SUBTYPE = 5
"""BSON binary subtype for an MD5 hash.
"""
USER_DEFINED_SUBTYPE = 128
"""BSON binary subtype for any user defined structure.
"""
class Binary(bytes):
"""Representation of BSON binary data.
This is necessary because we want to represent Python strings as
the BSON string type. We need to wrap binary data so we can tell
the difference between what should be considered binary data and
what should be considered a string when we encode to BSON.
Raises TypeError if `data` is not an instance of :class:`bytes`
(:class:`str` in python 2) or `subtype` is not an instance of
:class:`int`. Raises ValueError if `subtype` is not in [0, 256).
.. note::
In python 3 instances of Binary with subtype 0 will be decoded
directly to :class:`bytes`.
:Parameters:
- `data`: the binary data to represent. Can be any bytes-like type
that implements the buffer protocol.
- `subtype` (optional): the `binary subtype
`_
to use
.. versionchanged:: 3.9
Support any bytes-like type that implements the buffer protocol.
"""
_type_marker = 5
def __new__(cls, data, subtype=BINARY_SUBTYPE):
if not isinstance(subtype, int):
raise TypeError("subtype must be an instance of int")
if subtype >= 256 or subtype < 0:
raise ValueError("subtype must be contained in [0, 256)")
# Support any type that implements the buffer protocol.
self = bytes.__new__(cls, memoryview(data).tobytes())
self.__subtype = subtype
return self
@property
def subtype(self):
"""Subtype of this binary data.
"""
return self.__subtype
def __getnewargs__(self):
# Work around http://bugs.python.org/issue7382
data = super(Binary, self).__getnewargs__()[0]
if PY3 and not isinstance(data, bytes):
data = data.encode('latin-1')
return data, self.__subtype
def __eq__(self, other):
if isinstance(other, Binary):
return ((self.__subtype, bytes(self)) ==
(other.subtype, bytes(other)))
# We don't return NotImplemented here because if we did then
# Binary("foo") == "foo" would return True, since Binary is a
# subclass of str...
return False
def __hash__(self):
return super(Binary, self).__hash__() ^ hash(self.__subtype)
def __ne__(self, other):
return not self == other
def __repr__(self):
return "Binary(%s, %s)" % (bytes.__repr__(self), self.__subtype)
class UUIDLegacy(Binary):
"""UUID wrapper to support working with UUIDs stored as PYTHON_LEGACY.
.. doctest::
>>> import uuid
>>> from bson.binary import Binary, UUIDLegacy, STANDARD
>>> from bson.codec_options import CodecOptions
>>> my_uuid = uuid.uuid4()
>>> coll = db.get_collection('test',
... CodecOptions(uuid_representation=STANDARD))
>>> coll.insert_one({'uuid': Binary(my_uuid.bytes, 3)}).inserted_id
ObjectId('...')
>>> coll.count_documents({'uuid': my_uuid})
0
>>> coll.count_documents({'uuid': UUIDLegacy(my_uuid)})
1
>>> coll.find({'uuid': UUIDLegacy(my_uuid)})[0]['uuid']
UUID('...')
>>>
>>> # Convert from subtype 3 to subtype 4
>>> doc = coll.find_one({'uuid': UUIDLegacy(my_uuid)})
>>> coll.replace_one({"_id": doc["_id"]}, doc).matched_count
1
>>> coll.count_documents({'uuid': UUIDLegacy(my_uuid)})
0
>>> coll.count_documents({'uuid': {'$in': [UUIDLegacy(my_uuid), my_uuid]}})
1
>>> coll.find_one({'uuid': my_uuid})['uuid']
UUID('...')
Raises TypeError if `obj` is not an instance of :class:`~uuid.UUID`.
:Parameters:
- `obj`: An instance of :class:`~uuid.UUID`.
"""
def __new__(cls, obj):
if not isinstance(obj, UUID):
raise TypeError("obj must be an instance of uuid.UUID")
self = Binary.__new__(cls, obj.bytes, OLD_UUID_SUBTYPE)
self.__uuid = obj
return self
def __getnewargs__(self):
# Support copy and deepcopy
return (self.__uuid,)
@property
def uuid(self):
"""UUID instance wrapped by this UUIDLegacy instance.
"""
return self.__uuid
def __repr__(self):
return "UUIDLegacy('%s')" % self.__uuid
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/code.py
================================================
# Copyright 2009-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tools for representing JavaScript code in BSON.
"""
from bson.py3compat import abc, string_type, PY3, text_type
class Code(str):
"""BSON's JavaScript code type.
Raises :class:`TypeError` if `code` is not an instance of
:class:`basestring` (:class:`str` in python 3) or `scope`
is not ``None`` or an instance of :class:`dict`.
Scope variables can be set by passing a dictionary as the `scope`
argument or by using keyword arguments. If a variable is set as a
keyword argument it will override any setting for that variable in
the `scope` dictionary.
:Parameters:
- `code`: A string containing JavaScript code to be evaluated or another
instance of Code. In the latter case, the scope of `code` becomes this
Code's :attr:`scope`.
- `scope` (optional): dictionary representing the scope in which
`code` should be evaluated - a mapping from identifiers (as
strings) to values. Defaults to ``None``. This is applied after any
scope associated with a given `code` above.
- `**kwargs` (optional): scope variables can also be passed as
keyword arguments. These are applied after `scope` and `code`.
.. versionchanged:: 3.4
The default value for :attr:`scope` is ``None`` instead of ``{}``.
"""
_type_marker = 13
def __new__(cls, code, scope=None, **kwargs):
if not isinstance(code, string_type):
raise TypeError("code must be an "
"instance of %s" % (string_type.__name__))
if not PY3 and isinstance(code, text_type):
self = str.__new__(cls, code.encode('utf8'))
else:
self = str.__new__(cls, code)
try:
self.__scope = code.scope
except AttributeError:
self.__scope = None
if scope is not None:
if not isinstance(scope, abc.Mapping):
raise TypeError("scope must be an instance of dict")
if self.__scope is not None:
self.__scope.update(scope)
else:
self.__scope = scope
if kwargs:
if self.__scope is not None:
self.__scope.update(kwargs)
else:
self.__scope = kwargs
return self
@property
def scope(self):
"""Scope dictionary for this instance or ``None``.
"""
return self.__scope
def __repr__(self):
return "Code(%s, %r)" % (str.__repr__(self), self.__scope)
def __eq__(self, other):
if isinstance(other, Code):
return (self.__scope, str(self)) == (other.__scope, str(other))
return False
__hash__ = None
def __ne__(self, other):
return not self == other
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/codec_options.py
================================================
# Copyright 2014-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tools for specifying BSON codec options."""
import datetime
from abc import abstractmethod
from collections import namedtuple
from bson.py3compat import ABC, abc, abstractproperty, string_type
from bson.binary import (ALL_UUID_REPRESENTATIONS,
PYTHON_LEGACY,
UUID_REPRESENTATION_NAMES)
_RAW_BSON_DOCUMENT_MARKER = 101
def _raw_document_class(document_class):
"""Determine if a document_class is a RawBSONDocument class."""
marker = getattr(document_class, '_type_marker', None)
return marker == _RAW_BSON_DOCUMENT_MARKER
class TypeEncoder(ABC):
"""Base class for defining type codec classes which describe how a
custom type can be transformed to one of the types BSON understands.
Codec classes must implement the ``python_type`` attribute, and the
``transform_python`` method to support encoding.
See :ref:`custom-type-type-codec` documentation for an example.
"""
@abstractproperty
def python_type(self):
"""The Python type to be converted into something serializable."""
pass
@abstractmethod
def transform_python(self, value):
"""Convert the given Python object into something serializable."""
pass
class TypeDecoder(ABC):
"""Base class for defining type codec classes which describe how a
BSON type can be transformed to a custom type.
Codec classes must implement the ``bson_type`` attribute, and the
``transform_bson`` method to support decoding.
See :ref:`custom-type-type-codec` documentation for an example.
"""
@abstractproperty
def bson_type(self):
"""The BSON type to be converted into our own type."""
pass
@abstractmethod
def transform_bson(self, value):
"""Convert the given BSON value into our own type."""
pass
class TypeCodec(TypeEncoder, TypeDecoder):
"""Base class for defining type codec classes which describe how a
custom type can be transformed to/from one of the types :mod:`bson`
can already encode/decode.
Codec classes must implement the ``python_type`` attribute, and the
``transform_python`` method to support encoding, as well as the
``bson_type`` attribute, and the ``transform_bson`` method to support
decoding.
See :ref:`custom-type-type-codec` documentation for an example.
"""
pass
class TypeRegistry(object):
"""Encapsulates type codecs used in encoding and / or decoding BSON, as
well as the fallback encoder. Type registries cannot be modified after
instantiation.
``TypeRegistry`` can be initialized with an iterable of type codecs, and
a callable for the fallback encoder::
>>> from bson.codec_options import TypeRegistry
>>> type_registry = TypeRegistry([Codec1, Codec2, Codec3, ...],
... fallback_encoder)
See :ref:`custom-type-type-registry` documentation for an example.
:Parameters:
- `type_codecs` (optional): iterable of type codec instances. If
``type_codecs`` contains multiple codecs that transform a single
python or BSON type, the transformation specified by the type codec
occurring last prevails. A TypeError will be raised if one or more
type codecs modify the encoding behavior of a built-in :mod:`bson`
type.
- `fallback_encoder` (optional): callable that accepts a single,
unencodable python value and transforms it into a type that
:mod:`bson` can encode. See :ref:`fallback-encoder-callable`
documentation for an example.
"""
def __init__(self, type_codecs=None, fallback_encoder=None):
self.__type_codecs = list(type_codecs or [])
self._fallback_encoder = fallback_encoder
self._encoder_map = {}
self._decoder_map = {}
if self._fallback_encoder is not None:
if not callable(fallback_encoder):
raise TypeError("fallback_encoder %r is not a callable" % (
fallback_encoder))
for codec in self.__type_codecs:
is_valid_codec = False
if isinstance(codec, TypeEncoder):
self._validate_type_encoder(codec)
is_valid_codec = True
self._encoder_map[codec.python_type] = codec.transform_python
if isinstance(codec, TypeDecoder):
is_valid_codec = True
self._decoder_map[codec.bson_type] = codec.transform_bson
if not is_valid_codec:
raise TypeError(
"Expected an instance of %s, %s, or %s, got %r instead" % (
TypeEncoder.__name__, TypeDecoder.__name__,
TypeCodec.__name__, codec))
def _validate_type_encoder(self, codec):
from bson import _BUILT_IN_TYPES
for pytype in _BUILT_IN_TYPES:
if issubclass(codec.python_type, pytype):
err_msg = ("TypeEncoders cannot change how built-in types are "
"encoded (encoder %s transforms type %s)" %
(codec, pytype))
raise TypeError(err_msg)
def __repr__(self):
return ('%s(type_codecs=%r, fallback_encoder=%r)' % (
self.__class__.__name__, self.__type_codecs,
self._fallback_encoder))
def __eq__(self, other):
if not isinstance(other, type(self)):
return NotImplemented
return ((self._decoder_map == other._decoder_map) and
(self._encoder_map == other._encoder_map) and
(self._fallback_encoder == other._fallback_encoder))
_options_base = namedtuple(
'CodecOptions',
('document_class', 'tz_aware', 'uuid_representation',
'unicode_decode_error_handler', 'tzinfo', 'type_registry'))
class CodecOptions(_options_base):
"""Encapsulates options used encoding and / or decoding BSON.
The `document_class` option is used to define a custom type for use
decoding BSON documents. Access to the underlying raw BSON bytes for
a document is available using the :class:`~bson.raw_bson.RawBSONDocument`
type::
>>> from bson.raw_bson import RawBSONDocument
>>> from bson.codec_options import CodecOptions
>>> codec_options = CodecOptions(document_class=RawBSONDocument)
>>> coll = db.get_collection('test', codec_options=codec_options)
>>> doc = coll.find_one()
>>> doc.raw
'\\x16\\x00\\x00\\x00\\x07_id\\x00[0\\x165\\x91\\x10\\xea\\x14\\xe8\\xc5\\x8b\\x93\\x00'
The document class can be any type that inherits from
:class:`~collections.MutableMapping`::
>>> class AttributeDict(dict):
... # A dict that supports attribute access.
... def __getattr__(self, key):
... return self[key]
... def __setattr__(self, key, value):
... self[key] = value
...
>>> codec_options = CodecOptions(document_class=AttributeDict)
>>> coll = db.get_collection('test', codec_options=codec_options)
>>> doc = coll.find_one()
>>> doc._id
ObjectId('5b3016359110ea14e8c58b93')
See :doc:`/examples/datetimes` for examples using the `tz_aware` and
`tzinfo` options.
See :class:`~bson.binary.UUIDLegacy` for examples using the
`uuid_representation` option.
:Parameters:
- `document_class`: BSON documents returned in queries will be decoded
to an instance of this class. Must be a subclass of
:class:`~collections.MutableMapping`. Defaults to :class:`dict`.
- `tz_aware`: If ``True``, BSON datetimes will be decoded to timezone
aware instances of :class:`~datetime.datetime`. Otherwise they will be
naive. Defaults to ``False``.
- `uuid_representation`: The BSON representation to use when encoding
and decoding instances of :class:`~uuid.UUID`. Defaults to
:data:`~bson.binary.PYTHON_LEGACY`.
- `unicode_decode_error_handler`: The error handler to apply when
a Unicode-related error occurs during BSON decoding that would
otherwise raise :exc:`UnicodeDecodeError`. Valid options include
'strict', 'replace', and 'ignore'. Defaults to 'strict'.
- `tzinfo`: A :class:`~datetime.tzinfo` subclass that specifies the
timezone to/from which :class:`~datetime.datetime` objects should be
encoded/decoded.
- `type_registry`: Instance of :class:`TypeRegistry` used to customize
encoding and decoding behavior.
.. versionadded:: 3.8
`type_registry` attribute.
.. warning:: Care must be taken when changing
`unicode_decode_error_handler` from its default value ('strict').
The 'replace' and 'ignore' modes should not be used when documents
retrieved from the server will be modified in the client application
and stored back to the server.
"""
def __new__(cls, document_class=dict,
tz_aware=False, uuid_representation=PYTHON_LEGACY,
unicode_decode_error_handler="strict",
tzinfo=None, type_registry=None):
if not (issubclass(document_class, abc.MutableMapping) or
_raw_document_class(document_class)):
raise TypeError("document_class must be dict, bson.son.SON, "
"bson.raw_bson.RawBSONDocument, or a "
"sublass of collections.MutableMapping")
if not isinstance(tz_aware, bool):
raise TypeError("tz_aware must be True or False")
if uuid_representation not in ALL_UUID_REPRESENTATIONS:
raise ValueError("uuid_representation must be a value "
"from bson.binary.ALL_UUID_REPRESENTATIONS")
if not isinstance(unicode_decode_error_handler, (string_type, None)):
raise ValueError("unicode_decode_error_handler must be a string "
"or None")
if tzinfo is not None:
if not isinstance(tzinfo, datetime.tzinfo):
raise TypeError(
"tzinfo must be an instance of datetime.tzinfo")
if not tz_aware:
raise ValueError(
"cannot specify tzinfo without also setting tz_aware=True")
type_registry = type_registry or TypeRegistry()
if not isinstance(type_registry, TypeRegistry):
raise TypeError("type_registry must be an instance of TypeRegistry")
return tuple.__new__(
cls, (document_class, tz_aware, uuid_representation,
unicode_decode_error_handler, tzinfo, type_registry))
def _arguments_repr(self):
"""Representation of the arguments used to create this object."""
document_class_repr = (
'dict' if self.document_class is dict
else repr(self.document_class))
uuid_rep_repr = UUID_REPRESENTATION_NAMES.get(self.uuid_representation,
self.uuid_representation)
return ('document_class=%s, tz_aware=%r, uuid_representation=%s, '
'unicode_decode_error_handler=%r, tzinfo=%r, '
'type_registry=%r' %
(document_class_repr, self.tz_aware, uuid_rep_repr,
self.unicode_decode_error_handler, self.tzinfo,
self.type_registry))
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, self._arguments_repr())
def with_options(self, **kwargs):
"""Make a copy of this CodecOptions, overriding some options::
>>> from bson.codec_options import DEFAULT_CODEC_OPTIONS
>>> DEFAULT_CODEC_OPTIONS.tz_aware
False
>>> options = DEFAULT_CODEC_OPTIONS.with_options(tz_aware=True)
>>> options.tz_aware
True
.. versionadded:: 3.5
"""
return CodecOptions(
kwargs.get('document_class', self.document_class),
kwargs.get('tz_aware', self.tz_aware),
kwargs.get('uuid_representation', self.uuid_representation),
kwargs.get('unicode_decode_error_handler',
self.unicode_decode_error_handler),
kwargs.get('tzinfo', self.tzinfo),
kwargs.get('type_registry', self.type_registry)
)
DEFAULT_CODEC_OPTIONS = CodecOptions()
def _parse_codec_options(options):
"""Parse BSON codec options."""
return CodecOptions(
document_class=options.get(
'document_class', DEFAULT_CODEC_OPTIONS.document_class),
tz_aware=options.get(
'tz_aware', DEFAULT_CODEC_OPTIONS.tz_aware),
uuid_representation=options.get(
'uuidrepresentation', DEFAULT_CODEC_OPTIONS.uuid_representation),
unicode_decode_error_handler=options.get(
'unicode_decode_error_handler',
DEFAULT_CODEC_OPTIONS.unicode_decode_error_handler),
tzinfo=options.get('tzinfo', DEFAULT_CODEC_OPTIONS.tzinfo),
type_registry=options.get(
'type_registry', DEFAULT_CODEC_OPTIONS.type_registry))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/dbref.py
================================================
# Copyright 2009-2015 MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tools for manipulating DBRefs (references to MongoDB documents)."""
from copy import deepcopy
from bson.py3compat import iteritems, string_type
from bson.son import SON
class DBRef(object):
"""A reference to a document stored in MongoDB.
"""
# DBRef isn't actually a BSON "type" so this number was arbitrarily chosen.
_type_marker = 100
def __init__(self, collection, id, database=None, _extra={}, **kwargs):
"""Initialize a new :class:`DBRef`.
Raises :class:`TypeError` if `collection` or `database` is not
an instance of :class:`basestring` (:class:`str` in python 3).
`database` is optional and allows references to documents to work
across databases. Any additional keyword arguments will create
additional fields in the resultant embedded document.
:Parameters:
- `collection`: name of the collection the document is stored in
- `id`: the value of the document's ``"_id"`` field
- `database` (optional): name of the database to reference
- `**kwargs` (optional): additional keyword arguments will
create additional, custom fields
.. mongodoc:: dbrefs
"""
if not isinstance(collection, string_type):
raise TypeError("collection must be an "
"instance of %s" % string_type.__name__)
if database is not None and not isinstance(database, string_type):
raise TypeError("database must be an "
"instance of %s" % string_type.__name__)
self.__collection = collection
self.__id = id
self.__database = database
kwargs.update(_extra)
self.__kwargs = kwargs
@property
def collection(self):
"""Get the name of this DBRef's collection as unicode.
"""
return self.__collection
@property
def id(self):
"""Get this DBRef's _id.
"""
return self.__id
@property
def database(self):
"""Get the name of this DBRef's database.
Returns None if this DBRef doesn't specify a database.
"""
return self.__database
def __getattr__(self, key):
try:
return self.__kwargs[key]
except KeyError:
raise AttributeError(key)
# Have to provide __setstate__ to avoid
# infinite recursion since we override
# __getattr__.
def __setstate__(self, state):
self.__dict__.update(state)
def as_doc(self):
"""Get the SON document representation of this DBRef.
Generally not needed by application developers
"""
doc = SON([("$ref", self.collection),
("$id", self.id)])
if self.database is not None:
doc["$db"] = self.database
doc.update(self.__kwargs)
return doc
def __repr__(self):
extra = "".join([", %s=%r" % (k, v)
for k, v in iteritems(self.__kwargs)])
if self.database is None:
return "DBRef(%r, %r%s)" % (self.collection, self.id, extra)
return "DBRef(%r, %r, %r%s)" % (self.collection, self.id,
self.database, extra)
def __eq__(self, other):
if isinstance(other, DBRef):
us = (self.__database, self.__collection,
self.__id, self.__kwargs)
them = (other.__database, other.__collection,
other.__id, other.__kwargs)
return us == them
return NotImplemented
def __ne__(self, other):
return not self == other
def __hash__(self):
"""Get a hash value for this :class:`DBRef`."""
return hash((self.__collection, self.__id, self.__database,
tuple(sorted(self.__kwargs.items()))))
def __deepcopy__(self, memo):
"""Support function for `copy.deepcopy()`."""
return DBRef(deepcopy(self.__collection, memo),
deepcopy(self.__id, memo),
deepcopy(self.__database, memo),
deepcopy(self.__kwargs, memo))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/decimal128.py
================================================
# Copyright 2016-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tools for working with the BSON decimal128 type.
.. versionadded:: 3.4
.. note:: The Decimal128 BSON type requires MongoDB 3.4+.
"""
import decimal
import struct
import sys
from bson.py3compat import (PY3 as _PY3,
string_type as _string_type)
if _PY3:
_from_bytes = int.from_bytes # pylint: disable=no-member, invalid-name
else:
import binascii
def _from_bytes(value, dummy, _int=int, _hexlify=binascii.hexlify):
"An implementation of int.from_bytes for python 2.x."
return _int(_hexlify(value), 16)
_PACK_64 = struct.Struct("= 3.3, cdecimal
decimal.Context(clamp=1) # pylint: disable=unexpected-keyword-arg
_CTX_OPTIONS['clamp'] = 1
except TypeError:
# Python < 3.3
_CTX_OPTIONS['_clamp'] = 1
_DEC128_CTX = decimal.Context(**_CTX_OPTIONS.copy())
def create_decimal128_context():
"""Returns an instance of :class:`decimal.Context` appropriate
for working with IEEE-754 128-bit decimal floating point values.
"""
opts = _CTX_OPTIONS.copy()
opts['traps'] = []
return decimal.Context(**opts)
def _decimal_to_128(value):
"""Converts a decimal.Decimal to BID (high bits, low bits).
:Parameters:
- `value`: An instance of decimal.Decimal
"""
with decimal.localcontext(_DEC128_CTX) as ctx:
value = ctx.create_decimal(value)
if value.is_infinite():
return _NINF if value.is_signed() else _PINF
sign, digits, exponent = value.as_tuple()
if value.is_nan():
if digits:
raise ValueError("NaN with debug payload is not supported")
if value.is_snan():
return _NSNAN if value.is_signed() else _PSNAN
return _NNAN if value.is_signed() else _PNAN
significand = int("".join([str(digit) for digit in digits]))
bit_length = significand.bit_length()
high = 0
low = 0
for i in range(min(64, bit_length)):
if significand & (1 << i):
low |= 1 << i
for i in range(64, bit_length):
if significand & (1 << i):
high |= 1 << (i - 64)
biased_exponent = exponent + _EXPONENT_BIAS
if high >> 49 == 1:
high = high & 0x7fffffffffff
high |= _EXPONENT_MASK
high |= (biased_exponent & 0x3fff) << 47
else:
high |= biased_exponent << 49
if sign:
high |= _SIGN
return high, low
class Decimal128(object):
"""BSON Decimal128 type::
>>> Decimal128(Decimal("0.0005"))
Decimal128('0.0005')
>>> Decimal128("0.0005")
Decimal128('0.0005')
>>> Decimal128((3474527112516337664, 5))
Decimal128('0.0005')
:Parameters:
- `value`: An instance of :class:`decimal.Decimal`, string, or tuple of
(high bits, low bits) from Binary Integer Decimal (BID) format.
.. note:: :class:`~Decimal128` uses an instance of :class:`decimal.Context`
configured for IEEE-754 Decimal128 when validating parameters.
Signals like :class:`decimal.InvalidOperation`, :class:`decimal.Inexact`,
and :class:`decimal.Overflow` are trapped and raised as exceptions::
>>> Decimal128(".13.1")
Traceback (most recent call last):
File "", line 1, in
...
decimal.InvalidOperation: []
>>>
>>> Decimal128("1E-6177")
Traceback (most recent call last):
File "", line 1, in
...
decimal.Inexact: []
>>>
>>> Decimal128("1E6145")
Traceback (most recent call last):
File "", line 1, in
...
decimal.Overflow: [, ]
To ensure the result of a calculation can always be stored as BSON
Decimal128 use the context returned by
:func:`create_decimal128_context`::
>>> import decimal
>>> decimal128_ctx = create_decimal128_context()
>>> with decimal.localcontext(decimal128_ctx) as ctx:
... Decimal128(ctx.create_decimal(".13.3"))
...
Decimal128('NaN')
>>>
>>> with decimal.localcontext(decimal128_ctx) as ctx:
... Decimal128(ctx.create_decimal("1E-6177"))
...
Decimal128('0E-6176')
>>>
>>> with decimal.localcontext(DECIMAL128_CTX) as ctx:
... Decimal128(ctx.create_decimal("1E6145"))
...
Decimal128('Infinity')
To match the behavior of MongoDB's Decimal128 implementation
str(Decimal(value)) may not match str(Decimal128(value)) for NaN values::
>>> Decimal128(Decimal('NaN'))
Decimal128('NaN')
>>> Decimal128(Decimal('-NaN'))
Decimal128('NaN')
>>> Decimal128(Decimal('sNaN'))
Decimal128('NaN')
>>> Decimal128(Decimal('-sNaN'))
Decimal128('NaN')
However, :meth:`~Decimal128.to_decimal` will return the exact value::
>>> Decimal128(Decimal('NaN')).to_decimal()
Decimal('NaN')
>>> Decimal128(Decimal('-NaN')).to_decimal()
Decimal('-NaN')
>>> Decimal128(Decimal('sNaN')).to_decimal()
Decimal('sNaN')
>>> Decimal128(Decimal('-sNaN')).to_decimal()
Decimal('-sNaN')
Two instances of :class:`Decimal128` compare equal if their Binary
Integer Decimal encodings are equal::
>>> Decimal128('NaN') == Decimal128('NaN')
True
>>> Decimal128('NaN').bid == Decimal128('NaN').bid
True
This differs from :class:`decimal.Decimal` comparisons for NaN::
>>> Decimal('NaN') == Decimal('NaN')
False
"""
__slots__ = ('__high', '__low')
_type_marker = 19
def __init__(self, value):
if isinstance(value, (_string_type, decimal.Decimal)):
self.__high, self.__low = _decimal_to_128(value)
elif isinstance(value, (list, tuple)):
if len(value) != 2:
raise ValueError('Invalid size for creation of Decimal128 '
'from list or tuple. Must have exactly 2 '
'elements.')
self.__high, self.__low = value
else:
raise TypeError("Cannot convert %r to Decimal128" % (value,))
def to_decimal(self):
"""Returns an instance of :class:`decimal.Decimal` for this
:class:`Decimal128`.
"""
high = self.__high
low = self.__low
sign = 1 if (high & _SIGN) else 0
if (high & _SNAN) == _SNAN:
return decimal.Decimal((sign, (), 'N'))
elif (high & _NAN) == _NAN:
return decimal.Decimal((sign, (), 'n'))
elif (high & _INF) == _INF:
return decimal.Decimal((sign, (), 'F'))
if (high & _EXPONENT_MASK) == _EXPONENT_MASK:
exponent = ((high & 0x1fffe00000000000) >> 47) - _EXPONENT_BIAS
return decimal.Decimal((sign, (0,), exponent))
else:
exponent = ((high & 0x7fff800000000000) >> 49) - _EXPONENT_BIAS
arr = bytearray(15)
mask = 0x00000000000000ff
for i in range(14, 6, -1):
arr[i] = (low & mask) >> ((14 - i) << 3)
mask = mask << 8
mask = 0x00000000000000ff
for i in range(6, 0, -1):
arr[i] = (high & mask) >> ((6 - i) << 3)
mask = mask << 8
mask = 0x0001000000000000
arr[0] = (high & mask) >> 48
# cdecimal only accepts a tuple for digits.
digits = tuple(
int(digit) for digit in str(_from_bytes(arr, 'big')))
with decimal.localcontext(_DEC128_CTX) as ctx:
return ctx.create_decimal((sign, digits, exponent))
@classmethod
def from_bid(cls, value):
"""Create an instance of :class:`Decimal128` from Binary Integer
Decimal string.
:Parameters:
- `value`: 16 byte string (128-bit IEEE 754-2008 decimal floating
point in Binary Integer Decimal (BID) format).
"""
if not isinstance(value, bytes):
raise TypeError("value must be an instance of bytes")
if len(value) != 16:
raise ValueError("value must be exactly 16 bytes")
return cls((_UNPACK_64(value[8:])[0], _UNPACK_64(value[:8])[0]))
@property
def bid(self):
"""The Binary Integer Decimal (BID) encoding of this instance."""
return _PACK_64(self.__low) + _PACK_64(self.__high)
def __str__(self):
dec = self.to_decimal()
if dec.is_nan():
# Required by the drivers spec to match MongoDB behavior.
return "NaN"
return str(dec)
def __repr__(self):
return "Decimal128('%s')" % (str(self),)
def __setstate__(self, value):
self.__high, self.__low = value
def __getstate__(self):
return self.__high, self.__low
def __eq__(self, other):
if isinstance(other, Decimal128):
return self.bid == other.bid
return NotImplemented
def __ne__(self, other):
return not self == other
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/errors.py
================================================
# Copyright 2009-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Exceptions raised by the BSON package."""
class BSONError(Exception):
"""Base class for all BSON exceptions.
"""
class InvalidBSON(BSONError):
"""Raised when trying to create a BSON object from invalid data.
"""
class InvalidStringData(BSONError):
"""Raised when trying to encode a string containing non-UTF8 data.
"""
class InvalidDocument(BSONError):
"""Raised when trying to create a BSON object from an invalid document.
"""
class InvalidId(BSONError):
"""Raised when trying to create an ObjectId from invalid data.
"""
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/int64.py
================================================
# Copyright 2014-2015 MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""A BSON wrapper for long (int in python3)"""
from bson.py3compat import PY3
if PY3:
long = int
class Int64(long):
"""Representation of the BSON int64 type.
This is necessary because every integral number is an :class:`int` in
Python 3. Small integral numbers are encoded to BSON int32 by default,
but Int64 numbers will always be encoded to BSON int64.
:Parameters:
- `value`: the numeric value to represent
"""
_type_marker = 18
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/json_util.py
================================================
# Copyright 2009-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tools for using Python's :mod:`json` module with BSON documents.
This module provides two helper methods `dumps` and `loads` that wrap the
native :mod:`json` methods and provide explicit BSON conversion to and from
JSON. :class:`~bson.json_util.JSONOptions` provides a way to control how JSON
is emitted and parsed, with the default being the legacy PyMongo format.
:mod:`~bson.json_util` can also generate Canonical or Relaxed `Extended JSON`_
when :const:`CANONICAL_JSON_OPTIONS` or :const:`RELAXED_JSON_OPTIONS` is
provided, respectively.
.. _Extended JSON: https://github.com/mongodb/specifications/blob/master/source/extended-json.rst
Example usage (deserialization):
.. doctest::
>>> from bson.json_util import loads
>>> loads('[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$scope": {}, "$code": "function x() { return 1; }"}}, {"bin": {"$type": "80", "$binary": "AQIDBA=="}}]')
[{u'foo': [1, 2]}, {u'bar': {u'hello': u'world'}}, {u'code': Code('function x() { return 1; }', {})}, {u'bin': Binary('...', 128)}]
Example usage (serialization):
.. doctest::
>>> from bson import Binary, Code
>>> from bson.json_util import dumps
>>> dumps([{'foo': [1, 2]},
... {'bar': {'hello': 'world'}},
... {'code': Code("function x() { return 1; }", {})},
... {'bin': Binary(b"\x01\x02\x03\x04")}])
'[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }", "$scope": {}}}, {"bin": {"$binary": "AQIDBA==", "$type": "00"}}]'
Example usage (with :const:`CANONICAL_JSON_OPTIONS`):
.. doctest::
>>> from bson import Binary, Code
>>> from bson.json_util import dumps, CANONICAL_JSON_OPTIONS
>>> dumps([{'foo': [1, 2]},
... {'bar': {'hello': 'world'}},
... {'code': Code("function x() { return 1; }")},
... {'bin': Binary(b"\x01\x02\x03\x04")}],
... json_options=CANONICAL_JSON_OPTIONS)
'[{"foo": [{"$numberInt": "1"}, {"$numberInt": "2"}]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }"}}, {"bin": {"$binary": {"base64": "AQIDBA==", "subType": "00"}}}]'
Example usage (with :const:`RELAXED_JSON_OPTIONS`):
.. doctest::
>>> from bson import Binary, Code
>>> from bson.json_util import dumps, RELAXED_JSON_OPTIONS
>>> dumps([{'foo': [1, 2]},
... {'bar': {'hello': 'world'}},
... {'code': Code("function x() { return 1; }")},
... {'bin': Binary(b"\x01\x02\x03\x04")}],
... json_options=RELAXED_JSON_OPTIONS)
'[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }"}}, {"bin": {"$binary": {"base64": "AQIDBA==", "subType": "00"}}}]'
Alternatively, you can manually pass the `default` to :func:`json.dumps`.
It won't handle :class:`~bson.binary.Binary` and :class:`~bson.code.Code`
instances (as they are extended strings you can't provide custom defaults),
but it will be faster as there is less recursion.
.. note::
If your application does not need the flexibility offered by
:class:`JSONOptions` and spends a large amount of time in the `json_util`
module, look to
`python-bsonjs `_ for a nice
performance improvement. `python-bsonjs` is a fast BSON to MongoDB
Extended JSON converter for Python built on top of
`libbson `_. `python-bsonjs` works best
with PyMongo when using :class:`~bson.raw_bson.RawBSONDocument`.
.. versionchanged:: 2.8
The output format for :class:`~bson.timestamp.Timestamp` has changed from
'{"t": , "i": }' to '{"$timestamp": {"t": , "i": }}'.
This new format will be decoded to an instance of
:class:`~bson.timestamp.Timestamp`. The old format will continue to be
decoded to a python dict as before. Encoding to the old format is no longer
supported as it was never correct and loses type information.
Added support for $numberLong and $undefined - new in MongoDB 2.6 - and
parsing $date in ISO-8601 format.
.. versionchanged:: 2.7
Preserves order when rendering SON, Timestamp, Code, Binary, and DBRef
instances.
.. versionchanged:: 2.3
Added dumps and loads helpers to automatically handle conversion to and
from json and supports :class:`~bson.binary.Binary` and
:class:`~bson.code.Code`
"""
import base64
import datetime
import json
import math
import re
import sys
import uuid
from pymongo.errors import ConfigurationError
import bson
from bson import EPOCH_AWARE, EPOCH_NAIVE, RE_TYPE, SON
from bson.binary import (Binary, JAVA_LEGACY, CSHARP_LEGACY, OLD_UUID_SUBTYPE,
UUID_SUBTYPE)
from bson.code import Code
from bson.codec_options import CodecOptions
from bson.dbref import DBRef
from bson.decimal128 import Decimal128
from bson.int64 import Int64
from bson.max_key import MaxKey
from bson.min_key import MinKey
from bson.objectid import ObjectId
from bson.py3compat import (PY3, iteritems, integer_types, string_type,
text_type)
from bson.regex import Regex
from bson.timestamp import Timestamp
from bson.tz_util import utc
_RE_OPT_TABLE = {
"i": re.I,
"l": re.L,
"m": re.M,
"s": re.S,
"u": re.U,
"x": re.X,
}
# Dollar-prefixed keys which may appear in DBRefs.
_DBREF_KEYS = frozenset(['$id', '$ref', '$db'])
class DatetimeRepresentation:
LEGACY = 0
"""Legacy MongoDB Extended JSON datetime representation.
:class:`datetime.datetime` instances will be encoded to JSON in the
format `{"$date": }`, where `dateAsMilliseconds` is
a 64-bit signed integer giving the number of milliseconds since the Unix
epoch UTC. This was the default encoding before PyMongo version 3.4.
.. versionadded:: 3.4
"""
NUMBERLONG = 1
"""NumberLong datetime representation.
:class:`datetime.datetime` instances will be encoded to JSON in the
format `{"$date": {"$numberLong": ""}}`,
where `dateAsMilliseconds` is the string representation of a 64-bit signed
integer giving the number of milliseconds since the Unix epoch UTC.
.. versionadded:: 3.4
"""
ISO8601 = 2
"""ISO-8601 datetime representation.
:class:`datetime.datetime` instances greater than or equal to the Unix
epoch UTC will be encoded to JSON in the format `{"$date": ""}`.
:class:`datetime.datetime` instances before the Unix epoch UTC will be
encoded as if the datetime representation is
:const:`~DatetimeRepresentation.NUMBERLONG`.
.. versionadded:: 3.4
"""
class JSONMode:
LEGACY = 0
"""Legacy Extended JSON representation.
In this mode, :func:`~bson.json_util.dumps` produces PyMongo's legacy
non-standard JSON output. Consider using
:const:`~bson.json_util.JSONMode.RELAXED` or
:const:`~bson.json_util.JSONMode.CANONICAL` instead.
.. versionadded:: 3.5
"""
RELAXED = 1
"""Relaxed Extended JSON representation.
In this mode, :func:`~bson.json_util.dumps` produces Relaxed Extended JSON,
a mostly JSON-like format. Consider using this for things like a web API,
where one is sending a document (or a projection of a document) that only
uses ordinary JSON type primitives. In particular, the ``int``,
:class:`~bson.int64.Int64`, and ``float`` numeric types are represented in
the native JSON number format. This output is also the most human readable
and is useful for debugging and documentation.
.. seealso:: The specification for Relaxed `Extended JSON`_.
.. versionadded:: 3.5
"""
CANONICAL = 2
"""Canonical Extended JSON representation.
In this mode, :func:`~bson.json_util.dumps` produces Canonical Extended
JSON, a type preserving format. Consider using this for things like
testing, where one has to precisely specify expected types in JSON. In
particular, the ``int``, :class:`~bson.int64.Int64`, and ``float`` numeric
types are encoded with type wrappers.
.. seealso:: The specification for Canonical `Extended JSON`_.
.. versionadded:: 3.5
"""
class JSONOptions(CodecOptions):
"""Encapsulates JSON options for :func:`dumps` and :func:`loads`.
:Parameters:
- `strict_number_long`: If ``True``, :class:`~bson.int64.Int64` objects
are encoded to MongoDB Extended JSON's *Strict mode* type
`NumberLong`, ie ``'{"$numberLong": "" }'``. Otherwise they
will be encoded as an `int`. Defaults to ``False``.
- `datetime_representation`: The representation to use when encoding
instances of :class:`datetime.datetime`. Defaults to
:const:`~DatetimeRepresentation.LEGACY`.
- `strict_uuid`: If ``True``, :class:`uuid.UUID` object are encoded to
MongoDB Extended JSON's *Strict mode* type `Binary`. Otherwise it
will be encoded as ``'{"$uuid": "" }'``. Defaults to ``False``.
- `json_mode`: The :class:`JSONMode` to use when encoding BSON types to
Extended JSON. Defaults to :const:`~JSONMode.LEGACY`.
- `document_class`: BSON documents returned by :func:`loads` will be
decoded to an instance of this class. Must be a subclass of
:class:`collections.MutableMapping`. Defaults to :class:`dict`.
- `uuid_representation`: The BSON representation to use when encoding
and decoding instances of :class:`uuid.UUID`. Defaults to
:const:`~bson.binary.PYTHON_LEGACY`.
- `tz_aware`: If ``True``, MongoDB Extended JSON's *Strict mode* type
`Date` will be decoded to timezone aware instances of
:class:`datetime.datetime`. Otherwise they will be naive. Defaults
to ``True``.
- `tzinfo`: A :class:`datetime.tzinfo` subclass that specifies the
timezone from which :class:`~datetime.datetime` objects should be
decoded. Defaults to :const:`~bson.tz_util.utc`.
- `args`: arguments to :class:`~bson.codec_options.CodecOptions`
- `kwargs`: arguments to :class:`~bson.codec_options.CodecOptions`
.. seealso:: The specification for Relaxed and Canonical `Extended JSON`_.
.. versionadded:: 3.4
.. versionchanged:: 3.5
Accepts the optional parameter `json_mode`.
"""
def __new__(cls, strict_number_long=False,
datetime_representation=DatetimeRepresentation.LEGACY,
strict_uuid=False, json_mode=JSONMode.LEGACY,
*args, **kwargs):
kwargs["tz_aware"] = kwargs.get("tz_aware", True)
if kwargs["tz_aware"]:
kwargs["tzinfo"] = kwargs.get("tzinfo", utc)
if datetime_representation not in (DatetimeRepresentation.LEGACY,
DatetimeRepresentation.NUMBERLONG,
DatetimeRepresentation.ISO8601):
raise ConfigurationError(
"JSONOptions.datetime_representation must be one of LEGACY, "
"NUMBERLONG, or ISO8601 from DatetimeRepresentation.")
self = super(JSONOptions, cls).__new__(cls, *args, **kwargs)
if json_mode not in (JSONMode.LEGACY,
JSONMode.RELAXED,
JSONMode.CANONICAL):
raise ConfigurationError(
"JSONOptions.json_mode must be one of LEGACY, RELAXED, "
"or CANONICAL from JSONMode.")
self.json_mode = json_mode
if self.json_mode == JSONMode.RELAXED:
self.strict_number_long = False
self.datetime_representation = DatetimeRepresentation.ISO8601
self.strict_uuid = True
elif self.json_mode == JSONMode.CANONICAL:
self.strict_number_long = True
self.datetime_representation = DatetimeRepresentation.NUMBERLONG
self.strict_uuid = True
else:
self.strict_number_long = strict_number_long
self.datetime_representation = datetime_representation
self.strict_uuid = strict_uuid
return self
def _arguments_repr(self):
return ('strict_number_long=%r, '
'datetime_representation=%r, '
'strict_uuid=%r, json_mode=%r, %s' % (
self.strict_number_long,
self.datetime_representation,
self.strict_uuid,
self.json_mode,
super(JSONOptions, self)._arguments_repr()))
LEGACY_JSON_OPTIONS = JSONOptions(json_mode=JSONMode.LEGACY)
""":class:`JSONOptions` for encoding to PyMongo's legacy JSON format.
.. seealso:: The documentation for :const:`bson.json_util.JSONMode.LEGACY`.
.. versionadded:: 3.5
"""
DEFAULT_JSON_OPTIONS = LEGACY_JSON_OPTIONS
"""The default :class:`JSONOptions` for JSON encoding/decoding.
The same as :const:`LEGACY_JSON_OPTIONS`. This will change to
:const:`RELAXED_JSON_OPTIONS` in a future release.
.. versionadded:: 3.4
"""
CANONICAL_JSON_OPTIONS = JSONOptions(json_mode=JSONMode.CANONICAL)
""":class:`JSONOptions` for Canonical Extended JSON.
.. seealso:: The documentation for :const:`bson.json_util.JSONMode.CANONICAL`.
.. versionadded:: 3.5
"""
RELAXED_JSON_OPTIONS = JSONOptions(json_mode=JSONMode.RELAXED)
""":class:`JSONOptions` for Relaxed Extended JSON.
.. seealso:: The documentation for :const:`bson.json_util.JSONMode.RELAXED`.
.. versionadded:: 3.5
"""
STRICT_JSON_OPTIONS = JSONOptions(
strict_number_long=True,
datetime_representation=DatetimeRepresentation.ISO8601,
strict_uuid=True)
"""**DEPRECATED** - :class:`JSONOptions` for MongoDB Extended JSON's *Strict
mode* encoding.
.. versionadded:: 3.4
.. versionchanged:: 3.5
Deprecated. Use :const:`RELAXED_JSON_OPTIONS` or
:const:`CANONICAL_JSON_OPTIONS` instead.
"""
def dumps(obj, *args, **kwargs):
"""Helper function that wraps :func:`json.dumps`.
Recursive function that handles all BSON types including
:class:`~bson.binary.Binary` and :class:`~bson.code.Code`.
:Parameters:
- `json_options`: A :class:`JSONOptions` instance used to modify the
encoding of MongoDB Extended JSON types. Defaults to
:const:`DEFAULT_JSON_OPTIONS`.
.. versionchanged:: 3.4
Accepts optional parameter `json_options`. See :class:`JSONOptions`.
.. versionchanged:: 2.7
Preserves order when rendering SON, Timestamp, Code, Binary, and DBRef
instances.
"""
json_options = kwargs.pop("json_options", DEFAULT_JSON_OPTIONS)
return json.dumps(_json_convert(obj, json_options), *args, **kwargs)
def loads(s, *args, **kwargs):
"""Helper function that wraps :func:`json.loads`.
Automatically passes the object_hook for BSON type conversion.
Raises ``TypeError``, ``ValueError``, ``KeyError``, or
:exc:`~bson.errors.InvalidId` on invalid MongoDB Extended JSON.
:Parameters:
- `json_options`: A :class:`JSONOptions` instance used to modify the
decoding of MongoDB Extended JSON types. Defaults to
:const:`DEFAULT_JSON_OPTIONS`.
.. versionchanged:: 3.5
Parses Relaxed and Canonical Extended JSON as well as PyMongo's legacy
format. Now raises ``TypeError`` or ``ValueError`` when parsing JSON
type wrappers with values of the wrong type or any extra keys.
.. versionchanged:: 3.4
Accepts optional parameter `json_options`. See :class:`JSONOptions`.
"""
json_options = kwargs.pop("json_options", DEFAULT_JSON_OPTIONS)
kwargs["object_pairs_hook"] = lambda pairs: object_pairs_hook(
pairs, json_options)
return json.loads(s, *args, **kwargs)
def _json_convert(obj, json_options=DEFAULT_JSON_OPTIONS):
"""Recursive helper method that converts BSON types so they can be
converted into json.
"""
if hasattr(obj, 'iteritems') or hasattr(obj, 'items'): # PY3 support
return SON(((k, _json_convert(v, json_options))
for k, v in iteritems(obj)))
elif hasattr(obj, '__iter__') and not isinstance(obj, (text_type, bytes)):
return list((_json_convert(v, json_options) for v in obj))
try:
return default(obj, json_options)
except TypeError:
return obj
def object_pairs_hook(pairs, json_options=DEFAULT_JSON_OPTIONS):
return object_hook(json_options.document_class(pairs), json_options)
def object_hook(dct, json_options=DEFAULT_JSON_OPTIONS):
if "$oid" in dct:
return _parse_canonical_oid(dct)
if "$ref" in dct:
return _parse_canonical_dbref(dct)
if "$date" in dct:
return _parse_canonical_datetime(dct, json_options)
if "$regex" in dct:
return _parse_legacy_regex(dct)
if "$minKey" in dct:
return _parse_canonical_minkey(dct)
if "$maxKey" in dct:
return _parse_canonical_maxkey(dct)
if "$binary" in dct:
if "$type" in dct:
return _parse_legacy_binary(dct, json_options)
else:
return _parse_canonical_binary(dct, json_options)
if "$code" in dct:
return _parse_canonical_code(dct)
if "$uuid" in dct:
return _parse_legacy_uuid(dct)
if "$undefined" in dct:
return None
if "$numberLong" in dct:
return _parse_canonical_int64(dct)
if "$timestamp" in dct:
tsp = dct["$timestamp"]
return Timestamp(tsp["t"], tsp["i"])
if "$numberDecimal" in dct:
return _parse_canonical_decimal128(dct)
if "$dbPointer" in dct:
return _parse_canonical_dbpointer(dct)
if "$regularExpression" in dct:
return _parse_canonical_regex(dct)
if "$symbol" in dct:
return _parse_canonical_symbol(dct)
if "$numberInt" in dct:
return _parse_canonical_int32(dct)
if "$numberDouble" in dct:
return _parse_canonical_double(dct)
return dct
def _parse_legacy_regex(doc):
pattern = doc["$regex"]
# Check if this is the $regex query operator.
if isinstance(pattern, Regex):
return doc
flags = 0
# PyMongo always adds $options but some other tools may not.
for opt in doc.get("$options", ""):
flags |= _RE_OPT_TABLE.get(opt, 0)
return Regex(pattern, flags)
def _parse_legacy_uuid(doc):
"""Decode a JSON legacy $uuid to Python UUID."""
if len(doc) != 1:
raise TypeError('Bad $uuid, extra field(s): %s' % (doc,))
return uuid.UUID(doc["$uuid"])
def _binary_or_uuid(data, subtype, json_options):
# special handling for UUID
if subtype == OLD_UUID_SUBTYPE:
if json_options.uuid_representation == CSHARP_LEGACY:
return uuid.UUID(bytes_le=data)
if json_options.uuid_representation == JAVA_LEGACY:
data = data[7::-1] + data[:7:-1]
return uuid.UUID(bytes=data)
if subtype == UUID_SUBTYPE:
return uuid.UUID(bytes=data)
if PY3 and subtype == 0:
return data
return Binary(data, subtype)
def _parse_legacy_binary(doc, json_options):
if isinstance(doc["$type"], int):
doc["$type"] = "%02x" % doc["$type"]
subtype = int(doc["$type"], 16)
if subtype >= 0xffffff80: # Handle mongoexport values
subtype = int(doc["$type"][6:], 16)
data = base64.b64decode(doc["$binary"].encode())
return _binary_or_uuid(data, subtype, json_options)
def _parse_canonical_binary(doc, json_options):
binary = doc["$binary"]
b64 = binary["base64"]
subtype = binary["subType"]
if not isinstance(b64, string_type):
raise TypeError('$binary base64 must be a string: %s' % (doc,))
if not isinstance(subtype, string_type) or len(subtype) > 2:
raise TypeError('$binary subType must be a string at most 2 '
'characters: %s' % (doc,))
if len(binary) != 2:
raise TypeError('$binary must include only "base64" and "subType" '
'components: %s' % (doc,))
data = base64.b64decode(b64.encode())
return _binary_or_uuid(data, int(subtype, 16), json_options)
def _parse_canonical_datetime(doc, json_options):
"""Decode a JSON datetime to python datetime.datetime."""
dtm = doc["$date"]
if len(doc) != 1:
raise TypeError('Bad $date, extra field(s): %s' % (doc,))
# mongoexport 2.6 and newer
if isinstance(dtm, string_type):
# Parse offset
if dtm[-1] == 'Z':
dt = dtm[:-1]
offset = 'Z'
elif dtm[-6] in ('+', '-') and dtm[-3] == ':':
# (+|-)HH:MM
dt = dtm[:-6]
offset = dtm[-6:]
elif dtm[-5] in ('+', '-'):
# (+|-)HHMM
dt = dtm[:-5]
offset = dtm[-5:]
elif dtm[-3] in ('+', '-'):
# (+|-)HH
dt = dtm[:-3]
offset = dtm[-3:]
else:
dt = dtm
offset = ''
# Parse the optional factional seconds portion.
dot_index = dt.rfind('.')
microsecond = 0
if dot_index != -1:
microsecond = int(float(dt[dot_index:]) * 1000000)
dt = dt[:dot_index]
aware = datetime.datetime.strptime(
dt, "%Y-%m-%dT%H:%M:%S").replace(microsecond=microsecond,
tzinfo=utc)
if offset and offset != 'Z':
if len(offset) == 6:
hours, minutes = offset[1:].split(':')
secs = (int(hours) * 3600 + int(minutes) * 60)
elif len(offset) == 5:
secs = (int(offset[1:3]) * 3600 + int(offset[3:]) * 60)
elif len(offset) == 3:
secs = int(offset[1:3]) * 3600
if offset[0] == "-":
secs *= -1
aware = aware - datetime.timedelta(seconds=secs)
if json_options.tz_aware:
if json_options.tzinfo:
aware = aware.astimezone(json_options.tzinfo)
return aware
else:
return aware.replace(tzinfo=None)
return bson._millis_to_datetime(int(dtm), json_options)
def _parse_canonical_oid(doc):
"""Decode a JSON ObjectId to bson.objectid.ObjectId."""
if len(doc) != 1:
raise TypeError('Bad $oid, extra field(s): %s' % (doc,))
return ObjectId(doc['$oid'])
def _parse_canonical_symbol(doc):
"""Decode a JSON symbol to Python string."""
symbol = doc['$symbol']
if len(doc) != 1:
raise TypeError('Bad $symbol, extra field(s): %s' % (doc,))
return text_type(symbol)
def _parse_canonical_code(doc):
"""Decode a JSON code to bson.code.Code."""
for key in doc:
if key not in ('$code', '$scope'):
raise TypeError('Bad $code, extra field(s): %s' % (doc,))
return Code(doc['$code'], scope=doc.get('$scope'))
def _parse_canonical_regex(doc):
"""Decode a JSON regex to bson.regex.Regex."""
regex = doc['$regularExpression']
if len(doc) != 1:
raise TypeError('Bad $regularExpression, extra field(s): %s' % (doc,))
if len(regex) != 2:
raise TypeError('Bad $regularExpression must include only "pattern"'
'and "options" components: %s' % (doc,))
return Regex(regex['pattern'], regex['options'])
def _parse_canonical_dbref(doc):
"""Decode a JSON DBRef to bson.dbref.DBRef."""
for key in doc:
if key.startswith('$') and key not in _DBREF_KEYS:
# Other keys start with $, so dct cannot be parsed as a DBRef.
return doc
return DBRef(doc.pop('$ref'), doc.pop('$id'),
database=doc.pop('$db', None), **doc)
def _parse_canonical_dbpointer(doc):
"""Decode a JSON (deprecated) DBPointer to bson.dbref.DBRef."""
dbref = doc['$dbPointer']
if len(doc) != 1:
raise TypeError('Bad $dbPointer, extra field(s): %s' % (doc,))
if isinstance(dbref, DBRef):
dbref_doc = dbref.as_doc()
# DBPointer must not contain $db in its value.
if dbref.database is not None:
raise TypeError(
'Bad $dbPointer, extra field $db: %s' % (dbref_doc,))
if not isinstance(dbref.id, ObjectId):
raise TypeError(
'Bad $dbPointer, $id must be an ObjectId: %s' % (dbref_doc,))
if len(dbref_doc) != 2:
raise TypeError(
'Bad $dbPointer, extra field(s) in DBRef: %s' % (dbref_doc,))
return dbref
else:
raise TypeError('Bad $dbPointer, expected a DBRef: %s' % (doc,))
def _parse_canonical_int32(doc):
"""Decode a JSON int32 to python int."""
i_str = doc['$numberInt']
if len(doc) != 1:
raise TypeError('Bad $numberInt, extra field(s): %s' % (doc,))
if not isinstance(i_str, string_type):
raise TypeError('$numberInt must be string: %s' % (doc,))
return int(i_str)
def _parse_canonical_int64(doc):
"""Decode a JSON int64 to bson.int64.Int64."""
l_str = doc['$numberLong']
if len(doc) != 1:
raise TypeError('Bad $numberLong, extra field(s): %s' % (doc,))
return Int64(l_str)
def _parse_canonical_double(doc):
"""Decode a JSON double to python float."""
d_str = doc['$numberDouble']
if len(doc) != 1:
raise TypeError('Bad $numberDouble, extra field(s): %s' % (doc,))
if not isinstance(d_str, string_type):
raise TypeError('$numberDouble must be string: %s' % (doc,))
return float(d_str)
def _parse_canonical_decimal128(doc):
"""Decode a JSON decimal128 to bson.decimal128.Decimal128."""
d_str = doc['$numberDecimal']
if len(doc) != 1:
raise TypeError('Bad $numberDecimal, extra field(s): %s' % (doc,))
if not isinstance(d_str, string_type):
raise TypeError('$numberDecimal must be string: %s' % (doc,))
return Decimal128(d_str)
def _parse_canonical_minkey(doc):
"""Decode a JSON MinKey to bson.min_key.MinKey."""
if doc['$minKey'] is not 1:
raise TypeError('$minKey value must be 1: %s' % (doc,))
if len(doc) != 1:
raise TypeError('Bad $minKey, extra field(s): %s' % (doc,))
return MinKey()
def _parse_canonical_maxkey(doc):
"""Decode a JSON MaxKey to bson.max_key.MaxKey."""
if doc['$maxKey'] is not 1:
raise TypeError('$maxKey value must be 1: %s', (doc,))
if len(doc) != 1:
raise TypeError('Bad $minKey, extra field(s): %s' % (doc,))
return MaxKey()
def _encode_binary(data, subtype, json_options):
if json_options.json_mode == JSONMode.LEGACY:
return SON([
('$binary', base64.b64encode(data).decode()),
('$type', "%02x" % subtype)])
return {'$binary': SON([
('base64', base64.b64encode(data).decode()),
('subType', "%02x" % subtype)])}
def default(obj, json_options=DEFAULT_JSON_OPTIONS):
# We preserve key order when rendering SON, DBRef, etc. as JSON by
# returning a SON for those types instead of a dict.
if isinstance(obj, ObjectId):
return {"$oid": str(obj)}
if isinstance(obj, DBRef):
return _json_convert(obj.as_doc(), json_options=json_options)
if isinstance(obj, datetime.datetime):
if (json_options.datetime_representation ==
DatetimeRepresentation.ISO8601):
if not obj.tzinfo:
obj = obj.replace(tzinfo=utc)
if obj >= EPOCH_AWARE:
off = obj.tzinfo.utcoffset(obj)
if (off.days, off.seconds, off.microseconds) == (0, 0, 0):
tz_string = 'Z'
else:
tz_string = obj.strftime('%z')
millis = int(obj.microsecond / 1000)
fracsecs = ".%03d" % (millis,) if millis else ""
return {"$date": "%s%s%s" % (
obj.strftime("%Y-%m-%dT%H:%M:%S"), fracsecs, tz_string)}
millis = bson._datetime_to_millis(obj)
if (json_options.datetime_representation ==
DatetimeRepresentation.LEGACY):
return {"$date": millis}
return {"$date": {"$numberLong": str(millis)}}
if json_options.strict_number_long and isinstance(obj, Int64):
return {"$numberLong": str(obj)}
if isinstance(obj, (RE_TYPE, Regex)):
flags = ""
if obj.flags & re.IGNORECASE:
flags += "i"
if obj.flags & re.LOCALE:
flags += "l"
if obj.flags & re.MULTILINE:
flags += "m"
if obj.flags & re.DOTALL:
flags += "s"
if obj.flags & re.UNICODE:
flags += "u"
if obj.flags & re.VERBOSE:
flags += "x"
if isinstance(obj.pattern, text_type):
pattern = obj.pattern
else:
pattern = obj.pattern.decode('utf-8')
if json_options.json_mode == JSONMode.LEGACY:
return SON([("$regex", pattern), ("$options", flags)])
return {'$regularExpression': SON([("pattern", pattern),
("options", flags)])}
if isinstance(obj, MinKey):
return {"$minKey": 1}
if isinstance(obj, MaxKey):
return {"$maxKey": 1}
if isinstance(obj, Timestamp):
return {"$timestamp": SON([("t", obj.time), ("i", obj.inc)])}
if isinstance(obj, Code):
if obj.scope is None:
return {'$code': str(obj)}
return SON([
('$code', str(obj)),
('$scope', _json_convert(obj.scope, json_options))])
if isinstance(obj, Binary):
return _encode_binary(obj, obj.subtype, json_options)
if PY3 and isinstance(obj, bytes):
return _encode_binary(obj, 0, json_options)
if isinstance(obj, uuid.UUID):
if json_options.strict_uuid:
data = obj.bytes
subtype = OLD_UUID_SUBTYPE
if json_options.uuid_representation == CSHARP_LEGACY:
data = obj.bytes_le
elif json_options.uuid_representation == JAVA_LEGACY:
data = data[7::-1] + data[:7:-1]
elif json_options.uuid_representation == UUID_SUBTYPE:
subtype = UUID_SUBTYPE
return _encode_binary(data, subtype, json_options)
else:
return {"$uuid": obj.hex}
if isinstance(obj, Decimal128):
return {"$numberDecimal": str(obj)}
if isinstance(obj, bool):
return obj
if (json_options.json_mode == JSONMode.CANONICAL and
isinstance(obj, integer_types)):
if -2 ** 31 <= obj < 2 ** 31:
return {'$numberInt': text_type(obj)}
return {'$numberLong': text_type(obj)}
if json_options.json_mode != JSONMode.LEGACY and isinstance(obj, float):
if math.isnan(obj):
return {'$numberDouble': 'NaN'}
elif math.isinf(obj):
representation = 'Infinity' if obj > 0 else '-Infinity'
return {'$numberDouble': representation}
elif json_options.json_mode == JSONMode.CANONICAL:
# repr() will return the shortest string guaranteed to produce the
# original value, when float() is called on it. str produces a
# shorter string in Python 2.
return {'$numberDouble': text_type(repr(obj))}
raise TypeError("%r is not JSON serializable" % obj)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/max_key.py
================================================
# Copyright 2010-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Representation for the MongoDB internal MaxKey type.
"""
class MaxKey(object):
"""MongoDB internal MaxKey type.
.. versionchanged:: 2.7
``MaxKey`` now implements comparison operators.
"""
_type_marker = 127
def __eq__(self, other):
return isinstance(other, MaxKey)
def __hash__(self):
return hash(self._type_marker)
def __ne__(self, other):
return not self == other
def __le__(self, other):
return isinstance(other, MaxKey)
def __lt__(self, dummy):
return False
def __ge__(self, dummy):
return True
def __gt__(self, other):
return not isinstance(other, MaxKey)
def __repr__(self):
return "MaxKey()"
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/min_key.py
================================================
# Copyright 2010-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Representation for the MongoDB internal MinKey type.
"""
class MinKey(object):
"""MongoDB internal MinKey type.
.. versionchanged:: 2.7
``MinKey`` now implements comparison operators.
"""
_type_marker = 255
def __eq__(self, other):
return isinstance(other, MinKey)
def __hash__(self):
return hash(self._type_marker)
def __ne__(self, other):
return not self == other
def __le__(self, dummy):
return True
def __lt__(self, other):
return not isinstance(other, MinKey)
def __ge__(self, other):
return isinstance(other, MinKey)
def __gt__(self, dummy):
return False
def __repr__(self):
return "MinKey()"
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/objectid.py
================================================
# Copyright 2009-2015 MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tools for working with MongoDB `ObjectIds
`_.
"""
import binascii
import calendar
import datetime
import os
import struct
import threading
import time
from random import SystemRandom
from bson.errors import InvalidId
from bson.py3compat import PY3, bytes_from_hex, string_type, text_type
from bson.tz_util import utc
_MAX_COUNTER_VALUE = 0xFFFFFF
def _raise_invalid_id(oid):
raise InvalidId(
"%r is not a valid ObjectId, it must be a 12-byte input"
" or a 24-character hex string" % oid)
def _random_bytes():
"""Get the 5-byte random field of an ObjectId."""
return os.urandom(5)
class ObjectId(object):
"""A MongoDB ObjectId.
"""
_pid = os.getpid()
_inc = SystemRandom().randint(0, _MAX_COUNTER_VALUE)
_inc_lock = threading.Lock()
__random = _random_bytes()
__slots__ = ('__id',)
_type_marker = 7
def __init__(self, oid=None):
"""Initialize a new ObjectId.
An ObjectId is a 12-byte unique identifier consisting of:
- a 4-byte value representing the seconds since the Unix epoch,
- a 5-byte random value,
- a 3-byte counter, starting with a random value.
By default, ``ObjectId()`` creates a new unique identifier. The
optional parameter `oid` can be an :class:`ObjectId`, or any 12
:class:`bytes` or, in Python 2, any 12-character :class:`str`.
For example, the 12 bytes b'foo-bar-quux' do not follow the ObjectId
specification but they are acceptable input::
>>> ObjectId(b'foo-bar-quux')
ObjectId('666f6f2d6261722d71757578')
`oid` can also be a :class:`unicode` or :class:`str` of 24 hex digits::
>>> ObjectId('0123456789ab0123456789ab')
ObjectId('0123456789ab0123456789ab')
>>>
>>> # A u-prefixed unicode literal:
>>> ObjectId(u'0123456789ab0123456789ab')
ObjectId('0123456789ab0123456789ab')
Raises :class:`~bson.errors.InvalidId` if `oid` is not 12 bytes nor
24 hex digits, or :class:`TypeError` if `oid` is not an accepted type.
:Parameters:
- `oid` (optional): a valid ObjectId.
.. mongodoc:: objectids
.. versionchanged:: 3.8
:class:`~bson.objectid.ObjectId` now implements the `ObjectID
specification version 0.2
`_.
"""
if oid is None:
self.__generate()
elif isinstance(oid, bytes) and len(oid) == 12:
self.__id = oid
else:
self.__validate(oid)
@classmethod
def from_datetime(cls, generation_time):
"""Create a dummy ObjectId instance with a specific generation time.
This method is useful for doing range queries on a field
containing :class:`ObjectId` instances.
.. warning::
It is not safe to insert a document containing an ObjectId
generated using this method. This method deliberately
eliminates the uniqueness guarantee that ObjectIds
generally provide. ObjectIds generated with this method
should be used exclusively in queries.
`generation_time` will be converted to UTC. Naive datetime
instances will be treated as though they already contain UTC.
An example using this helper to get documents where ``"_id"``
was generated before January 1, 2010 would be:
>>> gen_time = datetime.datetime(2010, 1, 1)
>>> dummy_id = ObjectId.from_datetime(gen_time)
>>> result = collection.find({"_id": {"$lt": dummy_id}})
:Parameters:
- `generation_time`: :class:`~datetime.datetime` to be used
as the generation time for the resulting ObjectId.
"""
if generation_time.utcoffset() is not None:
generation_time = generation_time - generation_time.utcoffset()
timestamp = calendar.timegm(generation_time.timetuple())
oid = struct.pack(
">I", int(timestamp)) + b"\x00\x00\x00\x00\x00\x00\x00\x00"
return cls(oid)
@classmethod
def is_valid(cls, oid):
"""Checks if a `oid` string is valid or not.
:Parameters:
- `oid`: the object id to validate
.. versionadded:: 2.3
"""
if not oid:
return False
try:
ObjectId(oid)
return True
except (InvalidId, TypeError):
return False
@classmethod
def _random(cls):
"""Generate a 5-byte random number once per process.
"""
pid = os.getpid()
if pid != cls._pid:
cls._pid = pid
cls.__random = _random_bytes()
return cls.__random
def __generate(self):
"""Generate a new value for this ObjectId.
"""
# 4 bytes current time
oid = struct.pack(">I", int(time.time()))
# 5 bytes random
oid += ObjectId._random()
# 3 bytes inc
with ObjectId._inc_lock:
oid += struct.pack(">I", ObjectId._inc)[1:4]
ObjectId._inc = (ObjectId._inc + 1) % (_MAX_COUNTER_VALUE + 1)
self.__id = oid
def __validate(self, oid):
"""Validate and use the given id for this ObjectId.
Raises TypeError if id is not an instance of
(:class:`basestring` (:class:`str` or :class:`bytes`
in python 3), ObjectId) and InvalidId if it is not a
valid ObjectId.
:Parameters:
- `oid`: a valid ObjectId
"""
if isinstance(oid, ObjectId):
self.__id = oid.binary
# bytes or unicode in python 2, str in python 3
elif isinstance(oid, string_type):
if len(oid) == 24:
try:
self.__id = bytes_from_hex(oid)
except (TypeError, ValueError):
_raise_invalid_id(oid)
else:
_raise_invalid_id(oid)
else:
raise TypeError("id must be an instance of (bytes, %s, ObjectId), "
"not %s" % (text_type.__name__, type(oid)))
@property
def binary(self):
"""12-byte binary representation of this ObjectId.
"""
return self.__id
@property
def generation_time(self):
"""A :class:`datetime.datetime` instance representing the time of
generation for this :class:`ObjectId`.
The :class:`datetime.datetime` is timezone aware, and
represents the generation time in UTC. It is precise to the
second.
"""
timestamp = struct.unpack(">I", self.__id[0:4])[0]
return datetime.datetime.fromtimestamp(timestamp, utc)
def __getstate__(self):
"""return value of object for pickling.
needed explicitly because __slots__() defined.
"""
return self.__id
def __setstate__(self, value):
"""explicit state set from pickling
"""
# Provide backwards compatability with OIDs
# pickled with pymongo-1.9 or older.
if isinstance(value, dict):
oid = value["_ObjectId__id"]
else:
oid = value
# ObjectIds pickled in python 2.x used `str` for __id.
# In python 3.x this has to be converted to `bytes`
# by encoding latin-1.
if PY3 and isinstance(oid, text_type):
self.__id = oid.encode('latin-1')
else:
self.__id = oid
def __str__(self):
if PY3:
return binascii.hexlify(self.__id).decode()
return binascii.hexlify(self.__id)
def __repr__(self):
return "ObjectId('%s')" % (str(self),)
def __eq__(self, other):
if isinstance(other, ObjectId):
return self.__id == other.binary
return NotImplemented
def __ne__(self, other):
if isinstance(other, ObjectId):
return self.__id != other.binary
return NotImplemented
def __lt__(self, other):
if isinstance(other, ObjectId):
return self.__id < other.binary
return NotImplemented
def __le__(self, other):
if isinstance(other, ObjectId):
return self.__id <= other.binary
return NotImplemented
def __gt__(self, other):
if isinstance(other, ObjectId):
return self.__id > other.binary
return NotImplemented
def __ge__(self, other):
if isinstance(other, ObjectId):
return self.__id >= other.binary
return NotImplemented
def __hash__(self):
"""Get a hash value for this :class:`ObjectId`."""
return hash(self.__id)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/py3compat.py
================================================
# Copyright 2009-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you
# may not use this file except in compliance with the License. You
# may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing
# permissions and limitations under the License.
"""Utility functions and definitions for python3 compatibility."""
import sys
PY3 = sys.version_info[0] == 3
if PY3:
import codecs
import collections.abc as abc
import _thread as thread
from abc import ABC, abstractmethod
from io import BytesIO as StringIO
def abstractproperty(func):
return property(abstractmethod(func))
MAXSIZE = sys.maxsize
imap = map
def b(s):
# BSON and socket operations deal in binary data. In
# python 3 that means instances of `bytes`. In python
# 2.7 you can create an alias for `bytes` using
# the b prefix (e.g. b'foo').
# See http://python3porting.com/problems.html#nicer-solutions
return codecs.latin_1_encode(s)[0]
def bytes_from_hex(h):
return bytes.fromhex(h)
def iteritems(d):
return iter(d.items())
def itervalues(d):
return iter(d.values())
def reraise(exctype, value, trace=None):
raise exctype(str(value)).with_traceback(trace)
def reraise_instance(exc_instance, trace=None):
raise exc_instance.with_traceback(trace)
def _unicode(s):
return s
text_type = str
string_type = str
integer_types = int
else:
import collections as abc
import thread
from abc import ABCMeta, abstractproperty
from itertools import imap
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
ABC = ABCMeta('ABC', (object,), {})
MAXSIZE = sys.maxint
def b(s):
# See comments above. In python 2.x b('foo') is just 'foo'.
return s
def bytes_from_hex(h):
return h.decode('hex')
def iteritems(d):
return d.iteritems()
def itervalues(d):
return d.itervalues()
def reraise(exctype, value, trace=None):
_reraise(exctype, str(value), trace)
def reraise_instance(exc_instance, trace=None):
_reraise(exc_instance, None, trace)
# "raise x, y, z" raises SyntaxError in Python 3
exec("""def _reraise(exc, value, trace):
raise exc, value, trace
""")
_unicode = unicode
string_type = basestring
text_type = unicode
integer_types = (int, long)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/raw_bson.py
================================================
# Copyright 2015-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tools for representing raw BSON documents.
"""
from bson import _raw_to_dict, _get_object_size
from bson.py3compat import abc, iteritems
from bson.codec_options import (
DEFAULT_CODEC_OPTIONS as DEFAULT, _RAW_BSON_DOCUMENT_MARKER)
from bson.son import SON
class RawBSONDocument(abc.Mapping):
"""Representation for a MongoDB document that provides access to the raw
BSON bytes that compose it.
Only when a field is accessed or modified within the document does
RawBSONDocument decode its bytes.
"""
__slots__ = ('__raw', '__inflated_doc', '__codec_options')
_type_marker = _RAW_BSON_DOCUMENT_MARKER
def __init__(self, bson_bytes, codec_options=None):
"""Create a new :class:`RawBSONDocument`
:class:`RawBSONDocument` is a representation of a BSON document that
provides access to the underlying raw BSON bytes. Only when a field is
accessed or modified within the document does RawBSONDocument decode
its bytes.
:class:`RawBSONDocument` implements the ``Mapping`` abstract base
class from the standard library so it can be used like a read-only
``dict``::
>>> raw_doc = RawBSONDocument(BSON.encode({'_id': 'my_doc'}))
>>> raw_doc.raw
b'...'
>>> raw_doc['_id']
'my_doc'
:Parameters:
- `bson_bytes`: the BSON bytes that compose this document
- `codec_options` (optional): An instance of
:class:`~bson.codec_options.CodecOptions` whose ``document_class``
must be :class:`RawBSONDocument`. The default is
:attr:`DEFAULT_RAW_BSON_OPTIONS`.
.. versionchanged:: 3.8
:class:`RawBSONDocument` now validates that the ``bson_bytes``
passed in represent a single bson document.
.. versionchanged:: 3.5
If a :class:`~bson.codec_options.CodecOptions` is passed in, its
`document_class` must be :class:`RawBSONDocument`.
"""
self.__raw = bson_bytes
self.__inflated_doc = None
# Can't default codec_options to DEFAULT_RAW_BSON_OPTIONS in signature,
# it refers to this class RawBSONDocument.
if codec_options is None:
codec_options = DEFAULT_RAW_BSON_OPTIONS
elif codec_options.document_class is not RawBSONDocument:
raise TypeError(
"RawBSONDocument cannot use CodecOptions with document "
"class %s" % (codec_options.document_class, ))
self.__codec_options = codec_options
# Validate the bson object size.
_get_object_size(bson_bytes, 0, len(bson_bytes))
@property
def raw(self):
"""The raw BSON bytes composing this document."""
return self.__raw
def items(self):
"""Lazily decode and iterate elements in this document."""
return iteritems(self.__inflated)
@property
def __inflated(self):
if self.__inflated_doc is None:
# We already validated the object's size when this document was
# created, so no need to do that again.
# Use SON to preserve ordering of elements.
self.__inflated_doc = _inflate_bson(
self.__raw, self.__codec_options)
return self.__inflated_doc
def __getitem__(self, item):
return self.__inflated[item]
def __iter__(self):
return iter(self.__inflated)
def __len__(self):
return len(self.__inflated)
def __eq__(self, other):
if isinstance(other, RawBSONDocument):
return self.__raw == other.raw
return NotImplemented
def __repr__(self):
return ("RawBSONDocument(%r, codec_options=%r)"
% (self.raw, self.__codec_options))
def _inflate_bson(bson_bytes, codec_options):
"""Inflates the top level fields of a BSON document.
:Parameters:
- `bson_bytes`: the BSON bytes that compose this document
- `codec_options`: An instance of
:class:`~bson.codec_options.CodecOptions` whose ``document_class``
must be :class:`RawBSONDocument`.
"""
# Use SON to preserve ordering of elements.
return _raw_to_dict(
bson_bytes, 4, len(bson_bytes)-1, codec_options, SON())
DEFAULT_RAW_BSON_OPTIONS = DEFAULT.with_options(document_class=RawBSONDocument)
"""The default :class:`~bson.codec_options.CodecOptions` for
:class:`RawBSONDocument`.
"""
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/regex.py
================================================
# Copyright 2013-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tools for representing MongoDB regular expressions.
"""
import re
from bson.son import RE_TYPE
from bson.py3compat import string_type, text_type
def str_flags_to_int(str_flags):
flags = 0
if "i" in str_flags:
flags |= re.IGNORECASE
if "l" in str_flags:
flags |= re.LOCALE
if "m" in str_flags:
flags |= re.MULTILINE
if "s" in str_flags:
flags |= re.DOTALL
if "u" in str_flags:
flags |= re.UNICODE
if "x" in str_flags:
flags |= re.VERBOSE
return flags
class Regex(object):
"""BSON regular expression data."""
_type_marker = 11
@classmethod
def from_native(cls, regex):
"""Convert a Python regular expression into a ``Regex`` instance.
Note that in Python 3, a regular expression compiled from a
:class:`str` has the ``re.UNICODE`` flag set. If it is undesirable
to store this flag in a BSON regular expression, unset it first::
>>> pattern = re.compile('.*')
>>> regex = Regex.from_native(pattern)
>>> regex.flags ^= re.UNICODE
>>> db.collection.insert({'pattern': regex})
:Parameters:
- `regex`: A regular expression object from ``re.compile()``.
.. warning::
Python regular expressions use a different syntax and different
set of flags than MongoDB, which uses `PCRE`_. A regular
expression retrieved from the server may not compile in
Python, or may match a different set of strings in Python than
when used in a MongoDB query.
.. _PCRE: http://www.pcre.org/
"""
if not isinstance(regex, RE_TYPE):
raise TypeError(
"regex must be a compiled regular expression, not %s"
% type(regex))
return Regex(regex.pattern, regex.flags)
def __init__(self, pattern, flags=0):
"""BSON regular expression data.
This class is useful to store and retrieve regular expressions that are
incompatible with Python's regular expression dialect.
:Parameters:
- `pattern`: string
- `flags`: (optional) an integer bitmask, or a string of flag
characters like "im" for IGNORECASE and MULTILINE
"""
if not isinstance(pattern, (text_type, bytes)):
raise TypeError("pattern must be a string, not %s" % type(pattern))
self.pattern = pattern
if isinstance(flags, string_type):
self.flags = str_flags_to_int(flags)
elif isinstance(flags, int):
self.flags = flags
else:
raise TypeError(
"flags must be a string or int, not %s" % type(flags))
def __eq__(self, other):
if isinstance(other, Regex):
return self.pattern == other.pattern and self.flags == other.flags
else:
return NotImplemented
__hash__ = None
def __ne__(self, other):
return not self == other
def __repr__(self):
return "Regex(%r, %r)" % (self.pattern, self.flags)
def try_compile(self):
"""Compile this :class:`Regex` as a Python regular expression.
.. warning::
Python regular expressions use a different syntax and different
set of flags than MongoDB, which uses `PCRE`_. A regular
expression retrieved from the server may not compile in
Python, or may match a different set of strings in Python than
when used in a MongoDB query. :meth:`try_compile()` may raise
:exc:`re.error`.
.. _PCRE: http://www.pcre.org/
"""
return re.compile(self.pattern, self.flags)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/son.py
================================================
# Copyright 2009-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tools for creating and manipulating SON, the Serialized Ocument Notation.
Regular dictionaries can be used instead of SON objects, but not when the order
of keys is important. A SON object can be used just like a normal Python
dictionary."""
import copy
import re
from bson.py3compat import abc, iteritems
# This sort of sucks, but seems to be as good as it gets...
# This is essentially the same as re._pattern_type
RE_TYPE = type(re.compile(""))
class SON(dict):
"""SON data.
A subclass of dict that maintains ordering of keys and provides a
few extra niceties for dealing with SON. SON provides an API
similar to collections.OrderedDict from Python 2.7+.
"""
def __init__(self, data=None, **kwargs):
self.__keys = []
dict.__init__(self)
self.update(data)
self.update(kwargs)
def __new__(cls, *args, **kwargs):
instance = super(SON, cls).__new__(cls, *args, **kwargs)
instance.__keys = []
return instance
def __repr__(self):
result = []
for key in self.__keys:
result.append("(%r, %r)" % (key, self[key]))
return "SON([%s])" % ", ".join(result)
def __setitem__(self, key, value):
if key not in self.__keys:
self.__keys.append(key)
dict.__setitem__(self, key, value)
def __delitem__(self, key):
self.__keys.remove(key)
dict.__delitem__(self, key)
def keys(self):
return list(self.__keys)
def copy(self):
other = SON()
other.update(self)
return other
# TODO this is all from UserDict.DictMixin. it could probably be made more
# efficient.
# second level definitions support higher levels
def __iter__(self):
for k in self.__keys:
yield k
def has_key(self, key):
return key in self.__keys
# third level takes advantage of second level definitions
def iteritems(self):
for k in self:
yield (k, self[k])
def iterkeys(self):
return self.__iter__()
# fourth level uses definitions from lower levels
def itervalues(self):
for _, v in self.iteritems():
yield v
def values(self):
return [v for _, v in self.iteritems()]
def items(self):
return [(key, self[key]) for key in self]
def clear(self):
self.__keys = []
super(SON, self).clear()
def setdefault(self, key, default=None):
try:
return self[key]
except KeyError:
self[key] = default
return default
def pop(self, key, *args):
if len(args) > 1:
raise TypeError("pop expected at most 2 arguments, got "\
+ repr(1 + len(args)))
try:
value = self[key]
except KeyError:
if args:
return args[0]
raise
del self[key]
return value
def popitem(self):
try:
k, v = next(self.iteritems())
except StopIteration:
raise KeyError('container is empty')
del self[k]
return (k, v)
def update(self, other=None, **kwargs):
# Make progressively weaker assumptions about "other"
if other is None:
pass
elif hasattr(other, 'iteritems'): # iteritems saves memory and lookups
for k, v in other.iteritems():
self[k] = v
elif hasattr(other, 'keys'):
for k in other.keys():
self[k] = other[k]
else:
for k, v in other:
self[k] = v
if kwargs:
self.update(kwargs)
def get(self, key, default=None):
try:
return self[key]
except KeyError:
return default
def __eq__(self, other):
"""Comparison to another SON is order-sensitive while comparison to a
regular dictionary is order-insensitive.
"""
if isinstance(other, SON):
return len(self) == len(other) and self.items() == other.items()
return self.to_dict() == other
def __ne__(self, other):
return not self == other
def __len__(self):
return len(self.__keys)
def to_dict(self):
"""Convert a SON document to a normal Python dictionary instance.
This is trickier than just *dict(...)* because it needs to be
recursive.
"""
def transform_value(value):
if isinstance(value, list):
return [transform_value(v) for v in value]
elif isinstance(value, abc.Mapping):
return dict([
(k, transform_value(v))
for k, v in iteritems(value)])
else:
return value
return transform_value(dict(self))
def __deepcopy__(self, memo):
out = SON()
val_id = id(self)
if val_id in memo:
return memo.get(val_id)
memo[val_id] = out
for k, v in self.iteritems():
if not isinstance(v, RE_TYPE):
v = copy.deepcopy(v, memo)
out[k] = v
return out
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/timestamp.py
================================================
# Copyright 2010-2015 MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tools for representing MongoDB internal Timestamps.
"""
import calendar
import datetime
from bson.py3compat import integer_types
from bson.tz_util import utc
UPPERBOUND = 4294967296
class Timestamp(object):
"""MongoDB internal timestamps used in the opLog.
"""
_type_marker = 17
def __init__(self, time, inc):
"""Create a new :class:`Timestamp`.
This class is only for use with the MongoDB opLog. If you need
to store a regular timestamp, please use a
:class:`~datetime.datetime`.
Raises :class:`TypeError` if `time` is not an instance of
:class: `int` or :class:`~datetime.datetime`, or `inc` is not
an instance of :class:`int`. Raises :class:`ValueError` if
`time` or `inc` is not in [0, 2**32).
:Parameters:
- `time`: time in seconds since epoch UTC, or a naive UTC
:class:`~datetime.datetime`, or an aware
:class:`~datetime.datetime`
- `inc`: the incrementing counter
"""
if isinstance(time, datetime.datetime):
if time.utcoffset() is not None:
time = time - time.utcoffset()
time = int(calendar.timegm(time.timetuple()))
if not isinstance(time, integer_types):
raise TypeError("time must be an instance of int")
if not isinstance(inc, integer_types):
raise TypeError("inc must be an instance of int")
if not 0 <= time < UPPERBOUND:
raise ValueError("time must be contained in [0, 2**32)")
if not 0 <= inc < UPPERBOUND:
raise ValueError("inc must be contained in [0, 2**32)")
self.__time = time
self.__inc = inc
@property
def time(self):
"""Get the time portion of this :class:`Timestamp`.
"""
return self.__time
@property
def inc(self):
"""Get the inc portion of this :class:`Timestamp`.
"""
return self.__inc
def __eq__(self, other):
if isinstance(other, Timestamp):
return (self.__time == other.time and self.__inc == other.inc)
else:
return NotImplemented
def __hash__(self):
return hash(self.time) ^ hash(self.inc)
def __ne__(self, other):
return not self == other
def __lt__(self, other):
if isinstance(other, Timestamp):
return (self.time, self.inc) < (other.time, other.inc)
return NotImplemented
def __le__(self, other):
if isinstance(other, Timestamp):
return (self.time, self.inc) <= (other.time, other.inc)
return NotImplemented
def __gt__(self, other):
if isinstance(other, Timestamp):
return (self.time, self.inc) > (other.time, other.inc)
return NotImplemented
def __ge__(self, other):
if isinstance(other, Timestamp):
return (self.time, self.inc) >= (other.time, other.inc)
return NotImplemented
def __repr__(self):
return "Timestamp(%s, %s)" % (self.__time, self.__inc)
def as_datetime(self):
"""Return a :class:`~datetime.datetime` instance corresponding
to the time portion of this :class:`Timestamp`.
The returned datetime's timezone is UTC.
"""
return datetime.datetime.fromtimestamp(self.__time, utc)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/bson/tz_util.py
================================================
# Copyright 2010-2015 MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Timezone related utilities for BSON."""
from datetime import (timedelta,
tzinfo)
ZERO = timedelta(0)
class FixedOffset(tzinfo):
"""Fixed offset timezone, in minutes east from UTC.
Implementation based from the Python `standard library documentation
`_.
Defining __getinitargs__ enables pickling / copying.
"""
def __init__(self, offset, name):
if isinstance(offset, timedelta):
self.__offset = offset
else:
self.__offset = timedelta(minutes=offset)
self.__name = name
def __getinitargs__(self):
return self.__offset, self.__name
def utcoffset(self, dt):
return self.__offset
def tzname(self, dt):
return self.__name
def dst(self, dt):
return ZERO
utc = FixedOffset(0, "UTC")
"""Fixed offset timezone representing UTC."""
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/__init__.py
================================================
__all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError',
'FFIError']
from .api import FFI
from .error import CDefError, FFIError, VerificationError, VerificationMissing
from .error import PkgConfigError
__version__ = "1.13.1"
__version_info__ = (1, 13, 1)
# The verifier module file names are based on the CRC32 of a string that
# contains the following version number. It may be older than __version__
# if nothing is clearly incompatible.
__version_verifier_modules__ = "0.8.6"
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/_cffi_errors.h
================================================
#ifndef CFFI_MESSAGEBOX
# ifdef _MSC_VER
# define CFFI_MESSAGEBOX 1
# else
# define CFFI_MESSAGEBOX 0
# endif
#endif
#if CFFI_MESSAGEBOX
/* Windows only: logic to take the Python-CFFI embedding logic
initialization errors and display them in a background thread
with MessageBox. The idea is that if the whole program closes
as a result of this problem, then likely it is already a console
program and you can read the stderr output in the console too.
If it is not a console program, then it will likely show its own
dialog to complain, or generally not abruptly close, and for this
case the background thread should stay alive.
*/
static void *volatile _cffi_bootstrap_text;
static PyObject *_cffi_start_error_capture(void)
{
PyObject *result = NULL;
PyObject *x, *m, *bi;
if (InterlockedCompareExchangePointer(&_cffi_bootstrap_text,
(void *)1, NULL) != NULL)
return (PyObject *)1;
m = PyImport_AddModule("_cffi_error_capture");
if (m == NULL)
goto error;
result = PyModule_GetDict(m);
if (result == NULL)
goto error;
#if PY_MAJOR_VERSION >= 3
bi = PyImport_ImportModule("builtins");
#else
bi = PyImport_ImportModule("__builtin__");
#endif
if (bi == NULL)
goto error;
PyDict_SetItemString(result, "__builtins__", bi);
Py_DECREF(bi);
x = PyRun_String(
"import sys\n"
"class FileLike:\n"
" def write(self, x):\n"
" try:\n"
" of.write(x)\n"
" except: pass\n"
" self.buf += x\n"
"fl = FileLike()\n"
"fl.buf = ''\n"
"of = sys.stderr\n"
"sys.stderr = fl\n"
"def done():\n"
" sys.stderr = of\n"
" return fl.buf\n", /* make sure the returned value stays alive */
Py_file_input,
result, result);
Py_XDECREF(x);
error:
if (PyErr_Occurred())
{
PyErr_WriteUnraisable(Py_None);
PyErr_Clear();
}
return result;
}
#pragma comment(lib, "user32.lib")
static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored)
{
Sleep(666); /* may be interrupted if the whole process is closing */
#if PY_MAJOR_VERSION >= 3
MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text,
L"Python-CFFI error",
MB_OK | MB_ICONERROR);
#else
MessageBoxA(NULL, (char *)_cffi_bootstrap_text,
"Python-CFFI error",
MB_OK | MB_ICONERROR);
#endif
_cffi_bootstrap_text = NULL;
return 0;
}
static void _cffi_stop_error_capture(PyObject *ecap)
{
PyObject *s;
void *text;
if (ecap == (PyObject *)1)
return;
if (ecap == NULL)
goto error;
s = PyRun_String("done()", Py_eval_input, ecap, ecap);
if (s == NULL)
goto error;
/* Show a dialog box, but in a background thread, and
never show multiple dialog boxes at once. */
#if PY_MAJOR_VERSION >= 3
text = PyUnicode_AsWideCharString(s, NULL);
#else
text = PyString_AsString(s);
#endif
_cffi_bootstrap_text = text;
if (text != NULL)
{
HANDLE h;
h = CreateThread(NULL, 0, _cffi_bootstrap_dialog,
NULL, 0, NULL);
if (h != NULL)
CloseHandle(h);
}
/* decref the string, but it should stay alive as 'fl.buf'
in the small module above. It will really be freed only if
we later get another similar error. So it's a leak of at
most one copy of the small module. That's fine for this
situation which is usually a "fatal error" anyway. */
Py_DECREF(s);
PyErr_Clear();
return;
error:
_cffi_bootstrap_text = NULL;
PyErr_Clear();
}
#else
static PyObject *_cffi_start_error_capture(void) { return NULL; }
static void _cffi_stop_error_capture(PyObject *ecap) { }
#endif
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/_cffi_include.h
================================================
#define _CFFI_
/* We try to define Py_LIMITED_API before including Python.h.
Mess: we can only define it if Py_DEBUG, Py_TRACE_REFS and
Py_REF_DEBUG are not defined. This is a best-effort approximation:
we can learn about Py_DEBUG from pyconfig.h, but it is unclear if
the same works for the other two macros. Py_DEBUG implies them,
but not the other way around.
Issue #350 is still open: on Windows, the code here causes it to link
with PYTHON36.DLL (for example) instead of PYTHON3.DLL. A fix was
attempted in 164e526a5515 and 14ce6985e1c3, but reverted: virtualenv
does not make PYTHON3.DLL available, and so the "correctly" compiled
version would not run inside a virtualenv. We will re-apply the fix
after virtualenv has been fixed for some time. For explanation, see
issue #355. For a workaround if you want PYTHON3.DLL and don't worry
about virtualenv, see issue #350. See also 'py_limited_api' in
setuptools_ext.py.
*/
#if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API)
# include
# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG)
# define Py_LIMITED_API
# endif
#endif
#include
#ifdef __cplusplus
extern "C" {
#endif
#include
#include "parse_c_type.h"
/* this block of #ifs should be kept exactly identical between
c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py
and cffi/_cffi_include.h */
#if defined(_MSC_VER)
# include /* for alloca() */
# if _MSC_VER < 1600 /* MSVC < 2010 */
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
typedef __int8 int_least8_t;
typedef __int16 int_least16_t;
typedef __int32 int_least32_t;
typedef __int64 int_least64_t;
typedef unsigned __int8 uint_least8_t;
typedef unsigned __int16 uint_least16_t;
typedef unsigned __int32 uint_least32_t;
typedef unsigned __int64 uint_least64_t;
typedef __int8 int_fast8_t;
typedef __int16 int_fast16_t;
typedef __int32 int_fast32_t;
typedef __int64 int_fast64_t;
typedef unsigned __int8 uint_fast8_t;
typedef unsigned __int16 uint_fast16_t;
typedef unsigned __int32 uint_fast32_t;
typedef unsigned __int64 uint_fast64_t;
typedef __int64 intmax_t;
typedef unsigned __int64 uintmax_t;
# else
# include
# endif
# if _MSC_VER < 1800 /* MSVC < 2013 */
# ifndef __cplusplus
typedef unsigned char _Bool;
# endif
# endif
#else
# include
# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux)
# include
# endif
#endif
#ifdef __GNUC__
# define _CFFI_UNUSED_FN __attribute__((unused))
#else
# define _CFFI_UNUSED_FN /* nothing */
#endif
#ifdef __cplusplus
# ifndef _Bool
typedef bool _Bool; /* semi-hackish: C++ has no _Bool; bool is builtin */
# endif
#endif
/********** CPython-specific section **********/
#ifndef PYPY_VERSION
#if PY_MAJOR_VERSION >= 3
# define PyInt_FromLong PyLong_FromLong
#endif
#define _cffi_from_c_double PyFloat_FromDouble
#define _cffi_from_c_float PyFloat_FromDouble
#define _cffi_from_c_long PyInt_FromLong
#define _cffi_from_c_ulong PyLong_FromUnsignedLong
#define _cffi_from_c_longlong PyLong_FromLongLong
#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong
#define _cffi_from_c__Bool PyBool_FromLong
#define _cffi_to_c_double PyFloat_AsDouble
#define _cffi_to_c_float PyFloat_AsDouble
#define _cffi_from_c_int(x, type) \
(((type)-1) > 0 ? /* unsigned */ \
(sizeof(type) < sizeof(long) ? \
PyInt_FromLong((long)x) : \
sizeof(type) == sizeof(long) ? \
PyLong_FromUnsignedLong((unsigned long)x) : \
PyLong_FromUnsignedLongLong((unsigned long long)x)) : \
(sizeof(type) <= sizeof(long) ? \
PyInt_FromLong((long)x) : \
PyLong_FromLongLong((long long)x)))
#define _cffi_to_c_int(o, type) \
((type)( \
sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \
: (type)_cffi_to_c_i8(o)) : \
sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \
: (type)_cffi_to_c_i16(o)) : \
sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \
: (type)_cffi_to_c_i32(o)) : \
sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \
: (type)_cffi_to_c_i64(o)) : \
(Py_FatalError("unsupported size for type " #type), (type)0)))
#define _cffi_to_c_i8 \
((int(*)(PyObject *))_cffi_exports[1])
#define _cffi_to_c_u8 \
((int(*)(PyObject *))_cffi_exports[2])
#define _cffi_to_c_i16 \
((int(*)(PyObject *))_cffi_exports[3])
#define _cffi_to_c_u16 \
((int(*)(PyObject *))_cffi_exports[4])
#define _cffi_to_c_i32 \
((int(*)(PyObject *))_cffi_exports[5])
#define _cffi_to_c_u32 \
((unsigned int(*)(PyObject *))_cffi_exports[6])
#define _cffi_to_c_i64 \
((long long(*)(PyObject *))_cffi_exports[7])
#define _cffi_to_c_u64 \
((unsigned long long(*)(PyObject *))_cffi_exports[8])
#define _cffi_to_c_char \
((int(*)(PyObject *))_cffi_exports[9])
#define _cffi_from_c_pointer \
((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[10])
#define _cffi_to_c_pointer \
((char *(*)(PyObject *, struct _cffi_ctypedescr *))_cffi_exports[11])
#define _cffi_get_struct_layout \
not used any more
#define _cffi_restore_errno \
((void(*)(void))_cffi_exports[13])
#define _cffi_save_errno \
((void(*)(void))_cffi_exports[14])
#define _cffi_from_c_char \
((PyObject *(*)(char))_cffi_exports[15])
#define _cffi_from_c_deref \
((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[16])
#define _cffi_to_c \
((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[17])
#define _cffi_from_c_struct \
((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[18])
#define _cffi_to_c_wchar_t \
((_cffi_wchar_t(*)(PyObject *))_cffi_exports[19])
#define _cffi_from_c_wchar_t \
((PyObject *(*)(_cffi_wchar_t))_cffi_exports[20])
#define _cffi_to_c_long_double \
((long double(*)(PyObject *))_cffi_exports[21])
#define _cffi_to_c__Bool \
((_Bool(*)(PyObject *))_cffi_exports[22])
#define _cffi_prepare_pointer_call_argument \
((Py_ssize_t(*)(struct _cffi_ctypedescr *, \
PyObject *, char **))_cffi_exports[23])
#define _cffi_convert_array_from_object \
((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[24])
#define _CFFI_CPIDX 25
#define _cffi_call_python \
((void(*)(struct _cffi_externpy_s *, char *))_cffi_exports[_CFFI_CPIDX])
#define _cffi_to_c_wchar3216_t \
((int(*)(PyObject *))_cffi_exports[26])
#define _cffi_from_c_wchar3216_t \
((PyObject *(*)(int))_cffi_exports[27])
#define _CFFI_NUM_EXPORTS 28
struct _cffi_ctypedescr;
static void *_cffi_exports[_CFFI_NUM_EXPORTS];
#define _cffi_type(index) ( \
assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \
(struct _cffi_ctypedescr *)_cffi_types[index])
static PyObject *_cffi_init(const char *module_name, Py_ssize_t version,
const struct _cffi_type_context_s *ctx)
{
PyObject *module, *o_arg, *new_module;
void *raw[] = {
(void *)module_name,
(void *)version,
(void *)_cffi_exports,
(void *)ctx,
};
module = PyImport_ImportModule("_cffi_backend");
if (module == NULL)
goto failure;
o_arg = PyLong_FromVoidPtr((void *)raw);
if (o_arg == NULL)
goto failure;
new_module = PyObject_CallMethod(
module, (char *)"_init_cffi_1_0_external_module", (char *)"O", o_arg);
Py_DECREF(o_arg);
Py_DECREF(module);
return new_module;
failure:
Py_XDECREF(module);
return NULL;
}
#ifdef HAVE_WCHAR_H
typedef wchar_t _cffi_wchar_t;
#else
typedef uint16_t _cffi_wchar_t; /* same random pick as _cffi_backend.c */
#endif
_CFFI_UNUSED_FN static uint16_t _cffi_to_c_char16_t(PyObject *o)
{
if (sizeof(_cffi_wchar_t) == 2)
return (uint16_t)_cffi_to_c_wchar_t(o);
else
return (uint16_t)_cffi_to_c_wchar3216_t(o);
}
_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char16_t(uint16_t x)
{
if (sizeof(_cffi_wchar_t) == 2)
return _cffi_from_c_wchar_t((_cffi_wchar_t)x);
else
return _cffi_from_c_wchar3216_t((int)x);
}
_CFFI_UNUSED_FN static int _cffi_to_c_char32_t(PyObject *o)
{
if (sizeof(_cffi_wchar_t) == 4)
return (int)_cffi_to_c_wchar_t(o);
else
return (int)_cffi_to_c_wchar3216_t(o);
}
_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char32_t(int x)
{
if (sizeof(_cffi_wchar_t) == 4)
return _cffi_from_c_wchar_t((_cffi_wchar_t)x);
else
return _cffi_from_c_wchar3216_t(x);
}
/********** end CPython-specific section **********/
#else
_CFFI_UNUSED_FN
static void (*_cffi_call_python_org)(struct _cffi_externpy_s *, char *);
# define _cffi_call_python _cffi_call_python_org
#endif
#define _cffi_array_len(array) (sizeof(array) / sizeof((array)[0]))
#define _cffi_prim_int(size, sign) \
((size) == 1 ? ((sign) ? _CFFI_PRIM_INT8 : _CFFI_PRIM_UINT8) : \
(size) == 2 ? ((sign) ? _CFFI_PRIM_INT16 : _CFFI_PRIM_UINT16) : \
(size) == 4 ? ((sign) ? _CFFI_PRIM_INT32 : _CFFI_PRIM_UINT32) : \
(size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \
_CFFI__UNKNOWN_PRIM)
#define _cffi_prim_float(size) \
((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \
(size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \
(size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \
_CFFI__UNKNOWN_FLOAT_PRIM)
#define _cffi_check_int(got, got_nonpos, expected) \
((got_nonpos) == (expected <= 0) && \
(got) == (unsigned long long)expected)
#ifdef MS_WIN32
# define _cffi_stdcall __stdcall
#else
# define _cffi_stdcall /* nothing */
#endif
#ifdef __cplusplus
}
#endif
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/_embedding.h
================================================
/***** Support code for embedding *****/
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_WIN32)
# define CFFI_DLLEXPORT __declspec(dllexport)
#elif defined(__GNUC__)
# define CFFI_DLLEXPORT __attribute__((visibility("default")))
#else
# define CFFI_DLLEXPORT /* nothing */
#endif
/* There are two global variables of type _cffi_call_python_fnptr:
* _cffi_call_python, which we declare just below, is the one called
by ``extern "Python"`` implementations.
* _cffi_call_python_org, which on CPython is actually part of the
_cffi_exports[] array, is the function pointer copied from
_cffi_backend.
After initialization is complete, both are equal. However, the
first one remains equal to &_cffi_start_and_call_python until the
very end of initialization, when we are (or should be) sure that
concurrent threads also see a completely initialized world, and
only then is it changed.
*/
#undef _cffi_call_python
typedef void (*_cffi_call_python_fnptr)(struct _cffi_externpy_s *, char *);
static void _cffi_start_and_call_python(struct _cffi_externpy_s *, char *);
static _cffi_call_python_fnptr _cffi_call_python = &_cffi_start_and_call_python;
#ifndef _MSC_VER
/* --- Assuming a GCC not infinitely old --- */
# define cffi_compare_and_swap(l,o,n) __sync_bool_compare_and_swap(l,o,n)
# define cffi_write_barrier() __sync_synchronize()
# if !defined(__amd64__) && !defined(__x86_64__) && \
!defined(__i386__) && !defined(__i386)
# define cffi_read_barrier() __sync_synchronize()
# else
# define cffi_read_barrier() (void)0
# endif
#else
/* --- Windows threads version --- */
# include
# define cffi_compare_and_swap(l,o,n) \
(InterlockedCompareExchangePointer(l,n,o) == (o))
# define cffi_write_barrier() InterlockedCompareExchange(&_cffi_dummy,0,0)
# define cffi_read_barrier() (void)0
static volatile LONG _cffi_dummy;
#endif
#ifdef WITH_THREAD
# ifndef _MSC_VER
# include
static pthread_mutex_t _cffi_embed_startup_lock;
# else
static CRITICAL_SECTION _cffi_embed_startup_lock;
# endif
static char _cffi_embed_startup_lock_ready = 0;
#endif
static void _cffi_acquire_reentrant_mutex(void)
{
static void *volatile lock = NULL;
while (!cffi_compare_and_swap(&lock, NULL, (void *)1)) {
/* should ideally do a spin loop instruction here, but
hard to do it portably and doesn't really matter I
think: pthread_mutex_init() should be very fast, and
this is only run at start-up anyway. */
}
#ifdef WITH_THREAD
if (!_cffi_embed_startup_lock_ready) {
# ifndef _MSC_VER
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&_cffi_embed_startup_lock, &attr);
# else
InitializeCriticalSection(&_cffi_embed_startup_lock);
# endif
_cffi_embed_startup_lock_ready = 1;
}
#endif
while (!cffi_compare_and_swap(&lock, (void *)1, NULL))
;
#ifndef _MSC_VER
pthread_mutex_lock(&_cffi_embed_startup_lock);
#else
EnterCriticalSection(&_cffi_embed_startup_lock);
#endif
}
static void _cffi_release_reentrant_mutex(void)
{
#ifndef _MSC_VER
pthread_mutex_unlock(&_cffi_embed_startup_lock);
#else
LeaveCriticalSection(&_cffi_embed_startup_lock);
#endif
}
/********** CPython-specific section **********/
#ifndef PYPY_VERSION
#include "_cffi_errors.h"
#define _cffi_call_python_org _cffi_exports[_CFFI_CPIDX]
PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(void); /* forward */
static void _cffi_py_initialize(void)
{
/* XXX use initsigs=0, which "skips initialization registration of
signal handlers, which might be useful when Python is
embedded" according to the Python docs. But review and think
if it should be a user-controllable setting.
XXX we should also give a way to write errors to a buffer
instead of to stderr.
XXX if importing 'site' fails, CPython (any version) calls
exit(). Should we try to work around this behavior here?
*/
Py_InitializeEx(0);
}
static int _cffi_initialize_python(void)
{
/* This initializes Python, imports _cffi_backend, and then the
present .dll/.so is set up as a CPython C extension module.
*/
int result;
PyGILState_STATE state;
PyObject *pycode=NULL, *global_dict=NULL, *x;
PyObject *builtins;
state = PyGILState_Ensure();
/* Call the initxxx() function from the present module. It will
create and initialize us as a CPython extension module, instead
of letting the startup Python code do it---it might reimport
the same .dll/.so and get maybe confused on some platforms.
It might also have troubles locating the .dll/.so again for all
I know.
*/
(void)_CFFI_PYTHON_STARTUP_FUNC();
if (PyErr_Occurred())
goto error;
/* Now run the Python code provided to ffi.embedding_init_code().
*/
pycode = Py_CompileString(_CFFI_PYTHON_STARTUP_CODE,
"",
Py_file_input);
if (pycode == NULL)
goto error;
global_dict = PyDict_New();
if (global_dict == NULL)
goto error;
builtins = PyEval_GetBuiltins();
if (builtins == NULL)
goto error;
if (PyDict_SetItemString(global_dict, "__builtins__", builtins) < 0)
goto error;
x = PyEval_EvalCode(
#if PY_MAJOR_VERSION < 3
(PyCodeObject *)
#endif
pycode, global_dict, global_dict);
if (x == NULL)
goto error;
Py_DECREF(x);
/* Done! Now if we've been called from
_cffi_start_and_call_python() in an ``extern "Python"``, we can
only hope that the Python code did correctly set up the
corresponding @ffi.def_extern() function. Otherwise, the
general logic of ``extern "Python"`` functions (inside the
_cffi_backend module) will find that the reference is still
missing and print an error.
*/
result = 0;
done:
Py_XDECREF(pycode);
Py_XDECREF(global_dict);
PyGILState_Release(state);
return result;
error:;
{
/* Print as much information as potentially useful.
Debugging load-time failures with embedding is not fun
*/
PyObject *ecap;
PyObject *exception, *v, *tb, *f, *modules, *mod;
PyErr_Fetch(&exception, &v, &tb);
ecap = _cffi_start_error_capture();
f = PySys_GetObject((char *)"stderr");
if (f != NULL && f != Py_None) {
PyFile_WriteString(
"Failed to initialize the Python-CFFI embedding logic:\n\n", f);
}
if (exception != NULL) {
PyErr_NormalizeException(&exception, &v, &tb);
PyErr_Display(exception, v, tb);
}
Py_XDECREF(exception);
Py_XDECREF(v);
Py_XDECREF(tb);
if (f != NULL && f != Py_None) {
PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
"\ncompiled with cffi version: 1.13.1"
"\n_cffi_backend module: ", f);
modules = PyImport_GetModuleDict();
mod = PyDict_GetItemString(modules, "_cffi_backend");
if (mod == NULL) {
PyFile_WriteString("not loaded", f);
}
else {
v = PyObject_GetAttrString(mod, "__file__");
PyFile_WriteObject(v, f, 0);
Py_XDECREF(v);
}
PyFile_WriteString("\nsys.path: ", f);
PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0);
PyFile_WriteString("\n\n", f);
}
_cffi_stop_error_capture(ecap);
}
result = -1;
goto done;
}
PyAPI_DATA(char *) _PyParser_TokenNames[]; /* from CPython */
static int _cffi_carefully_make_gil(void)
{
/* This does the basic initialization of Python. It can be called
completely concurrently from unrelated threads. It assumes
that we don't hold the GIL before (if it exists), and we don't
hold it afterwards.
(What it really does used to be completely different in Python 2
and Python 3, with the Python 2 solution avoiding the spin-lock
around the Py_InitializeEx() call. However, after recent changes
to CPython 2.7 (issue #358) it no longer works. So we use the
Python 3 solution everywhere.)
This initializes Python by calling Py_InitializeEx().
Important: this must not be called concurrently at all.
So we use a global variable as a simple spin lock. This global
variable must be from 'libpythonX.Y.so', not from this
cffi-based extension module, because it must be shared from
different cffi-based extension modules.
In Python < 3.8, we choose
_PyParser_TokenNames[0] as a completely arbitrary pointer value
that is never written to. The default is to point to the
string "ENDMARKER". We change it temporarily to point to the
next character in that string. (Yes, I know it's REALLY
obscure.)
In Python >= 3.8, this string array is no longer writable, so
instead we pick PyCapsuleType.tp_version_tag. We can't change
Python < 3.8 because someone might use a mixture of cffi
embedded modules, some of which were compiled before this file
changed.
*/
#ifdef WITH_THREAD
# if PY_VERSION_HEX < 0x03080000
char *volatile *lock = (char *volatile *)_PyParser_TokenNames;
char *old_value, *locked_value;
while (1) { /* spin loop */
old_value = *lock;
locked_value = old_value + 1;
if (old_value[0] == 'E') {
assert(old_value[1] == 'N');
if (cffi_compare_and_swap(lock, old_value, locked_value))
break;
}
else {
assert(old_value[0] == 'N');
/* should ideally do a spin loop instruction here, but
hard to do it portably and doesn't really matter I
think: PyEval_InitThreads() should be very fast, and
this is only run at start-up anyway. */
}
}
# else
int volatile *lock = (int volatile *)&PyCapsule_Type.tp_version_tag;
int old_value, locked_value;
assert(!(PyCapsule_Type.tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG));
while (1) { /* spin loop */
old_value = *lock;
locked_value = -42;
if (old_value == 0) {
if (cffi_compare_and_swap(lock, old_value, locked_value))
break;
}
else {
assert(old_value == locked_value);
/* should ideally do a spin loop instruction here, but
hard to do it portably and doesn't really matter I
think: PyEval_InitThreads() should be very fast, and
this is only run at start-up anyway. */
}
}
# endif
#endif
/* call Py_InitializeEx() */
if (!Py_IsInitialized()) {
_cffi_py_initialize();
PyEval_InitThreads();
PyEval_SaveThread(); /* release the GIL */
/* the returned tstate must be the one that has been stored into the
autoTLSkey by _PyGILState_Init() called from Py_Initialize(). */
}
else {
PyGILState_STATE state = PyGILState_Ensure();
PyEval_InitThreads();
PyGILState_Release(state);
}
#ifdef WITH_THREAD
/* release the lock */
while (!cffi_compare_and_swap(lock, locked_value, old_value))
;
#endif
return 0;
}
/********** end CPython-specific section **********/
#else
/********** PyPy-specific section **********/
PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]); /* forward */
static struct _cffi_pypy_init_s {
const char *name;
void (*func)(const void *[]);
const char *code;
} _cffi_pypy_init = {
_CFFI_MODULE_NAME,
(void(*)(const void *[]))_CFFI_PYTHON_STARTUP_FUNC,
_CFFI_PYTHON_STARTUP_CODE,
};
extern int pypy_carefully_make_gil(const char *);
extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *);
static int _cffi_carefully_make_gil(void)
{
return pypy_carefully_make_gil(_CFFI_MODULE_NAME);
}
static int _cffi_initialize_python(void)
{
return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init);
}
/********** end PyPy-specific section **********/
#endif
#ifdef __GNUC__
__attribute__((noinline))
#endif
static _cffi_call_python_fnptr _cffi_start_python(void)
{
/* Delicate logic to initialize Python. This function can be
called multiple times concurrently, e.g. when the process calls
its first ``extern "Python"`` functions in multiple threads at
once. It can also be called recursively, in which case we must
ignore it. We also have to consider what occurs if several
different cffi-based extensions reach this code in parallel
threads---it is a different copy of the code, then, and we
can't have any shared global variable unless it comes from
'libpythonX.Y.so'.
Idea:
* _cffi_carefully_make_gil(): "carefully" call
PyEval_InitThreads() (possibly with Py_InitializeEx() first).
* then we use a (local) custom lock to make sure that a call to this
cffi-based extension will wait if another call to the *same*
extension is running the initialization in another thread.
It is reentrant, so that a recursive call will not block, but
only one from a different thread.
* then we grab the GIL and (Python 2) we call Py_InitializeEx().
At this point, concurrent calls to Py_InitializeEx() are not
possible: we have the GIL.
* do the rest of the specific initialization, which may
temporarily release the GIL but not the custom lock.
Only release the custom lock when we are done.
*/
static char called = 0;
if (_cffi_carefully_make_gil() != 0)
return NULL;
_cffi_acquire_reentrant_mutex();
/* Here the GIL exists, but we don't have it. We're only protected
from concurrency by the reentrant mutex. */
/* This file only initializes the embedded module once, the first
time this is called, even if there are subinterpreters. */
if (!called) {
called = 1; /* invoke _cffi_initialize_python() only once,
but don't set '_cffi_call_python' right now,
otherwise concurrent threads won't call
this function at all (we need them to wait) */
if (_cffi_initialize_python() == 0) {
/* now initialization is finished. Switch to the fast-path. */
/* We would like nobody to see the new value of
'_cffi_call_python' without also seeing the rest of the
data initialized. However, this is not possible. But
the new value of '_cffi_call_python' is the function
'cffi_call_python()' from _cffi_backend. So: */
cffi_write_barrier();
/* ^^^ we put a write barrier here, and a corresponding
read barrier at the start of cffi_call_python(). This
ensures that after that read barrier, we see everything
done here before the write barrier.
*/
assert(_cffi_call_python_org != NULL);
_cffi_call_python = (_cffi_call_python_fnptr)_cffi_call_python_org;
}
else {
/* initialization failed. Reset this to NULL, even if it was
already set to some other value. Future calls to
_cffi_start_python() are still forced to occur, and will
always return NULL from now on. */
_cffi_call_python_org = NULL;
}
}
_cffi_release_reentrant_mutex();
return (_cffi_call_python_fnptr)_cffi_call_python_org;
}
static
void _cffi_start_and_call_python(struct _cffi_externpy_s *externpy, char *args)
{
_cffi_call_python_fnptr fnptr;
int current_err = errno;
#ifdef _MSC_VER
int current_lasterr = GetLastError();
#endif
fnptr = _cffi_start_python();
if (fnptr == NULL) {
fprintf(stderr, "function %s() called, but initialization code "
"failed. Returning 0.\n", externpy->name);
memset(args, 0, externpy->size_of_result);
}
#ifdef _MSC_VER
SetLastError(current_lasterr);
#endif
errno = current_err;
if (fnptr != NULL)
fnptr(externpy, args);
}
/* The cffi_start_python() function makes sure Python is initialized
and our cffi module is set up. It can be called manually from the
user C code. The same effect is obtained automatically from any
dll-exported ``extern "Python"`` function. This function returns
-1 if initialization failed, 0 if all is OK. */
_CFFI_UNUSED_FN
static int cffi_start_python(void)
{
if (_cffi_call_python == &_cffi_start_and_call_python) {
if (_cffi_start_python() == NULL)
return -1;
}
cffi_read_barrier();
return 0;
}
#undef cffi_compare_and_swap
#undef cffi_write_barrier
#undef cffi_read_barrier
#ifdef __cplusplus
}
#endif
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/api.py
================================================
import sys, types
from .lock import allocate_lock
from .error import CDefError
from . import model
try:
callable
except NameError:
# Python 3.1
from collections import Callable
callable = lambda x: isinstance(x, Callable)
try:
basestring
except NameError:
# Python 3.x
basestring = str
_unspecified = object()
class FFI(object):
r'''
The main top-level class that you instantiate once, or once per module.
Example usage:
ffi = FFI()
ffi.cdef("""
int printf(const char *, ...);
""")
C = ffi.dlopen(None) # standard library
-or-
C = ffi.verify() # use a C compiler: verify the decl above is right
C.printf("hello, %s!\n", ffi.new("char[]", "world"))
'''
def __init__(self, backend=None):
"""Create an FFI instance. The 'backend' argument is used to
select a non-default backend, mostly for tests.
"""
if backend is None:
# You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with
# _cffi_backend.so compiled.
import _cffi_backend as backend
from . import __version__
if backend.__version__ != __version__:
# bad version! Try to be as explicit as possible.
if hasattr(backend, '__file__'):
# CPython
raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. When we import the top-level '_cffi_backend' extension module, we get version %s, located in %r. The two versions should be equal; check your installation." % (
__version__, __file__,
backend.__version__, backend.__file__))
else:
# PyPy
raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. This interpreter comes with a built-in '_cffi_backend' module, which is version %s. The two versions should be equal; check your installation." % (
__version__, __file__, backend.__version__))
# (If you insist you can also try to pass the option
# 'backend=backend_ctypes.CTypesBackend()', but don't
# rely on it! It's probably not going to work well.)
from . import cparser
self._backend = backend
self._lock = allocate_lock()
self._parser = cparser.Parser()
self._cached_btypes = {}
self._parsed_types = types.ModuleType('parsed_types').__dict__
self._new_types = types.ModuleType('new_types').__dict__
self._function_caches = []
self._libraries = []
self._cdefsources = []
self._included_ffis = []
self._windows_unicode = None
self._init_once_cache = {}
self._cdef_version = None
self._embedding = None
self._typecache = model.get_typecache(backend)
if hasattr(backend, 'set_ffi'):
backend.set_ffi(self)
for name in list(backend.__dict__):
if name.startswith('RTLD_'):
setattr(self, name, getattr(backend, name))
#
with self._lock:
self.BVoidP = self._get_cached_btype(model.voidp_type)
self.BCharA = self._get_cached_btype(model.char_array_type)
if isinstance(backend, types.ModuleType):
# _cffi_backend: attach these constants to the class
if not hasattr(FFI, 'NULL'):
FFI.NULL = self.cast(self.BVoidP, 0)
FFI.CData, FFI.CType = backend._get_types()
else:
# ctypes backend: attach these constants to the instance
self.NULL = self.cast(self.BVoidP, 0)
self.CData, self.CType = backend._get_types()
self.buffer = backend.buffer
def cdef(self, csource, override=False, packed=False, pack=None):
"""Parse the given C source. This registers all declared functions,
types, and global variables. The functions and global variables can
then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'.
The types can be used in 'ffi.new()' and other functions.
If 'packed' is specified as True, all structs declared inside this
cdef are packed, i.e. laid out without any field alignment at all.
Alternatively, 'pack' can be a small integer, and requests for
alignment greater than that are ignored (pack=1 is equivalent to
packed=True).
"""
self._cdef(csource, override=override, packed=packed, pack=pack)
def embedding_api(self, csource, packed=False, pack=None):
self._cdef(csource, packed=packed, pack=pack, dllexport=True)
if self._embedding is None:
self._embedding = ''
def _cdef(self, csource, override=False, **options):
if not isinstance(csource, str): # unicode, on Python 2
if not isinstance(csource, basestring):
raise TypeError("cdef() argument must be a string")
csource = csource.encode('ascii')
with self._lock:
self._cdef_version = object()
self._parser.parse(csource, override=override, **options)
self._cdefsources.append(csource)
if override:
for cache in self._function_caches:
cache.clear()
finishlist = self._parser._recomplete
if finishlist:
self._parser._recomplete = []
for tp in finishlist:
tp.finish_backend_type(self, finishlist)
def dlopen(self, name, flags=0):
"""Load and return a dynamic library identified by 'name'.
The standard C library can be loaded by passing None.
Note that functions and types declared by 'ffi.cdef()' are not
linked to a particular library, just like C headers; in the
library we only look for the actual (untyped) symbols.
"""
assert isinstance(name, basestring) or name is None
with self._lock:
lib, function_cache = _make_ffi_library(self, name, flags)
self._function_caches.append(function_cache)
self._libraries.append(lib)
return lib
def dlclose(self, lib):
"""Close a library obtained with ffi.dlopen(). After this call,
access to functions or variables from the library will fail
(possibly with a segmentation fault).
"""
type(lib).__cffi_close__(lib)
def _typeof_locked(self, cdecl):
# call me with the lock!
key = cdecl
if key in self._parsed_types:
return self._parsed_types[key]
#
if not isinstance(cdecl, str): # unicode, on Python 2
cdecl = cdecl.encode('ascii')
#
type = self._parser.parse_type(cdecl)
really_a_function_type = type.is_raw_function
if really_a_function_type:
type = type.as_function_pointer()
btype = self._get_cached_btype(type)
result = btype, really_a_function_type
self._parsed_types[key] = result
return result
def _typeof(self, cdecl, consider_function_as_funcptr=False):
# string -> ctype object
try:
result = self._parsed_types[cdecl]
except KeyError:
with self._lock:
result = self._typeof_locked(cdecl)
#
btype, really_a_function_type = result
if really_a_function_type and not consider_function_as_funcptr:
raise CDefError("the type %r is a function type, not a "
"pointer-to-function type" % (cdecl,))
return btype
def typeof(self, cdecl):
"""Parse the C type given as a string and return the
corresponding object.
It can also be used on 'cdata' instance to get its C type.
"""
if isinstance(cdecl, basestring):
return self._typeof(cdecl)
if isinstance(cdecl, self.CData):
return self._backend.typeof(cdecl)
if isinstance(cdecl, types.BuiltinFunctionType):
res = _builtin_function_type(cdecl)
if res is not None:
return res
if (isinstance(cdecl, types.FunctionType)
and hasattr(cdecl, '_cffi_base_type')):
with self._lock:
return self._get_cached_btype(cdecl._cffi_base_type)
raise TypeError(type(cdecl))
def sizeof(self, cdecl):
"""Return the size in bytes of the argument. It can be a
string naming a C type, or a 'cdata' instance.
"""
if isinstance(cdecl, basestring):
BType = self._typeof(cdecl)
return self._backend.sizeof(BType)
else:
return self._backend.sizeof(cdecl)
def alignof(self, cdecl):
"""Return the natural alignment size in bytes of the C type
given as a string.
"""
if isinstance(cdecl, basestring):
cdecl = self._typeof(cdecl)
return self._backend.alignof(cdecl)
def offsetof(self, cdecl, *fields_or_indexes):
"""Return the offset of the named field inside the given
structure or array, which must be given as a C type name.
You can give several field names in case of nested structures.
You can also give numeric values which correspond to array
items, in case of an array type.
"""
if isinstance(cdecl, basestring):
cdecl = self._typeof(cdecl)
return self._typeoffsetof(cdecl, *fields_or_indexes)[1]
def new(self, cdecl, init=None):
"""Allocate an instance according to the specified C type and
return a pointer to it. The specified C type must be either a
pointer or an array: ``new('X *')`` allocates an X and returns
a pointer to it, whereas ``new('X[n]')`` allocates an array of
n X'es and returns an array referencing it (which works
mostly like a pointer, like in C). You can also use
``new('X[]', n)`` to allocate an array of a non-constant
length n.
The memory is initialized following the rules of declaring a
global variable in C: by default it is zero-initialized, but
an explicit initializer can be given which can be used to
fill all or part of the memory.
When the returned object goes out of scope, the memory
is freed. In other words the returned object has
ownership of the value of type 'cdecl' that it points to. This
means that the raw data can be used as long as this object is
kept alive, but must not be used for a longer time. Be careful
about that when copying the pointer to the memory somewhere
else, e.g. into another structure.
"""
if isinstance(cdecl, basestring):
cdecl = self._typeof(cdecl)
return self._backend.newp(cdecl, init)
def new_allocator(self, alloc=None, free=None,
should_clear_after_alloc=True):
"""Return a new allocator, i.e. a function that behaves like ffi.new()
but uses the provided low-level 'alloc' and 'free' functions.
'alloc' is called with the size as argument. If it returns NULL, a
MemoryError is raised. 'free' is called with the result of 'alloc'
as argument. Both can be either Python function or directly C
functions. If 'free' is None, then no free function is called.
If both 'alloc' and 'free' are None, the default is used.
If 'should_clear_after_alloc' is set to False, then the memory
returned by 'alloc' is assumed to be already cleared (or you are
fine with garbage); otherwise CFFI will clear it.
"""
compiled_ffi = self._backend.FFI()
allocator = compiled_ffi.new_allocator(alloc, free,
should_clear_after_alloc)
def allocate(cdecl, init=None):
if isinstance(cdecl, basestring):
cdecl = self._typeof(cdecl)
return allocator(cdecl, init)
return allocate
def cast(self, cdecl, source):
"""Similar to a C cast: returns an instance of the named C
type initialized with the given 'source'. The source is
casted between integers or pointers of any type.
"""
if isinstance(cdecl, basestring):
cdecl = self._typeof(cdecl)
return self._backend.cast(cdecl, source)
def string(self, cdata, maxlen=-1):
"""Return a Python string (or unicode string) from the 'cdata'.
If 'cdata' is a pointer or array of characters or bytes, returns
the null-terminated string. The returned string extends until
the first null character, or at most 'maxlen' characters. If
'cdata' is an array then 'maxlen' defaults to its length.
If 'cdata' is a pointer or array of wchar_t, returns a unicode
string following the same rules.
If 'cdata' is a single character or byte or a wchar_t, returns
it as a string or unicode string.
If 'cdata' is an enum, returns the value of the enumerator as a
string, or 'NUMBER' if the value is out of range.
"""
return self._backend.string(cdata, maxlen)
def unpack(self, cdata, length):
"""Unpack an array of C data of the given length,
returning a Python string/unicode/list.
If 'cdata' is a pointer to 'char', returns a byte string.
It does not stop at the first null. This is equivalent to:
ffi.buffer(cdata, length)[:]
If 'cdata' is a pointer to 'wchar_t', returns a unicode string.
'length' is measured in wchar_t's; it is not the size in bytes.
If 'cdata' is a pointer to anything else, returns a list of
'length' items. This is a faster equivalent to:
[cdata[i] for i in range(length)]
"""
return self._backend.unpack(cdata, length)
#def buffer(self, cdata, size=-1):
# """Return a read-write buffer object that references the raw C data
# pointed to by the given 'cdata'. The 'cdata' must be a pointer or
# an array. Can be passed to functions expecting a buffer, or directly
# manipulated with:
#
# buf[:] get a copy of it in a regular string, or
# buf[idx] as a single character
# buf[:] = ...
# buf[idx] = ... change the content
# """
# note that 'buffer' is a type, set on this instance by __init__
def from_buffer(self, cdecl, python_buffer=_unspecified,
require_writable=False):
"""Return a cdata of the given type pointing to the data of the
given Python object, which must support the buffer interface.
Note that this is not meant to be used on the built-in types
str or unicode (you can build 'char[]' arrays explicitly)
but only on objects containing large quantities of raw data
in some other format, like 'array.array' or numpy arrays.
The first argument is optional and default to 'char[]'.
"""
if python_buffer is _unspecified:
cdecl, python_buffer = self.BCharA, cdecl
elif isinstance(cdecl, basestring):
cdecl = self._typeof(cdecl)
return self._backend.from_buffer(cdecl, python_buffer,
require_writable)
def memmove(self, dest, src, n):
"""ffi.memmove(dest, src, n) copies n bytes of memory from src to dest.
Like the C function memmove(), the memory areas may overlap;
apart from that it behaves like the C function memcpy().
'src' can be any cdata ptr or array, or any Python buffer object.
'dest' can be any cdata ptr or array, or a writable Python buffer
object. The size to copy, 'n', is always measured in bytes.
Unlike other methods, this one supports all Python buffer including
byte strings and bytearrays---but it still does not support
non-contiguous buffers.
"""
return self._backend.memmove(dest, src, n)
def callback(self, cdecl, python_callable=None, error=None, onerror=None):
"""Return a callback object or a decorator making such a
callback object. 'cdecl' must name a C function pointer type.
The callback invokes the specified 'python_callable' (which may
be provided either directly or via a decorator). Important: the
callback object must be manually kept alive for as long as the
callback may be invoked from the C level.
"""
def callback_decorator_wrap(python_callable):
if not callable(python_callable):
raise TypeError("the 'python_callable' argument "
"is not callable")
return self._backend.callback(cdecl, python_callable,
error, onerror)
if isinstance(cdecl, basestring):
cdecl = self._typeof(cdecl, consider_function_as_funcptr=True)
if python_callable is None:
return callback_decorator_wrap # decorator mode
else:
return callback_decorator_wrap(python_callable) # direct mode
def getctype(self, cdecl, replace_with=''):
"""Return a string giving the C type 'cdecl', which may be itself
a string or a object. If 'replace_with' is given, it gives
extra text to append (or insert for more complicated C types), like
a variable name, or '*' to get actually the C type 'pointer-to-cdecl'.
"""
if isinstance(cdecl, basestring):
cdecl = self._typeof(cdecl)
replace_with = replace_with.strip()
if (replace_with.startswith('*')
and '&[' in self._backend.getcname(cdecl, '&')):
replace_with = '(%s)' % replace_with
elif replace_with and not replace_with[0] in '[(':
replace_with = ' ' + replace_with
return self._backend.getcname(cdecl, replace_with)
def gc(self, cdata, destructor, size=0):
"""Return a new cdata object that points to the same
data. Later, when this new cdata object is garbage-collected,
'destructor(old_cdata_object)' will be called.
The optional 'size' gives an estimate of the size, used to
trigger the garbage collection more eagerly. So far only used
on PyPy. It tells the GC that the returned object keeps alive
roughly 'size' bytes of external memory.
"""
return self._backend.gcp(cdata, destructor, size)
def _get_cached_btype(self, type):
assert self._lock.acquire(False) is False
# call me with the lock!
try:
BType = self._cached_btypes[type]
except KeyError:
finishlist = []
BType = type.get_cached_btype(self, finishlist)
for type in finishlist:
type.finish_backend_type(self, finishlist)
return BType
def verify(self, source='', tmpdir=None, **kwargs):
"""Verify that the current ffi signatures compile on this
machine, and return a dynamic library object. The dynamic
library can be used to call functions and access global
variables declared in this 'ffi'. The library is compiled
by the C compiler: it gives you C-level API compatibility
(including calling macros). This is unlike 'ffi.dlopen()',
which requires binary compatibility in the signatures.
"""
from .verifier import Verifier, _caller_dir_pycache
#
# If set_unicode(True) was called, insert the UNICODE and
# _UNICODE macro declarations
if self._windows_unicode:
self._apply_windows_unicode(kwargs)
#
# Set the tmpdir here, and not in Verifier.__init__: it picks
# up the caller's directory, which we want to be the caller of
# ffi.verify(), as opposed to the caller of Veritier().
tmpdir = tmpdir or _caller_dir_pycache()
#
# Make a Verifier() and use it to load the library.
self.verifier = Verifier(self, source, tmpdir, **kwargs)
lib = self.verifier.load_library()
#
# Save the loaded library for keep-alive purposes, even
# if the caller doesn't keep it alive itself (it should).
self._libraries.append(lib)
return lib
def _get_errno(self):
return self._backend.get_errno()
def _set_errno(self, errno):
self._backend.set_errno(errno)
errno = property(_get_errno, _set_errno, None,
"the value of 'errno' from/to the C calls")
def getwinerror(self, code=-1):
return self._backend.getwinerror(code)
def _pointer_to(self, ctype):
with self._lock:
return model.pointer_cache(self, ctype)
def addressof(self, cdata, *fields_or_indexes):
"""Return the address of a .
If 'fields_or_indexes' are given, returns the address of that
field or array item in the structure or array, recursively in
case of nested structures.
"""
try:
ctype = self._backend.typeof(cdata)
except TypeError:
if '__addressof__' in type(cdata).__dict__:
return type(cdata).__addressof__(cdata, *fields_or_indexes)
raise
if fields_or_indexes:
ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes)
else:
if ctype.kind == "pointer":
raise TypeError("addressof(pointer)")
offset = 0
ctypeptr = self._pointer_to(ctype)
return self._backend.rawaddressof(ctypeptr, cdata, offset)
def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes):
ctype, offset = self._backend.typeoffsetof(ctype, field_or_index)
for field1 in fields_or_indexes:
ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1)
offset += offset1
return ctype, offset
def include(self, ffi_to_include):
"""Includes the typedefs, structs, unions and enums defined
in another FFI instance. Usage is similar to a #include in C,
where a part of the program might include types defined in
another part for its own usage. Note that the include()
method has no effect on functions, constants and global
variables, which must anyway be accessed directly from the
lib object returned by the original FFI instance.
"""
if not isinstance(ffi_to_include, FFI):
raise TypeError("ffi.include() expects an argument that is also of"
" type cffi.FFI, not %r" % (
type(ffi_to_include).__name__,))
if ffi_to_include is self:
raise ValueError("self.include(self)")
with ffi_to_include._lock:
with self._lock:
self._parser.include(ffi_to_include._parser)
self._cdefsources.append('[')
self._cdefsources.extend(ffi_to_include._cdefsources)
self._cdefsources.append(']')
self._included_ffis.append(ffi_to_include)
def new_handle(self, x):
return self._backend.newp_handle(self.BVoidP, x)
def from_handle(self, x):
return self._backend.from_handle(x)
def release(self, x):
self._backend.release(x)
def set_unicode(self, enabled_flag):
"""Windows: if 'enabled_flag' is True, enable the UNICODE and
_UNICODE defines in C, and declare the types like TCHAR and LPTCSTR
to be (pointers to) wchar_t. If 'enabled_flag' is False,
declare these types to be (pointers to) plain 8-bit characters.
This is mostly for backward compatibility; you usually want True.
"""
if self._windows_unicode is not None:
raise ValueError("set_unicode() can only be called once")
enabled_flag = bool(enabled_flag)
if enabled_flag:
self.cdef("typedef wchar_t TBYTE;"
"typedef wchar_t TCHAR;"
"typedef const wchar_t *LPCTSTR;"
"typedef const wchar_t *PCTSTR;"
"typedef wchar_t *LPTSTR;"
"typedef wchar_t *PTSTR;"
"typedef TBYTE *PTBYTE;"
"typedef TCHAR *PTCHAR;")
else:
self.cdef("typedef char TBYTE;"
"typedef char TCHAR;"
"typedef const char *LPCTSTR;"
"typedef const char *PCTSTR;"
"typedef char *LPTSTR;"
"typedef char *PTSTR;"
"typedef TBYTE *PTBYTE;"
"typedef TCHAR *PTCHAR;")
self._windows_unicode = enabled_flag
def _apply_windows_unicode(self, kwds):
defmacros = kwds.get('define_macros', ())
if not isinstance(defmacros, (list, tuple)):
raise TypeError("'define_macros' must be a list or tuple")
defmacros = list(defmacros) + [('UNICODE', '1'),
('_UNICODE', '1')]
kwds['define_macros'] = defmacros
def _apply_embedding_fix(self, kwds):
# must include an argument like "-lpython2.7" for the compiler
def ensure(key, value):
lst = kwds.setdefault(key, [])
if value not in lst:
lst.append(value)
#
if '__pypy__' in sys.builtin_module_names:
import os
if sys.platform == "win32":
# we need 'libpypy-c.lib'. Current distributions of
# pypy (>= 4.1) contain it as 'libs/python27.lib'.
pythonlib = "python{0[0]}{0[1]}".format(sys.version_info)
if hasattr(sys, 'prefix'):
ensure('library_dirs', os.path.join(sys.prefix, 'libs'))
else:
# we need 'libpypy-c.{so,dylib}', which should be by
# default located in 'sys.prefix/bin' for installed
# systems.
if sys.version_info < (3,):
pythonlib = "pypy-c"
else:
pythonlib = "pypy3-c"
if hasattr(sys, 'prefix'):
ensure('library_dirs', os.path.join(sys.prefix, 'bin'))
# On uninstalled pypy's, the libpypy-c is typically found in
# .../pypy/goal/.
if hasattr(sys, 'prefix'):
ensure('library_dirs', os.path.join(sys.prefix, 'pypy', 'goal'))
else:
if sys.platform == "win32":
template = "python%d%d"
if hasattr(sys, 'gettotalrefcount'):
template += '_d'
else:
try:
import sysconfig
except ImportError: # 2.6
from distutils import sysconfig
template = "python%d.%d"
if sysconfig.get_config_var('DEBUG_EXT'):
template += sysconfig.get_config_var('DEBUG_EXT')
pythonlib = (template %
(sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
if hasattr(sys, 'abiflags'):
pythonlib += sys.abiflags
ensure('libraries', pythonlib)
if sys.platform == "win32":
ensure('extra_link_args', '/MANIFEST')
def set_source(self, module_name, source, source_extension='.c', **kwds):
import os
if hasattr(self, '_assigned_source'):
raise ValueError("set_source() cannot be called several times "
"per ffi object")
if not isinstance(module_name, basestring):
raise TypeError("'module_name' must be a string")
if os.sep in module_name or (os.altsep and os.altsep in module_name):
raise ValueError("'module_name' must not contain '/': use a dotted "
"name to make a 'package.module' location")
self._assigned_source = (str(module_name), source,
source_extension, kwds)
def set_source_pkgconfig(self, module_name, pkgconfig_libs, source,
source_extension='.c', **kwds):
from . import pkgconfig
if not isinstance(pkgconfig_libs, list):
raise TypeError("the pkgconfig_libs argument must be a list "
"of package names")
kwds2 = pkgconfig.flags_from_pkgconfig(pkgconfig_libs)
pkgconfig.merge_flags(kwds, kwds2)
self.set_source(module_name, source, source_extension, **kwds)
def distutils_extension(self, tmpdir='build', verbose=True):
from distutils.dir_util import mkpath
from .recompiler import recompile
#
if not hasattr(self, '_assigned_source'):
if hasattr(self, 'verifier'): # fallback, 'tmpdir' ignored
return self.verifier.get_extension()
raise ValueError("set_source() must be called before"
" distutils_extension()")
module_name, source, source_extension, kwds = self._assigned_source
if source is None:
raise TypeError("distutils_extension() is only for C extension "
"modules, not for dlopen()-style pure Python "
"modules")
mkpath(tmpdir)
ext, updated = recompile(self, module_name,
source, tmpdir=tmpdir, extradir=tmpdir,
source_extension=source_extension,
call_c_compiler=False, **kwds)
if verbose:
if updated:
sys.stderr.write("regenerated: %r\n" % (ext.sources[0],))
else:
sys.stderr.write("not modified: %r\n" % (ext.sources[0],))
return ext
def emit_c_code(self, filename):
from .recompiler import recompile
#
if not hasattr(self, '_assigned_source'):
raise ValueError("set_source() must be called before emit_c_code()")
module_name, source, source_extension, kwds = self._assigned_source
if source is None:
raise TypeError("emit_c_code() is only for C extension modules, "
"not for dlopen()-style pure Python modules")
recompile(self, module_name, source,
c_file=filename, call_c_compiler=False, **kwds)
def emit_python_code(self, filename):
from .recompiler import recompile
#
if not hasattr(self, '_assigned_source'):
raise ValueError("set_source() must be called before emit_c_code()")
module_name, source, source_extension, kwds = self._assigned_source
if source is not None:
raise TypeError("emit_python_code() is only for dlopen()-style "
"pure Python modules, not for C extension modules")
recompile(self, module_name, source,
c_file=filename, call_c_compiler=False, **kwds)
def compile(self, tmpdir='.', verbose=0, target=None, debug=None):
"""The 'target' argument gives the final file name of the
compiled DLL. Use '*' to force distutils' choice, suitable for
regular CPython C API modules. Use a file name ending in '.*'
to ask for the system's default extension for dynamic libraries
(.so/.dll/.dylib).
The default is '*' when building a non-embedded C API extension,
and (module_name + '.*') when building an embedded library.
"""
from .recompiler import recompile
#
if not hasattr(self, '_assigned_source'):
raise ValueError("set_source() must be called before compile()")
module_name, source, source_extension, kwds = self._assigned_source
return recompile(self, module_name, source, tmpdir=tmpdir,
target=target, source_extension=source_extension,
compiler_verbose=verbose, debug=debug, **kwds)
def init_once(self, func, tag):
# Read _init_once_cache[tag], which is either (False, lock) if
# we're calling the function now in some thread, or (True, result).
# Don't call setdefault() in most cases, to avoid allocating and
# immediately freeing a lock; but still use setdefaut() to avoid
# races.
try:
x = self._init_once_cache[tag]
except KeyError:
x = self._init_once_cache.setdefault(tag, (False, allocate_lock()))
# Common case: we got (True, result), so we return the result.
if x[0]:
return x[1]
# Else, it's a lock. Acquire it to serialize the following tests.
with x[1]:
# Read again from _init_once_cache the current status.
x = self._init_once_cache[tag]
if x[0]:
return x[1]
# Call the function and store the result back.
result = func()
self._init_once_cache[tag] = (True, result)
return result
def embedding_init_code(self, pysource):
if self._embedding:
raise ValueError("embedding_init_code() can only be called once")
# fix 'pysource' before it gets dumped into the C file:
# - remove empty lines at the beginning, so it starts at "line 1"
# - dedent, if all non-empty lines are indented
# - check for SyntaxErrors
import re
match = re.match(r'\s*\n', pysource)
if match:
pysource = pysource[match.end():]
lines = pysource.splitlines() or ['']
prefix = re.match(r'\s*', lines[0]).group()
for i in range(1, len(lines)):
line = lines[i]
if line.rstrip():
while not line.startswith(prefix):
prefix = prefix[:-1]
i = len(prefix)
lines = [line[i:]+'\n' for line in lines]
pysource = ''.join(lines)
#
compile(pysource, "cffi_init", "exec")
#
self._embedding = pysource
def def_extern(self, *args, **kwds):
raise ValueError("ffi.def_extern() is only available on API-mode FFI "
"objects")
def list_types(self):
"""Returns the user type names known to this FFI instance.
This returns a tuple containing three lists of names:
(typedef_names, names_of_structs, names_of_unions)
"""
typedefs = []
structs = []
unions = []
for key in self._parser._declarations:
if key.startswith('typedef '):
typedefs.append(key[8:])
elif key.startswith('struct '):
structs.append(key[7:])
elif key.startswith('union '):
unions.append(key[6:])
typedefs.sort()
structs.sort()
unions.sort()
return (typedefs, structs, unions)
def _load_backend_lib(backend, name, flags):
import os
if name is None:
if sys.platform != "win32":
return backend.load_library(None, flags)
name = "c" # Windows: load_library(None) fails, but this works
# on Python 2 (backward compatibility hack only)
first_error = None
if '.' in name or '/' in name or os.sep in name:
try:
return backend.load_library(name, flags)
except OSError as e:
first_error = e
import ctypes.util
path = ctypes.util.find_library(name)
if path is None:
if name == "c" and sys.platform == "win32" and sys.version_info >= (3,):
raise OSError("dlopen(None) cannot work on Windows for Python 3 "
"(see http://bugs.python.org/issue23606)")
msg = ("ctypes.util.find_library() did not manage "
"to locate a library called %r" % (name,))
if first_error is not None:
msg = "%s. Additionally, %s" % (first_error, msg)
raise OSError(msg)
return backend.load_library(path, flags)
def _make_ffi_library(ffi, libname, flags):
backend = ffi._backend
backendlib = _load_backend_lib(backend, libname, flags)
#
def accessor_function(name):
key = 'function ' + name
tp, _ = ffi._parser._declarations[key]
BType = ffi._get_cached_btype(tp)
value = backendlib.load_function(BType, name)
library.__dict__[name] = value
#
def accessor_variable(name):
key = 'variable ' + name
tp, _ = ffi._parser._declarations[key]
BType = ffi._get_cached_btype(tp)
read_variable = backendlib.read_variable
write_variable = backendlib.write_variable
setattr(FFILibrary, name, property(
lambda self: read_variable(BType, name),
lambda self, value: write_variable(BType, name, value)))
#
def addressof_var(name):
try:
return addr_variables[name]
except KeyError:
with ffi._lock:
if name not in addr_variables:
key = 'variable ' + name
tp, _ = ffi._parser._declarations[key]
BType = ffi._get_cached_btype(tp)
if BType.kind != 'array':
BType = model.pointer_cache(ffi, BType)
p = backendlib.load_function(BType, name)
addr_variables[name] = p
return addr_variables[name]
#
def accessor_constant(name):
raise NotImplementedError("non-integer constant '%s' cannot be "
"accessed from a dlopen() library" % (name,))
#
def accessor_int_constant(name):
library.__dict__[name] = ffi._parser._int_constants[name]
#
accessors = {}
accessors_version = [False]
addr_variables = {}
#
def update_accessors():
if accessors_version[0] is ffi._cdef_version:
return
#
for key, (tp, _) in ffi._parser._declarations.items():
if not isinstance(tp, model.EnumType):
tag, name = key.split(' ', 1)
if tag == 'function':
accessors[name] = accessor_function
elif tag == 'variable':
accessors[name] = accessor_variable
elif tag == 'constant':
accessors[name] = accessor_constant
else:
for i, enumname in enumerate(tp.enumerators):
def accessor_enum(name, tp=tp, i=i):
tp.check_not_partial()
library.__dict__[name] = tp.enumvalues[i]
accessors[enumname] = accessor_enum
for name in ffi._parser._int_constants:
accessors.setdefault(name, accessor_int_constant)
accessors_version[0] = ffi._cdef_version
#
def make_accessor(name):
with ffi._lock:
if name in library.__dict__ or name in FFILibrary.__dict__:
return # added by another thread while waiting for the lock
if name not in accessors:
update_accessors()
if name not in accessors:
raise AttributeError(name)
accessors[name](name)
#
class FFILibrary(object):
def __getattr__(self, name):
make_accessor(name)
return getattr(self, name)
def __setattr__(self, name, value):
try:
property = getattr(self.__class__, name)
except AttributeError:
make_accessor(name)
setattr(self, name, value)
else:
property.__set__(self, value)
def __dir__(self):
with ffi._lock:
update_accessors()
return accessors.keys()
def __addressof__(self, name):
if name in library.__dict__:
return library.__dict__[name]
if name in FFILibrary.__dict__:
return addressof_var(name)
make_accessor(name)
if name in library.__dict__:
return library.__dict__[name]
if name in FFILibrary.__dict__:
return addressof_var(name)
raise AttributeError("cffi library has no function or "
"global variable named '%s'" % (name,))
def __cffi_close__(self):
backendlib.close_lib()
self.__dict__.clear()
#
if libname is not None:
try:
if not isinstance(libname, str): # unicode, on Python 2
libname = libname.encode('utf-8')
FFILibrary.__name__ = 'FFILibrary_%s' % libname
except UnicodeError:
pass
library = FFILibrary()
return library, library.__dict__
def _builtin_function_type(func):
# a hack to make at least ffi.typeof(builtin_function) work,
# if the builtin function was obtained by 'vengine_cpy'.
import sys
try:
module = sys.modules[func.__module__]
ffi = module._cffi_original_ffi
types_of_builtin_funcs = module._cffi_types_of_builtin_funcs
tp = types_of_builtin_funcs[func]
except (KeyError, AttributeError, TypeError):
return None
else:
with ffi._lock:
return ffi._get_cached_btype(tp)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/backend_ctypes.py
================================================
import ctypes, ctypes.util, operator, sys
from . import model
if sys.version_info < (3,):
bytechr = chr
else:
unicode = str
long = int
xrange = range
bytechr = lambda num: bytes([num])
class CTypesType(type):
pass
class CTypesData(object):
__metaclass__ = CTypesType
__slots__ = ['__weakref__']
__name__ = ''
def __init__(self, *args):
raise TypeError("cannot instantiate %r" % (self.__class__,))
@classmethod
def _newp(cls, init):
raise TypeError("expected a pointer or array ctype, got '%s'"
% (cls._get_c_name(),))
@staticmethod
def _to_ctypes(value):
raise TypeError
@classmethod
def _arg_to_ctypes(cls, *value):
try:
ctype = cls._ctype
except AttributeError:
raise TypeError("cannot create an instance of %r" % (cls,))
if value:
res = cls._to_ctypes(*value)
if not isinstance(res, ctype):
res = cls._ctype(res)
else:
res = cls._ctype()
return res
@classmethod
def _create_ctype_obj(cls, init):
if init is None:
return cls._arg_to_ctypes()
else:
return cls._arg_to_ctypes(init)
@staticmethod
def _from_ctypes(ctypes_value):
raise TypeError
@classmethod
def _get_c_name(cls, replace_with=''):
return cls._reftypename.replace(' &', replace_with)
@classmethod
def _fix_class(cls):
cls.__name__ = 'CData<%s>' % (cls._get_c_name(),)
cls.__qualname__ = 'CData<%s>' % (cls._get_c_name(),)
cls.__module__ = 'ffi'
def _get_own_repr(self):
raise NotImplementedError
def _addr_repr(self, address):
if address == 0:
return 'NULL'
else:
if address < 0:
address += 1 << (8*ctypes.sizeof(ctypes.c_void_p))
return '0x%x' % address
def __repr__(self, c_name=None):
own = self._get_own_repr()
return '' % (c_name or self._get_c_name(), own)
def _convert_to_address(self, BClass):
if BClass is None:
raise TypeError("cannot convert %r to an address" % (
self._get_c_name(),))
else:
raise TypeError("cannot convert %r to %r" % (
self._get_c_name(), BClass._get_c_name()))
@classmethod
def _get_size(cls):
return ctypes.sizeof(cls._ctype)
def _get_size_of_instance(self):
return ctypes.sizeof(self._ctype)
@classmethod
def _cast_from(cls, source):
raise TypeError("cannot cast to %r" % (cls._get_c_name(),))
def _cast_to_integer(self):
return self._convert_to_address(None)
@classmethod
def _alignment(cls):
return ctypes.alignment(cls._ctype)
def __iter__(self):
raise TypeError("cdata %r does not support iteration" % (
self._get_c_name()),)
def _make_cmp(name):
cmpfunc = getattr(operator, name)
def cmp(self, other):
v_is_ptr = not isinstance(self, CTypesGenericPrimitive)
w_is_ptr = (isinstance(other, CTypesData) and
not isinstance(other, CTypesGenericPrimitive))
if v_is_ptr and w_is_ptr:
return cmpfunc(self._convert_to_address(None),
other._convert_to_address(None))
elif v_is_ptr or w_is_ptr:
return NotImplemented
else:
if isinstance(self, CTypesGenericPrimitive):
self = self._value
if isinstance(other, CTypesGenericPrimitive):
other = other._value
return cmpfunc(self, other)
cmp.func_name = name
return cmp
__eq__ = _make_cmp('__eq__')
__ne__ = _make_cmp('__ne__')
__lt__ = _make_cmp('__lt__')
__le__ = _make_cmp('__le__')
__gt__ = _make_cmp('__gt__')
__ge__ = _make_cmp('__ge__')
def __hash__(self):
return hash(self._convert_to_address(None))
def _to_string(self, maxlen):
raise TypeError("string(): %r" % (self,))
class CTypesGenericPrimitive(CTypesData):
__slots__ = []
def __hash__(self):
return hash(self._value)
def _get_own_repr(self):
return repr(self._from_ctypes(self._value))
class CTypesGenericArray(CTypesData):
__slots__ = []
@classmethod
def _newp(cls, init):
return cls(init)
def __iter__(self):
for i in xrange(len(self)):
yield self[i]
def _get_own_repr(self):
return self._addr_repr(ctypes.addressof(self._blob))
class CTypesGenericPtr(CTypesData):
__slots__ = ['_address', '_as_ctype_ptr']
_automatic_casts = False
kind = "pointer"
@classmethod
def _newp(cls, init):
return cls(init)
@classmethod
def _cast_from(cls, source):
if source is None:
address = 0
elif isinstance(source, CTypesData):
address = source._cast_to_integer()
elif isinstance(source, (int, long)):
address = source
else:
raise TypeError("bad type for cast to %r: %r" %
(cls, type(source).__name__))
return cls._new_pointer_at(address)
@classmethod
def _new_pointer_at(cls, address):
self = cls.__new__(cls)
self._address = address
self._as_ctype_ptr = ctypes.cast(address, cls._ctype)
return self
def _get_own_repr(self):
try:
return self._addr_repr(self._address)
except AttributeError:
return '???'
def _cast_to_integer(self):
return self._address
def __nonzero__(self):
return bool(self._address)
__bool__ = __nonzero__
@classmethod
def _to_ctypes(cls, value):
if not isinstance(value, CTypesData):
raise TypeError("unexpected %s object" % type(value).__name__)
address = value._convert_to_address(cls)
return ctypes.cast(address, cls._ctype)
@classmethod
def _from_ctypes(cls, ctypes_ptr):
address = ctypes.cast(ctypes_ptr, ctypes.c_void_p).value or 0
return cls._new_pointer_at(address)
@classmethod
def _initialize(cls, ctypes_ptr, value):
if value:
ctypes_ptr.contents = cls._to_ctypes(value).contents
def _convert_to_address(self, BClass):
if (BClass in (self.__class__, None) or BClass._automatic_casts
or self._automatic_casts):
return self._address
else:
return CTypesData._convert_to_address(self, BClass)
class CTypesBaseStructOrUnion(CTypesData):
__slots__ = ['_blob']
@classmethod
def _create_ctype_obj(cls, init):
# may be overridden
raise TypeError("cannot instantiate opaque type %s" % (cls,))
def _get_own_repr(self):
return self._addr_repr(ctypes.addressof(self._blob))
@classmethod
def _offsetof(cls, fieldname):
return getattr(cls._ctype, fieldname).offset
def _convert_to_address(self, BClass):
if getattr(BClass, '_BItem', None) is self.__class__:
return ctypes.addressof(self._blob)
else:
return CTypesData._convert_to_address(self, BClass)
@classmethod
def _from_ctypes(cls, ctypes_struct_or_union):
self = cls.__new__(cls)
self._blob = ctypes_struct_or_union
return self
@classmethod
def _to_ctypes(cls, value):
return value._blob
def __repr__(self, c_name=None):
return CTypesData.__repr__(self, c_name or self._get_c_name(' &'))
class CTypesBackend(object):
PRIMITIVE_TYPES = {
'char': ctypes.c_char,
'short': ctypes.c_short,
'int': ctypes.c_int,
'long': ctypes.c_long,
'long long': ctypes.c_longlong,
'signed char': ctypes.c_byte,
'unsigned char': ctypes.c_ubyte,
'unsigned short': ctypes.c_ushort,
'unsigned int': ctypes.c_uint,
'unsigned long': ctypes.c_ulong,
'unsigned long long': ctypes.c_ulonglong,
'float': ctypes.c_float,
'double': ctypes.c_double,
'_Bool': ctypes.c_bool,
}
for _name in ['unsigned long long', 'unsigned long',
'unsigned int', 'unsigned short', 'unsigned char']:
_size = ctypes.sizeof(PRIMITIVE_TYPES[_name])
PRIMITIVE_TYPES['uint%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name]
if _size == ctypes.sizeof(ctypes.c_void_p):
PRIMITIVE_TYPES['uintptr_t'] = PRIMITIVE_TYPES[_name]
if _size == ctypes.sizeof(ctypes.c_size_t):
PRIMITIVE_TYPES['size_t'] = PRIMITIVE_TYPES[_name]
for _name in ['long long', 'long', 'int', 'short', 'signed char']:
_size = ctypes.sizeof(PRIMITIVE_TYPES[_name])
PRIMITIVE_TYPES['int%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name]
if _size == ctypes.sizeof(ctypes.c_void_p):
PRIMITIVE_TYPES['intptr_t'] = PRIMITIVE_TYPES[_name]
PRIMITIVE_TYPES['ptrdiff_t'] = PRIMITIVE_TYPES[_name]
if _size == ctypes.sizeof(ctypes.c_size_t):
PRIMITIVE_TYPES['ssize_t'] = PRIMITIVE_TYPES[_name]
def __init__(self):
self.RTLD_LAZY = 0 # not supported anyway by ctypes
self.RTLD_NOW = 0
self.RTLD_GLOBAL = ctypes.RTLD_GLOBAL
self.RTLD_LOCAL = ctypes.RTLD_LOCAL
def set_ffi(self, ffi):
self.ffi = ffi
def _get_types(self):
return CTypesData, CTypesType
def load_library(self, path, flags=0):
cdll = ctypes.CDLL(path, flags)
return CTypesLibrary(self, cdll)
def new_void_type(self):
class CTypesVoid(CTypesData):
__slots__ = []
_reftypename = 'void &'
@staticmethod
def _from_ctypes(novalue):
return None
@staticmethod
def _to_ctypes(novalue):
if novalue is not None:
raise TypeError("None expected, got %s object" %
(type(novalue).__name__,))
return None
CTypesVoid._fix_class()
return CTypesVoid
def new_primitive_type(self, name):
if name == 'wchar_t':
raise NotImplementedError(name)
ctype = self.PRIMITIVE_TYPES[name]
if name == 'char':
kind = 'char'
elif name in ('float', 'double'):
kind = 'float'
else:
if name in ('signed char', 'unsigned char'):
kind = 'byte'
elif name == '_Bool':
kind = 'bool'
else:
kind = 'int'
is_signed = (ctype(-1).value == -1)
#
def _cast_source_to_int(source):
if isinstance(source, (int, long, float)):
source = int(source)
elif isinstance(source, CTypesData):
source = source._cast_to_integer()
elif isinstance(source, bytes):
source = ord(source)
elif source is None:
source = 0
else:
raise TypeError("bad type for cast to %r: %r" %
(CTypesPrimitive, type(source).__name__))
return source
#
kind1 = kind
class CTypesPrimitive(CTypesGenericPrimitive):
__slots__ = ['_value']
_ctype = ctype
_reftypename = '%s &' % name
kind = kind1
def __init__(self, value):
self._value = value
@staticmethod
def _create_ctype_obj(init):
if init is None:
return ctype()
return ctype(CTypesPrimitive._to_ctypes(init))
if kind == 'int' or kind == 'byte':
@classmethod
def _cast_from(cls, source):
source = _cast_source_to_int(source)
source = ctype(source).value # cast within range
return cls(source)
def __int__(self):
return self._value
if kind == 'bool':
@classmethod
def _cast_from(cls, source):
if not isinstance(source, (int, long, float)):
source = _cast_source_to_int(source)
return cls(bool(source))
def __int__(self):
return int(self._value)
if kind == 'char':
@classmethod
def _cast_from(cls, source):
source = _cast_source_to_int(source)
source = bytechr(source & 0xFF)
return cls(source)
def __int__(self):
return ord(self._value)
if kind == 'float':
@classmethod
def _cast_from(cls, source):
if isinstance(source, float):
pass
elif isinstance(source, CTypesGenericPrimitive):
if hasattr(source, '__float__'):
source = float(source)
else:
source = int(source)
else:
source = _cast_source_to_int(source)
source = ctype(source).value # fix precision
return cls(source)
def __int__(self):
return int(self._value)
def __float__(self):
return self._value
_cast_to_integer = __int__
if kind == 'int' or kind == 'byte' or kind == 'bool':
@staticmethod
def _to_ctypes(x):
if not isinstance(x, (int, long)):
if isinstance(x, CTypesData):
x = int(x)
else:
raise TypeError("integer expected, got %s" %
type(x).__name__)
if ctype(x).value != x:
if not is_signed and x < 0:
raise OverflowError("%s: negative integer" % name)
else:
raise OverflowError("%s: integer out of bounds"
% name)
return x
if kind == 'char':
@staticmethod
def _to_ctypes(x):
if isinstance(x, bytes) and len(x) == 1:
return x
if isinstance(x, CTypesPrimitive): # >
return x._value
raise TypeError("character expected, got %s" %
type(x).__name__)
def __nonzero__(self):
return ord(self._value) != 0
else:
def __nonzero__(self):
return self._value != 0
__bool__ = __nonzero__
if kind == 'float':
@staticmethod
def _to_ctypes(x):
if not isinstance(x, (int, long, float, CTypesData)):
raise TypeError("float expected, got %s" %
type(x).__name__)
return ctype(x).value
@staticmethod
def _from_ctypes(value):
return getattr(value, 'value', value)
@staticmethod
def _initialize(blob, init):
blob.value = CTypesPrimitive._to_ctypes(init)
if kind == 'char':
def _to_string(self, maxlen):
return self._value
if kind == 'byte':
def _to_string(self, maxlen):
return chr(self._value & 0xff)
#
CTypesPrimitive._fix_class()
return CTypesPrimitive
def new_pointer_type(self, BItem):
getbtype = self.ffi._get_cached_btype
if BItem is getbtype(model.PrimitiveType('char')):
kind = 'charp'
elif BItem in (getbtype(model.PrimitiveType('signed char')),
getbtype(model.PrimitiveType('unsigned char'))):
kind = 'bytep'
elif BItem is getbtype(model.void_type):
kind = 'voidp'
else:
kind = 'generic'
#
class CTypesPtr(CTypesGenericPtr):
__slots__ = ['_own']
if kind == 'charp':
__slots__ += ['__as_strbuf']
_BItem = BItem
if hasattr(BItem, '_ctype'):
_ctype = ctypes.POINTER(BItem._ctype)
_bitem_size = ctypes.sizeof(BItem._ctype)
else:
_ctype = ctypes.c_void_p
if issubclass(BItem, CTypesGenericArray):
_reftypename = BItem._get_c_name('(* &)')
else:
_reftypename = BItem._get_c_name(' * &')
def __init__(self, init):
ctypeobj = BItem._create_ctype_obj(init)
if kind == 'charp':
self.__as_strbuf = ctypes.create_string_buffer(
ctypeobj.value + b'\x00')
self._as_ctype_ptr = ctypes.cast(
self.__as_strbuf, self._ctype)
else:
self._as_ctype_ptr = ctypes.pointer(ctypeobj)
self._address = ctypes.cast(self._as_ctype_ptr,
ctypes.c_void_p).value
self._own = True
def __add__(self, other):
if isinstance(other, (int, long)):
return self._new_pointer_at(self._address +
other * self._bitem_size)
else:
return NotImplemented
def __sub__(self, other):
if isinstance(other, (int, long)):
return self._new_pointer_at(self._address -
other * self._bitem_size)
elif type(self) is type(other):
return (self._address - other._address) // self._bitem_size
else:
return NotImplemented
def __getitem__(self, index):
if getattr(self, '_own', False) and index != 0:
raise IndexError
return BItem._from_ctypes(self._as_ctype_ptr[index])
def __setitem__(self, index, value):
self._as_ctype_ptr[index] = BItem._to_ctypes(value)
if kind == 'charp' or kind == 'voidp':
@classmethod
def _arg_to_ctypes(cls, *value):
if value and isinstance(value[0], bytes):
return ctypes.c_char_p(value[0])
else:
return super(CTypesPtr, cls)._arg_to_ctypes(*value)
if kind == 'charp' or kind == 'bytep':
def _to_string(self, maxlen):
if maxlen < 0:
maxlen = sys.maxsize
p = ctypes.cast(self._as_ctype_ptr,
ctypes.POINTER(ctypes.c_char))
n = 0
while n < maxlen and p[n] != b'\x00':
n += 1
return b''.join([p[i] for i in range(n)])
def _get_own_repr(self):
if getattr(self, '_own', False):
return 'owning %d bytes' % (
ctypes.sizeof(self._as_ctype_ptr.contents),)
return super(CTypesPtr, self)._get_own_repr()
#
if (BItem is self.ffi._get_cached_btype(model.void_type) or
BItem is self.ffi._get_cached_btype(model.PrimitiveType('char'))):
CTypesPtr._automatic_casts = True
#
CTypesPtr._fix_class()
return CTypesPtr
def new_array_type(self, CTypesPtr, length):
if length is None:
brackets = ' &[]'
else:
brackets = ' &[%d]' % length
BItem = CTypesPtr._BItem
getbtype = self.ffi._get_cached_btype
if BItem is getbtype(model.PrimitiveType('char')):
kind = 'char'
elif BItem in (getbtype(model.PrimitiveType('signed char')),
getbtype(model.PrimitiveType('unsigned char'))):
kind = 'byte'
else:
kind = 'generic'
#
class CTypesArray(CTypesGenericArray):
__slots__ = ['_blob', '_own']
if length is not None:
_ctype = BItem._ctype * length
else:
__slots__.append('_ctype')
_reftypename = BItem._get_c_name(brackets)
_declared_length = length
_CTPtr = CTypesPtr
def __init__(self, init):
if length is None:
if isinstance(init, (int, long)):
len1 = init
init = None
elif kind == 'char' and isinstance(init, bytes):
len1 = len(init) + 1 # extra null
else:
init = tuple(init)
len1 = len(init)
self._ctype = BItem._ctype * len1
self._blob = self._ctype()
self._own = True
if init is not None:
self._initialize(self._blob, init)
@staticmethod
def _initialize(blob, init):
if isinstance(init, bytes):
init = [init[i:i+1] for i in range(len(init))]
else:
if isinstance(init, CTypesGenericArray):
if (len(init) != len(blob) or
not isinstance(init, CTypesArray)):
raise TypeError("length/type mismatch: %s" % (init,))
init = tuple(init)
if len(init) > len(blob):
raise IndexError("too many initializers")
addr = ctypes.cast(blob, ctypes.c_void_p).value
PTR = ctypes.POINTER(BItem._ctype)
itemsize = ctypes.sizeof(BItem._ctype)
for i, value in enumerate(init):
p = ctypes.cast(addr + i * itemsize, PTR)
BItem._initialize(p.contents, value)
def __len__(self):
return len(self._blob)
def __getitem__(self, index):
if not (0 <= index < len(self._blob)):
raise IndexError
return BItem._from_ctypes(self._blob[index])
def __setitem__(self, index, value):
if not (0 <= index < len(self._blob)):
raise IndexError
self._blob[index] = BItem._to_ctypes(value)
if kind == 'char' or kind == 'byte':
def _to_string(self, maxlen):
if maxlen < 0:
maxlen = len(self._blob)
p = ctypes.cast(self._blob,
ctypes.POINTER(ctypes.c_char))
n = 0
while n < maxlen and p[n] != b'\x00':
n += 1
return b''.join([p[i] for i in range(n)])
def _get_own_repr(self):
if getattr(self, '_own', False):
return 'owning %d bytes' % (ctypes.sizeof(self._blob),)
return super(CTypesArray, self)._get_own_repr()
def _convert_to_address(self, BClass):
if BClass in (CTypesPtr, None) or BClass._automatic_casts:
return ctypes.addressof(self._blob)
else:
return CTypesData._convert_to_address(self, BClass)
@staticmethod
def _from_ctypes(ctypes_array):
self = CTypesArray.__new__(CTypesArray)
self._blob = ctypes_array
return self
@staticmethod
def _arg_to_ctypes(value):
return CTypesPtr._arg_to_ctypes(value)
def __add__(self, other):
if isinstance(other, (int, long)):
return CTypesPtr._new_pointer_at(
ctypes.addressof(self._blob) +
other * ctypes.sizeof(BItem._ctype))
else:
return NotImplemented
@classmethod
def _cast_from(cls, source):
raise NotImplementedError("casting to %r" % (
cls._get_c_name(),))
#
CTypesArray._fix_class()
return CTypesArray
def _new_struct_or_union(self, kind, name, base_ctypes_class):
#
class struct_or_union(base_ctypes_class):
pass
struct_or_union.__name__ = '%s_%s' % (kind, name)
kind1 = kind
#
class CTypesStructOrUnion(CTypesBaseStructOrUnion):
__slots__ = ['_blob']
_ctype = struct_or_union
_reftypename = '%s &' % (name,)
_kind = kind = kind1
#
CTypesStructOrUnion._fix_class()
return CTypesStructOrUnion
def new_struct_type(self, name):
return self._new_struct_or_union('struct', name, ctypes.Structure)
def new_union_type(self, name):
return self._new_struct_or_union('union', name, ctypes.Union)
def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp,
totalsize=-1, totalalignment=-1, sflags=0,
pack=0):
if totalsize >= 0 or totalalignment >= 0:
raise NotImplementedError("the ctypes backend of CFFI does not support "
"structures completed by verify(); please "
"compile and install the _cffi_backend module.")
struct_or_union = CTypesStructOrUnion._ctype
fnames = [fname for (fname, BField, bitsize) in fields]
btypes = [BField for (fname, BField, bitsize) in fields]
bitfields = [bitsize for (fname, BField, bitsize) in fields]
#
bfield_types = {}
cfields = []
for (fname, BField, bitsize) in fields:
if bitsize < 0:
cfields.append((fname, BField._ctype))
bfield_types[fname] = BField
else:
cfields.append((fname, BField._ctype, bitsize))
bfield_types[fname] = Ellipsis
if sflags & 8:
struct_or_union._pack_ = 1
elif pack:
struct_or_union._pack_ = pack
struct_or_union._fields_ = cfields
CTypesStructOrUnion._bfield_types = bfield_types
#
@staticmethod
def _create_ctype_obj(init):
result = struct_or_union()
if init is not None:
initialize(result, init)
return result
CTypesStructOrUnion._create_ctype_obj = _create_ctype_obj
#
def initialize(blob, init):
if is_union:
if len(init) > 1:
raise ValueError("union initializer: %d items given, but "
"only one supported (use a dict if needed)"
% (len(init),))
if not isinstance(init, dict):
if isinstance(init, (bytes, unicode)):
raise TypeError("union initializer: got a str")
init = tuple(init)
if len(init) > len(fnames):
raise ValueError("too many values for %s initializer" %
CTypesStructOrUnion._get_c_name())
init = dict(zip(fnames, init))
addr = ctypes.addressof(blob)
for fname, value in init.items():
BField, bitsize = name2fieldtype[fname]
assert bitsize < 0, \
"not implemented: initializer with bit fields"
offset = CTypesStructOrUnion._offsetof(fname)
PTR = ctypes.POINTER(BField._ctype)
p = ctypes.cast(addr + offset, PTR)
BField._initialize(p.contents, value)
is_union = CTypesStructOrUnion._kind == 'union'
name2fieldtype = dict(zip(fnames, zip(btypes, bitfields)))
#
for fname, BField, bitsize in fields:
if fname == '':
raise NotImplementedError("nested anonymous structs/unions")
if hasattr(CTypesStructOrUnion, fname):
raise ValueError("the field name %r conflicts in "
"the ctypes backend" % fname)
if bitsize < 0:
def getter(self, fname=fname, BField=BField,
offset=CTypesStructOrUnion._offsetof(fname),
PTR=ctypes.POINTER(BField._ctype)):
addr = ctypes.addressof(self._blob)
p = ctypes.cast(addr + offset, PTR)
return BField._from_ctypes(p.contents)
def setter(self, value, fname=fname, BField=BField):
setattr(self._blob, fname, BField._to_ctypes(value))
#
if issubclass(BField, CTypesGenericArray):
setter = None
if BField._declared_length == 0:
def getter(self, fname=fname, BFieldPtr=BField._CTPtr,
offset=CTypesStructOrUnion._offsetof(fname),
PTR=ctypes.POINTER(BField._ctype)):
addr = ctypes.addressof(self._blob)
p = ctypes.cast(addr + offset, PTR)
return BFieldPtr._from_ctypes(p)
#
else:
def getter(self, fname=fname, BField=BField):
return BField._from_ctypes(getattr(self._blob, fname))
def setter(self, value, fname=fname, BField=BField):
# xxx obscure workaround
value = BField._to_ctypes(value)
oldvalue = getattr(self._blob, fname)
setattr(self._blob, fname, value)
if value != getattr(self._blob, fname):
setattr(self._blob, fname, oldvalue)
raise OverflowError("value too large for bitfield")
setattr(CTypesStructOrUnion, fname, property(getter, setter))
#
CTypesPtr = self.ffi._get_cached_btype(model.PointerType(tp))
for fname in fnames:
if hasattr(CTypesPtr, fname):
raise ValueError("the field name %r conflicts in "
"the ctypes backend" % fname)
def getter(self, fname=fname):
return getattr(self[0], fname)
def setter(self, value, fname=fname):
setattr(self[0], fname, value)
setattr(CTypesPtr, fname, property(getter, setter))
def new_function_type(self, BArgs, BResult, has_varargs):
nameargs = [BArg._get_c_name() for BArg in BArgs]
if has_varargs:
nameargs.append('...')
nameargs = ', '.join(nameargs)
#
class CTypesFunctionPtr(CTypesGenericPtr):
__slots__ = ['_own_callback', '_name']
_ctype = ctypes.CFUNCTYPE(getattr(BResult, '_ctype', None),
*[BArg._ctype for BArg in BArgs],
use_errno=True)
_reftypename = BResult._get_c_name('(* &)(%s)' % (nameargs,))
def __init__(self, init, error=None):
# create a callback to the Python callable init()
import traceback
assert not has_varargs, "varargs not supported for callbacks"
if getattr(BResult, '_ctype', None) is not None:
error = BResult._from_ctypes(
BResult._create_ctype_obj(error))
else:
error = None
def callback(*args):
args2 = []
for arg, BArg in zip(args, BArgs):
args2.append(BArg._from_ctypes(arg))
try:
res2 = init(*args2)
res2 = BResult._to_ctypes(res2)
except:
traceback.print_exc()
res2 = error
if issubclass(BResult, CTypesGenericPtr):
if res2:
res2 = ctypes.cast(res2, ctypes.c_void_p).value
# .value: http://bugs.python.org/issue1574593
else:
res2 = None
#print repr(res2)
return res2
if issubclass(BResult, CTypesGenericPtr):
# The only pointers callbacks can return are void*s:
# http://bugs.python.org/issue5710
callback_ctype = ctypes.CFUNCTYPE(
ctypes.c_void_p,
*[BArg._ctype for BArg in BArgs],
use_errno=True)
else:
callback_ctype = CTypesFunctionPtr._ctype
self._as_ctype_ptr = callback_ctype(callback)
self._address = ctypes.cast(self._as_ctype_ptr,
ctypes.c_void_p).value
self._own_callback = init
@staticmethod
def _initialize(ctypes_ptr, value):
if value:
raise NotImplementedError("ctypes backend: not supported: "
"initializers for function pointers")
def __repr__(self):
c_name = getattr(self, '_name', None)
if c_name:
i = self._reftypename.index('(* &)')
if self._reftypename[i-1] not in ' )*':
c_name = ' ' + c_name
c_name = self._reftypename.replace('(* &)', c_name)
return CTypesData.__repr__(self, c_name)
def _get_own_repr(self):
if getattr(self, '_own_callback', None) is not None:
return 'calling %r' % (self._own_callback,)
return super(CTypesFunctionPtr, self)._get_own_repr()
def __call__(self, *args):
if has_varargs:
assert len(args) >= len(BArgs)
extraargs = args[len(BArgs):]
args = args[:len(BArgs)]
else:
assert len(args) == len(BArgs)
ctypes_args = []
for arg, BArg in zip(args, BArgs):
ctypes_args.append(BArg._arg_to_ctypes(arg))
if has_varargs:
for i, arg in enumerate(extraargs):
if arg is None:
ctypes_args.append(ctypes.c_void_p(0)) # NULL
continue
if not isinstance(arg, CTypesData):
raise TypeError(
"argument %d passed in the variadic part "
"needs to be a cdata object (got %s)" %
(1 + len(BArgs) + i, type(arg).__name__))
ctypes_args.append(arg._arg_to_ctypes(arg))
result = self._as_ctype_ptr(*ctypes_args)
return BResult._from_ctypes(result)
#
CTypesFunctionPtr._fix_class()
return CTypesFunctionPtr
def new_enum_type(self, name, enumerators, enumvalues, CTypesInt):
assert isinstance(name, str)
reverse_mapping = dict(zip(reversed(enumvalues),
reversed(enumerators)))
#
class CTypesEnum(CTypesInt):
__slots__ = []
_reftypename = '%s &' % name
def _get_own_repr(self):
value = self._value
try:
return '%d: %s' % (value, reverse_mapping[value])
except KeyError:
return str(value)
def _to_string(self, maxlen):
value = self._value
try:
return reverse_mapping[value]
except KeyError:
return str(value)
#
CTypesEnum._fix_class()
return CTypesEnum
def get_errno(self):
return ctypes.get_errno()
def set_errno(self, value):
ctypes.set_errno(value)
def string(self, b, maxlen=-1):
return b._to_string(maxlen)
def buffer(self, bptr, size=-1):
raise NotImplementedError("buffer() with ctypes backend")
def sizeof(self, cdata_or_BType):
if isinstance(cdata_or_BType, CTypesData):
return cdata_or_BType._get_size_of_instance()
else:
assert issubclass(cdata_or_BType, CTypesData)
return cdata_or_BType._get_size()
def alignof(self, BType):
assert issubclass(BType, CTypesData)
return BType._alignment()
def newp(self, BType, source):
if not issubclass(BType, CTypesData):
raise TypeError
return BType._newp(source)
def cast(self, BType, source):
return BType._cast_from(source)
def callback(self, BType, source, error, onerror):
assert onerror is None # XXX not implemented
return BType(source, error)
_weakref_cache_ref = None
def gcp(self, cdata, destructor, size=0):
if self._weakref_cache_ref is None:
import weakref
class MyRef(weakref.ref):
def __eq__(self, other):
myref = self()
return self is other or (
myref is not None and myref is other())
def __ne__(self, other):
return not (self == other)
def __hash__(self):
try:
return self._hash
except AttributeError:
self._hash = hash(self())
return self._hash
self._weakref_cache_ref = {}, MyRef
weak_cache, MyRef = self._weakref_cache_ref
if destructor is None:
try:
del weak_cache[MyRef(cdata)]
except KeyError:
raise TypeError("Can remove destructor only on a object "
"previously returned by ffi.gc()")
return None
def remove(k):
cdata, destructor = weak_cache.pop(k, (None, None))
if destructor is not None:
destructor(cdata)
new_cdata = self.cast(self.typeof(cdata), cdata)
assert new_cdata is not cdata
weak_cache[MyRef(new_cdata, remove)] = (cdata, destructor)
return new_cdata
typeof = type
def getcname(self, BType, replace_with):
return BType._get_c_name(replace_with)
def typeoffsetof(self, BType, fieldname, num=0):
if isinstance(fieldname, str):
if num == 0 and issubclass(BType, CTypesGenericPtr):
BType = BType._BItem
if not issubclass(BType, CTypesBaseStructOrUnion):
raise TypeError("expected a struct or union ctype")
BField = BType._bfield_types[fieldname]
if BField is Ellipsis:
raise TypeError("not supported for bitfields")
return (BField, BType._offsetof(fieldname))
elif isinstance(fieldname, (int, long)):
if issubclass(BType, CTypesGenericArray):
BType = BType._CTPtr
if not issubclass(BType, CTypesGenericPtr):
raise TypeError("expected an array or ptr ctype")
BItem = BType._BItem
offset = BItem._get_size() * fieldname
if offset > sys.maxsize:
raise OverflowError
return (BItem, offset)
else:
raise TypeError(type(fieldname))
def rawaddressof(self, BTypePtr, cdata, offset=None):
if isinstance(cdata, CTypesBaseStructOrUnion):
ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata))
elif isinstance(cdata, CTypesGenericPtr):
if offset is None or not issubclass(type(cdata)._BItem,
CTypesBaseStructOrUnion):
raise TypeError("unexpected cdata type")
ptr = type(cdata)._to_ctypes(cdata)
elif isinstance(cdata, CTypesGenericArray):
ptr = type(cdata)._to_ctypes(cdata)
else:
raise TypeError("expected a ")
if offset:
ptr = ctypes.cast(
ctypes.c_void_p(
ctypes.cast(ptr, ctypes.c_void_p).value + offset),
type(ptr))
return BTypePtr._from_ctypes(ptr)
class CTypesLibrary(object):
def __init__(self, backend, cdll):
self.backend = backend
self.cdll = cdll
def load_function(self, BType, name):
c_func = getattr(self.cdll, name)
funcobj = BType._from_ctypes(c_func)
funcobj._name = name
return funcobj
def read_variable(self, BType, name):
try:
ctypes_obj = BType._ctype.in_dll(self.cdll, name)
except AttributeError as e:
raise NotImplementedError(e)
return BType._from_ctypes(ctypes_obj)
def write_variable(self, BType, name, value):
new_ctypes_obj = BType._to_ctypes(value)
ctypes_obj = BType._ctype.in_dll(self.cdll, name)
ctypes.memmove(ctypes.addressof(ctypes_obj),
ctypes.addressof(new_ctypes_obj),
ctypes.sizeof(BType._ctype))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/cffi_opcode.py
================================================
from .error import VerificationError
class CffiOp(object):
def __init__(self, op, arg):
self.op = op
self.arg = arg
def as_c_expr(self):
if self.op is None:
assert isinstance(self.arg, str)
return '(_cffi_opcode_t)(%s)' % (self.arg,)
classname = CLASS_NAME[self.op]
return '_CFFI_OP(_CFFI_OP_%s, %s)' % (classname, self.arg)
def as_python_bytes(self):
if self.op is None and self.arg.isdigit():
value = int(self.arg) # non-negative: '-' not in self.arg
if value >= 2**31:
raise OverflowError("cannot emit %r: limited to 2**31-1"
% (self.arg,))
return format_four_bytes(value)
if isinstance(self.arg, str):
raise VerificationError("cannot emit to Python: %r" % (self.arg,))
return format_four_bytes((self.arg << 8) | self.op)
def __str__(self):
classname = CLASS_NAME.get(self.op, self.op)
return '(%s %s)' % (classname, self.arg)
def format_four_bytes(num):
return '\\x%02X\\x%02X\\x%02X\\x%02X' % (
(num >> 24) & 0xFF,
(num >> 16) & 0xFF,
(num >> 8) & 0xFF,
(num ) & 0xFF)
OP_PRIMITIVE = 1
OP_POINTER = 3
OP_ARRAY = 5
OP_OPEN_ARRAY = 7
OP_STRUCT_UNION = 9
OP_ENUM = 11
OP_FUNCTION = 13
OP_FUNCTION_END = 15
OP_NOOP = 17
OP_BITFIELD = 19
OP_TYPENAME = 21
OP_CPYTHON_BLTN_V = 23 # varargs
OP_CPYTHON_BLTN_N = 25 # noargs
OP_CPYTHON_BLTN_O = 27 # O (i.e. a single arg)
OP_CONSTANT = 29
OP_CONSTANT_INT = 31
OP_GLOBAL_VAR = 33
OP_DLOPEN_FUNC = 35
OP_DLOPEN_CONST = 37
OP_GLOBAL_VAR_F = 39
OP_EXTERN_PYTHON = 41
PRIM_VOID = 0
PRIM_BOOL = 1
PRIM_CHAR = 2
PRIM_SCHAR = 3
PRIM_UCHAR = 4
PRIM_SHORT = 5
PRIM_USHORT = 6
PRIM_INT = 7
PRIM_UINT = 8
PRIM_LONG = 9
PRIM_ULONG = 10
PRIM_LONGLONG = 11
PRIM_ULONGLONG = 12
PRIM_FLOAT = 13
PRIM_DOUBLE = 14
PRIM_LONGDOUBLE = 15
PRIM_WCHAR = 16
PRIM_INT8 = 17
PRIM_UINT8 = 18
PRIM_INT16 = 19
PRIM_UINT16 = 20
PRIM_INT32 = 21
PRIM_UINT32 = 22
PRIM_INT64 = 23
PRIM_UINT64 = 24
PRIM_INTPTR = 25
PRIM_UINTPTR = 26
PRIM_PTRDIFF = 27
PRIM_SIZE = 28
PRIM_SSIZE = 29
PRIM_INT_LEAST8 = 30
PRIM_UINT_LEAST8 = 31
PRIM_INT_LEAST16 = 32
PRIM_UINT_LEAST16 = 33
PRIM_INT_LEAST32 = 34
PRIM_UINT_LEAST32 = 35
PRIM_INT_LEAST64 = 36
PRIM_UINT_LEAST64 = 37
PRIM_INT_FAST8 = 38
PRIM_UINT_FAST8 = 39
PRIM_INT_FAST16 = 40
PRIM_UINT_FAST16 = 41
PRIM_INT_FAST32 = 42
PRIM_UINT_FAST32 = 43
PRIM_INT_FAST64 = 44
PRIM_UINT_FAST64 = 45
PRIM_INTMAX = 46
PRIM_UINTMAX = 47
PRIM_FLOATCOMPLEX = 48
PRIM_DOUBLECOMPLEX = 49
PRIM_CHAR16 = 50
PRIM_CHAR32 = 51
_NUM_PRIM = 52
_UNKNOWN_PRIM = -1
_UNKNOWN_FLOAT_PRIM = -2
_UNKNOWN_LONG_DOUBLE = -3
_IO_FILE_STRUCT = -1
PRIMITIVE_TO_INDEX = {
'char': PRIM_CHAR,
'short': PRIM_SHORT,
'int': PRIM_INT,
'long': PRIM_LONG,
'long long': PRIM_LONGLONG,
'signed char': PRIM_SCHAR,
'unsigned char': PRIM_UCHAR,
'unsigned short': PRIM_USHORT,
'unsigned int': PRIM_UINT,
'unsigned long': PRIM_ULONG,
'unsigned long long': PRIM_ULONGLONG,
'float': PRIM_FLOAT,
'double': PRIM_DOUBLE,
'long double': PRIM_LONGDOUBLE,
'float _Complex': PRIM_FLOATCOMPLEX,
'double _Complex': PRIM_DOUBLECOMPLEX,
'_Bool': PRIM_BOOL,
'wchar_t': PRIM_WCHAR,
'char16_t': PRIM_CHAR16,
'char32_t': PRIM_CHAR32,
'int8_t': PRIM_INT8,
'uint8_t': PRIM_UINT8,
'int16_t': PRIM_INT16,
'uint16_t': PRIM_UINT16,
'int32_t': PRIM_INT32,
'uint32_t': PRIM_UINT32,
'int64_t': PRIM_INT64,
'uint64_t': PRIM_UINT64,
'intptr_t': PRIM_INTPTR,
'uintptr_t': PRIM_UINTPTR,
'ptrdiff_t': PRIM_PTRDIFF,
'size_t': PRIM_SIZE,
'ssize_t': PRIM_SSIZE,
'int_least8_t': PRIM_INT_LEAST8,
'uint_least8_t': PRIM_UINT_LEAST8,
'int_least16_t': PRIM_INT_LEAST16,
'uint_least16_t': PRIM_UINT_LEAST16,
'int_least32_t': PRIM_INT_LEAST32,
'uint_least32_t': PRIM_UINT_LEAST32,
'int_least64_t': PRIM_INT_LEAST64,
'uint_least64_t': PRIM_UINT_LEAST64,
'int_fast8_t': PRIM_INT_FAST8,
'uint_fast8_t': PRIM_UINT_FAST8,
'int_fast16_t': PRIM_INT_FAST16,
'uint_fast16_t': PRIM_UINT_FAST16,
'int_fast32_t': PRIM_INT_FAST32,
'uint_fast32_t': PRIM_UINT_FAST32,
'int_fast64_t': PRIM_INT_FAST64,
'uint_fast64_t': PRIM_UINT_FAST64,
'intmax_t': PRIM_INTMAX,
'uintmax_t': PRIM_UINTMAX,
}
F_UNION = 0x01
F_CHECK_FIELDS = 0x02
F_PACKED = 0x04
F_EXTERNAL = 0x08
F_OPAQUE = 0x10
G_FLAGS = dict([('_CFFI_' + _key, globals()[_key])
for _key in ['F_UNION', 'F_CHECK_FIELDS', 'F_PACKED',
'F_EXTERNAL', 'F_OPAQUE']])
CLASS_NAME = {}
for _name, _value in list(globals().items()):
if _name.startswith('OP_') and isinstance(_value, int):
CLASS_NAME[_value] = _name[3:]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/commontypes.py
================================================
import sys
from . import model
from .error import FFIError
COMMON_TYPES = {}
try:
# fetch "bool" and all simple Windows types
from _cffi_backend import _get_common_types
_get_common_types(COMMON_TYPES)
except ImportError:
pass
COMMON_TYPES['FILE'] = model.unknown_type('FILE', '_IO_FILE')
COMMON_TYPES['bool'] = '_Bool' # in case we got ImportError above
for _type in model.PrimitiveType.ALL_PRIMITIVE_TYPES:
if _type.endswith('_t'):
COMMON_TYPES[_type] = _type
del _type
_CACHE = {}
def resolve_common_type(parser, commontype):
try:
return _CACHE[commontype]
except KeyError:
cdecl = COMMON_TYPES.get(commontype, commontype)
if not isinstance(cdecl, str):
result, quals = cdecl, 0 # cdecl is already a BaseType
elif cdecl in model.PrimitiveType.ALL_PRIMITIVE_TYPES:
result, quals = model.PrimitiveType(cdecl), 0
elif cdecl == 'set-unicode-needed':
raise FFIError("The Windows type %r is only available after "
"you call ffi.set_unicode()" % (commontype,))
else:
if commontype == cdecl:
raise FFIError(
"Unsupported type: %r. Please look at "
"http://cffi.readthedocs.io/en/latest/cdef.html#ffi-cdef-limitations "
"and file an issue if you think this type should really "
"be supported." % (commontype,))
result, quals = parser.parse_type_and_quals(cdecl) # recursive
assert isinstance(result, model.BaseTypeByIdentity)
_CACHE[commontype] = result, quals
return result, quals
# ____________________________________________________________
# extra types for Windows (most of them are in commontypes.c)
def win_common_types():
return {
"UNICODE_STRING": model.StructType(
"_UNICODE_STRING",
["Length",
"MaximumLength",
"Buffer"],
[model.PrimitiveType("unsigned short"),
model.PrimitiveType("unsigned short"),
model.PointerType(model.PrimitiveType("wchar_t"))],
[-1, -1, -1]),
"PUNICODE_STRING": "UNICODE_STRING *",
"PCUNICODE_STRING": "const UNICODE_STRING *",
"TBYTE": "set-unicode-needed",
"TCHAR": "set-unicode-needed",
"LPCTSTR": "set-unicode-needed",
"PCTSTR": "set-unicode-needed",
"LPTSTR": "set-unicode-needed",
"PTSTR": "set-unicode-needed",
"PTBYTE": "set-unicode-needed",
"PTCHAR": "set-unicode-needed",
}
if sys.platform == 'win32':
COMMON_TYPES.update(win_common_types())
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/cparser.py
================================================
from . import model
from .commontypes import COMMON_TYPES, resolve_common_type
from .error import FFIError, CDefError
try:
from . import _pycparser as pycparser
except ImportError:
import pycparser
import weakref, re, sys
try:
if sys.version_info < (3,):
import thread as _thread
else:
import _thread
lock = _thread.allocate_lock()
except ImportError:
lock = None
def _workaround_for_static_import_finders():
# Issue #392: packaging tools like cx_Freeze can not find these
# because pycparser uses exec dynamic import. This is an obscure
# workaround. This function is never called.
import pycparser.yacctab
import pycparser.lextab
CDEF_SOURCE_STRING = ""
_r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$",
re.DOTALL | re.MULTILINE)
_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)"
r"\b((?:[^\n\\]|\\.)*?)$",
re.DOTALL | re.MULTILINE)
_r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}")
_r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$")
_r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]")
_r_words = re.compile(r"\w+|\S")
_parser_cache = None
_r_int_literal = re.compile(r"-?0?x?[0-9a-f]+[lu]*$", re.IGNORECASE)
_r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b")
_r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b")
_r_cdecl = re.compile(r"\b__cdecl\b")
_r_extern_python = re.compile(r'\bextern\s*"'
r'(Python|Python\s*\+\s*C|C\s*\+\s*Python)"\s*.')
_r_star_const_space = re.compile( # matches "* const "
r"[*]\s*((const|volatile|restrict)\b\s*)+")
_r_int_dotdotdot = re.compile(r"(\b(int|long|short|signed|unsigned|char)\s*)+"
r"\.\.\.")
_r_float_dotdotdot = re.compile(r"\b(double|float)\s*\.\.\.")
def _get_parser():
global _parser_cache
if _parser_cache is None:
_parser_cache = pycparser.CParser()
return _parser_cache
def _workaround_for_old_pycparser(csource):
# Workaround for a pycparser issue (fixed between pycparser 2.10 and
# 2.14): "char*const***" gives us a wrong syntax tree, the same as
# for "char***(*const)". This means we can't tell the difference
# afterwards. But "char(*const(***))" gives us the right syntax
# tree. The issue only occurs if there are several stars in
# sequence with no parenthesis inbetween, just possibly qualifiers.
# Attempt to fix it by adding some parentheses in the source: each
# time we see "* const" or "* const *", we add an opening
# parenthesis before each star---the hard part is figuring out where
# to close them.
parts = []
while True:
match = _r_star_const_space.search(csource)
if not match:
break
#print repr(''.join(parts)+csource), '=>',
parts.append(csource[:match.start()])
parts.append('('); closing = ')'
parts.append(match.group()) # e.g. "* const "
endpos = match.end()
if csource.startswith('*', endpos):
parts.append('('); closing += ')'
level = 0
i = endpos
while i < len(csource):
c = csource[i]
if c == '(':
level += 1
elif c == ')':
if level == 0:
break
level -= 1
elif c in ',;=':
if level == 0:
break
i += 1
csource = csource[endpos:i] + closing + csource[i:]
#print repr(''.join(parts)+csource)
parts.append(csource)
return ''.join(parts)
def _preprocess_extern_python(csource):
# input: `extern "Python" int foo(int);` or
# `extern "Python" { int foo(int); }`
# output:
# void __cffi_extern_python_start;
# int foo(int);
# void __cffi_extern_python_stop;
#
# input: `extern "Python+C" int foo(int);`
# output:
# void __cffi_extern_python_plus_c_start;
# int foo(int);
# void __cffi_extern_python_stop;
parts = []
while True:
match = _r_extern_python.search(csource)
if not match:
break
endpos = match.end() - 1
#print
#print ''.join(parts)+csource
#print '=>'
parts.append(csource[:match.start()])
if 'C' in match.group(1):
parts.append('void __cffi_extern_python_plus_c_start; ')
else:
parts.append('void __cffi_extern_python_start; ')
if csource[endpos] == '{':
# grouping variant
closing = csource.find('}', endpos)
if closing < 0:
raise CDefError("'extern \"Python\" {': no '}' found")
if csource.find('{', endpos + 1, closing) >= 0:
raise NotImplementedError("cannot use { } inside a block "
"'extern \"Python\" { ... }'")
parts.append(csource[endpos+1:closing])
csource = csource[closing+1:]
else:
# non-grouping variant
semicolon = csource.find(';', endpos)
if semicolon < 0:
raise CDefError("'extern \"Python\": no ';' found")
parts.append(csource[endpos:semicolon+1])
csource = csource[semicolon+1:]
parts.append(' void __cffi_extern_python_stop;')
#print ''.join(parts)+csource
#print
parts.append(csource)
return ''.join(parts)
def _warn_for_string_literal(csource):
if '"' not in csource:
return
for line in csource.splitlines():
if '"' in line and not line.lstrip().startswith('#'):
import warnings
warnings.warn("String literal found in cdef() or type source. "
"String literals are ignored here, but you should "
"remove them anyway because some character sequences "
"confuse pre-parsing.")
break
def _warn_for_non_extern_non_static_global_variable(decl):
if not decl.storage:
import warnings
warnings.warn("Declaration of global variable '%s' in cdef() should "
"be marked 'extern' for consistency (or possibly "
"'static' in API mode)" % (decl.name,))
def _preprocess(csource):
# Remove comments. NOTE: this only work because the cdef() section
# should not contain any string literal!
csource = _r_comment.sub(' ', csource)
# Remove the "#define FOO x" lines
macros = {}
for match in _r_define.finditer(csource):
macroname, macrovalue = match.groups()
macrovalue = macrovalue.replace('\\\n', '').strip()
macros[macroname] = macrovalue
csource = _r_define.sub('', csource)
#
if pycparser.__version__ < '2.14':
csource = _workaround_for_old_pycparser(csource)
#
# BIG HACK: replace WINAPI or __stdcall with "volatile const".
# It doesn't make sense for the return type of a function to be
# "volatile volatile const", so we abuse it to detect __stdcall...
# Hack number 2 is that "int(volatile *fptr)();" is not valid C
# syntax, so we place the "volatile" before the opening parenthesis.
csource = _r_stdcall2.sub(' volatile volatile const(', csource)
csource = _r_stdcall1.sub(' volatile volatile const ', csource)
csource = _r_cdecl.sub(' ', csource)
#
# Replace `extern "Python"` with start/end markers
csource = _preprocess_extern_python(csource)
#
# Now there should not be any string literal left; warn if we get one
_warn_for_string_literal(csource)
#
# Replace "[...]" with "[__dotdotdotarray__]"
csource = _r_partial_array.sub('[__dotdotdotarray__]', csource)
#
# Replace "...}" with "__dotdotdotNUM__}". This construction should
# occur only at the end of enums; at the end of structs we have "...;}"
# and at the end of vararg functions "...);". Also replace "=...[,}]"
# with ",__dotdotdotNUM__[,}]": this occurs in the enums too, when
# giving an unknown value.
matches = list(_r_partial_enum.finditer(csource))
for number, match in enumerate(reversed(matches)):
p = match.start()
if csource[p] == '=':
p2 = csource.find('...', p, match.end())
assert p2 > p
csource = '%s,__dotdotdot%d__ %s' % (csource[:p], number,
csource[p2+3:])
else:
assert csource[p:p+3] == '...'
csource = '%s __dotdotdot%d__ %s' % (csource[:p], number,
csource[p+3:])
# Replace "int ..." or "unsigned long int..." with "__dotdotdotint__"
csource = _r_int_dotdotdot.sub(' __dotdotdotint__ ', csource)
# Replace "float ..." or "double..." with "__dotdotdotfloat__"
csource = _r_float_dotdotdot.sub(' __dotdotdotfloat__ ', csource)
# Replace all remaining "..." with the same name, "__dotdotdot__",
# which is declared with a typedef for the purpose of C parsing.
return csource.replace('...', ' __dotdotdot__ '), macros
def _common_type_names(csource):
# Look in the source for what looks like usages of types from the
# list of common types. A "usage" is approximated here as the
# appearance of the word, minus a "definition" of the type, which
# is the last word in a "typedef" statement. Approximative only
# but should be fine for all the common types.
look_for_words = set(COMMON_TYPES)
look_for_words.add(';')
look_for_words.add(',')
look_for_words.add('(')
look_for_words.add(')')
look_for_words.add('typedef')
words_used = set()
is_typedef = False
paren = 0
previous_word = ''
for word in _r_words.findall(csource):
if word in look_for_words:
if word == ';':
if is_typedef:
words_used.discard(previous_word)
look_for_words.discard(previous_word)
is_typedef = False
elif word == 'typedef':
is_typedef = True
paren = 0
elif word == '(':
paren += 1
elif word == ')':
paren -= 1
elif word == ',':
if is_typedef and paren == 0:
words_used.discard(previous_word)
look_for_words.discard(previous_word)
else: # word in COMMON_TYPES
words_used.add(word)
previous_word = word
return words_used
class Parser(object):
def __init__(self):
self._declarations = {}
self._included_declarations = set()
self._anonymous_counter = 0
self._structnode2type = weakref.WeakKeyDictionary()
self._options = {}
self._int_constants = {}
self._recomplete = []
self._uses_new_feature = None
def _parse(self, csource):
csource, macros = _preprocess(csource)
# XXX: for more efficiency we would need to poke into the
# internals of CParser... the following registers the
# typedefs, because their presence or absence influences the
# parsing itself (but what they are typedef'ed to plays no role)
ctn = _common_type_names(csource)
typenames = []
for name in sorted(self._declarations):
if name.startswith('typedef '):
name = name[8:]
typenames.append(name)
ctn.discard(name)
typenames += sorted(ctn)
#
csourcelines = []
csourcelines.append('# 1 ""')
for typename in typenames:
csourcelines.append('typedef int %s;' % typename)
csourcelines.append('typedef int __dotdotdotint__, __dotdotdotfloat__,'
' __dotdotdot__;')
# this forces pycparser to consider the following in the file
# called from line 1
csourcelines.append('# 1 "%s"' % (CDEF_SOURCE_STRING,))
csourcelines.append(csource)
fullcsource = '\n'.join(csourcelines)
if lock is not None:
lock.acquire() # pycparser is not thread-safe...
try:
ast = _get_parser().parse(fullcsource)
except pycparser.c_parser.ParseError as e:
self.convert_pycparser_error(e, csource)
finally:
if lock is not None:
lock.release()
# csource will be used to find buggy source text
return ast, macros, csource
def _convert_pycparser_error(self, e, csource):
# xxx look for ":NUM:" at the start of str(e)
# and interpret that as a line number. This will not work if
# the user gives explicit ``# NUM "FILE"`` directives.
line = None
msg = str(e)
match = re.match(r"%s:(\d+):" % (CDEF_SOURCE_STRING,), msg)
if match:
linenum = int(match.group(1), 10)
csourcelines = csource.splitlines()
if 1 <= linenum <= len(csourcelines):
line = csourcelines[linenum-1]
return line
def convert_pycparser_error(self, e, csource):
line = self._convert_pycparser_error(e, csource)
msg = str(e)
if line:
msg = 'cannot parse "%s"\n%s' % (line.strip(), msg)
else:
msg = 'parse error\n%s' % (msg,)
raise CDefError(msg)
def parse(self, csource, override=False, packed=False, pack=None,
dllexport=False):
if packed:
if packed != True:
raise ValueError("'packed' should be False or True; use "
"'pack' to give another value")
if pack:
raise ValueError("cannot give both 'pack' and 'packed'")
pack = 1
elif pack:
if pack & (pack - 1):
raise ValueError("'pack' must be a power of two, not %r" %
(pack,))
else:
pack = 0
prev_options = self._options
try:
self._options = {'override': override,
'packed': pack,
'dllexport': dllexport}
self._internal_parse(csource)
finally:
self._options = prev_options
def _internal_parse(self, csource):
ast, macros, csource = self._parse(csource)
# add the macros
self._process_macros(macros)
# find the first "__dotdotdot__" and use that as a separator
# between the repeated typedefs and the real csource
iterator = iter(ast.ext)
for decl in iterator:
if decl.name == '__dotdotdot__':
break
else:
assert 0
current_decl = None
#
try:
self._inside_extern_python = '__cffi_extern_python_stop'
for decl in iterator:
current_decl = decl
if isinstance(decl, pycparser.c_ast.Decl):
self._parse_decl(decl)
elif isinstance(decl, pycparser.c_ast.Typedef):
if not decl.name:
raise CDefError("typedef does not declare any name",
decl)
quals = 0
if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) and
decl.type.type.names[-1].startswith('__dotdotdot')):
realtype = self._get_unknown_type(decl)
elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and
isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and
isinstance(decl.type.type.type,
pycparser.c_ast.IdentifierType) and
decl.type.type.type.names[-1].startswith('__dotdotdot')):
realtype = self._get_unknown_ptr_type(decl)
else:
realtype, quals = self._get_type_and_quals(
decl.type, name=decl.name, partial_length_ok=True)
self._declare('typedef ' + decl.name, realtype, quals=quals)
elif decl.__class__.__name__ == 'Pragma':
pass # skip pragma, only in pycparser 2.15
else:
raise CDefError("unexpected <%s>: this construct is valid "
"C but not valid in cdef()" %
decl.__class__.__name__, decl)
except CDefError as e:
if len(e.args) == 1:
e.args = e.args + (current_decl,)
raise
except FFIError as e:
msg = self._convert_pycparser_error(e, csource)
if msg:
e.args = (e.args[0] + "\n *** Err: %s" % msg,)
raise
def _add_constants(self, key, val):
if key in self._int_constants:
if self._int_constants[key] == val:
return # ignore identical double declarations
raise FFIError(
"multiple declarations of constant: %s" % (key,))
self._int_constants[key] = val
def _add_integer_constant(self, name, int_str):
int_str = int_str.lower().rstrip("ul")
neg = int_str.startswith('-')
if neg:
int_str = int_str[1:]
# "010" is not valid oct in py3
if (int_str.startswith("0") and int_str != '0'
and not int_str.startswith("0x")):
int_str = "0o" + int_str[1:]
pyvalue = int(int_str, 0)
if neg:
pyvalue = -pyvalue
self._add_constants(name, pyvalue)
self._declare('macro ' + name, pyvalue)
def _process_macros(self, macros):
for key, value in macros.items():
value = value.strip()
if _r_int_literal.match(value):
self._add_integer_constant(key, value)
elif value == '...':
self._declare('macro ' + key, value)
else:
raise CDefError(
'only supports one of the following syntax:\n'
' #define %s ... (literally dot-dot-dot)\n'
' #define %s NUMBER (with NUMBER an integer'
' constant, decimal/hex/octal)\n'
'got:\n'
' #define %s %s'
% (key, key, key, value))
def _declare_function(self, tp, quals, decl):
tp = self._get_type_pointer(tp, quals)
if self._options.get('dllexport'):
tag = 'dllexport_python '
elif self._inside_extern_python == '__cffi_extern_python_start':
tag = 'extern_python '
elif self._inside_extern_python == '__cffi_extern_python_plus_c_start':
tag = 'extern_python_plus_c '
else:
tag = 'function '
self._declare(tag + decl.name, tp)
def _parse_decl(self, decl):
node = decl.type
if isinstance(node, pycparser.c_ast.FuncDecl):
tp, quals = self._get_type_and_quals(node, name=decl.name)
assert isinstance(tp, model.RawFunctionType)
self._declare_function(tp, quals, decl)
else:
if isinstance(node, pycparser.c_ast.Struct):
self._get_struct_union_enum_type('struct', node)
elif isinstance(node, pycparser.c_ast.Union):
self._get_struct_union_enum_type('union', node)
elif isinstance(node, pycparser.c_ast.Enum):
self._get_struct_union_enum_type('enum', node)
elif not decl.name:
raise CDefError("construct does not declare any variable",
decl)
#
if decl.name:
tp, quals = self._get_type_and_quals(node,
partial_length_ok=True)
if tp.is_raw_function:
self._declare_function(tp, quals, decl)
elif (tp.is_integer_type() and
hasattr(decl, 'init') and
hasattr(decl.init, 'value') and
_r_int_literal.match(decl.init.value)):
self._add_integer_constant(decl.name, decl.init.value)
elif (tp.is_integer_type() and
isinstance(decl.init, pycparser.c_ast.UnaryOp) and
decl.init.op == '-' and
hasattr(decl.init.expr, 'value') and
_r_int_literal.match(decl.init.expr.value)):
self._add_integer_constant(decl.name,
'-' + decl.init.expr.value)
elif (tp is model.void_type and
decl.name.startswith('__cffi_extern_python_')):
# hack: `extern "Python"` in the C source is replaced
# with "void __cffi_extern_python_start;" and
# "void __cffi_extern_python_stop;"
self._inside_extern_python = decl.name
else:
if self._inside_extern_python !='__cffi_extern_python_stop':
raise CDefError(
"cannot declare constants or "
"variables with 'extern \"Python\"'")
if (quals & model.Q_CONST) and not tp.is_array_type:
self._declare('constant ' + decl.name, tp, quals=quals)
else:
_warn_for_non_extern_non_static_global_variable(decl)
self._declare('variable ' + decl.name, tp, quals=quals)
def parse_type(self, cdecl):
return self.parse_type_and_quals(cdecl)[0]
def parse_type_and_quals(self, cdecl):
ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2]
assert not macros
exprnode = ast.ext[-1].type.args.params[0]
if isinstance(exprnode, pycparser.c_ast.ID):
raise CDefError("unknown identifier '%s'" % (exprnode.name,))
return self._get_type_and_quals(exprnode.type)
def _declare(self, name, obj, included=False, quals=0):
if name in self._declarations:
prevobj, prevquals = self._declarations[name]
if prevobj is obj and prevquals == quals:
return
if not self._options.get('override'):
raise FFIError(
"multiple declarations of %s (for interactive usage, "
"try cdef(xx, override=True))" % (name,))
assert '__dotdotdot__' not in name.split()
self._declarations[name] = (obj, quals)
if included:
self._included_declarations.add(obj)
def _extract_quals(self, type):
quals = 0
if isinstance(type, (pycparser.c_ast.TypeDecl,
pycparser.c_ast.PtrDecl)):
if 'const' in type.quals:
quals |= model.Q_CONST
if 'volatile' in type.quals:
quals |= model.Q_VOLATILE
if 'restrict' in type.quals:
quals |= model.Q_RESTRICT
return quals
def _get_type_pointer(self, type, quals, declname=None):
if isinstance(type, model.RawFunctionType):
return type.as_function_pointer()
if (isinstance(type, model.StructOrUnionOrEnum) and
type.name.startswith('$') and type.name[1:].isdigit() and
type.forcename is None and declname is not None):
return model.NamedPointerType(type, declname, quals)
return model.PointerType(type, quals)
def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False):
# first, dereference typedefs, if we have it already parsed, we're good
if (isinstance(typenode, pycparser.c_ast.TypeDecl) and
isinstance(typenode.type, pycparser.c_ast.IdentifierType) and
len(typenode.type.names) == 1 and
('typedef ' + typenode.type.names[0]) in self._declarations):
tp, quals = self._declarations['typedef ' + typenode.type.names[0]]
quals |= self._extract_quals(typenode)
return tp, quals
#
if isinstance(typenode, pycparser.c_ast.ArrayDecl):
# array type
if typenode.dim is None:
length = None
else:
length = self._parse_constant(
typenode.dim, partial_length_ok=partial_length_ok)
tp, quals = self._get_type_and_quals(typenode.type,
partial_length_ok=partial_length_ok)
return model.ArrayType(tp, length), quals
#
if isinstance(typenode, pycparser.c_ast.PtrDecl):
# pointer type
itemtype, itemquals = self._get_type_and_quals(typenode.type)
tp = self._get_type_pointer(itemtype, itemquals, declname=name)
quals = self._extract_quals(typenode)
return tp, quals
#
if isinstance(typenode, pycparser.c_ast.TypeDecl):
quals = self._extract_quals(typenode)
type = typenode.type
if isinstance(type, pycparser.c_ast.IdentifierType):
# assume a primitive type. get it from .names, but reduce
# synonyms to a single chosen combination
names = list(type.names)
if names != ['signed', 'char']: # keep this unmodified
prefixes = {}
while names:
name = names[0]
if name in ('short', 'long', 'signed', 'unsigned'):
prefixes[name] = prefixes.get(name, 0) + 1
del names[0]
else:
break
# ignore the 'signed' prefix below, and reorder the others
newnames = []
for prefix in ('unsigned', 'short', 'long'):
for i in range(prefixes.get(prefix, 0)):
newnames.append(prefix)
if not names:
names = ['int'] # implicitly
if names == ['int']: # but kill it if 'short' or 'long'
if 'short' in prefixes or 'long' in prefixes:
names = []
names = newnames + names
ident = ' '.join(names)
if ident == 'void':
return model.void_type, quals
if ident == '__dotdotdot__':
raise FFIError(':%d: bad usage of "..."' %
typenode.coord.line)
tp0, quals0 = resolve_common_type(self, ident)
return tp0, (quals | quals0)
#
if isinstance(type, pycparser.c_ast.Struct):
# 'struct foobar'
tp = self._get_struct_union_enum_type('struct', type, name)
return tp, quals
#
if isinstance(type, pycparser.c_ast.Union):
# 'union foobar'
tp = self._get_struct_union_enum_type('union', type, name)
return tp, quals
#
if isinstance(type, pycparser.c_ast.Enum):
# 'enum foobar'
tp = self._get_struct_union_enum_type('enum', type, name)
return tp, quals
#
if isinstance(typenode, pycparser.c_ast.FuncDecl):
# a function type
return self._parse_function_type(typenode, name), 0
#
# nested anonymous structs or unions end up here
if isinstance(typenode, pycparser.c_ast.Struct):
return self._get_struct_union_enum_type('struct', typenode, name,
nested=True), 0
if isinstance(typenode, pycparser.c_ast.Union):
return self._get_struct_union_enum_type('union', typenode, name,
nested=True), 0
#
raise FFIError(":%d: bad or unsupported type declaration" %
typenode.coord.line)
def _parse_function_type(self, typenode, funcname=None):
params = list(getattr(typenode.args, 'params', []))
for i, arg in enumerate(params):
if not hasattr(arg, 'type'):
raise CDefError("%s arg %d: unknown type '%s'"
" (if you meant to use the old C syntax of giving"
" untyped arguments, it is not supported)"
% (funcname or 'in expression', i + 1,
getattr(arg, 'name', '?')))
ellipsis = (
len(params) > 0 and
isinstance(params[-1].type, pycparser.c_ast.TypeDecl) and
isinstance(params[-1].type.type,
pycparser.c_ast.IdentifierType) and
params[-1].type.type.names == ['__dotdotdot__'])
if ellipsis:
params.pop()
if not params:
raise CDefError(
"%s: a function with only '(...)' as argument"
" is not correct C" % (funcname or 'in expression'))
args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type))
for argdeclnode in params]
if not ellipsis and args == [model.void_type]:
args = []
result, quals = self._get_type_and_quals(typenode.type)
# the 'quals' on the result type are ignored. HACK: we absure them
# to detect __stdcall functions: we textually replace "__stdcall"
# with "volatile volatile const" above.
abi = None
if hasattr(typenode.type, 'quals'): # else, probable syntax error anyway
if typenode.type.quals[-3:] == ['volatile', 'volatile', 'const']:
abi = '__stdcall'
return model.RawFunctionType(tuple(args), result, ellipsis, abi)
def _as_func_arg(self, type, quals):
if isinstance(type, model.ArrayType):
return model.PointerType(type.item, quals)
elif isinstance(type, model.RawFunctionType):
return type.as_function_pointer()
else:
return type
def _get_struct_union_enum_type(self, kind, type, name=None, nested=False):
# First, a level of caching on the exact 'type' node of the AST.
# This is obscure, but needed because pycparser "unrolls" declarations
# such as "typedef struct { } foo_t, *foo_p" and we end up with
# an AST that is not a tree, but a DAG, with the "type" node of the
# two branches foo_t and foo_p of the trees being the same node.
# It's a bit silly but detecting "DAG-ness" in the AST tree seems
# to be the only way to distinguish this case from two independent
# structs. See test_struct_with_two_usages.
try:
return self._structnode2type[type]
except KeyError:
pass
#
# Note that this must handle parsing "struct foo" any number of
# times and always return the same StructType object. Additionally,
# one of these times (not necessarily the first), the fields of
# the struct can be specified with "struct foo { ...fields... }".
# If no name is given, then we have to create a new anonymous struct
# with no caching; in this case, the fields are either specified
# right now or never.
#
force_name = name
name = type.name
#
# get the type or create it if needed
if name is None:
# 'force_name' is used to guess a more readable name for
# anonymous structs, for the common case "typedef struct { } foo".
if force_name is not None:
explicit_name = '$%s' % force_name
else:
self._anonymous_counter += 1
explicit_name = '$%d' % self._anonymous_counter
tp = None
else:
explicit_name = name
key = '%s %s' % (kind, name)
tp, _ = self._declarations.get(key, (None, None))
#
if tp is None:
if kind == 'struct':
tp = model.StructType(explicit_name, None, None, None)
elif kind == 'union':
tp = model.UnionType(explicit_name, None, None, None)
elif kind == 'enum':
if explicit_name == '__dotdotdot__':
raise CDefError("Enums cannot be declared with ...")
tp = self._build_enum_type(explicit_name, type.values)
else:
raise AssertionError("kind = %r" % (kind,))
if name is not None:
self._declare(key, tp)
else:
if kind == 'enum' and type.values is not None:
raise NotImplementedError(
"enum %s: the '{}' declaration should appear on the first "
"time the enum is mentioned, not later" % explicit_name)
if not tp.forcename:
tp.force_the_name(force_name)
if tp.forcename and '$' in tp.name:
self._declare('anonymous %s' % tp.forcename, tp)
#
self._structnode2type[type] = tp
#
# enums: done here
if kind == 'enum':
return tp
#
# is there a 'type.decls'? If yes, then this is the place in the
# C sources that declare the fields. If no, then just return the
# existing type, possibly still incomplete.
if type.decls is None:
return tp
#
if tp.fldnames is not None:
raise CDefError("duplicate declaration of struct %s" % name)
fldnames = []
fldtypes = []
fldbitsize = []
fldquals = []
for decl in type.decls:
if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and
''.join(decl.type.names) == '__dotdotdot__'):
# XXX pycparser is inconsistent: 'names' should be a list
# of strings, but is sometimes just one string. Use
# str.join() as a way to cope with both.
self._make_partial(tp, nested)
continue
if decl.bitsize is None:
bitsize = -1
else:
bitsize = self._parse_constant(decl.bitsize)
self._partial_length = False
type, fqual = self._get_type_and_quals(decl.type,
partial_length_ok=True)
if self._partial_length:
self._make_partial(tp, nested)
if isinstance(type, model.StructType) and type.partial:
self._make_partial(tp, nested)
fldnames.append(decl.name or '')
fldtypes.append(type)
fldbitsize.append(bitsize)
fldquals.append(fqual)
tp.fldnames = tuple(fldnames)
tp.fldtypes = tuple(fldtypes)
tp.fldbitsize = tuple(fldbitsize)
tp.fldquals = tuple(fldquals)
if fldbitsize != [-1] * len(fldbitsize):
if isinstance(tp, model.StructType) and tp.partial:
raise NotImplementedError("%s: using both bitfields and '...;'"
% (tp,))
tp.packed = self._options.get('packed')
if tp.completed: # must be re-completed: it is not opaque any more
tp.completed = 0
self._recomplete.append(tp)
return tp
def _make_partial(self, tp, nested):
if not isinstance(tp, model.StructOrUnion):
raise CDefError("%s cannot be partial" % (tp,))
if not tp.has_c_name() and not nested:
raise NotImplementedError("%s is partial but has no C name" %(tp,))
tp.partial = True
def _parse_constant(self, exprnode, partial_length_ok=False):
# for now, limited to expressions that are an immediate number
# or positive/negative number
if isinstance(exprnode, pycparser.c_ast.Constant):
s = exprnode.value
if '0' <= s[0] <= '9':
s = s.rstrip('uUlL')
try:
if s.startswith('0'):
return int(s, 8)
else:
return int(s, 10)
except ValueError:
if len(s) > 1:
if s.lower()[0:2] == '0x':
return int(s, 16)
elif s.lower()[0:2] == '0b':
return int(s, 2)
raise CDefError("invalid constant %r" % (s,))
elif s[0] == "'" and s[-1] == "'" and (
len(s) == 3 or (len(s) == 4 and s[1] == "\\")):
return ord(s[-2])
else:
raise CDefError("invalid constant %r" % (s,))
#
if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and
exprnode.op == '+'):
return self._parse_constant(exprnode.expr)
#
if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and
exprnode.op == '-'):
return -self._parse_constant(exprnode.expr)
# load previously defined int constant
if (isinstance(exprnode, pycparser.c_ast.ID) and
exprnode.name in self._int_constants):
return self._int_constants[exprnode.name]
#
if (isinstance(exprnode, pycparser.c_ast.ID) and
exprnode.name == '__dotdotdotarray__'):
if partial_length_ok:
self._partial_length = True
return '...'
raise FFIError(":%d: unsupported '[...]' here, cannot derive "
"the actual array length in this context"
% exprnode.coord.line)
#
if isinstance(exprnode, pycparser.c_ast.BinaryOp):
left = self._parse_constant(exprnode.left)
right = self._parse_constant(exprnode.right)
if exprnode.op == '+':
return left + right
elif exprnode.op == '-':
return left - right
elif exprnode.op == '*':
return left * right
elif exprnode.op == '/':
return self._c_div(left, right)
elif exprnode.op == '%':
return left - self._c_div(left, right) * right
elif exprnode.op == '<<':
return left << right
elif exprnode.op == '>>':
return left >> right
elif exprnode.op == '&':
return left & right
elif exprnode.op == '|':
return left | right
elif exprnode.op == '^':
return left ^ right
#
raise FFIError(":%d: unsupported expression: expected a "
"simple numeric constant" % exprnode.coord.line)
def _c_div(self, a, b):
result = a // b
if ((a < 0) ^ (b < 0)) and (a % b) != 0:
result += 1
return result
def _build_enum_type(self, explicit_name, decls):
if decls is not None:
partial = False
enumerators = []
enumvalues = []
nextenumvalue = 0
for enum in decls.enumerators:
if _r_enum_dotdotdot.match(enum.name):
partial = True
continue
if enum.value is not None:
nextenumvalue = self._parse_constant(enum.value)
enumerators.append(enum.name)
enumvalues.append(nextenumvalue)
self._add_constants(enum.name, nextenumvalue)
nextenumvalue += 1
enumerators = tuple(enumerators)
enumvalues = tuple(enumvalues)
tp = model.EnumType(explicit_name, enumerators, enumvalues)
tp.partial = partial
else: # opaque enum
tp = model.EnumType(explicit_name, (), ())
return tp
def include(self, other):
for name, (tp, quals) in other._declarations.items():
if name.startswith('anonymous $enum_$'):
continue # fix for test_anonymous_enum_include
kind = name.split(' ', 1)[0]
if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'):
self._declare(name, tp, included=True, quals=quals)
for k, v in other._int_constants.items():
self._add_constants(k, v)
def _get_unknown_type(self, decl):
typenames = decl.type.type.names
if typenames == ['__dotdotdot__']:
return model.unknown_type(decl.name)
if typenames == ['__dotdotdotint__']:
if self._uses_new_feature is None:
self._uses_new_feature = "'typedef int... %s'" % decl.name
return model.UnknownIntegerType(decl.name)
if typenames == ['__dotdotdotfloat__']:
# note: not for 'long double' so far
if self._uses_new_feature is None:
self._uses_new_feature = "'typedef float... %s'" % decl.name
return model.UnknownFloatType(decl.name)
raise FFIError(':%d: unsupported usage of "..." in typedef'
% decl.coord.line)
def _get_unknown_ptr_type(self, decl):
if decl.type.type.type.names == ['__dotdotdot__']:
return model.unknown_ptr_type(decl.name)
raise FFIError(':%d: unsupported usage of "..." in typedef'
% decl.coord.line)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/error.py
================================================
class FFIError(Exception):
__module__ = 'cffi'
class CDefError(Exception):
__module__ = 'cffi'
def __str__(self):
try:
current_decl = self.args[1]
filename = current_decl.coord.file
linenum = current_decl.coord.line
prefix = '%s:%d: ' % (filename, linenum)
except (AttributeError, TypeError, IndexError):
prefix = ''
return '%s%s' % (prefix, self.args[0])
class VerificationError(Exception):
""" An error raised when verification fails
"""
__module__ = 'cffi'
class VerificationMissing(Exception):
""" An error raised when incomplete structures are passed into
cdef, but no verification has been done
"""
__module__ = 'cffi'
class PkgConfigError(Exception):
""" An error raised for missing modules in pkg-config
"""
__module__ = 'cffi'
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/ffiplatform.py
================================================
import sys, os
from .error import VerificationError
LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs',
'extra_objects', 'depends']
def get_extension(srcfilename, modname, sources=(), **kwds):
_hack_at_distutils()
from distutils.core import Extension
allsources = [srcfilename]
for src in sources:
allsources.append(os.path.normpath(src))
return Extension(name=modname, sources=allsources, **kwds)
def compile(tmpdir, ext, compiler_verbose=0, debug=None):
"""Compile a C extension module using distutils."""
_hack_at_distutils()
saved_environ = os.environ.copy()
try:
outputfilename = _build(tmpdir, ext, compiler_verbose, debug)
outputfilename = os.path.abspath(outputfilename)
finally:
# workaround for a distutils bugs where some env vars can
# become longer and longer every time it is used
for key, value in saved_environ.items():
if os.environ.get(key) != value:
os.environ[key] = value
return outputfilename
def _build(tmpdir, ext, compiler_verbose=0, debug=None):
# XXX compact but horrible :-(
from distutils.core import Distribution
import distutils.errors, distutils.log
#
dist = Distribution({'ext_modules': [ext]})
dist.parse_config_files()
options = dist.get_option_dict('build_ext')
if debug is None:
debug = sys.flags.debug
options['debug'] = ('ffiplatform', debug)
options['force'] = ('ffiplatform', True)
options['build_lib'] = ('ffiplatform', tmpdir)
options['build_temp'] = ('ffiplatform', tmpdir)
#
try:
old_level = distutils.log.set_threshold(0) or 0
try:
distutils.log.set_verbosity(compiler_verbose)
dist.run_command('build_ext')
cmd_obj = dist.get_command_obj('build_ext')
[soname] = cmd_obj.get_outputs()
finally:
distutils.log.set_threshold(old_level)
except (distutils.errors.CompileError,
distutils.errors.LinkError) as e:
raise VerificationError('%s: %s' % (e.__class__.__name__, e))
#
return soname
try:
from os.path import samefile
except ImportError:
def samefile(f1, f2):
return os.path.abspath(f1) == os.path.abspath(f2)
def maybe_relative_path(path):
if not os.path.isabs(path):
return path # already relative
dir = path
names = []
while True:
prevdir = dir
dir, name = os.path.split(prevdir)
if dir == prevdir or not dir:
return path # failed to make it relative
names.append(name)
try:
if samefile(dir, os.curdir):
names.reverse()
return os.path.join(*names)
except OSError:
pass
# ____________________________________________________________
try:
int_or_long = (int, long)
import cStringIO
except NameError:
int_or_long = int # Python 3
import io as cStringIO
def _flatten(x, f):
if isinstance(x, str):
f.write('%ds%s' % (len(x), x))
elif isinstance(x, dict):
keys = sorted(x.keys())
f.write('%dd' % len(keys))
for key in keys:
_flatten(key, f)
_flatten(x[key], f)
elif isinstance(x, (list, tuple)):
f.write('%dl' % len(x))
for value in x:
_flatten(value, f)
elif isinstance(x, int_or_long):
f.write('%di' % (x,))
else:
raise TypeError(
"the keywords to verify() contains unsupported object %r" % (x,))
def flatten(x):
f = cStringIO.StringIO()
_flatten(x, f)
return f.getvalue()
def _hack_at_distutils():
# Windows-only workaround for some configurations: see
# https://bugs.python.org/issue23246 (Python 2.7 with
# a specific MS compiler suite download)
if sys.platform == "win32":
try:
import setuptools # for side-effects, patches distutils
except ImportError:
pass
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/lock.py
================================================
import sys
if sys.version_info < (3,):
try:
from thread import allocate_lock
except ImportError:
from dummy_thread import allocate_lock
else:
try:
from _thread import allocate_lock
except ImportError:
from _dummy_thread import allocate_lock
##import sys
##l1 = allocate_lock
##class allocate_lock(object):
## def __init__(self):
## self._real = l1()
## def __enter__(self):
## for i in range(4, 0, -1):
## print sys._getframe(i).f_code
## print
## return self._real.__enter__()
## def __exit__(self, *args):
## return self._real.__exit__(*args)
## def acquire(self, f):
## assert f is False
## return self._real.acquire(f)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/model.py
================================================
import types
import weakref
from .lock import allocate_lock
from .error import CDefError, VerificationError, VerificationMissing
# type qualifiers
Q_CONST = 0x01
Q_RESTRICT = 0x02
Q_VOLATILE = 0x04
def qualify(quals, replace_with):
if quals & Q_CONST:
replace_with = ' const ' + replace_with.lstrip()
if quals & Q_VOLATILE:
replace_with = ' volatile ' + replace_with.lstrip()
if quals & Q_RESTRICT:
# It seems that __restrict is supported by gcc and msvc.
# If you hit some different compiler, add a #define in
# _cffi_include.h for it (and in its copies, documented there)
replace_with = ' __restrict ' + replace_with.lstrip()
return replace_with
class BaseTypeByIdentity(object):
is_array_type = False
is_raw_function = False
def get_c_name(self, replace_with='', context='a C file', quals=0):
result = self.c_name_with_marker
assert result.count('&') == 1
# some logic duplication with ffi.getctype()... :-(
replace_with = replace_with.strip()
if replace_with:
if replace_with.startswith('*') and '&[' in result:
replace_with = '(%s)' % replace_with
elif not replace_with[0] in '[(':
replace_with = ' ' + replace_with
replace_with = qualify(quals, replace_with)
result = result.replace('&', replace_with)
if '$' in result:
raise VerificationError(
"cannot generate '%s' in %s: unknown type name"
% (self._get_c_name(), context))
return result
def _get_c_name(self):
return self.c_name_with_marker.replace('&', '')
def has_c_name(self):
return '$' not in self._get_c_name()
def is_integer_type(self):
return False
def get_cached_btype(self, ffi, finishlist, can_delay=False):
try:
BType = ffi._cached_btypes[self]
except KeyError:
BType = self.build_backend_type(ffi, finishlist)
BType2 = ffi._cached_btypes.setdefault(self, BType)
assert BType2 is BType
return BType
def __repr__(self):
return '<%s>' % (self._get_c_name(),)
def _get_items(self):
return [(name, getattr(self, name)) for name in self._attrs_]
class BaseType(BaseTypeByIdentity):
def __eq__(self, other):
return (self.__class__ == other.__class__ and
self._get_items() == other._get_items())
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.__class__, tuple(self._get_items())))
class VoidType(BaseType):
_attrs_ = ()
def __init__(self):
self.c_name_with_marker = 'void&'
def build_backend_type(self, ffi, finishlist):
return global_cache(self, ffi, 'new_void_type')
void_type = VoidType()
class BasePrimitiveType(BaseType):
def is_complex_type(self):
return False
class PrimitiveType(BasePrimitiveType):
_attrs_ = ('name',)
ALL_PRIMITIVE_TYPES = {
'char': 'c',
'short': 'i',
'int': 'i',
'long': 'i',
'long long': 'i',
'signed char': 'i',
'unsigned char': 'i',
'unsigned short': 'i',
'unsigned int': 'i',
'unsigned long': 'i',
'unsigned long long': 'i',
'float': 'f',
'double': 'f',
'long double': 'f',
'float _Complex': 'j',
'double _Complex': 'j',
'_Bool': 'i',
# the following types are not primitive in the C sense
'wchar_t': 'c',
'char16_t': 'c',
'char32_t': 'c',
'int8_t': 'i',
'uint8_t': 'i',
'int16_t': 'i',
'uint16_t': 'i',
'int32_t': 'i',
'uint32_t': 'i',
'int64_t': 'i',
'uint64_t': 'i',
'int_least8_t': 'i',
'uint_least8_t': 'i',
'int_least16_t': 'i',
'uint_least16_t': 'i',
'int_least32_t': 'i',
'uint_least32_t': 'i',
'int_least64_t': 'i',
'uint_least64_t': 'i',
'int_fast8_t': 'i',
'uint_fast8_t': 'i',
'int_fast16_t': 'i',
'uint_fast16_t': 'i',
'int_fast32_t': 'i',
'uint_fast32_t': 'i',
'int_fast64_t': 'i',
'uint_fast64_t': 'i',
'intptr_t': 'i',
'uintptr_t': 'i',
'intmax_t': 'i',
'uintmax_t': 'i',
'ptrdiff_t': 'i',
'size_t': 'i',
'ssize_t': 'i',
}
def __init__(self, name):
assert name in self.ALL_PRIMITIVE_TYPES
self.name = name
self.c_name_with_marker = name + '&'
def is_char_type(self):
return self.ALL_PRIMITIVE_TYPES[self.name] == 'c'
def is_integer_type(self):
return self.ALL_PRIMITIVE_TYPES[self.name] == 'i'
def is_float_type(self):
return self.ALL_PRIMITIVE_TYPES[self.name] == 'f'
def is_complex_type(self):
return self.ALL_PRIMITIVE_TYPES[self.name] == 'j'
def build_backend_type(self, ffi, finishlist):
return global_cache(self, ffi, 'new_primitive_type', self.name)
class UnknownIntegerType(BasePrimitiveType):
_attrs_ = ('name',)
def __init__(self, name):
self.name = name
self.c_name_with_marker = name + '&'
def is_integer_type(self):
return True
def build_backend_type(self, ffi, finishlist):
raise NotImplementedError("integer type '%s' can only be used after "
"compilation" % self.name)
class UnknownFloatType(BasePrimitiveType):
_attrs_ = ('name', )
def __init__(self, name):
self.name = name
self.c_name_with_marker = name + '&'
def build_backend_type(self, ffi, finishlist):
raise NotImplementedError("float type '%s' can only be used after "
"compilation" % self.name)
class BaseFunctionType(BaseType):
_attrs_ = ('args', 'result', 'ellipsis', 'abi')
def __init__(self, args, result, ellipsis, abi=None):
self.args = args
self.result = result
self.ellipsis = ellipsis
self.abi = abi
#
reprargs = [arg._get_c_name() for arg in self.args]
if self.ellipsis:
reprargs.append('...')
reprargs = reprargs or ['void']
replace_with = self._base_pattern % (', '.join(reprargs),)
if abi is not None:
replace_with = replace_with[:1] + abi + ' ' + replace_with[1:]
self.c_name_with_marker = (
self.result.c_name_with_marker.replace('&', replace_with))
class RawFunctionType(BaseFunctionType):
# Corresponds to a C type like 'int(int)', which is the C type of
# a function, but not a pointer-to-function. The backend has no
# notion of such a type; it's used temporarily by parsing.
_base_pattern = '(&)(%s)'
is_raw_function = True
def build_backend_type(self, ffi, finishlist):
raise CDefError("cannot render the type %r: it is a function "
"type, not a pointer-to-function type" % (self,))
def as_function_pointer(self):
return FunctionPtrType(self.args, self.result, self.ellipsis, self.abi)
class FunctionPtrType(BaseFunctionType):
_base_pattern = '(*&)(%s)'
def build_backend_type(self, ffi, finishlist):
result = self.result.get_cached_btype(ffi, finishlist)
args = []
for tp in self.args:
args.append(tp.get_cached_btype(ffi, finishlist))
abi_args = ()
if self.abi == "__stdcall":
if not self.ellipsis: # __stdcall ignored for variadic funcs
try:
abi_args = (ffi._backend.FFI_STDCALL,)
except AttributeError:
pass
return global_cache(self, ffi, 'new_function_type',
tuple(args), result, self.ellipsis, *abi_args)
def as_raw_function(self):
return RawFunctionType(self.args, self.result, self.ellipsis, self.abi)
class PointerType(BaseType):
_attrs_ = ('totype', 'quals')
def __init__(self, totype, quals=0):
self.totype = totype
self.quals = quals
extra = qualify(quals, " *&")
if totype.is_array_type:
extra = "(%s)" % (extra.lstrip(),)
self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra)
def build_backend_type(self, ffi, finishlist):
BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True)
return global_cache(self, ffi, 'new_pointer_type', BItem)
voidp_type = PointerType(void_type)
def ConstPointerType(totype):
return PointerType(totype, Q_CONST)
const_voidp_type = ConstPointerType(void_type)
class NamedPointerType(PointerType):
_attrs_ = ('totype', 'name')
def __init__(self, totype, name, quals=0):
PointerType.__init__(self, totype, quals)
self.name = name
self.c_name_with_marker = name + '&'
class ArrayType(BaseType):
_attrs_ = ('item', 'length')
is_array_type = True
def __init__(self, item, length):
self.item = item
self.length = length
#
if length is None:
brackets = '&[]'
elif length == '...':
brackets = '&[/*...*/]'
else:
brackets = '&[%s]' % length
self.c_name_with_marker = (
self.item.c_name_with_marker.replace('&', brackets))
def resolve_length(self, newlength):
return ArrayType(self.item, newlength)
def build_backend_type(self, ffi, finishlist):
if self.length == '...':
raise CDefError("cannot render the type %r: unknown length" %
(self,))
self.item.get_cached_btype(ffi, finishlist) # force the item BType
BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist)
return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length)
char_array_type = ArrayType(PrimitiveType('char'), None)
class StructOrUnionOrEnum(BaseTypeByIdentity):
_attrs_ = ('name',)
forcename = None
def build_c_name_with_marker(self):
name = self.forcename or '%s %s' % (self.kind, self.name)
self.c_name_with_marker = name + '&'
def force_the_name(self, forcename):
self.forcename = forcename
self.build_c_name_with_marker()
def get_official_name(self):
assert self.c_name_with_marker.endswith('&')
return self.c_name_with_marker[:-1]
class StructOrUnion(StructOrUnionOrEnum):
fixedlayout = None
completed = 0
partial = False
packed = 0
def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None):
self.name = name
self.fldnames = fldnames
self.fldtypes = fldtypes
self.fldbitsize = fldbitsize
self.fldquals = fldquals
self.build_c_name_with_marker()
def anonymous_struct_fields(self):
if self.fldtypes is not None:
for name, type in zip(self.fldnames, self.fldtypes):
if name == '' and isinstance(type, StructOrUnion):
yield type
def enumfields(self, expand_anonymous_struct_union=True):
fldquals = self.fldquals
if fldquals is None:
fldquals = (0,) * len(self.fldnames)
for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes,
self.fldbitsize, fldquals):
if (name == '' and isinstance(type, StructOrUnion)
and expand_anonymous_struct_union):
# nested anonymous struct/union
for result in type.enumfields():
yield result
else:
yield (name, type, bitsize, quals)
def force_flatten(self):
# force the struct or union to have a declaration that lists
# directly all fields returned by enumfields(), flattening
# nested anonymous structs/unions.
names = []
types = []
bitsizes = []
fldquals = []
for name, type, bitsize, quals in self.enumfields():
names.append(name)
types.append(type)
bitsizes.append(bitsize)
fldquals.append(quals)
self.fldnames = tuple(names)
self.fldtypes = tuple(types)
self.fldbitsize = tuple(bitsizes)
self.fldquals = tuple(fldquals)
def get_cached_btype(self, ffi, finishlist, can_delay=False):
BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist,
can_delay)
if not can_delay:
self.finish_backend_type(ffi, finishlist)
return BType
def finish_backend_type(self, ffi, finishlist):
if self.completed:
if self.completed != 2:
raise NotImplementedError("recursive structure declaration "
"for '%s'" % (self.name,))
return
BType = ffi._cached_btypes[self]
#
self.completed = 1
#
if self.fldtypes is None:
pass # not completing it: it's an opaque struct
#
elif self.fixedlayout is None:
fldtypes = [tp.get_cached_btype(ffi, finishlist)
for tp in self.fldtypes]
lst = list(zip(self.fldnames, fldtypes, self.fldbitsize))
extra_flags = ()
if self.packed:
if self.packed == 1:
extra_flags = (8,) # SF_PACKED
else:
extra_flags = (0, self.packed)
ffi._backend.complete_struct_or_union(BType, lst, self,
-1, -1, *extra_flags)
#
else:
fldtypes = []
fieldofs, fieldsize, totalsize, totalalignment = self.fixedlayout
for i in range(len(self.fldnames)):
fsize = fieldsize[i]
ftype = self.fldtypes[i]
#
if isinstance(ftype, ArrayType) and ftype.length == '...':
# fix the length to match the total size
BItemType = ftype.item.get_cached_btype(ffi, finishlist)
nlen, nrest = divmod(fsize, ffi.sizeof(BItemType))
if nrest != 0:
self._verification_error(
"field '%s.%s' has a bogus size?" % (
self.name, self.fldnames[i] or '{}'))
ftype = ftype.resolve_length(nlen)
self.fldtypes = (self.fldtypes[:i] + (ftype,) +
self.fldtypes[i+1:])
#
BFieldType = ftype.get_cached_btype(ffi, finishlist)
if isinstance(ftype, ArrayType) and ftype.length is None:
assert fsize == 0
else:
bitemsize = ffi.sizeof(BFieldType)
if bitemsize != fsize:
self._verification_error(
"field '%s.%s' is declared as %d bytes, but is "
"really %d bytes" % (self.name,
self.fldnames[i] or '{}',
bitemsize, fsize))
fldtypes.append(BFieldType)
#
lst = list(zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs))
ffi._backend.complete_struct_or_union(BType, lst, self,
totalsize, totalalignment)
self.completed = 2
def _verification_error(self, msg):
raise VerificationError(msg)
def check_not_partial(self):
if self.partial and self.fixedlayout is None:
raise VerificationMissing(self._get_c_name())
def build_backend_type(self, ffi, finishlist):
self.check_not_partial()
finishlist.append(self)
#
return global_cache(self, ffi, 'new_%s_type' % self.kind,
self.get_official_name(), key=self)
class StructType(StructOrUnion):
kind = 'struct'
class UnionType(StructOrUnion):
kind = 'union'
class EnumType(StructOrUnionOrEnum):
kind = 'enum'
partial = False
partial_resolved = False
def __init__(self, name, enumerators, enumvalues, baseinttype=None):
self.name = name
self.enumerators = enumerators
self.enumvalues = enumvalues
self.baseinttype = baseinttype
self.build_c_name_with_marker()
def force_the_name(self, forcename):
StructOrUnionOrEnum.force_the_name(self, forcename)
if self.forcename is None:
name = self.get_official_name()
self.forcename = '$' + name.replace(' ', '_')
def check_not_partial(self):
if self.partial and not self.partial_resolved:
raise VerificationMissing(self._get_c_name())
def build_backend_type(self, ffi, finishlist):
self.check_not_partial()
base_btype = self.build_baseinttype(ffi, finishlist)
return global_cache(self, ffi, 'new_enum_type',
self.get_official_name(),
self.enumerators, self.enumvalues,
base_btype, key=self)
def build_baseinttype(self, ffi, finishlist):
if self.baseinttype is not None:
return self.baseinttype.get_cached_btype(ffi, finishlist)
#
if self.enumvalues:
smallest_value = min(self.enumvalues)
largest_value = max(self.enumvalues)
else:
import warnings
try:
# XXX! The goal is to ensure that the warnings.warn()
# will not suppress the warning. We want to get it
# several times if we reach this point several times.
__warningregistry__.clear()
except NameError:
pass
warnings.warn("%r has no values explicitly defined; "
"guessing that it is equivalent to 'unsigned int'"
% self._get_c_name())
smallest_value = largest_value = 0
if smallest_value < 0: # needs a signed type
sign = 1
candidate1 = PrimitiveType("int")
candidate2 = PrimitiveType("long")
else:
sign = 0
candidate1 = PrimitiveType("unsigned int")
candidate2 = PrimitiveType("unsigned long")
btype1 = candidate1.get_cached_btype(ffi, finishlist)
btype2 = candidate2.get_cached_btype(ffi, finishlist)
size1 = ffi.sizeof(btype1)
size2 = ffi.sizeof(btype2)
if (smallest_value >= ((-1) << (8*size1-1)) and
largest_value < (1 << (8*size1-sign))):
return btype1
if (smallest_value >= ((-1) << (8*size2-1)) and
largest_value < (1 << (8*size2-sign))):
return btype2
raise CDefError("%s values don't all fit into either 'long' "
"or 'unsigned long'" % self._get_c_name())
def unknown_type(name, structname=None):
if structname is None:
structname = '$%s' % name
tp = StructType(structname, None, None, None)
tp.force_the_name(name)
tp.origin = "unknown_type"
return tp
def unknown_ptr_type(name, structname=None):
if structname is None:
structname = '$$%s' % name
tp = StructType(structname, None, None, None)
return NamedPointerType(tp, name)
global_lock = allocate_lock()
_typecache_cffi_backend = weakref.WeakValueDictionary()
def get_typecache(backend):
# returns _typecache_cffi_backend if backend is the _cffi_backend
# module, or type(backend).__typecache if backend is an instance of
# CTypesBackend (or some FakeBackend class during tests)
if isinstance(backend, types.ModuleType):
return _typecache_cffi_backend
with global_lock:
if not hasattr(type(backend), '__typecache'):
type(backend).__typecache = weakref.WeakValueDictionary()
return type(backend).__typecache
def global_cache(srctype, ffi, funcname, *args, **kwds):
key = kwds.pop('key', (funcname, args))
assert not kwds
try:
return ffi._typecache[key]
except KeyError:
pass
try:
res = getattr(ffi._backend, funcname)(*args)
except NotImplementedError as e:
raise NotImplementedError("%s: %r: %s" % (funcname, srctype, e))
# note that setdefault() on WeakValueDictionary is not atomic
# and contains a rare bug (http://bugs.python.org/issue19542);
# we have to use a lock and do it ourselves
cache = ffi._typecache
with global_lock:
res1 = cache.get(key)
if res1 is None:
cache[key] = res
return res
else:
return res1
def pointer_cache(ffi, BType):
return global_cache('?', ffi, 'new_pointer_type', BType)
def attach_exception_info(e, name):
if e.args and type(e.args[0]) is str:
e.args = ('%s: %s' % (name, e.args[0]),) + e.args[1:]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/parse_c_type.h
================================================
/* This part is from file 'cffi/parse_c_type.h'. It is copied at the
beginning of C sources generated by CFFI's ffi.set_source(). */
typedef void *_cffi_opcode_t;
#define _CFFI_OP(opcode, arg) (_cffi_opcode_t)(opcode | (((uintptr_t)(arg)) << 8))
#define _CFFI_GETOP(cffi_opcode) ((unsigned char)(uintptr_t)cffi_opcode)
#define _CFFI_GETARG(cffi_opcode) (((intptr_t)cffi_opcode) >> 8)
#define _CFFI_OP_PRIMITIVE 1
#define _CFFI_OP_POINTER 3
#define _CFFI_OP_ARRAY 5
#define _CFFI_OP_OPEN_ARRAY 7
#define _CFFI_OP_STRUCT_UNION 9
#define _CFFI_OP_ENUM 11
#define _CFFI_OP_FUNCTION 13
#define _CFFI_OP_FUNCTION_END 15
#define _CFFI_OP_NOOP 17
#define _CFFI_OP_BITFIELD 19
#define _CFFI_OP_TYPENAME 21
#define _CFFI_OP_CPYTHON_BLTN_V 23 // varargs
#define _CFFI_OP_CPYTHON_BLTN_N 25 // noargs
#define _CFFI_OP_CPYTHON_BLTN_O 27 // O (i.e. a single arg)
#define _CFFI_OP_CONSTANT 29
#define _CFFI_OP_CONSTANT_INT 31
#define _CFFI_OP_GLOBAL_VAR 33
#define _CFFI_OP_DLOPEN_FUNC 35
#define _CFFI_OP_DLOPEN_CONST 37
#define _CFFI_OP_GLOBAL_VAR_F 39
#define _CFFI_OP_EXTERN_PYTHON 41
#define _CFFI_PRIM_VOID 0
#define _CFFI_PRIM_BOOL 1
#define _CFFI_PRIM_CHAR 2
#define _CFFI_PRIM_SCHAR 3
#define _CFFI_PRIM_UCHAR 4
#define _CFFI_PRIM_SHORT 5
#define _CFFI_PRIM_USHORT 6
#define _CFFI_PRIM_INT 7
#define _CFFI_PRIM_UINT 8
#define _CFFI_PRIM_LONG 9
#define _CFFI_PRIM_ULONG 10
#define _CFFI_PRIM_LONGLONG 11
#define _CFFI_PRIM_ULONGLONG 12
#define _CFFI_PRIM_FLOAT 13
#define _CFFI_PRIM_DOUBLE 14
#define _CFFI_PRIM_LONGDOUBLE 15
#define _CFFI_PRIM_WCHAR 16
#define _CFFI_PRIM_INT8 17
#define _CFFI_PRIM_UINT8 18
#define _CFFI_PRIM_INT16 19
#define _CFFI_PRIM_UINT16 20
#define _CFFI_PRIM_INT32 21
#define _CFFI_PRIM_UINT32 22
#define _CFFI_PRIM_INT64 23
#define _CFFI_PRIM_UINT64 24
#define _CFFI_PRIM_INTPTR 25
#define _CFFI_PRIM_UINTPTR 26
#define _CFFI_PRIM_PTRDIFF 27
#define _CFFI_PRIM_SIZE 28
#define _CFFI_PRIM_SSIZE 29
#define _CFFI_PRIM_INT_LEAST8 30
#define _CFFI_PRIM_UINT_LEAST8 31
#define _CFFI_PRIM_INT_LEAST16 32
#define _CFFI_PRIM_UINT_LEAST16 33
#define _CFFI_PRIM_INT_LEAST32 34
#define _CFFI_PRIM_UINT_LEAST32 35
#define _CFFI_PRIM_INT_LEAST64 36
#define _CFFI_PRIM_UINT_LEAST64 37
#define _CFFI_PRIM_INT_FAST8 38
#define _CFFI_PRIM_UINT_FAST8 39
#define _CFFI_PRIM_INT_FAST16 40
#define _CFFI_PRIM_UINT_FAST16 41
#define _CFFI_PRIM_INT_FAST32 42
#define _CFFI_PRIM_UINT_FAST32 43
#define _CFFI_PRIM_INT_FAST64 44
#define _CFFI_PRIM_UINT_FAST64 45
#define _CFFI_PRIM_INTMAX 46
#define _CFFI_PRIM_UINTMAX 47
#define _CFFI_PRIM_FLOATCOMPLEX 48
#define _CFFI_PRIM_DOUBLECOMPLEX 49
#define _CFFI_PRIM_CHAR16 50
#define _CFFI_PRIM_CHAR32 51
#define _CFFI__NUM_PRIM 52
#define _CFFI__UNKNOWN_PRIM (-1)
#define _CFFI__UNKNOWN_FLOAT_PRIM (-2)
#define _CFFI__UNKNOWN_LONG_DOUBLE (-3)
#define _CFFI__IO_FILE_STRUCT (-1)
struct _cffi_global_s {
const char *name;
void *address;
_cffi_opcode_t type_op;
void *size_or_direct_fn; // OP_GLOBAL_VAR: size, or 0 if unknown
// OP_CPYTHON_BLTN_*: addr of direct function
};
struct _cffi_getconst_s {
unsigned long long value;
const struct _cffi_type_context_s *ctx;
int gindex;
};
struct _cffi_struct_union_s {
const char *name;
int type_index; // -> _cffi_types, on a OP_STRUCT_UNION
int flags; // _CFFI_F_* flags below
size_t size;
int alignment;
int first_field_index; // -> _cffi_fields array
int num_fields;
};
#define _CFFI_F_UNION 0x01 // is a union, not a struct
#define _CFFI_F_CHECK_FIELDS 0x02 // complain if fields are not in the
// "standard layout" or if some are missing
#define _CFFI_F_PACKED 0x04 // for CHECK_FIELDS, assume a packed struct
#define _CFFI_F_EXTERNAL 0x08 // in some other ffi.include()
#define _CFFI_F_OPAQUE 0x10 // opaque
struct _cffi_field_s {
const char *name;
size_t field_offset;
size_t field_size;
_cffi_opcode_t field_type_op;
};
struct _cffi_enum_s {
const char *name;
int type_index; // -> _cffi_types, on a OP_ENUM
int type_prim; // _CFFI_PRIM_xxx
const char *enumerators; // comma-delimited string
};
struct _cffi_typename_s {
const char *name;
int type_index; /* if opaque, points to a possibly artificial
OP_STRUCT which is itself opaque */
};
struct _cffi_type_context_s {
_cffi_opcode_t *types;
const struct _cffi_global_s *globals;
const struct _cffi_field_s *fields;
const struct _cffi_struct_union_s *struct_unions;
const struct _cffi_enum_s *enums;
const struct _cffi_typename_s *typenames;
int num_globals;
int num_struct_unions;
int num_enums;
int num_typenames;
const char *const *includes;
int num_types;
int flags; /* future extension */
};
struct _cffi_parse_info_s {
const struct _cffi_type_context_s *ctx;
_cffi_opcode_t *output;
unsigned int output_size;
size_t error_location;
const char *error_message;
};
struct _cffi_externpy_s {
const char *name;
size_t size_of_result;
void *reserved1, *reserved2;
};
#ifdef _CFFI_INTERNAL
static int parse_c_type(struct _cffi_parse_info_s *info, const char *input);
static int search_in_globals(const struct _cffi_type_context_s *ctx,
const char *search, size_t search_len);
static int search_in_struct_unions(const struct _cffi_type_context_s *ctx,
const char *search, size_t search_len);
#endif
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/pkgconfig.py
================================================
# pkg-config, https://www.freedesktop.org/wiki/Software/pkg-config/ integration for cffi
import sys, os, subprocess
from .error import PkgConfigError
def merge_flags(cfg1, cfg2):
"""Merge values from cffi config flags cfg2 to cf1
Example:
merge_flags({"libraries": ["one"]}, {"libraries": ["two"]})
{"libraries": ["one", "two"]}
"""
for key, value in cfg2.items():
if key not in cfg1:
cfg1[key] = value
else:
if not isinstance(cfg1[key], list):
raise TypeError("cfg1[%r] should be a list of strings" % (key,))
if not isinstance(value, list):
raise TypeError("cfg2[%r] should be a list of strings" % (key,))
cfg1[key].extend(value)
return cfg1
def call(libname, flag, encoding=sys.getfilesystemencoding()):
"""Calls pkg-config and returns the output if found
"""
a = ["pkg-config", "--print-errors"]
a.append(flag)
a.append(libname)
try:
pc = subprocess.Popen(a, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except EnvironmentError as e:
raise PkgConfigError("cannot run pkg-config: %s" % (str(e).strip(),))
bout, berr = pc.communicate()
if pc.returncode != 0:
try:
berr = berr.decode(encoding)
except Exception:
pass
raise PkgConfigError(berr.strip())
if sys.version_info >= (3,) and not isinstance(bout, str): # Python 3.x
try:
bout = bout.decode(encoding)
except UnicodeDecodeError:
raise PkgConfigError("pkg-config %s %s returned bytes that cannot "
"be decoded with encoding %r:\n%r" %
(flag, libname, encoding, bout))
if os.altsep != '\\' and '\\' in bout:
raise PkgConfigError("pkg-config %s %s returned an unsupported "
"backslash-escaped output:\n%r" %
(flag, libname, bout))
return bout
def flags_from_pkgconfig(libs):
r"""Return compiler line flags for FFI.set_source based on pkg-config output
Usage
...
ffibuilder.set_source("_foo", pkgconfig = ["libfoo", "libbar >= 1.8.3"])
If pkg-config is installed on build machine, then arguments include_dirs,
library_dirs, libraries, define_macros, extra_compile_args and
extra_link_args are extended with an output of pkg-config for libfoo and
libbar.
Raises PkgConfigError in case the pkg-config call fails.
"""
def get_include_dirs(string):
return [x[2:] for x in string.split() if x.startswith("-I")]
def get_library_dirs(string):
return [x[2:] for x in string.split() if x.startswith("-L")]
def get_libraries(string):
return [x[2:] for x in string.split() if x.startswith("-l")]
# convert -Dfoo=bar to list of tuples [("foo", "bar")] expected by distutils
def get_macros(string):
def _macro(x):
x = x[2:] # drop "-D"
if '=' in x:
return tuple(x.split("=", 1)) # "-Dfoo=bar" => ("foo", "bar")
else:
return (x, None) # "-Dfoo" => ("foo", None)
return [_macro(x) for x in string.split() if x.startswith("-D")]
def get_other_cflags(string):
return [x for x in string.split() if not x.startswith("-I") and
not x.startswith("-D")]
def get_other_libs(string):
return [x for x in string.split() if not x.startswith("-L") and
not x.startswith("-l")]
# return kwargs for given libname
def kwargs(libname):
fse = sys.getfilesystemencoding()
all_cflags = call(libname, "--cflags")
all_libs = call(libname, "--libs")
return {
"include_dirs": get_include_dirs(all_cflags),
"library_dirs": get_library_dirs(all_libs),
"libraries": get_libraries(all_libs),
"define_macros": get_macros(all_cflags),
"extra_compile_args": get_other_cflags(all_cflags),
"extra_link_args": get_other_libs(all_libs),
}
# merge all arguments together
ret = {}
for libname in libs:
lib_flags = kwargs(libname)
merge_flags(ret, lib_flags)
return ret
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/recompiler.py
================================================
import os, sys, io
from . import ffiplatform, model
from .error import VerificationError
from .cffi_opcode import *
VERSION_BASE = 0x2601
VERSION_EMBEDDED = 0x2701
VERSION_CHAR16CHAR32 = 0x2801
class GlobalExpr:
def __init__(self, name, address, type_op, size=0, check_value=0):
self.name = name
self.address = address
self.type_op = type_op
self.size = size
self.check_value = check_value
def as_c_expr(self):
return ' { "%s", (void *)%s, %s, (void *)%s },' % (
self.name, self.address, self.type_op.as_c_expr(), self.size)
def as_python_expr(self):
return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name,
self.check_value)
class FieldExpr:
def __init__(self, name, field_offset, field_size, fbitsize, field_type_op):
self.name = name
self.field_offset = field_offset
self.field_size = field_size
self.fbitsize = fbitsize
self.field_type_op = field_type_op
def as_c_expr(self):
spaces = " " * len(self.name)
return (' { "%s", %s,\n' % (self.name, self.field_offset) +
' %s %s,\n' % (spaces, self.field_size) +
' %s %s },' % (spaces, self.field_type_op.as_c_expr()))
def as_python_expr(self):
raise NotImplementedError
def as_field_python_expr(self):
if self.field_type_op.op == OP_NOOP:
size_expr = ''
elif self.field_type_op.op == OP_BITFIELD:
size_expr = format_four_bytes(self.fbitsize)
else:
raise NotImplementedError
return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(),
size_expr,
self.name)
class StructUnionExpr:
def __init__(self, name, type_index, flags, size, alignment, comment,
first_field_index, c_fields):
self.name = name
self.type_index = type_index
self.flags = flags
self.size = size
self.alignment = alignment
self.comment = comment
self.first_field_index = first_field_index
self.c_fields = c_fields
def as_c_expr(self):
return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags)
+ '\n %s, %s, ' % (self.size, self.alignment)
+ '%d, %d ' % (self.first_field_index, len(self.c_fields))
+ ('/* %s */ ' % self.comment if self.comment else '')
+ '},')
def as_python_expr(self):
flags = eval(self.flags, G_FLAGS)
fields_expr = [c_field.as_field_python_expr()
for c_field in self.c_fields]
return "(b'%s%s%s',%s)" % (
format_four_bytes(self.type_index),
format_four_bytes(flags),
self.name,
','.join(fields_expr))
class EnumExpr:
def __init__(self, name, type_index, size, signed, allenums):
self.name = name
self.type_index = type_index
self.size = size
self.signed = signed
self.allenums = allenums
def as_c_expr(self):
return (' { "%s", %d, _cffi_prim_int(%s, %s),\n'
' "%s" },' % (self.name, self.type_index,
self.size, self.signed, self.allenums))
def as_python_expr(self):
prim_index = {
(1, 0): PRIM_UINT8, (1, 1): PRIM_INT8,
(2, 0): PRIM_UINT16, (2, 1): PRIM_INT16,
(4, 0): PRIM_UINT32, (4, 1): PRIM_INT32,
(8, 0): PRIM_UINT64, (8, 1): PRIM_INT64,
}[self.size, self.signed]
return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index),
format_four_bytes(prim_index),
self.name, self.allenums)
class TypenameExpr:
def __init__(self, name, type_index):
self.name = name
self.type_index = type_index
def as_c_expr(self):
return ' { "%s", %d },' % (self.name, self.type_index)
def as_python_expr(self):
return "b'%s%s'" % (format_four_bytes(self.type_index), self.name)
# ____________________________________________________________
class Recompiler:
_num_externpy = 0
def __init__(self, ffi, module_name, target_is_python=False):
self.ffi = ffi
self.module_name = module_name
self.target_is_python = target_is_python
self._version = VERSION_BASE
def needs_version(self, ver):
self._version = max(self._version, ver)
def collect_type_table(self):
self._typesdict = {}
self._generate("collecttype")
#
all_decls = sorted(self._typesdict, key=str)
#
# prepare all FUNCTION bytecode sequences first
self.cffi_types = []
for tp in all_decls:
if tp.is_raw_function:
assert self._typesdict[tp] is None
self._typesdict[tp] = len(self.cffi_types)
self.cffi_types.append(tp) # placeholder
for tp1 in tp.args:
assert isinstance(tp1, (model.VoidType,
model.BasePrimitiveType,
model.PointerType,
model.StructOrUnionOrEnum,
model.FunctionPtrType))
if self._typesdict[tp1] is None:
self._typesdict[tp1] = len(self.cffi_types)
self.cffi_types.append(tp1) # placeholder
self.cffi_types.append('END') # placeholder
#
# prepare all OTHER bytecode sequences
for tp in all_decls:
if not tp.is_raw_function and self._typesdict[tp] is None:
self._typesdict[tp] = len(self.cffi_types)
self.cffi_types.append(tp) # placeholder
if tp.is_array_type and tp.length is not None:
self.cffi_types.append('LEN') # placeholder
assert None not in self._typesdict.values()
#
# collect all structs and unions and enums
self._struct_unions = {}
self._enums = {}
for tp in all_decls:
if isinstance(tp, model.StructOrUnion):
self._struct_unions[tp] = None
elif isinstance(tp, model.EnumType):
self._enums[tp] = None
for i, tp in enumerate(sorted(self._struct_unions,
key=lambda tp: tp.name)):
self._struct_unions[tp] = i
for i, tp in enumerate(sorted(self._enums,
key=lambda tp: tp.name)):
self._enums[tp] = i
#
# emit all bytecode sequences now
for tp in all_decls:
method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__)
method(tp, self._typesdict[tp])
#
# consistency check
for op in self.cffi_types:
assert isinstance(op, CffiOp)
self.cffi_types = tuple(self.cffi_types) # don't change any more
def _do_collect_type(self, tp):
if not isinstance(tp, model.BaseTypeByIdentity):
if isinstance(tp, tuple):
for x in tp:
self._do_collect_type(x)
return
if tp not in self._typesdict:
self._typesdict[tp] = None
if isinstance(tp, model.FunctionPtrType):
self._do_collect_type(tp.as_raw_function())
elif isinstance(tp, model.StructOrUnion):
if tp.fldtypes is not None and (
tp not in self.ffi._parser._included_declarations):
for name1, tp1, _, _ in tp.enumfields():
self._do_collect_type(self._field_type(tp, name1, tp1))
else:
for _, x in tp._get_items():
self._do_collect_type(x)
def _generate(self, step_name):
lst = self.ffi._parser._declarations.items()
for name, (tp, quals) in sorted(lst):
kind, realname = name.split(' ', 1)
try:
method = getattr(self, '_generate_cpy_%s_%s' % (kind,
step_name))
except AttributeError:
raise VerificationError(
"not implemented in recompile(): %r" % name)
try:
self._current_quals = quals
method(tp, realname)
except Exception as e:
model.attach_exception_info(e, name)
raise
# ----------
ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"]
def collect_step_tables(self):
# collect the declarations for '_cffi_globals', '_cffi_typenames', etc.
self._lsts = {}
for step_name in self.ALL_STEPS:
self._lsts[step_name] = []
self._seen_struct_unions = set()
self._generate("ctx")
self._add_missing_struct_unions()
#
for step_name in self.ALL_STEPS:
lst = self._lsts[step_name]
if step_name != "field":
lst.sort(key=lambda entry: entry.name)
self._lsts[step_name] = tuple(lst) # don't change any more
#
# check for a possible internal inconsistency: _cffi_struct_unions
# should have been generated with exactly self._struct_unions
lst = self._lsts["struct_union"]
for tp, i in self._struct_unions.items():
assert i < len(lst)
assert lst[i].name == tp.name
assert len(lst) == len(self._struct_unions)
# same with enums
lst = self._lsts["enum"]
for tp, i in self._enums.items():
assert i < len(lst)
assert lst[i].name == tp.name
assert len(lst) == len(self._enums)
# ----------
def _prnt(self, what=''):
self._f.write(what + '\n')
def write_source_to_f(self, f, preamble):
if self.target_is_python:
assert preamble is None
self.write_py_source_to_f(f)
else:
assert preamble is not None
self.write_c_source_to_f(f, preamble)
def _rel_readlines(self, filename):
g = open(os.path.join(os.path.dirname(__file__), filename), 'r')
lines = g.readlines()
g.close()
return lines
def write_c_source_to_f(self, f, preamble):
self._f = f
prnt = self._prnt
if self.ffi._embedding is not None:
prnt('#define _CFFI_USE_EMBEDDING')
#
# first the '#include' (actually done by inlining the file's content)
lines = self._rel_readlines('_cffi_include.h')
i = lines.index('#include "parse_c_type.h"\n')
lines[i:i+1] = self._rel_readlines('parse_c_type.h')
prnt(''.join(lines))
#
# if we have ffi._embedding != None, we give it here as a macro
# and include an extra file
base_module_name = self.module_name.split('.')[-1]
if self.ffi._embedding is not None:
prnt('#define _CFFI_MODULE_NAME "%s"' % (self.module_name,))
prnt('static const char _CFFI_PYTHON_STARTUP_CODE[] = {')
self._print_string_literal_in_array(self.ffi._embedding)
prnt('0 };')
prnt('#ifdef PYPY_VERSION')
prnt('# define _CFFI_PYTHON_STARTUP_FUNC _cffi_pypyinit_%s' % (
base_module_name,))
prnt('#elif PY_MAJOR_VERSION >= 3')
prnt('# define _CFFI_PYTHON_STARTUP_FUNC PyInit_%s' % (
base_module_name,))
prnt('#else')
prnt('# define _CFFI_PYTHON_STARTUP_FUNC init%s' % (
base_module_name,))
prnt('#endif')
lines = self._rel_readlines('_embedding.h')
i = lines.index('#include "_cffi_errors.h"\n')
lines[i:i+1] = self._rel_readlines('_cffi_errors.h')
prnt(''.join(lines))
self.needs_version(VERSION_EMBEDDED)
#
# then paste the C source given by the user, verbatim.
prnt('/************************************************************/')
prnt()
prnt(preamble)
prnt()
prnt('/************************************************************/')
prnt()
#
# the declaration of '_cffi_types'
prnt('static void *_cffi_types[] = {')
typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()])
for i, op in enumerate(self.cffi_types):
comment = ''
if i in typeindex2type:
comment = ' // ' + typeindex2type[i]._get_c_name()
prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment))
if not self.cffi_types:
prnt(' 0')
prnt('};')
prnt()
#
# call generate_cpy_xxx_decl(), for every xxx found from
# ffi._parser._declarations. This generates all the functions.
self._seen_constants = set()
self._generate("decl")
#
# the declaration of '_cffi_globals' and '_cffi_typenames'
nums = {}
for step_name in self.ALL_STEPS:
lst = self._lsts[step_name]
nums[step_name] = len(lst)
if nums[step_name] > 0:
prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % (
step_name, step_name))
for entry in lst:
prnt(entry.as_c_expr())
prnt('};')
prnt()
#
# the declaration of '_cffi_includes'
if self.ffi._included_ffis:
prnt('static const char * const _cffi_includes[] = {')
for ffi_to_include in self.ffi._included_ffis:
try:
included_module_name, included_source = (
ffi_to_include._assigned_source[:2])
except AttributeError:
raise VerificationError(
"ffi object %r includes %r, but the latter has not "
"been prepared with set_source()" % (
self.ffi, ffi_to_include,))
if included_source is None:
raise VerificationError(
"not implemented yet: ffi.include() of a Python-based "
"ffi inside a C-based ffi")
prnt(' "%s",' % (included_module_name,))
prnt(' NULL')
prnt('};')
prnt()
#
# the declaration of '_cffi_type_context'
prnt('static const struct _cffi_type_context_s _cffi_type_context = {')
prnt(' _cffi_types,')
for step_name in self.ALL_STEPS:
if nums[step_name] > 0:
prnt(' _cffi_%ss,' % step_name)
else:
prnt(' NULL, /* no %ss */' % step_name)
for step_name in self.ALL_STEPS:
if step_name != "field":
prnt(' %d, /* num_%ss */' % (nums[step_name], step_name))
if self.ffi._included_ffis:
prnt(' _cffi_includes,')
else:
prnt(' NULL, /* no includes */')
prnt(' %d, /* num_types */' % (len(self.cffi_types),))
flags = 0
if self._num_externpy:
flags |= 1 # set to mean that we use extern "Python"
prnt(' %d, /* flags */' % flags)
prnt('};')
prnt()
#
# the init function
prnt('#ifdef __GNUC__')
prnt('# pragma GCC visibility push(default) /* for -fvisibility= */')
prnt('#endif')
prnt()
prnt('#ifdef PYPY_VERSION')
prnt('PyMODINIT_FUNC')
prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,))
prnt('{')
if self._num_externpy:
prnt(' if (((intptr_t)p[0]) >= 0x0A03) {')
prnt(' _cffi_call_python_org = '
'(void(*)(struct _cffi_externpy_s *, char *))p[1];')
prnt(' }')
prnt(' p[0] = (const void *)0x%x;' % self._version)
prnt(' p[1] = &_cffi_type_context;')
prnt('#if PY_MAJOR_VERSION >= 3')
prnt(' return NULL;')
prnt('#endif')
prnt('}')
# on Windows, distutils insists on putting init_cffi_xyz in
# 'export_symbols', so instead of fighting it, just give up and
# give it one
prnt('# ifdef _MSC_VER')
prnt(' PyMODINIT_FUNC')
prnt('# if PY_MAJOR_VERSION >= 3')
prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,))
prnt('# else')
prnt(' init%s(void) { }' % (base_module_name,))
prnt('# endif')
prnt('# endif')
prnt('#elif PY_MAJOR_VERSION >= 3')
prnt('PyMODINIT_FUNC')
prnt('PyInit_%s(void)' % (base_module_name,))
prnt('{')
prnt(' return _cffi_init("%s", 0x%x, &_cffi_type_context);' % (
self.module_name, self._version))
prnt('}')
prnt('#else')
prnt('PyMODINIT_FUNC')
prnt('init%s(void)' % (base_module_name,))
prnt('{')
prnt(' _cffi_init("%s", 0x%x, &_cffi_type_context);' % (
self.module_name, self._version))
prnt('}')
prnt('#endif')
prnt()
prnt('#ifdef __GNUC__')
prnt('# pragma GCC visibility pop')
prnt('#endif')
self._version = None
def _to_py(self, x):
if isinstance(x, str):
return "b'%s'" % (x,)
if isinstance(x, (list, tuple)):
rep = [self._to_py(item) for item in x]
if len(rep) == 1:
rep.append('')
return "(%s)" % (','.join(rep),)
return x.as_python_expr() # Py2: unicode unexpected; Py3: bytes unexp.
def write_py_source_to_f(self, f):
self._f = f
prnt = self._prnt
#
# header
prnt("# auto-generated file")
prnt("import _cffi_backend")
#
# the 'import' of the included ffis
num_includes = len(self.ffi._included_ffis or ())
for i in range(num_includes):
ffi_to_include = self.ffi._included_ffis[i]
try:
included_module_name, included_source = (
ffi_to_include._assigned_source[:2])
except AttributeError:
raise VerificationError(
"ffi object %r includes %r, but the latter has not "
"been prepared with set_source()" % (
self.ffi, ffi_to_include,))
if included_source is not None:
raise VerificationError(
"not implemented yet: ffi.include() of a C-based "
"ffi inside a Python-based ffi")
prnt('from %s import ffi as _ffi%d' % (included_module_name, i))
prnt()
prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,))
prnt(" _version = 0x%x," % (self._version,))
self._version = None
#
# the '_types' keyword argument
self.cffi_types = tuple(self.cffi_types) # don't change any more
types_lst = [op.as_python_bytes() for op in self.cffi_types]
prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),))
typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()])
#
# the keyword arguments from ALL_STEPS
for step_name in self.ALL_STEPS:
lst = self._lsts[step_name]
if len(lst) > 0 and step_name != "field":
prnt(' _%ss = %s,' % (step_name, self._to_py(lst)))
#
# the '_includes' keyword argument
if num_includes > 0:
prnt(' _includes = (%s,),' % (
', '.join(['_ffi%d' % i for i in range(num_includes)]),))
#
# the footer
prnt(')')
# ----------
def _gettypenum(self, type):
# a KeyError here is a bug. please report it! :-)
return self._typesdict[type]
def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode):
extraarg = ''
if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type():
if tp.is_integer_type() and tp.name != '_Bool':
converter = '_cffi_to_c_int'
extraarg = ', %s' % tp.name
elif isinstance(tp, model.UnknownFloatType):
# don't check with is_float_type(): it may be a 'long
# double' here, and _cffi_to_c_double would loose precision
converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),)
else:
cname = tp.get_c_name('')
converter = '(%s)_cffi_to_c_%s' % (cname,
tp.name.replace(' ', '_'))
if cname in ('char16_t', 'char32_t'):
self.needs_version(VERSION_CHAR16CHAR32)
errvalue = '-1'
#
elif isinstance(tp, model.PointerType):
self._convert_funcarg_to_c_ptr_or_array(tp, fromvar,
tovar, errcode)
return
#
elif (isinstance(tp, model.StructOrUnionOrEnum) or
isinstance(tp, model.BasePrimitiveType)):
# a struct (not a struct pointer) as a function argument;
# or, a complex (the same code works)
self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)'
% (tovar, self._gettypenum(tp), fromvar))
self._prnt(' %s;' % errcode)
return
#
elif isinstance(tp, model.FunctionPtrType):
converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('')
extraarg = ', _cffi_type(%d)' % self._gettypenum(tp)
errvalue = 'NULL'
#
else:
raise NotImplementedError(tp)
#
self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg))
self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % (
tovar, tp.get_c_name(''), errvalue))
self._prnt(' %s;' % errcode)
def _extra_local_variables(self, tp, localvars):
if isinstance(tp, model.PointerType):
localvars.add('Py_ssize_t datasize')
def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode):
self._prnt(' datasize = _cffi_prepare_pointer_call_argument(')
self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % (
self._gettypenum(tp), fromvar, tovar))
self._prnt(' if (datasize != 0) {')
self._prnt(' if (datasize < 0)')
self._prnt(' %s;' % errcode)
self._prnt(' %s = (%s)alloca((size_t)datasize);' % (
tovar, tp.get_c_name('')))
self._prnt(' memset((void *)%s, 0, (size_t)datasize);' % (tovar,))
self._prnt(' if (_cffi_convert_array_from_object('
'(char *)%s, _cffi_type(%d), %s) < 0)' % (
tovar, self._gettypenum(tp), fromvar))
self._prnt(' %s;' % errcode)
self._prnt(' }')
def _convert_expr_from_c(self, tp, var, context):
if isinstance(tp, model.BasePrimitiveType):
if tp.is_integer_type() and tp.name != '_Bool':
return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
elif isinstance(tp, model.UnknownFloatType):
return '_cffi_from_c_double(%s)' % (var,)
elif tp.name != 'long double' and not tp.is_complex_type():
cname = tp.name.replace(' ', '_')
if cname in ('char16_t', 'char32_t'):
self.needs_version(VERSION_CHAR16CHAR32)
return '_cffi_from_c_%s(%s)' % (cname, var)
else:
return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
var, self._gettypenum(tp))
elif isinstance(tp, (model.PointerType, model.FunctionPtrType)):
return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
var, self._gettypenum(tp))
elif isinstance(tp, model.ArrayType):
return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
var, self._gettypenum(model.PointerType(tp.item)))
elif isinstance(tp, model.StructOrUnion):
if tp.fldnames is None:
raise TypeError("'%s' is used as %s, but is opaque" % (
tp._get_c_name(), context))
return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % (
var, self._gettypenum(tp))
elif isinstance(tp, model.EnumType):
return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
var, self._gettypenum(tp))
else:
raise NotImplementedError(tp)
# ----------
# typedefs
def _typedef_type(self, tp, name):
return self._global_type(tp, "(*(%s *)0)" % (name,))
def _generate_cpy_typedef_collecttype(self, tp, name):
self._do_collect_type(self._typedef_type(tp, name))
def _generate_cpy_typedef_decl(self, tp, name):
pass
def _typedef_ctx(self, tp, name):
type_index = self._typesdict[tp]
self._lsts["typename"].append(TypenameExpr(name, type_index))
def _generate_cpy_typedef_ctx(self, tp, name):
tp = self._typedef_type(tp, name)
self._typedef_ctx(tp, name)
if getattr(tp, "origin", None) == "unknown_type":
self._struct_ctx(tp, tp.name, approxname=None)
elif isinstance(tp, model.NamedPointerType):
self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name,
named_ptr=tp)
# ----------
# function declarations
def _generate_cpy_function_collecttype(self, tp, name):
self._do_collect_type(tp.as_raw_function())
if tp.ellipsis and not self.target_is_python:
self._do_collect_type(tp)
def _generate_cpy_function_decl(self, tp, name):
assert not self.target_is_python
assert isinstance(tp, model.FunctionPtrType)
if tp.ellipsis:
# cannot support vararg functions better than this: check for its
# exact type (including the fixed arguments), and build it as a
# constant function pointer (no CPython wrapper)
self._generate_cpy_constant_decl(tp, name)
return
prnt = self._prnt
numargs = len(tp.args)
if numargs == 0:
argname = 'noarg'
elif numargs == 1:
argname = 'arg0'
else:
argname = 'args'
#
# ------------------------------
# the 'd' version of the function, only for addressof(lib, 'func')
arguments = []
call_arguments = []
context = 'argument of %s' % name
for i, type in enumerate(tp.args):
arguments.append(type.get_c_name(' x%d' % i, context))
call_arguments.append('x%d' % i)
repr_arguments = ', '.join(arguments)
repr_arguments = repr_arguments or 'void'
if tp.abi:
abi = tp.abi + ' '
else:
abi = ''
name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments)
prnt('static %s' % (tp.result.get_c_name(name_and_arguments),))
prnt('{')
call_arguments = ', '.join(call_arguments)
result_code = 'return '
if isinstance(tp.result, model.VoidType):
result_code = ''
prnt(' %s%s(%s);' % (result_code, name, call_arguments))
prnt('}')
#
prnt('#ifndef PYPY_VERSION') # ------------------------------
#
prnt('static PyObject *')
prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
prnt('{')
#
context = 'argument of %s' % name
for i, type in enumerate(tp.args):
arg = type.get_c_name(' x%d' % i, context)
prnt(' %s;' % arg)
#
localvars = set()
for type in tp.args:
self._extra_local_variables(type, localvars)
for decl in localvars:
prnt(' %s;' % (decl,))
#
if not isinstance(tp.result, model.VoidType):
result_code = 'result = '
context = 'result of %s' % name
result_decl = ' %s;' % tp.result.get_c_name(' result', context)
prnt(result_decl)
else:
result_decl = None
result_code = ''
#
if len(tp.args) > 1:
rng = range(len(tp.args))
for i in rng:
prnt(' PyObject *arg%d;' % i)
prnt()
prnt(' if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % (
name, len(rng), len(rng),
', '.join(['&arg%d' % i for i in rng])))
prnt(' return NULL;')
prnt()
#
for i, type in enumerate(tp.args):
self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i,
'return NULL')
prnt()
#
prnt(' Py_BEGIN_ALLOW_THREADS')
prnt(' _cffi_restore_errno();')
call_arguments = ['x%d' % i for i in range(len(tp.args))]
call_arguments = ', '.join(call_arguments)
prnt(' { %s%s(%s); }' % (result_code, name, call_arguments))
prnt(' _cffi_save_errno();')
prnt(' Py_END_ALLOW_THREADS')
prnt()
#
prnt(' (void)self; /* unused */')
if numargs == 0:
prnt(' (void)noarg; /* unused */')
if result_code:
prnt(' return %s;' %
self._convert_expr_from_c(tp.result, 'result', 'result type'))
else:
prnt(' Py_INCREF(Py_None);')
prnt(' return Py_None;')
prnt('}')
#
prnt('#else') # ------------------------------
#
# the PyPy version: need to replace struct/union arguments with
# pointers, and if the result is a struct/union, insert a first
# arg that is a pointer to the result. We also do that for
# complex args and return type.
def need_indirection(type):
return (isinstance(type, model.StructOrUnion) or
(isinstance(type, model.PrimitiveType) and
type.is_complex_type()))
difference = False
arguments = []
call_arguments = []
context = 'argument of %s' % name
for i, type in enumerate(tp.args):
indirection = ''
if need_indirection(type):
indirection = '*'
difference = True
arg = type.get_c_name(' %sx%d' % (indirection, i), context)
arguments.append(arg)
call_arguments.append('%sx%d' % (indirection, i))
tp_result = tp.result
if need_indirection(tp_result):
context = 'result of %s' % name
arg = tp_result.get_c_name(' *result', context)
arguments.insert(0, arg)
tp_result = model.void_type
result_decl = None
result_code = '*result = '
difference = True
if difference:
repr_arguments = ', '.join(arguments)
repr_arguments = repr_arguments or 'void'
name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name,
repr_arguments)
prnt('static %s' % (tp_result.get_c_name(name_and_arguments),))
prnt('{')
if result_decl:
prnt(result_decl)
call_arguments = ', '.join(call_arguments)
prnt(' { %s%s(%s); }' % (result_code, name, call_arguments))
if result_decl:
prnt(' return result;')
prnt('}')
else:
prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name))
#
prnt('#endif') # ------------------------------
prnt()
def _generate_cpy_function_ctx(self, tp, name):
if tp.ellipsis and not self.target_is_python:
self._generate_cpy_constant_ctx(tp, name)
return
type_index = self._typesdict[tp.as_raw_function()]
numargs = len(tp.args)
if self.target_is_python:
meth_kind = OP_DLOPEN_FUNC
elif numargs == 0:
meth_kind = OP_CPYTHON_BLTN_N # 'METH_NOARGS'
elif numargs == 1:
meth_kind = OP_CPYTHON_BLTN_O # 'METH_O'
else:
meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS'
self._lsts["global"].append(
GlobalExpr(name, '_cffi_f_%s' % name,
CffiOp(meth_kind, type_index),
size='_cffi_d_%s' % name))
# ----------
# named structs or unions
def _field_type(self, tp_struct, field_name, tp_field):
if isinstance(tp_field, model.ArrayType):
actual_length = tp_field.length
if actual_length == '...':
ptr_struct_name = tp_struct.get_c_name('*')
actual_length = '_cffi_array_len(((%s)0)->%s)' % (
ptr_struct_name, field_name)
tp_item = self._field_type(tp_struct, '%s[0]' % field_name,
tp_field.item)
tp_field = model.ArrayType(tp_item, actual_length)
return tp_field
def _struct_collecttype(self, tp):
self._do_collect_type(tp)
if self.target_is_python:
# also requires nested anon struct/unions in ABI mode, recursively
for fldtype in tp.anonymous_struct_fields():
self._struct_collecttype(fldtype)
def _struct_decl(self, tp, cname, approxname):
if tp.fldtypes is None:
return
prnt = self._prnt
checkfuncname = '_cffi_checkfld_%s' % (approxname,)
prnt('_CFFI_UNUSED_FN')
prnt('static void %s(%s *p)' % (checkfuncname, cname))
prnt('{')
prnt(' /* only to generate compile-time warnings or errors */')
prnt(' (void)p;')
for fname, ftype, fbitsize, fqual in tp.enumfields():
try:
if ftype.is_integer_type() or fbitsize >= 0:
# accept all integers, but complain on float or double
if fname != '':
prnt(" (void)((p->%s) | 0); /* check that '%s.%s' is "
"an integer */" % (fname, cname, fname))
continue
# only accept exactly the type declared, except that '[]'
# is interpreted as a '*' and so will match any array length.
# (It would also match '*', but that's harder to detect...)
while (isinstance(ftype, model.ArrayType)
and (ftype.length is None or ftype.length == '...')):
ftype = ftype.item
fname = fname + '[0]'
prnt(' { %s = &p->%s; (void)tmp; }' % (
ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
fname))
except VerificationError as e:
prnt(' /* %s */' % str(e)) # cannot verify it, ignore
prnt('}')
prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname))
prnt()
def _struct_ctx(self, tp, cname, approxname, named_ptr=None):
type_index = self._typesdict[tp]
reason_for_not_expanding = None
flags = []
if isinstance(tp, model.UnionType):
flags.append("_CFFI_F_UNION")
if tp.fldtypes is None:
flags.append("_CFFI_F_OPAQUE")
reason_for_not_expanding = "opaque"
if (tp not in self.ffi._parser._included_declarations and
(named_ptr is None or
named_ptr not in self.ffi._parser._included_declarations)):
if tp.fldtypes is None:
pass # opaque
elif tp.partial or any(tp.anonymous_struct_fields()):
pass # field layout obtained silently from the C compiler
else:
flags.append("_CFFI_F_CHECK_FIELDS")
if tp.packed:
if tp.packed > 1:
raise NotImplementedError(
"%r is declared with 'pack=%r'; only 0 or 1 are "
"supported in API mode (try to use \"...;\", which "
"does not require a 'pack' declaration)" %
(tp, tp.packed))
flags.append("_CFFI_F_PACKED")
else:
flags.append("_CFFI_F_EXTERNAL")
reason_for_not_expanding = "external"
flags = '|'.join(flags) or '0'
c_fields = []
if reason_for_not_expanding is None:
expand_anonymous_struct_union = not self.target_is_python
enumfields = list(tp.enumfields(expand_anonymous_struct_union))
for fldname, fldtype, fbitsize, fqual in enumfields:
fldtype = self._field_type(tp, fldname, fldtype)
self._check_not_opaque(fldtype,
"field '%s.%s'" % (tp.name, fldname))
# cname is None for _add_missing_struct_unions() only
op = OP_NOOP
if fbitsize >= 0:
op = OP_BITFIELD
size = '%d /* bits */' % fbitsize
elif cname is None or (
isinstance(fldtype, model.ArrayType) and
fldtype.length is None):
size = '(size_t)-1'
else:
size = 'sizeof(((%s)0)->%s)' % (
tp.get_c_name('*') if named_ptr is None
else named_ptr.name,
fldname)
if cname is None or fbitsize >= 0:
offset = '(size_t)-1'
elif named_ptr is not None:
offset = '((char *)&((%s)0)->%s) - (char *)0' % (
named_ptr.name, fldname)
else:
offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname)
c_fields.append(
FieldExpr(fldname, offset, size, fbitsize,
CffiOp(op, self._typesdict[fldtype])))
first_field_index = len(self._lsts["field"])
self._lsts["field"].extend(c_fields)
#
if cname is None: # unknown name, for _add_missing_struct_unions
size = '(size_t)-2'
align = -2
comment = "unnamed"
else:
if named_ptr is not None:
size = 'sizeof(*(%s)0)' % (named_ptr.name,)
align = '-1 /* unknown alignment */'
else:
size = 'sizeof(%s)' % (cname,)
align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,)
comment = None
else:
size = '(size_t)-1'
align = -1
first_field_index = -1
comment = reason_for_not_expanding
self._lsts["struct_union"].append(
StructUnionExpr(tp.name, type_index, flags, size, align, comment,
first_field_index, c_fields))
self._seen_struct_unions.add(tp)
def _check_not_opaque(self, tp, location):
while isinstance(tp, model.ArrayType):
tp = tp.item
if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None:
raise TypeError(
"%s is of an opaque type (not declared in cdef())" % location)
def _add_missing_struct_unions(self):
# not very nice, but some struct declarations might be missing
# because they don't have any known C name. Check that they are
# not partial (we can't complete or verify them!) and emit them
# anonymously.
lst = list(self._struct_unions.items())
lst.sort(key=lambda tp_order: tp_order[1])
for tp, order in lst:
if tp not in self._seen_struct_unions:
if tp.partial:
raise NotImplementedError("internal inconsistency: %r is "
"partial but was not seen at "
"this point" % (tp,))
if tp.name.startswith('$') and tp.name[1:].isdigit():
approxname = tp.name[1:]
elif tp.name == '_IO_FILE' and tp.forcename == 'FILE':
approxname = 'FILE'
self._typedef_ctx(tp, 'FILE')
else:
raise NotImplementedError("internal inconsistency: %r" %
(tp,))
self._struct_ctx(tp, None, approxname)
def _generate_cpy_struct_collecttype(self, tp, name):
self._struct_collecttype(tp)
_generate_cpy_union_collecttype = _generate_cpy_struct_collecttype
def _struct_names(self, tp):
cname = tp.get_c_name('')
if ' ' in cname:
return cname, cname.replace(' ', '_')
else:
return cname, '_' + cname
def _generate_cpy_struct_decl(self, tp, name):
self._struct_decl(tp, *self._struct_names(tp))
_generate_cpy_union_decl = _generate_cpy_struct_decl
def _generate_cpy_struct_ctx(self, tp, name):
self._struct_ctx(tp, *self._struct_names(tp))
_generate_cpy_union_ctx = _generate_cpy_struct_ctx
# ----------
# 'anonymous' declarations. These are produced for anonymous structs
# or unions; the 'name' is obtained by a typedef.
def _generate_cpy_anonymous_collecttype(self, tp, name):
if isinstance(tp, model.EnumType):
self._generate_cpy_enum_collecttype(tp, name)
else:
self._struct_collecttype(tp)
def _generate_cpy_anonymous_decl(self, tp, name):
if isinstance(tp, model.EnumType):
self._generate_cpy_enum_decl(tp)
else:
self._struct_decl(tp, name, 'typedef_' + name)
def _generate_cpy_anonymous_ctx(self, tp, name):
if isinstance(tp, model.EnumType):
self._enum_ctx(tp, name)
else:
self._struct_ctx(tp, name, 'typedef_' + name)
# ----------
# constants, declared with "static const ..."
def _generate_cpy_const(self, is_int, name, tp=None, category='const',
check_value=None):
if (category, name) in self._seen_constants:
raise VerificationError(
"duplicate declaration of %s '%s'" % (category, name))
self._seen_constants.add((category, name))
#
prnt = self._prnt
funcname = '_cffi_%s_%s' % (category, name)
if is_int:
prnt('static int %s(unsigned long long *o)' % funcname)
prnt('{')
prnt(' int n = (%s) <= 0;' % (name,))
prnt(' *o = (unsigned long long)((%s) | 0);'
' /* check that %s is an integer */' % (name, name))
if check_value is not None:
if check_value > 0:
check_value = '%dU' % (check_value,)
prnt(' if (!_cffi_check_int(*o, n, %s))' % (check_value,))
prnt(' n |= 2;')
prnt(' return n;')
prnt('}')
else:
assert check_value is None
prnt('static void %s(char *o)' % funcname)
prnt('{')
prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name))
prnt('}')
prnt()
def _generate_cpy_constant_collecttype(self, tp, name):
is_int = tp.is_integer_type()
if not is_int or self.target_is_python:
self._do_collect_type(tp)
def _generate_cpy_constant_decl(self, tp, name):
is_int = tp.is_integer_type()
self._generate_cpy_const(is_int, name, tp)
def _generate_cpy_constant_ctx(self, tp, name):
if not self.target_is_python and tp.is_integer_type():
type_op = CffiOp(OP_CONSTANT_INT, -1)
else:
if self.target_is_python:
const_kind = OP_DLOPEN_CONST
else:
const_kind = OP_CONSTANT
type_index = self._typesdict[tp]
type_op = CffiOp(const_kind, type_index)
self._lsts["global"].append(
GlobalExpr(name, '_cffi_const_%s' % name, type_op))
# ----------
# enums
def _generate_cpy_enum_collecttype(self, tp, name):
self._do_collect_type(tp)
def _generate_cpy_enum_decl(self, tp, name=None):
for enumerator in tp.enumerators:
self._generate_cpy_const(True, enumerator)
def _enum_ctx(self, tp, cname):
type_index = self._typesdict[tp]
type_op = CffiOp(OP_ENUM, -1)
if self.target_is_python:
tp.check_not_partial()
for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
self._lsts["global"].append(
GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op,
check_value=enumvalue))
#
if cname is not None and '$' not in cname and not self.target_is_python:
size = "sizeof(%s)" % cname
signed = "((%s)-1) <= 0" % cname
else:
basetp = tp.build_baseinttype(self.ffi, [])
size = self.ffi.sizeof(basetp)
signed = int(int(self.ffi.cast(basetp, -1)) < 0)
allenums = ",".join(tp.enumerators)
self._lsts["enum"].append(
EnumExpr(tp.name, type_index, size, signed, allenums))
def _generate_cpy_enum_ctx(self, tp, name):
self._enum_ctx(tp, tp._get_c_name())
# ----------
# macros: for now only for integers
def _generate_cpy_macro_collecttype(self, tp, name):
pass
def _generate_cpy_macro_decl(self, tp, name):
if tp == '...':
check_value = None
else:
check_value = tp # an integer
self._generate_cpy_const(True, name, check_value=check_value)
def _generate_cpy_macro_ctx(self, tp, name):
if tp == '...':
if self.target_is_python:
raise VerificationError(
"cannot use the syntax '...' in '#define %s ...' when "
"using the ABI mode" % (name,))
check_value = None
else:
check_value = tp # an integer
type_op = CffiOp(OP_CONSTANT_INT, -1)
self._lsts["global"].append(
GlobalExpr(name, '_cffi_const_%s' % name, type_op,
check_value=check_value))
# ----------
# global variables
def _global_type(self, tp, global_name):
if isinstance(tp, model.ArrayType):
actual_length = tp.length
if actual_length == '...':
actual_length = '_cffi_array_len(%s)' % (global_name,)
tp_item = self._global_type(tp.item, '%s[0]' % global_name)
tp = model.ArrayType(tp_item, actual_length)
return tp
def _generate_cpy_variable_collecttype(self, tp, name):
self._do_collect_type(self._global_type(tp, name))
def _generate_cpy_variable_decl(self, tp, name):
prnt = self._prnt
tp = self._global_type(tp, name)
if isinstance(tp, model.ArrayType) and tp.length is None:
tp = tp.item
ampersand = ''
else:
ampersand = '&'
# This code assumes that casts from "tp *" to "void *" is a
# no-op, i.e. a function that returns a "tp *" can be called
# as if it returned a "void *". This should be generally true
# on any modern machine. The only exception to that rule (on
# uncommon architectures, and as far as I can tell) might be
# if 'tp' were a function type, but that is not possible here.
# (If 'tp' is a function _pointer_ type, then casts from "fn_t
# **" to "void *" are again no-ops, as far as I can tell.)
decl = '*_cffi_var_%s(void)' % (name,)
prnt('static ' + tp.get_c_name(decl, quals=self._current_quals))
prnt('{')
prnt(' return %s(%s);' % (ampersand, name))
prnt('}')
prnt()
def _generate_cpy_variable_ctx(self, tp, name):
tp = self._global_type(tp, name)
type_index = self._typesdict[tp]
if self.target_is_python:
op = OP_GLOBAL_VAR
else:
op = OP_GLOBAL_VAR_F
self._lsts["global"].append(
GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index)))
# ----------
# extern "Python"
def _generate_cpy_extern_python_collecttype(self, tp, name):
assert isinstance(tp, model.FunctionPtrType)
self._do_collect_type(tp)
_generate_cpy_dllexport_python_collecttype = \
_generate_cpy_extern_python_plus_c_collecttype = \
_generate_cpy_extern_python_collecttype
def _extern_python_decl(self, tp, name, tag_and_space):
prnt = self._prnt
if isinstance(tp.result, model.VoidType):
size_of_result = '0'
else:
context = 'result of %s' % name
size_of_result = '(int)sizeof(%s)' % (
tp.result.get_c_name('', context),)
prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name)
prnt(' { "%s.%s", %s };' % (self.module_name, name, size_of_result))
prnt()
#
arguments = []
context = 'argument of %s' % name
for i, type in enumerate(tp.args):
arg = type.get_c_name(' a%d' % i, context)
arguments.append(arg)
#
repr_arguments = ', '.join(arguments)
repr_arguments = repr_arguments or 'void'
name_and_arguments = '%s(%s)' % (name, repr_arguments)
if tp.abi == "__stdcall":
name_and_arguments = '_cffi_stdcall ' + name_and_arguments
#
def may_need_128_bits(tp):
return (isinstance(tp, model.PrimitiveType) and
tp.name == 'long double')
#
size_of_a = max(len(tp.args)*8, 8)
if may_need_128_bits(tp.result):
size_of_a = max(size_of_a, 16)
if isinstance(tp.result, model.StructOrUnion):
size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % (
tp.result.get_c_name(''), size_of_a,
tp.result.get_c_name(''), size_of_a)
prnt('%s%s' % (tag_and_space, tp.result.get_c_name(name_and_arguments)))
prnt('{')
prnt(' char a[%s];' % size_of_a)
prnt(' char *p = a;')
for i, type in enumerate(tp.args):
arg = 'a%d' % i
if (isinstance(type, model.StructOrUnion) or
may_need_128_bits(type)):
arg = '&' + arg
type = model.PointerType(type)
prnt(' *(%s)(p + %d) = %s;' % (type.get_c_name('*'), i*8, arg))
prnt(' _cffi_call_python(&_cffi_externpy__%s, p);' % name)
if not isinstance(tp.result, model.VoidType):
prnt(' return *(%s)p;' % (tp.result.get_c_name('*'),))
prnt('}')
prnt()
self._num_externpy += 1
def _generate_cpy_extern_python_decl(self, tp, name):
self._extern_python_decl(tp, name, 'static ')
def _generate_cpy_dllexport_python_decl(self, tp, name):
self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ')
def _generate_cpy_extern_python_plus_c_decl(self, tp, name):
self._extern_python_decl(tp, name, '')
def _generate_cpy_extern_python_ctx(self, tp, name):
if self.target_is_python:
raise VerificationError(
"cannot use 'extern \"Python\"' in the ABI mode")
if tp.ellipsis:
raise NotImplementedError("a vararg function is extern \"Python\"")
type_index = self._typesdict[tp]
type_op = CffiOp(OP_EXTERN_PYTHON, type_index)
self._lsts["global"].append(
GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name))
_generate_cpy_dllexport_python_ctx = \
_generate_cpy_extern_python_plus_c_ctx = \
_generate_cpy_extern_python_ctx
def _print_string_literal_in_array(self, s):
prnt = self._prnt
prnt('// # NB. this is not a string because of a size limit in MSVC')
for line in s.splitlines(True):
prnt(('// ' + line).rstrip())
printed_line = ''
for c in line:
if len(printed_line) >= 76:
prnt(printed_line)
printed_line = ''
printed_line += '%d,' % (ord(c),)
prnt(printed_line)
# ----------
# emitting the opcodes for individual types
def _emit_bytecode_VoidType(self, tp, index):
self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID)
def _emit_bytecode_PrimitiveType(self, tp, index):
prim_index = PRIMITIVE_TO_INDEX[tp.name]
self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index)
def _emit_bytecode_UnknownIntegerType(self, tp, index):
s = ('_cffi_prim_int(sizeof(%s), (\n'
' ((%s)-1) | 0 /* check that %s is an integer type */\n'
' ) <= 0)' % (tp.name, tp.name, tp.name))
self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s)
def _emit_bytecode_UnknownFloatType(self, tp, index):
s = ('_cffi_prim_float(sizeof(%s) *\n'
' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n'
' )' % (tp.name, tp.name))
self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s)
def _emit_bytecode_RawFunctionType(self, tp, index):
self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result])
index += 1
for tp1 in tp.args:
realindex = self._typesdict[tp1]
if index != realindex:
if isinstance(tp1, model.PrimitiveType):
self._emit_bytecode_PrimitiveType(tp1, index)
else:
self.cffi_types[index] = CffiOp(OP_NOOP, realindex)
index += 1
flags = int(tp.ellipsis)
if tp.abi is not None:
if tp.abi == '__stdcall':
flags |= 2
else:
raise NotImplementedError("abi=%r" % (tp.abi,))
self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags)
def _emit_bytecode_PointerType(self, tp, index):
self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype])
_emit_bytecode_ConstPointerType = _emit_bytecode_PointerType
_emit_bytecode_NamedPointerType = _emit_bytecode_PointerType
def _emit_bytecode_FunctionPtrType(self, tp, index):
raw = tp.as_raw_function()
self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw])
def _emit_bytecode_ArrayType(self, tp, index):
item_index = self._typesdict[tp.item]
if tp.length is None:
self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index)
elif tp.length == '...':
raise VerificationError(
"type %s badly placed: the '...' array length can only be "
"used on global arrays or on fields of structures" % (
str(tp).replace('/*...*/', '...'),))
else:
assert self.cffi_types[index + 1] == 'LEN'
self.cffi_types[index] = CffiOp(OP_ARRAY, item_index)
self.cffi_types[index + 1] = CffiOp(None, str(tp.length))
def _emit_bytecode_StructType(self, tp, index):
struct_index = self._struct_unions[tp]
self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index)
_emit_bytecode_UnionType = _emit_bytecode_StructType
def _emit_bytecode_EnumType(self, tp, index):
enum_index = self._enums[tp]
self.cffi_types[index] = CffiOp(OP_ENUM, enum_index)
if sys.version_info >= (3,):
NativeIO = io.StringIO
else:
class NativeIO(io.BytesIO):
def write(self, s):
if isinstance(s, unicode):
s = s.encode('ascii')
super(NativeIO, self).write(s)
def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose):
if verbose:
print("generating %s" % (target_file,))
recompiler = Recompiler(ffi, module_name,
target_is_python=(preamble is None))
recompiler.collect_type_table()
recompiler.collect_step_tables()
f = NativeIO()
recompiler.write_source_to_f(f, preamble)
output = f.getvalue()
try:
with open(target_file, 'r') as f1:
if f1.read(len(output) + 1) != output:
raise IOError
if verbose:
print("(already up-to-date)")
return False # already up-to-date
except IOError:
tmp_file = '%s.~%d' % (target_file, os.getpid())
with open(tmp_file, 'w') as f1:
f1.write(output)
try:
os.rename(tmp_file, target_file)
except OSError:
os.unlink(target_file)
os.rename(tmp_file, target_file)
return True
def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False):
assert preamble is not None
return _make_c_or_py_source(ffi, module_name, preamble, target_c_file,
verbose)
def make_py_source(ffi, module_name, target_py_file, verbose=False):
return _make_c_or_py_source(ffi, module_name, None, target_py_file,
verbose)
def _modname_to_file(outputdir, modname, extension):
parts = modname.split('.')
try:
os.makedirs(os.path.join(outputdir, *parts[:-1]))
except OSError:
pass
parts[-1] += extension
return os.path.join(outputdir, *parts), parts
# Aaargh. Distutils is not tested at all for the purpose of compiling
# DLLs that are not extension modules. Here are some hacks to work
# around that, in the _patch_for_*() functions...
def _patch_meth(patchlist, cls, name, new_meth):
old = getattr(cls, name)
patchlist.append((cls, name, old))
setattr(cls, name, new_meth)
return old
def _unpatch_meths(patchlist):
for cls, name, old_meth in reversed(patchlist):
setattr(cls, name, old_meth)
def _patch_for_embedding(patchlist):
if sys.platform == 'win32':
# we must not remove the manifest when building for embedding!
from distutils.msvc9compiler import MSVCCompiler
_patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref',
lambda self, manifest_file: manifest_file)
if sys.platform == 'darwin':
# we must not make a '-bundle', but a '-dynamiclib' instead
from distutils.ccompiler import CCompiler
def my_link_shared_object(self, *args, **kwds):
if '-bundle' in self.linker_so:
self.linker_so = list(self.linker_so)
i = self.linker_so.index('-bundle')
self.linker_so[i] = '-dynamiclib'
return old_link_shared_object(self, *args, **kwds)
old_link_shared_object = _patch_meth(patchlist, CCompiler,
'link_shared_object',
my_link_shared_object)
def _patch_for_target(patchlist, target):
from distutils.command.build_ext import build_ext
# if 'target' is different from '*', we need to patch some internal
# method to just return this 'target' value, instead of having it
# built from module_name
if target.endswith('.*'):
target = target[:-2]
if sys.platform == 'win32':
target += '.dll'
elif sys.platform == 'darwin':
target += '.dylib'
else:
target += '.so'
_patch_meth(patchlist, build_ext, 'get_ext_filename',
lambda self, ext_name: target)
def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True,
c_file=None, source_extension='.c', extradir=None,
compiler_verbose=1, target=None, debug=None, **kwds):
if not isinstance(module_name, str):
module_name = module_name.encode('ascii')
if ffi._windows_unicode:
ffi._apply_windows_unicode(kwds)
if preamble is not None:
embedding = (ffi._embedding is not None)
if embedding:
ffi._apply_embedding_fix(kwds)
if c_file is None:
c_file, parts = _modname_to_file(tmpdir, module_name,
source_extension)
if extradir:
parts = [extradir] + parts
ext_c_file = os.path.join(*parts)
else:
ext_c_file = c_file
#
if target is None:
if embedding:
target = '%s.*' % module_name
else:
target = '*'
#
ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds)
updated = make_c_source(ffi, module_name, preamble, c_file,
verbose=compiler_verbose)
if call_c_compiler:
patchlist = []
cwd = os.getcwd()
try:
if embedding:
_patch_for_embedding(patchlist)
if target != '*':
_patch_for_target(patchlist, target)
if compiler_verbose:
if tmpdir == '.':
msg = 'the current directory is'
else:
msg = 'setting the current directory to'
print('%s %r' % (msg, os.path.abspath(tmpdir)))
os.chdir(tmpdir)
outputfilename = ffiplatform.compile('.', ext,
compiler_verbose, debug)
finally:
os.chdir(cwd)
_unpatch_meths(patchlist)
return outputfilename
else:
return ext, updated
else:
if c_file is None:
c_file, _ = _modname_to_file(tmpdir, module_name, '.py')
updated = make_py_source(ffi, module_name, c_file,
verbose=compiler_verbose)
if call_c_compiler:
return c_file
else:
return None, updated
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/setuptools_ext.py
================================================
import os
import sys
try:
basestring
except NameError:
# Python 3.x
basestring = str
def error(msg):
from distutils.errors import DistutilsSetupError
raise DistutilsSetupError(msg)
def execfile(filename, glob):
# We use execfile() (here rewritten for Python 3) instead of
# __import__() to load the build script. The problem with
# a normal import is that in some packages, the intermediate
# __init__.py files may already try to import the file that
# we are generating.
with open(filename) as f:
src = f.read()
src += '\n' # Python 2.6 compatibility
code = compile(src, filename, 'exec')
exec(code, glob, glob)
def add_cffi_module(dist, mod_spec):
from cffi.api import FFI
if not isinstance(mod_spec, basestring):
error("argument to 'cffi_modules=...' must be a str or a list of str,"
" not %r" % (type(mod_spec).__name__,))
mod_spec = str(mod_spec)
try:
build_file_name, ffi_var_name = mod_spec.split(':')
except ValueError:
error("%r must be of the form 'path/build.py:ffi_variable'" %
(mod_spec,))
if not os.path.exists(build_file_name):
ext = ''
rewritten = build_file_name.replace('.', '/') + '.py'
if os.path.exists(rewritten):
ext = ' (rewrite cffi_modules to [%r])' % (
rewritten + ':' + ffi_var_name,)
error("%r does not name an existing file%s" % (build_file_name, ext))
mod_vars = {'__name__': '__cffi__', '__file__': build_file_name}
execfile(build_file_name, mod_vars)
try:
ffi = mod_vars[ffi_var_name]
except KeyError:
error("%r: object %r not found in module" % (mod_spec,
ffi_var_name))
if not isinstance(ffi, FFI):
ffi = ffi() # maybe it's a function instead of directly an ffi
if not isinstance(ffi, FFI):
error("%r is not an FFI instance (got %r)" % (mod_spec,
type(ffi).__name__))
if not hasattr(ffi, '_assigned_source'):
error("%r: the set_source() method was not called" % (mod_spec,))
module_name, source, source_extension, kwds = ffi._assigned_source
if ffi._windows_unicode:
kwds = kwds.copy()
ffi._apply_windows_unicode(kwds)
if source is None:
_add_py_module(dist, ffi, module_name)
else:
_add_c_module(dist, ffi, module_name, source, source_extension, kwds)
def _set_py_limited_api(Extension, kwds):
"""
Add py_limited_api to kwds if setuptools >= 26 is in use.
Do not alter the setting if it already exists.
Setuptools takes care of ignoring the flag on Python 2 and PyPy.
CPython itself should ignore the flag in a debugging version
(by not listing .abi3.so in the extensions it supports), but
it doesn't so far, creating troubles. That's why we check
for "not hasattr(sys, 'gettotalrefcount')" (the 2.7 compatible equivalent
of 'd' not in sys.abiflags). (http://bugs.python.org/issue28401)
On Windows, with CPython <= 3.4, it's better not to use py_limited_api
because virtualenv *still* doesn't copy PYTHON3.DLL on these versions.
For now we'll skip py_limited_api on all Windows versions to avoid an
inconsistent mess.
"""
if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount')
and sys.platform != 'win32'):
import setuptools
try:
setuptools_major_version = int(setuptools.__version__.partition('.')[0])
if setuptools_major_version >= 26:
kwds['py_limited_api'] = True
except ValueError: # certain development versions of setuptools
# If we don't know the version number of setuptools, we
# try to set 'py_limited_api' anyway. At worst, we get a
# warning.
kwds['py_limited_api'] = True
return kwds
def _add_c_module(dist, ffi, module_name, source, source_extension, kwds):
from distutils.core import Extension
# We are a setuptools extension. Need this build_ext for py_limited_api.
from setuptools.command.build_ext import build_ext
from distutils.dir_util import mkpath
from distutils import log
from cffi import recompiler
allsources = ['$PLACEHOLDER']
allsources.extend(kwds.pop('sources', []))
kwds = _set_py_limited_api(Extension, kwds)
ext = Extension(name=module_name, sources=allsources, **kwds)
def make_mod(tmpdir, pre_run=None):
c_file = os.path.join(tmpdir, module_name + source_extension)
log.info("generating cffi module %r" % c_file)
mkpath(tmpdir)
# a setuptools-only, API-only hook: called with the "ext" and "ffi"
# arguments just before we turn the ffi into C code. To use it,
# subclass the 'distutils.command.build_ext.build_ext' class and
# add a method 'def pre_run(self, ext, ffi)'.
if pre_run is not None:
pre_run(ext, ffi)
updated = recompiler.make_c_source(ffi, module_name, source, c_file)
if not updated:
log.info("already up-to-date")
return c_file
if dist.ext_modules is None:
dist.ext_modules = []
dist.ext_modules.append(ext)
base_class = dist.cmdclass.get('build_ext', build_ext)
class build_ext_make_mod(base_class):
def run(self):
if ext.sources[0] == '$PLACEHOLDER':
pre_run = getattr(self, 'pre_run', None)
ext.sources[0] = make_mod(self.build_temp, pre_run)
base_class.run(self)
dist.cmdclass['build_ext'] = build_ext_make_mod
# NB. multiple runs here will create multiple 'build_ext_make_mod'
# classes. Even in this case the 'build_ext' command should be
# run once; but just in case, the logic above does nothing if
# called again.
def _add_py_module(dist, ffi, module_name):
from distutils.dir_util import mkpath
from setuptools.command.build_py import build_py
from setuptools.command.build_ext import build_ext
from distutils import log
from cffi import recompiler
def generate_mod(py_file):
log.info("generating cffi module %r" % py_file)
mkpath(os.path.dirname(py_file))
updated = recompiler.make_py_source(ffi, module_name, py_file)
if not updated:
log.info("already up-to-date")
base_class = dist.cmdclass.get('build_py', build_py)
class build_py_make_mod(base_class):
def run(self):
base_class.run(self)
module_path = module_name.split('.')
module_path[-1] += '.py'
generate_mod(os.path.join(self.build_lib, *module_path))
def get_source_files(self):
# This is called from 'setup.py sdist' only. Exclude
# the generate .py module in this case.
saved_py_modules = self.py_modules
try:
if saved_py_modules:
self.py_modules = [m for m in saved_py_modules
if m != module_name]
return base_class.get_source_files(self)
finally:
self.py_modules = saved_py_modules
dist.cmdclass['build_py'] = build_py_make_mod
# distutils and setuptools have no notion I could find of a
# generated python module. If we don't add module_name to
# dist.py_modules, then things mostly work but there are some
# combination of options (--root and --record) that will miss
# the module. So we add it here, which gives a few apparently
# harmless warnings about not finding the file outside the
# build directory.
# Then we need to hack more in get_source_files(); see above.
if dist.py_modules is None:
dist.py_modules = []
dist.py_modules.append(module_name)
# the following is only for "build_ext -i"
base_class_2 = dist.cmdclass.get('build_ext', build_ext)
class build_ext_make_mod(base_class_2):
def run(self):
base_class_2.run(self)
if self.inplace:
# from get_ext_fullpath() in distutils/command/build_ext.py
module_path = module_name.split('.')
package = '.'.join(module_path[:-1])
build_py = self.get_finalized_command('build_py')
package_dir = build_py.get_package_dir(package)
file_name = module_path[-1] + '.py'
generate_mod(os.path.join(package_dir, file_name))
dist.cmdclass['build_ext'] = build_ext_make_mod
def cffi_modules(dist, attr, value):
assert attr == 'cffi_modules'
if isinstance(value, basestring):
value = [value]
for cffi_module in value:
add_cffi_module(dist, cffi_module)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/vengine_cpy.py
================================================
#
# DEPRECATED: implementation for ffi.verify()
#
import sys, imp
from . import model
from .error import VerificationError
class VCPythonEngine(object):
_class_key = 'x'
_gen_python_module = True
def __init__(self, verifier):
self.verifier = verifier
self.ffi = verifier.ffi
self._struct_pending_verification = {}
self._types_of_builtin_functions = {}
def patch_extension_kwds(self, kwds):
pass
def find_module(self, module_name, path, so_suffixes):
try:
f, filename, descr = imp.find_module(module_name, path)
except ImportError:
return None
if f is not None:
f.close()
# Note that after a setuptools installation, there are both .py
# and .so files with the same basename. The code here relies on
# imp.find_module() locating the .so in priority.
if descr[0] not in so_suffixes:
return None
return filename
def collect_types(self):
self._typesdict = {}
self._generate("collecttype")
def _prnt(self, what=''):
self._f.write(what + '\n')
def _gettypenum(self, type):
# a KeyError here is a bug. please report it! :-)
return self._typesdict[type]
def _do_collect_type(self, tp):
if ((not isinstance(tp, model.PrimitiveType)
or tp.name == 'long double')
and tp not in self._typesdict):
num = len(self._typesdict)
self._typesdict[tp] = num
def write_source_to_f(self):
self.collect_types()
#
# The new module will have a _cffi_setup() function that receives
# objects from the ffi world, and that calls some setup code in
# the module. This setup code is split in several independent
# functions, e.g. one per constant. The functions are "chained"
# by ending in a tail call to each other.
#
# This is further split in two chained lists, depending on if we
# can do it at import-time or if we must wait for _cffi_setup() to
# provide us with the objects. This is needed because we
# need the values of the enum constants in order to build the
# that we may have to pass to _cffi_setup().
#
# The following two 'chained_list_constants' items contains
# the head of these two chained lists, as a string that gives the
# call to do, if any.
self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)']
#
prnt = self._prnt
# first paste some standard set of lines that are mostly '#define'
prnt(cffimod_header)
prnt()
# then paste the C source given by the user, verbatim.
prnt(self.verifier.preamble)
prnt()
#
# call generate_cpy_xxx_decl(), for every xxx found from
# ffi._parser._declarations. This generates all the functions.
self._generate("decl")
#
# implement the function _cffi_setup_custom() as calling the
# head of the chained list.
self._generate_setup_custom()
prnt()
#
# produce the method table, including the entries for the
# generated Python->C function wrappers, which are done
# by generate_cpy_function_method().
prnt('static PyMethodDef _cffi_methods[] = {')
self._generate("method")
prnt(' {"_cffi_setup", _cffi_setup, METH_VARARGS, NULL},')
prnt(' {NULL, NULL, 0, NULL} /* Sentinel */')
prnt('};')
prnt()
#
# standard init.
modname = self.verifier.get_module_name()
constants = self._chained_list_constants[False]
prnt('#if PY_MAJOR_VERSION >= 3')
prnt()
prnt('static struct PyModuleDef _cffi_module_def = {')
prnt(' PyModuleDef_HEAD_INIT,')
prnt(' "%s",' % modname)
prnt(' NULL,')
prnt(' -1,')
prnt(' _cffi_methods,')
prnt(' NULL, NULL, NULL, NULL')
prnt('};')
prnt()
prnt('PyMODINIT_FUNC')
prnt('PyInit_%s(void)' % modname)
prnt('{')
prnt(' PyObject *lib;')
prnt(' lib = PyModule_Create(&_cffi_module_def);')
prnt(' if (lib == NULL)')
prnt(' return NULL;')
prnt(' if (%s < 0 || _cffi_init() < 0) {' % (constants,))
prnt(' Py_DECREF(lib);')
prnt(' return NULL;')
prnt(' }')
prnt(' return lib;')
prnt('}')
prnt()
prnt('#else')
prnt()
prnt('PyMODINIT_FUNC')
prnt('init%s(void)' % modname)
prnt('{')
prnt(' PyObject *lib;')
prnt(' lib = Py_InitModule("%s", _cffi_methods);' % modname)
prnt(' if (lib == NULL)')
prnt(' return;')
prnt(' if (%s < 0 || _cffi_init() < 0)' % (constants,))
prnt(' return;')
prnt(' return;')
prnt('}')
prnt()
prnt('#endif')
def load_library(self, flags=None):
# XXX review all usages of 'self' here!
# import it as a new extension module
imp.acquire_lock()
try:
if hasattr(sys, "getdlopenflags"):
previous_flags = sys.getdlopenflags()
try:
if hasattr(sys, "setdlopenflags") and flags is not None:
sys.setdlopenflags(flags)
module = imp.load_dynamic(self.verifier.get_module_name(),
self.verifier.modulefilename)
except ImportError as e:
error = "importing %r: %s" % (self.verifier.modulefilename, e)
raise VerificationError(error)
finally:
if hasattr(sys, "setdlopenflags"):
sys.setdlopenflags(previous_flags)
finally:
imp.release_lock()
#
# call loading_cpy_struct() to get the struct layout inferred by
# the C compiler
self._load(module, 'loading')
#
# the C code will need the objects. Collect them in
# order in a list.
revmapping = dict([(value, key)
for (key, value) in self._typesdict.items()])
lst = [revmapping[i] for i in range(len(revmapping))]
lst = list(map(self.ffi._get_cached_btype, lst))
#
# build the FFILibrary class and instance and call _cffi_setup().
# this will set up some fields like '_cffi_types', and only then
# it will invoke the chained list of functions that will really
# build (notably) the constant objects, as if they are
# pointers, and store them as attributes on the 'library' object.
class FFILibrary(object):
_cffi_python_module = module
_cffi_ffi = self.ffi
_cffi_dir = []
def __dir__(self):
return FFILibrary._cffi_dir + list(self.__dict__)
library = FFILibrary()
if module._cffi_setup(lst, VerificationError, library):
import warnings
warnings.warn("reimporting %r might overwrite older definitions"
% (self.verifier.get_module_name()))
#
# finally, call the loaded_cpy_xxx() functions. This will perform
# the final adjustments, like copying the Python->C wrapper
# functions from the module to the 'library' object, and setting
# up the FFILibrary class with properties for the global C variables.
self._load(module, 'loaded', library=library)
module._cffi_original_ffi = self.ffi
module._cffi_types_of_builtin_funcs = self._types_of_builtin_functions
return library
def _get_declarations(self):
lst = [(key, tp) for (key, (tp, qual)) in
self.ffi._parser._declarations.items()]
lst.sort()
return lst
def _generate(self, step_name):
for name, tp in self._get_declarations():
kind, realname = name.split(' ', 1)
try:
method = getattr(self, '_generate_cpy_%s_%s' % (kind,
step_name))
except AttributeError:
raise VerificationError(
"not implemented in verify(): %r" % name)
try:
method(tp, realname)
except Exception as e:
model.attach_exception_info(e, name)
raise
def _load(self, module, step_name, **kwds):
for name, tp in self._get_declarations():
kind, realname = name.split(' ', 1)
method = getattr(self, '_%s_cpy_%s' % (step_name, kind))
try:
method(tp, realname, module, **kwds)
except Exception as e:
model.attach_exception_info(e, name)
raise
def _generate_nothing(self, tp, name):
pass
def _loaded_noop(self, tp, name, module, **kwds):
pass
# ----------
def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode):
extraarg = ''
if isinstance(tp, model.PrimitiveType):
if tp.is_integer_type() and tp.name != '_Bool':
converter = '_cffi_to_c_int'
extraarg = ', %s' % tp.name
else:
converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''),
tp.name.replace(' ', '_'))
errvalue = '-1'
#
elif isinstance(tp, model.PointerType):
self._convert_funcarg_to_c_ptr_or_array(tp, fromvar,
tovar, errcode)
return
#
elif isinstance(tp, (model.StructOrUnion, model.EnumType)):
# a struct (not a struct pointer) as a function argument
self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)'
% (tovar, self._gettypenum(tp), fromvar))
self._prnt(' %s;' % errcode)
return
#
elif isinstance(tp, model.FunctionPtrType):
converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('')
extraarg = ', _cffi_type(%d)' % self._gettypenum(tp)
errvalue = 'NULL'
#
else:
raise NotImplementedError(tp)
#
self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg))
self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % (
tovar, tp.get_c_name(''), errvalue))
self._prnt(' %s;' % errcode)
def _extra_local_variables(self, tp, localvars):
if isinstance(tp, model.PointerType):
localvars.add('Py_ssize_t datasize')
def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode):
self._prnt(' datasize = _cffi_prepare_pointer_call_argument(')
self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % (
self._gettypenum(tp), fromvar, tovar))
self._prnt(' if (datasize != 0) {')
self._prnt(' if (datasize < 0)')
self._prnt(' %s;' % errcode)
self._prnt(' %s = alloca((size_t)datasize);' % (tovar,))
self._prnt(' memset((void *)%s, 0, (size_t)datasize);' % (tovar,))
self._prnt(' if (_cffi_convert_array_from_object('
'(char *)%s, _cffi_type(%d), %s) < 0)' % (
tovar, self._gettypenum(tp), fromvar))
self._prnt(' %s;' % errcode)
self._prnt(' }')
def _convert_expr_from_c(self, tp, var, context):
if isinstance(tp, model.PrimitiveType):
if tp.is_integer_type() and tp.name != '_Bool':
return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
elif tp.name != 'long double':
return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var)
else:
return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
var, self._gettypenum(tp))
elif isinstance(tp, (model.PointerType, model.FunctionPtrType)):
return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
var, self._gettypenum(tp))
elif isinstance(tp, model.ArrayType):
return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
var, self._gettypenum(model.PointerType(tp.item)))
elif isinstance(tp, model.StructOrUnion):
if tp.fldnames is None:
raise TypeError("'%s' is used as %s, but is opaque" % (
tp._get_c_name(), context))
return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % (
var, self._gettypenum(tp))
elif isinstance(tp, model.EnumType):
return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
var, self._gettypenum(tp))
else:
raise NotImplementedError(tp)
# ----------
# typedefs: generates no code so far
_generate_cpy_typedef_collecttype = _generate_nothing
_generate_cpy_typedef_decl = _generate_nothing
_generate_cpy_typedef_method = _generate_nothing
_loading_cpy_typedef = _loaded_noop
_loaded_cpy_typedef = _loaded_noop
# ----------
# function declarations
def _generate_cpy_function_collecttype(self, tp, name):
assert isinstance(tp, model.FunctionPtrType)
if tp.ellipsis:
self._do_collect_type(tp)
else:
# don't call _do_collect_type(tp) in this common case,
# otherwise test_autofilled_struct_as_argument fails
for type in tp.args:
self._do_collect_type(type)
self._do_collect_type(tp.result)
def _generate_cpy_function_decl(self, tp, name):
assert isinstance(tp, model.FunctionPtrType)
if tp.ellipsis:
# cannot support vararg functions better than this: check for its
# exact type (including the fixed arguments), and build it as a
# constant function pointer (no CPython wrapper)
self._generate_cpy_const(False, name, tp)
return
prnt = self._prnt
numargs = len(tp.args)
if numargs == 0:
argname = 'noarg'
elif numargs == 1:
argname = 'arg0'
else:
argname = 'args'
prnt('static PyObject *')
prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
prnt('{')
#
context = 'argument of %s' % name
for i, type in enumerate(tp.args):
prnt(' %s;' % type.get_c_name(' x%d' % i, context))
#
localvars = set()
for type in tp.args:
self._extra_local_variables(type, localvars)
for decl in localvars:
prnt(' %s;' % (decl,))
#
if not isinstance(tp.result, model.VoidType):
result_code = 'result = '
context = 'result of %s' % name
prnt(' %s;' % tp.result.get_c_name(' result', context))
else:
result_code = ''
#
if len(tp.args) > 1:
rng = range(len(tp.args))
for i in rng:
prnt(' PyObject *arg%d;' % i)
prnt()
prnt(' if (!PyArg_ParseTuple(args, "%s:%s", %s))' % (
'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng])))
prnt(' return NULL;')
prnt()
#
for i, type in enumerate(tp.args):
self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i,
'return NULL')
prnt()
#
prnt(' Py_BEGIN_ALLOW_THREADS')
prnt(' _cffi_restore_errno();')
prnt(' { %s%s(%s); }' % (
result_code, name,
', '.join(['x%d' % i for i in range(len(tp.args))])))
prnt(' _cffi_save_errno();')
prnt(' Py_END_ALLOW_THREADS')
prnt()
#
prnt(' (void)self; /* unused */')
if numargs == 0:
prnt(' (void)noarg; /* unused */')
if result_code:
prnt(' return %s;' %
self._convert_expr_from_c(tp.result, 'result', 'result type'))
else:
prnt(' Py_INCREF(Py_None);')
prnt(' return Py_None;')
prnt('}')
prnt()
def _generate_cpy_function_method(self, tp, name):
if tp.ellipsis:
return
numargs = len(tp.args)
if numargs == 0:
meth = 'METH_NOARGS'
elif numargs == 1:
meth = 'METH_O'
else:
meth = 'METH_VARARGS'
self._prnt(' {"%s", _cffi_f_%s, %s, NULL},' % (name, name, meth))
_loading_cpy_function = _loaded_noop
def _loaded_cpy_function(self, tp, name, module, library):
if tp.ellipsis:
return
func = getattr(module, name)
setattr(library, name, func)
self._types_of_builtin_functions[func] = tp
# ----------
# named structs
_generate_cpy_struct_collecttype = _generate_nothing
def _generate_cpy_struct_decl(self, tp, name):
assert name == tp.name
self._generate_struct_or_union_decl(tp, 'struct', name)
def _generate_cpy_struct_method(self, tp, name):
self._generate_struct_or_union_method(tp, 'struct', name)
def _loading_cpy_struct(self, tp, name, module):
self._loading_struct_or_union(tp, 'struct', name, module)
def _loaded_cpy_struct(self, tp, name, module, **kwds):
self._loaded_struct_or_union(tp)
_generate_cpy_union_collecttype = _generate_nothing
def _generate_cpy_union_decl(self, tp, name):
assert name == tp.name
self._generate_struct_or_union_decl(tp, 'union', name)
def _generate_cpy_union_method(self, tp, name):
self._generate_struct_or_union_method(tp, 'union', name)
def _loading_cpy_union(self, tp, name, module):
self._loading_struct_or_union(tp, 'union', name, module)
def _loaded_cpy_union(self, tp, name, module, **kwds):
self._loaded_struct_or_union(tp)
def _generate_struct_or_union_decl(self, tp, prefix, name):
if tp.fldnames is None:
return # nothing to do with opaque structs
checkfuncname = '_cffi_check_%s_%s' % (prefix, name)
layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
cname = ('%s %s' % (prefix, name)).strip()
#
prnt = self._prnt
prnt('static void %s(%s *p)' % (checkfuncname, cname))
prnt('{')
prnt(' /* only to generate compile-time warnings or errors */')
prnt(' (void)p;')
for fname, ftype, fbitsize, fqual in tp.enumfields():
if (isinstance(ftype, model.PrimitiveType)
and ftype.is_integer_type()) or fbitsize >= 0:
# accept all integers, but complain on float or double
prnt(' (void)((p->%s) << 1);' % fname)
else:
# only accept exactly the type declared.
try:
prnt(' { %s = &p->%s; (void)tmp; }' % (
ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
fname))
except VerificationError as e:
prnt(' /* %s */' % str(e)) # cannot verify it, ignore
prnt('}')
prnt('static PyObject *')
prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,))
prnt('{')
prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname)
prnt(' static Py_ssize_t nums[] = {')
prnt(' sizeof(%s),' % cname)
prnt(' offsetof(struct _cffi_aligncheck, y),')
for fname, ftype, fbitsize, fqual in tp.enumfields():
if fbitsize >= 0:
continue # xxx ignore fbitsize for now
prnt(' offsetof(%s, %s),' % (cname, fname))
if isinstance(ftype, model.ArrayType) and ftype.length is None:
prnt(' 0, /* %s */' % ftype._get_c_name())
else:
prnt(' sizeof(((%s *)0)->%s),' % (cname, fname))
prnt(' -1')
prnt(' };')
prnt(' (void)self; /* unused */')
prnt(' (void)noarg; /* unused */')
prnt(' return _cffi_get_struct_layout(nums);')
prnt(' /* the next line is not executed, but compiled */')
prnt(' %s(0);' % (checkfuncname,))
prnt('}')
prnt()
def _generate_struct_or_union_method(self, tp, prefix, name):
if tp.fldnames is None:
return # nothing to do with opaque structs
layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
self._prnt(' {"%s", %s, METH_NOARGS, NULL},' % (layoutfuncname,
layoutfuncname))
def _loading_struct_or_union(self, tp, prefix, name, module):
if tp.fldnames is None:
return # nothing to do with opaque structs
layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
#
function = getattr(module, layoutfuncname)
layout = function()
if isinstance(tp, model.StructOrUnion) and tp.partial:
# use the function()'s sizes and offsets to guide the
# layout of the struct
totalsize = layout[0]
totalalignment = layout[1]
fieldofs = layout[2::2]
fieldsize = layout[3::2]
tp.force_flatten()
assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)
tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment
else:
cname = ('%s %s' % (prefix, name)).strip()
self._struct_pending_verification[tp] = layout, cname
def _loaded_struct_or_union(self, tp):
if tp.fldnames is None:
return # nothing to do with opaque structs
self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered
if tp in self._struct_pending_verification:
# check that the layout sizes and offsets match the real ones
def check(realvalue, expectedvalue, msg):
if realvalue != expectedvalue:
raise VerificationError(
"%s (we have %d, but C compiler says %d)"
% (msg, expectedvalue, realvalue))
ffi = self.ffi
BStruct = ffi._get_cached_btype(tp)
layout, cname = self._struct_pending_verification.pop(tp)
check(layout[0], ffi.sizeof(BStruct), "wrong total size")
check(layout[1], ffi.alignof(BStruct), "wrong total alignment")
i = 2
for fname, ftype, fbitsize, fqual in tp.enumfields():
if fbitsize >= 0:
continue # xxx ignore fbitsize for now
check(layout[i], ffi.offsetof(BStruct, fname),
"wrong offset for field %r" % (fname,))
if layout[i+1] != 0:
BField = ffi._get_cached_btype(ftype)
check(layout[i+1], ffi.sizeof(BField),
"wrong size for field %r" % (fname,))
i += 2
assert i == len(layout)
# ----------
# 'anonymous' declarations. These are produced for anonymous structs
# or unions; the 'name' is obtained by a typedef.
_generate_cpy_anonymous_collecttype = _generate_nothing
def _generate_cpy_anonymous_decl(self, tp, name):
if isinstance(tp, model.EnumType):
self._generate_cpy_enum_decl(tp, name, '')
else:
self._generate_struct_or_union_decl(tp, '', name)
def _generate_cpy_anonymous_method(self, tp, name):
if not isinstance(tp, model.EnumType):
self._generate_struct_or_union_method(tp, '', name)
def _loading_cpy_anonymous(self, tp, name, module):
if isinstance(tp, model.EnumType):
self._loading_cpy_enum(tp, name, module)
else:
self._loading_struct_or_union(tp, '', name, module)
def _loaded_cpy_anonymous(self, tp, name, module, **kwds):
if isinstance(tp, model.EnumType):
self._loaded_cpy_enum(tp, name, module, **kwds)
else:
self._loaded_struct_or_union(tp)
# ----------
# constants, likely declared with '#define'
def _generate_cpy_const(self, is_int, name, tp=None, category='const',
vartp=None, delayed=True, size_too=False,
check_value=None):
prnt = self._prnt
funcname = '_cffi_%s_%s' % (category, name)
prnt('static int %s(PyObject *lib)' % funcname)
prnt('{')
prnt(' PyObject *o;')
prnt(' int res;')
if not is_int:
prnt(' %s;' % (vartp or tp).get_c_name(' i', name))
else:
assert category == 'const'
#
if check_value is not None:
self._check_int_constant_value(name, check_value)
#
if not is_int:
if category == 'var':
realexpr = '&' + name
else:
realexpr = name
prnt(' i = (%s);' % (realexpr,))
prnt(' o = %s;' % (self._convert_expr_from_c(tp, 'i',
'variable type'),))
assert delayed
else:
prnt(' o = _cffi_from_c_int_const(%s);' % name)
prnt(' if (o == NULL)')
prnt(' return -1;')
if size_too:
prnt(' {')
prnt(' PyObject *o1 = o;')
prnt(' o = Py_BuildValue("On", o1, (Py_ssize_t)sizeof(%s));'
% (name,))
prnt(' Py_DECREF(o1);')
prnt(' if (o == NULL)')
prnt(' return -1;')
prnt(' }')
prnt(' res = PyObject_SetAttrString(lib, "%s", o);' % name)
prnt(' Py_DECREF(o);')
prnt(' if (res < 0)')
prnt(' return -1;')
prnt(' return %s;' % self._chained_list_constants[delayed])
self._chained_list_constants[delayed] = funcname + '(lib)'
prnt('}')
prnt()
def _generate_cpy_constant_collecttype(self, tp, name):
is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
if not is_int:
self._do_collect_type(tp)
def _generate_cpy_constant_decl(self, tp, name):
is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
self._generate_cpy_const(is_int, name, tp)
_generate_cpy_constant_method = _generate_nothing
_loading_cpy_constant = _loaded_noop
_loaded_cpy_constant = _loaded_noop
# ----------
# enums
def _check_int_constant_value(self, name, value, err_prefix=''):
prnt = self._prnt
if value <= 0:
prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % (
name, name, value))
else:
prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % (
name, name, value))
prnt(' char buf[64];')
prnt(' if ((%s) <= 0)' % name)
prnt(' snprintf(buf, 63, "%%ld", (long)(%s));' % name)
prnt(' else')
prnt(' snprintf(buf, 63, "%%lu", (unsigned long)(%s));' %
name)
prnt(' PyErr_Format(_cffi_VerificationError,')
prnt(' "%s%s has the real value %s, not %s",')
prnt(' "%s", "%s", buf, "%d");' % (
err_prefix, name, value))
prnt(' return -1;')
prnt(' }')
def _enum_funcname(self, prefix, name):
# "$enum_$1" => "___D_enum____D_1"
name = name.replace('$', '___D_')
return '_cffi_e_%s_%s' % (prefix, name)
def _generate_cpy_enum_decl(self, tp, name, prefix='enum'):
if tp.partial:
for enumerator in tp.enumerators:
self._generate_cpy_const(True, enumerator, delayed=False)
return
#
funcname = self._enum_funcname(prefix, name)
prnt = self._prnt
prnt('static int %s(PyObject *lib)' % funcname)
prnt('{')
for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
self._check_int_constant_value(enumerator, enumvalue,
"enum %s: " % name)
prnt(' return %s;' % self._chained_list_constants[True])
self._chained_list_constants[True] = funcname + '(lib)'
prnt('}')
prnt()
_generate_cpy_enum_collecttype = _generate_nothing
_generate_cpy_enum_method = _generate_nothing
def _loading_cpy_enum(self, tp, name, module):
if tp.partial:
enumvalues = [getattr(module, enumerator)
for enumerator in tp.enumerators]
tp.enumvalues = tuple(enumvalues)
tp.partial_resolved = True
def _loaded_cpy_enum(self, tp, name, module, library):
for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
setattr(library, enumerator, enumvalue)
# ----------
# macros: for now only for integers
def _generate_cpy_macro_decl(self, tp, name):
if tp == '...':
check_value = None
else:
check_value = tp # an integer
self._generate_cpy_const(True, name, check_value=check_value)
_generate_cpy_macro_collecttype = _generate_nothing
_generate_cpy_macro_method = _generate_nothing
_loading_cpy_macro = _loaded_noop
_loaded_cpy_macro = _loaded_noop
# ----------
# global variables
def _generate_cpy_variable_collecttype(self, tp, name):
if isinstance(tp, model.ArrayType):
tp_ptr = model.PointerType(tp.item)
else:
tp_ptr = model.PointerType(tp)
self._do_collect_type(tp_ptr)
def _generate_cpy_variable_decl(self, tp, name):
if isinstance(tp, model.ArrayType):
tp_ptr = model.PointerType(tp.item)
self._generate_cpy_const(False, name, tp, vartp=tp_ptr,
size_too = (tp.length == '...'))
else:
tp_ptr = model.PointerType(tp)
self._generate_cpy_const(False, name, tp_ptr, category='var')
_generate_cpy_variable_method = _generate_nothing
_loading_cpy_variable = _loaded_noop
def _loaded_cpy_variable(self, tp, name, module, library):
value = getattr(library, name)
if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the
# sense that "a=..." is forbidden
if tp.length == '...':
assert isinstance(value, tuple)
(value, size) = value
BItemType = self.ffi._get_cached_btype(tp.item)
length, rest = divmod(size, self.ffi.sizeof(BItemType))
if rest != 0:
raise VerificationError(
"bad size: %r does not seem to be an array of %s" %
(name, tp.item))
tp = tp.resolve_length(length)
# 'value' is a which we have to replace with
# a if the N is actually known
if tp.length is not None:
BArray = self.ffi._get_cached_btype(tp)
value = self.ffi.cast(BArray, value)
setattr(library, name, value)
return
# remove ptr= from the library instance, and replace
# it by a property on the class, which reads/writes into ptr[0].
ptr = value
delattr(library, name)
def getter(library):
return ptr[0]
def setter(library, value):
ptr[0] = value
setattr(type(library), name, property(getter, setter))
type(library)._cffi_dir.append(name)
# ----------
def _generate_setup_custom(self):
prnt = self._prnt
prnt('static int _cffi_setup_custom(PyObject *lib)')
prnt('{')
prnt(' return %s;' % self._chained_list_constants[True])
prnt('}')
cffimod_header = r'''
#include
#include
/* this block of #ifs should be kept exactly identical between
c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py
and cffi/_cffi_include.h */
#if defined(_MSC_VER)
# include /* for alloca() */
# if _MSC_VER < 1600 /* MSVC < 2010 */
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
typedef __int8 int_least8_t;
typedef __int16 int_least16_t;
typedef __int32 int_least32_t;
typedef __int64 int_least64_t;
typedef unsigned __int8 uint_least8_t;
typedef unsigned __int16 uint_least16_t;
typedef unsigned __int32 uint_least32_t;
typedef unsigned __int64 uint_least64_t;
typedef __int8 int_fast8_t;
typedef __int16 int_fast16_t;
typedef __int32 int_fast32_t;
typedef __int64 int_fast64_t;
typedef unsigned __int8 uint_fast8_t;
typedef unsigned __int16 uint_fast16_t;
typedef unsigned __int32 uint_fast32_t;
typedef unsigned __int64 uint_fast64_t;
typedef __int64 intmax_t;
typedef unsigned __int64 uintmax_t;
# else
# include
# endif
# if _MSC_VER < 1800 /* MSVC < 2013 */
# ifndef __cplusplus
typedef unsigned char _Bool;
# endif
# endif
#else
# include
# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux)
# include
# endif
#endif
#if PY_MAJOR_VERSION < 3
# undef PyCapsule_CheckExact
# undef PyCapsule_GetPointer
# define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule))
# define PyCapsule_GetPointer(capsule, name) \
(PyCObject_AsVoidPtr(capsule))
#endif
#if PY_MAJOR_VERSION >= 3
# define PyInt_FromLong PyLong_FromLong
#endif
#define _cffi_from_c_double PyFloat_FromDouble
#define _cffi_from_c_float PyFloat_FromDouble
#define _cffi_from_c_long PyInt_FromLong
#define _cffi_from_c_ulong PyLong_FromUnsignedLong
#define _cffi_from_c_longlong PyLong_FromLongLong
#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong
#define _cffi_from_c__Bool PyBool_FromLong
#define _cffi_to_c_double PyFloat_AsDouble
#define _cffi_to_c_float PyFloat_AsDouble
#define _cffi_from_c_int_const(x) \
(((x) > 0) ? \
((unsigned long long)(x) <= (unsigned long long)LONG_MAX) ? \
PyInt_FromLong((long)(x)) : \
PyLong_FromUnsignedLongLong((unsigned long long)(x)) : \
((long long)(x) >= (long long)LONG_MIN) ? \
PyInt_FromLong((long)(x)) : \
PyLong_FromLongLong((long long)(x)))
#define _cffi_from_c_int(x, type) \
(((type)-1) > 0 ? /* unsigned */ \
(sizeof(type) < sizeof(long) ? \
PyInt_FromLong((long)x) : \
sizeof(type) == sizeof(long) ? \
PyLong_FromUnsignedLong((unsigned long)x) : \
PyLong_FromUnsignedLongLong((unsigned long long)x)) : \
(sizeof(type) <= sizeof(long) ? \
PyInt_FromLong((long)x) : \
PyLong_FromLongLong((long long)x)))
#define _cffi_to_c_int(o, type) \
((type)( \
sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \
: (type)_cffi_to_c_i8(o)) : \
sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \
: (type)_cffi_to_c_i16(o)) : \
sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \
: (type)_cffi_to_c_i32(o)) : \
sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \
: (type)_cffi_to_c_i64(o)) : \
(Py_FatalError("unsupported size for type " #type), (type)0)))
#define _cffi_to_c_i8 \
((int(*)(PyObject *))_cffi_exports[1])
#define _cffi_to_c_u8 \
((int(*)(PyObject *))_cffi_exports[2])
#define _cffi_to_c_i16 \
((int(*)(PyObject *))_cffi_exports[3])
#define _cffi_to_c_u16 \
((int(*)(PyObject *))_cffi_exports[4])
#define _cffi_to_c_i32 \
((int(*)(PyObject *))_cffi_exports[5])
#define _cffi_to_c_u32 \
((unsigned int(*)(PyObject *))_cffi_exports[6])
#define _cffi_to_c_i64 \
((long long(*)(PyObject *))_cffi_exports[7])
#define _cffi_to_c_u64 \
((unsigned long long(*)(PyObject *))_cffi_exports[8])
#define _cffi_to_c_char \
((int(*)(PyObject *))_cffi_exports[9])
#define _cffi_from_c_pointer \
((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10])
#define _cffi_to_c_pointer \
((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11])
#define _cffi_get_struct_layout \
((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12])
#define _cffi_restore_errno \
((void(*)(void))_cffi_exports[13])
#define _cffi_save_errno \
((void(*)(void))_cffi_exports[14])
#define _cffi_from_c_char \
((PyObject *(*)(char))_cffi_exports[15])
#define _cffi_from_c_deref \
((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16])
#define _cffi_to_c \
((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17])
#define _cffi_from_c_struct \
((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18])
#define _cffi_to_c_wchar_t \
((wchar_t(*)(PyObject *))_cffi_exports[19])
#define _cffi_from_c_wchar_t \
((PyObject *(*)(wchar_t))_cffi_exports[20])
#define _cffi_to_c_long_double \
((long double(*)(PyObject *))_cffi_exports[21])
#define _cffi_to_c__Bool \
((_Bool(*)(PyObject *))_cffi_exports[22])
#define _cffi_prepare_pointer_call_argument \
((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23])
#define _cffi_convert_array_from_object \
((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24])
#define _CFFI_NUM_EXPORTS 25
typedef struct _ctypedescr CTypeDescrObject;
static void *_cffi_exports[_CFFI_NUM_EXPORTS];
static PyObject *_cffi_types, *_cffi_VerificationError;
static int _cffi_setup_custom(PyObject *lib); /* forward */
static PyObject *_cffi_setup(PyObject *self, PyObject *args)
{
PyObject *library;
int was_alive = (_cffi_types != NULL);
(void)self; /* unused */
if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError,
&library))
return NULL;
Py_INCREF(_cffi_types);
Py_INCREF(_cffi_VerificationError);
if (_cffi_setup_custom(library) < 0)
return NULL;
return PyBool_FromLong(was_alive);
}
static int _cffi_init(void)
{
PyObject *module, *c_api_object = NULL;
module = PyImport_ImportModule("_cffi_backend");
if (module == NULL)
goto failure;
c_api_object = PyObject_GetAttrString(module, "_C_API");
if (c_api_object == NULL)
goto failure;
if (!PyCapsule_CheckExact(c_api_object)) {
PyErr_SetNone(PyExc_ImportError);
goto failure;
}
memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"),
_CFFI_NUM_EXPORTS * sizeof(void *));
Py_DECREF(module);
Py_DECREF(c_api_object);
return 0;
failure:
Py_XDECREF(module);
Py_XDECREF(c_api_object);
return -1;
}
#define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num))
/**********/
'''
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/vengine_gen.py
================================================
#
# DEPRECATED: implementation for ffi.verify()
#
import sys, os
import types
from . import model
from .error import VerificationError
class VGenericEngine(object):
_class_key = 'g'
_gen_python_module = False
def __init__(self, verifier):
self.verifier = verifier
self.ffi = verifier.ffi
self.export_symbols = []
self._struct_pending_verification = {}
def patch_extension_kwds(self, kwds):
# add 'export_symbols' to the dictionary. Note that we add the
# list before filling it. When we fill it, it will thus also show
# up in kwds['export_symbols'].
kwds.setdefault('export_symbols', self.export_symbols)
def find_module(self, module_name, path, so_suffixes):
for so_suffix in so_suffixes:
basename = module_name + so_suffix
if path is None:
path = sys.path
for dirname in path:
filename = os.path.join(dirname, basename)
if os.path.isfile(filename):
return filename
def collect_types(self):
pass # not needed in the generic engine
def _prnt(self, what=''):
self._f.write(what + '\n')
def write_source_to_f(self):
prnt = self._prnt
# first paste some standard set of lines that are mostly '#include'
prnt(cffimod_header)
# then paste the C source given by the user, verbatim.
prnt(self.verifier.preamble)
#
# call generate_gen_xxx_decl(), for every xxx found from
# ffi._parser._declarations. This generates all the functions.
self._generate('decl')
#
# on Windows, distutils insists on putting init_cffi_xyz in
# 'export_symbols', so instead of fighting it, just give up and
# give it one
if sys.platform == 'win32':
if sys.version_info >= (3,):
prefix = 'PyInit_'
else:
prefix = 'init'
modname = self.verifier.get_module_name()
prnt("void %s%s(void) { }\n" % (prefix, modname))
def load_library(self, flags=0):
# import it with the CFFI backend
backend = self.ffi._backend
# needs to make a path that contains '/', on Posix
filename = os.path.join(os.curdir, self.verifier.modulefilename)
module = backend.load_library(filename, flags)
#
# call loading_gen_struct() to get the struct layout inferred by
# the C compiler
self._load(module, 'loading')
# build the FFILibrary class and instance, this is a module subclass
# because modules are expected to have usually-constant-attributes and
# in PyPy this means the JIT is able to treat attributes as constant,
# which we want.
class FFILibrary(types.ModuleType):
_cffi_generic_module = module
_cffi_ffi = self.ffi
_cffi_dir = []
def __dir__(self):
return FFILibrary._cffi_dir
library = FFILibrary("")
#
# finally, call the loaded_gen_xxx() functions. This will set
# up the 'library' object.
self._load(module, 'loaded', library=library)
return library
def _get_declarations(self):
lst = [(key, tp) for (key, (tp, qual)) in
self.ffi._parser._declarations.items()]
lst.sort()
return lst
def _generate(self, step_name):
for name, tp in self._get_declarations():
kind, realname = name.split(' ', 1)
try:
method = getattr(self, '_generate_gen_%s_%s' % (kind,
step_name))
except AttributeError:
raise VerificationError(
"not implemented in verify(): %r" % name)
try:
method(tp, realname)
except Exception as e:
model.attach_exception_info(e, name)
raise
def _load(self, module, step_name, **kwds):
for name, tp in self._get_declarations():
kind, realname = name.split(' ', 1)
method = getattr(self, '_%s_gen_%s' % (step_name, kind))
try:
method(tp, realname, module, **kwds)
except Exception as e:
model.attach_exception_info(e, name)
raise
def _generate_nothing(self, tp, name):
pass
def _loaded_noop(self, tp, name, module, **kwds):
pass
# ----------
# typedefs: generates no code so far
_generate_gen_typedef_decl = _generate_nothing
_loading_gen_typedef = _loaded_noop
_loaded_gen_typedef = _loaded_noop
# ----------
# function declarations
def _generate_gen_function_decl(self, tp, name):
assert isinstance(tp, model.FunctionPtrType)
if tp.ellipsis:
# cannot support vararg functions better than this: check for its
# exact type (including the fixed arguments), and build it as a
# constant function pointer (no _cffi_f_%s wrapper)
self._generate_gen_const(False, name, tp)
return
prnt = self._prnt
numargs = len(tp.args)
argnames = []
for i, type in enumerate(tp.args):
indirection = ''
if isinstance(type, model.StructOrUnion):
indirection = '*'
argnames.append('%sx%d' % (indirection, i))
context = 'argument of %s' % name
arglist = [type.get_c_name(' %s' % arg, context)
for type, arg in zip(tp.args, argnames)]
tpresult = tp.result
if isinstance(tpresult, model.StructOrUnion):
arglist.insert(0, tpresult.get_c_name(' *r', context))
tpresult = model.void_type
arglist = ', '.join(arglist) or 'void'
wrappername = '_cffi_f_%s' % name
self.export_symbols.append(wrappername)
if tp.abi:
abi = tp.abi + ' '
else:
abi = ''
funcdecl = ' %s%s(%s)' % (abi, wrappername, arglist)
context = 'result of %s' % name
prnt(tpresult.get_c_name(funcdecl, context))
prnt('{')
#
if isinstance(tp.result, model.StructOrUnion):
result_code = '*r = '
elif not isinstance(tp.result, model.VoidType):
result_code = 'return '
else:
result_code = ''
prnt(' %s%s(%s);' % (result_code, name, ', '.join(argnames)))
prnt('}')
prnt()
_loading_gen_function = _loaded_noop
def _loaded_gen_function(self, tp, name, module, library):
assert isinstance(tp, model.FunctionPtrType)
if tp.ellipsis:
newfunction = self._load_constant(False, tp, name, module)
else:
indirections = []
base_tp = tp
if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args)
or isinstance(tp.result, model.StructOrUnion)):
indirect_args = []
for i, typ in enumerate(tp.args):
if isinstance(typ, model.StructOrUnion):
typ = model.PointerType(typ)
indirections.append((i, typ))
indirect_args.append(typ)
indirect_result = tp.result
if isinstance(indirect_result, model.StructOrUnion):
if indirect_result.fldtypes is None:
raise TypeError("'%s' is used as result type, "
"but is opaque" % (
indirect_result._get_c_name(),))
indirect_result = model.PointerType(indirect_result)
indirect_args.insert(0, indirect_result)
indirections.insert(0, ("result", indirect_result))
indirect_result = model.void_type
tp = model.FunctionPtrType(tuple(indirect_args),
indirect_result, tp.ellipsis)
BFunc = self.ffi._get_cached_btype(tp)
wrappername = '_cffi_f_%s' % name
newfunction = module.load_function(BFunc, wrappername)
for i, typ in indirections:
newfunction = self._make_struct_wrapper(newfunction, i, typ,
base_tp)
setattr(library, name, newfunction)
type(library)._cffi_dir.append(name)
def _make_struct_wrapper(self, oldfunc, i, tp, base_tp):
backend = self.ffi._backend
BType = self.ffi._get_cached_btype(tp)
if i == "result":
ffi = self.ffi
def newfunc(*args):
res = ffi.new(BType)
oldfunc(res, *args)
return res[0]
else:
def newfunc(*args):
args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:]
return oldfunc(*args)
newfunc._cffi_base_type = base_tp
return newfunc
# ----------
# named structs
def _generate_gen_struct_decl(self, tp, name):
assert name == tp.name
self._generate_struct_or_union_decl(tp, 'struct', name)
def _loading_gen_struct(self, tp, name, module):
self._loading_struct_or_union(tp, 'struct', name, module)
def _loaded_gen_struct(self, tp, name, module, **kwds):
self._loaded_struct_or_union(tp)
def _generate_gen_union_decl(self, tp, name):
assert name == tp.name
self._generate_struct_or_union_decl(tp, 'union', name)
def _loading_gen_union(self, tp, name, module):
self._loading_struct_or_union(tp, 'union', name, module)
def _loaded_gen_union(self, tp, name, module, **kwds):
self._loaded_struct_or_union(tp)
def _generate_struct_or_union_decl(self, tp, prefix, name):
if tp.fldnames is None:
return # nothing to do with opaque structs
checkfuncname = '_cffi_check_%s_%s' % (prefix, name)
layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
cname = ('%s %s' % (prefix, name)).strip()
#
prnt = self._prnt
prnt('static void %s(%s *p)' % (checkfuncname, cname))
prnt('{')
prnt(' /* only to generate compile-time warnings or errors */')
prnt(' (void)p;')
for fname, ftype, fbitsize, fqual in tp.enumfields():
if (isinstance(ftype, model.PrimitiveType)
and ftype.is_integer_type()) or fbitsize >= 0:
# accept all integers, but complain on float or double
prnt(' (void)((p->%s) << 1);' % fname)
else:
# only accept exactly the type declared.
try:
prnt(' { %s = &p->%s; (void)tmp; }' % (
ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
fname))
except VerificationError as e:
prnt(' /* %s */' % str(e)) # cannot verify it, ignore
prnt('}')
self.export_symbols.append(layoutfuncname)
prnt('intptr_t %s(intptr_t i)' % (layoutfuncname,))
prnt('{')
prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname)
prnt(' static intptr_t nums[] = {')
prnt(' sizeof(%s),' % cname)
prnt(' offsetof(struct _cffi_aligncheck, y),')
for fname, ftype, fbitsize, fqual in tp.enumfields():
if fbitsize >= 0:
continue # xxx ignore fbitsize for now
prnt(' offsetof(%s, %s),' % (cname, fname))
if isinstance(ftype, model.ArrayType) and ftype.length is None:
prnt(' 0, /* %s */' % ftype._get_c_name())
else:
prnt(' sizeof(((%s *)0)->%s),' % (cname, fname))
prnt(' -1')
prnt(' };')
prnt(' return nums[i];')
prnt(' /* the next line is not executed, but compiled */')
prnt(' %s(0);' % (checkfuncname,))
prnt('}')
prnt()
def _loading_struct_or_union(self, tp, prefix, name, module):
if tp.fldnames is None:
return # nothing to do with opaque structs
layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
#
BFunc = self.ffi._typeof_locked("intptr_t(*)(intptr_t)")[0]
function = module.load_function(BFunc, layoutfuncname)
layout = []
num = 0
while True:
x = function(num)
if x < 0: break
layout.append(x)
num += 1
if isinstance(tp, model.StructOrUnion) and tp.partial:
# use the function()'s sizes and offsets to guide the
# layout of the struct
totalsize = layout[0]
totalalignment = layout[1]
fieldofs = layout[2::2]
fieldsize = layout[3::2]
tp.force_flatten()
assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)
tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment
else:
cname = ('%s %s' % (prefix, name)).strip()
self._struct_pending_verification[tp] = layout, cname
def _loaded_struct_or_union(self, tp):
if tp.fldnames is None:
return # nothing to do with opaque structs
self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered
if tp in self._struct_pending_verification:
# check that the layout sizes and offsets match the real ones
def check(realvalue, expectedvalue, msg):
if realvalue != expectedvalue:
raise VerificationError(
"%s (we have %d, but C compiler says %d)"
% (msg, expectedvalue, realvalue))
ffi = self.ffi
BStruct = ffi._get_cached_btype(tp)
layout, cname = self._struct_pending_verification.pop(tp)
check(layout[0], ffi.sizeof(BStruct), "wrong total size")
check(layout[1], ffi.alignof(BStruct), "wrong total alignment")
i = 2
for fname, ftype, fbitsize, fqual in tp.enumfields():
if fbitsize >= 0:
continue # xxx ignore fbitsize for now
check(layout[i], ffi.offsetof(BStruct, fname),
"wrong offset for field %r" % (fname,))
if layout[i+1] != 0:
BField = ffi._get_cached_btype(ftype)
check(layout[i+1], ffi.sizeof(BField),
"wrong size for field %r" % (fname,))
i += 2
assert i == len(layout)
# ----------
# 'anonymous' declarations. These are produced for anonymous structs
# or unions; the 'name' is obtained by a typedef.
def _generate_gen_anonymous_decl(self, tp, name):
if isinstance(tp, model.EnumType):
self._generate_gen_enum_decl(tp, name, '')
else:
self._generate_struct_or_union_decl(tp, '', name)
def _loading_gen_anonymous(self, tp, name, module):
if isinstance(tp, model.EnumType):
self._loading_gen_enum(tp, name, module, '')
else:
self._loading_struct_or_union(tp, '', name, module)
def _loaded_gen_anonymous(self, tp, name, module, **kwds):
if isinstance(tp, model.EnumType):
self._loaded_gen_enum(tp, name, module, **kwds)
else:
self._loaded_struct_or_union(tp)
# ----------
# constants, likely declared with '#define'
def _generate_gen_const(self, is_int, name, tp=None, category='const',
check_value=None):
prnt = self._prnt
funcname = '_cffi_%s_%s' % (category, name)
self.export_symbols.append(funcname)
if check_value is not None:
assert is_int
assert category == 'const'
prnt('int %s(char *out_error)' % funcname)
prnt('{')
self._check_int_constant_value(name, check_value)
prnt(' return 0;')
prnt('}')
elif is_int:
assert category == 'const'
prnt('int %s(long long *out_value)' % funcname)
prnt('{')
prnt(' *out_value = (long long)(%s);' % (name,))
prnt(' return (%s) <= 0;' % (name,))
prnt('}')
else:
assert tp is not None
assert check_value is None
if category == 'var':
ampersand = '&'
else:
ampersand = ''
extra = ''
if category == 'const' and isinstance(tp, model.StructOrUnion):
extra = 'const *'
ampersand = '&'
prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name))
prnt('{')
prnt(' return (%s%s);' % (ampersand, name))
prnt('}')
prnt()
def _generate_gen_constant_decl(self, tp, name):
is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
self._generate_gen_const(is_int, name, tp)
_loading_gen_constant = _loaded_noop
def _load_constant(self, is_int, tp, name, module, check_value=None):
funcname = '_cffi_const_%s' % name
if check_value is not None:
assert is_int
self._load_known_int_constant(module, funcname)
value = check_value
elif is_int:
BType = self.ffi._typeof_locked("long long*")[0]
BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0]
function = module.load_function(BFunc, funcname)
p = self.ffi.new(BType)
negative = function(p)
value = int(p[0])
if value < 0 and not negative:
BLongLong = self.ffi._typeof_locked("long long")[0]
value += (1 << (8*self.ffi.sizeof(BLongLong)))
else:
assert check_value is None
fntypeextra = '(*)(void)'
if isinstance(tp, model.StructOrUnion):
fntypeextra = '*' + fntypeextra
BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0]
function = module.load_function(BFunc, funcname)
value = function()
if isinstance(tp, model.StructOrUnion):
value = value[0]
return value
def _loaded_gen_constant(self, tp, name, module, library):
is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
value = self._load_constant(is_int, tp, name, module)
setattr(library, name, value)
type(library)._cffi_dir.append(name)
# ----------
# enums
def _check_int_constant_value(self, name, value):
prnt = self._prnt
if value <= 0:
prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % (
name, name, value))
else:
prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % (
name, name, value))
prnt(' char buf[64];')
prnt(' if ((%s) <= 0)' % name)
prnt(' sprintf(buf, "%%ld", (long)(%s));' % name)
prnt(' else')
prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' %
name)
prnt(' sprintf(out_error, "%s has the real value %s, not %s",')
prnt(' "%s", buf, "%d");' % (name[:100], value))
prnt(' return -1;')
prnt(' }')
def _load_known_int_constant(self, module, funcname):
BType = self.ffi._typeof_locked("char[]")[0]
BFunc = self.ffi._typeof_locked("int(*)(char*)")[0]
function = module.load_function(BFunc, funcname)
p = self.ffi.new(BType, 256)
if function(p) < 0:
error = self.ffi.string(p)
if sys.version_info >= (3,):
error = str(error, 'utf-8')
raise VerificationError(error)
def _enum_funcname(self, prefix, name):
# "$enum_$1" => "___D_enum____D_1"
name = name.replace('$', '___D_')
return '_cffi_e_%s_%s' % (prefix, name)
def _generate_gen_enum_decl(self, tp, name, prefix='enum'):
if tp.partial:
for enumerator in tp.enumerators:
self._generate_gen_const(True, enumerator)
return
#
funcname = self._enum_funcname(prefix, name)
self.export_symbols.append(funcname)
prnt = self._prnt
prnt('int %s(char *out_error)' % funcname)
prnt('{')
for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
self._check_int_constant_value(enumerator, enumvalue)
prnt(' return 0;')
prnt('}')
prnt()
def _loading_gen_enum(self, tp, name, module, prefix='enum'):
if tp.partial:
enumvalues = [self._load_constant(True, tp, enumerator, module)
for enumerator in tp.enumerators]
tp.enumvalues = tuple(enumvalues)
tp.partial_resolved = True
else:
funcname = self._enum_funcname(prefix, name)
self._load_known_int_constant(module, funcname)
def _loaded_gen_enum(self, tp, name, module, library):
for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
setattr(library, enumerator, enumvalue)
type(library)._cffi_dir.append(enumerator)
# ----------
# macros: for now only for integers
def _generate_gen_macro_decl(self, tp, name):
if tp == '...':
check_value = None
else:
check_value = tp # an integer
self._generate_gen_const(True, name, check_value=check_value)
_loading_gen_macro = _loaded_noop
def _loaded_gen_macro(self, tp, name, module, library):
if tp == '...':
check_value = None
else:
check_value = tp # an integer
value = self._load_constant(True, tp, name, module,
check_value=check_value)
setattr(library, name, value)
type(library)._cffi_dir.append(name)
# ----------
# global variables
def _generate_gen_variable_decl(self, tp, name):
if isinstance(tp, model.ArrayType):
if tp.length == '...':
prnt = self._prnt
funcname = '_cffi_sizeof_%s' % (name,)
self.export_symbols.append(funcname)
prnt("size_t %s(void)" % funcname)
prnt("{")
prnt(" return sizeof(%s);" % (name,))
prnt("}")
tp_ptr = model.PointerType(tp.item)
self._generate_gen_const(False, name, tp_ptr)
else:
tp_ptr = model.PointerType(tp)
self._generate_gen_const(False, name, tp_ptr, category='var')
_loading_gen_variable = _loaded_noop
def _loaded_gen_variable(self, tp, name, module, library):
if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the
# sense that "a=..." is forbidden
if tp.length == '...':
funcname = '_cffi_sizeof_%s' % (name,)
BFunc = self.ffi._typeof_locked('size_t(*)(void)')[0]
function = module.load_function(BFunc, funcname)
size = function()
BItemType = self.ffi._get_cached_btype(tp.item)
length, rest = divmod(size, self.ffi.sizeof(BItemType))
if rest != 0:
raise VerificationError(
"bad size: %r does not seem to be an array of %s" %
(name, tp.item))
tp = tp.resolve_length(length)
tp_ptr = model.PointerType(tp.item)
value = self._load_constant(False, tp_ptr, name, module)
# 'value' is a which we have to replace with
# a if the N is actually known
if tp.length is not None:
BArray = self.ffi._get_cached_btype(tp)
value = self.ffi.cast(BArray, value)
setattr(library, name, value)
type(library)._cffi_dir.append(name)
return
# remove ptr= from the library instance, and replace
# it by a property on the class, which reads/writes into ptr[0].
funcname = '_cffi_var_%s' % name
BFunc = self.ffi._typeof_locked(tp.get_c_name('*(*)(void)', name))[0]
function = module.load_function(BFunc, funcname)
ptr = function()
def getter(library):
return ptr[0]
def setter(library, value):
ptr[0] = value
setattr(type(library), name, property(getter, setter))
type(library)._cffi_dir.append(name)
cffimod_header = r'''
#include
#include
#include
#include
#include /* XXX for ssize_t on some platforms */
/* this block of #ifs should be kept exactly identical between
c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py
and cffi/_cffi_include.h */
#if defined(_MSC_VER)
# include /* for alloca() */
# if _MSC_VER < 1600 /* MSVC < 2010 */
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
typedef __int8 int_least8_t;
typedef __int16 int_least16_t;
typedef __int32 int_least32_t;
typedef __int64 int_least64_t;
typedef unsigned __int8 uint_least8_t;
typedef unsigned __int16 uint_least16_t;
typedef unsigned __int32 uint_least32_t;
typedef unsigned __int64 uint_least64_t;
typedef __int8 int_fast8_t;
typedef __int16 int_fast16_t;
typedef __int32 int_fast32_t;
typedef __int64 int_fast64_t;
typedef unsigned __int8 uint_fast8_t;
typedef unsigned __int16 uint_fast16_t;
typedef unsigned __int32 uint_fast32_t;
typedef unsigned __int64 uint_fast64_t;
typedef __int64 intmax_t;
typedef unsigned __int64 uintmax_t;
# else
# include
# endif
# if _MSC_VER < 1800 /* MSVC < 2013 */
# ifndef __cplusplus
typedef unsigned char _Bool;
# endif
# endif
#else
# include
# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux)
# include
# endif
#endif
'''
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi/verifier.py
================================================
#
# DEPRECATED: implementation for ffi.verify()
#
import sys, os, binascii, shutil, io
from . import __version_verifier_modules__
from . import ffiplatform
from .error import VerificationError
if sys.version_info >= (3, 3):
import importlib.machinery
def _extension_suffixes():
return importlib.machinery.EXTENSION_SUFFIXES[:]
else:
import imp
def _extension_suffixes():
return [suffix for suffix, _, type in imp.get_suffixes()
if type == imp.C_EXTENSION]
if sys.version_info >= (3,):
NativeIO = io.StringIO
else:
class NativeIO(io.BytesIO):
def write(self, s):
if isinstance(s, unicode):
s = s.encode('ascii')
super(NativeIO, self).write(s)
class Verifier(object):
def __init__(self, ffi, preamble, tmpdir=None, modulename=None,
ext_package=None, tag='', force_generic_engine=False,
source_extension='.c', flags=None, relative_to=None, **kwds):
if ffi._parser._uses_new_feature:
raise VerificationError(
"feature not supported with ffi.verify(), but only "
"with ffi.set_source(): %s" % (ffi._parser._uses_new_feature,))
self.ffi = ffi
self.preamble = preamble
if not modulename:
flattened_kwds = ffiplatform.flatten(kwds)
vengine_class = _locate_engine_class(ffi, force_generic_engine)
self._vengine = vengine_class(self)
self._vengine.patch_extension_kwds(kwds)
self.flags = flags
self.kwds = self.make_relative_to(kwds, relative_to)
#
if modulename:
if tag:
raise TypeError("can't specify both 'modulename' and 'tag'")
else:
key = '\x00'.join([sys.version[:3], __version_verifier_modules__,
preamble, flattened_kwds] +
ffi._cdefsources)
if sys.version_info >= (3,):
key = key.encode('utf-8')
k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff)
k1 = k1.lstrip('0x').rstrip('L')
k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff)
k2 = k2.lstrip('0').rstrip('L')
modulename = '_cffi_%s_%s%s%s' % (tag, self._vengine._class_key,
k1, k2)
suffix = _get_so_suffixes()[0]
self.tmpdir = tmpdir or _caller_dir_pycache()
self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension)
self.modulefilename = os.path.join(self.tmpdir, modulename + suffix)
self.ext_package = ext_package
self._has_source = False
self._has_module = False
def write_source(self, file=None):
"""Write the C source code. It is produced in 'self.sourcefilename',
which can be tweaked beforehand."""
with self.ffi._lock:
if self._has_source and file is None:
raise VerificationError(
"source code already written")
self._write_source(file)
def compile_module(self):
"""Write the C source code (if not done already) and compile it.
This produces a dynamic link library in 'self.modulefilename'."""
with self.ffi._lock:
if self._has_module:
raise VerificationError("module already compiled")
if not self._has_source:
self._write_source()
self._compile_module()
def load_library(self):
"""Get a C module from this Verifier instance.
Returns an instance of a FFILibrary class that behaves like the
objects returned by ffi.dlopen(), but that delegates all
operations to the C module. If necessary, the C code is written
and compiled first.
"""
with self.ffi._lock:
if not self._has_module:
self._locate_module()
if not self._has_module:
if not self._has_source:
self._write_source()
self._compile_module()
return self._load_library()
def get_module_name(self):
basename = os.path.basename(self.modulefilename)
# kill both the .so extension and the other .'s, as introduced
# by Python 3: 'basename.cpython-33m.so'
basename = basename.split('.', 1)[0]
# and the _d added in Python 2 debug builds --- but try to be
# conservative and not kill a legitimate _d
if basename.endswith('_d') and hasattr(sys, 'gettotalrefcount'):
basename = basename[:-2]
return basename
def get_extension(self):
ffiplatform._hack_at_distutils() # backward compatibility hack
if not self._has_source:
with self.ffi._lock:
if not self._has_source:
self._write_source()
sourcename = ffiplatform.maybe_relative_path(self.sourcefilename)
modname = self.get_module_name()
return ffiplatform.get_extension(sourcename, modname, **self.kwds)
def generates_python_module(self):
return self._vengine._gen_python_module
def make_relative_to(self, kwds, relative_to):
if relative_to and os.path.dirname(relative_to):
dirname = os.path.dirname(relative_to)
kwds = kwds.copy()
for key in ffiplatform.LIST_OF_FILE_NAMES:
if key in kwds:
lst = kwds[key]
if not isinstance(lst, (list, tuple)):
raise TypeError("keyword '%s' should be a list or tuple"
% (key,))
lst = [os.path.join(dirname, fn) for fn in lst]
kwds[key] = lst
return kwds
# ----------
def _locate_module(self):
if not os.path.isfile(self.modulefilename):
if self.ext_package:
try:
pkg = __import__(self.ext_package, None, None, ['__doc__'])
except ImportError:
return # cannot import the package itself, give up
# (e.g. it might be called differently before installation)
path = pkg.__path__
else:
path = None
filename = self._vengine.find_module(self.get_module_name(), path,
_get_so_suffixes())
if filename is None:
return
self.modulefilename = filename
self._vengine.collect_types()
self._has_module = True
def _write_source_to(self, file):
self._vengine._f = file
try:
self._vengine.write_source_to_f()
finally:
del self._vengine._f
def _write_source(self, file=None):
if file is not None:
self._write_source_to(file)
else:
# Write our source file to an in memory file.
f = NativeIO()
self._write_source_to(f)
source_data = f.getvalue()
# Determine if this matches the current file
if os.path.exists(self.sourcefilename):
with open(self.sourcefilename, "r") as fp:
needs_written = not (fp.read() == source_data)
else:
needs_written = True
# Actually write the file out if it doesn't match
if needs_written:
_ensure_dir(self.sourcefilename)
with open(self.sourcefilename, "w") as fp:
fp.write(source_data)
# Set this flag
self._has_source = True
def _compile_module(self):
# compile this C source
tmpdir = os.path.dirname(self.sourcefilename)
outputfilename = ffiplatform.compile(tmpdir, self.get_extension())
try:
same = ffiplatform.samefile(outputfilename, self.modulefilename)
except OSError:
same = False
if not same:
_ensure_dir(self.modulefilename)
shutil.move(outputfilename, self.modulefilename)
self._has_module = True
def _load_library(self):
assert self._has_module
if self.flags is not None:
return self._vengine.load_library(self.flags)
else:
return self._vengine.load_library()
# ____________________________________________________________
_FORCE_GENERIC_ENGINE = False # for tests
def _locate_engine_class(ffi, force_generic_engine):
if _FORCE_GENERIC_ENGINE:
force_generic_engine = True
if not force_generic_engine:
if '__pypy__' in sys.builtin_module_names:
force_generic_engine = True
else:
try:
import _cffi_backend
except ImportError:
_cffi_backend = '?'
if ffi._backend is not _cffi_backend:
force_generic_engine = True
if force_generic_engine:
from . import vengine_gen
return vengine_gen.VGenericEngine
else:
from . import vengine_cpy
return vengine_cpy.VCPythonEngine
# ____________________________________________________________
_TMPDIR = None
def _caller_dir_pycache():
if _TMPDIR:
return _TMPDIR
result = os.environ.get('CFFI_TMPDIR')
if result:
return result
filename = sys._getframe(2).f_code.co_filename
return os.path.abspath(os.path.join(os.path.dirname(filename),
'__pycache__'))
def set_tmpdir(dirname):
"""Set the temporary directory to use instead of __pycache__."""
global _TMPDIR
_TMPDIR = dirname
def cleanup_tmpdir(tmpdir=None, keep_so=False):
"""Clean up the temporary directory by removing all files in it
called `_cffi_*.{c,so}` as well as the `build` subdirectory."""
tmpdir = tmpdir or _caller_dir_pycache()
try:
filelist = os.listdir(tmpdir)
except OSError:
return
if keep_so:
suffix = '.c' # only remove .c files
else:
suffix = _get_so_suffixes()[0].lower()
for fn in filelist:
if fn.lower().startswith('_cffi_') and (
fn.lower().endswith(suffix) or fn.lower().endswith('.c')):
try:
os.unlink(os.path.join(tmpdir, fn))
except OSError:
pass
clean_dir = [os.path.join(tmpdir, 'build')]
for dir in clean_dir:
try:
for fn in os.listdir(dir):
fn = os.path.join(dir, fn)
if os.path.isdir(fn):
clean_dir.append(fn)
else:
os.unlink(fn)
except OSError:
pass
def _get_so_suffixes():
suffixes = _extension_suffixes()
if not suffixes:
# bah, no C_EXTENSION available. Occurs on pypy without cpyext
if sys.platform == 'win32':
suffixes = [".pyd"]
else:
suffixes = [".so"]
return suffixes
def _ensure_dir(filename):
dirname = os.path.dirname(filename)
if dirname and not os.path.isdir(dirname):
os.makedirs(dirname)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi-1.13.1.dist-info/INSTALLER
================================================
pip
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi-1.13.1.dist-info/LICENSE.txt
================================================
Except when otherwise stated (look for LICENSE files in directories or
information at the beginning of each file) all software and
documentation is licensed as follows:
The MIT License
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi-1.13.1.dist-info/METADATA
================================================
Metadata-Version: 2.1
Name: cffi
Version: 1.13.1
Summary: Foreign Function Interface for Python calling C code.
Home-page: http://cffi.readthedocs.org
Author: Armin Rigo, Maciej Fijalkowski
Author-email: python-cffi@googlegroups.com
License: MIT
Platform: UNKNOWN
Classifier: Programming Language :: Python
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.2
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Requires-Dist: pycparser
CFFI
====
Foreign Function Interface for Python calling C code.
Please see the `Documentation `_.
Contact
-------
`Mailing list `_
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi-1.13.1.dist-info/RECORD
================================================
.libs_cffi_backend/libffi-10449faf.so.5.0.6,sha256=PG7U56gJ8uCf3HUyfp4gVBQTu7rwI2GdyE7quplTB2o,34248
_cffi_backend.cpython-36m-x86_64-linux-gnu.so,sha256=lyO5RSJGQG5eqiZKAfaFBevoOb4awoyRoAXv8qaxO0s,849704
cffi-1.13.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
cffi-1.13.1.dist-info/LICENSE.txt,sha256=BLgPWwd7vtaICM_rreteNSPyqMmpZJXFh72W3x6sKjM,1294
cffi-1.13.1.dist-info/METADATA,sha256=M7h8dR2tpB6Q5V46_Imv7Gxe7pKzA1hufeVHtu2sNAo,1140
cffi-1.13.1.dist-info/RECORD,,
cffi-1.13.1.dist-info/WHEEL,sha256=d2ILPScH-y2UwGxsW1PeA2TT-KW0Git4AJ6LeOK8sQo,109
cffi-1.13.1.dist-info/entry_points.txt,sha256=Q9f5C9IpjYxo0d2PK9eUcnkgxHc9pHWwjEMaANPKNCI,76
cffi-1.13.1.dist-info/top_level.txt,sha256=rE7WR3rZfNKxWI9-jn6hsHCAl7MDkB-FmuQbxWjFehQ,19
cffi/__init__.py,sha256=vMoBBQacAlqzOsFf931EfnNqZnslrwcuaSeLUO6JTvY,513
cffi/__pycache__/__init__.cpython-36.pyc,,
cffi/__pycache__/api.cpython-36.pyc,,
cffi/__pycache__/backend_ctypes.cpython-36.pyc,,
cffi/__pycache__/cffi_opcode.cpython-36.pyc,,
cffi/__pycache__/commontypes.cpython-36.pyc,,
cffi/__pycache__/cparser.cpython-36.pyc,,
cffi/__pycache__/error.cpython-36.pyc,,
cffi/__pycache__/ffiplatform.cpython-36.pyc,,
cffi/__pycache__/lock.cpython-36.pyc,,
cffi/__pycache__/model.cpython-36.pyc,,
cffi/__pycache__/pkgconfig.cpython-36.pyc,,
cffi/__pycache__/recompiler.cpython-36.pyc,,
cffi/__pycache__/setuptools_ext.cpython-36.pyc,,
cffi/__pycache__/vengine_cpy.cpython-36.pyc,,
cffi/__pycache__/vengine_gen.cpython-36.pyc,,
cffi/__pycache__/verifier.cpython-36.pyc,,
cffi/_cffi_errors.h,sha256=6nFQ-4dRQI1bXRoSeqdvyKU33TmutQJB_2fAhWSzdl8,3856
cffi/_cffi_include.h,sha256=JuFfmwpRE65vym3Nxr9vDMOIEuv21tXdarkL1l2WNms,12149
cffi/_embedding.h,sha256=bhLhKOkF46V3C5gHLb4OkxH9pdcwMJqpjPHNDYojwbc,17411
cffi/api.py,sha256=Q07iwDD0FRwWa2fx2ZzQft69iJs9aNR52fvrtUy3EY4,41800
cffi/backend_ctypes.py,sha256=h5ZIzLc6BFVXnGyc9xPqZWUS7qGy7yFSDqXe68Sa8z4,42454
cffi/cffi_opcode.py,sha256=v9RdD_ovA8rCtqsC95Ivki5V667rAOhGgs3fb2q9xpM,5724
cffi/commontypes.py,sha256=QS4uxCDI7JhtTyjh1hlnCA-gynmaszWxJaRRLGkJa1A,2689
cffi/cparser.py,sha256=DIChXOqV-T3bZ3APc42V9zgeU0PdF4e57GU4WvIK4JQ,42079
cffi/error.py,sha256=v6xTiS4U0kvDcy4h_BDRo5v39ZQuj-IMRYLv5ETddZs,877
cffi/ffiplatform.py,sha256=HMXqR8ks2wtdsNxGaWpQ_PyqIvtiuos_vf1qKCy-cwg,4046
cffi/lock.py,sha256=l9TTdwMIMpi6jDkJGnQgE9cvTIR7CAntIJr8EGHt3pY,747
cffi/model.py,sha256=AYyjS26uiFKXtkm43qmStpy9zfGh5HVJF4UETYFBt6w,21682
cffi/parse_c_type.h,sha256=OdwQfwM9ktq6vlCB43exFQmxDBtj2MBNdK8LYl15tjw,5976
cffi/pkgconfig.py,sha256=LP1w7vmWvmKwyqLaU1Z243FOWGNQMrgMUZrvgFuOlco,4374
cffi/recompiler.py,sha256=9BR4oOQ9wFTMrp6CGa4Pa4U1pAU64Mv5-KwW5Hdn3ZM,62755
cffi/setuptools_ext.py,sha256=qc6arfrSzm4RNT5oJz6d5td7KJ-pHfI7bqYD0X4Q-08,8848
cffi/vengine_cpy.py,sha256=hdyjjZNijLrg_uGMnnFyC-7GG_LxWtwB8BlS2vvVDQ0,41470
cffi/vengine_gen.py,sha256=Zkq0-EdeZwn6qUvf_CI8iUEs2UxVIvDmKCH1j0-y0GI,26676
cffi/verifier.py,sha256=J9Enz2rbJb9CHPqWlWQ5uQESoyr0uc7MNWugchjXBv4,11207
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi-1.13.1.dist-info/WHEEL
================================================
Wheel-Version: 1.0
Generator: bdist_wheel (0.31.1)
Root-Is-Purelib: false
Tag: cp36-cp36m-manylinux1_x86_64
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi-1.13.1.dist-info/entry_points.txt
================================================
[distutils.setup_keywords]
cffi_modules = cffi.setuptools_ext:cffi_modules
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cffi-1.13.1.dist-info/top_level.txt
================================================
_cffi_backend
cffi
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/constantly/__init__.py
================================================
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
from constantly._constants import (
NamedConstant, Names, ValueConstant, Values, FlagConstant, Flags
)
from ._version import get_versions
__version__ = get_versions()['version']
del get_versions
__author__ = "Twisted Matrix Laboratories"
__license__ = "MIT"
__copyright__ = "Copyright 2011-2015 {0}".format(__author__)
__all__ = [
'NamedConstant',
'ValueConstant',
'FlagConstant',
'Names',
'Values',
'Flags',
]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/constantly/_constants.py
================================================
# -*- test-case-name: constantly.test.test_constants -*-
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Symbolic constant support, including collections and constants with text,
numeric, and bit flag values.
"""
from __future__ import division, absolute_import
__all__ = [
'NamedConstant', 'ValueConstant', 'FlagConstant',
'Names', 'Values', 'Flags']
from functools import partial
from itertools import count
from operator import and_, or_, xor
_unspecified = object()
_constantOrder = partial(next, count())
class _Constant(object):
"""
@ivar _index: A C{int} allocated from a shared counter in order to keep
track of the order in which L{_Constant}s are instantiated.
@ivar name: A C{str} giving the name of this constant; only set once the
constant is initialized by L{_ConstantsContainer}.
@ivar _container: The L{_ConstantsContainer} subclass this constant belongs
to; C{None} until the constant is initialized by that subclass.
"""
def __init__(self):
self._container = None
self._index = _constantOrder()
def __repr__(self):
"""
Return text identifying both which constant this is and which
collection it belongs to.
"""
return "<%s=%s>" % (self._container.__name__, self.name)
def __lt__(self, other):
"""
Implements C{<}. Order is defined by instantiation order.
@param other: An object.
@return: C{NotImplemented} if C{other} is not a constant belonging to
the same container as this constant, C{True} if this constant is
defined before C{other}, otherwise C{False}.
"""
if (
not isinstance(other, self.__class__) or
not self._container == other._container
):
return NotImplemented
return self._index < other._index
def __le__(self, other):
"""
Implements C{<=}. Order is defined by instantiation order.
@param other: An object.
@return: C{NotImplemented} if C{other} is not a constant belonging to
the same container as this constant, C{True} if this constant is
defined before or equal to C{other}, otherwise C{False}.
"""
if (
not isinstance(other, self.__class__) or
not self._container == other._container
):
return NotImplemented
return self is other or self._index < other._index
def __gt__(self, other):
"""
Implements C{>}. Order is defined by instantiation order.
@param other: An object.
@return: C{NotImplemented} if C{other} is not a constant belonging to
the same container as this constant, C{True} if this constant is
defined after C{other}, otherwise C{False}.
"""
if (
not isinstance(other, self.__class__) or
not self._container == other._container
):
return NotImplemented
return self._index > other._index
def __ge__(self, other):
"""
Implements C{>=}. Order is defined by instantiation order.
@param other: An object.
@return: C{NotImplemented} if C{other} is not a constant belonging to
the same container as this constant, C{True} if this constant is
defined after or equal to C{other}, otherwise C{False}.
"""
if (
not isinstance(other, self.__class__) or
not self._container == other._container
):
return NotImplemented
return self is other or self._index > other._index
def _realize(self, container, name, value):
"""
Complete the initialization of this L{_Constant}.
@param container: The L{_ConstantsContainer} subclass this constant is
part of.
@param name: The name of this constant in its container.
@param value: The value of this constant; not used, as named constants
have no value apart from their identity.
"""
self._container = container
self.name = name
class _ConstantsContainerType(type):
"""
L{_ConstantsContainerType} is a metaclass for creating constants container
classes.
"""
def __new__(self, name, bases, attributes):
"""
Create a new constants container class.
If C{attributes} includes a value of C{None} for the C{"_constantType"}
key, the new class will not be initialized as a constants container and
it will behave as a normal class.
@param name: The name of the container class.
@type name: L{str}
@param bases: A tuple of the base classes for the new container class.
@type bases: L{tuple} of L{_ConstantsContainerType} instances
@param attributes: The attributes of the new container class, including
any constants it is to contain.
@type attributes: L{dict}
"""
cls = super(_ConstantsContainerType, self).__new__(
self, name, bases, attributes)
# Only realize constants in concrete _ConstantsContainer subclasses.
# Ignore intermediate base classes.
constantType = getattr(cls, '_constantType', None)
if constantType is None:
return cls
constants = []
for (name, descriptor) in attributes.items():
if isinstance(descriptor, cls._constantType):
if descriptor._container is not None:
raise ValueError(
"Cannot use %s as the value of an attribute on %s" % (
descriptor, cls.__name__))
constants.append((descriptor._index, name, descriptor))
enumerants = {}
for (index, enumerant, descriptor) in sorted(constants):
value = cls._constantFactory(enumerant, descriptor)
descriptor._realize(cls, enumerant, value)
enumerants[enumerant] = descriptor
# Save the dictionary which contains *only* constants (distinct from
# any other attributes the application may have given the container)
# where the class can use it later (eg for lookupByName).
cls._enumerants = enumerants
return cls
# In Python3 metaclasses are defined using a C{metaclass} keyword argument in
# the class definition. This would cause a syntax error in Python2.
# So we use L{type} to introduce an intermediate base class with the desired
# metaclass.
# See:
# * http://docs.python.org/2/library/functions.html#type
# * http://docs.python.org/3/reference/datamodel.html#customizing-class-creation
class _ConstantsContainer(_ConstantsContainerType('', (object,), {})):
"""
L{_ConstantsContainer} is a class with attributes used as symbolic
constants. It is up to subclasses to specify what kind of constants are
allowed.
@cvar _constantType: Specified by a L{_ConstantsContainer} subclass to
specify the type of constants allowed by that subclass.
@cvar _enumerants: A C{dict} mapping the names of constants (eg
L{NamedConstant} instances) found in the class definition to those
instances.
"""
_constantType = None
def __new__(cls):
"""
Classes representing constants containers are not intended to be
instantiated.
The class object itself is used directly.
"""
raise TypeError("%s may not be instantiated." % (cls.__name__,))
@classmethod
def _constantFactory(cls, name, descriptor):
"""
Construct the value for a new constant to add to this container.
@param name: The name of the constant to create.
@param descriptor: An instance of a L{_Constant} subclass (eg
L{NamedConstant}) which is assigned to C{name}.
@return: L{NamedConstant} instances have no value apart from identity,
so return a meaningless dummy value.
"""
return _unspecified
@classmethod
def lookupByName(cls, name):
"""
Retrieve a constant by its name or raise a C{ValueError} if there is no
constant associated with that name.
@param name: A C{str} giving the name of one of the constants defined
by C{cls}.
@raise ValueError: If C{name} is not the name of one of the constants
defined by C{cls}.
@return: The L{NamedConstant} associated with C{name}.
"""
if name in cls._enumerants:
return getattr(cls, name)
raise ValueError(name)
@classmethod
def iterconstants(cls):
"""
Iteration over a L{Names} subclass results in all of the constants it
contains.
@return: an iterator the elements of which are the L{NamedConstant}
instances defined in the body of this L{Names} subclass.
"""
constants = cls._enumerants.values()
return iter(
sorted(constants, key=lambda descriptor: descriptor._index))
class NamedConstant(_Constant):
"""
L{NamedConstant} defines an attribute to be a named constant within a
collection defined by a L{Names} subclass.
L{NamedConstant} is only for use in the definition of L{Names}
subclasses. Do not instantiate L{NamedConstant} elsewhere and do not
subclass it.
"""
class Names(_ConstantsContainer):
"""
A L{Names} subclass contains constants which differ only in their names and
identities.
"""
_constantType = NamedConstant
class ValueConstant(_Constant):
"""
L{ValueConstant} defines an attribute to be a named constant within a
collection defined by a L{Values} subclass.
L{ValueConstant} is only for use in the definition of L{Values} subclasses.
Do not instantiate L{ValueConstant} elsewhere and do not subclass it.
"""
def __init__(self, value):
_Constant.__init__(self)
self.value = value
class Values(_ConstantsContainer):
"""
A L{Values} subclass contains constants which are associated with arbitrary
values.
"""
_constantType = ValueConstant
@classmethod
def lookupByValue(cls, value):
"""
Retrieve a constant by its value or raise a C{ValueError} if there is
no constant associated with that value.
@param value: The value of one of the constants defined by C{cls}.
@raise ValueError: If C{value} is not the value of one of the constants
defined by C{cls}.
@return: The L{ValueConstant} associated with C{value}.
"""
for constant in cls.iterconstants():
if constant.value == value:
return constant
raise ValueError(value)
def _flagOp(op, left, right):
"""
Implement a binary operator for a L{FlagConstant} instance.
@param op: A two-argument callable implementing the binary operation. For
example, C{operator.or_}.
@param left: The left-hand L{FlagConstant} instance.
@param right: The right-hand L{FlagConstant} instance.
@return: A new L{FlagConstant} instance representing the result of the
operation.
"""
value = op(left.value, right.value)
names = op(left.names, right.names)
result = FlagConstant()
result._realize(left._container, names, value)
return result
class FlagConstant(_Constant):
"""
L{FlagConstant} defines an attribute to be a flag constant within a
collection defined by a L{Flags} subclass.
L{FlagConstant} is only for use in the definition of L{Flags} subclasses.
Do not instantiate L{FlagConstant} elsewhere and do not subclass it.
"""
def __init__(self, value=_unspecified):
_Constant.__init__(self)
self.value = value
def _realize(self, container, names, value):
"""
Complete the initialization of this L{FlagConstant}.
This implementation differs from other C{_realize} implementations in
that a L{FlagConstant} may have several names which apply to it, due to
flags being combined with various operators.
@param container: The L{Flags} subclass this constant is part of.
@param names: When a single-flag value is being initialized, a C{str}
giving the name of that flag. This is the case which happens when
a L{Flags} subclass is being initialized and L{FlagConstant}
instances from its body are being realized. Otherwise, a C{set} of
C{str} giving names of all the flags set on this L{FlagConstant}
instance. This is the case when two flags are combined using C{|},
for example.
"""
if isinstance(names, str):
name = names
names = set([names])
elif len(names) == 1:
(name,) = names
else:
name = "{" + ",".join(sorted(names)) + "}"
_Constant._realize(self, container, name, value)
self.value = value
self.names = names
def __or__(self, other):
"""
Define C{|} on two L{FlagConstant} instances to create a new
L{FlagConstant} instance with all flags set in either instance set.
"""
return _flagOp(or_, self, other)
def __and__(self, other):
"""
Define C{&} on two L{FlagConstant} instances to create a new
L{FlagConstant} instance with only flags set in both instances set.
"""
return _flagOp(and_, self, other)
def __xor__(self, other):
"""
Define C{^} on two L{FlagConstant} instances to create a new
L{FlagConstant} instance with only flags set on exactly one instance
set.
"""
return _flagOp(xor, self, other)
def __invert__(self):
"""
Define C{~} on a L{FlagConstant} instance to create a new
L{FlagConstant} instance with all flags not set on this instance set.
"""
result = FlagConstant()
result._realize(self._container, set(), 0)
for flag in self._container.iterconstants():
if flag.value & self.value == 0:
result |= flag
return result
def __iter__(self):
"""
@return: An iterator of flags set on this instance set.
"""
return (self._container.lookupByName(name) for name in self.names)
def __contains__(self, flag):
"""
@param flag: The flag to test for membership in this instance
set.
@return: C{True} if C{flag} is in this instance set, else
C{False}.
"""
# Optimization for testing membership without iteration.
return bool(flag & self)
def __nonzero__(self):
"""
@return: C{False} if this flag's value is 0, else C{True}.
"""
return bool(self.value)
__bool__ = __nonzero__
class Flags(Values):
"""
A L{Flags} subclass contains constants which can be combined using the
common bitwise operators (C{|}, C{&}, etc) similar to a I{bitvector} from a
language like C.
"""
_constantType = FlagConstant
_value = 1
@classmethod
def _constantFactory(cls, name, descriptor):
"""
For L{FlagConstant} instances with no explicitly defined value, assign
the next power of two as its value.
@param name: The name of the constant to create.
@param descriptor: An instance of a L{FlagConstant} which is assigned
to C{name}.
@return: Either the value passed to the C{descriptor} constructor, or
the next power of 2 value which will be assigned to C{descriptor},
relative to the value of the last defined L{FlagConstant}.
"""
if descriptor.value is _unspecified:
value = cls._value
cls._value <<= 1
else:
value = descriptor.value
cls._value = value << 1
return value
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/constantly/_version.py
================================================
# This file was generated by 'versioneer.py' (0.15) from
# revision-control system data, or from the parent directory name of an
# unpacked source archive. Distribution tarballs contain a pre-generated copy
# of this file.
import json
import sys
version_json = '''
{
"dirty": false,
"error": null,
"full-revisionid": "c8375a7e3431792ea1b1b44678f3f6878d5e8c9a",
"version": "15.1.0"
}
''' # END VERSION_JSON
def get_versions():
return json.loads(version_json)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/constantly-15.1.0.dist-info/DESCRIPTION.rst
================================================
Constantly
==========
A library that provides symbolic constant support.
It includes collections and constants with text, numeric, and bit flag values.
Originally ``twisted.python.constants`` from the `Twisted `_ project.
Tests
-----
To run tests::
$ tox
This will run tests on Python 2.7, 3.3, 3.4, and PyPy, as well as doing coverage and pyflakes checks.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/constantly-15.1.0.dist-info/INSTALLER
================================================
pip
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/constantly-15.1.0.dist-info/METADATA
================================================
Metadata-Version: 2.0
Name: constantly
Version: 15.1.0
Summary: Symbolic constants in Python
Home-page: https://github.com/twisted/constantly
Author: Twisted Matrix Labs Developers
Author-email: UNKNOWN
License: MIT
Keywords: constants,enum,twisted
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Constantly
==========
A library that provides symbolic constant support.
It includes collections and constants with text, numeric, and bit flag values.
Originally ``twisted.python.constants`` from the `Twisted `_ project.
Tests
-----
To run tests::
$ tox
This will run tests on Python 2.7, 3.3, 3.4, and PyPy, as well as doing coverage and pyflakes checks.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/constantly-15.1.0.dist-info/RECORD
================================================
constantly-15.1.0.dist-info/DESCRIPTION.rst,sha256=sx7cfQa9trLrI06ORsPDOgA4UkW9KdPxYfygiqt50R4,397
constantly-15.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
constantly-15.1.0.dist-info/METADATA,sha256=4Rt-WjQ0S-JhhzVk__zpXfYLaC7KaVjQzW9SVaBhwoY,1214
constantly-15.1.0.dist-info/RECORD,,
constantly-15.1.0.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110
constantly-15.1.0.dist-info/metadata.json,sha256=y1-W-VJW79doSoMail8qNDduY5oHC2JGG1-tBZ_dA0k,923
constantly-15.1.0.dist-info/pbr.json,sha256=of4UIk4TOAoS3Gxf7oE2PwaRBcQW2ij9ZLRX1LMhy1A,47
constantly-15.1.0.dist-info/top_level.txt,sha256=Z3LZxRT3sV7OIcLddygWy8rRaguc4a1hlGotDs-vFIM,11
constantly/__init__.py,sha256=K2EFx89mIF8TkuE4F2ZhqeiE9UuB9S0DpFy0SNhu6uc,517
constantly/__pycache__/__init__.cpython-36.pyc,,
constantly/__pycache__/_constants.cpython-36.pyc,,
constantly/__pycache__/_version.cpython-36.pyc,,
constantly/_constants.py,sha256=n-QpkK73fCIyebkqp6hvUMuEe3uYeIptBtl4KahxpcI,16090
constantly/_version.py,sha256=kp8Hoj2tpH_Xpb4CONVFfYjTpEOr3EGzNRaT_IFZ3Ao,472
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/constantly-15.1.0.dist-info/WHEEL
================================================
Wheel-Version: 1.0
Generator: bdist_wheel (0.24.0)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/constantly-15.1.0.dist-info/metadata.json
================================================
{"license": "MIT", "name": "constantly", "metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "summary": "Symbolic constants in Python", "version": "15.1.0", "extensions": {"python.details": {"project_urls": {"Home": "https://github.com/twisted/constantly"}, "document_names": {"description": "DESCRIPTION.rst"}, "contacts": [{"role": "author", "name": "Twisted Matrix Labs Developers"}]}}, "keywords": ["constants", "enum", "twisted"], "classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries :: Python Modules"]}
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/constantly-15.1.0.dist-info/pbr.json
================================================
{"is_release": false, "git_version": "c8375a7"}
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/constantly-15.1.0.dist-info/top_level.txt
================================================
constantly
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/__about__.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
__all__ = [
"__title__", "__summary__", "__uri__", "__version__", "__author__",
"__email__", "__license__", "__copyright__",
]
__title__ = "cryptography"
__summary__ = ("cryptography is a package which provides cryptographic recipes"
" and primitives to Python developers.")
__uri__ = "https://github.com/pyca/cryptography"
__version__ = "2.8"
__author__ = "The cryptography developers"
__email__ = "cryptography-dev@python.org"
__license__ = "BSD or Apache License, Version 2.0"
__copyright__ = "Copyright 2013-2019 {}".format(__author__)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/__init__.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography.__about__ import (
__author__, __copyright__, __email__, __license__, __summary__, __title__,
__uri__, __version__
)
__all__ = [
"__title__", "__summary__", "__uri__", "__version__", "__author__",
"__email__", "__license__", "__copyright__",
]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/exceptions.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from enum import Enum
class _Reasons(Enum):
BACKEND_MISSING_INTERFACE = 0
UNSUPPORTED_HASH = 1
UNSUPPORTED_CIPHER = 2
UNSUPPORTED_PADDING = 3
UNSUPPORTED_MGF = 4
UNSUPPORTED_PUBLIC_KEY_ALGORITHM = 5
UNSUPPORTED_ELLIPTIC_CURVE = 6
UNSUPPORTED_SERIALIZATION = 7
UNSUPPORTED_X509 = 8
UNSUPPORTED_EXCHANGE_ALGORITHM = 9
UNSUPPORTED_DIFFIE_HELLMAN = 10
UNSUPPORTED_MAC = 11
class UnsupportedAlgorithm(Exception):
def __init__(self, message, reason=None):
super(UnsupportedAlgorithm, self).__init__(message)
self._reason = reason
class AlreadyFinalized(Exception):
pass
class AlreadyUpdated(Exception):
pass
class NotYetFinalized(Exception):
pass
class InvalidTag(Exception):
pass
class InvalidSignature(Exception):
pass
class InternalError(Exception):
def __init__(self, msg, err_code):
super(InternalError, self).__init__(msg)
self.err_code = err_code
class InvalidKey(Exception):
pass
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/fernet.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import base64
import binascii
import os
import struct
import time
import six
from cryptography import utils
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.hmac import HMAC
class InvalidToken(Exception):
pass
_MAX_CLOCK_SKEW = 60
class Fernet(object):
def __init__(self, key, backend=None):
if backend is None:
backend = default_backend()
key = base64.urlsafe_b64decode(key)
if len(key) != 32:
raise ValueError(
"Fernet key must be 32 url-safe base64-encoded bytes."
)
self._signing_key = key[:16]
self._encryption_key = key[16:]
self._backend = backend
@classmethod
def generate_key(cls):
return base64.urlsafe_b64encode(os.urandom(32))
def encrypt(self, data):
current_time = int(time.time())
iv = os.urandom(16)
return self._encrypt_from_parts(data, current_time, iv)
def _encrypt_from_parts(self, data, current_time, iv):
utils._check_bytes("data", data)
padder = padding.PKCS7(algorithms.AES.block_size).padder()
padded_data = padder.update(data) + padder.finalize()
encryptor = Cipher(
algorithms.AES(self._encryption_key), modes.CBC(iv), self._backend
).encryptor()
ciphertext = encryptor.update(padded_data) + encryptor.finalize()
basic_parts = (
b"\x80" + struct.pack(">Q", current_time) + iv + ciphertext
)
h = HMAC(self._signing_key, hashes.SHA256(), backend=self._backend)
h.update(basic_parts)
hmac = h.finalize()
return base64.urlsafe_b64encode(basic_parts + hmac)
def decrypt(self, token, ttl=None):
timestamp, data = Fernet._get_unverified_token_data(token)
return self._decrypt_data(data, timestamp, ttl)
def extract_timestamp(self, token):
timestamp, data = Fernet._get_unverified_token_data(token)
# Verify the token was not tampered with.
self._verify_signature(data)
return timestamp
@staticmethod
def _get_unverified_token_data(token):
utils._check_bytes("token", token)
try:
data = base64.urlsafe_b64decode(token)
except (TypeError, binascii.Error):
raise InvalidToken
if not data or six.indexbytes(data, 0) != 0x80:
raise InvalidToken
try:
timestamp, = struct.unpack(">Q", data[1:9])
except struct.error:
raise InvalidToken
return timestamp, data
def _verify_signature(self, data):
h = HMAC(self._signing_key, hashes.SHA256(), backend=self._backend)
h.update(data[:-32])
try:
h.verify(data[-32:])
except InvalidSignature:
raise InvalidToken
def _decrypt_data(self, data, timestamp, ttl):
current_time = int(time.time())
if ttl is not None:
if timestamp + ttl < current_time:
raise InvalidToken
if current_time + _MAX_CLOCK_SKEW < timestamp:
raise InvalidToken
self._verify_signature(data)
iv = data[9:25]
ciphertext = data[25:-32]
decryptor = Cipher(
algorithms.AES(self._encryption_key), modes.CBC(iv), self._backend
).decryptor()
plaintext_padded = decryptor.update(ciphertext)
try:
plaintext_padded += decryptor.finalize()
except ValueError:
raise InvalidToken
unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
unpadded = unpadder.update(plaintext_padded)
try:
unpadded += unpadder.finalize()
except ValueError:
raise InvalidToken
return unpadded
class MultiFernet(object):
def __init__(self, fernets):
fernets = list(fernets)
if not fernets:
raise ValueError(
"MultiFernet requires at least one Fernet instance"
)
self._fernets = fernets
def encrypt(self, msg):
return self._fernets[0].encrypt(msg)
def rotate(self, msg):
timestamp, data = Fernet._get_unverified_token_data(msg)
for f in self._fernets:
try:
p = f._decrypt_data(data, timestamp, None)
break
except InvalidToken:
pass
else:
raise InvalidToken
iv = os.urandom(16)
return self._fernets[0]._encrypt_from_parts(p, timestamp, iv)
def decrypt(self, msg, ttl=None):
for f in self._fernets:
try:
return f.decrypt(msg, ttl)
except InvalidToken:
pass
raise InvalidToken
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/__init__.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
"""
Hazardous Materials
This is a "Hazardous Materials" module. You should ONLY use it if you're
100% absolutely sure that you know what you're doing because this module
is full of land mines, dragons, and dinosaurs with laser guns.
"""
from __future__ import absolute_import, division, print_function
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/_der.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import six
from cryptography.utils import int_from_bytes, int_to_bytes
# This module contains a lightweight DER encoder and decoder. See X.690 for the
# specification. This module intentionally does not implement the more complex
# BER encoding, only DER.
#
# Note this implementation treats an element's constructed bit as part of the
# tag. This is fine for DER, where the bit is always computable from the type.
CONSTRUCTED = 0x20
CONTEXT_SPECIFIC = 0x80
INTEGER = 0x02
BIT_STRING = 0x03
OCTET_STRING = 0x04
NULL = 0x05
OBJECT_IDENTIFIER = 0x06
SEQUENCE = 0x10 | CONSTRUCTED
SET = 0x11 | CONSTRUCTED
PRINTABLE_STRING = 0x13
UTC_TIME = 0x17
GENERALIZED_TIME = 0x18
class DERReader(object):
def __init__(self, data):
self.data = memoryview(data)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, tb):
if exc_value is None:
self.check_empty()
def is_empty(self):
return len(self.data) == 0
def check_empty(self):
if not self.is_empty():
raise ValueError("Invalid DER input: trailing data")
def read_byte(self):
if len(self.data) < 1:
raise ValueError("Invalid DER input: insufficient data")
ret = six.indexbytes(self.data, 0)
self.data = self.data[1:]
return ret
def read_bytes(self, n):
if len(self.data) < n:
raise ValueError("Invalid DER input: insufficient data")
ret = self.data[:n]
self.data = self.data[n:]
return ret
def read_any_element(self):
tag = self.read_byte()
# Tag numbers 31 or higher are stored in multiple bytes. No supported
# ASN.1 types use such tags, so reject these.
if tag & 0x1f == 0x1f:
raise ValueError("Invalid DER input: unexpected high tag number")
length_byte = self.read_byte()
if length_byte & 0x80 == 0:
# If the high bit is clear, the first length byte is the length.
length = length_byte
else:
# If the high bit is set, the first length byte encodes the length
# of the length.
length_byte &= 0x7f
if length_byte == 0:
raise ValueError(
"Invalid DER input: indefinite length form is not allowed "
"in DER"
)
length = 0
for i in range(length_byte):
length <<= 8
length |= self.read_byte()
if length == 0:
raise ValueError(
"Invalid DER input: length was not minimally-encoded"
)
if length < 0x80:
# If the length could have been encoded in short form, it must
# not use long form.
raise ValueError(
"Invalid DER input: length was not minimally-encoded"
)
body = self.read_bytes(length)
return tag, DERReader(body)
def read_element(self, expected_tag):
tag, body = self.read_any_element()
if tag != expected_tag:
raise ValueError("Invalid DER input: unexpected tag")
return body
def read_single_element(self, expected_tag):
with self:
return self.read_element(expected_tag)
def read_optional_element(self, expected_tag):
if len(self.data) > 0 and six.indexbytes(self.data, 0) == expected_tag:
return self.read_element(expected_tag)
return None
def as_integer(self):
if len(self.data) == 0:
raise ValueError("Invalid DER input: empty integer contents")
first = six.indexbytes(self.data, 0)
if first & 0x80 == 0x80:
raise ValueError("Negative DER integers are not supported")
# The first 9 bits must not all be zero or all be ones. Otherwise, the
# encoding should have been one byte shorter.
if len(self.data) > 1:
second = six.indexbytes(self.data, 1)
if first == 0 and second & 0x80 == 0:
raise ValueError(
"Invalid DER input: integer not minimally-encoded"
)
return int_from_bytes(self.data, "big")
def encode_der_integer(x):
if not isinstance(x, six.integer_types):
raise ValueError("Value must be an integer")
if x < 0:
raise ValueError("Negative integers are not supported")
n = x.bit_length() // 8 + 1
return int_to_bytes(x, n)
def encode_der(tag, *children):
length = 0
for child in children:
length += len(child)
chunks = [six.int2byte(tag)]
if length < 0x80:
chunks.append(six.int2byte(length))
else:
length_bytes = int_to_bytes(length)
chunks.append(six.int2byte(0x80 | len(length_bytes)))
chunks.append(length_bytes)
chunks.extend(children)
return b"".join(chunks)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/_oid.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
class ObjectIdentifier(object):
def __init__(self, dotted_string):
self._dotted_string = dotted_string
nodes = self._dotted_string.split(".")
intnodes = []
# There must be at least 2 nodes, the first node must be 0..2, and
# if less than 2, the second node cannot have a value outside the
# range 0..39. All nodes must be integers.
for node in nodes:
try:
intnodes.append(int(node, 0))
except ValueError:
raise ValueError(
"Malformed OID: %s (non-integer nodes)" % (
self._dotted_string))
if len(nodes) < 2:
raise ValueError(
"Malformed OID: %s (insufficient number of nodes)" % (
self._dotted_string))
if intnodes[0] > 2:
raise ValueError(
"Malformed OID: %s (first node outside valid range)" % (
self._dotted_string))
if intnodes[0] < 2 and intnodes[1] >= 40:
raise ValueError(
"Malformed OID: %s (second node outside valid range)" % (
self._dotted_string))
def __eq__(self, other):
if not isinstance(other, ObjectIdentifier):
return NotImplemented
return self.dotted_string == other.dotted_string
def __ne__(self, other):
return not self == other
def __repr__(self):
return "".format(
self.dotted_string,
self._name
)
def __hash__(self):
return hash(self.dotted_string)
@property
def _name(self):
# Lazy import to avoid an import cycle
from cryptography.x509.oid import _OID_NAMES
return _OID_NAMES.get(self, "Unknown OID")
dotted_string = utils.read_only_property("_dotted_string")
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/__init__.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
_default_backend = None
def default_backend():
global _default_backend
if _default_backend is None:
from cryptography.hazmat.backends.openssl.backend import backend
_default_backend = backend
return _default_backend
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/interfaces.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class CipherBackend(object):
@abc.abstractmethod
def cipher_supported(self, cipher, mode):
"""
Return True if the given cipher and mode are supported.
"""
@abc.abstractmethod
def create_symmetric_encryption_ctx(self, cipher, mode):
"""
Get a CipherContext that can be used for encryption.
"""
@abc.abstractmethod
def create_symmetric_decryption_ctx(self, cipher, mode):
"""
Get a CipherContext that can be used for decryption.
"""
@six.add_metaclass(abc.ABCMeta)
class HashBackend(object):
@abc.abstractmethod
def hash_supported(self, algorithm):
"""
Return True if the hash algorithm is supported by this backend.
"""
@abc.abstractmethod
def create_hash_ctx(self, algorithm):
"""
Create a HashContext for calculating a message digest.
"""
@six.add_metaclass(abc.ABCMeta)
class HMACBackend(object):
@abc.abstractmethod
def hmac_supported(self, algorithm):
"""
Return True if the hash algorithm is supported for HMAC by this
backend.
"""
@abc.abstractmethod
def create_hmac_ctx(self, key, algorithm):
"""
Create a context for calculating a message authentication code.
"""
@six.add_metaclass(abc.ABCMeta)
class CMACBackend(object):
@abc.abstractmethod
def cmac_algorithm_supported(self, algorithm):
"""
Returns True if the block cipher is supported for CMAC by this backend
"""
@abc.abstractmethod
def create_cmac_ctx(self, algorithm):
"""
Create a context for calculating a message authentication code.
"""
@six.add_metaclass(abc.ABCMeta)
class PBKDF2HMACBackend(object):
@abc.abstractmethod
def pbkdf2_hmac_supported(self, algorithm):
"""
Return True if the hash algorithm is supported for PBKDF2 by this
backend.
"""
@abc.abstractmethod
def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations,
key_material):
"""
Return length bytes derived from provided PBKDF2 parameters.
"""
@six.add_metaclass(abc.ABCMeta)
class RSABackend(object):
@abc.abstractmethod
def generate_rsa_private_key(self, public_exponent, key_size):
"""
Generate an RSAPrivateKey instance with public_exponent and a modulus
of key_size bits.
"""
@abc.abstractmethod
def rsa_padding_supported(self, padding):
"""
Returns True if the backend supports the given padding options.
"""
@abc.abstractmethod
def generate_rsa_parameters_supported(self, public_exponent, key_size):
"""
Returns True if the backend supports the given parameters for key
generation.
"""
@abc.abstractmethod
def load_rsa_private_numbers(self, numbers):
"""
Returns an RSAPrivateKey provider.
"""
@abc.abstractmethod
def load_rsa_public_numbers(self, numbers):
"""
Returns an RSAPublicKey provider.
"""
@six.add_metaclass(abc.ABCMeta)
class DSABackend(object):
@abc.abstractmethod
def generate_dsa_parameters(self, key_size):
"""
Generate a DSAParameters instance with a modulus of key_size bits.
"""
@abc.abstractmethod
def generate_dsa_private_key(self, parameters):
"""
Generate a DSAPrivateKey instance with parameters as a DSAParameters
object.
"""
@abc.abstractmethod
def generate_dsa_private_key_and_parameters(self, key_size):
"""
Generate a DSAPrivateKey instance using key size only.
"""
@abc.abstractmethod
def dsa_hash_supported(self, algorithm):
"""
Return True if the hash algorithm is supported by the backend for DSA.
"""
@abc.abstractmethod
def dsa_parameters_supported(self, p, q, g):
"""
Return True if the parameters are supported by the backend for DSA.
"""
@abc.abstractmethod
def load_dsa_private_numbers(self, numbers):
"""
Returns a DSAPrivateKey provider.
"""
@abc.abstractmethod
def load_dsa_public_numbers(self, numbers):
"""
Returns a DSAPublicKey provider.
"""
@abc.abstractmethod
def load_dsa_parameter_numbers(self, numbers):
"""
Returns a DSAParameters provider.
"""
@six.add_metaclass(abc.ABCMeta)
class EllipticCurveBackend(object):
@abc.abstractmethod
def elliptic_curve_signature_algorithm_supported(
self, signature_algorithm, curve
):
"""
Returns True if the backend supports the named elliptic curve with the
specified signature algorithm.
"""
@abc.abstractmethod
def elliptic_curve_supported(self, curve):
"""
Returns True if the backend supports the named elliptic curve.
"""
@abc.abstractmethod
def generate_elliptic_curve_private_key(self, curve):
"""
Return an object conforming to the EllipticCurvePrivateKey interface.
"""
@abc.abstractmethod
def load_elliptic_curve_public_numbers(self, numbers):
"""
Return an EllipticCurvePublicKey provider using the given numbers.
"""
@abc.abstractmethod
def load_elliptic_curve_private_numbers(self, numbers):
"""
Return an EllipticCurvePrivateKey provider using the given numbers.
"""
@abc.abstractmethod
def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve):
"""
Returns whether the exchange algorithm is supported by this backend.
"""
@abc.abstractmethod
def derive_elliptic_curve_private_key(self, private_value, curve):
"""
Compute the private key given the private value and curve.
"""
@six.add_metaclass(abc.ABCMeta)
class PEMSerializationBackend(object):
@abc.abstractmethod
def load_pem_private_key(self, data, password):
"""
Loads a private key from PEM encoded data, using the provided password
if the data is encrypted.
"""
@abc.abstractmethod
def load_pem_public_key(self, data):
"""
Loads a public key from PEM encoded data.
"""
@abc.abstractmethod
def load_pem_parameters(self, data):
"""
Load encryption parameters from PEM encoded data.
"""
@six.add_metaclass(abc.ABCMeta)
class DERSerializationBackend(object):
@abc.abstractmethod
def load_der_private_key(self, data, password):
"""
Loads a private key from DER encoded data. Uses the provided password
if the data is encrypted.
"""
@abc.abstractmethod
def load_der_public_key(self, data):
"""
Loads a public key from DER encoded data.
"""
@abc.abstractmethod
def load_der_parameters(self, data):
"""
Load encryption parameters from DER encoded data.
"""
@six.add_metaclass(abc.ABCMeta)
class X509Backend(object):
@abc.abstractmethod
def load_pem_x509_certificate(self, data):
"""
Load an X.509 certificate from PEM encoded data.
"""
@abc.abstractmethod
def load_der_x509_certificate(self, data):
"""
Load an X.509 certificate from DER encoded data.
"""
@abc.abstractmethod
def load_der_x509_csr(self, data):
"""
Load an X.509 CSR from DER encoded data.
"""
@abc.abstractmethod
def load_pem_x509_csr(self, data):
"""
Load an X.509 CSR from PEM encoded data.
"""
@abc.abstractmethod
def create_x509_csr(self, builder, private_key, algorithm):
"""
Create and sign an X.509 CSR from a CSR builder object.
"""
@abc.abstractmethod
def create_x509_certificate(self, builder, private_key, algorithm):
"""
Create and sign an X.509 certificate from a CertificateBuilder object.
"""
@abc.abstractmethod
def create_x509_crl(self, builder, private_key, algorithm):
"""
Create and sign an X.509 CertificateRevocationList from a
CertificateRevocationListBuilder object.
"""
@abc.abstractmethod
def create_x509_revoked_certificate(self, builder):
"""
Create a RevokedCertificate object from a RevokedCertificateBuilder
object.
"""
@abc.abstractmethod
def x509_name_bytes(self, name):
"""
Compute the DER encoded bytes of an X509 Name object.
"""
@six.add_metaclass(abc.ABCMeta)
class DHBackend(object):
@abc.abstractmethod
def generate_dh_parameters(self, generator, key_size):
"""
Generate a DHParameters instance with a modulus of key_size bits.
Using the given generator. Often 2 or 5.
"""
@abc.abstractmethod
def generate_dh_private_key(self, parameters):
"""
Generate a DHPrivateKey instance with parameters as a DHParameters
object.
"""
@abc.abstractmethod
def generate_dh_private_key_and_parameters(self, generator, key_size):
"""
Generate a DHPrivateKey instance using key size only.
Using the given generator. Often 2 or 5.
"""
@abc.abstractmethod
def load_dh_private_numbers(self, numbers):
"""
Load a DHPrivateKey from DHPrivateNumbers
"""
@abc.abstractmethod
def load_dh_public_numbers(self, numbers):
"""
Load a DHPublicKey from DHPublicNumbers.
"""
@abc.abstractmethod
def load_dh_parameter_numbers(self, numbers):
"""
Load DHParameters from DHParameterNumbers.
"""
@abc.abstractmethod
def dh_parameters_supported(self, p, g, q=None):
"""
Returns whether the backend supports DH with these parameter values.
"""
@abc.abstractmethod
def dh_x942_serialization_supported(self):
"""
Returns True if the backend supports the serialization of DH objects
with subgroup order (q).
"""
@six.add_metaclass(abc.ABCMeta)
class ScryptBackend(object):
@abc.abstractmethod
def derive_scrypt(self, key_material, salt, length, n, r, p):
"""
Return bytes derived from provided Scrypt parameters.
"""
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/__init__.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography.hazmat.backends.openssl.backend import backend
__all__ = ["backend"]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/aead.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography.exceptions import InvalidTag
_ENCRYPT = 1
_DECRYPT = 0
def _aead_cipher_name(cipher):
from cryptography.hazmat.primitives.ciphers.aead import (
AESCCM, AESGCM, ChaCha20Poly1305
)
if isinstance(cipher, ChaCha20Poly1305):
return b"chacha20-poly1305"
elif isinstance(cipher, AESCCM):
return "aes-{}-ccm".format(len(cipher._key) * 8).encode("ascii")
else:
assert isinstance(cipher, AESGCM)
return "aes-{}-gcm".format(len(cipher._key) * 8).encode("ascii")
def _aead_setup(backend, cipher_name, key, nonce, tag, tag_len, operation):
evp_cipher = backend._lib.EVP_get_cipherbyname(cipher_name)
backend.openssl_assert(evp_cipher != backend._ffi.NULL)
ctx = backend._lib.EVP_CIPHER_CTX_new()
ctx = backend._ffi.gc(ctx, backend._lib.EVP_CIPHER_CTX_free)
res = backend._lib.EVP_CipherInit_ex(
ctx, evp_cipher,
backend._ffi.NULL,
backend._ffi.NULL,
backend._ffi.NULL,
int(operation == _ENCRYPT)
)
backend.openssl_assert(res != 0)
res = backend._lib.EVP_CIPHER_CTX_set_key_length(ctx, len(key))
backend.openssl_assert(res != 0)
res = backend._lib.EVP_CIPHER_CTX_ctrl(
ctx, backend._lib.EVP_CTRL_AEAD_SET_IVLEN, len(nonce),
backend._ffi.NULL
)
backend.openssl_assert(res != 0)
if operation == _DECRYPT:
res = backend._lib.EVP_CIPHER_CTX_ctrl(
ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, len(tag), tag
)
backend.openssl_assert(res != 0)
elif cipher_name.endswith(b"-ccm"):
res = backend._lib.EVP_CIPHER_CTX_ctrl(
ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, tag_len, backend._ffi.NULL
)
backend.openssl_assert(res != 0)
nonce_ptr = backend._ffi.from_buffer(nonce)
key_ptr = backend._ffi.from_buffer(key)
res = backend._lib.EVP_CipherInit_ex(
ctx,
backend._ffi.NULL,
backend._ffi.NULL,
key_ptr,
nonce_ptr,
int(operation == _ENCRYPT)
)
backend.openssl_assert(res != 0)
return ctx
def _set_length(backend, ctx, data_len):
intptr = backend._ffi.new("int *")
res = backend._lib.EVP_CipherUpdate(
ctx,
backend._ffi.NULL,
intptr,
backend._ffi.NULL,
data_len
)
backend.openssl_assert(res != 0)
def _process_aad(backend, ctx, associated_data):
outlen = backend._ffi.new("int *")
res = backend._lib.EVP_CipherUpdate(
ctx, backend._ffi.NULL, outlen, associated_data, len(associated_data)
)
backend.openssl_assert(res != 0)
def _process_data(backend, ctx, data):
outlen = backend._ffi.new("int *")
buf = backend._ffi.new("unsigned char[]", len(data))
res = backend._lib.EVP_CipherUpdate(ctx, buf, outlen, data, len(data))
backend.openssl_assert(res != 0)
return backend._ffi.buffer(buf, outlen[0])[:]
def _encrypt(backend, cipher, nonce, data, associated_data, tag_length):
from cryptography.hazmat.primitives.ciphers.aead import AESCCM
cipher_name = _aead_cipher_name(cipher)
ctx = _aead_setup(
backend, cipher_name, cipher._key, nonce, None, tag_length, _ENCRYPT
)
# CCM requires us to pass the length of the data before processing anything
# However calling this with any other AEAD results in an error
if isinstance(cipher, AESCCM):
_set_length(backend, ctx, len(data))
_process_aad(backend, ctx, associated_data)
processed_data = _process_data(backend, ctx, data)
outlen = backend._ffi.new("int *")
res = backend._lib.EVP_CipherFinal_ex(ctx, backend._ffi.NULL, outlen)
backend.openssl_assert(res != 0)
backend.openssl_assert(outlen[0] == 0)
tag_buf = backend._ffi.new("unsigned char[]", tag_length)
res = backend._lib.EVP_CIPHER_CTX_ctrl(
ctx, backend._lib.EVP_CTRL_AEAD_GET_TAG, tag_length, tag_buf
)
backend.openssl_assert(res != 0)
tag = backend._ffi.buffer(tag_buf)[:]
return processed_data + tag
def _decrypt(backend, cipher, nonce, data, associated_data, tag_length):
from cryptography.hazmat.primitives.ciphers.aead import AESCCM
if len(data) < tag_length:
raise InvalidTag
tag = data[-tag_length:]
data = data[:-tag_length]
cipher_name = _aead_cipher_name(cipher)
ctx = _aead_setup(
backend, cipher_name, cipher._key, nonce, tag, tag_length, _DECRYPT
)
# CCM requires us to pass the length of the data before processing anything
# However calling this with any other AEAD results in an error
if isinstance(cipher, AESCCM):
_set_length(backend, ctx, len(data))
_process_aad(backend, ctx, associated_data)
# CCM has a different error path if the tag doesn't match. Errors are
# raised in Update and Final is irrelevant.
if isinstance(cipher, AESCCM):
outlen = backend._ffi.new("int *")
buf = backend._ffi.new("unsigned char[]", len(data))
res = backend._lib.EVP_CipherUpdate(ctx, buf, outlen, data, len(data))
if res != 1:
backend._consume_errors()
raise InvalidTag
processed_data = backend._ffi.buffer(buf, outlen[0])[:]
else:
processed_data = _process_data(backend, ctx, data)
outlen = backend._ffi.new("int *")
res = backend._lib.EVP_CipherFinal_ex(ctx, backend._ffi.NULL, outlen)
if res == 0:
backend._consume_errors()
raise InvalidTag
return processed_data
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/backend.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import base64
import collections
import contextlib
import itertools
from contextlib import contextmanager
import six
from six.moves import range
from cryptography import utils, x509
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat._der import (
INTEGER, NULL, SEQUENCE, encode_der, encode_der_integer
)
from cryptography.hazmat.backends.interfaces import (
CMACBackend, CipherBackend, DERSerializationBackend, DHBackend, DSABackend,
EllipticCurveBackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
PEMSerializationBackend, RSABackend, ScryptBackend, X509Backend
)
from cryptography.hazmat.backends.openssl import aead
from cryptography.hazmat.backends.openssl.ciphers import _CipherContext
from cryptography.hazmat.backends.openssl.cmac import _CMACContext
from cryptography.hazmat.backends.openssl.decode_asn1 import (
_CRL_ENTRY_REASON_ENUM_TO_CODE
)
from cryptography.hazmat.backends.openssl.dh import (
_DHParameters, _DHPrivateKey, _DHPublicKey, _dh_params_dup
)
from cryptography.hazmat.backends.openssl.dsa import (
_DSAParameters, _DSAPrivateKey, _DSAPublicKey
)
from cryptography.hazmat.backends.openssl.ec import (
_EllipticCurvePrivateKey, _EllipticCurvePublicKey
)
from cryptography.hazmat.backends.openssl.ed25519 import (
_Ed25519PrivateKey, _Ed25519PublicKey
)
from cryptography.hazmat.backends.openssl.ed448 import (
_ED448_KEY_SIZE, _Ed448PrivateKey, _Ed448PublicKey
)
from cryptography.hazmat.backends.openssl.encode_asn1 import (
_CRL_ENTRY_EXTENSION_ENCODE_HANDLERS,
_CRL_EXTENSION_ENCODE_HANDLERS, _EXTENSION_ENCODE_HANDLERS,
_OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS,
_OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS,
_encode_asn1_int_gc, _encode_asn1_str_gc, _encode_name_gc, _txt2obj_gc,
)
from cryptography.hazmat.backends.openssl.hashes import _HashContext
from cryptography.hazmat.backends.openssl.hmac import _HMACContext
from cryptography.hazmat.backends.openssl.ocsp import (
_OCSPRequest, _OCSPResponse
)
from cryptography.hazmat.backends.openssl.poly1305 import (
_POLY1305_KEY_SIZE, _Poly1305Context
)
from cryptography.hazmat.backends.openssl.rsa import (
_RSAPrivateKey, _RSAPublicKey
)
from cryptography.hazmat.backends.openssl.x25519 import (
_X25519PrivateKey, _X25519PublicKey
)
from cryptography.hazmat.backends.openssl.x448 import (
_X448PrivateKey, _X448PublicKey
)
from cryptography.hazmat.backends.openssl.x509 import (
_Certificate, _CertificateRevocationList,
_CertificateSigningRequest, _RevokedCertificate
)
from cryptography.hazmat.bindings.openssl import binding
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import (
dsa, ec, ed25519, ed448, rsa
)
from cryptography.hazmat.primitives.asymmetric.padding import (
MGF1, OAEP, PKCS1v15, PSS
)
from cryptography.hazmat.primitives.ciphers.algorithms import (
AES, ARC4, Blowfish, CAST5, Camellia, ChaCha20, IDEA, SEED, TripleDES
)
from cryptography.hazmat.primitives.ciphers.modes import (
CBC, CFB, CFB8, CTR, ECB, GCM, OFB, XTS
)
from cryptography.hazmat.primitives.kdf import scrypt
from cryptography.hazmat.primitives.serialization import ssh
from cryptography.x509 import ocsp
_MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"])
@utils.register_interface(CipherBackend)
@utils.register_interface(CMACBackend)
@utils.register_interface(DERSerializationBackend)
@utils.register_interface(DHBackend)
@utils.register_interface(DSABackend)
@utils.register_interface(EllipticCurveBackend)
@utils.register_interface(HashBackend)
@utils.register_interface(HMACBackend)
@utils.register_interface(PBKDF2HMACBackend)
@utils.register_interface(RSABackend)
@utils.register_interface(PEMSerializationBackend)
@utils.register_interface(X509Backend)
@utils.register_interface_if(
binding.Binding().lib.Cryptography_HAS_SCRYPT, ScryptBackend
)
class Backend(object):
"""
OpenSSL API binding interfaces.
"""
name = "openssl"
def __init__(self):
self._binding = binding.Binding()
self._ffi = self._binding.ffi
self._lib = self._binding.lib
self._cipher_registry = {}
self._register_default_ciphers()
self.activate_osrandom_engine()
self._dh_types = [self._lib.EVP_PKEY_DH]
if self._lib.Cryptography_HAS_EVP_PKEY_DHX:
self._dh_types.append(self._lib.EVP_PKEY_DHX)
def openssl_assert(self, ok):
return binding._openssl_assert(self._lib, ok)
def activate_builtin_random(self):
if self._lib.Cryptography_HAS_ENGINE:
# Obtain a new structural reference.
e = self._lib.ENGINE_get_default_RAND()
if e != self._ffi.NULL:
self._lib.ENGINE_unregister_RAND(e)
# Reset the RNG to use the built-in.
res = self._lib.RAND_set_rand_method(self._ffi.NULL)
self.openssl_assert(res == 1)
# decrement the structural reference from get_default_RAND
res = self._lib.ENGINE_finish(e)
self.openssl_assert(res == 1)
@contextlib.contextmanager
def _get_osurandom_engine(self):
# Fetches an engine by id and returns it. This creates a structural
# reference.
e = self._lib.ENGINE_by_id(self._lib.Cryptography_osrandom_engine_id)
self.openssl_assert(e != self._ffi.NULL)
# Initialize the engine for use. This adds a functional reference.
res = self._lib.ENGINE_init(e)
self.openssl_assert(res == 1)
try:
yield e
finally:
# Decrement the structural ref incremented by ENGINE_by_id.
res = self._lib.ENGINE_free(e)
self.openssl_assert(res == 1)
# Decrement the functional ref incremented by ENGINE_init.
res = self._lib.ENGINE_finish(e)
self.openssl_assert(res == 1)
def activate_osrandom_engine(self):
if self._lib.Cryptography_HAS_ENGINE:
# Unregister and free the current engine.
self.activate_builtin_random()
with self._get_osurandom_engine() as e:
# Set the engine as the default RAND provider.
res = self._lib.ENGINE_set_default_RAND(e)
self.openssl_assert(res == 1)
# Reset the RNG to use the engine
res = self._lib.RAND_set_rand_method(self._ffi.NULL)
self.openssl_assert(res == 1)
def osrandom_engine_implementation(self):
buf = self._ffi.new("char[]", 64)
with self._get_osurandom_engine() as e:
res = self._lib.ENGINE_ctrl_cmd(e, b"get_implementation",
len(buf), buf,
self._ffi.NULL, 0)
self.openssl_assert(res > 0)
return self._ffi.string(buf).decode('ascii')
def openssl_version_text(self):
"""
Friendly string name of the loaded OpenSSL library. This is not
necessarily the same version as it was compiled against.
Example: OpenSSL 1.0.1e 11 Feb 2013
"""
return self._ffi.string(
self._lib.OpenSSL_version(self._lib.OPENSSL_VERSION)
).decode("ascii")
def openssl_version_number(self):
return self._lib.OpenSSL_version_num()
def create_hmac_ctx(self, key, algorithm):
return _HMACContext(self, key, algorithm)
def _evp_md_from_algorithm(self, algorithm):
if algorithm.name == "blake2b" or algorithm.name == "blake2s":
alg = "{}{}".format(
algorithm.name, algorithm.digest_size * 8
).encode("ascii")
else:
alg = algorithm.name.encode("ascii")
evp_md = self._lib.EVP_get_digestbyname(alg)
return evp_md
def _evp_md_non_null_from_algorithm(self, algorithm):
evp_md = self._evp_md_from_algorithm(algorithm)
self.openssl_assert(evp_md != self._ffi.NULL)
return evp_md
def hash_supported(self, algorithm):
evp_md = self._evp_md_from_algorithm(algorithm)
return evp_md != self._ffi.NULL
def hmac_supported(self, algorithm):
return self.hash_supported(algorithm)
def create_hash_ctx(self, algorithm):
return _HashContext(self, algorithm)
def cipher_supported(self, cipher, mode):
try:
adapter = self._cipher_registry[type(cipher), type(mode)]
except KeyError:
return False
evp_cipher = adapter(self, cipher, mode)
return self._ffi.NULL != evp_cipher
def register_cipher_adapter(self, cipher_cls, mode_cls, adapter):
if (cipher_cls, mode_cls) in self._cipher_registry:
raise ValueError("Duplicate registration for: {} {}.".format(
cipher_cls, mode_cls)
)
self._cipher_registry[cipher_cls, mode_cls] = adapter
def _register_default_ciphers(self):
for mode_cls in [CBC, CTR, ECB, OFB, CFB, CFB8, GCM]:
self.register_cipher_adapter(
AES,
mode_cls,
GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}")
)
for mode_cls in [CBC, CTR, ECB, OFB, CFB]:
self.register_cipher_adapter(
Camellia,
mode_cls,
GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}")
)
for mode_cls in [CBC, CFB, CFB8, OFB]:
self.register_cipher_adapter(
TripleDES,
mode_cls,
GetCipherByName("des-ede3-{mode.name}")
)
self.register_cipher_adapter(
TripleDES,
ECB,
GetCipherByName("des-ede3")
)
for mode_cls in [CBC, CFB, OFB, ECB]:
self.register_cipher_adapter(
Blowfish,
mode_cls,
GetCipherByName("bf-{mode.name}")
)
for mode_cls in [CBC, CFB, OFB, ECB]:
self.register_cipher_adapter(
SEED,
mode_cls,
GetCipherByName("seed-{mode.name}")
)
for cipher_cls, mode_cls in itertools.product(
[CAST5, IDEA],
[CBC, OFB, CFB, ECB],
):
self.register_cipher_adapter(
cipher_cls,
mode_cls,
GetCipherByName("{cipher.name}-{mode.name}")
)
self.register_cipher_adapter(
ARC4,
type(None),
GetCipherByName("rc4")
)
self.register_cipher_adapter(
ChaCha20,
type(None),
GetCipherByName("chacha20")
)
self.register_cipher_adapter(AES, XTS, _get_xts_cipher)
def create_symmetric_encryption_ctx(self, cipher, mode):
return _CipherContext(self, cipher, mode, _CipherContext._ENCRYPT)
def create_symmetric_decryption_ctx(self, cipher, mode):
return _CipherContext(self, cipher, mode, _CipherContext._DECRYPT)
def pbkdf2_hmac_supported(self, algorithm):
return self.hmac_supported(algorithm)
def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations,
key_material):
buf = self._ffi.new("unsigned char[]", length)
evp_md = self._evp_md_non_null_from_algorithm(algorithm)
key_material_ptr = self._ffi.from_buffer(key_material)
res = self._lib.PKCS5_PBKDF2_HMAC(
key_material_ptr,
len(key_material),
salt,
len(salt),
iterations,
evp_md,
length,
buf
)
self.openssl_assert(res == 1)
return self._ffi.buffer(buf)[:]
def _consume_errors(self):
return binding._consume_errors(self._lib)
def _bn_to_int(self, bn):
assert bn != self._ffi.NULL
if not six.PY2:
# Python 3 has constant time from_bytes, so use that.
bn_num_bytes = self._lib.BN_num_bytes(bn)
bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes)
bin_len = self._lib.BN_bn2bin(bn, bin_ptr)
# A zero length means the BN has value 0
self.openssl_assert(bin_len >= 0)
val = int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big")
if self._lib.BN_is_negative(bn):
val = -val
return val
else:
# Under Python 2 the best we can do is hex()
hex_cdata = self._lib.BN_bn2hex(bn)
self.openssl_assert(hex_cdata != self._ffi.NULL)
hex_str = self._ffi.string(hex_cdata)
self._lib.OPENSSL_free(hex_cdata)
return int(hex_str, 16)
def _int_to_bn(self, num, bn=None):
"""
Converts a python integer to a BIGNUM. The returned BIGNUM will not
be garbage collected (to support adding them to structs that take
ownership of the object). Be sure to register it for GC if it will
be discarded after use.
"""
assert bn is None or bn != self._ffi.NULL
if bn is None:
bn = self._ffi.NULL
if not six.PY2:
# Python 3 has constant time to_bytes, so use that.
binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big")
bn_ptr = self._lib.BN_bin2bn(binary, len(binary), bn)
self.openssl_assert(bn_ptr != self._ffi.NULL)
return bn_ptr
else:
# Under Python 2 the best we can do is hex(), [2:] removes the 0x
# prefix.
hex_num = hex(num).rstrip("L")[2:].encode("ascii")
bn_ptr = self._ffi.new("BIGNUM **")
bn_ptr[0] = bn
res = self._lib.BN_hex2bn(bn_ptr, hex_num)
self.openssl_assert(res != 0)
self.openssl_assert(bn_ptr[0] != self._ffi.NULL)
return bn_ptr[0]
def generate_rsa_private_key(self, public_exponent, key_size):
rsa._verify_rsa_parameters(public_exponent, key_size)
rsa_cdata = self._lib.RSA_new()
self.openssl_assert(rsa_cdata != self._ffi.NULL)
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
bn = self._int_to_bn(public_exponent)
bn = self._ffi.gc(bn, self._lib.BN_free)
res = self._lib.RSA_generate_key_ex(
rsa_cdata, key_size, bn, self._ffi.NULL
)
self.openssl_assert(res == 1)
evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata)
return _RSAPrivateKey(self, rsa_cdata, evp_pkey)
def generate_rsa_parameters_supported(self, public_exponent, key_size):
return (public_exponent >= 3 and public_exponent & 1 != 0 and
key_size >= 512)
def load_rsa_private_numbers(self, numbers):
rsa._check_private_key_components(
numbers.p,
numbers.q,
numbers.d,
numbers.dmp1,
numbers.dmq1,
numbers.iqmp,
numbers.public_numbers.e,
numbers.public_numbers.n
)
rsa_cdata = self._lib.RSA_new()
self.openssl_assert(rsa_cdata != self._ffi.NULL)
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
p = self._int_to_bn(numbers.p)
q = self._int_to_bn(numbers.q)
d = self._int_to_bn(numbers.d)
dmp1 = self._int_to_bn(numbers.dmp1)
dmq1 = self._int_to_bn(numbers.dmq1)
iqmp = self._int_to_bn(numbers.iqmp)
e = self._int_to_bn(numbers.public_numbers.e)
n = self._int_to_bn(numbers.public_numbers.n)
res = self._lib.RSA_set0_factors(rsa_cdata, p, q)
self.openssl_assert(res == 1)
res = self._lib.RSA_set0_key(rsa_cdata, n, e, d)
self.openssl_assert(res == 1)
res = self._lib.RSA_set0_crt_params(rsa_cdata, dmp1, dmq1, iqmp)
self.openssl_assert(res == 1)
res = self._lib.RSA_blinding_on(rsa_cdata, self._ffi.NULL)
self.openssl_assert(res == 1)
evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata)
return _RSAPrivateKey(self, rsa_cdata, evp_pkey)
def load_rsa_public_numbers(self, numbers):
rsa._check_public_key_components(numbers.e, numbers.n)
rsa_cdata = self._lib.RSA_new()
self.openssl_assert(rsa_cdata != self._ffi.NULL)
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
e = self._int_to_bn(numbers.e)
n = self._int_to_bn(numbers.n)
res = self._lib.RSA_set0_key(rsa_cdata, n, e, self._ffi.NULL)
self.openssl_assert(res == 1)
evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata)
return _RSAPublicKey(self, rsa_cdata, evp_pkey)
def _create_evp_pkey_gc(self):
evp_pkey = self._lib.EVP_PKEY_new()
self.openssl_assert(evp_pkey != self._ffi.NULL)
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
return evp_pkey
def _rsa_cdata_to_evp_pkey(self, rsa_cdata):
evp_pkey = self._create_evp_pkey_gc()
res = self._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata)
self.openssl_assert(res == 1)
return evp_pkey
def _bytes_to_bio(self, data):
"""
Return a _MemoryBIO namedtuple of (BIO, char*).
The char* is the storage for the BIO and it must stay alive until the
BIO is finished with.
"""
data_ptr = self._ffi.from_buffer(data)
bio = self._lib.BIO_new_mem_buf(
data_ptr, len(data)
)
self.openssl_assert(bio != self._ffi.NULL)
return _MemoryBIO(self._ffi.gc(bio, self._lib.BIO_free), data_ptr)
def _create_mem_bio_gc(self):
"""
Creates an empty memory BIO.
"""
bio_method = self._lib.BIO_s_mem()
self.openssl_assert(bio_method != self._ffi.NULL)
bio = self._lib.BIO_new(bio_method)
self.openssl_assert(bio != self._ffi.NULL)
bio = self._ffi.gc(bio, self._lib.BIO_free)
return bio
def _read_mem_bio(self, bio):
"""
Reads a memory BIO. This only works on memory BIOs.
"""
buf = self._ffi.new("char **")
buf_len = self._lib.BIO_get_mem_data(bio, buf)
self.openssl_assert(buf_len > 0)
self.openssl_assert(buf[0] != self._ffi.NULL)
bio_data = self._ffi.buffer(buf[0], buf_len)[:]
return bio_data
def _evp_pkey_to_private_key(self, evp_pkey):
"""
Return the appropriate type of PrivateKey given an evp_pkey cdata
pointer.
"""
key_type = self._lib.EVP_PKEY_id(evp_pkey)
if key_type == self._lib.EVP_PKEY_RSA:
rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey)
self.openssl_assert(rsa_cdata != self._ffi.NULL)
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
return _RSAPrivateKey(self, rsa_cdata, evp_pkey)
elif key_type == self._lib.EVP_PKEY_DSA:
dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey)
self.openssl_assert(dsa_cdata != self._ffi.NULL)
dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free)
return _DSAPrivateKey(self, dsa_cdata, evp_pkey)
elif key_type == self._lib.EVP_PKEY_EC:
ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey)
self.openssl_assert(ec_cdata != self._ffi.NULL)
ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey)
elif key_type in self._dh_types:
dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey)
self.openssl_assert(dh_cdata != self._ffi.NULL)
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
return _DHPrivateKey(self, dh_cdata, evp_pkey)
elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None):
# EVP_PKEY_ED25519 is not present in OpenSSL < 1.1.1
return _Ed25519PrivateKey(self, evp_pkey)
elif key_type == getattr(self._lib, "EVP_PKEY_X448", None):
# EVP_PKEY_X448 is not present in OpenSSL < 1.1.1
return _X448PrivateKey(self, evp_pkey)
elif key_type == getattr(self._lib, "EVP_PKEY_X25519", None):
# EVP_PKEY_X25519 is not present in OpenSSL < 1.1.0
return _X25519PrivateKey(self, evp_pkey)
elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None):
# EVP_PKEY_ED448 is not present in OpenSSL < 1.1.1
return _Ed448PrivateKey(self, evp_pkey)
else:
raise UnsupportedAlgorithm("Unsupported key type.")
def _evp_pkey_to_public_key(self, evp_pkey):
"""
Return the appropriate type of PublicKey given an evp_pkey cdata
pointer.
"""
key_type = self._lib.EVP_PKEY_id(evp_pkey)
if key_type == self._lib.EVP_PKEY_RSA:
rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey)
self.openssl_assert(rsa_cdata != self._ffi.NULL)
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
return _RSAPublicKey(self, rsa_cdata, evp_pkey)
elif key_type == self._lib.EVP_PKEY_DSA:
dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey)
self.openssl_assert(dsa_cdata != self._ffi.NULL)
dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free)
return _DSAPublicKey(self, dsa_cdata, evp_pkey)
elif key_type == self._lib.EVP_PKEY_EC:
ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey)
self.openssl_assert(ec_cdata != self._ffi.NULL)
ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey)
elif key_type in self._dh_types:
dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey)
self.openssl_assert(dh_cdata != self._ffi.NULL)
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
return _DHPublicKey(self, dh_cdata, evp_pkey)
elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None):
# EVP_PKEY_ED25519 is not present in OpenSSL < 1.1.1
return _Ed25519PublicKey(self, evp_pkey)
elif key_type == getattr(self._lib, "EVP_PKEY_X448", None):
# EVP_PKEY_X448 is not present in OpenSSL < 1.1.1
return _X448PublicKey(self, evp_pkey)
elif key_type == getattr(self._lib, "EVP_PKEY_X25519", None):
# EVP_PKEY_X25519 is not present in OpenSSL < 1.1.0
return _X25519PublicKey(self, evp_pkey)
elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None):
# EVP_PKEY_X25519 is not present in OpenSSL < 1.1.1
return _Ed448PublicKey(self, evp_pkey)
else:
raise UnsupportedAlgorithm("Unsupported key type.")
def _oaep_hash_supported(self, algorithm):
if self._lib.Cryptography_HAS_RSA_OAEP_MD:
return isinstance(
algorithm, (
hashes.SHA1,
hashes.SHA224,
hashes.SHA256,
hashes.SHA384,
hashes.SHA512,
)
)
else:
return isinstance(algorithm, hashes.SHA1)
def rsa_padding_supported(self, padding):
if isinstance(padding, PKCS1v15):
return True
elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1):
return self.hash_supported(padding._mgf._algorithm)
elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1):
return (
self._oaep_hash_supported(padding._mgf._algorithm) and
self._oaep_hash_supported(padding._algorithm) and
(
(padding._label is None or len(padding._label) == 0) or
self._lib.Cryptography_HAS_RSA_OAEP_LABEL == 1
)
)
else:
return False
def generate_dsa_parameters(self, key_size):
if key_size not in (1024, 2048, 3072):
raise ValueError("Key size must be 1024 or 2048 or 3072 bits.")
ctx = self._lib.DSA_new()
self.openssl_assert(ctx != self._ffi.NULL)
ctx = self._ffi.gc(ctx, self._lib.DSA_free)
res = self._lib.DSA_generate_parameters_ex(
ctx, key_size, self._ffi.NULL, 0,
self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
)
self.openssl_assert(res == 1)
return _DSAParameters(self, ctx)
def generate_dsa_private_key(self, parameters):
ctx = self._lib.DSAparams_dup(parameters._dsa_cdata)
self.openssl_assert(ctx != self._ffi.NULL)
ctx = self._ffi.gc(ctx, self._lib.DSA_free)
self._lib.DSA_generate_key(ctx)
evp_pkey = self._dsa_cdata_to_evp_pkey(ctx)
return _DSAPrivateKey(self, ctx, evp_pkey)
def generate_dsa_private_key_and_parameters(self, key_size):
parameters = self.generate_dsa_parameters(key_size)
return self.generate_dsa_private_key(parameters)
def _dsa_cdata_set_values(self, dsa_cdata, p, q, g, pub_key, priv_key):
res = self._lib.DSA_set0_pqg(dsa_cdata, p, q, g)
self.openssl_assert(res == 1)
res = self._lib.DSA_set0_key(dsa_cdata, pub_key, priv_key)
self.openssl_assert(res == 1)
def load_dsa_private_numbers(self, numbers):
dsa._check_dsa_private_numbers(numbers)
parameter_numbers = numbers.public_numbers.parameter_numbers
dsa_cdata = self._lib.DSA_new()
self.openssl_assert(dsa_cdata != self._ffi.NULL)
dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free)
p = self._int_to_bn(parameter_numbers.p)
q = self._int_to_bn(parameter_numbers.q)
g = self._int_to_bn(parameter_numbers.g)
pub_key = self._int_to_bn(numbers.public_numbers.y)
priv_key = self._int_to_bn(numbers.x)
self._dsa_cdata_set_values(dsa_cdata, p, q, g, pub_key, priv_key)
evp_pkey = self._dsa_cdata_to_evp_pkey(dsa_cdata)
return _DSAPrivateKey(self, dsa_cdata, evp_pkey)
def load_dsa_public_numbers(self, numbers):
dsa._check_dsa_parameters(numbers.parameter_numbers)
dsa_cdata = self._lib.DSA_new()
self.openssl_assert(dsa_cdata != self._ffi.NULL)
dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free)
p = self._int_to_bn(numbers.parameter_numbers.p)
q = self._int_to_bn(numbers.parameter_numbers.q)
g = self._int_to_bn(numbers.parameter_numbers.g)
pub_key = self._int_to_bn(numbers.y)
priv_key = self._ffi.NULL
self._dsa_cdata_set_values(dsa_cdata, p, q, g, pub_key, priv_key)
evp_pkey = self._dsa_cdata_to_evp_pkey(dsa_cdata)
return _DSAPublicKey(self, dsa_cdata, evp_pkey)
def load_dsa_parameter_numbers(self, numbers):
dsa._check_dsa_parameters(numbers)
dsa_cdata = self._lib.DSA_new()
self.openssl_assert(dsa_cdata != self._ffi.NULL)
dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free)
p = self._int_to_bn(numbers.p)
q = self._int_to_bn(numbers.q)
g = self._int_to_bn(numbers.g)
res = self._lib.DSA_set0_pqg(dsa_cdata, p, q, g)
self.openssl_assert(res == 1)
return _DSAParameters(self, dsa_cdata)
def _dsa_cdata_to_evp_pkey(self, dsa_cdata):
evp_pkey = self._create_evp_pkey_gc()
res = self._lib.EVP_PKEY_set1_DSA(evp_pkey, dsa_cdata)
self.openssl_assert(res == 1)
return evp_pkey
def dsa_hash_supported(self, algorithm):
return self.hash_supported(algorithm)
def dsa_parameters_supported(self, p, q, g):
return True
def cmac_algorithm_supported(self, algorithm):
return self.cipher_supported(
algorithm, CBC(b"\x00" * algorithm.block_size)
)
def create_cmac_ctx(self, algorithm):
return _CMACContext(self, algorithm)
def create_x509_csr(self, builder, private_key, algorithm):
if not isinstance(builder, x509.CertificateSigningRequestBuilder):
raise TypeError('Builder type mismatch.')
if isinstance(private_key,
(ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)):
if algorithm is not None:
raise ValueError(
"algorithm must be None when signing via ed25519 or ed448"
)
elif not isinstance(algorithm, hashes.HashAlgorithm):
raise TypeError('Algorithm must be a registered hash algorithm.')
elif (
isinstance(algorithm, hashes.MD5) and not
isinstance(private_key, rsa.RSAPrivateKey)
):
raise ValueError(
"MD5 is not a supported hash algorithm for EC/DSA CSRs"
)
# Resolve the signature algorithm.
evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm)
# Create an empty request.
x509_req = self._lib.X509_REQ_new()
self.openssl_assert(x509_req != self._ffi.NULL)
x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free)
# Set x509 version.
res = self._lib.X509_REQ_set_version(x509_req, x509.Version.v1.value)
self.openssl_assert(res == 1)
# Set subject name.
res = self._lib.X509_REQ_set_subject_name(
x509_req, _encode_name_gc(self, builder._subject_name)
)
self.openssl_assert(res == 1)
# Set subject public key.
public_key = private_key.public_key()
res = self._lib.X509_REQ_set_pubkey(
x509_req, public_key._evp_pkey
)
self.openssl_assert(res == 1)
# Add extensions.
sk_extension = self._lib.sk_X509_EXTENSION_new_null()
self.openssl_assert(sk_extension != self._ffi.NULL)
sk_extension = self._ffi.gc(
sk_extension,
lambda x: self._lib.sk_X509_EXTENSION_pop_free(
x, self._ffi.addressof(
self._lib._original_lib, "X509_EXTENSION_free"
)
)
)
# Don't GC individual extensions because the memory is owned by
# sk_extensions and will be freed along with it.
self._create_x509_extensions(
extensions=builder._extensions,
handlers=_EXTENSION_ENCODE_HANDLERS,
x509_obj=sk_extension,
add_func=self._lib.sk_X509_EXTENSION_insert,
gc=False
)
res = self._lib.X509_REQ_add_extensions(x509_req, sk_extension)
self.openssl_assert(res == 1)
# Sign the request using the requester's private key.
res = self._lib.X509_REQ_sign(
x509_req, private_key._evp_pkey, evp_md
)
if res == 0:
errors = self._consume_errors()
self.openssl_assert(
errors[0]._lib_reason_match(
self._lib.ERR_LIB_RSA,
self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
)
)
raise ValueError("Digest too big for RSA key")
return _CertificateSigningRequest(self, x509_req)
def create_x509_certificate(self, builder, private_key, algorithm):
if not isinstance(builder, x509.CertificateBuilder):
raise TypeError('Builder type mismatch.')
if isinstance(private_key,
(ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)):
if algorithm is not None:
raise ValueError(
"algorithm must be None when signing via ed25519 or ed448"
)
elif not isinstance(algorithm, hashes.HashAlgorithm):
raise TypeError('Algorithm must be a registered hash algorithm.')
if (
isinstance(algorithm, hashes.MD5) and not
isinstance(private_key, rsa.RSAPrivateKey)
):
raise ValueError(
"MD5 is only (reluctantly) supported for RSA certificates"
)
# Resolve the signature algorithm.
evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm)
# Create an empty certificate.
x509_cert = self._lib.X509_new()
x509_cert = self._ffi.gc(x509_cert, backend._lib.X509_free)
# Set the x509 version.
res = self._lib.X509_set_version(x509_cert, builder._version.value)
self.openssl_assert(res == 1)
# Set the subject's name.
res = self._lib.X509_set_subject_name(
x509_cert, _encode_name_gc(self, builder._subject_name)
)
self.openssl_assert(res == 1)
# Set the subject's public key.
res = self._lib.X509_set_pubkey(
x509_cert, builder._public_key._evp_pkey
)
self.openssl_assert(res == 1)
# Set the certificate serial number.
serial_number = _encode_asn1_int_gc(self, builder._serial_number)
res = self._lib.X509_set_serialNumber(x509_cert, serial_number)
self.openssl_assert(res == 1)
# Set the "not before" time.
self._set_asn1_time(
self._lib.X509_getm_notBefore(x509_cert), builder._not_valid_before
)
# Set the "not after" time.
self._set_asn1_time(
self._lib.X509_getm_notAfter(x509_cert), builder._not_valid_after
)
# Add extensions.
self._create_x509_extensions(
extensions=builder._extensions,
handlers=_EXTENSION_ENCODE_HANDLERS,
x509_obj=x509_cert,
add_func=self._lib.X509_add_ext,
gc=True
)
# Set the issuer name.
res = self._lib.X509_set_issuer_name(
x509_cert, _encode_name_gc(self, builder._issuer_name)
)
self.openssl_assert(res == 1)
# Sign the certificate with the issuer's private key.
res = self._lib.X509_sign(
x509_cert, private_key._evp_pkey, evp_md
)
if res == 0:
errors = self._consume_errors()
self.openssl_assert(
errors[0]._lib_reason_match(
self._lib.ERR_LIB_RSA,
self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
)
)
raise ValueError("Digest too big for RSA key")
return _Certificate(self, x509_cert)
def _evp_md_x509_null_if_eddsa(self, private_key, algorithm):
if isinstance(private_key,
(ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)):
# OpenSSL requires us to pass NULL for EVP_MD for ed25519/ed448
return self._ffi.NULL
else:
return self._evp_md_non_null_from_algorithm(algorithm)
def _set_asn1_time(self, asn1_time, time):
if time.year >= 2050:
asn1_str = time.strftime('%Y%m%d%H%M%SZ').encode('ascii')
else:
asn1_str = time.strftime('%y%m%d%H%M%SZ').encode('ascii')
res = self._lib.ASN1_TIME_set_string(asn1_time, asn1_str)
self.openssl_assert(res == 1)
def _create_asn1_time(self, time):
asn1_time = self._lib.ASN1_TIME_new()
self.openssl_assert(asn1_time != self._ffi.NULL)
asn1_time = self._ffi.gc(asn1_time, self._lib.ASN1_TIME_free)
self._set_asn1_time(asn1_time, time)
return asn1_time
def create_x509_crl(self, builder, private_key, algorithm):
if not isinstance(builder, x509.CertificateRevocationListBuilder):
raise TypeError('Builder type mismatch.')
if isinstance(private_key,
(ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)):
if algorithm is not None:
raise ValueError(
"algorithm must be None when signing via ed25519 or ed448"
)
elif not isinstance(algorithm, hashes.HashAlgorithm):
raise TypeError('Algorithm must be a registered hash algorithm.')
if (
isinstance(algorithm, hashes.MD5) and not
isinstance(private_key, rsa.RSAPrivateKey)
):
raise ValueError(
"MD5 is not a supported hash algorithm for EC/DSA CRLs"
)
evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm)
# Create an empty CRL.
x509_crl = self._lib.X509_CRL_new()
x509_crl = self._ffi.gc(x509_crl, backend._lib.X509_CRL_free)
# Set the x509 CRL version. We only support v2 (integer value 1).
res = self._lib.X509_CRL_set_version(x509_crl, 1)
self.openssl_assert(res == 1)
# Set the issuer name.
res = self._lib.X509_CRL_set_issuer_name(
x509_crl, _encode_name_gc(self, builder._issuer_name)
)
self.openssl_assert(res == 1)
# Set the last update time.
last_update = self._create_asn1_time(builder._last_update)
res = self._lib.X509_CRL_set_lastUpdate(x509_crl, last_update)
self.openssl_assert(res == 1)
# Set the next update time.
next_update = self._create_asn1_time(builder._next_update)
res = self._lib.X509_CRL_set_nextUpdate(x509_crl, next_update)
self.openssl_assert(res == 1)
# Add extensions.
self._create_x509_extensions(
extensions=builder._extensions,
handlers=_CRL_EXTENSION_ENCODE_HANDLERS,
x509_obj=x509_crl,
add_func=self._lib.X509_CRL_add_ext,
gc=True
)
# add revoked certificates
for revoked_cert in builder._revoked_certificates:
# Duplicating because the X509_CRL takes ownership and will free
# this memory when X509_CRL_free is called.
revoked = self._lib.Cryptography_X509_REVOKED_dup(
revoked_cert._x509_revoked
)
self.openssl_assert(revoked != self._ffi.NULL)
res = self._lib.X509_CRL_add0_revoked(x509_crl, revoked)
self.openssl_assert(res == 1)
res = self._lib.X509_CRL_sign(
x509_crl, private_key._evp_pkey, evp_md
)
if res == 0:
errors = self._consume_errors()
self.openssl_assert(
errors[0]._lib_reason_match(
self._lib.ERR_LIB_RSA,
self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
)
)
raise ValueError("Digest too big for RSA key")
return _CertificateRevocationList(self, x509_crl)
def _create_x509_extensions(self, extensions, handlers, x509_obj,
add_func, gc):
for i, extension in enumerate(extensions):
x509_extension = self._create_x509_extension(
handlers, extension
)
self.openssl_assert(x509_extension != self._ffi.NULL)
if gc:
x509_extension = self._ffi.gc(
x509_extension, self._lib.X509_EXTENSION_free
)
res = add_func(x509_obj, x509_extension, i)
self.openssl_assert(res >= 1)
def _create_raw_x509_extension(self, extension, value):
obj = _txt2obj_gc(self, extension.oid.dotted_string)
return self._lib.X509_EXTENSION_create_by_OBJ(
self._ffi.NULL, obj, 1 if extension.critical else 0, value
)
def _create_x509_extension(self, handlers, extension):
if isinstance(extension.value, x509.UnrecognizedExtension):
value = _encode_asn1_str_gc(self, extension.value.value)
return self._create_raw_x509_extension(extension, value)
elif isinstance(extension.value, x509.TLSFeature):
asn1 = encode_der(
SEQUENCE,
*[
encode_der(INTEGER, encode_der_integer(x.value))
for x in extension.value
]
)
value = _encode_asn1_str_gc(self, asn1)
return self._create_raw_x509_extension(extension, value)
elif isinstance(extension.value, x509.PrecertPoison):
value = _encode_asn1_str_gc(self, encode_der(NULL))
return self._create_raw_x509_extension(extension, value)
else:
try:
encode = handlers[extension.oid]
except KeyError:
raise NotImplementedError(
'Extension not supported: {}'.format(extension.oid)
)
ext_struct = encode(self, extension.value)
nid = self._lib.OBJ_txt2nid(
extension.oid.dotted_string.encode("ascii")
)
backend.openssl_assert(nid != self._lib.NID_undef)
return self._lib.X509V3_EXT_i2d(
nid, 1 if extension.critical else 0, ext_struct
)
def create_x509_revoked_certificate(self, builder):
if not isinstance(builder, x509.RevokedCertificateBuilder):
raise TypeError('Builder type mismatch.')
x509_revoked = self._lib.X509_REVOKED_new()
self.openssl_assert(x509_revoked != self._ffi.NULL)
x509_revoked = self._ffi.gc(x509_revoked, self._lib.X509_REVOKED_free)
serial_number = _encode_asn1_int_gc(self, builder._serial_number)
res = self._lib.X509_REVOKED_set_serialNumber(
x509_revoked, serial_number
)
self.openssl_assert(res == 1)
rev_date = self._create_asn1_time(builder._revocation_date)
res = self._lib.X509_REVOKED_set_revocationDate(x509_revoked, rev_date)
self.openssl_assert(res == 1)
# add CRL entry extensions
self._create_x509_extensions(
extensions=builder._extensions,
handlers=_CRL_ENTRY_EXTENSION_ENCODE_HANDLERS,
x509_obj=x509_revoked,
add_func=self._lib.X509_REVOKED_add_ext,
gc=True
)
return _RevokedCertificate(self, None, x509_revoked)
def load_pem_private_key(self, data, password):
return self._load_key(
self._lib.PEM_read_bio_PrivateKey,
self._evp_pkey_to_private_key,
data,
password,
)
def load_pem_public_key(self, data):
mem_bio = self._bytes_to_bio(data)
evp_pkey = self._lib.PEM_read_bio_PUBKEY(
mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
)
if evp_pkey != self._ffi.NULL:
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
return self._evp_pkey_to_public_key(evp_pkey)
else:
# It's not a (RSA/DSA/ECDSA) subjectPublicKeyInfo, but we still
# need to check to see if it is a pure PKCS1 RSA public key (not
# embedded in a subjectPublicKeyInfo)
self._consume_errors()
res = self._lib.BIO_reset(mem_bio.bio)
self.openssl_assert(res == 1)
rsa_cdata = self._lib.PEM_read_bio_RSAPublicKey(
mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
)
if rsa_cdata != self._ffi.NULL:
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata)
return _RSAPublicKey(self, rsa_cdata, evp_pkey)
else:
self._handle_key_loading_error()
def load_pem_parameters(self, data):
mem_bio = self._bytes_to_bio(data)
# only DH is supported currently
dh_cdata = self._lib.PEM_read_bio_DHparams(
mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL)
if dh_cdata != self._ffi.NULL:
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
return _DHParameters(self, dh_cdata)
else:
self._handle_key_loading_error()
def load_der_private_key(self, data, password):
# OpenSSL has a function called d2i_AutoPrivateKey that in theory
# handles this automatically, however it doesn't handle encrypted
# private keys. Instead we try to load the key two different ways.
# First we'll try to load it as a traditional key.
bio_data = self._bytes_to_bio(data)
key = self._evp_pkey_from_der_traditional_key(bio_data, password)
if key:
return self._evp_pkey_to_private_key(key)
else:
# Finally we try to load it with the method that handles encrypted
# PKCS8 properly.
return self._load_key(
self._lib.d2i_PKCS8PrivateKey_bio,
self._evp_pkey_to_private_key,
data,
password,
)
def _evp_pkey_from_der_traditional_key(self, bio_data, password):
key = self._lib.d2i_PrivateKey_bio(bio_data.bio, self._ffi.NULL)
if key != self._ffi.NULL:
key = self._ffi.gc(key, self._lib.EVP_PKEY_free)
if password is not None:
raise TypeError(
"Password was given but private key is not encrypted."
)
return key
else:
self._consume_errors()
return None
def load_der_public_key(self, data):
mem_bio = self._bytes_to_bio(data)
evp_pkey = self._lib.d2i_PUBKEY_bio(mem_bio.bio, self._ffi.NULL)
if evp_pkey != self._ffi.NULL:
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
return self._evp_pkey_to_public_key(evp_pkey)
else:
# It's not a (RSA/DSA/ECDSA) subjectPublicKeyInfo, but we still
# need to check to see if it is a pure PKCS1 RSA public key (not
# embedded in a subjectPublicKeyInfo)
self._consume_errors()
res = self._lib.BIO_reset(mem_bio.bio)
self.openssl_assert(res == 1)
rsa_cdata = self._lib.d2i_RSAPublicKey_bio(
mem_bio.bio, self._ffi.NULL
)
if rsa_cdata != self._ffi.NULL:
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata)
return _RSAPublicKey(self, rsa_cdata, evp_pkey)
else:
self._handle_key_loading_error()
def load_der_parameters(self, data):
mem_bio = self._bytes_to_bio(data)
dh_cdata = self._lib.d2i_DHparams_bio(
mem_bio.bio, self._ffi.NULL
)
if dh_cdata != self._ffi.NULL:
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
return _DHParameters(self, dh_cdata)
elif self._lib.Cryptography_HAS_EVP_PKEY_DHX:
# We check to see if the is dhx.
self._consume_errors()
res = self._lib.BIO_reset(mem_bio.bio)
self.openssl_assert(res == 1)
dh_cdata = self._lib.Cryptography_d2i_DHxparams_bio(
mem_bio.bio, self._ffi.NULL
)
if dh_cdata != self._ffi.NULL:
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
return _DHParameters(self, dh_cdata)
self._handle_key_loading_error()
def load_pem_x509_certificate(self, data):
mem_bio = self._bytes_to_bio(data)
x509 = self._lib.PEM_read_bio_X509(
mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
)
if x509 == self._ffi.NULL:
self._consume_errors()
raise ValueError(
"Unable to load certificate. See https://cryptography.io/en/la"
"test/faq/#why-can-t-i-import-my-pem-file for more details."
)
x509 = self._ffi.gc(x509, self._lib.X509_free)
return _Certificate(self, x509)
def load_der_x509_certificate(self, data):
mem_bio = self._bytes_to_bio(data)
x509 = self._lib.d2i_X509_bio(mem_bio.bio, self._ffi.NULL)
if x509 == self._ffi.NULL:
self._consume_errors()
raise ValueError("Unable to load certificate")
x509 = self._ffi.gc(x509, self._lib.X509_free)
return _Certificate(self, x509)
def load_pem_x509_crl(self, data):
mem_bio = self._bytes_to_bio(data)
x509_crl = self._lib.PEM_read_bio_X509_CRL(
mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
)
if x509_crl == self._ffi.NULL:
self._consume_errors()
raise ValueError(
"Unable to load CRL. See https://cryptography.io/en/la"
"test/faq/#why-can-t-i-import-my-pem-file for more details."
)
x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free)
return _CertificateRevocationList(self, x509_crl)
def load_der_x509_crl(self, data):
mem_bio = self._bytes_to_bio(data)
x509_crl = self._lib.d2i_X509_CRL_bio(mem_bio.bio, self._ffi.NULL)
if x509_crl == self._ffi.NULL:
self._consume_errors()
raise ValueError("Unable to load CRL")
x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free)
return _CertificateRevocationList(self, x509_crl)
def load_pem_x509_csr(self, data):
mem_bio = self._bytes_to_bio(data)
x509_req = self._lib.PEM_read_bio_X509_REQ(
mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
)
if x509_req == self._ffi.NULL:
self._consume_errors()
raise ValueError(
"Unable to load request. See https://cryptography.io/en/la"
"test/faq/#why-can-t-i-import-my-pem-file for more details."
)
x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free)
return _CertificateSigningRequest(self, x509_req)
def load_der_x509_csr(self, data):
mem_bio = self._bytes_to_bio(data)
x509_req = self._lib.d2i_X509_REQ_bio(mem_bio.bio, self._ffi.NULL)
if x509_req == self._ffi.NULL:
self._consume_errors()
raise ValueError("Unable to load request")
x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free)
return _CertificateSigningRequest(self, x509_req)
def _load_key(self, openssl_read_func, convert_func, data, password):
mem_bio = self._bytes_to_bio(data)
userdata = self._ffi.new("CRYPTOGRAPHY_PASSWORD_DATA *")
if password is not None:
utils._check_byteslike("password", password)
password_ptr = self._ffi.from_buffer(password)
userdata.password = password_ptr
userdata.length = len(password)
evp_pkey = openssl_read_func(
mem_bio.bio,
self._ffi.NULL,
self._ffi.addressof(
self._lib._original_lib, "Cryptography_pem_password_cb"
),
userdata,
)
if evp_pkey == self._ffi.NULL:
if userdata.error != 0:
errors = self._consume_errors()
self.openssl_assert(errors)
if userdata.error == -1:
raise TypeError(
"Password was not given but private key is encrypted"
)
else:
assert userdata.error == -2
raise ValueError(
"Passwords longer than {} bytes are not supported "
"by this backend.".format(userdata.maxsize - 1)
)
else:
self._handle_key_loading_error()
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
if password is not None and userdata.called == 0:
raise TypeError(
"Password was given but private key is not encrypted.")
assert (
(password is not None and userdata.called == 1) or
password is None
)
return convert_func(evp_pkey)
def _handle_key_loading_error(self):
errors = self._consume_errors()
if not errors:
raise ValueError("Could not deserialize key data.")
elif (
errors[0]._lib_reason_match(
self._lib.ERR_LIB_EVP, self._lib.EVP_R_BAD_DECRYPT
) or errors[0]._lib_reason_match(
self._lib.ERR_LIB_PKCS12,
self._lib.PKCS12_R_PKCS12_CIPHERFINAL_ERROR
)
):
raise ValueError("Bad decrypt. Incorrect password?")
elif (
errors[0]._lib_reason_match(
self._lib.ERR_LIB_EVP, self._lib.EVP_R_UNKNOWN_PBE_ALGORITHM
) or errors[0]._lib_reason_match(
self._lib.ERR_LIB_PEM, self._lib.PEM_R_UNSUPPORTED_ENCRYPTION
)
):
raise UnsupportedAlgorithm(
"PEM data is encrypted with an unsupported cipher",
_Reasons.UNSUPPORTED_CIPHER
)
elif any(
error._lib_reason_match(
self._lib.ERR_LIB_EVP,
self._lib.EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM
)
for error in errors
):
raise ValueError("Unsupported public key algorithm.")
else:
assert errors[0].lib in (
self._lib.ERR_LIB_EVP,
self._lib.ERR_LIB_PEM,
self._lib.ERR_LIB_ASN1,
)
raise ValueError("Could not deserialize key data.")
def elliptic_curve_supported(self, curve):
try:
curve_nid = self._elliptic_curve_to_nid(curve)
except UnsupportedAlgorithm:
curve_nid = self._lib.NID_undef
group = self._lib.EC_GROUP_new_by_curve_name(curve_nid)
if group == self._ffi.NULL:
errors = self._consume_errors()
self.openssl_assert(
curve_nid == self._lib.NID_undef or
errors[0]._lib_reason_match(
self._lib.ERR_LIB_EC,
self._lib.EC_R_UNKNOWN_GROUP
)
)
return False
else:
self.openssl_assert(curve_nid != self._lib.NID_undef)
self._lib.EC_GROUP_free(group)
return True
def elliptic_curve_signature_algorithm_supported(
self, signature_algorithm, curve
):
# We only support ECDSA right now.
if not isinstance(signature_algorithm, ec.ECDSA):
return False
return self.elliptic_curve_supported(curve)
def generate_elliptic_curve_private_key(self, curve):
"""
Generate a new private key on the named curve.
"""
if self.elliptic_curve_supported(curve):
ec_cdata = self._ec_key_new_by_curve(curve)
res = self._lib.EC_KEY_generate_key(ec_cdata)
self.openssl_assert(res == 1)
evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata)
return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey)
else:
raise UnsupportedAlgorithm(
"Backend object does not support {}.".format(curve.name),
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE
)
def load_elliptic_curve_private_numbers(self, numbers):
public = numbers.public_numbers
ec_cdata = self._ec_key_new_by_curve(public.curve)
private_value = self._ffi.gc(
self._int_to_bn(numbers.private_value), self._lib.BN_clear_free
)
res = self._lib.EC_KEY_set_private_key(ec_cdata, private_value)
self.openssl_assert(res == 1)
ec_cdata = self._ec_key_set_public_key_affine_coordinates(
ec_cdata, public.x, public.y)
evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata)
return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey)
def load_elliptic_curve_public_numbers(self, numbers):
ec_cdata = self._ec_key_new_by_curve(numbers.curve)
ec_cdata = self._ec_key_set_public_key_affine_coordinates(
ec_cdata, numbers.x, numbers.y)
evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata)
return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey)
def load_elliptic_curve_public_bytes(self, curve, point_bytes):
ec_cdata = self._ec_key_new_by_curve(curve)
group = self._lib.EC_KEY_get0_group(ec_cdata)
self.openssl_assert(group != self._ffi.NULL)
point = self._lib.EC_POINT_new(group)
self.openssl_assert(point != self._ffi.NULL)
point = self._ffi.gc(point, self._lib.EC_POINT_free)
with self._tmp_bn_ctx() as bn_ctx:
res = self._lib.EC_POINT_oct2point(
group, point, point_bytes, len(point_bytes), bn_ctx
)
if res != 1:
self._consume_errors()
raise ValueError("Invalid public bytes for the given curve")
res = self._lib.EC_KEY_set_public_key(ec_cdata, point)
self.openssl_assert(res == 1)
evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata)
return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey)
def derive_elliptic_curve_private_key(self, private_value, curve):
ec_cdata = self._ec_key_new_by_curve(curve)
get_func, group = self._ec_key_determine_group_get_func(ec_cdata)
point = self._lib.EC_POINT_new(group)
self.openssl_assert(point != self._ffi.NULL)
point = self._ffi.gc(point, self._lib.EC_POINT_free)
value = self._int_to_bn(private_value)
value = self._ffi.gc(value, self._lib.BN_clear_free)
with self._tmp_bn_ctx() as bn_ctx:
res = self._lib.EC_POINT_mul(group, point, value, self._ffi.NULL,
self._ffi.NULL, bn_ctx)
self.openssl_assert(res == 1)
bn_x = self._lib.BN_CTX_get(bn_ctx)
bn_y = self._lib.BN_CTX_get(bn_ctx)
res = get_func(group, point, bn_x, bn_y, bn_ctx)
self.openssl_assert(res == 1)
res = self._lib.EC_KEY_set_public_key(ec_cdata, point)
self.openssl_assert(res == 1)
private = self._int_to_bn(private_value)
private = self._ffi.gc(private, self._lib.BN_clear_free)
res = self._lib.EC_KEY_set_private_key(ec_cdata, private)
self.openssl_assert(res == 1)
evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata)
return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey)
def _ec_key_new_by_curve(self, curve):
curve_nid = self._elliptic_curve_to_nid(curve)
ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid)
self.openssl_assert(ec_cdata != self._ffi.NULL)
return self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
def load_der_ocsp_request(self, data):
mem_bio = self._bytes_to_bio(data)
request = self._lib.d2i_OCSP_REQUEST_bio(mem_bio.bio, self._ffi.NULL)
if request == self._ffi.NULL:
self._consume_errors()
raise ValueError("Unable to load OCSP request")
request = self._ffi.gc(request, self._lib.OCSP_REQUEST_free)
return _OCSPRequest(self, request)
def load_der_ocsp_response(self, data):
mem_bio = self._bytes_to_bio(data)
response = self._lib.d2i_OCSP_RESPONSE_bio(mem_bio.bio, self._ffi.NULL)
if response == self._ffi.NULL:
self._consume_errors()
raise ValueError("Unable to load OCSP response")
response = self._ffi.gc(response, self._lib.OCSP_RESPONSE_free)
return _OCSPResponse(self, response)
def create_ocsp_request(self, builder):
ocsp_req = self._lib.OCSP_REQUEST_new()
self.openssl_assert(ocsp_req != self._ffi.NULL)
ocsp_req = self._ffi.gc(ocsp_req, self._lib.OCSP_REQUEST_free)
cert, issuer, algorithm = builder._request
evp_md = self._evp_md_non_null_from_algorithm(algorithm)
certid = self._lib.OCSP_cert_to_id(
evp_md, cert._x509, issuer._x509
)
self.openssl_assert(certid != self._ffi.NULL)
onereq = self._lib.OCSP_request_add0_id(ocsp_req, certid)
self.openssl_assert(onereq != self._ffi.NULL)
self._create_x509_extensions(
extensions=builder._extensions,
handlers=_OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS,
x509_obj=ocsp_req,
add_func=self._lib.OCSP_REQUEST_add_ext,
gc=True,
)
return _OCSPRequest(self, ocsp_req)
def _create_ocsp_basic_response(self, builder, private_key, algorithm):
basic = self._lib.OCSP_BASICRESP_new()
self.openssl_assert(basic != self._ffi.NULL)
basic = self._ffi.gc(basic, self._lib.OCSP_BASICRESP_free)
evp_md = self._evp_md_non_null_from_algorithm(
builder._response._algorithm
)
certid = self._lib.OCSP_cert_to_id(
evp_md, builder._response._cert._x509,
builder._response._issuer._x509
)
self.openssl_assert(certid != self._ffi.NULL)
certid = self._ffi.gc(certid, self._lib.OCSP_CERTID_free)
if builder._response._revocation_reason is None:
reason = -1
else:
reason = _CRL_ENTRY_REASON_ENUM_TO_CODE[
builder._response._revocation_reason
]
if builder._response._revocation_time is None:
rev_time = self._ffi.NULL
else:
rev_time = self._create_asn1_time(
builder._response._revocation_time
)
next_update = self._ffi.NULL
if builder._response._next_update is not None:
next_update = self._create_asn1_time(
builder._response._next_update
)
this_update = self._create_asn1_time(builder._response._this_update)
res = self._lib.OCSP_basic_add1_status(
basic,
certid,
builder._response._cert_status.value,
reason,
rev_time,
this_update,
next_update
)
self.openssl_assert(res != self._ffi.NULL)
# okay, now sign the basic structure
evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm)
responder_cert, responder_encoding = builder._responder_id
flags = self._lib.OCSP_NOCERTS
if responder_encoding is ocsp.OCSPResponderEncoding.HASH:
flags |= self._lib.OCSP_RESPID_KEY
if builder._certs is not None:
for cert in builder._certs:
res = self._lib.OCSP_basic_add1_cert(basic, cert._x509)
self.openssl_assert(res == 1)
self._create_x509_extensions(
extensions=builder._extensions,
handlers=_OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS,
x509_obj=basic,
add_func=self._lib.OCSP_BASICRESP_add_ext,
gc=True,
)
res = self._lib.OCSP_basic_sign(
basic, responder_cert._x509, private_key._evp_pkey,
evp_md, self._ffi.NULL, flags
)
if res != 1:
errors = self._consume_errors()
self.openssl_assert(
errors[0]._lib_reason_match(
self._lib.ERR_LIB_X509,
self._lib.X509_R_KEY_VALUES_MISMATCH
)
)
raise ValueError("responder_cert must be signed by private_key")
return basic
def create_ocsp_response(self, response_status, builder, private_key,
algorithm):
if response_status is ocsp.OCSPResponseStatus.SUCCESSFUL:
basic = self._create_ocsp_basic_response(
builder, private_key, algorithm
)
else:
basic = self._ffi.NULL
ocsp_resp = self._lib.OCSP_response_create(
response_status.value, basic
)
self.openssl_assert(ocsp_resp != self._ffi.NULL)
ocsp_resp = self._ffi.gc(ocsp_resp, self._lib.OCSP_RESPONSE_free)
return _OCSPResponse(self, ocsp_resp)
def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve):
return (
self.elliptic_curve_supported(curve) and
isinstance(algorithm, ec.ECDH)
)
def _ec_cdata_to_evp_pkey(self, ec_cdata):
evp_pkey = self._create_evp_pkey_gc()
res = self._lib.EVP_PKEY_set1_EC_KEY(evp_pkey, ec_cdata)
self.openssl_assert(res == 1)
return evp_pkey
def _elliptic_curve_to_nid(self, curve):
"""
Get the NID for a curve name.
"""
curve_aliases = {
"secp192r1": "prime192v1",
"secp256r1": "prime256v1"
}
curve_name = curve_aliases.get(curve.name, curve.name)
curve_nid = self._lib.OBJ_sn2nid(curve_name.encode())
if curve_nid == self._lib.NID_undef:
raise UnsupportedAlgorithm(
"{} is not a supported elliptic curve".format(curve.name),
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE
)
return curve_nid
@contextmanager
def _tmp_bn_ctx(self):
bn_ctx = self._lib.BN_CTX_new()
self.openssl_assert(bn_ctx != self._ffi.NULL)
bn_ctx = self._ffi.gc(bn_ctx, self._lib.BN_CTX_free)
self._lib.BN_CTX_start(bn_ctx)
try:
yield bn_ctx
finally:
self._lib.BN_CTX_end(bn_ctx)
def _ec_key_determine_group_get_func(self, ctx):
"""
Given an EC_KEY determine the group and what function is required to
get point coordinates.
"""
self.openssl_assert(ctx != self._ffi.NULL)
nid_two_field = self._lib.OBJ_sn2nid(b"characteristic-two-field")
self.openssl_assert(nid_two_field != self._lib.NID_undef)
group = self._lib.EC_KEY_get0_group(ctx)
self.openssl_assert(group != self._ffi.NULL)
method = self._lib.EC_GROUP_method_of(group)
self.openssl_assert(method != self._ffi.NULL)
nid = self._lib.EC_METHOD_get_field_type(method)
self.openssl_assert(nid != self._lib.NID_undef)
if nid == nid_two_field and self._lib.Cryptography_HAS_EC2M:
get_func = self._lib.EC_POINT_get_affine_coordinates_GF2m
else:
get_func = self._lib.EC_POINT_get_affine_coordinates_GFp
assert get_func
return get_func, group
def _ec_key_set_public_key_affine_coordinates(self, ctx, x, y):
"""
Sets the public key point in the EC_KEY context to the affine x and y
values.
"""
if x < 0 or y < 0:
raise ValueError(
"Invalid EC key. Both x and y must be non-negative."
)
x = self._ffi.gc(self._int_to_bn(x), self._lib.BN_free)
y = self._ffi.gc(self._int_to_bn(y), self._lib.BN_free)
res = self._lib.EC_KEY_set_public_key_affine_coordinates(ctx, x, y)
if res != 1:
self._consume_errors()
raise ValueError("Invalid EC key.")
return ctx
def _private_key_bytes(self, encoding, format, encryption_algorithm,
evp_pkey, cdata):
if not isinstance(format, serialization.PrivateFormat):
raise TypeError(
"format must be an item from the PrivateFormat enum"
)
# X9.62 encoding is only valid for EC public keys
if encoding is serialization.Encoding.X962:
raise ValueError("X9.62 format is only valid for EC public keys")
# Raw format and encoding are only valid for X25519, Ed25519, X448, and
# Ed448 keys. We capture those cases before this method is called so if
# we see those enum values here it means the caller has passed them to
# a key that doesn't support raw type
if format is serialization.PrivateFormat.Raw:
raise ValueError("raw format is invalid with this key or encoding")
if encoding is serialization.Encoding.Raw:
raise ValueError("raw encoding is invalid with this key or format")
if not isinstance(encryption_algorithm,
serialization.KeySerializationEncryption):
raise TypeError(
"Encryption algorithm must be a KeySerializationEncryption "
"instance"
)
if isinstance(encryption_algorithm, serialization.NoEncryption):
password = b""
passlen = 0
evp_cipher = self._ffi.NULL
elif isinstance(encryption_algorithm,
serialization.BestAvailableEncryption):
# This is a curated value that we will update over time.
evp_cipher = self._lib.EVP_get_cipherbyname(
b"aes-256-cbc"
)
password = encryption_algorithm.password
passlen = len(password)
if passlen > 1023:
raise ValueError(
"Passwords longer than 1023 bytes are not supported by "
"this backend"
)
else:
raise ValueError("Unsupported encryption type")
key_type = self._lib.EVP_PKEY_id(evp_pkey)
if encoding is serialization.Encoding.PEM:
if format is serialization.PrivateFormat.PKCS8:
write_bio = self._lib.PEM_write_bio_PKCS8PrivateKey
key = evp_pkey
else:
assert format is serialization.PrivateFormat.TraditionalOpenSSL
if key_type == self._lib.EVP_PKEY_RSA:
write_bio = self._lib.PEM_write_bio_RSAPrivateKey
elif key_type == self._lib.EVP_PKEY_DSA:
write_bio = self._lib.PEM_write_bio_DSAPrivateKey
else:
assert key_type == self._lib.EVP_PKEY_EC
write_bio = self._lib.PEM_write_bio_ECPrivateKey
key = cdata
elif encoding is serialization.Encoding.DER:
if format is serialization.PrivateFormat.TraditionalOpenSSL:
if not isinstance(
encryption_algorithm, serialization.NoEncryption
):
raise ValueError(
"Encryption is not supported for DER encoded "
"traditional OpenSSL keys"
)
return self._private_key_bytes_traditional_der(key_type, cdata)
else:
assert format is serialization.PrivateFormat.PKCS8
write_bio = self._lib.i2d_PKCS8PrivateKey_bio
key = evp_pkey
else:
raise TypeError("encoding must be Encoding.PEM or Encoding.DER")
bio = self._create_mem_bio_gc()
res = write_bio(
bio,
key,
evp_cipher,
password,
passlen,
self._ffi.NULL,
self._ffi.NULL
)
self.openssl_assert(res == 1)
return self._read_mem_bio(bio)
def _private_key_bytes_traditional_der(self, key_type, cdata):
if key_type == self._lib.EVP_PKEY_RSA:
write_bio = self._lib.i2d_RSAPrivateKey_bio
elif key_type == self._lib.EVP_PKEY_EC:
write_bio = self._lib.i2d_ECPrivateKey_bio
else:
self.openssl_assert(key_type == self._lib.EVP_PKEY_DSA)
write_bio = self._lib.i2d_DSAPrivateKey_bio
bio = self._create_mem_bio_gc()
res = write_bio(bio, cdata)
self.openssl_assert(res == 1)
return self._read_mem_bio(bio)
def _public_key_bytes(self, encoding, format, key, evp_pkey, cdata):
if not isinstance(encoding, serialization.Encoding):
raise TypeError("encoding must be an item from the Encoding enum")
# Compressed/UncompressedPoint are only valid for EC keys and those
# cases are handled by the ECPublicKey public_bytes method before this
# method is called
if format in (serialization.PublicFormat.UncompressedPoint,
serialization.PublicFormat.CompressedPoint):
raise ValueError("Point formats are not valid for this key type")
# Raw format and encoding are only valid for X25519, Ed25519, X448, and
# Ed448 keys. We capture those cases before this method is called so if
# we see those enum values here it means the caller has passed them to
# a key that doesn't support raw type
if format is serialization.PublicFormat.Raw:
raise ValueError("raw format is invalid with this key or encoding")
if encoding is serialization.Encoding.Raw:
raise ValueError("raw encoding is invalid with this key or format")
if (
format is serialization.PublicFormat.OpenSSH or
encoding is serialization.Encoding.OpenSSH
):
if (
format is not serialization.PublicFormat.OpenSSH or
encoding is not serialization.Encoding.OpenSSH
):
raise ValueError(
"OpenSSH format must be used with OpenSSH encoding"
)
return self._openssh_public_key_bytes(key)
elif format is serialization.PublicFormat.SubjectPublicKeyInfo:
if encoding is serialization.Encoding.PEM:
write_bio = self._lib.PEM_write_bio_PUBKEY
else:
assert encoding is serialization.Encoding.DER
write_bio = self._lib.i2d_PUBKEY_bio
key = evp_pkey
elif format is serialization.PublicFormat.PKCS1:
# Only RSA is supported here.
assert self._lib.EVP_PKEY_id(evp_pkey) == self._lib.EVP_PKEY_RSA
if encoding is serialization.Encoding.PEM:
write_bio = self._lib.PEM_write_bio_RSAPublicKey
else:
assert encoding is serialization.Encoding.DER
write_bio = self._lib.i2d_RSAPublicKey_bio
key = cdata
else:
raise TypeError(
"format must be an item from the PublicFormat enum"
)
bio = self._create_mem_bio_gc()
res = write_bio(bio, key)
self.openssl_assert(res == 1)
return self._read_mem_bio(bio)
def _openssh_public_key_bytes(self, key):
if isinstance(key, rsa.RSAPublicKey):
public_numbers = key.public_numbers()
return b"ssh-rsa " + base64.b64encode(
ssh._ssh_write_string(b"ssh-rsa") +
ssh._ssh_write_mpint(public_numbers.e) +
ssh._ssh_write_mpint(public_numbers.n)
)
elif isinstance(key, dsa.DSAPublicKey):
public_numbers = key.public_numbers()
parameter_numbers = public_numbers.parameter_numbers
return b"ssh-dss " + base64.b64encode(
ssh._ssh_write_string(b"ssh-dss") +
ssh._ssh_write_mpint(parameter_numbers.p) +
ssh._ssh_write_mpint(parameter_numbers.q) +
ssh._ssh_write_mpint(parameter_numbers.g) +
ssh._ssh_write_mpint(public_numbers.y)
)
elif isinstance(key, ed25519.Ed25519PublicKey):
raw_bytes = key.public_bytes(serialization.Encoding.Raw,
serialization.PublicFormat.Raw)
return b"ssh-ed25519 " + base64.b64encode(
ssh._ssh_write_string(b"ssh-ed25519") +
ssh._ssh_write_string(raw_bytes)
)
elif isinstance(key, ec.EllipticCurvePublicKey):
public_numbers = key.public_numbers()
try:
curve_name = {
ec.SECP256R1: b"nistp256",
ec.SECP384R1: b"nistp384",
ec.SECP521R1: b"nistp521",
}[type(public_numbers.curve)]
except KeyError:
raise ValueError(
"Only SECP256R1, SECP384R1, and SECP521R1 curves are "
"supported by the SSH public key format"
)
point = key.public_bytes(
serialization.Encoding.X962,
serialization.PublicFormat.UncompressedPoint
)
return b"ecdsa-sha2-" + curve_name + b" " + base64.b64encode(
ssh._ssh_write_string(b"ecdsa-sha2-" + curve_name) +
ssh._ssh_write_string(curve_name) +
ssh._ssh_write_string(point)
)
else:
raise ValueError(
"OpenSSH encoding is not supported for this key type"
)
def _parameter_bytes(self, encoding, format, cdata):
if encoding is serialization.Encoding.OpenSSH:
raise TypeError(
"OpenSSH encoding is not supported"
)
# Only DH is supported here currently.
q = self._ffi.new("BIGNUM **")
self._lib.DH_get0_pqg(cdata,
self._ffi.NULL,
q,
self._ffi.NULL)
if encoding is serialization.Encoding.PEM:
if q[0] != self._ffi.NULL:
write_bio = self._lib.PEM_write_bio_DHxparams
else:
write_bio = self._lib.PEM_write_bio_DHparams
elif encoding is serialization.Encoding.DER:
if q[0] != self._ffi.NULL:
write_bio = self._lib.Cryptography_i2d_DHxparams_bio
else:
write_bio = self._lib.i2d_DHparams_bio
else:
raise TypeError("encoding must be an item from the Encoding enum")
bio = self._create_mem_bio_gc()
res = write_bio(bio, cdata)
self.openssl_assert(res == 1)
return self._read_mem_bio(bio)
def generate_dh_parameters(self, generator, key_size):
if key_size < 512:
raise ValueError("DH key_size must be at least 512 bits")
if generator not in (2, 5):
raise ValueError("DH generator must be 2 or 5")
dh_param_cdata = self._lib.DH_new()
self.openssl_assert(dh_param_cdata != self._ffi.NULL)
dh_param_cdata = self._ffi.gc(dh_param_cdata, self._lib.DH_free)
res = self._lib.DH_generate_parameters_ex(
dh_param_cdata,
key_size,
generator,
self._ffi.NULL
)
self.openssl_assert(res == 1)
return _DHParameters(self, dh_param_cdata)
def _dh_cdata_to_evp_pkey(self, dh_cdata):
evp_pkey = self._create_evp_pkey_gc()
res = self._lib.EVP_PKEY_set1_DH(evp_pkey, dh_cdata)
self.openssl_assert(res == 1)
return evp_pkey
def generate_dh_private_key(self, parameters):
dh_key_cdata = _dh_params_dup(parameters._dh_cdata, self)
res = self._lib.DH_generate_key(dh_key_cdata)
self.openssl_assert(res == 1)
evp_pkey = self._dh_cdata_to_evp_pkey(dh_key_cdata)
return _DHPrivateKey(self, dh_key_cdata, evp_pkey)
def generate_dh_private_key_and_parameters(self, generator, key_size):
return self.generate_dh_private_key(
self.generate_dh_parameters(generator, key_size))
def load_dh_private_numbers(self, numbers):
parameter_numbers = numbers.public_numbers.parameter_numbers
dh_cdata = self._lib.DH_new()
self.openssl_assert(dh_cdata != self._ffi.NULL)
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
p = self._int_to_bn(parameter_numbers.p)
g = self._int_to_bn(parameter_numbers.g)
if parameter_numbers.q is not None:
q = self._int_to_bn(parameter_numbers.q)
else:
q = self._ffi.NULL
pub_key = self._int_to_bn(numbers.public_numbers.y)
priv_key = self._int_to_bn(numbers.x)
res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
self.openssl_assert(res == 1)
res = self._lib.DH_set0_key(dh_cdata, pub_key, priv_key)
self.openssl_assert(res == 1)
codes = self._ffi.new("int[]", 1)
res = self._lib.Cryptography_DH_check(dh_cdata, codes)
self.openssl_assert(res == 1)
# DH_check will return DH_NOT_SUITABLE_GENERATOR if p % 24 does not
# equal 11 when the generator is 2 (a quadratic nonresidue).
# We want to ignore that error because p % 24 == 23 is also fine.
# Specifically, g is then a quadratic residue. Within the context of
# Diffie-Hellman this means it can only generate half the possible
# values. That sounds bad, but quadratic nonresidues leak a bit of
# the key to the attacker in exchange for having the full key space
# available. See: https://crypto.stackexchange.com/questions/12961
if codes[0] != 0 and not (
parameter_numbers.g == 2 and
codes[0] ^ self._lib.DH_NOT_SUITABLE_GENERATOR == 0
):
raise ValueError(
"DH private numbers did not pass safety checks."
)
evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata)
return _DHPrivateKey(self, dh_cdata, evp_pkey)
def load_dh_public_numbers(self, numbers):
dh_cdata = self._lib.DH_new()
self.openssl_assert(dh_cdata != self._ffi.NULL)
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
parameter_numbers = numbers.parameter_numbers
p = self._int_to_bn(parameter_numbers.p)
g = self._int_to_bn(parameter_numbers.g)
if parameter_numbers.q is not None:
q = self._int_to_bn(parameter_numbers.q)
else:
q = self._ffi.NULL
pub_key = self._int_to_bn(numbers.y)
res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
self.openssl_assert(res == 1)
res = self._lib.DH_set0_key(dh_cdata, pub_key, self._ffi.NULL)
self.openssl_assert(res == 1)
evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata)
return _DHPublicKey(self, dh_cdata, evp_pkey)
def load_dh_parameter_numbers(self, numbers):
dh_cdata = self._lib.DH_new()
self.openssl_assert(dh_cdata != self._ffi.NULL)
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
p = self._int_to_bn(numbers.p)
g = self._int_to_bn(numbers.g)
if numbers.q is not None:
q = self._int_to_bn(numbers.q)
else:
q = self._ffi.NULL
res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
self.openssl_assert(res == 1)
return _DHParameters(self, dh_cdata)
def dh_parameters_supported(self, p, g, q=None):
dh_cdata = self._lib.DH_new()
self.openssl_assert(dh_cdata != self._ffi.NULL)
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
p = self._int_to_bn(p)
g = self._int_to_bn(g)
if q is not None:
q = self._int_to_bn(q)
else:
q = self._ffi.NULL
res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
self.openssl_assert(res == 1)
codes = self._ffi.new("int[]", 1)
res = self._lib.Cryptography_DH_check(dh_cdata, codes)
self.openssl_assert(res == 1)
return codes[0] == 0
def dh_x942_serialization_supported(self):
return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1
def x509_name_bytes(self, name):
x509_name = _encode_name_gc(self, name)
pp = self._ffi.new("unsigned char **")
res = self._lib.i2d_X509_NAME(x509_name, pp)
self.openssl_assert(pp[0] != self._ffi.NULL)
pp = self._ffi.gc(
pp, lambda pointer: self._lib.OPENSSL_free(pointer[0])
)
self.openssl_assert(res > 0)
return self._ffi.buffer(pp[0], res)[:]
def x25519_load_public_bytes(self, data):
# When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can
# switch this to EVP_PKEY_new_raw_public_key
if len(data) != 32:
raise ValueError("An X25519 public key is 32 bytes long")
evp_pkey = self._create_evp_pkey_gc()
res = self._lib.EVP_PKEY_set_type(evp_pkey, self._lib.NID_X25519)
backend.openssl_assert(res == 1)
res = self._lib.EVP_PKEY_set1_tls_encodedpoint(
evp_pkey, data, len(data)
)
backend.openssl_assert(res == 1)
return _X25519PublicKey(self, evp_pkey)
def x25519_load_private_bytes(self, data):
# When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can
# switch this to EVP_PKEY_new_raw_private_key and drop the
# zeroed_bytearray garbage.
# OpenSSL only has facilities for loading PKCS8 formatted private
# keys using the algorithm identifiers specified in
# https://tools.ietf.org/html/draft-ietf-curdle-pkix-09.
# This is the standard PKCS8 prefix for a 32 byte X25519 key.
# The form is:
# 0:d=0 hl=2 l= 46 cons: SEQUENCE
# 2:d=1 hl=2 l= 1 prim: INTEGER :00
# 5:d=1 hl=2 l= 5 cons: SEQUENCE
# 7:d=2 hl=2 l= 3 prim: OBJECT :1.3.101.110
# 12:d=1 hl=2 l= 34 prim: OCTET STRING (the key)
# Of course there's a bit more complexity. In reality OCTET STRING
# contains an OCTET STRING of length 32! So the last two bytes here
# are \x04\x20, which is an OCTET STRING of length 32.
if len(data) != 32:
raise ValueError("An X25519 private key is 32 bytes long")
pkcs8_prefix = b'0.\x02\x01\x000\x05\x06\x03+en\x04"\x04 '
with self._zeroed_bytearray(48) as ba:
ba[0:16] = pkcs8_prefix
ba[16:] = data
bio = self._bytes_to_bio(ba)
evp_pkey = backend._lib.d2i_PrivateKey_bio(bio.bio, self._ffi.NULL)
self.openssl_assert(evp_pkey != self._ffi.NULL)
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
self.openssl_assert(
self._lib.EVP_PKEY_id(evp_pkey) == self._lib.EVP_PKEY_X25519
)
return _X25519PrivateKey(self, evp_pkey)
def _evp_pkey_keygen_gc(self, nid):
evp_pkey_ctx = self._lib.EVP_PKEY_CTX_new_id(nid, self._ffi.NULL)
self.openssl_assert(evp_pkey_ctx != self._ffi.NULL)
evp_pkey_ctx = self._ffi.gc(evp_pkey_ctx, self._lib.EVP_PKEY_CTX_free)
res = self._lib.EVP_PKEY_keygen_init(evp_pkey_ctx)
self.openssl_assert(res == 1)
evp_ppkey = self._ffi.new("EVP_PKEY **")
res = self._lib.EVP_PKEY_keygen(evp_pkey_ctx, evp_ppkey)
self.openssl_assert(res == 1)
self.openssl_assert(evp_ppkey[0] != self._ffi.NULL)
evp_pkey = self._ffi.gc(evp_ppkey[0], self._lib.EVP_PKEY_free)
return evp_pkey
def x25519_generate_key(self):
evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_X25519)
return _X25519PrivateKey(self, evp_pkey)
def x25519_supported(self):
return self._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER
def x448_load_public_bytes(self, data):
if len(data) != 56:
raise ValueError("An X448 public key is 56 bytes long")
evp_pkey = self._lib.EVP_PKEY_new_raw_public_key(
self._lib.NID_X448, self._ffi.NULL, data, len(data)
)
self.openssl_assert(evp_pkey != self._ffi.NULL)
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
return _X448PublicKey(self, evp_pkey)
def x448_load_private_bytes(self, data):
if len(data) != 56:
raise ValueError("An X448 private key is 56 bytes long")
data_ptr = self._ffi.from_buffer(data)
evp_pkey = self._lib.EVP_PKEY_new_raw_private_key(
self._lib.NID_X448, self._ffi.NULL, data_ptr, len(data)
)
self.openssl_assert(evp_pkey != self._ffi.NULL)
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
return _X448PrivateKey(self, evp_pkey)
def x448_generate_key(self):
evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_X448)
return _X448PrivateKey(self, evp_pkey)
def x448_supported(self):
return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111
def ed25519_supported(self):
return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B
def ed25519_load_public_bytes(self, data):
utils._check_bytes("data", data)
if len(data) != ed25519._ED25519_KEY_SIZE:
raise ValueError("An Ed25519 public key is 32 bytes long")
evp_pkey = self._lib.EVP_PKEY_new_raw_public_key(
self._lib.NID_ED25519, self._ffi.NULL, data, len(data)
)
self.openssl_assert(evp_pkey != self._ffi.NULL)
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
return _Ed25519PublicKey(self, evp_pkey)
def ed25519_load_private_bytes(self, data):
if len(data) != ed25519._ED25519_KEY_SIZE:
raise ValueError("An Ed25519 private key is 32 bytes long")
utils._check_byteslike("data", data)
data_ptr = self._ffi.from_buffer(data)
evp_pkey = self._lib.EVP_PKEY_new_raw_private_key(
self._lib.NID_ED25519, self._ffi.NULL, data_ptr, len(data)
)
self.openssl_assert(evp_pkey != self._ffi.NULL)
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
return _Ed25519PrivateKey(self, evp_pkey)
def ed25519_generate_key(self):
evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED25519)
return _Ed25519PrivateKey(self, evp_pkey)
def ed448_supported(self):
return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B
def ed448_load_public_bytes(self, data):
utils._check_bytes("data", data)
if len(data) != _ED448_KEY_SIZE:
raise ValueError("An Ed448 public key is 57 bytes long")
evp_pkey = self._lib.EVP_PKEY_new_raw_public_key(
self._lib.NID_ED448, self._ffi.NULL, data, len(data)
)
self.openssl_assert(evp_pkey != self._ffi.NULL)
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
return _Ed448PublicKey(self, evp_pkey)
def ed448_load_private_bytes(self, data):
utils._check_byteslike("data", data)
if len(data) != _ED448_KEY_SIZE:
raise ValueError("An Ed448 private key is 57 bytes long")
data_ptr = self._ffi.from_buffer(data)
evp_pkey = self._lib.EVP_PKEY_new_raw_private_key(
self._lib.NID_ED448, self._ffi.NULL, data_ptr, len(data)
)
self.openssl_assert(evp_pkey != self._ffi.NULL)
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
return _Ed448PrivateKey(self, evp_pkey)
def ed448_generate_key(self):
evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED448)
return _Ed448PrivateKey(self, evp_pkey)
def derive_scrypt(self, key_material, salt, length, n, r, p):
buf = self._ffi.new("unsigned char[]", length)
key_material_ptr = self._ffi.from_buffer(key_material)
res = self._lib.EVP_PBE_scrypt(
key_material_ptr, len(key_material), salt, len(salt), n, r, p,
scrypt._MEM_LIMIT, buf, length
)
if res != 1:
errors = self._consume_errors()
if not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111:
# This error is only added to the stack in 1.1.1+
self.openssl_assert(
errors[0]._lib_reason_match(
self._lib.ERR_LIB_EVP,
self._lib.ERR_R_MALLOC_FAILURE
) or
errors[0]._lib_reason_match(
self._lib.ERR_LIB_EVP,
self._lib.EVP_R_MEMORY_LIMIT_EXCEEDED
)
)
# memory required formula explained here:
# https://blog.filippo.io/the-scrypt-parameters/
min_memory = 128 * n * r // (1024**2)
raise MemoryError(
"Not enough memory to derive key. These parameters require"
" {} MB of memory.".format(min_memory)
)
return self._ffi.buffer(buf)[:]
def aead_cipher_supported(self, cipher):
cipher_name = aead._aead_cipher_name(cipher)
return (
self._lib.EVP_get_cipherbyname(cipher_name) != self._ffi.NULL
)
@contextlib.contextmanager
def _zeroed_bytearray(self, length):
"""
This method creates a bytearray, which we copy data into (hopefully
also from a mutable buffer that can be dynamically erased!), and then
zero when we're done.
"""
ba = bytearray(length)
try:
yield ba
finally:
self._zero_data(ba, length)
def _zero_data(self, data, length):
# We clear things this way because at the moment we're not
# sure of a better way that can guarantee it overwrites the
# memory of a bytearray and doesn't just replace the underlying char *.
for i in range(length):
data[i] = 0
@contextlib.contextmanager
def _zeroed_null_terminated_buf(self, data):
"""
This method takes bytes, which can be a bytestring or a mutable
buffer like a bytearray, and yields a null-terminated version of that
data. This is required because PKCS12_parse doesn't take a length with
its password char * and ffi.from_buffer doesn't provide null
termination. So, to support zeroing the data via bytearray we
need to build this ridiculous construct that copies the memory, but
zeroes it after use.
"""
if data is None:
yield self._ffi.NULL
else:
data_len = len(data)
buf = self._ffi.new("char[]", data_len + 1)
self._ffi.memmove(buf, data, data_len)
try:
yield buf
finally:
# Cast to a uint8_t * so we can assign by integer
self._zero_data(self._ffi.cast("uint8_t *", buf), data_len)
def load_key_and_certificates_from_pkcs12(self, data, password):
if password is not None:
utils._check_byteslike("password", password)
bio = self._bytes_to_bio(data)
p12 = self._lib.d2i_PKCS12_bio(bio.bio, self._ffi.NULL)
if p12 == self._ffi.NULL:
self._consume_errors()
raise ValueError("Could not deserialize PKCS12 data")
p12 = self._ffi.gc(p12, self._lib.PKCS12_free)
evp_pkey_ptr = self._ffi.new("EVP_PKEY **")
x509_ptr = self._ffi.new("X509 **")
sk_x509_ptr = self._ffi.new("Cryptography_STACK_OF_X509 **")
with self._zeroed_null_terminated_buf(password) as password_buf:
res = self._lib.PKCS12_parse(
p12, password_buf, evp_pkey_ptr, x509_ptr, sk_x509_ptr
)
if res == 0:
self._consume_errors()
raise ValueError("Invalid password or PKCS12 data")
cert = None
key = None
additional_certificates = []
if evp_pkey_ptr[0] != self._ffi.NULL:
evp_pkey = self._ffi.gc(evp_pkey_ptr[0], self._lib.EVP_PKEY_free)
key = self._evp_pkey_to_private_key(evp_pkey)
if x509_ptr[0] != self._ffi.NULL:
x509 = self._ffi.gc(x509_ptr[0], self._lib.X509_free)
cert = _Certificate(self, x509)
if sk_x509_ptr[0] != self._ffi.NULL:
sk_x509 = self._ffi.gc(sk_x509_ptr[0], self._lib.sk_X509_free)
num = self._lib.sk_X509_num(sk_x509_ptr[0])
for i in range(num):
x509 = self._lib.sk_X509_value(sk_x509, i)
x509 = self._ffi.gc(x509, self._lib.X509_free)
self.openssl_assert(x509 != self._ffi.NULL)
additional_certificates.append(_Certificate(self, x509))
return (key, cert, additional_certificates)
def poly1305_supported(self):
return self._lib.Cryptography_HAS_POLY1305 == 1
def create_poly1305_ctx(self, key):
utils._check_byteslike("key", key)
if len(key) != _POLY1305_KEY_SIZE:
raise ValueError("A poly1305 key is 32 bytes long")
return _Poly1305Context(self, key)
class GetCipherByName(object):
def __init__(self, fmt):
self._fmt = fmt
def __call__(self, backend, cipher, mode):
cipher_name = self._fmt.format(cipher=cipher, mode=mode).lower()
return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii"))
def _get_xts_cipher(backend, cipher, mode):
cipher_name = "aes-{}-xts".format(cipher.key_size // 2)
return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii"))
backend = Backend()
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/ciphers.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import InvalidTag, UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.primitives import ciphers
from cryptography.hazmat.primitives.ciphers import modes
@utils.register_interface(ciphers.CipherContext)
@utils.register_interface(ciphers.AEADCipherContext)
@utils.register_interface(ciphers.AEADEncryptionContext)
@utils.register_interface(ciphers.AEADDecryptionContext)
class _CipherContext(object):
_ENCRYPT = 1
_DECRYPT = 0
def __init__(self, backend, cipher, mode, operation):
self._backend = backend
self._cipher = cipher
self._mode = mode
self._operation = operation
self._tag = None
if isinstance(self._cipher, ciphers.BlockCipherAlgorithm):
self._block_size_bytes = self._cipher.block_size // 8
else:
self._block_size_bytes = 1
ctx = self._backend._lib.EVP_CIPHER_CTX_new()
ctx = self._backend._ffi.gc(
ctx, self._backend._lib.EVP_CIPHER_CTX_free
)
registry = self._backend._cipher_registry
try:
adapter = registry[type(cipher), type(mode)]
except KeyError:
raise UnsupportedAlgorithm(
"cipher {} in {} mode is not supported "
"by this backend.".format(
cipher.name, mode.name if mode else mode),
_Reasons.UNSUPPORTED_CIPHER
)
evp_cipher = adapter(self._backend, cipher, mode)
if evp_cipher == self._backend._ffi.NULL:
msg = "cipher {0.name} ".format(cipher)
if mode is not None:
msg += "in {0.name} mode ".format(mode)
msg += (
"is not supported by this backend (Your version of OpenSSL "
"may be too old. Current version: {}.)"
).format(self._backend.openssl_version_text())
raise UnsupportedAlgorithm(msg, _Reasons.UNSUPPORTED_CIPHER)
if isinstance(mode, modes.ModeWithInitializationVector):
iv_nonce = self._backend._ffi.from_buffer(
mode.initialization_vector
)
elif isinstance(mode, modes.ModeWithTweak):
iv_nonce = self._backend._ffi.from_buffer(mode.tweak)
elif isinstance(mode, modes.ModeWithNonce):
iv_nonce = self._backend._ffi.from_buffer(mode.nonce)
elif isinstance(cipher, modes.ModeWithNonce):
iv_nonce = self._backend._ffi.from_buffer(cipher.nonce)
else:
iv_nonce = self._backend._ffi.NULL
# begin init with cipher and operation type
res = self._backend._lib.EVP_CipherInit_ex(ctx, evp_cipher,
self._backend._ffi.NULL,
self._backend._ffi.NULL,
self._backend._ffi.NULL,
operation)
self._backend.openssl_assert(res != 0)
# set the key length to handle variable key ciphers
res = self._backend._lib.EVP_CIPHER_CTX_set_key_length(
ctx, len(cipher.key)
)
self._backend.openssl_assert(res != 0)
if isinstance(mode, modes.GCM):
res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
ctx, self._backend._lib.EVP_CTRL_AEAD_SET_IVLEN,
len(iv_nonce), self._backend._ffi.NULL
)
self._backend.openssl_assert(res != 0)
if mode.tag is not None:
res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
ctx, self._backend._lib.EVP_CTRL_AEAD_SET_TAG,
len(mode.tag), mode.tag
)
self._backend.openssl_assert(res != 0)
self._tag = mode.tag
elif (
self._operation == self._DECRYPT and
self._backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and
not self._backend._lib.CRYPTOGRAPHY_IS_LIBRESSL
):
raise NotImplementedError(
"delayed passing of GCM tag requires OpenSSL >= 1.0.2."
" To use this feature please update OpenSSL"
)
# pass key/iv
res = self._backend._lib.EVP_CipherInit_ex(
ctx,
self._backend._ffi.NULL,
self._backend._ffi.NULL,
self._backend._ffi.from_buffer(cipher.key),
iv_nonce,
operation
)
self._backend.openssl_assert(res != 0)
# We purposely disable padding here as it's handled higher up in the
# API.
self._backend._lib.EVP_CIPHER_CTX_set_padding(ctx, 0)
self._ctx = ctx
def update(self, data):
buf = bytearray(len(data) + self._block_size_bytes - 1)
n = self.update_into(data, buf)
return bytes(buf[:n])
def update_into(self, data, buf):
if len(buf) < (len(data) + self._block_size_bytes - 1):
raise ValueError(
"buffer must be at least {} bytes for this "
"payload".format(len(data) + self._block_size_bytes - 1)
)
buf = self._backend._ffi.cast(
"unsigned char *", self._backend._ffi.from_buffer(buf)
)
outlen = self._backend._ffi.new("int *")
res = self._backend._lib.EVP_CipherUpdate(
self._ctx, buf, outlen,
self._backend._ffi.from_buffer(data), len(data)
)
self._backend.openssl_assert(res != 0)
return outlen[0]
def finalize(self):
# OpenSSL 1.0.1 on Ubuntu 12.04 (and possibly other distributions)
# appears to have a bug where you must make at least one call to update
# even if you are only using authenticate_additional_data or the
# GCM tag will be wrong. An (empty) call to update resolves this
# and is harmless for all other versions of OpenSSL.
if isinstance(self._mode, modes.GCM):
self.update(b"")
if (
self._operation == self._DECRYPT and
isinstance(self._mode, modes.ModeWithAuthenticationTag) and
self.tag is None
):
raise ValueError(
"Authentication tag must be provided when decrypting."
)
buf = self._backend._ffi.new("unsigned char[]", self._block_size_bytes)
outlen = self._backend._ffi.new("int *")
res = self._backend._lib.EVP_CipherFinal_ex(self._ctx, buf, outlen)
if res == 0:
errors = self._backend._consume_errors()
if not errors and isinstance(self._mode, modes.GCM):
raise InvalidTag
self._backend.openssl_assert(
errors[0]._lib_reason_match(
self._backend._lib.ERR_LIB_EVP,
self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
)
)
raise ValueError(
"The length of the provided data is not a multiple of "
"the block length."
)
if (isinstance(self._mode, modes.GCM) and
self._operation == self._ENCRYPT):
tag_buf = self._backend._ffi.new(
"unsigned char[]", self._block_size_bytes
)
res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
self._ctx, self._backend._lib.EVP_CTRL_AEAD_GET_TAG,
self._block_size_bytes, tag_buf
)
self._backend.openssl_assert(res != 0)
self._tag = self._backend._ffi.buffer(tag_buf)[:]
res = self._backend._lib.EVP_CIPHER_CTX_cleanup(self._ctx)
self._backend.openssl_assert(res == 1)
return self._backend._ffi.buffer(buf)[:outlen[0]]
def finalize_with_tag(self, tag):
if (
self._backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and
not self._backend._lib.CRYPTOGRAPHY_IS_LIBRESSL
):
raise NotImplementedError(
"finalize_with_tag requires OpenSSL >= 1.0.2. To use this "
"method please update OpenSSL"
)
if len(tag) < self._mode._min_tag_length:
raise ValueError(
"Authentication tag must be {} bytes or longer.".format(
self._mode._min_tag_length)
)
res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
self._ctx, self._backend._lib.EVP_CTRL_AEAD_SET_TAG,
len(tag), tag
)
self._backend.openssl_assert(res != 0)
self._tag = tag
return self.finalize()
def authenticate_additional_data(self, data):
outlen = self._backend._ffi.new("int *")
res = self._backend._lib.EVP_CipherUpdate(
self._ctx, self._backend._ffi.NULL, outlen,
self._backend._ffi.from_buffer(data), len(data)
)
self._backend.openssl_assert(res != 0)
tag = utils.read_only_property("_tag")
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/cmac.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import (
InvalidSignature, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.primitives import constant_time
from cryptography.hazmat.primitives.ciphers.modes import CBC
class _CMACContext(object):
def __init__(self, backend, algorithm, ctx=None):
if not backend.cmac_algorithm_supported(algorithm):
raise UnsupportedAlgorithm("This backend does not support CMAC.",
_Reasons.UNSUPPORTED_CIPHER)
self._backend = backend
self._key = algorithm.key
self._algorithm = algorithm
self._output_length = algorithm.block_size // 8
if ctx is None:
registry = self._backend._cipher_registry
adapter = registry[type(algorithm), CBC]
evp_cipher = adapter(self._backend, algorithm, CBC)
ctx = self._backend._lib.CMAC_CTX_new()
self._backend.openssl_assert(ctx != self._backend._ffi.NULL)
ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free)
key_ptr = self._backend._ffi.from_buffer(self._key)
res = self._backend._lib.CMAC_Init(
ctx, key_ptr, len(self._key),
evp_cipher, self._backend._ffi.NULL
)
self._backend.openssl_assert(res == 1)
self._ctx = ctx
algorithm = utils.read_only_property("_algorithm")
def update(self, data):
res = self._backend._lib.CMAC_Update(self._ctx, data, len(data))
self._backend.openssl_assert(res == 1)
def finalize(self):
buf = self._backend._ffi.new("unsigned char[]", self._output_length)
length = self._backend._ffi.new("size_t *", self._output_length)
res = self._backend._lib.CMAC_Final(
self._ctx, buf, length
)
self._backend.openssl_assert(res == 1)
self._ctx = None
return self._backend._ffi.buffer(buf)[:]
def copy(self):
copied_ctx = self._backend._lib.CMAC_CTX_new()
copied_ctx = self._backend._ffi.gc(
copied_ctx, self._backend._lib.CMAC_CTX_free
)
res = self._backend._lib.CMAC_CTX_copy(
copied_ctx, self._ctx
)
self._backend.openssl_assert(res == 1)
return _CMACContext(
self._backend, self._algorithm, ctx=copied_ctx
)
def verify(self, signature):
digest = self.finalize()
if not constant_time.bytes_eq(digest, signature):
raise InvalidSignature("Signature did not match digest.")
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import datetime
import ipaddress
import six
from cryptography import x509
from cryptography.hazmat._der import DERReader, INTEGER, NULL, SEQUENCE
from cryptography.x509.extensions import _TLS_FEATURE_TYPE_TO_ENUM
from cryptography.x509.name import _ASN1_TYPE_TO_ENUM
from cryptography.x509.oid import (
CRLEntryExtensionOID, CertificatePoliciesOID, ExtensionOID,
OCSPExtensionOID,
)
def _obj2txt(backend, obj):
# Set to 80 on the recommendation of
# https://www.openssl.org/docs/crypto/OBJ_nid2ln.html#return_values
#
# But OIDs longer than this occur in real life (e.g. Active
# Directory makes some very long OIDs). So we need to detect
# and properly handle the case where the default buffer is not
# big enough.
#
buf_len = 80
buf = backend._ffi.new("char[]", buf_len)
# 'res' is the number of bytes that *would* be written if the
# buffer is large enough. If 'res' > buf_len - 1, we need to
# alloc a big-enough buffer and go again.
res = backend._lib.OBJ_obj2txt(buf, buf_len, obj, 1)
if res > buf_len - 1: # account for terminating null byte
buf_len = res + 1
buf = backend._ffi.new("char[]", buf_len)
res = backend._lib.OBJ_obj2txt(buf, buf_len, obj, 1)
backend.openssl_assert(res > 0)
return backend._ffi.buffer(buf, res)[:].decode()
def _decode_x509_name_entry(backend, x509_name_entry):
obj = backend._lib.X509_NAME_ENTRY_get_object(x509_name_entry)
backend.openssl_assert(obj != backend._ffi.NULL)
data = backend._lib.X509_NAME_ENTRY_get_data(x509_name_entry)
backend.openssl_assert(data != backend._ffi.NULL)
value = _asn1_string_to_utf8(backend, data)
oid = _obj2txt(backend, obj)
type = _ASN1_TYPE_TO_ENUM[data.type]
return x509.NameAttribute(x509.ObjectIdentifier(oid), value, type)
def _decode_x509_name(backend, x509_name):
count = backend._lib.X509_NAME_entry_count(x509_name)
attributes = []
prev_set_id = -1
for x in range(count):
entry = backend._lib.X509_NAME_get_entry(x509_name, x)
attribute = _decode_x509_name_entry(backend, entry)
set_id = backend._lib.Cryptography_X509_NAME_ENTRY_set(entry)
if set_id != prev_set_id:
attributes.append(set([attribute]))
else:
# is in the same RDN a previous entry
attributes[-1].add(attribute)
prev_set_id = set_id
return x509.Name(x509.RelativeDistinguishedName(rdn) for rdn in attributes)
def _decode_general_names(backend, gns):
num = backend._lib.sk_GENERAL_NAME_num(gns)
names = []
for i in range(num):
gn = backend._lib.sk_GENERAL_NAME_value(gns, i)
backend.openssl_assert(gn != backend._ffi.NULL)
names.append(_decode_general_name(backend, gn))
return names
def _decode_general_name(backend, gn):
if gn.type == backend._lib.GEN_DNS:
# Convert to bytes and then decode to utf8. We don't use
# asn1_string_to_utf8 here because it doesn't properly convert
# utf8 from ia5strings.
data = _asn1_string_to_bytes(backend, gn.d.dNSName).decode("utf8")
# We don't use the constructor for DNSName so we can bypass validation
# This allows us to create DNSName objects that have unicode chars
# when a certificate (against the RFC) contains them.
return x509.DNSName._init_without_validation(data)
elif gn.type == backend._lib.GEN_URI:
# Convert to bytes and then decode to utf8. We don't use
# asn1_string_to_utf8 here because it doesn't properly convert
# utf8 from ia5strings.
data = _asn1_string_to_bytes(
backend, gn.d.uniformResourceIdentifier
).decode("utf8")
# We don't use the constructor for URI so we can bypass validation
# This allows us to create URI objects that have unicode chars
# when a certificate (against the RFC) contains them.
return x509.UniformResourceIdentifier._init_without_validation(data)
elif gn.type == backend._lib.GEN_RID:
oid = _obj2txt(backend, gn.d.registeredID)
return x509.RegisteredID(x509.ObjectIdentifier(oid))
elif gn.type == backend._lib.GEN_IPADD:
data = _asn1_string_to_bytes(backend, gn.d.iPAddress)
data_len = len(data)
if data_len == 8 or data_len == 32:
# This is an IPv4 or IPv6 Network and not a single IP. This
# type of data appears in Name Constraints. Unfortunately,
# ipaddress doesn't support packed bytes + netmask. Additionally,
# IPv6Network can only handle CIDR rather than the full 16 byte
# netmask. To handle this we convert the netmask to integer, then
# find the first 0 bit, which will be the prefix. If another 1
# bit is present after that the netmask is invalid.
base = ipaddress.ip_address(data[:data_len // 2])
netmask = ipaddress.ip_address(data[data_len // 2:])
bits = bin(int(netmask))[2:]
prefix = bits.find('0')
# If no 0 bits are found it is a /32 or /128
if prefix == -1:
prefix = len(bits)
if "1" in bits[prefix:]:
raise ValueError("Invalid netmask")
ip = ipaddress.ip_network(base.exploded + u"/{}".format(prefix))
else:
ip = ipaddress.ip_address(data)
return x509.IPAddress(ip)
elif gn.type == backend._lib.GEN_DIRNAME:
return x509.DirectoryName(
_decode_x509_name(backend, gn.d.directoryName)
)
elif gn.type == backend._lib.GEN_EMAIL:
# Convert to bytes and then decode to utf8. We don't use
# asn1_string_to_utf8 here because it doesn't properly convert
# utf8 from ia5strings.
data = _asn1_string_to_bytes(backend, gn.d.rfc822Name).decode("utf8")
# We don't use the constructor for RFC822Name so we can bypass
# validation. This allows us to create RFC822Name objects that have
# unicode chars when a certificate (against the RFC) contains them.
return x509.RFC822Name._init_without_validation(data)
elif gn.type == backend._lib.GEN_OTHERNAME:
type_id = _obj2txt(backend, gn.d.otherName.type_id)
value = _asn1_to_der(backend, gn.d.otherName.value)
return x509.OtherName(x509.ObjectIdentifier(type_id), value)
else:
# x400Address or ediPartyName
raise x509.UnsupportedGeneralNameType(
"{} is not a supported type".format(
x509._GENERAL_NAMES.get(gn.type, gn.type)
),
gn.type
)
def _decode_ocsp_no_check(backend, ext):
return x509.OCSPNoCheck()
def _decode_crl_number(backend, ext):
asn1_int = backend._ffi.cast("ASN1_INTEGER *", ext)
asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free)
return x509.CRLNumber(_asn1_integer_to_int(backend, asn1_int))
def _decode_delta_crl_indicator(backend, ext):
asn1_int = backend._ffi.cast("ASN1_INTEGER *", ext)
asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free)
return x509.DeltaCRLIndicator(_asn1_integer_to_int(backend, asn1_int))
class _X509ExtensionParser(object):
def __init__(self, ext_count, get_ext, handlers):
self.ext_count = ext_count
self.get_ext = get_ext
self.handlers = handlers
def parse(self, backend, x509_obj):
extensions = []
seen_oids = set()
for i in range(self.ext_count(backend, x509_obj)):
ext = self.get_ext(backend, x509_obj, i)
backend.openssl_assert(ext != backend._ffi.NULL)
crit = backend._lib.X509_EXTENSION_get_critical(ext)
critical = crit == 1
oid = x509.ObjectIdentifier(
_obj2txt(backend, backend._lib.X509_EXTENSION_get_object(ext))
)
if oid in seen_oids:
raise x509.DuplicateExtension(
"Duplicate {} extension found".format(oid), oid
)
# These OIDs are only supported in OpenSSL 1.1.0+ but we want
# to support them in all versions of OpenSSL so we decode them
# ourselves.
if oid == ExtensionOID.TLS_FEATURE:
# The extension contents are a SEQUENCE OF INTEGERs.
data = backend._lib.X509_EXTENSION_get_data(ext)
data_bytes = _asn1_string_to_bytes(backend, data)
features = DERReader(data_bytes).read_single_element(SEQUENCE)
parsed = []
while not features.is_empty():
parsed.append(features.read_element(INTEGER).as_integer())
# Map the features to their enum value.
value = x509.TLSFeature(
[_TLS_FEATURE_TYPE_TO_ENUM[x] for x in parsed]
)
extensions.append(x509.Extension(oid, critical, value))
seen_oids.add(oid)
continue
elif oid == ExtensionOID.PRECERT_POISON:
data = backend._lib.X509_EXTENSION_get_data(ext)
# The contents of the extension must be an ASN.1 NULL.
reader = DERReader(_asn1_string_to_bytes(backend, data))
reader.read_single_element(NULL).check_empty()
extensions.append(x509.Extension(
oid, critical, x509.PrecertPoison()
))
seen_oids.add(oid)
continue
try:
handler = self.handlers[oid]
except KeyError:
# Dump the DER payload into an UnrecognizedExtension object
data = backend._lib.X509_EXTENSION_get_data(ext)
backend.openssl_assert(data != backend._ffi.NULL)
der = backend._ffi.buffer(data.data, data.length)[:]
unrecognized = x509.UnrecognizedExtension(oid, der)
extensions.append(
x509.Extension(oid, critical, unrecognized)
)
else:
ext_data = backend._lib.X509V3_EXT_d2i(ext)
if ext_data == backend._ffi.NULL:
backend._consume_errors()
raise ValueError(
"The {} extension is invalid and can't be "
"parsed".format(oid)
)
value = handler(backend, ext_data)
extensions.append(x509.Extension(oid, critical, value))
seen_oids.add(oid)
return x509.Extensions(extensions)
def _decode_certificate_policies(backend, cp):
cp = backend._ffi.cast("Cryptography_STACK_OF_POLICYINFO *", cp)
cp = backend._ffi.gc(cp, backend._lib.CERTIFICATEPOLICIES_free)
num = backend._lib.sk_POLICYINFO_num(cp)
certificate_policies = []
for i in range(num):
qualifiers = None
pi = backend._lib.sk_POLICYINFO_value(cp, i)
oid = x509.ObjectIdentifier(_obj2txt(backend, pi.policyid))
if pi.qualifiers != backend._ffi.NULL:
qnum = backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers)
qualifiers = []
for j in range(qnum):
pqi = backend._lib.sk_POLICYQUALINFO_value(
pi.qualifiers, j
)
pqualid = x509.ObjectIdentifier(
_obj2txt(backend, pqi.pqualid)
)
if pqualid == CertificatePoliciesOID.CPS_QUALIFIER:
cpsuri = backend._ffi.buffer(
pqi.d.cpsuri.data, pqi.d.cpsuri.length
)[:].decode('ascii')
qualifiers.append(cpsuri)
else:
assert pqualid == CertificatePoliciesOID.CPS_USER_NOTICE
user_notice = _decode_user_notice(
backend, pqi.d.usernotice
)
qualifiers.append(user_notice)
certificate_policies.append(
x509.PolicyInformation(oid, qualifiers)
)
return x509.CertificatePolicies(certificate_policies)
def _decode_user_notice(backend, un):
explicit_text = None
notice_reference = None
if un.exptext != backend._ffi.NULL:
explicit_text = _asn1_string_to_utf8(backend, un.exptext)
if un.noticeref != backend._ffi.NULL:
organization = _asn1_string_to_utf8(
backend, un.noticeref.organization
)
num = backend._lib.sk_ASN1_INTEGER_num(
un.noticeref.noticenos
)
notice_numbers = []
for i in range(num):
asn1_int = backend._lib.sk_ASN1_INTEGER_value(
un.noticeref.noticenos, i
)
notice_num = _asn1_integer_to_int(backend, asn1_int)
notice_numbers.append(notice_num)
notice_reference = x509.NoticeReference(
organization, notice_numbers
)
return x509.UserNotice(notice_reference, explicit_text)
def _decode_basic_constraints(backend, bc_st):
basic_constraints = backend._ffi.cast("BASIC_CONSTRAINTS *", bc_st)
basic_constraints = backend._ffi.gc(
basic_constraints, backend._lib.BASIC_CONSTRAINTS_free
)
# The byte representation of an ASN.1 boolean true is \xff. OpenSSL
# chooses to just map this to its ordinal value, so true is 255 and
# false is 0.
ca = basic_constraints.ca == 255
path_length = _asn1_integer_to_int_or_none(
backend, basic_constraints.pathlen
)
return x509.BasicConstraints(ca, path_length)
def _decode_subject_key_identifier(backend, asn1_string):
asn1_string = backend._ffi.cast("ASN1_OCTET_STRING *", asn1_string)
asn1_string = backend._ffi.gc(
asn1_string, backend._lib.ASN1_OCTET_STRING_free
)
return x509.SubjectKeyIdentifier(
backend._ffi.buffer(asn1_string.data, asn1_string.length)[:]
)
def _decode_authority_key_identifier(backend, akid):
akid = backend._ffi.cast("AUTHORITY_KEYID *", akid)
akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free)
key_identifier = None
authority_cert_issuer = None
if akid.keyid != backend._ffi.NULL:
key_identifier = backend._ffi.buffer(
akid.keyid.data, akid.keyid.length
)[:]
if akid.issuer != backend._ffi.NULL:
authority_cert_issuer = _decode_general_names(
backend, akid.issuer
)
authority_cert_serial_number = _asn1_integer_to_int_or_none(
backend, akid.serial
)
return x509.AuthorityKeyIdentifier(
key_identifier, authority_cert_issuer, authority_cert_serial_number
)
def _decode_authority_information_access(backend, aia):
aia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia)
aia = backend._ffi.gc(
aia,
lambda x: backend._lib.sk_ACCESS_DESCRIPTION_pop_free(
x, backend._ffi.addressof(
backend._lib._original_lib, "ACCESS_DESCRIPTION_free"
)
)
)
num = backend._lib.sk_ACCESS_DESCRIPTION_num(aia)
access_descriptions = []
for i in range(num):
ad = backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i)
backend.openssl_assert(ad.method != backend._ffi.NULL)
oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method))
backend.openssl_assert(ad.location != backend._ffi.NULL)
gn = _decode_general_name(backend, ad.location)
access_descriptions.append(x509.AccessDescription(oid, gn))
return x509.AuthorityInformationAccess(access_descriptions)
def _decode_key_usage(backend, bit_string):
bit_string = backend._ffi.cast("ASN1_BIT_STRING *", bit_string)
bit_string = backend._ffi.gc(bit_string, backend._lib.ASN1_BIT_STRING_free)
get_bit = backend._lib.ASN1_BIT_STRING_get_bit
digital_signature = get_bit(bit_string, 0) == 1
content_commitment = get_bit(bit_string, 1) == 1
key_encipherment = get_bit(bit_string, 2) == 1
data_encipherment = get_bit(bit_string, 3) == 1
key_agreement = get_bit(bit_string, 4) == 1
key_cert_sign = get_bit(bit_string, 5) == 1
crl_sign = get_bit(bit_string, 6) == 1
encipher_only = get_bit(bit_string, 7) == 1
decipher_only = get_bit(bit_string, 8) == 1
return x509.KeyUsage(
digital_signature,
content_commitment,
key_encipherment,
data_encipherment,
key_agreement,
key_cert_sign,
crl_sign,
encipher_only,
decipher_only
)
def _decode_general_names_extension(backend, gns):
gns = backend._ffi.cast("GENERAL_NAMES *", gns)
gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free)
general_names = _decode_general_names(backend, gns)
return general_names
def _decode_subject_alt_name(backend, ext):
return x509.SubjectAlternativeName(
_decode_general_names_extension(backend, ext)
)
def _decode_issuer_alt_name(backend, ext):
return x509.IssuerAlternativeName(
_decode_general_names_extension(backend, ext)
)
def _decode_name_constraints(backend, nc):
nc = backend._ffi.cast("NAME_CONSTRAINTS *", nc)
nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free)
permitted = _decode_general_subtrees(backend, nc.permittedSubtrees)
excluded = _decode_general_subtrees(backend, nc.excludedSubtrees)
return x509.NameConstraints(
permitted_subtrees=permitted, excluded_subtrees=excluded
)
def _decode_general_subtrees(backend, stack_subtrees):
if stack_subtrees == backend._ffi.NULL:
return None
num = backend._lib.sk_GENERAL_SUBTREE_num(stack_subtrees)
subtrees = []
for i in range(num):
obj = backend._lib.sk_GENERAL_SUBTREE_value(stack_subtrees, i)
backend.openssl_assert(obj != backend._ffi.NULL)
name = _decode_general_name(backend, obj.base)
subtrees.append(name)
return subtrees
def _decode_issuing_dist_point(backend, idp):
idp = backend._ffi.cast("ISSUING_DIST_POINT *", idp)
idp = backend._ffi.gc(idp, backend._lib.ISSUING_DIST_POINT_free)
if idp.distpoint != backend._ffi.NULL:
full_name, relative_name = _decode_distpoint(backend, idp.distpoint)
else:
full_name = None
relative_name = None
only_user = idp.onlyuser == 255
only_ca = idp.onlyCA == 255
indirect_crl = idp.indirectCRL == 255
only_attr = idp.onlyattr == 255
if idp.onlysomereasons != backend._ffi.NULL:
only_some_reasons = _decode_reasons(backend, idp.onlysomereasons)
else:
only_some_reasons = None
return x509.IssuingDistributionPoint(
full_name, relative_name, only_user, only_ca, only_some_reasons,
indirect_crl, only_attr
)
def _decode_policy_constraints(backend, pc):
pc = backend._ffi.cast("POLICY_CONSTRAINTS *", pc)
pc = backend._ffi.gc(pc, backend._lib.POLICY_CONSTRAINTS_free)
require_explicit_policy = _asn1_integer_to_int_or_none(
backend, pc.requireExplicitPolicy
)
inhibit_policy_mapping = _asn1_integer_to_int_or_none(
backend, pc.inhibitPolicyMapping
)
return x509.PolicyConstraints(
require_explicit_policy, inhibit_policy_mapping
)
def _decode_extended_key_usage(backend, sk):
sk = backend._ffi.cast("Cryptography_STACK_OF_ASN1_OBJECT *", sk)
sk = backend._ffi.gc(sk, backend._lib.sk_ASN1_OBJECT_free)
num = backend._lib.sk_ASN1_OBJECT_num(sk)
ekus = []
for i in range(num):
obj = backend._lib.sk_ASN1_OBJECT_value(sk, i)
backend.openssl_assert(obj != backend._ffi.NULL)
oid = x509.ObjectIdentifier(_obj2txt(backend, obj))
ekus.append(oid)
return x509.ExtendedKeyUsage(ekus)
_DISTPOINT_TYPE_FULLNAME = 0
_DISTPOINT_TYPE_RELATIVENAME = 1
def _decode_dist_points(backend, cdps):
cdps = backend._ffi.cast("Cryptography_STACK_OF_DIST_POINT *", cdps)
cdps = backend._ffi.gc(cdps, backend._lib.CRL_DIST_POINTS_free)
num = backend._lib.sk_DIST_POINT_num(cdps)
dist_points = []
for i in range(num):
full_name = None
relative_name = None
crl_issuer = None
reasons = None
cdp = backend._lib.sk_DIST_POINT_value(cdps, i)
if cdp.reasons != backend._ffi.NULL:
reasons = _decode_reasons(backend, cdp.reasons)
if cdp.CRLissuer != backend._ffi.NULL:
crl_issuer = _decode_general_names(backend, cdp.CRLissuer)
# Certificates may have a crl_issuer/reasons and no distribution
# point so make sure it's not null.
if cdp.distpoint != backend._ffi.NULL:
full_name, relative_name = _decode_distpoint(
backend, cdp.distpoint
)
dist_points.append(
x509.DistributionPoint(
full_name, relative_name, reasons, crl_issuer
)
)
return dist_points
# ReasonFlags ::= BIT STRING {
# unused (0),
# keyCompromise (1),
# cACompromise (2),
# affiliationChanged (3),
# superseded (4),
# cessationOfOperation (5),
# certificateHold (6),
# privilegeWithdrawn (7),
# aACompromise (8) }
_REASON_BIT_MAPPING = {
1: x509.ReasonFlags.key_compromise,
2: x509.ReasonFlags.ca_compromise,
3: x509.ReasonFlags.affiliation_changed,
4: x509.ReasonFlags.superseded,
5: x509.ReasonFlags.cessation_of_operation,
6: x509.ReasonFlags.certificate_hold,
7: x509.ReasonFlags.privilege_withdrawn,
8: x509.ReasonFlags.aa_compromise,
}
def _decode_reasons(backend, reasons):
# We will check each bit from RFC 5280
enum_reasons = []
for bit_position, reason in six.iteritems(_REASON_BIT_MAPPING):
if backend._lib.ASN1_BIT_STRING_get_bit(reasons, bit_position):
enum_reasons.append(reason)
return frozenset(enum_reasons)
def _decode_distpoint(backend, distpoint):
if distpoint.type == _DISTPOINT_TYPE_FULLNAME:
full_name = _decode_general_names(backend, distpoint.name.fullname)
return full_name, None
# OpenSSL code doesn't test for a specific type for
# relativename, everything that isn't fullname is considered
# relativename. Per RFC 5280:
#
# DistributionPointName ::= CHOICE {
# fullName [0] GeneralNames,
# nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
rns = distpoint.name.relativename
rnum = backend._lib.sk_X509_NAME_ENTRY_num(rns)
attributes = set()
for i in range(rnum):
rn = backend._lib.sk_X509_NAME_ENTRY_value(
rns, i
)
backend.openssl_assert(rn != backend._ffi.NULL)
attributes.add(
_decode_x509_name_entry(backend, rn)
)
relative_name = x509.RelativeDistinguishedName(attributes)
return None, relative_name
def _decode_crl_distribution_points(backend, cdps):
dist_points = _decode_dist_points(backend, cdps)
return x509.CRLDistributionPoints(dist_points)
def _decode_freshest_crl(backend, cdps):
dist_points = _decode_dist_points(backend, cdps)
return x509.FreshestCRL(dist_points)
def _decode_inhibit_any_policy(backend, asn1_int):
asn1_int = backend._ffi.cast("ASN1_INTEGER *", asn1_int)
asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free)
skip_certs = _asn1_integer_to_int(backend, asn1_int)
return x509.InhibitAnyPolicy(skip_certs)
def _decode_precert_signed_certificate_timestamps(backend, asn1_scts):
from cryptography.hazmat.backends.openssl.x509 import (
_SignedCertificateTimestamp
)
asn1_scts = backend._ffi.cast("Cryptography_STACK_OF_SCT *", asn1_scts)
asn1_scts = backend._ffi.gc(asn1_scts, backend._lib.SCT_LIST_free)
scts = []
for i in range(backend._lib.sk_SCT_num(asn1_scts)):
sct = backend._lib.sk_SCT_value(asn1_scts, i)
scts.append(_SignedCertificateTimestamp(backend, asn1_scts, sct))
return x509.PrecertificateSignedCertificateTimestamps(scts)
# CRLReason ::= ENUMERATED {
# unspecified (0),
# keyCompromise (1),
# cACompromise (2),
# affiliationChanged (3),
# superseded (4),
# cessationOfOperation (5),
# certificateHold (6),
# -- value 7 is not used
# removeFromCRL (8),
# privilegeWithdrawn (9),
# aACompromise (10) }
_CRL_ENTRY_REASON_CODE_TO_ENUM = {
0: x509.ReasonFlags.unspecified,
1: x509.ReasonFlags.key_compromise,
2: x509.ReasonFlags.ca_compromise,
3: x509.ReasonFlags.affiliation_changed,
4: x509.ReasonFlags.superseded,
5: x509.ReasonFlags.cessation_of_operation,
6: x509.ReasonFlags.certificate_hold,
8: x509.ReasonFlags.remove_from_crl,
9: x509.ReasonFlags.privilege_withdrawn,
10: x509.ReasonFlags.aa_compromise,
}
_CRL_ENTRY_REASON_ENUM_TO_CODE = {
x509.ReasonFlags.unspecified: 0,
x509.ReasonFlags.key_compromise: 1,
x509.ReasonFlags.ca_compromise: 2,
x509.ReasonFlags.affiliation_changed: 3,
x509.ReasonFlags.superseded: 4,
x509.ReasonFlags.cessation_of_operation: 5,
x509.ReasonFlags.certificate_hold: 6,
x509.ReasonFlags.remove_from_crl: 8,
x509.ReasonFlags.privilege_withdrawn: 9,
x509.ReasonFlags.aa_compromise: 10
}
def _decode_crl_reason(backend, enum):
enum = backend._ffi.cast("ASN1_ENUMERATED *", enum)
enum = backend._ffi.gc(enum, backend._lib.ASN1_ENUMERATED_free)
code = backend._lib.ASN1_ENUMERATED_get(enum)
try:
return x509.CRLReason(_CRL_ENTRY_REASON_CODE_TO_ENUM[code])
except KeyError:
raise ValueError("Unsupported reason code: {}".format(code))
def _decode_invalidity_date(backend, inv_date):
generalized_time = backend._ffi.cast(
"ASN1_GENERALIZEDTIME *", inv_date
)
generalized_time = backend._ffi.gc(
generalized_time, backend._lib.ASN1_GENERALIZEDTIME_free
)
return x509.InvalidityDate(
_parse_asn1_generalized_time(backend, generalized_time)
)
def _decode_cert_issuer(backend, gns):
gns = backend._ffi.cast("GENERAL_NAMES *", gns)
gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free)
general_names = _decode_general_names(backend, gns)
return x509.CertificateIssuer(general_names)
def _asn1_to_der(backend, asn1_type):
buf = backend._ffi.new("unsigned char **")
res = backend._lib.i2d_ASN1_TYPE(asn1_type, buf)
backend.openssl_assert(res >= 0)
backend.openssl_assert(buf[0] != backend._ffi.NULL)
buf = backend._ffi.gc(
buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0])
)
return backend._ffi.buffer(buf[0], res)[:]
def _asn1_integer_to_int(backend, asn1_int):
bn = backend._lib.ASN1_INTEGER_to_BN(asn1_int, backend._ffi.NULL)
backend.openssl_assert(bn != backend._ffi.NULL)
bn = backend._ffi.gc(bn, backend._lib.BN_free)
return backend._bn_to_int(bn)
def _asn1_integer_to_int_or_none(backend, asn1_int):
if asn1_int == backend._ffi.NULL:
return None
else:
return _asn1_integer_to_int(backend, asn1_int)
def _asn1_string_to_bytes(backend, asn1_string):
return backend._ffi.buffer(asn1_string.data, asn1_string.length)[:]
def _asn1_string_to_ascii(backend, asn1_string):
return _asn1_string_to_bytes(backend, asn1_string).decode("ascii")
def _asn1_string_to_utf8(backend, asn1_string):
buf = backend._ffi.new("unsigned char **")
res = backend._lib.ASN1_STRING_to_UTF8(buf, asn1_string)
if res == -1:
raise ValueError(
"Unsupported ASN1 string type. Type: {}".format(asn1_string.type)
)
backend.openssl_assert(buf[0] != backend._ffi.NULL)
buf = backend._ffi.gc(
buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0])
)
return backend._ffi.buffer(buf[0], res)[:].decode('utf8')
def _parse_asn1_time(backend, asn1_time):
backend.openssl_assert(asn1_time != backend._ffi.NULL)
generalized_time = backend._lib.ASN1_TIME_to_generalizedtime(
asn1_time, backend._ffi.NULL
)
if generalized_time == backend._ffi.NULL:
raise ValueError(
"Couldn't parse ASN.1 time as generalizedtime {!r}".format(
_asn1_string_to_bytes(backend, asn1_time)
)
)
generalized_time = backend._ffi.gc(
generalized_time, backend._lib.ASN1_GENERALIZEDTIME_free
)
return _parse_asn1_generalized_time(backend, generalized_time)
def _parse_asn1_generalized_time(backend, generalized_time):
time = _asn1_string_to_ascii(
backend, backend._ffi.cast("ASN1_STRING *", generalized_time)
)
return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ")
def _decode_nonce(backend, nonce):
nonce = backend._ffi.cast("ASN1_OCTET_STRING *", nonce)
nonce = backend._ffi.gc(nonce, backend._lib.ASN1_OCTET_STRING_free)
return x509.OCSPNonce(_asn1_string_to_bytes(backend, nonce))
_EXTENSION_HANDLERS_NO_SCT = {
ExtensionOID.BASIC_CONSTRAINTS: _decode_basic_constraints,
ExtensionOID.SUBJECT_KEY_IDENTIFIER: _decode_subject_key_identifier,
ExtensionOID.KEY_USAGE: _decode_key_usage,
ExtensionOID.SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name,
ExtensionOID.EXTENDED_KEY_USAGE: _decode_extended_key_usage,
ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier,
ExtensionOID.AUTHORITY_INFORMATION_ACCESS: (
_decode_authority_information_access
),
ExtensionOID.CERTIFICATE_POLICIES: _decode_certificate_policies,
ExtensionOID.CRL_DISTRIBUTION_POINTS: _decode_crl_distribution_points,
ExtensionOID.FRESHEST_CRL: _decode_freshest_crl,
ExtensionOID.OCSP_NO_CHECK: _decode_ocsp_no_check,
ExtensionOID.INHIBIT_ANY_POLICY: _decode_inhibit_any_policy,
ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name,
ExtensionOID.NAME_CONSTRAINTS: _decode_name_constraints,
ExtensionOID.POLICY_CONSTRAINTS: _decode_policy_constraints,
}
_EXTENSION_HANDLERS = _EXTENSION_HANDLERS_NO_SCT.copy()
_EXTENSION_HANDLERS[
ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS
] = _decode_precert_signed_certificate_timestamps
_REVOKED_EXTENSION_HANDLERS = {
CRLEntryExtensionOID.CRL_REASON: _decode_crl_reason,
CRLEntryExtensionOID.INVALIDITY_DATE: _decode_invalidity_date,
CRLEntryExtensionOID.CERTIFICATE_ISSUER: _decode_cert_issuer,
}
_CRL_EXTENSION_HANDLERS = {
ExtensionOID.CRL_NUMBER: _decode_crl_number,
ExtensionOID.DELTA_CRL_INDICATOR: _decode_delta_crl_indicator,
ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier,
ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name,
ExtensionOID.AUTHORITY_INFORMATION_ACCESS: (
_decode_authority_information_access
),
ExtensionOID.ISSUING_DISTRIBUTION_POINT: _decode_issuing_dist_point,
ExtensionOID.FRESHEST_CRL: _decode_freshest_crl,
}
_OCSP_REQ_EXTENSION_HANDLERS = {
OCSPExtensionOID.NONCE: _decode_nonce,
}
_OCSP_BASICRESP_EXTENSION_HANDLERS = {
OCSPExtensionOID.NONCE: _decode_nonce,
}
_CERTIFICATE_EXTENSION_PARSER_NO_SCT = _X509ExtensionParser(
ext_count=lambda backend, x: backend._lib.X509_get_ext_count(x),
get_ext=lambda backend, x, i: backend._lib.X509_get_ext(x, i),
handlers=_EXTENSION_HANDLERS_NO_SCT
)
_CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser(
ext_count=lambda backend, x: backend._lib.X509_get_ext_count(x),
get_ext=lambda backend, x, i: backend._lib.X509_get_ext(x, i),
handlers=_EXTENSION_HANDLERS
)
_CSR_EXTENSION_PARSER = _X509ExtensionParser(
ext_count=lambda backend, x: backend._lib.sk_X509_EXTENSION_num(x),
get_ext=lambda backend, x, i: backend._lib.sk_X509_EXTENSION_value(x, i),
handlers=_EXTENSION_HANDLERS
)
_REVOKED_CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser(
ext_count=lambda backend, x: backend._lib.X509_REVOKED_get_ext_count(x),
get_ext=lambda backend, x, i: backend._lib.X509_REVOKED_get_ext(x, i),
handlers=_REVOKED_EXTENSION_HANDLERS,
)
_CRL_EXTENSION_PARSER = _X509ExtensionParser(
ext_count=lambda backend, x: backend._lib.X509_CRL_get_ext_count(x),
get_ext=lambda backend, x, i: backend._lib.X509_CRL_get_ext(x, i),
handlers=_CRL_EXTENSION_HANDLERS,
)
_OCSP_REQ_EXT_PARSER = _X509ExtensionParser(
ext_count=lambda backend, x: backend._lib.OCSP_REQUEST_get_ext_count(x),
get_ext=lambda backend, x, i: backend._lib.OCSP_REQUEST_get_ext(x, i),
handlers=_OCSP_REQ_EXTENSION_HANDLERS,
)
_OCSP_BASICRESP_EXT_PARSER = _X509ExtensionParser(
ext_count=lambda backend, x: backend._lib.OCSP_BASICRESP_get_ext_count(x),
get_ext=lambda backend, x, i: backend._lib.OCSP_BASICRESP_get_ext(x, i),
handlers=_OCSP_BASICRESP_EXTENSION_HANDLERS,
)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/dh.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import dh
def _dh_params_dup(dh_cdata, backend):
lib = backend._lib
ffi = backend._ffi
param_cdata = lib.DHparams_dup(dh_cdata)
backend.openssl_assert(param_cdata != ffi.NULL)
param_cdata = ffi.gc(param_cdata, lib.DH_free)
if lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102:
# In OpenSSL versions < 1.0.2 or libressl DHparams_dup don't copy q
q = ffi.new("BIGNUM **")
lib.DH_get0_pqg(dh_cdata, ffi.NULL, q, ffi.NULL)
q_dup = lib.BN_dup(q[0])
res = lib.DH_set0_pqg(param_cdata, ffi.NULL, q_dup, ffi.NULL)
backend.openssl_assert(res == 1)
return param_cdata
def _dh_cdata_to_parameters(dh_cdata, backend):
param_cdata = _dh_params_dup(dh_cdata, backend)
return _DHParameters(backend, param_cdata)
@utils.register_interface(dh.DHParametersWithSerialization)
class _DHParameters(object):
def __init__(self, backend, dh_cdata):
self._backend = backend
self._dh_cdata = dh_cdata
def parameter_numbers(self):
p = self._backend._ffi.new("BIGNUM **")
g = self._backend._ffi.new("BIGNUM **")
q = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g)
self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
if q[0] == self._backend._ffi.NULL:
q_val = None
else:
q_val = self._backend._bn_to_int(q[0])
return dh.DHParameterNumbers(
p=self._backend._bn_to_int(p[0]),
g=self._backend._bn_to_int(g[0]),
q=q_val
)
def generate_private_key(self):
return self._backend.generate_dh_private_key(self)
def parameter_bytes(self, encoding, format):
if format is not serialization.ParameterFormat.PKCS3:
raise ValueError(
"Only PKCS3 serialization is supported"
)
if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX:
q = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_pqg(self._dh_cdata,
self._backend._ffi.NULL,
q,
self._backend._ffi.NULL)
if q[0] != self._backend._ffi.NULL:
raise UnsupportedAlgorithm(
"DH X9.42 serialization is not supported",
_Reasons.UNSUPPORTED_SERIALIZATION)
return self._backend._parameter_bytes(
encoding,
format,
self._dh_cdata
)
def _handle_dh_compute_key_error(errors, backend):
lib = backend._lib
backend.openssl_assert(
errors[0]._lib_reason_match(
lib.ERR_LIB_DH, lib.DH_R_INVALID_PUBKEY
)
)
raise ValueError("Public key value is invalid for this exchange.")
def _get_dh_num_bits(backend, dh_cdata):
p = backend._ffi.new("BIGNUM **")
backend._lib.DH_get0_pqg(dh_cdata, p,
backend._ffi.NULL,
backend._ffi.NULL)
backend.openssl_assert(p[0] != backend._ffi.NULL)
return backend._lib.BN_num_bits(p[0])
@utils.register_interface(dh.DHPrivateKeyWithSerialization)
class _DHPrivateKey(object):
def __init__(self, backend, dh_cdata, evp_pkey):
self._backend = backend
self._dh_cdata = dh_cdata
self._evp_pkey = evp_pkey
self._key_size_bytes = self._backend._lib.DH_size(dh_cdata)
@property
def key_size(self):
return _get_dh_num_bits(self._backend, self._dh_cdata)
def private_numbers(self):
p = self._backend._ffi.new("BIGNUM **")
g = self._backend._ffi.new("BIGNUM **")
q = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g)
self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
if q[0] == self._backend._ffi.NULL:
q_val = None
else:
q_val = self._backend._bn_to_int(q[0])
pub_key = self._backend._ffi.new("BIGNUM **")
priv_key = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_key(self._dh_cdata, pub_key, priv_key)
self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL)
return dh.DHPrivateNumbers(
public_numbers=dh.DHPublicNumbers(
parameter_numbers=dh.DHParameterNumbers(
p=self._backend._bn_to_int(p[0]),
g=self._backend._bn_to_int(g[0]),
q=q_val
),
y=self._backend._bn_to_int(pub_key[0])
),
x=self._backend._bn_to_int(priv_key[0])
)
def exchange(self, peer_public_key):
buf = self._backend._ffi.new("unsigned char[]", self._key_size_bytes)
pub_key = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_key(peer_public_key._dh_cdata, pub_key,
self._backend._ffi.NULL)
self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
res = self._backend._lib.DH_compute_key(
buf,
pub_key[0],
self._dh_cdata
)
if res == -1:
errors = self._backend._consume_errors()
return _handle_dh_compute_key_error(errors, self._backend)
else:
self._backend.openssl_assert(res >= 1)
key = self._backend._ffi.buffer(buf)[:res]
pad = self._key_size_bytes - len(key)
if pad > 0:
key = (b"\x00" * pad) + key
return key
def public_key(self):
dh_cdata = _dh_params_dup(self._dh_cdata, self._backend)
pub_key = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_key(self._dh_cdata,
pub_key, self._backend._ffi.NULL)
self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
pub_key_dup = self._backend._lib.BN_dup(pub_key[0])
self._backend.openssl_assert(pub_key_dup != self._backend._ffi.NULL)
res = self._backend._lib.DH_set0_key(dh_cdata,
pub_key_dup,
self._backend._ffi.NULL)
self._backend.openssl_assert(res == 1)
evp_pkey = self._backend._dh_cdata_to_evp_pkey(dh_cdata)
return _DHPublicKey(self._backend, dh_cdata, evp_pkey)
def parameters(self):
return _dh_cdata_to_parameters(self._dh_cdata, self._backend)
def private_bytes(self, encoding, format, encryption_algorithm):
if format is not serialization.PrivateFormat.PKCS8:
raise ValueError(
"DH private keys support only PKCS8 serialization"
)
if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX:
q = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_pqg(self._dh_cdata,
self._backend._ffi.NULL,
q,
self._backend._ffi.NULL)
if q[0] != self._backend._ffi.NULL:
raise UnsupportedAlgorithm(
"DH X9.42 serialization is not supported",
_Reasons.UNSUPPORTED_SERIALIZATION)
return self._backend._private_key_bytes(
encoding,
format,
encryption_algorithm,
self._evp_pkey,
self._dh_cdata
)
@utils.register_interface(dh.DHPublicKeyWithSerialization)
class _DHPublicKey(object):
def __init__(self, backend, dh_cdata, evp_pkey):
self._backend = backend
self._dh_cdata = dh_cdata
self._evp_pkey = evp_pkey
self._key_size_bits = _get_dh_num_bits(self._backend, self._dh_cdata)
@property
def key_size(self):
return self._key_size_bits
def public_numbers(self):
p = self._backend._ffi.new("BIGNUM **")
g = self._backend._ffi.new("BIGNUM **")
q = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g)
self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
if q[0] == self._backend._ffi.NULL:
q_val = None
else:
q_val = self._backend._bn_to_int(q[0])
pub_key = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_key(self._dh_cdata,
pub_key, self._backend._ffi.NULL)
self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
return dh.DHPublicNumbers(
parameter_numbers=dh.DHParameterNumbers(
p=self._backend._bn_to_int(p[0]),
g=self._backend._bn_to_int(g[0]),
q=q_val
),
y=self._backend._bn_to_int(pub_key[0])
)
def parameters(self):
return _dh_cdata_to_parameters(self._dh_cdata, self._backend)
def public_bytes(self, encoding, format):
if format is not serialization.PublicFormat.SubjectPublicKeyInfo:
raise ValueError(
"DH public keys support only "
"SubjectPublicKeyInfo serialization"
)
if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX:
q = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_pqg(self._dh_cdata,
self._backend._ffi.NULL,
q,
self._backend._ffi.NULL)
if q[0] != self._backend._ffi.NULL:
raise UnsupportedAlgorithm(
"DH X9.42 serialization is not supported",
_Reasons.UNSUPPORTED_SERIALIZATION)
return self._backend._public_key_bytes(
encoding,
format,
self,
self._evp_pkey,
None
)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/dsa.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends.openssl.utils import (
_calculate_digest_and_algorithm, _check_not_prehashed,
_warn_sign_verify_deprecated
)
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import (
AsymmetricSignatureContext, AsymmetricVerificationContext, dsa
)
def _dsa_sig_sign(backend, private_key, data):
sig_buf_len = backend._lib.DSA_size(private_key._dsa_cdata)
sig_buf = backend._ffi.new("unsigned char[]", sig_buf_len)
buflen = backend._ffi.new("unsigned int *")
# The first parameter passed to DSA_sign is unused by OpenSSL but
# must be an integer.
res = backend._lib.DSA_sign(
0, data, len(data), sig_buf, buflen, private_key._dsa_cdata
)
backend.openssl_assert(res == 1)
backend.openssl_assert(buflen[0])
return backend._ffi.buffer(sig_buf)[:buflen[0]]
def _dsa_sig_verify(backend, public_key, signature, data):
# The first parameter passed to DSA_verify is unused by OpenSSL but
# must be an integer.
res = backend._lib.DSA_verify(
0, data, len(data), signature, len(signature), public_key._dsa_cdata
)
if res != 1:
backend._consume_errors()
raise InvalidSignature
@utils.register_interface(AsymmetricVerificationContext)
class _DSAVerificationContext(object):
def __init__(self, backend, public_key, signature, algorithm):
self._backend = backend
self._public_key = public_key
self._signature = signature
self._algorithm = algorithm
self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
def update(self, data):
self._hash_ctx.update(data)
def verify(self):
data_to_verify = self._hash_ctx.finalize()
_dsa_sig_verify(
self._backend, self._public_key, self._signature, data_to_verify
)
@utils.register_interface(AsymmetricSignatureContext)
class _DSASignatureContext(object):
def __init__(self, backend, private_key, algorithm):
self._backend = backend
self._private_key = private_key
self._algorithm = algorithm
self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
def update(self, data):
self._hash_ctx.update(data)
def finalize(self):
data_to_sign = self._hash_ctx.finalize()
return _dsa_sig_sign(self._backend, self._private_key, data_to_sign)
@utils.register_interface(dsa.DSAParametersWithNumbers)
class _DSAParameters(object):
def __init__(self, backend, dsa_cdata):
self._backend = backend
self._dsa_cdata = dsa_cdata
def parameter_numbers(self):
p = self._backend._ffi.new("BIGNUM **")
q = self._backend._ffi.new("BIGNUM **")
g = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g)
self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(q[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
return dsa.DSAParameterNumbers(
p=self._backend._bn_to_int(p[0]),
q=self._backend._bn_to_int(q[0]),
g=self._backend._bn_to_int(g[0])
)
def generate_private_key(self):
return self._backend.generate_dsa_private_key(self)
@utils.register_interface(dsa.DSAPrivateKeyWithSerialization)
class _DSAPrivateKey(object):
def __init__(self, backend, dsa_cdata, evp_pkey):
self._backend = backend
self._dsa_cdata = dsa_cdata
self._evp_pkey = evp_pkey
p = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DSA_get0_pqg(
dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL
)
self._backend.openssl_assert(p[0] != backend._ffi.NULL)
self._key_size = self._backend._lib.BN_num_bits(p[0])
key_size = utils.read_only_property("_key_size")
def signer(self, signature_algorithm):
_warn_sign_verify_deprecated()
_check_not_prehashed(signature_algorithm)
return _DSASignatureContext(self._backend, self, signature_algorithm)
def private_numbers(self):
p = self._backend._ffi.new("BIGNUM **")
q = self._backend._ffi.new("BIGNUM **")
g = self._backend._ffi.new("BIGNUM **")
pub_key = self._backend._ffi.new("BIGNUM **")
priv_key = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g)
self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(q[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
self._backend._lib.DSA_get0_key(self._dsa_cdata, pub_key, priv_key)
self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL)
return dsa.DSAPrivateNumbers(
public_numbers=dsa.DSAPublicNumbers(
parameter_numbers=dsa.DSAParameterNumbers(
p=self._backend._bn_to_int(p[0]),
q=self._backend._bn_to_int(q[0]),
g=self._backend._bn_to_int(g[0])
),
y=self._backend._bn_to_int(pub_key[0])
),
x=self._backend._bn_to_int(priv_key[0])
)
def public_key(self):
dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata)
self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL)
dsa_cdata = self._backend._ffi.gc(
dsa_cdata, self._backend._lib.DSA_free
)
pub_key = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DSA_get0_key(
self._dsa_cdata, pub_key, self._backend._ffi.NULL
)
self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
pub_key_dup = self._backend._lib.BN_dup(pub_key[0])
res = self._backend._lib.DSA_set0_key(
dsa_cdata, pub_key_dup, self._backend._ffi.NULL
)
self._backend.openssl_assert(res == 1)
evp_pkey = self._backend._dsa_cdata_to_evp_pkey(dsa_cdata)
return _DSAPublicKey(self._backend, dsa_cdata, evp_pkey)
def parameters(self):
dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata)
self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL)
dsa_cdata = self._backend._ffi.gc(
dsa_cdata, self._backend._lib.DSA_free
)
return _DSAParameters(self._backend, dsa_cdata)
def private_bytes(self, encoding, format, encryption_algorithm):
return self._backend._private_key_bytes(
encoding,
format,
encryption_algorithm,
self._evp_pkey,
self._dsa_cdata
)
def sign(self, data, algorithm):
data, algorithm = _calculate_digest_and_algorithm(
self._backend, data, algorithm
)
return _dsa_sig_sign(self._backend, self, data)
@utils.register_interface(dsa.DSAPublicKeyWithSerialization)
class _DSAPublicKey(object):
def __init__(self, backend, dsa_cdata, evp_pkey):
self._backend = backend
self._dsa_cdata = dsa_cdata
self._evp_pkey = evp_pkey
p = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DSA_get0_pqg(
dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL
)
self._backend.openssl_assert(p[0] != backend._ffi.NULL)
self._key_size = self._backend._lib.BN_num_bits(p[0])
key_size = utils.read_only_property("_key_size")
def verifier(self, signature, signature_algorithm):
_warn_sign_verify_deprecated()
utils._check_bytes("signature", signature)
_check_not_prehashed(signature_algorithm)
return _DSAVerificationContext(
self._backend, self, signature, signature_algorithm
)
def public_numbers(self):
p = self._backend._ffi.new("BIGNUM **")
q = self._backend._ffi.new("BIGNUM **")
g = self._backend._ffi.new("BIGNUM **")
pub_key = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g)
self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(q[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
self._backend._lib.DSA_get0_key(
self._dsa_cdata, pub_key, self._backend._ffi.NULL
)
self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
return dsa.DSAPublicNumbers(
parameter_numbers=dsa.DSAParameterNumbers(
p=self._backend._bn_to_int(p[0]),
q=self._backend._bn_to_int(q[0]),
g=self._backend._bn_to_int(g[0])
),
y=self._backend._bn_to_int(pub_key[0])
)
def parameters(self):
dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata)
dsa_cdata = self._backend._ffi.gc(
dsa_cdata, self._backend._lib.DSA_free
)
return _DSAParameters(self._backend, dsa_cdata)
def public_bytes(self, encoding, format):
if format is serialization.PublicFormat.PKCS1:
raise ValueError(
"DSA public keys do not support PKCS1 serialization"
)
return self._backend._public_key_bytes(
encoding,
format,
self,
self._evp_pkey,
None
)
def verify(self, signature, data, algorithm):
data, algorithm = _calculate_digest_and_algorithm(
self._backend, data, algorithm
)
return _dsa_sig_verify(self._backend, self, signature, data)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/ec.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import (
InvalidSignature, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.openssl.utils import (
_calculate_digest_and_algorithm, _check_not_prehashed,
_warn_sign_verify_deprecated
)
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import (
AsymmetricSignatureContext, AsymmetricVerificationContext, ec
)
def _check_signature_algorithm(signature_algorithm):
if not isinstance(signature_algorithm, ec.ECDSA):
raise UnsupportedAlgorithm(
"Unsupported elliptic curve signature algorithm.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def _ec_key_curve_sn(backend, ec_key):
group = backend._lib.EC_KEY_get0_group(ec_key)
backend.openssl_assert(group != backend._ffi.NULL)
nid = backend._lib.EC_GROUP_get_curve_name(group)
# The following check is to find EC keys with unnamed curves and raise
# an error for now.
if nid == backend._lib.NID_undef:
raise NotImplementedError(
"ECDSA keys with unnamed curves are unsupported "
"at this time"
)
# This is like the above check, but it also catches the case where you
# explicitly encoded a curve with the same parameters as a named curve.
# Don't do that.
if (
backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER and
backend._lib.EC_GROUP_get_asn1_flag(group) == 0
):
raise NotImplementedError(
"ECDSA keys with unnamed curves are unsupported "
"at this time"
)
curve_name = backend._lib.OBJ_nid2sn(nid)
backend.openssl_assert(curve_name != backend._ffi.NULL)
sn = backend._ffi.string(curve_name).decode('ascii')
return sn
def _mark_asn1_named_ec_curve(backend, ec_cdata):
"""
Set the named curve flag on the EC_KEY. This causes OpenSSL to
serialize EC keys along with their curve OID which makes
deserialization easier.
"""
backend._lib.EC_KEY_set_asn1_flag(
ec_cdata, backend._lib.OPENSSL_EC_NAMED_CURVE
)
def _sn_to_elliptic_curve(backend, sn):
try:
return ec._CURVE_TYPES[sn]()
except KeyError:
raise UnsupportedAlgorithm(
"{} is not a supported elliptic curve".format(sn),
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE
)
def _ecdsa_sig_sign(backend, private_key, data):
max_size = backend._lib.ECDSA_size(private_key._ec_key)
backend.openssl_assert(max_size > 0)
sigbuf = backend._ffi.new("unsigned char[]", max_size)
siglen_ptr = backend._ffi.new("unsigned int[]", 1)
res = backend._lib.ECDSA_sign(
0, data, len(data), sigbuf, siglen_ptr, private_key._ec_key
)
backend.openssl_assert(res == 1)
return backend._ffi.buffer(sigbuf)[:siglen_ptr[0]]
def _ecdsa_sig_verify(backend, public_key, signature, data):
res = backend._lib.ECDSA_verify(
0, data, len(data), signature, len(signature), public_key._ec_key
)
if res != 1:
backend._consume_errors()
raise InvalidSignature
@utils.register_interface(AsymmetricSignatureContext)
class _ECDSASignatureContext(object):
def __init__(self, backend, private_key, algorithm):
self._backend = backend
self._private_key = private_key
self._digest = hashes.Hash(algorithm, backend)
def update(self, data):
self._digest.update(data)
def finalize(self):
digest = self._digest.finalize()
return _ecdsa_sig_sign(self._backend, self._private_key, digest)
@utils.register_interface(AsymmetricVerificationContext)
class _ECDSAVerificationContext(object):
def __init__(self, backend, public_key, signature, algorithm):
self._backend = backend
self._public_key = public_key
self._signature = signature
self._digest = hashes.Hash(algorithm, backend)
def update(self, data):
self._digest.update(data)
def verify(self):
digest = self._digest.finalize()
_ecdsa_sig_verify(
self._backend, self._public_key, self._signature, digest
)
@utils.register_interface(ec.EllipticCurvePrivateKeyWithSerialization)
class _EllipticCurvePrivateKey(object):
def __init__(self, backend, ec_key_cdata, evp_pkey):
self._backend = backend
self._ec_key = ec_key_cdata
self._evp_pkey = evp_pkey
sn = _ec_key_curve_sn(backend, ec_key_cdata)
self._curve = _sn_to_elliptic_curve(backend, sn)
_mark_asn1_named_ec_curve(backend, ec_key_cdata)
curve = utils.read_only_property("_curve")
@property
def key_size(self):
return self.curve.key_size
def signer(self, signature_algorithm):
_warn_sign_verify_deprecated()
_check_signature_algorithm(signature_algorithm)
_check_not_prehashed(signature_algorithm.algorithm)
return _ECDSASignatureContext(
self._backend, self, signature_algorithm.algorithm
)
def exchange(self, algorithm, peer_public_key):
if not (
self._backend.elliptic_curve_exchange_algorithm_supported(
algorithm, self.curve
)
):
raise UnsupportedAlgorithm(
"This backend does not support the ECDH algorithm.",
_Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
)
if peer_public_key.curve.name != self.curve.name:
raise ValueError(
"peer_public_key and self are not on the same curve"
)
group = self._backend._lib.EC_KEY_get0_group(self._ec_key)
z_len = (self._backend._lib.EC_GROUP_get_degree(group) + 7) // 8
self._backend.openssl_assert(z_len > 0)
z_buf = self._backend._ffi.new("uint8_t[]", z_len)
peer_key = self._backend._lib.EC_KEY_get0_public_key(
peer_public_key._ec_key
)
r = self._backend._lib.ECDH_compute_key(
z_buf, z_len, peer_key, self._ec_key, self._backend._ffi.NULL
)
self._backend.openssl_assert(r > 0)
return self._backend._ffi.buffer(z_buf)[:z_len]
def public_key(self):
group = self._backend._lib.EC_KEY_get0_group(self._ec_key)
self._backend.openssl_assert(group != self._backend._ffi.NULL)
curve_nid = self._backend._lib.EC_GROUP_get_curve_name(group)
public_ec_key = self._backend._lib.EC_KEY_new_by_curve_name(curve_nid)
self._backend.openssl_assert(public_ec_key != self._backend._ffi.NULL)
public_ec_key = self._backend._ffi.gc(
public_ec_key, self._backend._lib.EC_KEY_free
)
point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key)
self._backend.openssl_assert(point != self._backend._ffi.NULL)
res = self._backend._lib.EC_KEY_set_public_key(public_ec_key, point)
self._backend.openssl_assert(res == 1)
evp_pkey = self._backend._ec_cdata_to_evp_pkey(public_ec_key)
return _EllipticCurvePublicKey(self._backend, public_ec_key, evp_pkey)
def private_numbers(self):
bn = self._backend._lib.EC_KEY_get0_private_key(self._ec_key)
private_value = self._backend._bn_to_int(bn)
return ec.EllipticCurvePrivateNumbers(
private_value=private_value,
public_numbers=self.public_key().public_numbers()
)
def private_bytes(self, encoding, format, encryption_algorithm):
return self._backend._private_key_bytes(
encoding,
format,
encryption_algorithm,
self._evp_pkey,
self._ec_key
)
def sign(self, data, signature_algorithm):
_check_signature_algorithm(signature_algorithm)
data, algorithm = _calculate_digest_and_algorithm(
self._backend, data, signature_algorithm._algorithm
)
return _ecdsa_sig_sign(self._backend, self, data)
@utils.register_interface(ec.EllipticCurvePublicKeyWithSerialization)
class _EllipticCurvePublicKey(object):
def __init__(self, backend, ec_key_cdata, evp_pkey):
self._backend = backend
self._ec_key = ec_key_cdata
self._evp_pkey = evp_pkey
sn = _ec_key_curve_sn(backend, ec_key_cdata)
self._curve = _sn_to_elliptic_curve(backend, sn)
_mark_asn1_named_ec_curve(backend, ec_key_cdata)
curve = utils.read_only_property("_curve")
@property
def key_size(self):
return self.curve.key_size
def verifier(self, signature, signature_algorithm):
_warn_sign_verify_deprecated()
utils._check_bytes("signature", signature)
_check_signature_algorithm(signature_algorithm)
_check_not_prehashed(signature_algorithm.algorithm)
return _ECDSAVerificationContext(
self._backend, self, signature, signature_algorithm.algorithm
)
def public_numbers(self):
get_func, group = (
self._backend._ec_key_determine_group_get_func(self._ec_key)
)
point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key)
self._backend.openssl_assert(point != self._backend._ffi.NULL)
with self._backend._tmp_bn_ctx() as bn_ctx:
bn_x = self._backend._lib.BN_CTX_get(bn_ctx)
bn_y = self._backend._lib.BN_CTX_get(bn_ctx)
res = get_func(group, point, bn_x, bn_y, bn_ctx)
self._backend.openssl_assert(res == 1)
x = self._backend._bn_to_int(bn_x)
y = self._backend._bn_to_int(bn_y)
return ec.EllipticCurvePublicNumbers(
x=x,
y=y,
curve=self._curve
)
def _encode_point(self, format):
if format is serialization.PublicFormat.CompressedPoint:
conversion = self._backend._lib.POINT_CONVERSION_COMPRESSED
else:
assert format is serialization.PublicFormat.UncompressedPoint
conversion = self._backend._lib.POINT_CONVERSION_UNCOMPRESSED
group = self._backend._lib.EC_KEY_get0_group(self._ec_key)
self._backend.openssl_assert(group != self._backend._ffi.NULL)
point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key)
self._backend.openssl_assert(point != self._backend._ffi.NULL)
with self._backend._tmp_bn_ctx() as bn_ctx:
buflen = self._backend._lib.EC_POINT_point2oct(
group, point, conversion, self._backend._ffi.NULL, 0, bn_ctx
)
self._backend.openssl_assert(buflen > 0)
buf = self._backend._ffi.new("char[]", buflen)
res = self._backend._lib.EC_POINT_point2oct(
group, point, conversion, buf, buflen, bn_ctx
)
self._backend.openssl_assert(buflen == res)
return self._backend._ffi.buffer(buf)[:]
def public_bytes(self, encoding, format):
if format is serialization.PublicFormat.PKCS1:
raise ValueError(
"EC public keys do not support PKCS1 serialization"
)
if (
encoding is serialization.Encoding.X962 or
format is serialization.PublicFormat.CompressedPoint or
format is serialization.PublicFormat.UncompressedPoint
):
if (
encoding is not serialization.Encoding.X962 or
format not in (
serialization.PublicFormat.CompressedPoint,
serialization.PublicFormat.UncompressedPoint
)
):
raise ValueError(
"X962 encoding must be used with CompressedPoint or "
"UncompressedPoint format"
)
return self._encode_point(format)
else:
return self._backend._public_key_bytes(
encoding,
format,
self,
self._evp_pkey,
None
)
def verify(self, signature, data, signature_algorithm):
_check_signature_algorithm(signature_algorithm)
data, algorithm = _calculate_digest_and_algorithm(
self._backend, data, signature_algorithm._algorithm
)
_ecdsa_sig_verify(self._backend, self, signature, data)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/ed25519.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import exceptions, utils
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import (
Ed25519PrivateKey, Ed25519PublicKey, _ED25519_KEY_SIZE, _ED25519_SIG_SIZE
)
@utils.register_interface(Ed25519PublicKey)
class _Ed25519PublicKey(object):
def __init__(self, backend, evp_pkey):
self._backend = backend
self._evp_pkey = evp_pkey
def public_bytes(self, encoding, format):
if (
encoding is serialization.Encoding.Raw or
format is serialization.PublicFormat.Raw
):
if (
encoding is not serialization.Encoding.Raw or
format is not serialization.PublicFormat.Raw
):
raise ValueError(
"When using Raw both encoding and format must be Raw"
)
return self._raw_public_bytes()
if (
encoding in serialization._PEM_DER and
format is not serialization.PublicFormat.SubjectPublicKeyInfo
):
raise ValueError(
"format must be SubjectPublicKeyInfo when encoding is PEM or "
"DER"
)
return self._backend._public_key_bytes(
encoding, format, self, self._evp_pkey, None
)
def _raw_public_bytes(self):
buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE)
buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE)
res = self._backend._lib.EVP_PKEY_get_raw_public_key(
self._evp_pkey, buf, buflen
)
self._backend.openssl_assert(res == 1)
self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE)
return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:]
def verify(self, signature, data):
evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL)
evp_md_ctx = self._backend._ffi.gc(
evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
)
res = self._backend._lib.EVP_DigestVerifyInit(
evp_md_ctx, self._backend._ffi.NULL, self._backend._ffi.NULL,
self._backend._ffi.NULL, self._evp_pkey
)
self._backend.openssl_assert(res == 1)
res = self._backend._lib.EVP_DigestVerify(
evp_md_ctx, signature, len(signature), data, len(data)
)
if res != 1:
self._backend._consume_errors()
raise exceptions.InvalidSignature
@utils.register_interface(Ed25519PrivateKey)
class _Ed25519PrivateKey(object):
def __init__(self, backend, evp_pkey):
self._backend = backend
self._evp_pkey = evp_pkey
def public_key(self):
buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE)
buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE)
res = self._backend._lib.EVP_PKEY_get_raw_public_key(
self._evp_pkey, buf, buflen
)
self._backend.openssl_assert(res == 1)
self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE)
public_bytes = self._backend._ffi.buffer(buf)[:]
return self._backend.ed25519_load_public_bytes(public_bytes)
def sign(self, data):
evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL)
evp_md_ctx = self._backend._ffi.gc(
evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
)
res = self._backend._lib.EVP_DigestSignInit(
evp_md_ctx, self._backend._ffi.NULL, self._backend._ffi.NULL,
self._backend._ffi.NULL, self._evp_pkey
)
self._backend.openssl_assert(res == 1)
buf = self._backend._ffi.new("unsigned char[]", _ED25519_SIG_SIZE)
buflen = self._backend._ffi.new("size_t *", len(buf))
res = self._backend._lib.EVP_DigestSign(
evp_md_ctx, buf, buflen, data, len(data)
)
self._backend.openssl_assert(res == 1)
self._backend.openssl_assert(buflen[0] == _ED25519_SIG_SIZE)
return self._backend._ffi.buffer(buf, buflen[0])[:]
def private_bytes(self, encoding, format, encryption_algorithm):
if (
encoding is serialization.Encoding.Raw or
format is serialization.PublicFormat.Raw
):
if (
format is not serialization.PrivateFormat.Raw or
encoding is not serialization.Encoding.Raw or not
isinstance(encryption_algorithm, serialization.NoEncryption)
):
raise ValueError(
"When using Raw both encoding and format must be Raw "
"and encryption_algorithm must be NoEncryption()"
)
return self._raw_private_bytes()
if (
encoding in serialization._PEM_DER and
format is not serialization.PrivateFormat.PKCS8
):
raise ValueError(
"format must be PKCS8 when encoding is PEM or DER"
)
return self._backend._private_key_bytes(
encoding, format, encryption_algorithm, self._evp_pkey, None
)
def _raw_private_bytes(self):
buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE)
buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE)
res = self._backend._lib.EVP_PKEY_get_raw_private_key(
self._evp_pkey, buf, buflen
)
self._backend.openssl_assert(res == 1)
self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE)
return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/ed448.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import exceptions, utils
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed448 import (
Ed448PrivateKey, Ed448PublicKey
)
_ED448_KEY_SIZE = 57
_ED448_SIG_SIZE = 114
@utils.register_interface(Ed448PublicKey)
class _Ed448PublicKey(object):
def __init__(self, backend, evp_pkey):
self._backend = backend
self._evp_pkey = evp_pkey
def public_bytes(self, encoding, format):
if (
encoding is serialization.Encoding.Raw or
format is serialization.PublicFormat.Raw
):
if (
encoding is not serialization.Encoding.Raw or
format is not serialization.PublicFormat.Raw
):
raise ValueError(
"When using Raw both encoding and format must be Raw"
)
return self._raw_public_bytes()
if (
encoding in serialization._PEM_DER and
format is not serialization.PublicFormat.SubjectPublicKeyInfo
):
raise ValueError(
"format must be SubjectPublicKeyInfo when encoding is PEM or "
"DER"
)
return self._backend._public_key_bytes(
encoding, format, self, self._evp_pkey, None
)
def _raw_public_bytes(self):
buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE)
buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE)
res = self._backend._lib.EVP_PKEY_get_raw_public_key(
self._evp_pkey, buf, buflen
)
self._backend.openssl_assert(res == 1)
self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE)
return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:]
def verify(self, signature, data):
evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL)
evp_md_ctx = self._backend._ffi.gc(
evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
)
res = self._backend._lib.EVP_DigestVerifyInit(
evp_md_ctx, self._backend._ffi.NULL, self._backend._ffi.NULL,
self._backend._ffi.NULL, self._evp_pkey
)
self._backend.openssl_assert(res == 1)
res = self._backend._lib.EVP_DigestVerify(
evp_md_ctx, signature, len(signature), data, len(data)
)
if res != 1:
self._backend._consume_errors()
raise exceptions.InvalidSignature
@utils.register_interface(Ed448PrivateKey)
class _Ed448PrivateKey(object):
def __init__(self, backend, evp_pkey):
self._backend = backend
self._evp_pkey = evp_pkey
def public_key(self):
buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE)
buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE)
res = self._backend._lib.EVP_PKEY_get_raw_public_key(
self._evp_pkey, buf, buflen
)
self._backend.openssl_assert(res == 1)
self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE)
public_bytes = self._backend._ffi.buffer(buf)[:]
return self._backend.ed448_load_public_bytes(public_bytes)
def sign(self, data):
evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL)
evp_md_ctx = self._backend._ffi.gc(
evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
)
res = self._backend._lib.EVP_DigestSignInit(
evp_md_ctx, self._backend._ffi.NULL, self._backend._ffi.NULL,
self._backend._ffi.NULL, self._evp_pkey
)
self._backend.openssl_assert(res == 1)
buf = self._backend._ffi.new("unsigned char[]", _ED448_SIG_SIZE)
buflen = self._backend._ffi.new("size_t *", len(buf))
res = self._backend._lib.EVP_DigestSign(
evp_md_ctx, buf, buflen, data, len(data)
)
self._backend.openssl_assert(res == 1)
self._backend.openssl_assert(buflen[0] == _ED448_SIG_SIZE)
return self._backend._ffi.buffer(buf, buflen[0])[:]
def private_bytes(self, encoding, format, encryption_algorithm):
if (
encoding is serialization.Encoding.Raw or
format is serialization.PublicFormat.Raw
):
if (
format is not serialization.PrivateFormat.Raw or
encoding is not serialization.Encoding.Raw or not
isinstance(encryption_algorithm, serialization.NoEncryption)
):
raise ValueError(
"When using Raw both encoding and format must be Raw "
"and encryption_algorithm must be NoEncryption()"
)
return self._raw_private_bytes()
if (
encoding in serialization._PEM_DER and
format is not serialization.PrivateFormat.PKCS8
):
raise ValueError(
"format must be PKCS8 when encoding is PEM or DER"
)
return self._backend._private_key_bytes(
encoding, format, encryption_algorithm, self._evp_pkey, None
)
def _raw_private_bytes(self):
buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE)
buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE)
res = self._backend._lib.EVP_PKEY_get_raw_private_key(
self._evp_pkey, buf, buflen
)
self._backend.openssl_assert(res == 1)
self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE)
return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import calendar
import ipaddress
import six
from cryptography import utils, x509
from cryptography.hazmat.backends.openssl.decode_asn1 import (
_CRL_ENTRY_REASON_ENUM_TO_CODE, _DISTPOINT_TYPE_FULLNAME,
_DISTPOINT_TYPE_RELATIVENAME
)
from cryptography.x509.name import _ASN1Type
from cryptography.x509.oid import (
CRLEntryExtensionOID, ExtensionOID, OCSPExtensionOID,
)
def _encode_asn1_int(backend, x):
"""
Converts a python integer to an ASN1_INTEGER. The returned ASN1_INTEGER
will not be garbage collected (to support adding them to structs that take
ownership of the object). Be sure to register it for GC if it will be
discarded after use.
"""
# Convert Python integer to OpenSSL "bignum" in case value exceeds
# machine's native integer limits (note: `int_to_bn` doesn't automatically
# GC).
i = backend._int_to_bn(x)
i = backend._ffi.gc(i, backend._lib.BN_free)
# Wrap in an ASN.1 integer. Don't GC -- as documented.
i = backend._lib.BN_to_ASN1_INTEGER(i, backend._ffi.NULL)
backend.openssl_assert(i != backend._ffi.NULL)
return i
def _encode_asn1_int_gc(backend, x):
i = _encode_asn1_int(backend, x)
i = backend._ffi.gc(i, backend._lib.ASN1_INTEGER_free)
return i
def _encode_asn1_str(backend, data):
"""
Create an ASN1_OCTET_STRING from a Python byte string.
"""
s = backend._lib.ASN1_OCTET_STRING_new()
res = backend._lib.ASN1_OCTET_STRING_set(s, data, len(data))
backend.openssl_assert(res == 1)
return s
def _encode_asn1_utf8_str(backend, string):
"""
Create an ASN1_UTF8STRING from a Python unicode string.
This object will be an ASN1_STRING with UTF8 type in OpenSSL and
can be decoded with ASN1_STRING_to_UTF8.
"""
s = backend._lib.ASN1_UTF8STRING_new()
res = backend._lib.ASN1_STRING_set(
s, string.encode("utf8"), len(string.encode("utf8"))
)
backend.openssl_assert(res == 1)
return s
def _encode_asn1_str_gc(backend, data):
s = _encode_asn1_str(backend, data)
s = backend._ffi.gc(s, backend._lib.ASN1_OCTET_STRING_free)
return s
def _encode_inhibit_any_policy(backend, inhibit_any_policy):
return _encode_asn1_int_gc(backend, inhibit_any_policy.skip_certs)
def _encode_name(backend, name):
"""
The X509_NAME created will not be gc'd. Use _encode_name_gc if needed.
"""
subject = backend._lib.X509_NAME_new()
for rdn in name.rdns:
set_flag = 0 # indicate whether to add to last RDN or create new RDN
for attribute in rdn:
name_entry = _encode_name_entry(backend, attribute)
# X509_NAME_add_entry dups the object so we need to gc this copy
name_entry = backend._ffi.gc(
name_entry, backend._lib.X509_NAME_ENTRY_free
)
res = backend._lib.X509_NAME_add_entry(
subject, name_entry, -1, set_flag)
backend.openssl_assert(res == 1)
set_flag = -1
return subject
def _encode_name_gc(backend, attributes):
subject = _encode_name(backend, attributes)
subject = backend._ffi.gc(subject, backend._lib.X509_NAME_free)
return subject
def _encode_sk_name_entry(backend, attributes):
"""
The sk_X509_NAME_ENTRY created will not be gc'd.
"""
stack = backend._lib.sk_X509_NAME_ENTRY_new_null()
for attribute in attributes:
name_entry = _encode_name_entry(backend, attribute)
res = backend._lib.sk_X509_NAME_ENTRY_push(stack, name_entry)
backend.openssl_assert(res >= 1)
return stack
def _encode_name_entry(backend, attribute):
if attribute._type is _ASN1Type.BMPString:
value = attribute.value.encode('utf_16_be')
elif attribute._type is _ASN1Type.UniversalString:
value = attribute.value.encode('utf_32_be')
else:
value = attribute.value.encode('utf8')
obj = _txt2obj_gc(backend, attribute.oid.dotted_string)
name_entry = backend._lib.X509_NAME_ENTRY_create_by_OBJ(
backend._ffi.NULL, obj, attribute._type.value, value, len(value)
)
return name_entry
def _encode_crl_number_delta_crl_indicator(backend, ext):
return _encode_asn1_int_gc(backend, ext.crl_number)
def _encode_issuing_dist_point(backend, ext):
idp = backend._lib.ISSUING_DIST_POINT_new()
backend.openssl_assert(idp != backend._ffi.NULL)
idp = backend._ffi.gc(idp, backend._lib.ISSUING_DIST_POINT_free)
idp.onlyuser = 255 if ext.only_contains_user_certs else 0
idp.onlyCA = 255 if ext.only_contains_ca_certs else 0
idp.indirectCRL = 255 if ext.indirect_crl else 0
idp.onlyattr = 255 if ext.only_contains_attribute_certs else 0
if ext.only_some_reasons:
idp.onlysomereasons = _encode_reasonflags(
backend, ext.only_some_reasons
)
if ext.full_name:
idp.distpoint = _encode_full_name(backend, ext.full_name)
if ext.relative_name:
idp.distpoint = _encode_relative_name(backend, ext.relative_name)
return idp
def _encode_crl_reason(backend, crl_reason):
asn1enum = backend._lib.ASN1_ENUMERATED_new()
backend.openssl_assert(asn1enum != backend._ffi.NULL)
asn1enum = backend._ffi.gc(asn1enum, backend._lib.ASN1_ENUMERATED_free)
res = backend._lib.ASN1_ENUMERATED_set(
asn1enum, _CRL_ENTRY_REASON_ENUM_TO_CODE[crl_reason.reason]
)
backend.openssl_assert(res == 1)
return asn1enum
def _encode_invalidity_date(backend, invalidity_date):
time = backend._lib.ASN1_GENERALIZEDTIME_set(
backend._ffi.NULL, calendar.timegm(
invalidity_date.invalidity_date.timetuple()
)
)
backend.openssl_assert(time != backend._ffi.NULL)
time = backend._ffi.gc(time, backend._lib.ASN1_GENERALIZEDTIME_free)
return time
def _encode_certificate_policies(backend, certificate_policies):
cp = backend._lib.sk_POLICYINFO_new_null()
backend.openssl_assert(cp != backend._ffi.NULL)
cp = backend._ffi.gc(cp, backend._lib.sk_POLICYINFO_free)
for policy_info in certificate_policies:
pi = backend._lib.POLICYINFO_new()
backend.openssl_assert(pi != backend._ffi.NULL)
res = backend._lib.sk_POLICYINFO_push(cp, pi)
backend.openssl_assert(res >= 1)
oid = _txt2obj(backend, policy_info.policy_identifier.dotted_string)
pi.policyid = oid
if policy_info.policy_qualifiers:
pqis = backend._lib.sk_POLICYQUALINFO_new_null()
backend.openssl_assert(pqis != backend._ffi.NULL)
for qualifier in policy_info.policy_qualifiers:
pqi = backend._lib.POLICYQUALINFO_new()
backend.openssl_assert(pqi != backend._ffi.NULL)
res = backend._lib.sk_POLICYQUALINFO_push(pqis, pqi)
backend.openssl_assert(res >= 1)
if isinstance(qualifier, six.text_type):
pqi.pqualid = _txt2obj(
backend, x509.OID_CPS_QUALIFIER.dotted_string
)
pqi.d.cpsuri = _encode_asn1_str(
backend,
qualifier.encode("ascii"),
)
else:
assert isinstance(qualifier, x509.UserNotice)
pqi.pqualid = _txt2obj(
backend, x509.OID_CPS_USER_NOTICE.dotted_string
)
un = backend._lib.USERNOTICE_new()
backend.openssl_assert(un != backend._ffi.NULL)
pqi.d.usernotice = un
if qualifier.explicit_text:
un.exptext = _encode_asn1_utf8_str(
backend, qualifier.explicit_text
)
un.noticeref = _encode_notice_reference(
backend, qualifier.notice_reference
)
pi.qualifiers = pqis
return cp
def _encode_notice_reference(backend, notice):
if notice is None:
return backend._ffi.NULL
else:
nr = backend._lib.NOTICEREF_new()
backend.openssl_assert(nr != backend._ffi.NULL)
# organization is a required field
nr.organization = _encode_asn1_utf8_str(backend, notice.organization)
notice_stack = backend._lib.sk_ASN1_INTEGER_new_null()
nr.noticenos = notice_stack
for number in notice.notice_numbers:
num = _encode_asn1_int(backend, number)
res = backend._lib.sk_ASN1_INTEGER_push(notice_stack, num)
backend.openssl_assert(res >= 1)
return nr
def _txt2obj(backend, name):
"""
Converts a Python string with an ASN.1 object ID in dotted form to a
ASN1_OBJECT.
"""
name = name.encode('ascii')
obj = backend._lib.OBJ_txt2obj(name, 1)
backend.openssl_assert(obj != backend._ffi.NULL)
return obj
def _txt2obj_gc(backend, name):
obj = _txt2obj(backend, name)
obj = backend._ffi.gc(obj, backend._lib.ASN1_OBJECT_free)
return obj
def _encode_ocsp_nocheck(backend, ext):
# Doesn't need to be GC'd
return backend._lib.ASN1_NULL_new()
def _encode_key_usage(backend, key_usage):
set_bit = backend._lib.ASN1_BIT_STRING_set_bit
ku = backend._lib.ASN1_BIT_STRING_new()
ku = backend._ffi.gc(ku, backend._lib.ASN1_BIT_STRING_free)
res = set_bit(ku, 0, key_usage.digital_signature)
backend.openssl_assert(res == 1)
res = set_bit(ku, 1, key_usage.content_commitment)
backend.openssl_assert(res == 1)
res = set_bit(ku, 2, key_usage.key_encipherment)
backend.openssl_assert(res == 1)
res = set_bit(ku, 3, key_usage.data_encipherment)
backend.openssl_assert(res == 1)
res = set_bit(ku, 4, key_usage.key_agreement)
backend.openssl_assert(res == 1)
res = set_bit(ku, 5, key_usage.key_cert_sign)
backend.openssl_assert(res == 1)
res = set_bit(ku, 6, key_usage.crl_sign)
backend.openssl_assert(res == 1)
if key_usage.key_agreement:
res = set_bit(ku, 7, key_usage.encipher_only)
backend.openssl_assert(res == 1)
res = set_bit(ku, 8, key_usage.decipher_only)
backend.openssl_assert(res == 1)
else:
res = set_bit(ku, 7, 0)
backend.openssl_assert(res == 1)
res = set_bit(ku, 8, 0)
backend.openssl_assert(res == 1)
return ku
def _encode_authority_key_identifier(backend, authority_keyid):
akid = backend._lib.AUTHORITY_KEYID_new()
backend.openssl_assert(akid != backend._ffi.NULL)
akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free)
if authority_keyid.key_identifier is not None:
akid.keyid = _encode_asn1_str(
backend,
authority_keyid.key_identifier,
)
if authority_keyid.authority_cert_issuer is not None:
akid.issuer = _encode_general_names(
backend, authority_keyid.authority_cert_issuer
)
if authority_keyid.authority_cert_serial_number is not None:
akid.serial = _encode_asn1_int(
backend, authority_keyid.authority_cert_serial_number
)
return akid
def _encode_basic_constraints(backend, basic_constraints):
constraints = backend._lib.BASIC_CONSTRAINTS_new()
constraints = backend._ffi.gc(
constraints, backend._lib.BASIC_CONSTRAINTS_free
)
constraints.ca = 255 if basic_constraints.ca else 0
if basic_constraints.ca and basic_constraints.path_length is not None:
constraints.pathlen = _encode_asn1_int(
backend, basic_constraints.path_length
)
return constraints
def _encode_authority_information_access(backend, authority_info_access):
aia = backend._lib.sk_ACCESS_DESCRIPTION_new_null()
backend.openssl_assert(aia != backend._ffi.NULL)
aia = backend._ffi.gc(
aia,
lambda x: backend._lib.sk_ACCESS_DESCRIPTION_pop_free(
x, backend._ffi.addressof(
backend._lib._original_lib, "ACCESS_DESCRIPTION_free"
)
)
)
for access_description in authority_info_access:
ad = backend._lib.ACCESS_DESCRIPTION_new()
method = _txt2obj(
backend, access_description.access_method.dotted_string
)
_encode_general_name_preallocated(
backend, access_description.access_location, ad.location
)
ad.method = method
res = backend._lib.sk_ACCESS_DESCRIPTION_push(aia, ad)
backend.openssl_assert(res >= 1)
return aia
def _encode_general_names(backend, names):
general_names = backend._lib.GENERAL_NAMES_new()
backend.openssl_assert(general_names != backend._ffi.NULL)
for name in names:
gn = _encode_general_name(backend, name)
res = backend._lib.sk_GENERAL_NAME_push(general_names, gn)
backend.openssl_assert(res != 0)
return general_names
def _encode_alt_name(backend, san):
general_names = _encode_general_names(backend, san)
general_names = backend._ffi.gc(
general_names, backend._lib.GENERAL_NAMES_free
)
return general_names
def _encode_subject_key_identifier(backend, ski):
return _encode_asn1_str_gc(backend, ski.digest)
def _encode_general_name(backend, name):
gn = backend._lib.GENERAL_NAME_new()
_encode_general_name_preallocated(backend, name, gn)
return gn
def _encode_general_name_preallocated(backend, name, gn):
if isinstance(name, x509.DNSName):
backend.openssl_assert(gn != backend._ffi.NULL)
gn.type = backend._lib.GEN_DNS
ia5 = backend._lib.ASN1_IA5STRING_new()
backend.openssl_assert(ia5 != backend._ffi.NULL)
# ia5strings are supposed to be ITU T.50 but to allow round-tripping
# of broken certs that encode utf8 we'll encode utf8 here too.
value = name.value.encode("utf8")
res = backend._lib.ASN1_STRING_set(ia5, value, len(value))
backend.openssl_assert(res == 1)
gn.d.dNSName = ia5
elif isinstance(name, x509.RegisteredID):
backend.openssl_assert(gn != backend._ffi.NULL)
gn.type = backend._lib.GEN_RID
obj = backend._lib.OBJ_txt2obj(
name.value.dotted_string.encode('ascii'), 1
)
backend.openssl_assert(obj != backend._ffi.NULL)
gn.d.registeredID = obj
elif isinstance(name, x509.DirectoryName):
backend.openssl_assert(gn != backend._ffi.NULL)
dir_name = _encode_name(backend, name.value)
gn.type = backend._lib.GEN_DIRNAME
gn.d.directoryName = dir_name
elif isinstance(name, x509.IPAddress):
backend.openssl_assert(gn != backend._ffi.NULL)
if isinstance(name.value, ipaddress.IPv4Network):
packed = (
name.value.network_address.packed +
utils.int_to_bytes(((1 << 32) - name.value.num_addresses), 4)
)
elif isinstance(name.value, ipaddress.IPv6Network):
packed = (
name.value.network_address.packed +
utils.int_to_bytes((1 << 128) - name.value.num_addresses, 16)
)
else:
packed = name.value.packed
ipaddr = _encode_asn1_str(backend, packed)
gn.type = backend._lib.GEN_IPADD
gn.d.iPAddress = ipaddr
elif isinstance(name, x509.OtherName):
backend.openssl_assert(gn != backend._ffi.NULL)
other_name = backend._lib.OTHERNAME_new()
backend.openssl_assert(other_name != backend._ffi.NULL)
type_id = backend._lib.OBJ_txt2obj(
name.type_id.dotted_string.encode('ascii'), 1
)
backend.openssl_assert(type_id != backend._ffi.NULL)
data = backend._ffi.new("unsigned char[]", name.value)
data_ptr_ptr = backend._ffi.new("unsigned char **")
data_ptr_ptr[0] = data
value = backend._lib.d2i_ASN1_TYPE(
backend._ffi.NULL, data_ptr_ptr, len(name.value)
)
if value == backend._ffi.NULL:
backend._consume_errors()
raise ValueError("Invalid ASN.1 data")
other_name.type_id = type_id
other_name.value = value
gn.type = backend._lib.GEN_OTHERNAME
gn.d.otherName = other_name
elif isinstance(name, x509.RFC822Name):
backend.openssl_assert(gn != backend._ffi.NULL)
# ia5strings are supposed to be ITU T.50 but to allow round-tripping
# of broken certs that encode utf8 we'll encode utf8 here too.
data = name.value.encode("utf8")
asn1_str = _encode_asn1_str(backend, data)
gn.type = backend._lib.GEN_EMAIL
gn.d.rfc822Name = asn1_str
elif isinstance(name, x509.UniformResourceIdentifier):
backend.openssl_assert(gn != backend._ffi.NULL)
# ia5strings are supposed to be ITU T.50 but to allow round-tripping
# of broken certs that encode utf8 we'll encode utf8 here too.
data = name.value.encode("utf8")
asn1_str = _encode_asn1_str(backend, data)
gn.type = backend._lib.GEN_URI
gn.d.uniformResourceIdentifier = asn1_str
else:
raise ValueError(
"{} is an unknown GeneralName type".format(name)
)
def _encode_extended_key_usage(backend, extended_key_usage):
eku = backend._lib.sk_ASN1_OBJECT_new_null()
eku = backend._ffi.gc(eku, backend._lib.sk_ASN1_OBJECT_free)
for oid in extended_key_usage:
obj = _txt2obj(backend, oid.dotted_string)
res = backend._lib.sk_ASN1_OBJECT_push(eku, obj)
backend.openssl_assert(res >= 1)
return eku
_CRLREASONFLAGS = {
x509.ReasonFlags.key_compromise: 1,
x509.ReasonFlags.ca_compromise: 2,
x509.ReasonFlags.affiliation_changed: 3,
x509.ReasonFlags.superseded: 4,
x509.ReasonFlags.cessation_of_operation: 5,
x509.ReasonFlags.certificate_hold: 6,
x509.ReasonFlags.privilege_withdrawn: 7,
x509.ReasonFlags.aa_compromise: 8,
}
def _encode_reasonflags(backend, reasons):
bitmask = backend._lib.ASN1_BIT_STRING_new()
backend.openssl_assert(bitmask != backend._ffi.NULL)
for reason in reasons:
res = backend._lib.ASN1_BIT_STRING_set_bit(
bitmask, _CRLREASONFLAGS[reason], 1
)
backend.openssl_assert(res == 1)
return bitmask
def _encode_full_name(backend, full_name):
dpn = backend._lib.DIST_POINT_NAME_new()
backend.openssl_assert(dpn != backend._ffi.NULL)
dpn.type = _DISTPOINT_TYPE_FULLNAME
dpn.name.fullname = _encode_general_names(backend, full_name)
return dpn
def _encode_relative_name(backend, relative_name):
dpn = backend._lib.DIST_POINT_NAME_new()
backend.openssl_assert(dpn != backend._ffi.NULL)
dpn.type = _DISTPOINT_TYPE_RELATIVENAME
dpn.name.relativename = _encode_sk_name_entry(backend, relative_name)
return dpn
def _encode_cdps_freshest_crl(backend, cdps):
cdp = backend._lib.sk_DIST_POINT_new_null()
cdp = backend._ffi.gc(cdp, backend._lib.sk_DIST_POINT_free)
for point in cdps:
dp = backend._lib.DIST_POINT_new()
backend.openssl_assert(dp != backend._ffi.NULL)
if point.reasons:
dp.reasons = _encode_reasonflags(backend, point.reasons)
if point.full_name:
dp.distpoint = _encode_full_name(backend, point.full_name)
if point.relative_name:
dp.distpoint = _encode_relative_name(backend, point.relative_name)
if point.crl_issuer:
dp.CRLissuer = _encode_general_names(backend, point.crl_issuer)
res = backend._lib.sk_DIST_POINT_push(cdp, dp)
backend.openssl_assert(res >= 1)
return cdp
def _encode_name_constraints(backend, name_constraints):
nc = backend._lib.NAME_CONSTRAINTS_new()
backend.openssl_assert(nc != backend._ffi.NULL)
nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free)
permitted = _encode_general_subtree(
backend, name_constraints.permitted_subtrees
)
nc.permittedSubtrees = permitted
excluded = _encode_general_subtree(
backend, name_constraints.excluded_subtrees
)
nc.excludedSubtrees = excluded
return nc
def _encode_policy_constraints(backend, policy_constraints):
pc = backend._lib.POLICY_CONSTRAINTS_new()
backend.openssl_assert(pc != backend._ffi.NULL)
pc = backend._ffi.gc(pc, backend._lib.POLICY_CONSTRAINTS_free)
if policy_constraints.require_explicit_policy is not None:
pc.requireExplicitPolicy = _encode_asn1_int(
backend, policy_constraints.require_explicit_policy
)
if policy_constraints.inhibit_policy_mapping is not None:
pc.inhibitPolicyMapping = _encode_asn1_int(
backend, policy_constraints.inhibit_policy_mapping
)
return pc
def _encode_general_subtree(backend, subtrees):
if subtrees is None:
return backend._ffi.NULL
else:
general_subtrees = backend._lib.sk_GENERAL_SUBTREE_new_null()
for name in subtrees:
gs = backend._lib.GENERAL_SUBTREE_new()
gs.base = _encode_general_name(backend, name)
res = backend._lib.sk_GENERAL_SUBTREE_push(general_subtrees, gs)
assert res >= 1
return general_subtrees
def _encode_nonce(backend, nonce):
return _encode_asn1_str_gc(backend, nonce.nonce)
_EXTENSION_ENCODE_HANDLERS = {
ExtensionOID.BASIC_CONSTRAINTS: _encode_basic_constraints,
ExtensionOID.SUBJECT_KEY_IDENTIFIER: _encode_subject_key_identifier,
ExtensionOID.KEY_USAGE: _encode_key_usage,
ExtensionOID.SUBJECT_ALTERNATIVE_NAME: _encode_alt_name,
ExtensionOID.ISSUER_ALTERNATIVE_NAME: _encode_alt_name,
ExtensionOID.EXTENDED_KEY_USAGE: _encode_extended_key_usage,
ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier,
ExtensionOID.CERTIFICATE_POLICIES: _encode_certificate_policies,
ExtensionOID.AUTHORITY_INFORMATION_ACCESS: (
_encode_authority_information_access
),
ExtensionOID.CRL_DISTRIBUTION_POINTS: _encode_cdps_freshest_crl,
ExtensionOID.FRESHEST_CRL: _encode_cdps_freshest_crl,
ExtensionOID.INHIBIT_ANY_POLICY: _encode_inhibit_any_policy,
ExtensionOID.OCSP_NO_CHECK: _encode_ocsp_nocheck,
ExtensionOID.NAME_CONSTRAINTS: _encode_name_constraints,
ExtensionOID.POLICY_CONSTRAINTS: _encode_policy_constraints,
}
_CRL_EXTENSION_ENCODE_HANDLERS = {
ExtensionOID.ISSUER_ALTERNATIVE_NAME: _encode_alt_name,
ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier,
ExtensionOID.AUTHORITY_INFORMATION_ACCESS: (
_encode_authority_information_access
),
ExtensionOID.CRL_NUMBER: _encode_crl_number_delta_crl_indicator,
ExtensionOID.DELTA_CRL_INDICATOR: _encode_crl_number_delta_crl_indicator,
ExtensionOID.ISSUING_DISTRIBUTION_POINT: _encode_issuing_dist_point,
ExtensionOID.FRESHEST_CRL: _encode_cdps_freshest_crl,
}
_CRL_ENTRY_EXTENSION_ENCODE_HANDLERS = {
CRLEntryExtensionOID.CERTIFICATE_ISSUER: _encode_alt_name,
CRLEntryExtensionOID.CRL_REASON: _encode_crl_reason,
CRLEntryExtensionOID.INVALIDITY_DATE: _encode_invalidity_date,
}
_OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS = {
OCSPExtensionOID.NONCE: _encode_nonce,
}
_OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS = {
OCSPExtensionOID.NONCE: _encode_nonce,
}
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/hashes.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.primitives import hashes
@utils.register_interface(hashes.HashContext)
class _HashContext(object):
def __init__(self, backend, algorithm, ctx=None):
self._algorithm = algorithm
self._backend = backend
if ctx is None:
ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
ctx = self._backend._ffi.gc(
ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
)
evp_md = self._backend._evp_md_from_algorithm(algorithm)
if evp_md == self._backend._ffi.NULL:
raise UnsupportedAlgorithm(
"{} is not a supported hash on this backend.".format(
algorithm.name),
_Reasons.UNSUPPORTED_HASH
)
res = self._backend._lib.EVP_DigestInit_ex(ctx, evp_md,
self._backend._ffi.NULL)
self._backend.openssl_assert(res != 0)
self._ctx = ctx
algorithm = utils.read_only_property("_algorithm")
def copy(self):
copied_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
copied_ctx = self._backend._ffi.gc(
copied_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
)
res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx)
self._backend.openssl_assert(res != 0)
return _HashContext(self._backend, self.algorithm, ctx=copied_ctx)
def update(self, data):
data_ptr = self._backend._ffi.from_buffer(data)
res = self._backend._lib.EVP_DigestUpdate(
self._ctx, data_ptr, len(data)
)
self._backend.openssl_assert(res != 0)
def finalize(self):
if isinstance(self.algorithm, hashes.ExtendableOutputFunction):
# extendable output functions use a different finalize
return self._finalize_xof()
else:
buf = self._backend._ffi.new("unsigned char[]",
self._backend._lib.EVP_MAX_MD_SIZE)
outlen = self._backend._ffi.new("unsigned int *")
res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen)
self._backend.openssl_assert(res != 0)
self._backend.openssl_assert(
outlen[0] == self.algorithm.digest_size
)
return self._backend._ffi.buffer(buf)[:outlen[0]]
def _finalize_xof(self):
buf = self._backend._ffi.new("unsigned char[]",
self.algorithm.digest_size)
res = self._backend._lib.EVP_DigestFinalXOF(
self._ctx, buf, self.algorithm.digest_size
)
self._backend.openssl_assert(res != 0)
return self._backend._ffi.buffer(buf)[:self.algorithm.digest_size]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/hmac.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import (
InvalidSignature, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.primitives import constant_time, hashes
@utils.register_interface(hashes.HashContext)
class _HMACContext(object):
def __init__(self, backend, key, algorithm, ctx=None):
self._algorithm = algorithm
self._backend = backend
if ctx is None:
ctx = self._backend._lib.Cryptography_HMAC_CTX_new()
self._backend.openssl_assert(ctx != self._backend._ffi.NULL)
ctx = self._backend._ffi.gc(
ctx, self._backend._lib.Cryptography_HMAC_CTX_free
)
evp_md = self._backend._evp_md_from_algorithm(algorithm)
if evp_md == self._backend._ffi.NULL:
raise UnsupportedAlgorithm(
"{} is not a supported hash on this backend".format(
algorithm.name),
_Reasons.UNSUPPORTED_HASH
)
key_ptr = self._backend._ffi.from_buffer(key)
res = self._backend._lib.HMAC_Init_ex(
ctx, key_ptr, len(key), evp_md, self._backend._ffi.NULL
)
self._backend.openssl_assert(res != 0)
self._ctx = ctx
self._key = key
algorithm = utils.read_only_property("_algorithm")
def copy(self):
copied_ctx = self._backend._lib.Cryptography_HMAC_CTX_new()
self._backend.openssl_assert(copied_ctx != self._backend._ffi.NULL)
copied_ctx = self._backend._ffi.gc(
copied_ctx, self._backend._lib.Cryptography_HMAC_CTX_free
)
res = self._backend._lib.HMAC_CTX_copy(copied_ctx, self._ctx)
self._backend.openssl_assert(res != 0)
return _HMACContext(
self._backend, self._key, self.algorithm, ctx=copied_ctx
)
def update(self, data):
data_ptr = self._backend._ffi.from_buffer(data)
res = self._backend._lib.HMAC_Update(self._ctx, data_ptr, len(data))
self._backend.openssl_assert(res != 0)
def finalize(self):
buf = self._backend._ffi.new("unsigned char[]",
self._backend._lib.EVP_MAX_MD_SIZE)
outlen = self._backend._ffi.new("unsigned int *")
res = self._backend._lib.HMAC_Final(self._ctx, buf, outlen)
self._backend.openssl_assert(res != 0)
self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size)
return self._backend._ffi.buffer(buf)[:outlen[0]]
def verify(self, signature):
digest = self.finalize()
if not constant_time.bytes_eq(digest, signature):
raise InvalidSignature("Signature did not match digest.")
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/ocsp.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import functools
from cryptography import utils, x509
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.backends.openssl.decode_asn1 import (
_CRL_ENTRY_REASON_CODE_TO_ENUM, _OCSP_BASICRESP_EXT_PARSER,
_OCSP_REQ_EXT_PARSER, _asn1_integer_to_int,
_asn1_string_to_bytes, _decode_x509_name, _obj2txt,
_parse_asn1_generalized_time,
)
from cryptography.hazmat.backends.openssl.x509 import _Certificate
from cryptography.hazmat.primitives import serialization
from cryptography.x509.ocsp import (
OCSPCertStatus, OCSPRequest, OCSPResponse, OCSPResponseStatus,
_CERT_STATUS_TO_ENUM, _OIDS_TO_HASH, _RESPONSE_STATUS_TO_ENUM,
)
def _requires_successful_response(func):
@functools.wraps(func)
def wrapper(self, *args):
if self.response_status != OCSPResponseStatus.SUCCESSFUL:
raise ValueError(
"OCSP response status is not successful so the property "
"has no value"
)
else:
return func(self, *args)
return wrapper
def _issuer_key_hash(backend, cert_id):
key_hash = backend._ffi.new("ASN1_OCTET_STRING **")
res = backend._lib.OCSP_id_get0_info(
backend._ffi.NULL, backend._ffi.NULL,
key_hash, backend._ffi.NULL, cert_id
)
backend.openssl_assert(res == 1)
backend.openssl_assert(key_hash[0] != backend._ffi.NULL)
return _asn1_string_to_bytes(backend, key_hash[0])
def _issuer_name_hash(backend, cert_id):
name_hash = backend._ffi.new("ASN1_OCTET_STRING **")
res = backend._lib.OCSP_id_get0_info(
name_hash, backend._ffi.NULL,
backend._ffi.NULL, backend._ffi.NULL, cert_id
)
backend.openssl_assert(res == 1)
backend.openssl_assert(name_hash[0] != backend._ffi.NULL)
return _asn1_string_to_bytes(backend, name_hash[0])
def _serial_number(backend, cert_id):
num = backend._ffi.new("ASN1_INTEGER **")
res = backend._lib.OCSP_id_get0_info(
backend._ffi.NULL, backend._ffi.NULL,
backend._ffi.NULL, num, cert_id
)
backend.openssl_assert(res == 1)
backend.openssl_assert(num[0] != backend._ffi.NULL)
return _asn1_integer_to_int(backend, num[0])
def _hash_algorithm(backend, cert_id):
asn1obj = backend._ffi.new("ASN1_OBJECT **")
res = backend._lib.OCSP_id_get0_info(
backend._ffi.NULL, asn1obj,
backend._ffi.NULL, backend._ffi.NULL, cert_id
)
backend.openssl_assert(res == 1)
backend.openssl_assert(asn1obj[0] != backend._ffi.NULL)
oid = _obj2txt(backend, asn1obj[0])
try:
return _OIDS_TO_HASH[oid]
except KeyError:
raise UnsupportedAlgorithm(
"Signature algorithm OID: {} not recognized".format(oid)
)
@utils.register_interface(OCSPResponse)
class _OCSPResponse(object):
def __init__(self, backend, ocsp_response):
self._backend = backend
self._ocsp_response = ocsp_response
status = self._backend._lib.OCSP_response_status(self._ocsp_response)
self._backend.openssl_assert(status in _RESPONSE_STATUS_TO_ENUM)
self._status = _RESPONSE_STATUS_TO_ENUM[status]
if self._status is OCSPResponseStatus.SUCCESSFUL:
basic = self._backend._lib.OCSP_response_get1_basic(
self._ocsp_response
)
self._backend.openssl_assert(basic != self._backend._ffi.NULL)
self._basic = self._backend._ffi.gc(
basic, self._backend._lib.OCSP_BASICRESP_free
)
self._backend.openssl_assert(
self._backend._lib.OCSP_resp_count(self._basic) == 1
)
self._single = self._backend._lib.OCSP_resp_get0(self._basic, 0)
self._backend.openssl_assert(
self._single != self._backend._ffi.NULL
)
self._cert_id = self._backend._lib.OCSP_SINGLERESP_get0_id(
self._single
)
self._backend.openssl_assert(
self._cert_id != self._backend._ffi.NULL
)
response_status = utils.read_only_property("_status")
@property
@_requires_successful_response
def signature_algorithm_oid(self):
alg = self._backend._lib.OCSP_resp_get0_tbs_sigalg(self._basic)
self._backend.openssl_assert(alg != self._backend._ffi.NULL)
oid = _obj2txt(self._backend, alg.algorithm)
return x509.ObjectIdentifier(oid)
@property
@_requires_successful_response
def signature_hash_algorithm(self):
oid = self.signature_algorithm_oid
try:
return x509._SIG_OIDS_TO_HASH[oid]
except KeyError:
raise UnsupportedAlgorithm(
"Signature algorithm OID:{} not recognized".format(oid)
)
@property
@_requires_successful_response
def signature(self):
sig = self._backend._lib.OCSP_resp_get0_signature(self._basic)
self._backend.openssl_assert(sig != self._backend._ffi.NULL)
return _asn1_string_to_bytes(self._backend, sig)
@property
@_requires_successful_response
def tbs_response_bytes(self):
respdata = self._backend._lib.OCSP_resp_get0_respdata(self._basic)
self._backend.openssl_assert(respdata != self._backend._ffi.NULL)
pp = self._backend._ffi.new("unsigned char **")
res = self._backend._lib.i2d_OCSP_RESPDATA(respdata, pp)
self._backend.openssl_assert(pp[0] != self._backend._ffi.NULL)
pp = self._backend._ffi.gc(
pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0])
)
self._backend.openssl_assert(res > 0)
return self._backend._ffi.buffer(pp[0], res)[:]
@property
@_requires_successful_response
def certificates(self):
sk_x509 = self._backend._lib.OCSP_resp_get0_certs(self._basic)
num = self._backend._lib.sk_X509_num(sk_x509)
certs = []
for i in range(num):
x509 = self._backend._lib.sk_X509_value(sk_x509, i)
self._backend.openssl_assert(x509 != self._backend._ffi.NULL)
cert = _Certificate(self._backend, x509)
# We need to keep the OCSP response that the certificate came from
# alive until the Certificate object itself goes out of scope, so
# we give it a private reference.
cert._ocsp_resp = self
certs.append(cert)
return certs
@property
@_requires_successful_response
def responder_key_hash(self):
_, asn1_string = self._responder_key_name()
if asn1_string == self._backend._ffi.NULL:
return None
else:
return _asn1_string_to_bytes(self._backend, asn1_string)
@property
@_requires_successful_response
def responder_name(self):
x509_name, _ = self._responder_key_name()
if x509_name == self._backend._ffi.NULL:
return None
else:
return _decode_x509_name(self._backend, x509_name)
def _responder_key_name(self):
asn1_string = self._backend._ffi.new("ASN1_OCTET_STRING **")
x509_name = self._backend._ffi.new("X509_NAME **")
res = self._backend._lib.OCSP_resp_get0_id(
self._basic, asn1_string, x509_name
)
self._backend.openssl_assert(res == 1)
return x509_name[0], asn1_string[0]
@property
@_requires_successful_response
def produced_at(self):
produced_at = self._backend._lib.OCSP_resp_get0_produced_at(
self._basic
)
return _parse_asn1_generalized_time(self._backend, produced_at)
@property
@_requires_successful_response
def certificate_status(self):
status = self._backend._lib.OCSP_single_get0_status(
self._single,
self._backend._ffi.NULL,
self._backend._ffi.NULL,
self._backend._ffi.NULL,
self._backend._ffi.NULL,
)
self._backend.openssl_assert(status in _CERT_STATUS_TO_ENUM)
return _CERT_STATUS_TO_ENUM[status]
@property
@_requires_successful_response
def revocation_time(self):
if self.certificate_status is not OCSPCertStatus.REVOKED:
return None
asn1_time = self._backend._ffi.new("ASN1_GENERALIZEDTIME **")
self._backend._lib.OCSP_single_get0_status(
self._single,
self._backend._ffi.NULL,
asn1_time,
self._backend._ffi.NULL,
self._backend._ffi.NULL,
)
self._backend.openssl_assert(asn1_time[0] != self._backend._ffi.NULL)
return _parse_asn1_generalized_time(self._backend, asn1_time[0])
@property
@_requires_successful_response
def revocation_reason(self):
if self.certificate_status is not OCSPCertStatus.REVOKED:
return None
reason_ptr = self._backend._ffi.new("int *")
self._backend._lib.OCSP_single_get0_status(
self._single,
reason_ptr,
self._backend._ffi.NULL,
self._backend._ffi.NULL,
self._backend._ffi.NULL,
)
# If no reason is encoded OpenSSL returns -1
if reason_ptr[0] == -1:
return None
else:
self._backend.openssl_assert(
reason_ptr[0] in _CRL_ENTRY_REASON_CODE_TO_ENUM
)
return _CRL_ENTRY_REASON_CODE_TO_ENUM[reason_ptr[0]]
@property
@_requires_successful_response
def this_update(self):
asn1_time = self._backend._ffi.new("ASN1_GENERALIZEDTIME **")
self._backend._lib.OCSP_single_get0_status(
self._single,
self._backend._ffi.NULL,
self._backend._ffi.NULL,
asn1_time,
self._backend._ffi.NULL,
)
self._backend.openssl_assert(asn1_time[0] != self._backend._ffi.NULL)
return _parse_asn1_generalized_time(self._backend, asn1_time[0])
@property
@_requires_successful_response
def next_update(self):
asn1_time = self._backend._ffi.new("ASN1_GENERALIZEDTIME **")
self._backend._lib.OCSP_single_get0_status(
self._single,
self._backend._ffi.NULL,
self._backend._ffi.NULL,
self._backend._ffi.NULL,
asn1_time,
)
if asn1_time[0] != self._backend._ffi.NULL:
return _parse_asn1_generalized_time(self._backend, asn1_time[0])
else:
return None
@property
@_requires_successful_response
def issuer_key_hash(self):
return _issuer_key_hash(self._backend, self._cert_id)
@property
@_requires_successful_response
def issuer_name_hash(self):
return _issuer_name_hash(self._backend, self._cert_id)
@property
@_requires_successful_response
def hash_algorithm(self):
return _hash_algorithm(self._backend, self._cert_id)
@property
@_requires_successful_response
def serial_number(self):
return _serial_number(self._backend, self._cert_id)
@utils.cached_property
@_requires_successful_response
def extensions(self):
return _OCSP_BASICRESP_EXT_PARSER.parse(self._backend, self._basic)
def public_bytes(self, encoding):
if encoding is not serialization.Encoding.DER:
raise ValueError(
"The only allowed encoding value is Encoding.DER"
)
bio = self._backend._create_mem_bio_gc()
res = self._backend._lib.i2d_OCSP_RESPONSE_bio(
bio, self._ocsp_response
)
self._backend.openssl_assert(res > 0)
return self._backend._read_mem_bio(bio)
@utils.register_interface(OCSPRequest)
class _OCSPRequest(object):
def __init__(self, backend, ocsp_request):
if backend._lib.OCSP_request_onereq_count(ocsp_request) > 1:
raise NotImplementedError(
'OCSP request contains more than one request'
)
self._backend = backend
self._ocsp_request = ocsp_request
self._request = self._backend._lib.OCSP_request_onereq_get0(
self._ocsp_request, 0
)
self._backend.openssl_assert(self._request != self._backend._ffi.NULL)
self._cert_id = self._backend._lib.OCSP_onereq_get0_id(self._request)
self._backend.openssl_assert(self._cert_id != self._backend._ffi.NULL)
@property
def issuer_key_hash(self):
return _issuer_key_hash(self._backend, self._cert_id)
@property
def issuer_name_hash(self):
return _issuer_name_hash(self._backend, self._cert_id)
@property
def serial_number(self):
return _serial_number(self._backend, self._cert_id)
@property
def hash_algorithm(self):
return _hash_algorithm(self._backend, self._cert_id)
@utils.cached_property
def extensions(self):
return _OCSP_REQ_EXT_PARSER.parse(self._backend, self._ocsp_request)
def public_bytes(self, encoding):
if encoding is not serialization.Encoding.DER:
raise ValueError(
"The only allowed encoding value is Encoding.DER"
)
bio = self._backend._create_mem_bio_gc()
res = self._backend._lib.i2d_OCSP_REQUEST_bio(bio, self._ocsp_request)
self._backend.openssl_assert(res > 0)
return self._backend._read_mem_bio(bio)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/poly1305.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import constant_time
_POLY1305_TAG_SIZE = 16
_POLY1305_KEY_SIZE = 32
class _Poly1305Context(object):
def __init__(self, backend, key):
self._backend = backend
key_ptr = self._backend._ffi.from_buffer(key)
# This function copies the key into OpenSSL-owned memory so we don't
# need to retain it ourselves
evp_pkey = self._backend._lib.EVP_PKEY_new_raw_private_key(
self._backend._lib.NID_poly1305,
self._backend._ffi.NULL, key_ptr, len(key)
)
self._backend.openssl_assert(evp_pkey != self._backend._ffi.NULL)
self._evp_pkey = self._backend._ffi.gc(
evp_pkey, self._backend._lib.EVP_PKEY_free
)
ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
self._backend.openssl_assert(ctx != self._backend._ffi.NULL)
self._ctx = self._backend._ffi.gc(
ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
)
res = self._backend._lib.EVP_DigestSignInit(
self._ctx, self._backend._ffi.NULL, self._backend._ffi.NULL,
self._backend._ffi.NULL, self._evp_pkey
)
self._backend.openssl_assert(res == 1)
def update(self, data):
data_ptr = self._backend._ffi.from_buffer(data)
res = self._backend._lib.EVP_DigestSignUpdate(
self._ctx, data_ptr, len(data)
)
self._backend.openssl_assert(res != 0)
def finalize(self):
buf = self._backend._ffi.new("unsigned char[]", _POLY1305_TAG_SIZE)
outlen = self._backend._ffi.new("size_t *")
res = self._backend._lib.EVP_DigestSignFinal(self._ctx, buf, outlen)
self._backend.openssl_assert(res != 0)
self._backend.openssl_assert(outlen[0] == _POLY1305_TAG_SIZE)
return self._backend._ffi.buffer(buf)[:outlen[0]]
def verify(self, tag):
mac = self.finalize()
if not constant_time.bytes_eq(mac, tag):
raise InvalidSignature("Value did not match computed tag.")
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/rsa.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import math
from cryptography import utils
from cryptography.exceptions import (
InvalidSignature, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.openssl.utils import (
_calculate_digest_and_algorithm, _check_not_prehashed,
_warn_sign_verify_deprecated
)
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import (
AsymmetricSignatureContext, AsymmetricVerificationContext, rsa
)
from cryptography.hazmat.primitives.asymmetric.padding import (
AsymmetricPadding, MGF1, OAEP, PKCS1v15, PSS, calculate_max_pss_salt_length
)
from cryptography.hazmat.primitives.asymmetric.rsa import (
RSAPrivateKeyWithSerialization, RSAPublicKeyWithSerialization
)
def _get_rsa_pss_salt_length(pss, key, hash_algorithm):
salt = pss._salt_length
if salt is MGF1.MAX_LENGTH or salt is PSS.MAX_LENGTH:
return calculate_max_pss_salt_length(key, hash_algorithm)
else:
return salt
def _enc_dec_rsa(backend, key, data, padding):
if not isinstance(padding, AsymmetricPadding):
raise TypeError("Padding must be an instance of AsymmetricPadding.")
if isinstance(padding, PKCS1v15):
padding_enum = backend._lib.RSA_PKCS1_PADDING
elif isinstance(padding, OAEP):
padding_enum = backend._lib.RSA_PKCS1_OAEP_PADDING
if not isinstance(padding._mgf, MGF1):
raise UnsupportedAlgorithm(
"Only MGF1 is supported by this backend.",
_Reasons.UNSUPPORTED_MGF
)
if not backend.rsa_padding_supported(padding):
raise UnsupportedAlgorithm(
"This combination of padding and hash algorithm is not "
"supported by this backend.",
_Reasons.UNSUPPORTED_PADDING
)
else:
raise UnsupportedAlgorithm(
"{} is not supported by this backend.".format(
padding.name
),
_Reasons.UNSUPPORTED_PADDING
)
return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding)
def _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding):
if isinstance(key, _RSAPublicKey):
init = backend._lib.EVP_PKEY_encrypt_init
crypt = backend._lib.EVP_PKEY_encrypt
else:
init = backend._lib.EVP_PKEY_decrypt_init
crypt = backend._lib.EVP_PKEY_decrypt
pkey_ctx = backend._lib.EVP_PKEY_CTX_new(
key._evp_pkey, backend._ffi.NULL
)
backend.openssl_assert(pkey_ctx != backend._ffi.NULL)
pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free)
res = init(pkey_ctx)
backend.openssl_assert(res == 1)
res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(
pkey_ctx, padding_enum)
backend.openssl_assert(res > 0)
buf_size = backend._lib.EVP_PKEY_size(key._evp_pkey)
backend.openssl_assert(buf_size > 0)
if (
isinstance(padding, OAEP) and
backend._lib.Cryptography_HAS_RSA_OAEP_MD
):
mgf1_md = backend._evp_md_non_null_from_algorithm(
padding._mgf._algorithm)
res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md)
backend.openssl_assert(res > 0)
oaep_md = backend._evp_md_non_null_from_algorithm(padding._algorithm)
res = backend._lib.EVP_PKEY_CTX_set_rsa_oaep_md(pkey_ctx, oaep_md)
backend.openssl_assert(res > 0)
if (
isinstance(padding, OAEP) and
padding._label is not None and
len(padding._label) > 0
):
# set0_rsa_oaep_label takes ownership of the char * so we need to
# copy it into some new memory
labelptr = backend._lib.OPENSSL_malloc(len(padding._label))
backend.openssl_assert(labelptr != backend._ffi.NULL)
backend._ffi.memmove(labelptr, padding._label, len(padding._label))
res = backend._lib.EVP_PKEY_CTX_set0_rsa_oaep_label(
pkey_ctx, labelptr, len(padding._label)
)
backend.openssl_assert(res == 1)
outlen = backend._ffi.new("size_t *", buf_size)
buf = backend._ffi.new("unsigned char[]", buf_size)
res = crypt(pkey_ctx, buf, outlen, data, len(data))
if res <= 0:
_handle_rsa_enc_dec_error(backend, key)
return backend._ffi.buffer(buf)[:outlen[0]]
def _handle_rsa_enc_dec_error(backend, key):
errors = backend._consume_errors()
backend.openssl_assert(errors)
backend.openssl_assert(errors[0].lib == backend._lib.ERR_LIB_RSA)
if isinstance(key, _RSAPublicKey):
backend.openssl_assert(
errors[0].reason == backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE
)
raise ValueError(
"Data too long for key size. Encrypt less data or use a "
"larger key size."
)
else:
decoding_errors = [
backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_01,
backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_02,
backend._lib.RSA_R_OAEP_DECODING_ERROR,
# Though this error looks similar to the
# RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE, this occurs on decrypts,
# rather than on encrypts
backend._lib.RSA_R_DATA_TOO_LARGE_FOR_MODULUS,
]
if backend._lib.Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR:
decoding_errors.append(backend._lib.RSA_R_PKCS_DECODING_ERROR)
backend.openssl_assert(errors[0].reason in decoding_errors)
raise ValueError("Decryption failed.")
def _rsa_sig_determine_padding(backend, key, padding, algorithm):
if not isinstance(padding, AsymmetricPadding):
raise TypeError("Expected provider of AsymmetricPadding.")
pkey_size = backend._lib.EVP_PKEY_size(key._evp_pkey)
backend.openssl_assert(pkey_size > 0)
if isinstance(padding, PKCS1v15):
padding_enum = backend._lib.RSA_PKCS1_PADDING
elif isinstance(padding, PSS):
if not isinstance(padding._mgf, MGF1):
raise UnsupportedAlgorithm(
"Only MGF1 is supported by this backend.",
_Reasons.UNSUPPORTED_MGF
)
# Size of key in bytes - 2 is the maximum
# PSS signature length (salt length is checked later)
if pkey_size - algorithm.digest_size - 2 < 0:
raise ValueError("Digest too large for key size. Use a larger "
"key or different digest.")
padding_enum = backend._lib.RSA_PKCS1_PSS_PADDING
else:
raise UnsupportedAlgorithm(
"{} is not supported by this backend.".format(padding.name),
_Reasons.UNSUPPORTED_PADDING
)
return padding_enum
def _rsa_sig_setup(backend, padding, algorithm, key, data, init_func):
padding_enum = _rsa_sig_determine_padding(backend, key, padding, algorithm)
evp_md = backend._evp_md_non_null_from_algorithm(algorithm)
pkey_ctx = backend._lib.EVP_PKEY_CTX_new(key._evp_pkey, backend._ffi.NULL)
backend.openssl_assert(pkey_ctx != backend._ffi.NULL)
pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free)
res = init_func(pkey_ctx)
backend.openssl_assert(res == 1)
res = backend._lib.EVP_PKEY_CTX_set_signature_md(pkey_ctx, evp_md)
if res == 0:
backend._consume_errors()
raise UnsupportedAlgorithm(
"{} is not supported by this backend for RSA signing.".format(
algorithm.name
),
_Reasons.UNSUPPORTED_HASH
)
res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_enum)
backend.openssl_assert(res > 0)
if isinstance(padding, PSS):
res = backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen(
pkey_ctx, _get_rsa_pss_salt_length(padding, key, algorithm)
)
backend.openssl_assert(res > 0)
mgf1_md = backend._evp_md_non_null_from_algorithm(
padding._mgf._algorithm)
res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md)
backend.openssl_assert(res > 0)
return pkey_ctx
def _rsa_sig_sign(backend, padding, algorithm, private_key, data):
pkey_ctx = _rsa_sig_setup(
backend, padding, algorithm, private_key, data,
backend._lib.EVP_PKEY_sign_init
)
buflen = backend._ffi.new("size_t *")
res = backend._lib.EVP_PKEY_sign(
pkey_ctx,
backend._ffi.NULL,
buflen,
data,
len(data)
)
backend.openssl_assert(res == 1)
buf = backend._ffi.new("unsigned char[]", buflen[0])
res = backend._lib.EVP_PKEY_sign(
pkey_ctx, buf, buflen, data, len(data))
if res != 1:
errors = backend._consume_errors()
backend.openssl_assert(errors[0].lib == backend._lib.ERR_LIB_RSA)
if (
errors[0].reason ==
backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE
):
reason = ("Salt length too long for key size. Try using "
"MAX_LENGTH instead.")
else:
backend.openssl_assert(
errors[0].reason ==
backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
)
reason = "Digest too large for key size. Use a larger key."
raise ValueError(reason)
return backend._ffi.buffer(buf)[:]
def _rsa_sig_verify(backend, padding, algorithm, public_key, signature, data):
pkey_ctx = _rsa_sig_setup(
backend, padding, algorithm, public_key, data,
backend._lib.EVP_PKEY_verify_init
)
res = backend._lib.EVP_PKEY_verify(
pkey_ctx, signature, len(signature), data, len(data)
)
# The previous call can return negative numbers in the event of an
# error. This is not a signature failure but we need to fail if it
# occurs.
backend.openssl_assert(res >= 0)
if res == 0:
backend._consume_errors()
raise InvalidSignature
@utils.register_interface(AsymmetricSignatureContext)
class _RSASignatureContext(object):
def __init__(self, backend, private_key, padding, algorithm):
self._backend = backend
self._private_key = private_key
# We now call _rsa_sig_determine_padding in _rsa_sig_setup. However
# we need to make a pointless call to it here so we maintain the
# API of erroring on init with this context if the values are invalid.
_rsa_sig_determine_padding(backend, private_key, padding, algorithm)
self._padding = padding
self._algorithm = algorithm
self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
def update(self, data):
self._hash_ctx.update(data)
def finalize(self):
return _rsa_sig_sign(
self._backend,
self._padding,
self._algorithm,
self._private_key,
self._hash_ctx.finalize()
)
@utils.register_interface(AsymmetricVerificationContext)
class _RSAVerificationContext(object):
def __init__(self, backend, public_key, signature, padding, algorithm):
self._backend = backend
self._public_key = public_key
self._signature = signature
self._padding = padding
# We now call _rsa_sig_determine_padding in _rsa_sig_setup. However
# we need to make a pointless call to it here so we maintain the
# API of erroring on init with this context if the values are invalid.
_rsa_sig_determine_padding(backend, public_key, padding, algorithm)
padding = padding
self._algorithm = algorithm
self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
def update(self, data):
self._hash_ctx.update(data)
def verify(self):
return _rsa_sig_verify(
self._backend,
self._padding,
self._algorithm,
self._public_key,
self._signature,
self._hash_ctx.finalize()
)
@utils.register_interface(RSAPrivateKeyWithSerialization)
class _RSAPrivateKey(object):
def __init__(self, backend, rsa_cdata, evp_pkey):
self._backend = backend
self._rsa_cdata = rsa_cdata
self._evp_pkey = evp_pkey
n = self._backend._ffi.new("BIGNUM **")
self._backend._lib.RSA_get0_key(
self._rsa_cdata, n, self._backend._ffi.NULL,
self._backend._ffi.NULL
)
self._backend.openssl_assert(n[0] != self._backend._ffi.NULL)
self._key_size = self._backend._lib.BN_num_bits(n[0])
key_size = utils.read_only_property("_key_size")
def signer(self, padding, algorithm):
_warn_sign_verify_deprecated()
_check_not_prehashed(algorithm)
return _RSASignatureContext(self._backend, self, padding, algorithm)
def decrypt(self, ciphertext, padding):
key_size_bytes = int(math.ceil(self.key_size / 8.0))
if key_size_bytes != len(ciphertext):
raise ValueError("Ciphertext length must be equal to key size.")
return _enc_dec_rsa(self._backend, self, ciphertext, padding)
def public_key(self):
ctx = self._backend._lib.RSAPublicKey_dup(self._rsa_cdata)
self._backend.openssl_assert(ctx != self._backend._ffi.NULL)
ctx = self._backend._ffi.gc(ctx, self._backend._lib.RSA_free)
res = self._backend._lib.RSA_blinding_on(ctx, self._backend._ffi.NULL)
self._backend.openssl_assert(res == 1)
evp_pkey = self._backend._rsa_cdata_to_evp_pkey(ctx)
return _RSAPublicKey(self._backend, ctx, evp_pkey)
def private_numbers(self):
n = self._backend._ffi.new("BIGNUM **")
e = self._backend._ffi.new("BIGNUM **")
d = self._backend._ffi.new("BIGNUM **")
p = self._backend._ffi.new("BIGNUM **")
q = self._backend._ffi.new("BIGNUM **")
dmp1 = self._backend._ffi.new("BIGNUM **")
dmq1 = self._backend._ffi.new("BIGNUM **")
iqmp = self._backend._ffi.new("BIGNUM **")
self._backend._lib.RSA_get0_key(self._rsa_cdata, n, e, d)
self._backend.openssl_assert(n[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(e[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(d[0] != self._backend._ffi.NULL)
self._backend._lib.RSA_get0_factors(self._rsa_cdata, p, q)
self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(q[0] != self._backend._ffi.NULL)
self._backend._lib.RSA_get0_crt_params(
self._rsa_cdata, dmp1, dmq1, iqmp
)
self._backend.openssl_assert(dmp1[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(dmq1[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(iqmp[0] != self._backend._ffi.NULL)
return rsa.RSAPrivateNumbers(
p=self._backend._bn_to_int(p[0]),
q=self._backend._bn_to_int(q[0]),
d=self._backend._bn_to_int(d[0]),
dmp1=self._backend._bn_to_int(dmp1[0]),
dmq1=self._backend._bn_to_int(dmq1[0]),
iqmp=self._backend._bn_to_int(iqmp[0]),
public_numbers=rsa.RSAPublicNumbers(
e=self._backend._bn_to_int(e[0]),
n=self._backend._bn_to_int(n[0]),
)
)
def private_bytes(self, encoding, format, encryption_algorithm):
return self._backend._private_key_bytes(
encoding,
format,
encryption_algorithm,
self._evp_pkey,
self._rsa_cdata
)
def sign(self, data, padding, algorithm):
data, algorithm = _calculate_digest_and_algorithm(
self._backend, data, algorithm
)
return _rsa_sig_sign(self._backend, padding, algorithm, self, data)
@utils.register_interface(RSAPublicKeyWithSerialization)
class _RSAPublicKey(object):
def __init__(self, backend, rsa_cdata, evp_pkey):
self._backend = backend
self._rsa_cdata = rsa_cdata
self._evp_pkey = evp_pkey
n = self._backend._ffi.new("BIGNUM **")
self._backend._lib.RSA_get0_key(
self._rsa_cdata, n, self._backend._ffi.NULL,
self._backend._ffi.NULL
)
self._backend.openssl_assert(n[0] != self._backend._ffi.NULL)
self._key_size = self._backend._lib.BN_num_bits(n[0])
key_size = utils.read_only_property("_key_size")
def verifier(self, signature, padding, algorithm):
_warn_sign_verify_deprecated()
utils._check_bytes("signature", signature)
_check_not_prehashed(algorithm)
return _RSAVerificationContext(
self._backend, self, signature, padding, algorithm
)
def encrypt(self, plaintext, padding):
return _enc_dec_rsa(self._backend, self, plaintext, padding)
def public_numbers(self):
n = self._backend._ffi.new("BIGNUM **")
e = self._backend._ffi.new("BIGNUM **")
self._backend._lib.RSA_get0_key(
self._rsa_cdata, n, e, self._backend._ffi.NULL
)
self._backend.openssl_assert(n[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(e[0] != self._backend._ffi.NULL)
return rsa.RSAPublicNumbers(
e=self._backend._bn_to_int(e[0]),
n=self._backend._bn_to_int(n[0]),
)
def public_bytes(self, encoding, format):
return self._backend._public_key_bytes(
encoding,
format,
self,
self._evp_pkey,
self._rsa_cdata
)
def verify(self, signature, data, padding, algorithm):
data, algorithm = _calculate_digest_and_algorithm(
self._backend, data, algorithm
)
return _rsa_sig_verify(
self._backend, padding, algorithm, self, signature, data
)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/utils.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import warnings
from cryptography import utils
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric.utils import Prehashed
def _evp_pkey_derive(backend, evp_pkey, peer_public_key):
ctx = backend._lib.EVP_PKEY_CTX_new(evp_pkey, backend._ffi.NULL)
backend.openssl_assert(ctx != backend._ffi.NULL)
ctx = backend._ffi.gc(ctx, backend._lib.EVP_PKEY_CTX_free)
res = backend._lib.EVP_PKEY_derive_init(ctx)
backend.openssl_assert(res == 1)
res = backend._lib.EVP_PKEY_derive_set_peer(
ctx, peer_public_key._evp_pkey
)
backend.openssl_assert(res == 1)
keylen = backend._ffi.new("size_t *")
res = backend._lib.EVP_PKEY_derive(ctx, backend._ffi.NULL, keylen)
backend.openssl_assert(res == 1)
backend.openssl_assert(keylen[0] > 0)
buf = backend._ffi.new("unsigned char[]", keylen[0])
res = backend._lib.EVP_PKEY_derive(ctx, buf, keylen)
if res != 1:
raise ValueError(
"Null shared key derived from public/private pair."
)
return backend._ffi.buffer(buf, keylen[0])[:]
def _calculate_digest_and_algorithm(backend, data, algorithm):
if not isinstance(algorithm, Prehashed):
hash_ctx = hashes.Hash(algorithm, backend)
hash_ctx.update(data)
data = hash_ctx.finalize()
else:
algorithm = algorithm._algorithm
if len(data) != algorithm.digest_size:
raise ValueError(
"The provided data must be the same length as the hash "
"algorithm's digest size."
)
return (data, algorithm)
def _check_not_prehashed(signature_algorithm):
if isinstance(signature_algorithm, Prehashed):
raise TypeError(
"Prehashed is only supported in the sign and verify methods. "
"It cannot be used with signer or verifier."
)
def _warn_sign_verify_deprecated():
warnings.warn(
"signer and verifier have been deprecated. Please use sign "
"and verify instead.",
utils.PersistentlyDeprecated2017,
stacklevel=3
)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/x25519.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import warnings
from cryptography import utils
from cryptography.hazmat.backends.openssl.utils import _evp_pkey_derive
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.x25519 import (
X25519PrivateKey, X25519PublicKey
)
_X25519_KEY_SIZE = 32
@utils.register_interface(X25519PublicKey)
class _X25519PublicKey(object):
def __init__(self, backend, evp_pkey):
self._backend = backend
self._evp_pkey = evp_pkey
def public_bytes(self, encoding=None, format=None):
if encoding is None or format is None:
if encoding is not None or format is not None:
raise ValueError("Both encoding and format are required")
else:
warnings.warn(
"public_bytes now requires encoding and format arguments. "
"Support for calling without arguments will be removed in "
"cryptography 2.7",
utils.DeprecatedIn25,
)
encoding = serialization.Encoding.Raw
format = serialization.PublicFormat.Raw
if (
encoding is serialization.Encoding.Raw or
format is serialization.PublicFormat.Raw
):
if (
encoding is not serialization.Encoding.Raw or
format is not serialization.PublicFormat.Raw
):
raise ValueError(
"When using Raw both encoding and format must be Raw"
)
return self._raw_public_bytes()
if (
encoding in serialization._PEM_DER and
format is not serialization.PublicFormat.SubjectPublicKeyInfo
):
raise ValueError(
"format must be SubjectPublicKeyInfo when encoding is PEM or "
"DER"
)
return self._backend._public_key_bytes(
encoding, format, self, self._evp_pkey, None
)
def _raw_public_bytes(self):
ucharpp = self._backend._ffi.new("unsigned char **")
res = self._backend._lib.EVP_PKEY_get1_tls_encodedpoint(
self._evp_pkey, ucharpp
)
self._backend.openssl_assert(res == 32)
self._backend.openssl_assert(ucharpp[0] != self._backend._ffi.NULL)
data = self._backend._ffi.gc(
ucharpp[0], self._backend._lib.OPENSSL_free
)
return self._backend._ffi.buffer(data, res)[:]
@utils.register_interface(X25519PrivateKey)
class _X25519PrivateKey(object):
def __init__(self, backend, evp_pkey):
self._backend = backend
self._evp_pkey = evp_pkey
def public_key(self):
bio = self._backend._create_mem_bio_gc()
res = self._backend._lib.i2d_PUBKEY_bio(bio, self._evp_pkey)
self._backend.openssl_assert(res == 1)
evp_pkey = self._backend._lib.d2i_PUBKEY_bio(
bio, self._backend._ffi.NULL
)
self._backend.openssl_assert(evp_pkey != self._backend._ffi.NULL)
evp_pkey = self._backend._ffi.gc(
evp_pkey, self._backend._lib.EVP_PKEY_free
)
return _X25519PublicKey(self._backend, evp_pkey)
def exchange(self, peer_public_key):
if not isinstance(peer_public_key, X25519PublicKey):
raise TypeError("peer_public_key must be X25519PublicKey.")
return _evp_pkey_derive(
self._backend, self._evp_pkey, peer_public_key
)
def private_bytes(self, encoding, format, encryption_algorithm):
if (
encoding is serialization.Encoding.Raw or
format is serialization.PublicFormat.Raw
):
if (
format is not serialization.PrivateFormat.Raw or
encoding is not serialization.Encoding.Raw or not
isinstance(encryption_algorithm, serialization.NoEncryption)
):
raise ValueError(
"When using Raw both encoding and format must be Raw "
"and encryption_algorithm must be NoEncryption()"
)
return self._raw_private_bytes()
if (
encoding in serialization._PEM_DER and
format is not serialization.PrivateFormat.PKCS8
):
raise ValueError(
"format must be PKCS8 when encoding is PEM or DER"
)
return self._backend._private_key_bytes(
encoding, format, encryption_algorithm, self._evp_pkey, None
)
def _raw_private_bytes(self):
# When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can
# switch this to EVP_PKEY_new_raw_private_key
# The trick we use here is serializing to a PKCS8 key and just
# using the last 32 bytes, which is the key itself.
bio = self._backend._create_mem_bio_gc()
res = self._backend._lib.i2d_PKCS8PrivateKey_bio(
bio, self._evp_pkey,
self._backend._ffi.NULL, self._backend._ffi.NULL,
0, self._backend._ffi.NULL, self._backend._ffi.NULL
)
self._backend.openssl_assert(res == 1)
pkcs8 = self._backend._read_mem_bio(bio)
self._backend.openssl_assert(len(pkcs8) == 48)
return pkcs8[-_X25519_KEY_SIZE:]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/x448.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.hazmat.backends.openssl.utils import _evp_pkey_derive
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.x448 import (
X448PrivateKey, X448PublicKey
)
_X448_KEY_SIZE = 56
@utils.register_interface(X448PublicKey)
class _X448PublicKey(object):
def __init__(self, backend, evp_pkey):
self._backend = backend
self._evp_pkey = evp_pkey
def public_bytes(self, encoding, format):
if (
encoding is serialization.Encoding.Raw or
format is serialization.PublicFormat.Raw
):
if (
encoding is not serialization.Encoding.Raw or
format is not serialization.PublicFormat.Raw
):
raise ValueError(
"When using Raw both encoding and format must be Raw"
)
return self._raw_public_bytes()
if (
encoding in serialization._PEM_DER and
format is not serialization.PublicFormat.SubjectPublicKeyInfo
):
raise ValueError(
"format must be SubjectPublicKeyInfo when encoding is PEM or "
"DER"
)
return self._backend._public_key_bytes(
encoding, format, self, self._evp_pkey, None
)
def _raw_public_bytes(self):
buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE)
buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE)
res = self._backend._lib.EVP_PKEY_get_raw_public_key(
self._evp_pkey, buf, buflen
)
self._backend.openssl_assert(res == 1)
self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE)
return self._backend._ffi.buffer(buf, _X448_KEY_SIZE)[:]
@utils.register_interface(X448PrivateKey)
class _X448PrivateKey(object):
def __init__(self, backend, evp_pkey):
self._backend = backend
self._evp_pkey = evp_pkey
def public_key(self):
buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE)
buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE)
res = self._backend._lib.EVP_PKEY_get_raw_public_key(
self._evp_pkey, buf, buflen
)
self._backend.openssl_assert(res == 1)
self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE)
return self._backend.x448_load_public_bytes(buf)
def exchange(self, peer_public_key):
if not isinstance(peer_public_key, X448PublicKey):
raise TypeError("peer_public_key must be X448PublicKey.")
return _evp_pkey_derive(
self._backend, self._evp_pkey, peer_public_key
)
def private_bytes(self, encoding, format, encryption_algorithm):
if (
encoding is serialization.Encoding.Raw or
format is serialization.PublicFormat.Raw
):
if (
format is not serialization.PrivateFormat.Raw or
encoding is not serialization.Encoding.Raw or not
isinstance(encryption_algorithm, serialization.NoEncryption)
):
raise ValueError(
"When using Raw both encoding and format must be Raw "
"and encryption_algorithm must be NoEncryption()"
)
return self._raw_private_bytes()
if (
encoding in serialization._PEM_DER and
format is not serialization.PrivateFormat.PKCS8
):
raise ValueError(
"format must be PKCS8 when encoding is PEM or DER"
)
return self._backend._private_key_bytes(
encoding, format, encryption_algorithm, self._evp_pkey, None
)
def _raw_private_bytes(self):
buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE)
buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE)
res = self._backend._lib.EVP_PKEY_get_raw_private_key(
self._evp_pkey, buf, buflen
)
self._backend.openssl_assert(res == 1)
self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE)
return self._backend._ffi.buffer(buf, _X448_KEY_SIZE)[:]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/x509.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import datetime
import operator
from cryptography import utils, x509
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.backends.openssl.decode_asn1 import (
_CERTIFICATE_EXTENSION_PARSER, _CERTIFICATE_EXTENSION_PARSER_NO_SCT,
_CRL_EXTENSION_PARSER, _CSR_EXTENSION_PARSER,
_REVOKED_CERTIFICATE_EXTENSION_PARSER, _asn1_integer_to_int,
_asn1_string_to_bytes, _decode_x509_name, _obj2txt, _parse_asn1_time
)
from cryptography.hazmat.backends.openssl.encode_asn1 import (
_encode_asn1_int_gc
)
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
@utils.register_interface(x509.Certificate)
class _Certificate(object):
def __init__(self, backend, x509):
self._backend = backend
self._x509 = x509
def __repr__(self):
return "".format(self.subject)
def __eq__(self, other):
if not isinstance(other, x509.Certificate):
return NotImplemented
res = self._backend._lib.X509_cmp(self._x509, other._x509)
return res == 0
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.public_bytes(serialization.Encoding.DER))
def fingerprint(self, algorithm):
h = hashes.Hash(algorithm, self._backend)
h.update(self.public_bytes(serialization.Encoding.DER))
return h.finalize()
@property
def version(self):
version = self._backend._lib.X509_get_version(self._x509)
if version == 0:
return x509.Version.v1
elif version == 2:
return x509.Version.v3
else:
raise x509.InvalidVersion(
"{} is not a valid X509 version".format(version), version
)
@property
def serial_number(self):
asn1_int = self._backend._lib.X509_get_serialNumber(self._x509)
self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL)
return _asn1_integer_to_int(self._backend, asn1_int)
def public_key(self):
pkey = self._backend._lib.X509_get_pubkey(self._x509)
if pkey == self._backend._ffi.NULL:
# Remove errors from the stack.
self._backend._consume_errors()
raise ValueError("Certificate public key is of an unknown type")
pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free)
return self._backend._evp_pkey_to_public_key(pkey)
@property
def not_valid_before(self):
asn1_time = self._backend._lib.X509_getm_notBefore(self._x509)
return _parse_asn1_time(self._backend, asn1_time)
@property
def not_valid_after(self):
asn1_time = self._backend._lib.X509_getm_notAfter(self._x509)
return _parse_asn1_time(self._backend, asn1_time)
@property
def issuer(self):
issuer = self._backend._lib.X509_get_issuer_name(self._x509)
self._backend.openssl_assert(issuer != self._backend._ffi.NULL)
return _decode_x509_name(self._backend, issuer)
@property
def subject(self):
subject = self._backend._lib.X509_get_subject_name(self._x509)
self._backend.openssl_assert(subject != self._backend._ffi.NULL)
return _decode_x509_name(self._backend, subject)
@property
def signature_hash_algorithm(self):
oid = self.signature_algorithm_oid
try:
return x509._SIG_OIDS_TO_HASH[oid]
except KeyError:
raise UnsupportedAlgorithm(
"Signature algorithm OID:{} not recognized".format(oid)
)
@property
def signature_algorithm_oid(self):
alg = self._backend._ffi.new("X509_ALGOR **")
self._backend._lib.X509_get0_signature(
self._backend._ffi.NULL, alg, self._x509
)
self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL)
oid = _obj2txt(self._backend, alg[0].algorithm)
return x509.ObjectIdentifier(oid)
@utils.cached_property
def extensions(self):
if self._backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER:
return _CERTIFICATE_EXTENSION_PARSER.parse(
self._backend, self._x509
)
else:
return _CERTIFICATE_EXTENSION_PARSER_NO_SCT.parse(
self._backend, self._x509
)
@property
def signature(self):
sig = self._backend._ffi.new("ASN1_BIT_STRING **")
self._backend._lib.X509_get0_signature(
sig, self._backend._ffi.NULL, self._x509
)
self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL)
return _asn1_string_to_bytes(self._backend, sig[0])
@property
def tbs_certificate_bytes(self):
pp = self._backend._ffi.new("unsigned char **")
res = self._backend._lib.i2d_re_X509_tbs(self._x509, pp)
self._backend.openssl_assert(res > 0)
pp = self._backend._ffi.gc(
pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0])
)
return self._backend._ffi.buffer(pp[0], res)[:]
def public_bytes(self, encoding):
bio = self._backend._create_mem_bio_gc()
if encoding is serialization.Encoding.PEM:
res = self._backend._lib.PEM_write_bio_X509(bio, self._x509)
elif encoding is serialization.Encoding.DER:
res = self._backend._lib.i2d_X509_bio(bio, self._x509)
else:
raise TypeError("encoding must be an item from the Encoding enum")
self._backend.openssl_assert(res == 1)
return self._backend._read_mem_bio(bio)
@utils.register_interface(x509.RevokedCertificate)
class _RevokedCertificate(object):
def __init__(self, backend, crl, x509_revoked):
self._backend = backend
# The X509_REVOKED_value is a X509_REVOKED * that has
# no reference counting. This means when X509_CRL_free is
# called then the CRL and all X509_REVOKED * are freed. Since
# you can retain a reference to a single revoked certificate
# and let the CRL fall out of scope we need to retain a
# private reference to the CRL inside the RevokedCertificate
# object to prevent the gc from being called inappropriately.
self._crl = crl
self._x509_revoked = x509_revoked
@property
def serial_number(self):
asn1_int = self._backend._lib.X509_REVOKED_get0_serialNumber(
self._x509_revoked
)
self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL)
return _asn1_integer_to_int(self._backend, asn1_int)
@property
def revocation_date(self):
return _parse_asn1_time(
self._backend,
self._backend._lib.X509_REVOKED_get0_revocationDate(
self._x509_revoked
)
)
@utils.cached_property
def extensions(self):
return _REVOKED_CERTIFICATE_EXTENSION_PARSER.parse(
self._backend, self._x509_revoked
)
@utils.register_interface(x509.CertificateRevocationList)
class _CertificateRevocationList(object):
def __init__(self, backend, x509_crl):
self._backend = backend
self._x509_crl = x509_crl
def __eq__(self, other):
if not isinstance(other, x509.CertificateRevocationList):
return NotImplemented
res = self._backend._lib.X509_CRL_cmp(self._x509_crl, other._x509_crl)
return res == 0
def __ne__(self, other):
return not self == other
def fingerprint(self, algorithm):
h = hashes.Hash(algorithm, self._backend)
bio = self._backend._create_mem_bio_gc()
res = self._backend._lib.i2d_X509_CRL_bio(
bio, self._x509_crl
)
self._backend.openssl_assert(res == 1)
der = self._backend._read_mem_bio(bio)
h.update(der)
return h.finalize()
@utils.cached_property
def _sorted_crl(self):
# X509_CRL_get0_by_serial sorts in place, which breaks a variety of
# things we don't want to break (like iteration and the signature).
# Let's dupe it and sort that instead.
dup = self._backend._lib.X509_CRL_dup(self._x509_crl)
self._backend.openssl_assert(dup != self._backend._ffi.NULL)
dup = self._backend._ffi.gc(dup, self._backend._lib.X509_CRL_free)
return dup
def get_revoked_certificate_by_serial_number(self, serial_number):
revoked = self._backend._ffi.new("X509_REVOKED **")
asn1_int = _encode_asn1_int_gc(self._backend, serial_number)
res = self._backend._lib.X509_CRL_get0_by_serial(
self._sorted_crl, revoked, asn1_int
)
if res == 0:
return None
else:
self._backend.openssl_assert(
revoked[0] != self._backend._ffi.NULL
)
return _RevokedCertificate(
self._backend, self._sorted_crl, revoked[0]
)
@property
def signature_hash_algorithm(self):
oid = self.signature_algorithm_oid
try:
return x509._SIG_OIDS_TO_HASH[oid]
except KeyError:
raise UnsupportedAlgorithm(
"Signature algorithm OID:{} not recognized".format(oid)
)
@property
def signature_algorithm_oid(self):
alg = self._backend._ffi.new("X509_ALGOR **")
self._backend._lib.X509_CRL_get0_signature(
self._x509_crl, self._backend._ffi.NULL, alg
)
self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL)
oid = _obj2txt(self._backend, alg[0].algorithm)
return x509.ObjectIdentifier(oid)
@property
def issuer(self):
issuer = self._backend._lib.X509_CRL_get_issuer(self._x509_crl)
self._backend.openssl_assert(issuer != self._backend._ffi.NULL)
return _decode_x509_name(self._backend, issuer)
@property
def next_update(self):
nu = self._backend._lib.X509_CRL_get_nextUpdate(self._x509_crl)
self._backend.openssl_assert(nu != self._backend._ffi.NULL)
return _parse_asn1_time(self._backend, nu)
@property
def last_update(self):
lu = self._backend._lib.X509_CRL_get_lastUpdate(self._x509_crl)
self._backend.openssl_assert(lu != self._backend._ffi.NULL)
return _parse_asn1_time(self._backend, lu)
@property
def signature(self):
sig = self._backend._ffi.new("ASN1_BIT_STRING **")
self._backend._lib.X509_CRL_get0_signature(
self._x509_crl, sig, self._backend._ffi.NULL
)
self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL)
return _asn1_string_to_bytes(self._backend, sig[0])
@property
def tbs_certlist_bytes(self):
pp = self._backend._ffi.new("unsigned char **")
res = self._backend._lib.i2d_re_X509_CRL_tbs(self._x509_crl, pp)
self._backend.openssl_assert(res > 0)
pp = self._backend._ffi.gc(
pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0])
)
return self._backend._ffi.buffer(pp[0], res)[:]
def public_bytes(self, encoding):
bio = self._backend._create_mem_bio_gc()
if encoding is serialization.Encoding.PEM:
res = self._backend._lib.PEM_write_bio_X509_CRL(
bio, self._x509_crl
)
elif encoding is serialization.Encoding.DER:
res = self._backend._lib.i2d_X509_CRL_bio(bio, self._x509_crl)
else:
raise TypeError("encoding must be an item from the Encoding enum")
self._backend.openssl_assert(res == 1)
return self._backend._read_mem_bio(bio)
def _revoked_cert(self, idx):
revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl)
r = self._backend._lib.sk_X509_REVOKED_value(revoked, idx)
self._backend.openssl_assert(r != self._backend._ffi.NULL)
return _RevokedCertificate(self._backend, self, r)
def __iter__(self):
for i in range(len(self)):
yield self._revoked_cert(i)
def __getitem__(self, idx):
if isinstance(idx, slice):
start, stop, step = idx.indices(len(self))
return [self._revoked_cert(i) for i in range(start, stop, step)]
else:
idx = operator.index(idx)
if idx < 0:
idx += len(self)
if not 0 <= idx < len(self):
raise IndexError
return self._revoked_cert(idx)
def __len__(self):
revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl)
if revoked == self._backend._ffi.NULL:
return 0
else:
return self._backend._lib.sk_X509_REVOKED_num(revoked)
@utils.cached_property
def extensions(self):
return _CRL_EXTENSION_PARSER.parse(self._backend, self._x509_crl)
def is_signature_valid(self, public_key):
if not isinstance(public_key, (dsa.DSAPublicKey, rsa.RSAPublicKey,
ec.EllipticCurvePublicKey)):
raise TypeError('Expecting one of DSAPublicKey, RSAPublicKey,'
' or EllipticCurvePublicKey.')
res = self._backend._lib.X509_CRL_verify(
self._x509_crl, public_key._evp_pkey
)
if res != 1:
self._backend._consume_errors()
return False
return True
@utils.register_interface(x509.CertificateSigningRequest)
class _CertificateSigningRequest(object):
def __init__(self, backend, x509_req):
self._backend = backend
self._x509_req = x509_req
def __eq__(self, other):
if not isinstance(other, _CertificateSigningRequest):
return NotImplemented
self_bytes = self.public_bytes(serialization.Encoding.DER)
other_bytes = other.public_bytes(serialization.Encoding.DER)
return self_bytes == other_bytes
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.public_bytes(serialization.Encoding.DER))
def public_key(self):
pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req)
self._backend.openssl_assert(pkey != self._backend._ffi.NULL)
pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free)
return self._backend._evp_pkey_to_public_key(pkey)
@property
def subject(self):
subject = self._backend._lib.X509_REQ_get_subject_name(self._x509_req)
self._backend.openssl_assert(subject != self._backend._ffi.NULL)
return _decode_x509_name(self._backend, subject)
@property
def signature_hash_algorithm(self):
oid = self.signature_algorithm_oid
try:
return x509._SIG_OIDS_TO_HASH[oid]
except KeyError:
raise UnsupportedAlgorithm(
"Signature algorithm OID:{} not recognized".format(oid)
)
@property
def signature_algorithm_oid(self):
alg = self._backend._ffi.new("X509_ALGOR **")
self._backend._lib.X509_REQ_get0_signature(
self._x509_req, self._backend._ffi.NULL, alg
)
self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL)
oid = _obj2txt(self._backend, alg[0].algorithm)
return x509.ObjectIdentifier(oid)
@utils.cached_property
def extensions(self):
x509_exts = self._backend._lib.X509_REQ_get_extensions(self._x509_req)
x509_exts = self._backend._ffi.gc(
x509_exts,
lambda x: self._backend._lib.sk_X509_EXTENSION_pop_free(
x, self._backend._ffi.addressof(
self._backend._lib._original_lib, "X509_EXTENSION_free"
)
)
)
return _CSR_EXTENSION_PARSER.parse(self._backend, x509_exts)
def public_bytes(self, encoding):
bio = self._backend._create_mem_bio_gc()
if encoding is serialization.Encoding.PEM:
res = self._backend._lib.PEM_write_bio_X509_REQ(
bio, self._x509_req
)
elif encoding is serialization.Encoding.DER:
res = self._backend._lib.i2d_X509_REQ_bio(bio, self._x509_req)
else:
raise TypeError("encoding must be an item from the Encoding enum")
self._backend.openssl_assert(res == 1)
return self._backend._read_mem_bio(bio)
@property
def tbs_certrequest_bytes(self):
pp = self._backend._ffi.new("unsigned char **")
res = self._backend._lib.i2d_re_X509_REQ_tbs(self._x509_req, pp)
self._backend.openssl_assert(res > 0)
pp = self._backend._ffi.gc(
pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0])
)
return self._backend._ffi.buffer(pp[0], res)[:]
@property
def signature(self):
sig = self._backend._ffi.new("ASN1_BIT_STRING **")
self._backend._lib.X509_REQ_get0_signature(
self._x509_req, sig, self._backend._ffi.NULL
)
self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL)
return _asn1_string_to_bytes(self._backend, sig[0])
@property
def is_signature_valid(self):
pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req)
self._backend.openssl_assert(pkey != self._backend._ffi.NULL)
pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free)
res = self._backend._lib.X509_REQ_verify(self._x509_req, pkey)
if res != 1:
self._backend._consume_errors()
return False
return True
@utils.register_interface(
x509.certificate_transparency.SignedCertificateTimestamp
)
class _SignedCertificateTimestamp(object):
def __init__(self, backend, sct_list, sct):
self._backend = backend
# Keep the SCT_LIST that this SCT came from alive.
self._sct_list = sct_list
self._sct = sct
@property
def version(self):
version = self._backend._lib.SCT_get_version(self._sct)
assert version == self._backend._lib.SCT_VERSION_V1
return x509.certificate_transparency.Version.v1
@property
def log_id(self):
out = self._backend._ffi.new("unsigned char **")
log_id_length = self._backend._lib.SCT_get0_log_id(self._sct, out)
assert log_id_length >= 0
return self._backend._ffi.buffer(out[0], log_id_length)[:]
@property
def timestamp(self):
timestamp = self._backend._lib.SCT_get_timestamp(self._sct)
milliseconds = timestamp % 1000
return datetime.datetime.utcfromtimestamp(
timestamp // 1000
).replace(microsecond=milliseconds * 1000)
@property
def entry_type(self):
entry_type = self._backend._lib.SCT_get_log_entry_type(self._sct)
# We currently only support loading SCTs from the X.509 extension, so
# we only have precerts.
assert entry_type == self._backend._lib.CT_LOG_ENTRY_TYPE_PRECERT
return x509.certificate_transparency.LogEntryType.PRE_CERTIFICATE
@property
def _signature(self):
ptrptr = self._backend._ffi.new("unsigned char **")
res = self._backend._lib.SCT_get0_signature(self._sct, ptrptr)
self._backend.openssl_assert(res > 0)
self._backend.openssl_assert(ptrptr[0] != self._backend._ffi.NULL)
return self._backend._ffi.buffer(ptrptr[0], res)[:]
def __hash__(self):
return hash(self._signature)
def __eq__(self, other):
if not isinstance(other, _SignedCertificateTimestamp):
return NotImplemented
return self._signature == other._signature
def __ne__(self, other):
return not self == other
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/bindings/__init__.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/bindings/openssl/__init__.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
def cryptography_has_ec2m():
return [
"EC_POINT_set_affine_coordinates_GF2m",
"EC_POINT_get_affine_coordinates_GF2m",
"EC_POINT_set_compressed_coordinates_GF2m",
]
def cryptography_has_ec_1_0_2():
return [
"EC_curve_nid2nist",
]
def cryptography_has_set_ecdh_auto():
return [
"SSL_CTX_set_ecdh_auto",
]
def cryptography_has_rsa_r_pkcs_decoding_error():
return [
"RSA_R_PKCS_DECODING_ERROR"
]
def cryptography_has_rsa_oaep_md():
return [
"EVP_PKEY_CTX_set_rsa_oaep_md",
]
def cryptography_has_rsa_oaep_label():
return [
"EVP_PKEY_CTX_set0_rsa_oaep_label",
]
def cryptography_has_ssl3_method():
return [
"SSLv3_method",
"SSLv3_client_method",
"SSLv3_server_method",
]
def cryptography_has_alpn():
return [
"SSL_CTX_set_alpn_protos",
"SSL_set_alpn_protos",
"SSL_CTX_set_alpn_select_cb",
"SSL_get0_alpn_selected",
]
def cryptography_has_compression():
return [
"SSL_get_current_compression",
"SSL_get_current_expansion",
"SSL_COMP_get_name",
]
def cryptography_has_get_server_tmp_key():
return [
"SSL_get_server_tmp_key",
]
def cryptography_has_102_verification_error_codes():
return [
'X509_V_ERR_SUITE_B_INVALID_VERSION',
'X509_V_ERR_SUITE_B_INVALID_ALGORITHM',
'X509_V_ERR_SUITE_B_INVALID_CURVE',
'X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM',
'X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED',
'X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256',
'X509_V_ERR_HOSTNAME_MISMATCH',
'X509_V_ERR_EMAIL_MISMATCH',
'X509_V_ERR_IP_ADDRESS_MISMATCH'
]
def cryptography_has_102_verification_params():
return [
"X509_V_FLAG_SUITEB_128_LOS_ONLY",
"X509_V_FLAG_SUITEB_192_LOS",
"X509_V_FLAG_SUITEB_128_LOS",
"X509_VERIFY_PARAM_set1_host",
"X509_VERIFY_PARAM_set1_email",
"X509_VERIFY_PARAM_set1_ip",
"X509_VERIFY_PARAM_set1_ip_asc",
"X509_VERIFY_PARAM_set_hostflags",
"SSL_get0_param",
"X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT",
"X509_CHECK_FLAG_NO_WILDCARDS",
"X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS",
"X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS",
"X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS"
]
def cryptography_has_110_verification_params():
return [
"X509_CHECK_FLAG_NEVER_CHECK_SUBJECT"
]
def cryptography_has_x509_v_flag_trusted_first():
return [
"X509_V_FLAG_TRUSTED_FIRST",
]
def cryptography_has_x509_v_flag_partial_chain():
return [
"X509_V_FLAG_PARTIAL_CHAIN",
]
def cryptography_has_set_cert_cb():
return [
"SSL_CTX_set_cert_cb",
"SSL_set_cert_cb",
]
def cryptography_has_ssl_st():
return [
"SSL_ST_BEFORE",
"SSL_ST_OK",
"SSL_ST_INIT",
"SSL_ST_RENEGOTIATE",
]
def cryptography_has_tls_st():
return [
"TLS_ST_BEFORE",
"TLS_ST_OK",
]
def cryptography_has_locking_callbacks():
return [
"Cryptography_setup_ssl_threads",
]
def cryptography_has_scrypt():
return [
"EVP_PBE_scrypt",
]
def cryptography_has_generic_dtls_method():
return [
"DTLS_method",
"DTLS_server_method",
"DTLS_client_method",
"SSL_OP_NO_DTLSv1",
"SSL_OP_NO_DTLSv1_2",
"DTLS_set_link_mtu",
"DTLS_get_link_min_mtu",
]
def cryptography_has_evp_pkey_dhx():
return [
"EVP_PKEY_DHX",
]
def cryptography_has_mem_functions():
return [
"Cryptography_CRYPTO_set_mem_functions",
]
def cryptography_has_sct():
return [
"SCT_get_version",
"SCT_get_log_entry_type",
"SCT_get0_log_id",
"SCT_get0_signature",
"SCT_get_timestamp",
"SCT_set_source",
"sk_SCT_num",
"sk_SCT_value",
"SCT_LIST_free",
"sk_SCT_push",
"sk_SCT_new_null",
"SCT_new",
"SCT_set1_log_id",
"SCT_set_timestamp",
"SCT_set_version",
"SCT_set_log_entry_type",
]
def cryptography_has_x509_store_ctx_get_issuer():
return [
"X509_STORE_get_get_issuer",
"X509_STORE_set_get_issuer",
]
def cryptography_has_x25519():
return [
"EVP_PKEY_X25519",
"NID_X25519",
]
def cryptography_has_x448():
return [
"EVP_PKEY_X448",
"NID_X448",
]
def cryptography_has_ed448():
return [
"EVP_PKEY_ED448",
"NID_ED448",
]
def cryptography_has_ed25519():
return [
"NID_ED25519",
"EVP_PKEY_ED25519",
]
def cryptography_has_poly1305():
return [
"NID_poly1305",
"EVP_PKEY_POLY1305",
]
def cryptography_has_oneshot_evp_digest_sign_verify():
return [
"EVP_DigestSign",
"EVP_DigestVerify",
]
def cryptography_has_evp_digestfinal_xof():
return [
"EVP_DigestFinalXOF",
]
def cryptography_has_evp_pkey_get_set_tls_encodedpoint():
return [
"EVP_PKEY_get1_tls_encodedpoint",
"EVP_PKEY_set1_tls_encodedpoint",
]
def cryptography_has_fips():
return [
"FIPS_mode_set",
"FIPS_mode",
]
def cryptography_has_ssl_sigalgs():
return [
"SSL_CTX_set1_sigalgs_list",
"SSL_get_sigalgs",
]
def cryptography_has_psk():
return [
"SSL_CTX_use_psk_identity_hint",
"SSL_CTX_set_psk_server_callback",
"SSL_CTX_set_psk_client_callback",
]
def cryptography_has_custom_ext():
return [
"SSL_CTX_add_client_custom_ext",
"SSL_CTX_add_server_custom_ext",
"SSL_extension_supported",
]
def cryptography_has_openssl_cleanup():
return [
"OPENSSL_cleanup",
]
def cryptography_has_cipher_details():
return [
"SSL_CIPHER_is_aead",
"SSL_CIPHER_get_cipher_nid",
"SSL_CIPHER_get_digest_nid",
"SSL_CIPHER_get_kx_nid",
"SSL_CIPHER_get_auth_nid",
]
def cryptography_has_tlsv13():
return [
"SSL_OP_NO_TLSv1_3",
"SSL_VERIFY_POST_HANDSHAKE",
"SSL_CTX_set_ciphersuites",
"SSL_verify_client_post_handshake",
"SSL_CTX_set_post_handshake_auth",
"SSL_set_post_handshake_auth",
"SSL_SESSION_get_max_early_data",
"SSL_write_early_data",
"SSL_read_early_data",
"SSL_CTX_set_max_early_data",
]
def cryptography_has_raw_key():
return [
"EVP_PKEY_new_raw_private_key",
"EVP_PKEY_new_raw_public_key",
"EVP_PKEY_get_raw_private_key",
"EVP_PKEY_get_raw_public_key",
]
def cryptography_has_evp_r_memory_limit_exceeded():
return [
"EVP_R_MEMORY_LIMIT_EXCEEDED",
]
def cryptography_has_engine():
return [
"ENGINE_by_id",
"ENGINE_init",
"ENGINE_finish",
"ENGINE_get_default_RAND",
"ENGINE_set_default_RAND",
"ENGINE_unregister_RAND",
"ENGINE_ctrl_cmd",
"ENGINE_free",
"ENGINE_get_name",
"Cryptography_add_osrandom_engine",
]
def cryptography_has_verified_chain():
return [
"SSL_get0_verified_chain",
]
# This is a mapping of
# {condition: function-returning-names-dependent-on-that-condition} so we can
# loop over them and delete unsupported names at runtime. It will be removed
# when cffi supports #if in cdef. We use functions instead of just a dict of
# lists so we can use coverage to measure which are used.
CONDITIONAL_NAMES = {
"Cryptography_HAS_EC2M": cryptography_has_ec2m,
"Cryptography_HAS_EC_1_0_2": cryptography_has_ec_1_0_2,
"Cryptography_HAS_SET_ECDH_AUTO": cryptography_has_set_ecdh_auto,
"Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR": (
cryptography_has_rsa_r_pkcs_decoding_error
),
"Cryptography_HAS_RSA_OAEP_MD": cryptography_has_rsa_oaep_md,
"Cryptography_HAS_RSA_OAEP_LABEL": cryptography_has_rsa_oaep_label,
"Cryptography_HAS_SSL3_METHOD": cryptography_has_ssl3_method,
"Cryptography_HAS_ALPN": cryptography_has_alpn,
"Cryptography_HAS_COMPRESSION": cryptography_has_compression,
"Cryptography_HAS_GET_SERVER_TMP_KEY": cryptography_has_get_server_tmp_key,
"Cryptography_HAS_102_VERIFICATION_ERROR_CODES": (
cryptography_has_102_verification_error_codes
),
"Cryptography_HAS_102_VERIFICATION_PARAMS": (
cryptography_has_102_verification_params
),
"Cryptography_HAS_110_VERIFICATION_PARAMS": (
cryptography_has_110_verification_params
),
"Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST": (
cryptography_has_x509_v_flag_trusted_first
),
"Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN": (
cryptography_has_x509_v_flag_partial_chain
),
"Cryptography_HAS_SET_CERT_CB": cryptography_has_set_cert_cb,
"Cryptography_HAS_SSL_ST": cryptography_has_ssl_st,
"Cryptography_HAS_TLS_ST": cryptography_has_tls_st,
"Cryptography_HAS_LOCKING_CALLBACKS": cryptography_has_locking_callbacks,
"Cryptography_HAS_SCRYPT": cryptography_has_scrypt,
"Cryptography_HAS_GENERIC_DTLS_METHOD": (
cryptography_has_generic_dtls_method
),
"Cryptography_HAS_EVP_PKEY_DHX": cryptography_has_evp_pkey_dhx,
"Cryptography_HAS_MEM_FUNCTIONS": cryptography_has_mem_functions,
"Cryptography_HAS_SCT": cryptography_has_sct,
"Cryptography_HAS_X509_STORE_CTX_GET_ISSUER": (
cryptography_has_x509_store_ctx_get_issuer
),
"Cryptography_HAS_X25519": cryptography_has_x25519,
"Cryptography_HAS_X448": cryptography_has_x448,
"Cryptography_HAS_ED448": cryptography_has_ed448,
"Cryptography_HAS_ED25519": cryptography_has_ed25519,
"Cryptography_HAS_POLY1305": cryptography_has_poly1305,
"Cryptography_HAS_ONESHOT_EVP_DIGEST_SIGN_VERIFY": (
cryptography_has_oneshot_evp_digest_sign_verify
),
"Cryptography_HAS_EVP_PKEY_get_set_tls_encodedpoint": (
cryptography_has_evp_pkey_get_set_tls_encodedpoint
),
"Cryptography_HAS_FIPS": cryptography_has_fips,
"Cryptography_HAS_SIGALGS": cryptography_has_ssl_sigalgs,
"Cryptography_HAS_PSK": cryptography_has_psk,
"Cryptography_HAS_CUSTOM_EXT": cryptography_has_custom_ext,
"Cryptography_HAS_OPENSSL_CLEANUP": cryptography_has_openssl_cleanup,
"Cryptography_HAS_CIPHER_DETAILS": cryptography_has_cipher_details,
"Cryptography_HAS_TLSv1_3": cryptography_has_tlsv13,
"Cryptography_HAS_RAW_KEY": cryptography_has_raw_key,
"Cryptography_HAS_EVP_DIGESTFINAL_XOF": (
cryptography_has_evp_digestfinal_xof
),
"Cryptography_HAS_EVP_R_MEMORY_LIMIT_EXCEEDED": (
cryptography_has_evp_r_memory_limit_exceeded
),
"Cryptography_HAS_ENGINE": cryptography_has_engine,
"Cryptography_HAS_VERIFIED_CHAIN": cryptography_has_verified_chain,
}
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/bindings/openssl/binding.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import collections
import threading
import types
import warnings
import cryptography
from cryptography import utils
from cryptography.exceptions import InternalError
from cryptography.hazmat.bindings._openssl import ffi, lib
from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES
_OpenSSLErrorWithText = collections.namedtuple(
"_OpenSSLErrorWithText", ["code", "lib", "func", "reason", "reason_text"]
)
class _OpenSSLError(object):
def __init__(self, code, lib, func, reason):
self._code = code
self._lib = lib
self._func = func
self._reason = reason
def _lib_reason_match(self, lib, reason):
return lib == self.lib and reason == self.reason
code = utils.read_only_property("_code")
lib = utils.read_only_property("_lib")
func = utils.read_only_property("_func")
reason = utils.read_only_property("_reason")
def _consume_errors(lib):
errors = []
while True:
code = lib.ERR_get_error()
if code == 0:
break
err_lib = lib.ERR_GET_LIB(code)
err_func = lib.ERR_GET_FUNC(code)
err_reason = lib.ERR_GET_REASON(code)
errors.append(_OpenSSLError(code, err_lib, err_func, err_reason))
return errors
def _openssl_assert(lib, ok):
if not ok:
errors = _consume_errors(lib)
errors_with_text = []
for err in errors:
buf = ffi.new("char[]", 256)
lib.ERR_error_string_n(err.code, buf, len(buf))
err_text_reason = ffi.string(buf)
errors_with_text.append(
_OpenSSLErrorWithText(
err.code, err.lib, err.func, err.reason, err_text_reason
)
)
raise InternalError(
"Unknown OpenSSL error. This error is commonly encountered when "
"another library is not cleaning up the OpenSSL error stack. If "
"you are using cryptography with another library that uses "
"OpenSSL try disabling it before reporting a bug. Otherwise "
"please file an issue at https://github.com/pyca/cryptography/"
"issues with information on how to reproduce "
"this. ({0!r})".format(errors_with_text),
errors_with_text
)
def build_conditional_library(lib, conditional_names):
conditional_lib = types.ModuleType("lib")
conditional_lib._original_lib = lib
excluded_names = set()
for condition, names_cb in conditional_names.items():
if not getattr(lib, condition):
excluded_names.update(names_cb())
for attr in dir(lib):
if attr not in excluded_names:
setattr(conditional_lib, attr, getattr(lib, attr))
return conditional_lib
class Binding(object):
"""
OpenSSL API wrapper.
"""
lib = None
ffi = ffi
_lib_loaded = False
_init_lock = threading.Lock()
_lock_init_lock = threading.Lock()
def __init__(self):
self._ensure_ffi_initialized()
@classmethod
def _register_osrandom_engine(cls):
# Clear any errors extant in the queue before we start. In many
# scenarios other things may be interacting with OpenSSL in the same
# process space and it has proven untenable to assume that they will
# reliably clear the error queue. Once we clear it here we will
# error on any subsequent unexpected item in the stack.
cls.lib.ERR_clear_error()
if cls.lib.Cryptography_HAS_ENGINE:
result = cls.lib.Cryptography_add_osrandom_engine()
_openssl_assert(cls.lib, result in (1, 2))
@classmethod
def _ensure_ffi_initialized(cls):
with cls._init_lock:
if not cls._lib_loaded:
cls.lib = build_conditional_library(lib, CONDITIONAL_NAMES)
cls._lib_loaded = True
# initialize the SSL library
cls.lib.SSL_library_init()
# adds all ciphers/digests for EVP
cls.lib.OpenSSL_add_all_algorithms()
# loads error strings for libcrypto and libssl functions
cls.lib.SSL_load_error_strings()
cls._register_osrandom_engine()
@classmethod
def init_static_locks(cls):
with cls._lock_init_lock:
cls._ensure_ffi_initialized()
# Use Python's implementation if available, importing _ssl triggers
# the setup for this.
__import__("_ssl")
if (not cls.lib.Cryptography_HAS_LOCKING_CALLBACKS or
cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL):
return
# If nothing else has setup a locking callback already, we set up
# our own
res = lib.Cryptography_setup_ssl_threads()
_openssl_assert(cls.lib, res == 1)
def _verify_openssl_version(lib):
if (
lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and
not lib.CRYPTOGRAPHY_IS_LIBRESSL
):
warnings.warn(
"OpenSSL version 1.0.1 is no longer supported by the OpenSSL "
"project, please upgrade. The next version of cryptography will "
"drop support for it.",
utils.CryptographyDeprecationWarning
)
def _verify_package_version(version):
# Occasionally we run into situations where the version of the Python
# package does not match the version of the shared object that is loaded.
# This may occur in environments where multiple versions of cryptography
# are installed and available in the python path. To avoid errors cropping
# up later this code checks that the currently imported package and the
# shared object that were loaded have the same version and raise an
# ImportError if they do not
so_package_version = ffi.string(lib.CRYPTOGRAPHY_PACKAGE_VERSION)
if version.encode("ascii") != so_package_version:
raise ImportError(
"The version of cryptography does not match the loaded "
"shared object. This can happen if you have multiple copies of "
"cryptography installed in your Python path. Please try creating "
"a new virtual environment to resolve this issue. "
"Loaded python version: {}, shared object version: {}".format(
version, so_package_version
)
)
_verify_package_version(cryptography.__version__)
# OpenSSL is not thread safe until the locks are initialized. We call this
# method in module scope so that it executes with the import lock. On
# Pythons < 3.4 this import lock is a global lock, which can prevent a race
# condition registering the OpenSSL locks. On Python 3.4+ the import lock
# is per module so this approach will not work.
Binding.init_static_locks()
_verify_openssl_version(Binding.lib)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/__init__.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class AsymmetricSignatureContext(object):
@abc.abstractmethod
def update(self, data):
"""
Processes the provided bytes and returns nothing.
"""
@abc.abstractmethod
def finalize(self):
"""
Returns the signature as bytes.
"""
@six.add_metaclass(abc.ABCMeta)
class AsymmetricVerificationContext(object):
@abc.abstractmethod
def update(self, data):
"""
Processes the provided bytes and returns nothing.
"""
@abc.abstractmethod
def verify(self):
"""
Raises an exception if the bytes provided to update do not match the
signature or the signature does not match the public key.
"""
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import six
from cryptography import utils
def generate_parameters(generator, key_size, backend):
return backend.generate_dh_parameters(generator, key_size)
class DHPrivateNumbers(object):
def __init__(self, x, public_numbers):
if not isinstance(x, six.integer_types):
raise TypeError("x must be an integer.")
if not isinstance(public_numbers, DHPublicNumbers):
raise TypeError("public_numbers must be an instance of "
"DHPublicNumbers.")
self._x = x
self._public_numbers = public_numbers
def __eq__(self, other):
if not isinstance(other, DHPrivateNumbers):
return NotImplemented
return (
self._x == other._x and
self._public_numbers == other._public_numbers
)
def __ne__(self, other):
return not self == other
def private_key(self, backend):
return backend.load_dh_private_numbers(self)
public_numbers = utils.read_only_property("_public_numbers")
x = utils.read_only_property("_x")
class DHPublicNumbers(object):
def __init__(self, y, parameter_numbers):
if not isinstance(y, six.integer_types):
raise TypeError("y must be an integer.")
if not isinstance(parameter_numbers, DHParameterNumbers):
raise TypeError(
"parameters must be an instance of DHParameterNumbers.")
self._y = y
self._parameter_numbers = parameter_numbers
def __eq__(self, other):
if not isinstance(other, DHPublicNumbers):
return NotImplemented
return (
self._y == other._y and
self._parameter_numbers == other._parameter_numbers
)
def __ne__(self, other):
return not self == other
def public_key(self, backend):
return backend.load_dh_public_numbers(self)
y = utils.read_only_property("_y")
parameter_numbers = utils.read_only_property("_parameter_numbers")
class DHParameterNumbers(object):
def __init__(self, p, g, q=None):
if (
not isinstance(p, six.integer_types) or
not isinstance(g, six.integer_types)
):
raise TypeError("p and g must be integers")
if q is not None and not isinstance(q, six.integer_types):
raise TypeError("q must be integer or None")
if g < 2:
raise ValueError("DH generator must be 2 or greater")
self._p = p
self._g = g
self._q = q
def __eq__(self, other):
if not isinstance(other, DHParameterNumbers):
return NotImplemented
return (
self._p == other._p and
self._g == other._g and
self._q == other._q
)
def __ne__(self, other):
return not self == other
def parameters(self, backend):
return backend.load_dh_parameter_numbers(self)
p = utils.read_only_property("_p")
g = utils.read_only_property("_g")
q = utils.read_only_property("_q")
@six.add_metaclass(abc.ABCMeta)
class DHParameters(object):
@abc.abstractmethod
def generate_private_key(self):
"""
Generates and returns a DHPrivateKey.
"""
@abc.abstractmethod
def parameter_bytes(self, encoding, format):
"""
Returns the parameters serialized as bytes.
"""
@abc.abstractmethod
def parameter_numbers(self):
"""
Returns a DHParameterNumbers.
"""
DHParametersWithSerialization = DHParameters
@six.add_metaclass(abc.ABCMeta)
class DHPrivateKey(object):
@abc.abstractproperty
def key_size(self):
"""
The bit length of the prime modulus.
"""
@abc.abstractmethod
def public_key(self):
"""
The DHPublicKey associated with this private key.
"""
@abc.abstractmethod
def parameters(self):
"""
The DHParameters object associated with this private key.
"""
@abc.abstractmethod
def exchange(self, peer_public_key):
"""
Given peer's DHPublicKey, carry out the key exchange and
return shared key as bytes.
"""
@six.add_metaclass(abc.ABCMeta)
class DHPrivateKeyWithSerialization(DHPrivateKey):
@abc.abstractmethod
def private_numbers(self):
"""
Returns a DHPrivateNumbers.
"""
@abc.abstractmethod
def private_bytes(self, encoding, format, encryption_algorithm):
"""
Returns the key serialized as bytes.
"""
@six.add_metaclass(abc.ABCMeta)
class DHPublicKey(object):
@abc.abstractproperty
def key_size(self):
"""
The bit length of the prime modulus.
"""
@abc.abstractmethod
def parameters(self):
"""
The DHParameters object associated with this public key.
"""
@abc.abstractmethod
def public_numbers(self):
"""
Returns a DHPublicNumbers.
"""
@abc.abstractmethod
def public_bytes(self, encoding, format):
"""
Returns the key serialized as bytes.
"""
DHPublicKeyWithSerialization = DHPublicKey
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import six
from cryptography import utils
@six.add_metaclass(abc.ABCMeta)
class DSAParameters(object):
@abc.abstractmethod
def generate_private_key(self):
"""
Generates and returns a DSAPrivateKey.
"""
@six.add_metaclass(abc.ABCMeta)
class DSAParametersWithNumbers(DSAParameters):
@abc.abstractmethod
def parameter_numbers(self):
"""
Returns a DSAParameterNumbers.
"""
@six.add_metaclass(abc.ABCMeta)
class DSAPrivateKey(object):
@abc.abstractproperty
def key_size(self):
"""
The bit length of the prime modulus.
"""
@abc.abstractmethod
def public_key(self):
"""
The DSAPublicKey associated with this private key.
"""
@abc.abstractmethod
def parameters(self):
"""
The DSAParameters object associated with this private key.
"""
@abc.abstractmethod
def signer(self, signature_algorithm):
"""
Returns an AsymmetricSignatureContext used for signing data.
"""
@abc.abstractmethod
def sign(self, data, algorithm):
"""
Signs the data
"""
@six.add_metaclass(abc.ABCMeta)
class DSAPrivateKeyWithSerialization(DSAPrivateKey):
@abc.abstractmethod
def private_numbers(self):
"""
Returns a DSAPrivateNumbers.
"""
@abc.abstractmethod
def private_bytes(self, encoding, format, encryption_algorithm):
"""
Returns the key serialized as bytes.
"""
@six.add_metaclass(abc.ABCMeta)
class DSAPublicKey(object):
@abc.abstractproperty
def key_size(self):
"""
The bit length of the prime modulus.
"""
@abc.abstractmethod
def parameters(self):
"""
The DSAParameters object associated with this public key.
"""
@abc.abstractmethod
def verifier(self, signature, signature_algorithm):
"""
Returns an AsymmetricVerificationContext used for signing data.
"""
@abc.abstractmethod
def public_numbers(self):
"""
Returns a DSAPublicNumbers.
"""
@abc.abstractmethod
def public_bytes(self, encoding, format):
"""
Returns the key serialized as bytes.
"""
@abc.abstractmethod
def verify(self, signature, data, algorithm):
"""
Verifies the signature of the data.
"""
DSAPublicKeyWithSerialization = DSAPublicKey
def generate_parameters(key_size, backend):
return backend.generate_dsa_parameters(key_size)
def generate_private_key(key_size, backend):
return backend.generate_dsa_private_key_and_parameters(key_size)
def _check_dsa_parameters(parameters):
if parameters.p.bit_length() not in [1024, 2048, 3072]:
raise ValueError("p must be exactly 1024, 2048, or 3072 bits long")
if parameters.q.bit_length() not in [160, 224, 256]:
raise ValueError("q must be exactly 160, 224, or 256 bits long")
if not (1 < parameters.g < parameters.p):
raise ValueError("g, p don't satisfy 1 < g < p.")
def _check_dsa_private_numbers(numbers):
parameters = numbers.public_numbers.parameter_numbers
_check_dsa_parameters(parameters)
if numbers.x <= 0 or numbers.x >= parameters.q:
raise ValueError("x must be > 0 and < q.")
if numbers.public_numbers.y != pow(parameters.g, numbers.x, parameters.p):
raise ValueError("y must be equal to (g ** x % p).")
class DSAParameterNumbers(object):
def __init__(self, p, q, g):
if (
not isinstance(p, six.integer_types) or
not isinstance(q, six.integer_types) or
not isinstance(g, six.integer_types)
):
raise TypeError(
"DSAParameterNumbers p, q, and g arguments must be integers."
)
self._p = p
self._q = q
self._g = g
p = utils.read_only_property("_p")
q = utils.read_only_property("_q")
g = utils.read_only_property("_g")
def parameters(self, backend):
return backend.load_dsa_parameter_numbers(self)
def __eq__(self, other):
if not isinstance(other, DSAParameterNumbers):
return NotImplemented
return self.p == other.p and self.q == other.q and self.g == other.g
def __ne__(self, other):
return not self == other
def __repr__(self):
return (
"".format(
self=self
)
)
class DSAPublicNumbers(object):
def __init__(self, y, parameter_numbers):
if not isinstance(y, six.integer_types):
raise TypeError("DSAPublicNumbers y argument must be an integer.")
if not isinstance(parameter_numbers, DSAParameterNumbers):
raise TypeError(
"parameter_numbers must be a DSAParameterNumbers instance."
)
self._y = y
self._parameter_numbers = parameter_numbers
y = utils.read_only_property("_y")
parameter_numbers = utils.read_only_property("_parameter_numbers")
def public_key(self, backend):
return backend.load_dsa_public_numbers(self)
def __eq__(self, other):
if not isinstance(other, DSAPublicNumbers):
return NotImplemented
return (
self.y == other.y and
self.parameter_numbers == other.parameter_numbers
)
def __ne__(self, other):
return not self == other
def __repr__(self):
return (
"".format(self=self)
)
class DSAPrivateNumbers(object):
def __init__(self, x, public_numbers):
if not isinstance(x, six.integer_types):
raise TypeError("DSAPrivateNumbers x argument must be an integer.")
if not isinstance(public_numbers, DSAPublicNumbers):
raise TypeError(
"public_numbers must be a DSAPublicNumbers instance."
)
self._public_numbers = public_numbers
self._x = x
x = utils.read_only_property("_x")
public_numbers = utils.read_only_property("_public_numbers")
def private_key(self, backend):
return backend.load_dsa_private_numbers(self)
def __eq__(self, other):
if not isinstance(other, DSAPrivateNumbers):
return NotImplemented
return (
self.x == other.x and self.public_numbers == other.public_numbers
)
def __ne__(self, other):
return not self == other
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import warnings
import six
from cryptography import utils
from cryptography.hazmat._oid import ObjectIdentifier
class EllipticCurveOID(object):
SECP192R1 = ObjectIdentifier("1.2.840.10045.3.1.1")
SECP224R1 = ObjectIdentifier("1.3.132.0.33")
SECP256K1 = ObjectIdentifier("1.3.132.0.10")
SECP256R1 = ObjectIdentifier("1.2.840.10045.3.1.7")
SECP384R1 = ObjectIdentifier("1.3.132.0.34")
SECP521R1 = ObjectIdentifier("1.3.132.0.35")
BRAINPOOLP256R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.7")
BRAINPOOLP384R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.11")
BRAINPOOLP512R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.13")
SECT163K1 = ObjectIdentifier("1.3.132.0.1")
SECT163R2 = ObjectIdentifier("1.3.132.0.15")
SECT233K1 = ObjectIdentifier("1.3.132.0.26")
SECT233R1 = ObjectIdentifier("1.3.132.0.27")
SECT283K1 = ObjectIdentifier("1.3.132.0.16")
SECT283R1 = ObjectIdentifier("1.3.132.0.17")
SECT409K1 = ObjectIdentifier("1.3.132.0.36")
SECT409R1 = ObjectIdentifier("1.3.132.0.37")
SECT571K1 = ObjectIdentifier("1.3.132.0.38")
SECT571R1 = ObjectIdentifier("1.3.132.0.39")
@six.add_metaclass(abc.ABCMeta)
class EllipticCurve(object):
@abc.abstractproperty
def name(self):
"""
The name of the curve. e.g. secp256r1.
"""
@abc.abstractproperty
def key_size(self):
"""
Bit size of a secret scalar for the curve.
"""
@six.add_metaclass(abc.ABCMeta)
class EllipticCurveSignatureAlgorithm(object):
@abc.abstractproperty
def algorithm(self):
"""
The digest algorithm used with this signature.
"""
@six.add_metaclass(abc.ABCMeta)
class EllipticCurvePrivateKey(object):
@abc.abstractmethod
def signer(self, signature_algorithm):
"""
Returns an AsymmetricSignatureContext used for signing data.
"""
@abc.abstractmethod
def exchange(self, algorithm, peer_public_key):
"""
Performs a key exchange operation using the provided algorithm with the
provided peer's public key.
"""
@abc.abstractmethod
def public_key(self):
"""
The EllipticCurvePublicKey for this private key.
"""
@abc.abstractproperty
def curve(self):
"""
The EllipticCurve that this key is on.
"""
@abc.abstractproperty
def key_size(self):
"""
Bit size of a secret scalar for the curve.
"""
@abc.abstractmethod
def sign(self, data, signature_algorithm):
"""
Signs the data
"""
@six.add_metaclass(abc.ABCMeta)
class EllipticCurvePrivateKeyWithSerialization(EllipticCurvePrivateKey):
@abc.abstractmethod
def private_numbers(self):
"""
Returns an EllipticCurvePrivateNumbers.
"""
@abc.abstractmethod
def private_bytes(self, encoding, format, encryption_algorithm):
"""
Returns the key serialized as bytes.
"""
@six.add_metaclass(abc.ABCMeta)
class EllipticCurvePublicKey(object):
@abc.abstractmethod
def verifier(self, signature, signature_algorithm):
"""
Returns an AsymmetricVerificationContext used for signing data.
"""
@abc.abstractproperty
def curve(self):
"""
The EllipticCurve that this key is on.
"""
@abc.abstractproperty
def key_size(self):
"""
Bit size of a secret scalar for the curve.
"""
@abc.abstractmethod
def public_numbers(self):
"""
Returns an EllipticCurvePublicNumbers.
"""
@abc.abstractmethod
def public_bytes(self, encoding, format):
"""
Returns the key serialized as bytes.
"""
@abc.abstractmethod
def verify(self, signature, data, signature_algorithm):
"""
Verifies the signature of the data.
"""
@classmethod
def from_encoded_point(cls, curve, data):
utils._check_bytes("data", data)
if not isinstance(curve, EllipticCurve):
raise TypeError("curve must be an EllipticCurve instance")
if len(data) == 0:
raise ValueError("data must not be an empty byte string")
if six.indexbytes(data, 0) not in [0x02, 0x03, 0x04]:
raise ValueError("Unsupported elliptic curve point type")
from cryptography.hazmat.backends.openssl.backend import backend
return backend.load_elliptic_curve_public_bytes(curve, data)
EllipticCurvePublicKeyWithSerialization = EllipticCurvePublicKey
@utils.register_interface(EllipticCurve)
class SECT571R1(object):
name = "sect571r1"
key_size = 570
@utils.register_interface(EllipticCurve)
class SECT409R1(object):
name = "sect409r1"
key_size = 409
@utils.register_interface(EllipticCurve)
class SECT283R1(object):
name = "sect283r1"
key_size = 283
@utils.register_interface(EllipticCurve)
class SECT233R1(object):
name = "sect233r1"
key_size = 233
@utils.register_interface(EllipticCurve)
class SECT163R2(object):
name = "sect163r2"
key_size = 163
@utils.register_interface(EllipticCurve)
class SECT571K1(object):
name = "sect571k1"
key_size = 571
@utils.register_interface(EllipticCurve)
class SECT409K1(object):
name = "sect409k1"
key_size = 409
@utils.register_interface(EllipticCurve)
class SECT283K1(object):
name = "sect283k1"
key_size = 283
@utils.register_interface(EllipticCurve)
class SECT233K1(object):
name = "sect233k1"
key_size = 233
@utils.register_interface(EllipticCurve)
class SECT163K1(object):
name = "sect163k1"
key_size = 163
@utils.register_interface(EllipticCurve)
class SECP521R1(object):
name = "secp521r1"
key_size = 521
@utils.register_interface(EllipticCurve)
class SECP384R1(object):
name = "secp384r1"
key_size = 384
@utils.register_interface(EllipticCurve)
class SECP256R1(object):
name = "secp256r1"
key_size = 256
@utils.register_interface(EllipticCurve)
class SECP256K1(object):
name = "secp256k1"
key_size = 256
@utils.register_interface(EllipticCurve)
class SECP224R1(object):
name = "secp224r1"
key_size = 224
@utils.register_interface(EllipticCurve)
class SECP192R1(object):
name = "secp192r1"
key_size = 192
@utils.register_interface(EllipticCurve)
class BrainpoolP256R1(object):
name = "brainpoolP256r1"
key_size = 256
@utils.register_interface(EllipticCurve)
class BrainpoolP384R1(object):
name = "brainpoolP384r1"
key_size = 384
@utils.register_interface(EllipticCurve)
class BrainpoolP512R1(object):
name = "brainpoolP512r1"
key_size = 512
_CURVE_TYPES = {
"prime192v1": SECP192R1,
"prime256v1": SECP256R1,
"secp192r1": SECP192R1,
"secp224r1": SECP224R1,
"secp256r1": SECP256R1,
"secp384r1": SECP384R1,
"secp521r1": SECP521R1,
"secp256k1": SECP256K1,
"sect163k1": SECT163K1,
"sect233k1": SECT233K1,
"sect283k1": SECT283K1,
"sect409k1": SECT409K1,
"sect571k1": SECT571K1,
"sect163r2": SECT163R2,
"sect233r1": SECT233R1,
"sect283r1": SECT283R1,
"sect409r1": SECT409R1,
"sect571r1": SECT571R1,
"brainpoolP256r1": BrainpoolP256R1,
"brainpoolP384r1": BrainpoolP384R1,
"brainpoolP512r1": BrainpoolP512R1,
}
@utils.register_interface(EllipticCurveSignatureAlgorithm)
class ECDSA(object):
def __init__(self, algorithm):
self._algorithm = algorithm
algorithm = utils.read_only_property("_algorithm")
def generate_private_key(curve, backend):
return backend.generate_elliptic_curve_private_key(curve)
def derive_private_key(private_value, curve, backend):
if not isinstance(private_value, six.integer_types):
raise TypeError("private_value must be an integer type.")
if private_value <= 0:
raise ValueError("private_value must be a positive integer.")
if not isinstance(curve, EllipticCurve):
raise TypeError("curve must provide the EllipticCurve interface.")
return backend.derive_elliptic_curve_private_key(private_value, curve)
class EllipticCurvePublicNumbers(object):
def __init__(self, x, y, curve):
if (
not isinstance(x, six.integer_types) or
not isinstance(y, six.integer_types)
):
raise TypeError("x and y must be integers.")
if not isinstance(curve, EllipticCurve):
raise TypeError("curve must provide the EllipticCurve interface.")
self._y = y
self._x = x
self._curve = curve
def public_key(self, backend):
return backend.load_elliptic_curve_public_numbers(self)
def encode_point(self):
warnings.warn(
"encode_point has been deprecated on EllipticCurvePublicNumbers"
" and will be removed in a future version. Please use "
"EllipticCurvePublicKey.public_bytes to obtain both "
"compressed and uncompressed point encoding.",
utils.DeprecatedIn25,
stacklevel=2,
)
# key_size is in bits. Convert to bytes and round up
byte_length = (self.curve.key_size + 7) // 8
return (
b'\x04' + utils.int_to_bytes(self.x, byte_length) +
utils.int_to_bytes(self.y, byte_length)
)
@classmethod
def from_encoded_point(cls, curve, data):
if not isinstance(curve, EllipticCurve):
raise TypeError("curve must be an EllipticCurve instance")
warnings.warn(
"Support for unsafe construction of public numbers from "
"encoded data will be removed in a future version. "
"Please use EllipticCurvePublicKey.from_encoded_point",
utils.DeprecatedIn25,
stacklevel=2,
)
if data.startswith(b'\x04'):
# key_size is in bits. Convert to bytes and round up
byte_length = (curve.key_size + 7) // 8
if len(data) == 2 * byte_length + 1:
x = utils.int_from_bytes(data[1:byte_length + 1], 'big')
y = utils.int_from_bytes(data[byte_length + 1:], 'big')
return cls(x, y, curve)
else:
raise ValueError('Invalid elliptic curve point data length')
else:
raise ValueError('Unsupported elliptic curve point type')
curve = utils.read_only_property("_curve")
x = utils.read_only_property("_x")
y = utils.read_only_property("_y")
def __eq__(self, other):
if not isinstance(other, EllipticCurvePublicNumbers):
return NotImplemented
return (
self.x == other.x and
self.y == other.y and
self.curve.name == other.curve.name and
self.curve.key_size == other.curve.key_size
)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.x, self.y, self.curve.name, self.curve.key_size))
def __repr__(self):
return (
"".format(self)
)
class EllipticCurvePrivateNumbers(object):
def __init__(self, private_value, public_numbers):
if not isinstance(private_value, six.integer_types):
raise TypeError("private_value must be an integer.")
if not isinstance(public_numbers, EllipticCurvePublicNumbers):
raise TypeError(
"public_numbers must be an EllipticCurvePublicNumbers "
"instance."
)
self._private_value = private_value
self._public_numbers = public_numbers
def private_key(self, backend):
return backend.load_elliptic_curve_private_numbers(self)
private_value = utils.read_only_property("_private_value")
public_numbers = utils.read_only_property("_public_numbers")
def __eq__(self, other):
if not isinstance(other, EllipticCurvePrivateNumbers):
return NotImplemented
return (
self.private_value == other.private_value and
self.public_numbers == other.public_numbers
)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.private_value, self.public_numbers))
class ECDH(object):
pass
_OID_TO_CURVE = {
EllipticCurveOID.SECP192R1: SECP192R1,
EllipticCurveOID.SECP224R1: SECP224R1,
EllipticCurveOID.SECP256K1: SECP256K1,
EllipticCurveOID.SECP256R1: SECP256R1,
EllipticCurveOID.SECP384R1: SECP384R1,
EllipticCurveOID.SECP521R1: SECP521R1,
EllipticCurveOID.BRAINPOOLP256R1: BrainpoolP256R1,
EllipticCurveOID.BRAINPOOLP384R1: BrainpoolP384R1,
EllipticCurveOID.BRAINPOOLP512R1: BrainpoolP512R1,
EllipticCurveOID.SECT163K1: SECT163K1,
EllipticCurveOID.SECT163R2: SECT163R2,
EllipticCurveOID.SECT233K1: SECT233K1,
EllipticCurveOID.SECT233R1: SECT233R1,
EllipticCurveOID.SECT283K1: SECT283K1,
EllipticCurveOID.SECT283R1: SECT283R1,
EllipticCurveOID.SECT409K1: SECT409K1,
EllipticCurveOID.SECT409R1: SECT409R1,
EllipticCurveOID.SECT571K1: SECT571K1,
EllipticCurveOID.SECT571R1: SECT571R1,
}
def get_curve_for_oid(oid):
try:
return _OID_TO_CURVE[oid]
except KeyError:
raise LookupError(
"The provided object identifier has no matching elliptic "
"curve class"
)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import six
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
_ED25519_KEY_SIZE = 32
_ED25519_SIG_SIZE = 64
@six.add_metaclass(abc.ABCMeta)
class Ed25519PublicKey(object):
@classmethod
def from_public_bytes(cls, data):
from cryptography.hazmat.backends.openssl.backend import backend
if not backend.ed25519_supported():
raise UnsupportedAlgorithm(
"ed25519 is not supported by this version of OpenSSL.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
)
return backend.ed25519_load_public_bytes(data)
@abc.abstractmethod
def public_bytes(self, encoding, format):
"""
The serialized bytes of the public key.
"""
@abc.abstractmethod
def verify(self, signature, data):
"""
Verify the signature.
"""
@six.add_metaclass(abc.ABCMeta)
class Ed25519PrivateKey(object):
@classmethod
def generate(cls):
from cryptography.hazmat.backends.openssl.backend import backend
if not backend.ed25519_supported():
raise UnsupportedAlgorithm(
"ed25519 is not supported by this version of OpenSSL.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
)
return backend.ed25519_generate_key()
@classmethod
def from_private_bytes(cls, data):
from cryptography.hazmat.backends.openssl.backend import backend
if not backend.ed25519_supported():
raise UnsupportedAlgorithm(
"ed25519 is not supported by this version of OpenSSL.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
)
return backend.ed25519_load_private_bytes(data)
@abc.abstractmethod
def public_key(self):
"""
The Ed25519PublicKey derived from the private key.
"""
@abc.abstractmethod
def private_bytes(self, encoding, format, encryption_algorithm):
"""
The serialized bytes of the private key.
"""
@abc.abstractmethod
def sign(self, data):
"""
Signs the data.
"""
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import six
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
@six.add_metaclass(abc.ABCMeta)
class Ed448PublicKey(object):
@classmethod
def from_public_bytes(cls, data):
from cryptography.hazmat.backends.openssl.backend import backend
if not backend.ed448_supported():
raise UnsupportedAlgorithm(
"ed448 is not supported by this version of OpenSSL.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
)
return backend.ed448_load_public_bytes(data)
@abc.abstractmethod
def public_bytes(self, encoding, format):
"""
The serialized bytes of the public key.
"""
@abc.abstractmethod
def verify(self, signature, data):
"""
Verify the signature.
"""
@six.add_metaclass(abc.ABCMeta)
class Ed448PrivateKey(object):
@classmethod
def generate(cls):
from cryptography.hazmat.backends.openssl.backend import backend
if not backend.ed448_supported():
raise UnsupportedAlgorithm(
"ed448 is not supported by this version of OpenSSL.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
)
return backend.ed448_generate_key()
@classmethod
def from_private_bytes(cls, data):
from cryptography.hazmat.backends.openssl.backend import backend
if not backend.ed448_supported():
raise UnsupportedAlgorithm(
"ed448 is not supported by this version of OpenSSL.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
)
return backend.ed448_load_private_bytes(data)
@abc.abstractmethod
def public_key(self):
"""
The Ed448PublicKey derived from the private key.
"""
@abc.abstractmethod
def sign(self, data):
"""
Signs the data.
"""
@abc.abstractmethod
def private_bytes(self, encoding, format, encryption_algorithm):
"""
The serialized bytes of the private key.
"""
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import math
import six
from cryptography import utils
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
@six.add_metaclass(abc.ABCMeta)
class AsymmetricPadding(object):
@abc.abstractproperty
def name(self):
"""
A string naming this padding (e.g. "PSS", "PKCS1").
"""
@utils.register_interface(AsymmetricPadding)
class PKCS1v15(object):
name = "EMSA-PKCS1-v1_5"
@utils.register_interface(AsymmetricPadding)
class PSS(object):
MAX_LENGTH = object()
name = "EMSA-PSS"
def __init__(self, mgf, salt_length):
self._mgf = mgf
if (not isinstance(salt_length, six.integer_types) and
salt_length is not self.MAX_LENGTH):
raise TypeError("salt_length must be an integer.")
if salt_length is not self.MAX_LENGTH and salt_length < 0:
raise ValueError("salt_length must be zero or greater.")
self._salt_length = salt_length
@utils.register_interface(AsymmetricPadding)
class OAEP(object):
name = "EME-OAEP"
def __init__(self, mgf, algorithm, label):
if not isinstance(algorithm, hashes.HashAlgorithm):
raise TypeError("Expected instance of hashes.HashAlgorithm.")
self._mgf = mgf
self._algorithm = algorithm
self._label = label
class MGF1(object):
MAX_LENGTH = object()
def __init__(self, algorithm):
if not isinstance(algorithm, hashes.HashAlgorithm):
raise TypeError("Expected instance of hashes.HashAlgorithm.")
self._algorithm = algorithm
def calculate_max_pss_salt_length(key, hash_algorithm):
if not isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)):
raise TypeError("key must be an RSA public or private key")
# bit length - 1 per RFC 3447
emlen = int(math.ceil((key.key_size - 1) / 8.0))
salt_length = emlen - hash_algorithm.digest_size - 2
assert salt_length >= 0
return salt_length
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
try:
# Only available in math in 3.5+
from math import gcd
except ImportError:
from fractions import gcd
import six
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.backends.interfaces import RSABackend
@six.add_metaclass(abc.ABCMeta)
class RSAPrivateKey(object):
@abc.abstractmethod
def signer(self, padding, algorithm):
"""
Returns an AsymmetricSignatureContext used for signing data.
"""
@abc.abstractmethod
def decrypt(self, ciphertext, padding):
"""
Decrypts the provided ciphertext.
"""
@abc.abstractproperty
def key_size(self):
"""
The bit length of the public modulus.
"""
@abc.abstractmethod
def public_key(self):
"""
The RSAPublicKey associated with this private key.
"""
@abc.abstractmethod
def sign(self, data, padding, algorithm):
"""
Signs the data.
"""
@six.add_metaclass(abc.ABCMeta)
class RSAPrivateKeyWithSerialization(RSAPrivateKey):
@abc.abstractmethod
def private_numbers(self):
"""
Returns an RSAPrivateNumbers.
"""
@abc.abstractmethod
def private_bytes(self, encoding, format, encryption_algorithm):
"""
Returns the key serialized as bytes.
"""
@six.add_metaclass(abc.ABCMeta)
class RSAPublicKey(object):
@abc.abstractmethod
def verifier(self, signature, padding, algorithm):
"""
Returns an AsymmetricVerificationContext used for verifying signatures.
"""
@abc.abstractmethod
def encrypt(self, plaintext, padding):
"""
Encrypts the given plaintext.
"""
@abc.abstractproperty
def key_size(self):
"""
The bit length of the public modulus.
"""
@abc.abstractmethod
def public_numbers(self):
"""
Returns an RSAPublicNumbers
"""
@abc.abstractmethod
def public_bytes(self, encoding, format):
"""
Returns the key serialized as bytes.
"""
@abc.abstractmethod
def verify(self, signature, data, padding, algorithm):
"""
Verifies the signature of the data.
"""
RSAPublicKeyWithSerialization = RSAPublicKey
def generate_private_key(public_exponent, key_size, backend):
if not isinstance(backend, RSABackend):
raise UnsupportedAlgorithm(
"Backend object does not implement RSABackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
_verify_rsa_parameters(public_exponent, key_size)
return backend.generate_rsa_private_key(public_exponent, key_size)
def _verify_rsa_parameters(public_exponent, key_size):
if public_exponent < 3:
raise ValueError("public_exponent must be >= 3.")
if public_exponent & 1 == 0:
raise ValueError("public_exponent must be odd.")
if key_size < 512:
raise ValueError("key_size must be at least 512-bits.")
def _check_private_key_components(p, q, private_exponent, dmp1, dmq1, iqmp,
public_exponent, modulus):
if modulus < 3:
raise ValueError("modulus must be >= 3.")
if p >= modulus:
raise ValueError("p must be < modulus.")
if q >= modulus:
raise ValueError("q must be < modulus.")
if dmp1 >= modulus:
raise ValueError("dmp1 must be < modulus.")
if dmq1 >= modulus:
raise ValueError("dmq1 must be < modulus.")
if iqmp >= modulus:
raise ValueError("iqmp must be < modulus.")
if private_exponent >= modulus:
raise ValueError("private_exponent must be < modulus.")
if public_exponent < 3 or public_exponent >= modulus:
raise ValueError("public_exponent must be >= 3 and < modulus.")
if public_exponent & 1 == 0:
raise ValueError("public_exponent must be odd.")
if dmp1 & 1 == 0:
raise ValueError("dmp1 must be odd.")
if dmq1 & 1 == 0:
raise ValueError("dmq1 must be odd.")
if p * q != modulus:
raise ValueError("p*q must equal modulus.")
def _check_public_key_components(e, n):
if n < 3:
raise ValueError("n must be >= 3.")
if e < 3 or e >= n:
raise ValueError("e must be >= 3 and < n.")
if e & 1 == 0:
raise ValueError("e must be odd.")
def _modinv(e, m):
"""
Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1
"""
x1, y1, x2, y2 = 1, 0, 0, 1
a, b = e, m
while b > 0:
q, r = divmod(a, b)
xn, yn = x1 - q * x2, y1 - q * y2
a, b, x1, y1, x2, y2 = b, r, x2, y2, xn, yn
return x1 % m
def rsa_crt_iqmp(p, q):
"""
Compute the CRT (q ** -1) % p value from RSA primes p and q.
"""
return _modinv(q, p)
def rsa_crt_dmp1(private_exponent, p):
"""
Compute the CRT private_exponent % (p - 1) value from the RSA
private_exponent (d) and p.
"""
return private_exponent % (p - 1)
def rsa_crt_dmq1(private_exponent, q):
"""
Compute the CRT private_exponent % (q - 1) value from the RSA
private_exponent (d) and q.
"""
return private_exponent % (q - 1)
# Controls the number of iterations rsa_recover_prime_factors will perform
# to obtain the prime factors. Each iteration increments by 2 so the actual
# maximum attempts is half this number.
_MAX_RECOVERY_ATTEMPTS = 1000
def rsa_recover_prime_factors(n, e, d):
"""
Compute factors p and q from the private exponent d. We assume that n has
no more than two factors. This function is adapted from code in PyCrypto.
"""
# See 8.2.2(i) in Handbook of Applied Cryptography.
ktot = d * e - 1
# The quantity d*e-1 is a multiple of phi(n), even,
# and can be represented as t*2^s.
t = ktot
while t % 2 == 0:
t = t // 2
# Cycle through all multiplicative inverses in Zn.
# The algorithm is non-deterministic, but there is a 50% chance
# any candidate a leads to successful factoring.
# See "Digitalized Signatures and Public Key Functions as Intractable
# as Factorization", M. Rabin, 1979
spotted = False
a = 2
while not spotted and a < _MAX_RECOVERY_ATTEMPTS:
k = t
# Cycle through all values a^{t*2^i}=a^k
while k < ktot:
cand = pow(a, k, n)
# Check if a^k is a non-trivial root of unity (mod n)
if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1:
# We have found a number such that (cand-1)(cand+1)=0 (mod n).
# Either of the terms divides n.
p = gcd(cand + 1, n)
spotted = True
break
k *= 2
# This value was not any good... let's try another!
a += 2
if not spotted:
raise ValueError("Unable to compute factors p and q from exponent d.")
# Found !
q, r = divmod(n, p)
assert r == 0
p, q = sorted((p, q), reverse=True)
return (p, q)
class RSAPrivateNumbers(object):
def __init__(self, p, q, d, dmp1, dmq1, iqmp,
public_numbers):
if (
not isinstance(p, six.integer_types) or
not isinstance(q, six.integer_types) or
not isinstance(d, six.integer_types) or
not isinstance(dmp1, six.integer_types) or
not isinstance(dmq1, six.integer_types) or
not isinstance(iqmp, six.integer_types)
):
raise TypeError(
"RSAPrivateNumbers p, q, d, dmp1, dmq1, iqmp arguments must"
" all be an integers."
)
if not isinstance(public_numbers, RSAPublicNumbers):
raise TypeError(
"RSAPrivateNumbers public_numbers must be an RSAPublicNumbers"
" instance."
)
self._p = p
self._q = q
self._d = d
self._dmp1 = dmp1
self._dmq1 = dmq1
self._iqmp = iqmp
self._public_numbers = public_numbers
p = utils.read_only_property("_p")
q = utils.read_only_property("_q")
d = utils.read_only_property("_d")
dmp1 = utils.read_only_property("_dmp1")
dmq1 = utils.read_only_property("_dmq1")
iqmp = utils.read_only_property("_iqmp")
public_numbers = utils.read_only_property("_public_numbers")
def private_key(self, backend):
return backend.load_rsa_private_numbers(self)
def __eq__(self, other):
if not isinstance(other, RSAPrivateNumbers):
return NotImplemented
return (
self.p == other.p and
self.q == other.q and
self.d == other.d and
self.dmp1 == other.dmp1 and
self.dmq1 == other.dmq1 and
self.iqmp == other.iqmp and
self.public_numbers == other.public_numbers
)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((
self.p,
self.q,
self.d,
self.dmp1,
self.dmq1,
self.iqmp,
self.public_numbers,
))
class RSAPublicNumbers(object):
def __init__(self, e, n):
if (
not isinstance(e, six.integer_types) or
not isinstance(n, six.integer_types)
):
raise TypeError("RSAPublicNumbers arguments must be integers.")
self._e = e
self._n = n
e = utils.read_only_property("_e")
n = utils.read_only_property("_n")
def public_key(self, backend):
return backend.load_rsa_public_numbers(self)
def __repr__(self):
return "".format(self)
def __eq__(self, other):
if not isinstance(other, RSAPublicNumbers):
return NotImplemented
return self.e == other.e and self.n == other.n
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.e, self.n))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.hazmat._der import (
DERReader, INTEGER, SEQUENCE, encode_der, encode_der_integer
)
from cryptography.hazmat.primitives import hashes
def decode_dss_signature(signature):
with DERReader(signature).read_single_element(SEQUENCE) as seq:
r = seq.read_element(INTEGER).as_integer()
s = seq.read_element(INTEGER).as_integer()
return r, s
def encode_dss_signature(r, s):
return encode_der(
SEQUENCE,
encode_der(INTEGER, encode_der_integer(r)),
encode_der(INTEGER, encode_der_integer(s)),
)
class Prehashed(object):
def __init__(self, algorithm):
if not isinstance(algorithm, hashes.HashAlgorithm):
raise TypeError("Expected instance of HashAlgorithm.")
self._algorithm = algorithm
self._digest_size = algorithm.digest_size
digest_size = utils.read_only_property("_digest_size")
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import six
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
@six.add_metaclass(abc.ABCMeta)
class X25519PublicKey(object):
@classmethod
def from_public_bytes(cls, data):
from cryptography.hazmat.backends.openssl.backend import backend
if not backend.x25519_supported():
raise UnsupportedAlgorithm(
"X25519 is not supported by this version of OpenSSL.",
_Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
)
return backend.x25519_load_public_bytes(data)
@abc.abstractmethod
def public_bytes(self, encoding=None, format=None):
"""
The serialized bytes of the public key.
"""
@six.add_metaclass(abc.ABCMeta)
class X25519PrivateKey(object):
@classmethod
def generate(cls):
from cryptography.hazmat.backends.openssl.backend import backend
if not backend.x25519_supported():
raise UnsupportedAlgorithm(
"X25519 is not supported by this version of OpenSSL.",
_Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
)
return backend.x25519_generate_key()
@classmethod
def from_private_bytes(cls, data):
from cryptography.hazmat.backends.openssl.backend import backend
if not backend.x25519_supported():
raise UnsupportedAlgorithm(
"X25519 is not supported by this version of OpenSSL.",
_Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
)
return backend.x25519_load_private_bytes(data)
@abc.abstractmethod
def public_key(self):
"""
The serialized bytes of the public key.
"""
@abc.abstractmethod
def private_bytes(self, encoding, format, encryption_algorithm):
"""
The serialized bytes of the private key.
"""
@abc.abstractmethod
def exchange(self, peer_public_key):
"""
Performs a key exchange operation using the provided peer's public key.
"""
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import six
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
@six.add_metaclass(abc.ABCMeta)
class X448PublicKey(object):
@classmethod
def from_public_bytes(cls, data):
from cryptography.hazmat.backends.openssl.backend import backend
if not backend.x448_supported():
raise UnsupportedAlgorithm(
"X448 is not supported by this version of OpenSSL.",
_Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
)
return backend.x448_load_public_bytes(data)
@abc.abstractmethod
def public_bytes(self, encoding, format):
"""
The serialized bytes of the public key.
"""
@six.add_metaclass(abc.ABCMeta)
class X448PrivateKey(object):
@classmethod
def generate(cls):
from cryptography.hazmat.backends.openssl.backend import backend
if not backend.x448_supported():
raise UnsupportedAlgorithm(
"X448 is not supported by this version of OpenSSL.",
_Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
)
return backend.x448_generate_key()
@classmethod
def from_private_bytes(cls, data):
from cryptography.hazmat.backends.openssl.backend import backend
if not backend.x448_supported():
raise UnsupportedAlgorithm(
"X448 is not supported by this version of OpenSSL.",
_Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
)
return backend.x448_load_private_bytes(data)
@abc.abstractmethod
def public_key(self):
"""
The serialized bytes of the public key.
"""
@abc.abstractmethod
def private_bytes(self, encoding, format, encryption_algorithm):
"""
The serialized bytes of the private key.
"""
@abc.abstractmethod
def exchange(self, peer_public_key):
"""
Performs a key exchange operation using the provided peer's public key.
"""
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography.hazmat.primitives.ciphers.base import (
AEADCipherContext, AEADDecryptionContext, AEADEncryptionContext,
BlockCipherAlgorithm, Cipher, CipherAlgorithm, CipherContext
)
__all__ = [
"Cipher",
"CipherAlgorithm",
"BlockCipherAlgorithm",
"CipherContext",
"AEADCipherContext",
"AEADDecryptionContext",
"AEADEncryptionContext",
]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/ciphers/aead.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import os
from cryptography import exceptions, utils
from cryptography.hazmat.backends.openssl import aead
from cryptography.hazmat.backends.openssl.backend import backend
class ChaCha20Poly1305(object):
_MAX_SIZE = 2 ** 32
def __init__(self, key):
if not backend.aead_cipher_supported(self):
raise exceptions.UnsupportedAlgorithm(
"ChaCha20Poly1305 is not supported by this version of OpenSSL",
exceptions._Reasons.UNSUPPORTED_CIPHER
)
utils._check_byteslike("key", key)
if len(key) != 32:
raise ValueError("ChaCha20Poly1305 key must be 32 bytes.")
self._key = key
@classmethod
def generate_key(cls):
return os.urandom(32)
def encrypt(self, nonce, data, associated_data):
if associated_data is None:
associated_data = b""
if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE:
# This is OverflowError to match what cffi would raise
raise OverflowError(
"Data or associated data too long. Max 2**32 bytes"
)
self._check_params(nonce, data, associated_data)
return aead._encrypt(
backend, self, nonce, data, associated_data, 16
)
def decrypt(self, nonce, data, associated_data):
if associated_data is None:
associated_data = b""
self._check_params(nonce, data, associated_data)
return aead._decrypt(
backend, self, nonce, data, associated_data, 16
)
def _check_params(self, nonce, data, associated_data):
utils._check_byteslike("nonce", nonce)
utils._check_bytes("data", data)
utils._check_bytes("associated_data", associated_data)
if len(nonce) != 12:
raise ValueError("Nonce must be 12 bytes")
class AESCCM(object):
_MAX_SIZE = 2 ** 32
def __init__(self, key, tag_length=16):
utils._check_byteslike("key", key)
if len(key) not in (16, 24, 32):
raise ValueError("AESCCM key must be 128, 192, or 256 bits.")
self._key = key
if not isinstance(tag_length, int):
raise TypeError("tag_length must be an integer")
if tag_length not in (4, 6, 8, 10, 12, 14, 16):
raise ValueError("Invalid tag_length")
self._tag_length = tag_length
if not backend.aead_cipher_supported(self):
raise exceptions.UnsupportedAlgorithm(
"AESCCM is not supported by this version of OpenSSL",
exceptions._Reasons.UNSUPPORTED_CIPHER
)
@classmethod
def generate_key(cls, bit_length):
if not isinstance(bit_length, int):
raise TypeError("bit_length must be an integer")
if bit_length not in (128, 192, 256):
raise ValueError("bit_length must be 128, 192, or 256")
return os.urandom(bit_length // 8)
def encrypt(self, nonce, data, associated_data):
if associated_data is None:
associated_data = b""
if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE:
# This is OverflowError to match what cffi would raise
raise OverflowError(
"Data or associated data too long. Max 2**32 bytes"
)
self._check_params(nonce, data, associated_data)
self._validate_lengths(nonce, len(data))
return aead._encrypt(
backend, self, nonce, data, associated_data, self._tag_length
)
def decrypt(self, nonce, data, associated_data):
if associated_data is None:
associated_data = b""
self._check_params(nonce, data, associated_data)
return aead._decrypt(
backend, self, nonce, data, associated_data, self._tag_length
)
def _validate_lengths(self, nonce, data_len):
# For information about computing this, see
# https://tools.ietf.org/html/rfc3610#section-2.1
l_val = 15 - len(nonce)
if 2 ** (8 * l_val) < data_len:
raise ValueError("Nonce too long for data")
def _check_params(self, nonce, data, associated_data):
utils._check_byteslike("nonce", nonce)
utils._check_bytes("data", data)
utils._check_bytes("associated_data", associated_data)
if not 7 <= len(nonce) <= 13:
raise ValueError("Nonce must be between 7 and 13 bytes")
class AESGCM(object):
_MAX_SIZE = 2 ** 32
def __init__(self, key):
utils._check_byteslike("key", key)
if len(key) not in (16, 24, 32):
raise ValueError("AESGCM key must be 128, 192, or 256 bits.")
self._key = key
@classmethod
def generate_key(cls, bit_length):
if not isinstance(bit_length, int):
raise TypeError("bit_length must be an integer")
if bit_length not in (128, 192, 256):
raise ValueError("bit_length must be 128, 192, or 256")
return os.urandom(bit_length // 8)
def encrypt(self, nonce, data, associated_data):
if associated_data is None:
associated_data = b""
if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE:
# This is OverflowError to match what cffi would raise
raise OverflowError(
"Data or associated data too long. Max 2**32 bytes"
)
self._check_params(nonce, data, associated_data)
return aead._encrypt(
backend, self, nonce, data, associated_data, 16
)
def decrypt(self, nonce, data, associated_data):
if associated_data is None:
associated_data = b""
self._check_params(nonce, data, associated_data)
return aead._decrypt(
backend, self, nonce, data, associated_data, 16
)
def _check_params(self, nonce, data, associated_data):
utils._check_byteslike("nonce", nonce)
utils._check_bytes("data", data)
utils._check_bytes("associated_data", associated_data)
if len(nonce) == 0:
raise ValueError("Nonce must be at least 1 byte")
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.hazmat.primitives.ciphers import (
BlockCipherAlgorithm, CipherAlgorithm
)
from cryptography.hazmat.primitives.ciphers.modes import ModeWithNonce
def _verify_key_size(algorithm, key):
# Verify that the key is instance of bytes
utils._check_byteslike("key", key)
# Verify that the key size matches the expected key size
if len(key) * 8 not in algorithm.key_sizes:
raise ValueError("Invalid key size ({}) for {}.".format(
len(key) * 8, algorithm.name
))
return key
@utils.register_interface(BlockCipherAlgorithm)
@utils.register_interface(CipherAlgorithm)
class AES(object):
name = "AES"
block_size = 128
# 512 added to support AES-256-XTS, which uses 512-bit keys
key_sizes = frozenset([128, 192, 256, 512])
def __init__(self, key):
self.key = _verify_key_size(self, key)
@property
def key_size(self):
return len(self.key) * 8
@utils.register_interface(BlockCipherAlgorithm)
@utils.register_interface(CipherAlgorithm)
class Camellia(object):
name = "camellia"
block_size = 128
key_sizes = frozenset([128, 192, 256])
def __init__(self, key):
self.key = _verify_key_size(self, key)
@property
def key_size(self):
return len(self.key) * 8
@utils.register_interface(BlockCipherAlgorithm)
@utils.register_interface(CipherAlgorithm)
class TripleDES(object):
name = "3DES"
block_size = 64
key_sizes = frozenset([64, 128, 192])
def __init__(self, key):
if len(key) == 8:
key += key + key
elif len(key) == 16:
key += key[:8]
self.key = _verify_key_size(self, key)
@property
def key_size(self):
return len(self.key) * 8
@utils.register_interface(BlockCipherAlgorithm)
@utils.register_interface(CipherAlgorithm)
class Blowfish(object):
name = "Blowfish"
block_size = 64
key_sizes = frozenset(range(32, 449, 8))
def __init__(self, key):
self.key = _verify_key_size(self, key)
@property
def key_size(self):
return len(self.key) * 8
@utils.register_interface(BlockCipherAlgorithm)
@utils.register_interface(CipherAlgorithm)
class CAST5(object):
name = "CAST5"
block_size = 64
key_sizes = frozenset(range(40, 129, 8))
def __init__(self, key):
self.key = _verify_key_size(self, key)
@property
def key_size(self):
return len(self.key) * 8
@utils.register_interface(CipherAlgorithm)
class ARC4(object):
name = "RC4"
key_sizes = frozenset([40, 56, 64, 80, 128, 160, 192, 256])
def __init__(self, key):
self.key = _verify_key_size(self, key)
@property
def key_size(self):
return len(self.key) * 8
@utils.register_interface(CipherAlgorithm)
class IDEA(object):
name = "IDEA"
block_size = 64
key_sizes = frozenset([128])
def __init__(self, key):
self.key = _verify_key_size(self, key)
@property
def key_size(self):
return len(self.key) * 8
@utils.register_interface(BlockCipherAlgorithm)
@utils.register_interface(CipherAlgorithm)
class SEED(object):
name = "SEED"
block_size = 128
key_sizes = frozenset([128])
def __init__(self, key):
self.key = _verify_key_size(self, key)
@property
def key_size(self):
return len(self.key) * 8
@utils.register_interface(CipherAlgorithm)
@utils.register_interface(ModeWithNonce)
class ChaCha20(object):
name = "ChaCha20"
key_sizes = frozenset([256])
def __init__(self, key, nonce):
self.key = _verify_key_size(self, key)
utils._check_byteslike("nonce", nonce)
if len(nonce) != 16:
raise ValueError("nonce must be 128-bits (16 bytes)")
self._nonce = nonce
nonce = utils.read_only_property("_nonce")
@property
def key_size(self):
return len(self.key) * 8
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/ciphers/base.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import six
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, AlreadyUpdated, NotYetFinalized, UnsupportedAlgorithm,
_Reasons
)
from cryptography.hazmat.backends.interfaces import CipherBackend
from cryptography.hazmat.primitives.ciphers import modes
@six.add_metaclass(abc.ABCMeta)
class CipherAlgorithm(object):
@abc.abstractproperty
def name(self):
"""
A string naming this mode (e.g. "AES", "Camellia").
"""
@abc.abstractproperty
def key_size(self):
"""
The size of the key being used as an integer in bits (e.g. 128, 256).
"""
@six.add_metaclass(abc.ABCMeta)
class BlockCipherAlgorithm(object):
@abc.abstractproperty
def block_size(self):
"""
The size of a block as an integer in bits (e.g. 64, 128).
"""
@six.add_metaclass(abc.ABCMeta)
class CipherContext(object):
@abc.abstractmethod
def update(self, data):
"""
Processes the provided bytes through the cipher and returns the results
as bytes.
"""
@abc.abstractmethod
def update_into(self, data, buf):
"""
Processes the provided bytes and writes the resulting data into the
provided buffer. Returns the number of bytes written.
"""
@abc.abstractmethod
def finalize(self):
"""
Returns the results of processing the final block as bytes.
"""
@six.add_metaclass(abc.ABCMeta)
class AEADCipherContext(object):
@abc.abstractmethod
def authenticate_additional_data(self, data):
"""
Authenticates the provided bytes.
"""
@six.add_metaclass(abc.ABCMeta)
class AEADDecryptionContext(object):
@abc.abstractmethod
def finalize_with_tag(self, tag):
"""
Returns the results of processing the final block as bytes and allows
delayed passing of the authentication tag.
"""
@six.add_metaclass(abc.ABCMeta)
class AEADEncryptionContext(object):
@abc.abstractproperty
def tag(self):
"""
Returns tag bytes. This is only available after encryption is
finalized.
"""
class Cipher(object):
def __init__(self, algorithm, mode, backend):
if not isinstance(backend, CipherBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement CipherBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
if not isinstance(algorithm, CipherAlgorithm):
raise TypeError("Expected interface of CipherAlgorithm.")
if mode is not None:
mode.validate_for_algorithm(algorithm)
self.algorithm = algorithm
self.mode = mode
self._backend = backend
def encryptor(self):
if isinstance(self.mode, modes.ModeWithAuthenticationTag):
if self.mode.tag is not None:
raise ValueError(
"Authentication tag must be None when encrypting."
)
ctx = self._backend.create_symmetric_encryption_ctx(
self.algorithm, self.mode
)
return self._wrap_ctx(ctx, encrypt=True)
def decryptor(self):
ctx = self._backend.create_symmetric_decryption_ctx(
self.algorithm, self.mode
)
return self._wrap_ctx(ctx, encrypt=False)
def _wrap_ctx(self, ctx, encrypt):
if isinstance(self.mode, modes.ModeWithAuthenticationTag):
if encrypt:
return _AEADEncryptionContext(ctx)
else:
return _AEADCipherContext(ctx)
else:
return _CipherContext(ctx)
@utils.register_interface(CipherContext)
class _CipherContext(object):
def __init__(self, ctx):
self._ctx = ctx
def update(self, data):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
return self._ctx.update(data)
def update_into(self, data, buf):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
return self._ctx.update_into(data, buf)
def finalize(self):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
data = self._ctx.finalize()
self._ctx = None
return data
@utils.register_interface(AEADCipherContext)
@utils.register_interface(CipherContext)
@utils.register_interface(AEADDecryptionContext)
class _AEADCipherContext(object):
def __init__(self, ctx):
self._ctx = ctx
self._bytes_processed = 0
self._aad_bytes_processed = 0
self._tag = None
self._updated = False
def _check_limit(self, data_size):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
self._updated = True
self._bytes_processed += data_size
if self._bytes_processed > self._ctx._mode._MAX_ENCRYPTED_BYTES:
raise ValueError(
"{} has a maximum encrypted byte limit of {}".format(
self._ctx._mode.name, self._ctx._mode._MAX_ENCRYPTED_BYTES
)
)
def update(self, data):
self._check_limit(len(data))
return self._ctx.update(data)
def update_into(self, data, buf):
self._check_limit(len(data))
return self._ctx.update_into(data, buf)
def finalize(self):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
data = self._ctx.finalize()
self._tag = self._ctx.tag
self._ctx = None
return data
def finalize_with_tag(self, tag):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
data = self._ctx.finalize_with_tag(tag)
self._tag = self._ctx.tag
self._ctx = None
return data
def authenticate_additional_data(self, data):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
if self._updated:
raise AlreadyUpdated("Update has been called on this context.")
self._aad_bytes_processed += len(data)
if self._aad_bytes_processed > self._ctx._mode._MAX_AAD_BYTES:
raise ValueError(
"{} has a maximum AAD byte limit of {}".format(
self._ctx._mode.name, self._ctx._mode._MAX_AAD_BYTES
)
)
self._ctx.authenticate_additional_data(data)
@utils.register_interface(AEADEncryptionContext)
class _AEADEncryptionContext(_AEADCipherContext):
@property
def tag(self):
if self._ctx is not None:
raise NotYetFinalized("You must finalize encryption before "
"getting the tag.")
return self._tag
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/ciphers/modes.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import six
from cryptography import utils
@six.add_metaclass(abc.ABCMeta)
class Mode(object):
@abc.abstractproperty
def name(self):
"""
A string naming this mode (e.g. "ECB", "CBC").
"""
@abc.abstractmethod
def validate_for_algorithm(self, algorithm):
"""
Checks that all the necessary invariants of this (mode, algorithm)
combination are met.
"""
@six.add_metaclass(abc.ABCMeta)
class ModeWithInitializationVector(object):
@abc.abstractproperty
def initialization_vector(self):
"""
The value of the initialization vector for this mode as bytes.
"""
@six.add_metaclass(abc.ABCMeta)
class ModeWithTweak(object):
@abc.abstractproperty
def tweak(self):
"""
The value of the tweak for this mode as bytes.
"""
@six.add_metaclass(abc.ABCMeta)
class ModeWithNonce(object):
@abc.abstractproperty
def nonce(self):
"""
The value of the nonce for this mode as bytes.
"""
@six.add_metaclass(abc.ABCMeta)
class ModeWithAuthenticationTag(object):
@abc.abstractproperty
def tag(self):
"""
The value of the tag supplied to the constructor of this mode.
"""
def _check_aes_key_length(self, algorithm):
if algorithm.key_size > 256 and algorithm.name == "AES":
raise ValueError(
"Only 128, 192, and 256 bit keys are allowed for this AES mode"
)
def _check_iv_length(self, algorithm):
if len(self.initialization_vector) * 8 != algorithm.block_size:
raise ValueError("Invalid IV size ({}) for {}.".format(
len(self.initialization_vector), self.name
))
def _check_iv_and_key_length(self, algorithm):
_check_aes_key_length(self, algorithm)
_check_iv_length(self, algorithm)
@utils.register_interface(Mode)
@utils.register_interface(ModeWithInitializationVector)
class CBC(object):
name = "CBC"
def __init__(self, initialization_vector):
utils._check_byteslike("initialization_vector", initialization_vector)
self._initialization_vector = initialization_vector
initialization_vector = utils.read_only_property("_initialization_vector")
validate_for_algorithm = _check_iv_and_key_length
@utils.register_interface(Mode)
@utils.register_interface(ModeWithTweak)
class XTS(object):
name = "XTS"
def __init__(self, tweak):
utils._check_byteslike("tweak", tweak)
if len(tweak) != 16:
raise ValueError("tweak must be 128-bits (16 bytes)")
self._tweak = tweak
tweak = utils.read_only_property("_tweak")
def validate_for_algorithm(self, algorithm):
if algorithm.key_size not in (256, 512):
raise ValueError(
"The XTS specification requires a 256-bit key for AES-128-XTS"
" and 512-bit key for AES-256-XTS"
)
@utils.register_interface(Mode)
class ECB(object):
name = "ECB"
validate_for_algorithm = _check_aes_key_length
@utils.register_interface(Mode)
@utils.register_interface(ModeWithInitializationVector)
class OFB(object):
name = "OFB"
def __init__(self, initialization_vector):
utils._check_byteslike("initialization_vector", initialization_vector)
self._initialization_vector = initialization_vector
initialization_vector = utils.read_only_property("_initialization_vector")
validate_for_algorithm = _check_iv_and_key_length
@utils.register_interface(Mode)
@utils.register_interface(ModeWithInitializationVector)
class CFB(object):
name = "CFB"
def __init__(self, initialization_vector):
utils._check_byteslike("initialization_vector", initialization_vector)
self._initialization_vector = initialization_vector
initialization_vector = utils.read_only_property("_initialization_vector")
validate_for_algorithm = _check_iv_and_key_length
@utils.register_interface(Mode)
@utils.register_interface(ModeWithInitializationVector)
class CFB8(object):
name = "CFB8"
def __init__(self, initialization_vector):
utils._check_byteslike("initialization_vector", initialization_vector)
self._initialization_vector = initialization_vector
initialization_vector = utils.read_only_property("_initialization_vector")
validate_for_algorithm = _check_iv_and_key_length
@utils.register_interface(Mode)
@utils.register_interface(ModeWithNonce)
class CTR(object):
name = "CTR"
def __init__(self, nonce):
utils._check_byteslike("nonce", nonce)
self._nonce = nonce
nonce = utils.read_only_property("_nonce")
def validate_for_algorithm(self, algorithm):
_check_aes_key_length(self, algorithm)
if len(self.nonce) * 8 != algorithm.block_size:
raise ValueError("Invalid nonce size ({}) for {}.".format(
len(self.nonce), self.name
))
@utils.register_interface(Mode)
@utils.register_interface(ModeWithInitializationVector)
@utils.register_interface(ModeWithAuthenticationTag)
class GCM(object):
name = "GCM"
_MAX_ENCRYPTED_BYTES = (2 ** 39 - 256) // 8
_MAX_AAD_BYTES = (2 ** 64) // 8
def __init__(self, initialization_vector, tag=None, min_tag_length=16):
# len(initialization_vector) must in [1, 2 ** 64), but it's impossible
# to actually construct a bytes object that large, so we don't check
# for it
utils._check_byteslike("initialization_vector", initialization_vector)
if len(initialization_vector) == 0:
raise ValueError("initialization_vector must be at least 1 byte")
self._initialization_vector = initialization_vector
if tag is not None:
utils._check_bytes("tag", tag)
if min_tag_length < 4:
raise ValueError("min_tag_length must be >= 4")
if len(tag) < min_tag_length:
raise ValueError(
"Authentication tag must be {} bytes or longer.".format(
min_tag_length)
)
self._tag = tag
self._min_tag_length = min_tag_length
tag = utils.read_only_property("_tag")
initialization_vector = utils.read_only_property("_initialization_vector")
def validate_for_algorithm(self, algorithm):
_check_aes_key_length(self, algorithm)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/cmac.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import CMACBackend
from cryptography.hazmat.primitives import ciphers
class CMAC(object):
def __init__(self, algorithm, backend, ctx=None):
if not isinstance(backend, CMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement CMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
if not isinstance(algorithm, ciphers.BlockCipherAlgorithm):
raise TypeError(
"Expected instance of BlockCipherAlgorithm."
)
self._algorithm = algorithm
self._backend = backend
if ctx is None:
self._ctx = self._backend.create_cmac_ctx(self._algorithm)
else:
self._ctx = ctx
def update(self, data):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
utils._check_bytes("data", data)
self._ctx.update(data)
def finalize(self):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
digest = self._ctx.finalize()
self._ctx = None
return digest
def verify(self, signature):
utils._check_bytes("signature", signature)
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
ctx, self._ctx = self._ctx, None
ctx.verify(signature)
def copy(self):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
return CMAC(
self._algorithm,
backend=self._backend,
ctx=self._ctx.copy()
)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/constant_time.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import hmac
import warnings
from cryptography import utils
from cryptography.hazmat.bindings._constant_time import lib
if hasattr(hmac, "compare_digest"):
def bytes_eq(a, b):
if not isinstance(a, bytes) or not isinstance(b, bytes):
raise TypeError("a and b must be bytes.")
return hmac.compare_digest(a, b)
else:
warnings.warn(
"Support for your Python version is deprecated. The next version of "
"cryptography will remove support. Please upgrade to a release "
"(2.7.7+) that supports hmac.compare_digest as soon as possible.",
utils.PersistentlyDeprecated2018,
)
def bytes_eq(a, b):
if not isinstance(a, bytes) or not isinstance(b, bytes):
raise TypeError("a and b must be bytes.")
return lib.Cryptography_constant_time_bytes_eq(
a, len(a), b, len(b)
) == 1
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/hashes.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import six
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import HashBackend
@six.add_metaclass(abc.ABCMeta)
class HashAlgorithm(object):
@abc.abstractproperty
def name(self):
"""
A string naming this algorithm (e.g. "sha256", "md5").
"""
@abc.abstractproperty
def digest_size(self):
"""
The size of the resulting digest in bytes.
"""
@six.add_metaclass(abc.ABCMeta)
class HashContext(object):
@abc.abstractproperty
def algorithm(self):
"""
A HashAlgorithm that will be used by this context.
"""
@abc.abstractmethod
def update(self, data):
"""
Processes the provided bytes through the hash.
"""
@abc.abstractmethod
def finalize(self):
"""
Finalizes the hash context and returns the hash digest as bytes.
"""
@abc.abstractmethod
def copy(self):
"""
Return a HashContext that is a copy of the current context.
"""
@six.add_metaclass(abc.ABCMeta)
class ExtendableOutputFunction(object):
"""
An interface for extendable output functions.
"""
@utils.register_interface(HashContext)
class Hash(object):
def __init__(self, algorithm, backend, ctx=None):
if not isinstance(backend, HashBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HashBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
if not isinstance(algorithm, HashAlgorithm):
raise TypeError("Expected instance of hashes.HashAlgorithm.")
self._algorithm = algorithm
self._backend = backend
if ctx is None:
self._ctx = self._backend.create_hash_ctx(self.algorithm)
else:
self._ctx = ctx
algorithm = utils.read_only_property("_algorithm")
def update(self, data):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
utils._check_byteslike("data", data)
self._ctx.update(data)
def copy(self):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
return Hash(
self.algorithm, backend=self._backend, ctx=self._ctx.copy()
)
def finalize(self):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
digest = self._ctx.finalize()
self._ctx = None
return digest
@utils.register_interface(HashAlgorithm)
class SHA1(object):
name = "sha1"
digest_size = 20
block_size = 64
@utils.register_interface(HashAlgorithm)
class SHA512_224(object): # noqa: N801
name = "sha512-224"
digest_size = 28
block_size = 128
@utils.register_interface(HashAlgorithm)
class SHA512_256(object): # noqa: N801
name = "sha512-256"
digest_size = 32
block_size = 128
@utils.register_interface(HashAlgorithm)
class SHA224(object):
name = "sha224"
digest_size = 28
block_size = 64
@utils.register_interface(HashAlgorithm)
class SHA256(object):
name = "sha256"
digest_size = 32
block_size = 64
@utils.register_interface(HashAlgorithm)
class SHA384(object):
name = "sha384"
digest_size = 48
block_size = 128
@utils.register_interface(HashAlgorithm)
class SHA512(object):
name = "sha512"
digest_size = 64
block_size = 128
@utils.register_interface(HashAlgorithm)
class SHA3_224(object): # noqa: N801
name = "sha3-224"
digest_size = 28
@utils.register_interface(HashAlgorithm)
class SHA3_256(object): # noqa: N801
name = "sha3-256"
digest_size = 32
@utils.register_interface(HashAlgorithm)
class SHA3_384(object): # noqa: N801
name = "sha3-384"
digest_size = 48
@utils.register_interface(HashAlgorithm)
class SHA3_512(object): # noqa: N801
name = "sha3-512"
digest_size = 64
@utils.register_interface(HashAlgorithm)
@utils.register_interface(ExtendableOutputFunction)
class SHAKE128(object):
name = "shake128"
def __init__(self, digest_size):
if not isinstance(digest_size, six.integer_types):
raise TypeError("digest_size must be an integer")
if digest_size < 1:
raise ValueError("digest_size must be a positive integer")
self._digest_size = digest_size
digest_size = utils.read_only_property("_digest_size")
@utils.register_interface(HashAlgorithm)
@utils.register_interface(ExtendableOutputFunction)
class SHAKE256(object):
name = "shake256"
def __init__(self, digest_size):
if not isinstance(digest_size, six.integer_types):
raise TypeError("digest_size must be an integer")
if digest_size < 1:
raise ValueError("digest_size must be a positive integer")
self._digest_size = digest_size
digest_size = utils.read_only_property("_digest_size")
@utils.register_interface(HashAlgorithm)
class MD5(object):
name = "md5"
digest_size = 16
block_size = 64
@utils.register_interface(HashAlgorithm)
class BLAKE2b(object):
name = "blake2b"
_max_digest_size = 64
_min_digest_size = 1
block_size = 128
def __init__(self, digest_size):
if digest_size != 64:
raise ValueError("Digest size must be 64")
self._digest_size = digest_size
digest_size = utils.read_only_property("_digest_size")
@utils.register_interface(HashAlgorithm)
class BLAKE2s(object):
name = "blake2s"
block_size = 64
_max_digest_size = 32
_min_digest_size = 1
def __init__(self, digest_size):
if digest_size != 32:
raise ValueError("Digest size must be 32")
self._digest_size = digest_size
digest_size = utils.read_only_property("_digest_size")
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/hmac.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import HMACBackend
from cryptography.hazmat.primitives import hashes
@utils.register_interface(hashes.HashContext)
class HMAC(object):
def __init__(self, key, algorithm, backend, ctx=None):
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
if not isinstance(algorithm, hashes.HashAlgorithm):
raise TypeError("Expected instance of hashes.HashAlgorithm.")
self._algorithm = algorithm
self._backend = backend
self._key = key
if ctx is None:
self._ctx = self._backend.create_hmac_ctx(key, self.algorithm)
else:
self._ctx = ctx
algorithm = utils.read_only_property("_algorithm")
def update(self, data):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
utils._check_byteslike("data", data)
self._ctx.update(data)
def copy(self):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
return HMAC(
self._key,
self.algorithm,
backend=self._backend,
ctx=self._ctx.copy()
)
def finalize(self):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
digest = self._ctx.finalize()
self._ctx = None
return digest
def verify(self, signature):
utils._check_bytes("signature", signature)
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
ctx, self._ctx = self._ctx, None
ctx.verify(signature)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/kdf/__init__.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class KeyDerivationFunction(object):
@abc.abstractmethod
def derive(self, key_material):
"""
Deterministically generates and returns a new key based on the existing
key material.
"""
@abc.abstractmethod
def verify(self, key_material, expected_key):
"""
Checks whether the key generated by the key material matches the
expected derived key. Raises an exception if they do not match.
"""
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import struct
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import HMACBackend
from cryptography.hazmat.backends.interfaces import HashBackend
from cryptography.hazmat.primitives import constant_time, hashes, hmac
from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
def _int_to_u32be(n):
return struct.pack('>I', n)
def _common_args_checks(algorithm, length, otherinfo):
max_length = algorithm.digest_size * (2 ** 32 - 1)
if length > max_length:
raise ValueError(
"Can not derive keys larger than {} bits.".format(
max_length
))
if otherinfo is not None:
utils._check_bytes("otherinfo", otherinfo)
def _concatkdf_derive(key_material, length, auxfn, otherinfo):
utils._check_byteslike("key_material", key_material)
output = [b""]
outlen = 0
counter = 1
while (length > outlen):
h = auxfn()
h.update(_int_to_u32be(counter))
h.update(key_material)
h.update(otherinfo)
output.append(h.finalize())
outlen += len(output[-1])
counter += 1
return b"".join(output)[:length]
@utils.register_interface(KeyDerivationFunction)
class ConcatKDFHash(object):
def __init__(self, algorithm, length, otherinfo, backend):
_common_args_checks(algorithm, length, otherinfo)
self._algorithm = algorithm
self._length = length
self._otherinfo = otherinfo
if self._otherinfo is None:
self._otherinfo = b""
if not isinstance(backend, HashBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HashBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
self._backend = backend
self._used = False
def _hash(self):
return hashes.Hash(self._algorithm, self._backend)
def derive(self, key_material):
if self._used:
raise AlreadyFinalized
self._used = True
return _concatkdf_derive(key_material, self._length,
self._hash, self._otherinfo)
def verify(self, key_material, expected_key):
if not constant_time.bytes_eq(self.derive(key_material), expected_key):
raise InvalidKey
@utils.register_interface(KeyDerivationFunction)
class ConcatKDFHMAC(object):
def __init__(self, algorithm, length, salt, otherinfo, backend):
_common_args_checks(algorithm, length, otherinfo)
self._algorithm = algorithm
self._length = length
self._otherinfo = otherinfo
if self._otherinfo is None:
self._otherinfo = b""
if salt is None:
salt = b"\x00" * algorithm.block_size
else:
utils._check_bytes("salt", salt)
self._salt = salt
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
self._backend = backend
self._used = False
def _hmac(self):
return hmac.HMAC(self._salt, self._algorithm, self._backend)
def derive(self, key_material):
if self._used:
raise AlreadyFinalized
self._used = True
return _concatkdf_derive(key_material, self._length,
self._hmac, self._otherinfo)
def verify(self, key_material, expected_key):
if not constant_time.bytes_eq(self.derive(key_material), expected_key):
raise InvalidKey
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import six
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import HMACBackend
from cryptography.hazmat.primitives import constant_time, hmac
from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
@utils.register_interface(KeyDerivationFunction)
class HKDF(object):
def __init__(self, algorithm, length, salt, info, backend):
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
self._algorithm = algorithm
if salt is None:
salt = b"\x00" * self._algorithm.digest_size
else:
utils._check_bytes("salt", salt)
self._salt = salt
self._backend = backend
self._hkdf_expand = HKDFExpand(self._algorithm, length, info, backend)
def _extract(self, key_material):
h = hmac.HMAC(self._salt, self._algorithm, backend=self._backend)
h.update(key_material)
return h.finalize()
def derive(self, key_material):
utils._check_byteslike("key_material", key_material)
return self._hkdf_expand.derive(self._extract(key_material))
def verify(self, key_material, expected_key):
if not constant_time.bytes_eq(self.derive(key_material), expected_key):
raise InvalidKey
@utils.register_interface(KeyDerivationFunction)
class HKDFExpand(object):
def __init__(self, algorithm, length, info, backend):
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
self._algorithm = algorithm
self._backend = backend
max_length = 255 * algorithm.digest_size
if length > max_length:
raise ValueError(
"Can not derive keys larger than {} octets.".format(
max_length
))
self._length = length
if info is None:
info = b""
else:
utils._check_bytes("info", info)
self._info = info
self._used = False
def _expand(self, key_material):
output = [b""]
counter = 1
while self._algorithm.digest_size * (len(output) - 1) < self._length:
h = hmac.HMAC(key_material, self._algorithm, backend=self._backend)
h.update(output[-1])
h.update(self._info)
h.update(six.int2byte(counter))
output.append(h.finalize())
counter += 1
return b"".join(output)[:self._length]
def derive(self, key_material):
utils._check_byteslike("key_material", key_material)
if self._used:
raise AlreadyFinalized
self._used = True
return self._expand(key_material)
def verify(self, key_material, expected_key):
if not constant_time.bytes_eq(self.derive(key_material), expected_key):
raise InvalidKey
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from enum import Enum
from six.moves import range
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import HMACBackend
from cryptography.hazmat.primitives import constant_time, hashes, hmac
from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
class Mode(Enum):
CounterMode = "ctr"
class CounterLocation(Enum):
BeforeFixed = "before_fixed"
AfterFixed = "after_fixed"
@utils.register_interface(KeyDerivationFunction)
class KBKDFHMAC(object):
def __init__(self, algorithm, mode, length, rlen, llen,
location, label, context, fixed, backend):
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
if not isinstance(algorithm, hashes.HashAlgorithm):
raise UnsupportedAlgorithm(
"Algorithm supplied is not a supported hash algorithm.",
_Reasons.UNSUPPORTED_HASH
)
if not backend.hmac_supported(algorithm):
raise UnsupportedAlgorithm(
"Algorithm supplied is not a supported hmac algorithm.",
_Reasons.UNSUPPORTED_HASH
)
if not isinstance(mode, Mode):
raise TypeError("mode must be of type Mode")
if not isinstance(location, CounterLocation):
raise TypeError("location must be of type CounterLocation")
if (label or context) and fixed:
raise ValueError("When supplying fixed data, "
"label and context are ignored.")
if rlen is None or not self._valid_byte_length(rlen):
raise ValueError("rlen must be between 1 and 4")
if llen is None and fixed is None:
raise ValueError("Please specify an llen")
if llen is not None and not isinstance(llen, int):
raise TypeError("llen must be an integer")
if label is None:
label = b''
if context is None:
context = b''
utils._check_bytes("label", label)
utils._check_bytes("context", context)
self._algorithm = algorithm
self._mode = mode
self._length = length
self._rlen = rlen
self._llen = llen
self._location = location
self._label = label
self._context = context
self._backend = backend
self._used = False
self._fixed_data = fixed
def _valid_byte_length(self, value):
if not isinstance(value, int):
raise TypeError('value must be of type int')
value_bin = utils.int_to_bytes(1, value)
if not 1 <= len(value_bin) <= 4:
return False
return True
def derive(self, key_material):
if self._used:
raise AlreadyFinalized
utils._check_byteslike("key_material", key_material)
self._used = True
# inverse floor division (equivalent to ceiling)
rounds = -(-self._length // self._algorithm.digest_size)
output = [b'']
# For counter mode, the number of iterations shall not be
# larger than 2^r-1, where r <= 32 is the binary length of the counter
# This ensures that the counter values used as an input to the
# PRF will not repeat during a particular call to the KDF function.
r_bin = utils.int_to_bytes(1, self._rlen)
if rounds > pow(2, len(r_bin) * 8) - 1:
raise ValueError('There are too many iterations.')
for i in range(1, rounds + 1):
h = hmac.HMAC(key_material, self._algorithm, backend=self._backend)
counter = utils.int_to_bytes(i, self._rlen)
if self._location == CounterLocation.BeforeFixed:
h.update(counter)
h.update(self._generate_fixed_input())
if self._location == CounterLocation.AfterFixed:
h.update(counter)
output.append(h.finalize())
return b''.join(output)[:self._length]
def _generate_fixed_input(self):
if self._fixed_data and isinstance(self._fixed_data, bytes):
return self._fixed_data
l_val = utils.int_to_bytes(self._length * 8, self._llen)
return b"".join([self._label, b"\x00", self._context, l_val])
def verify(self, key_material, expected_key):
if not constant_time.bytes_eq(self.derive(key_material), expected_key):
raise InvalidKey
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import PBKDF2HMACBackend
from cryptography.hazmat.primitives import constant_time
from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
@utils.register_interface(KeyDerivationFunction)
class PBKDF2HMAC(object):
def __init__(self, algorithm, length, salt, iterations, backend):
if not isinstance(backend, PBKDF2HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement PBKDF2HMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
if not backend.pbkdf2_hmac_supported(algorithm):
raise UnsupportedAlgorithm(
"{} is not supported for PBKDF2 by this backend.".format(
algorithm.name),
_Reasons.UNSUPPORTED_HASH
)
self._used = False
self._algorithm = algorithm
self._length = length
utils._check_bytes("salt", salt)
self._salt = salt
self._iterations = iterations
self._backend = backend
def derive(self, key_material):
if self._used:
raise AlreadyFinalized("PBKDF2 instances can only be used once.")
self._used = True
utils._check_byteslike("key_material", key_material)
return self._backend.derive_pbkdf2_hmac(
self._algorithm,
self._length,
self._salt,
self._iterations,
key_material
)
def verify(self, key_material, expected_key):
derived_key = self.derive(key_material)
if not constant_time.bytes_eq(derived_key, expected_key):
raise InvalidKey("Keys do not match.")
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import sys
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import ScryptBackend
from cryptography.hazmat.primitives import constant_time
from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
# This is used by the scrypt tests to skip tests that require more memory
# than the MEM_LIMIT
_MEM_LIMIT = sys.maxsize // 2
@utils.register_interface(KeyDerivationFunction)
class Scrypt(object):
def __init__(self, salt, length, n, r, p, backend):
if not isinstance(backend, ScryptBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement ScryptBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
self._length = length
utils._check_bytes("salt", salt)
if n < 2 or (n & (n - 1)) != 0:
raise ValueError("n must be greater than 1 and be a power of 2.")
if r < 1:
raise ValueError("r must be greater than or equal to 1.")
if p < 1:
raise ValueError("p must be greater than or equal to 1.")
self._used = False
self._salt = salt
self._n = n
self._r = r
self._p = p
self._backend = backend
def derive(self, key_material):
if self._used:
raise AlreadyFinalized("Scrypt instances can only be used once.")
self._used = True
utils._check_byteslike("key_material", key_material)
return self._backend.derive_scrypt(
key_material, self._salt, self._length, self._n, self._r, self._p
)
def verify(self, key_material, expected_key):
derived_key = self.derive(key_material)
if not constant_time.bytes_eq(derived_key, expected_key):
raise InvalidKey("Keys do not match.")
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import struct
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import HashBackend
from cryptography.hazmat.primitives import constant_time, hashes
from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
def _int_to_u32be(n):
return struct.pack('>I', n)
@utils.register_interface(KeyDerivationFunction)
class X963KDF(object):
def __init__(self, algorithm, length, sharedinfo, backend):
max_len = algorithm.digest_size * (2 ** 32 - 1)
if length > max_len:
raise ValueError(
"Can not derive keys larger than {} bits.".format(max_len))
if sharedinfo is not None:
utils._check_bytes("sharedinfo", sharedinfo)
self._algorithm = algorithm
self._length = length
self._sharedinfo = sharedinfo
if not isinstance(backend, HashBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HashBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
self._backend = backend
self._used = False
def derive(self, key_material):
if self._used:
raise AlreadyFinalized
self._used = True
utils._check_byteslike("key_material", key_material)
output = [b""]
outlen = 0
counter = 1
while self._length > outlen:
h = hashes.Hash(self._algorithm, self._backend)
h.update(key_material)
h.update(_int_to_u32be(counter))
if self._sharedinfo is not None:
h.update(self._sharedinfo)
output.append(h.finalize())
outlen += len(output[-1])
counter += 1
return b"".join(output)[:self._length]
def verify(self, key_material, expected_key):
if not constant_time.bytes_eq(self.derive(key_material), expected_key):
raise InvalidKey
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/keywrap.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import struct
from cryptography.hazmat.primitives.ciphers import Cipher
from cryptography.hazmat.primitives.ciphers.algorithms import AES
from cryptography.hazmat.primitives.ciphers.modes import ECB
from cryptography.hazmat.primitives.constant_time import bytes_eq
def _wrap_core(wrapping_key, a, r, backend):
# RFC 3394 Key Wrap - 2.2.1 (index method)
encryptor = Cipher(AES(wrapping_key), ECB(), backend).encryptor()
n = len(r)
for j in range(6):
for i in range(n):
# every encryption operation is a discrete 16 byte chunk (because
# AES has a 128-bit block size) and since we're using ECB it is
# safe to reuse the encryptor for the entire operation
b = encryptor.update(a + r[i])
# pack/unpack are safe as these are always 64-bit chunks
a = struct.pack(
">Q", struct.unpack(">Q", b[:8])[0] ^ ((n * j) + i + 1)
)
r[i] = b[-8:]
assert encryptor.finalize() == b""
return a + b"".join(r)
def aes_key_wrap(wrapping_key, key_to_wrap, backend):
if len(wrapping_key) not in [16, 24, 32]:
raise ValueError("The wrapping key must be a valid AES key length")
if len(key_to_wrap) < 16:
raise ValueError("The key to wrap must be at least 16 bytes")
if len(key_to_wrap) % 8 != 0:
raise ValueError("The key to wrap must be a multiple of 8 bytes")
a = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6"
r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)]
return _wrap_core(wrapping_key, a, r, backend)
def _unwrap_core(wrapping_key, a, r, backend):
# Implement RFC 3394 Key Unwrap - 2.2.2 (index method)
decryptor = Cipher(AES(wrapping_key), ECB(), backend).decryptor()
n = len(r)
for j in reversed(range(6)):
for i in reversed(range(n)):
# pack/unpack are safe as these are always 64-bit chunks
atr = struct.pack(
">Q", struct.unpack(">Q", a)[0] ^ ((n * j) + i + 1)
) + r[i]
# every decryption operation is a discrete 16 byte chunk so
# it is safe to reuse the decryptor for the entire operation
b = decryptor.update(atr)
a = b[:8]
r[i] = b[-8:]
assert decryptor.finalize() == b""
return a, r
def aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend):
if len(wrapping_key) not in [16, 24, 32]:
raise ValueError("The wrapping key must be a valid AES key length")
aiv = b"\xA6\x59\x59\xA6" + struct.pack(">i", len(key_to_wrap))
# pad the key to wrap if necessary
pad = (8 - (len(key_to_wrap) % 8)) % 8
key_to_wrap = key_to_wrap + b"\x00" * pad
if len(key_to_wrap) == 8:
# RFC 5649 - 4.1 - exactly 8 octets after padding
encryptor = Cipher(AES(wrapping_key), ECB(), backend).encryptor()
b = encryptor.update(aiv + key_to_wrap)
assert encryptor.finalize() == b""
return b
else:
r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)]
return _wrap_core(wrapping_key, aiv, r, backend)
def aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend):
if len(wrapped_key) < 16:
raise InvalidUnwrap("Must be at least 16 bytes")
if len(wrapping_key) not in [16, 24, 32]:
raise ValueError("The wrapping key must be a valid AES key length")
if len(wrapped_key) == 16:
# RFC 5649 - 4.2 - exactly two 64-bit blocks
decryptor = Cipher(AES(wrapping_key), ECB(), backend).decryptor()
b = decryptor.update(wrapped_key)
assert decryptor.finalize() == b""
a = b[:8]
data = b[8:]
n = 1
else:
r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)]
encrypted_aiv = r.pop(0)
n = len(r)
a, r = _unwrap_core(wrapping_key, encrypted_aiv, r, backend)
data = b"".join(r)
# 1) Check that MSB(32,A) = A65959A6.
# 2) Check that 8*(n-1) < LSB(32,A) <= 8*n. If so, let
# MLI = LSB(32,A).
# 3) Let b = (8*n)-MLI, and then check that the rightmost b octets of
# the output data are zero.
(mli,) = struct.unpack(">I", a[4:])
b = (8 * n) - mli
if (
not bytes_eq(a[:4], b"\xa6\x59\x59\xa6") or not
8 * (n - 1) < mli <= 8 * n or (
b != 0 and not bytes_eq(data[-b:], b"\x00" * b)
)
):
raise InvalidUnwrap()
if b == 0:
return data
else:
return data[:-b]
def aes_key_unwrap(wrapping_key, wrapped_key, backend):
if len(wrapped_key) < 24:
raise InvalidUnwrap("Must be at least 24 bytes")
if len(wrapped_key) % 8 != 0:
raise InvalidUnwrap("The wrapped key must be a multiple of 8 bytes")
if len(wrapping_key) not in [16, 24, 32]:
raise ValueError("The wrapping key must be a valid AES key length")
aiv = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6"
r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)]
a = r.pop(0)
a, r = _unwrap_core(wrapping_key, a, r, backend)
if not bytes_eq(a, aiv):
raise InvalidUnwrap()
return b"".join(r)
class InvalidUnwrap(Exception):
pass
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/padding.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import six
from cryptography import utils
from cryptography.exceptions import AlreadyFinalized
from cryptography.hazmat.bindings._padding import lib
@six.add_metaclass(abc.ABCMeta)
class PaddingContext(object):
@abc.abstractmethod
def update(self, data):
"""
Pads the provided bytes and returns any available data as bytes.
"""
@abc.abstractmethod
def finalize(self):
"""
Finalize the padding, returns bytes.
"""
def _byte_padding_check(block_size):
if not (0 <= block_size <= 2040):
raise ValueError("block_size must be in range(0, 2041).")
if block_size % 8 != 0:
raise ValueError("block_size must be a multiple of 8.")
def _byte_padding_update(buffer_, data, block_size):
if buffer_ is None:
raise AlreadyFinalized("Context was already finalized.")
utils._check_bytes("data", data)
buffer_ += data
finished_blocks = len(buffer_) // (block_size // 8)
result = buffer_[:finished_blocks * (block_size // 8)]
buffer_ = buffer_[finished_blocks * (block_size // 8):]
return buffer_, result
def _byte_padding_pad(buffer_, block_size, paddingfn):
if buffer_ is None:
raise AlreadyFinalized("Context was already finalized.")
pad_size = block_size // 8 - len(buffer_)
return buffer_ + paddingfn(pad_size)
def _byte_unpadding_update(buffer_, data, block_size):
if buffer_ is None:
raise AlreadyFinalized("Context was already finalized.")
utils._check_bytes("data", data)
buffer_ += data
finished_blocks = max(len(buffer_) // (block_size // 8) - 1, 0)
result = buffer_[:finished_blocks * (block_size // 8)]
buffer_ = buffer_[finished_blocks * (block_size // 8):]
return buffer_, result
def _byte_unpadding_check(buffer_, block_size, checkfn):
if buffer_ is None:
raise AlreadyFinalized("Context was already finalized.")
if len(buffer_) != block_size // 8:
raise ValueError("Invalid padding bytes.")
valid = checkfn(buffer_, block_size // 8)
if not valid:
raise ValueError("Invalid padding bytes.")
pad_size = six.indexbytes(buffer_, -1)
return buffer_[:-pad_size]
class PKCS7(object):
def __init__(self, block_size):
_byte_padding_check(block_size)
self.block_size = block_size
def padder(self):
return _PKCS7PaddingContext(self.block_size)
def unpadder(self):
return _PKCS7UnpaddingContext(self.block_size)
@utils.register_interface(PaddingContext)
class _PKCS7PaddingContext(object):
def __init__(self, block_size):
self.block_size = block_size
# TODO: more copies than necessary, we should use zero-buffer (#193)
self._buffer = b""
def update(self, data):
self._buffer, result = _byte_padding_update(
self._buffer, data, self.block_size)
return result
def _padding(self, size):
return six.int2byte(size) * size
def finalize(self):
result = _byte_padding_pad(
self._buffer, self.block_size, self._padding)
self._buffer = None
return result
@utils.register_interface(PaddingContext)
class _PKCS7UnpaddingContext(object):
def __init__(self, block_size):
self.block_size = block_size
# TODO: more copies than necessary, we should use zero-buffer (#193)
self._buffer = b""
def update(self, data):
self._buffer, result = _byte_unpadding_update(
self._buffer, data, self.block_size)
return result
def finalize(self):
result = _byte_unpadding_check(
self._buffer, self.block_size,
lib.Cryptography_check_pkcs7_padding)
self._buffer = None
return result
class ANSIX923(object):
def __init__(self, block_size):
_byte_padding_check(block_size)
self.block_size = block_size
def padder(self):
return _ANSIX923PaddingContext(self.block_size)
def unpadder(self):
return _ANSIX923UnpaddingContext(self.block_size)
@utils.register_interface(PaddingContext)
class _ANSIX923PaddingContext(object):
def __init__(self, block_size):
self.block_size = block_size
# TODO: more copies than necessary, we should use zero-buffer (#193)
self._buffer = b""
def update(self, data):
self._buffer, result = _byte_padding_update(
self._buffer, data, self.block_size)
return result
def _padding(self, size):
return six.int2byte(0) * (size - 1) + six.int2byte(size)
def finalize(self):
result = _byte_padding_pad(
self._buffer, self.block_size, self._padding)
self._buffer = None
return result
@utils.register_interface(PaddingContext)
class _ANSIX923UnpaddingContext(object):
def __init__(self, block_size):
self.block_size = block_size
# TODO: more copies than necessary, we should use zero-buffer (#193)
self._buffer = b""
def update(self, data):
self._buffer, result = _byte_unpadding_update(
self._buffer, data, self.block_size)
return result
def finalize(self):
result = _byte_unpadding_check(
self._buffer, self.block_size,
lib.Cryptography_check_ansix923_padding)
self._buffer = None
return result
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/poly1305.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, UnsupportedAlgorithm, _Reasons
)
class Poly1305(object):
def __init__(self, key):
from cryptography.hazmat.backends.openssl.backend import backend
if not backend.poly1305_supported():
raise UnsupportedAlgorithm(
"poly1305 is not supported by this version of OpenSSL.",
_Reasons.UNSUPPORTED_MAC
)
self._ctx = backend.create_poly1305_ctx(key)
def update(self, data):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
utils._check_byteslike("data", data)
self._ctx.update(data)
def finalize(self):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
mac = self._ctx.finalize()
self._ctx = None
return mac
def verify(self, tag):
utils._check_bytes("tag", tag)
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
ctx, self._ctx = self._ctx, None
ctx.verify(tag)
@classmethod
def generate_tag(cls, key, data):
p = Poly1305(key)
p.update(data)
return p.finalize()
@classmethod
def verify_tag(cls, key, data, tag):
p = Poly1305(key)
p.update(data)
p.verify(tag)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/serialization/__init__.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography.hazmat.primitives.serialization.base import (
BestAvailableEncryption, Encoding, KeySerializationEncryption,
NoEncryption, ParameterFormat, PrivateFormat, PublicFormat,
load_der_parameters, load_der_private_key, load_der_public_key,
load_pem_parameters, load_pem_private_key, load_pem_public_key,
)
from cryptography.hazmat.primitives.serialization.ssh import (
load_ssh_public_key
)
_PEM_DER = (Encoding.PEM, Encoding.DER)
__all__ = [
"load_der_parameters", "load_der_private_key", "load_der_public_key",
"load_pem_parameters", "load_pem_private_key", "load_pem_public_key",
"load_ssh_public_key", "Encoding", "PrivateFormat", "PublicFormat",
"ParameterFormat", "KeySerializationEncryption", "BestAvailableEncryption",
"NoEncryption",
]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/serialization/base.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
from enum import Enum
import six
from cryptography import utils
def load_pem_private_key(data, password, backend):
return backend.load_pem_private_key(data, password)
def load_pem_public_key(data, backend):
return backend.load_pem_public_key(data)
def load_pem_parameters(data, backend):
return backend.load_pem_parameters(data)
def load_der_private_key(data, password, backend):
return backend.load_der_private_key(data, password)
def load_der_public_key(data, backend):
return backend.load_der_public_key(data)
def load_der_parameters(data, backend):
return backend.load_der_parameters(data)
class Encoding(Enum):
PEM = "PEM"
DER = "DER"
OpenSSH = "OpenSSH"
Raw = "Raw"
X962 = "ANSI X9.62"
class PrivateFormat(Enum):
PKCS8 = "PKCS8"
TraditionalOpenSSL = "TraditionalOpenSSL"
Raw = "Raw"
class PublicFormat(Enum):
SubjectPublicKeyInfo = "X.509 subjectPublicKeyInfo with PKCS#1"
PKCS1 = "Raw PKCS#1"
OpenSSH = "OpenSSH"
Raw = "Raw"
CompressedPoint = "X9.62 Compressed Point"
UncompressedPoint = "X9.62 Uncompressed Point"
class ParameterFormat(Enum):
PKCS3 = "PKCS3"
@six.add_metaclass(abc.ABCMeta)
class KeySerializationEncryption(object):
pass
@utils.register_interface(KeySerializationEncryption)
class BestAvailableEncryption(object):
def __init__(self, password):
if not isinstance(password, bytes) or len(password) == 0:
raise ValueError("Password must be 1 or more bytes.")
self.password = password
@utils.register_interface(KeySerializationEncryption)
class NoEncryption(object):
pass
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
def load_key_and_certificates(data, password, backend):
return backend.load_key_and_certificates_from_pkcs12(data, password)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/serialization/ssh.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import base64
import struct
import six
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.primitives.asymmetric import dsa, ec, ed25519, rsa
def load_ssh_public_key(data, backend):
key_parts = data.split(b' ', 2)
if len(key_parts) < 2:
raise ValueError(
'Key is not in the proper format or contains extra data.')
key_type = key_parts[0]
if key_type == b'ssh-rsa':
loader = _load_ssh_rsa_public_key
elif key_type == b'ssh-dss':
loader = _load_ssh_dss_public_key
elif key_type in [
b'ecdsa-sha2-nistp256', b'ecdsa-sha2-nistp384', b'ecdsa-sha2-nistp521',
]:
loader = _load_ssh_ecdsa_public_key
elif key_type == b'ssh-ed25519':
loader = _load_ssh_ed25519_public_key
else:
raise UnsupportedAlgorithm('Key type is not supported.')
key_body = key_parts[1]
try:
decoded_data = base64.b64decode(key_body)
except TypeError:
raise ValueError('Key is not in the proper format.')
inner_key_type, rest = _ssh_read_next_string(decoded_data)
if inner_key_type != key_type:
raise ValueError(
'Key header and key body contain different key type values.'
)
return loader(key_type, rest, backend)
def _load_ssh_rsa_public_key(key_type, decoded_data, backend):
e, rest = _ssh_read_next_mpint(decoded_data)
n, rest = _ssh_read_next_mpint(rest)
if rest:
raise ValueError('Key body contains extra bytes.')
return rsa.RSAPublicNumbers(e, n).public_key(backend)
def _load_ssh_dss_public_key(key_type, decoded_data, backend):
p, rest = _ssh_read_next_mpint(decoded_data)
q, rest = _ssh_read_next_mpint(rest)
g, rest = _ssh_read_next_mpint(rest)
y, rest = _ssh_read_next_mpint(rest)
if rest:
raise ValueError('Key body contains extra bytes.')
parameter_numbers = dsa.DSAParameterNumbers(p, q, g)
public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers)
return public_numbers.public_key(backend)
def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend):
curve_name, rest = _ssh_read_next_string(decoded_data)
data, rest = _ssh_read_next_string(rest)
if expected_key_type != b"ecdsa-sha2-" + curve_name:
raise ValueError(
'Key header and key body contain different key type values.'
)
if rest:
raise ValueError('Key body contains extra bytes.')
curve = {
b"nistp256": ec.SECP256R1,
b"nistp384": ec.SECP384R1,
b"nistp521": ec.SECP521R1,
}[curve_name]()
if six.indexbytes(data, 0) != 4:
raise NotImplementedError(
"Compressed elliptic curve points are not supported"
)
return ec.EllipticCurvePublicKey.from_encoded_point(curve, data)
def _load_ssh_ed25519_public_key(expected_key_type, decoded_data, backend):
data, rest = _ssh_read_next_string(decoded_data)
if rest:
raise ValueError('Key body contains extra bytes.')
return ed25519.Ed25519PublicKey.from_public_bytes(data)
def _ssh_read_next_string(data):
"""
Retrieves the next RFC 4251 string value from the data.
While the RFC calls these strings, in Python they are bytes objects.
"""
if len(data) < 4:
raise ValueError("Key is not in the proper format")
str_len, = struct.unpack('>I', data[:4])
if len(data) < str_len + 4:
raise ValueError("Key is not in the proper format")
return data[4:4 + str_len], data[4 + str_len:]
def _ssh_read_next_mpint(data):
"""
Reads the next mpint from the data.
Currently, all mpints are interpreted as unsigned.
"""
mpint_data, rest = _ssh_read_next_string(data)
return (
utils.int_from_bytes(mpint_data, byteorder='big', signed=False), rest
)
def _ssh_write_string(data):
return struct.pack(">I", len(data)) + data
def _ssh_write_mpint(value):
data = utils.int_to_bytes(value)
if six.indexbytes(data, 0) & 0x80:
data = b"\x00" + data
return _ssh_write_string(data)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
class InvalidToken(Exception):
pass
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import struct
import six
from cryptography.exceptions import (
UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import HMACBackend
from cryptography.hazmat.primitives import constant_time, hmac
from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512
from cryptography.hazmat.primitives.twofactor import InvalidToken
from cryptography.hazmat.primitives.twofactor.utils import _generate_uri
class HOTP(object):
def __init__(self, key, length, algorithm, backend,
enforce_key_length=True):
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
if len(key) < 16 and enforce_key_length is True:
raise ValueError("Key length has to be at least 128 bits.")
if not isinstance(length, six.integer_types):
raise TypeError("Length parameter must be an integer type.")
if length < 6 or length > 8:
raise ValueError("Length of HOTP has to be between 6 to 8.")
if not isinstance(algorithm, (SHA1, SHA256, SHA512)):
raise TypeError("Algorithm must be SHA1, SHA256 or SHA512.")
self._key = key
self._length = length
self._algorithm = algorithm
self._backend = backend
def generate(self, counter):
truncated_value = self._dynamic_truncate(counter)
hotp = truncated_value % (10 ** self._length)
return "{0:0{1}}".format(hotp, self._length).encode()
def verify(self, hotp, counter):
if not constant_time.bytes_eq(self.generate(counter), hotp):
raise InvalidToken("Supplied HOTP value does not match.")
def _dynamic_truncate(self, counter):
ctx = hmac.HMAC(self._key, self._algorithm, self._backend)
ctx.update(struct.pack(">Q", counter))
hmac_value = ctx.finalize()
offset = six.indexbytes(hmac_value, len(hmac_value) - 1) & 0b1111
p = hmac_value[offset:offset + 4]
return struct.unpack(">I", p)[0] & 0x7fffffff
def get_provisioning_uri(self, account_name, counter, issuer):
return _generate_uri(self, "hotp", account_name, issuer, [
("counter", int(counter)),
])
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/twofactor/totp.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography.exceptions import (
UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import HMACBackend
from cryptography.hazmat.primitives import constant_time
from cryptography.hazmat.primitives.twofactor import InvalidToken
from cryptography.hazmat.primitives.twofactor.hotp import HOTP
from cryptography.hazmat.primitives.twofactor.utils import _generate_uri
class TOTP(object):
def __init__(self, key, length, algorithm, time_step, backend,
enforce_key_length=True):
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
self._time_step = time_step
self._hotp = HOTP(key, length, algorithm, backend, enforce_key_length)
def generate(self, time):
counter = int(time / self._time_step)
return self._hotp.generate(counter)
def verify(self, totp, time):
if not constant_time.bytes_eq(self.generate(time), totp):
raise InvalidToken("Supplied TOTP value does not match.")
def get_provisioning_uri(self, account_name, issuer):
return _generate_uri(self._hotp, "totp", account_name, issuer, [
("period", int(self._time_step)),
])
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/hazmat/primitives/twofactor/utils.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import base64
from six.moves.urllib.parse import quote, urlencode
def _generate_uri(hotp, type_name, account_name, issuer, extra_parameters):
parameters = [
("digits", hotp._length),
("secret", base64.b32encode(hotp._key)),
("algorithm", hotp._algorithm.name.upper()),
]
if issuer is not None:
parameters.append(("issuer", issuer))
parameters.extend(extra_parameters)
uriparts = {
"type": type_name,
"label": ("%s:%s" % (quote(issuer), quote(account_name)) if issuer
else quote(account_name)),
"parameters": urlencode(parameters),
}
return "otpauth://{type}/{label}?{parameters}".format(**uriparts)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/utils.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import binascii
import inspect
import sys
import warnings
# We use a UserWarning subclass, instead of DeprecationWarning, because CPython
# decided deprecation warnings should be invisble by default.
class CryptographyDeprecationWarning(UserWarning):
pass
# Several APIs were deprecated with no specific end-of-life date because of the
# ubiquity of their use. They should not be removed until we agree on when that
# cycle ends.
PersistentlyDeprecated2017 = CryptographyDeprecationWarning
PersistentlyDeprecated2018 = CryptographyDeprecationWarning
DeprecatedIn25 = CryptographyDeprecationWarning
DeprecatedIn27 = CryptographyDeprecationWarning
def _check_bytes(name, value):
if not isinstance(value, bytes):
raise TypeError("{} must be bytes".format(name))
def _check_byteslike(name, value):
try:
memoryview(value)
except TypeError:
raise TypeError("{} must be bytes-like".format(name))
def read_only_property(name):
return property(lambda self: getattr(self, name))
def register_interface(iface):
def register_decorator(klass):
verify_interface(iface, klass)
iface.register(klass)
return klass
return register_decorator
def register_interface_if(predicate, iface):
def register_decorator(klass):
if predicate:
verify_interface(iface, klass)
iface.register(klass)
return klass
return register_decorator
if hasattr(int, "from_bytes"):
int_from_bytes = int.from_bytes
else:
def int_from_bytes(data, byteorder, signed=False):
assert byteorder == 'big'
assert not signed
return int(binascii.hexlify(data), 16)
if hasattr(int, "to_bytes"):
def int_to_bytes(integer, length=None):
return integer.to_bytes(
length or (integer.bit_length() + 7) // 8 or 1, 'big'
)
else:
def int_to_bytes(integer, length=None):
hex_string = '%x' % integer
if length is None:
n = len(hex_string)
else:
n = length * 2
return binascii.unhexlify(hex_string.zfill(n + (n & 1)))
class InterfaceNotImplemented(Exception):
pass
if hasattr(inspect, "signature"):
signature = inspect.signature
else:
signature = inspect.getargspec
def verify_interface(iface, klass):
for method in iface.__abstractmethods__:
if not hasattr(klass, method):
raise InterfaceNotImplemented(
"{} is missing a {!r} method".format(klass, method)
)
if isinstance(getattr(iface, method), abc.abstractproperty):
# Can't properly verify these yet.
continue
sig = signature(getattr(iface, method))
actual = signature(getattr(klass, method))
if sig != actual:
raise InterfaceNotImplemented(
"{}.{}'s signature differs from the expected. Expected: "
"{!r}. Received: {!r}".format(
klass, method, sig, actual
)
)
# No longer needed as of 2.2, but retained because we have external consumers
# who use it.
def bit_length(x):
return x.bit_length()
class _DeprecatedValue(object):
def __init__(self, value, message, warning_class):
self.value = value
self.message = message
self.warning_class = warning_class
class _ModuleWithDeprecations(object):
def __init__(self, module):
self.__dict__["_module"] = module
def __getattr__(self, attr):
obj = getattr(self._module, attr)
if isinstance(obj, _DeprecatedValue):
warnings.warn(obj.message, obj.warning_class, stacklevel=2)
obj = obj.value
return obj
def __setattr__(self, attr, value):
setattr(self._module, attr, value)
def __delattr__(self, attr):
obj = getattr(self._module, attr)
if isinstance(obj, _DeprecatedValue):
warnings.warn(obj.message, obj.warning_class, stacklevel=2)
delattr(self._module, attr)
def __dir__(self):
return ["_module"] + dir(self._module)
def deprecated(value, module_name, message, warning_class):
module = sys.modules[module_name]
if not isinstance(module, _ModuleWithDeprecations):
sys.modules[module_name] = _ModuleWithDeprecations(module)
return _DeprecatedValue(value, message, warning_class)
def cached_property(func):
cached_name = "_cached_{}".format(func)
sentinel = object()
def inner(instance):
cache = getattr(instance, cached_name, sentinel)
if cache is not sentinel:
return cache
result = func(instance)
setattr(instance, cached_name, result)
return result
return property(inner)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/x509/__init__.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography.x509 import certificate_transparency
from cryptography.x509.base import (
Certificate, CertificateBuilder, CertificateRevocationList,
CertificateRevocationListBuilder,
CertificateSigningRequest, CertificateSigningRequestBuilder,
InvalidVersion, RevokedCertificate, RevokedCertificateBuilder,
Version, load_der_x509_certificate, load_der_x509_crl, load_der_x509_csr,
load_pem_x509_certificate, load_pem_x509_crl, load_pem_x509_csr,
random_serial_number,
)
from cryptography.x509.extensions import (
AccessDescription, AuthorityInformationAccess,
AuthorityKeyIdentifier, BasicConstraints, CRLDistributionPoints,
CRLNumber, CRLReason, CertificateIssuer, CertificatePolicies,
DeltaCRLIndicator, DistributionPoint, DuplicateExtension, ExtendedKeyUsage,
Extension, ExtensionNotFound, ExtensionType, Extensions, FreshestCRL,
GeneralNames, InhibitAnyPolicy, InvalidityDate, IssuerAlternativeName,
IssuingDistributionPoint, KeyUsage, NameConstraints, NoticeReference,
OCSPNoCheck, OCSPNonce, PolicyConstraints, PolicyInformation,
PrecertPoison, PrecertificateSignedCertificateTimestamps, ReasonFlags,
SubjectAlternativeName, SubjectKeyIdentifier, TLSFeature, TLSFeatureType,
UnrecognizedExtension, UserNotice
)
from cryptography.x509.general_name import (
DNSName, DirectoryName, GeneralName, IPAddress, OtherName, RFC822Name,
RegisteredID, UniformResourceIdentifier, UnsupportedGeneralNameType,
_GENERAL_NAMES
)
from cryptography.x509.name import (
Name, NameAttribute, RelativeDistinguishedName
)
from cryptography.x509.oid import (
AuthorityInformationAccessOID, CRLEntryExtensionOID,
CertificatePoliciesOID, ExtendedKeyUsageOID, ExtensionOID, NameOID,
ObjectIdentifier, SignatureAlgorithmOID, _SIG_OIDS_TO_HASH
)
OID_AUTHORITY_INFORMATION_ACCESS = ExtensionOID.AUTHORITY_INFORMATION_ACCESS
OID_AUTHORITY_KEY_IDENTIFIER = ExtensionOID.AUTHORITY_KEY_IDENTIFIER
OID_BASIC_CONSTRAINTS = ExtensionOID.BASIC_CONSTRAINTS
OID_CERTIFICATE_POLICIES = ExtensionOID.CERTIFICATE_POLICIES
OID_CRL_DISTRIBUTION_POINTS = ExtensionOID.CRL_DISTRIBUTION_POINTS
OID_EXTENDED_KEY_USAGE = ExtensionOID.EXTENDED_KEY_USAGE
OID_FRESHEST_CRL = ExtensionOID.FRESHEST_CRL
OID_INHIBIT_ANY_POLICY = ExtensionOID.INHIBIT_ANY_POLICY
OID_ISSUER_ALTERNATIVE_NAME = ExtensionOID.ISSUER_ALTERNATIVE_NAME
OID_KEY_USAGE = ExtensionOID.KEY_USAGE
OID_NAME_CONSTRAINTS = ExtensionOID.NAME_CONSTRAINTS
OID_OCSP_NO_CHECK = ExtensionOID.OCSP_NO_CHECK
OID_POLICY_CONSTRAINTS = ExtensionOID.POLICY_CONSTRAINTS
OID_POLICY_MAPPINGS = ExtensionOID.POLICY_MAPPINGS
OID_SUBJECT_ALTERNATIVE_NAME = ExtensionOID.SUBJECT_ALTERNATIVE_NAME
OID_SUBJECT_DIRECTORY_ATTRIBUTES = ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES
OID_SUBJECT_INFORMATION_ACCESS = ExtensionOID.SUBJECT_INFORMATION_ACCESS
OID_SUBJECT_KEY_IDENTIFIER = ExtensionOID.SUBJECT_KEY_IDENTIFIER
OID_DSA_WITH_SHA1 = SignatureAlgorithmOID.DSA_WITH_SHA1
OID_DSA_WITH_SHA224 = SignatureAlgorithmOID.DSA_WITH_SHA224
OID_DSA_WITH_SHA256 = SignatureAlgorithmOID.DSA_WITH_SHA256
OID_ECDSA_WITH_SHA1 = SignatureAlgorithmOID.ECDSA_WITH_SHA1
OID_ECDSA_WITH_SHA224 = SignatureAlgorithmOID.ECDSA_WITH_SHA224
OID_ECDSA_WITH_SHA256 = SignatureAlgorithmOID.ECDSA_WITH_SHA256
OID_ECDSA_WITH_SHA384 = SignatureAlgorithmOID.ECDSA_WITH_SHA384
OID_ECDSA_WITH_SHA512 = SignatureAlgorithmOID.ECDSA_WITH_SHA512
OID_RSA_WITH_MD5 = SignatureAlgorithmOID.RSA_WITH_MD5
OID_RSA_WITH_SHA1 = SignatureAlgorithmOID.RSA_WITH_SHA1
OID_RSA_WITH_SHA224 = SignatureAlgorithmOID.RSA_WITH_SHA224
OID_RSA_WITH_SHA256 = SignatureAlgorithmOID.RSA_WITH_SHA256
OID_RSA_WITH_SHA384 = SignatureAlgorithmOID.RSA_WITH_SHA384
OID_RSA_WITH_SHA512 = SignatureAlgorithmOID.RSA_WITH_SHA512
OID_RSASSA_PSS = SignatureAlgorithmOID.RSASSA_PSS
OID_COMMON_NAME = NameOID.COMMON_NAME
OID_COUNTRY_NAME = NameOID.COUNTRY_NAME
OID_DOMAIN_COMPONENT = NameOID.DOMAIN_COMPONENT
OID_DN_QUALIFIER = NameOID.DN_QUALIFIER
OID_EMAIL_ADDRESS = NameOID.EMAIL_ADDRESS
OID_GENERATION_QUALIFIER = NameOID.GENERATION_QUALIFIER
OID_GIVEN_NAME = NameOID.GIVEN_NAME
OID_LOCALITY_NAME = NameOID.LOCALITY_NAME
OID_ORGANIZATIONAL_UNIT_NAME = NameOID.ORGANIZATIONAL_UNIT_NAME
OID_ORGANIZATION_NAME = NameOID.ORGANIZATION_NAME
OID_PSEUDONYM = NameOID.PSEUDONYM
OID_SERIAL_NUMBER = NameOID.SERIAL_NUMBER
OID_STATE_OR_PROVINCE_NAME = NameOID.STATE_OR_PROVINCE_NAME
OID_SURNAME = NameOID.SURNAME
OID_TITLE = NameOID.TITLE
OID_CLIENT_AUTH = ExtendedKeyUsageOID.CLIENT_AUTH
OID_CODE_SIGNING = ExtendedKeyUsageOID.CODE_SIGNING
OID_EMAIL_PROTECTION = ExtendedKeyUsageOID.EMAIL_PROTECTION
OID_OCSP_SIGNING = ExtendedKeyUsageOID.OCSP_SIGNING
OID_SERVER_AUTH = ExtendedKeyUsageOID.SERVER_AUTH
OID_TIME_STAMPING = ExtendedKeyUsageOID.TIME_STAMPING
OID_ANY_POLICY = CertificatePoliciesOID.ANY_POLICY
OID_CPS_QUALIFIER = CertificatePoliciesOID.CPS_QUALIFIER
OID_CPS_USER_NOTICE = CertificatePoliciesOID.CPS_USER_NOTICE
OID_CERTIFICATE_ISSUER = CRLEntryExtensionOID.CERTIFICATE_ISSUER
OID_CRL_REASON = CRLEntryExtensionOID.CRL_REASON
OID_INVALIDITY_DATE = CRLEntryExtensionOID.INVALIDITY_DATE
OID_CA_ISSUERS = AuthorityInformationAccessOID.CA_ISSUERS
OID_OCSP = AuthorityInformationAccessOID.OCSP
__all__ = [
"certificate_transparency",
"load_pem_x509_certificate",
"load_der_x509_certificate",
"load_pem_x509_csr",
"load_der_x509_csr",
"load_pem_x509_crl",
"load_der_x509_crl",
"random_serial_number",
"InvalidVersion",
"DeltaCRLIndicator",
"DuplicateExtension",
"ExtensionNotFound",
"UnsupportedGeneralNameType",
"NameAttribute",
"Name",
"RelativeDistinguishedName",
"ObjectIdentifier",
"ExtensionType",
"Extensions",
"Extension",
"ExtendedKeyUsage",
"FreshestCRL",
"IssuingDistributionPoint",
"TLSFeature",
"TLSFeatureType",
"OCSPNoCheck",
"BasicConstraints",
"CRLNumber",
"KeyUsage",
"AuthorityInformationAccess",
"AccessDescription",
"CertificatePolicies",
"PolicyInformation",
"UserNotice",
"NoticeReference",
"SubjectKeyIdentifier",
"NameConstraints",
"CRLDistributionPoints",
"DistributionPoint",
"ReasonFlags",
"InhibitAnyPolicy",
"SubjectAlternativeName",
"IssuerAlternativeName",
"AuthorityKeyIdentifier",
"GeneralNames",
"GeneralName",
"RFC822Name",
"DNSName",
"UniformResourceIdentifier",
"RegisteredID",
"DirectoryName",
"IPAddress",
"OtherName",
"Certificate",
"CertificateRevocationList",
"CertificateRevocationListBuilder",
"CertificateSigningRequest",
"RevokedCertificate",
"RevokedCertificateBuilder",
"CertificateSigningRequestBuilder",
"CertificateBuilder",
"Version",
"_SIG_OIDS_TO_HASH",
"OID_CA_ISSUERS",
"OID_OCSP",
"_GENERAL_NAMES",
"CertificateIssuer",
"CRLReason",
"InvalidityDate",
"UnrecognizedExtension",
"PolicyConstraints",
"PrecertificateSignedCertificateTimestamps",
"PrecertPoison",
"OCSPNonce",
]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/x509/base.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import datetime
import os
from enum import Enum
import six
from cryptography import utils
from cryptography.hazmat.primitives.asymmetric import (
dsa, ec, ed25519, ed448, rsa
)
from cryptography.x509.extensions import Extension, ExtensionType
from cryptography.x509.name import Name
_EARLIEST_UTC_TIME = datetime.datetime(1950, 1, 1)
def _reject_duplicate_extension(extension, extensions):
# This is quadratic in the number of extensions
for e in extensions:
if e.oid == extension.oid:
raise ValueError('This extension has already been set.')
def _convert_to_naive_utc_time(time):
"""Normalizes a datetime to a naive datetime in UTC.
time -- datetime to normalize. Assumed to be in UTC if not timezone
aware.
"""
if time.tzinfo is not None:
offset = time.utcoffset()
offset = offset if offset else datetime.timedelta()
return time.replace(tzinfo=None) - offset
else:
return time
class Version(Enum):
v1 = 0
v3 = 2
def load_pem_x509_certificate(data, backend):
return backend.load_pem_x509_certificate(data)
def load_der_x509_certificate(data, backend):
return backend.load_der_x509_certificate(data)
def load_pem_x509_csr(data, backend):
return backend.load_pem_x509_csr(data)
def load_der_x509_csr(data, backend):
return backend.load_der_x509_csr(data)
def load_pem_x509_crl(data, backend):
return backend.load_pem_x509_crl(data)
def load_der_x509_crl(data, backend):
return backend.load_der_x509_crl(data)
class InvalidVersion(Exception):
def __init__(self, msg, parsed_version):
super(InvalidVersion, self).__init__(msg)
self.parsed_version = parsed_version
@six.add_metaclass(abc.ABCMeta)
class Certificate(object):
@abc.abstractmethod
def fingerprint(self, algorithm):
"""
Returns bytes using digest passed.
"""
@abc.abstractproperty
def serial_number(self):
"""
Returns certificate serial number
"""
@abc.abstractproperty
def version(self):
"""
Returns the certificate version
"""
@abc.abstractmethod
def public_key(self):
"""
Returns the public key
"""
@abc.abstractproperty
def not_valid_before(self):
"""
Not before time (represented as UTC datetime)
"""
@abc.abstractproperty
def not_valid_after(self):
"""
Not after time (represented as UTC datetime)
"""
@abc.abstractproperty
def issuer(self):
"""
Returns the issuer name object.
"""
@abc.abstractproperty
def subject(self):
"""
Returns the subject name object.
"""
@abc.abstractproperty
def signature_hash_algorithm(self):
"""
Returns a HashAlgorithm corresponding to the type of the digest signed
in the certificate.
"""
@abc.abstractproperty
def signature_algorithm_oid(self):
"""
Returns the ObjectIdentifier of the signature algorithm.
"""
@abc.abstractproperty
def extensions(self):
"""
Returns an Extensions object.
"""
@abc.abstractproperty
def signature(self):
"""
Returns the signature bytes.
"""
@abc.abstractproperty
def tbs_certificate_bytes(self):
"""
Returns the tbsCertificate payload bytes as defined in RFC 5280.
"""
@abc.abstractmethod
def __eq__(self, other):
"""
Checks equality.
"""
@abc.abstractmethod
def __ne__(self, other):
"""
Checks not equal.
"""
@abc.abstractmethod
def __hash__(self):
"""
Computes a hash.
"""
@abc.abstractmethod
def public_bytes(self, encoding):
"""
Serializes the certificate to PEM or DER format.
"""
@six.add_metaclass(abc.ABCMeta)
class CertificateRevocationList(object):
@abc.abstractmethod
def public_bytes(self, encoding):
"""
Serializes the CRL to PEM or DER format.
"""
@abc.abstractmethod
def fingerprint(self, algorithm):
"""
Returns bytes using digest passed.
"""
@abc.abstractmethod
def get_revoked_certificate_by_serial_number(self, serial_number):
"""
Returns an instance of RevokedCertificate or None if the serial_number
is not in the CRL.
"""
@abc.abstractproperty
def signature_hash_algorithm(self):
"""
Returns a HashAlgorithm corresponding to the type of the digest signed
in the certificate.
"""
@abc.abstractproperty
def signature_algorithm_oid(self):
"""
Returns the ObjectIdentifier of the signature algorithm.
"""
@abc.abstractproperty
def issuer(self):
"""
Returns the X509Name with the issuer of this CRL.
"""
@abc.abstractproperty
def next_update(self):
"""
Returns the date of next update for this CRL.
"""
@abc.abstractproperty
def last_update(self):
"""
Returns the date of last update for this CRL.
"""
@abc.abstractproperty
def extensions(self):
"""
Returns an Extensions object containing a list of CRL extensions.
"""
@abc.abstractproperty
def signature(self):
"""
Returns the signature bytes.
"""
@abc.abstractproperty
def tbs_certlist_bytes(self):
"""
Returns the tbsCertList payload bytes as defined in RFC 5280.
"""
@abc.abstractmethod
def __eq__(self, other):
"""
Checks equality.
"""
@abc.abstractmethod
def __ne__(self, other):
"""
Checks not equal.
"""
@abc.abstractmethod
def __len__(self):
"""
Number of revoked certificates in the CRL.
"""
@abc.abstractmethod
def __getitem__(self, idx):
"""
Returns a revoked certificate (or slice of revoked certificates).
"""
@abc.abstractmethod
def __iter__(self):
"""
Iterator over the revoked certificates
"""
@abc.abstractmethod
def is_signature_valid(self, public_key):
"""
Verifies signature of revocation list against given public key.
"""
@six.add_metaclass(abc.ABCMeta)
class CertificateSigningRequest(object):
@abc.abstractmethod
def __eq__(self, other):
"""
Checks equality.
"""
@abc.abstractmethod
def __ne__(self, other):
"""
Checks not equal.
"""
@abc.abstractmethod
def __hash__(self):
"""
Computes a hash.
"""
@abc.abstractmethod
def public_key(self):
"""
Returns the public key
"""
@abc.abstractproperty
def subject(self):
"""
Returns the subject name object.
"""
@abc.abstractproperty
def signature_hash_algorithm(self):
"""
Returns a HashAlgorithm corresponding to the type of the digest signed
in the certificate.
"""
@abc.abstractproperty
def signature_algorithm_oid(self):
"""
Returns the ObjectIdentifier of the signature algorithm.
"""
@abc.abstractproperty
def extensions(self):
"""
Returns the extensions in the signing request.
"""
@abc.abstractmethod
def public_bytes(self, encoding):
"""
Encodes the request to PEM or DER format.
"""
@abc.abstractproperty
def signature(self):
"""
Returns the signature bytes.
"""
@abc.abstractproperty
def tbs_certrequest_bytes(self):
"""
Returns the PKCS#10 CertificationRequestInfo bytes as defined in RFC
2986.
"""
@abc.abstractproperty
def is_signature_valid(self):
"""
Verifies signature of signing request.
"""
@six.add_metaclass(abc.ABCMeta)
class RevokedCertificate(object):
@abc.abstractproperty
def serial_number(self):
"""
Returns the serial number of the revoked certificate.
"""
@abc.abstractproperty
def revocation_date(self):
"""
Returns the date of when this certificate was revoked.
"""
@abc.abstractproperty
def extensions(self):
"""
Returns an Extensions object containing a list of Revoked extensions.
"""
class CertificateSigningRequestBuilder(object):
def __init__(self, subject_name=None, extensions=[]):
"""
Creates an empty X.509 certificate request (v1).
"""
self._subject_name = subject_name
self._extensions = extensions
def subject_name(self, name):
"""
Sets the certificate requestor's distinguished name.
"""
if not isinstance(name, Name):
raise TypeError('Expecting x509.Name object.')
if self._subject_name is not None:
raise ValueError('The subject name may only be set once.')
return CertificateSigningRequestBuilder(name, self._extensions)
def add_extension(self, extension, critical):
"""
Adds an X.509 extension to the certificate request.
"""
if not isinstance(extension, ExtensionType):
raise TypeError("extension must be an ExtensionType")
extension = Extension(extension.oid, critical, extension)
_reject_duplicate_extension(extension, self._extensions)
return CertificateSigningRequestBuilder(
self._subject_name, self._extensions + [extension]
)
def sign(self, private_key, algorithm, backend):
"""
Signs the request using the requestor's private key.
"""
if self._subject_name is None:
raise ValueError("A CertificateSigningRequest must have a subject")
return backend.create_x509_csr(self, private_key, algorithm)
class CertificateBuilder(object):
def __init__(self, issuer_name=None, subject_name=None,
public_key=None, serial_number=None, not_valid_before=None,
not_valid_after=None, extensions=[]):
self._version = Version.v3
self._issuer_name = issuer_name
self._subject_name = subject_name
self._public_key = public_key
self._serial_number = serial_number
self._not_valid_before = not_valid_before
self._not_valid_after = not_valid_after
self._extensions = extensions
def issuer_name(self, name):
"""
Sets the CA's distinguished name.
"""
if not isinstance(name, Name):
raise TypeError('Expecting x509.Name object.')
if self._issuer_name is not None:
raise ValueError('The issuer name may only be set once.')
return CertificateBuilder(
name, self._subject_name, self._public_key,
self._serial_number, self._not_valid_before,
self._not_valid_after, self._extensions
)
def subject_name(self, name):
"""
Sets the requestor's distinguished name.
"""
if not isinstance(name, Name):
raise TypeError('Expecting x509.Name object.')
if self._subject_name is not None:
raise ValueError('The subject name may only be set once.')
return CertificateBuilder(
self._issuer_name, name, self._public_key,
self._serial_number, self._not_valid_before,
self._not_valid_after, self._extensions
)
def public_key(self, key):
"""
Sets the requestor's public key (as found in the signing request).
"""
if not isinstance(key, (dsa.DSAPublicKey, rsa.RSAPublicKey,
ec.EllipticCurvePublicKey,
ed25519.Ed25519PublicKey,
ed448.Ed448PublicKey)):
raise TypeError('Expecting one of DSAPublicKey, RSAPublicKey,'
' EllipticCurvePublicKey, Ed25519PublicKey or'
' Ed448PublicKey.')
if self._public_key is not None:
raise ValueError('The public key may only be set once.')
return CertificateBuilder(
self._issuer_name, self._subject_name, key,
self._serial_number, self._not_valid_before,
self._not_valid_after, self._extensions
)
def serial_number(self, number):
"""
Sets the certificate serial number.
"""
if not isinstance(number, six.integer_types):
raise TypeError('Serial number must be of integral type.')
if self._serial_number is not None:
raise ValueError('The serial number may only be set once.')
if number <= 0:
raise ValueError('The serial number should be positive.')
# ASN.1 integers are always signed, so most significant bit must be
# zero.
if number.bit_length() >= 160: # As defined in RFC 5280
raise ValueError('The serial number should not be more than 159 '
'bits.')
return CertificateBuilder(
self._issuer_name, self._subject_name,
self._public_key, number, self._not_valid_before,
self._not_valid_after, self._extensions
)
def not_valid_before(self, time):
"""
Sets the certificate activation time.
"""
if not isinstance(time, datetime.datetime):
raise TypeError('Expecting datetime object.')
if self._not_valid_before is not None:
raise ValueError('The not valid before may only be set once.')
time = _convert_to_naive_utc_time(time)
if time < _EARLIEST_UTC_TIME:
raise ValueError('The not valid before date must be on or after'
' 1950 January 1).')
if self._not_valid_after is not None and time > self._not_valid_after:
raise ValueError(
'The not valid before date must be before the not valid after '
'date.'
)
return CertificateBuilder(
self._issuer_name, self._subject_name,
self._public_key, self._serial_number, time,
self._not_valid_after, self._extensions
)
def not_valid_after(self, time):
"""
Sets the certificate expiration time.
"""
if not isinstance(time, datetime.datetime):
raise TypeError('Expecting datetime object.')
if self._not_valid_after is not None:
raise ValueError('The not valid after may only be set once.')
time = _convert_to_naive_utc_time(time)
if time < _EARLIEST_UTC_TIME:
raise ValueError('The not valid after date must be on or after'
' 1950 January 1.')
if (self._not_valid_before is not None and
time < self._not_valid_before):
raise ValueError(
'The not valid after date must be after the not valid before '
'date.'
)
return CertificateBuilder(
self._issuer_name, self._subject_name,
self._public_key, self._serial_number, self._not_valid_before,
time, self._extensions
)
def add_extension(self, extension, critical):
"""
Adds an X.509 extension to the certificate.
"""
if not isinstance(extension, ExtensionType):
raise TypeError("extension must be an ExtensionType")
extension = Extension(extension.oid, critical, extension)
_reject_duplicate_extension(extension, self._extensions)
return CertificateBuilder(
self._issuer_name, self._subject_name,
self._public_key, self._serial_number, self._not_valid_before,
self._not_valid_after, self._extensions + [extension]
)
def sign(self, private_key, algorithm, backend):
"""
Signs the certificate using the CA's private key.
"""
if self._subject_name is None:
raise ValueError("A certificate must have a subject name")
if self._issuer_name is None:
raise ValueError("A certificate must have an issuer name")
if self._serial_number is None:
raise ValueError("A certificate must have a serial number")
if self._not_valid_before is None:
raise ValueError("A certificate must have a not valid before time")
if self._not_valid_after is None:
raise ValueError("A certificate must have a not valid after time")
if self._public_key is None:
raise ValueError("A certificate must have a public key")
return backend.create_x509_certificate(self, private_key, algorithm)
class CertificateRevocationListBuilder(object):
def __init__(self, issuer_name=None, last_update=None, next_update=None,
extensions=[], revoked_certificates=[]):
self._issuer_name = issuer_name
self._last_update = last_update
self._next_update = next_update
self._extensions = extensions
self._revoked_certificates = revoked_certificates
def issuer_name(self, issuer_name):
if not isinstance(issuer_name, Name):
raise TypeError('Expecting x509.Name object.')
if self._issuer_name is not None:
raise ValueError('The issuer name may only be set once.')
return CertificateRevocationListBuilder(
issuer_name, self._last_update, self._next_update,
self._extensions, self._revoked_certificates
)
def last_update(self, last_update):
if not isinstance(last_update, datetime.datetime):
raise TypeError('Expecting datetime object.')
if self._last_update is not None:
raise ValueError('Last update may only be set once.')
last_update = _convert_to_naive_utc_time(last_update)
if last_update < _EARLIEST_UTC_TIME:
raise ValueError('The last update date must be on or after'
' 1950 January 1.')
if self._next_update is not None and last_update > self._next_update:
raise ValueError(
'The last update date must be before the next update date.'
)
return CertificateRevocationListBuilder(
self._issuer_name, last_update, self._next_update,
self._extensions, self._revoked_certificates
)
def next_update(self, next_update):
if not isinstance(next_update, datetime.datetime):
raise TypeError('Expecting datetime object.')
if self._next_update is not None:
raise ValueError('Last update may only be set once.')
next_update = _convert_to_naive_utc_time(next_update)
if next_update < _EARLIEST_UTC_TIME:
raise ValueError('The last update date must be on or after'
' 1950 January 1.')
if self._last_update is not None and next_update < self._last_update:
raise ValueError(
'The next update date must be after the last update date.'
)
return CertificateRevocationListBuilder(
self._issuer_name, self._last_update, next_update,
self._extensions, self._revoked_certificates
)
def add_extension(self, extension, critical):
"""
Adds an X.509 extension to the certificate revocation list.
"""
if not isinstance(extension, ExtensionType):
raise TypeError("extension must be an ExtensionType")
extension = Extension(extension.oid, critical, extension)
_reject_duplicate_extension(extension, self._extensions)
return CertificateRevocationListBuilder(
self._issuer_name, self._last_update, self._next_update,
self._extensions + [extension], self._revoked_certificates
)
def add_revoked_certificate(self, revoked_certificate):
"""
Adds a revoked certificate to the CRL.
"""
if not isinstance(revoked_certificate, RevokedCertificate):
raise TypeError("Must be an instance of RevokedCertificate")
return CertificateRevocationListBuilder(
self._issuer_name, self._last_update,
self._next_update, self._extensions,
self._revoked_certificates + [revoked_certificate]
)
def sign(self, private_key, algorithm, backend):
if self._issuer_name is None:
raise ValueError("A CRL must have an issuer name")
if self._last_update is None:
raise ValueError("A CRL must have a last update time")
if self._next_update is None:
raise ValueError("A CRL must have a next update time")
return backend.create_x509_crl(self, private_key, algorithm)
class RevokedCertificateBuilder(object):
def __init__(self, serial_number=None, revocation_date=None,
extensions=[]):
self._serial_number = serial_number
self._revocation_date = revocation_date
self._extensions = extensions
def serial_number(self, number):
if not isinstance(number, six.integer_types):
raise TypeError('Serial number must be of integral type.')
if self._serial_number is not None:
raise ValueError('The serial number may only be set once.')
if number <= 0:
raise ValueError('The serial number should be positive')
# ASN.1 integers are always signed, so most significant bit must be
# zero.
if number.bit_length() >= 160: # As defined in RFC 5280
raise ValueError('The serial number should not be more than 159 '
'bits.')
return RevokedCertificateBuilder(
number, self._revocation_date, self._extensions
)
def revocation_date(self, time):
if not isinstance(time, datetime.datetime):
raise TypeError('Expecting datetime object.')
if self._revocation_date is not None:
raise ValueError('The revocation date may only be set once.')
time = _convert_to_naive_utc_time(time)
if time < _EARLIEST_UTC_TIME:
raise ValueError('The revocation date must be on or after'
' 1950 January 1.')
return RevokedCertificateBuilder(
self._serial_number, time, self._extensions
)
def add_extension(self, extension, critical):
if not isinstance(extension, ExtensionType):
raise TypeError("extension must be an ExtensionType")
extension = Extension(extension.oid, critical, extension)
_reject_duplicate_extension(extension, self._extensions)
return RevokedCertificateBuilder(
self._serial_number, self._revocation_date,
self._extensions + [extension]
)
def build(self, backend):
if self._serial_number is None:
raise ValueError("A revoked certificate must have a serial number")
if self._revocation_date is None:
raise ValueError(
"A revoked certificate must have a revocation date"
)
return backend.create_x509_revoked_certificate(self)
def random_serial_number():
return utils.int_from_bytes(os.urandom(20), "big") >> 1
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/x509/certificate_transparency.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
from enum import Enum
import six
class LogEntryType(Enum):
X509_CERTIFICATE = 0
PRE_CERTIFICATE = 1
class Version(Enum):
v1 = 0
@six.add_metaclass(abc.ABCMeta)
class SignedCertificateTimestamp(object):
@abc.abstractproperty
def version(self):
"""
Returns the SCT version.
"""
@abc.abstractproperty
def log_id(self):
"""
Returns an identifier indicating which log this SCT is for.
"""
@abc.abstractproperty
def timestamp(self):
"""
Returns the timestamp for this SCT.
"""
@abc.abstractproperty
def entry_type(self):
"""
Returns whether this is an SCT for a certificate or pre-certificate.
"""
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/x509/extensions.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import datetime
import hashlib
import ipaddress
import warnings
from enum import Enum
import six
from cryptography import utils
from cryptography.hazmat._der import (
BIT_STRING, DERReader, OBJECT_IDENTIFIER, SEQUENCE
)
from cryptography.hazmat.primitives import constant_time, serialization
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
from cryptography.x509.certificate_transparency import (
SignedCertificateTimestamp
)
from cryptography.x509.general_name import GeneralName, IPAddress, OtherName
from cryptography.x509.name import RelativeDistinguishedName
from cryptography.x509.oid import (
CRLEntryExtensionOID, ExtensionOID, OCSPExtensionOID, ObjectIdentifier,
)
def _key_identifier_from_public_key(public_key):
if isinstance(public_key, RSAPublicKey):
data = public_key.public_bytes(
serialization.Encoding.DER,
serialization.PublicFormat.PKCS1,
)
elif isinstance(public_key, EllipticCurvePublicKey):
data = public_key.public_bytes(
serialization.Encoding.X962,
serialization.PublicFormat.UncompressedPoint
)
else:
# This is a very slow way to do this.
serialized = public_key.public_bytes(
serialization.Encoding.DER,
serialization.PublicFormat.SubjectPublicKeyInfo
)
reader = DERReader(serialized)
with reader.read_single_element(SEQUENCE) as public_key_info:
algorithm = public_key_info.read_element(SEQUENCE)
public_key = public_key_info.read_element(BIT_STRING)
# Double-check the algorithm structure.
with algorithm:
algorithm.read_element(OBJECT_IDENTIFIER)
if not algorithm.is_empty():
# Skip the optional parameters field.
algorithm.read_any_element()
# BIT STRING contents begin with the number of padding bytes added. It
# must be zero for SubjectPublicKeyInfo structures.
if public_key.read_byte() != 0:
raise ValueError('Invalid public key encoding')
data = public_key.data
return hashlib.sha1(data).digest()
def _make_sequence_methods(field_name):
def len_method(self):
return len(getattr(self, field_name))
def iter_method(self):
return iter(getattr(self, field_name))
def getitem_method(self, idx):
return getattr(self, field_name)[idx]
return len_method, iter_method, getitem_method
class DuplicateExtension(Exception):
def __init__(self, msg, oid):
super(DuplicateExtension, self).__init__(msg)
self.oid = oid
class ExtensionNotFound(Exception):
def __init__(self, msg, oid):
super(ExtensionNotFound, self).__init__(msg)
self.oid = oid
@six.add_metaclass(abc.ABCMeta)
class ExtensionType(object):
@abc.abstractproperty
def oid(self):
"""
Returns the oid associated with the given extension type.
"""
class Extensions(object):
def __init__(self, extensions):
self._extensions = extensions
def get_extension_for_oid(self, oid):
for ext in self:
if ext.oid == oid:
return ext
raise ExtensionNotFound("No {} extension was found".format(oid), oid)
def get_extension_for_class(self, extclass):
if extclass is UnrecognizedExtension:
raise TypeError(
"UnrecognizedExtension can't be used with "
"get_extension_for_class because more than one instance of the"
" class may be present."
)
for ext in self:
if isinstance(ext.value, extclass):
return ext
raise ExtensionNotFound(
"No {} extension was found".format(extclass), extclass.oid
)
__len__, __iter__, __getitem__ = _make_sequence_methods("_extensions")
def __repr__(self):
return (
"".format(self._extensions)
)
@utils.register_interface(ExtensionType)
class CRLNumber(object):
oid = ExtensionOID.CRL_NUMBER
def __init__(self, crl_number):
if not isinstance(crl_number, six.integer_types):
raise TypeError("crl_number must be an integer")
self._crl_number = crl_number
def __eq__(self, other):
if not isinstance(other, CRLNumber):
return NotImplemented
return self.crl_number == other.crl_number
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.crl_number)
def __repr__(self):
return "".format(self.crl_number)
crl_number = utils.read_only_property("_crl_number")
@utils.register_interface(ExtensionType)
class AuthorityKeyIdentifier(object):
oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER
def __init__(self, key_identifier, authority_cert_issuer,
authority_cert_serial_number):
if (authority_cert_issuer is None) != (
authority_cert_serial_number is None
):
raise ValueError(
"authority_cert_issuer and authority_cert_serial_number "
"must both be present or both None"
)
if authority_cert_issuer is not None:
authority_cert_issuer = list(authority_cert_issuer)
if not all(
isinstance(x, GeneralName) for x in authority_cert_issuer
):
raise TypeError(
"authority_cert_issuer must be a list of GeneralName "
"objects"
)
if authority_cert_serial_number is not None and not isinstance(
authority_cert_serial_number, six.integer_types
):
raise TypeError(
"authority_cert_serial_number must be an integer"
)
self._key_identifier = key_identifier
self._authority_cert_issuer = authority_cert_issuer
self._authority_cert_serial_number = authority_cert_serial_number
@classmethod
def from_issuer_public_key(cls, public_key):
digest = _key_identifier_from_public_key(public_key)
return cls(
key_identifier=digest,
authority_cert_issuer=None,
authority_cert_serial_number=None
)
@classmethod
def from_issuer_subject_key_identifier(cls, ski):
if isinstance(ski, SubjectKeyIdentifier):
digest = ski.digest
else:
digest = ski.value.digest
warnings.warn(
"Extension objects are deprecated as arguments to "
"from_issuer_subject_key_identifier and support will be "
"removed soon. Please migrate to passing a "
"SubjectKeyIdentifier directly.",
utils.DeprecatedIn27,
stacklevel=2,
)
return cls(
key_identifier=digest,
authority_cert_issuer=None,
authority_cert_serial_number=None
)
def __repr__(self):
return (
"".format(self)
)
def __eq__(self, other):
if not isinstance(other, AuthorityKeyIdentifier):
return NotImplemented
return (
self.key_identifier == other.key_identifier and
self.authority_cert_issuer == other.authority_cert_issuer and
self.authority_cert_serial_number ==
other.authority_cert_serial_number
)
def __ne__(self, other):
return not self == other
def __hash__(self):
if self.authority_cert_issuer is None:
aci = None
else:
aci = tuple(self.authority_cert_issuer)
return hash((
self.key_identifier, aci, self.authority_cert_serial_number
))
key_identifier = utils.read_only_property("_key_identifier")
authority_cert_issuer = utils.read_only_property("_authority_cert_issuer")
authority_cert_serial_number = utils.read_only_property(
"_authority_cert_serial_number"
)
@utils.register_interface(ExtensionType)
class SubjectKeyIdentifier(object):
oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER
def __init__(self, digest):
self._digest = digest
@classmethod
def from_public_key(cls, public_key):
return cls(_key_identifier_from_public_key(public_key))
digest = utils.read_only_property("_digest")
def __repr__(self):
return "".format(self.digest)
def __eq__(self, other):
if not isinstance(other, SubjectKeyIdentifier):
return NotImplemented
return constant_time.bytes_eq(self.digest, other.digest)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.digest)
@utils.register_interface(ExtensionType)
class AuthorityInformationAccess(object):
oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS
def __init__(self, descriptions):
descriptions = list(descriptions)
if not all(isinstance(x, AccessDescription) for x in descriptions):
raise TypeError(
"Every item in the descriptions list must be an "
"AccessDescription"
)
self._descriptions = descriptions
__len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions")
def __repr__(self):
return "".format(self._descriptions)
def __eq__(self, other):
if not isinstance(other, AuthorityInformationAccess):
return NotImplemented
return self._descriptions == other._descriptions
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(tuple(self._descriptions))
class AccessDescription(object):
def __init__(self, access_method, access_location):
if not isinstance(access_method, ObjectIdentifier):
raise TypeError("access_method must be an ObjectIdentifier")
if not isinstance(access_location, GeneralName):
raise TypeError("access_location must be a GeneralName")
self._access_method = access_method
self._access_location = access_location
def __repr__(self):
return (
"".format(self)
)
def __eq__(self, other):
if not isinstance(other, AccessDescription):
return NotImplemented
return (
self.access_method == other.access_method and
self.access_location == other.access_location
)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.access_method, self.access_location))
access_method = utils.read_only_property("_access_method")
access_location = utils.read_only_property("_access_location")
@utils.register_interface(ExtensionType)
class BasicConstraints(object):
oid = ExtensionOID.BASIC_CONSTRAINTS
def __init__(self, ca, path_length):
if not isinstance(ca, bool):
raise TypeError("ca must be a boolean value")
if path_length is not None and not ca:
raise ValueError("path_length must be None when ca is False")
if (
path_length is not None and
(not isinstance(path_length, six.integer_types) or path_length < 0)
):
raise TypeError(
"path_length must be a non-negative integer or None"
)
self._ca = ca
self._path_length = path_length
ca = utils.read_only_property("_ca")
path_length = utils.read_only_property("_path_length")
def __repr__(self):
return ("").format(self)
def __eq__(self, other):
if not isinstance(other, BasicConstraints):
return NotImplemented
return self.ca == other.ca and self.path_length == other.path_length
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.ca, self.path_length))
@utils.register_interface(ExtensionType)
class DeltaCRLIndicator(object):
oid = ExtensionOID.DELTA_CRL_INDICATOR
def __init__(self, crl_number):
if not isinstance(crl_number, six.integer_types):
raise TypeError("crl_number must be an integer")
self._crl_number = crl_number
crl_number = utils.read_only_property("_crl_number")
def __eq__(self, other):
if not isinstance(other, DeltaCRLIndicator):
return NotImplemented
return self.crl_number == other.crl_number
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.crl_number)
def __repr__(self):
return "".format(self)
@utils.register_interface(ExtensionType)
class CRLDistributionPoints(object):
oid = ExtensionOID.CRL_DISTRIBUTION_POINTS
def __init__(self, distribution_points):
distribution_points = list(distribution_points)
if not all(
isinstance(x, DistributionPoint) for x in distribution_points
):
raise TypeError(
"distribution_points must be a list of DistributionPoint "
"objects"
)
self._distribution_points = distribution_points
__len__, __iter__, __getitem__ = _make_sequence_methods(
"_distribution_points"
)
def __repr__(self):
return "".format(self._distribution_points)
def __eq__(self, other):
if not isinstance(other, CRLDistributionPoints):
return NotImplemented
return self._distribution_points == other._distribution_points
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(tuple(self._distribution_points))
@utils.register_interface(ExtensionType)
class FreshestCRL(object):
oid = ExtensionOID.FRESHEST_CRL
def __init__(self, distribution_points):
distribution_points = list(distribution_points)
if not all(
isinstance(x, DistributionPoint) for x in distribution_points
):
raise TypeError(
"distribution_points must be a list of DistributionPoint "
"objects"
)
self._distribution_points = distribution_points
__len__, __iter__, __getitem__ = _make_sequence_methods(
"_distribution_points"
)
def __repr__(self):
return "".format(self._distribution_points)
def __eq__(self, other):
if not isinstance(other, FreshestCRL):
return NotImplemented
return self._distribution_points == other._distribution_points
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(tuple(self._distribution_points))
class DistributionPoint(object):
def __init__(self, full_name, relative_name, reasons, crl_issuer):
if full_name and relative_name:
raise ValueError(
"You cannot provide both full_name and relative_name, at "
"least one must be None."
)
if full_name:
full_name = list(full_name)
if not all(isinstance(x, GeneralName) for x in full_name):
raise TypeError(
"full_name must be a list of GeneralName objects"
)
if relative_name:
if not isinstance(relative_name, RelativeDistinguishedName):
raise TypeError(
"relative_name must be a RelativeDistinguishedName"
)
if crl_issuer:
crl_issuer = list(crl_issuer)
if not all(isinstance(x, GeneralName) for x in crl_issuer):
raise TypeError(
"crl_issuer must be None or a list of general names"
)
if reasons and (not isinstance(reasons, frozenset) or not all(
isinstance(x, ReasonFlags) for x in reasons
)):
raise TypeError("reasons must be None or frozenset of ReasonFlags")
if reasons and (
ReasonFlags.unspecified in reasons or
ReasonFlags.remove_from_crl in reasons
):
raise ValueError(
"unspecified and remove_from_crl are not valid reasons in a "
"DistributionPoint"
)
if reasons and not crl_issuer and not (full_name or relative_name):
raise ValueError(
"You must supply crl_issuer, full_name, or relative_name when "
"reasons is not None"
)
self._full_name = full_name
self._relative_name = relative_name
self._reasons = reasons
self._crl_issuer = crl_issuer
def __repr__(self):
return (
""
.format(self)
)
def __eq__(self, other):
if not isinstance(other, DistributionPoint):
return NotImplemented
return (
self.full_name == other.full_name and
self.relative_name == other.relative_name and
self.reasons == other.reasons and
self.crl_issuer == other.crl_issuer
)
def __ne__(self, other):
return not self == other
def __hash__(self):
if self.full_name is not None:
fn = tuple(self.full_name)
else:
fn = None
if self.crl_issuer is not None:
crl_issuer = tuple(self.crl_issuer)
else:
crl_issuer = None
return hash((fn, self.relative_name, self.reasons, crl_issuer))
full_name = utils.read_only_property("_full_name")
relative_name = utils.read_only_property("_relative_name")
reasons = utils.read_only_property("_reasons")
crl_issuer = utils.read_only_property("_crl_issuer")
class ReasonFlags(Enum):
unspecified = "unspecified"
key_compromise = "keyCompromise"
ca_compromise = "cACompromise"
affiliation_changed = "affiliationChanged"
superseded = "superseded"
cessation_of_operation = "cessationOfOperation"
certificate_hold = "certificateHold"
privilege_withdrawn = "privilegeWithdrawn"
aa_compromise = "aACompromise"
remove_from_crl = "removeFromCRL"
@utils.register_interface(ExtensionType)
class PolicyConstraints(object):
oid = ExtensionOID.POLICY_CONSTRAINTS
def __init__(self, require_explicit_policy, inhibit_policy_mapping):
if require_explicit_policy is not None and not isinstance(
require_explicit_policy, six.integer_types
):
raise TypeError(
"require_explicit_policy must be a non-negative integer or "
"None"
)
if inhibit_policy_mapping is not None and not isinstance(
inhibit_policy_mapping, six.integer_types
):
raise TypeError(
"inhibit_policy_mapping must be a non-negative integer or None"
)
if inhibit_policy_mapping is None and require_explicit_policy is None:
raise ValueError(
"At least one of require_explicit_policy and "
"inhibit_policy_mapping must not be None"
)
self._require_explicit_policy = require_explicit_policy
self._inhibit_policy_mapping = inhibit_policy_mapping
def __repr__(self):
return (
u"".format(self)
)
def __eq__(self, other):
if not isinstance(other, PolicyConstraints):
return NotImplemented
return (
self.require_explicit_policy == other.require_explicit_policy and
self.inhibit_policy_mapping == other.inhibit_policy_mapping
)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(
(self.require_explicit_policy, self.inhibit_policy_mapping)
)
require_explicit_policy = utils.read_only_property(
"_require_explicit_policy"
)
inhibit_policy_mapping = utils.read_only_property(
"_inhibit_policy_mapping"
)
@utils.register_interface(ExtensionType)
class CertificatePolicies(object):
oid = ExtensionOID.CERTIFICATE_POLICIES
def __init__(self, policies):
policies = list(policies)
if not all(isinstance(x, PolicyInformation) for x in policies):
raise TypeError(
"Every item in the policies list must be a "
"PolicyInformation"
)
self._policies = policies
__len__, __iter__, __getitem__ = _make_sequence_methods("_policies")
def __repr__(self):
return "".format(self._policies)
def __eq__(self, other):
if not isinstance(other, CertificatePolicies):
return NotImplemented
return self._policies == other._policies
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(tuple(self._policies))
class PolicyInformation(object):
def __init__(self, policy_identifier, policy_qualifiers):
if not isinstance(policy_identifier, ObjectIdentifier):
raise TypeError("policy_identifier must be an ObjectIdentifier")
self._policy_identifier = policy_identifier
if policy_qualifiers:
policy_qualifiers = list(policy_qualifiers)
if not all(
isinstance(x, (six.text_type, UserNotice))
for x in policy_qualifiers
):
raise TypeError(
"policy_qualifiers must be a list of strings and/or "
"UserNotice objects or None"
)
self._policy_qualifiers = policy_qualifiers
def __repr__(self):
return (
"".format(self)
)
def __eq__(self, other):
if not isinstance(other, PolicyInformation):
return NotImplemented
return (
self.policy_identifier == other.policy_identifier and
self.policy_qualifiers == other.policy_qualifiers
)
def __ne__(self, other):
return not self == other
def __hash__(self):
if self.policy_qualifiers is not None:
pq = tuple(self.policy_qualifiers)
else:
pq = None
return hash((self.policy_identifier, pq))
policy_identifier = utils.read_only_property("_policy_identifier")
policy_qualifiers = utils.read_only_property("_policy_qualifiers")
class UserNotice(object):
def __init__(self, notice_reference, explicit_text):
if notice_reference and not isinstance(
notice_reference, NoticeReference
):
raise TypeError(
"notice_reference must be None or a NoticeReference"
)
self._notice_reference = notice_reference
self._explicit_text = explicit_text
def __repr__(self):
return (
"".format(self)
)
def __eq__(self, other):
if not isinstance(other, UserNotice):
return NotImplemented
return (
self.notice_reference == other.notice_reference and
self.explicit_text == other.explicit_text
)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.notice_reference, self.explicit_text))
notice_reference = utils.read_only_property("_notice_reference")
explicit_text = utils.read_only_property("_explicit_text")
class NoticeReference(object):
def __init__(self, organization, notice_numbers):
self._organization = organization
notice_numbers = list(notice_numbers)
if not all(isinstance(x, int) for x in notice_numbers):
raise TypeError(
"notice_numbers must be a list of integers"
)
self._notice_numbers = notice_numbers
def __repr__(self):
return (
"".format(self)
)
def __eq__(self, other):
if not isinstance(other, NoticeReference):
return NotImplemented
return (
self.organization == other.organization and
self.notice_numbers == other.notice_numbers
)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.organization, tuple(self.notice_numbers)))
organization = utils.read_only_property("_organization")
notice_numbers = utils.read_only_property("_notice_numbers")
@utils.register_interface(ExtensionType)
class ExtendedKeyUsage(object):
oid = ExtensionOID.EXTENDED_KEY_USAGE
def __init__(self, usages):
usages = list(usages)
if not all(isinstance(x, ObjectIdentifier) for x in usages):
raise TypeError(
"Every item in the usages list must be an ObjectIdentifier"
)
self._usages = usages
__len__, __iter__, __getitem__ = _make_sequence_methods("_usages")
def __repr__(self):
return "".format(self._usages)
def __eq__(self, other):
if not isinstance(other, ExtendedKeyUsage):
return NotImplemented
return self._usages == other._usages
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(tuple(self._usages))
@utils.register_interface(ExtensionType)
class OCSPNoCheck(object):
oid = ExtensionOID.OCSP_NO_CHECK
def __eq__(self, other):
if not isinstance(other, OCSPNoCheck):
return NotImplemented
return True
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(OCSPNoCheck)
def __repr__(self):
return ""
@utils.register_interface(ExtensionType)
class PrecertPoison(object):
oid = ExtensionOID.PRECERT_POISON
def __eq__(self, other):
if not isinstance(other, PrecertPoison):
return NotImplemented
return True
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(PrecertPoison)
def __repr__(self):
return ""
@utils.register_interface(ExtensionType)
class TLSFeature(object):
oid = ExtensionOID.TLS_FEATURE
def __init__(self, features):
features = list(features)
if (
not all(isinstance(x, TLSFeatureType) for x in features) or
len(features) == 0
):
raise TypeError(
"features must be a list of elements from the TLSFeatureType "
"enum"
)
self._features = features
__len__, __iter__, __getitem__ = _make_sequence_methods("_features")
def __repr__(self):
return "".format(self)
def __eq__(self, other):
if not isinstance(other, TLSFeature):
return NotImplemented
return self._features == other._features
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(tuple(self._features))
class TLSFeatureType(Enum):
# status_request is defined in RFC 6066 and is used for what is commonly
# called OCSP Must-Staple when present in the TLS Feature extension in an
# X.509 certificate.
status_request = 5
# status_request_v2 is defined in RFC 6961 and allows multiple OCSP
# responses to be provided. It is not currently in use by clients or
# servers.
status_request_v2 = 17
_TLS_FEATURE_TYPE_TO_ENUM = dict((x.value, x) for x in TLSFeatureType)
@utils.register_interface(ExtensionType)
class InhibitAnyPolicy(object):
oid = ExtensionOID.INHIBIT_ANY_POLICY
def __init__(self, skip_certs):
if not isinstance(skip_certs, six.integer_types):
raise TypeError("skip_certs must be an integer")
if skip_certs < 0:
raise ValueError("skip_certs must be a non-negative integer")
self._skip_certs = skip_certs
def __repr__(self):
return "".format(self)
def __eq__(self, other):
if not isinstance(other, InhibitAnyPolicy):
return NotImplemented
return self.skip_certs == other.skip_certs
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.skip_certs)
skip_certs = utils.read_only_property("_skip_certs")
@utils.register_interface(ExtensionType)
class KeyUsage(object):
oid = ExtensionOID.KEY_USAGE
def __init__(self, digital_signature, content_commitment, key_encipherment,
data_encipherment, key_agreement, key_cert_sign, crl_sign,
encipher_only, decipher_only):
if not key_agreement and (encipher_only or decipher_only):
raise ValueError(
"encipher_only and decipher_only can only be true when "
"key_agreement is true"
)
self._digital_signature = digital_signature
self._content_commitment = content_commitment
self._key_encipherment = key_encipherment
self._data_encipherment = data_encipherment
self._key_agreement = key_agreement
self._key_cert_sign = key_cert_sign
self._crl_sign = crl_sign
self._encipher_only = encipher_only
self._decipher_only = decipher_only
digital_signature = utils.read_only_property("_digital_signature")
content_commitment = utils.read_only_property("_content_commitment")
key_encipherment = utils.read_only_property("_key_encipherment")
data_encipherment = utils.read_only_property("_data_encipherment")
key_agreement = utils.read_only_property("_key_agreement")
key_cert_sign = utils.read_only_property("_key_cert_sign")
crl_sign = utils.read_only_property("_crl_sign")
@property
def encipher_only(self):
if not self.key_agreement:
raise ValueError(
"encipher_only is undefined unless key_agreement is true"
)
else:
return self._encipher_only
@property
def decipher_only(self):
if not self.key_agreement:
raise ValueError(
"decipher_only is undefined unless key_agreement is true"
)
else:
return self._decipher_only
def __repr__(self):
try:
encipher_only = self.encipher_only
decipher_only = self.decipher_only
except ValueError:
encipher_only = None
decipher_only = None
return ("").format(
self, encipher_only, decipher_only)
def __eq__(self, other):
if not isinstance(other, KeyUsage):
return NotImplemented
return (
self.digital_signature == other.digital_signature and
self.content_commitment == other.content_commitment and
self.key_encipherment == other.key_encipherment and
self.data_encipherment == other.data_encipherment and
self.key_agreement == other.key_agreement and
self.key_cert_sign == other.key_cert_sign and
self.crl_sign == other.crl_sign and
self._encipher_only == other._encipher_only and
self._decipher_only == other._decipher_only
)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((
self.digital_signature, self.content_commitment,
self.key_encipherment, self.data_encipherment,
self.key_agreement, self.key_cert_sign,
self.crl_sign, self._encipher_only,
self._decipher_only
))
@utils.register_interface(ExtensionType)
class NameConstraints(object):
oid = ExtensionOID.NAME_CONSTRAINTS
def __init__(self, permitted_subtrees, excluded_subtrees):
if permitted_subtrees is not None:
permitted_subtrees = list(permitted_subtrees)
if not all(
isinstance(x, GeneralName) for x in permitted_subtrees
):
raise TypeError(
"permitted_subtrees must be a list of GeneralName objects "
"or None"
)
self._validate_ip_name(permitted_subtrees)
if excluded_subtrees is not None:
excluded_subtrees = list(excluded_subtrees)
if not all(
isinstance(x, GeneralName) for x in excluded_subtrees
):
raise TypeError(
"excluded_subtrees must be a list of GeneralName objects "
"or None"
)
self._validate_ip_name(excluded_subtrees)
if permitted_subtrees is None and excluded_subtrees is None:
raise ValueError(
"At least one of permitted_subtrees and excluded_subtrees "
"must not be None"
)
self._permitted_subtrees = permitted_subtrees
self._excluded_subtrees = excluded_subtrees
def __eq__(self, other):
if not isinstance(other, NameConstraints):
return NotImplemented
return (
self.excluded_subtrees == other.excluded_subtrees and
self.permitted_subtrees == other.permitted_subtrees
)
def __ne__(self, other):
return not self == other
def _validate_ip_name(self, tree):
if any(isinstance(name, IPAddress) and not isinstance(
name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)
) for name in tree):
raise TypeError(
"IPAddress name constraints must be an IPv4Network or"
" IPv6Network object"
)
def __repr__(self):
return (
u"".format(self)
)
def __hash__(self):
if self.permitted_subtrees is not None:
ps = tuple(self.permitted_subtrees)
else:
ps = None
if self.excluded_subtrees is not None:
es = tuple(self.excluded_subtrees)
else:
es = None
return hash((ps, es))
permitted_subtrees = utils.read_only_property("_permitted_subtrees")
excluded_subtrees = utils.read_only_property("_excluded_subtrees")
class Extension(object):
def __init__(self, oid, critical, value):
if not isinstance(oid, ObjectIdentifier):
raise TypeError(
"oid argument must be an ObjectIdentifier instance."
)
if not isinstance(critical, bool):
raise TypeError("critical must be a boolean value")
self._oid = oid
self._critical = critical
self._value = value
oid = utils.read_only_property("_oid")
critical = utils.read_only_property("_critical")
value = utils.read_only_property("_value")
def __repr__(self):
return ("").format(self)
def __eq__(self, other):
if not isinstance(other, Extension):
return NotImplemented
return (
self.oid == other.oid and
self.critical == other.critical and
self.value == other.value
)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.oid, self.critical, self.value))
class GeneralNames(object):
def __init__(self, general_names):
general_names = list(general_names)
if not all(isinstance(x, GeneralName) for x in general_names):
raise TypeError(
"Every item in the general_names list must be an "
"object conforming to the GeneralName interface"
)
self._general_names = general_names
__len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
def get_values_for_type(self, type):
# Return the value of each GeneralName, except for OtherName instances
# which we return directly because it has two important properties not
# just one value.
objs = (i for i in self if isinstance(i, type))
if type != OtherName:
objs = (i.value for i in objs)
return list(objs)
def __repr__(self):
return "".format(self._general_names)
def __eq__(self, other):
if not isinstance(other, GeneralNames):
return NotImplemented
return self._general_names == other._general_names
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(tuple(self._general_names))
@utils.register_interface(ExtensionType)
class SubjectAlternativeName(object):
oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME
def __init__(self, general_names):
self._general_names = GeneralNames(general_names)
__len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
def get_values_for_type(self, type):
return self._general_names.get_values_for_type(type)
def __repr__(self):
return "".format(self._general_names)
def __eq__(self, other):
if not isinstance(other, SubjectAlternativeName):
return NotImplemented
return self._general_names == other._general_names
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self._general_names)
@utils.register_interface(ExtensionType)
class IssuerAlternativeName(object):
oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME
def __init__(self, general_names):
self._general_names = GeneralNames(general_names)
__len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
def get_values_for_type(self, type):
return self._general_names.get_values_for_type(type)
def __repr__(self):
return "".format(self._general_names)
def __eq__(self, other):
if not isinstance(other, IssuerAlternativeName):
return NotImplemented
return self._general_names == other._general_names
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self._general_names)
@utils.register_interface(ExtensionType)
class CertificateIssuer(object):
oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER
def __init__(self, general_names):
self._general_names = GeneralNames(general_names)
__len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
def get_values_for_type(self, type):
return self._general_names.get_values_for_type(type)
def __repr__(self):
return "".format(self._general_names)
def __eq__(self, other):
if not isinstance(other, CertificateIssuer):
return NotImplemented
return self._general_names == other._general_names
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self._general_names)
@utils.register_interface(ExtensionType)
class CRLReason(object):
oid = CRLEntryExtensionOID.CRL_REASON
def __init__(self, reason):
if not isinstance(reason, ReasonFlags):
raise TypeError("reason must be an element from ReasonFlags")
self._reason = reason
def __repr__(self):
return "".format(self._reason)
def __eq__(self, other):
if not isinstance(other, CRLReason):
return NotImplemented
return self.reason == other.reason
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.reason)
reason = utils.read_only_property("_reason")
@utils.register_interface(ExtensionType)
class InvalidityDate(object):
oid = CRLEntryExtensionOID.INVALIDITY_DATE
def __init__(self, invalidity_date):
if not isinstance(invalidity_date, datetime.datetime):
raise TypeError("invalidity_date must be a datetime.datetime")
self._invalidity_date = invalidity_date
def __repr__(self):
return "".format(
self._invalidity_date
)
def __eq__(self, other):
if not isinstance(other, InvalidityDate):
return NotImplemented
return self.invalidity_date == other.invalidity_date
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.invalidity_date)
invalidity_date = utils.read_only_property("_invalidity_date")
@utils.register_interface(ExtensionType)
class PrecertificateSignedCertificateTimestamps(object):
oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS
def __init__(self, signed_certificate_timestamps):
signed_certificate_timestamps = list(signed_certificate_timestamps)
if not all(
isinstance(sct, SignedCertificateTimestamp)
for sct in signed_certificate_timestamps
):
raise TypeError(
"Every item in the signed_certificate_timestamps list must be "
"a SignedCertificateTimestamp"
)
self._signed_certificate_timestamps = signed_certificate_timestamps
__len__, __iter__, __getitem__ = _make_sequence_methods(
"_signed_certificate_timestamps"
)
def __repr__(self):
return (
"".format(
list(self)
)
)
def __hash__(self):
return hash(tuple(self._signed_certificate_timestamps))
def __eq__(self, other):
if not isinstance(other, PrecertificateSignedCertificateTimestamps):
return NotImplemented
return (
self._signed_certificate_timestamps ==
other._signed_certificate_timestamps
)
def __ne__(self, other):
return not self == other
@utils.register_interface(ExtensionType)
class OCSPNonce(object):
oid = OCSPExtensionOID.NONCE
def __init__(self, nonce):
if not isinstance(nonce, bytes):
raise TypeError("nonce must be bytes")
self._nonce = nonce
def __eq__(self, other):
if not isinstance(other, OCSPNonce):
return NotImplemented
return self.nonce == other.nonce
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.nonce)
def __repr__(self):
return "".format(self)
nonce = utils.read_only_property("_nonce")
@utils.register_interface(ExtensionType)
class IssuingDistributionPoint(object):
oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT
def __init__(self, full_name, relative_name, only_contains_user_certs,
only_contains_ca_certs, only_some_reasons, indirect_crl,
only_contains_attribute_certs):
if (
only_some_reasons and (
not isinstance(only_some_reasons, frozenset) or not all(
isinstance(x, ReasonFlags) for x in only_some_reasons
)
)
):
raise TypeError(
"only_some_reasons must be None or frozenset of ReasonFlags"
)
if only_some_reasons and (
ReasonFlags.unspecified in only_some_reasons or
ReasonFlags.remove_from_crl in only_some_reasons
):
raise ValueError(
"unspecified and remove_from_crl are not valid reasons in an "
"IssuingDistributionPoint"
)
if not (
isinstance(only_contains_user_certs, bool) and
isinstance(only_contains_ca_certs, bool) and
isinstance(indirect_crl, bool) and
isinstance(only_contains_attribute_certs, bool)
):
raise TypeError(
"only_contains_user_certs, only_contains_ca_certs, "
"indirect_crl and only_contains_attribute_certs "
"must all be boolean."
)
crl_constraints = [
only_contains_user_certs, only_contains_ca_certs,
indirect_crl, only_contains_attribute_certs
]
if len([x for x in crl_constraints if x]) > 1:
raise ValueError(
"Only one of the following can be set to True: "
"only_contains_user_certs, only_contains_ca_certs, "
"indirect_crl, only_contains_attribute_certs"
)
if (
not any([
only_contains_user_certs, only_contains_ca_certs,
indirect_crl, only_contains_attribute_certs, full_name,
relative_name, only_some_reasons
])
):
raise ValueError(
"Cannot create empty extension: "
"if only_contains_user_certs, only_contains_ca_certs, "
"indirect_crl, and only_contains_attribute_certs are all False"
", then either full_name, relative_name, or only_some_reasons "
"must have a value."
)
self._only_contains_user_certs = only_contains_user_certs
self._only_contains_ca_certs = only_contains_ca_certs
self._indirect_crl = indirect_crl
self._only_contains_attribute_certs = only_contains_attribute_certs
self._only_some_reasons = only_some_reasons
self._full_name = full_name
self._relative_name = relative_name
def __repr__(self):
return (
"".format(self)
)
def __eq__(self, other):
if not isinstance(other, IssuingDistributionPoint):
return NotImplemented
return (
self.full_name == other.full_name and
self.relative_name == other.relative_name and
self.only_contains_user_certs == other.only_contains_user_certs and
self.only_contains_ca_certs == other.only_contains_ca_certs and
self.only_some_reasons == other.only_some_reasons and
self.indirect_crl == other.indirect_crl and
self.only_contains_attribute_certs ==
other.only_contains_attribute_certs
)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((
self.full_name,
self.relative_name,
self.only_contains_user_certs,
self.only_contains_ca_certs,
self.only_some_reasons,
self.indirect_crl,
self.only_contains_attribute_certs,
))
full_name = utils.read_only_property("_full_name")
relative_name = utils.read_only_property("_relative_name")
only_contains_user_certs = utils.read_only_property(
"_only_contains_user_certs"
)
only_contains_ca_certs = utils.read_only_property(
"_only_contains_ca_certs"
)
only_some_reasons = utils.read_only_property("_only_some_reasons")
indirect_crl = utils.read_only_property("_indirect_crl")
only_contains_attribute_certs = utils.read_only_property(
"_only_contains_attribute_certs"
)
@utils.register_interface(ExtensionType)
class UnrecognizedExtension(object):
def __init__(self, oid, value):
if not isinstance(oid, ObjectIdentifier):
raise TypeError("oid must be an ObjectIdentifier")
self._oid = oid
self._value = value
oid = utils.read_only_property("_oid")
value = utils.read_only_property("_value")
def __repr__(self):
return (
"".format(
self
)
)
def __eq__(self, other):
if not isinstance(other, UnrecognizedExtension):
return NotImplemented
return self.oid == other.oid and self.value == other.value
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.oid, self.value))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/x509/general_name.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import ipaddress
import warnings
from email.utils import parseaddr
import six
from six.moves import urllib_parse
from cryptography import utils
from cryptography.x509.name import Name
from cryptography.x509.oid import ObjectIdentifier
_GENERAL_NAMES = {
0: "otherName",
1: "rfc822Name",
2: "dNSName",
3: "x400Address",
4: "directoryName",
5: "ediPartyName",
6: "uniformResourceIdentifier",
7: "iPAddress",
8: "registeredID",
}
def _lazy_import_idna():
# Import idna lazily becase it allocates a decent amount of memory, and
# we're only using it in deprecated paths.
try:
import idna
return idna
except ImportError:
raise ImportError(
"idna is not installed, but a deprecated feature that requires it"
" was used. See: https://cryptography.io/en/latest/faq/#importe"
"rror-idna-is-not-installed"
)
class UnsupportedGeneralNameType(Exception):
def __init__(self, msg, type):
super(UnsupportedGeneralNameType, self).__init__(msg)
self.type = type
@six.add_metaclass(abc.ABCMeta)
class GeneralName(object):
@abc.abstractproperty
def value(self):
"""
Return the value of the object
"""
@utils.register_interface(GeneralName)
class RFC822Name(object):
def __init__(self, value):
if isinstance(value, six.text_type):
try:
value.encode("ascii")
except UnicodeEncodeError:
value = self._idna_encode(value)
warnings.warn(
"RFC822Name values should be passed as an A-label string. "
"This means unicode characters should be encoded via "
"idna. Support for passing unicode strings (aka U-label) "
"will be removed in a future version.",
utils.PersistentlyDeprecated2017,
stacklevel=2,
)
else:
raise TypeError("value must be string")
name, address = parseaddr(value)
if name or not address:
# parseaddr has found a name (e.g. Name ) or the entire
# value is an empty string.
raise ValueError("Invalid rfc822name value")
self._value = value
value = utils.read_only_property("_value")
@classmethod
def _init_without_validation(cls, value):
instance = cls.__new__(cls)
instance._value = value
return instance
def _idna_encode(self, value):
idna = _lazy_import_idna()
_, address = parseaddr(value)
parts = address.split(u"@")
return parts[0] + "@" + idna.encode(parts[1]).decode("ascii")
def __repr__(self):
return "".format(self.value)
def __eq__(self, other):
if not isinstance(other, RFC822Name):
return NotImplemented
return self.value == other.value
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.value)
def _idna_encode(value):
idna = _lazy_import_idna()
# Retain prefixes '*.' for common/alt names and '.' for name constraints
for prefix in ['*.', '.']:
if value.startswith(prefix):
value = value[len(prefix):]
return prefix + idna.encode(value).decode("ascii")
return idna.encode(value).decode("ascii")
@utils.register_interface(GeneralName)
class DNSName(object):
def __init__(self, value):
if isinstance(value, six.text_type):
try:
value.encode("ascii")
except UnicodeEncodeError:
value = _idna_encode(value)
warnings.warn(
"DNSName values should be passed as an A-label string. "
"This means unicode characters should be encoded via "
"idna. Support for passing unicode strings (aka U-label) "
"will be removed in a future version.",
utils.PersistentlyDeprecated2017,
stacklevel=2,
)
else:
raise TypeError("value must be string")
self._value = value
value = utils.read_only_property("_value")
@classmethod
def _init_without_validation(cls, value):
instance = cls.__new__(cls)
instance._value = value
return instance
def __repr__(self):
return "".format(self.value)
def __eq__(self, other):
if not isinstance(other, DNSName):
return NotImplemented
return self.value == other.value
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.value)
@utils.register_interface(GeneralName)
class UniformResourceIdentifier(object):
def __init__(self, value):
if isinstance(value, six.text_type):
try:
value.encode("ascii")
except UnicodeEncodeError:
value = self._idna_encode(value)
warnings.warn(
"URI values should be passed as an A-label string. "
"This means unicode characters should be encoded via "
"idna. Support for passing unicode strings (aka U-label) "
" will be removed in a future version.",
utils.PersistentlyDeprecated2017,
stacklevel=2,
)
else:
raise TypeError("value must be string")
self._value = value
value = utils.read_only_property("_value")
@classmethod
def _init_without_validation(cls, value):
instance = cls.__new__(cls)
instance._value = value
return instance
def _idna_encode(self, value):
idna = _lazy_import_idna()
parsed = urllib_parse.urlparse(value)
if parsed.port:
netloc = (
idna.encode(parsed.hostname) +
":{}".format(parsed.port).encode("ascii")
).decode("ascii")
else:
netloc = idna.encode(parsed.hostname).decode("ascii")
# Note that building a URL in this fashion means it should be
# semantically indistinguishable from the original but is not
# guaranteed to be exactly the same.
return urllib_parse.urlunparse((
parsed.scheme,
netloc,
parsed.path,
parsed.params,
parsed.query,
parsed.fragment
))
def __repr__(self):
return "".format(self.value)
def __eq__(self, other):
if not isinstance(other, UniformResourceIdentifier):
return NotImplemented
return self.value == other.value
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.value)
@utils.register_interface(GeneralName)
class DirectoryName(object):
def __init__(self, value):
if not isinstance(value, Name):
raise TypeError("value must be a Name")
self._value = value
value = utils.read_only_property("_value")
def __repr__(self):
return "".format(self.value)
def __eq__(self, other):
if not isinstance(other, DirectoryName):
return NotImplemented
return self.value == other.value
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.value)
@utils.register_interface(GeneralName)
class RegisteredID(object):
def __init__(self, value):
if not isinstance(value, ObjectIdentifier):
raise TypeError("value must be an ObjectIdentifier")
self._value = value
value = utils.read_only_property("_value")
def __repr__(self):
return "".format(self.value)
def __eq__(self, other):
if not isinstance(other, RegisteredID):
return NotImplemented
return self.value == other.value
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.value)
@utils.register_interface(GeneralName)
class IPAddress(object):
def __init__(self, value):
if not isinstance(
value,
(
ipaddress.IPv4Address,
ipaddress.IPv6Address,
ipaddress.IPv4Network,
ipaddress.IPv6Network
)
):
raise TypeError(
"value must be an instance of ipaddress.IPv4Address, "
"ipaddress.IPv6Address, ipaddress.IPv4Network, or "
"ipaddress.IPv6Network"
)
self._value = value
value = utils.read_only_property("_value")
def __repr__(self):
return "".format(self.value)
def __eq__(self, other):
if not isinstance(other, IPAddress):
return NotImplemented
return self.value == other.value
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.value)
@utils.register_interface(GeneralName)
class OtherName(object):
def __init__(self, type_id, value):
if not isinstance(type_id, ObjectIdentifier):
raise TypeError("type_id must be an ObjectIdentifier")
if not isinstance(value, bytes):
raise TypeError("value must be a binary string")
self._type_id = type_id
self._value = value
type_id = utils.read_only_property("_type_id")
value = utils.read_only_property("_value")
def __repr__(self):
return "".format(
self.type_id, self.value)
def __eq__(self, other):
if not isinstance(other, OtherName):
return NotImplemented
return self.type_id == other.type_id and self.value == other.value
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.type_id, self.value))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/x509/name.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from enum import Enum
import six
from cryptography import utils
from cryptography.x509.oid import NameOID, ObjectIdentifier
class _ASN1Type(Enum):
UTF8String = 12
NumericString = 18
PrintableString = 19
T61String = 20
IA5String = 22
UTCTime = 23
GeneralizedTime = 24
VisibleString = 26
UniversalString = 28
BMPString = 30
_ASN1_TYPE_TO_ENUM = dict((i.value, i) for i in _ASN1Type)
_SENTINEL = object()
_NAMEOID_DEFAULT_TYPE = {
NameOID.COUNTRY_NAME: _ASN1Type.PrintableString,
NameOID.JURISDICTION_COUNTRY_NAME: _ASN1Type.PrintableString,
NameOID.SERIAL_NUMBER: _ASN1Type.PrintableString,
NameOID.DN_QUALIFIER: _ASN1Type.PrintableString,
NameOID.EMAIL_ADDRESS: _ASN1Type.IA5String,
NameOID.DOMAIN_COMPONENT: _ASN1Type.IA5String,
}
#: Short attribute names from RFC 4514:
#: https://tools.ietf.org/html/rfc4514#page-7
_NAMEOID_TO_NAME = {
NameOID.COMMON_NAME: 'CN',
NameOID.LOCALITY_NAME: 'L',
NameOID.STATE_OR_PROVINCE_NAME: 'ST',
NameOID.ORGANIZATION_NAME: 'O',
NameOID.ORGANIZATIONAL_UNIT_NAME: 'OU',
NameOID.COUNTRY_NAME: 'C',
NameOID.STREET_ADDRESS: 'STREET',
NameOID.DOMAIN_COMPONENT: 'DC',
NameOID.USER_ID: 'UID',
}
def _escape_dn_value(val):
"""Escape special characters in RFC4514 Distinguished Name value."""
# See https://tools.ietf.org/html/rfc4514#section-2.4
val = val.replace('\\', '\\\\')
val = val.replace('"', '\\"')
val = val.replace('+', '\\+')
val = val.replace(',', '\\,')
val = val.replace(';', '\\;')
val = val.replace('<', '\\<')
val = val.replace('>', '\\>')
val = val.replace('\0', '\\00')
if val[0] in ('#', ' '):
val = '\\' + val
if val[-1] == ' ':
val = val[:-1] + '\\ '
return val
class NameAttribute(object):
def __init__(self, oid, value, _type=_SENTINEL):
if not isinstance(oid, ObjectIdentifier):
raise TypeError(
"oid argument must be an ObjectIdentifier instance."
)
if not isinstance(value, six.text_type):
raise TypeError(
"value argument must be a text type."
)
if (
oid == NameOID.COUNTRY_NAME or
oid == NameOID.JURISDICTION_COUNTRY_NAME
):
if len(value.encode("utf8")) != 2:
raise ValueError(
"Country name must be a 2 character country code"
)
if len(value) == 0:
raise ValueError("Value cannot be an empty string")
# The appropriate ASN1 string type varies by OID and is defined across
# multiple RFCs including 2459, 3280, and 5280. In general UTF8String
# is preferred (2459), but 3280 and 5280 specify several OIDs with
# alternate types. This means when we see the sentinel value we need
# to look up whether the OID has a non-UTF8 type. If it does, set it
# to that. Otherwise, UTF8!
if _type == _SENTINEL:
_type = _NAMEOID_DEFAULT_TYPE.get(oid, _ASN1Type.UTF8String)
if not isinstance(_type, _ASN1Type):
raise TypeError("_type must be from the _ASN1Type enum")
self._oid = oid
self._value = value
self._type = _type
oid = utils.read_only_property("_oid")
value = utils.read_only_property("_value")
def rfc4514_string(self):
"""
Format as RFC4514 Distinguished Name string.
Use short attribute name if available, otherwise fall back to OID
dotted string.
"""
key = _NAMEOID_TO_NAME.get(self.oid, self.oid.dotted_string)
return '%s=%s' % (key, _escape_dn_value(self.value))
def __eq__(self, other):
if not isinstance(other, NameAttribute):
return NotImplemented
return (
self.oid == other.oid and
self.value == other.value
)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.oid, self.value))
def __repr__(self):
return "".format(self)
class RelativeDistinguishedName(object):
def __init__(self, attributes):
attributes = list(attributes)
if not attributes:
raise ValueError("a relative distinguished name cannot be empty")
if not all(isinstance(x, NameAttribute) for x in attributes):
raise TypeError("attributes must be an iterable of NameAttribute")
# Keep list and frozenset to preserve attribute order where it matters
self._attributes = attributes
self._attribute_set = frozenset(attributes)
if len(self._attribute_set) != len(attributes):
raise ValueError("duplicate attributes are not allowed")
def get_attributes_for_oid(self, oid):
return [i for i in self if i.oid == oid]
def rfc4514_string(self):
"""
Format as RFC4514 Distinguished Name string.
Within each RDN, attributes are joined by '+', although that is rarely
used in certificates.
"""
return '+'.join(attr.rfc4514_string() for attr in self._attributes)
def __eq__(self, other):
if not isinstance(other, RelativeDistinguishedName):
return NotImplemented
return self._attribute_set == other._attribute_set
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self._attribute_set)
def __iter__(self):
return iter(self._attributes)
def __len__(self):
return len(self._attributes)
def __repr__(self):
return "".format(self.rfc4514_string())
class Name(object):
def __init__(self, attributes):
attributes = list(attributes)
if all(isinstance(x, NameAttribute) for x in attributes):
self._attributes = [
RelativeDistinguishedName([x]) for x in attributes
]
elif all(isinstance(x, RelativeDistinguishedName) for x in attributes):
self._attributes = attributes
else:
raise TypeError(
"attributes must be a list of NameAttribute"
" or a list RelativeDistinguishedName"
)
def rfc4514_string(self):
"""
Format as RFC4514 Distinguished Name string.
For example 'CN=foobar.com,O=Foo Corp,C=US'
An X.509 name is a two-level structure: a list of sets of attributes.
Each list element is separated by ',' and within each list element, set
elements are separated by '+'. The latter is almost never used in
real world certificates.
"""
return ','.join(attr.rfc4514_string() for attr in self._attributes)
def get_attributes_for_oid(self, oid):
return [i for i in self if i.oid == oid]
@property
def rdns(self):
return self._attributes
def public_bytes(self, backend):
return backend.x509_name_bytes(self)
def __eq__(self, other):
if not isinstance(other, Name):
return NotImplemented
return self._attributes == other._attributes
def __ne__(self, other):
return not self == other
def __hash__(self):
# TODO: this is relatively expensive, if this looks like a bottleneck
# for you, consider optimizing!
return hash(tuple(self._attributes))
def __iter__(self):
for rdn in self._attributes:
for ava in rdn:
yield ava
def __len__(self):
return sum(len(rdn) for rdn in self._attributes)
def __repr__(self):
if six.PY2:
return "".format(self.rfc4514_string().encode('utf8'))
else:
return "".format(self.rfc4514_string())
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/x509/ocsp.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
import datetime
from enum import Enum
import six
from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ed25519, ed448
from cryptography.x509.base import (
_EARLIEST_UTC_TIME, _convert_to_naive_utc_time, _reject_duplicate_extension
)
_OIDS_TO_HASH = {
"1.3.14.3.2.26": hashes.SHA1(),
"2.16.840.1.101.3.4.2.4": hashes.SHA224(),
"2.16.840.1.101.3.4.2.1": hashes.SHA256(),
"2.16.840.1.101.3.4.2.2": hashes.SHA384(),
"2.16.840.1.101.3.4.2.3": hashes.SHA512(),
}
class OCSPResponderEncoding(Enum):
HASH = "By Hash"
NAME = "By Name"
class OCSPResponseStatus(Enum):
SUCCESSFUL = 0
MALFORMED_REQUEST = 1
INTERNAL_ERROR = 2
TRY_LATER = 3
SIG_REQUIRED = 5
UNAUTHORIZED = 6
_RESPONSE_STATUS_TO_ENUM = dict((x.value, x) for x in OCSPResponseStatus)
_ALLOWED_HASHES = (
hashes.SHA1, hashes.SHA224, hashes.SHA256,
hashes.SHA384, hashes.SHA512
)
def _verify_algorithm(algorithm):
if not isinstance(algorithm, _ALLOWED_HASHES):
raise ValueError(
"Algorithm must be SHA1, SHA224, SHA256, SHA384, or SHA512"
)
class OCSPCertStatus(Enum):
GOOD = 0
REVOKED = 1
UNKNOWN = 2
_CERT_STATUS_TO_ENUM = dict((x.value, x) for x in OCSPCertStatus)
def load_der_ocsp_request(data):
from cryptography.hazmat.backends.openssl.backend import backend
return backend.load_der_ocsp_request(data)
def load_der_ocsp_response(data):
from cryptography.hazmat.backends.openssl.backend import backend
return backend.load_der_ocsp_response(data)
class OCSPRequestBuilder(object):
def __init__(self, request=None, extensions=[]):
self._request = request
self._extensions = extensions
def add_certificate(self, cert, issuer, algorithm):
if self._request is not None:
raise ValueError("Only one certificate can be added to a request")
_verify_algorithm(algorithm)
if (
not isinstance(cert, x509.Certificate) or
not isinstance(issuer, x509.Certificate)
):
raise TypeError("cert and issuer must be a Certificate")
return OCSPRequestBuilder((cert, issuer, algorithm), self._extensions)
def add_extension(self, extension, critical):
if not isinstance(extension, x509.ExtensionType):
raise TypeError("extension must be an ExtensionType")
extension = x509.Extension(extension.oid, critical, extension)
_reject_duplicate_extension(extension, self._extensions)
return OCSPRequestBuilder(
self._request, self._extensions + [extension]
)
def build(self):
from cryptography.hazmat.backends.openssl.backend import backend
if self._request is None:
raise ValueError("You must add a certificate before building")
return backend.create_ocsp_request(self)
class _SingleResponse(object):
def __init__(self, cert, issuer, algorithm, cert_status, this_update,
next_update, revocation_time, revocation_reason):
if (
not isinstance(cert, x509.Certificate) or
not isinstance(issuer, x509.Certificate)
):
raise TypeError("cert and issuer must be a Certificate")
_verify_algorithm(algorithm)
if not isinstance(this_update, datetime.datetime):
raise TypeError("this_update must be a datetime object")
if (
next_update is not None and
not isinstance(next_update, datetime.datetime)
):
raise TypeError("next_update must be a datetime object or None")
self._cert = cert
self._issuer = issuer
self._algorithm = algorithm
self._this_update = this_update
self._next_update = next_update
if not isinstance(cert_status, OCSPCertStatus):
raise TypeError(
"cert_status must be an item from the OCSPCertStatus enum"
)
if cert_status is not OCSPCertStatus.REVOKED:
if revocation_time is not None:
raise ValueError(
"revocation_time can only be provided if the certificate "
"is revoked"
)
if revocation_reason is not None:
raise ValueError(
"revocation_reason can only be provided if the certificate"
" is revoked"
)
else:
if not isinstance(revocation_time, datetime.datetime):
raise TypeError("revocation_time must be a datetime object")
revocation_time = _convert_to_naive_utc_time(revocation_time)
if revocation_time < _EARLIEST_UTC_TIME:
raise ValueError('The revocation_time must be on or after'
' 1950 January 1.')
if (
revocation_reason is not None and
not isinstance(revocation_reason, x509.ReasonFlags)
):
raise TypeError(
"revocation_reason must be an item from the ReasonFlags "
"enum or None"
)
self._cert_status = cert_status
self._revocation_time = revocation_time
self._revocation_reason = revocation_reason
class OCSPResponseBuilder(object):
def __init__(self, response=None, responder_id=None, certs=None,
extensions=[]):
self._response = response
self._responder_id = responder_id
self._certs = certs
self._extensions = extensions
def add_response(self, cert, issuer, algorithm, cert_status, this_update,
next_update, revocation_time, revocation_reason):
if self._response is not None:
raise ValueError("Only one response per OCSPResponse.")
singleresp = _SingleResponse(
cert, issuer, algorithm, cert_status, this_update, next_update,
revocation_time, revocation_reason
)
return OCSPResponseBuilder(
singleresp, self._responder_id,
self._certs, self._extensions,
)
def responder_id(self, encoding, responder_cert):
if self._responder_id is not None:
raise ValueError("responder_id can only be set once")
if not isinstance(responder_cert, x509.Certificate):
raise TypeError("responder_cert must be a Certificate")
if not isinstance(encoding, OCSPResponderEncoding):
raise TypeError(
"encoding must be an element from OCSPResponderEncoding"
)
return OCSPResponseBuilder(
self._response, (responder_cert, encoding),
self._certs, self._extensions,
)
def certificates(self, certs):
if self._certs is not None:
raise ValueError("certificates may only be set once")
certs = list(certs)
if len(certs) == 0:
raise ValueError("certs must not be an empty list")
if not all(isinstance(x, x509.Certificate) for x in certs):
raise TypeError("certs must be a list of Certificates")
return OCSPResponseBuilder(
self._response, self._responder_id,
certs, self._extensions,
)
def add_extension(self, extension, critical):
if not isinstance(extension, x509.ExtensionType):
raise TypeError("extension must be an ExtensionType")
extension = x509.Extension(extension.oid, critical, extension)
_reject_duplicate_extension(extension, self._extensions)
return OCSPResponseBuilder(
self._response, self._responder_id,
self._certs, self._extensions + [extension],
)
def sign(self, private_key, algorithm):
from cryptography.hazmat.backends.openssl.backend import backend
if self._response is None:
raise ValueError("You must add a response before signing")
if self._responder_id is None:
raise ValueError("You must add a responder_id before signing")
if isinstance(private_key,
(ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)):
if algorithm is not None:
raise ValueError(
"algorithm must be None when signing via ed25519 or ed448"
)
elif not isinstance(algorithm, hashes.HashAlgorithm):
raise TypeError("Algorithm must be a registered hash algorithm.")
return backend.create_ocsp_response(
OCSPResponseStatus.SUCCESSFUL, self, private_key, algorithm
)
@classmethod
def build_unsuccessful(cls, response_status):
from cryptography.hazmat.backends.openssl.backend import backend
if not isinstance(response_status, OCSPResponseStatus):
raise TypeError(
"response_status must be an item from OCSPResponseStatus"
)
if response_status is OCSPResponseStatus.SUCCESSFUL:
raise ValueError("response_status cannot be SUCCESSFUL")
return backend.create_ocsp_response(response_status, None, None, None)
@six.add_metaclass(abc.ABCMeta)
class OCSPRequest(object):
@abc.abstractproperty
def issuer_key_hash(self):
"""
The hash of the issuer public key
"""
@abc.abstractproperty
def issuer_name_hash(self):
"""
The hash of the issuer name
"""
@abc.abstractproperty
def hash_algorithm(self):
"""
The hash algorithm used in the issuer name and key hashes
"""
@abc.abstractproperty
def serial_number(self):
"""
The serial number of the cert whose status is being checked
"""
@abc.abstractmethod
def public_bytes(self, encoding):
"""
Serializes the request to DER
"""
@abc.abstractproperty
def extensions(self):
"""
The list of request extensions. Not single request extensions.
"""
@six.add_metaclass(abc.ABCMeta)
class OCSPResponse(object):
@abc.abstractproperty
def response_status(self):
"""
The status of the response. This is a value from the OCSPResponseStatus
enumeration
"""
@abc.abstractproperty
def signature_algorithm_oid(self):
"""
The ObjectIdentifier of the signature algorithm
"""
@abc.abstractproperty
def signature_hash_algorithm(self):
"""
Returns a HashAlgorithm corresponding to the type of the digest signed
"""
@abc.abstractproperty
def signature(self):
"""
The signature bytes
"""
@abc.abstractproperty
def tbs_response_bytes(self):
"""
The tbsResponseData bytes
"""
@abc.abstractproperty
def certificates(self):
"""
A list of certificates used to help build a chain to verify the OCSP
response. This situation occurs when the OCSP responder uses a delegate
certificate.
"""
@abc.abstractproperty
def responder_key_hash(self):
"""
The responder's key hash or None
"""
@abc.abstractproperty
def responder_name(self):
"""
The responder's Name or None
"""
@abc.abstractproperty
def produced_at(self):
"""
The time the response was produced
"""
@abc.abstractproperty
def certificate_status(self):
"""
The status of the certificate (an element from the OCSPCertStatus enum)
"""
@abc.abstractproperty
def revocation_time(self):
"""
The date of when the certificate was revoked or None if not
revoked.
"""
@abc.abstractproperty
def revocation_reason(self):
"""
The reason the certificate was revoked or None if not specified or
not revoked.
"""
@abc.abstractproperty
def this_update(self):
"""
The most recent time at which the status being indicated is known by
the responder to have been correct
"""
@abc.abstractproperty
def next_update(self):
"""
The time when newer information will be available
"""
@abc.abstractproperty
def issuer_key_hash(self):
"""
The hash of the issuer public key
"""
@abc.abstractproperty
def issuer_name_hash(self):
"""
The hash of the issuer name
"""
@abc.abstractproperty
def hash_algorithm(self):
"""
The hash algorithm used in the issuer name and key hashes
"""
@abc.abstractproperty
def serial_number(self):
"""
The serial number of the cert whose status is being checked
"""
@abc.abstractproperty
def extensions(self):
"""
The list of response extensions. Not single response extensions.
"""
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography/x509/oid.py
================================================
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography.hazmat._oid import ObjectIdentifier
from cryptography.hazmat.primitives import hashes
class ExtensionOID(object):
SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9")
SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14")
KEY_USAGE = ObjectIdentifier("2.5.29.15")
SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17")
ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18")
BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19")
NAME_CONSTRAINTS = ObjectIdentifier("2.5.29.30")
CRL_DISTRIBUTION_POINTS = ObjectIdentifier("2.5.29.31")
CERTIFICATE_POLICIES = ObjectIdentifier("2.5.29.32")
POLICY_MAPPINGS = ObjectIdentifier("2.5.29.33")
AUTHORITY_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.35")
POLICY_CONSTRAINTS = ObjectIdentifier("2.5.29.36")
EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37")
FRESHEST_CRL = ObjectIdentifier("2.5.29.46")
INHIBIT_ANY_POLICY = ObjectIdentifier("2.5.29.54")
ISSUING_DISTRIBUTION_POINT = ObjectIdentifier("2.5.29.28")
AUTHORITY_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.1")
SUBJECT_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.11")
OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5")
TLS_FEATURE = ObjectIdentifier("1.3.6.1.5.5.7.1.24")
CRL_NUMBER = ObjectIdentifier("2.5.29.20")
DELTA_CRL_INDICATOR = ObjectIdentifier("2.5.29.27")
PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS = (
ObjectIdentifier("1.3.6.1.4.1.11129.2.4.2")
)
PRECERT_POISON = (
ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3")
)
class OCSPExtensionOID(object):
NONCE = ObjectIdentifier("1.3.6.1.5.5.7.48.1.2")
class CRLEntryExtensionOID(object):
CERTIFICATE_ISSUER = ObjectIdentifier("2.5.29.29")
CRL_REASON = ObjectIdentifier("2.5.29.21")
INVALIDITY_DATE = ObjectIdentifier("2.5.29.24")
class NameOID(object):
COMMON_NAME = ObjectIdentifier("2.5.4.3")
COUNTRY_NAME = ObjectIdentifier("2.5.4.6")
LOCALITY_NAME = ObjectIdentifier("2.5.4.7")
STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8")
STREET_ADDRESS = ObjectIdentifier("2.5.4.9")
ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10")
ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier("2.5.4.11")
SERIAL_NUMBER = ObjectIdentifier("2.5.4.5")
SURNAME = ObjectIdentifier("2.5.4.4")
GIVEN_NAME = ObjectIdentifier("2.5.4.42")
TITLE = ObjectIdentifier("2.5.4.12")
GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44")
X500_UNIQUE_IDENTIFIER = ObjectIdentifier("2.5.4.45")
DN_QUALIFIER = ObjectIdentifier("2.5.4.46")
PSEUDONYM = ObjectIdentifier("2.5.4.65")
USER_ID = ObjectIdentifier("0.9.2342.19200300.100.1.1")
DOMAIN_COMPONENT = ObjectIdentifier("0.9.2342.19200300.100.1.25")
EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1")
JURISDICTION_COUNTRY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.3")
JURISDICTION_LOCALITY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.1")
JURISDICTION_STATE_OR_PROVINCE_NAME = ObjectIdentifier(
"1.3.6.1.4.1.311.60.2.1.2"
)
BUSINESS_CATEGORY = ObjectIdentifier("2.5.4.15")
POSTAL_ADDRESS = ObjectIdentifier("2.5.4.16")
POSTAL_CODE = ObjectIdentifier("2.5.4.17")
class SignatureAlgorithmOID(object):
RSA_WITH_MD5 = ObjectIdentifier("1.2.840.113549.1.1.4")
RSA_WITH_SHA1 = ObjectIdentifier("1.2.840.113549.1.1.5")
# This is an alternate OID for RSA with SHA1 that is occasionally seen
_RSA_WITH_SHA1 = ObjectIdentifier("1.3.14.3.2.29")
RSA_WITH_SHA224 = ObjectIdentifier("1.2.840.113549.1.1.14")
RSA_WITH_SHA256 = ObjectIdentifier("1.2.840.113549.1.1.11")
RSA_WITH_SHA384 = ObjectIdentifier("1.2.840.113549.1.1.12")
RSA_WITH_SHA512 = ObjectIdentifier("1.2.840.113549.1.1.13")
RSASSA_PSS = ObjectIdentifier("1.2.840.113549.1.1.10")
ECDSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10045.4.1")
ECDSA_WITH_SHA224 = ObjectIdentifier("1.2.840.10045.4.3.1")
ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2")
ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3")
ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4")
DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3")
DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1")
DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2")
ED25519 = ObjectIdentifier("1.3.101.112")
ED448 = ObjectIdentifier("1.3.101.113")
_SIG_OIDS_TO_HASH = {
SignatureAlgorithmOID.RSA_WITH_MD5: hashes.MD5(),
SignatureAlgorithmOID.RSA_WITH_SHA1: hashes.SHA1(),
SignatureAlgorithmOID._RSA_WITH_SHA1: hashes.SHA1(),
SignatureAlgorithmOID.RSA_WITH_SHA224: hashes.SHA224(),
SignatureAlgorithmOID.RSA_WITH_SHA256: hashes.SHA256(),
SignatureAlgorithmOID.RSA_WITH_SHA384: hashes.SHA384(),
SignatureAlgorithmOID.RSA_WITH_SHA512: hashes.SHA512(),
SignatureAlgorithmOID.ECDSA_WITH_SHA1: hashes.SHA1(),
SignatureAlgorithmOID.ECDSA_WITH_SHA224: hashes.SHA224(),
SignatureAlgorithmOID.ECDSA_WITH_SHA256: hashes.SHA256(),
SignatureAlgorithmOID.ECDSA_WITH_SHA384: hashes.SHA384(),
SignatureAlgorithmOID.ECDSA_WITH_SHA512: hashes.SHA512(),
SignatureAlgorithmOID.DSA_WITH_SHA1: hashes.SHA1(),
SignatureAlgorithmOID.DSA_WITH_SHA224: hashes.SHA224(),
SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256(),
SignatureAlgorithmOID.ED25519: None,
SignatureAlgorithmOID.ED448: None,
}
class ExtendedKeyUsageOID(object):
SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1")
CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2")
CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3")
EMAIL_PROTECTION = ObjectIdentifier("1.3.6.1.5.5.7.3.4")
TIME_STAMPING = ObjectIdentifier("1.3.6.1.5.5.7.3.8")
OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9")
ANY_EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37.0")
class AuthorityInformationAccessOID(object):
CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2")
OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1")
class CertificatePoliciesOID(object):
CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1")
CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2")
ANY_POLICY = ObjectIdentifier("2.5.29.32.0")
_OID_NAMES = {
NameOID.COMMON_NAME: "commonName",
NameOID.COUNTRY_NAME: "countryName",
NameOID.LOCALITY_NAME: "localityName",
NameOID.STATE_OR_PROVINCE_NAME: "stateOrProvinceName",
NameOID.STREET_ADDRESS: "streetAddress",
NameOID.ORGANIZATION_NAME: "organizationName",
NameOID.ORGANIZATIONAL_UNIT_NAME: "organizationalUnitName",
NameOID.SERIAL_NUMBER: "serialNumber",
NameOID.SURNAME: "surname",
NameOID.GIVEN_NAME: "givenName",
NameOID.TITLE: "title",
NameOID.GENERATION_QUALIFIER: "generationQualifier",
NameOID.X500_UNIQUE_IDENTIFIER: "x500UniqueIdentifier",
NameOID.DN_QUALIFIER: "dnQualifier",
NameOID.PSEUDONYM: "pseudonym",
NameOID.USER_ID: "userID",
NameOID.DOMAIN_COMPONENT: "domainComponent",
NameOID.EMAIL_ADDRESS: "emailAddress",
NameOID.JURISDICTION_COUNTRY_NAME: "jurisdictionCountryName",
NameOID.JURISDICTION_LOCALITY_NAME: "jurisdictionLocalityName",
NameOID.JURISDICTION_STATE_OR_PROVINCE_NAME: (
"jurisdictionStateOrProvinceName"
),
NameOID.BUSINESS_CATEGORY: "businessCategory",
NameOID.POSTAL_ADDRESS: "postalAddress",
NameOID.POSTAL_CODE: "postalCode",
SignatureAlgorithmOID.RSA_WITH_MD5: "md5WithRSAEncryption",
SignatureAlgorithmOID.RSA_WITH_SHA1: "sha1WithRSAEncryption",
SignatureAlgorithmOID.RSA_WITH_SHA224: "sha224WithRSAEncryption",
SignatureAlgorithmOID.RSA_WITH_SHA256: "sha256WithRSAEncryption",
SignatureAlgorithmOID.RSA_WITH_SHA384: "sha384WithRSAEncryption",
SignatureAlgorithmOID.RSA_WITH_SHA512: "sha512WithRSAEncryption",
SignatureAlgorithmOID.RSASSA_PSS: "RSASSA-PSS",
SignatureAlgorithmOID.ECDSA_WITH_SHA1: "ecdsa-with-SHA1",
SignatureAlgorithmOID.ECDSA_WITH_SHA224: "ecdsa-with-SHA224",
SignatureAlgorithmOID.ECDSA_WITH_SHA256: "ecdsa-with-SHA256",
SignatureAlgorithmOID.ECDSA_WITH_SHA384: "ecdsa-with-SHA384",
SignatureAlgorithmOID.ECDSA_WITH_SHA512: "ecdsa-with-SHA512",
SignatureAlgorithmOID.DSA_WITH_SHA1: "dsa-with-sha1",
SignatureAlgorithmOID.DSA_WITH_SHA224: "dsa-with-sha224",
SignatureAlgorithmOID.DSA_WITH_SHA256: "dsa-with-sha256",
SignatureAlgorithmOID.ED25519: "ed25519",
SignatureAlgorithmOID.ED448: "ed448",
ExtendedKeyUsageOID.SERVER_AUTH: "serverAuth",
ExtendedKeyUsageOID.CLIENT_AUTH: "clientAuth",
ExtendedKeyUsageOID.CODE_SIGNING: "codeSigning",
ExtendedKeyUsageOID.EMAIL_PROTECTION: "emailProtection",
ExtendedKeyUsageOID.TIME_STAMPING: "timeStamping",
ExtendedKeyUsageOID.OCSP_SIGNING: "OCSPSigning",
ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES: "subjectDirectoryAttributes",
ExtensionOID.SUBJECT_KEY_IDENTIFIER: "subjectKeyIdentifier",
ExtensionOID.KEY_USAGE: "keyUsage",
ExtensionOID.SUBJECT_ALTERNATIVE_NAME: "subjectAltName",
ExtensionOID.ISSUER_ALTERNATIVE_NAME: "issuerAltName",
ExtensionOID.BASIC_CONSTRAINTS: "basicConstraints",
ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: (
"signedCertificateTimestampList"
),
ExtensionOID.PRECERT_POISON: "ctPoison",
CRLEntryExtensionOID.CRL_REASON: "cRLReason",
CRLEntryExtensionOID.INVALIDITY_DATE: "invalidityDate",
CRLEntryExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer",
ExtensionOID.NAME_CONSTRAINTS: "nameConstraints",
ExtensionOID.CRL_DISTRIBUTION_POINTS: "cRLDistributionPoints",
ExtensionOID.CERTIFICATE_POLICIES: "certificatePolicies",
ExtensionOID.POLICY_MAPPINGS: "policyMappings",
ExtensionOID.AUTHORITY_KEY_IDENTIFIER: "authorityKeyIdentifier",
ExtensionOID.POLICY_CONSTRAINTS: "policyConstraints",
ExtensionOID.EXTENDED_KEY_USAGE: "extendedKeyUsage",
ExtensionOID.FRESHEST_CRL: "freshestCRL",
ExtensionOID.INHIBIT_ANY_POLICY: "inhibitAnyPolicy",
ExtensionOID.ISSUING_DISTRIBUTION_POINT: (
"issuingDistributionPoint"
),
ExtensionOID.AUTHORITY_INFORMATION_ACCESS: "authorityInfoAccess",
ExtensionOID.SUBJECT_INFORMATION_ACCESS: "subjectInfoAccess",
ExtensionOID.OCSP_NO_CHECK: "OCSPNoCheck",
ExtensionOID.CRL_NUMBER: "cRLNumber",
ExtensionOID.DELTA_CRL_INDICATOR: "deltaCRLIndicator",
ExtensionOID.TLS_FEATURE: "TLSFeature",
AuthorityInformationAccessOID.OCSP: "OCSP",
AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers",
CertificatePoliciesOID.CPS_QUALIFIER: "id-qt-cps",
CertificatePoliciesOID.CPS_USER_NOTICE: "id-qt-unotice",
OCSPExtensionOID.NONCE: "OCSPNonce",
}
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography-2.8.dist-info/AUTHORS.rst
================================================
AUTHORS
=======
PGP key fingerprints are enclosed in parentheses.
* Alex Gaynor (E27D 4AA0 1651 72CB C5D2 AF2B 125F 5C67 DFE9 4084)
* Hynek Schlawack (C2A0 4F86 ACE2 8ADC F817 DBB7 AE25 3622 7F69 F181)
* Donald Stufft
* Laurens Van Houtven <_@lvh.io> (D9DC 4315 772F 8E91 DD22 B153 DFD1 3DF7 A8DD 569B)
* Christian Heimes
* Paul Kehrer (05FD 9FA1 6CF7 5735 0D91 A560 235A E5F1 29F9 ED98)
* Jarret Raim
* Alex Stapleton (A1C7 E50B 66DE 39ED C847 9665 8E3C 20D1 9BD9 5C4C)
* David Reid (0F83 CC87 B32F 482B C726 B58A 9FBF D8F4 DA89 6D74)
* Matthew Lefkowitz (06AB F638 E878 CD29 1264 18AB 7EC2 8125 0FBC 4A07)
* Konstantinos Koukopoulos (D6BD 52B6 8C99 A91C E2C8 934D 3300 566B 3A46 726E)
* Stephen Holsapple
* Terry Chia
* Matthew Iversen (2F04 3DCC D6E6 D5AC D262 2E0B C046 E8A8 7452 2973)
* Mohammed Attia
* Michael Hart
* Mark Adams (A18A 7DD3 283C CF2A B0CE FE0E C7A0 5E3F C972 098C)
* Gregory Haynes (6FB6 44BF 9FD0 EBA2 1CE9 471F B08F 42F9 0DC6 599F)
* Chelsea Winfree
* Steven Buss (1FB9 2EC1 CF93 DFD6 B47F F583 B1A5 6C22 290D A4C3)
* Andre Caron
* Jiangge Zhang (BBEC 782B 015F 71B1 5FF7 EACA 1A8C AA98 255F 5000)
* Major Hayden (1BF9 9264 9596 0033 698C 252B 7370 51E0 C101 1FB1)
* Phoebe Queen (10D4 7741 AB65 50F4 B264 3888 DA40 201A 072B C1FA)
* Google Inc.
* Amaury Forgeot d'Arc
* Dirkjan Ochtman (25BB BAC1 13C1 BFD5 AA59 4A4C 9F96 B929 3038 0381)
* Maximilian Hils
* Simo Sorce
* Thomas Sileo
* Fraser Tweedale
* Ofek Lev (FFB6 B92B 30B1 7848 546E 9912 972F E913 DAD5 A46E)
* Erik Daguerre
* Aviv Palivoda
* Chris Wolfe
* Jeremy Lainé
* Denis Gladkikh
* John Pacific (2CF6 0381 B5EF 29B7 D48C 2020 7BB9 71A0 E891 44D9)
* Marti Raudsepp
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography-2.8.dist-info/INSTALLER
================================================
pip
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography-2.8.dist-info/LICENSE
================================================
This software is made available under the terms of *either* of the licenses
found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made
under the terms of *both* these licenses.
The code used in the OpenSSL locking callback and OS random engine is derived
from CPython, and is licensed under the terms of the PSF License Agreement.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography-2.8.dist-info/LICENSE.APACHE
================================================
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography-2.8.dist-info/LICENSE.BSD
================================================
Copyright (c) Individual contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of PyCA Cryptography nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography-2.8.dist-info/LICENSE.PSF
================================================
1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
the Individual or Organization ("Licensee") accessing and otherwise using Python
2.7.12 software in source or binary form and its associated documentation.
2. Subject to the terms and conditions of this License Agreement, PSF hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
analyze, test, perform and/or display publicly, prepare derivative works,
distribute, and otherwise use Python 2.7.12 alone or in any derivative
version, provided, however, that PSF's License Agreement and PSF's notice of
copyright, i.e., "Copyright © 2001-2016 Python Software Foundation; All Rights
Reserved" are retained in Python 2.7.12 alone or in any derivative version
prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on or
incorporates Python 2.7.12 or any part thereof, and wants to make the
derivative work available to others as provided herein, then Licensee hereby
agrees to include in any such work a brief summary of the changes made to Python
2.7.12.
4. PSF is making Python 2.7.12 available to Licensee on an "AS IS" basis.
PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
USE OF PYTHON 2.7.12 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.7.12
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.7.12, OR ANY DERIVATIVE
THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material breach of
its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any relationship
of agency, partnership, or joint venture between PSF and Licensee. This License
Agreement does not grant permission to use PSF trademarks or trade name in a
trademark sense to endorse or promote products or services of Licensee, or any
third party.
8. By copying, installing or otherwise using Python 2.7.12, Licensee agrees
to be bound by the terms and conditions of this License Agreement.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography-2.8.dist-info/METADATA
================================================
Metadata-Version: 2.1
Name: cryptography
Version: 2.8
Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers.
Home-page: https://github.com/pyca/cryptography
Author: The cryptography developers
Author-email: cryptography-dev@python.org
License: BSD or Apache License, Version 2.0
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: License :: OSI Approved :: BSD License
Classifier: Natural Language :: English
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: POSIX
Classifier: Operating System :: POSIX :: BSD
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Security :: Cryptography
Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*
Description-Content-Type: text/x-rst
Requires-Dist: six (>=1.4.1)
Requires-Dist: cffi (!=1.11.3,>=1.8)
Requires-Dist: enum34 ; python_version < '3'
Requires-Dist: ipaddress ; python_version < '3'
Provides-Extra: docs
Requires-Dist: sphinx (!=1.8.0,>=1.6.5) ; extra == 'docs'
Requires-Dist: sphinx-rtd-theme ; extra == 'docs'
Provides-Extra: docstest
Requires-Dist: doc8 ; extra == 'docstest'
Requires-Dist: pyenchant (>=1.6.11) ; extra == 'docstest'
Requires-Dist: twine (>=1.12.0) ; extra == 'docstest'
Requires-Dist: sphinxcontrib-spelling (>=4.0.1) ; extra == 'docstest'
Provides-Extra: idna
Requires-Dist: idna (>=2.1) ; extra == 'idna'
Provides-Extra: pep8test
Requires-Dist: flake8 ; extra == 'pep8test'
Requires-Dist: flake8-import-order ; extra == 'pep8test'
Requires-Dist: pep8-naming ; extra == 'pep8test'
Provides-Extra: test
Requires-Dist: pytest (!=3.9.0,!=3.9.1,!=3.9.2,>=3.6.0) ; extra == 'test'
Requires-Dist: pretend ; extra == 'test'
Requires-Dist: iso8601 ; extra == 'test'
Requires-Dist: pytz ; extra == 'test'
Requires-Dist: hypothesis (!=3.79.2,>=1.11.4) ; extra == 'test'
pyca/cryptography
=================
.. image:: https://img.shields.io/pypi/v/cryptography.svg
:target: https://pypi.org/project/cryptography/
:alt: Latest Version
.. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest
:target: https://cryptography.io
:alt: Latest Docs
.. image:: https://travis-ci.org/pyca/cryptography.svg?branch=master
:target: https://travis-ci.org/pyca/cryptography
.. image:: https://dev.azure.com/pyca/cryptography/_apis/build/status/Azure%20CI?branchName=master
:target: https://dev.azure.com/pyca/cryptography/_build/latest?definitionId=3&branchName=master
.. image:: https://codecov.io/github/pyca/cryptography/coverage.svg?branch=master
:target: https://codecov.io/github/pyca/cryptography?branch=master
``cryptography`` is a package which provides cryptographic recipes and
primitives to Python developers. Our goal is for it to be your "cryptographic
standard library". It supports Python 2.7, Python 3.4+, and PyPy 5.4+.
``cryptography`` includes both high level recipes and low level interfaces to
common cryptographic algorithms such as symmetric ciphers, message digests, and
key derivation functions. For example, to encrypt something with
``cryptography``'s high level symmetric encryption recipe:
.. code-block:: pycon
>>> from cryptography.fernet import Fernet
>>> # Put this somewhere safe!
>>> key = Fernet.generate_key()
>>> f = Fernet(key)
>>> token = f.encrypt(b"A really secret message. Not for prying eyes.")
>>> token
'...'
>>> f.decrypt(token)
'A really secret message. Not for prying eyes.'
You can find more information in the `documentation`_.
You can install ``cryptography`` with:
.. code-block:: console
$ pip install cryptography
For full details see `the installation documentation`_.
Discussion
~~~~~~~~~~
If you run into bugs, you can file them in our `issue tracker`_.
We maintain a `cryptography-dev`_ mailing list for development discussion.
You can also join ``#cryptography-dev`` on Freenode to ask questions or get
involved.
Security
~~~~~~~~
Need to report a security issue? Please consult our `security reporting`_
documentation.
.. _`documentation`: https://cryptography.io/
.. _`the installation documentation`: https://cryptography.io/en/latest/installation/
.. _`issue tracker`: https://github.com/pyca/cryptography/issues
.. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev
.. _`security reporting`: https://cryptography.io/en/latest/security/
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography-2.8.dist-info/RECORD
================================================
cryptography-2.8.dist-info/AUTHORS.rst,sha256=MoKTlP6yOmnLC_KXarHVQP0sItBk11dtZ7LzV0VhNB0,2475
cryptography-2.8.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
cryptography-2.8.dist-info/LICENSE,sha256=NUUrVX-rDvsegNftucTlEYuThAgq2qBR3eNCECy53o0,352
cryptography-2.8.dist-info/LICENSE.APACHE,sha256=qsc7MUj20dcRHbyjIJn2jSbGRMaBOuHk8F9leaomY_4,11360
cryptography-2.8.dist-info/LICENSE.BSD,sha256=YCxMdILeZHndLpeTzaJ15eY9dz2s0eymiSMqtwCPtPs,1532
cryptography-2.8.dist-info/LICENSE.PSF,sha256=aT7ApmKzn5laTyUrA6YiKUVHDBtvEsoCkY5O_g32S58,2415
cryptography-2.8.dist-info/METADATA,sha256=DTs0WZ8nip9kDpwx2m_l-9t0E6gBmIPs-BuE_EJOtbg,5175
cryptography-2.8.dist-info/RECORD,,
cryptography-2.8.dist-info/WHEEL,sha256=QMVol4obO-h_ZZLSvUyPjs3tbFnVOtWLzOTlaMWgEN8,111
cryptography-2.8.dist-info/top_level.txt,sha256=QCkYQE4HJBpqIr-aBqbOZ70NlfbejKnDE6ODbNgUwwg,46
cryptography/__about__.py,sha256=DfioEQ1oTJa9q9bA7yTTxFvxt_oik9bZQDZbgeU5XcE,814
cryptography/__init__.py,sha256=M7mQrfCHYuk7TpEPpfYxkhc95comqxOt41xYjLa5wiA,527
cryptography/__pycache__/__about__.cpython-36.pyc,,
cryptography/__pycache__/__init__.cpython-36.pyc,,
cryptography/__pycache__/exceptions.cpython-36.pyc,,
cryptography/__pycache__/fernet.cpython-36.pyc,,
cryptography/__pycache__/utils.cpython-36.pyc,,
cryptography/exceptions.py,sha256=NPtDqIq1lsQ1Gb1BXkjsGIvbMrWMaKCaT8epiSgi010,1259
cryptography/fernet.py,sha256=CA4iWQvPDeF9EN0IWq8xyuBBqMvcpEE17Ii8VGbi19Y,5220
cryptography/hazmat/__init__.py,sha256=hEPNQw8dgjIPIn42qaLwXNRLCyTGNZeSvkQb57DPhbs,483
cryptography/hazmat/__pycache__/__init__.cpython-36.pyc,,
cryptography/hazmat/__pycache__/_der.cpython-36.pyc,,
cryptography/hazmat/__pycache__/_oid.cpython-36.pyc,,
cryptography/hazmat/_der.py,sha256=9wV7usssA-_Ikxo0h5uVEJJcY6uRbw4UhlgjLhXYsk0,5205
cryptography/hazmat/_oid.py,sha256=F1RU1q8LPLrCoCxyBk_TZ5yJeFt1kYcPMqaIHu4sBRY,2178
cryptography/hazmat/backends/__init__.py,sha256=92UZdmqTyQPOYA2ui17tksyjxBnTmj1XDsxDCChLvxE,496
cryptography/hazmat/backends/__pycache__/__init__.cpython-36.pyc,,
cryptography/hazmat/backends/__pycache__/interfaces.cpython-36.pyc,,
cryptography/hazmat/backends/interfaces.py,sha256=MoNrfcaP5cpD0_wJH5v6vyGSXC8OsbAAHm4-9TZSIU0,10783
cryptography/hazmat/backends/openssl/__init__.py,sha256=k4DMe228_hTuB2kY3Lwk62JdI3EmCd7VkV01zJm57ps,336
cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/aead.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/ciphers.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/cmac.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/decode_asn1.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/dh.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/dsa.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/ec.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/ed25519.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/ed448.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/encode_asn1.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/hashes.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/hmac.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/ocsp.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/poly1305.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/rsa.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/utils.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/x25519.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/x448.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/__pycache__/x509.cpython-36.pyc,,
cryptography/hazmat/backends/openssl/aead.py,sha256=U0Ncw0z4-pqEWRxJu9GzZDPTvp8YBW5GHFebckaFLTs,5750
cryptography/hazmat/backends/openssl/backend.py,sha256=9ZcByUpQS8kwqLKeZoKUDZGj1dwCnrnAyEJ1ng__TUc,97231
cryptography/hazmat/backends/openssl/ciphers.py,sha256=glsURUBxfMqj0XYTcEosZx6oBL-FCadhIIuQA1cxmfU,9314
cryptography/hazmat/backends/openssl/cmac.py,sha256=wxCHffVAEFxcn6ATMPy7HATIjWZWMoKdTXHJCgeUf48,2855
cryptography/hazmat/backends/openssl/decode_asn1.py,sha256=kPsCTGczXnxkGP471kot8rw9CBFvcuyAtJX13caubDo,33303
cryptography/hazmat/backends/openssl/dh.py,sha256=kXH0LXLsgo7FLNan6V5BiidS30zVkWNwaWuVZ-n6Uog,10814
cryptography/hazmat/backends/openssl/dsa.py,sha256=YOFM_ml2J4q6TI5-oh8M9RPS3u2dcUWxT51Yxfpbs7o,10228
cryptography/hazmat/backends/openssl/ec.py,sha256=okZ87EcaOJRGmjEUvIPqDV7Jp6xcky4oFPSN6fXbGrs,12590
cryptography/hazmat/backends/openssl/ed25519.py,sha256=66dkJPZ6gvUCJSA0RPydi1-0Q2WjhiAcKwvD2R59Zzc,6081
cryptography/hazmat/backends/openssl/ed448.py,sha256=2W6KwzPQXPvvkaNZWFxI_L8rIP80vhBcdZVbIzS5MmY,6045
cryptography/hazmat/backends/openssl/encode_asn1.py,sha256=8XUOTdGreOYvWhiVeQtL7XVqlBpP-rnLuDrmM7bG4LQ,23593
cryptography/hazmat/backends/openssl/hashes.py,sha256=_uYcKjrWzCifz9uONPFBGba7QC3o66-KzxkSNf2uI_A,3196
cryptography/hazmat/backends/openssl/hmac.py,sha256=-5MsNq9-A7Is_nUjMdz0FnOpdy3MnowCWqDGGL67hyM,2998
cryptography/hazmat/backends/openssl/ocsp.py,sha256=lnCm5e37lLoqI_dTgf2dv5qS-vGo8CL3MQh6ojLFBA0,13654
cryptography/hazmat/backends/openssl/poly1305.py,sha256=WaQ3LyxPD2m9auySy4mzDMMoWxTT4pw_zhg55n1D6Gg,2356
cryptography/hazmat/backends/openssl/rsa.py,sha256=swgjJBJfxskdLzAiUJ_jJ9lAzkn83un5Tqvi4fV8p98,18021
cryptography/hazmat/backends/openssl/utils.py,sha256=LqzoMfLbO3385h-JgV8RiWQj0bvtRy76LzimRqjIT2Q,2339
cryptography/hazmat/backends/openssl/x25519.py,sha256=Soo-zS0WsXp6jwJgzVWjhhosMNWbZ6QR6kC-Splwd8I,5580
cryptography/hazmat/backends/openssl/x448.py,sha256=-vMoIJJ4X3HdB4LrWxxq0_xp0sDM69S6VM_P-dqie24,4526
cryptography/hazmat/backends/openssl/x509.py,sha256=Jjl-sJiQvtmM9CbnRCqGs3bxeyfW-TrDsUAX0GvHqrM,20099
cryptography/hazmat/bindings/__init__.py,sha256=0wGw2OF9R7fHX7NWENCmrsYigbXHU2ojgn-N4Rkjs9U,246
cryptography/hazmat/bindings/__pycache__/__init__.cpython-36.pyc,,
cryptography/hazmat/bindings/_constant_time.abi3.so,sha256=F5VZJgeBmqhXqtR39Uf3-T3tZUwRx0Qcwm5XZL_MoXI,30048
cryptography/hazmat/bindings/_openssl.abi3.so,sha256=k2K7IN4Ao0OhMNPZY-GV3CgX0ie3f2WS3XzDZKltrSw,5627248
cryptography/hazmat/bindings/_padding.abi3.so,sha256=pT7wrkBNuG7Y-gm6XSqV7pq_Ni1nadb1rJAh7QUKQNM,33520
cryptography/hazmat/bindings/openssl/__init__.py,sha256=0wGw2OF9R7fHX7NWENCmrsYigbXHU2ojgn-N4Rkjs9U,246
cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-36.pyc,,
cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-36.pyc,,
cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-36.pyc,,
cryptography/hazmat/bindings/openssl/_conditional.py,sha256=HXtnoHgt5jIsEjWcKQFHJ47yBAVsBfLO2XMSbffd-JE,11233
cryptography/hazmat/bindings/openssl/binding.py,sha256=QCYFKaDiuYFhxK3l6Lkvr4V-PXuu26saC09AUNzUJvQ,7120
cryptography/hazmat/primitives/__init__.py,sha256=0wGw2OF9R7fHX7NWENCmrsYigbXHU2ojgn-N4Rkjs9U,246
cryptography/hazmat/primitives/__pycache__/__init__.cpython-36.pyc,,
cryptography/hazmat/primitives/__pycache__/cmac.cpython-36.pyc,,
cryptography/hazmat/primitives/__pycache__/constant_time.cpython-36.pyc,,
cryptography/hazmat/primitives/__pycache__/hashes.cpython-36.pyc,,
cryptography/hazmat/primitives/__pycache__/hmac.cpython-36.pyc,,
cryptography/hazmat/primitives/__pycache__/keywrap.cpython-36.pyc,,
cryptography/hazmat/primitives/__pycache__/padding.cpython-36.pyc,,
cryptography/hazmat/primitives/__pycache__/poly1305.cpython-36.pyc,,
cryptography/hazmat/primitives/asymmetric/__init__.py,sha256=WhUn3tGxoLAxGAsZHElJ2aOILXSh55AZi04MBudYmQA,1020
cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-36.pyc,,
cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-36.pyc,,
cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-36.pyc,,
cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-36.pyc,,
cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-36.pyc,,
cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-36.pyc,,
cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-36.pyc,,
cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-36.pyc,,
cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-36.pyc,,
cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-36.pyc,,
cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-36.pyc,,
cryptography/hazmat/primitives/asymmetric/dh.py,sha256=6Xl01bjTVHFCcdJr3Ph2cQ7hxkYYedqm-SekZpxnntY,5454
cryptography/hazmat/primitives/asymmetric/dsa.py,sha256=uzK7qpe0BtqHkgVLSrNGtska1w3JSUN_uZp6XAA5LMY,6891
cryptography/hazmat/primitives/asymmetric/ec.py,sha256=omk32C3oyISuzjH37lmzO2e95DU3qnkTPwzZAHXj4dw,13758
cryptography/hazmat/primitives/asymmetric/ed25519.py,sha256=K7dGHENDEmO0kS0fqeT6dcmMRo9IbKLus26WAfDDhjM,2395
cryptography/hazmat/primitives/asymmetric/ed448.py,sha256=eoRniA5yN3fgT0Vutuo-j6i1yeiKEKA_-4aErJPdl6w,2322
cryptography/hazmat/primitives/asymmetric/padding.py,sha256=aCZatU5-q_WW5vazBWeKPF8ZZa0AI8hWzbJaVRN3RWI,2261
cryptography/hazmat/primitives/asymmetric/rsa.py,sha256=V7MKK29BpNGF2f3uWEs3HPYbGuL3YtDFujvjFQrle0Q,10317
cryptography/hazmat/primitives/asymmetric/utils.py,sha256=Og5jZxYoCE9BMb3dmquMTantjsjzl0z2mqoc9s-0588,1184
cryptography/hazmat/primitives/asymmetric/x25519.py,sha256=LZ9dKxAjFdR-VE5OO0CijGUyJxiqFFynCeucTOYQUCk,2281
cryptography/hazmat/primitives/asymmetric/x448.py,sha256=gbZ_UdVIozeZV7FfdpI5qp4t31nWGUXiKwfgMYrF2iY,2249
cryptography/hazmat/primitives/ciphers/__init__.py,sha256=QxaxejeFfz6CPhI1c4iNq_7DsiB41Y_Q-uLfzOx7fv8,626
cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-36.pyc,,
cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-36.pyc,,
cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-36.pyc,,
cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-36.pyc,,
cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-36.pyc,,
cryptography/hazmat/primitives/ciphers/aead.py,sha256=XpXxKVAOznjEpFcPxa-sU_kJSowGjGljpp779Ob8W9g,6437
cryptography/hazmat/primitives/ciphers/algorithms.py,sha256=IXGUj-SRVKyHfDdyqUkRkVdySJ5s9qjIesjFd-EIbwI,4190
cryptography/hazmat/primitives/ciphers/base.py,sha256=hUe5MPVeWB-21ako6_yVGI7GBNCnROkkS53zy8oSO-o,7144
cryptography/hazmat/primitives/ciphers/modes.py,sha256=nUHeQ9I0AIs30Ni2w9TcU9w-AQIpeOA6wLdfA-zkTmI,6641
cryptography/hazmat/primitives/cmac.py,sha256=QgOXACkva7RUbVYvSq3ryw2RdZLOOJgt_zgyCKBmJF4,2075
cryptography/hazmat/primitives/constant_time.py,sha256=TYFSRknWvKlz68rCwfdMw93w0Jy1-3B5F9PQzxH0MbI,1139
cryptography/hazmat/primitives/hashes.py,sha256=hqAOjSu4l7ZOG0U7kJQn0kSHgFuI57o5nb4oTQ7vGnE,6206
cryptography/hazmat/primitives/hmac.py,sha256=MGsVrE_ghlZW0HUH70seV4vCWlIZNSUgB0v9n05vcGg,2196
cryptography/hazmat/primitives/kdf/__init__.py,sha256=nod5HjPswjZr8wFp6Tsu6en9blHYF3khgXI5R0zIcnM,771
cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-36.pyc,,
cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-36.pyc,,
cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-36.pyc,,
cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-36.pyc,,
cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-36.pyc,,
cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-36.pyc,,
cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-36.pyc,,
cryptography/hazmat/primitives/kdf/concatkdf.py,sha256=MSb4abF8jrICg1v9NSr0QQMfQ1r23RDoUkU0X8rQrhE,3981
cryptography/hazmat/primitives/kdf/hkdf.py,sha256=lcqU0pI3HFKUC9L5LpO4gxPSRsES-x1lePDfryu5U4w,3463
cryptography/hazmat/primitives/kdf/kbkdf.py,sha256=EWeLFPINGl50hkSJj3z62WwePpzRiqGMo1nKm7at1_g,4905
cryptography/hazmat/primitives/kdf/pbkdf2.py,sha256=EK3xDD-Y29DLJulQjHraWrwX7psqCWs7NwSTto4YRxs,2088
cryptography/hazmat/primitives/kdf/scrypt.py,sha256=2BrGwbyk3VvY4szQY2EBvZMaf8AYPWlX84aSj-TXLXk,2155
cryptography/hazmat/primitives/kdf/x963kdf.py,sha256=YL88ILo4eBYP_LhlJcEgKnMqputkOmB-FBCsy6KZ2RA,2280
cryptography/hazmat/primitives/keywrap.py,sha256=LqjkVIs7ub5I5gwmYSb9Ia0VdXMqWWHmnKSdQ7HOGEA,5462
cryptography/hazmat/primitives/padding.py,sha256=CtKBj2nR50m4ZXFAonOxDcymW8Jkj0A9xxt7EMLbpJY,5644
cryptography/hazmat/primitives/poly1305.py,sha256=n7CbIXH3F3HwDsXIaaHJGC-RsSPUuLZG1MJeb1FqBv8,1668
cryptography/hazmat/primitives/serialization/__init__.py,sha256=R-4wUb_UMp3Wh_tWn8nIBJXWVR7Oo0ZRhgm1wEPCMjE,1046
cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-36.pyc,,
cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-36.pyc,,
cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-36.pyc,,
cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-36.pyc,,
cryptography/hazmat/primitives/serialization/base.py,sha256=CY8d3TjQ2wPotHpQpkZ-kyVkAwW95y6TFw0JN9KpbFM,1904
cryptography/hazmat/primitives/serialization/pkcs12.py,sha256=LWIA6SVMxc4nnAtSivs8rTpwG6Fy3ppSfHRDiJGdJUw,377
cryptography/hazmat/primitives/serialization/ssh.py,sha256=U94cOHI42BlgiqRXDlsPoqUa5C_Ww_uuu2Njr93d1fA,4381
cryptography/hazmat/primitives/twofactor/__init__.py,sha256=BWrm3DKDoAa281E7U_nzz8v44OmAiXmlIycFcsehwfE,288
cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-36.pyc,,
cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-36.pyc,,
cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-36.pyc,,
cryptography/hazmat/primitives/twofactor/__pycache__/utils.cpython-36.pyc,,
cryptography/hazmat/primitives/twofactor/hotp.py,sha256=6_EnKl-zRs0yCXuHxQhs2TEkHaprWxZnfJGrQjs5RIg,2589
cryptography/hazmat/primitives/twofactor/totp.py,sha256=KL3A4bjpqaqynQYd9hfPVkvs5vYVqf1JVpucEX7_ddM,1594
cryptography/hazmat/primitives/twofactor/utils.py,sha256=71gX1bJeP9TQa-HbSPzeUUJwVY78ALYQNvuusknUO4U,954
cryptography/utils.py,sha256=2ml4dp8EPZ-1SNwmqy5vVVFhMWTeHVvHoDJo9QswlPc,5010
cryptography/x509/__init__.py,sha256=F01ZMHaefgsvMeSthFQEa1gz_q7553LMa_IqOq8tD7w,7305
cryptography/x509/__pycache__/__init__.cpython-36.pyc,,
cryptography/x509/__pycache__/base.cpython-36.pyc,,
cryptography/x509/__pycache__/certificate_transparency.cpython-36.pyc,,
cryptography/x509/__pycache__/extensions.cpython-36.pyc,,
cryptography/x509/__pycache__/general_name.cpython-36.pyc,,
cryptography/x509/__pycache__/name.cpython-36.pyc,,
cryptography/x509/__pycache__/ocsp.cpython-36.pyc,,
cryptography/x509/__pycache__/oid.cpython-36.pyc,,
cryptography/x509/base.py,sha256=HlnDQMCpOqZu_ARcysk6zjUNulMPP7nuQz57L8bW-HM,23939
cryptography/x509/certificate_transparency.py,sha256=eJ9lrITdyMn4XsrcVdrTaFVI_RR7mX_VzMZyiaEpbps,1000
cryptography/x509/extensions.py,sha256=T_Xo0Rugk4xZUwDVTtEaci7y2MDHeBXf5jXT3fB_8PU,50781
cryptography/x509/general_name.py,sha256=cwcI1Yez1K9OEdG0wukDWGfS_b6xN21eHOyPaCqjrGY,10462
cryptography/x509/name.py,sha256=f4lg9Ej5izBMHm2sv5OeviQpzmvjSA3951PMGWUF7ac,8131
cryptography/x509/ocsp.py,sha256=_Tbb3M2qe65r2MYlsjXH_vjLwDvaAZZ7-Y5GAXwuqxY,13310
cryptography/x509/oid.py,sha256=iN1TLtCuI1j-WebvLeQM_yni-Uu90nYOglGJAXCCYao,10936
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography-2.8.dist-info/WHEEL
================================================
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.6)
Root-Is-Purelib: false
Tag: cp34-abi3-manylinux2010_x86_64
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cryptography-2.8.dist-info/top_level.txt
================================================
_constant_time
_openssl
_padding
cryptography
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cssselect/__init__.py
================================================
# -*- coding: utf-8 -*-
"""
CSS Selectors based on XPath
============================
This module supports selecting XML/HTML elements based on CSS selectors.
See the `CSSSelector` class for details.
:copyright: (c) 2007-2012 Ian Bicking and contributors.
See AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from cssselect.parser import (parse, Selector, FunctionalPseudoElement,
SelectorError, SelectorSyntaxError)
from cssselect.xpath import GenericTranslator, HTMLTranslator, ExpressionError
VERSION = '1.1.0'
__version__ = VERSION
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cssselect/parser.py
================================================
# -*- coding: utf-8 -*-
"""
cssselect.parser
================
Tokenizer, parser and parsed objects for CSS selectors.
:copyright: (c) 2007-2012 Ian Bicking and contributors.
See AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
import sys
import re
import operator
if sys.version_info[0] < 3:
_unicode = unicode
_unichr = unichr
else:
_unicode = str
_unichr = chr
def ascii_lower(string):
"""Lower-case, but only in the ASCII range."""
return string.encode('utf8').lower().decode('utf8')
class SelectorError(Exception):
"""Common parent for :class:`SelectorSyntaxError` and
:class:`ExpressionError`.
You can just use ``except SelectorError:`` when calling
:meth:`~GenericTranslator.css_to_xpath` and handle both exceptions types.
"""
class SelectorSyntaxError(SelectorError, SyntaxError):
"""Parsing a selector that does not match the grammar."""
#### Parsed objects
class Selector(object):
"""
Represents a parsed selector.
:meth:`~GenericTranslator.selector_to_xpath` accepts this object,
but ignores :attr:`pseudo_element`. It is the user’s responsibility
to account for pseudo-elements and reject selectors with unknown
or unsupported pseudo-elements.
"""
def __init__(self, tree, pseudo_element=None):
self.parsed_tree = tree
if pseudo_element is not None and not isinstance(
pseudo_element, FunctionalPseudoElement):
pseudo_element = ascii_lower(pseudo_element)
#: A :class:`FunctionalPseudoElement`,
#: or the identifier for the pseudo-element as a string,
# or ``None``.
#:
#: +-------------------------+----------------+--------------------------------+
#: | | Selector | Pseudo-element |
#: +=========================+================+================================+
#: | CSS3 syntax | ``a::before`` | ``'before'`` |
#: +-------------------------+----------------+--------------------------------+
#: | Older syntax | ``a:before`` | ``'before'`` |
#: +-------------------------+----------------+--------------------------------+
#: | From the Lists3_ draft, | ``li::marker`` | ``'marker'`` |
#: | not in Selectors3 | | |
#: +-------------------------+----------------+--------------------------------+
#: | Invalid pseudo-class | ``li:marker`` | ``None`` |
#: +-------------------------+----------------+--------------------------------+
#: | Functional | ``a::foo(2)`` | ``FunctionalPseudoElement(…)`` |
#: +-------------------------+----------------+--------------------------------+
#:
#: .. _Lists3: http://www.w3.org/TR/2011/WD-css3-lists-20110524/#marker-pseudoelement
self.pseudo_element = pseudo_element
def __repr__(self):
if isinstance(self.pseudo_element, FunctionalPseudoElement):
pseudo_element = repr(self.pseudo_element)
elif self.pseudo_element:
pseudo_element = '::%s' % self.pseudo_element
else:
pseudo_element = ''
return '%s[%r%s]' % (
self.__class__.__name__, self.parsed_tree, pseudo_element)
def canonical(self):
"""Return a CSS representation for this selector (a string)
"""
if isinstance(self.pseudo_element, FunctionalPseudoElement):
pseudo_element = '::%s' % self.pseudo_element.canonical()
elif self.pseudo_element:
pseudo_element = '::%s' % self.pseudo_element
else:
pseudo_element = ''
res = '%s%s' % (self.parsed_tree.canonical(), pseudo_element)
if len(res) > 1:
res = res.lstrip('*')
return res
def specificity(self):
"""Return the specificity_ of this selector as a tuple of 3 integers.
.. _specificity: http://www.w3.org/TR/selectors/#specificity
"""
a, b, c = self.parsed_tree.specificity()
if self.pseudo_element:
c += 1
return a, b, c
class Class(object):
"""
Represents selector.class_name
"""
def __init__(self, selector, class_name):
self.selector = selector
self.class_name = class_name
def __repr__(self):
return '%s[%r.%s]' % (
self.__class__.__name__, self.selector, self.class_name)
def canonical(self):
return '%s.%s' % (self.selector.canonical(), self.class_name)
def specificity(self):
a, b, c = self.selector.specificity()
b += 1
return a, b, c
class FunctionalPseudoElement(object):
"""
Represents selector::name(arguments)
.. attribute:: name
The name (identifier) of the pseudo-element, as a string.
.. attribute:: arguments
The arguments of the pseudo-element, as a list of tokens.
**Note:** tokens are not part of the public API,
and may change between cssselect versions.
Use at your own risks.
"""
def __init__(self, name, arguments):
self.name = ascii_lower(name)
self.arguments = arguments
def __repr__(self):
return '%s[::%s(%r)]' % (
self.__class__.__name__, self.name,
[token.value for token in self.arguments])
def argument_types(self):
return [token.type for token in self.arguments]
def canonical(self):
args = ''.join(token.css() for token in self.arguments)
return '%s(%s)' % (self.name, args)
def specificity(self):
a, b, c = self.selector.specificity()
b += 1
return a, b, c
class Function(object):
"""
Represents selector:name(expr)
"""
def __init__(self, selector, name, arguments):
self.selector = selector
self.name = ascii_lower(name)
self.arguments = arguments
def __repr__(self):
return '%s[%r:%s(%r)]' % (
self.__class__.__name__, self.selector, self.name,
[token.value for token in self.arguments])
def argument_types(self):
return [token.type for token in self.arguments]
def canonical(self):
args = ''.join(token.css() for token in self.arguments)
return '%s:%s(%s)' % (self.selector.canonical(), self.name, args)
def specificity(self):
a, b, c = self.selector.specificity()
b += 1
return a, b, c
class Pseudo(object):
"""
Represents selector:ident
"""
def __init__(self, selector, ident):
self.selector = selector
self.ident = ascii_lower(ident)
def __repr__(self):
return '%s[%r:%s]' % (
self.__class__.__name__, self.selector, self.ident)
def canonical(self):
return '%s:%s' % (self.selector.canonical(), self.ident)
def specificity(self):
a, b, c = self.selector.specificity()
b += 1
return a, b, c
class Negation(object):
"""
Represents selector:not(subselector)
"""
def __init__(self, selector, subselector):
self.selector = selector
self.subselector = subselector
def __repr__(self):
return '%s[%r:not(%r)]' % (
self.__class__.__name__, self.selector, self.subselector)
def canonical(self):
subsel = self.subselector.canonical()
if len(subsel) > 1:
subsel = subsel.lstrip('*')
return '%s:not(%s)' % (self.selector.canonical(), subsel)
def specificity(self):
a1, b1, c1 = self.selector.specificity()
a2, b2, c2 = self.subselector.specificity()
return a1 + a2, b1 + b2, c1 + c2
class Attrib(object):
"""
Represents selector[namespace|attrib operator value]
"""
def __init__(self, selector, namespace, attrib, operator, value):
self.selector = selector
self.namespace = namespace
self.attrib = attrib
self.operator = operator
self.value = value
def __repr__(self):
if self.namespace:
attrib = '%s|%s' % (self.namespace, self.attrib)
else:
attrib = self.attrib
if self.operator == 'exists':
return '%s[%r[%s]]' % (
self.__class__.__name__, self.selector, attrib)
else:
return '%s[%r[%s %s %r]]' % (
self.__class__.__name__, self.selector, attrib,
self.operator, self.value.value)
def canonical(self):
if self.namespace:
attrib = '%s|%s' % (self.namespace, self.attrib)
else:
attrib = self.attrib
if self.operator == 'exists':
op = attrib
else:
op = '%s%s%s' % (attrib, self.operator, self.value.css())
return '%s[%s]' % (self.selector.canonical(), op)
def specificity(self):
a, b, c = self.selector.specificity()
b += 1
return a, b, c
class Element(object):
"""
Represents namespace|element
`None` is for the universal selector '*'
"""
def __init__(self, namespace=None, element=None):
self.namespace = namespace
self.element = element
def __repr__(self):
return '%s[%s]' % (self.__class__.__name__, self.canonical())
def canonical(self):
element = self.element or '*'
if self.namespace:
element = '%s|%s' % (self.namespace, element)
return element
def specificity(self):
if self.element:
return 0, 0, 1
else:
return 0, 0, 0
class Hash(object):
"""
Represents selector#id
"""
def __init__(self, selector, id):
self.selector = selector
self.id = id
def __repr__(self):
return '%s[%r#%s]' % (
self.__class__.__name__, self.selector, self.id)
def canonical(self):
return '%s#%s' % (self.selector.canonical(), self.id)
def specificity(self):
a, b, c = self.selector.specificity()
a += 1
return a, b, c
class CombinedSelector(object):
def __init__(self, selector, combinator, subselector):
assert selector is not None
self.selector = selector
self.combinator = combinator
self.subselector = subselector
def __repr__(self):
if self.combinator == ' ':
comb = ''
else:
comb = self.combinator
return '%s[%r %s %r]' % (
self.__class__.__name__, self.selector, comb, self.subselector)
def canonical(self):
subsel = self.subselector.canonical()
if len(subsel) > 1:
subsel = subsel.lstrip('*')
return '%s %s %s' % (
self.selector.canonical(), self.combinator, subsel)
def specificity(self):
a1, b1, c1 = self.selector.specificity()
a2, b2, c2 = self.subselector.specificity()
return a1 + a2, b1 + b2, c1 + c2
#### Parser
# foo
_el_re = re.compile(r'^[ \t\r\n\f]*([a-zA-Z]+)[ \t\r\n\f]*$')
# foo#bar or #bar
_id_re = re.compile(r'^[ \t\r\n\f]*([a-zA-Z]*)#([a-zA-Z0-9_-]+)[ \t\r\n\f]*$')
# foo.bar or .bar
_class_re = re.compile(
r'^[ \t\r\n\f]*([a-zA-Z]*)\.([a-zA-Z][a-zA-Z0-9_-]*)[ \t\r\n\f]*$')
def parse(css):
"""Parse a CSS *group of selectors*.
If you don't care about pseudo-elements or selector specificity,
you can skip this and use :meth:`~GenericTranslator.css_to_xpath`.
:param css:
A *group of selectors* as an Unicode string.
:raises:
:class:`SelectorSyntaxError` on invalid selectors.
:returns:
A list of parsed :class:`Selector` objects, one for each
selector in the comma-separated group.
"""
# Fast path for simple cases
match = _el_re.match(css)
if match:
return [Selector(Element(element=match.group(1)))]
match = _id_re.match(css)
if match is not None:
return [Selector(Hash(Element(element=match.group(1) or None),
match.group(2)))]
match = _class_re.match(css)
if match is not None:
return [Selector(Class(Element(element=match.group(1) or None),
match.group(2)))]
stream = TokenStream(tokenize(css))
stream.source = css
return list(parse_selector_group(stream))
# except SelectorSyntaxError:
# e = sys.exc_info()[1]
# message = "%s at %s -> %r" % (
# e, stream.used, stream.peek())
# e.msg = message
# e.args = tuple([message])
# raise
def parse_selector_group(stream):
stream.skip_whitespace()
while 1:
yield Selector(*parse_selector(stream))
if stream.peek() == ('DELIM', ','):
stream.next()
stream.skip_whitespace()
else:
break
def parse_selector(stream):
result, pseudo_element = parse_simple_selector(stream)
while 1:
stream.skip_whitespace()
peek = stream.peek()
if peek in (('EOF', None), ('DELIM', ',')):
break
if pseudo_element:
raise SelectorSyntaxError(
'Got pseudo-element ::%s not at the end of a selector'
% pseudo_element)
if peek.is_delim('+', '>', '~'):
# A combinator
combinator = stream.next().value
stream.skip_whitespace()
else:
# By exclusion, the last parse_simple_selector() ended
# at peek == ' '
combinator = ' '
next_selector, pseudo_element = parse_simple_selector(stream)
result = CombinedSelector(result, combinator, next_selector)
return result, pseudo_element
def parse_simple_selector(stream, inside_negation=False):
stream.skip_whitespace()
selector_start = len(stream.used)
peek = stream.peek()
if peek.type == 'IDENT' or peek == ('DELIM', '*'):
if peek.type == 'IDENT':
namespace = stream.next().value
else:
stream.next()
namespace = None
if stream.peek() == ('DELIM', '|'):
stream.next()
element = stream.next_ident_or_star()
else:
element = namespace
namespace = None
else:
element = namespace = None
result = Element(namespace, element)
pseudo_element = None
while 1:
peek = stream.peek()
if peek.type in ('S', 'EOF') or peek.is_delim(',', '+', '>', '~') or (
inside_negation and peek == ('DELIM', ')')):
break
if pseudo_element:
raise SelectorSyntaxError(
'Got pseudo-element ::%s not at the end of a selector'
% pseudo_element)
if peek.type == 'HASH':
result = Hash(result, stream.next().value)
elif peek == ('DELIM', '.'):
stream.next()
result = Class(result, stream.next_ident())
elif peek == ('DELIM', '|'):
stream.next()
result = Element(None, stream.next_ident())
elif peek == ('DELIM', '['):
stream.next()
result = parse_attrib(result, stream)
elif peek == ('DELIM', ':'):
stream.next()
if stream.peek() == ('DELIM', ':'):
stream.next()
pseudo_element = stream.next_ident()
if stream.peek() == ('DELIM', '('):
stream.next()
pseudo_element = FunctionalPseudoElement(
pseudo_element, parse_arguments(stream))
continue
ident = stream.next_ident()
if ident.lower() in ('first-line', 'first-letter',
'before', 'after'):
# Special case: CSS 2.1 pseudo-elements can have a single ':'
# Any new pseudo-element must have two.
pseudo_element = _unicode(ident)
continue
if stream.peek() != ('DELIM', '('):
result = Pseudo(result, ident)
if result.__repr__() == 'Pseudo[Element[*]:scope]':
if not (len(stream.used) == 2 or
(len(stream.used) == 3
and stream.used[0].type == 'S')):
raise SelectorSyntaxError(
'Got immediate child pseudo-element ":scope" '
'not at the start of a selector')
continue
stream.next()
stream.skip_whitespace()
if ident.lower() == 'not':
if inside_negation:
raise SelectorSyntaxError('Got nested :not()')
argument, argument_pseudo_element = parse_simple_selector(
stream, inside_negation=True)
next = stream.next()
if argument_pseudo_element:
raise SelectorSyntaxError(
'Got pseudo-element ::%s inside :not() at %s'
% (argument_pseudo_element, next.pos))
if next != ('DELIM', ')'):
raise SelectorSyntaxError("Expected ')', got %s" % (next,))
result = Negation(result, argument)
else:
result = Function(result, ident, parse_arguments(stream))
else:
raise SelectorSyntaxError(
"Expected selector, got %s" % (peek,))
if len(stream.used) == selector_start:
raise SelectorSyntaxError(
"Expected selector, got %s" % (stream.peek(),))
return result, pseudo_element
def parse_arguments(stream):
arguments = []
while 1:
stream.skip_whitespace()
next = stream.next()
if next.type in ('IDENT', 'STRING', 'NUMBER') or next in [
('DELIM', '+'), ('DELIM', '-')]:
arguments.append(next)
elif next == ('DELIM', ')'):
return arguments
else:
raise SelectorSyntaxError(
"Expected an argument, got %s" % (next,))
def parse_attrib(selector, stream):
stream.skip_whitespace()
attrib = stream.next_ident_or_star()
if attrib is None and stream.peek() != ('DELIM', '|'):
raise SelectorSyntaxError(
"Expected '|', got %s" % (stream.peek(),))
if stream.peek() == ('DELIM', '|'):
stream.next()
if stream.peek() == ('DELIM', '='):
namespace = None
stream.next()
op = '|='
else:
namespace = attrib
attrib = stream.next_ident()
op = None
else:
namespace = op = None
if op is None:
stream.skip_whitespace()
next = stream.next()
if next == ('DELIM', ']'):
return Attrib(selector, namespace, attrib, 'exists', None)
elif next == ('DELIM', '='):
op = '='
elif next.is_delim('^', '$', '*', '~', '|', '!') and (
stream.peek() == ('DELIM', '=')):
op = next.value + '='
stream.next()
else:
raise SelectorSyntaxError(
"Operator expected, got %s" % (next,))
stream.skip_whitespace()
value = stream.next()
if value.type not in ('IDENT', 'STRING'):
raise SelectorSyntaxError(
"Expected string or ident, got %s" % (value,))
stream.skip_whitespace()
next = stream.next()
if next != ('DELIM', ']'):
raise SelectorSyntaxError(
"Expected ']', got %s" % (next,))
return Attrib(selector, namespace, attrib, op, value)
def parse_series(tokens):
"""
Parses the arguments for :nth-child() and friends.
:raises: A list of tokens
:returns: :``(a, b)``
"""
for token in tokens:
if token.type == 'STRING':
raise ValueError('String tokens not allowed in series.')
s = ''.join(token.value for token in tokens).strip()
if s == 'odd':
return 2, 1
elif s == 'even':
return 2, 0
elif s == 'n':
return 1, 0
if 'n' not in s:
# Just b
return 0, int(s)
a, b = s.split('n', 1)
if not a:
a = 1
elif a == '-' or a == '+':
a = int(a+'1')
else:
a = int(a)
if not b:
b = 0
else:
b = int(b)
return a, b
#### Token objects
class Token(tuple):
def __new__(cls, type_, value, pos):
obj = tuple.__new__(cls, (type_, value))
obj.pos = pos
return obj
def __repr__(self):
return "<%s '%s' at %i>" % (self.type, self.value, self.pos)
def is_delim(self, *values):
return self.type == 'DELIM' and self.value in values
type = property(operator.itemgetter(0))
value = property(operator.itemgetter(1))
def css(self):
if self.type == 'STRING':
return repr(self.value)
else:
return self.value
class EOFToken(Token):
def __new__(cls, pos):
return Token.__new__(cls, 'EOF', None, pos)
def __repr__(self):
return '<%s at %i>' % (self.type, self.pos)
#### Tokenizer
class TokenMacros:
unicode_escape = r'\\([0-9a-f]{1,6})(?:\r\n|[ \n\r\t\f])?'
escape = unicode_escape + r'|\\[^\n\r\f0-9a-f]'
string_escape = r'\\(?:\n|\r\n|\r|\f)|' + escape
nonascii = r'[^\0-\177]'
nmchar = '[_a-z0-9-]|%s|%s' % (escape, nonascii)
nmstart = '[_a-z]|%s|%s' % (escape, nonascii)
def _compile(pattern):
return re.compile(pattern % vars(TokenMacros), re.IGNORECASE).match
_match_whitespace = _compile(r'[ \t\r\n\f]+')
_match_number = _compile(r'[+-]?(?:[0-9]*\.[0-9]+|[0-9]+)')
_match_hash = _compile('#(?:%(nmchar)s)+')
_match_ident = _compile('-?(?:%(nmstart)s)(?:%(nmchar)s)*')
_match_string_by_quote = {
"'": _compile(r"([^\n\r\f\\']|%(string_escape)s)*"),
'"': _compile(r'([^\n\r\f\\"]|%(string_escape)s)*'),
}
_sub_simple_escape = re.compile(r'\\(.)').sub
_sub_unicode_escape = re.compile(TokenMacros.unicode_escape, re.I).sub
_sub_newline_escape =re.compile(r'\\(?:\n|\r\n|\r|\f)').sub
# Same as r'\1', but faster on CPython
_replace_simple = operator.methodcaller('group', 1)
def _replace_unicode(match):
codepoint = int(match.group(1), 16)
if codepoint > sys.maxunicode:
codepoint = 0xFFFD
return _unichr(codepoint)
def unescape_ident(value):
value = _sub_unicode_escape(_replace_unicode, value)
value = _sub_simple_escape(_replace_simple, value)
return value
def tokenize(s):
pos = 0
len_s = len(s)
while pos < len_s:
match = _match_whitespace(s, pos=pos)
if match:
yield Token('S', ' ', pos)
pos = match.end()
continue
match = _match_ident(s, pos=pos)
if match:
value = _sub_simple_escape(_replace_simple,
_sub_unicode_escape(_replace_unicode, match.group()))
yield Token('IDENT', value, pos)
pos = match.end()
continue
match = _match_hash(s, pos=pos)
if match:
value = _sub_simple_escape(_replace_simple,
_sub_unicode_escape(_replace_unicode, match.group()[1:]))
yield Token('HASH', value, pos)
pos = match.end()
continue
quote = s[pos]
if quote in _match_string_by_quote:
match = _match_string_by_quote[quote](s, pos=pos + 1)
assert match, 'Should have found at least an empty match'
end_pos = match.end()
if end_pos == len_s:
raise SelectorSyntaxError('Unclosed string at %s' % pos)
if s[end_pos] != quote:
raise SelectorSyntaxError('Invalid string at %s' % pos)
value = _sub_simple_escape(_replace_simple,
_sub_unicode_escape(_replace_unicode,
_sub_newline_escape('', match.group())))
yield Token('STRING', value, pos)
pos = end_pos + 1
continue
match = _match_number(s, pos=pos)
if match:
value = match.group()
yield Token('NUMBER', value, pos)
pos = match.end()
continue
pos2 = pos + 2
if s[pos:pos2] == '/*':
pos = s.find('*/', pos2)
if pos == -1:
pos = len_s
else:
pos += 2
continue
yield Token('DELIM', s[pos], pos)
pos += 1
assert pos == len_s
yield EOFToken(pos)
class TokenStream(object):
def __init__(self, tokens, source=None):
self.used = []
self.tokens = iter(tokens)
self.source = source
self.peeked = None
self._peeking = False
try:
self.next_token = self.tokens.next
except AttributeError:
# Python 3
self.next_token = self.tokens.__next__
def next(self):
if self._peeking:
self._peeking = False
self.used.append(self.peeked)
return self.peeked
else:
next = self.next_token()
self.used.append(next)
return next
def peek(self):
if not self._peeking:
self.peeked = self.next_token()
self._peeking = True
return self.peeked
def next_ident(self):
next = self.next()
if next.type != 'IDENT':
raise SelectorSyntaxError('Expected ident, got %s' % (next,))
return next.value
def next_ident_or_star(self):
next = self.next()
if next.type == 'IDENT':
return next.value
elif next == ('DELIM', '*'):
return None
else:
raise SelectorSyntaxError(
"Expected ident or '*', got %s" % (next,))
def skip_whitespace(self):
peek = self.peek()
if peek.type == 'S':
self.next()
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cssselect/xpath.py
================================================
# -*- coding: utf-8 -*-
"""
cssselect.xpath
===============
Translation of parsed CSS selectors to XPath expressions.
:copyright: (c) 2007-2012 Ian Bicking and contributors.
See AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
import sys
import re
from cssselect.parser import parse, parse_series, SelectorError
if sys.version_info[0] < 3:
_basestring = basestring
_unicode = unicode
else:
_basestring = str
_unicode = str
def _unicode_safe_getattr(obj, name, default=None):
# getattr() with a non-ASCII name fails on Python 2.x
name = name.encode('ascii', 'replace').decode('ascii')
return getattr(obj, name, default)
class ExpressionError(SelectorError, RuntimeError):
"""Unknown or unsupported selector (eg. pseudo-class)."""
#### XPath Helpers
class XPathExpr(object):
def __init__(self, path='', element='*', condition='', star_prefix=False):
self.path = path
self.element = element
self.condition = condition
def __str__(self):
path = _unicode(self.path) + _unicode(self.element)
if self.condition:
path += '[%s]' % self.condition
return path
def __repr__(self):
return '%s[%s]' % (self.__class__.__name__, self)
def add_condition(self, condition):
if self.condition:
self.condition = '%s and (%s)' % (self.condition, condition)
else:
self.condition = condition
return self
def add_name_test(self):
if self.element == '*':
# We weren't doing a test anyway
return
self.add_condition(
"name() = %s" % GenericTranslator.xpath_literal(self.element))
self.element = '*'
def add_star_prefix(self):
"""
Append '*/' to the path to keep the context constrained
to a single parent.
"""
self.path += '*/'
def join(self, combiner, other):
path = _unicode(self) + combiner
# Any "star prefix" is redundant when joining.
if other.path != '*/':
path += other.path
self.path = path
self.element = other.element
self.condition = other.condition
return self
split_at_single_quotes = re.compile("('+)").split
# The spec is actually more permissive than that, but don’t bother.
# This is just for the fast path.
# http://www.w3.org/TR/REC-xml/#NT-NameStartChar
is_safe_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$').match
# Test that the string is not empty and does not contain whitespace
is_non_whitespace = re.compile(r'^[^ \t\r\n\f]+$').match
#### Translation
class GenericTranslator(object):
"""
Translator for "generic" XML documents.
Everything is case-sensitive, no assumption is made on the meaning
of element names and attribute names.
"""
####
#### HERE BE DRAGONS
####
#### You are welcome to hook into this to change some behavior,
#### but do so at your own risks.
#### Until it has received a lot more work and review,
#### I reserve the right to change this API in backward-incompatible ways
#### with any minor version of cssselect.
#### See https://github.com/scrapy/cssselect/pull/22
#### -- Simon Sapin.
####
combinator_mapping = {
' ': 'descendant',
'>': 'child',
'+': 'direct_adjacent',
'~': 'indirect_adjacent',
}
attribute_operator_mapping = {
'exists': 'exists',
'=': 'equals',
'~=': 'includes',
'|=': 'dashmatch',
'^=': 'prefixmatch',
'$=': 'suffixmatch',
'*=': 'substringmatch',
'!=': 'different', # XXX Not in Level 3 but meh
}
#: The attribute used for ID selectors depends on the document language:
#: http://www.w3.org/TR/selectors/#id-selectors
id_attribute = 'id'
#: The attribute used for ``:lang()`` depends on the document language:
#: http://www.w3.org/TR/selectors/#lang-pseudo
lang_attribute = 'xml:lang'
#: The case sensitivity of document language element names,
#: attribute names, and attribute values in selectors depends
#: on the document language.
#: http://www.w3.org/TR/selectors/#casesens
#:
#: When a document language defines one of these as case-insensitive,
#: cssselect assumes that the document parser makes the parsed values
#: lower-case. Making the selector lower-case too makes the comparaison
#: case-insensitive.
#:
#: In HTML, element names and attributes names (but not attribute values)
#: are case-insensitive. All of lxml.html, html5lib, BeautifulSoup4
#: and HTMLParser make them lower-case in their parse result, so
#: the assumption holds.
lower_case_element_names = False
lower_case_attribute_names = False
lower_case_attribute_values = False
# class used to represent and xpath expression
xpathexpr_cls = XPathExpr
def css_to_xpath(self, css, prefix='descendant-or-self::'):
"""Translate a *group of selectors* to XPath.
Pseudo-elements are not supported here since XPath only knows
about "real" elements.
:param css:
A *group of selectors* as an Unicode string.
:param prefix:
This string is prepended to the XPath expression for each selector.
The default makes selectors scoped to the context node’s subtree.
:raises:
:class:`SelectorSyntaxError` on invalid selectors,
:class:`ExpressionError` on unknown/unsupported selectors,
including pseudo-elements.
:returns:
The equivalent XPath 1.0 expression as an Unicode string.
"""
return ' | '.join(self.selector_to_xpath(selector, prefix,
translate_pseudo_elements=True)
for selector in parse(css))
def selector_to_xpath(self, selector, prefix='descendant-or-self::',
translate_pseudo_elements=False):
"""Translate a parsed selector to XPath.
:param selector:
A parsed :class:`Selector` object.
:param prefix:
This string is prepended to the resulting XPath expression.
The default makes selectors scoped to the context node’s subtree.
:param translate_pseudo_elements:
Unless this is set to ``True`` (as :meth:`css_to_xpath` does),
the :attr:`~Selector.pseudo_element` attribute of the selector
is ignored.
It is the caller's responsibility to reject selectors
with pseudo-elements, or to account for them somehow.
:raises:
:class:`ExpressionError` on unknown/unsupported selectors.
:returns:
The equivalent XPath 1.0 expression as an Unicode string.
"""
tree = getattr(selector, 'parsed_tree', None)
if not tree:
raise TypeError('Expected a parsed selector, got %r' % (selector,))
xpath = self.xpath(tree)
assert isinstance(xpath, self.xpathexpr_cls) # help debug a missing 'return'
if translate_pseudo_elements and selector.pseudo_element:
xpath = self.xpath_pseudo_element(xpath, selector.pseudo_element)
return (prefix or '') + _unicode(xpath)
def xpath_pseudo_element(self, xpath, pseudo_element):
"""Translate a pseudo-element.
Defaults to not supporting pseudo-elements at all,
but can be overridden by sub-classes.
"""
raise ExpressionError('Pseudo-elements are not supported.')
@staticmethod
def xpath_literal(s):
s = _unicode(s)
if "'" not in s:
s = "'%s'" % s
elif '"' not in s:
s = '"%s"' % s
else:
s = "concat(%s)" % ','.join([
(("'" in part) and '"%s"' or "'%s'") % part
for part in split_at_single_quotes(s) if part
])
return s
def xpath(self, parsed_selector):
"""Translate any parsed selector object."""
type_name = type(parsed_selector).__name__
method = getattr(self, 'xpath_%s' % type_name.lower(), None)
if method is None:
raise ExpressionError('%s is not supported.' % type_name)
return method(parsed_selector)
# Dispatched by parsed object type
def xpath_combinedselector(self, combined):
"""Translate a combined selector."""
combinator = self.combinator_mapping[combined.combinator]
method = getattr(self, 'xpath_%s_combinator' % combinator)
return method(self.xpath(combined.selector),
self.xpath(combined.subselector))
def xpath_negation(self, negation):
xpath = self.xpath(negation.selector)
sub_xpath = self.xpath(negation.subselector)
sub_xpath.add_name_test()
if sub_xpath.condition:
return xpath.add_condition('not(%s)' % sub_xpath.condition)
else:
return xpath.add_condition('0')
def xpath_function(self, function):
"""Translate a functional pseudo-class."""
method = 'xpath_%s_function' % function.name.replace('-', '_')
method = _unicode_safe_getattr(self, method, None)
if not method:
raise ExpressionError(
"The pseudo-class :%s() is unknown" % function.name)
return method(self.xpath(function.selector), function)
def xpath_pseudo(self, pseudo):
"""Translate a pseudo-class."""
method = 'xpath_%s_pseudo' % pseudo.ident.replace('-', '_')
method = _unicode_safe_getattr(self, method, None)
if not method:
# TODO: better error message for pseudo-elements?
raise ExpressionError(
"The pseudo-class :%s is unknown" % pseudo.ident)
return method(self.xpath(pseudo.selector))
def xpath_attrib(self, selector):
"""Translate an attribute selector."""
operator = self.attribute_operator_mapping[selector.operator]
method = getattr(self, 'xpath_attrib_%s' % operator)
if self.lower_case_attribute_names:
name = selector.attrib.lower()
else:
name = selector.attrib
safe = is_safe_name(name)
if selector.namespace:
name = '%s:%s' % (selector.namespace, name)
safe = safe and is_safe_name(selector.namespace)
if safe:
attrib = '@' + name
else:
attrib = 'attribute::*[name() = %s]' % self.xpath_literal(name)
if selector.value is None:
value = None
elif self.lower_case_attribute_values:
value = selector.value.value.lower()
else:
value = selector.value.value
return method(self.xpath(selector.selector), attrib, value)
def xpath_class(self, class_selector):
"""Translate a class selector."""
# .foo is defined as [class~=foo] in the spec.
xpath = self.xpath(class_selector.selector)
return self.xpath_attrib_includes(
xpath, '@class', class_selector.class_name)
def xpath_hash(self, id_selector):
"""Translate an ID selector."""
xpath = self.xpath(id_selector.selector)
return self.xpath_attrib_equals(xpath, '@id', id_selector.id)
def xpath_element(self, selector):
"""Translate a type or universal selector."""
element = selector.element
if not element:
element = '*'
safe = True
else:
safe = is_safe_name(element)
if self.lower_case_element_names:
element = element.lower()
if selector.namespace:
# Namespace prefixes are case-sensitive.
# http://www.w3.org/TR/css3-namespace/#prefixes
element = '%s:%s' % (selector.namespace, element)
safe = safe and is_safe_name(selector.namespace)
xpath = self.xpathexpr_cls(element=element)
if not safe:
xpath.add_name_test()
return xpath
# CombinedSelector: dispatch by combinator
def xpath_descendant_combinator(self, left, right):
"""right is a child, grand-child or further descendant of left"""
return left.join('/descendant-or-self::*/', right)
def xpath_child_combinator(self, left, right):
"""right is an immediate child of left"""
return left.join('/', right)
def xpath_direct_adjacent_combinator(self, left, right):
"""right is a sibling immediately after left"""
xpath = left.join('/following-sibling::', right)
xpath.add_name_test()
return xpath.add_condition('position() = 1')
def xpath_indirect_adjacent_combinator(self, left, right):
"""right is a sibling after left, immediately or not"""
return left.join('/following-sibling::', right)
# Function: dispatch by function/pseudo-class name
def xpath_nth_child_function(self, xpath, function, last=False,
add_name_test=True):
try:
a, b = parse_series(function.arguments)
except ValueError:
raise ExpressionError("Invalid series: '%r'" % function.arguments)
# From https://www.w3.org/TR/css3-selectors/#structural-pseudos:
#
# :nth-child(an+b)
# an+b-1 siblings before
#
# :nth-last-child(an+b)
# an+b-1 siblings after
#
# :nth-of-type(an+b)
# an+b-1 siblings with the same expanded element name before
#
# :nth-last-of-type(an+b)
# an+b-1 siblings with the same expanded element name after
#
# So,
# for :nth-child and :nth-of-type
#
# count(preceding-sibling::) = an+b-1
#
# for :nth-last-child and :nth-last-of-type
#
# count(following-sibling::) = an+b-1
#
# therefore,
# count(...) - (b-1) ≡ 0 (mod a)
#
# if a == 0:
# ~~~~~~~~~~
# count(...) = b-1
#
# if a < 0:
# ~~~~~~~~~
# count(...) - b +1 <= 0
# -> count(...) <= b-1
#
# if a > 0:
# ~~~~~~~~~
# count(...) - b +1 >= 0
# -> count(...) >= b-1
# work with b-1 instead
b_min_1 = b - 1
# early-exit condition 1:
# ~~~~~~~~~~~~~~~~~~~~~~~
# for a == 1, nth-*(an+b) means n+b-1 siblings before/after,
# and since n ∈ {0, 1, 2, ...}, if b-1<=0,
# there is always an "n" matching any number of siblings (maybe none)
if a == 1 and b_min_1 <=0:
return xpath
# early-exit condition 2:
# ~~~~~~~~~~~~~~~~~~~~~~~
# an+b-1 siblings with a<0 and (b-1)<0 is not possible
if a < 0 and b_min_1 < 0:
return xpath.add_condition('0')
# `add_name_test` boolean is inverted and somewhat counter-intuitive:
#
# nth_of_type() calls nth_child(add_name_test=False)
if add_name_test:
nodetest = '*'
else:
nodetest = '%s' % xpath.element
# count siblings before or after the element
if not last:
siblings_count = 'count(preceding-sibling::%s)' % nodetest
else:
siblings_count = 'count(following-sibling::%s)' % nodetest
# special case of fixed position: nth-*(0n+b)
# if a == 0:
# ~~~~~~~~~~
# count(***-sibling::***) = b-1
if a == 0:
return xpath.add_condition('%s = %s' % (siblings_count, b_min_1))
expr = []
if a > 0:
# siblings count, an+b-1, is always >= 0,
# so if a>0, and (b-1)<=0, an "n" exists to satisfy this,
# therefore, the predicate is only interesting if (b-1)>0
if b_min_1 > 0:
expr.append('%s >= %s' % (siblings_count, b_min_1))
else:
# if a<0, and (b-1)<0, no "n" satisfies this,
# this is tested above as an early exist condition
# otherwise,
expr.append('%s <= %s' % (siblings_count, b_min_1))
# operations modulo 1 or -1 are simpler, one only needs to verify:
#
# - either:
# count(***-sibling::***) - (b-1) = n = 0, 1, 2, 3, etc.,
# i.e. count(***-sibling::***) >= (b-1)
#
# - or:
# count(***-sibling::***) - (b-1) = -n = 0, -1, -2, -3, etc.,
# i.e. count(***-sibling::***) <= (b-1)
# we we just did above.
#
if abs(a) != 1:
# count(***-sibling::***) - (b-1) ≡ 0 (mod a)
left = siblings_count
# apply "modulo a" on 2nd term, -(b-1),
# to simplify things like "(... +6) % -3",
# and also make it positive with |a|
b_neg = (-b_min_1) % abs(a)
if b_neg != 0:
b_neg = '+%s' % b_neg
left = '(%s %s)' % (left, b_neg)
expr.append('%s mod %s = 0' % (left, a))
xpath.add_condition(' and '.join(expr))
return xpath
def xpath_nth_last_child_function(self, xpath, function):
return self.xpath_nth_child_function(xpath, function, last=True)
def xpath_nth_of_type_function(self, xpath, function):
if xpath.element == '*':
raise ExpressionError(
"*:nth-of-type() is not implemented")
return self.xpath_nth_child_function(xpath, function,
add_name_test=False)
def xpath_nth_last_of_type_function(self, xpath, function):
if xpath.element == '*':
raise ExpressionError(
"*:nth-of-type() is not implemented")
return self.xpath_nth_child_function(xpath, function, last=True,
add_name_test=False)
def xpath_contains_function(self, xpath, function):
# Defined there, removed in later drafts:
# http://www.w3.org/TR/2001/CR-css3-selectors-20011113/#content-selectors
if function.argument_types() not in (['STRING'], ['IDENT']):
raise ExpressionError(
"Expected a single string or ident for :contains(), got %r"
% function.arguments)
value = function.arguments[0].value
return xpath.add_condition(
'contains(., %s)' % self.xpath_literal(value))
def xpath_lang_function(self, xpath, function):
if function.argument_types() not in (['STRING'], ['IDENT']):
raise ExpressionError(
"Expected a single string or ident for :lang(), got %r"
% function.arguments)
value = function.arguments[0].value
return xpath.add_condition(
"lang(%s)" % (self.xpath_literal(value)))
# Pseudo: dispatch by pseudo-class name
def xpath_root_pseudo(self, xpath):
return xpath.add_condition("not(parent::*)")
# CSS immediate children (CSS ":scope > div" to XPath "child::div" or "./div")
# Works only at the start of a selector
# Needed to get immediate children of a processed selector in Scrapy
# for product in response.css('.product'):
# description = product.css(':scope > div::text').get()
def xpath_scope_pseudo(self, xpath):
return xpath.add_condition("1")
def xpath_first_child_pseudo(self, xpath):
return xpath.add_condition('count(preceding-sibling::*) = 0')
def xpath_last_child_pseudo(self, xpath):
return xpath.add_condition('count(following-sibling::*) = 0')
def xpath_first_of_type_pseudo(self, xpath):
if xpath.element == '*':
raise ExpressionError(
"*:first-of-type is not implemented")
return xpath.add_condition('count(preceding-sibling::%s) = 0' % xpath.element)
def xpath_last_of_type_pseudo(self, xpath):
if xpath.element == '*':
raise ExpressionError(
"*:last-of-type is not implemented")
return xpath.add_condition('count(following-sibling::%s) = 0' % xpath.element)
def xpath_only_child_pseudo(self, xpath):
return xpath.add_condition('count(parent::*/child::*) = 1')
def xpath_only_of_type_pseudo(self, xpath):
if xpath.element == '*':
raise ExpressionError(
"*:only-of-type is not implemented")
return xpath.add_condition('count(parent::*/child::%s) = 1' % xpath.element)
def xpath_empty_pseudo(self, xpath):
return xpath.add_condition("not(*) and not(string-length())")
def pseudo_never_matches(self, xpath):
"""Common implementation for pseudo-classes that never match."""
return xpath.add_condition("0")
xpath_link_pseudo = pseudo_never_matches
xpath_visited_pseudo = pseudo_never_matches
xpath_hover_pseudo = pseudo_never_matches
xpath_active_pseudo = pseudo_never_matches
xpath_focus_pseudo = pseudo_never_matches
xpath_target_pseudo = pseudo_never_matches
xpath_enabled_pseudo = pseudo_never_matches
xpath_disabled_pseudo = pseudo_never_matches
xpath_checked_pseudo = pseudo_never_matches
# Attrib: dispatch by attribute operator
def xpath_attrib_exists(self, xpath, name, value):
assert not value
xpath.add_condition(name)
return xpath
def xpath_attrib_equals(self, xpath, name, value):
xpath.add_condition('%s = %s' % (name, self.xpath_literal(value)))
return xpath
def xpath_attrib_different(self, xpath, name, value):
# FIXME: this seems like a weird hack...
if value:
xpath.add_condition('not(%s) or %s != %s'
% (name, name, self.xpath_literal(value)))
else:
xpath.add_condition('%s != %s'
% (name, self.xpath_literal(value)))
return xpath
def xpath_attrib_includes(self, xpath, name, value):
if is_non_whitespace(value):
xpath.add_condition(
"%s and contains(concat(' ', normalize-space(%s), ' '), %s)"
% (name, name, self.xpath_literal(' '+value+' ')))
else:
xpath.add_condition('0')
return xpath
def xpath_attrib_dashmatch(self, xpath, name, value):
# Weird, but true...
xpath.add_condition('%s and (%s = %s or starts-with(%s, %s))' % (
name,
name, self.xpath_literal(value),
name, self.xpath_literal(value + '-')))
return xpath
def xpath_attrib_prefixmatch(self, xpath, name, value):
if value:
xpath.add_condition('%s and starts-with(%s, %s)' % (
name, name, self.xpath_literal(value)))
else:
xpath.add_condition('0')
return xpath
def xpath_attrib_suffixmatch(self, xpath, name, value):
if value:
# Oddly there is a starts-with in XPath 1.0, but not ends-with
xpath.add_condition(
'%s and substring(%s, string-length(%s)-%s) = %s'
% (name, name, name, len(value)-1, self.xpath_literal(value)))
else:
xpath.add_condition('0')
return xpath
def xpath_attrib_substringmatch(self, xpath, name, value):
if value:
# Attribute selectors are case sensitive
xpath.add_condition('%s and contains(%s, %s)' % (
name, name, self.xpath_literal(value)))
else:
xpath.add_condition('0')
return xpath
class HTMLTranslator(GenericTranslator):
"""
Translator for (X)HTML documents.
Has a more useful implementation of some pseudo-classes based on
HTML-specific element names and attribute names, as described in
the `HTML5 specification`_. It assumes no-quirks mode.
The API is the same as :class:`GenericTranslator`.
.. _HTML5 specification: http://www.w3.org/TR/html5/links.html#selectors
:param xhtml:
If false (the default), element names and attribute names
are case-insensitive.
"""
lang_attribute = 'lang'
def __init__(self, xhtml=False):
self.xhtml = xhtml # Might be useful for sub-classes?
if not xhtml:
# See their definition in GenericTranslator.
self.lower_case_element_names = True
self.lower_case_attribute_names = True
def xpath_checked_pseudo(self, xpath):
# FIXME: is this really all the elements?
return xpath.add_condition(
"(@selected and name(.) = 'option') or "
"(@checked "
"and (name(.) = 'input' or name(.) = 'command')"
"and (@type = 'checkbox' or @type = 'radio'))")
def xpath_lang_function(self, xpath, function):
if function.argument_types() not in (['STRING'], ['IDENT']):
raise ExpressionError(
"Expected a single string or ident for :lang(), got %r"
% function.arguments)
value = function.arguments[0].value
return xpath.add_condition(
"ancestor-or-self::*[@lang][1][starts-with(concat("
# XPath 1.0 has no lower-case function...
"translate(@%s, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', "
"'abcdefghijklmnopqrstuvwxyz'), "
"'-'), %s)]"
% (self.lang_attribute, self.xpath_literal(value.lower() + '-')))
def xpath_link_pseudo(self, xpath):
return xpath.add_condition("@href and "
"(name(.) = 'a' or name(.) = 'link' or name(.) = 'area')")
# Links are never visited, the implementation for :visited is the same
# as in GenericTranslator
def xpath_disabled_pseudo(self, xpath):
# http://www.w3.org/TR/html5/section-index.html#attributes-1
return xpath.add_condition('''
(
@disabled and
(
(name(.) = 'input' and @type != 'hidden') or
name(.) = 'button' or
name(.) = 'select' or
name(.) = 'textarea' or
name(.) = 'command' or
name(.) = 'fieldset' or
name(.) = 'optgroup' or
name(.) = 'option'
)
) or (
(
(name(.) = 'input' and @type != 'hidden') or
name(.) = 'button' or
name(.) = 'select' or
name(.) = 'textarea'
)
and ancestor::fieldset[@disabled]
)
''')
# FIXME: in the second half, add "and is not a descendant of that
# fieldset element's first legend element child, if any."
def xpath_enabled_pseudo(self, xpath):
# http://www.w3.org/TR/html5/section-index.html#attributes-1
return xpath.add_condition('''
(
@href and (
name(.) = 'a' or
name(.) = 'link' or
name(.) = 'area'
)
) or (
(
name(.) = 'command' or
name(.) = 'fieldset' or
name(.) = 'optgroup'
)
and not(@disabled)
) or (
(
(name(.) = 'input' and @type != 'hidden') or
name(.) = 'button' or
name(.) = 'select' or
name(.) = 'textarea' or
name(.) = 'keygen'
)
and not (@disabled or ancestor::fieldset[@disabled])
) or (
name(.) = 'option' and not(
@disabled or ancestor::optgroup[@disabled]
)
)
''')
# FIXME: ... or "li elements that are children of menu elements,
# and that have a child element that defines a command, if the first
# such element's Disabled State facet is false (not disabled)".
# FIXME: after ancestor::fieldset[@disabled], add "and is not a
# descendant of that fieldset element's first legend element child,
# if any."
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cssselect-1.1.0.dist-info/AUTHORS
================================================
Daniel Graña
Ian Bicking
James Salter
Laurence Rowe
Mikhail Korobov
Nik Nyby
Paul Tremberth
Simon Potter
Simon Sapin
Stefan Behnel
Thomas Grainger
Varialus
Arthur Darcet
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cssselect-1.1.0.dist-info/INSTALLER
================================================
pip
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cssselect-1.1.0.dist-info/LICENSE
================================================
Copyright (c) 2007-2012 Ian Bicking and contributors. See AUTHORS
for more details.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. Neither the name of Ian Bicking nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IAN BICKING OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cssselect-1.1.0.dist-info/METADATA
================================================
Metadata-Version: 2.1
Name: cssselect
Version: 1.1.0
Summary: cssselect parses CSS3 Selectors and translates them to XPath 1.0
Home-page: https://github.com/scrapy/cssselect
Author: Ian Bicking
Author-email: ianb@colorstudy.com
Maintainer: Paul Tremberth
Maintainer-email: paul.tremberth@gmail.com
License: BSD
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
===================================
cssselect: CSS Selectors for Python
===================================
.. image:: https://img.shields.io/pypi/v/cssselect.svg
:target: https://pypi.python.org/pypi/cssselect
:alt: PyPI Version
.. image:: https://img.shields.io/pypi/pyversions/cssselect.svg
:target: https://pypi.python.org/pypi/cssselect
:alt: Supported Python Versions
.. image:: https://img.shields.io/travis/scrapy/cssselect/master.svg
:target: https://travis-ci.org/scrapy/cssselect
:alt: Build Status
.. image:: https://img.shields.io/codecov/c/github/scrapy/cssselect/master.svg
:target: https://codecov.io/github/scrapy/cssselect?branch=master
:alt: Coverage report
*cssselect* parses `CSS3 Selectors`_ and translate them to `XPath 1.0`_
expressions. Such expressions can be used in lxml_ or another XPath engine
to find the matching elements in an XML or HTML document.
This module used to live inside of lxml as ``lxml.cssselect`` before it was
extracted as a stand-alone project.
.. _CSS3 Selectors: https://www.w3.org/TR/css3-selectors/
.. _XPath 1.0: https://www.w3.org/TR/xpath/
.. _lxml: http://lxml.de/
Quick facts:
* Free software: BSD licensed
* Compatible with Python 2.7 and 3.4+
* Latest documentation `on Read the Docs `_
* Source, issues and pull requests `on GitHub
`_
* Releases `on PyPI `_
* Install with ``pip install cssselect``
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cssselect-1.1.0.dist-info/RECORD
================================================
cssselect-1.1.0.dist-info/AUTHORS,sha256=0xOj3H8iII6M_KWmoDYQRuzTrYrLPbJ8K2kVSAoQ5zQ,171
cssselect-1.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
cssselect-1.1.0.dist-info/LICENSE,sha256=XI2p90Tgr7qBpIybXb5zBI95izKH1vGvigXuCOuxCJI,1517
cssselect-1.1.0.dist-info/METADATA,sha256=L1k9gxlz3quPBMPepkTOo0tPXV2l8cQl-yZGnO-gNUc,2332
cssselect-1.1.0.dist-info/RECORD,,
cssselect-1.1.0.dist-info/WHEEL,sha256=h_aVn5OB2IERUjMbi2pucmR_zzWJtk303YXvhh60NJ8,110
cssselect-1.1.0.dist-info/top_level.txt,sha256=GKK3Utu_ceog6CK27VXNdbyiqGnoyJo3970FLo5JdUU,10
cssselect/__init__.py,sha256=fmdpKrz5-uYAzXUh3LMOrEPiJMENB1gf962v5Nq5yis,639
cssselect/__pycache__/__init__.cpython-36.pyc,,
cssselect/__pycache__/parser.cpython-36.pyc,,
cssselect/__pycache__/xpath.cpython-36.pyc,,
cssselect/parser.py,sha256=jrlRxEpSFfiqYHKfUHjgERdMQwFbvsh3sONi_HiTDys,26145
cssselect/xpath.py,sha256=Izy4CXmK6zMHg13PP63bBp065eFZNBfPJeNyhjSsS7Q,28257
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cssselect-1.1.0.dist-info/WHEEL
================================================
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.4)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/cssselect-1.1.0.dist-info/top_level.txt
================================================
cssselect
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/easy-install.pth
================================================
./setuptools-40.8.0-py3.6.egg
./pip-19.0.3-py3.6.egg
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/exampleproj/__init__.py
================================================
"""
An example project.
@added: exampleproj NEXT
"""
from incremental import Version
from ._version import __version__
__all__ = ["__version__"]
if Version("exampleproj", "NEXT", 0, 0) > __version__:
print("Unreleased!")
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/exampleproj/_version.py
================================================
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update exampleproj` to change this file.
from incremental import Version
__version__ = Version('exampleproj', 1, 2, 3)
__all__ = ["__version__"]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/gridfs/__init__.py
================================================
# Copyright 2009-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""GridFS is a specification for storing large objects in Mongo.
The :mod:`gridfs` package is an implementation of GridFS on top of
:mod:`pymongo`, exposing a file-like interface.
.. mongodoc:: gridfs
"""
from bson.py3compat import abc
from gridfs.errors import NoFile
from gridfs.grid_file import (GridIn,
GridOut,
GridOutCursor,
DEFAULT_CHUNK_SIZE,
_clear_entity_type_registry)
from pymongo import (ASCENDING,
DESCENDING)
from pymongo.common import UNAUTHORIZED_CODES, validate_string
from pymongo.database import Database
from pymongo.errors import ConfigurationError, OperationFailure
class GridFS(object):
"""An instance of GridFS on top of a single Database.
"""
def __init__(self, database, collection="fs", disable_md5=False):
"""Create a new instance of :class:`GridFS`.
Raises :class:`TypeError` if `database` is not an instance of
:class:`~pymongo.database.Database`.
:Parameters:
- `database`: database to use
- `collection` (optional): root collection to use
- `disable_md5` (optional): When True, MD5 checksums will not be
computed for uploaded files. Useful in environments where MD5
cannot be used for regulatory or other reasons. Defaults to False.
.. versionchanged:: 3.1
Indexes are only ensured on the first write to the DB.
.. versionchanged:: 3.0
`database` must use an acknowledged
:attr:`~pymongo.database.Database.write_concern`
.. mongodoc:: gridfs
"""
if not isinstance(database, Database):
raise TypeError("database must be an instance of Database")
database = _clear_entity_type_registry(database)
if not database.write_concern.acknowledged:
raise ConfigurationError('database must use '
'acknowledged write_concern')
self.__database = database
self.__collection = database[collection]
self.__files = self.__collection.files
self.__chunks = self.__collection.chunks
self.__disable_md5 = disable_md5
def new_file(self, **kwargs):
"""Create a new file in GridFS.
Returns a new :class:`~gridfs.grid_file.GridIn` instance to
which data can be written. Any keyword arguments will be
passed through to :meth:`~gridfs.grid_file.GridIn`.
If the ``"_id"`` of the file is manually specified, it must
not already exist in GridFS. Otherwise
:class:`~gridfs.errors.FileExists` is raised.
:Parameters:
- `**kwargs` (optional): keyword arguments for file creation
"""
# No need for __ensure_index_files_id() here; GridIn ensures
# the (files_id, n) index when needed.
return GridIn(
self.__collection, disable_md5=self.__disable_md5, **kwargs)
def put(self, data, **kwargs):
"""Put data in GridFS as a new file.
Equivalent to doing::
try:
f = new_file(**kwargs)
f.write(data)
finally:
f.close()
`data` can be either an instance of :class:`str` (:class:`bytes`
in python 3) or a file-like object providing a :meth:`read` method.
If an `encoding` keyword argument is passed, `data` can also be a
:class:`unicode` (:class:`str` in python 3) instance, which will
be encoded as `encoding` before being written. Any keyword arguments
will be passed through to the created file - see
:meth:`~gridfs.grid_file.GridIn` for possible arguments. Returns the
``"_id"`` of the created file.
If the ``"_id"`` of the file is manually specified, it must
not already exist in GridFS. Otherwise
:class:`~gridfs.errors.FileExists` is raised.
:Parameters:
- `data`: data to be written as a file.
- `**kwargs` (optional): keyword arguments for file creation
.. versionchanged:: 3.0
w=0 writes to GridFS are now prohibited.
"""
grid_file = GridIn(
self.__collection, disable_md5=self.__disable_md5, **kwargs)
try:
grid_file.write(data)
finally:
grid_file.close()
return grid_file._id
def get(self, file_id, session=None):
"""Get a file from GridFS by ``"_id"``.
Returns an instance of :class:`~gridfs.grid_file.GridOut`,
which provides a file-like interface for reading.
:Parameters:
- `file_id`: ``"_id"`` of the file to get
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
.. versionchanged:: 3.6
Added ``session`` parameter.
"""
gout = GridOut(self.__collection, file_id, session=session)
# Raise NoFile now, instead of on first attribute access.
gout._ensure_file()
return gout
def get_version(self, filename=None, version=-1, session=None, **kwargs):
"""Get a file from GridFS by ``"filename"`` or metadata fields.
Returns a version of the file in GridFS whose filename matches
`filename` and whose metadata fields match the supplied keyword
arguments, as an instance of :class:`~gridfs.grid_file.GridOut`.
Version numbering is a convenience atop the GridFS API provided
by MongoDB. If more than one file matches the query (either by
`filename` alone, by metadata fields, or by a combination of
both), then version ``-1`` will be the most recently uploaded
matching file, ``-2`` the second most recently
uploaded, etc. Version ``0`` will be the first version
uploaded, ``1`` the second version, etc. So if three versions
have been uploaded, then version ``0`` is the same as version
``-3``, version ``1`` is the same as version ``-2``, and
version ``2`` is the same as version ``-1``.
Raises :class:`~gridfs.errors.NoFile` if no such version of
that file exists.
:Parameters:
- `filename`: ``"filename"`` of the file to get, or `None`
- `version` (optional): version of the file to get (defaults
to -1, the most recent version uploaded)
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
- `**kwargs` (optional): find files by custom metadata.
.. versionchanged:: 3.6
Added ``session`` parameter.
.. versionchanged:: 3.1
``get_version`` no longer ensures indexes.
"""
query = kwargs
if filename is not None:
query["filename"] = filename
cursor = self.__files.find(query, session=session)
if version < 0:
skip = abs(version) - 1
cursor.limit(-1).skip(skip).sort("uploadDate", DESCENDING)
else:
cursor.limit(-1).skip(version).sort("uploadDate", ASCENDING)
try:
doc = next(cursor)
return GridOut(
self.__collection, file_document=doc, session=session)
except StopIteration:
raise NoFile("no version %d for filename %r" % (version, filename))
def get_last_version(self, filename=None, session=None, **kwargs):
"""Get the most recent version of a file in GridFS by ``"filename"``
or metadata fields.
Equivalent to calling :meth:`get_version` with the default
`version` (``-1``).
:Parameters:
- `filename`: ``"filename"`` of the file to get, or `None`
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
- `**kwargs` (optional): find files by custom metadata.
.. versionchanged:: 3.6
Added ``session`` parameter.
"""
return self.get_version(filename=filename, session=session, **kwargs)
# TODO add optional safe mode for chunk removal?
def delete(self, file_id, session=None):
"""Delete a file from GridFS by ``"_id"``.
Deletes all data belonging to the file with ``"_id"``:
`file_id`.
.. warning:: Any processes/threads reading from the file while
this method is executing will likely see an invalid/corrupt
file. Care should be taken to avoid concurrent reads to a file
while it is being deleted.
.. note:: Deletes of non-existent files are considered successful
since the end result is the same: no file with that _id remains.
:Parameters:
- `file_id`: ``"_id"`` of the file to delete
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
.. versionchanged:: 3.6
Added ``session`` parameter.
.. versionchanged:: 3.1
``delete`` no longer ensures indexes.
"""
self.__files.delete_one({"_id": file_id}, session=session)
self.__chunks.delete_many({"files_id": file_id}, session=session)
def list(self, session=None):
"""List the names of all files stored in this instance of
:class:`GridFS`.
:Parameters:
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
.. versionchanged:: 3.6
Added ``session`` parameter.
.. versionchanged:: 3.1
``list`` no longer ensures indexes.
"""
# With an index, distinct includes documents with no filename
# as None.
return [
name for name in self.__files.distinct("filename", session=session)
if name is not None]
def find_one(self, filter=None, session=None, *args, **kwargs):
"""Get a single file from gridfs.
All arguments to :meth:`find` are also valid arguments for
:meth:`find_one`, although any `limit` argument will be
ignored. Returns a single :class:`~gridfs.grid_file.GridOut`,
or ``None`` if no matching file is found. For example::
file = fs.find_one({"filename": "lisa.txt"})
:Parameters:
- `filter` (optional): a dictionary specifying
the query to be performing OR any other type to be used as
the value for a query for ``"_id"`` in the file collection.
- `*args` (optional): any additional positional arguments are
the same as the arguments to :meth:`find`.
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
- `**kwargs` (optional): any additional keyword arguments
are the same as the arguments to :meth:`find`.
.. versionchanged:: 3.6
Added ``session`` parameter.
"""
if filter is not None and not isinstance(filter, abc.Mapping):
filter = {"_id": filter}
for f in self.find(filter, *args, session=session, **kwargs):
return f
return None
def find(self, *args, **kwargs):
"""Query GridFS for files.
Returns a cursor that iterates across files matching
arbitrary queries on the files collection. Can be combined
with other modifiers for additional control. For example::
for grid_out in fs.find({"filename": "lisa.txt"},
no_cursor_timeout=True):
data = grid_out.read()
would iterate through all versions of "lisa.txt" stored in GridFS.
Note that setting no_cursor_timeout to True may be important to
prevent the cursor from timing out during long multi-file processing
work.
As another example, the call::
most_recent_three = fs.find().sort("uploadDate", -1).limit(3)
would return a cursor to the three most recently uploaded files
in GridFS.
Follows a similar interface to
:meth:`~pymongo.collection.Collection.find`
in :class:`~pymongo.collection.Collection`.
If a :class:`~pymongo.client_session.ClientSession` is passed to
:meth:`find`, all returned :class:`~gridfs.grid_file.GridOut` instances
are associated with that session.
:Parameters:
- `filter` (optional): a SON object specifying elements which
must be present for a document to be included in the
result set
- `skip` (optional): the number of files to omit (from
the start of the result set) when returning the results
- `limit` (optional): the maximum number of results to
return
- `no_cursor_timeout` (optional): if False (the default), any
returned cursor is closed by the server after 10 minutes of
inactivity. If set to True, the returned cursor will never
time out on the server. Care should be taken to ensure that
cursors with no_cursor_timeout turned on are properly closed.
- `sort` (optional): a list of (key, direction) pairs
specifying the sort order for this query. See
:meth:`~pymongo.cursor.Cursor.sort` for details.
Raises :class:`TypeError` if any of the arguments are of
improper type. Returns an instance of
:class:`~gridfs.grid_file.GridOutCursor`
corresponding to this query.
.. versionchanged:: 3.0
Removed the read_preference, tag_sets, and
secondary_acceptable_latency_ms options.
.. versionadded:: 2.7
.. mongodoc:: find
"""
return GridOutCursor(self.__collection, *args, **kwargs)
def exists(self, document_or_id=None, session=None, **kwargs):
"""Check if a file exists in this instance of :class:`GridFS`.
The file to check for can be specified by the value of its
``_id`` key, or by passing in a query document. A query
document can be passed in as dictionary, or by using keyword
arguments. Thus, the following three calls are equivalent:
>>> fs.exists(file_id)
>>> fs.exists({"_id": file_id})
>>> fs.exists(_id=file_id)
As are the following two calls:
>>> fs.exists({"filename": "mike.txt"})
>>> fs.exists(filename="mike.txt")
And the following two:
>>> fs.exists({"foo": {"$gt": 12}})
>>> fs.exists(foo={"$gt": 12})
Returns ``True`` if a matching file exists, ``False``
otherwise. Calls to :meth:`exists` will not automatically
create appropriate indexes; application developers should be
sure to create indexes if needed and as appropriate.
:Parameters:
- `document_or_id` (optional): query document, or _id of the
document to check for
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
- `**kwargs` (optional): keyword arguments are used as a
query document, if they're present.
.. versionchanged:: 3.6
Added ``session`` parameter.
"""
if kwargs:
f = self.__files.find_one(kwargs, ["_id"], session=session)
else:
f = self.__files.find_one(document_or_id, ["_id"], session=session)
return f is not None
class GridFSBucket(object):
"""An instance of GridFS on top of a single Database."""
def __init__(self, db, bucket_name="fs",
chunk_size_bytes=DEFAULT_CHUNK_SIZE, write_concern=None,
read_preference=None, disable_md5=False):
"""Create a new instance of :class:`GridFSBucket`.
Raises :exc:`TypeError` if `database` is not an instance of
:class:`~pymongo.database.Database`.
Raises :exc:`~pymongo.errors.ConfigurationError` if `write_concern`
is not acknowledged.
:Parameters:
- `database`: database to use.
- `bucket_name` (optional): The name of the bucket. Defaults to 'fs'.
- `chunk_size_bytes` (optional): The chunk size in bytes. Defaults
to 255KB.
- `write_concern` (optional): The
:class:`~pymongo.write_concern.WriteConcern` to use. If ``None``
(the default) db.write_concern is used.
- `read_preference` (optional): The read preference to use. If
``None`` (the default) db.read_preference is used.
- `disable_md5` (optional): When True, MD5 checksums will not be
computed for uploaded files. Useful in environments where MD5
cannot be used for regulatory or other reasons. Defaults to False.
.. versionadded:: 3.1
.. mongodoc:: gridfs
"""
if not isinstance(db, Database):
raise TypeError("database must be an instance of Database")
db = _clear_entity_type_registry(db)
wtc = write_concern if write_concern is not None else db.write_concern
if not wtc.acknowledged:
raise ConfigurationError('write concern must be acknowledged')
self._db = db
self._bucket_name = bucket_name
self._collection = db[bucket_name]
self._disable_md5 = disable_md5
self._chunks = self._collection.chunks.with_options(
write_concern=write_concern,
read_preference=read_preference)
self._files = self._collection.files.with_options(
write_concern=write_concern,
read_preference=read_preference)
self._chunk_size_bytes = chunk_size_bytes
def open_upload_stream(self, filename, chunk_size_bytes=None,
metadata=None, session=None):
"""Opens a Stream that the application can write the contents of the
file to.
The user must specify the filename, and can choose to add any
additional information in the metadata field of the file document or
modify the chunk size.
For example::
my_db = MongoClient().test
fs = GridFSBucket(my_db)
grid_in = fs.open_upload_stream(
"test_file", chunk_size_bytes=4,
metadata={"contentType": "text/plain"})
grid_in.write("data I want to store!")
grid_in.close() # uploaded on close
Returns an instance of :class:`~gridfs.grid_file.GridIn`.
Raises :exc:`~gridfs.errors.NoFile` if no such version of
that file exists.
Raises :exc:`~ValueError` if `filename` is not a string.
:Parameters:
- `filename`: The name of the file to upload.
- `chunk_size_bytes` (options): The number of bytes per chunk of this
file. Defaults to the chunk_size_bytes in :class:`GridFSBucket`.
- `metadata` (optional): User data for the 'metadata' field of the
files collection document. If not provided the metadata field will
be omitted from the files collection document.
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
.. versionchanged:: 3.6
Added ``session`` parameter.
"""
validate_string("filename", filename)
opts = {"filename": filename,
"chunk_size": (chunk_size_bytes if chunk_size_bytes
is not None else self._chunk_size_bytes)}
if metadata is not None:
opts["metadata"] = metadata
return GridIn(
self._collection,
session=session,
disable_md5=self._disable_md5,
**opts)
def open_upload_stream_with_id(
self, file_id, filename, chunk_size_bytes=None, metadata=None,
session=None):
"""Opens a Stream that the application can write the contents of the
file to.
The user must specify the file id and filename, and can choose to add
any additional information in the metadata field of the file document
or modify the chunk size.
For example::
my_db = MongoClient().test
fs = GridFSBucket(my_db)
grid_in = fs.open_upload_stream_with_id(
ObjectId(),
"test_file",
chunk_size_bytes=4,
metadata={"contentType": "text/plain"})
grid_in.write("data I want to store!")
grid_in.close() # uploaded on close
Returns an instance of :class:`~gridfs.grid_file.GridIn`.
Raises :exc:`~gridfs.errors.NoFile` if no such version of
that file exists.
Raises :exc:`~ValueError` if `filename` is not a string.
:Parameters:
- `file_id`: The id to use for this file. The id must not have
already been used for another file.
- `filename`: The name of the file to upload.
- `chunk_size_bytes` (options): The number of bytes per chunk of this
file. Defaults to the chunk_size_bytes in :class:`GridFSBucket`.
- `metadata` (optional): User data for the 'metadata' field of the
files collection document. If not provided the metadata field will
be omitted from the files collection document.
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
.. versionchanged:: 3.6
Added ``session`` parameter.
"""
validate_string("filename", filename)
opts = {"_id": file_id,
"filename": filename,
"chunk_size": (chunk_size_bytes if chunk_size_bytes
is not None else self._chunk_size_bytes)}
if metadata is not None:
opts["metadata"] = metadata
return GridIn(
self._collection,
session=session,
disable_md5=self._disable_md5,
**opts)
def upload_from_stream(self, filename, source, chunk_size_bytes=None,
metadata=None, session=None):
"""Uploads a user file to a GridFS bucket.
Reads the contents of the user file from `source` and uploads
it to the file `filename`. Source can be a string or file-like object.
For example::
my_db = MongoClient().test
fs = GridFSBucket(my_db)
file_id = fs.upload_from_stream(
"test_file",
"data I want to store!",
chunk_size_bytes=4,
metadata={"contentType": "text/plain"})
Returns the _id of the uploaded file.
Raises :exc:`~gridfs.errors.NoFile` if no such version of
that file exists.
Raises :exc:`~ValueError` if `filename` is not a string.
:Parameters:
- `filename`: The name of the file to upload.
- `source`: The source stream of the content to be uploaded. Must be
a file-like object that implements :meth:`read` or a string.
- `chunk_size_bytes` (options): The number of bytes per chunk of this
file. Defaults to the chunk_size_bytes of :class:`GridFSBucket`.
- `metadata` (optional): User data for the 'metadata' field of the
files collection document. If not provided the metadata field will
be omitted from the files collection document.
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
.. versionchanged:: 3.6
Added ``session`` parameter.
"""
with self.open_upload_stream(
filename, chunk_size_bytes, metadata, session=session) as gin:
gin.write(source)
return gin._id
def upload_from_stream_with_id(self, file_id, filename, source,
chunk_size_bytes=None, metadata=None,
session=None):
"""Uploads a user file to a GridFS bucket with a custom file id.
Reads the contents of the user file from `source` and uploads
it to the file `filename`. Source can be a string or file-like object.
For example::
my_db = MongoClient().test
fs = GridFSBucket(my_db)
file_id = fs.upload_from_stream(
ObjectId(),
"test_file",
"data I want to store!",
chunk_size_bytes=4,
metadata={"contentType": "text/plain"})
Raises :exc:`~gridfs.errors.NoFile` if no such version of
that file exists.
Raises :exc:`~ValueError` if `filename` is not a string.
:Parameters:
- `file_id`: The id to use for this file. The id must not have
already been used for another file.
- `filename`: The name of the file to upload.
- `source`: The source stream of the content to be uploaded. Must be
a file-like object that implements :meth:`read` or a string.
- `chunk_size_bytes` (options): The number of bytes per chunk of this
file. Defaults to the chunk_size_bytes of :class:`GridFSBucket`.
- `metadata` (optional): User data for the 'metadata' field of the
files collection document. If not provided the metadata field will
be omitted from the files collection document.
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
.. versionchanged:: 3.6
Added ``session`` parameter.
"""
with self.open_upload_stream_with_id(
file_id, filename, chunk_size_bytes, metadata,
session=session) as gin:
gin.write(source)
def open_download_stream(self, file_id, session=None):
"""Opens a Stream from which the application can read the contents of
the stored file specified by file_id.
For example::
my_db = MongoClient().test
fs = GridFSBucket(my_db)
# get _id of file to read.
file_id = fs.upload_from_stream("test_file", "data I want to store!")
grid_out = fs.open_download_stream(file_id)
contents = grid_out.read()
Returns an instance of :class:`~gridfs.grid_file.GridOut`.
Raises :exc:`~gridfs.errors.NoFile` if no file with file_id exists.
:Parameters:
- `file_id`: The _id of the file to be downloaded.
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
.. versionchanged:: 3.6
Added ``session`` parameter.
"""
gout = GridOut(self._collection, file_id, session=session)
# Raise NoFile now, instead of on first attribute access.
gout._ensure_file()
return gout
def download_to_stream(self, file_id, destination, session=None):
"""Downloads the contents of the stored file specified by file_id and
writes the contents to `destination`.
For example::
my_db = MongoClient().test
fs = GridFSBucket(my_db)
# Get _id of file to read
file_id = fs.upload_from_stream("test_file", "data I want to store!")
# Get file to write to
file = open('myfile','wb+')
fs.download_to_stream(file_id, file)
file.seek(0)
contents = file.read()
Raises :exc:`~gridfs.errors.NoFile` if no file with file_id exists.
:Parameters:
- `file_id`: The _id of the file to be downloaded.
- `destination`: a file-like object implementing :meth:`write`.
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
.. versionchanged:: 3.6
Added ``session`` parameter.
"""
with self.open_download_stream(file_id, session=session) as gout:
for chunk in gout:
destination.write(chunk)
def delete(self, file_id, session=None):
"""Given an file_id, delete this stored file's files collection document
and associated chunks from a GridFS bucket.
For example::
my_db = MongoClient().test
fs = GridFSBucket(my_db)
# Get _id of file to delete
file_id = fs.upload_from_stream("test_file", "data I want to store!")
fs.delete(file_id)
Raises :exc:`~gridfs.errors.NoFile` if no file with file_id exists.
:Parameters:
- `file_id`: The _id of the file to be deleted.
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
.. versionchanged:: 3.6
Added ``session`` parameter.
"""
res = self._files.delete_one({"_id": file_id}, session=session)
self._chunks.delete_many({"files_id": file_id}, session=session)
if not res.deleted_count:
raise NoFile(
"no file could be deleted because none matched %s" % file_id)
def find(self, *args, **kwargs):
"""Find and return the files collection documents that match ``filter``
Returns a cursor that iterates across files matching
arbitrary queries on the files collection. Can be combined
with other modifiers for additional control.
For example::
for grid_data in fs.find({"filename": "lisa.txt"},
no_cursor_timeout=True):
data = grid_data.read()
would iterate through all versions of "lisa.txt" stored in GridFS.
Note that setting no_cursor_timeout to True may be important to
prevent the cursor from timing out during long multi-file processing
work.
As another example, the call::
most_recent_three = fs.find().sort("uploadDate", -1).limit(3)
would return a cursor to the three most recently uploaded files
in GridFS.
Follows a similar interface to
:meth:`~pymongo.collection.Collection.find`
in :class:`~pymongo.collection.Collection`.
If a :class:`~pymongo.client_session.ClientSession` is passed to
:meth:`find`, all returned :class:`~gridfs.grid_file.GridOut` instances
are associated with that session.
:Parameters:
- `filter`: Search query.
- `batch_size` (optional): The number of documents to return per
batch.
- `limit` (optional): The maximum number of documents to return.
- `no_cursor_timeout` (optional): The server normally times out idle
cursors after an inactivity period (10 minutes) to prevent excess
memory use. Set this option to True prevent that.
- `skip` (optional): The number of documents to skip before
returning.
- `sort` (optional): The order by which to sort results. Defaults to
None.
"""
return GridOutCursor(self._collection, *args, **kwargs)
def open_download_stream_by_name(self, filename, revision=-1, session=None):
"""Opens a Stream from which the application can read the contents of
`filename` and optional `revision`.
For example::
my_db = MongoClient().test
fs = GridFSBucket(my_db)
grid_out = fs.open_download_stream_by_name("test_file")
contents = grid_out.read()
Returns an instance of :class:`~gridfs.grid_file.GridOut`.
Raises :exc:`~gridfs.errors.NoFile` if no such version of
that file exists.
Raises :exc:`~ValueError` filename is not a string.
:Parameters:
- `filename`: The name of the file to read from.
- `revision` (optional): Which revision (documents with the same
filename and different uploadDate) of the file to retrieve.
Defaults to -1 (the most recent revision).
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
:Note: Revision numbers are defined as follows:
- 0 = the original stored file
- 1 = the first revision
- 2 = the second revision
- etc...
- -2 = the second most recent revision
- -1 = the most recent revision
.. versionchanged:: 3.6
Added ``session`` parameter.
"""
validate_string("filename", filename)
query = {"filename": filename}
cursor = self._files.find(query, session=session)
if revision < 0:
skip = abs(revision) - 1
cursor.limit(-1).skip(skip).sort("uploadDate", DESCENDING)
else:
cursor.limit(-1).skip(revision).sort("uploadDate", ASCENDING)
try:
grid_file = next(cursor)
return GridOut(
self._collection, file_document=grid_file, session=session)
except StopIteration:
raise NoFile(
"no version %d for filename %r" % (revision, filename))
def download_to_stream_by_name(self, filename, destination, revision=-1,
session=None):
"""Write the contents of `filename` (with optional `revision`) to
`destination`.
For example::
my_db = MongoClient().test
fs = GridFSBucket(my_db)
# Get file to write to
file = open('myfile','wb')
fs.download_to_stream_by_name("test_file", file)
Raises :exc:`~gridfs.errors.NoFile` if no such version of
that file exists.
Raises :exc:`~ValueError` if `filename` is not a string.
:Parameters:
- `filename`: The name of the file to read from.
- `destination`: A file-like object that implements :meth:`write`.
- `revision` (optional): Which revision (documents with the same
filename and different uploadDate) of the file to retrieve.
Defaults to -1 (the most recent revision).
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
:Note: Revision numbers are defined as follows:
- 0 = the original stored file
- 1 = the first revision
- 2 = the second revision
- etc...
- -2 = the second most recent revision
- -1 = the most recent revision
.. versionchanged:: 3.6
Added ``session`` parameter.
"""
with self.open_download_stream_by_name(
filename, revision, session=session) as gout:
for chunk in gout:
destination.write(chunk)
def rename(self, file_id, new_filename, session=None):
"""Renames the stored file with the specified file_id.
For example::
my_db = MongoClient().test
fs = GridFSBucket(my_db)
# Get _id of file to rename
file_id = fs.upload_from_stream("test_file", "data I want to store!")
fs.rename(file_id, "new_test_name")
Raises :exc:`~gridfs.errors.NoFile` if no file with file_id exists.
:Parameters:
- `file_id`: The _id of the file to be renamed.
- `new_filename`: The new name of the file.
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession`
.. versionchanged:: 3.6
Added ``session`` parameter.
"""
result = self._files.update_one({"_id": file_id},
{"$set": {"filename": new_filename}},
session=session)
if not result.matched_count:
raise NoFile("no files could be renamed %r because none "
"matched file_id %i" % (new_filename, file_id))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/gridfs/errors.py
================================================
# Copyright 2009-2015 MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Exceptions raised by the :mod:`gridfs` package"""
from pymongo.errors import PyMongoError
class GridFSError(PyMongoError):
"""Base class for all GridFS exceptions."""
class CorruptGridFile(GridFSError):
"""Raised when a file in :class:`~gridfs.GridFS` is malformed."""
class NoFile(GridFSError):
"""Raised when trying to read from a non-existent file."""
class FileExists(GridFSError):
"""Raised when trying to create a file that already exists."""
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/gridfs/grid_file.py
================================================
# Copyright 2009-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tools for representing files stored in GridFS."""
import datetime
import hashlib
import io
import math
import os
from bson.int64 import Int64
from bson.son import SON
from bson.binary import Binary
from bson.objectid import ObjectId
from bson.py3compat import text_type, StringIO
from gridfs.errors import CorruptGridFile, FileExists, NoFile
from pymongo import ASCENDING
from pymongo.collection import Collection
from pymongo.cursor import Cursor
from pymongo.errors import (ConfigurationError,
CursorNotFound,
DuplicateKeyError,
OperationFailure)
from pymongo.read_preferences import ReadPreference
try:
_SEEK_SET = os.SEEK_SET
_SEEK_CUR = os.SEEK_CUR
_SEEK_END = os.SEEK_END
# before 2.5
except AttributeError:
_SEEK_SET = 0
_SEEK_CUR = 1
_SEEK_END = 2
EMPTY = b""
NEWLN = b"\n"
"""Default chunk size, in bytes."""
# Slightly under a power of 2, to work well with server's record allocations.
DEFAULT_CHUNK_SIZE = 255 * 1024
_C_INDEX = SON([("files_id", ASCENDING), ("n", ASCENDING)])
_F_INDEX = SON([("filename", ASCENDING), ("uploadDate", ASCENDING)])
def _grid_in_property(field_name, docstring, read_only=False,
closed_only=False):
"""Create a GridIn property."""
def getter(self):
if closed_only and not self._closed:
raise AttributeError("can only get %r on a closed file" %
field_name)
# Protect against PHP-237
if field_name == 'length':
return self._file.get(field_name, 0)
return self._file.get(field_name, None)
def setter(self, value):
if self._closed:
self._coll.files.update_one({"_id": self._file["_id"]},
{"$set": {field_name: value}})
self._file[field_name] = value
if read_only:
docstring += "\n\nThis attribute is read-only."
elif closed_only:
docstring = "%s\n\n%s" % (docstring, "This attribute is read-only and "
"can only be read after :meth:`close` "
"has been called.")
if not read_only and not closed_only:
return property(getter, setter, doc=docstring)
return property(getter, doc=docstring)
def _grid_out_property(field_name, docstring):
"""Create a GridOut property."""
def getter(self):
self._ensure_file()
# Protect against PHP-237
if field_name == 'length':
return self._file.get(field_name, 0)
return self._file.get(field_name, None)
docstring += "\n\nThis attribute is read-only."
return property(getter, doc=docstring)
def _clear_entity_type_registry(entity, **kwargs):
"""Clear the given database/collection object's type registry."""
codecopts = entity.codec_options.with_options(type_registry=None)
return entity.with_options(codec_options=codecopts, **kwargs)
class GridIn(object):
"""Class to write data to GridFS.
"""
def __init__(
self, root_collection, session=None, disable_md5=False, **kwargs):
"""Write a file to GridFS
Application developers should generally not need to
instantiate this class directly - instead see the methods
provided by :class:`~gridfs.GridFS`.
Raises :class:`TypeError` if `root_collection` is not an
instance of :class:`~pymongo.collection.Collection`.
Any of the file level options specified in the `GridFS Spec
`_ may be passed as
keyword arguments. Any additional keyword arguments will be
set as additional fields on the file document. Valid keyword
arguments include:
- ``"_id"``: unique ID for this file (default:
:class:`~bson.objectid.ObjectId`) - this ``"_id"`` must
not have already been used for another file
- ``"filename"``: human name for the file
- ``"contentType"`` or ``"content_type"``: valid mime-type
for the file
- ``"chunkSize"`` or ``"chunk_size"``: size of each of the
chunks, in bytes (default: 255 kb)
- ``"encoding"``: encoding used for this file. In Python 2,
any :class:`unicode` that is written to the file will be
converted to a :class:`str`. In Python 3, any :class:`str`
that is written to the file will be converted to
:class:`bytes`.
:Parameters:
- `root_collection`: root collection to write to
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession` to use for all
commands
- `disable_md5` (optional): When True, an MD5 checksum will not be
computed for the uploaded file. Useful in environments where
MD5 cannot be used for regulatory or other reasons. Defaults to
False.
- `**kwargs` (optional): file level options (see above)
.. versionchanged:: 3.6
Added ``session`` parameter.
.. versionchanged:: 3.0
`root_collection` must use an acknowledged
:attr:`~pymongo.collection.Collection.write_concern`
"""
if not isinstance(root_collection, Collection):
raise TypeError("root_collection must be an "
"instance of Collection")
if not root_collection.write_concern.acknowledged:
raise ConfigurationError('root_collection must use '
'acknowledged write_concern')
# Handle alternative naming
if "content_type" in kwargs:
kwargs["contentType"] = kwargs.pop("content_type")
if "chunk_size" in kwargs:
kwargs["chunkSize"] = kwargs.pop("chunk_size")
coll = _clear_entity_type_registry(
root_collection, read_preference=ReadPreference.PRIMARY)
if not disable_md5:
kwargs["md5"] = hashlib.md5()
# Defaults
kwargs["_id"] = kwargs.get("_id", ObjectId())
kwargs["chunkSize"] = kwargs.get("chunkSize", DEFAULT_CHUNK_SIZE)
object.__setattr__(self, "_session", session)
object.__setattr__(self, "_coll", coll)
object.__setattr__(self, "_chunks", coll.chunks)
object.__setattr__(self, "_file", kwargs)
object.__setattr__(self, "_buffer", StringIO())
object.__setattr__(self, "_position", 0)
object.__setattr__(self, "_chunk_number", 0)
object.__setattr__(self, "_closed", False)
object.__setattr__(self, "_ensured_index", False)
def __create_index(self, collection, index_key, unique):
doc = collection.find_one(projection={"_id": 1}, session=self._session)
if doc is None:
try:
index_keys = [index_spec['key'] for index_spec in
collection.list_indexes(session=self._session)]
except OperationFailure:
index_keys = []
if index_key not in index_keys:
collection.create_index(
index_key.items(), unique=unique, session=self._session)
def __ensure_indexes(self):
if not object.__getattribute__(self, "_ensured_index"):
self.__create_index(self._coll.files, _F_INDEX, False)
self.__create_index(self._coll.chunks, _C_INDEX, True)
object.__setattr__(self, "_ensured_index", True)
def abort(self):
"""Remove all chunks/files that may have been uploaded and close.
"""
self._coll.chunks.delete_many(
{"files_id": self._file['_id']}, session=self._session)
self._coll.files.delete_one(
{"_id": self._file['_id']}, session=self._session)
object.__setattr__(self, "_closed", True)
@property
def closed(self):
"""Is this file closed?
"""
return self._closed
_id = _grid_in_property("_id", "The ``'_id'`` value for this file.",
read_only=True)
filename = _grid_in_property("filename", "Name of this file.")
name = _grid_in_property("filename", "Alias for `filename`.")
content_type = _grid_in_property("contentType", "Mime-type for this file.")
length = _grid_in_property("length", "Length (in bytes) of this file.",
closed_only=True)
chunk_size = _grid_in_property("chunkSize", "Chunk size for this file.",
read_only=True)
upload_date = _grid_in_property("uploadDate",
"Date that this file was uploaded.",
closed_only=True)
md5 = _grid_in_property("md5", "MD5 of the contents of this file "
"if an md5 sum was created.",
closed_only=True)
def __getattr__(self, name):
if name in self._file:
return self._file[name]
raise AttributeError("GridIn object has no attribute '%s'" % name)
def __setattr__(self, name, value):
# For properties of this instance like _buffer, or descriptors set on
# the class like filename, use regular __setattr__
if name in self.__dict__ or name in self.__class__.__dict__:
object.__setattr__(self, name, value)
else:
# All other attributes are part of the document in db.fs.files.
# Store them to be sent to server on close() or if closed, send
# them now.
self._file[name] = value
if self._closed:
self._coll.files.update_one({"_id": self._file["_id"]},
{"$set": {name: value}})
def __flush_data(self, data):
"""Flush `data` to a chunk.
"""
self.__ensure_indexes()
if 'md5' in self._file:
self._file['md5'].update(data)
if not data:
return
assert(len(data) <= self.chunk_size)
chunk = {"files_id": self._file["_id"],
"n": self._chunk_number,
"data": Binary(data)}
try:
self._chunks.insert_one(chunk, session=self._session)
except DuplicateKeyError:
self._raise_file_exists(self._file['_id'])
self._chunk_number += 1
self._position += len(data)
def __flush_buffer(self):
"""Flush the buffer contents out to a chunk.
"""
self.__flush_data(self._buffer.getvalue())
self._buffer.close()
self._buffer = StringIO()
def __flush(self):
"""Flush the file to the database.
"""
try:
self.__flush_buffer()
if "md5" in self._file:
self._file["md5"] = self._file["md5"].hexdigest()
# The GridFS spec says length SHOULD be an Int64.
self._file["length"] = Int64(self._position)
self._file["uploadDate"] = datetime.datetime.utcnow()
return self._coll.files.insert_one(
self._file, session=self._session)
except DuplicateKeyError:
self._raise_file_exists(self._id)
def _raise_file_exists(self, file_id):
"""Raise a FileExists exception for the given file_id."""
raise FileExists("file with _id %r already exists" % file_id)
def close(self):
"""Flush the file and close it.
A closed file cannot be written any more. Calling
:meth:`close` more than once is allowed.
"""
if not self._closed:
self.__flush()
object.__setattr__(self, "_closed", True)
def read(self, size=-1):
raise io.UnsupportedOperation('read')
def readable(self):
return False
def seekable(self):
return False
def write(self, data):
"""Write data to the file. There is no return value.
`data` can be either a string of bytes or a file-like object
(implementing :meth:`read`). If the file has an
:attr:`encoding` attribute, `data` can also be a
:class:`unicode` (:class:`str` in python 3) instance, which
will be encoded as :attr:`encoding` before being written.
Due to buffering, the data may not actually be written to the
database until the :meth:`close` method is called. Raises
:class:`ValueError` if this file is already closed. Raises
:class:`TypeError` if `data` is not an instance of
:class:`str` (:class:`bytes` in python 3), a file-like object,
or an instance of :class:`unicode` (:class:`str` in python 3).
Unicode data is only allowed if the file has an :attr:`encoding`
attribute.
:Parameters:
- `data`: string of bytes or file-like object to be written
to the file
"""
if self._closed:
raise ValueError("cannot write to a closed file")
try:
# file-like
read = data.read
except AttributeError:
# string
if not isinstance(data, (text_type, bytes)):
raise TypeError("can only write strings or file-like objects")
if isinstance(data, text_type):
try:
data = data.encode(self.encoding)
except AttributeError:
raise TypeError("must specify an encoding for file in "
"order to write %s" % (text_type.__name__,))
read = StringIO(data).read
if self._buffer.tell() > 0:
# Make sure to flush only when _buffer is complete
space = self.chunk_size - self._buffer.tell()
if space:
try:
to_write = read(space)
except:
self.abort()
raise
self._buffer.write(to_write)
if len(to_write) < space:
return # EOF or incomplete
self.__flush_buffer()
to_write = read(self.chunk_size)
while to_write and len(to_write) == self.chunk_size:
self.__flush_data(to_write)
to_write = read(self.chunk_size)
self._buffer.write(to_write)
def writelines(self, sequence):
"""Write a sequence of strings to the file.
Does not add seperators.
"""
for line in sequence:
self.write(line)
def writeable(self):
return True
def __enter__(self):
"""Support for the context manager protocol.
"""
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""Support for the context manager protocol.
Close the file and allow exceptions to propagate.
"""
self.close()
# propagate exceptions
return False
class GridOut(object):
"""Class to read data out of GridFS.
"""
def __init__(self, root_collection, file_id=None, file_document=None,
session=None):
"""Read a file from GridFS
Application developers should generally not need to
instantiate this class directly - instead see the methods
provided by :class:`~gridfs.GridFS`.
Either `file_id` or `file_document` must be specified,
`file_document` will be given priority if present. Raises
:class:`TypeError` if `root_collection` is not an instance of
:class:`~pymongo.collection.Collection`.
:Parameters:
- `root_collection`: root collection to read from
- `file_id` (optional): value of ``"_id"`` for the file to read
- `file_document` (optional): file document from
`root_collection.files`
- `session` (optional): a
:class:`~pymongo.client_session.ClientSession` to use for all
commands
.. versionchanged:: 3.8
For better performance and to better follow the GridFS spec,
:class:`GridOut` now uses a single cursor to read all the chunks in
the file.
.. versionchanged:: 3.6
Added ``session`` parameter.
.. versionchanged:: 3.0
Creating a GridOut does not immediately retrieve the file metadata
from the server. Metadata is fetched when first needed.
"""
if not isinstance(root_collection, Collection):
raise TypeError("root_collection must be an "
"instance of Collection")
root_collection = _clear_entity_type_registry(root_collection)
self.__chunks = root_collection.chunks
self.__files = root_collection.files
self.__file_id = file_id
self.__buffer = EMPTY
self.__chunk_iter = None
self.__position = 0
self._file = file_document
self._session = session
_id = _grid_out_property("_id", "The ``'_id'`` value for this file.")
filename = _grid_out_property("filename", "Name of this file.")
name = _grid_out_property("filename", "Alias for `filename`.")
content_type = _grid_out_property("contentType", "Mime-type for this file.")
length = _grid_out_property("length", "Length (in bytes) of this file.")
chunk_size = _grid_out_property("chunkSize", "Chunk size for this file.")
upload_date = _grid_out_property("uploadDate",
"Date that this file was first uploaded.")
aliases = _grid_out_property("aliases", "List of aliases for this file.")
metadata = _grid_out_property("metadata", "Metadata attached to this file.")
md5 = _grid_out_property("md5", "MD5 of the contents of this file "
"if an md5 sum was created.")
def _ensure_file(self):
if not self._file:
self._file = self.__files.find_one({"_id": self.__file_id},
session=self._session)
if not self._file:
raise NoFile("no file in gridfs collection %r with _id %r" %
(self.__files, self.__file_id))
def __getattr__(self, name):
self._ensure_file()
if name in self._file:
return self._file[name]
raise AttributeError("GridOut object has no attribute '%s'" % name)
def readable(self):
return True
def readchunk(self):
"""Reads a chunk at a time. If the current position is within a
chunk the remainder of the chunk is returned.
"""
received = len(self.__buffer)
chunk_data = EMPTY
chunk_size = int(self.chunk_size)
if received > 0:
chunk_data = self.__buffer
elif self.__position < int(self.length):
chunk_number = int((received + self.__position) / chunk_size)
if self.__chunk_iter is None:
self.__chunk_iter = _GridOutChunkIterator(
self, self.__chunks, self._session, chunk_number)
chunk = self.__chunk_iter.next()
chunk_data = chunk["data"][self.__position % chunk_size:]
if not chunk_data:
raise CorruptGridFile("truncated chunk")
self.__position += len(chunk_data)
self.__buffer = EMPTY
return chunk_data
def read(self, size=-1):
"""Read at most `size` bytes from the file (less if there
isn't enough data).
The bytes are returned as an instance of :class:`str` (:class:`bytes`
in python 3). If `size` is negative or omitted all data is read.
:Parameters:
- `size` (optional): the number of bytes to read
.. versionchanged:: 3.8
This method now only checks for extra chunks after reading the
entire file. Previously, this method would check for extra chunks
on every call.
"""
self._ensure_file()
remainder = int(self.length) - self.__position
if size < 0 or size > remainder:
size = remainder
if size == 0:
return EMPTY
received = 0
data = StringIO()
while received < size:
chunk_data = self.readchunk()
received += len(chunk_data)
data.write(chunk_data)
# Detect extra chunks after reading the entire file.
if size == remainder and self.__chunk_iter:
try:
self.__chunk_iter.next()
except StopIteration:
pass
self.__position -= received - size
# Return 'size' bytes and store the rest.
data.seek(size)
self.__buffer = data.read()
data.seek(0)
return data.read(size)
def readline(self, size=-1):
"""Read one line or up to `size` bytes from the file.
:Parameters:
- `size` (optional): the maximum number of bytes to read
"""
remainder = int(self.length) - self.__position
if size < 0 or size > remainder:
size = remainder
if size == 0:
return EMPTY
received = 0
data = StringIO()
while received < size:
chunk_data = self.readchunk()
pos = chunk_data.find(NEWLN, 0, size)
if pos != -1:
size = received + pos + 1
received += len(chunk_data)
data.write(chunk_data)
if pos != -1:
break
self.__position -= received - size
# Return 'size' bytes and store the rest.
data.seek(size)
self.__buffer = data.read()
data.seek(0)
return data.read(size)
def tell(self):
"""Return the current position of this file.
"""
return self.__position
def seek(self, pos, whence=_SEEK_SET):
"""Set the current position of this file.
:Parameters:
- `pos`: the position (or offset if using relative
positioning) to seek to
- `whence` (optional): where to seek
from. :attr:`os.SEEK_SET` (``0``) for absolute file
positioning, :attr:`os.SEEK_CUR` (``1``) to seek relative
to the current position, :attr:`os.SEEK_END` (``2``) to
seek relative to the file's end.
"""
if whence == _SEEK_SET:
new_pos = pos
elif whence == _SEEK_CUR:
new_pos = self.__position + pos
elif whence == _SEEK_END:
new_pos = int(self.length) + pos
else:
raise IOError(22, "Invalid value for `whence`")
if new_pos < 0:
raise IOError(22, "Invalid value for `pos` - must be positive")
# Optimization, continue using the same buffer and chunk iterator.
if new_pos == self.__position:
return
self.__position = new_pos
self.__buffer = EMPTY
if self.__chunk_iter:
self.__chunk_iter.close()
self.__chunk_iter = None
def seekable(self):
return True
def __iter__(self):
"""Return an iterator over all of this file's data.
The iterator will return chunk-sized instances of
:class:`str` (:class:`bytes` in python 3). This can be
useful when serving files using a webserver that handles
such an iterator efficiently.
.. note::
This is different from :py:class:`io.IOBase` which iterates over
*lines* in the file. Use :meth:`GridOut.readline` to read line by
line instead of chunk by chunk.
.. versionchanged:: 3.8
The iterator now raises :class:`CorruptGridFile` when encountering
any truncated, missing, or extra chunk in a file. The previous
behavior was to only raise :class:`CorruptGridFile` on a missing
chunk.
"""
return GridOutIterator(self, self.__chunks, self._session)
def close(self):
"""Make GridOut more generically file-like."""
if self.__chunk_iter:
self.__chunk_iter.close()
self.__chunk_iter = None
def write(self, value):
raise io.UnsupportedOperation('write')
def __enter__(self):
"""Makes it possible to use :class:`GridOut` files
with the context manager protocol.
"""
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""Makes it possible to use :class:`GridOut` files
with the context manager protocol.
"""
self.close()
return False
class _GridOutChunkIterator(object):
"""Iterates over a file's chunks using a single cursor.
Raises CorruptGridFile when encountering any truncated, missing, or extra
chunk in a file.
"""
def __init__(self, grid_out, chunks, session, next_chunk):
self._id = grid_out._id
self._chunk_size = int(grid_out.chunk_size)
self._length = int(grid_out.length)
self._chunks = chunks
self._session = session
self._next_chunk = next_chunk
self._num_chunks = math.ceil(float(self._length) / self._chunk_size)
self._cursor = None
def expected_chunk_length(self, chunk_n):
if chunk_n < self._num_chunks - 1:
return self._chunk_size
return self._length - (self._chunk_size * (self._num_chunks - 1))
def __iter__(self):
return self
def _create_cursor(self):
filter = {"files_id": self._id}
if self._next_chunk > 0:
filter["n"] = {"$gte": self._next_chunk}
self._cursor = self._chunks.find(filter, sort=[("n", 1)],
session=self._session)
def _next_with_retry(self):
"""Return the next chunk and retry once on CursorNotFound.
We retry on CursorNotFound to maintain backwards compatibility in
cases where two calls to read occur more than 10 minutes apart (the
server's default cursor timeout).
"""
if self._cursor is None:
self._create_cursor()
try:
return self._cursor.next()
except CursorNotFound:
self._cursor.close()
self._create_cursor()
return self._cursor.next()
def next(self):
try:
chunk = self._next_with_retry()
except StopIteration:
if self._next_chunk >= self._num_chunks:
raise
raise CorruptGridFile("no chunk #%d" % self._next_chunk)
if chunk["n"] != self._next_chunk:
self.close()
raise CorruptGridFile(
"Missing chunk: expected chunk #%d but found "
"chunk with n=%d" % (self._next_chunk, chunk["n"]))
if chunk["n"] >= self._num_chunks:
# According to spec, ignore extra chunks if they are empty.
if len(chunk["data"]):
self.close()
raise CorruptGridFile(
"Extra chunk found: expected %d chunks but found "
"chunk with n=%d" % (self._num_chunks, chunk["n"]))
expected_length = self.expected_chunk_length(chunk["n"])
if len(chunk["data"]) != expected_length:
self.close()
raise CorruptGridFile(
"truncated chunk #%d: expected chunk length to be %d but "
"found chunk with length %d" % (
chunk["n"], expected_length, len(chunk["data"])))
self._next_chunk += 1
return chunk
__next__ = next
def close(self):
if self._cursor:
self._cursor.close()
self._cursor = None
class GridOutIterator(object):
def __init__(self, grid_out, chunks, session):
self.__chunk_iter = _GridOutChunkIterator(grid_out, chunks, session, 0)
def __iter__(self):
return self
def next(self):
chunk = self.__chunk_iter.next()
return bytes(chunk["data"])
__next__ = next
class GridOutCursor(Cursor):
"""A cursor / iterator for returning GridOut objects as the result
of an arbitrary query against the GridFS files collection.
"""
def __init__(self, collection, filter=None, skip=0, limit=0,
no_cursor_timeout=False, sort=None, batch_size=0,
session=None):
"""Create a new cursor, similar to the normal
:class:`~pymongo.cursor.Cursor`.
Should not be called directly by application developers - see
the :class:`~gridfs.GridFS` method :meth:`~gridfs.GridFS.find` instead.
.. versionadded 2.7
.. mongodoc:: cursors
"""
collection = _clear_entity_type_registry(collection)
# Hold on to the base "fs" collection to create GridOut objects later.
self.__root_collection = collection
super(GridOutCursor, self).__init__(
collection.files, filter, skip=skip, limit=limit,
no_cursor_timeout=no_cursor_timeout, sort=sort,
batch_size=batch_size, session=session)
def next(self):
"""Get next GridOut object from cursor.
"""
# Work around "super is not iterable" issue in Python 3.x
next_file = super(GridOutCursor, self).next()
return GridOut(self.__root_collection, file_document=next_file,
session=self.session)
__next__ = next
def add_option(self, *args, **kwargs):
raise NotImplementedError("Method does not exist for GridOutCursor")
def remove_option(self, *args, **kwargs):
raise NotImplementedError("Method does not exist for GridOutCursor")
def _clone_base(self, session):
"""Creates an empty GridOutCursor for information to be copied into.
"""
return GridOutCursor(self.__root_collection, session=session)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/__init__.py
================================================
from __future__ import absolute_import
from hamcrest.core import *
from hamcrest.library import *
__version__ = "1.9.0"
__author__ = "Chris Rose"
__copyright__ = "Copyright 2015 hamcrest.org"
__license__ = "BSD, see License.txt"
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/__init__.py
================================================
from __future__ import absolute_import
from hamcrest.core.assert_that import assert_that
from hamcrest.core.core import *
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/assert_that.py
================================================
from __future__ import absolute_import
from hamcrest.core.matcher import Matcher
from hamcrest.core.string_description import StringDescription
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
# unittest integration; hide these frames from tracebacks
__unittest = True
# py.test integration; hide these frames from tracebacks
__tracebackhide__ = True
def assert_that(arg1, arg2=None, arg3=''):
"""Asserts that actual value satisfies matcher. (Can also assert plain
boolean condition.)
:param actual: The object to evaluate as the actual value.
:param matcher: The matcher to satisfy as the expected condition.
:param reason: Optional explanation to include in failure description.
``assert_that`` passes the actual value to the matcher for evaluation. If
the matcher is not satisfied, an exception is thrown describing the
mismatch.
``assert_that`` is designed to integrate well with PyUnit and other unit
testing frameworks. The exception raised for an unmet assertion is an
:py:exc:`AssertionError`, which PyUnit reports as a test failure.
With a different set of parameters, ``assert_that`` can also verify a
boolean condition:
.. function:: assert_that(assertion[, reason])
:param assertion: Boolean condition to verify.
:param reason: Optional explanation to include in failure description.
This is equivalent to the :py:meth:`~unittest.TestCase.assertTrue` method
of :py:class:`unittest.TestCase`, but offers greater flexibility in test
writing by being a standalone function.
"""
if isinstance(arg2, Matcher):
_assert_match(actual=arg1, matcher=arg2, reason=arg3)
else:
_assert_bool(assertion=arg1, reason=arg2)
def _assert_match(actual, matcher, reason):
if not matcher.matches(actual):
description = StringDescription()
description.append_text(reason) \
.append_text('\nExpected: ') \
.append_description_of(matcher) \
.append_text('\n but: ')
matcher.describe_mismatch(actual, description)
description.append_text('\n')
raise AssertionError(description)
def _assert_bool(assertion, reason=None):
if not assertion:
if not reason:
reason = 'Assertion failed'
raise AssertionError(reason)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/base_description.py
================================================
from __future__ import absolute_import
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
import warnings
import six
from hamcrest.core.description import Description
from hamcrest.core.selfdescribingvalue import SelfDescribingValue
from hamcrest.core.helpers.hasmethod import hasmethod
class BaseDescription(Description):
"""Base class for all :py:class:`~hamcrest.core.description.Description`
implementations.
"""
def append_text(self, text):
self.append(text)
return self
def append_description_of(self, value):
if hasmethod(value, 'describe_to'):
value.describe_to(self)
elif six.PY3 and isinstance(value, six.text_type):
self.append(repr(value))
elif six.PY2 and isinstance(value, six.binary_type):
self.append_string_in_python_syntax(value)
elif isinstance(value, six.text_type):
self.append_string_in_python_syntax(value)
else:
description = str(value)
if description[:1] == '<' and description[-1:] == '>':
self.append(description)
else:
self.append('<')
self.append(description)
self.append('>')
return self
def append_value(self, value):
warnings.warn('Call append_description_of instead of append_value',
DeprecationWarning)
if isinstance(value, str):
self.append_string_in_python_syntax(value)
else:
self.append('<')
self.append(str(value))
self.append('>')
return self
def append_value_list(self, start, separator, end, list):
warnings.warn('Call append_list instead of append_value_list',
DeprecationWarning)
return self.append_list(start, separator, end,
map(SelfDescribingValue, list))
def append_list(self, start, separator, end, list):
separate = False
self.append(start)
for item in list:
if separate:
self.append(separator)
self.append_description_of(item)
separate = True
self.append(end)
return self
def append(self, string):
"""Append the string to the description."""
raise NotImplementedError('append')
def append_string_in_python_syntax(self, string):
self.append("'")
for ch in string:
self.append(character_in_python_syntax(ch))
self.append("'")
def character_in_python_syntax(ch):
if ch == "'":
return "\'"
elif ch == '\n':
return '\\n'
elif ch == '\r':
return '\\r'
elif ch == '\t':
return '\\t'
else:
return ch
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/base_matcher.py
================================================
from __future__ import absolute_import
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
from hamcrest.core.matcher import Matcher
from hamcrest.core.string_description import tostring
class BaseMatcher(Matcher):
"""Base class for all :py:class:`~hamcrest.core.matcher.Matcher`
implementations.
Most implementations can just implement :py:obj:`_matches`, leaving the
handling of any mismatch description to the ``matches`` method. But if it
makes more sense to generate the mismatch description during the matching,
override :py:meth:`~hamcrest.core.matcher.Matcher.matches` instead.
"""
def __str__(self):
return tostring(self)
def _matches(self, item):
raise NotImplementedError('_matches')
def matches(self, item, mismatch_description=None):
match_result = self._matches(item)
if not match_result and mismatch_description:
self.describe_mismatch(item, mismatch_description)
return match_result
def describe_mismatch(self, item, mismatch_description):
mismatch_description.append_text('was ').append_description_of(item)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/compat.py
================================================
__author__ = "Per Fagrell"
__copyright__ = "Copyright 2013 hamcrest.org"
__license__ = "BSD, see License.txt"
__all__ = ['is_callable']
import sys
# callable was not part of py3k until 3.2, so we create this
# generic is_callable to use callable if possible, otherwise
# we use generic homebrew.
if sys.version_info[0] == 3 and sys.version_info[1] < 2:
def is_callable(function):
"""Return whether the object is callable (i.e., some kind of function)."""
if function is None:
return False
return any("__call__" in klass.__dict__ for klass in type(function).__mro__)
else:
is_callable = callable
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/core/__init__.py
================================================
from __future__ import absolute_import
"""Fundamental matchers of objects and values, and composite matchers."""
from hamcrest.core.core.allof import all_of
from hamcrest.core.core.anyof import any_of
from hamcrest.core.core.described_as import described_as
from hamcrest.core.core.is_ import is_
from hamcrest.core.core.isanything import anything
from hamcrest.core.core.isequal import equal_to
from hamcrest.core.core.isinstanceof import instance_of
from hamcrest.core.core.isnone import none, not_none
from hamcrest.core.core.isnot import is_not, not_
from hamcrest.core.core.issame import same_instance
from hamcrest.core.core.raises import calling, raises
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/core/allof.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class AllOf(BaseMatcher):
def __init__(self, *matchers):
self.matchers = matchers
def matches(self, item, mismatch_description=None):
for matcher in self.matchers:
if not matcher.matches(item):
if mismatch_description:
mismatch_description.append_description_of(matcher) \
.append_text(' ')
matcher.describe_mismatch(item, mismatch_description)
return False
return True
def describe_mismatch(self, item, mismatch_description):
self.matches(item, mismatch_description)
def describe_to(self, description):
description.append_list('(', ' and ', ')', self.matchers)
def all_of(*items):
"""Matches if all of the given matchers evaluate to ``True``.
:param matcher1,...: A comma-separated list of matchers.
The matchers are evaluated from left to right using short-circuit
evaluation, so evaluation stops as soon as a matcher returns ``False``.
Any argument that is not a matcher is implicitly wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
equality.
"""
return AllOf(*[wrap_matcher(item) for item in items])
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/core/anyof.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class AnyOf(BaseMatcher):
def __init__(self, *matchers):
self.matchers = matchers
def _matches(self, item):
for matcher in self.matchers:
if matcher.matches(item):
return True
return False
def describe_to(self, description):
description.append_list('(', ' or ', ')', self.matchers)
def any_of(*items):
"""Matches if any of the given matchers evaluate to ``True``.
:param matcher1,...: A comma-separated list of matchers.
The matchers are evaluated from left to right using short-circuit
evaluation, so evaluation stops as soon as a matcher returns ``True``.
Any argument that is not a matcher is implicitly wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
equality.
"""
return AnyOf(*[wrap_matcher(item) for item in items])
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/core/described_as.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
import re
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
ARG_PATTERN = re.compile('%([0-9]+)')
class DescribedAs(BaseMatcher):
def __init__(self, description_template, matcher, *values):
self.template = description_template
self.matcher = matcher
self.values = values
def matches(self, item, mismatch_description=None):
return self.matcher.matches(item, mismatch_description)
def describe_mismatch(self, item, mismatch_description):
self.matcher.describe_mismatch(item, mismatch_description)
def describe_to(self, description):
text_start = 0
for match in re.finditer(ARG_PATTERN, self.template):
description.append_text(self.template[text_start:match.start()])
arg_index = int(match.group()[1:])
description.append_description_of(self.values[arg_index])
text_start = match.end()
if text_start < len(self.template):
description.append_text(self.template[text_start:])
def described_as(description, matcher, *values):
"""Adds custom failure description to a given matcher.
:param description: Overrides the matcher's description.
:param matcher: The matcher to satisfy.
:param value1,...: Optional comma-separated list of substitution values.
The description may contain substitution placeholders %0, %1, etc. These
will be replaced by any values that follow the matcher.
"""
return DescribedAs(description, matcher, *values)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/core/is_.py
================================================
from __future__ import absolute_import
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.wrap_matcher import wrap_matcher, is_matchable_type
from .isinstanceof import instance_of
class Is(BaseMatcher):
def __init__(self, matcher):
self.matcher = matcher
def matches(self, item, mismatch_description=None):
return self.matcher.matches(item, mismatch_description)
def describe_mismatch(self, item, mismatch_description):
return self.matcher.describe_mismatch(item, mismatch_description)
def describe_to(self, description):
description.append_description_of(self.matcher)
def wrap_value_or_type(x):
if is_matchable_type(x):
return instance_of(x)
else:
return wrap_matcher(x)
def is_(x):
"""Decorates another matcher, or provides shortcuts to the frequently used
``is(equal_to(x))`` and ``is(instance_of(x))``.
:param x: The matcher to satisfy, or a type for
:py:func:`~hamcrest.core.core.isinstanceof.instance_of` matching, or an
expected value for :py:func:`~hamcrest.core.core.isequal.equal_to`
matching.
This matcher compares the evaluated object to the given matcher.
.. note::
PyHamcrest's ``is_`` matcher is unrelated to Python's ``is`` operator.
The matcher for object identity is
:py:func:`~hamcrest.core.core.issame.same_instance`.
If the ``x`` argument is a matcher, its behavior is retained, but the test
may be more expressive. For example::
assert_that(value, less_than(5))
assert_that(value, is_(less_than(5)))
If the ``x`` argument is a type, it is wrapped in an
:py:func:`~hamcrest.core.core.isinstanceof.instance_of` matcher. This makes
the following statements equivalent::
assert_that(cheese, instance_of(Cheddar))
assert_that(cheese, is_(instance_of(Cheddar)))
assert_that(cheese, is_(Cheddar))
Otherwise, if the ``x`` argument is not a matcher, it is wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher. This makes the
following statements equivalent::
assert_that(cheese, equal_to(smelly))
assert_that(cheese, is_(equal_to(smelly)))
assert_that(cheese, is_(smelly))
Choose the style that makes your expression most readable. This will vary
depending on context.
"""
return Is(wrap_value_or_type(x))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/core/isanything.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class IsAnything(BaseMatcher):
def __init__(self, description):
self.description = description
if not description:
self.description = 'ANYTHING'
def _matches(self, item):
return True
def describe_to(self, description):
description.append_text(self.description)
def anything(description=None):
"""Matches anything.
:param description: Optional string used to describe this matcher.
This matcher always evaluates to ``True``. Specify this in composite
matchers when the value of a particular element is unimportant.
"""
return IsAnything(description)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/core/isequal.py
================================================
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.matcher import Matcher
class IsEqual(BaseMatcher):
def __init__(self, equals):
self.object = equals
def _matches(self, item):
return item == self.object
def describe_to(self, description):
nested_matcher = isinstance(self.object, Matcher)
if nested_matcher:
description.append_text('<')
description.append_description_of(self.object)
if nested_matcher:
description.append_text('>')
def equal_to(obj):
"""Matches if object is equal to a given object.
:param obj: The object to compare against as the expected value.
This matcher compares the evaluated object to ``obj`` for equality."""
return IsEqual(obj)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/core/isinstanceof.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.wrap_matcher import is_matchable_type
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
import types
class IsInstanceOf(BaseMatcher):
def __init__(self, expected_type):
if not is_matchable_type(expected_type):
raise TypeError('IsInstanceOf requires type or a tuple of classes and types')
self.expected_type = expected_type
def _matches(self, item):
return isinstance(item, self.expected_type)
def describe_to(self, description):
try:
type_description = self.expected_type.__name__
except AttributeError:
type_description = "one of %s" % ",".join(str(e) for e in self.expected_type)
description.append_text('an instance of ') \
.append_text(type_description)
def instance_of(atype):
"""Matches if object is an instance of, or inherits from, a given type.
:param atype: The type to compare against as the expected type or a tuple
of types.
This matcher checks whether the evaluated object is an instance of
``atype`` or an instance of any class that inherits from ``atype``.
Example::
instance_of(str)
"""
return IsInstanceOf(atype)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/core/isnone.py
================================================
from __future__ import absolute_import
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
from hamcrest.core.base_matcher import BaseMatcher
from .isnot import is_not
class IsNone(BaseMatcher):
def _matches(self, item):
return item is None
def describe_to(self, description):
description.append_text('None')
def none():
"""Matches if object is ``None``."""
return IsNone()
def not_none():
"""Matches if object is not ``None``."""
return is_not(none())
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/core/isnot.py
================================================
from __future__ import absolute_import
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
from hamcrest.core.base_matcher import BaseMatcher, Matcher
from hamcrest.core.helpers.wrap_matcher import wrap_matcher, is_matchable_type
from .isequal import equal_to
from .isinstanceof import instance_of
class IsNot(BaseMatcher):
def __init__(self, matcher):
self.matcher = matcher
def _matches(self, item):
return not self.matcher.matches(item)
def describe_to(self, description):
description.append_text('not ').append_description_of(self.matcher)
def wrap_value_or_type(x):
if is_matchable_type(x):
return instance_of(x)
else:
return wrap_matcher(x)
def is_not(match):
"""Inverts the given matcher to its logical negation.
:param match: The matcher to negate.
This matcher compares the evaluated object to the negation of the given
matcher. If the ``match`` argument is not a matcher, it is implicitly
wrapped in an :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to
check for equality, and thus matches for inequality.
Examples::
assert_that(cheese, is_not(equal_to(smelly)))
assert_that(cheese, is_not(smelly))
"""
return IsNot(wrap_value_or_type(match))
def not_(match):
"""Alias of :py:func:`is_not` for better readability of negations.
Examples::
assert_that(alist, not_(has_item(item)))
"""
return is_not(match)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/core/issame.py
================================================
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
from hamcrest.core.base_matcher import BaseMatcher
class IsSame(BaseMatcher):
def __init__(self, object):
self.object = object
def _matches(self, item):
return item is self.object
def describe_to(self, description):
description.append_text('same instance as ') \
.append_text(hex(id(self.object))) \
.append_text(' ') \
.append_description_of(self.object)
def describe_mismatch(self, item, mismatch_description):
mismatch_description.append_text('was ')
if item is not None:
mismatch_description.append_text(hex(id(item))) \
.append_text(' ')
mismatch_description.append_description_of(item)
def same_instance(obj):
"""Matches if evaluated object is the same instance as a given object.
:param obj: The object to compare against as the expected value.
This matcher invokes the ``is`` identity operator to determine if the
evaluated object is the the same object as ``obj``.
"""
return IsSame(obj)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/core/raises.py
================================================
from weakref import ref
import re
import sys
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.compat import is_callable
__author__ = "Per Fagrell"
__copyright__ = "Copyright 2013 hamcrest.org"
__license__ = "BSD, see License.txt"
class Raises(BaseMatcher):
def __init__(self, expected, pattern=None):
self.pattern = pattern
self.expected = expected
self.actual = None
self.function = None
def _matches(self, function):
if not is_callable(function):
return False
self.function = ref(function)
return self._call_function(function)
def _call_function(self, function):
self.actual = None
try:
function()
except Exception:
self.actual = sys.exc_info()[1]
if isinstance(self.actual, self.expected):
if self.pattern is not None:
return re.search(self.pattern, str(self.actual)) is not None
return True
return False
def describe_to(self, description):
description.append_text('Expected a callable raising %s' % self.expected)
def describe_mismatch(self, item, description):
if not is_callable(item):
description.append_text('%s is not callable' % item)
return
function = None if self.function is None else self.function()
if function is None or function is not item:
self.function = ref(item)
if not self._call_function(item):
return
if self.actual is None:
description.append_text('No exception raised.')
elif isinstance(self.actual, self.expected) and self.pattern is not None:
description.append_text('Correct assertion type raised, but the expected pattern ("%s") not found.' % self.pattern)
description.append_text('\n message was: "%s"' % str(self.actual))
else:
description.append_text('%s was raised instead' % type(self.actual))
def raises(exception, pattern=None):
"""Matches if the called function raised the expected exception.
:param exception: The class of the expected exception
:param pattern: Optional regular expression to match exception message.
Expects the actual to be wrapped by using :py:func:`~hamcrest.core.core.raises.calling`,
or a callable taking no arguments.
Optional argument pattern should be a string containing a regular expression. If provided,
the string representation of the actual exception - e.g. `str(actual)` - must match pattern.
Examples::
assert_that(calling(int).with_args('q'), raises(TypeError))
assert_that(calling(parse, broken_input), raises(ValueError))
"""
return Raises(exception, pattern)
class DeferredCallable(object):
def __init__(self, func):
self.func = func
self.args = tuple()
self.kwargs = {}
def __call__(self):
return self.func(*self.args, **self.kwargs)
def with_args(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
return self
def calling(func):
"""Wrapper for function call that delays the actual execution so that
:py:func:`~hamcrest.core.core.raises.raises` matcher can catch any thrown exception.
:param func: The function or method to be called
The arguments can be provided with a call to the `with_args` function on the returned
object::
calling(my_method).with_args(arguments, and_='keywords')
"""
return DeferredCallable(func)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/description.py
================================================
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class Description(object):
"""A description of a :py:class:`~hamcrest.core.matcher.Matcher`.
A :py:class:`~hamcrest.core.matcher.Matcher` will describe itself to a
description which can later be used for reporting.
"""
def append_text(self, text):
"""Appends some plain text to the description.
:returns: ``self``, for chaining
"""
raise NotImplementedError('append_text')
def append_description_of(self, value):
"""Appends description of given value to this description.
If the value implements
:py:meth:`~hamcrest.core.selfdescribing.SelfDescribing.describe_to`,
then it will be used.
:returns: ``self``, for chaining
"""
raise NotImplementedError('append_description_of')
def append_value(self, value):
"""Appends an arbitary value to the description.
**Deprecated:** Call
:py:meth:`~hamcrest.core.description.Description.append_description_of`
instead.
:returns: ``self``, for chaining
"""
raise NotImplementedError('append_value')
def append_list(self, start, separator, end, list):
"""Appends a list of objects to the description.
:param start: String that will begin the list description.
:param separator: String that will separate each object in the
description.
:param end: String that will end the list description.
:param list: List of objects to be described.
:returns: ``self``, for chaining
"""
raise NotImplementedError('append_list')
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/helpers/__init__.py
================================================
"""Utilities for writing Matchers."""
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/helpers/hasmethod.py
================================================
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
def hasmethod(obj, methodname):
"""Does ``obj`` have a method named ``methodname``?"""
if not hasattr(obj, methodname):
return False
method = getattr(obj, methodname)
return callable(method)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/helpers/wrap_matcher.py
================================================
import six
from hamcrest.core.base_matcher import Matcher
from hamcrest.core.core.isequal import equal_to
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
import types
def wrap_matcher(x):
"""Wraps argument in a matcher, if necessary.
:returns: the argument as-is if it is already a matcher, otherwise wrapped
in an :py:func:`~hamcrest.core.core.isequal.equal_to` matcher.
"""
if isinstance(x, Matcher):
return x
else:
return equal_to(x)
def is_matchable_type(expected_type):
if isinstance(expected_type, type):
return True
if isinstance(expected_type, six.class_types):
return True
if isinstance(expected_type, tuple) and \
expected_type and \
all(map(is_matchable_type, expected_type)):
return True
return False
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/matcher.py
================================================
from __future__ import absolute_import
from .selfdescribing import SelfDescribing
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class Matcher(SelfDescribing):
"""A matcher over acceptable values.
A matcher is able to describe itself to give feedback when it fails.
Matcher implementations should *not* directly implement this protocol.
Instead, *extend* the :py:class:`~hamcrest.core.base_matcher.BaseMatcher`
class, which will ensure that the
:py:class:`~hamcrest.core.matcher.Matcher` API can grow to support new
features and remain compatible with all
:py:class:`~hamcrest.core.matcher.Matcher` implementations.
"""
def matches(self, item, mismatch_description=None):
"""Evaluates the matcher for argument item.
If a mismatch is detected and argument ``mismatch_description`` is
provided, it will generate a description of why the matcher has not
accepted the item.
:param item: The object against which the matcher is evaluated.
:returns: ``True`` if ``item`` matches, otherwise ``False``.
"""
raise NotImplementedError('matches')
def describe_mismatch(self, item, mismatch_description):
"""Generates a description of why the matcher has not accepted the
item.
The description will be part of a larger description of why a matching
failed, so it should be concise.
This method assumes that ``matches(item)`` is ``False``, but will not
check this.
:param item: The item that the
:py:class:`~hamcrest.core.matcher.Matcher` has rejected.
:param mismatch_description: The description to be built or appended
to.
"""
raise NotImplementedError('describe_mismatch')
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/selfdescribing.py
================================================
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class SelfDescribing(object):
"""The ability of an object to describe itself."""
def describe_to(self, description):
"""Generates a description of the object.
The description may be part of a description of a larger object of
which this is just a component, so it should be worded appropriately.
:param description: The description to be built or appended to.
"""
raise NotImplementedError('describe_to')
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/selfdescribingvalue.py
================================================
from hamcrest.core.selfdescribing import SelfDescribing
import warnings
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class SelfDescribingValue(SelfDescribing):
"""Wrap any value in a ``SelfDescribingValue`` to satisfy the
:py:class:`~hamcrest.core.selfdescribing.SelfDescribing` interface.
**Deprecated:** No need for this class now that
:py:meth:`~hamcrest.core.description.Description.append_description_of`
handles any type of value.
"""
def __init__(self, value):
warnings.warn('SelfDescribingValue no longer needed',
DeprecationWarning)
self.value = value
def describe_to(self, description):
"""Generates a description of the value."""
description.append_value(self.value)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/core/string_description.py
================================================
from __future__ import absolute_import
import codecs
import six
from .base_description import BaseDescription
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
def tostring(selfdescribing):
"""Returns the description of a
:py:class:`~hamcrest.core.selfdescribing.SelfDescribing` object as a
string.
:param selfdescribing: The object to be described.
:returns: The description of the object.
"""
return str(StringDescription().append_description_of(selfdescribing))
class StringDescription(BaseDescription):
"""A :py:class:`~hamcrest.core.description.Description` that is stored as a
string.
"""
def __init__(self):
self.out = ''
def __str__(self):
"""Returns the description."""
return self.out
def append(self, string):
self.out += six.text_type(string)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/__init__.py
================================================
from __future__ import absolute_import
"""Library of Matcher implementations."""
from hamcrest.core import *
from hamcrest.library.collection import *
from hamcrest.library.integration import *
from hamcrest.library.number import *
from hamcrest.library.object import *
from hamcrest.library.text import *
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
__all__ = [
'has_entry',
'has_entries',
'has_key',
'has_value',
'is_in',
'empty',
'has_item',
'has_items',
'contains_inanyorder',
'contains',
'only_contains',
'match_equality',
'matches_regexp',
'close_to',
'greater_than',
'greater_than_or_equal_to',
'less_than',
'less_than_or_equal_to',
'has_length',
'has_property',
'has_properties',
'has_string',
'equal_to_ignoring_case',
'equal_to_ignoring_whitespace',
'contains_string',
'ends_with',
'starts_with',
'string_contains_in_order',
]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/collection/__init__.py
================================================
"""Matchers of collections."""
from __future__ import absolute_import
from .isdict_containing import has_entry
from .isdict_containingentries import has_entries
from .isdict_containingkey import has_key
from .isdict_containingvalue import has_value
from .isin import is_in
from .issequence_containing import has_item, has_items
from .issequence_containinginanyorder import contains_inanyorder
from .issequence_containinginorder import contains
from .issequence_onlycontaining import only_contains
from .is_empty import empty
__author__ = "Chris Rose"
__copyright__ = "Copyright 2013 hamcrest.org"
__license__ = "BSD, see License.txt"
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/collection/is_empty.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
__author__ = "Chris Rose"
__copyright__ = "Copyright 2012 hamcrest.org"
__license__ = "BSD, see License.txt"
class IsEmpty(BaseMatcher):
def matches(self, item, mismatch_description=None):
try:
if len(item) == 0:
return True
if mismatch_description:
mismatch_description \
.append_text('has %d item(s)' % len(item))
except TypeError:
if mismatch_description:
mismatch_description \
.append_text('does not support length')
return False
def describe_to(self, description):
description.append_text('an empty collection')
def empty():
"""
This matcher matches any collection-like object that responds to the
__len__ method, and has a length of 0.
"""
return IsEmpty()
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/collection/isdict_containing.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.hasmethod import hasmethod
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class IsDictContaining(BaseMatcher):
def __init__(self, key_matcher, value_matcher):
self.key_matcher = key_matcher
self.value_matcher = value_matcher
def _matches(self, dictionary):
if hasmethod(dictionary, 'items'):
for key, value in dictionary.items():
if self.key_matcher.matches(key) and self.value_matcher.matches(value):
return True
return False
def describe_to(self, description):
description.append_text('a dictionary containing [') \
.append_description_of(self.key_matcher) \
.append_text(': ') \
.append_description_of(self.value_matcher) \
.append_text(']')
def has_entry(key_match, value_match):
"""Matches if dictionary contains key-value entry satisfying a given pair
of matchers.
:param key_match: The matcher to satisfy for the key, or an expected value
for :py:func:`~hamcrest.core.core.isequal.equal_to` matching.
:param value_match: The matcher to satisfy for the value, or an expected
value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching.
This matcher iterates the evaluated dictionary, searching for any key-value
entry that satisfies ``key_match`` and ``value_match``. If a matching entry
is found, ``has_entry`` is satisfied.
Any argument that is not a matcher is implicitly wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
equality.
Examples::
has_entry(equal_to('foo'), equal_to(1))
has_entry('foo', 1)
"""
return IsDictContaining(wrap_matcher(key_match), wrap_matcher(value_match))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/collection/isdict_containingentries.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.hasmethod import hasmethod
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class IsDictContainingEntries(BaseMatcher):
def __init__(self, value_matchers):
self.value_matchers = sorted(value_matchers.items())
def _not_a_dictionary(self, dictionary, mismatch_description):
if mismatch_description:
mismatch_description.append_description_of(dictionary) \
.append_text(' is not a mapping object')
return False
def matches(self, dictionary, mismatch_description=None):
for key, value_matcher in self.value_matchers:
try:
if not key in dictionary:
if mismatch_description:
mismatch_description.append_text('no ') \
.append_description_of(key) \
.append_text(' key in ') \
.append_description_of(dictionary)
return False
except TypeError:
return self._not_a_dictionary(dictionary, mismatch_description)
try:
actual_value = dictionary[key]
except TypeError:
return self._not_a_dictionary(dictionary, mismatch_description)
if not value_matcher.matches(actual_value):
if mismatch_description:
mismatch_description.append_text('value for ') \
.append_description_of(key) \
.append_text(' ')
value_matcher.describe_mismatch(actual_value, mismatch_description)
return False
return True
def describe_mismatch(self, item, mismatch_description):
self.matches(item, mismatch_description)
def describe_keyvalue(self, index, value, description):
"""Describes key-value pair at given index."""
description.append_description_of(index) \
.append_text(': ') \
.append_description_of(value)
def describe_to(self, description):
description.append_text('a dictionary containing {')
first = True
for key, value in self.value_matchers:
if not first:
description.append_text(', ')
self.describe_keyvalue(key, value, description)
first = False
description.append_text('}')
def has_entries(*keys_valuematchers, **kv_args):
"""Matches if dictionary contains entries satisfying a dictionary of keys
and corresponding value matchers.
:param matcher_dict: A dictionary mapping keys to associated value matchers,
or to expected values for
:py:func:`~hamcrest.core.core.isequal.equal_to` matching.
Note that the keys must be actual keys, not matchers. Any value argument
that is not a matcher is implicitly wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
equality.
Examples::
has_entries({'foo':equal_to(1), 'bar':equal_to(2)})
has_entries({'foo':1, 'bar':2})
``has_entries`` also accepts a list of keyword arguments:
.. function:: has_entries(keyword1=value_matcher1[, keyword2=value_matcher2[, ...]])
:param keyword1: A keyword to look up.
:param valueMatcher1: The matcher to satisfy for the value, or an expected
value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching.
Examples::
has_entries(foo=equal_to(1), bar=equal_to(2))
has_entries(foo=1, bar=2)
Finally, ``has_entries`` also accepts a list of alternating keys and their
value matchers:
.. function:: has_entries(key1, value_matcher1[, ...])
:param key1: A key (not a matcher) to look up.
:param valueMatcher1: The matcher to satisfy for the value, or an expected
value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching.
Examples::
has_entries('foo', equal_to(1), 'bar', equal_to(2))
has_entries('foo', 1, 'bar', 2)
"""
if len(keys_valuematchers) == 1:
try:
base_dict = keys_valuematchers[0].copy()
for key in base_dict:
base_dict[key] = wrap_matcher(base_dict[key])
except AttributeError:
raise ValueError('single-argument calls to has_entries must pass a dict as the argument')
else:
if len(keys_valuematchers) % 2:
raise ValueError('has_entries requires key-value pairs')
base_dict = {}
for index in range(int(len(keys_valuematchers) / 2)):
base_dict[keys_valuematchers[2 * index]] = wrap_matcher(keys_valuematchers[2 * index + 1])
for key, value in kv_args.items():
base_dict[key] = wrap_matcher(value)
return IsDictContainingEntries(base_dict)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/collection/isdict_containingkey.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.hasmethod import hasmethod
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class IsDictContainingKey(BaseMatcher):
def __init__(self, key_matcher):
self.key_matcher = key_matcher
def _matches(self, dictionary):
if hasmethod(dictionary, 'keys'):
for key in dictionary.keys():
if self.key_matcher.matches(key):
return True
return False
def describe_to(self, description):
description.append_text('a dictionary containing key ') \
.append_description_of(self.key_matcher)
def has_key(key_match):
"""Matches if dictionary contains an entry whose key satisfies a given
matcher.
:param key_match: The matcher to satisfy for the key, or an expected value
for :py:func:`~hamcrest.core.core.isequal.equal_to` matching.
This matcher iterates the evaluated dictionary, searching for any key-value
entry whose key satisfies the given matcher. If a matching entry is found,
``has_key`` is satisfied.
Any argument that is not a matcher is implicitly wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
equality.
Examples::
has_key(equal_to('foo'))
has_key('foo')
"""
return IsDictContainingKey(wrap_matcher(key_match))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/collection/isdict_containingvalue.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.hasmethod import hasmethod
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class IsDictContainingValue(BaseMatcher):
def __init__(self, value_matcher):
self.value_matcher = value_matcher
def _matches(self, dictionary):
if hasmethod(dictionary, 'values'):
for value in dictionary.values():
if self.value_matcher.matches(value):
return True
return False
def describe_to(self, description):
description.append_text('a dictionary containing value ') \
.append_description_of(self.value_matcher)
def has_value(value):
"""Matches if dictionary contains an entry whose value satisfies a given
matcher.
:param value_match: The matcher to satisfy for the value, or an expected
value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching.
This matcher iterates the evaluated dictionary, searching for any key-value
entry whose value satisfies the given matcher. If a matching entry is
found, ``has_value`` is satisfied.
Any argument that is not a matcher is implicitly wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
equality.
Examples::
has_value(equal_to('bar'))
has_value('bar')
"""
return IsDictContainingValue(wrap_matcher(value))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/collection/isin.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class IsIn(BaseMatcher):
def __init__(self, sequence):
self.sequence = sequence
def _matches(self, item):
return item in self.sequence
def describe_to(self, description):
description.append_text('one of ') \
.append_list('(', ', ', ')', self.sequence)
def is_in(sequence):
"""Matches if evaluated object is present in a given sequence.
:param sequence: The sequence to search.
This matcher invokes the ``in`` membership operator to determine if the
evaluated object is a member of the sequence.
"""
return IsIn(sequence)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/collection/issequence_containing.py
================================================
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.core.allof import all_of
from hamcrest.core.helpers.hasmethod import hasmethod
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
class IsSequenceContaining(BaseMatcher):
def __init__(self, element_matcher):
self.element_matcher = element_matcher
def _matches(self, sequence):
try:
for item in sequence:
if self.element_matcher.matches(item):
return True
except TypeError: # not a sequence
return False
def describe_to(self, description):
description.append_text('a sequence containing ') \
.append_description_of(self.element_matcher)
# It'd be great to make use of all_of, but we can't be sure we won't
# be seeing a one-time sequence here (like a generator); see issue #20
# Instead, we wrap it inside a class that will convert the sequence into
# a concrete list and then hand it off to the all_of matcher.
class IsSequenceContainingEvery(BaseMatcher):
def __init__(self, *element_matchers):
delegates = [has_item(e) for e in element_matchers]
self.matcher = all_of(*delegates)
def _matches(self, sequence):
try:
return self.matcher.matches(list(sequence))
except TypeError:
return False
def describe_mismatch(self, item, mismatch_description):
self.matcher.describe_mismatch(item, mismatch_description)
def describe_to(self, description):
self.matcher.describe_to(description)
def has_item(match):
"""Matches if any element of sequence satisfies a given matcher.
:param match: The matcher to satisfy, or an expected value for
:py:func:`~hamcrest.core.core.isequal.equal_to` matching.
This matcher iterates the evaluated sequence, searching for any element
that satisfies a given matcher. If a matching element is found,
``has_item`` is satisfied.
If the ``match`` argument is not a matcher, it is implicitly wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
equality.
"""
return IsSequenceContaining(wrap_matcher(match))
def has_items(*items):
"""Matches if all of the given matchers are satisfied by any elements of
the sequence.
:param match1,...: A comma-separated list of matchers.
This matcher iterates the given matchers, searching for any elements in the
evaluated sequence that satisfy them. If each matcher is satisfied, then
``has_items`` is satisfied.
Any argument that is not a matcher is implicitly wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
equality.
"""
matchers = []
for item in items:
matchers.append(wrap_matcher(item))
return IsSequenceContainingEvery(*matchers)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/collection/issequence_containinginanyorder.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.hasmethod import hasmethod
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class MatchInAnyOrder(object):
def __init__(self, matchers, mismatch_description):
self.matchers = matchers[:]
self.mismatch_description = mismatch_description
def matches(self, item):
return self.isnotsurplus(item) and self.ismatched(item)
def isfinished(self, sequence):
if not self.matchers:
return True
if self.mismatch_description:
self.mismatch_description.append_text('no item matches: ') \
.append_list('', ', ', '', self.matchers) \
.append_text(' in ') \
.append_list('[', ', ', ']', sequence)
return False
def isnotsurplus(self, item):
if not self.matchers:
if self.mismatch_description:
self.mismatch_description.append_text('not matched: ') \
.append_description_of(item)
return False
return True
def ismatched(self, item):
for index, matcher in enumerate(self.matchers):
if matcher.matches(item):
del self.matchers[index]
return True
if self.mismatch_description:
self.mismatch_description.append_text('not matched: ') \
.append_description_of(item)
return False
class IsSequenceContainingInAnyOrder(BaseMatcher):
def __init__(self, matchers):
self.matchers = matchers
def matches(self, sequence, mismatch_description=None):
try:
sequence = list(sequence)
matchsequence = MatchInAnyOrder(self.matchers, mismatch_description)
for item in sequence:
if not matchsequence.matches(item):
return False
return matchsequence.isfinished(sequence)
except TypeError:
if mismatch_description:
super(IsSequenceContainingInAnyOrder, self) \
.describe_mismatch(sequence, mismatch_description)
return False
def describe_mismatch(self, item, mismatch_description):
self.matches(item, mismatch_description)
def describe_to(self, description):
description.append_text('a sequence over ') \
.append_list('[', ', ', ']', self.matchers) \
.append_text(' in any order')
def contains_inanyorder(*items):
"""Matches if sequences's elements, in any order, satisfy a given list of
matchers.
:param match1,...: A comma-separated list of matchers.
This matcher iterates the evaluated sequence, seeing if each element
satisfies any of the given matchers. The matchers are tried from left to
right, and when a satisfied matcher is found, it is no longer a candidate
for the remaining elements. If a one-to-one correspondence is established
between elements and matchers, ``contains_inanyorder`` is satisfied.
Any argument that is not a matcher is implicitly wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
equality.
"""
matchers = []
for item in items:
matchers.append(wrap_matcher(item))
return IsSequenceContainingInAnyOrder(matchers)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/collection/issequence_containinginorder.py
================================================
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.hasmethod import hasmethod
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
class MatchingInOrder(object):
def __init__(self, matchers, mismatch_description):
self.matchers = matchers
self.mismatch_description = mismatch_description
self.next_match_index = 0
def matches(self, item):
return self.isnotsurplus(item) and self.ismatched(item)
def isfinished(self):
if self.next_match_index < len(self.matchers):
if self.mismatch_description:
self.mismatch_description.append_text('No item matched: ') \
.append_description_of(self.matchers[self.next_match_index])
return False
return True
def ismatched(self, item):
matcher = self.matchers[self.next_match_index]
if not matcher.matches(item):
if self.mismatch_description:
self.mismatch_description.append_text('item ' + str(self.next_match_index) + ': ')
matcher.describe_mismatch(item, self.mismatch_description)
return False
self.next_match_index += 1
return True
def isnotsurplus(self, item):
if len(self.matchers) <= self.next_match_index:
if self.mismatch_description:
self.mismatch_description.append_text('Not matched: ') \
.append_description_of(item)
return False
return True
class IsSequenceContainingInOrder(BaseMatcher):
def __init__(self, matchers):
self.matchers = matchers
def matches(self, sequence, mismatch_description=None):
try:
matchsequence = MatchingInOrder(self.matchers, mismatch_description)
for item in sequence:
if not matchsequence.matches(item):
return False
return matchsequence.isfinished()
except TypeError:
if mismatch_description:
super(IsSequenceContainingInOrder, self) \
.describe_mismatch(sequence, mismatch_description)
return False
def describe_mismatch(self, item, mismatch_description):
self.matches(item, mismatch_description)
def describe_to(self, description):
description.append_text('a sequence containing ') \
.append_list('[', ', ', ']', self.matchers)
def contains(*items):
"""Matches if sequence's elements satisfy a given list of matchers, in order.
:param match1,...: A comma-separated list of matchers.
This matcher iterates the evaluated sequence and a given list of matchers,
seeing if each element satisfies its corresponding matcher.
Any argument that is not a matcher is implicitly wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
equality.
"""
matchers = []
for item in items:
matchers.append(wrap_matcher(item))
return IsSequenceContainingInOrder(matchers)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/collection/issequence_onlycontaining.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.core.anyof import any_of
from hamcrest.core.helpers.hasmethod import hasmethod
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class IsSequenceOnlyContaining(BaseMatcher):
def __init__(self, matcher):
self.matcher = matcher
def _matches(self, sequence):
try:
sequence = list(sequence)
if len(sequence) == 0:
return False
for item in sequence:
if not self.matcher.matches(item):
return False
return True
except TypeError:
return False
def describe_to(self, description):
description.append_text('a sequence containing items matching ') \
.append_description_of(self.matcher)
def only_contains(*items):
"""Matches if each element of sequence satisfies any of the given matchers.
:param match1,...: A comma-separated list of matchers.
This matcher iterates the evaluated sequence, confirming whether each
element satisfies any of the given matchers.
Example::
only_contains(less_than(4))
will match ``[3,1,2]``.
Any argument that is not a matcher is implicitly wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
equality.
"""
matchers = []
for item in items:
matchers.append(wrap_matcher(item))
return IsSequenceOnlyContaining(any_of(*matchers))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/integration/__init__.py
================================================
from __future__ import absolute_import
"""Utilities for integrating Hamcrest with other libraries."""
from .match_equality import match_equality
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/integration/match_equality.py
================================================
from hamcrest.core.string_description import tostring
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
__author__ = "Chris Rose"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
__unittest = True
class EqualityWrapper(object):
def __init__(self, matcher):
self.matcher = matcher
def __eq__(self, object):
return self.matcher.matches(object)
def __str__(self):
return repr(self)
def __repr__(self):
return tostring(self.matcher)
def match_equality(matcher):
"""Wraps a matcher to define equality in terms of satisfying the matcher.
``match_equality`` allows Hamcrest matchers to be used in libraries that
are not Hamcrest-aware. They might use the equality operator::
assert match_equality(matcher) == object
Or they might provide a method that uses equality for its test::
library.method_that_tests_eq(match_equality(matcher))
One concrete example is integrating with the ``assert_called_with`` methods
in Michael Foord's `mock `_
library.
"""
return EqualityWrapper(wrap_matcher(matcher))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/number/__init__.py
================================================
from __future__ import absolute_import
"""Matchers that perform numeric comparisons."""
from .iscloseto import close_to
from .ordering_comparison import greater_than, greater_than_or_equal_to, less_than, less_than_or_equal_to
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/number/iscloseto.py
================================================
import six
from hamcrest.core.base_matcher import BaseMatcher
from math import fabs
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
def isnumeric(value):
"""Confirm that 'value' can be treated numerically; duck-test accordingly
"""
if isinstance(value, (float, complex) + six.integer_types):
return True
try:
_ = (fabs(value) + 0 - 0) * 1
return True
except ArithmeticError:
return True
except:
return False
return False
class IsCloseTo(BaseMatcher):
def __init__(self, value, delta):
if not isnumeric(value):
raise TypeError('IsCloseTo value must be numeric')
if not isnumeric(delta):
raise TypeError('IsCloseTo delta must be numeric')
self.value = value
self.delta = delta
def _matches(self, item):
if not isnumeric(item):
return False
return fabs(item - self.value) <= self.delta
def describe_mismatch(self, item, mismatch_description):
if not isnumeric(item):
super(IsCloseTo, self).describe_mismatch(item, mismatch_description)
else:
actual_delta = fabs(item - self.value)
mismatch_description.append_description_of(item) \
.append_text(' differed by ') \
.append_description_of(actual_delta)
def describe_to(self, description):
description.append_text('a numeric value within ') \
.append_description_of(self.delta) \
.append_text(' of ') \
.append_description_of(self.value)
def close_to(value, delta):
"""Matches if object is a number close to a given value, within a given
delta.
:param value: The value to compare against as the expected value.
:param delta: The maximum delta between the values for which the numbers
are considered close.
This matcher compares the evaluated object against ``value`` to see if the
difference is within a positive ``delta``.
Example::
close_to(3.0, 0.25)
"""
return IsCloseTo(value, delta)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/number/ordering_comparison.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
import operator
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class OrderingComparison(BaseMatcher):
def __init__(self, value, comparison_function, comparison_description):
self.value = value
self.comparison_function = comparison_function
self.comparison_description = comparison_description
def _matches(self, item):
return self.comparison_function(item, self.value)
def describe_to(self, description):
description.append_text('a value ') \
.append_text(self.comparison_description) \
.append_text(' ') \
.append_description_of(self.value)
def greater_than(value):
"""Matches if object is greater than a given value.
:param value: The value to compare against.
"""
return OrderingComparison(value, operator.gt, 'greater than')
def greater_than_or_equal_to(value):
"""Matches if object is greater than or equal to a given value.
:param value: The value to compare against.
"""
return OrderingComparison(value, operator.ge, 'greater than or equal to')
def less_than(value):
"""Matches if object is less than a given value.
:param value: The value to compare against.
"""
return OrderingComparison(value, operator.lt, 'less than')
def less_than_or_equal_to(value):
"""Matches if object is less than or equal to a given value.
:param value: The value to compare against.
"""
return OrderingComparison(value, operator.le, 'less than or equal to')
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/object/__init__.py
================================================
from __future__ import absolute_import
"""Matchers that inspect objects and classes."""
from .haslength import has_length
from .hasproperty import has_property, has_properties
from .hasstring import has_string
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/object/haslength.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.hasmethod import hasmethod
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class HasLength(BaseMatcher):
def __init__(self, len_matcher):
self.len_matcher = len_matcher
def _matches(self, item):
if not hasmethod(item, '__len__'):
return False
return self.len_matcher.matches(len(item))
def describe_mismatch(self, item, mismatch_description):
super(HasLength, self).describe_mismatch(item, mismatch_description)
if hasmethod(item, '__len__'):
mismatch_description.append_text(' with length of ') \
.append_description_of(len(item))
def describe_to(self, description):
description.append_text('an object with length of ') \
.append_description_of(self.len_matcher)
def has_length(match):
"""Matches if ``len(item)`` satisfies a given matcher.
:param match: The matcher to satisfy, or an expected value for
:py:func:`~hamcrest.core.core.isequal.equal_to` matching.
This matcher invokes the :py:func:`len` function on the evaluated object to
get its length, passing the result to a given matcher for evaluation.
If the ``match`` argument is not a matcher, it is implicitly wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
:equality.
Examples::
has_length(greater_than(6))
has_length(5)
"""
return HasLength(wrap_matcher(match))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/object/hasproperty.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core import anything
from hamcrest.core.core.allof import all_of
from hamcrest.core.string_description import StringDescription
from hamcrest.core.helpers.hasmethod import hasmethod
from hamcrest.core.helpers.wrap_matcher import wrap_matcher as wrap_shortcut
__author__ = "Chris Rose"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class IsObjectWithProperty(BaseMatcher):
def __init__(self, property_name, value_matcher):
self.property_name = property_name
self.value_matcher = value_matcher
def _matches(self, o):
if o is None:
return False
if not hasattr(o, self.property_name):
return False
value = getattr(o, self.property_name)
return self.value_matcher.matches(value)
def describe_to(self, description):
description.append_text("an object with a property '") \
.append_text(self.property_name) \
.append_text("' matching ") \
.append_description_of(self.value_matcher)
def describe_mismatch(self, item, mismatch_description):
if item is None:
mismatch_description.append_text('was None')
return
if not hasattr(item, self.property_name):
mismatch_description.append_value(item) \
.append_text(' did not have the ') \
.append_value(self.property_name) \
.append_text(' property')
return
mismatch_description.append_text('property ').append_value(self.property_name).append_text(' ')
value = getattr(item, self.property_name)
self.value_matcher.describe_mismatch(value, mismatch_description)
def __str__(self):
d = StringDescription()
self.describe_to(d)
return str(d)
def has_property(name, match=None):
"""Matches if object has a property with a given name whose value satisfies
a given matcher.
:param name: The name of the property.
:param match: Optional matcher to satisfy.
This matcher determines if the evaluated object has a property with a given
name. If no such property is found, ``has_property`` is not satisfied.
If the property is found, its value is passed to a given matcher for
evaluation. If the ``match`` argument is not a matcher, it is implicitly
wrapped in an :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to
check for equality.
If the ``match`` argument is not provided, the
:py:func:`~hamcrest.core.core.isanything.anything` matcher is used so that
``has_property`` is satisfied if a matching property is found.
Examples::
has_property('name', starts_with('J'))
has_property('name', 'Jon')
has_property('name')
"""
if match is None:
match = anything()
return IsObjectWithProperty(name, wrap_shortcut(match))
def has_properties(*keys_valuematchers, **kv_args):
"""Matches if an object has properties satisfying all of a dictionary
of string property names and corresponding value matchers.
:param matcher_dict: A dictionary mapping keys to associated value matchers,
or to expected values for
:py:func:`~hamcrest.core.core.isequal.equal_to` matching.
Note that the keys must be actual keys, not matchers. Any value argument
that is not a matcher is implicitly wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
equality.
Examples::
has_properties({'foo':equal_to(1), 'bar':equal_to(2)})
has_properties({'foo':1, 'bar':2})
``has_properties`` also accepts a list of keyword arguments:
.. function:: has_properties(keyword1=value_matcher1[, keyword2=value_matcher2[, ...]])
:param keyword1: A keyword to look up.
:param valueMatcher1: The matcher to satisfy for the value, or an expected
value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching.
Examples::
has_properties(foo=equal_to(1), bar=equal_to(2))
has_properties(foo=1, bar=2)
Finally, ``has_properties`` also accepts a list of alternating keys and their
value matchers:
.. function:: has_properties(key1, value_matcher1[, ...])
:param key1: A key (not a matcher) to look up.
:param valueMatcher1: The matcher to satisfy for the value, or an expected
value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching.
Examples::
has_properties('foo', equal_to(1), 'bar', equal_to(2))
has_properties('foo', 1, 'bar', 2)
"""
if len(keys_valuematchers) == 1:
try:
base_dict = keys_valuematchers[0].copy()
for key in base_dict:
base_dict[key] = wrap_shortcut(base_dict[key])
except AttributeError:
raise ValueError('single-argument calls to has_properties must pass a dict as the argument')
else:
if len(keys_valuematchers) % 2:
raise ValueError('has_properties requires key-value pairs')
base_dict = {}
for index in range(int(len(keys_valuematchers) / 2)):
base_dict[keys_valuematchers[2 * index]] = wrap_shortcut(keys_valuematchers[2 * index + 1])
for key, value in kv_args.items():
base_dict[key] = wrap_shortcut(value)
return all_of(*[has_property(property_name, property_value_matcher) for \
property_name, property_value_matcher in base_dict.items()])
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/object/hasstring.py
================================================
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class HasString(BaseMatcher):
def __init__(self, str_matcher):
self.str_matcher = str_matcher
def _matches(self, item):
return self.str_matcher.matches(str(item))
def describe_to(self, description):
description.append_text('an object with str ') \
.append_description_of(self.str_matcher)
def has_string(match):
"""Matches if ``str(item)`` satisfies a given matcher.
:param match: The matcher to satisfy, or an expected value for
:py:func:`~hamcrest.core.core.isequal.equal_to` matching.
This matcher invokes the :py:func:`str` function on the evaluated object to
get its length, passing the result to a given matcher for evaluation. If
the ``match`` argument is not a matcher, it is implicitly wrapped in an
:py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
equality.
Examples::
has_string(starts_with('foo'))
has_string('bar')
"""
return HasString(wrap_matcher(match))
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/text/__init__.py
================================================
from __future__ import absolute_import
"""Matchers that perform text comparisons."""
from .isequal_ignoring_case import equal_to_ignoring_case
from .isequal_ignoring_whitespace import equal_to_ignoring_whitespace
from .stringcontains import contains_string
from .stringendswith import ends_with
from .stringstartswith import starts_with
from .stringmatches import matches_regexp
from .stringcontainsinorder import string_contains_in_order
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/text/isequal_ignoring_case.py
================================================
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
from hamcrest.core.base_matcher import BaseMatcher
import six
class IsEqualIgnoringCase(BaseMatcher):
def __init__(self, string):
if not isinstance(string, six.string_types):
raise TypeError('IsEqualIgnoringCase requires string')
self.original_string = string
self.lowered_string = string.lower()
def _matches(self, item):
if not isinstance(item, six.string_types):
return False
return self.lowered_string == item.lower()
def describe_to(self, description):
description.append_description_of(self.original_string) \
.append_text(' ignoring case')
def equal_to_ignoring_case(string):
"""Matches if object is a string equal to a given string, ignoring case
differences.
:param string: The string to compare against as the expected value.
This matcher first checks whether the evaluated object is a string. If so,
it compares it with ``string``, ignoring differences of case.
Example::
equal_to_ignoring_case("hello world")
will match "heLLo WorlD".
"""
return IsEqualIgnoringCase(string)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/text/isequal_ignoring_whitespace.py
================================================
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
from hamcrest.core.base_matcher import BaseMatcher
import six
def stripspace(string):
result = ''
last_was_space = True
for character in string:
if character.isspace():
if not last_was_space:
result += ' '
last_was_space = True
else:
result += character
last_was_space = False
return result.strip()
class IsEqualIgnoringWhiteSpace(BaseMatcher):
def __init__(self, string):
if not isinstance(string, six.string_types):
raise TypeError('IsEqualIgnoringWhiteSpace requires string')
self.original_string = string
self.stripped_string = stripspace(string)
def _matches(self, item):
if not isinstance(item, six.string_types):
return False
return self.stripped_string == stripspace(item)
def describe_to(self, description):
description.append_description_of(self.original_string) \
.append_text(' ignoring whitespace')
def equal_to_ignoring_whitespace(string):
"""Matches if object is a string equal to a given string, ignoring
differences in whitespace.
:param string: The string to compare against as the expected value.
This matcher first checks whether the evaluated object is a string. If so,
it compares it with ``string``, ignoring differences in runs of whitespace.
Example::
equal_to_ignoring_whitespace("hello world")
will match ``"hello world"``.
"""
return IsEqualIgnoringWhiteSpace(string)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/text/stringcontains.py
================================================
from hamcrest.library.text.substringmatcher import SubstringMatcher
from hamcrest.core.helpers.hasmethod import hasmethod
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class StringContains(SubstringMatcher):
def __init__(self, substring):
super(StringContains, self).__init__(substring)
def _matches(self, item):
if not hasmethod(item, 'find'):
return False
return item.find(self.substring) >= 0
def relationship(self):
return 'containing'
def contains_string(substring):
"""Matches if object is a string containing a given string.
:param string: The string to search for.
This matcher first checks whether the evaluated object is a string. If so,
it checks whether it contains ``string``.
Example::
contains_string("def")
will match "abcdefg".
"""
return StringContains(substring)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/text/stringcontainsinorder.py
================================================
__author__ = "Romilly Cocking"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.hasmethod import hasmethod
import six
class StringContainsInOrder(BaseMatcher):
def __init__(self, *substrings):
for substring in substrings:
if not isinstance(substring, six.string_types):
raise TypeError(self.__class__.__name__
+ ' requires string arguments')
self.substrings = substrings
def _matches(self, item):
if not hasmethod(item, 'find'):
return False
from_index = 0
for substring in self.substrings:
from_index = item.find(substring, from_index)
if from_index == -1:
return False
return True
def describe_to(self, description):
description.append_list('a string containing ', ', ', ' in order',
self.substrings)
def string_contains_in_order(*substrings):
"""Matches if object is a string containing a given list of substrings in
relative order.
:param string1,...: A comma-separated list of strings.
This matcher first checks whether the evaluated object is a string. If so,
it checks whether it contains a given list of strings, in relative order to
each other. The searches are performed starting from the beginning of the
evaluated string.
Example::
string_contains_in_order("bc", "fg", "jkl")
will match "abcdefghijklm".
"""
return StringContainsInOrder(*substrings)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/text/stringendswith.py
================================================
from hamcrest.library.text.substringmatcher import SubstringMatcher
from hamcrest.core.helpers.hasmethod import hasmethod
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
class StringEndsWith(SubstringMatcher):
def __init__(self, substring):
super(StringEndsWith, self).__init__(substring)
def _matches(self, item):
if not hasmethod(item, 'endswith'):
return False
return item.endswith(self.substring)
def relationship(self):
return 'ending with'
def ends_with(string):
"""Matches if object is a string ending with a given string.
:param string: The string to search for.
This matcher first checks whether the evaluated object is a string. If so,
it checks if ``string`` matches the ending characters of the evaluated
object.
Example::
ends_with("bar")
will match "foobar".
"""
return StringEndsWith(string)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/text/stringmatches.py
================================================
__author__ = "Chris Rose"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
import re
import six
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.hasmethod import hasmethod
class StringMatchesPattern(BaseMatcher):
def __init__(self, pattern):
self.pattern = pattern
def describe_to(self, description):
description.append_text("a string matching '") \
.append_text(self.pattern.pattern) \
.append_text("'")
def _matches(self, item):
return self.pattern.search(item) is not None
def matches_regexp(pattern):
"""Matches if object is a string containing a match for a given regular
expression.
:param pattern: The regular expression to search for.
This matcher first checks whether the evaluated object is a string. If so,
it checks if the regular expression ``pattern`` matches anywhere within the
evaluated object.
"""
if isinstance(pattern, six.string_types):
pattern = re.compile(pattern)
return StringMatchesPattern(pattern)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/text/stringstartswith.py
================================================
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
from hamcrest.library.text.substringmatcher import SubstringMatcher
from hamcrest.core.helpers.hasmethod import hasmethod
class StringStartsWith(SubstringMatcher):
def __init__(self, substring):
super(StringStartsWith, self).__init__(substring)
def _matches(self, item):
if not hasmethod(item, 'startswith'):
return False
return item.startswith(self.substring)
def relationship(self):
return 'starting with'
def starts_with(substring):
"""Matches if object is a string starting with a given string.
:param string: The string to search for.
This matcher first checks whether the evaluated object is a string. If so,
it checks if ``string`` matches the beginning characters of the evaluated
object.
Example::
starts_with("foo")
will match "foobar".
"""
return StringStartsWith(substring)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hamcrest/library/text/substringmatcher.py
================================================
__author__ = "Jon Reid"
__copyright__ = "Copyright 2011 hamcrest.org"
__license__ = "BSD, see License.txt"
from hamcrest.core.base_matcher import BaseMatcher
import six
class SubstringMatcher(BaseMatcher):
def __init__(self, substring):
if not isinstance(substring, six.string_types):
raise TypeError(self.__class__.__name__ + ' requires string')
self.substring = substring
def describe_to(self, description):
description.append_text('a string ') \
.append_text(self.relationship()) \
.append_text(' ') \
.append_description_of(self.substring)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink/__init__.py
================================================
from ._url import (URL,
parse,
EncodedURL,
DecodedURL,
URLParseError,
register_scheme)
__all__ = [
"URL",
"parse",
"EncodedURL",
"DecodedURL",
"URLParseError",
"register_scheme",
]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink/_url.py
================================================
# -*- coding: utf-8 -*-
u"""Hyperlink provides Pythonic URL parsing, construction, and rendering.
Usage is straightforward::
>>> from hyperlink import URL
>>> url = URL.from_text(u'http://github.com/mahmoud/hyperlink?utm_source=docs')
>>> url.host
u'github.com'
>>> secure_url = url.replace(scheme=u'https')
>>> secure_url.get('utm_source')[0]
u'docs'
As seen here, the API revolves around the lightweight and immutable
:class:`URL` type, documented below.
"""
import re
import sys
import string
import socket
from unicodedata import normalize
try:
from socket import inet_pton
except ImportError:
inet_pton = None # defined below
try:
from collections.abc import Mapping
except ImportError: # Python 2
from collections import Mapping
# Note: IDNAError is a subclass of UnicodeError
from idna import encode as idna_encode, decode as idna_decode, IDNAError
if inet_pton is None:
# based on https://gist.github.com/nnemkin/4966028
# this code only applies on Windows Python 2.7
import ctypes
class _sockaddr(ctypes.Structure):
_fields_ = [("sa_family", ctypes.c_short),
("__pad1", ctypes.c_ushort),
("ipv4_addr", ctypes.c_byte * 4),
("ipv6_addr", ctypes.c_byte * 16),
("__pad2", ctypes.c_ulong)]
WSAStringToAddressA = ctypes.windll.ws2_32.WSAStringToAddressA
WSAAddressToStringA = ctypes.windll.ws2_32.WSAAddressToStringA
def inet_pton(address_family, ip_string):
addr = _sockaddr()
ip_string = ip_string.encode('ascii')
addr.sa_family = address_family
addr_size = ctypes.c_int(ctypes.sizeof(addr))
if WSAStringToAddressA(ip_string, address_family, None, ctypes.byref(addr), ctypes.byref(addr_size)) != 0:
raise socket.error(ctypes.FormatError())
if address_family == socket.AF_INET:
return ctypes.string_at(addr.ipv4_addr, 4)
if address_family == socket.AF_INET6:
return ctypes.string_at(addr.ipv6_addr, 16)
raise socket.error('unknown address family')
PY2 = (sys.version_info[0] == 2)
unicode = type(u'')
try:
unichr
except NameError:
unichr = chr # py3
NoneType = type(None)
# from boltons.typeutils
def make_sentinel(name='_MISSING', var_name=None):
"""Creates and returns a new **instance** of a new class, suitable for
usage as a "sentinel", a kind of singleton often used to indicate
a value is missing when ``None`` is a valid input.
Args:
name (str): Name of the Sentinel
var_name (str): Set this name to the name of the variable in
its respective module enable pickleability.
>>> make_sentinel(var_name='_MISSING')
_MISSING
The most common use cases here in boltons are as default values
for optional function arguments, partly because of its
less-confusing appearance in automatically generated
documentation. Sentinels also function well as placeholders in queues
and linked lists.
.. note::
By design, additional calls to ``make_sentinel`` with the same
values will not produce equivalent objects.
>>> make_sentinel('TEST') == make_sentinel('TEST')
False
>>> type(make_sentinel('TEST')) == type(make_sentinel('TEST'))
False
"""
class Sentinel(object):
def __init__(self):
self.name = name
self.var_name = var_name
def __repr__(self):
if self.var_name:
return self.var_name
return '%s(%r)' % (self.__class__.__name__, self.name)
if var_name:
def __reduce__(self):
return self.var_name
def __nonzero__(self):
return False
__bool__ = __nonzero__
return Sentinel()
_unspecified = _UNSET = make_sentinel('_UNSET')
# RFC 3986 Section 2.3, Unreserved URI Characters
# https://tools.ietf.org/html/rfc3986#section-2.3
_UNRESERVED_CHARS = frozenset('~-._0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
'abcdefghijklmnopqrstuvwxyz')
# URL parsing regex (based on RFC 3986 Appendix B, with modifications)
_URL_RE = re.compile(r'^((?P[^:/?#]+):)?'
r'((?P<_netloc_sep>//)'
r'(?P[^/?#]*))?'
r'(?P[^?#]*)'
r'(\?(?P[^#]*))?'
r'(#(?P.*))?$')
_SCHEME_RE = re.compile(r'^[a-zA-Z0-9+-.]*$')
_AUTHORITY_RE = re.compile(r'^(?:(?P[^@/?#]*)@)?'
r'(?P'
r'(?:\[(?P[^[\]/?#]*)\])'
r'|(?P[^:/?#[\]]*)'
r'|(?P.*?))?'
r'(?::(?P.*))?$')
_HEX_CHAR_MAP = dict([((a + b).encode('ascii'),
unichr(int(a + b, 16)).encode('charmap'))
for a in string.hexdigits for b in string.hexdigits])
_ASCII_RE = re.compile('([\x00-\x7f]+)')
# RFC 3986 section 2.2, Reserved Characters
# https://tools.ietf.org/html/rfc3986#section-2.2
_GEN_DELIMS = frozenset(u':/?#[]@')
_SUB_DELIMS = frozenset(u"!$&'()*+,;=")
_ALL_DELIMS = _GEN_DELIMS | _SUB_DELIMS
_USERINFO_SAFE = _UNRESERVED_CHARS | _SUB_DELIMS | set(u'%')
_USERINFO_DELIMS = _ALL_DELIMS - _USERINFO_SAFE
_PATH_SAFE = _USERINFO_SAFE | set(u':@')
_PATH_DELIMS = _ALL_DELIMS - _PATH_SAFE
_SCHEMELESS_PATH_SAFE = _PATH_SAFE - set(':')
_SCHEMELESS_PATH_DELIMS = _ALL_DELIMS - _SCHEMELESS_PATH_SAFE
_FRAGMENT_SAFE = _UNRESERVED_CHARS | _PATH_SAFE | set(u'/?')
_FRAGMENT_DELIMS = _ALL_DELIMS - _FRAGMENT_SAFE
_QUERY_VALUE_SAFE = _UNRESERVED_CHARS | _FRAGMENT_SAFE - set(u'&+')
_QUERY_VALUE_DELIMS = _ALL_DELIMS - _QUERY_VALUE_SAFE
_QUERY_KEY_SAFE = _UNRESERVED_CHARS | _QUERY_VALUE_SAFE - set(u'=')
_QUERY_KEY_DELIMS = _ALL_DELIMS - _QUERY_KEY_SAFE
def _make_decode_map(delims, allow_percent=False):
ret = dict(_HEX_CHAR_MAP)
if not allow_percent:
delims = set(delims) | set([u'%'])
for delim in delims:
_hexord = '{0:02X}'.format(ord(delim)).encode('ascii')
_hexord_lower = _hexord.lower()
ret.pop(_hexord)
if _hexord != _hexord_lower:
ret.pop(_hexord_lower)
return ret
def _make_quote_map(safe_chars):
ret = {}
# v is included in the dict for py3 mostly, because bytestrings
# are iterables of ints, of course!
for i, v in zip(range(256), range(256)):
c = chr(v)
if c in safe_chars:
ret[c] = ret[v] = c
else:
ret[c] = ret[v] = '%{0:02X}'.format(i)
return ret
_USERINFO_PART_QUOTE_MAP = _make_quote_map(_USERINFO_SAFE)
_USERINFO_DECODE_MAP = _make_decode_map(_USERINFO_DELIMS)
_PATH_PART_QUOTE_MAP = _make_quote_map(_PATH_SAFE)
_SCHEMELESS_PATH_PART_QUOTE_MAP = _make_quote_map(_SCHEMELESS_PATH_SAFE)
_PATH_DECODE_MAP = _make_decode_map(_PATH_DELIMS)
_QUERY_KEY_QUOTE_MAP = _make_quote_map(_QUERY_KEY_SAFE)
_QUERY_KEY_DECODE_MAP = _make_decode_map(_QUERY_KEY_DELIMS)
_QUERY_VALUE_QUOTE_MAP = _make_quote_map(_QUERY_VALUE_SAFE)
_QUERY_VALUE_DECODE_MAP = _make_decode_map(_QUERY_VALUE_DELIMS)
_FRAGMENT_QUOTE_MAP = _make_quote_map(_FRAGMENT_SAFE)
_FRAGMENT_DECODE_MAP = _make_decode_map(_FRAGMENT_DELIMS)
_UNRESERVED_QUOTE_MAP = _make_quote_map(_UNRESERVED_CHARS)
_UNRESERVED_DECODE_MAP = dict([(k, v) for k, v in _HEX_CHAR_MAP.items()
if v.decode('ascii', 'replace')
in _UNRESERVED_CHARS])
_ROOT_PATHS = frozenset(((), (u'',)))
def _encode_reserved(text, maximal=True):
"""A very comprehensive percent encoding for encoding all
delimiters. Used for arguments to DecodedURL, where a % means a
percent sign, and not the character used by URLs for escaping
bytes.
"""
if maximal:
bytestr = normalize('NFC', text).encode('utf8')
return u''.join([_UNRESERVED_QUOTE_MAP[b] for b in bytestr])
return u''.join([_UNRESERVED_QUOTE_MAP[t] if t in _UNRESERVED_CHARS
else t for t in text])
def _encode_path_part(text, maximal=True):
"Percent-encode a single segment of a URL path."
if maximal:
bytestr = normalize('NFC', text).encode('utf8')
return u''.join([_PATH_PART_QUOTE_MAP[b] for b in bytestr])
return u''.join([_PATH_PART_QUOTE_MAP[t] if t in _PATH_DELIMS else t
for t in text])
def _encode_schemeless_path_part(text, maximal=True):
"""Percent-encode the first segment of a URL path for a URL without a
scheme specified.
"""
if maximal:
bytestr = normalize('NFC', text).encode('utf8')
return u''.join([_SCHEMELESS_PATH_PART_QUOTE_MAP[b] for b in bytestr])
return u''.join([_SCHEMELESS_PATH_PART_QUOTE_MAP[t]
if t in _SCHEMELESS_PATH_DELIMS else t for t in text])
def _encode_path_parts(text_parts, rooted=False, has_scheme=True,
has_authority=True, joined=True, maximal=True):
"""
Percent-encode a tuple of path parts into a complete path.
Setting *maximal* to False percent-encodes only the reserved
characters that are syntactically necessary for serialization,
preserving any IRI-style textual data.
Leaving *maximal* set to its default True percent-encodes
everything required to convert a portion of an IRI to a portion of
a URI.
RFC 3986 3.3:
If a URI contains an authority component, then the path component
must either be empty or begin with a slash ("/") character. If a URI
does not contain an authority component, then the path cannot begin
with two slash characters ("//"). In addition, a URI reference
(Section 4.1) may be a relative-path reference, in which case the
first path segment cannot contain a colon (":") character.
"""
if not text_parts:
return u'' if joined else text_parts
if rooted:
text_parts = (u'',) + text_parts
# elif has_authority and text_parts:
# raise Exception('see rfc above') # TODO: too late to fail like this?
encoded_parts = []
if has_scheme:
encoded_parts = [_encode_path_part(part, maximal=maximal)
if part else part for part in text_parts]
else:
encoded_parts = [_encode_schemeless_path_part(text_parts[0])]
encoded_parts.extend([_encode_path_part(part, maximal=maximal)
if part else part for part in text_parts[1:]])
if joined:
return u'/'.join(encoded_parts)
return tuple(encoded_parts)
def _encode_query_key(text, maximal=True):
"""
Percent-encode a single query string key or value.
"""
if maximal:
bytestr = normalize('NFC', text).encode('utf8')
return u''.join([_QUERY_KEY_QUOTE_MAP[b] for b in bytestr])
return u''.join([_QUERY_KEY_QUOTE_MAP[t] if t in _QUERY_KEY_DELIMS else t
for t in text])
def _encode_query_value(text, maximal=True):
"""
Percent-encode a single query string key or value.
"""
if maximal:
bytestr = normalize('NFC', text).encode('utf8')
return u''.join([_QUERY_VALUE_QUOTE_MAP[b] for b in bytestr])
return u''.join([_QUERY_VALUE_QUOTE_MAP[t]
if t in _QUERY_VALUE_DELIMS else t for t in text])
def _encode_fragment_part(text, maximal=True):
"""Quote the fragment part of the URL. Fragments don't have
subdelimiters, so the whole URL fragment can be passed.
"""
if maximal:
bytestr = normalize('NFC', text).encode('utf8')
return u''.join([_FRAGMENT_QUOTE_MAP[b] for b in bytestr])
return u''.join([_FRAGMENT_QUOTE_MAP[t] if t in _FRAGMENT_DELIMS else t
for t in text])
def _encode_userinfo_part(text, maximal=True):
"""Quote special characters in either the username or password
section of the URL.
"""
if maximal:
bytestr = normalize('NFC', text).encode('utf8')
return u''.join([_USERINFO_PART_QUOTE_MAP[b] for b in bytestr])
return u''.join([_USERINFO_PART_QUOTE_MAP[t] if t in _USERINFO_DELIMS
else t for t in text])
# This port list painstakingly curated by hand searching through
# https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml
# and
# https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
SCHEME_PORT_MAP = {'acap': 674, 'afp': 548, 'dict': 2628, 'dns': 53,
'file': None, 'ftp': 21, 'git': 9418, 'gopher': 70,
'http': 80, 'https': 443, 'imap': 143, 'ipp': 631,
'ipps': 631, 'irc': 194, 'ircs': 6697, 'ldap': 389,
'ldaps': 636, 'mms': 1755, 'msrp': 2855, 'msrps': None,
'mtqp': 1038, 'nfs': 111, 'nntp': 119, 'nntps': 563,
'pop': 110, 'prospero': 1525, 'redis': 6379, 'rsync': 873,
'rtsp': 554, 'rtsps': 322, 'rtspu': 5005, 'sftp': 22,
'smb': 445, 'snmp': 161, 'ssh': 22, 'steam': None,
'svn': 3690, 'telnet': 23, 'ventrilo': 3784, 'vnc': 5900,
'wais': 210, 'ws': 80, 'wss': 443, 'xmpp': None}
# This list of schemes that don't use authorities is also from the link above.
NO_NETLOC_SCHEMES = set(['urn', 'about', 'bitcoin', 'blob', 'data', 'geo',
'magnet', 'mailto', 'news', 'pkcs11',
'sip', 'sips', 'tel'])
# As of Mar 11, 2017, there were 44 netloc schemes, and 13 non-netloc
def register_scheme(text, uses_netloc=True, default_port=None):
"""Registers new scheme information, resulting in correct port and
slash behavior from the URL object. There are dozens of standard
schemes preregistered, so this function is mostly meant for
proprietary internal customizations or stopgaps on missing
standards information. If a scheme seems to be missing, please
`file an issue`_!
Args:
text (unicode): Text representing the scheme.
(the 'http' in 'http://hatnote.com')
uses_netloc (bool): Does the scheme support specifying a
network host? For instance, "http" does, "mailto" does
not. Defaults to True.
default_port (int): The default port, if any, for netloc-using
schemes.
.. _file an issue: https://github.com/mahmoud/hyperlink/issues
"""
text = text.lower()
if default_port is not None:
try:
default_port = int(default_port)
except (ValueError, TypeError):
raise ValueError('default_port expected integer or None, not %r'
% (default_port,))
if uses_netloc is True:
SCHEME_PORT_MAP[text] = default_port
elif uses_netloc is False:
if default_port is not None:
raise ValueError('unexpected default port while specifying'
' non-netloc scheme: %r' % default_port)
NO_NETLOC_SCHEMES.add(text)
else:
raise ValueError('uses_netloc expected bool, not: %r' % uses_netloc)
return
def scheme_uses_netloc(scheme, default=None):
"""Whether or not a URL uses :code:`:` or :code:`://` to separate the
scheme from the rest of the URL depends on the scheme's own
standard definition. There is no way to infer this behavior
from other parts of the URL. A scheme either supports network
locations or it does not.
The URL type's approach to this is to check for explicitly
registered schemes, with common schemes like HTTP
preregistered. This is the same approach taken by
:mod:`urlparse`.
URL adds two additional heuristics if the scheme as a whole is
not registered. First, it attempts to check the subpart of the
scheme after the last ``+`` character. This adds intuitive
behavior for schemes like ``git+ssh``. Second, if a URL with
an unrecognized scheme is loaded, it will maintain the
separator it sees.
"""
if not scheme:
return False
scheme = scheme.lower()
if scheme in SCHEME_PORT_MAP:
return True
if scheme in NO_NETLOC_SCHEMES:
return False
if scheme.split('+')[-1] in SCHEME_PORT_MAP:
return True
return default
class URLParseError(ValueError):
"""Exception inheriting from :exc:`ValueError`, raised when failing to
parse a URL. Mostly raised on invalid ports and IPv6 addresses.
"""
pass
def _optional(argument, default):
if argument is _UNSET:
return default
else:
return argument
def _typecheck(name, value, *types):
"""
Check that the given *value* is one of the given *types*, or raise an
exception describing the problem using *name*.
"""
if not types:
raise ValueError('expected one or more types, maybe use _textcheck?')
if not isinstance(value, types):
raise TypeError("expected %s for %s, got %r"
% (" or ".join([t.__name__ for t in types]),
name, value))
return value
def _textcheck(name, value, delims=frozenset(), nullable=False):
if not isinstance(value, unicode):
if nullable and value is None:
return value # used by query string values
else:
str_name = "unicode" if PY2 else "str"
exp = str_name + ' or NoneType' if nullable else str_name
raise TypeError('expected %s for %s, got %r' % (exp, name, value))
if delims and set(value) & set(delims): # TODO: test caching into regexes
raise ValueError('one or more reserved delimiters %s present in %s: %r'
% (''.join(delims), name, value))
return value
def iter_pairs(iterable):
"""
Iterate over the (key, value) pairs in ``iterable``.
This handles dictionaries sensibly, and falls back to assuming the
iterable yields (key, value) pairs. This behaviour is similar to
what Python's ``dict()`` constructor does.
"""
if isinstance(iterable, Mapping):
iterable = iterable.items()
return iter(iterable)
def _decode_unreserved(text, normalize_case=False, encode_stray_percents=False):
return _percent_decode(text, normalize_case=normalize_case,
encode_stray_percents=encode_stray_percents,
_decode_map=_UNRESERVED_DECODE_MAP)
def _decode_userinfo_part(text, normalize_case=False, encode_stray_percents=False):
return _percent_decode(text, normalize_case=normalize_case,
encode_stray_percents=encode_stray_percents,
_decode_map=_USERINFO_DECODE_MAP)
def _decode_path_part(text, normalize_case=False, encode_stray_percents=False):
"""
>>> _decode_path_part(u'%61%77%2f%7a')
u'aw%2fz'
>>> _decode_path_part(u'%61%77%2f%7a', normalize_case=True)
u'aw%2Fz'
"""
return _percent_decode(text, normalize_case=normalize_case,
encode_stray_percents=encode_stray_percents,
_decode_map=_PATH_DECODE_MAP)
def _decode_query_key(text, normalize_case=False, encode_stray_percents=False):
return _percent_decode(text, normalize_case=normalize_case,
encode_stray_percents=encode_stray_percents,
_decode_map=_QUERY_KEY_DECODE_MAP)
def _decode_query_value(text, normalize_case=False, encode_stray_percents=False):
return _percent_decode(text, normalize_case=normalize_case,
encode_stray_percents=encode_stray_percents,
_decode_map=_QUERY_VALUE_DECODE_MAP)
def _decode_fragment_part(text, normalize_case=False, encode_stray_percents=False):
return _percent_decode(text, normalize_case=normalize_case,
encode_stray_percents=encode_stray_percents,
_decode_map=_FRAGMENT_DECODE_MAP)
def _percent_decode(text, normalize_case=False, subencoding='utf-8',
raise_subencoding_exc=False, encode_stray_percents=False,
_decode_map=_HEX_CHAR_MAP):
"""Convert percent-encoded text characters to their normal,
human-readable equivalents.
All characters in the input text must be encodable by
*subencoding*. All special characters underlying the values in the
percent-encoding must be decodable as *subencoding*. If a
non-*subencoding*-valid string is passed, the original text is
returned with no changes applied.
Only called by field-tailored variants, e.g.,
:func:`_decode_path_part`, as every percent-encodable part of the
URL has characters which should not be percent decoded.
>>> _percent_decode(u'abc%20def')
u'abc def'
Args:
text (unicode): Text with percent-encoding present.
normalize_case (bool): Whether undecoded percent segments, such
as encoded delimiters, should be uppercased, per RFC 3986
Section 2.1. See :func:`_decode_path_part` for an example.
subencoding (unicode): The name of the encoding underlying the
percent-encoding. Pass `False` to get back raw bytes.
raise_subencoding_exc (bool): Whether an error in decoding the bytes
underlying the percent-decoding should be raised.
Returns:
unicode: The percent-decoded version of *text*, decoded by
*subencoding*, unless `subencoding=False` which returns bytes.
"""
try:
quoted_bytes = text.encode('utf-8' if subencoding is False else subencoding)
except UnicodeEncodeError:
return text
bits = quoted_bytes.split(b'%')
if len(bits) == 1:
return text
res = [bits[0]]
append = res.append
for item in bits[1:]:
hexpair, rest = item[:2], item[2:]
try:
append(_decode_map[hexpair])
append(rest)
except KeyError:
pair_is_hex = hexpair in _HEX_CHAR_MAP
if pair_is_hex or not encode_stray_percents:
append(b'%')
else:
# if it's undecodable, treat as a real percent sign,
# which is reserved (because it wasn't in the
# context-aware _decode_map passed in), and should
# stay in an encoded state.
append(b'%25')
if normalize_case and pair_is_hex:
append(hexpair.upper())
append(rest)
else:
append(item)
unquoted_bytes = b''.join(res)
if subencoding is False:
return unquoted_bytes
try:
return unquoted_bytes.decode(subencoding)
except UnicodeDecodeError:
if raise_subencoding_exc:
raise
return text
def _decode_host(host):
"""Decode a host from ASCII-encodable text to IDNA-decoded text. If
the host text is not ASCII, it is returned unchanged, as it is
presumed that it is already IDNA-decoded.
Some technical details: _decode_host is built on top of the "idna"
package, which has some quirks:
Capital letters are not valid IDNA2008. The idna package will
raise an exception like this on capital letters:
> idna.core.InvalidCodepoint: Codepoint U+004B at position 1 ... not allowed
However, if a segment of a host (i.e., something in
url.host.split('.')) is already ASCII, idna doesn't perform its
usual checks. In fact, for capital letters it automatically
lowercases them.
This check and some other functionality can be bypassed by passing
uts46=True to idna.encode/decode. This allows a more permissive and
convenient interface. So far it seems like the balanced approach.
Example output (from idna==2.6):
>> idna.encode(u'mahmöud.io')
'xn--mahmud-zxa.io'
>> idna.encode(u'Mahmöud.io')
Traceback (most recent call last):
File "", line 1, in
File "/home/mahmoud/virtualenvs/hyperlink/local/lib/python2.7/site-packages/idna/core.py", line 355, in encode
result.append(alabel(label))
File "/home/mahmoud/virtualenvs/hyperlink/local/lib/python2.7/site-packages/idna/core.py", line 276, in alabel
check_label(label)
File "/home/mahmoud/virtualenvs/hyperlink/local/lib/python2.7/site-packages/idna/core.py", line 253, in check_label
raise InvalidCodepoint('Codepoint {0} at position {1} of {2} not allowed'.format(_unot(cp_value), pos+1, repr(label)))
idna.core.InvalidCodepoint: Codepoint U+004D at position 1 of u'Mahm\xf6ud' not allowed
>> idna.encode(u'Mahmoud.io')
'Mahmoud.io'
# Similar behavior for decodes below
>> idna.decode(u'Mahmoud.io')
u'mahmoud.io
>> idna.decode(u'Méhmoud.io', uts46=True)
u'm\xe9hmoud.io'
"""
if not host:
return u''
try:
host_bytes = host.encode("ascii")
except UnicodeEncodeError:
host_text = host
else:
try:
host_text = idna_decode(host_bytes, uts46=True)
except ValueError:
# only reached on "narrow" (UCS-2) Python builds <3.4, see #7
# NOTE: not going to raise here, because there's no
# ambiguity in the IDNA, and the host is still
# technically usable
host_text = host
return host_text
def _resolve_dot_segments(path):
"""Normalize the URL path by resolving segments of '.' and '..'. For
more details, see `RFC 3986 section 5.2.4, Remove Dot Segments`_.
Args:
path (list): path segments in string form
Returns:
list: a new list of path segments with the '.' and '..' elements
removed and resolved.
.. _RFC 3986 section 5.2.4, Remove Dot Segments: https://tools.ietf.org/html/rfc3986#section-5.2.4
"""
segs = []
for seg in path:
if seg == u'.':
pass
elif seg == u'..':
if segs:
segs.pop()
else:
segs.append(seg)
if list(path[-1:]) in ([u'.'], [u'..']):
segs.append(u'')
return segs
def parse_host(host):
"""Parse the host into a tuple of ``(family, host)``, where family
is the appropriate :mod:`socket` module constant when the host is
an IP address. Family is ``None`` when the host is not an IP.
Will raise :class:`URLParseError` on invalid IPv6 constants.
Returns:
tuple: family (socket constant or None), host (string)
>>> parse_host('googlewebsite.com') == (None, 'googlewebsite.com')
True
>>> parse_host('::1') == (socket.AF_INET6, '::1')
True
>>> parse_host('192.168.1.1') == (socket.AF_INET, '192.168.1.1')
True
"""
if not host:
return None, u''
if u':' in host:
try:
inet_pton(socket.AF_INET6, host)
except socket.error as se:
raise URLParseError('invalid IPv6 host: %r (%r)' % (host, se))
except UnicodeEncodeError:
pass # TODO: this can't be a real host right?
else:
family = socket.AF_INET6
return family, host
try:
inet_pton(socket.AF_INET, host)
except (socket.error, UnicodeEncodeError):
family = None # not an IP
else:
family = socket.AF_INET
return family, host
class URL(object):
"""From blogs to billboards, URLs are so common, that it's easy to
overlook their complexity and power. With hyperlink's
:class:`URL` type, working with URLs doesn't have to be hard.
URLs are made of many parts. Most of these parts are officially
named in `RFC 3986`_ and this diagram may prove handy in identifying
them::
foo://user:pass@example.com:8042/over/there?name=ferret#nose
\_/ \_______/ \_________/ \__/\_________/ \_________/ \__/
| | | | | | |
scheme userinfo host port path query fragment
While :meth:`~URL.from_text` is used for parsing whole URLs, the
:class:`URL` constructor builds a URL from the individual
components, like so::
>>> from hyperlink import URL
>>> url = URL(scheme=u'https', host=u'example.com', path=[u'hello', u'world'])
>>> print(url.to_text())
https://example.com/hello/world
The constructor runs basic type checks. All strings are expected
to be decoded (:class:`unicode` in Python 2). All arguments are
optional, defaulting to appropriately empty values. A full list of
constructor arguments is below.
Args:
scheme (unicode): The text name of the scheme.
host (unicode): The host portion of the network location
port (int): The port part of the network location. If
``None`` or no port is passed, the port will default to
the default port of the scheme, if it is known. See the
``SCHEME_PORT_MAP`` and :func:`register_default_port`
for more info.
path (tuple): A tuple of strings representing the
slash-separated parts of the path.
query (tuple): The query parameters, as a dictionary or
as an iterable of key-value pairs.
fragment (unicode): The fragment part of the URL.
rooted (bool): Whether or not the path begins with a slash.
userinfo (unicode): The username or colon-separated
username:password pair.
uses_netloc (bool): Indicates whether two slashes appear
between the scheme and the host (``http://eg.com`` vs
``mailto:e@g.com``). Set automatically based on scheme.
All of these parts are also exposed as read-only attributes of
URL instances, along with several useful methods.
.. _RFC 3986: https://tools.ietf.org/html/rfc3986
.. _RFC 3987: https://tools.ietf.org/html/rfc3987
"""
def __init__(self, scheme=None, host=None, path=(), query=(), fragment=u'',
port=None, rooted=None, userinfo=u'', uses_netloc=None):
if host is not None and scheme is None:
scheme = u'http' # TODO: why
if port is None:
port = SCHEME_PORT_MAP.get(scheme)
if host and query and not path:
# per RFC 3986 6.2.3, "a URI that uses the generic syntax
# for authority with an empty path should be normalized to
# a path of '/'."
path = (u'',)
# Now that we're done detecting whether they were passed, we can set
# them to their defaults:
if scheme is None:
scheme = u''
if host is None:
host = u''
if rooted is None:
rooted = bool(host)
# Set attributes.
self._scheme = _textcheck("scheme", scheme)
if self._scheme:
if not _SCHEME_RE.match(self._scheme):
raise ValueError('invalid scheme: %r. Only alphanumeric, "+",'
' "-", and "." allowed. Did you meant to call'
' %s.from_text()?'
% (self._scheme, self.__class__.__name__))
_, self._host = parse_host(_textcheck('host', host, '/?#@'))
if isinstance(path, unicode):
raise TypeError("expected iterable of text for path, not: %r"
% (path,))
self._path = tuple((_textcheck("path segment", segment, '/?#')
for segment in path))
self._query = tuple(
(_textcheck("query parameter name", k, '&=#'),
_textcheck("query parameter value", v, '', nullable=True))
for k, v in iter_pairs(query))
self._fragment = _textcheck("fragment", fragment)
self._port = _typecheck("port", port, int, NoneType)
self._rooted = _typecheck("rooted", rooted, bool)
self._userinfo = _textcheck("userinfo", userinfo, '/?#@')
uses_netloc = scheme_uses_netloc(self._scheme, uses_netloc)
self._uses_netloc = _typecheck("uses_netloc",
uses_netloc, bool, NoneType)
return
def get_decoded_url(self, lazy=False):
try:
return self._decoded_url
except AttributeError:
self._decoded_url = DecodedURL(self, lazy=lazy)
return self._decoded_url
@property
def scheme(self):
"""The scheme is a string, and the first part of an absolute URL, the
part before the first colon, and the part which defines the
semantics of the rest of the URL. Examples include "http",
"https", "ssh", "file", "mailto", and many others. See
:func:`~hyperlink.register_scheme()` for more info.
"""
return self._scheme
@property
def host(self):
"""The host is a string, and the second standard part of an absolute
URL. When present, a valid host must be a domain name, or an
IP (v4 or v6). It occurs before the first slash, or the second
colon, if a :attr:`~hyperlink.URL.port` is provided.
"""
return self._host
@property
def port(self):
"""The port is an integer that is commonly used in connecting to the
:attr:`host`, and almost never appears without it.
When not present in the original URL, this attribute defaults
to the scheme's default port. If the scheme's default port is
not known, and the port is not provided, this attribute will
be set to None.
>>> URL.from_text(u'http://example.com/pa/th').port
80
>>> URL.from_text(u'foo://example.com/pa/th').port
>>> URL.from_text(u'foo://example.com:8042/pa/th').port
8042
.. note::
Per the standard, when the port is the same as the schemes
default port, it will be omitted in the text URL.
"""
return self._port
@property
def path(self):
"""A tuple of strings, created by splitting the slash-separated
hierarchical path. Started by the first slash after the host,
terminated by a "?", which indicates the start of the
:attr:`~hyperlink.URL.query` string.
"""
return self._path
@property
def query(self):
"""Tuple of pairs, created by splitting the ampersand-separated
mapping of keys and optional values representing
non-hierarchical data used to identify the resource. Keys are
always strings. Values are strings when present, or None when
missing.
For more operations on the mapping, see
:meth:`~hyperlink.URL.get()`, :meth:`~hyperlink.URL.add()`,
:meth:`~hyperlink.URL.set()`, and
:meth:`~hyperlink.URL.delete()`.
"""
return self._query
@property
def fragment(self):
"""A string, the last part of the URL, indicated by the first "#"
after the :attr:`~hyperlink.URL.path` or
:attr:`~hyperlink.URL.query`. Enables indirect identification
of a secondary resource, like an anchor within an HTML page.
"""
return self._fragment
@property
def rooted(self):
"""Whether or not the path starts with a forward slash (``/``).
This is taken from the terminology in the BNF grammar,
specifically the "path-rootless", rule, since "absolute path"
and "absolute URI" are somewhat ambiguous. :attr:`path` does
not contain the implicit prefixed ``"/"`` since that is
somewhat awkward to work with.
"""
return self._rooted
@property
def userinfo(self):
"""The colon-separated string forming the username-password
combination.
"""
return self._userinfo
@property
def uses_netloc(self):
"""
"""
return self._uses_netloc
@property
def user(self):
"""
The user portion of :attr:`~hyperlink.URL.userinfo`.
"""
return self.userinfo.split(u':')[0]
def authority(self, with_password=False, **kw):
"""Compute and return the appropriate host/port/userinfo combination.
>>> url = URL.from_text(u'http://user:pass@localhost:8080/a/b?x=y')
>>> url.authority()
u'user:@localhost:8080'
>>> url.authority(with_password=True)
u'user:pass@localhost:8080'
Args:
with_password (bool): Whether the return value of this
method include the password in the URL, if it is
set. Defaults to False.
Returns:
str: The authority (network location and user information) portion
of the URL.
"""
# first, a bit of twisted compat
with_password = kw.pop('includeSecrets', with_password)
if kw:
raise TypeError('got unexpected keyword arguments: %r' % kw.keys())
host = self.host
if ':' in host:
hostport = ['[' + host + ']']
else:
hostport = [self.host]
if self.port != SCHEME_PORT_MAP.get(self.scheme):
hostport.append(unicode(self.port))
authority = []
if self.userinfo:
userinfo = self.userinfo
if not with_password and u":" in userinfo:
userinfo = userinfo[:userinfo.index(u":") + 1]
authority.append(userinfo)
authority.append(u":".join(hostport))
return u"@".join(authority)
def __eq__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
for attr in ['scheme', 'userinfo', 'host', 'query',
'fragment', 'port', 'uses_netloc']:
if getattr(self, attr) != getattr(other, attr):
return False
if self.path == other.path or (self.path in _ROOT_PATHS
and other.path in _ROOT_PATHS):
return True
return False
def __ne__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return not self.__eq__(other)
def __hash__(self):
return hash((self.__class__, self.scheme, self.userinfo, self.host,
self.path, self.query, self.fragment, self.port,
self.rooted, self.uses_netloc))
@property
def absolute(self):
"""Whether or not the URL is "absolute". Absolute URLs are complete
enough to resolve to a network resource without being relative
to a base URI.
>>> URL.from_text(u'http://wikipedia.org/').absolute
True
>>> URL.from_text(u'?a=b&c=d').absolute
False
Absolute URLs must have both a scheme and a host set.
"""
return bool(self.scheme and self.host)
def replace(self, scheme=_UNSET, host=_UNSET, path=_UNSET, query=_UNSET,
fragment=_UNSET, port=_UNSET, rooted=_UNSET, userinfo=_UNSET,
uses_netloc=_UNSET):
""":class:`URL` objects are immutable, which means that attributes
are designed to be set only once, at construction. Instead of
modifying an existing URL, one simply creates a copy with the
desired changes.
If any of the following arguments is omitted, it defaults to
the value on the current URL.
Args:
scheme (unicode): The text name of the scheme.
host (unicode): The host portion of the network location
port (int): The port part of the network location.
path (tuple): A tuple of strings representing the
slash-separated parts of the path.
query (tuple): The query parameters, as a tuple of
key-value pairs.
query (tuple): The query parameters, as a dictionary or
as an iterable of key-value pairs.
fragment (unicode): The fragment part of the URL.
rooted (bool): Whether or not the path begins with a slash.
userinfo (unicode): The username or colon-separated
username:password pair.
uses_netloc (bool): Indicates whether two slashes appear
between the scheme and the host (``http://eg.com`` vs
``mailto:e@g.com``)
Returns:
URL: a copy of the current :class:`URL`, with new values for
parameters passed.
"""
return self.__class__(
scheme=_optional(scheme, self.scheme),
host=_optional(host, self.host),
path=_optional(path, self.path),
query=_optional(query, self.query),
fragment=_optional(fragment, self.fragment),
port=_optional(port, self.port),
rooted=_optional(rooted, self.rooted),
userinfo=_optional(userinfo, self.userinfo),
uses_netloc=_optional(uses_netloc, self.uses_netloc)
)
@classmethod
def from_text(cls, text):
"""Whereas the :class:`URL` constructor is useful for constructing
URLs from parts, :meth:`~URL.from_text` supports parsing whole
URLs from their string form::
>>> URL.from_text(u'http://example.com')
URL.from_text(u'http://example.com')
>>> URL.from_text(u'?a=b&x=y')
URL.from_text(u'?a=b&x=y')
As you can see above, it's also used as the :func:`repr` of
:class:`URL` objects. The natural counterpart to
:func:`~URL.to_text()`. This method only accepts *text*, so be
sure to decode those bytestrings.
Args:
text (unicode): A valid URL string.
Returns:
URL: The structured object version of the parsed string.
.. note::
Somewhat unexpectedly, URLs are a far more permissive
format than most would assume. Many strings which don't
look like URLs are still valid URLs. As a result, this
method only raises :class:`URLParseError` on invalid port
and IPv6 values in the host portion of the URL.
"""
um = _URL_RE.match(_textcheck('text', text))
try:
gs = um.groupdict()
except AttributeError:
raise URLParseError('could not parse url: %r' % text)
au_text = gs['authority'] or u''
au_m = _AUTHORITY_RE.match(au_text)
try:
au_gs = au_m.groupdict()
except AttributeError:
raise URLParseError('invalid authority %r in url: %r'
% (au_text, text))
if au_gs['bad_host']:
raise URLParseError('invalid host %r in url: %r'
% (au_gs['bad_host'], text))
userinfo = au_gs['userinfo'] or u''
host = au_gs['ipv6_host'] or au_gs['plain_host']
port = au_gs['port']
if port is not None:
try:
port = int(port)
except ValueError:
if not port: # TODO: excessive?
raise URLParseError('port must not be empty: %r' % au_text)
raise URLParseError('expected integer for port, not %r' % port)
scheme = gs['scheme'] or u''
fragment = gs['fragment'] or u''
uses_netloc = bool(gs['_netloc_sep'])
if gs['path']:
path = gs['path'].split(u"/")
if not path[0]:
path.pop(0)
rooted = True
else:
rooted = False
else:
path = ()
rooted = bool(au_text)
if gs['query']:
query = ((qe.split(u"=", 1) if u'=' in qe else (qe, None))
for qe in gs['query'].split(u"&"))
else:
query = ()
return cls(scheme, host, path, query, fragment, port,
rooted, userinfo, uses_netloc)
def normalize(self, scheme=True, host=True, path=True, query=True,
fragment=True, userinfo=True, percents=True):
"""Return a new URL object with several standard normalizations
applied:
* Decode unreserved characters (`RFC 3986 2.3`_)
* Uppercase remaining percent-encoded octets (`RFC 3986 2.1`_)
* Convert scheme and host casing to lowercase (`RFC 3986 3.2.2`_)
* Resolve any "." and ".." references in the path (`RFC 3986 6.2.2.3`_)
* Ensure an ending slash on URLs with an empty path (`RFC 3986 6.2.3`_)
* Encode any stray percent signs (`%`) in percent-encoded
fields (path, query, fragment, userinfo) (`RFC 3986 2.4`_)
All are applied by default, but normalizations can be disabled
per-part by passing `False` for that part's corresponding
name.
Args:
scheme (bool): Convert the scheme to lowercase
host (bool): Convert the host to lowercase
path (bool): Normalize the path (see above for details)
query (bool): Normalize the query string
fragment (bool): Normalize the fragment
userinfo (bool): Normalize the userinfo
percents (bool): Encode isolated percent signs
for any percent-encoded fields which are being
normalized (defaults to True).
>>> url = URL.from_text(u'Http://example.COM/a/../b/./c%2f?%61%')
>>> print(url.normalize().to_text())
http://example.com/b/c%2F?a%25
.. _RFC 3986 3.2.2: https://tools.ietf.org/html/rfc3986#section-3.2.2
.. _RFC 3986 2.3: https://tools.ietf.org/html/rfc3986#section-2.3
.. _RFC 3986 2.1: https://tools.ietf.org/html/rfc3986#section-2.1
.. _RFC 3986 6.2.2.3: https://tools.ietf.org/html/rfc3986#section-6.2.2.3
.. _RFC 3986 6.2.3: https://tools.ietf.org/html/rfc3986#section-6.2.3
.. _RFC 3986 2.4: https://tools.ietf.org/html/rfc3986#section-2.4
"""
kw = {}
if scheme:
kw['scheme'] = self.scheme.lower()
if host:
kw['host'] = self.host.lower()
def _dec_unres(target):
return _decode_unreserved(target, normalize_case=True,
encode_stray_percents=percents)
if path:
if self.path:
kw['path'] = [_dec_unres(p) for p in _resolve_dot_segments(self.path)]
else:
kw['path'] = (u'',)
if query:
kw['query'] = [(_dec_unres(k), _dec_unres(v) if v else v)
for k, v in self.query]
if fragment:
kw['fragment'] = _dec_unres(self.fragment)
if userinfo:
kw['userinfo'] = u':'.join([_dec_unres(p)
for p in self.userinfo.split(':', 1)])
return self.replace(**kw)
def child(self, *segments):
"""Make a new :class:`URL` where the given path segments are a child
of this URL, preserving other parts of the URL, including the
query string and fragment.
For example::
>>> url = URL.from_text(u'http://localhost/a/b?x=y')
>>> child_url = url.child(u"c", u"d")
>>> child_url.to_text()
u'http://localhost/a/b/c/d?x=y'
Args:
segments (unicode): Additional parts to be joined and added to
the path, like :func:`os.path.join`. Special characters
in segments will be percent encoded.
Returns:
URL: A copy of the current URL with the extra path segments.
"""
if not segments:
return self
segments = [_textcheck('path segment', s) for s in segments]
new_segs = _encode_path_parts(segments, joined=False, maximal=False)
new_path = self.path[:-1 if (self.path and self.path[-1] == u'')
else None] + new_segs
return self.replace(path=new_path)
def sibling(self, segment):
"""Make a new :class:`URL` with a single path segment that is a
sibling of this URL path.
Args:
segment (unicode): A single path segment.
Returns:
URL: A copy of the current URL with the last path segment
replaced by *segment*. Special characters such as
``/?#`` will be percent encoded.
"""
_textcheck('path segment', segment)
new_path = self.path[:-1] + (_encode_path_part(segment),)
return self.replace(path=new_path)
def click(self, href=u''):
"""Resolve the given URL relative to this URL.
The resulting URI should match what a web browser would
generate if you visited the current URL and clicked on *href*.
>>> url = URL.from_text(u'http://blog.hatnote.com/')
>>> url.click(u'/post/155074058790').to_text()
u'http://blog.hatnote.com/post/155074058790'
>>> url = URL.from_text(u'http://localhost/a/b/c/')
>>> url.click(u'../d/./e').to_text()
u'http://localhost/a/b/d/e'
Args:
href (unicode): A string representing a clicked URL.
Return:
URL: A copy of the current URL with navigation logic applied.
For more information, see `RFC 3986 section 5`_.
.. _RFC 3986 section 5: https://tools.ietf.org/html/rfc3986#section-5
"""
if href:
if isinstance(href, URL):
clicked = href
else:
# TODO: This error message is not completely accurate,
# as URL objects are now also valid, but Twisted's
# test suite (wrongly) relies on this exact message.
_textcheck('relative URL', href)
clicked = URL.from_text(href)
if clicked.absolute:
return clicked
else:
clicked = self
query = clicked.query
if clicked.scheme and not clicked.rooted:
# Schemes with relative paths are not well-defined. RFC 3986 calls
# them a "loophole in prior specifications" that should be avoided,
# or supported only for backwards compatibility.
raise NotImplementedError('absolute URI with rootless path: %r'
% (href,))
else:
if clicked.rooted:
path = clicked.path
elif clicked.path:
path = self.path[:-1] + clicked.path
else:
path = self.path
if not query:
query = self.query
return self.replace(scheme=clicked.scheme or self.scheme,
host=clicked.host or self.host,
port=clicked.port or self.port,
path=_resolve_dot_segments(path),
query=query,
fragment=clicked.fragment)
def to_uri(self):
u"""Make a new :class:`URL` instance with all non-ASCII characters
appropriately percent-encoded. This is useful to do in preparation
for sending a :class:`URL` over a network protocol.
For example::
>>> URL.from_text(u'https://ايران.com/foo⇧bar/').to_uri()
URL.from_text(u'https://xn--mgba3a4fra.com/foo%E2%87%A7bar/')
Returns:
URL: A new instance with its path segments, query parameters, and
hostname encoded, so that they are all in the standard
US-ASCII range.
"""
new_userinfo = u':'.join([_encode_userinfo_part(p) for p in
self.userinfo.split(':', 1)])
new_path = _encode_path_parts(self.path, has_scheme=bool(self.scheme),
rooted=False, joined=False, maximal=True)
new_host = self.host if not self.host else idna_encode(self.host, uts46=True).decode("ascii")
return self.replace(
userinfo=new_userinfo,
host=new_host,
path=new_path,
query=tuple([(_encode_query_key(k, maximal=True),
_encode_query_value(v, maximal=True)
if v is not None else None)
for k, v in self.query]),
fragment=_encode_fragment_part(self.fragment, maximal=True)
)
def to_iri(self):
u"""Make a new :class:`URL` instance with all but a few reserved
characters decoded into human-readable format.
Percent-encoded Unicode and IDNA-encoded hostnames are
decoded, like so::
>>> url = URL.from_text(u'https://xn--mgba3a4fra.example.com/foo%E2%87%A7bar/')
>>> print(url.to_iri().to_text())
https://ايران.example.com/foo⇧bar/
.. note::
As a general Python issue, "narrow" (UCS-2) builds of
Python may not be able to fully decode certain URLs, and
the in those cases, this method will return a best-effort,
partially-decoded, URL which is still valid. This issue
does not affect any Python builds 3.4+.
Returns:
URL: A new instance with its path segments, query parameters, and
hostname decoded for display purposes.
"""
new_userinfo = u':'.join([_decode_userinfo_part(p) for p in
self.userinfo.split(':', 1)])
host_text = _decode_host(self.host)
return self.replace(userinfo=new_userinfo,
host=host_text,
path=[_decode_path_part(segment)
for segment in self.path],
query=[(_decode_query_key(k),
_decode_query_value(v)
if v is not None else None)
for k, v in self.query],
fragment=_decode_fragment_part(self.fragment))
def to_text(self, with_password=False):
"""Render this URL to its textual representation.
By default, the URL text will *not* include a password, if one
is set. RFC 3986 considers using URLs to represent such
sensitive information as deprecated. Quoting from RFC 3986,
`section 3.2.1`:
"Applications should not render as clear text any data after the
first colon (":") character found within a userinfo subcomponent
unless the data after the colon is the empty string (indicating no
password)."
Args:
with_password (bool): Whether or not to include the
password in the URL text. Defaults to False.
Returns:
str: The serialized textual representation of this URL,
such as ``u"http://example.com/some/path?some=query"``.
The natural counterpart to :class:`URL.from_text()`.
.. _section 3.2.1: https://tools.ietf.org/html/rfc3986#section-3.2.1
"""
scheme = self.scheme
authority = self.authority(with_password)
path = _encode_path_parts(self.path,
rooted=self.rooted,
has_scheme=bool(scheme),
has_authority=bool(authority),
maximal=False)
query_parts = []
for k, v in self.query:
if v is None:
query_parts.append(_encode_query_key(k, maximal=False))
else:
query_parts.append(u'='.join((_encode_query_key(k, maximal=False),
_encode_query_value(v, maximal=False))))
query_string = u'&'.join(query_parts)
fragment = self.fragment
parts = []
_add = parts.append
if scheme:
_add(scheme)
_add(':')
if authority:
_add('//')
_add(authority)
elif (scheme and path[:2] != '//' and self.uses_netloc):
_add('//')
if path:
if scheme and authority and path[:1] != '/':
_add('/') # relpaths with abs authorities auto get '/'
_add(path)
if query_string:
_add('?')
_add(query_string)
if fragment:
_add('#')
_add(fragment)
return u''.join(parts)
def __repr__(self):
"""Convert this URL to an representation that shows all of its
constituent parts, as well as being a valid argument to
:func:`eval`.
"""
return '%s.from_text(%r)' % (self.__class__.__name__, self.to_text())
def _to_bytes(self):
"""
Allows for direct usage of URL objects with libraries like
requests, which automatically stringify URL parameters. See
issue #49.
"""
return self.to_uri().to_text().encode('ascii')
if PY2:
__str__ = _to_bytes
__unicode__ = to_text
else:
__bytes__ = _to_bytes
__str__ = to_text
# # Begin Twisted Compat Code
asURI = to_uri
asIRI = to_iri
@classmethod
def fromText(cls, s):
return cls.from_text(s)
def asText(self, includeSecrets=False):
return self.to_text(with_password=includeSecrets)
def __dir__(self):
try:
ret = object.__dir__(self)
except AttributeError:
# object.__dir__ == AttributeError # pdw for py2
ret = dir(self.__class__) + list(self.__dict__.keys())
ret = sorted(set(ret) - set(['fromText', 'asURI', 'asIRI', 'asText']))
return ret
# # End Twisted Compat Code
def add(self, name, value=None):
"""Make a new :class:`URL` instance with a given query argument,
*name*, added to it with the value *value*, like so::
>>> URL.from_text(u'https://example.com/?x=y').add(u'x')
URL.from_text(u'https://example.com/?x=y&x')
>>> URL.from_text(u'https://example.com/?x=y').add(u'x', u'z')
URL.from_text(u'https://example.com/?x=y&x=z')
Args:
name (unicode): The name of the query parameter to add. The
part before the ``=``.
value (unicode): The value of the query parameter to add. The
part after the ``=``. Defaults to ``None``, meaning no
value.
Returns:
URL: A new :class:`URL` instance with the parameter added.
"""
return self.replace(query=self.query + ((name, value),))
def set(self, name, value=None):
"""Make a new :class:`URL` instance with the query parameter *name*
set to *value*. All existing occurences, if any are replaced
by the single name-value pair.
>>> URL.from_text(u'https://example.com/?x=y').set(u'x')
URL.from_text(u'https://example.com/?x')
>>> URL.from_text(u'https://example.com/?x=y').set(u'x', u'z')
URL.from_text(u'https://example.com/?x=z')
Args:
name (unicode): The name of the query parameter to set. The
part before the ``=``.
value (unicode): The value of the query parameter to set. The
part after the ``=``. Defaults to ``None``, meaning no
value.
Returns:
URL: A new :class:`URL` instance with the parameter set.
"""
# Preserve the original position of the query key in the list
q = [(k, v) for (k, v) in self.query if k != name]
idx = next((i for (i, (k, v)) in enumerate(self.query)
if k == name), -1)
q[idx:idx] = [(name, value)]
return self.replace(query=q)
def get(self, name):
"""Get a list of values for the given query parameter, *name*::
>>> url = URL.from_text(u'?x=1&x=2')
>>> url.get('x')
[u'1', u'2']
>>> url.get('y')
[]
If the given *name* is not set, an empty list is returned. A
list is always returned, and this method raises no exceptions.
Args:
name (unicode): The name of the query parameter to get.
Returns:
list: A list of all the values associated with the key, in
string form.
"""
return [value for (key, value) in self.query if name == key]
def remove(self, name, value=_UNSET, limit=None):
"""Make a new :class:`URL` instance with occurrences of the query
parameter *name* removed, or, if *value* is set, parameters
matching *name* and *value*. No exception is raised if the
parameter is not already set.
Args:
name (unicode): The name of the query parameter to remove.
value (unicode): Optional value to additionally filter
on. Setting this removes query parameters which match
both name and value.
limit (int): Optional maximum number of parameters to remove.
Returns:
URL: A new :class:`URL` instance with the parameter removed.
"""
if limit is None:
if value is _UNSET:
nq = [(k, v) for (k, v) in self.query if k != name]
else:
nq = [(k, v) for (k, v) in self.query if not (k == name and v == value)]
else:
nq, removed_count = [], 0
for k, v in self.query:
if k == name and (value is _UNSET or v == value) and removed_count < limit:
removed_count += 1 # drop it
else:
nq.append((k, v)) # keep it
return self.replace(query=nq)
EncodedURL = URL # An alias better describing what the URL really is
class DecodedURL(object):
"""DecodedURL is a type meant to act as a higher-level interface to
the URL. It is the `unicode` to URL's `bytes`. `DecodedURL` has
almost exactly the same API as `URL`, but everything going in and
out is in its maximally decoded state. All percent decoding is
handled automatically.
Where applicable, a UTF-8 encoding is presumed. Be advised that
some interactions can raise :exc:`UnicodeEncodeErrors` and
:exc:`UnicodeDecodeErrors`, just like when working with
bytestrings. Examples of such interactions include handling query
strings encoding binary data, and paths containing segments with
special characters encoded with codecs other than UTF-8.
Args:
url (URL): A :class:`URL` object to wrap.
lazy (bool): Set to True to avoid pre-decode all parts of the
URL to check for validity. Defaults to False.
"""
def __init__(self, url, lazy=False):
self._url = url
if not lazy:
# cache the following, while triggering any decoding
# issues with decodable fields
self.host, self.userinfo, self.path, self.query, self.fragment
return
@classmethod
def from_text(cls, text, lazy=False):
"""\
Make a `DecodedURL` instance from any text string containing a URL.
Args:
text (unicode): Text containing the URL
lazy (bool): Whether to pre-decode all parts of the URL to
check for validity. Defaults to True.
"""
_url = URL.from_text(text)
return cls(_url, lazy=lazy)
@property
def encoded_url(self):
"""Access the underlying :class:`URL` object, which has any special
characters encoded.
"""
return self._url
def to_text(self, *a, **kw):
"Passthrough to :meth:`~hyperlink.URL.to_text()`"
return self._url.to_text(*a, **kw)
def to_uri(self, *a, **kw):
"Passthrough to :meth:`~hyperlink.URL.to_uri()`"
return self._url.to_uri(*a, **kw)
def to_iri(self, *a, **kw):
"Passthrough to :meth:`~hyperlink.URL.to_iri()`"
return self._url.to_iri(*a, **kw)
def click(self, href=u''):
"Return a new DecodedURL wrapping the result of :meth:`~hyperlink.URL.click()`"
if isinstance(href, DecodedURL):
href = href._url
return self.__class__(self._url.click(href=href))
def sibling(self, segment):
"""Automatically encode any reserved characters in *segment* and
return a new `DecodedURL` wrapping the result of
:meth:`~hyperlink.URL.sibling()`
"""
return self.__class__(self._url.sibling(_encode_reserved(segment)))
def child(self, *segments):
"""Automatically encode any reserved characters in *segments* and
return a new `DecodedURL` wrapping the result of
:meth:`~hyperlink.URL.child()`.
"""
if not segments:
return self
new_segs = [_encode_reserved(s) for s in segments]
return self.__class__(self._url.child(*new_segs))
def normalize(self, *a, **kw):
"Return a new `DecodedURL` wrapping the result of :meth:`~hyperlink.URL.normalize()`"
return self.__class__(self._url.normalize(*a, **kw))
@property
def absolute(self):
return self._url.absolute
@property
def scheme(self):
return self._url.scheme
@property
def host(self):
return _decode_host(self._url.host)
@property
def port(self):
return self._url.port
@property
def rooted(self):
return self._url.rooted
@property
def path(self):
try:
return self._path
except AttributeError:
pass
self._path = tuple([_percent_decode(p, raise_subencoding_exc=True)
for p in self._url.path])
return self._path
@property
def query(self):
try:
return self._query
except AttributeError:
pass
_q = [tuple(_percent_decode(x, raise_subencoding_exc=True)
if x is not None else None
for x in (k, v))
for k, v in self._url.query]
self._query = tuple(_q)
return self._query
@property
def fragment(self):
try:
return self._fragment
except AttributeError:
pass
frag = self._url.fragment
self._fragment = _percent_decode(frag, raise_subencoding_exc=True)
return self._fragment
@property
def userinfo(self):
try:
return self._userinfo
except AttributeError:
pass
self._userinfo = tuple([_percent_decode(p, raise_subencoding_exc=True)
for p in self._url.userinfo.split(':', 1)])
return self._userinfo
@property
def user(self):
return self.userinfo[0]
@property
def uses_netloc(self):
return self._url.uses_netloc
def replace(self, scheme=_UNSET, host=_UNSET, path=_UNSET, query=_UNSET,
fragment=_UNSET, port=_UNSET, rooted=_UNSET, userinfo=_UNSET,
uses_netloc=_UNSET):
"""While the signature is the same, this `replace()` differs a little
from URL.replace. For instance, it accepts userinfo as a
tuple, not as a string, handling the case of having a username
containing a `:`. As with the rest of the methods on
DecodedURL, if you pass a reserved character, it will be
automatically encoded instead of an error being raised.
"""
if path is not _UNSET:
path = [_encode_reserved(p) for p in path]
if query is not _UNSET:
query = [[_encode_reserved(x)
if x is not None else None
for x in (k, v)]
for k, v in iter_pairs(query)]
if userinfo is not _UNSET:
if len(userinfo) > 2:
raise ValueError('userinfo expected sequence of ["user"] or'
' ["user", "password"], got %r' % userinfo)
userinfo = u':'.join([_encode_reserved(p) for p in userinfo])
new_url = self._url.replace(scheme=scheme,
host=host,
path=path,
query=query,
fragment=fragment,
port=port,
rooted=rooted,
userinfo=userinfo,
uses_netloc=uses_netloc)
return self.__class__(url=new_url)
def get(self, name):
"Get the value of all query parameters whose name matches *name*"
return [v for (k, v) in self.query if name == k]
def add(self, name, value=None):
"Return a new DecodedURL with the query parameter *name* and *value* added."
return self.replace(query=self.query + ((name, value),))
def set(self, name, value=None):
"Return a new DecodedURL with query parameter *name* set to *value*"
query = self.query
q = [(k, v) for (k, v) in query if k != name]
idx = next((i for (i, (k, v)) in enumerate(query) if k == name), -1)
q[idx:idx] = [(name, value)]
return self.replace(query=q)
def remove(self, name, value=_UNSET, limit=None):
"""Return a new DecodedURL with query parameter *name* removed.
Optionally also filter for *value*, as well as cap the number
of parameters removed with *limit*.
"""
if limit is None:
if value is _UNSET:
nq = [(k, v) for (k, v) in self.query if k != name]
else:
nq = [(k, v) for (k, v) in self.query if not (k == name and v == value)]
else:
nq, removed_count = [], 0
for k, v in self.query:
if k == name and (value is _UNSET or v == value) and removed_count < limit:
removed_count += 1 # drop it
else:
nq.append((k, v)) # keep it
return self.replace(query=nq)
def __repr__(self):
cn = self.__class__.__name__
return '%s(url=%r)' % (cn, self._url)
def __str__(self):
# TODO: the underlying URL's __str__ needs to change to make
# this work as the URL, see #55
return str(self._url)
def __eq__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return self.normalize().to_uri() == other.normalize().to_uri()
def __ne__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return not self.__eq__(other)
def __hash__(self):
return hash((self.__class__, self.scheme, self.userinfo, self.host,
self.path, self.query, self.fragment, self.port,
self.rooted, self.uses_netloc))
# # Begin Twisted Compat Code
asURI = to_uri
asIRI = to_iri
@classmethod
def fromText(cls, s, lazy=False):
return cls.from_text(s, lazy=lazy)
def asText(self, includeSecrets=False):
return self.to_text(with_password=includeSecrets)
def __dir__(self):
try:
ret = object.__dir__(self)
except AttributeError:
# object.__dir__ == AttributeError # pdw for py2
ret = dir(self.__class__) + list(self.__dict__.keys())
ret = sorted(set(ret) - set(['fromText', 'asURI', 'asIRI', 'asText']))
return ret
# # End Twisted Compat Code
def parse(url, decoded=True, lazy=False):
"""Automatically turn text into a structured URL object.
Args:
decoded (bool): Whether or not to return a :class:`DecodedURL`,
which automatically handles all
encoding/decoding/quoting/unquoting for all the various
accessors of parts of the URL, or an :class:`EncodedURL`,
which has the same API, but requires handling of special
characters for different parts of the URL.
lazy (bool): In the case of `decoded=True`, this controls
whether the URL is decoded immediately or as accessed. The
default, `lazy=False`, checks all encoded parts of the URL
for decodability.
"""
enc_url = EncodedURL.from_text(url)
if not decoded:
return enc_url
dec_url = DecodedURL(enc_url, lazy=lazy)
return dec_url
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink/test/__init__.py
================================================
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink/test/common.py
================================================
from unittest import TestCase
class HyperlinkTestCase(TestCase):
"""This type mostly exists to provide a backwards-compatible
assertRaises method for Python 2.6 testing.
"""
def assertRaises(self, excClass, callableObj=None, *args, **kwargs):
"""Fail unless an exception of class excClass is raised
by callableObj when invoked with arguments args and keyword
arguments kwargs. If a different type of exception is
raised, it will not be caught, and the test case will be
deemed to have suffered an error, exactly as for an
unexpected exception.
If called with callableObj omitted or None, will return a
context object used like this::
with self.assertRaises(SomeException):
do_something()
The context manager keeps a reference to the exception as
the 'exception' attribute. This allows you to inspect the
exception after the assertion::
with self.assertRaises(SomeException) as cm:
do_something()
the_exception = cm.exception
self.assertEqual(the_exception.error_code, 3)
"""
context = _AssertRaisesContext(excClass, self)
if callableObj is None:
return context
with context:
callableObj(*args, **kwargs)
class _AssertRaisesContext(object):
"A context manager used to implement HyperlinkTestCase.assertRaises."
def __init__(self, expected, test_case):
self.expected = expected
self.failureException = test_case.failureException
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, tb):
if exc_type is None:
exc_name = self.expected.__name__
raise self.failureException("%s not raised" % (exc_name,))
if not issubclass(exc_type, self.expected):
# let unexpected exceptions pass through
return False
self.exception = exc_value # store for later retrieval
return True
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink/test/test_common.py
================================================
"""
Tests for hyperlink.test.common
"""
from unittest import TestCase
from .common import HyperlinkTestCase
class _ExpectedException(Exception):
"""An exception used to test HyperlinkTestCase.assertRaises.
"""
class _UnexpectedException(Exception):
"""An exception used to test HyperlinkTestCase.assertRaises.
"""
class TestHyperlink(TestCase):
"""Tests for HyperlinkTestCase"""
def setUp(self):
self.hyperlink_test = HyperlinkTestCase("run")
def test_assertRaisesWithCallable(self):
"""HyperlinkTestCase.assertRaises does not raise an AssertionError
when given a callable that, when called with the provided
arguments, raises the expected exception.
"""
called_with = []
def raisesExpected(*args, **kwargs):
called_with.append((args, kwargs))
raise _ExpectedException
self.hyperlink_test.assertRaises(_ExpectedException,
raisesExpected, 1, keyword=True)
self.assertEqual(called_with, [((1,), {"keyword": True})])
def test_assertRaisesWithCallableUnexpectedException(self):
"""When given a callable that raises an unexpected exception,
HyperlinkTestCase.assertRaises raises that exception.
"""
def doesNotRaiseExpected(*args, **kwargs):
raise _UnexpectedException
try:
self.hyperlink_test.assertRaises(_ExpectedException,
doesNotRaiseExpected)
except _UnexpectedException:
pass
def test_assertRaisesWithCallableDoesNotRaise(self):
"""HyperlinkTestCase.assertRaises raises an AssertionError when given
a callable that, when called, does not raise any exception.
"""
def doesNotRaise(*args, **kwargs):
return True
try:
self.hyperlink_test.assertRaises(_ExpectedException,
doesNotRaise)
except AssertionError:
pass
def test_assertRaisesContextManager(self):
"""HyperlinkTestCase.assertRaises does not raise an AssertionError
when used as a context manager with a suite that raises the
expected exception. The context manager stores the exception
instance under its `exception` instance variable.
"""
with self.hyperlink_test.assertRaises(_ExpectedException) as cm:
raise _ExpectedException
self.assertTrue(isinstance(cm.exception, _ExpectedException))
def test_assertRaisesContextManagerUnexpectedException(self):
"""When used as a context manager with a block that raises an
unexpected exception, HyperlinkTestCase.assertRaises raises
that unexpected exception.
"""
try:
with self.hyperlink_test.assertRaises(_ExpectedException):
raise _UnexpectedException
except _UnexpectedException:
pass
def test_assertRaisesContextManagerDoesNotRaise(self):
"""HyperlinkTestcase.assertRaises raises an AssertionError when used
as a context manager with a block that does not raise any
exception.
"""
try:
with self.hyperlink_test.assertRaises(_ExpectedException):
pass
except AssertionError:
pass
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink/test/test_decoded_url.py
================================================
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from .. import DecodedURL
from .._url import _percent_decode
from .common import HyperlinkTestCase
BASIC_URL = 'http://example.com/#'
TOTAL_URL = "https://%75%73%65%72:%00%00%00%00@xn--bcher-kva.ch:8080/a/nice%20nice/./path/?zot=23%25&zut#frég"
class TestURL(HyperlinkTestCase):
def test_durl_basic(self):
bdurl = DecodedURL.from_text(BASIC_URL)
assert bdurl.scheme == 'http'
assert bdurl.host == 'example.com'
assert bdurl.port == 80
assert bdurl.path == ('',)
assert bdurl.fragment == ''
durl = DecodedURL.from_text(TOTAL_URL)
assert durl.scheme == 'https'
assert durl.host == 'bücher.ch'
assert durl.port == 8080
assert durl.path == ('a', 'nice nice', '.', 'path', '')
assert durl.fragment == 'frég'
assert durl.get('zot') == ['23%']
assert durl.user == 'user'
assert durl.userinfo == ('user', '\0\0\0\0')
def test_passthroughs(self):
# just basic tests for the methods that more or less pass straight
# through to the underlying URL
durl = DecodedURL.from_text(TOTAL_URL)
assert durl.sibling('te%t').path[-1] == 'te%t'
assert durl.child('../test2%').path[-1] == '../test2%'
assert durl.child() == durl
assert durl.child() is durl
assert durl.click('/').path[-1] == ''
assert durl.user == 'user'
assert '.' in durl.path
assert '.' not in durl.normalize().path
assert durl.to_uri().fragment == 'fr%C3%A9g'
assert ' ' in durl.to_iri().path[1]
assert durl.to_text(with_password=True) == TOTAL_URL
assert durl.absolute
assert durl.rooted
assert durl == durl.encoded_url.get_decoded_url()
durl2 = DecodedURL.from_text(TOTAL_URL, lazy=True)
assert durl2 == durl2.encoded_url.get_decoded_url(lazy=True)
assert str(DecodedURL.from_text(BASIC_URL).child(' ')) == 'http://example.com/%20'
assert not (durl == 1)
assert durl != 1
def test_repr(self):
durl = DecodedURL.from_text(TOTAL_URL)
assert repr(durl) == 'DecodedURL(url=' + repr(durl._url) + ')'
def test_query_manipulation(self):
durl = DecodedURL.from_text(TOTAL_URL)
assert durl.get('zot') == ['23%']
durl = durl.add(' ', 'space')
assert durl.get(' ') == ['space']
durl = durl.set(' ', 'spa%ed')
assert durl.get(' ') == ['spa%ed']
durl = DecodedURL(url=durl.to_uri())
assert durl.get(' ') == ['spa%ed']
durl = durl.remove(' ')
assert durl.get(' ') == []
durl = DecodedURL.from_text('/?%61rg=b&arg=c')
assert durl.get('arg') == ['b', 'c']
assert durl.set('arg', 'd').get('arg') == ['d']
durl = DecodedURL.from_text(u"https://example.com/a/b/?fóó=1&bar=2&fóó=3")
assert durl.remove("fóó") == DecodedURL.from_text("https://example.com/a/b/?bar=2")
assert durl.remove("fóó", value="1") == DecodedURL.from_text("https://example.com/a/b/?bar=2&fóó=3")
assert durl.remove("fóó", limit=1) == DecodedURL.from_text("https://example.com/a/b/?bar=2&fóó=3")
assert durl.remove("fóó", value="1", limit=0) == DecodedURL.from_text("https://example.com/a/b/?fóó=1&bar=2&fóó=3")
def test_equality_and_hashability(self):
durl = DecodedURL.from_text(TOTAL_URL)
durl2 = DecodedURL.from_text(TOTAL_URL)
burl = DecodedURL.from_text(BASIC_URL)
durl_uri = durl.to_uri()
assert durl == durl
assert durl == durl2
assert durl != burl
assert durl != None
assert durl != durl._url
durl_map = {}
durl_map[durl] = durl
durl_map[durl2] = durl2
assert len(durl_map) == 1
durl_map[burl] = burl
assert len(durl_map) == 2
durl_map[durl_uri] = durl_uri
assert len(durl_map) == 3
def test_replace_roundtrip(self):
durl = DecodedURL.from_text(TOTAL_URL)
durl2 = durl.replace(scheme=durl.scheme,
host=durl.host,
path=durl.path,
query=durl.query,
fragment=durl.fragment,
port=durl.port,
rooted=durl.rooted,
userinfo=durl.userinfo,
uses_netloc=durl.uses_netloc)
assert durl == durl2
def test_replace_userinfo(self):
durl = DecodedURL.from_text(TOTAL_URL)
with self.assertRaises(ValueError):
durl.replace(userinfo=['user', 'pw', 'thiswillcauseafailure'])
return
def test_twisted_compat(self):
durl = DecodedURL.from_text(TOTAL_URL)
assert durl == DecodedURL.fromText(TOTAL_URL)
assert 'to_text' in dir(durl)
assert 'asText' not in dir(durl)
assert durl.to_text() == durl.asText()
def test_percent_decode_bytes(self):
assert _percent_decode('%00', subencoding=False) == b'\0'
def test_percent_decode_mixed(self):
# See https://github.com/python-hyper/hyperlink/pull/59 for a
# nice discussion of the possibilities
assert _percent_decode('abcdé%C3%A9éfg') == 'abcdéééfg'
# still allow percent encoding in the case of an error
assert _percent_decode('abcdé%C3éfg') == 'abcdé%C3éfg'
# ...unless explicitly told otherwise
with self.assertRaises(UnicodeDecodeError):
_percent_decode('abcdé%C3éfg', raise_subencoding_exc=True)
# check that getting raw bytes works ok
assert _percent_decode('a%00b', subencoding=False) == b'a\x00b'
# when not encodable as subencoding
assert _percent_decode('é%25é', subencoding='ascii') == 'é%25é'
def test_click_decoded_url(self):
durl = DecodedURL.from_text(TOTAL_URL)
durl_dest = DecodedURL.from_text('/tëst')
clicked = durl.click(durl_dest)
assert clicked.host == durl.host
assert clicked.path == durl_dest.path
assert clicked.path == ('tëst',)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink/test/test_parse.py
================================================
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from .common import HyperlinkTestCase
from hyperlink import parse, EncodedURL, DecodedURL
BASIC_URL = 'http://example.com/#'
TOTAL_URL = "https://%75%73%65%72:%00%00%00%00@xn--bcher-kva.ch:8080/a/nice%20nice/./path/?zot=23%25&zut#frég"
UNDECODABLE_FRAG_URL = TOTAL_URL + '%C3'
# the %C3 above percent-decodes to an unpaired \xc3 byte which makes this
# invalid utf8
class TestURL(HyperlinkTestCase):
def test_parse(self):
purl = parse(TOTAL_URL)
assert isinstance(purl, DecodedURL)
assert purl.user == 'user'
assert purl.get('zot') == ['23%']
assert purl.fragment == 'frég'
purl2 = parse(TOTAL_URL, decoded=False)
assert isinstance(purl2, EncodedURL)
assert purl2.get('zot') == ['23%25']
with self.assertRaises(UnicodeDecodeError):
purl3 = parse(UNDECODABLE_FRAG_URL)
purl3 = parse(UNDECODABLE_FRAG_URL, lazy=True)
with self.assertRaises(UnicodeDecodeError):
purl3.fragment
return
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink/test/test_scheme_registration.py
================================================
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from .. import _url
from .common import HyperlinkTestCase
from .._url import register_scheme, URL
class TestSchemeRegistration(HyperlinkTestCase):
def setUp(self):
self._orig_scheme_port_map = dict(_url.SCHEME_PORT_MAP)
self._orig_no_netloc_schemes = set(_url.NO_NETLOC_SCHEMES)
def tearDown(self):
_url.SCHEME_PORT_MAP = self._orig_scheme_port_map
_url.NO_NETLOC_SCHEMES = self._orig_no_netloc_schemes
def test_register_scheme_basic(self):
register_scheme('deltron', uses_netloc=True, default_port=3030)
u1 = URL.from_text('deltron://example.com')
assert u1.scheme == 'deltron'
assert u1.port == 3030
assert u1.uses_netloc is True
# test netloc works even when the original gives no indication
u2 = URL.from_text('deltron:')
u2 = u2.replace(host='example.com')
assert u2.to_text() == 'deltron://example.com'
# test default port means no emission
u3 = URL.from_text('deltron://example.com:3030')
assert u3.to_text() == 'deltron://example.com'
register_scheme('nonetron', default_port=3031)
u4 = URL(scheme='nonetron')
u4 = u4.replace(host='example.com')
assert u4.to_text() == 'nonetron://example.com'
def test_register_no_netloc_scheme(self):
register_scheme('noloctron', uses_netloc=False)
u4 = URL(scheme='noloctron')
u4 = u4.replace(path=("example", "path"))
assert u4.to_text() == 'noloctron:example/path'
def test_register_no_netloc_with_port(self):
with self.assertRaises(ValueError):
register_scheme('badnetlocless', uses_netloc=False, default_port=7)
def test_invalid_uses_netloc(self):
with self.assertRaises(ValueError):
register_scheme('badnetloc', uses_netloc=None)
with self.assertRaises(ValueError):
register_scheme('badnetloc', uses_netloc=object())
def test_register_invalid_uses_netloc(self):
with self.assertRaises(ValueError):
register_scheme('lol', uses_netloc=lambda: 'nope')
def test_register_invalid_port(self):
with self.assertRaises(ValueError):
register_scheme('nope', default_port=lambda: 'lol')
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink/test/test_url.py
================================================
# -*- coding: utf-8 -*-
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
from __future__ import unicode_literals
import sys
import socket
from .common import HyperlinkTestCase
from .. import URL, URLParseError
# automatically import the py27 windows implementation when appropriate
from .. import _url
from .._url import inet_pton, SCHEME_PORT_MAP, parse_host
PY2 = (sys.version_info[0] == 2)
unicode = type(u'')
BASIC_URL = "http://www.foo.com/a/nice/path/?zot=23&zut"
# Examples from RFC 3986 section 5.4, Reference Resolution Examples
relativeLinkBaseForRFC3986 = 'http://a/b/c/d;p?q'
relativeLinkTestsForRFC3986 = [
# "Normal"
# ('g:h', 'g:h'), # can't click on a scheme-having url without an abs path
('g', 'http://a/b/c/g'),
('./g', 'http://a/b/c/g'),
('g/', 'http://a/b/c/g/'),
('/g', 'http://a/g'),
('//g', 'http://g'),
('?y', 'http://a/b/c/d;p?y'),
('g?y', 'http://a/b/c/g?y'),
('#s', 'http://a/b/c/d;p?q#s'),
('g#s', 'http://a/b/c/g#s'),
('g?y#s', 'http://a/b/c/g?y#s'),
(';x', 'http://a/b/c/;x'),
('g;x', 'http://a/b/c/g;x'),
('g;x?y#s', 'http://a/b/c/g;x?y#s'),
('', 'http://a/b/c/d;p?q'),
('.', 'http://a/b/c/'),
('./', 'http://a/b/c/'),
('..', 'http://a/b/'),
('../', 'http://a/b/'),
('../g', 'http://a/b/g'),
('../..', 'http://a/'),
('../../', 'http://a/'),
('../../g', 'http://a/g'),
# Abnormal examples
# ".." cannot be used to change the authority component of a URI.
('../../../g', 'http://a/g'),
('../../../../g', 'http://a/g'),
# Only include "." and ".." when they are only part of a larger segment,
# not by themselves.
('/./g', 'http://a/g'),
('/../g', 'http://a/g'),
('g.', 'http://a/b/c/g.'),
('.g', 'http://a/b/c/.g'),
('g..', 'http://a/b/c/g..'),
('..g', 'http://a/b/c/..g'),
# Unnecessary or nonsensical forms of "." and "..".
('./../g', 'http://a/b/g'),
('./g/.', 'http://a/b/c/g/'),
('g/./h', 'http://a/b/c/g/h'),
('g/../h', 'http://a/b/c/h'),
('g;x=1/./y', 'http://a/b/c/g;x=1/y'),
('g;x=1/../y', 'http://a/b/c/y'),
# Separating the reference's query and fragment components from the path.
('g?y/./x', 'http://a/b/c/g?y/./x'),
('g?y/../x', 'http://a/b/c/g?y/../x'),
('g#s/./x', 'http://a/b/c/g#s/./x'),
('g#s/../x', 'http://a/b/c/g#s/../x')
]
ROUNDTRIP_TESTS = (
"http://localhost",
"http://localhost/",
"http://127.0.0.1/",
"http://[::127.0.0.1]/",
"http://[::1]/",
"http://localhost/foo",
"http://localhost/foo/",
"http://localhost/foo!!bar/",
"http://localhost/foo%20bar/",
"http://localhost/foo%2Fbar/",
"http://localhost/foo?n",
"http://localhost/foo?n=v",
"http://localhost/foo?n=/a/b",
"http://example.com/foo!@$bar?b!@z=123",
"http://localhost/asd?a=asd%20sdf/345",
"http://(%2525)/(%2525)?(%2525)&(%2525)=(%2525)#(%2525)",
"http://(%C3%A9)/(%C3%A9)?(%C3%A9)&(%C3%A9)=(%C3%A9)#(%C3%A9)",
"?sslrootcert=/Users/glyph/Downloads/rds-ca-2015-root.pem&sslmode=verify",
# from boltons.urlutils' tests
'http://googlewebsite.com/e-shops.aspx',
'http://example.com:8080/search?q=123&business=Nothing%20Special',
'http://hatnote.com:9000/?arg=1&arg=2&arg=3',
'https://xn--bcher-kva.ch',
'http://xn--ggbla1c4e.xn--ngbc5azd/',
'http://tools.ietf.org/html/rfc3986#section-3.4',
# 'http://wiki:pedia@hatnote.com',
'ftp://ftp.rfc-editor.org/in-notes/tar/RFCs0001-0500.tar.gz',
'http://[1080:0:0:0:8:800:200C:417A]/index.html',
'ssh://192.0.2.16:2222/',
'https://[::101.45.75.219]:80/?hi=bye',
'ldap://[::192.9.5.5]/dc=example,dc=com??sub?(sn=Jensen)',
'mailto:me@example.com?to=me@example.com&body=hi%20http://wikipedia.org',
'news:alt.rec.motorcycle',
'tel:+1-800-867-5309',
'urn:oasis:member:A00024:x',
('magnet:?xt=urn:btih:1a42b9e04e122b97a5254e3df77ab3c4b7da725f&dn=Puppy%'
'20Linux%20precise-5.7.1.iso&tr=udp://tracker.openbittorrent.com:80&'
'tr=udp://tracker.publicbt.com:80&tr=udp://tracker.istole.it:6969&'
'tr=udp://tracker.ccc.de:80&tr=udp://open.demonii.com:1337'),
# percent-encoded delimiters in percent-encodable fields
'https://%3A@example.com/', # colon in username
'https://%40@example.com/', # at sign in username
'https://%2f@example.com/', # slash in username
'https://a:%3a@example.com/', # colon in password
'https://a:%40@example.com/', # at sign in password
'https://a:%2f@example.com/', # slash in password
'https://a:%3f@example.com/', # question mark in password
'https://example.com/%2F/', # slash in path
'https://example.com/%3F/', # question mark in path
'https://example.com/%23/', # hash in path
'https://example.com/?%23=b', # hash in query param name
'https://example.com/?%3D=b', # equals in query param name
'https://example.com/?%26=b', # ampersand in query param name
'https://example.com/?a=%23', # hash in query param value
'https://example.com/?a=%26', # ampersand in query param value
'https://example.com/?a=%3D', # equals in query param value
# double-encoded percent sign in all percent-encodable positions:
"http://(%2525):(%2525)@example.com/(%2525)/?(%2525)=(%2525)#(%2525)",
# colon in first part of schemeless relative url
'first_seg_rel_path__colon%3Anotok/second_seg__colon%3Aok',
)
class TestURL(HyperlinkTestCase):
"""
Tests for L{URL}.
"""
def assertUnicoded(self, u):
"""
The given L{URL}'s components should be L{unicode}.
@param u: The L{URL} to test.
"""
self.assertTrue(isinstance(u.scheme, unicode) or u.scheme is None,
repr(u))
self.assertTrue(isinstance(u.host, unicode) or u.host is None,
repr(u))
for seg in u.path:
self.assertEqual(type(seg), unicode, repr(u))
for (k, v) in u.query:
self.assertEqual(type(seg), unicode, repr(u))
self.assertTrue(v is None or isinstance(v, unicode), repr(u))
self.assertEqual(type(u.fragment), unicode, repr(u))
def assertURL(self, u, scheme, host, path, query,
fragment, port, userinfo=''):
"""
The given L{URL} should have the given components.
@param u: The actual L{URL} to examine.
@param scheme: The expected scheme.
@param host: The expected host.
@param path: The expected path.
@param query: The expected query.
@param fragment: The expected fragment.
@param port: The expected port.
@param userinfo: The expected userinfo.
"""
actual = (u.scheme, u.host, u.path, u.query,
u.fragment, u.port, u.userinfo)
expected = (scheme, host, tuple(path), tuple(query),
fragment, port, u.userinfo)
self.assertEqual(actual, expected)
def test_initDefaults(self):
"""
L{URL} should have appropriate default values.
"""
def check(u):
self.assertUnicoded(u)
self.assertURL(u, 'http', '', [], [], '', 80, '')
check(URL('http', ''))
check(URL('http', '', [], []))
check(URL('http', '', [], [], ''))
def test_init(self):
"""
L{URL} should accept L{unicode} parameters.
"""
u = URL('s', 'h', ['p'], [('k', 'v'), ('k', None)], 'f')
self.assertUnicoded(u)
self.assertURL(u, 's', 'h', ['p'], [('k', 'v'), ('k', None)],
'f', None)
self.assertURL(URL('http', '\xe0', ['\xe9'],
[('\u03bb', '\u03c0')], '\u22a5'),
'http', '\xe0', ['\xe9'],
[('\u03bb', '\u03c0')], '\u22a5', 80)
def test_initPercent(self):
"""
L{URL} should accept (and not interpret) percent characters.
"""
u = URL('s', '%68', ['%70'], [('%6B', '%76'), ('%6B', None)],
'%66')
self.assertUnicoded(u)
self.assertURL(u,
's', '%68', ['%70'],
[('%6B', '%76'), ('%6B', None)],
'%66', None)
def test_repr(self):
"""
L{URL.__repr__} will display the canonical form of the URL, wrapped in
a L{URL.from_text} invocation, so that it is C{eval}-able but still easy
to read.
"""
self.assertEqual(
repr(URL(scheme='http', host='foo', path=['bar'],
query=[('baz', None), ('k', 'v')],
fragment='frob')),
"URL.from_text(%s)" % (repr(u"http://foo/bar?baz&k=v#frob"),)
)
def test_from_text(self):
"""
Round-tripping L{URL.from_text} with C{str} results in an equivalent
URL.
"""
urlpath = URL.from_text(BASIC_URL)
self.assertEqual(BASIC_URL, urlpath.to_text())
def test_roundtrip(self):
"""
L{URL.to_text} should invert L{URL.from_text}.
"""
for test in ROUNDTRIP_TESTS:
result = URL.from_text(test).to_text(with_password=True)
self.assertEqual(test, result)
def test_roundtrip_double_iri(self):
for test in ROUNDTRIP_TESTS:
url = URL.from_text(test)
iri = url.to_iri()
double_iri = iri.to_iri()
assert iri == double_iri
iri_text = iri.to_text(with_password=True)
double_iri_text = double_iri.to_text(with_password=True)
assert iri_text == double_iri_text
return
def test_equality(self):
"""
Two URLs decoded using L{URL.from_text} will be equal (C{==}) if they
decoded same URL string, and unequal (C{!=}) if they decoded different
strings.
"""
urlpath = URL.from_text(BASIC_URL)
self.assertEqual(urlpath, URL.from_text(BASIC_URL))
self.assertNotEqual(
urlpath,
URL.from_text('ftp://www.anotherinvaliddomain.com/'
'foo/bar/baz/?zot=21&zut')
)
def test_fragmentEquality(self):
"""
An URL created with the empty string for a fragment compares equal
to an URL created with an unspecified fragment.
"""
self.assertEqual(URL(fragment=''), URL())
self.assertEqual(URL.from_text(u"http://localhost/#"),
URL.from_text(u"http://localhost/"))
def test_child(self):
"""
L{URL.child} appends a new path segment, but does not affect the query
or fragment.
"""
urlpath = URL.from_text(BASIC_URL)
self.assertEqual("http://www.foo.com/a/nice/path/gong?zot=23&zut",
urlpath.child('gong').to_text())
self.assertEqual("http://www.foo.com/a/nice/path/gong%2F?zot=23&zut",
urlpath.child('gong/').to_text())
self.assertEqual(
"http://www.foo.com/a/nice/path/gong%2Fdouble?zot=23&zut",
urlpath.child('gong/double').to_text()
)
self.assertEqual(
"http://www.foo.com/a/nice/path/gong%2Fdouble%2F?zot=23&zut",
urlpath.child('gong/double/').to_text()
)
def test_multiChild(self):
"""
L{URL.child} receives multiple segments as C{*args} and appends each in
turn.
"""
url = URL.from_text('http://example.com/a/b')
self.assertEqual(url.child('c', 'd', 'e').to_text(),
'http://example.com/a/b/c/d/e')
def test_childInitRoot(self):
"""
L{URL.child} of a L{URL} without a path produces a L{URL} with a single
path segment.
"""
childURL = URL(host=u"www.foo.com").child(u"c")
self.assertTrue(childURL.rooted)
self.assertEqual("http://www.foo.com/c", childURL.to_text())
def test_emptyChild(self):
"""
L{URL.child} without any new segments returns the original L{URL}.
"""
url = URL(host=u"www.foo.com")
self.assertEqual(url.child(), url)
def test_sibling(self):
"""
L{URL.sibling} of a L{URL} replaces the last path segment, but does not
affect the query or fragment.
"""
urlpath = URL.from_text(BASIC_URL)
self.assertEqual(
"http://www.foo.com/a/nice/path/sister?zot=23&zut",
urlpath.sibling('sister').to_text()
)
# Use an url without trailing '/' to check child removal.
url_text = "http://www.foo.com/a/nice/path?zot=23&zut"
urlpath = URL.from_text(url_text)
self.assertEqual(
"http://www.foo.com/a/nice/sister?zot=23&zut",
urlpath.sibling('sister').to_text()
)
def test_click(self):
"""
L{URL.click} interprets the given string as a relative URI-reference
and returns a new L{URL} interpreting C{self} as the base absolute URI.
"""
urlpath = URL.from_text(BASIC_URL)
# A null uri should be valid (return here).
self.assertEqual("http://www.foo.com/a/nice/path/?zot=23&zut",
urlpath.click("").to_text())
# A simple relative path remove the query.
self.assertEqual("http://www.foo.com/a/nice/path/click",
urlpath.click("click").to_text())
# An absolute path replace path and query.
self.assertEqual("http://www.foo.com/click",
urlpath.click("/click").to_text())
# Replace just the query.
self.assertEqual("http://www.foo.com/a/nice/path/?burp",
urlpath.click("?burp").to_text())
# One full url to another should not generate '//' between authority.
# and path
self.assertTrue("//foobar" not in
urlpath.click('http://www.foo.com/foobar').to_text())
# From a url with no query clicking a url with a query, the query
# should be handled properly.
u = URL.from_text('http://www.foo.com/me/noquery')
self.assertEqual('http://www.foo.com/me/17?spam=158',
u.click('/me/17?spam=158').to_text())
# Check that everything from the path onward is removed when the click
# link has no path.
u = URL.from_text('http://localhost/foo?abc=def')
self.assertEqual(u.click('http://www.python.org').to_text(),
'http://www.python.org')
# https://twistedmatrix.com/trac/ticket/8184
u = URL.from_text('http://hatnote.com/a/b/../c/./d/e/..')
res = 'http://hatnote.com/a/c/d/'
self.assertEqual(u.click('').to_text(), res)
# test click default arg is same as empty string above
self.assertEqual(u.click().to_text(), res)
# test click on a URL instance
u = URL.fromText('http://localhost/foo/?abc=def')
u2 = URL.from_text('bar')
u3 = u.click(u2)
self.assertEqual(u3.to_text(), 'http://localhost/foo/bar')
def test_clickRFC3986(self):
"""
L{URL.click} should correctly resolve the examples in RFC 3986.
"""
base = URL.from_text(relativeLinkBaseForRFC3986)
for (ref, expected) in relativeLinkTestsForRFC3986:
self.assertEqual(base.click(ref).to_text(), expected)
def test_clickSchemeRelPath(self):
"""
L{URL.click} should not accept schemes with relative paths.
"""
base = URL.from_text(relativeLinkBaseForRFC3986)
self.assertRaises(NotImplementedError, base.click, 'g:h')
self.assertRaises(NotImplementedError, base.click, 'http:h')
def test_cloneUnchanged(self):
"""
Verify that L{URL.replace} doesn't change any of the arguments it
is passed.
"""
urlpath = URL.from_text('https://x:1/y?z=1#A')
self.assertEqual(urlpath.replace(urlpath.scheme,
urlpath.host,
urlpath.path,
urlpath.query,
urlpath.fragment,
urlpath.port),
urlpath)
self.assertEqual(urlpath.replace(), urlpath)
def test_clickCollapse(self):
"""
L{URL.click} collapses C{.} and C{..} according to RFC 3986 section
5.2.4.
"""
tests = [
['http://localhost/', '.', 'http://localhost/'],
['http://localhost/', '..', 'http://localhost/'],
['http://localhost/a/b/c', '.', 'http://localhost/a/b/'],
['http://localhost/a/b/c', '..', 'http://localhost/a/'],
['http://localhost/a/b/c', './d/e', 'http://localhost/a/b/d/e'],
['http://localhost/a/b/c', '../d/e', 'http://localhost/a/d/e'],
['http://localhost/a/b/c', '/./d/e', 'http://localhost/d/e'],
['http://localhost/a/b/c', '/../d/e', 'http://localhost/d/e'],
['http://localhost/a/b/c/', '../../d/e/',
'http://localhost/a/d/e/'],
['http://localhost/a/./c', '../d/e', 'http://localhost/d/e'],
['http://localhost/a/./c/', '../d/e', 'http://localhost/a/d/e'],
['http://localhost/a/b/c/d', './e/../f/../g',
'http://localhost/a/b/c/g'],
['http://localhost/a/b/c', 'd//e', 'http://localhost/a/b/d//e'],
]
for start, click, expected in tests:
actual = URL.from_text(start).click(click).to_text()
self.assertEqual(
actual,
expected,
"{start}.click({click}) => {actual} not {expected}".format(
start=start,
click=repr(click),
actual=actual,
expected=expected,
)
)
def test_queryAdd(self):
"""
L{URL.add} adds query parameters.
"""
self.assertEqual(
"http://www.foo.com/a/nice/path/?foo=bar",
URL.from_text("http://www.foo.com/a/nice/path/")
.add(u"foo", u"bar").to_text())
self.assertEqual(
"http://www.foo.com/?foo=bar",
URL(host=u"www.foo.com").add(u"foo", u"bar")
.to_text())
urlpath = URL.from_text(BASIC_URL)
self.assertEqual(
"http://www.foo.com/a/nice/path/?zot=23&zut&burp",
urlpath.add(u"burp").to_text())
self.assertEqual(
"http://www.foo.com/a/nice/path/?zot=23&zut&burp=xxx",
urlpath.add(u"burp", u"xxx").to_text())
self.assertEqual(
"http://www.foo.com/a/nice/path/?zot=23&zut&burp=xxx&zing",
urlpath.add(u"burp", u"xxx").add(u"zing").to_text())
# Note the inversion!
self.assertEqual(
"http://www.foo.com/a/nice/path/?zot=23&zut&zing&burp=xxx",
urlpath.add(u"zing").add(u"burp", u"xxx").to_text())
# Note the two values for the same name.
self.assertEqual(
"http://www.foo.com/a/nice/path/?zot=23&zut&burp=xxx&zot=32",
urlpath.add(u"burp", u"xxx").add(u"zot", '32')
.to_text())
def test_querySet(self):
"""
L{URL.set} replaces query parameters by name.
"""
urlpath = URL.from_text(BASIC_URL)
self.assertEqual(
"http://www.foo.com/a/nice/path/?zot=32&zut",
urlpath.set(u"zot", '32').to_text())
# Replace name without value with name/value and vice-versa.
self.assertEqual(
"http://www.foo.com/a/nice/path/?zot&zut=itworked",
urlpath.set(u"zot").set(u"zut", u"itworked").to_text()
)
# Q: what happens when the query has two values and we replace?
# A: we replace both values with a single one
self.assertEqual(
"http://www.foo.com/a/nice/path/?zot=32&zut",
urlpath.add(u"zot", u"xxx").set(u"zot", '32').to_text()
)
def test_queryRemove(self):
"""
L{URL.remove} removes instances of a query parameter.
"""
url = URL.from_text(u"https://example.com/a/b/?foo=1&bar=2&foo=3")
self.assertEqual(
url.remove(u"foo"),
URL.from_text(u"https://example.com/a/b/?bar=2")
)
self.assertEqual(
url.remove(name=u"foo", value=u"1"),
URL.from_text(u"https://example.com/a/b/?bar=2&foo=3")
)
self.assertEqual(
url.remove(name=u"foo", limit=1),
URL.from_text(u"https://example.com/a/b/?bar=2&foo=3")
)
self.assertEqual(
url.remove(name=u"foo", value=u"1", limit=0),
URL.from_text(u"https://example.com/a/b/?foo=1&bar=2&foo=3")
)
def test_parseEqualSignInParamValue(self):
"""
Every C{=}-sign after the first in a query parameter is simply included
in the value of the parameter.
"""
u = URL.from_text('http://localhost/?=x=x=x')
self.assertEqual(u.get(''), ['x=x=x'])
self.assertEqual(u.to_text(), 'http://localhost/?=x=x=x')
u = URL.from_text('http://localhost/?foo=x=x=x&bar=y')
self.assertEqual(u.query, (('foo', 'x=x=x'), ('bar', 'y')))
self.assertEqual(u.to_text(), 'http://localhost/?foo=x=x=x&bar=y')
u = URL.from_text('https://example.com/?argument=3&argument=4&operator=%3D')
iri = u.to_iri()
self.assertEqual(iri.get('operator'), ['='])
# assert that the equals is not unnecessarily escaped
self.assertEqual(iri.to_uri().get('operator'), ['='])
def test_empty(self):
"""
An empty L{URL} should serialize as the empty string.
"""
self.assertEqual(URL().to_text(), '')
def test_justQueryText(self):
"""
An L{URL} with query text should serialize as just query text.
"""
u = URL(query=[(u"hello", u"world")])
self.assertEqual(u.to_text(), '?hello=world')
def test_identicalEqual(self):
"""
L{URL} compares equal to itself.
"""
u = URL.from_text('http://localhost/')
self.assertEqual(u, u)
def test_similarEqual(self):
"""
URLs with equivalent components should compare equal.
"""
u1 = URL.from_text('http://u@localhost:8080/p/a/t/h?q=p#f')
u2 = URL.from_text('http://u@localhost:8080/p/a/t/h?q=p#f')
self.assertEqual(u1, u2)
def test_differentNotEqual(self):
"""
L{URL}s that refer to different resources are both unequal (C{!=}) and
also not equal (not C{==}).
"""
u1 = URL.from_text('http://localhost/a')
u2 = URL.from_text('http://localhost/b')
self.assertFalse(u1 == u2, "%r != %r" % (u1, u2))
self.assertNotEqual(u1, u2)
def test_otherTypesNotEqual(self):
"""
L{URL} is not equal (C{==}) to other types.
"""
u = URL.from_text('http://localhost/')
self.assertFalse(u == 42, "URL must not equal a number.")
self.assertFalse(u == object(), "URL must not equal an object.")
self.assertNotEqual(u, 42)
self.assertNotEqual(u, object())
def test_identicalNotUnequal(self):
"""
Identical L{URL}s are not unequal (C{!=}) to each other.
"""
u = URL.from_text('http://u@localhost:8080/p/a/t/h?q=p#f')
self.assertFalse(u != u, "%r == itself" % u)
def test_similarNotUnequal(self):
"""
Structurally similar L{URL}s are not unequal (C{!=}) to each other.
"""
u1 = URL.from_text('http://u@localhost:8080/p/a/t/h?q=p#f')
u2 = URL.from_text('http://u@localhost:8080/p/a/t/h?q=p#f')
self.assertFalse(u1 != u2, "%r == %r" % (u1, u2))
def test_differentUnequal(self):
"""
Structurally different L{URL}s are unequal (C{!=}) to each other.
"""
u1 = URL.from_text('http://localhost/a')
u2 = URL.from_text('http://localhost/b')
self.assertTrue(u1 != u2, "%r == %r" % (u1, u2))
def test_otherTypesUnequal(self):
"""
L{URL} is unequal (C{!=}) to other types.
"""
u = URL.from_text('http://localhost/')
self.assertTrue(u != 42, "URL must differ from a number.")
self.assertTrue(u != object(), "URL must be differ from an object.")
def test_asURI(self):
"""
L{URL.asURI} produces an URI which converts any URI unicode encoding
into pure US-ASCII and returns a new L{URL}.
"""
unicodey = ('http://\N{LATIN SMALL LETTER E WITH ACUTE}.com/'
'\N{LATIN SMALL LETTER E}\N{COMBINING ACUTE ACCENT}'
'?\N{LATIN SMALL LETTER A}\N{COMBINING ACUTE ACCENT}='
'\N{LATIN SMALL LETTER I}\N{COMBINING ACUTE ACCENT}'
'#\N{LATIN SMALL LETTER U}\N{COMBINING ACUTE ACCENT}')
iri = URL.from_text(unicodey)
uri = iri.asURI()
self.assertEqual(iri.host, '\N{LATIN SMALL LETTER E WITH ACUTE}.com')
self.assertEqual(iri.path[0],
'\N{LATIN SMALL LETTER E}\N{COMBINING ACUTE ACCENT}')
self.assertEqual(iri.to_text(), unicodey)
expectedURI = 'http://xn--9ca.com/%C3%A9?%C3%A1=%C3%AD#%C3%BA'
actualURI = uri.to_text()
self.assertEqual(actualURI, expectedURI,
'%r != %r' % (actualURI, expectedURI))
def test_asIRI(self):
"""
L{URL.asIRI} decodes any percent-encoded text in the URI, making it
more suitable for reading by humans, and returns a new L{URL}.
"""
asciiish = 'http://xn--9ca.com/%C3%A9?%C3%A1=%C3%AD#%C3%BA'
uri = URL.from_text(asciiish)
iri = uri.asIRI()
self.assertEqual(uri.host, 'xn--9ca.com')
self.assertEqual(uri.path[0], '%C3%A9')
self.assertEqual(uri.to_text(), asciiish)
expectedIRI = ('http://\N{LATIN SMALL LETTER E WITH ACUTE}.com/'
'\N{LATIN SMALL LETTER E WITH ACUTE}'
'?\N{LATIN SMALL LETTER A WITH ACUTE}='
'\N{LATIN SMALL LETTER I WITH ACUTE}'
'#\N{LATIN SMALL LETTER U WITH ACUTE}')
actualIRI = iri.to_text()
self.assertEqual(actualIRI, expectedIRI,
'%r != %r' % (actualIRI, expectedIRI))
def test_badUTF8AsIRI(self):
"""
Bad UTF-8 in a path segment, query parameter, or fragment results in
that portion of the URI remaining percent-encoded in the IRI.
"""
urlWithBinary = 'http://xn--9ca.com/%00%FF/%C3%A9'
uri = URL.from_text(urlWithBinary)
iri = uri.asIRI()
expectedIRI = ('http://\N{LATIN SMALL LETTER E WITH ACUTE}.com/'
'%00%FF/'
'\N{LATIN SMALL LETTER E WITH ACUTE}')
actualIRI = iri.to_text()
self.assertEqual(actualIRI, expectedIRI,
'%r != %r' % (actualIRI, expectedIRI))
def test_alreadyIRIAsIRI(self):
"""
A L{URL} composed of non-ASCII text will result in non-ASCII text.
"""
unicodey = ('http://\N{LATIN SMALL LETTER E WITH ACUTE}.com/'
'\N{LATIN SMALL LETTER E}\N{COMBINING ACUTE ACCENT}'
'?\N{LATIN SMALL LETTER A}\N{COMBINING ACUTE ACCENT}='
'\N{LATIN SMALL LETTER I}\N{COMBINING ACUTE ACCENT}'
'#\N{LATIN SMALL LETTER U}\N{COMBINING ACUTE ACCENT}')
iri = URL.from_text(unicodey)
alsoIRI = iri.asIRI()
self.assertEqual(alsoIRI.to_text(), unicodey)
def test_alreadyURIAsURI(self):
"""
A L{URL} composed of encoded text will remain encoded.
"""
expectedURI = 'http://xn--9ca.com/%C3%A9?%C3%A1=%C3%AD#%C3%BA'
uri = URL.from_text(expectedURI)
actualURI = uri.asURI().to_text()
self.assertEqual(actualURI, expectedURI)
def test_userinfo(self):
"""
L{URL.from_text} will parse the C{userinfo} portion of the URI
separately from the host and port.
"""
url = URL.from_text(
'http://someuser:somepassword@example.com/some-segment@ignore'
)
self.assertEqual(url.authority(True),
'someuser:somepassword@example.com')
self.assertEqual(url.authority(False), 'someuser:@example.com')
self.assertEqual(url.userinfo, 'someuser:somepassword')
self.assertEqual(url.user, 'someuser')
self.assertEqual(url.to_text(),
'http://someuser:@example.com/some-segment@ignore')
self.assertEqual(
url.replace(userinfo=u"someuser").to_text(),
'http://someuser@example.com/some-segment@ignore'
)
def test_portText(self):
"""
L{URL.from_text} parses custom port numbers as integers.
"""
portURL = URL.from_text(u"http://www.example.com:8080/")
self.assertEqual(portURL.port, 8080)
self.assertEqual(portURL.to_text(), u"http://www.example.com:8080/")
def test_mailto(self):
"""
Although L{URL} instances are mainly for dealing with HTTP, other
schemes (such as C{mailto:}) should work as well. For example,
L{URL.from_text}/L{URL.to_text} round-trips cleanly for a C{mailto:} URL
representing an email address.
"""
self.assertEqual(URL.from_text(u"mailto:user@example.com").to_text(),
u"mailto:user@example.com")
def test_queryIterable(self):
"""
When a L{URL} is created with a C{query} argument, the C{query}
argument is converted into an N-tuple of 2-tuples, sensibly
handling dictionaries.
"""
expected = (('alpha', 'beta'),)
url = URL(query=[['alpha', 'beta']])
self.assertEqual(url.query, expected)
url = URL(query={'alpha': 'beta'})
self.assertEqual(url.query, expected)
def test_pathIterable(self):
"""
When a L{URL} is created with a C{path} argument, the C{path} is
converted into a tuple.
"""
url = URL(path=['hello', 'world'])
self.assertEqual(url.path, ('hello', 'world'))
def test_invalidArguments(self):
"""
Passing an argument of the wrong type to any of the constructor
arguments of L{URL} will raise a descriptive L{TypeError}.
L{URL} typechecks very aggressively to ensure that its constitutent
parts are all properly immutable and to prevent confusing errors when
bad data crops up in a method call long after the code that called the
constructor is off the stack.
"""
class Unexpected(object):
def __str__(self):
return "wrong"
def __repr__(self):
return ""
defaultExpectation = "unicode" if bytes is str else "str"
def assertRaised(raised, expectation, name):
self.assertEqual(str(raised.exception),
"expected {0} for {1}, got {2}".format(
expectation,
name, ""))
def check(param, expectation=defaultExpectation):
with self.assertRaises(TypeError) as raised:
URL(**{param: Unexpected()})
assertRaised(raised, expectation, param)
check("scheme")
check("host")
check("fragment")
check("rooted", "bool")
check("userinfo")
check("port", "int or NoneType")
with self.assertRaises(TypeError) as raised:
URL(path=[Unexpected()])
assertRaised(raised, defaultExpectation, "path segment")
with self.assertRaises(TypeError) as raised:
URL(query=[(u"name", Unexpected())])
assertRaised(raised, defaultExpectation + " or NoneType",
"query parameter value")
with self.assertRaises(TypeError) as raised:
URL(query=[(Unexpected(), u"value")])
assertRaised(raised, defaultExpectation, "query parameter name")
# No custom error message for this one, just want to make sure
# non-2-tuples don't get through.
with self.assertRaises(TypeError):
URL(query=[Unexpected()])
with self.assertRaises(ValueError):
URL(query=[('k', 'v', 'vv')])
with self.assertRaises(ValueError):
URL(query=[('k',)])
url = URL.from_text("https://valid.example.com/")
with self.assertRaises(TypeError) as raised:
url.child(Unexpected())
assertRaised(raised, defaultExpectation, "path segment")
with self.assertRaises(TypeError) as raised:
url.sibling(Unexpected())
assertRaised(raised, defaultExpectation, "path segment")
with self.assertRaises(TypeError) as raised:
url.click(Unexpected())
assertRaised(raised, defaultExpectation, "relative URL")
def test_technicallyTextIsIterableBut(self):
"""
Technically, L{str} (or L{unicode}, as appropriate) is iterable, but
C{URL(path="foo")} resulting in C{URL.from_text("f/o/o")} is never what
you want.
"""
with self.assertRaises(TypeError) as raised:
URL(path='foo')
self.assertEqual(
str(raised.exception),
"expected iterable of text for path, not: {0}"
.format(repr('foo'))
)
def test_netloc(self):
url = URL(scheme='https')
self.assertEqual(url.uses_netloc, True)
url = URL(scheme='git+https')
self.assertEqual(url.uses_netloc, True)
url = URL(scheme='mailto')
self.assertEqual(url.uses_netloc, False)
url = URL(scheme='ztp')
self.assertEqual(url.uses_netloc, None)
url = URL.from_text('ztp://test.com')
self.assertEqual(url.uses_netloc, True)
url = URL.from_text('ztp:test:com')
self.assertEqual(url.uses_netloc, False)
def test_ipv6_with_port(self):
t = 'https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:80/'
url = URL.from_text(t)
assert url.host == '2001:0db8:85a3:0000:0000:8a2e:0370:7334'
assert url.port == 80
assert SCHEME_PORT_MAP[url.scheme] != url.port
def test_basic(self):
text = 'https://user:pass@example.com/path/to/here?k=v#nice'
url = URL.from_text(text)
assert url.scheme == 'https'
assert url.userinfo == 'user:pass'
assert url.host == 'example.com'
assert url.path == ('path', 'to', 'here')
assert url.fragment == 'nice'
text = 'https://user:pass@127.0.0.1/path/to/here?k=v#nice'
url = URL.from_text(text)
assert url.scheme == 'https'
assert url.userinfo == 'user:pass'
assert url.host == '127.0.0.1'
assert url.path == ('path', 'to', 'here')
text = 'https://user:pass@[::1]/path/to/here?k=v#nice'
url = URL.from_text(text)
assert url.scheme == 'https'
assert url.userinfo == 'user:pass'
assert url.host == '::1'
assert url.path == ('path', 'to', 'here')
def test_invalid_url(self):
self.assertRaises(URLParseError, URL.from_text, '#\n\n')
def test_invalid_authority_url(self):
self.assertRaises(URLParseError, URL.from_text, 'http://abc:\n\n/#')
def test_invalid_ipv6(self):
invalid_ipv6_ips = ['2001::0234:C1ab::A0:aabc:003F',
'2001::1::3F',
':',
'::::',
'::256.0.0.1']
for ip in invalid_ipv6_ips:
url_text = 'http://[' + ip + ']'
self.assertRaises(socket.error, inet_pton,
socket.AF_INET6, ip)
self.assertRaises(URLParseError, URL.from_text, url_text)
def test_invalid_port(self):
self.assertRaises(URLParseError, URL.from_text, 'ftp://portmouth:smash')
self.assertRaises(ValueError, URL.from_text,
'http://reader.googlewebsite.com:neverforget')
def test_idna(self):
u1 = URL.from_text('http://bücher.ch')
self.assertEquals(u1.host, 'bücher.ch')
self.assertEquals(u1.to_text(), 'http://bücher.ch')
self.assertEquals(u1.to_uri().to_text(), 'http://xn--bcher-kva.ch')
u2 = URL.from_text('https://xn--bcher-kva.ch')
self.assertEquals(u2.host, 'xn--bcher-kva.ch')
self.assertEquals(u2.to_text(), 'https://xn--bcher-kva.ch')
self.assertEquals(u2.to_iri().to_text(), u'https://bücher.ch')
def test_netloc_slashes(self):
# basic sanity checks
url = URL.from_text('mailto:mahmoud@hatnote.com')
self.assertEquals(url.scheme, 'mailto')
self.assertEquals(url.to_text(), 'mailto:mahmoud@hatnote.com')
url = URL.from_text('http://hatnote.com')
self.assertEquals(url.scheme, 'http')
self.assertEquals(url.to_text(), 'http://hatnote.com')
# test that unrecognized schemes stay consistent with '//'
url = URL.from_text('newscheme:a:b:c')
self.assertEquals(url.scheme, 'newscheme')
self.assertEquals(url.to_text(), 'newscheme:a:b:c')
url = URL.from_text('newerscheme://a/b/c')
self.assertEquals(url.scheme, 'newerscheme')
self.assertEquals(url.to_text(), 'newerscheme://a/b/c')
# test that reasonable guesses are made
url = URL.from_text('git+ftp://gitstub.biz/glyph/lefkowitz')
self.assertEquals(url.scheme, 'git+ftp')
self.assertEquals(url.to_text(),
'git+ftp://gitstub.biz/glyph/lefkowitz')
url = URL.from_text('what+mailto:freerealestate@enotuniq.org')
self.assertEquals(url.scheme, 'what+mailto')
self.assertEquals(url.to_text(),
'what+mailto:freerealestate@enotuniq.org')
url = URL(scheme='ztp', path=('x', 'y', 'z'), rooted=True)
self.assertEquals(url.to_text(), 'ztp:/x/y/z')
# also works when the input doesn't include '//'
url = URL(scheme='git+ftp', path=('x', 'y', 'z' ,''),
rooted=True, uses_netloc=True)
# broken bc urlunsplit
self.assertEquals(url.to_text(), 'git+ftp:///x/y/z/')
# really why would this ever come up but ok
url = URL.from_text('file:///path/to/heck')
url2 = url.replace(scheme='mailto')
self.assertEquals(url2.to_text(), 'mailto:/path/to/heck')
url_text = 'unregisteredscheme:///a/b/c'
url = URL.from_text(url_text)
no_netloc_url = url.replace(uses_netloc=False)
self.assertEquals(no_netloc_url.to_text(), 'unregisteredscheme:/a/b/c')
netloc_url = url.replace(uses_netloc=True)
self.assertEquals(netloc_url.to_text(), url_text)
return
def test_wrong_constructor(self):
with self.assertRaises(ValueError):
# whole URL not allowed
URL(BASIC_URL)
with self.assertRaises(ValueError):
# explicitly bad scheme not allowed
URL('HTTP_____more_like_imHoTTeP')
def test_encoded_userinfo(self):
url = URL.from_text('http://user:pass@example.com')
assert url.userinfo == 'user:pass'
url = url.replace(userinfo='us%20her:pass')
iri = url.to_iri()
assert iri.to_text(with_password=True) == 'http://us her:pass@example.com'
assert iri.to_text(with_password=False) == 'http://us her:@example.com'
assert iri.to_uri().to_text(with_password=True) == 'http://us%20her:pass@example.com'
def test_hash(self):
url_map = {}
url1 = URL.from_text('http://blog.hatnote.com/ask?utm_source=geocity')
assert hash(url1) == hash(url1) # sanity
url_map[url1] = 1
url2 = URL.from_text('http://blog.hatnote.com/ask')
url2 = url2.set('utm_source', 'geocity')
url_map[url2] = 2
assert len(url_map) == 1
assert list(url_map.values()) == [2]
assert hash(URL()) == hash(URL()) # slightly more sanity
def test_dir(self):
url = URL()
res = dir(url)
assert len(res) > 15
# twisted compat
assert 'fromText' not in res
assert 'asText' not in res
assert 'asURI' not in res
assert 'asIRI' not in res
def test_twisted_compat(self):
url = URL.fromText(u'http://example.com/a%20té%C3%A9st')
assert url.asText() == 'http://example.com/a%20té%C3%A9st'
assert url.asURI().asText() == 'http://example.com/a%20t%C3%A9%C3%A9st'
# TODO: assert url.asIRI().asText() == u'http://example.com/a%20téést'
def test_set_ordering(self):
# TODO
url = URL.from_text('http://example.com/?a=b&c')
url = url.set(u'x', u'x')
url = url.add(u'x', u'y')
assert url.to_text() == u'http://example.com/?a=b&x=x&c&x=y'
# Would expect:
# assert url.to_text() == u'http://example.com/?a=b&c&x=x&x=y'
def test_schemeless_path(self):
"See issue #4"
u1 = URL.from_text("urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob")
u2 = URL.from_text(u1.to_text())
assert u1 == u2 # sanity testing roundtripping
u3 = URL.from_text(u1.to_iri().to_text())
assert u1 == u3
assert u2 == u3
# test that colons are ok past the first segment
u4 = URL.from_text("first-segment/urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob")
u5 = u4.to_iri()
assert u5.to_text() == u'first-segment/urn:ietf:wg:oauth:2.0:oob'
u6 = URL.from_text(u5.to_text()).to_uri()
assert u5 == u6 # colons stay decoded bc they're not in the first seg
def test_emoji_domain(self):
"See issue #7, affecting only narrow builds (2.6-3.3)"
url = URL.from_text('https://xn--vi8hiv.ws')
iri = url.to_iri()
iri.to_text()
# as long as we don't get ValueErrors, we're good
def test_delim_in_param(self):
"Per issue #6 and #8"
self.assertRaises(ValueError, URL, scheme=u'http', host=u'a/c')
self.assertRaises(ValueError, URL, path=(u"?",))
self.assertRaises(ValueError, URL, path=(u"#",))
self.assertRaises(ValueError, URL, query=((u"&", "test")))
def test_empty_paths_eq(self):
u1 = URL.from_text('http://example.com/')
u2 = URL.from_text('http://example.com')
assert u1 == u2
u1 = URL.from_text('http://example.com')
u2 = URL.from_text('http://example.com')
assert u1 == u2
u1 = URL.from_text('http://example.com')
u2 = URL.from_text('http://example.com/')
assert u1 == u2
u1 = URL.from_text('http://example.com/')
u2 = URL.from_text('http://example.com/')
assert u1 == u2
def test_from_text_type(self):
assert URL.from_text(u'#ok').fragment == u'ok' # sanity
self.assertRaises(TypeError, URL.from_text, b'bytes://x.y.z')
self.assertRaises(TypeError, URL.from_text, object())
def test_from_text_bad_authority(self):
# bad ipv6 brackets
self.assertRaises(URLParseError, URL.from_text, 'http://[::1/')
self.assertRaises(URLParseError, URL.from_text, 'http://::1]/')
self.assertRaises(URLParseError, URL.from_text, 'http://[[::1]/')
self.assertRaises(URLParseError, URL.from_text, 'http://[::1]]/')
# empty port
self.assertRaises(URLParseError, URL.from_text, 'http://127.0.0.1:')
# non-integer port
self.assertRaises(URLParseError, URL.from_text, 'http://127.0.0.1:hi')
# extra port colon (makes for an invalid host)
self.assertRaises(URLParseError, URL.from_text, 'http://127.0.0.1::80')
def test_normalize(self):
url = URL.from_text('HTTP://Example.com/A%61/./../A%61?B%62=C%63#D%64')
assert url.get('Bb') == []
assert url.get('B%62') == ['C%63']
assert len(url.path) == 4
# test that most expected normalizations happen
norm_url = url.normalize()
assert norm_url.scheme == 'http'
assert norm_url.host == 'example.com'
assert norm_url.path == ('Aa',)
assert norm_url.get('Bb') == ['Cc']
assert norm_url.fragment == 'Dd'
assert norm_url.to_text() == 'http://example.com/Aa?Bb=Cc#Dd'
# test that flags work
noop_norm_url = url.normalize(scheme=False, host=False,
path=False, query=False, fragment=False)
assert noop_norm_url == url
# test that empty paths get at least one slash
slashless_url = URL.from_text('http://example.io')
slashful_url = slashless_url.normalize()
assert slashful_url.to_text() == 'http://example.io/'
# test case normalization for percent encoding
delimited_url = URL.from_text('/a%2fb/cd%3f?k%3d=v%23#test')
norm_delimited_url = delimited_url.normalize()
assert norm_delimited_url.to_text() == '/a%2Fb/cd%3F?k%3D=v%23#test'
# test invalid percent encoding during normalize
assert URL(path=('', '%te%sts')).normalize(percents=False).to_text() == '/%te%sts'
assert URL(path=('', '%te%sts')).normalize().to_text() == '/%25te%25sts'
percenty_url = URL(scheme='ftp', path=['%%%', '%a%b'], query=[('%', '%%')], fragment='%', userinfo='%:%')
assert percenty_url.to_text(with_password=True) == 'ftp://%:%@/%%%/%a%b?%=%%#%'
assert percenty_url.normalize().to_text(with_password=True) == 'ftp://%25:%25@/%25%25%25/%25a%25b?%25=%25%25#%25'
def test_str(self):
# see also issue #49
text = u'http://example.com/á/y%20a%20y/?b=%25'
url = URL.from_text(text)
assert unicode(url) == text
assert bytes(url) == b'http://example.com/%C3%A1/y%20a%20y/?b=%25'
if PY2:
assert isinstance(str(url), bytes)
assert isinstance(unicode(url), unicode)
else:
assert isinstance(str(url), unicode)
assert isinstance(bytes(url), bytes)
def test_idna_corners(self):
text = u'http://abé.com/'
url = URL.from_text(text)
assert url.to_iri().host == u'abé.com'
assert url.to_uri().host == u'xn--ab-cja.com'
url = URL.from_text("http://ドメイン.テスト.co.jp#test")
assert url.to_iri().host == u'ドメイン.テスト.co.jp'
assert url.to_uri().host == u'xn--eckwd4c7c.xn--zckzah.co.jp'
assert url.to_uri().get_decoded_url().host == u'ドメイン.テスト.co.jp'
assert URL.from_text('http://Example.com').to_uri().get_decoded_url().host == 'example.com'
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink-19.0.0.dist-info/DESCRIPTION.rst
================================================
The humble, but powerful, URL runs everything around us. Chances
are you've used several just to read this text.
Hyperlink is a featureful, pure-Python implementation of the URL, with
an emphasis on correctness. BSD licensed.
See the docs at http://hyperlink.readthedocs.io.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink-19.0.0.dist-info/INSTALLER
================================================
pip
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink-19.0.0.dist-info/METADATA
================================================
Metadata-Version: 2.0
Name: hyperlink
Version: 19.0.0
Summary: A featureful, immutable, and correct URL for Python.
Home-page: https://github.com/python-hyper/hyperlink
Author: Mahmoud Hashemi and Glyph Lefkowitz
Author-email: mahmoud@hatnote.com
License: MIT
Platform: any
Classifier: Topic :: Utilities
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries
Classifier: Development Status :: 5 - Production/Stable
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: Implementation :: PyPy
Requires-Dist: idna (>=2.5)
The humble, but powerful, URL runs everything around us. Chances
are you've used several just to read this text.
Hyperlink is a featureful, pure-Python implementation of the URL, with
an emphasis on correctness. BSD licensed.
See the docs at http://hyperlink.readthedocs.io.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink-19.0.0.dist-info/RECORD
================================================
hyperlink-19.0.0.dist-info/DESCRIPTION.rst,sha256=a-0GCP8glYZ0Ysq4Y0mPEe6VJHqJNsGdheikkI7rwCo,279
hyperlink-19.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
hyperlink-19.0.0.dist-info/METADATA,sha256=y172hVTAqkayU3cFJRIJNy5At7oX9iecXN70uD1tY68,1087
hyperlink-19.0.0.dist-info/RECORD,,
hyperlink-19.0.0.dist-info/WHEEL,sha256=5wvfB7GvgZAbKBSE9uX9Zbi6LCL-_KgezgHblXhCRnM,113
hyperlink-19.0.0.dist-info/metadata.json,sha256=JAh7SySskyDcNAPuBXetb6bTuS_-euZRkk75-LVtNBI,983
hyperlink-19.0.0.dist-info/top_level.txt,sha256=qKx9FGU_zxD9mGqiFgleNejfO4AwPY7duhQPaZ30U_M,10
hyperlink/__init__.py,sha256=OFqG_8hDTyyc8MmhVR-LyXL-aShz_Y9Qg98__-vcfTE,302
hyperlink/__pycache__/__init__.cpython-36.pyc,,
hyperlink/__pycache__/_url.cpython-36.pyc,,
hyperlink/_url.py,sha256=JW1raJr9hSmMyqDi_1GTgo0oes2RGL_zsEXhkaQLHKE,72479
hyperlink/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
hyperlink/test/__pycache__/__init__.cpython-36.pyc,,
hyperlink/test/__pycache__/common.cpython-36.pyc,,
hyperlink/test/__pycache__/test_common.cpython-36.pyc,,
hyperlink/test/__pycache__/test_decoded_url.cpython-36.pyc,,
hyperlink/test/__pycache__/test_parse.cpython-36.pyc,,
hyperlink/test/__pycache__/test_scheme_registration.cpython-36.pyc,,
hyperlink/test/__pycache__/test_url.cpython-36.pyc,,
hyperlink/test/common.py,sha256=fZ0gLTlEC1YFnlyn8Hc7_aJJCEGadL1Glw3BVtIvOkQ,2108
hyperlink/test/test_common.py,sha256=6wiI5TjCYO0cyJwPXSL3TFTlkaSyGYGem5_uGIN-6p8,3399
hyperlink/test/test_decoded_url.py,sha256=2aF0fxCJXVjSdownHyD7y-HMnlsnRnsHl4RPOPdKYpM,6259
hyperlink/test/test_parse.py,sha256=HOF7Ns2tGnXUDrX5i8apyVEfnqsiuCtHu2_9uueY5xg,1081
hyperlink/test/test_scheme_registration.py,sha256=cRlrJVt3aFCAYOpz6rqSf9YHFBgjsimbfNdW8PYqbfM,2328
hyperlink/test/test_url.py,sha256=a8mHV7_VfsW4_Uim13q3PSvmBCMLHut_lu9b4zFv8W4,47162
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink-19.0.0.dist-info/WHEEL
================================================
Wheel-Version: 1.0
Generator: bdist_wheel (0.30.0.a0)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink-19.0.0.dist-info/metadata.json
================================================
{"classifiers": ["Topic :: Utilities", "Intended Audience :: Developers", "Topic :: Software Development :: Libraries", "Development Status :: 5 - Production/Stable", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: PyPy"], "extensions": {"python.details": {"contacts": [{"email": "mahmoud@hatnote.com", "name": "Mahmoud Hashemi and Glyph Lefkowitz", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/python-hyper/hyperlink"}}}, "extras": [], "generator": "bdist_wheel (0.30.0.a0)", "license": "MIT", "metadata_version": "2.0", "name": "hyperlink", "platform": "any", "run_requires": [{"requires": ["idna (>=2.5)"]}], "summary": "A featureful, immutable, and correct URL for Python.", "version": "19.0.0"}
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/hyperlink-19.0.0.dist-info/top_level.txt
================================================
hyperlink
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/idna/__init__.py
================================================
from .package_data import __version__
from .core import *
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/idna/codec.py
================================================
from .core import encode, decode, alabel, ulabel, IDNAError
import codecs
import re
_unicode_dots_re = re.compile(u'[\u002e\u3002\uff0e\uff61]')
class Codec(codecs.Codec):
def encode(self, data, errors='strict'):
if errors != 'strict':
raise IDNAError("Unsupported error handling \"{0}\"".format(errors))
if not data:
return "", 0
return encode(data), len(data)
def decode(self, data, errors='strict'):
if errors != 'strict':
raise IDNAError("Unsupported error handling \"{0}\"".format(errors))
if not data:
return u"", 0
return decode(data), len(data)
class IncrementalEncoder(codecs.BufferedIncrementalEncoder):
def _buffer_encode(self, data, errors, final):
if errors != 'strict':
raise IDNAError("Unsupported error handling \"{0}\"".format(errors))
if not data:
return ("", 0)
labels = _unicode_dots_re.split(data)
trailing_dot = u''
if labels:
if not labels[-1]:
trailing_dot = '.'
del labels[-1]
elif not final:
# Keep potentially unfinished label until the next call
del labels[-1]
if labels:
trailing_dot = '.'
result = []
size = 0
for label in labels:
result.append(alabel(label))
if size:
size += 1
size += len(label)
# Join with U+002E
result = ".".join(result) + trailing_dot
size += len(trailing_dot)
return (result, size)
class IncrementalDecoder(codecs.BufferedIncrementalDecoder):
def _buffer_decode(self, data, errors, final):
if errors != 'strict':
raise IDNAError("Unsupported error handling \"{0}\"".format(errors))
if not data:
return (u"", 0)
# IDNA allows decoding to operate on Unicode strings, too.
if isinstance(data, unicode):
labels = _unicode_dots_re.split(data)
else:
# Must be ASCII string
data = str(data)
unicode(data, "ascii")
labels = data.split(".")
trailing_dot = u''
if labels:
if not labels[-1]:
trailing_dot = u'.'
del labels[-1]
elif not final:
# Keep potentially unfinished label until the next call
del labels[-1]
if labels:
trailing_dot = u'.'
result = []
size = 0
for label in labels:
result.append(ulabel(label))
if size:
size += 1
size += len(label)
result = u".".join(result) + trailing_dot
size += len(trailing_dot)
return (result, size)
class StreamWriter(Codec, codecs.StreamWriter):
pass
class StreamReader(Codec, codecs.StreamReader):
pass
def getregentry():
return codecs.CodecInfo(
name='idna',
encode=Codec().encode,
decode=Codec().decode,
incrementalencoder=IncrementalEncoder,
incrementaldecoder=IncrementalDecoder,
streamwriter=StreamWriter,
streamreader=StreamReader,
)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/idna/compat.py
================================================
from .core import *
from .codec import *
def ToASCII(label):
return encode(label)
def ToUnicode(label):
return decode(label)
def nameprep(s):
raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol")
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/idna/core.py
================================================
from . import idnadata
import bisect
import unicodedata
import re
import sys
from .intranges import intranges_contain
_virama_combining_class = 9
_alabel_prefix = b'xn--'
_unicode_dots_re = re.compile(u'[\u002e\u3002\uff0e\uff61]')
if sys.version_info[0] == 3:
unicode = str
unichr = chr
class IDNAError(UnicodeError):
""" Base exception for all IDNA-encoding related problems """
pass
class IDNABidiError(IDNAError):
""" Exception when bidirectional requirements are not satisfied """
pass
class InvalidCodepoint(IDNAError):
""" Exception when a disallowed or unallocated codepoint is used """
pass
class InvalidCodepointContext(IDNAError):
""" Exception when the codepoint is not valid in the context it is used """
pass
def _combining_class(cp):
v = unicodedata.combining(unichr(cp))
if v == 0:
if not unicodedata.name(unichr(cp)):
raise ValueError("Unknown character in unicodedata")
return v
def _is_script(cp, script):
return intranges_contain(ord(cp), idnadata.scripts[script])
def _punycode(s):
return s.encode('punycode')
def _unot(s):
return 'U+{0:04X}'.format(s)
def valid_label_length(label):
if len(label) > 63:
return False
return True
def valid_string_length(label, trailing_dot):
if len(label) > (254 if trailing_dot else 253):
return False
return True
def check_bidi(label, check_ltr=False):
# Bidi rules should only be applied if string contains RTL characters
bidi_label = False
for (idx, cp) in enumerate(label, 1):
direction = unicodedata.bidirectional(cp)
if direction == '':
# String likely comes from a newer version of Unicode
raise IDNABidiError('Unknown directionality in label {0} at position {1}'.format(repr(label), idx))
if direction in ['R', 'AL', 'AN']:
bidi_label = True
if not bidi_label and not check_ltr:
return True
# Bidi rule 1
direction = unicodedata.bidirectional(label[0])
if direction in ['R', 'AL']:
rtl = True
elif direction == 'L':
rtl = False
else:
raise IDNABidiError('First codepoint in label {0} must be directionality L, R or AL'.format(repr(label)))
valid_ending = False
number_type = False
for (idx, cp) in enumerate(label, 1):
direction = unicodedata.bidirectional(cp)
if rtl:
# Bidi rule 2
if not direction in ['R', 'AL', 'AN', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']:
raise IDNABidiError('Invalid direction for codepoint at position {0} in a right-to-left label'.format(idx))
# Bidi rule 3
if direction in ['R', 'AL', 'EN', 'AN']:
valid_ending = True
elif direction != 'NSM':
valid_ending = False
# Bidi rule 4
if direction in ['AN', 'EN']:
if not number_type:
number_type = direction
else:
if number_type != direction:
raise IDNABidiError('Can not mix numeral types in a right-to-left label')
else:
# Bidi rule 5
if not direction in ['L', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']:
raise IDNABidiError('Invalid direction for codepoint at position {0} in a left-to-right label'.format(idx))
# Bidi rule 6
if direction in ['L', 'EN']:
valid_ending = True
elif direction != 'NSM':
valid_ending = False
if not valid_ending:
raise IDNABidiError('Label ends with illegal codepoint directionality')
return True
def check_initial_combiner(label):
if unicodedata.category(label[0])[0] == 'M':
raise IDNAError('Label begins with an illegal combining character')
return True
def check_hyphen_ok(label):
if label[2:4] == '--':
raise IDNAError('Label has disallowed hyphens in 3rd and 4th position')
if label[0] == '-' or label[-1] == '-':
raise IDNAError('Label must not start or end with a hyphen')
return True
def check_nfc(label):
if unicodedata.normalize('NFC', label) != label:
raise IDNAError('Label must be in Normalization Form C')
def valid_contextj(label, pos):
cp_value = ord(label[pos])
if cp_value == 0x200c:
if pos > 0:
if _combining_class(ord(label[pos - 1])) == _virama_combining_class:
return True
ok = False
for i in range(pos-1, -1, -1):
joining_type = idnadata.joining_types.get(ord(label[i]))
if joining_type == ord('T'):
continue
if joining_type in [ord('L'), ord('D')]:
ok = True
break
if not ok:
return False
ok = False
for i in range(pos+1, len(label)):
joining_type = idnadata.joining_types.get(ord(label[i]))
if joining_type == ord('T'):
continue
if joining_type in [ord('R'), ord('D')]:
ok = True
break
return ok
if cp_value == 0x200d:
if pos > 0:
if _combining_class(ord(label[pos - 1])) == _virama_combining_class:
return True
return False
else:
return False
def valid_contexto(label, pos, exception=False):
cp_value = ord(label[pos])
if cp_value == 0x00b7:
if 0 < pos < len(label)-1:
if ord(label[pos - 1]) == 0x006c and ord(label[pos + 1]) == 0x006c:
return True
return False
elif cp_value == 0x0375:
if pos < len(label)-1 and len(label) > 1:
return _is_script(label[pos + 1], 'Greek')
return False
elif cp_value == 0x05f3 or cp_value == 0x05f4:
if pos > 0:
return _is_script(label[pos - 1], 'Hebrew')
return False
elif cp_value == 0x30fb:
for cp in label:
if cp == u'\u30fb':
continue
if _is_script(cp, 'Hiragana') or _is_script(cp, 'Katakana') or _is_script(cp, 'Han'):
return True
return False
elif 0x660 <= cp_value <= 0x669:
for cp in label:
if 0x6f0 <= ord(cp) <= 0x06f9:
return False
return True
elif 0x6f0 <= cp_value <= 0x6f9:
for cp in label:
if 0x660 <= ord(cp) <= 0x0669:
return False
return True
def check_label(label):
if isinstance(label, (bytes, bytearray)):
label = label.decode('utf-8')
if len(label) == 0:
raise IDNAError('Empty Label')
check_nfc(label)
check_hyphen_ok(label)
check_initial_combiner(label)
for (pos, cp) in enumerate(label):
cp_value = ord(cp)
if intranges_contain(cp_value, idnadata.codepoint_classes['PVALID']):
continue
elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTJ']):
try:
if not valid_contextj(label, pos):
raise InvalidCodepointContext('Joiner {0} not allowed at position {1} in {2}'.format(
_unot(cp_value), pos+1, repr(label)))
except ValueError:
raise IDNAError('Unknown codepoint adjacent to joiner {0} at position {1} in {2}'.format(
_unot(cp_value), pos+1, repr(label)))
elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTO']):
if not valid_contexto(label, pos):
raise InvalidCodepointContext('Codepoint {0} not allowed at position {1} in {2}'.format(_unot(cp_value), pos+1, repr(label)))
else:
raise InvalidCodepoint('Codepoint {0} at position {1} of {2} not allowed'.format(_unot(cp_value), pos+1, repr(label)))
check_bidi(label)
def alabel(label):
try:
label = label.encode('ascii')
ulabel(label)
if not valid_label_length(label):
raise IDNAError('Label too long')
return label
except UnicodeEncodeError:
pass
if not label:
raise IDNAError('No Input')
label = unicode(label)
check_label(label)
label = _punycode(label)
label = _alabel_prefix + label
if not valid_label_length(label):
raise IDNAError('Label too long')
return label
def ulabel(label):
if not isinstance(label, (bytes, bytearray)):
try:
label = label.encode('ascii')
except UnicodeEncodeError:
check_label(label)
return label
label = label.lower()
if label.startswith(_alabel_prefix):
label = label[len(_alabel_prefix):]
else:
check_label(label)
return label.decode('ascii')
label = label.decode('punycode')
check_label(label)
return label
def uts46_remap(domain, std3_rules=True, transitional=False):
"""Re-map the characters in the string according to UTS46 processing."""
from .uts46data import uts46data
output = u""
try:
for pos, char in enumerate(domain):
code_point = ord(char)
uts46row = uts46data[code_point if code_point < 256 else
bisect.bisect_left(uts46data, (code_point, "Z")) - 1]
status = uts46row[1]
replacement = uts46row[2] if len(uts46row) == 3 else None
if (status == "V" or
(status == "D" and not transitional) or
(status == "3" and not std3_rules and replacement is None)):
output += char
elif replacement is not None and (status == "M" or
(status == "3" and not std3_rules) or
(status == "D" and transitional)):
output += replacement
elif status != "I":
raise IndexError()
return unicodedata.normalize("NFC", output)
except IndexError:
raise InvalidCodepoint(
"Codepoint {0} not allowed at position {1} in {2}".format(
_unot(code_point), pos + 1, repr(domain)))
def encode(s, strict=False, uts46=False, std3_rules=False, transitional=False):
if isinstance(s, (bytes, bytearray)):
s = s.decode("ascii")
if uts46:
s = uts46_remap(s, std3_rules, transitional)
trailing_dot = False
result = []
if strict:
labels = s.split('.')
else:
labels = _unicode_dots_re.split(s)
if not labels or labels == ['']:
raise IDNAError('Empty domain')
if labels[-1] == '':
del labels[-1]
trailing_dot = True
for label in labels:
s = alabel(label)
if s:
result.append(s)
else:
raise IDNAError('Empty label')
if trailing_dot:
result.append(b'')
s = b'.'.join(result)
if not valid_string_length(s, trailing_dot):
raise IDNAError('Domain too long')
return s
def decode(s, strict=False, uts46=False, std3_rules=False):
if isinstance(s, (bytes, bytearray)):
s = s.decode("ascii")
if uts46:
s = uts46_remap(s, std3_rules, False)
trailing_dot = False
result = []
if not strict:
labels = _unicode_dots_re.split(s)
else:
labels = s.split(u'.')
if not labels or labels == ['']:
raise IDNAError('Empty domain')
if not labels[-1]:
del labels[-1]
trailing_dot = True
for label in labels:
s = ulabel(label)
if s:
result.append(s)
else:
raise IDNAError('Empty label')
if trailing_dot:
result.append(u'')
return u'.'.join(result)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/idna/idnadata.py
================================================
# This file is automatically generated by tools/idna-data
__version__ = "11.0.0"
scripts = {
'Greek': (
0x37000000374,
0x37500000378,
0x37a0000037e,
0x37f00000380,
0x38400000385,
0x38600000387,
0x3880000038b,
0x38c0000038d,
0x38e000003a2,
0x3a3000003e2,
0x3f000000400,
0x1d2600001d2b,
0x1d5d00001d62,
0x1d6600001d6b,
0x1dbf00001dc0,
0x1f0000001f16,
0x1f1800001f1e,
0x1f2000001f46,
0x1f4800001f4e,
0x1f5000001f58,
0x1f5900001f5a,
0x1f5b00001f5c,
0x1f5d00001f5e,
0x1f5f00001f7e,
0x1f8000001fb5,
0x1fb600001fc5,
0x1fc600001fd4,
0x1fd600001fdc,
0x1fdd00001ff0,
0x1ff200001ff5,
0x1ff600001fff,
0x212600002127,
0xab650000ab66,
0x101400001018f,
0x101a0000101a1,
0x1d2000001d246,
),
'Han': (
0x2e8000002e9a,
0x2e9b00002ef4,
0x2f0000002fd6,
0x300500003006,
0x300700003008,
0x30210000302a,
0x30380000303c,
0x340000004db6,
0x4e0000009ff0,
0xf9000000fa6e,
0xfa700000fada,
0x200000002a6d7,
0x2a7000002b735,
0x2b7400002b81e,
0x2b8200002cea2,
0x2ceb00002ebe1,
0x2f8000002fa1e,
),
'Hebrew': (
0x591000005c8,
0x5d0000005eb,
0x5ef000005f5,
0xfb1d0000fb37,
0xfb380000fb3d,
0xfb3e0000fb3f,
0xfb400000fb42,
0xfb430000fb45,
0xfb460000fb50,
),
'Hiragana': (
0x304100003097,
0x309d000030a0,
0x1b0010001b11f,
0x1f2000001f201,
),
'Katakana': (
0x30a1000030fb,
0x30fd00003100,
0x31f000003200,
0x32d0000032ff,
0x330000003358,
0xff660000ff70,
0xff710000ff9e,
0x1b0000001b001,
),
}
joining_types = {
0x600: 85,
0x601: 85,
0x602: 85,
0x603: 85,
0x604: 85,
0x605: 85,
0x608: 85,
0x60b: 85,
0x620: 68,
0x621: 85,
0x622: 82,
0x623: 82,
0x624: 82,
0x625: 82,
0x626: 68,
0x627: 82,
0x628: 68,
0x629: 82,
0x62a: 68,
0x62b: 68,
0x62c: 68,
0x62d: 68,
0x62e: 68,
0x62f: 82,
0x630: 82,
0x631: 82,
0x632: 82,
0x633: 68,
0x634: 68,
0x635: 68,
0x636: 68,
0x637: 68,
0x638: 68,
0x639: 68,
0x63a: 68,
0x63b: 68,
0x63c: 68,
0x63d: 68,
0x63e: 68,
0x63f: 68,
0x640: 67,
0x641: 68,
0x642: 68,
0x643: 68,
0x644: 68,
0x645: 68,
0x646: 68,
0x647: 68,
0x648: 82,
0x649: 68,
0x64a: 68,
0x66e: 68,
0x66f: 68,
0x671: 82,
0x672: 82,
0x673: 82,
0x674: 85,
0x675: 82,
0x676: 82,
0x677: 82,
0x678: 68,
0x679: 68,
0x67a: 68,
0x67b: 68,
0x67c: 68,
0x67d: 68,
0x67e: 68,
0x67f: 68,
0x680: 68,
0x681: 68,
0x682: 68,
0x683: 68,
0x684: 68,
0x685: 68,
0x686: 68,
0x687: 68,
0x688: 82,
0x689: 82,
0x68a: 82,
0x68b: 82,
0x68c: 82,
0x68d: 82,
0x68e: 82,
0x68f: 82,
0x690: 82,
0x691: 82,
0x692: 82,
0x693: 82,
0x694: 82,
0x695: 82,
0x696: 82,
0x697: 82,
0x698: 82,
0x699: 82,
0x69a: 68,
0x69b: 68,
0x69c: 68,
0x69d: 68,
0x69e: 68,
0x69f: 68,
0x6a0: 68,
0x6a1: 68,
0x6a2: 68,
0x6a3: 68,
0x6a4: 68,
0x6a5: 68,
0x6a6: 68,
0x6a7: 68,
0x6a8: 68,
0x6a9: 68,
0x6aa: 68,
0x6ab: 68,
0x6ac: 68,
0x6ad: 68,
0x6ae: 68,
0x6af: 68,
0x6b0: 68,
0x6b1: 68,
0x6b2: 68,
0x6b3: 68,
0x6b4: 68,
0x6b5: 68,
0x6b6: 68,
0x6b7: 68,
0x6b8: 68,
0x6b9: 68,
0x6ba: 68,
0x6bb: 68,
0x6bc: 68,
0x6bd: 68,
0x6be: 68,
0x6bf: 68,
0x6c0: 82,
0x6c1: 68,
0x6c2: 68,
0x6c3: 82,
0x6c4: 82,
0x6c5: 82,
0x6c6: 82,
0x6c7: 82,
0x6c8: 82,
0x6c9: 82,
0x6ca: 82,
0x6cb: 82,
0x6cc: 68,
0x6cd: 82,
0x6ce: 68,
0x6cf: 82,
0x6d0: 68,
0x6d1: 68,
0x6d2: 82,
0x6d3: 82,
0x6d5: 82,
0x6dd: 85,
0x6ee: 82,
0x6ef: 82,
0x6fa: 68,
0x6fb: 68,
0x6fc: 68,
0x6ff: 68,
0x70f: 84,
0x710: 82,
0x712: 68,
0x713: 68,
0x714: 68,
0x715: 82,
0x716: 82,
0x717: 82,
0x718: 82,
0x719: 82,
0x71a: 68,
0x71b: 68,
0x71c: 68,
0x71d: 68,
0x71e: 82,
0x71f: 68,
0x720: 68,
0x721: 68,
0x722: 68,
0x723: 68,
0x724: 68,
0x725: 68,
0x726: 68,
0x727: 68,
0x728: 82,
0x729: 68,
0x72a: 82,
0x72b: 68,
0x72c: 82,
0x72d: 68,
0x72e: 68,
0x72f: 82,
0x74d: 82,
0x74e: 68,
0x74f: 68,
0x750: 68,
0x751: 68,
0x752: 68,
0x753: 68,
0x754: 68,
0x755: 68,
0x756: 68,
0x757: 68,
0x758: 68,
0x759: 82,
0x75a: 82,
0x75b: 82,
0x75c: 68,
0x75d: 68,
0x75e: 68,
0x75f: 68,
0x760: 68,
0x761: 68,
0x762: 68,
0x763: 68,
0x764: 68,
0x765: 68,
0x766: 68,
0x767: 68,
0x768: 68,
0x769: 68,
0x76a: 68,
0x76b: 82,
0x76c: 82,
0x76d: 68,
0x76e: 68,
0x76f: 68,
0x770: 68,
0x771: 82,
0x772: 68,
0x773: 82,
0x774: 82,
0x775: 68,
0x776: 68,
0x777: 68,
0x778: 82,
0x779: 82,
0x77a: 68,
0x77b: 68,
0x77c: 68,
0x77d: 68,
0x77e: 68,
0x77f: 68,
0x7ca: 68,
0x7cb: 68,
0x7cc: 68,
0x7cd: 68,
0x7ce: 68,
0x7cf: 68,
0x7d0: 68,
0x7d1: 68,
0x7d2: 68,
0x7d3: 68,
0x7d4: 68,
0x7d5: 68,
0x7d6: 68,
0x7d7: 68,
0x7d8: 68,
0x7d9: 68,
0x7da: 68,
0x7db: 68,
0x7dc: 68,
0x7dd: 68,
0x7de: 68,
0x7df: 68,
0x7e0: 68,
0x7e1: 68,
0x7e2: 68,
0x7e3: 68,
0x7e4: 68,
0x7e5: 68,
0x7e6: 68,
0x7e7: 68,
0x7e8: 68,
0x7e9: 68,
0x7ea: 68,
0x7fa: 67,
0x840: 82,
0x841: 68,
0x842: 68,
0x843: 68,
0x844: 68,
0x845: 68,
0x846: 82,
0x847: 82,
0x848: 68,
0x849: 82,
0x84a: 68,
0x84b: 68,
0x84c: 68,
0x84d: 68,
0x84e: 68,
0x84f: 68,
0x850: 68,
0x851: 68,
0x852: 68,
0x853: 68,
0x854: 82,
0x855: 68,
0x856: 85,
0x857: 85,
0x858: 85,
0x860: 68,
0x861: 85,
0x862: 68,
0x863: 68,
0x864: 68,
0x865: 68,
0x866: 85,
0x867: 82,
0x868: 68,
0x869: 82,
0x86a: 82,
0x8a0: 68,
0x8a1: 68,
0x8a2: 68,
0x8a3: 68,
0x8a4: 68,
0x8a5: 68,
0x8a6: 68,
0x8a7: 68,
0x8a8: 68,
0x8a9: 68,
0x8aa: 82,
0x8ab: 82,
0x8ac: 82,
0x8ad: 85,
0x8ae: 82,
0x8af: 68,
0x8b0: 68,
0x8b1: 82,
0x8b2: 82,
0x8b3: 68,
0x8b4: 68,
0x8b6: 68,
0x8b7: 68,
0x8b8: 68,
0x8b9: 82,
0x8ba: 68,
0x8bb: 68,
0x8bc: 68,
0x8bd: 68,
0x8e2: 85,
0x1806: 85,
0x1807: 68,
0x180a: 67,
0x180e: 85,
0x1820: 68,
0x1821: 68,
0x1822: 68,
0x1823: 68,
0x1824: 68,
0x1825: 68,
0x1826: 68,
0x1827: 68,
0x1828: 68,
0x1829: 68,
0x182a: 68,
0x182b: 68,
0x182c: 68,
0x182d: 68,
0x182e: 68,
0x182f: 68,
0x1830: 68,
0x1831: 68,
0x1832: 68,
0x1833: 68,
0x1834: 68,
0x1835: 68,
0x1836: 68,
0x1837: 68,
0x1838: 68,
0x1839: 68,
0x183a: 68,
0x183b: 68,
0x183c: 68,
0x183d: 68,
0x183e: 68,
0x183f: 68,
0x1840: 68,
0x1841: 68,
0x1842: 68,
0x1843: 68,
0x1844: 68,
0x1845: 68,
0x1846: 68,
0x1847: 68,
0x1848: 68,
0x1849: 68,
0x184a: 68,
0x184b: 68,
0x184c: 68,
0x184d: 68,
0x184e: 68,
0x184f: 68,
0x1850: 68,
0x1851: 68,
0x1852: 68,
0x1853: 68,
0x1854: 68,
0x1855: 68,
0x1856: 68,
0x1857: 68,
0x1858: 68,
0x1859: 68,
0x185a: 68,
0x185b: 68,
0x185c: 68,
0x185d: 68,
0x185e: 68,
0x185f: 68,
0x1860: 68,
0x1861: 68,
0x1862: 68,
0x1863: 68,
0x1864: 68,
0x1865: 68,
0x1866: 68,
0x1867: 68,
0x1868: 68,
0x1869: 68,
0x186a: 68,
0x186b: 68,
0x186c: 68,
0x186d: 68,
0x186e: 68,
0x186f: 68,
0x1870: 68,
0x1871: 68,
0x1872: 68,
0x1873: 68,
0x1874: 68,
0x1875: 68,
0x1876: 68,
0x1877: 68,
0x1878: 68,
0x1880: 85,
0x1881: 85,
0x1882: 85,
0x1883: 85,
0x1884: 85,
0x1885: 84,
0x1886: 84,
0x1887: 68,
0x1888: 68,
0x1889: 68,
0x188a: 68,
0x188b: 68,
0x188c: 68,
0x188d: 68,
0x188e: 68,
0x188f: 68,
0x1890: 68,
0x1891: 68,
0x1892: 68,
0x1893: 68,
0x1894: 68,
0x1895: 68,
0x1896: 68,
0x1897: 68,
0x1898: 68,
0x1899: 68,
0x189a: 68,
0x189b: 68,
0x189c: 68,
0x189d: 68,
0x189e: 68,
0x189f: 68,
0x18a0: 68,
0x18a1: 68,
0x18a2: 68,
0x18a3: 68,
0x18a4: 68,
0x18a5: 68,
0x18a6: 68,
0x18a7: 68,
0x18a8: 68,
0x18aa: 68,
0x200c: 85,
0x200d: 67,
0x202f: 85,
0x2066: 85,
0x2067: 85,
0x2068: 85,
0x2069: 85,
0xa840: 68,
0xa841: 68,
0xa842: 68,
0xa843: 68,
0xa844: 68,
0xa845: 68,
0xa846: 68,
0xa847: 68,
0xa848: 68,
0xa849: 68,
0xa84a: 68,
0xa84b: 68,
0xa84c: 68,
0xa84d: 68,
0xa84e: 68,
0xa84f: 68,
0xa850: 68,
0xa851: 68,
0xa852: 68,
0xa853: 68,
0xa854: 68,
0xa855: 68,
0xa856: 68,
0xa857: 68,
0xa858: 68,
0xa859: 68,
0xa85a: 68,
0xa85b: 68,
0xa85c: 68,
0xa85d: 68,
0xa85e: 68,
0xa85f: 68,
0xa860: 68,
0xa861: 68,
0xa862: 68,
0xa863: 68,
0xa864: 68,
0xa865: 68,
0xa866: 68,
0xa867: 68,
0xa868: 68,
0xa869: 68,
0xa86a: 68,
0xa86b: 68,
0xa86c: 68,
0xa86d: 68,
0xa86e: 68,
0xa86f: 68,
0xa870: 68,
0xa871: 68,
0xa872: 76,
0xa873: 85,
0x10ac0: 68,
0x10ac1: 68,
0x10ac2: 68,
0x10ac3: 68,
0x10ac4: 68,
0x10ac5: 82,
0x10ac6: 85,
0x10ac7: 82,
0x10ac8: 85,
0x10ac9: 82,
0x10aca: 82,
0x10acb: 85,
0x10acc: 85,
0x10acd: 76,
0x10ace: 82,
0x10acf: 82,
0x10ad0: 82,
0x10ad1: 82,
0x10ad2: 82,
0x10ad3: 68,
0x10ad4: 68,
0x10ad5: 68,
0x10ad6: 68,
0x10ad7: 76,
0x10ad8: 68,
0x10ad9: 68,
0x10ada: 68,
0x10adb: 68,
0x10adc: 68,
0x10add: 82,
0x10ade: 68,
0x10adf: 68,
0x10ae0: 68,
0x10ae1: 82,
0x10ae2: 85,
0x10ae3: 85,
0x10ae4: 82,
0x10aeb: 68,
0x10aec: 68,
0x10aed: 68,
0x10aee: 68,
0x10aef: 82,
0x10b80: 68,
0x10b81: 82,
0x10b82: 68,
0x10b83: 82,
0x10b84: 82,
0x10b85: 82,
0x10b86: 68,
0x10b87: 68,
0x10b88: 68,
0x10b89: 82,
0x10b8a: 68,
0x10b8b: 68,
0x10b8c: 82,
0x10b8d: 68,
0x10b8e: 82,
0x10b8f: 82,
0x10b90: 68,
0x10b91: 82,
0x10ba9: 82,
0x10baa: 82,
0x10bab: 82,
0x10bac: 82,
0x10bad: 68,
0x10bae: 68,
0x10baf: 85,
0x10d00: 76,
0x10d01: 68,
0x10d02: 68,
0x10d03: 68,
0x10d04: 68,
0x10d05: 68,
0x10d06: 68,
0x10d07: 68,
0x10d08: 68,
0x10d09: 68,
0x10d0a: 68,
0x10d0b: 68,
0x10d0c: 68,
0x10d0d: 68,
0x10d0e: 68,
0x10d0f: 68,
0x10d10: 68,
0x10d11: 68,
0x10d12: 68,
0x10d13: 68,
0x10d14: 68,
0x10d15: 68,
0x10d16: 68,
0x10d17: 68,
0x10d18: 68,
0x10d19: 68,
0x10d1a: 68,
0x10d1b: 68,
0x10d1c: 68,
0x10d1d: 68,
0x10d1e: 68,
0x10d1f: 68,
0x10d20: 68,
0x10d21: 68,
0x10d22: 82,
0x10d23: 68,
0x10f30: 68,
0x10f31: 68,
0x10f32: 68,
0x10f33: 82,
0x10f34: 68,
0x10f35: 68,
0x10f36: 68,
0x10f37: 68,
0x10f38: 68,
0x10f39: 68,
0x10f3a: 68,
0x10f3b: 68,
0x10f3c: 68,
0x10f3d: 68,
0x10f3e: 68,
0x10f3f: 68,
0x10f40: 68,
0x10f41: 68,
0x10f42: 68,
0x10f43: 68,
0x10f44: 68,
0x10f45: 85,
0x10f51: 68,
0x10f52: 68,
0x10f53: 68,
0x10f54: 82,
0x110bd: 85,
0x110cd: 85,
0x1e900: 68,
0x1e901: 68,
0x1e902: 68,
0x1e903: 68,
0x1e904: 68,
0x1e905: 68,
0x1e906: 68,
0x1e907: 68,
0x1e908: 68,
0x1e909: 68,
0x1e90a: 68,
0x1e90b: 68,
0x1e90c: 68,
0x1e90d: 68,
0x1e90e: 68,
0x1e90f: 68,
0x1e910: 68,
0x1e911: 68,
0x1e912: 68,
0x1e913: 68,
0x1e914: 68,
0x1e915: 68,
0x1e916: 68,
0x1e917: 68,
0x1e918: 68,
0x1e919: 68,
0x1e91a: 68,
0x1e91b: 68,
0x1e91c: 68,
0x1e91d: 68,
0x1e91e: 68,
0x1e91f: 68,
0x1e920: 68,
0x1e921: 68,
0x1e922: 68,
0x1e923: 68,
0x1e924: 68,
0x1e925: 68,
0x1e926: 68,
0x1e927: 68,
0x1e928: 68,
0x1e929: 68,
0x1e92a: 68,
0x1e92b: 68,
0x1e92c: 68,
0x1e92d: 68,
0x1e92e: 68,
0x1e92f: 68,
0x1e930: 68,
0x1e931: 68,
0x1e932: 68,
0x1e933: 68,
0x1e934: 68,
0x1e935: 68,
0x1e936: 68,
0x1e937: 68,
0x1e938: 68,
0x1e939: 68,
0x1e93a: 68,
0x1e93b: 68,
0x1e93c: 68,
0x1e93d: 68,
0x1e93e: 68,
0x1e93f: 68,
0x1e940: 68,
0x1e941: 68,
0x1e942: 68,
0x1e943: 68,
}
codepoint_classes = {
'PVALID': (
0x2d0000002e,
0x300000003a,
0x610000007b,
0xdf000000f7,
0xf800000100,
0x10100000102,
0x10300000104,
0x10500000106,
0x10700000108,
0x1090000010a,
0x10b0000010c,
0x10d0000010e,
0x10f00000110,
0x11100000112,
0x11300000114,
0x11500000116,
0x11700000118,
0x1190000011a,
0x11b0000011c,
0x11d0000011e,
0x11f00000120,
0x12100000122,
0x12300000124,
0x12500000126,
0x12700000128,
0x1290000012a,
0x12b0000012c,
0x12d0000012e,
0x12f00000130,
0x13100000132,
0x13500000136,
0x13700000139,
0x13a0000013b,
0x13c0000013d,
0x13e0000013f,
0x14200000143,
0x14400000145,
0x14600000147,
0x14800000149,
0x14b0000014c,
0x14d0000014e,
0x14f00000150,
0x15100000152,
0x15300000154,
0x15500000156,
0x15700000158,
0x1590000015a,
0x15b0000015c,
0x15d0000015e,
0x15f00000160,
0x16100000162,
0x16300000164,
0x16500000166,
0x16700000168,
0x1690000016a,
0x16b0000016c,
0x16d0000016e,
0x16f00000170,
0x17100000172,
0x17300000174,
0x17500000176,
0x17700000178,
0x17a0000017b,
0x17c0000017d,
0x17e0000017f,
0x18000000181,
0x18300000184,
0x18500000186,
0x18800000189,
0x18c0000018e,
0x19200000193,
0x19500000196,
0x1990000019c,
0x19e0000019f,
0x1a1000001a2,
0x1a3000001a4,
0x1a5000001a6,
0x1a8000001a9,
0x1aa000001ac,
0x1ad000001ae,
0x1b0000001b1,
0x1b4000001b5,
0x1b6000001b7,
0x1b9000001bc,
0x1bd000001c4,
0x1ce000001cf,
0x1d0000001d1,
0x1d2000001d3,
0x1d4000001d5,
0x1d6000001d7,
0x1d8000001d9,
0x1da000001db,
0x1dc000001de,
0x1df000001e0,
0x1e1000001e2,
0x1e3000001e4,
0x1e5000001e6,
0x1e7000001e8,
0x1e9000001ea,
0x1eb000001ec,
0x1ed000001ee,
0x1ef000001f1,
0x1f5000001f6,
0x1f9000001fa,
0x1fb000001fc,
0x1fd000001fe,
0x1ff00000200,
0x20100000202,
0x20300000204,
0x20500000206,
0x20700000208,
0x2090000020a,
0x20b0000020c,
0x20d0000020e,
0x20f00000210,
0x21100000212,
0x21300000214,
0x21500000216,
0x21700000218,
0x2190000021a,
0x21b0000021c,
0x21d0000021e,
0x21f00000220,
0x22100000222,
0x22300000224,
0x22500000226,
0x22700000228,
0x2290000022a,
0x22b0000022c,
0x22d0000022e,
0x22f00000230,
0x23100000232,
0x2330000023a,
0x23c0000023d,
0x23f00000241,
0x24200000243,
0x24700000248,
0x2490000024a,
0x24b0000024c,
0x24d0000024e,
0x24f000002b0,
0x2b9000002c2,
0x2c6000002d2,
0x2ec000002ed,
0x2ee000002ef,
0x30000000340,
0x34200000343,
0x3460000034f,
0x35000000370,
0x37100000372,
0x37300000374,
0x37700000378,
0x37b0000037e,
0x39000000391,
0x3ac000003cf,
0x3d7000003d8,
0x3d9000003da,
0x3db000003dc,
0x3dd000003de,
0x3df000003e0,
0x3e1000003e2,
0x3e3000003e4,
0x3e5000003e6,
0x3e7000003e8,
0x3e9000003ea,
0x3eb000003ec,
0x3ed000003ee,
0x3ef000003f0,
0x3f3000003f4,
0x3f8000003f9,
0x3fb000003fd,
0x43000000460,
0x46100000462,
0x46300000464,
0x46500000466,
0x46700000468,
0x4690000046a,
0x46b0000046c,
0x46d0000046e,
0x46f00000470,
0x47100000472,
0x47300000474,
0x47500000476,
0x47700000478,
0x4790000047a,
0x47b0000047c,
0x47d0000047e,
0x47f00000480,
0x48100000482,
0x48300000488,
0x48b0000048c,
0x48d0000048e,
0x48f00000490,
0x49100000492,
0x49300000494,
0x49500000496,
0x49700000498,
0x4990000049a,
0x49b0000049c,
0x49d0000049e,
0x49f000004a0,
0x4a1000004a2,
0x4a3000004a4,
0x4a5000004a6,
0x4a7000004a8,
0x4a9000004aa,
0x4ab000004ac,
0x4ad000004ae,
0x4af000004b0,
0x4b1000004b2,
0x4b3000004b4,
0x4b5000004b6,
0x4b7000004b8,
0x4b9000004ba,
0x4bb000004bc,
0x4bd000004be,
0x4bf000004c0,
0x4c2000004c3,
0x4c4000004c5,
0x4c6000004c7,
0x4c8000004c9,
0x4ca000004cb,
0x4cc000004cd,
0x4ce000004d0,
0x4d1000004d2,
0x4d3000004d4,
0x4d5000004d6,
0x4d7000004d8,
0x4d9000004da,
0x4db000004dc,
0x4dd000004de,
0x4df000004e0,
0x4e1000004e2,
0x4e3000004e4,
0x4e5000004e6,
0x4e7000004e8,
0x4e9000004ea,
0x4eb000004ec,
0x4ed000004ee,
0x4ef000004f0,
0x4f1000004f2,
0x4f3000004f4,
0x4f5000004f6,
0x4f7000004f8,
0x4f9000004fa,
0x4fb000004fc,
0x4fd000004fe,
0x4ff00000500,
0x50100000502,
0x50300000504,
0x50500000506,
0x50700000508,
0x5090000050a,
0x50b0000050c,
0x50d0000050e,
0x50f00000510,
0x51100000512,
0x51300000514,
0x51500000516,
0x51700000518,
0x5190000051a,
0x51b0000051c,
0x51d0000051e,
0x51f00000520,
0x52100000522,
0x52300000524,
0x52500000526,
0x52700000528,
0x5290000052a,
0x52b0000052c,
0x52d0000052e,
0x52f00000530,
0x5590000055a,
0x56000000587,
0x58800000589,
0x591000005be,
0x5bf000005c0,
0x5c1000005c3,
0x5c4000005c6,
0x5c7000005c8,
0x5d0000005eb,
0x5ef000005f3,
0x6100000061b,
0x62000000640,
0x64100000660,
0x66e00000675,
0x679000006d4,
0x6d5000006dd,
0x6df000006e9,
0x6ea000006f0,
0x6fa00000700,
0x7100000074b,
0x74d000007b2,
0x7c0000007f6,
0x7fd000007fe,
0x8000000082e,
0x8400000085c,
0x8600000086b,
0x8a0000008b5,
0x8b6000008be,
0x8d3000008e2,
0x8e300000958,
0x96000000964,
0x96600000970,
0x97100000984,
0x9850000098d,
0x98f00000991,
0x993000009a9,
0x9aa000009b1,
0x9b2000009b3,
0x9b6000009ba,
0x9bc000009c5,
0x9c7000009c9,
0x9cb000009cf,
0x9d7000009d8,
0x9e0000009e4,
0x9e6000009f2,
0x9fc000009fd,
0x9fe000009ff,
0xa0100000a04,
0xa0500000a0b,
0xa0f00000a11,
0xa1300000a29,
0xa2a00000a31,
0xa3200000a33,
0xa3500000a36,
0xa3800000a3a,
0xa3c00000a3d,
0xa3e00000a43,
0xa4700000a49,
0xa4b00000a4e,
0xa5100000a52,
0xa5c00000a5d,
0xa6600000a76,
0xa8100000a84,
0xa8500000a8e,
0xa8f00000a92,
0xa9300000aa9,
0xaaa00000ab1,
0xab200000ab4,
0xab500000aba,
0xabc00000ac6,
0xac700000aca,
0xacb00000ace,
0xad000000ad1,
0xae000000ae4,
0xae600000af0,
0xaf900000b00,
0xb0100000b04,
0xb0500000b0d,
0xb0f00000b11,
0xb1300000b29,
0xb2a00000b31,
0xb3200000b34,
0xb3500000b3a,
0xb3c00000b45,
0xb4700000b49,
0xb4b00000b4e,
0xb5600000b58,
0xb5f00000b64,
0xb6600000b70,
0xb7100000b72,
0xb8200000b84,
0xb8500000b8b,
0xb8e00000b91,
0xb9200000b96,
0xb9900000b9b,
0xb9c00000b9d,
0xb9e00000ba0,
0xba300000ba5,
0xba800000bab,
0xbae00000bba,
0xbbe00000bc3,
0xbc600000bc9,
0xbca00000bce,
0xbd000000bd1,
0xbd700000bd8,
0xbe600000bf0,
0xc0000000c0d,
0xc0e00000c11,
0xc1200000c29,
0xc2a00000c3a,
0xc3d00000c45,
0xc4600000c49,
0xc4a00000c4e,
0xc5500000c57,
0xc5800000c5b,
0xc6000000c64,
0xc6600000c70,
0xc8000000c84,
0xc8500000c8d,
0xc8e00000c91,
0xc9200000ca9,
0xcaa00000cb4,
0xcb500000cba,
0xcbc00000cc5,
0xcc600000cc9,
0xcca00000cce,
0xcd500000cd7,
0xcde00000cdf,
0xce000000ce4,
0xce600000cf0,
0xcf100000cf3,
0xd0000000d04,
0xd0500000d0d,
0xd0e00000d11,
0xd1200000d45,
0xd4600000d49,
0xd4a00000d4f,
0xd5400000d58,
0xd5f00000d64,
0xd6600000d70,
0xd7a00000d80,
0xd8200000d84,
0xd8500000d97,
0xd9a00000db2,
0xdb300000dbc,
0xdbd00000dbe,
0xdc000000dc7,
0xdca00000dcb,
0xdcf00000dd5,
0xdd600000dd7,
0xdd800000de0,
0xde600000df0,
0xdf200000df4,
0xe0100000e33,
0xe3400000e3b,
0xe4000000e4f,
0xe5000000e5a,
0xe8100000e83,
0xe8400000e85,
0xe8700000e89,
0xe8a00000e8b,
0xe8d00000e8e,
0xe9400000e98,
0xe9900000ea0,
0xea100000ea4,
0xea500000ea6,
0xea700000ea8,
0xeaa00000eac,
0xead00000eb3,
0xeb400000eba,
0xebb00000ebe,
0xec000000ec5,
0xec600000ec7,
0xec800000ece,
0xed000000eda,
0xede00000ee0,
0xf0000000f01,
0xf0b00000f0c,
0xf1800000f1a,
0xf2000000f2a,
0xf3500000f36,
0xf3700000f38,
0xf3900000f3a,
0xf3e00000f43,
0xf4400000f48,
0xf4900000f4d,
0xf4e00000f52,
0xf5300000f57,
0xf5800000f5c,
0xf5d00000f69,
0xf6a00000f6d,
0xf7100000f73,
0xf7400000f75,
0xf7a00000f81,
0xf8200000f85,
0xf8600000f93,
0xf9400000f98,
0xf9900000f9d,
0xf9e00000fa2,
0xfa300000fa7,
0xfa800000fac,
0xfad00000fb9,
0xfba00000fbd,
0xfc600000fc7,
0x10000000104a,
0x10500000109e,
0x10d0000010fb,
0x10fd00001100,
0x120000001249,
0x124a0000124e,
0x125000001257,
0x125800001259,
0x125a0000125e,
0x126000001289,
0x128a0000128e,
0x1290000012b1,
0x12b2000012b6,
0x12b8000012bf,
0x12c0000012c1,
0x12c2000012c6,
0x12c8000012d7,
0x12d800001311,
0x131200001316,
0x13180000135b,
0x135d00001360,
0x138000001390,
0x13a0000013f6,
0x14010000166d,
0x166f00001680,
0x16810000169b,
0x16a0000016eb,
0x16f1000016f9,
0x17000000170d,
0x170e00001715,
0x172000001735,
0x174000001754,
0x17600000176d,
0x176e00001771,
0x177200001774,
0x1780000017b4,
0x17b6000017d4,
0x17d7000017d8,
0x17dc000017de,
0x17e0000017ea,
0x18100000181a,
0x182000001879,
0x1880000018ab,
0x18b0000018f6,
0x19000000191f,
0x19200000192c,
0x19300000193c,
0x19460000196e,
0x197000001975,
0x1980000019ac,
0x19b0000019ca,
0x19d0000019da,
0x1a0000001a1c,
0x1a2000001a5f,
0x1a6000001a7d,
0x1a7f00001a8a,
0x1a9000001a9a,
0x1aa700001aa8,
0x1ab000001abe,
0x1b0000001b4c,
0x1b5000001b5a,
0x1b6b00001b74,
0x1b8000001bf4,
0x1c0000001c38,
0x1c4000001c4a,
0x1c4d00001c7e,
0x1cd000001cd3,
0x1cd400001cfa,
0x1d0000001d2c,
0x1d2f00001d30,
0x1d3b00001d3c,
0x1d4e00001d4f,
0x1d6b00001d78,
0x1d7900001d9b,
0x1dc000001dfa,
0x1dfb00001e00,
0x1e0100001e02,
0x1e0300001e04,
0x1e0500001e06,
0x1e0700001e08,
0x1e0900001e0a,
0x1e0b00001e0c,
0x1e0d00001e0e,
0x1e0f00001e10,
0x1e1100001e12,
0x1e1300001e14,
0x1e1500001e16,
0x1e1700001e18,
0x1e1900001e1a,
0x1e1b00001e1c,
0x1e1d00001e1e,
0x1e1f00001e20,
0x1e2100001e22,
0x1e2300001e24,
0x1e2500001e26,
0x1e2700001e28,
0x1e2900001e2a,
0x1e2b00001e2c,
0x1e2d00001e2e,
0x1e2f00001e30,
0x1e3100001e32,
0x1e3300001e34,
0x1e3500001e36,
0x1e3700001e38,
0x1e3900001e3a,
0x1e3b00001e3c,
0x1e3d00001e3e,
0x1e3f00001e40,
0x1e4100001e42,
0x1e4300001e44,
0x1e4500001e46,
0x1e4700001e48,
0x1e4900001e4a,
0x1e4b00001e4c,
0x1e4d00001e4e,
0x1e4f00001e50,
0x1e5100001e52,
0x1e5300001e54,
0x1e5500001e56,
0x1e5700001e58,
0x1e5900001e5a,
0x1e5b00001e5c,
0x1e5d00001e5e,
0x1e5f00001e60,
0x1e6100001e62,
0x1e6300001e64,
0x1e6500001e66,
0x1e6700001e68,
0x1e6900001e6a,
0x1e6b00001e6c,
0x1e6d00001e6e,
0x1e6f00001e70,
0x1e7100001e72,
0x1e7300001e74,
0x1e7500001e76,
0x1e7700001e78,
0x1e7900001e7a,
0x1e7b00001e7c,
0x1e7d00001e7e,
0x1e7f00001e80,
0x1e8100001e82,
0x1e8300001e84,
0x1e8500001e86,
0x1e8700001e88,
0x1e8900001e8a,
0x1e8b00001e8c,
0x1e8d00001e8e,
0x1e8f00001e90,
0x1e9100001e92,
0x1e9300001e94,
0x1e9500001e9a,
0x1e9c00001e9e,
0x1e9f00001ea0,
0x1ea100001ea2,
0x1ea300001ea4,
0x1ea500001ea6,
0x1ea700001ea8,
0x1ea900001eaa,
0x1eab00001eac,
0x1ead00001eae,
0x1eaf00001eb0,
0x1eb100001eb2,
0x1eb300001eb4,
0x1eb500001eb6,
0x1eb700001eb8,
0x1eb900001eba,
0x1ebb00001ebc,
0x1ebd00001ebe,
0x1ebf00001ec0,
0x1ec100001ec2,
0x1ec300001ec4,
0x1ec500001ec6,
0x1ec700001ec8,
0x1ec900001eca,
0x1ecb00001ecc,
0x1ecd00001ece,
0x1ecf00001ed0,
0x1ed100001ed2,
0x1ed300001ed4,
0x1ed500001ed6,
0x1ed700001ed8,
0x1ed900001eda,
0x1edb00001edc,
0x1edd00001ede,
0x1edf00001ee0,
0x1ee100001ee2,
0x1ee300001ee4,
0x1ee500001ee6,
0x1ee700001ee8,
0x1ee900001eea,
0x1eeb00001eec,
0x1eed00001eee,
0x1eef00001ef0,
0x1ef100001ef2,
0x1ef300001ef4,
0x1ef500001ef6,
0x1ef700001ef8,
0x1ef900001efa,
0x1efb00001efc,
0x1efd00001efe,
0x1eff00001f08,
0x1f1000001f16,
0x1f2000001f28,
0x1f3000001f38,
0x1f4000001f46,
0x1f5000001f58,
0x1f6000001f68,
0x1f7000001f71,
0x1f7200001f73,
0x1f7400001f75,
0x1f7600001f77,
0x1f7800001f79,
0x1f7a00001f7b,
0x1f7c00001f7d,
0x1fb000001fb2,
0x1fb600001fb7,
0x1fc600001fc7,
0x1fd000001fd3,
0x1fd600001fd8,
0x1fe000001fe3,
0x1fe400001fe8,
0x1ff600001ff7,
0x214e0000214f,
0x218400002185,
0x2c3000002c5f,
0x2c6100002c62,
0x2c6500002c67,
0x2c6800002c69,
0x2c6a00002c6b,
0x2c6c00002c6d,
0x2c7100002c72,
0x2c7300002c75,
0x2c7600002c7c,
0x2c8100002c82,
0x2c8300002c84,
0x2c8500002c86,
0x2c8700002c88,
0x2c8900002c8a,
0x2c8b00002c8c,
0x2c8d00002c8e,
0x2c8f00002c90,
0x2c9100002c92,
0x2c9300002c94,
0x2c9500002c96,
0x2c9700002c98,
0x2c9900002c9a,
0x2c9b00002c9c,
0x2c9d00002c9e,
0x2c9f00002ca0,
0x2ca100002ca2,
0x2ca300002ca4,
0x2ca500002ca6,
0x2ca700002ca8,
0x2ca900002caa,
0x2cab00002cac,
0x2cad00002cae,
0x2caf00002cb0,
0x2cb100002cb2,
0x2cb300002cb4,
0x2cb500002cb6,
0x2cb700002cb8,
0x2cb900002cba,
0x2cbb00002cbc,
0x2cbd00002cbe,
0x2cbf00002cc0,
0x2cc100002cc2,
0x2cc300002cc4,
0x2cc500002cc6,
0x2cc700002cc8,
0x2cc900002cca,
0x2ccb00002ccc,
0x2ccd00002cce,
0x2ccf00002cd0,
0x2cd100002cd2,
0x2cd300002cd4,
0x2cd500002cd6,
0x2cd700002cd8,
0x2cd900002cda,
0x2cdb00002cdc,
0x2cdd00002cde,
0x2cdf00002ce0,
0x2ce100002ce2,
0x2ce300002ce5,
0x2cec00002ced,
0x2cee00002cf2,
0x2cf300002cf4,
0x2d0000002d26,
0x2d2700002d28,
0x2d2d00002d2e,
0x2d3000002d68,
0x2d7f00002d97,
0x2da000002da7,
0x2da800002daf,
0x2db000002db7,
0x2db800002dbf,
0x2dc000002dc7,
0x2dc800002dcf,
0x2dd000002dd7,
0x2dd800002ddf,
0x2de000002e00,
0x2e2f00002e30,
0x300500003008,
0x302a0000302e,
0x303c0000303d,
0x304100003097,
0x30990000309b,
0x309d0000309f,
0x30a1000030fb,
0x30fc000030ff,
0x310500003130,
0x31a0000031bb,
0x31f000003200,
0x340000004db6,
0x4e0000009ff0,
0xa0000000a48d,
0xa4d00000a4fe,
0xa5000000a60d,
0xa6100000a62c,
0xa6410000a642,
0xa6430000a644,
0xa6450000a646,
0xa6470000a648,
0xa6490000a64a,
0xa64b0000a64c,
0xa64d0000a64e,
0xa64f0000a650,
0xa6510000a652,
0xa6530000a654,
0xa6550000a656,
0xa6570000a658,
0xa6590000a65a,
0xa65b0000a65c,
0xa65d0000a65e,
0xa65f0000a660,
0xa6610000a662,
0xa6630000a664,
0xa6650000a666,
0xa6670000a668,
0xa6690000a66a,
0xa66b0000a66c,
0xa66d0000a670,
0xa6740000a67e,
0xa67f0000a680,
0xa6810000a682,
0xa6830000a684,
0xa6850000a686,
0xa6870000a688,
0xa6890000a68a,
0xa68b0000a68c,
0xa68d0000a68e,
0xa68f0000a690,
0xa6910000a692,
0xa6930000a694,
0xa6950000a696,
0xa6970000a698,
0xa6990000a69a,
0xa69b0000a69c,
0xa69e0000a6e6,
0xa6f00000a6f2,
0xa7170000a720,
0xa7230000a724,
0xa7250000a726,
0xa7270000a728,
0xa7290000a72a,
0xa72b0000a72c,
0xa72d0000a72e,
0xa72f0000a732,
0xa7330000a734,
0xa7350000a736,
0xa7370000a738,
0xa7390000a73a,
0xa73b0000a73c,
0xa73d0000a73e,
0xa73f0000a740,
0xa7410000a742,
0xa7430000a744,
0xa7450000a746,
0xa7470000a748,
0xa7490000a74a,
0xa74b0000a74c,
0xa74d0000a74e,
0xa74f0000a750,
0xa7510000a752,
0xa7530000a754,
0xa7550000a756,
0xa7570000a758,
0xa7590000a75a,
0xa75b0000a75c,
0xa75d0000a75e,
0xa75f0000a760,
0xa7610000a762,
0xa7630000a764,
0xa7650000a766,
0xa7670000a768,
0xa7690000a76a,
0xa76b0000a76c,
0xa76d0000a76e,
0xa76f0000a770,
0xa7710000a779,
0xa77a0000a77b,
0xa77c0000a77d,
0xa77f0000a780,
0xa7810000a782,
0xa7830000a784,
0xa7850000a786,
0xa7870000a789,
0xa78c0000a78d,
0xa78e0000a790,
0xa7910000a792,
0xa7930000a796,
0xa7970000a798,
0xa7990000a79a,
0xa79b0000a79c,
0xa79d0000a79e,
0xa79f0000a7a0,
0xa7a10000a7a2,
0xa7a30000a7a4,
0xa7a50000a7a6,
0xa7a70000a7a8,
0xa7a90000a7aa,
0xa7af0000a7b0,
0xa7b50000a7b6,
0xa7b70000a7b8,
0xa7b90000a7ba,
0xa7f70000a7f8,
0xa7fa0000a828,
0xa8400000a874,
0xa8800000a8c6,
0xa8d00000a8da,
0xa8e00000a8f8,
0xa8fb0000a8fc,
0xa8fd0000a92e,
0xa9300000a954,
0xa9800000a9c1,
0xa9cf0000a9da,
0xa9e00000a9ff,
0xaa000000aa37,
0xaa400000aa4e,
0xaa500000aa5a,
0xaa600000aa77,
0xaa7a0000aac3,
0xaadb0000aade,
0xaae00000aaf0,
0xaaf20000aaf7,
0xab010000ab07,
0xab090000ab0f,
0xab110000ab17,
0xab200000ab27,
0xab280000ab2f,
0xab300000ab5b,
0xab600000ab66,
0xabc00000abeb,
0xabec0000abee,
0xabf00000abfa,
0xac000000d7a4,
0xfa0e0000fa10,
0xfa110000fa12,
0xfa130000fa15,
0xfa1f0000fa20,
0xfa210000fa22,
0xfa230000fa25,
0xfa270000fa2a,
0xfb1e0000fb1f,
0xfe200000fe30,
0xfe730000fe74,
0x100000001000c,
0x1000d00010027,
0x100280001003b,
0x1003c0001003e,
0x1003f0001004e,
0x100500001005e,
0x10080000100fb,
0x101fd000101fe,
0x102800001029d,
0x102a0000102d1,
0x102e0000102e1,
0x1030000010320,
0x1032d00010341,
0x103420001034a,
0x103500001037b,
0x103800001039e,
0x103a0000103c4,
0x103c8000103d0,
0x104280001049e,
0x104a0000104aa,
0x104d8000104fc,
0x1050000010528,
0x1053000010564,
0x1060000010737,
0x1074000010756,
0x1076000010768,
0x1080000010806,
0x1080800010809,
0x1080a00010836,
0x1083700010839,
0x1083c0001083d,
0x1083f00010856,
0x1086000010877,
0x108800001089f,
0x108e0000108f3,
0x108f4000108f6,
0x1090000010916,
0x109200001093a,
0x10980000109b8,
0x109be000109c0,
0x10a0000010a04,
0x10a0500010a07,
0x10a0c00010a14,
0x10a1500010a18,
0x10a1900010a36,
0x10a3800010a3b,
0x10a3f00010a40,
0x10a6000010a7d,
0x10a8000010a9d,
0x10ac000010ac8,
0x10ac900010ae7,
0x10b0000010b36,
0x10b4000010b56,
0x10b6000010b73,
0x10b8000010b92,
0x10c0000010c49,
0x10cc000010cf3,
0x10d0000010d28,
0x10d3000010d3a,
0x10f0000010f1d,
0x10f2700010f28,
0x10f3000010f51,
0x1100000011047,
0x1106600011070,
0x1107f000110bb,
0x110d0000110e9,
0x110f0000110fa,
0x1110000011135,
0x1113600011140,
0x1114400011147,
0x1115000011174,
0x1117600011177,
0x11180000111c5,
0x111c9000111cd,
0x111d0000111db,
0x111dc000111dd,
0x1120000011212,
0x1121300011238,
0x1123e0001123f,
0x1128000011287,
0x1128800011289,
0x1128a0001128e,
0x1128f0001129e,
0x1129f000112a9,
0x112b0000112eb,
0x112f0000112fa,
0x1130000011304,
0x113050001130d,
0x1130f00011311,
0x1131300011329,
0x1132a00011331,
0x1133200011334,
0x113350001133a,
0x1133b00011345,
0x1134700011349,
0x1134b0001134e,
0x1135000011351,
0x1135700011358,
0x1135d00011364,
0x113660001136d,
0x1137000011375,
0x114000001144b,
0x114500001145a,
0x1145e0001145f,
0x11480000114c6,
0x114c7000114c8,
0x114d0000114da,
0x11580000115b6,
0x115b8000115c1,
0x115d8000115de,
0x1160000011641,
0x1164400011645,
0x116500001165a,
0x11680000116b8,
0x116c0000116ca,
0x117000001171b,
0x1171d0001172c,
0x117300001173a,
0x118000001183b,
0x118c0000118ea,
0x118ff00011900,
0x11a0000011a3f,
0x11a4700011a48,
0x11a5000011a84,
0x11a8600011a9a,
0x11a9d00011a9e,
0x11ac000011af9,
0x11c0000011c09,
0x11c0a00011c37,
0x11c3800011c41,
0x11c5000011c5a,
0x11c7200011c90,
0x11c9200011ca8,
0x11ca900011cb7,
0x11d0000011d07,
0x11d0800011d0a,
0x11d0b00011d37,
0x11d3a00011d3b,
0x11d3c00011d3e,
0x11d3f00011d48,
0x11d5000011d5a,
0x11d6000011d66,
0x11d6700011d69,
0x11d6a00011d8f,
0x11d9000011d92,
0x11d9300011d99,
0x11da000011daa,
0x11ee000011ef7,
0x120000001239a,
0x1248000012544,
0x130000001342f,
0x1440000014647,
0x1680000016a39,
0x16a4000016a5f,
0x16a6000016a6a,
0x16ad000016aee,
0x16af000016af5,
0x16b0000016b37,
0x16b4000016b44,
0x16b5000016b5a,
0x16b6300016b78,
0x16b7d00016b90,
0x16e6000016e80,
0x16f0000016f45,
0x16f5000016f7f,
0x16f8f00016fa0,
0x16fe000016fe2,
0x17000000187f2,
0x1880000018af3,
0x1b0000001b11f,
0x1b1700001b2fc,
0x1bc000001bc6b,
0x1bc700001bc7d,
0x1bc800001bc89,
0x1bc900001bc9a,
0x1bc9d0001bc9f,
0x1da000001da37,
0x1da3b0001da6d,
0x1da750001da76,
0x1da840001da85,
0x1da9b0001daa0,
0x1daa10001dab0,
0x1e0000001e007,
0x1e0080001e019,
0x1e01b0001e022,
0x1e0230001e025,
0x1e0260001e02b,
0x1e8000001e8c5,
0x1e8d00001e8d7,
0x1e9220001e94b,
0x1e9500001e95a,
0x200000002a6d7,
0x2a7000002b735,
0x2b7400002b81e,
0x2b8200002cea2,
0x2ceb00002ebe1,
),
'CONTEXTJ': (
0x200c0000200e,
),
'CONTEXTO': (
0xb7000000b8,
0x37500000376,
0x5f3000005f5,
0x6600000066a,
0x6f0000006fa,
0x30fb000030fc,
),
}
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/idna/intranges.py
================================================
"""
Given a list of integers, made up of (hopefully) a small number of long runs
of consecutive integers, compute a representation of the form
((start1, end1), (start2, end2) ...). Then answer the question "was x present
in the original list?" in time O(log(# runs)).
"""
import bisect
def intranges_from_list(list_):
"""Represent a list of integers as a sequence of ranges:
((start_0, end_0), (start_1, end_1), ...), such that the original
integers are exactly those x such that start_i <= x < end_i for some i.
Ranges are encoded as single integers (start << 32 | end), not as tuples.
"""
sorted_list = sorted(list_)
ranges = []
last_write = -1
for i in range(len(sorted_list)):
if i+1 < len(sorted_list):
if sorted_list[i] == sorted_list[i+1]-1:
continue
current_range = sorted_list[last_write+1:i+1]
ranges.append(_encode_range(current_range[0], current_range[-1] + 1))
last_write = i
return tuple(ranges)
def _encode_range(start, end):
return (start << 32) | end
def _decode_range(r):
return (r >> 32), (r & ((1 << 32) - 1))
def intranges_contain(int_, ranges):
"""Determine if `int_` falls into one of the ranges in `ranges`."""
tuple_ = _encode_range(int_, 0)
pos = bisect.bisect_left(ranges, tuple_)
# we could be immediately ahead of a tuple (start, end)
# with start < int_ <= end
if pos > 0:
left, right = _decode_range(ranges[pos-1])
if left <= int_ < right:
return True
# or we could be immediately behind a tuple (int_, end)
if pos < len(ranges):
left, _ = _decode_range(ranges[pos])
if left == int_:
return True
return False
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/idna/package_data.py
================================================
__version__ = '2.8'
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/idna/uts46data.py
================================================
# This file is automatically generated by tools/idna-data
# vim: set fileencoding=utf-8 :
"""IDNA Mapping Table from UTS46."""
__version__ = "11.0.0"
def _seg_0():
return [
(0x0, '3'),
(0x1, '3'),
(0x2, '3'),
(0x3, '3'),
(0x4, '3'),
(0x5, '3'),
(0x6, '3'),
(0x7, '3'),
(0x8, '3'),
(0x9, '3'),
(0xA, '3'),
(0xB, '3'),
(0xC, '3'),
(0xD, '3'),
(0xE, '3'),
(0xF, '3'),
(0x10, '3'),
(0x11, '3'),
(0x12, '3'),
(0x13, '3'),
(0x14, '3'),
(0x15, '3'),
(0x16, '3'),
(0x17, '3'),
(0x18, '3'),
(0x19, '3'),
(0x1A, '3'),
(0x1B, '3'),
(0x1C, '3'),
(0x1D, '3'),
(0x1E, '3'),
(0x1F, '3'),
(0x20, '3'),
(0x21, '3'),
(0x22, '3'),
(0x23, '3'),
(0x24, '3'),
(0x25, '3'),
(0x26, '3'),
(0x27, '3'),
(0x28, '3'),
(0x29, '3'),
(0x2A, '3'),
(0x2B, '3'),
(0x2C, '3'),
(0x2D, 'V'),
(0x2E, 'V'),
(0x2F, '3'),
(0x30, 'V'),
(0x31, 'V'),
(0x32, 'V'),
(0x33, 'V'),
(0x34, 'V'),
(0x35, 'V'),
(0x36, 'V'),
(0x37, 'V'),
(0x38, 'V'),
(0x39, 'V'),
(0x3A, '3'),
(0x3B, '3'),
(0x3C, '3'),
(0x3D, '3'),
(0x3E, '3'),
(0x3F, '3'),
(0x40, '3'),
(0x41, 'M', u'a'),
(0x42, 'M', u'b'),
(0x43, 'M', u'c'),
(0x44, 'M', u'd'),
(0x45, 'M', u'e'),
(0x46, 'M', u'f'),
(0x47, 'M', u'g'),
(0x48, 'M', u'h'),
(0x49, 'M', u'i'),
(0x4A, 'M', u'j'),
(0x4B, 'M', u'k'),
(0x4C, 'M', u'l'),
(0x4D, 'M', u'm'),
(0x4E, 'M', u'n'),
(0x4F, 'M', u'o'),
(0x50, 'M', u'p'),
(0x51, 'M', u'q'),
(0x52, 'M', u'r'),
(0x53, 'M', u's'),
(0x54, 'M', u't'),
(0x55, 'M', u'u'),
(0x56, 'M', u'v'),
(0x57, 'M', u'w'),
(0x58, 'M', u'x'),
(0x59, 'M', u'y'),
(0x5A, 'M', u'z'),
(0x5B, '3'),
(0x5C, '3'),
(0x5D, '3'),
(0x5E, '3'),
(0x5F, '3'),
(0x60, '3'),
(0x61, 'V'),
(0x62, 'V'),
(0x63, 'V'),
]
def _seg_1():
return [
(0x64, 'V'),
(0x65, 'V'),
(0x66, 'V'),
(0x67, 'V'),
(0x68, 'V'),
(0x69, 'V'),
(0x6A, 'V'),
(0x6B, 'V'),
(0x6C, 'V'),
(0x6D, 'V'),
(0x6E, 'V'),
(0x6F, 'V'),
(0x70, 'V'),
(0x71, 'V'),
(0x72, 'V'),
(0x73, 'V'),
(0x74, 'V'),
(0x75, 'V'),
(0x76, 'V'),
(0x77, 'V'),
(0x78, 'V'),
(0x79, 'V'),
(0x7A, 'V'),
(0x7B, '3'),
(0x7C, '3'),
(0x7D, '3'),
(0x7E, '3'),
(0x7F, '3'),
(0x80, 'X'),
(0x81, 'X'),
(0x82, 'X'),
(0x83, 'X'),
(0x84, 'X'),
(0x85, 'X'),
(0x86, 'X'),
(0x87, 'X'),
(0x88, 'X'),
(0x89, 'X'),
(0x8A, 'X'),
(0x8B, 'X'),
(0x8C, 'X'),
(0x8D, 'X'),
(0x8E, 'X'),
(0x8F, 'X'),
(0x90, 'X'),
(0x91, 'X'),
(0x92, 'X'),
(0x93, 'X'),
(0x94, 'X'),
(0x95, 'X'),
(0x96, 'X'),
(0x97, 'X'),
(0x98, 'X'),
(0x99, 'X'),
(0x9A, 'X'),
(0x9B, 'X'),
(0x9C, 'X'),
(0x9D, 'X'),
(0x9E, 'X'),
(0x9F, 'X'),
(0xA0, '3', u' '),
(0xA1, 'V'),
(0xA2, 'V'),
(0xA3, 'V'),
(0xA4, 'V'),
(0xA5, 'V'),
(0xA6, 'V'),
(0xA7, 'V'),
(0xA8, '3', u' ̈'),
(0xA9, 'V'),
(0xAA, 'M', u'a'),
(0xAB, 'V'),
(0xAC, 'V'),
(0xAD, 'I'),
(0xAE, 'V'),
(0xAF, '3', u' ̄'),
(0xB0, 'V'),
(0xB1, 'V'),
(0xB2, 'M', u'2'),
(0xB3, 'M', u'3'),
(0xB4, '3', u' ́'),
(0xB5, 'M', u'μ'),
(0xB6, 'V'),
(0xB7, 'V'),
(0xB8, '3', u' ̧'),
(0xB9, 'M', u'1'),
(0xBA, 'M', u'o'),
(0xBB, 'V'),
(0xBC, 'M', u'1⁄4'),
(0xBD, 'M', u'1⁄2'),
(0xBE, 'M', u'3⁄4'),
(0xBF, 'V'),
(0xC0, 'M', u'à'),
(0xC1, 'M', u'á'),
(0xC2, 'M', u'â'),
(0xC3, 'M', u'ã'),
(0xC4, 'M', u'ä'),
(0xC5, 'M', u'å'),
(0xC6, 'M', u'æ'),
(0xC7, 'M', u'ç'),
]
def _seg_2():
return [
(0xC8, 'M', u'è'),
(0xC9, 'M', u'é'),
(0xCA, 'M', u'ê'),
(0xCB, 'M', u'ë'),
(0xCC, 'M', u'ì'),
(0xCD, 'M', u'í'),
(0xCE, 'M', u'î'),
(0xCF, 'M', u'ï'),
(0xD0, 'M', u'ð'),
(0xD1, 'M', u'ñ'),
(0xD2, 'M', u'ò'),
(0xD3, 'M', u'ó'),
(0xD4, 'M', u'ô'),
(0xD5, 'M', u'õ'),
(0xD6, 'M', u'ö'),
(0xD7, 'V'),
(0xD8, 'M', u'ø'),
(0xD9, 'M', u'ù'),
(0xDA, 'M', u'ú'),
(0xDB, 'M', u'û'),
(0xDC, 'M', u'ü'),
(0xDD, 'M', u'ý'),
(0xDE, 'M', u'þ'),
(0xDF, 'D', u'ss'),
(0xE0, 'V'),
(0xE1, 'V'),
(0xE2, 'V'),
(0xE3, 'V'),
(0xE4, 'V'),
(0xE5, 'V'),
(0xE6, 'V'),
(0xE7, 'V'),
(0xE8, 'V'),
(0xE9, 'V'),
(0xEA, 'V'),
(0xEB, 'V'),
(0xEC, 'V'),
(0xED, 'V'),
(0xEE, 'V'),
(0xEF, 'V'),
(0xF0, 'V'),
(0xF1, 'V'),
(0xF2, 'V'),
(0xF3, 'V'),
(0xF4, 'V'),
(0xF5, 'V'),
(0xF6, 'V'),
(0xF7, 'V'),
(0xF8, 'V'),
(0xF9, 'V'),
(0xFA, 'V'),
(0xFB, 'V'),
(0xFC, 'V'),
(0xFD, 'V'),
(0xFE, 'V'),
(0xFF, 'V'),
(0x100, 'M', u'ā'),
(0x101, 'V'),
(0x102, 'M', u'ă'),
(0x103, 'V'),
(0x104, 'M', u'ą'),
(0x105, 'V'),
(0x106, 'M', u'ć'),
(0x107, 'V'),
(0x108, 'M', u'ĉ'),
(0x109, 'V'),
(0x10A, 'M', u'ċ'),
(0x10B, 'V'),
(0x10C, 'M', u'č'),
(0x10D, 'V'),
(0x10E, 'M', u'ď'),
(0x10F, 'V'),
(0x110, 'M', u'đ'),
(0x111, 'V'),
(0x112, 'M', u'ē'),
(0x113, 'V'),
(0x114, 'M', u'ĕ'),
(0x115, 'V'),
(0x116, 'M', u'ė'),
(0x117, 'V'),
(0x118, 'M', u'ę'),
(0x119, 'V'),
(0x11A, 'M', u'ě'),
(0x11B, 'V'),
(0x11C, 'M', u'ĝ'),
(0x11D, 'V'),
(0x11E, 'M', u'ğ'),
(0x11F, 'V'),
(0x120, 'M', u'ġ'),
(0x121, 'V'),
(0x122, 'M', u'ģ'),
(0x123, 'V'),
(0x124, 'M', u'ĥ'),
(0x125, 'V'),
(0x126, 'M', u'ħ'),
(0x127, 'V'),
(0x128, 'M', u'ĩ'),
(0x129, 'V'),
(0x12A, 'M', u'ī'),
(0x12B, 'V'),
]
def _seg_3():
return [
(0x12C, 'M', u'ĭ'),
(0x12D, 'V'),
(0x12E, 'M', u'į'),
(0x12F, 'V'),
(0x130, 'M', u'i̇'),
(0x131, 'V'),
(0x132, 'M', u'ij'),
(0x134, 'M', u'ĵ'),
(0x135, 'V'),
(0x136, 'M', u'ķ'),
(0x137, 'V'),
(0x139, 'M', u'ĺ'),
(0x13A, 'V'),
(0x13B, 'M', u'ļ'),
(0x13C, 'V'),
(0x13D, 'M', u'ľ'),
(0x13E, 'V'),
(0x13F, 'M', u'l·'),
(0x141, 'M', u'ł'),
(0x142, 'V'),
(0x143, 'M', u'ń'),
(0x144, 'V'),
(0x145, 'M', u'ņ'),
(0x146, 'V'),
(0x147, 'M', u'ň'),
(0x148, 'V'),
(0x149, 'M', u'ʼn'),
(0x14A, 'M', u'ŋ'),
(0x14B, 'V'),
(0x14C, 'M', u'ō'),
(0x14D, 'V'),
(0x14E, 'M', u'ŏ'),
(0x14F, 'V'),
(0x150, 'M', u'ő'),
(0x151, 'V'),
(0x152, 'M', u'œ'),
(0x153, 'V'),
(0x154, 'M', u'ŕ'),
(0x155, 'V'),
(0x156, 'M', u'ŗ'),
(0x157, 'V'),
(0x158, 'M', u'ř'),
(0x159, 'V'),
(0x15A, 'M', u'ś'),
(0x15B, 'V'),
(0x15C, 'M', u'ŝ'),
(0x15D, 'V'),
(0x15E, 'M', u'ş'),
(0x15F, 'V'),
(0x160, 'M', u'š'),
(0x161, 'V'),
(0x162, 'M', u'ţ'),
(0x163, 'V'),
(0x164, 'M', u'ť'),
(0x165, 'V'),
(0x166, 'M', u'ŧ'),
(0x167, 'V'),
(0x168, 'M', u'ũ'),
(0x169, 'V'),
(0x16A, 'M', u'ū'),
(0x16B, 'V'),
(0x16C, 'M', u'ŭ'),
(0x16D, 'V'),
(0x16E, 'M', u'ů'),
(0x16F, 'V'),
(0x170, 'M', u'ű'),
(0x171, 'V'),
(0x172, 'M', u'ų'),
(0x173, 'V'),
(0x174, 'M', u'ŵ'),
(0x175, 'V'),
(0x176, 'M', u'ŷ'),
(0x177, 'V'),
(0x178, 'M', u'ÿ'),
(0x179, 'M', u'ź'),
(0x17A, 'V'),
(0x17B, 'M', u'ż'),
(0x17C, 'V'),
(0x17D, 'M', u'ž'),
(0x17E, 'V'),
(0x17F, 'M', u's'),
(0x180, 'V'),
(0x181, 'M', u'ɓ'),
(0x182, 'M', u'ƃ'),
(0x183, 'V'),
(0x184, 'M', u'ƅ'),
(0x185, 'V'),
(0x186, 'M', u'ɔ'),
(0x187, 'M', u'ƈ'),
(0x188, 'V'),
(0x189, 'M', u'ɖ'),
(0x18A, 'M', u'ɗ'),
(0x18B, 'M', u'ƌ'),
(0x18C, 'V'),
(0x18E, 'M', u'ǝ'),
(0x18F, 'M', u'ə'),
(0x190, 'M', u'ɛ'),
(0x191, 'M', u'ƒ'),
(0x192, 'V'),
(0x193, 'M', u'ɠ'),
]
def _seg_4():
return [
(0x194, 'M', u'ɣ'),
(0x195, 'V'),
(0x196, 'M', u'ɩ'),
(0x197, 'M', u'ɨ'),
(0x198, 'M', u'ƙ'),
(0x199, 'V'),
(0x19C, 'M', u'ɯ'),
(0x19D, 'M', u'ɲ'),
(0x19E, 'V'),
(0x19F, 'M', u'ɵ'),
(0x1A0, 'M', u'ơ'),
(0x1A1, 'V'),
(0x1A2, 'M', u'ƣ'),
(0x1A3, 'V'),
(0x1A4, 'M', u'ƥ'),
(0x1A5, 'V'),
(0x1A6, 'M', u'ʀ'),
(0x1A7, 'M', u'ƨ'),
(0x1A8, 'V'),
(0x1A9, 'M', u'ʃ'),
(0x1AA, 'V'),
(0x1AC, 'M', u'ƭ'),
(0x1AD, 'V'),
(0x1AE, 'M', u'ʈ'),
(0x1AF, 'M', u'ư'),
(0x1B0, 'V'),
(0x1B1, 'M', u'ʊ'),
(0x1B2, 'M', u'ʋ'),
(0x1B3, 'M', u'ƴ'),
(0x1B4, 'V'),
(0x1B5, 'M', u'ƶ'),
(0x1B6, 'V'),
(0x1B7, 'M', u'ʒ'),
(0x1B8, 'M', u'ƹ'),
(0x1B9, 'V'),
(0x1BC, 'M', u'ƽ'),
(0x1BD, 'V'),
(0x1C4, 'M', u'dž'),
(0x1C7, 'M', u'lj'),
(0x1CA, 'M', u'nj'),
(0x1CD, 'M', u'ǎ'),
(0x1CE, 'V'),
(0x1CF, 'M', u'ǐ'),
(0x1D0, 'V'),
(0x1D1, 'M', u'ǒ'),
(0x1D2, 'V'),
(0x1D3, 'M', u'ǔ'),
(0x1D4, 'V'),
(0x1D5, 'M', u'ǖ'),
(0x1D6, 'V'),
(0x1D7, 'M', u'ǘ'),
(0x1D8, 'V'),
(0x1D9, 'M', u'ǚ'),
(0x1DA, 'V'),
(0x1DB, 'M', u'ǜ'),
(0x1DC, 'V'),
(0x1DE, 'M', u'ǟ'),
(0x1DF, 'V'),
(0x1E0, 'M', u'ǡ'),
(0x1E1, 'V'),
(0x1E2, 'M', u'ǣ'),
(0x1E3, 'V'),
(0x1E4, 'M', u'ǥ'),
(0x1E5, 'V'),
(0x1E6, 'M', u'ǧ'),
(0x1E7, 'V'),
(0x1E8, 'M', u'ǩ'),
(0x1E9, 'V'),
(0x1EA, 'M', u'ǫ'),
(0x1EB, 'V'),
(0x1EC, 'M', u'ǭ'),
(0x1ED, 'V'),
(0x1EE, 'M', u'ǯ'),
(0x1EF, 'V'),
(0x1F1, 'M', u'dz'),
(0x1F4, 'M', u'ǵ'),
(0x1F5, 'V'),
(0x1F6, 'M', u'ƕ'),
(0x1F7, 'M', u'ƿ'),
(0x1F8, 'M', u'ǹ'),
(0x1F9, 'V'),
(0x1FA, 'M', u'ǻ'),
(0x1FB, 'V'),
(0x1FC, 'M', u'ǽ'),
(0x1FD, 'V'),
(0x1FE, 'M', u'ǿ'),
(0x1FF, 'V'),
(0x200, 'M', u'ȁ'),
(0x201, 'V'),
(0x202, 'M', u'ȃ'),
(0x203, 'V'),
(0x204, 'M', u'ȅ'),
(0x205, 'V'),
(0x206, 'M', u'ȇ'),
(0x207, 'V'),
(0x208, 'M', u'ȉ'),
(0x209, 'V'),
(0x20A, 'M', u'ȋ'),
(0x20B, 'V'),
(0x20C, 'M', u'ȍ'),
]
def _seg_5():
return [
(0x20D, 'V'),
(0x20E, 'M', u'ȏ'),
(0x20F, 'V'),
(0x210, 'M', u'ȑ'),
(0x211, 'V'),
(0x212, 'M', u'ȓ'),
(0x213, 'V'),
(0x214, 'M', u'ȕ'),
(0x215, 'V'),
(0x216, 'M', u'ȗ'),
(0x217, 'V'),
(0x218, 'M', u'ș'),
(0x219, 'V'),
(0x21A, 'M', u'ț'),
(0x21B, 'V'),
(0x21C, 'M', u'ȝ'),
(0x21D, 'V'),
(0x21E, 'M', u'ȟ'),
(0x21F, 'V'),
(0x220, 'M', u'ƞ'),
(0x221, 'V'),
(0x222, 'M', u'ȣ'),
(0x223, 'V'),
(0x224, 'M', u'ȥ'),
(0x225, 'V'),
(0x226, 'M', u'ȧ'),
(0x227, 'V'),
(0x228, 'M', u'ȩ'),
(0x229, 'V'),
(0x22A, 'M', u'ȫ'),
(0x22B, 'V'),
(0x22C, 'M', u'ȭ'),
(0x22D, 'V'),
(0x22E, 'M', u'ȯ'),
(0x22F, 'V'),
(0x230, 'M', u'ȱ'),
(0x231, 'V'),
(0x232, 'M', u'ȳ'),
(0x233, 'V'),
(0x23A, 'M', u'ⱥ'),
(0x23B, 'M', u'ȼ'),
(0x23C, 'V'),
(0x23D, 'M', u'ƚ'),
(0x23E, 'M', u'ⱦ'),
(0x23F, 'V'),
(0x241, 'M', u'ɂ'),
(0x242, 'V'),
(0x243, 'M', u'ƀ'),
(0x244, 'M', u'ʉ'),
(0x245, 'M', u'ʌ'),
(0x246, 'M', u'ɇ'),
(0x247, 'V'),
(0x248, 'M', u'ɉ'),
(0x249, 'V'),
(0x24A, 'M', u'ɋ'),
(0x24B, 'V'),
(0x24C, 'M', u'ɍ'),
(0x24D, 'V'),
(0x24E, 'M', u'ɏ'),
(0x24F, 'V'),
(0x2B0, 'M', u'h'),
(0x2B1, 'M', u'ɦ'),
(0x2B2, 'M', u'j'),
(0x2B3, 'M', u'r'),
(0x2B4, 'M', u'ɹ'),
(0x2B5, 'M', u'ɻ'),
(0x2B6, 'M', u'ʁ'),
(0x2B7, 'M', u'w'),
(0x2B8, 'M', u'y'),
(0x2B9, 'V'),
(0x2D8, '3', u' ̆'),
(0x2D9, '3', u' ̇'),
(0x2DA, '3', u' ̊'),
(0x2DB, '3', u' ̨'),
(0x2DC, '3', u' ̃'),
(0x2DD, '3', u' ̋'),
(0x2DE, 'V'),
(0x2E0, 'M', u'ɣ'),
(0x2E1, 'M', u'l'),
(0x2E2, 'M', u's'),
(0x2E3, 'M', u'x'),
(0x2E4, 'M', u'ʕ'),
(0x2E5, 'V'),
(0x340, 'M', u'̀'),
(0x341, 'M', u'́'),
(0x342, 'V'),
(0x343, 'M', u'̓'),
(0x344, 'M', u'̈́'),
(0x345, 'M', u'ι'),
(0x346, 'V'),
(0x34F, 'I'),
(0x350, 'V'),
(0x370, 'M', u'ͱ'),
(0x371, 'V'),
(0x372, 'M', u'ͳ'),
(0x373, 'V'),
(0x374, 'M', u'ʹ'),
(0x375, 'V'),
(0x376, 'M', u'ͷ'),
(0x377, 'V'),
]
def _seg_6():
return [
(0x378, 'X'),
(0x37A, '3', u' ι'),
(0x37B, 'V'),
(0x37E, '3', u';'),
(0x37F, 'M', u'ϳ'),
(0x380, 'X'),
(0x384, '3', u' ́'),
(0x385, '3', u' ̈́'),
(0x386, 'M', u'ά'),
(0x387, 'M', u'·'),
(0x388, 'M', u'έ'),
(0x389, 'M', u'ή'),
(0x38A, 'M', u'ί'),
(0x38B, 'X'),
(0x38C, 'M', u'ό'),
(0x38D, 'X'),
(0x38E, 'M', u'ύ'),
(0x38F, 'M', u'ώ'),
(0x390, 'V'),
(0x391, 'M', u'α'),
(0x392, 'M', u'β'),
(0x393, 'M', u'γ'),
(0x394, 'M', u'δ'),
(0x395, 'M', u'ε'),
(0x396, 'M', u'ζ'),
(0x397, 'M', u'η'),
(0x398, 'M', u'θ'),
(0x399, 'M', u'ι'),
(0x39A, 'M', u'κ'),
(0x39B, 'M', u'λ'),
(0x39C, 'M', u'μ'),
(0x39D, 'M', u'ν'),
(0x39E, 'M', u'ξ'),
(0x39F, 'M', u'ο'),
(0x3A0, 'M', u'π'),
(0x3A1, 'M', u'ρ'),
(0x3A2, 'X'),
(0x3A3, 'M', u'σ'),
(0x3A4, 'M', u'τ'),
(0x3A5, 'M', u'υ'),
(0x3A6, 'M', u'φ'),
(0x3A7, 'M', u'χ'),
(0x3A8, 'M', u'ψ'),
(0x3A9, 'M', u'ω'),
(0x3AA, 'M', u'ϊ'),
(0x3AB, 'M', u'ϋ'),
(0x3AC, 'V'),
(0x3C2, 'D', u'σ'),
(0x3C3, 'V'),
(0x3CF, 'M', u'ϗ'),
(0x3D0, 'M', u'β'),
(0x3D1, 'M', u'θ'),
(0x3D2, 'M', u'υ'),
(0x3D3, 'M', u'ύ'),
(0x3D4, 'M', u'ϋ'),
(0x3D5, 'M', u'φ'),
(0x3D6, 'M', u'π'),
(0x3D7, 'V'),
(0x3D8, 'M', u'ϙ'),
(0x3D9, 'V'),
(0x3DA, 'M', u'ϛ'),
(0x3DB, 'V'),
(0x3DC, 'M', u'ϝ'),
(0x3DD, 'V'),
(0x3DE, 'M', u'ϟ'),
(0x3DF, 'V'),
(0x3E0, 'M', u'ϡ'),
(0x3E1, 'V'),
(0x3E2, 'M', u'ϣ'),
(0x3E3, 'V'),
(0x3E4, 'M', u'ϥ'),
(0x3E5, 'V'),
(0x3E6, 'M', u'ϧ'),
(0x3E7, 'V'),
(0x3E8, 'M', u'ϩ'),
(0x3E9, 'V'),
(0x3EA, 'M', u'ϫ'),
(0x3EB, 'V'),
(0x3EC, 'M', u'ϭ'),
(0x3ED, 'V'),
(0x3EE, 'M', u'ϯ'),
(0x3EF, 'V'),
(0x3F0, 'M', u'κ'),
(0x3F1, 'M', u'ρ'),
(0x3F2, 'M', u'σ'),
(0x3F3, 'V'),
(0x3F4, 'M', u'θ'),
(0x3F5, 'M', u'ε'),
(0x3F6, 'V'),
(0x3F7, 'M', u'ϸ'),
(0x3F8, 'V'),
(0x3F9, 'M', u'σ'),
(0x3FA, 'M', u'ϻ'),
(0x3FB, 'V'),
(0x3FD, 'M', u'ͻ'),
(0x3FE, 'M', u'ͼ'),
(0x3FF, 'M', u'ͽ'),
(0x400, 'M', u'ѐ'),
(0x401, 'M', u'ё'),
(0x402, 'M', u'ђ'),
]
def _seg_7():
return [
(0x403, 'M', u'ѓ'),
(0x404, 'M', u'є'),
(0x405, 'M', u'ѕ'),
(0x406, 'M', u'і'),
(0x407, 'M', u'ї'),
(0x408, 'M', u'ј'),
(0x409, 'M', u'љ'),
(0x40A, 'M', u'њ'),
(0x40B, 'M', u'ћ'),
(0x40C, 'M', u'ќ'),
(0x40D, 'M', u'ѝ'),
(0x40E, 'M', u'ў'),
(0x40F, 'M', u'џ'),
(0x410, 'M', u'а'),
(0x411, 'M', u'б'),
(0x412, 'M', u'в'),
(0x413, 'M', u'г'),
(0x414, 'M', u'д'),
(0x415, 'M', u'е'),
(0x416, 'M', u'ж'),
(0x417, 'M', u'з'),
(0x418, 'M', u'и'),
(0x419, 'M', u'й'),
(0x41A, 'M', u'к'),
(0x41B, 'M', u'л'),
(0x41C, 'M', u'м'),
(0x41D, 'M', u'н'),
(0x41E, 'M', u'о'),
(0x41F, 'M', u'п'),
(0x420, 'M', u'р'),
(0x421, 'M', u'с'),
(0x422, 'M', u'т'),
(0x423, 'M', u'у'),
(0x424, 'M', u'ф'),
(0x425, 'M', u'х'),
(0x426, 'M', u'ц'),
(0x427, 'M', u'ч'),
(0x428, 'M', u'ш'),
(0x429, 'M', u'щ'),
(0x42A, 'M', u'ъ'),
(0x42B, 'M', u'ы'),
(0x42C, 'M', u'ь'),
(0x42D, 'M', u'э'),
(0x42E, 'M', u'ю'),
(0x42F, 'M', u'я'),
(0x430, 'V'),
(0x460, 'M', u'ѡ'),
(0x461, 'V'),
(0x462, 'M', u'ѣ'),
(0x463, 'V'),
(0x464, 'M', u'ѥ'),
(0x465, 'V'),
(0x466, 'M', u'ѧ'),
(0x467, 'V'),
(0x468, 'M', u'ѩ'),
(0x469, 'V'),
(0x46A, 'M', u'ѫ'),
(0x46B, 'V'),
(0x46C, 'M', u'ѭ'),
(0x46D, 'V'),
(0x46E, 'M', u'ѯ'),
(0x46F, 'V'),
(0x470, 'M', u'ѱ'),
(0x471, 'V'),
(0x472, 'M', u'ѳ'),
(0x473, 'V'),
(0x474, 'M', u'ѵ'),
(0x475, 'V'),
(0x476, 'M', u'ѷ'),
(0x477, 'V'),
(0x478, 'M', u'ѹ'),
(0x479, 'V'),
(0x47A, 'M', u'ѻ'),
(0x47B, 'V'),
(0x47C, 'M', u'ѽ'),
(0x47D, 'V'),
(0x47E, 'M', u'ѿ'),
(0x47F, 'V'),
(0x480, 'M', u'ҁ'),
(0x481, 'V'),
(0x48A, 'M', u'ҋ'),
(0x48B, 'V'),
(0x48C, 'M', u'ҍ'),
(0x48D, 'V'),
(0x48E, 'M', u'ҏ'),
(0x48F, 'V'),
(0x490, 'M', u'ґ'),
(0x491, 'V'),
(0x492, 'M', u'ғ'),
(0x493, 'V'),
(0x494, 'M', u'ҕ'),
(0x495, 'V'),
(0x496, 'M', u'җ'),
(0x497, 'V'),
(0x498, 'M', u'ҙ'),
(0x499, 'V'),
(0x49A, 'M', u'қ'),
(0x49B, 'V'),
(0x49C, 'M', u'ҝ'),
(0x49D, 'V'),
]
def _seg_8():
return [
(0x49E, 'M', u'ҟ'),
(0x49F, 'V'),
(0x4A0, 'M', u'ҡ'),
(0x4A1, 'V'),
(0x4A2, 'M', u'ң'),
(0x4A3, 'V'),
(0x4A4, 'M', u'ҥ'),
(0x4A5, 'V'),
(0x4A6, 'M', u'ҧ'),
(0x4A7, 'V'),
(0x4A8, 'M', u'ҩ'),
(0x4A9, 'V'),
(0x4AA, 'M', u'ҫ'),
(0x4AB, 'V'),
(0x4AC, 'M', u'ҭ'),
(0x4AD, 'V'),
(0x4AE, 'M', u'ү'),
(0x4AF, 'V'),
(0x4B0, 'M', u'ұ'),
(0x4B1, 'V'),
(0x4B2, 'M', u'ҳ'),
(0x4B3, 'V'),
(0x4B4, 'M', u'ҵ'),
(0x4B5, 'V'),
(0x4B6, 'M', u'ҷ'),
(0x4B7, 'V'),
(0x4B8, 'M', u'ҹ'),
(0x4B9, 'V'),
(0x4BA, 'M', u'һ'),
(0x4BB, 'V'),
(0x4BC, 'M', u'ҽ'),
(0x4BD, 'V'),
(0x4BE, 'M', u'ҿ'),
(0x4BF, 'V'),
(0x4C0, 'X'),
(0x4C1, 'M', u'ӂ'),
(0x4C2, 'V'),
(0x4C3, 'M', u'ӄ'),
(0x4C4, 'V'),
(0x4C5, 'M', u'ӆ'),
(0x4C6, 'V'),
(0x4C7, 'M', u'ӈ'),
(0x4C8, 'V'),
(0x4C9, 'M', u'ӊ'),
(0x4CA, 'V'),
(0x4CB, 'M', u'ӌ'),
(0x4CC, 'V'),
(0x4CD, 'M', u'ӎ'),
(0x4CE, 'V'),
(0x4D0, 'M', u'ӑ'),
(0x4D1, 'V'),
(0x4D2, 'M', u'ӓ'),
(0x4D3, 'V'),
(0x4D4, 'M', u'ӕ'),
(0x4D5, 'V'),
(0x4D6, 'M', u'ӗ'),
(0x4D7, 'V'),
(0x4D8, 'M', u'ә'),
(0x4D9, 'V'),
(0x4DA, 'M', u'ӛ'),
(0x4DB, 'V'),
(0x4DC, 'M', u'ӝ'),
(0x4DD, 'V'),
(0x4DE, 'M', u'ӟ'),
(0x4DF, 'V'),
(0x4E0, 'M', u'ӡ'),
(0x4E1, 'V'),
(0x4E2, 'M', u'ӣ'),
(0x4E3, 'V'),
(0x4E4, 'M', u'ӥ'),
(0x4E5, 'V'),
(0x4E6, 'M', u'ӧ'),
(0x4E7, 'V'),
(0x4E8, 'M', u'ө'),
(0x4E9, 'V'),
(0x4EA, 'M', u'ӫ'),
(0x4EB, 'V'),
(0x4EC, 'M', u'ӭ'),
(0x4ED, 'V'),
(0x4EE, 'M', u'ӯ'),
(0x4EF, 'V'),
(0x4F0, 'M', u'ӱ'),
(0x4F1, 'V'),
(0x4F2, 'M', u'ӳ'),
(0x4F3, 'V'),
(0x4F4, 'M', u'ӵ'),
(0x4F5, 'V'),
(0x4F6, 'M', u'ӷ'),
(0x4F7, 'V'),
(0x4F8, 'M', u'ӹ'),
(0x4F9, 'V'),
(0x4FA, 'M', u'ӻ'),
(0x4FB, 'V'),
(0x4FC, 'M', u'ӽ'),
(0x4FD, 'V'),
(0x4FE, 'M', u'ӿ'),
(0x4FF, 'V'),
(0x500, 'M', u'ԁ'),
(0x501, 'V'),
(0x502, 'M', u'ԃ'),
]
def _seg_9():
return [
(0x503, 'V'),
(0x504, 'M', u'ԅ'),
(0x505, 'V'),
(0x506, 'M', u'ԇ'),
(0x507, 'V'),
(0x508, 'M', u'ԉ'),
(0x509, 'V'),
(0x50A, 'M', u'ԋ'),
(0x50B, 'V'),
(0x50C, 'M', u'ԍ'),
(0x50D, 'V'),
(0x50E, 'M', u'ԏ'),
(0x50F, 'V'),
(0x510, 'M', u'ԑ'),
(0x511, 'V'),
(0x512, 'M', u'ԓ'),
(0x513, 'V'),
(0x514, 'M', u'ԕ'),
(0x515, 'V'),
(0x516, 'M', u'ԗ'),
(0x517, 'V'),
(0x518, 'M', u'ԙ'),
(0x519, 'V'),
(0x51A, 'M', u'ԛ'),
(0x51B, 'V'),
(0x51C, 'M', u'ԝ'),
(0x51D, 'V'),
(0x51E, 'M', u'ԟ'),
(0x51F, 'V'),
(0x520, 'M', u'ԡ'),
(0x521, 'V'),
(0x522, 'M', u'ԣ'),
(0x523, 'V'),
(0x524, 'M', u'ԥ'),
(0x525, 'V'),
(0x526, 'M', u'ԧ'),
(0x527, 'V'),
(0x528, 'M', u'ԩ'),
(0x529, 'V'),
(0x52A, 'M', u'ԫ'),
(0x52B, 'V'),
(0x52C, 'M', u'ԭ'),
(0x52D, 'V'),
(0x52E, 'M', u'ԯ'),
(0x52F, 'V'),
(0x530, 'X'),
(0x531, 'M', u'ա'),
(0x532, 'M', u'բ'),
(0x533, 'M', u'գ'),
(0x534, 'M', u'դ'),
(0x535, 'M', u'ե'),
(0x536, 'M', u'զ'),
(0x537, 'M', u'է'),
(0x538, 'M', u'ը'),
(0x539, 'M', u'թ'),
(0x53A, 'M', u'ժ'),
(0x53B, 'M', u'ի'),
(0x53C, 'M', u'լ'),
(0x53D, 'M', u'խ'),
(0x53E, 'M', u'ծ'),
(0x53F, 'M', u'կ'),
(0x540, 'M', u'հ'),
(0x541, 'M', u'ձ'),
(0x542, 'M', u'ղ'),
(0x543, 'M', u'ճ'),
(0x544, 'M', u'մ'),
(0x545, 'M', u'յ'),
(0x546, 'M', u'ն'),
(0x547, 'M', u'շ'),
(0x548, 'M', u'ո'),
(0x549, 'M', u'չ'),
(0x54A, 'M', u'պ'),
(0x54B, 'M', u'ջ'),
(0x54C, 'M', u'ռ'),
(0x54D, 'M', u'ս'),
(0x54E, 'M', u'վ'),
(0x54F, 'M', u'տ'),
(0x550, 'M', u'ր'),
(0x551, 'M', u'ց'),
(0x552, 'M', u'ւ'),
(0x553, 'M', u'փ'),
(0x554, 'M', u'ք'),
(0x555, 'M', u'օ'),
(0x556, 'M', u'ֆ'),
(0x557, 'X'),
(0x559, 'V'),
(0x587, 'M', u'եւ'),
(0x588, 'V'),
(0x58B, 'X'),
(0x58D, 'V'),
(0x590, 'X'),
(0x591, 'V'),
(0x5C8, 'X'),
(0x5D0, 'V'),
(0x5EB, 'X'),
(0x5EF, 'V'),
(0x5F5, 'X'),
(0x606, 'V'),
(0x61C, 'X'),
(0x61E, 'V'),
]
def _seg_10():
return [
(0x675, 'M', u'اٴ'),
(0x676, 'M', u'وٴ'),
(0x677, 'M', u'ۇٴ'),
(0x678, 'M', u'يٴ'),
(0x679, 'V'),
(0x6DD, 'X'),
(0x6DE, 'V'),
(0x70E, 'X'),
(0x710, 'V'),
(0x74B, 'X'),
(0x74D, 'V'),
(0x7B2, 'X'),
(0x7C0, 'V'),
(0x7FB, 'X'),
(0x7FD, 'V'),
(0x82E, 'X'),
(0x830, 'V'),
(0x83F, 'X'),
(0x840, 'V'),
(0x85C, 'X'),
(0x85E, 'V'),
(0x85F, 'X'),
(0x860, 'V'),
(0x86B, 'X'),
(0x8A0, 'V'),
(0x8B5, 'X'),
(0x8B6, 'V'),
(0x8BE, 'X'),
(0x8D3, 'V'),
(0x8E2, 'X'),
(0x8E3, 'V'),
(0x958, 'M', u'क़'),
(0x959, 'M', u'ख़'),
(0x95A, 'M', u'ग़'),
(0x95B, 'M', u'ज़'),
(0x95C, 'M', u'ड़'),
(0x95D, 'M', u'ढ़'),
(0x95E, 'M', u'फ़'),
(0x95F, 'M', u'य़'),
(0x960, 'V'),
(0x984, 'X'),
(0x985, 'V'),
(0x98D, 'X'),
(0x98F, 'V'),
(0x991, 'X'),
(0x993, 'V'),
(0x9A9, 'X'),
(0x9AA, 'V'),
(0x9B1, 'X'),
(0x9B2, 'V'),
(0x9B3, 'X'),
(0x9B6, 'V'),
(0x9BA, 'X'),
(0x9BC, 'V'),
(0x9C5, 'X'),
(0x9C7, 'V'),
(0x9C9, 'X'),
(0x9CB, 'V'),
(0x9CF, 'X'),
(0x9D7, 'V'),
(0x9D8, 'X'),
(0x9DC, 'M', u'ড়'),
(0x9DD, 'M', u'ঢ়'),
(0x9DE, 'X'),
(0x9DF, 'M', u'য়'),
(0x9E0, 'V'),
(0x9E4, 'X'),
(0x9E6, 'V'),
(0x9FF, 'X'),
(0xA01, 'V'),
(0xA04, 'X'),
(0xA05, 'V'),
(0xA0B, 'X'),
(0xA0F, 'V'),
(0xA11, 'X'),
(0xA13, 'V'),
(0xA29, 'X'),
(0xA2A, 'V'),
(0xA31, 'X'),
(0xA32, 'V'),
(0xA33, 'M', u'ਲ਼'),
(0xA34, 'X'),
(0xA35, 'V'),
(0xA36, 'M', u'ਸ਼'),
(0xA37, 'X'),
(0xA38, 'V'),
(0xA3A, 'X'),
(0xA3C, 'V'),
(0xA3D, 'X'),
(0xA3E, 'V'),
(0xA43, 'X'),
(0xA47, 'V'),
(0xA49, 'X'),
(0xA4B, 'V'),
(0xA4E, 'X'),
(0xA51, 'V'),
(0xA52, 'X'),
(0xA59, 'M', u'ਖ਼'),
(0xA5A, 'M', u'ਗ਼'),
(0xA5B, 'M', u'ਜ਼'),
]
def _seg_11():
return [
(0xA5C, 'V'),
(0xA5D, 'X'),
(0xA5E, 'M', u'ਫ਼'),
(0xA5F, 'X'),
(0xA66, 'V'),
(0xA77, 'X'),
(0xA81, 'V'),
(0xA84, 'X'),
(0xA85, 'V'),
(0xA8E, 'X'),
(0xA8F, 'V'),
(0xA92, 'X'),
(0xA93, 'V'),
(0xAA9, 'X'),
(0xAAA, 'V'),
(0xAB1, 'X'),
(0xAB2, 'V'),
(0xAB4, 'X'),
(0xAB5, 'V'),
(0xABA, 'X'),
(0xABC, 'V'),
(0xAC6, 'X'),
(0xAC7, 'V'),
(0xACA, 'X'),
(0xACB, 'V'),
(0xACE, 'X'),
(0xAD0, 'V'),
(0xAD1, 'X'),
(0xAE0, 'V'),
(0xAE4, 'X'),
(0xAE6, 'V'),
(0xAF2, 'X'),
(0xAF9, 'V'),
(0xB00, 'X'),
(0xB01, 'V'),
(0xB04, 'X'),
(0xB05, 'V'),
(0xB0D, 'X'),
(0xB0F, 'V'),
(0xB11, 'X'),
(0xB13, 'V'),
(0xB29, 'X'),
(0xB2A, 'V'),
(0xB31, 'X'),
(0xB32, 'V'),
(0xB34, 'X'),
(0xB35, 'V'),
(0xB3A, 'X'),
(0xB3C, 'V'),
(0xB45, 'X'),
(0xB47, 'V'),
(0xB49, 'X'),
(0xB4B, 'V'),
(0xB4E, 'X'),
(0xB56, 'V'),
(0xB58, 'X'),
(0xB5C, 'M', u'ଡ଼'),
(0xB5D, 'M', u'ଢ଼'),
(0xB5E, 'X'),
(0xB5F, 'V'),
(0xB64, 'X'),
(0xB66, 'V'),
(0xB78, 'X'),
(0xB82, 'V'),
(0xB84, 'X'),
(0xB85, 'V'),
(0xB8B, 'X'),
(0xB8E, 'V'),
(0xB91, 'X'),
(0xB92, 'V'),
(0xB96, 'X'),
(0xB99, 'V'),
(0xB9B, 'X'),
(0xB9C, 'V'),
(0xB9D, 'X'),
(0xB9E, 'V'),
(0xBA0, 'X'),
(0xBA3, 'V'),
(0xBA5, 'X'),
(0xBA8, 'V'),
(0xBAB, 'X'),
(0xBAE, 'V'),
(0xBBA, 'X'),
(0xBBE, 'V'),
(0xBC3, 'X'),
(0xBC6, 'V'),
(0xBC9, 'X'),
(0xBCA, 'V'),
(0xBCE, 'X'),
(0xBD0, 'V'),
(0xBD1, 'X'),
(0xBD7, 'V'),
(0xBD8, 'X'),
(0xBE6, 'V'),
(0xBFB, 'X'),
(0xC00, 'V'),
(0xC0D, 'X'),
(0xC0E, 'V'),
(0xC11, 'X'),
(0xC12, 'V'),
]
def _seg_12():
return [
(0xC29, 'X'),
(0xC2A, 'V'),
(0xC3A, 'X'),
(0xC3D, 'V'),
(0xC45, 'X'),
(0xC46, 'V'),
(0xC49, 'X'),
(0xC4A, 'V'),
(0xC4E, 'X'),
(0xC55, 'V'),
(0xC57, 'X'),
(0xC58, 'V'),
(0xC5B, 'X'),
(0xC60, 'V'),
(0xC64, 'X'),
(0xC66, 'V'),
(0xC70, 'X'),
(0xC78, 'V'),
(0xC8D, 'X'),
(0xC8E, 'V'),
(0xC91, 'X'),
(0xC92, 'V'),
(0xCA9, 'X'),
(0xCAA, 'V'),
(0xCB4, 'X'),
(0xCB5, 'V'),
(0xCBA, 'X'),
(0xCBC, 'V'),
(0xCC5, 'X'),
(0xCC6, 'V'),
(0xCC9, 'X'),
(0xCCA, 'V'),
(0xCCE, 'X'),
(0xCD5, 'V'),
(0xCD7, 'X'),
(0xCDE, 'V'),
(0xCDF, 'X'),
(0xCE0, 'V'),
(0xCE4, 'X'),
(0xCE6, 'V'),
(0xCF0, 'X'),
(0xCF1, 'V'),
(0xCF3, 'X'),
(0xD00, 'V'),
(0xD04, 'X'),
(0xD05, 'V'),
(0xD0D, 'X'),
(0xD0E, 'V'),
(0xD11, 'X'),
(0xD12, 'V'),
(0xD45, 'X'),
(0xD46, 'V'),
(0xD49, 'X'),
(0xD4A, 'V'),
(0xD50, 'X'),
(0xD54, 'V'),
(0xD64, 'X'),
(0xD66, 'V'),
(0xD80, 'X'),
(0xD82, 'V'),
(0xD84, 'X'),
(0xD85, 'V'),
(0xD97, 'X'),
(0xD9A, 'V'),
(0xDB2, 'X'),
(0xDB3, 'V'),
(0xDBC, 'X'),
(0xDBD, 'V'),
(0xDBE, 'X'),
(0xDC0, 'V'),
(0xDC7, 'X'),
(0xDCA, 'V'),
(0xDCB, 'X'),
(0xDCF, 'V'),
(0xDD5, 'X'),
(0xDD6, 'V'),
(0xDD7, 'X'),
(0xDD8, 'V'),
(0xDE0, 'X'),
(0xDE6, 'V'),
(0xDF0, 'X'),
(0xDF2, 'V'),
(0xDF5, 'X'),
(0xE01, 'V'),
(0xE33, 'M', u'ํา'),
(0xE34, 'V'),
(0xE3B, 'X'),
(0xE3F, 'V'),
(0xE5C, 'X'),
(0xE81, 'V'),
(0xE83, 'X'),
(0xE84, 'V'),
(0xE85, 'X'),
(0xE87, 'V'),
(0xE89, 'X'),
(0xE8A, 'V'),
(0xE8B, 'X'),
(0xE8D, 'V'),
(0xE8E, 'X'),
(0xE94, 'V'),
]
def _seg_13():
return [
(0xE98, 'X'),
(0xE99, 'V'),
(0xEA0, 'X'),
(0xEA1, 'V'),
(0xEA4, 'X'),
(0xEA5, 'V'),
(0xEA6, 'X'),
(0xEA7, 'V'),
(0xEA8, 'X'),
(0xEAA, 'V'),
(0xEAC, 'X'),
(0xEAD, 'V'),
(0xEB3, 'M', u'ໍາ'),
(0xEB4, 'V'),
(0xEBA, 'X'),
(0xEBB, 'V'),
(0xEBE, 'X'),
(0xEC0, 'V'),
(0xEC5, 'X'),
(0xEC6, 'V'),
(0xEC7, 'X'),
(0xEC8, 'V'),
(0xECE, 'X'),
(0xED0, 'V'),
(0xEDA, 'X'),
(0xEDC, 'M', u'ຫນ'),
(0xEDD, 'M', u'ຫມ'),
(0xEDE, 'V'),
(0xEE0, 'X'),
(0xF00, 'V'),
(0xF0C, 'M', u'་'),
(0xF0D, 'V'),
(0xF43, 'M', u'གྷ'),
(0xF44, 'V'),
(0xF48, 'X'),
(0xF49, 'V'),
(0xF4D, 'M', u'ཌྷ'),
(0xF4E, 'V'),
(0xF52, 'M', u'དྷ'),
(0xF53, 'V'),
(0xF57, 'M', u'བྷ'),
(0xF58, 'V'),
(0xF5C, 'M', u'ཛྷ'),
(0xF5D, 'V'),
(0xF69, 'M', u'ཀྵ'),
(0xF6A, 'V'),
(0xF6D, 'X'),
(0xF71, 'V'),
(0xF73, 'M', u'ཱི'),
(0xF74, 'V'),
(0xF75, 'M', u'ཱུ'),
(0xF76, 'M', u'ྲྀ'),
(0xF77, 'M', u'ྲཱྀ'),
(0xF78, 'M', u'ླྀ'),
(0xF79, 'M', u'ླཱྀ'),
(0xF7A, 'V'),
(0xF81, 'M', u'ཱྀ'),
(0xF82, 'V'),
(0xF93, 'M', u'ྒྷ'),
(0xF94, 'V'),
(0xF98, 'X'),
(0xF99, 'V'),
(0xF9D, 'M', u'ྜྷ'),
(0xF9E, 'V'),
(0xFA2, 'M', u'ྡྷ'),
(0xFA3, 'V'),
(0xFA7, 'M', u'ྦྷ'),
(0xFA8, 'V'),
(0xFAC, 'M', u'ྫྷ'),
(0xFAD, 'V'),
(0xFB9, 'M', u'ྐྵ'),
(0xFBA, 'V'),
(0xFBD, 'X'),
(0xFBE, 'V'),
(0xFCD, 'X'),
(0xFCE, 'V'),
(0xFDB, 'X'),
(0x1000, 'V'),
(0x10A0, 'X'),
(0x10C7, 'M', u'ⴧ'),
(0x10C8, 'X'),
(0x10CD, 'M', u'ⴭ'),
(0x10CE, 'X'),
(0x10D0, 'V'),
(0x10FC, 'M', u'ნ'),
(0x10FD, 'V'),
(0x115F, 'X'),
(0x1161, 'V'),
(0x1249, 'X'),
(0x124A, 'V'),
(0x124E, 'X'),
(0x1250, 'V'),
(0x1257, 'X'),
(0x1258, 'V'),
(0x1259, 'X'),
(0x125A, 'V'),
(0x125E, 'X'),
(0x1260, 'V'),
(0x1289, 'X'),
(0x128A, 'V'),
]
def _seg_14():
return [
(0x128E, 'X'),
(0x1290, 'V'),
(0x12B1, 'X'),
(0x12B2, 'V'),
(0x12B6, 'X'),
(0x12B8, 'V'),
(0x12BF, 'X'),
(0x12C0, 'V'),
(0x12C1, 'X'),
(0x12C2, 'V'),
(0x12C6, 'X'),
(0x12C8, 'V'),
(0x12D7, 'X'),
(0x12D8, 'V'),
(0x1311, 'X'),
(0x1312, 'V'),
(0x1316, 'X'),
(0x1318, 'V'),
(0x135B, 'X'),
(0x135D, 'V'),
(0x137D, 'X'),
(0x1380, 'V'),
(0x139A, 'X'),
(0x13A0, 'V'),
(0x13F6, 'X'),
(0x13F8, 'M', u'Ᏸ'),
(0x13F9, 'M', u'Ᏹ'),
(0x13FA, 'M', u'Ᏺ'),
(0x13FB, 'M', u'Ᏻ'),
(0x13FC, 'M', u'Ᏼ'),
(0x13FD, 'M', u'Ᏽ'),
(0x13FE, 'X'),
(0x1400, 'V'),
(0x1680, 'X'),
(0x1681, 'V'),
(0x169D, 'X'),
(0x16A0, 'V'),
(0x16F9, 'X'),
(0x1700, 'V'),
(0x170D, 'X'),
(0x170E, 'V'),
(0x1715, 'X'),
(0x1720, 'V'),
(0x1737, 'X'),
(0x1740, 'V'),
(0x1754, 'X'),
(0x1760, 'V'),
(0x176D, 'X'),
(0x176E, 'V'),
(0x1771, 'X'),
(0x1772, 'V'),
(0x1774, 'X'),
(0x1780, 'V'),
(0x17B4, 'X'),
(0x17B6, 'V'),
(0x17DE, 'X'),
(0x17E0, 'V'),
(0x17EA, 'X'),
(0x17F0, 'V'),
(0x17FA, 'X'),
(0x1800, 'V'),
(0x1806, 'X'),
(0x1807, 'V'),
(0x180B, 'I'),
(0x180E, 'X'),
(0x1810, 'V'),
(0x181A, 'X'),
(0x1820, 'V'),
(0x1879, 'X'),
(0x1880, 'V'),
(0x18AB, 'X'),
(0x18B0, 'V'),
(0x18F6, 'X'),
(0x1900, 'V'),
(0x191F, 'X'),
(0x1920, 'V'),
(0x192C, 'X'),
(0x1930, 'V'),
(0x193C, 'X'),
(0x1940, 'V'),
(0x1941, 'X'),
(0x1944, 'V'),
(0x196E, 'X'),
(0x1970, 'V'),
(0x1975, 'X'),
(0x1980, 'V'),
(0x19AC, 'X'),
(0x19B0, 'V'),
(0x19CA, 'X'),
(0x19D0, 'V'),
(0x19DB, 'X'),
(0x19DE, 'V'),
(0x1A1C, 'X'),
(0x1A1E, 'V'),
(0x1A5F, 'X'),
(0x1A60, 'V'),
(0x1A7D, 'X'),
(0x1A7F, 'V'),
(0x1A8A, 'X'),
(0x1A90, 'V'),
]
def _seg_15():
return [
(0x1A9A, 'X'),
(0x1AA0, 'V'),
(0x1AAE, 'X'),
(0x1AB0, 'V'),
(0x1ABF, 'X'),
(0x1B00, 'V'),
(0x1B4C, 'X'),
(0x1B50, 'V'),
(0x1B7D, 'X'),
(0x1B80, 'V'),
(0x1BF4, 'X'),
(0x1BFC, 'V'),
(0x1C38, 'X'),
(0x1C3B, 'V'),
(0x1C4A, 'X'),
(0x1C4D, 'V'),
(0x1C80, 'M', u'в'),
(0x1C81, 'M', u'д'),
(0x1C82, 'M', u'о'),
(0x1C83, 'M', u'с'),
(0x1C84, 'M', u'т'),
(0x1C86, 'M', u'ъ'),
(0x1C87, 'M', u'ѣ'),
(0x1C88, 'M', u'ꙋ'),
(0x1C89, 'X'),
(0x1CC0, 'V'),
(0x1CC8, 'X'),
(0x1CD0, 'V'),
(0x1CFA, 'X'),
(0x1D00, 'V'),
(0x1D2C, 'M', u'a'),
(0x1D2D, 'M', u'æ'),
(0x1D2E, 'M', u'b'),
(0x1D2F, 'V'),
(0x1D30, 'M', u'd'),
(0x1D31, 'M', u'e'),
(0x1D32, 'M', u'ǝ'),
(0x1D33, 'M', u'g'),
(0x1D34, 'M', u'h'),
(0x1D35, 'M', u'i'),
(0x1D36, 'M', u'j'),
(0x1D37, 'M', u'k'),
(0x1D38, 'M', u'l'),
(0x1D39, 'M', u'm'),
(0x1D3A, 'M', u'n'),
(0x1D3B, 'V'),
(0x1D3C, 'M', u'o'),
(0x1D3D, 'M', u'ȣ'),
(0x1D3E, 'M', u'p'),
(0x1D3F, 'M', u'r'),
(0x1D40, 'M', u't'),
(0x1D41, 'M', u'u'),
(0x1D42, 'M', u'w'),
(0x1D43, 'M', u'a'),
(0x1D44, 'M', u'ɐ'),
(0x1D45, 'M', u'ɑ'),
(0x1D46, 'M', u'ᴂ'),
(0x1D47, 'M', u'b'),
(0x1D48, 'M', u'd'),
(0x1D49, 'M', u'e'),
(0x1D4A, 'M', u'ə'),
(0x1D4B, 'M', u'ɛ'),
(0x1D4C, 'M', u'ɜ'),
(0x1D4D, 'M', u'g'),
(0x1D4E, 'V'),
(0x1D4F, 'M', u'k'),
(0x1D50, 'M', u'm'),
(0x1D51, 'M', u'ŋ'),
(0x1D52, 'M', u'o'),
(0x1D53, 'M', u'ɔ'),
(0x1D54, 'M', u'ᴖ'),
(0x1D55, 'M', u'ᴗ'),
(0x1D56, 'M', u'p'),
(0x1D57, 'M', u't'),
(0x1D58, 'M', u'u'),
(0x1D59, 'M', u'ᴝ'),
(0x1D5A, 'M', u'ɯ'),
(0x1D5B, 'M', u'v'),
(0x1D5C, 'M', u'ᴥ'),
(0x1D5D, 'M', u'β'),
(0x1D5E, 'M', u'γ'),
(0x1D5F, 'M', u'δ'),
(0x1D60, 'M', u'φ'),
(0x1D61, 'M', u'χ'),
(0x1D62, 'M', u'i'),
(0x1D63, 'M', u'r'),
(0x1D64, 'M', u'u'),
(0x1D65, 'M', u'v'),
(0x1D66, 'M', u'β'),
(0x1D67, 'M', u'γ'),
(0x1D68, 'M', u'ρ'),
(0x1D69, 'M', u'φ'),
(0x1D6A, 'M', u'χ'),
(0x1D6B, 'V'),
(0x1D78, 'M', u'н'),
(0x1D79, 'V'),
(0x1D9B, 'M', u'ɒ'),
(0x1D9C, 'M', u'c'),
(0x1D9D, 'M', u'ɕ'),
(0x1D9E, 'M', u'ð'),
]
def _seg_16():
return [
(0x1D9F, 'M', u'ɜ'),
(0x1DA0, 'M', u'f'),
(0x1DA1, 'M', u'ɟ'),
(0x1DA2, 'M', u'ɡ'),
(0x1DA3, 'M', u'ɥ'),
(0x1DA4, 'M', u'ɨ'),
(0x1DA5, 'M', u'ɩ'),
(0x1DA6, 'M', u'ɪ'),
(0x1DA7, 'M', u'ᵻ'),
(0x1DA8, 'M', u'ʝ'),
(0x1DA9, 'M', u'ɭ'),
(0x1DAA, 'M', u'ᶅ'),
(0x1DAB, 'M', u'ʟ'),
(0x1DAC, 'M', u'ɱ'),
(0x1DAD, 'M', u'ɰ'),
(0x1DAE, 'M', u'ɲ'),
(0x1DAF, 'M', u'ɳ'),
(0x1DB0, 'M', u'ɴ'),
(0x1DB1, 'M', u'ɵ'),
(0x1DB2, 'M', u'ɸ'),
(0x1DB3, 'M', u'ʂ'),
(0x1DB4, 'M', u'ʃ'),
(0x1DB5, 'M', u'ƫ'),
(0x1DB6, 'M', u'ʉ'),
(0x1DB7, 'M', u'ʊ'),
(0x1DB8, 'M', u'ᴜ'),
(0x1DB9, 'M', u'ʋ'),
(0x1DBA, 'M', u'ʌ'),
(0x1DBB, 'M', u'z'),
(0x1DBC, 'M', u'ʐ'),
(0x1DBD, 'M', u'ʑ'),
(0x1DBE, 'M', u'ʒ'),
(0x1DBF, 'M', u'θ'),
(0x1DC0, 'V'),
(0x1DFA, 'X'),
(0x1DFB, 'V'),
(0x1E00, 'M', u'ḁ'),
(0x1E01, 'V'),
(0x1E02, 'M', u'ḃ'),
(0x1E03, 'V'),
(0x1E04, 'M', u'ḅ'),
(0x1E05, 'V'),
(0x1E06, 'M', u'ḇ'),
(0x1E07, 'V'),
(0x1E08, 'M', u'ḉ'),
(0x1E09, 'V'),
(0x1E0A, 'M', u'ḋ'),
(0x1E0B, 'V'),
(0x1E0C, 'M', u'ḍ'),
(0x1E0D, 'V'),
(0x1E0E, 'M', u'ḏ'),
(0x1E0F, 'V'),
(0x1E10, 'M', u'ḑ'),
(0x1E11, 'V'),
(0x1E12, 'M', u'ḓ'),
(0x1E13, 'V'),
(0x1E14, 'M', u'ḕ'),
(0x1E15, 'V'),
(0x1E16, 'M', u'ḗ'),
(0x1E17, 'V'),
(0x1E18, 'M', u'ḙ'),
(0x1E19, 'V'),
(0x1E1A, 'M', u'ḛ'),
(0x1E1B, 'V'),
(0x1E1C, 'M', u'ḝ'),
(0x1E1D, 'V'),
(0x1E1E, 'M', u'ḟ'),
(0x1E1F, 'V'),
(0x1E20, 'M', u'ḡ'),
(0x1E21, 'V'),
(0x1E22, 'M', u'ḣ'),
(0x1E23, 'V'),
(0x1E24, 'M', u'ḥ'),
(0x1E25, 'V'),
(0x1E26, 'M', u'ḧ'),
(0x1E27, 'V'),
(0x1E28, 'M', u'ḩ'),
(0x1E29, 'V'),
(0x1E2A, 'M', u'ḫ'),
(0x1E2B, 'V'),
(0x1E2C, 'M', u'ḭ'),
(0x1E2D, 'V'),
(0x1E2E, 'M', u'ḯ'),
(0x1E2F, 'V'),
(0x1E30, 'M', u'ḱ'),
(0x1E31, 'V'),
(0x1E32, 'M', u'ḳ'),
(0x1E33, 'V'),
(0x1E34, 'M', u'ḵ'),
(0x1E35, 'V'),
(0x1E36, 'M', u'ḷ'),
(0x1E37, 'V'),
(0x1E38, 'M', u'ḹ'),
(0x1E39, 'V'),
(0x1E3A, 'M', u'ḻ'),
(0x1E3B, 'V'),
(0x1E3C, 'M', u'ḽ'),
(0x1E3D, 'V'),
(0x1E3E, 'M', u'ḿ'),
(0x1E3F, 'V'),
]
def _seg_17():
return [
(0x1E40, 'M', u'ṁ'),
(0x1E41, 'V'),
(0x1E42, 'M', u'ṃ'),
(0x1E43, 'V'),
(0x1E44, 'M', u'ṅ'),
(0x1E45, 'V'),
(0x1E46, 'M', u'ṇ'),
(0x1E47, 'V'),
(0x1E48, 'M', u'ṉ'),
(0x1E49, 'V'),
(0x1E4A, 'M', u'ṋ'),
(0x1E4B, 'V'),
(0x1E4C, 'M', u'ṍ'),
(0x1E4D, 'V'),
(0x1E4E, 'M', u'ṏ'),
(0x1E4F, 'V'),
(0x1E50, 'M', u'ṑ'),
(0x1E51, 'V'),
(0x1E52, 'M', u'ṓ'),
(0x1E53, 'V'),
(0x1E54, 'M', u'ṕ'),
(0x1E55, 'V'),
(0x1E56, 'M', u'ṗ'),
(0x1E57, 'V'),
(0x1E58, 'M', u'ṙ'),
(0x1E59, 'V'),
(0x1E5A, 'M', u'ṛ'),
(0x1E5B, 'V'),
(0x1E5C, 'M', u'ṝ'),
(0x1E5D, 'V'),
(0x1E5E, 'M', u'ṟ'),
(0x1E5F, 'V'),
(0x1E60, 'M', u'ṡ'),
(0x1E61, 'V'),
(0x1E62, 'M', u'ṣ'),
(0x1E63, 'V'),
(0x1E64, 'M', u'ṥ'),
(0x1E65, 'V'),
(0x1E66, 'M', u'ṧ'),
(0x1E67, 'V'),
(0x1E68, 'M', u'ṩ'),
(0x1E69, 'V'),
(0x1E6A, 'M', u'ṫ'),
(0x1E6B, 'V'),
(0x1E6C, 'M', u'ṭ'),
(0x1E6D, 'V'),
(0x1E6E, 'M', u'ṯ'),
(0x1E6F, 'V'),
(0x1E70, 'M', u'ṱ'),
(0x1E71, 'V'),
(0x1E72, 'M', u'ṳ'),
(0x1E73, 'V'),
(0x1E74, 'M', u'ṵ'),
(0x1E75, 'V'),
(0x1E76, 'M', u'ṷ'),
(0x1E77, 'V'),
(0x1E78, 'M', u'ṹ'),
(0x1E79, 'V'),
(0x1E7A, 'M', u'ṻ'),
(0x1E7B, 'V'),
(0x1E7C, 'M', u'ṽ'),
(0x1E7D, 'V'),
(0x1E7E, 'M', u'ṿ'),
(0x1E7F, 'V'),
(0x1E80, 'M', u'ẁ'),
(0x1E81, 'V'),
(0x1E82, 'M', u'ẃ'),
(0x1E83, 'V'),
(0x1E84, 'M', u'ẅ'),
(0x1E85, 'V'),
(0x1E86, 'M', u'ẇ'),
(0x1E87, 'V'),
(0x1E88, 'M', u'ẉ'),
(0x1E89, 'V'),
(0x1E8A, 'M', u'ẋ'),
(0x1E8B, 'V'),
(0x1E8C, 'M', u'ẍ'),
(0x1E8D, 'V'),
(0x1E8E, 'M', u'ẏ'),
(0x1E8F, 'V'),
(0x1E90, 'M', u'ẑ'),
(0x1E91, 'V'),
(0x1E92, 'M', u'ẓ'),
(0x1E93, 'V'),
(0x1E94, 'M', u'ẕ'),
(0x1E95, 'V'),
(0x1E9A, 'M', u'aʾ'),
(0x1E9B, 'M', u'ṡ'),
(0x1E9C, 'V'),
(0x1E9E, 'M', u'ss'),
(0x1E9F, 'V'),
(0x1EA0, 'M', u'ạ'),
(0x1EA1, 'V'),
(0x1EA2, 'M', u'ả'),
(0x1EA3, 'V'),
(0x1EA4, 'M', u'ấ'),
(0x1EA5, 'V'),
(0x1EA6, 'M', u'ầ'),
(0x1EA7, 'V'),
(0x1EA8, 'M', u'ẩ'),
]
def _seg_18():
return [
(0x1EA9, 'V'),
(0x1EAA, 'M', u'ẫ'),
(0x1EAB, 'V'),
(0x1EAC, 'M', u'ậ'),
(0x1EAD, 'V'),
(0x1EAE, 'M', u'ắ'),
(0x1EAF, 'V'),
(0x1EB0, 'M', u'ằ'),
(0x1EB1, 'V'),
(0x1EB2, 'M', u'ẳ'),
(0x1EB3, 'V'),
(0x1EB4, 'M', u'ẵ'),
(0x1EB5, 'V'),
(0x1EB6, 'M', u'ặ'),
(0x1EB7, 'V'),
(0x1EB8, 'M', u'ẹ'),
(0x1EB9, 'V'),
(0x1EBA, 'M', u'ẻ'),
(0x1EBB, 'V'),
(0x1EBC, 'M', u'ẽ'),
(0x1EBD, 'V'),
(0x1EBE, 'M', u'ế'),
(0x1EBF, 'V'),
(0x1EC0, 'M', u'ề'),
(0x1EC1, 'V'),
(0x1EC2, 'M', u'ể'),
(0x1EC3, 'V'),
(0x1EC4, 'M', u'ễ'),
(0x1EC5, 'V'),
(0x1EC6, 'M', u'ệ'),
(0x1EC7, 'V'),
(0x1EC8, 'M', u'ỉ'),
(0x1EC9, 'V'),
(0x1ECA, 'M', u'ị'),
(0x1ECB, 'V'),
(0x1ECC, 'M', u'ọ'),
(0x1ECD, 'V'),
(0x1ECE, 'M', u'ỏ'),
(0x1ECF, 'V'),
(0x1ED0, 'M', u'ố'),
(0x1ED1, 'V'),
(0x1ED2, 'M', u'ồ'),
(0x1ED3, 'V'),
(0x1ED4, 'M', u'ổ'),
(0x1ED5, 'V'),
(0x1ED6, 'M', u'ỗ'),
(0x1ED7, 'V'),
(0x1ED8, 'M', u'ộ'),
(0x1ED9, 'V'),
(0x1EDA, 'M', u'ớ'),
(0x1EDB, 'V'),
(0x1EDC, 'M', u'ờ'),
(0x1EDD, 'V'),
(0x1EDE, 'M', u'ở'),
(0x1EDF, 'V'),
(0x1EE0, 'M', u'ỡ'),
(0x1EE1, 'V'),
(0x1EE2, 'M', u'ợ'),
(0x1EE3, 'V'),
(0x1EE4, 'M', u'ụ'),
(0x1EE5, 'V'),
(0x1EE6, 'M', u'ủ'),
(0x1EE7, 'V'),
(0x1EE8, 'M', u'ứ'),
(0x1EE9, 'V'),
(0x1EEA, 'M', u'ừ'),
(0x1EEB, 'V'),
(0x1EEC, 'M', u'ử'),
(0x1EED, 'V'),
(0x1EEE, 'M', u'ữ'),
(0x1EEF, 'V'),
(0x1EF0, 'M', u'ự'),
(0x1EF1, 'V'),
(0x1EF2, 'M', u'ỳ'),
(0x1EF3, 'V'),
(0x1EF4, 'M', u'ỵ'),
(0x1EF5, 'V'),
(0x1EF6, 'M', u'ỷ'),
(0x1EF7, 'V'),
(0x1EF8, 'M', u'ỹ'),
(0x1EF9, 'V'),
(0x1EFA, 'M', u'ỻ'),
(0x1EFB, 'V'),
(0x1EFC, 'M', u'ỽ'),
(0x1EFD, 'V'),
(0x1EFE, 'M', u'ỿ'),
(0x1EFF, 'V'),
(0x1F08, 'M', u'ἀ'),
(0x1F09, 'M', u'ἁ'),
(0x1F0A, 'M', u'ἂ'),
(0x1F0B, 'M', u'ἃ'),
(0x1F0C, 'M', u'ἄ'),
(0x1F0D, 'M', u'ἅ'),
(0x1F0E, 'M', u'ἆ'),
(0x1F0F, 'M', u'ἇ'),
(0x1F10, 'V'),
(0x1F16, 'X'),
(0x1F18, 'M', u'ἐ'),
(0x1F19, 'M', u'ἑ'),
(0x1F1A, 'M', u'ἒ'),
]
def _seg_19():
return [
(0x1F1B, 'M', u'ἓ'),
(0x1F1C, 'M', u'ἔ'),
(0x1F1D, 'M', u'ἕ'),
(0x1F1E, 'X'),
(0x1F20, 'V'),
(0x1F28, 'M', u'ἠ'),
(0x1F29, 'M', u'ἡ'),
(0x1F2A, 'M', u'ἢ'),
(0x1F2B, 'M', u'ἣ'),
(0x1F2C, 'M', u'ἤ'),
(0x1F2D, 'M', u'ἥ'),
(0x1F2E, 'M', u'ἦ'),
(0x1F2F, 'M', u'ἧ'),
(0x1F30, 'V'),
(0x1F38, 'M', u'ἰ'),
(0x1F39, 'M', u'ἱ'),
(0x1F3A, 'M', u'ἲ'),
(0x1F3B, 'M', u'ἳ'),
(0x1F3C, 'M', u'ἴ'),
(0x1F3D, 'M', u'ἵ'),
(0x1F3E, 'M', u'ἶ'),
(0x1F3F, 'M', u'ἷ'),
(0x1F40, 'V'),
(0x1F46, 'X'),
(0x1F48, 'M', u'ὀ'),
(0x1F49, 'M', u'ὁ'),
(0x1F4A, 'M', u'ὂ'),
(0x1F4B, 'M', u'ὃ'),
(0x1F4C, 'M', u'ὄ'),
(0x1F4D, 'M', u'ὅ'),
(0x1F4E, 'X'),
(0x1F50, 'V'),
(0x1F58, 'X'),
(0x1F59, 'M', u'ὑ'),
(0x1F5A, 'X'),
(0x1F5B, 'M', u'ὓ'),
(0x1F5C, 'X'),
(0x1F5D, 'M', u'ὕ'),
(0x1F5E, 'X'),
(0x1F5F, 'M', u'ὗ'),
(0x1F60, 'V'),
(0x1F68, 'M', u'ὠ'),
(0x1F69, 'M', u'ὡ'),
(0x1F6A, 'M', u'ὢ'),
(0x1F6B, 'M', u'ὣ'),
(0x1F6C, 'M', u'ὤ'),
(0x1F6D, 'M', u'ὥ'),
(0x1F6E, 'M', u'ὦ'),
(0x1F6F, 'M', u'ὧ'),
(0x1F70, 'V'),
(0x1F71, 'M', u'ά'),
(0x1F72, 'V'),
(0x1F73, 'M', u'έ'),
(0x1F74, 'V'),
(0x1F75, 'M', u'ή'),
(0x1F76, 'V'),
(0x1F77, 'M', u'ί'),
(0x1F78, 'V'),
(0x1F79, 'M', u'ό'),
(0x1F7A, 'V'),
(0x1F7B, 'M', u'ύ'),
(0x1F7C, 'V'),
(0x1F7D, 'M', u'ώ'),
(0x1F7E, 'X'),
(0x1F80, 'M', u'ἀι'),
(0x1F81, 'M', u'ἁι'),
(0x1F82, 'M', u'ἂι'),
(0x1F83, 'M', u'ἃι'),
(0x1F84, 'M', u'ἄι'),
(0x1F85, 'M', u'ἅι'),
(0x1F86, 'M', u'ἆι'),
(0x1F87, 'M', u'ἇι'),
(0x1F88, 'M', u'ἀι'),
(0x1F89, 'M', u'ἁι'),
(0x1F8A, 'M', u'ἂι'),
(0x1F8B, 'M', u'ἃι'),
(0x1F8C, 'M', u'ἄι'),
(0x1F8D, 'M', u'ἅι'),
(0x1F8E, 'M', u'ἆι'),
(0x1F8F, 'M', u'ἇι'),
(0x1F90, 'M', u'ἠι'),
(0x1F91, 'M', u'ἡι'),
(0x1F92, 'M', u'ἢι'),
(0x1F93, 'M', u'ἣι'),
(0x1F94, 'M', u'ἤι'),
(0x1F95, 'M', u'ἥι'),
(0x1F96, 'M', u'ἦι'),
(0x1F97, 'M', u'ἧι'),
(0x1F98, 'M', u'ἠι'),
(0x1F99, 'M', u'ἡι'),
(0x1F9A, 'M', u'ἢι'),
(0x1F9B, 'M', u'ἣι'),
(0x1F9C, 'M', u'ἤι'),
(0x1F9D, 'M', u'ἥι'),
(0x1F9E, 'M', u'ἦι'),
(0x1F9F, 'M', u'ἧι'),
(0x1FA0, 'M', u'ὠι'),
(0x1FA1, 'M', u'ὡι'),
(0x1FA2, 'M', u'ὢι'),
(0x1FA3, 'M', u'ὣι'),
]
def _seg_20():
return [
(0x1FA4, 'M', u'ὤι'),
(0x1FA5, 'M', u'ὥι'),
(0x1FA6, 'M', u'ὦι'),
(0x1FA7, 'M', u'ὧι'),
(0x1FA8, 'M', u'ὠι'),
(0x1FA9, 'M', u'ὡι'),
(0x1FAA, 'M', u'ὢι'),
(0x1FAB, 'M', u'ὣι'),
(0x1FAC, 'M', u'ὤι'),
(0x1FAD, 'M', u'ὥι'),
(0x1FAE, 'M', u'ὦι'),
(0x1FAF, 'M', u'ὧι'),
(0x1FB0, 'V'),
(0x1FB2, 'M', u'ὰι'),
(0x1FB3, 'M', u'αι'),
(0x1FB4, 'M', u'άι'),
(0x1FB5, 'X'),
(0x1FB6, 'V'),
(0x1FB7, 'M', u'ᾶι'),
(0x1FB8, 'M', u'ᾰ'),
(0x1FB9, 'M', u'ᾱ'),
(0x1FBA, 'M', u'ὰ'),
(0x1FBB, 'M', u'ά'),
(0x1FBC, 'M', u'αι'),
(0x1FBD, '3', u' ̓'),
(0x1FBE, 'M', u'ι'),
(0x1FBF, '3', u' ̓'),
(0x1FC0, '3', u' ͂'),
(0x1FC1, '3', u' ̈͂'),
(0x1FC2, 'M', u'ὴι'),
(0x1FC3, 'M', u'ηι'),
(0x1FC4, 'M', u'ήι'),
(0x1FC5, 'X'),
(0x1FC6, 'V'),
(0x1FC7, 'M', u'ῆι'),
(0x1FC8, 'M', u'ὲ'),
(0x1FC9, 'M', u'έ'),
(0x1FCA, 'M', u'ὴ'),
(0x1FCB, 'M', u'ή'),
(0x1FCC, 'M', u'ηι'),
(0x1FCD, '3', u' ̓̀'),
(0x1FCE, '3', u' ̓́'),
(0x1FCF, '3', u' ̓͂'),
(0x1FD0, 'V'),
(0x1FD3, 'M', u'ΐ'),
(0x1FD4, 'X'),
(0x1FD6, 'V'),
(0x1FD8, 'M', u'ῐ'),
(0x1FD9, 'M', u'ῑ'),
(0x1FDA, 'M', u'ὶ'),
(0x1FDB, 'M', u'ί'),
(0x1FDC, 'X'),
(0x1FDD, '3', u' ̔̀'),
(0x1FDE, '3', u' ̔́'),
(0x1FDF, '3', u' ̔͂'),
(0x1FE0, 'V'),
(0x1FE3, 'M', u'ΰ'),
(0x1FE4, 'V'),
(0x1FE8, 'M', u'ῠ'),
(0x1FE9, 'M', u'ῡ'),
(0x1FEA, 'M', u'ὺ'),
(0x1FEB, 'M', u'ύ'),
(0x1FEC, 'M', u'ῥ'),
(0x1FED, '3', u' ̈̀'),
(0x1FEE, '3', u' ̈́'),
(0x1FEF, '3', u'`'),
(0x1FF0, 'X'),
(0x1FF2, 'M', u'ὼι'),
(0x1FF3, 'M', u'ωι'),
(0x1FF4, 'M', u'ώι'),
(0x1FF5, 'X'),
(0x1FF6, 'V'),
(0x1FF7, 'M', u'ῶι'),
(0x1FF8, 'M', u'ὸ'),
(0x1FF9, 'M', u'ό'),
(0x1FFA, 'M', u'ὼ'),
(0x1FFB, 'M', u'ώ'),
(0x1FFC, 'M', u'ωι'),
(0x1FFD, '3', u' ́'),
(0x1FFE, '3', u' ̔'),
(0x1FFF, 'X'),
(0x2000, '3', u' '),
(0x200B, 'I'),
(0x200C, 'D', u''),
(0x200E, 'X'),
(0x2010, 'V'),
(0x2011, 'M', u'‐'),
(0x2012, 'V'),
(0x2017, '3', u' ̳'),
(0x2018, 'V'),
(0x2024, 'X'),
(0x2027, 'V'),
(0x2028, 'X'),
(0x202F, '3', u' '),
(0x2030, 'V'),
(0x2033, 'M', u'′′'),
(0x2034, 'M', u'′′′'),
(0x2035, 'V'),
(0x2036, 'M', u'‵‵'),
(0x2037, 'M', u'‵‵‵'),
]
def _seg_21():
return [
(0x2038, 'V'),
(0x203C, '3', u'!!'),
(0x203D, 'V'),
(0x203E, '3', u' ̅'),
(0x203F, 'V'),
(0x2047, '3', u'??'),
(0x2048, '3', u'?!'),
(0x2049, '3', u'!?'),
(0x204A, 'V'),
(0x2057, 'M', u'′′′′'),
(0x2058, 'V'),
(0x205F, '3', u' '),
(0x2060, 'I'),
(0x2061, 'X'),
(0x2064, 'I'),
(0x2065, 'X'),
(0x2070, 'M', u'0'),
(0x2071, 'M', u'i'),
(0x2072, 'X'),
(0x2074, 'M', u'4'),
(0x2075, 'M', u'5'),
(0x2076, 'M', u'6'),
(0x2077, 'M', u'7'),
(0x2078, 'M', u'8'),
(0x2079, 'M', u'9'),
(0x207A, '3', u'+'),
(0x207B, 'M', u'−'),
(0x207C, '3', u'='),
(0x207D, '3', u'('),
(0x207E, '3', u')'),
(0x207F, 'M', u'n'),
(0x2080, 'M', u'0'),
(0x2081, 'M', u'1'),
(0x2082, 'M', u'2'),
(0x2083, 'M', u'3'),
(0x2084, 'M', u'4'),
(0x2085, 'M', u'5'),
(0x2086, 'M', u'6'),
(0x2087, 'M', u'7'),
(0x2088, 'M', u'8'),
(0x2089, 'M', u'9'),
(0x208A, '3', u'+'),
(0x208B, 'M', u'−'),
(0x208C, '3', u'='),
(0x208D, '3', u'('),
(0x208E, '3', u')'),
(0x208F, 'X'),
(0x2090, 'M', u'a'),
(0x2091, 'M', u'e'),
(0x2092, 'M', u'o'),
(0x2093, 'M', u'x'),
(0x2094, 'M', u'ə'),
(0x2095, 'M', u'h'),
(0x2096, 'M', u'k'),
(0x2097, 'M', u'l'),
(0x2098, 'M', u'm'),
(0x2099, 'M', u'n'),
(0x209A, 'M', u'p'),
(0x209B, 'M', u's'),
(0x209C, 'M', u't'),
(0x209D, 'X'),
(0x20A0, 'V'),
(0x20A8, 'M', u'rs'),
(0x20A9, 'V'),
(0x20C0, 'X'),
(0x20D0, 'V'),
(0x20F1, 'X'),
(0x2100, '3', u'a/c'),
(0x2101, '3', u'a/s'),
(0x2102, 'M', u'c'),
(0x2103, 'M', u'°c'),
(0x2104, 'V'),
(0x2105, '3', u'c/o'),
(0x2106, '3', u'c/u'),
(0x2107, 'M', u'ɛ'),
(0x2108, 'V'),
(0x2109, 'M', u'°f'),
(0x210A, 'M', u'g'),
(0x210B, 'M', u'h'),
(0x210F, 'M', u'ħ'),
(0x2110, 'M', u'i'),
(0x2112, 'M', u'l'),
(0x2114, 'V'),
(0x2115, 'M', u'n'),
(0x2116, 'M', u'no'),
(0x2117, 'V'),
(0x2119, 'M', u'p'),
(0x211A, 'M', u'q'),
(0x211B, 'M', u'r'),
(0x211E, 'V'),
(0x2120, 'M', u'sm'),
(0x2121, 'M', u'tel'),
(0x2122, 'M', u'tm'),
(0x2123, 'V'),
(0x2124, 'M', u'z'),
(0x2125, 'V'),
(0x2126, 'M', u'ω'),
(0x2127, 'V'),
(0x2128, 'M', u'z'),
(0x2129, 'V'),
]
def _seg_22():
return [
(0x212A, 'M', u'k'),
(0x212B, 'M', u'å'),
(0x212C, 'M', u'b'),
(0x212D, 'M', u'c'),
(0x212E, 'V'),
(0x212F, 'M', u'e'),
(0x2131, 'M', u'f'),
(0x2132, 'X'),
(0x2133, 'M', u'm'),
(0x2134, 'M', u'o'),
(0x2135, 'M', u'א'),
(0x2136, 'M', u'ב'),
(0x2137, 'M', u'ג'),
(0x2138, 'M', u'ד'),
(0x2139, 'M', u'i'),
(0x213A, 'V'),
(0x213B, 'M', u'fax'),
(0x213C, 'M', u'π'),
(0x213D, 'M', u'γ'),
(0x213F, 'M', u'π'),
(0x2140, 'M', u'∑'),
(0x2141, 'V'),
(0x2145, 'M', u'd'),
(0x2147, 'M', u'e'),
(0x2148, 'M', u'i'),
(0x2149, 'M', u'j'),
(0x214A, 'V'),
(0x2150, 'M', u'1⁄7'),
(0x2151, 'M', u'1⁄9'),
(0x2152, 'M', u'1⁄10'),
(0x2153, 'M', u'1⁄3'),
(0x2154, 'M', u'2⁄3'),
(0x2155, 'M', u'1⁄5'),
(0x2156, 'M', u'2⁄5'),
(0x2157, 'M', u'3⁄5'),
(0x2158, 'M', u'4⁄5'),
(0x2159, 'M', u'1⁄6'),
(0x215A, 'M', u'5⁄6'),
(0x215B, 'M', u'1⁄8'),
(0x215C, 'M', u'3⁄8'),
(0x215D, 'M', u'5⁄8'),
(0x215E, 'M', u'7⁄8'),
(0x215F, 'M', u'1⁄'),
(0x2160, 'M', u'i'),
(0x2161, 'M', u'ii'),
(0x2162, 'M', u'iii'),
(0x2163, 'M', u'iv'),
(0x2164, 'M', u'v'),
(0x2165, 'M', u'vi'),
(0x2166, 'M', u'vii'),
(0x2167, 'M', u'viii'),
(0x2168, 'M', u'ix'),
(0x2169, 'M', u'x'),
(0x216A, 'M', u'xi'),
(0x216B, 'M', u'xii'),
(0x216C, 'M', u'l'),
(0x216D, 'M', u'c'),
(0x216E, 'M', u'd'),
(0x216F, 'M', u'm'),
(0x2170, 'M', u'i'),
(0x2171, 'M', u'ii'),
(0x2172, 'M', u'iii'),
(0x2173, 'M', u'iv'),
(0x2174, 'M', u'v'),
(0x2175, 'M', u'vi'),
(0x2176, 'M', u'vii'),
(0x2177, 'M', u'viii'),
(0x2178, 'M', u'ix'),
(0x2179, 'M', u'x'),
(0x217A, 'M', u'xi'),
(0x217B, 'M', u'xii'),
(0x217C, 'M', u'l'),
(0x217D, 'M', u'c'),
(0x217E, 'M', u'd'),
(0x217F, 'M', u'm'),
(0x2180, 'V'),
(0x2183, 'X'),
(0x2184, 'V'),
(0x2189, 'M', u'0⁄3'),
(0x218A, 'V'),
(0x218C, 'X'),
(0x2190, 'V'),
(0x222C, 'M', u'∫∫'),
(0x222D, 'M', u'∫∫∫'),
(0x222E, 'V'),
(0x222F, 'M', u'∮∮'),
(0x2230, 'M', u'∮∮∮'),
(0x2231, 'V'),
(0x2260, '3'),
(0x2261, 'V'),
(0x226E, '3'),
(0x2270, 'V'),
(0x2329, 'M', u'〈'),
(0x232A, 'M', u'〉'),
(0x232B, 'V'),
(0x2427, 'X'),
(0x2440, 'V'),
(0x244B, 'X'),
(0x2460, 'M', u'1'),
(0x2461, 'M', u'2'),
]
def _seg_23():
return [
(0x2462, 'M', u'3'),
(0x2463, 'M', u'4'),
(0x2464, 'M', u'5'),
(0x2465, 'M', u'6'),
(0x2466, 'M', u'7'),
(0x2467, 'M', u'8'),
(0x2468, 'M', u'9'),
(0x2469, 'M', u'10'),
(0x246A, 'M', u'11'),
(0x246B, 'M', u'12'),
(0x246C, 'M', u'13'),
(0x246D, 'M', u'14'),
(0x246E, 'M', u'15'),
(0x246F, 'M', u'16'),
(0x2470, 'M', u'17'),
(0x2471, 'M', u'18'),
(0x2472, 'M', u'19'),
(0x2473, 'M', u'20'),
(0x2474, '3', u'(1)'),
(0x2475, '3', u'(2)'),
(0x2476, '3', u'(3)'),
(0x2477, '3', u'(4)'),
(0x2478, '3', u'(5)'),
(0x2479, '3', u'(6)'),
(0x247A, '3', u'(7)'),
(0x247B, '3', u'(8)'),
(0x247C, '3', u'(9)'),
(0x247D, '3', u'(10)'),
(0x247E, '3', u'(11)'),
(0x247F, '3', u'(12)'),
(0x2480, '3', u'(13)'),
(0x2481, '3', u'(14)'),
(0x2482, '3', u'(15)'),
(0x2483, '3', u'(16)'),
(0x2484, '3', u'(17)'),
(0x2485, '3', u'(18)'),
(0x2486, '3', u'(19)'),
(0x2487, '3', u'(20)'),
(0x2488, 'X'),
(0x249C, '3', u'(a)'),
(0x249D, '3', u'(b)'),
(0x249E, '3', u'(c)'),
(0x249F, '3', u'(d)'),
(0x24A0, '3', u'(e)'),
(0x24A1, '3', u'(f)'),
(0x24A2, '3', u'(g)'),
(0x24A3, '3', u'(h)'),
(0x24A4, '3', u'(i)'),
(0x24A5, '3', u'(j)'),
(0x24A6, '3', u'(k)'),
(0x24A7, '3', u'(l)'),
(0x24A8, '3', u'(m)'),
(0x24A9, '3', u'(n)'),
(0x24AA, '3', u'(o)'),
(0x24AB, '3', u'(p)'),
(0x24AC, '3', u'(q)'),
(0x24AD, '3', u'(r)'),
(0x24AE, '3', u'(s)'),
(0x24AF, '3', u'(t)'),
(0x24B0, '3', u'(u)'),
(0x24B1, '3', u'(v)'),
(0x24B2, '3', u'(w)'),
(0x24B3, '3', u'(x)'),
(0x24B4, '3', u'(y)'),
(0x24B5, '3', u'(z)'),
(0x24B6, 'M', u'a'),
(0x24B7, 'M', u'b'),
(0x24B8, 'M', u'c'),
(0x24B9, 'M', u'd'),
(0x24BA, 'M', u'e'),
(0x24BB, 'M', u'f'),
(0x24BC, 'M', u'g'),
(0x24BD, 'M', u'h'),
(0x24BE, 'M', u'i'),
(0x24BF, 'M', u'j'),
(0x24C0, 'M', u'k'),
(0x24C1, 'M', u'l'),
(0x24C2, 'M', u'm'),
(0x24C3, 'M', u'n'),
(0x24C4, 'M', u'o'),
(0x24C5, 'M', u'p'),
(0x24C6, 'M', u'q'),
(0x24C7, 'M', u'r'),
(0x24C8, 'M', u's'),
(0x24C9, 'M', u't'),
(0x24CA, 'M', u'u'),
(0x24CB, 'M', u'v'),
(0x24CC, 'M', u'w'),
(0x24CD, 'M', u'x'),
(0x24CE, 'M', u'y'),
(0x24CF, 'M', u'z'),
(0x24D0, 'M', u'a'),
(0x24D1, 'M', u'b'),
(0x24D2, 'M', u'c'),
(0x24D3, 'M', u'd'),
(0x24D4, 'M', u'e'),
(0x24D5, 'M', u'f'),
(0x24D6, 'M', u'g'),
(0x24D7, 'M', u'h'),
(0x24D8, 'M', u'i'),
]
def _seg_24():
return [
(0x24D9, 'M', u'j'),
(0x24DA, 'M', u'k'),
(0x24DB, 'M', u'l'),
(0x24DC, 'M', u'm'),
(0x24DD, 'M', u'n'),
(0x24DE, 'M', u'o'),
(0x24DF, 'M', u'p'),
(0x24E0, 'M', u'q'),
(0x24E1, 'M', u'r'),
(0x24E2, 'M', u's'),
(0x24E3, 'M', u't'),
(0x24E4, 'M', u'u'),
(0x24E5, 'M', u'v'),
(0x24E6, 'M', u'w'),
(0x24E7, 'M', u'x'),
(0x24E8, 'M', u'y'),
(0x24E9, 'M', u'z'),
(0x24EA, 'M', u'0'),
(0x24EB, 'V'),
(0x2A0C, 'M', u'∫∫∫∫'),
(0x2A0D, 'V'),
(0x2A74, '3', u'::='),
(0x2A75, '3', u'=='),
(0x2A76, '3', u'==='),
(0x2A77, 'V'),
(0x2ADC, 'M', u'⫝̸'),
(0x2ADD, 'V'),
(0x2B74, 'X'),
(0x2B76, 'V'),
(0x2B96, 'X'),
(0x2B98, 'V'),
(0x2BC9, 'X'),
(0x2BCA, 'V'),
(0x2BFF, 'X'),
(0x2C00, 'M', u'ⰰ'),
(0x2C01, 'M', u'ⰱ'),
(0x2C02, 'M', u'ⰲ'),
(0x2C03, 'M', u'ⰳ'),
(0x2C04, 'M', u'ⰴ'),
(0x2C05, 'M', u'ⰵ'),
(0x2C06, 'M', u'ⰶ'),
(0x2C07, 'M', u'ⰷ'),
(0x2C08, 'M', u'ⰸ'),
(0x2C09, 'M', u'ⰹ'),
(0x2C0A, 'M', u'ⰺ'),
(0x2C0B, 'M', u'ⰻ'),
(0x2C0C, 'M', u'ⰼ'),
(0x2C0D, 'M', u'ⰽ'),
(0x2C0E, 'M', u'ⰾ'),
(0x2C0F, 'M', u'ⰿ'),
(0x2C10, 'M', u'ⱀ'),
(0x2C11, 'M', u'ⱁ'),
(0x2C12, 'M', u'ⱂ'),
(0x2C13, 'M', u'ⱃ'),
(0x2C14, 'M', u'ⱄ'),
(0x2C15, 'M', u'ⱅ'),
(0x2C16, 'M', u'ⱆ'),
(0x2C17, 'M', u'ⱇ'),
(0x2C18, 'M', u'ⱈ'),
(0x2C19, 'M', u'ⱉ'),
(0x2C1A, 'M', u'ⱊ'),
(0x2C1B, 'M', u'ⱋ'),
(0x2C1C, 'M', u'ⱌ'),
(0x2C1D, 'M', u'ⱍ'),
(0x2C1E, 'M', u'ⱎ'),
(0x2C1F, 'M', u'ⱏ'),
(0x2C20, 'M', u'ⱐ'),
(0x2C21, 'M', u'ⱑ'),
(0x2C22, 'M', u'ⱒ'),
(0x2C23, 'M', u'ⱓ'),
(0x2C24, 'M', u'ⱔ'),
(0x2C25, 'M', u'ⱕ'),
(0x2C26, 'M', u'ⱖ'),
(0x2C27, 'M', u'ⱗ'),
(0x2C28, 'M', u'ⱘ'),
(0x2C29, 'M', u'ⱙ'),
(0x2C2A, 'M', u'ⱚ'),
(0x2C2B, 'M', u'ⱛ'),
(0x2C2C, 'M', u'ⱜ'),
(0x2C2D, 'M', u'ⱝ'),
(0x2C2E, 'M', u'ⱞ'),
(0x2C2F, 'X'),
(0x2C30, 'V'),
(0x2C5F, 'X'),
(0x2C60, 'M', u'ⱡ'),
(0x2C61, 'V'),
(0x2C62, 'M', u'ɫ'),
(0x2C63, 'M', u'ᵽ'),
(0x2C64, 'M', u'ɽ'),
(0x2C65, 'V'),
(0x2C67, 'M', u'ⱨ'),
(0x2C68, 'V'),
(0x2C69, 'M', u'ⱪ'),
(0x2C6A, 'V'),
(0x2C6B, 'M', u'ⱬ'),
(0x2C6C, 'V'),
(0x2C6D, 'M', u'ɑ'),
(0x2C6E, 'M', u'ɱ'),
(0x2C6F, 'M', u'ɐ'),
(0x2C70, 'M', u'ɒ'),
]
def _seg_25():
return [
(0x2C71, 'V'),
(0x2C72, 'M', u'ⱳ'),
(0x2C73, 'V'),
(0x2C75, 'M', u'ⱶ'),
(0x2C76, 'V'),
(0x2C7C, 'M', u'j'),
(0x2C7D, 'M', u'v'),
(0x2C7E, 'M', u'ȿ'),
(0x2C7F, 'M', u'ɀ'),
(0x2C80, 'M', u'ⲁ'),
(0x2C81, 'V'),
(0x2C82, 'M', u'ⲃ'),
(0x2C83, 'V'),
(0x2C84, 'M', u'ⲅ'),
(0x2C85, 'V'),
(0x2C86, 'M', u'ⲇ'),
(0x2C87, 'V'),
(0x2C88, 'M', u'ⲉ'),
(0x2C89, 'V'),
(0x2C8A, 'M', u'ⲋ'),
(0x2C8B, 'V'),
(0x2C8C, 'M', u'ⲍ'),
(0x2C8D, 'V'),
(0x2C8E, 'M', u'ⲏ'),
(0x2C8F, 'V'),
(0x2C90, 'M', u'ⲑ'),
(0x2C91, 'V'),
(0x2C92, 'M', u'ⲓ'),
(0x2C93, 'V'),
(0x2C94, 'M', u'ⲕ'),
(0x2C95, 'V'),
(0x2C96, 'M', u'ⲗ'),
(0x2C97, 'V'),
(0x2C98, 'M', u'ⲙ'),
(0x2C99, 'V'),
(0x2C9A, 'M', u'ⲛ'),
(0x2C9B, 'V'),
(0x2C9C, 'M', u'ⲝ'),
(0x2C9D, 'V'),
(0x2C9E, 'M', u'ⲟ'),
(0x2C9F, 'V'),
(0x2CA0, 'M', u'ⲡ'),
(0x2CA1, 'V'),
(0x2CA2, 'M', u'ⲣ'),
(0x2CA3, 'V'),
(0x2CA4, 'M', u'ⲥ'),
(0x2CA5, 'V'),
(0x2CA6, 'M', u'ⲧ'),
(0x2CA7, 'V'),
(0x2CA8, 'M', u'ⲩ'),
(0x2CA9, 'V'),
(0x2CAA, 'M', u'ⲫ'),
(0x2CAB, 'V'),
(0x2CAC, 'M', u'ⲭ'),
(0x2CAD, 'V'),
(0x2CAE, 'M', u'ⲯ'),
(0x2CAF, 'V'),
(0x2CB0, 'M', u'ⲱ'),
(0x2CB1, 'V'),
(0x2CB2, 'M', u'ⲳ'),
(0x2CB3, 'V'),
(0x2CB4, 'M', u'ⲵ'),
(0x2CB5, 'V'),
(0x2CB6, 'M', u'ⲷ'),
(0x2CB7, 'V'),
(0x2CB8, 'M', u'ⲹ'),
(0x2CB9, 'V'),
(0x2CBA, 'M', u'ⲻ'),
(0x2CBB, 'V'),
(0x2CBC, 'M', u'ⲽ'),
(0x2CBD, 'V'),
(0x2CBE, 'M', u'ⲿ'),
(0x2CBF, 'V'),
(0x2CC0, 'M', u'ⳁ'),
(0x2CC1, 'V'),
(0x2CC2, 'M', u'ⳃ'),
(0x2CC3, 'V'),
(0x2CC4, 'M', u'ⳅ'),
(0x2CC5, 'V'),
(0x2CC6, 'M', u'ⳇ'),
(0x2CC7, 'V'),
(0x2CC8, 'M', u'ⳉ'),
(0x2CC9, 'V'),
(0x2CCA, 'M', u'ⳋ'),
(0x2CCB, 'V'),
(0x2CCC, 'M', u'ⳍ'),
(0x2CCD, 'V'),
(0x2CCE, 'M', u'ⳏ'),
(0x2CCF, 'V'),
(0x2CD0, 'M', u'ⳑ'),
(0x2CD1, 'V'),
(0x2CD2, 'M', u'ⳓ'),
(0x2CD3, 'V'),
(0x2CD4, 'M', u'ⳕ'),
(0x2CD5, 'V'),
(0x2CD6, 'M', u'ⳗ'),
(0x2CD7, 'V'),
(0x2CD8, 'M', u'ⳙ'),
(0x2CD9, 'V'),
(0x2CDA, 'M', u'ⳛ'),
]
def _seg_26():
return [
(0x2CDB, 'V'),
(0x2CDC, 'M', u'ⳝ'),
(0x2CDD, 'V'),
(0x2CDE, 'M', u'ⳟ'),
(0x2CDF, 'V'),
(0x2CE0, 'M', u'ⳡ'),
(0x2CE1, 'V'),
(0x2CE2, 'M', u'ⳣ'),
(0x2CE3, 'V'),
(0x2CEB, 'M', u'ⳬ'),
(0x2CEC, 'V'),
(0x2CED, 'M', u'ⳮ'),
(0x2CEE, 'V'),
(0x2CF2, 'M', u'ⳳ'),
(0x2CF3, 'V'),
(0x2CF4, 'X'),
(0x2CF9, 'V'),
(0x2D26, 'X'),
(0x2D27, 'V'),
(0x2D28, 'X'),
(0x2D2D, 'V'),
(0x2D2E, 'X'),
(0x2D30, 'V'),
(0x2D68, 'X'),
(0x2D6F, 'M', u'ⵡ'),
(0x2D70, 'V'),
(0x2D71, 'X'),
(0x2D7F, 'V'),
(0x2D97, 'X'),
(0x2DA0, 'V'),
(0x2DA7, 'X'),
(0x2DA8, 'V'),
(0x2DAF, 'X'),
(0x2DB0, 'V'),
(0x2DB7, 'X'),
(0x2DB8, 'V'),
(0x2DBF, 'X'),
(0x2DC0, 'V'),
(0x2DC7, 'X'),
(0x2DC8, 'V'),
(0x2DCF, 'X'),
(0x2DD0, 'V'),
(0x2DD7, 'X'),
(0x2DD8, 'V'),
(0x2DDF, 'X'),
(0x2DE0, 'V'),
(0x2E4F, 'X'),
(0x2E80, 'V'),
(0x2E9A, 'X'),
(0x2E9B, 'V'),
(0x2E9F, 'M', u'母'),
(0x2EA0, 'V'),
(0x2EF3, 'M', u'龟'),
(0x2EF4, 'X'),
(0x2F00, 'M', u'一'),
(0x2F01, 'M', u'丨'),
(0x2F02, 'M', u'丶'),
(0x2F03, 'M', u'丿'),
(0x2F04, 'M', u'乙'),
(0x2F05, 'M', u'亅'),
(0x2F06, 'M', u'二'),
(0x2F07, 'M', u'亠'),
(0x2F08, 'M', u'人'),
(0x2F09, 'M', u'儿'),
(0x2F0A, 'M', u'入'),
(0x2F0B, 'M', u'八'),
(0x2F0C, 'M', u'冂'),
(0x2F0D, 'M', u'冖'),
(0x2F0E, 'M', u'冫'),
(0x2F0F, 'M', u'几'),
(0x2F10, 'M', u'凵'),
(0x2F11, 'M', u'刀'),
(0x2F12, 'M', u'力'),
(0x2F13, 'M', u'勹'),
(0x2F14, 'M', u'匕'),
(0x2F15, 'M', u'匚'),
(0x2F16, 'M', u'匸'),
(0x2F17, 'M', u'十'),
(0x2F18, 'M', u'卜'),
(0x2F19, 'M', u'卩'),
(0x2F1A, 'M', u'厂'),
(0x2F1B, 'M', u'厶'),
(0x2F1C, 'M', u'又'),
(0x2F1D, 'M', u'口'),
(0x2F1E, 'M', u'囗'),
(0x2F1F, 'M', u'土'),
(0x2F20, 'M', u'士'),
(0x2F21, 'M', u'夂'),
(0x2F22, 'M', u'夊'),
(0x2F23, 'M', u'夕'),
(0x2F24, 'M', u'大'),
(0x2F25, 'M', u'女'),
(0x2F26, 'M', u'子'),
(0x2F27, 'M', u'宀'),
(0x2F28, 'M', u'寸'),
(0x2F29, 'M', u'小'),
(0x2F2A, 'M', u'尢'),
(0x2F2B, 'M', u'尸'),
(0x2F2C, 'M', u'屮'),
(0x2F2D, 'M', u'山'),
]
def _seg_27():
return [
(0x2F2E, 'M', u'巛'),
(0x2F2F, 'M', u'工'),
(0x2F30, 'M', u'己'),
(0x2F31, 'M', u'巾'),
(0x2F32, 'M', u'干'),
(0x2F33, 'M', u'幺'),
(0x2F34, 'M', u'广'),
(0x2F35, 'M', u'廴'),
(0x2F36, 'M', u'廾'),
(0x2F37, 'M', u'弋'),
(0x2F38, 'M', u'弓'),
(0x2F39, 'M', u'彐'),
(0x2F3A, 'M', u'彡'),
(0x2F3B, 'M', u'彳'),
(0x2F3C, 'M', u'心'),
(0x2F3D, 'M', u'戈'),
(0x2F3E, 'M', u'戶'),
(0x2F3F, 'M', u'手'),
(0x2F40, 'M', u'支'),
(0x2F41, 'M', u'攴'),
(0x2F42, 'M', u'文'),
(0x2F43, 'M', u'斗'),
(0x2F44, 'M', u'斤'),
(0x2F45, 'M', u'方'),
(0x2F46, 'M', u'无'),
(0x2F47, 'M', u'日'),
(0x2F48, 'M', u'曰'),
(0x2F49, 'M', u'月'),
(0x2F4A, 'M', u'木'),
(0x2F4B, 'M', u'欠'),
(0x2F4C, 'M', u'止'),
(0x2F4D, 'M', u'歹'),
(0x2F4E, 'M', u'殳'),
(0x2F4F, 'M', u'毋'),
(0x2F50, 'M', u'比'),
(0x2F51, 'M', u'毛'),
(0x2F52, 'M', u'氏'),
(0x2F53, 'M', u'气'),
(0x2F54, 'M', u'水'),
(0x2F55, 'M', u'火'),
(0x2F56, 'M', u'爪'),
(0x2F57, 'M', u'父'),
(0x2F58, 'M', u'爻'),
(0x2F59, 'M', u'爿'),
(0x2F5A, 'M', u'片'),
(0x2F5B, 'M', u'牙'),
(0x2F5C, 'M', u'牛'),
(0x2F5D, 'M', u'犬'),
(0x2F5E, 'M', u'玄'),
(0x2F5F, 'M', u'玉'),
(0x2F60, 'M', u'瓜'),
(0x2F61, 'M', u'瓦'),
(0x2F62, 'M', u'甘'),
(0x2F63, 'M', u'生'),
(0x2F64, 'M', u'用'),
(0x2F65, 'M', u'田'),
(0x2F66, 'M', u'疋'),
(0x2F67, 'M', u'疒'),
(0x2F68, 'M', u'癶'),
(0x2F69, 'M', u'白'),
(0x2F6A, 'M', u'皮'),
(0x2F6B, 'M', u'皿'),
(0x2F6C, 'M', u'目'),
(0x2F6D, 'M', u'矛'),
(0x2F6E, 'M', u'矢'),
(0x2F6F, 'M', u'石'),
(0x2F70, 'M', u'示'),
(0x2F71, 'M', u'禸'),
(0x2F72, 'M', u'禾'),
(0x2F73, 'M', u'穴'),
(0x2F74, 'M', u'立'),
(0x2F75, 'M', u'竹'),
(0x2F76, 'M', u'米'),
(0x2F77, 'M', u'糸'),
(0x2F78, 'M', u'缶'),
(0x2F79, 'M', u'网'),
(0x2F7A, 'M', u'羊'),
(0x2F7B, 'M', u'羽'),
(0x2F7C, 'M', u'老'),
(0x2F7D, 'M', u'而'),
(0x2F7E, 'M', u'耒'),
(0x2F7F, 'M', u'耳'),
(0x2F80, 'M', u'聿'),
(0x2F81, 'M', u'肉'),
(0x2F82, 'M', u'臣'),
(0x2F83, 'M', u'自'),
(0x2F84, 'M', u'至'),
(0x2F85, 'M', u'臼'),
(0x2F86, 'M', u'舌'),
(0x2F87, 'M', u'舛'),
(0x2F88, 'M', u'舟'),
(0x2F89, 'M', u'艮'),
(0x2F8A, 'M', u'色'),
(0x2F8B, 'M', u'艸'),
(0x2F8C, 'M', u'虍'),
(0x2F8D, 'M', u'虫'),
(0x2F8E, 'M', u'血'),
(0x2F8F, 'M', u'行'),
(0x2F90, 'M', u'衣'),
(0x2F91, 'M', u'襾'),
]
def _seg_28():
return [
(0x2F92, 'M', u'見'),
(0x2F93, 'M', u'角'),
(0x2F94, 'M', u'言'),
(0x2F95, 'M', u'谷'),
(0x2F96, 'M', u'豆'),
(0x2F97, 'M', u'豕'),
(0x2F98, 'M', u'豸'),
(0x2F99, 'M', u'貝'),
(0x2F9A, 'M', u'赤'),
(0x2F9B, 'M', u'走'),
(0x2F9C, 'M', u'足'),
(0x2F9D, 'M', u'身'),
(0x2F9E, 'M', u'車'),
(0x2F9F, 'M', u'辛'),
(0x2FA0, 'M', u'辰'),
(0x2FA1, 'M', u'辵'),
(0x2FA2, 'M', u'邑'),
(0x2FA3, 'M', u'酉'),
(0x2FA4, 'M', u'釆'),
(0x2FA5, 'M', u'里'),
(0x2FA6, 'M', u'金'),
(0x2FA7, 'M', u'長'),
(0x2FA8, 'M', u'門'),
(0x2FA9, 'M', u'阜'),
(0x2FAA, 'M', u'隶'),
(0x2FAB, 'M', u'隹'),
(0x2FAC, 'M', u'雨'),
(0x2FAD, 'M', u'靑'),
(0x2FAE, 'M', u'非'),
(0x2FAF, 'M', u'面'),
(0x2FB0, 'M', u'革'),
(0x2FB1, 'M', u'韋'),
(0x2FB2, 'M', u'韭'),
(0x2FB3, 'M', u'音'),
(0x2FB4, 'M', u'頁'),
(0x2FB5, 'M', u'風'),
(0x2FB6, 'M', u'飛'),
(0x2FB7, 'M', u'食'),
(0x2FB8, 'M', u'首'),
(0x2FB9, 'M', u'香'),
(0x2FBA, 'M', u'馬'),
(0x2FBB, 'M', u'骨'),
(0x2FBC, 'M', u'高'),
(0x2FBD, 'M', u'髟'),
(0x2FBE, 'M', u'鬥'),
(0x2FBF, 'M', u'鬯'),
(0x2FC0, 'M', u'鬲'),
(0x2FC1, 'M', u'鬼'),
(0x2FC2, 'M', u'魚'),
(0x2FC3, 'M', u'鳥'),
(0x2FC4, 'M', u'鹵'),
(0x2FC5, 'M', u'鹿'),
(0x2FC6, 'M', u'麥'),
(0x2FC7, 'M', u'麻'),
(0x2FC8, 'M', u'黃'),
(0x2FC9, 'M', u'黍'),
(0x2FCA, 'M', u'黑'),
(0x2FCB, 'M', u'黹'),
(0x2FCC, 'M', u'黽'),
(0x2FCD, 'M', u'鼎'),
(0x2FCE, 'M', u'鼓'),
(0x2FCF, 'M', u'鼠'),
(0x2FD0, 'M', u'鼻'),
(0x2FD1, 'M', u'齊'),
(0x2FD2, 'M', u'齒'),
(0x2FD3, 'M', u'龍'),
(0x2FD4, 'M', u'龜'),
(0x2FD5, 'M', u'龠'),
(0x2FD6, 'X'),
(0x3000, '3', u' '),
(0x3001, 'V'),
(0x3002, 'M', u'.'),
(0x3003, 'V'),
(0x3036, 'M', u'〒'),
(0x3037, 'V'),
(0x3038, 'M', u'十'),
(0x3039, 'M', u'卄'),
(0x303A, 'M', u'卅'),
(0x303B, 'V'),
(0x3040, 'X'),
(0x3041, 'V'),
(0x3097, 'X'),
(0x3099, 'V'),
(0x309B, '3', u' ゙'),
(0x309C, '3', u' ゚'),
(0x309D, 'V'),
(0x309F, 'M', u'より'),
(0x30A0, 'V'),
(0x30FF, 'M', u'コト'),
(0x3100, 'X'),
(0x3105, 'V'),
(0x3130, 'X'),
(0x3131, 'M', u'ᄀ'),
(0x3132, 'M', u'ᄁ'),
(0x3133, 'M', u'ᆪ'),
(0x3134, 'M', u'ᄂ'),
(0x3135, 'M', u'ᆬ'),
(0x3136, 'M', u'ᆭ'),
(0x3137, 'M', u'ᄃ'),
(0x3138, 'M', u'ᄄ'),
]
def _seg_29():
return [
(0x3139, 'M', u'ᄅ'),
(0x313A, 'M', u'ᆰ'),
(0x313B, 'M', u'ᆱ'),
(0x313C, 'M', u'ᆲ'),
(0x313D, 'M', u'ᆳ'),
(0x313E, 'M', u'ᆴ'),
(0x313F, 'M', u'ᆵ'),
(0x3140, 'M', u'ᄚ'),
(0x3141, 'M', u'ᄆ'),
(0x3142, 'M', u'ᄇ'),
(0x3143, 'M', u'ᄈ'),
(0x3144, 'M', u'ᄡ'),
(0x3145, 'M', u'ᄉ'),
(0x3146, 'M', u'ᄊ'),
(0x3147, 'M', u'ᄋ'),
(0x3148, 'M', u'ᄌ'),
(0x3149, 'M', u'ᄍ'),
(0x314A, 'M', u'ᄎ'),
(0x314B, 'M', u'ᄏ'),
(0x314C, 'M', u'ᄐ'),
(0x314D, 'M', u'ᄑ'),
(0x314E, 'M', u'ᄒ'),
(0x314F, 'M', u'ᅡ'),
(0x3150, 'M', u'ᅢ'),
(0x3151, 'M', u'ᅣ'),
(0x3152, 'M', u'ᅤ'),
(0x3153, 'M', u'ᅥ'),
(0x3154, 'M', u'ᅦ'),
(0x3155, 'M', u'ᅧ'),
(0x3156, 'M', u'ᅨ'),
(0x3157, 'M', u'ᅩ'),
(0x3158, 'M', u'ᅪ'),
(0x3159, 'M', u'ᅫ'),
(0x315A, 'M', u'ᅬ'),
(0x315B, 'M', u'ᅭ'),
(0x315C, 'M', u'ᅮ'),
(0x315D, 'M', u'ᅯ'),
(0x315E, 'M', u'ᅰ'),
(0x315F, 'M', u'ᅱ'),
(0x3160, 'M', u'ᅲ'),
(0x3161, 'M', u'ᅳ'),
(0x3162, 'M', u'ᅴ'),
(0x3163, 'M', u'ᅵ'),
(0x3164, 'X'),
(0x3165, 'M', u'ᄔ'),
(0x3166, 'M', u'ᄕ'),
(0x3167, 'M', u'ᇇ'),
(0x3168, 'M', u'ᇈ'),
(0x3169, 'M', u'ᇌ'),
(0x316A, 'M', u'ᇎ'),
(0x316B, 'M', u'ᇓ'),
(0x316C, 'M', u'ᇗ'),
(0x316D, 'M', u'ᇙ'),
(0x316E, 'M', u'ᄜ'),
(0x316F, 'M', u'ᇝ'),
(0x3170, 'M', u'ᇟ'),
(0x3171, 'M', u'ᄝ'),
(0x3172, 'M', u'ᄞ'),
(0x3173, 'M', u'ᄠ'),
(0x3174, 'M', u'ᄢ'),
(0x3175, 'M', u'ᄣ'),
(0x3176, 'M', u'ᄧ'),
(0x3177, 'M', u'ᄩ'),
(0x3178, 'M', u'ᄫ'),
(0x3179, 'M', u'ᄬ'),
(0x317A, 'M', u'ᄭ'),
(0x317B, 'M', u'ᄮ'),
(0x317C, 'M', u'ᄯ'),
(0x317D, 'M', u'ᄲ'),
(0x317E, 'M', u'ᄶ'),
(0x317F, 'M', u'ᅀ'),
(0x3180, 'M', u'ᅇ'),
(0x3181, 'M', u'ᅌ'),
(0x3182, 'M', u'ᇱ'),
(0x3183, 'M', u'ᇲ'),
(0x3184, 'M', u'ᅗ'),
(0x3185, 'M', u'ᅘ'),
(0x3186, 'M', u'ᅙ'),
(0x3187, 'M', u'ᆄ'),
(0x3188, 'M', u'ᆅ'),
(0x3189, 'M', u'ᆈ'),
(0x318A, 'M', u'ᆑ'),
(0x318B, 'M', u'ᆒ'),
(0x318C, 'M', u'ᆔ'),
(0x318D, 'M', u'ᆞ'),
(0x318E, 'M', u'ᆡ'),
(0x318F, 'X'),
(0x3190, 'V'),
(0x3192, 'M', u'一'),
(0x3193, 'M', u'二'),
(0x3194, 'M', u'三'),
(0x3195, 'M', u'四'),
(0x3196, 'M', u'上'),
(0x3197, 'M', u'中'),
(0x3198, 'M', u'下'),
(0x3199, 'M', u'甲'),
(0x319A, 'M', u'乙'),
(0x319B, 'M', u'丙'),
(0x319C, 'M', u'丁'),
(0x319D, 'M', u'天'),
]
def _seg_30():
return [
(0x319E, 'M', u'地'),
(0x319F, 'M', u'人'),
(0x31A0, 'V'),
(0x31BB, 'X'),
(0x31C0, 'V'),
(0x31E4, 'X'),
(0x31F0, 'V'),
(0x3200, '3', u'(ᄀ)'),
(0x3201, '3', u'(ᄂ)'),
(0x3202, '3', u'(ᄃ)'),
(0x3203, '3', u'(ᄅ)'),
(0x3204, '3', u'(ᄆ)'),
(0x3205, '3', u'(ᄇ)'),
(0x3206, '3', u'(ᄉ)'),
(0x3207, '3', u'(ᄋ)'),
(0x3208, '3', u'(ᄌ)'),
(0x3209, '3', u'(ᄎ)'),
(0x320A, '3', u'(ᄏ)'),
(0x320B, '3', u'(ᄐ)'),
(0x320C, '3', u'(ᄑ)'),
(0x320D, '3', u'(ᄒ)'),
(0x320E, '3', u'(가)'),
(0x320F, '3', u'(나)'),
(0x3210, '3', u'(다)'),
(0x3211, '3', u'(라)'),
(0x3212, '3', u'(마)'),
(0x3213, '3', u'(바)'),
(0x3214, '3', u'(사)'),
(0x3215, '3', u'(아)'),
(0x3216, '3', u'(자)'),
(0x3217, '3', u'(차)'),
(0x3218, '3', u'(카)'),
(0x3219, '3', u'(타)'),
(0x321A, '3', u'(파)'),
(0x321B, '3', u'(하)'),
(0x321C, '3', u'(주)'),
(0x321D, '3', u'(오전)'),
(0x321E, '3', u'(오후)'),
(0x321F, 'X'),
(0x3220, '3', u'(一)'),
(0x3221, '3', u'(二)'),
(0x3222, '3', u'(三)'),
(0x3223, '3', u'(四)'),
(0x3224, '3', u'(五)'),
(0x3225, '3', u'(六)'),
(0x3226, '3', u'(七)'),
(0x3227, '3', u'(八)'),
(0x3228, '3', u'(九)'),
(0x3229, '3', u'(十)'),
(0x322A, '3', u'(月)'),
(0x322B, '3', u'(火)'),
(0x322C, '3', u'(水)'),
(0x322D, '3', u'(木)'),
(0x322E, '3', u'(金)'),
(0x322F, '3', u'(土)'),
(0x3230, '3', u'(日)'),
(0x3231, '3', u'(株)'),
(0x3232, '3', u'(有)'),
(0x3233, '3', u'(社)'),
(0x3234, '3', u'(名)'),
(0x3235, '3', u'(特)'),
(0x3236, '3', u'(財)'),
(0x3237, '3', u'(祝)'),
(0x3238, '3', u'(労)'),
(0x3239, '3', u'(代)'),
(0x323A, '3', u'(呼)'),
(0x323B, '3', u'(学)'),
(0x323C, '3', u'(監)'),
(0x323D, '3', u'(企)'),
(0x323E, '3', u'(資)'),
(0x323F, '3', u'(協)'),
(0x3240, '3', u'(祭)'),
(0x3241, '3', u'(休)'),
(0x3242, '3', u'(自)'),
(0x3243, '3', u'(至)'),
(0x3244, 'M', u'問'),
(0x3245, 'M', u'幼'),
(0x3246, 'M', u'文'),
(0x3247, 'M', u'箏'),
(0x3248, 'V'),
(0x3250, 'M', u'pte'),
(0x3251, 'M', u'21'),
(0x3252, 'M', u'22'),
(0x3253, 'M', u'23'),
(0x3254, 'M', u'24'),
(0x3255, 'M', u'25'),
(0x3256, 'M', u'26'),
(0x3257, 'M', u'27'),
(0x3258, 'M', u'28'),
(0x3259, 'M', u'29'),
(0x325A, 'M', u'30'),
(0x325B, 'M', u'31'),
(0x325C, 'M', u'32'),
(0x325D, 'M', u'33'),
(0x325E, 'M', u'34'),
(0x325F, 'M', u'35'),
(0x3260, 'M', u'ᄀ'),
(0x3261, 'M', u'ᄂ'),
(0x3262, 'M', u'ᄃ'),
(0x3263, 'M', u'ᄅ'),
]
def _seg_31():
return [
(0x3264, 'M', u'ᄆ'),
(0x3265, 'M', u'ᄇ'),
(0x3266, 'M', u'ᄉ'),
(0x3267, 'M', u'ᄋ'),
(0x3268, 'M', u'ᄌ'),
(0x3269, 'M', u'ᄎ'),
(0x326A, 'M', u'ᄏ'),
(0x326B, 'M', u'ᄐ'),
(0x326C, 'M', u'ᄑ'),
(0x326D, 'M', u'ᄒ'),
(0x326E, 'M', u'가'),
(0x326F, 'M', u'나'),
(0x3270, 'M', u'다'),
(0x3271, 'M', u'라'),
(0x3272, 'M', u'마'),
(0x3273, 'M', u'바'),
(0x3274, 'M', u'사'),
(0x3275, 'M', u'아'),
(0x3276, 'M', u'자'),
(0x3277, 'M', u'차'),
(0x3278, 'M', u'카'),
(0x3279, 'M', u'타'),
(0x327A, 'M', u'파'),
(0x327B, 'M', u'하'),
(0x327C, 'M', u'참고'),
(0x327D, 'M', u'주의'),
(0x327E, 'M', u'우'),
(0x327F, 'V'),
(0x3280, 'M', u'一'),
(0x3281, 'M', u'二'),
(0x3282, 'M', u'三'),
(0x3283, 'M', u'四'),
(0x3284, 'M', u'五'),
(0x3285, 'M', u'六'),
(0x3286, 'M', u'七'),
(0x3287, 'M', u'八'),
(0x3288, 'M', u'九'),
(0x3289, 'M', u'十'),
(0x328A, 'M', u'月'),
(0x328B, 'M', u'火'),
(0x328C, 'M', u'水'),
(0x328D, 'M', u'木'),
(0x328E, 'M', u'金'),
(0x328F, 'M', u'土'),
(0x3290, 'M', u'日'),
(0x3291, 'M', u'株'),
(0x3292, 'M', u'有'),
(0x3293, 'M', u'社'),
(0x3294, 'M', u'名'),
(0x3295, 'M', u'特'),
(0x3296, 'M', u'財'),
(0x3297, 'M', u'祝'),
(0x3298, 'M', u'労'),
(0x3299, 'M', u'秘'),
(0x329A, 'M', u'男'),
(0x329B, 'M', u'女'),
(0x329C, 'M', u'適'),
(0x329D, 'M', u'優'),
(0x329E, 'M', u'印'),
(0x329F, 'M', u'注'),
(0x32A0, 'M', u'項'),
(0x32A1, 'M', u'休'),
(0x32A2, 'M', u'写'),
(0x32A3, 'M', u'正'),
(0x32A4, 'M', u'上'),
(0x32A5, 'M', u'中'),
(0x32A6, 'M', u'下'),
(0x32A7, 'M', u'左'),
(0x32A8, 'M', u'右'),
(0x32A9, 'M', u'医'),
(0x32AA, 'M', u'宗'),
(0x32AB, 'M', u'学'),
(0x32AC, 'M', u'監'),
(0x32AD, 'M', u'企'),
(0x32AE, 'M', u'資'),
(0x32AF, 'M', u'協'),
(0x32B0, 'M', u'夜'),
(0x32B1, 'M', u'36'),
(0x32B2, 'M', u'37'),
(0x32B3, 'M', u'38'),
(0x32B4, 'M', u'39'),
(0x32B5, 'M', u'40'),
(0x32B6, 'M', u'41'),
(0x32B7, 'M', u'42'),
(0x32B8, 'M', u'43'),
(0x32B9, 'M', u'44'),
(0x32BA, 'M', u'45'),
(0x32BB, 'M', u'46'),
(0x32BC, 'M', u'47'),
(0x32BD, 'M', u'48'),
(0x32BE, 'M', u'49'),
(0x32BF, 'M', u'50'),
(0x32C0, 'M', u'1月'),
(0x32C1, 'M', u'2月'),
(0x32C2, 'M', u'3月'),
(0x32C3, 'M', u'4月'),
(0x32C4, 'M', u'5月'),
(0x32C5, 'M', u'6月'),
(0x32C6, 'M', u'7月'),
(0x32C7, 'M', u'8月'),
]
def _seg_32():
return [
(0x32C8, 'M', u'9月'),
(0x32C9, 'M', u'10月'),
(0x32CA, 'M', u'11月'),
(0x32CB, 'M', u'12月'),
(0x32CC, 'M', u'hg'),
(0x32CD, 'M', u'erg'),
(0x32CE, 'M', u'ev'),
(0x32CF, 'M', u'ltd'),
(0x32D0, 'M', u'ア'),
(0x32D1, 'M', u'イ'),
(0x32D2, 'M', u'ウ'),
(0x32D3, 'M', u'エ'),
(0x32D4, 'M', u'オ'),
(0x32D5, 'M', u'カ'),
(0x32D6, 'M', u'キ'),
(0x32D7, 'M', u'ク'),
(0x32D8, 'M', u'ケ'),
(0x32D9, 'M', u'コ'),
(0x32DA, 'M', u'サ'),
(0x32DB, 'M', u'シ'),
(0x32DC, 'M', u'ス'),
(0x32DD, 'M', u'セ'),
(0x32DE, 'M', u'ソ'),
(0x32DF, 'M', u'タ'),
(0x32E0, 'M', u'チ'),
(0x32E1, 'M', u'ツ'),
(0x32E2, 'M', u'テ'),
(0x32E3, 'M', u'ト'),
(0x32E4, 'M', u'ナ'),
(0x32E5, 'M', u'ニ'),
(0x32E6, 'M', u'ヌ'),
(0x32E7, 'M', u'ネ'),
(0x32E8, 'M', u'ノ'),
(0x32E9, 'M', u'ハ'),
(0x32EA, 'M', u'ヒ'),
(0x32EB, 'M', u'フ'),
(0x32EC, 'M', u'ヘ'),
(0x32ED, 'M', u'ホ'),
(0x32EE, 'M', u'マ'),
(0x32EF, 'M', u'ミ'),
(0x32F0, 'M', u'ム'),
(0x32F1, 'M', u'メ'),
(0x32F2, 'M', u'モ'),
(0x32F3, 'M', u'ヤ'),
(0x32F4, 'M', u'ユ'),
(0x32F5, 'M', u'ヨ'),
(0x32F6, 'M', u'ラ'),
(0x32F7, 'M', u'リ'),
(0x32F8, 'M', u'ル'),
(0x32F9, 'M', u'レ'),
(0x32FA, 'M', u'ロ'),
(0x32FB, 'M', u'ワ'),
(0x32FC, 'M', u'ヰ'),
(0x32FD, 'M', u'ヱ'),
(0x32FE, 'M', u'ヲ'),
(0x32FF, 'X'),
(0x3300, 'M', u'アパート'),
(0x3301, 'M', u'アルファ'),
(0x3302, 'M', u'アンペア'),
(0x3303, 'M', u'アール'),
(0x3304, 'M', u'イニング'),
(0x3305, 'M', u'インチ'),
(0x3306, 'M', u'ウォン'),
(0x3307, 'M', u'エスクード'),
(0x3308, 'M', u'エーカー'),
(0x3309, 'M', u'オンス'),
(0x330A, 'M', u'オーム'),
(0x330B, 'M', u'カイリ'),
(0x330C, 'M', u'カラット'),
(0x330D, 'M', u'カロリー'),
(0x330E, 'M', u'ガロン'),
(0x330F, 'M', u'ガンマ'),
(0x3310, 'M', u'ギガ'),
(0x3311, 'M', u'ギニー'),
(0x3312, 'M', u'キュリー'),
(0x3313, 'M', u'ギルダー'),
(0x3314, 'M', u'キロ'),
(0x3315, 'M', u'キログラム'),
(0x3316, 'M', u'キロメートル'),
(0x3317, 'M', u'キロワット'),
(0x3318, 'M', u'グラム'),
(0x3319, 'M', u'グラムトン'),
(0x331A, 'M', u'クルゼイロ'),
(0x331B, 'M', u'クローネ'),
(0x331C, 'M', u'ケース'),
(0x331D, 'M', u'コルナ'),
(0x331E, 'M', u'コーポ'),
(0x331F, 'M', u'サイクル'),
(0x3320, 'M', u'サンチーム'),
(0x3321, 'M', u'シリング'),
(0x3322, 'M', u'センチ'),
(0x3323, 'M', u'セント'),
(0x3324, 'M', u'ダース'),
(0x3325, 'M', u'デシ'),
(0x3326, 'M', u'ドル'),
(0x3327, 'M', u'トン'),
(0x3328, 'M', u'ナノ'),
(0x3329, 'M', u'ノット'),
(0x332A, 'M', u'ハイツ'),
(0x332B, 'M', u'パーセント'),
]
def _seg_33():
return [
(0x332C, 'M', u'パーツ'),
(0x332D, 'M', u'バーレル'),
(0x332E, 'M', u'ピアストル'),
(0x332F, 'M', u'ピクル'),
(0x3330, 'M', u'ピコ'),
(0x3331, 'M', u'ビル'),
(0x3332, 'M', u'ファラッド'),
(0x3333, 'M', u'フィート'),
(0x3334, 'M', u'ブッシェル'),
(0x3335, 'M', u'フラン'),
(0x3336, 'M', u'ヘクタール'),
(0x3337, 'M', u'ペソ'),
(0x3338, 'M', u'ペニヒ'),
(0x3339, 'M', u'ヘルツ'),
(0x333A, 'M', u'ペンス'),
(0x333B, 'M', u'ページ'),
(0x333C, 'M', u'ベータ'),
(0x333D, 'M', u'ポイント'),
(0x333E, 'M', u'ボルト'),
(0x333F, 'M', u'ホン'),
(0x3340, 'M', u'ポンド'),
(0x3341, 'M', u'ホール'),
(0x3342, 'M', u'ホーン'),
(0x3343, 'M', u'マイクロ'),
(0x3344, 'M', u'マイル'),
(0x3345, 'M', u'マッハ'),
(0x3346, 'M', u'マルク'),
(0x3347, 'M', u'マンション'),
(0x3348, 'M', u'ミクロン'),
(0x3349, 'M', u'ミリ'),
(0x334A, 'M', u'ミリバール'),
(0x334B, 'M', u'メガ'),
(0x334C, 'M', u'メガトン'),
(0x334D, 'M', u'メートル'),
(0x334E, 'M', u'ヤード'),
(0x334F, 'M', u'ヤール'),
(0x3350, 'M', u'ユアン'),
(0x3351, 'M', u'リットル'),
(0x3352, 'M', u'リラ'),
(0x3353, 'M', u'ルピー'),
(0x3354, 'M', u'ルーブル'),
(0x3355, 'M', u'レム'),
(0x3356, 'M', u'レントゲン'),
(0x3357, 'M', u'ワット'),
(0x3358, 'M', u'0点'),
(0x3359, 'M', u'1点'),
(0x335A, 'M', u'2点'),
(0x335B, 'M', u'3点'),
(0x335C, 'M', u'4点'),
(0x335D, 'M', u'5点'),
(0x335E, 'M', u'6点'),
(0x335F, 'M', u'7点'),
(0x3360, 'M', u'8点'),
(0x3361, 'M', u'9点'),
(0x3362, 'M', u'10点'),
(0x3363, 'M', u'11点'),
(0x3364, 'M', u'12点'),
(0x3365, 'M', u'13点'),
(0x3366, 'M', u'14点'),
(0x3367, 'M', u'15点'),
(0x3368, 'M', u'16点'),
(0x3369, 'M', u'17点'),
(0x336A, 'M', u'18点'),
(0x336B, 'M', u'19点'),
(0x336C, 'M', u'20点'),
(0x336D, 'M', u'21点'),
(0x336E, 'M', u'22点'),
(0x336F, 'M', u'23点'),
(0x3370, 'M', u'24点'),
(0x3371, 'M', u'hpa'),
(0x3372, 'M', u'da'),
(0x3373, 'M', u'au'),
(0x3374, 'M', u'bar'),
(0x3375, 'M', u'ov'),
(0x3376, 'M', u'pc'),
(0x3377, 'M', u'dm'),
(0x3378, 'M', u'dm2'),
(0x3379, 'M', u'dm3'),
(0x337A, 'M', u'iu'),
(0x337B, 'M', u'平成'),
(0x337C, 'M', u'昭和'),
(0x337D, 'M', u'大正'),
(0x337E, 'M', u'明治'),
(0x337F, 'M', u'株式会社'),
(0x3380, 'M', u'pa'),
(0x3381, 'M', u'na'),
(0x3382, 'M', u'μa'),
(0x3383, 'M', u'ma'),
(0x3384, 'M', u'ka'),
(0x3385, 'M', u'kb'),
(0x3386, 'M', u'mb'),
(0x3387, 'M', u'gb'),
(0x3388, 'M', u'cal'),
(0x3389, 'M', u'kcal'),
(0x338A, 'M', u'pf'),
(0x338B, 'M', u'nf'),
(0x338C, 'M', u'μf'),
(0x338D, 'M', u'μg'),
(0x338E, 'M', u'mg'),
(0x338F, 'M', u'kg'),
]
def _seg_34():
return [
(0x3390, 'M', u'hz'),
(0x3391, 'M', u'khz'),
(0x3392, 'M', u'mhz'),
(0x3393, 'M', u'ghz'),
(0x3394, 'M', u'thz'),
(0x3395, 'M', u'μl'),
(0x3396, 'M', u'ml'),
(0x3397, 'M', u'dl'),
(0x3398, 'M', u'kl'),
(0x3399, 'M', u'fm'),
(0x339A, 'M', u'nm'),
(0x339B, 'M', u'μm'),
(0x339C, 'M', u'mm'),
(0x339D, 'M', u'cm'),
(0x339E, 'M', u'km'),
(0x339F, 'M', u'mm2'),
(0x33A0, 'M', u'cm2'),
(0x33A1, 'M', u'm2'),
(0x33A2, 'M', u'km2'),
(0x33A3, 'M', u'mm3'),
(0x33A4, 'M', u'cm3'),
(0x33A5, 'M', u'm3'),
(0x33A6, 'M', u'km3'),
(0x33A7, 'M', u'm∕s'),
(0x33A8, 'M', u'm∕s2'),
(0x33A9, 'M', u'pa'),
(0x33AA, 'M', u'kpa'),
(0x33AB, 'M', u'mpa'),
(0x33AC, 'M', u'gpa'),
(0x33AD, 'M', u'rad'),
(0x33AE, 'M', u'rad∕s'),
(0x33AF, 'M', u'rad∕s2'),
(0x33B0, 'M', u'ps'),
(0x33B1, 'M', u'ns'),
(0x33B2, 'M', u'μs'),
(0x33B3, 'M', u'ms'),
(0x33B4, 'M', u'pv'),
(0x33B5, 'M', u'nv'),
(0x33B6, 'M', u'μv'),
(0x33B7, 'M', u'mv'),
(0x33B8, 'M', u'kv'),
(0x33B9, 'M', u'mv'),
(0x33BA, 'M', u'pw'),
(0x33BB, 'M', u'nw'),
(0x33BC, 'M', u'μw'),
(0x33BD, 'M', u'mw'),
(0x33BE, 'M', u'kw'),
(0x33BF, 'M', u'mw'),
(0x33C0, 'M', u'kω'),
(0x33C1, 'M', u'mω'),
(0x33C2, 'X'),
(0x33C3, 'M', u'bq'),
(0x33C4, 'M', u'cc'),
(0x33C5, 'M', u'cd'),
(0x33C6, 'M', u'c∕kg'),
(0x33C7, 'X'),
(0x33C8, 'M', u'db'),
(0x33C9, 'M', u'gy'),
(0x33CA, 'M', u'ha'),
(0x33CB, 'M', u'hp'),
(0x33CC, 'M', u'in'),
(0x33CD, 'M', u'kk'),
(0x33CE, 'M', u'km'),
(0x33CF, 'M', u'kt'),
(0x33D0, 'M', u'lm'),
(0x33D1, 'M', u'ln'),
(0x33D2, 'M', u'log'),
(0x33D3, 'M', u'lx'),
(0x33D4, 'M', u'mb'),
(0x33D5, 'M', u'mil'),
(0x33D6, 'M', u'mol'),
(0x33D7, 'M', u'ph'),
(0x33D8, 'X'),
(0x33D9, 'M', u'ppm'),
(0x33DA, 'M', u'pr'),
(0x33DB, 'M', u'sr'),
(0x33DC, 'M', u'sv'),
(0x33DD, 'M', u'wb'),
(0x33DE, 'M', u'v∕m'),
(0x33DF, 'M', u'a∕m'),
(0x33E0, 'M', u'1日'),
(0x33E1, 'M', u'2日'),
(0x33E2, 'M', u'3日'),
(0x33E3, 'M', u'4日'),
(0x33E4, 'M', u'5日'),
(0x33E5, 'M', u'6日'),
(0x33E6, 'M', u'7日'),
(0x33E7, 'M', u'8日'),
(0x33E8, 'M', u'9日'),
(0x33E9, 'M', u'10日'),
(0x33EA, 'M', u'11日'),
(0x33EB, 'M', u'12日'),
(0x33EC, 'M', u'13日'),
(0x33ED, 'M', u'14日'),
(0x33EE, 'M', u'15日'),
(0x33EF, 'M', u'16日'),
(0x33F0, 'M', u'17日'),
(0x33F1, 'M', u'18日'),
(0x33F2, 'M', u'19日'),
(0x33F3, 'M', u'20日'),
]
def _seg_35():
return [
(0x33F4, 'M', u'21日'),
(0x33F5, 'M', u'22日'),
(0x33F6, 'M', u'23日'),
(0x33F7, 'M', u'24日'),
(0x33F8, 'M', u'25日'),
(0x33F9, 'M', u'26日'),
(0x33FA, 'M', u'27日'),
(0x33FB, 'M', u'28日'),
(0x33FC, 'M', u'29日'),
(0x33FD, 'M', u'30日'),
(0x33FE, 'M', u'31日'),
(0x33FF, 'M', u'gal'),
(0x3400, 'V'),
(0x4DB6, 'X'),
(0x4DC0, 'V'),
(0x9FF0, 'X'),
(0xA000, 'V'),
(0xA48D, 'X'),
(0xA490, 'V'),
(0xA4C7, 'X'),
(0xA4D0, 'V'),
(0xA62C, 'X'),
(0xA640, 'M', u'ꙁ'),
(0xA641, 'V'),
(0xA642, 'M', u'ꙃ'),
(0xA643, 'V'),
(0xA644, 'M', u'ꙅ'),
(0xA645, 'V'),
(0xA646, 'M', u'ꙇ'),
(0xA647, 'V'),
(0xA648, 'M', u'ꙉ'),
(0xA649, 'V'),
(0xA64A, 'M', u'ꙋ'),
(0xA64B, 'V'),
(0xA64C, 'M', u'ꙍ'),
(0xA64D, 'V'),
(0xA64E, 'M', u'ꙏ'),
(0xA64F, 'V'),
(0xA650, 'M', u'ꙑ'),
(0xA651, 'V'),
(0xA652, 'M', u'ꙓ'),
(0xA653, 'V'),
(0xA654, 'M', u'ꙕ'),
(0xA655, 'V'),
(0xA656, 'M', u'ꙗ'),
(0xA657, 'V'),
(0xA658, 'M', u'ꙙ'),
(0xA659, 'V'),
(0xA65A, 'M', u'ꙛ'),
(0xA65B, 'V'),
(0xA65C, 'M', u'ꙝ'),
(0xA65D, 'V'),
(0xA65E, 'M', u'ꙟ'),
(0xA65F, 'V'),
(0xA660, 'M', u'ꙡ'),
(0xA661, 'V'),
(0xA662, 'M', u'ꙣ'),
(0xA663, 'V'),
(0xA664, 'M', u'ꙥ'),
(0xA665, 'V'),
(0xA666, 'M', u'ꙧ'),
(0xA667, 'V'),
(0xA668, 'M', u'ꙩ'),
(0xA669, 'V'),
(0xA66A, 'M', u'ꙫ'),
(0xA66B, 'V'),
(0xA66C, 'M', u'ꙭ'),
(0xA66D, 'V'),
(0xA680, 'M', u'ꚁ'),
(0xA681, 'V'),
(0xA682, 'M', u'ꚃ'),
(0xA683, 'V'),
(0xA684, 'M', u'ꚅ'),
(0xA685, 'V'),
(0xA686, 'M', u'ꚇ'),
(0xA687, 'V'),
(0xA688, 'M', u'ꚉ'),
(0xA689, 'V'),
(0xA68A, 'M', u'ꚋ'),
(0xA68B, 'V'),
(0xA68C, 'M', u'ꚍ'),
(0xA68D, 'V'),
(0xA68E, 'M', u'ꚏ'),
(0xA68F, 'V'),
(0xA690, 'M', u'ꚑ'),
(0xA691, 'V'),
(0xA692, 'M', u'ꚓ'),
(0xA693, 'V'),
(0xA694, 'M', u'ꚕ'),
(0xA695, 'V'),
(0xA696, 'M', u'ꚗ'),
(0xA697, 'V'),
(0xA698, 'M', u'ꚙ'),
(0xA699, 'V'),
(0xA69A, 'M', u'ꚛ'),
(0xA69B, 'V'),
(0xA69C, 'M', u'ъ'),
(0xA69D, 'M', u'ь'),
(0xA69E, 'V'),
(0xA6F8, 'X'),
]
def _seg_36():
return [
(0xA700, 'V'),
(0xA722, 'M', u'ꜣ'),
(0xA723, 'V'),
(0xA724, 'M', u'ꜥ'),
(0xA725, 'V'),
(0xA726, 'M', u'ꜧ'),
(0xA727, 'V'),
(0xA728, 'M', u'ꜩ'),
(0xA729, 'V'),
(0xA72A, 'M', u'ꜫ'),
(0xA72B, 'V'),
(0xA72C, 'M', u'ꜭ'),
(0xA72D, 'V'),
(0xA72E, 'M', u'ꜯ'),
(0xA72F, 'V'),
(0xA732, 'M', u'ꜳ'),
(0xA733, 'V'),
(0xA734, 'M', u'ꜵ'),
(0xA735, 'V'),
(0xA736, 'M', u'ꜷ'),
(0xA737, 'V'),
(0xA738, 'M', u'ꜹ'),
(0xA739, 'V'),
(0xA73A, 'M', u'ꜻ'),
(0xA73B, 'V'),
(0xA73C, 'M', u'ꜽ'),
(0xA73D, 'V'),
(0xA73E, 'M', u'ꜿ'),
(0xA73F, 'V'),
(0xA740, 'M', u'ꝁ'),
(0xA741, 'V'),
(0xA742, 'M', u'ꝃ'),
(0xA743, 'V'),
(0xA744, 'M', u'ꝅ'),
(0xA745, 'V'),
(0xA746, 'M', u'ꝇ'),
(0xA747, 'V'),
(0xA748, 'M', u'ꝉ'),
(0xA749, 'V'),
(0xA74A, 'M', u'ꝋ'),
(0xA74B, 'V'),
(0xA74C, 'M', u'ꝍ'),
(0xA74D, 'V'),
(0xA74E, 'M', u'ꝏ'),
(0xA74F, 'V'),
(0xA750, 'M', u'ꝑ'),
(0xA751, 'V'),
(0xA752, 'M', u'ꝓ'),
(0xA753, 'V'),
(0xA754, 'M', u'ꝕ'),
(0xA755, 'V'),
(0xA756, 'M', u'ꝗ'),
(0xA757, 'V'),
(0xA758, 'M', u'ꝙ'),
(0xA759, 'V'),
(0xA75A, 'M', u'ꝛ'),
(0xA75B, 'V'),
(0xA75C, 'M', u'ꝝ'),
(0xA75D, 'V'),
(0xA75E, 'M', u'ꝟ'),
(0xA75F, 'V'),
(0xA760, 'M', u'ꝡ'),
(0xA761, 'V'),
(0xA762, 'M', u'ꝣ'),
(0xA763, 'V'),
(0xA764, 'M', u'ꝥ'),
(0xA765, 'V'),
(0xA766, 'M', u'ꝧ'),
(0xA767, 'V'),
(0xA768, 'M', u'ꝩ'),
(0xA769, 'V'),
(0xA76A, 'M', u'ꝫ'),
(0xA76B, 'V'),
(0xA76C, 'M', u'ꝭ'),
(0xA76D, 'V'),
(0xA76E, 'M', u'ꝯ'),
(0xA76F, 'V'),
(0xA770, 'M', u'ꝯ'),
(0xA771, 'V'),
(0xA779, 'M', u'ꝺ'),
(0xA77A, 'V'),
(0xA77B, 'M', u'ꝼ'),
(0xA77C, 'V'),
(0xA77D, 'M', u'ᵹ'),
(0xA77E, 'M', u'ꝿ'),
(0xA77F, 'V'),
(0xA780, 'M', u'ꞁ'),
(0xA781, 'V'),
(0xA782, 'M', u'ꞃ'),
(0xA783, 'V'),
(0xA784, 'M', u'ꞅ'),
(0xA785, 'V'),
(0xA786, 'M', u'ꞇ'),
(0xA787, 'V'),
(0xA78B, 'M', u'ꞌ'),
(0xA78C, 'V'),
(0xA78D, 'M', u'ɥ'),
(0xA78E, 'V'),
(0xA790, 'M', u'ꞑ'),
(0xA791, 'V'),
]
def _seg_37():
return [
(0xA792, 'M', u'ꞓ'),
(0xA793, 'V'),
(0xA796, 'M', u'ꞗ'),
(0xA797, 'V'),
(0xA798, 'M', u'ꞙ'),
(0xA799, 'V'),
(0xA79A, 'M', u'ꞛ'),
(0xA79B, 'V'),
(0xA79C, 'M', u'ꞝ'),
(0xA79D, 'V'),
(0xA79E, 'M', u'ꞟ'),
(0xA79F, 'V'),
(0xA7A0, 'M', u'ꞡ'),
(0xA7A1, 'V'),
(0xA7A2, 'M', u'ꞣ'),
(0xA7A3, 'V'),
(0xA7A4, 'M', u'ꞥ'),
(0xA7A5, 'V'),
(0xA7A6, 'M', u'ꞧ'),
(0xA7A7, 'V'),
(0xA7A8, 'M', u'ꞩ'),
(0xA7A9, 'V'),
(0xA7AA, 'M', u'ɦ'),
(0xA7AB, 'M', u'ɜ'),
(0xA7AC, 'M', u'ɡ'),
(0xA7AD, 'M', u'ɬ'),
(0xA7AE, 'M', u'ɪ'),
(0xA7AF, 'V'),
(0xA7B0, 'M', u'ʞ'),
(0xA7B1, 'M', u'ʇ'),
(0xA7B2, 'M', u'ʝ'),
(0xA7B3, 'M', u'ꭓ'),
(0xA7B4, 'M', u'ꞵ'),
(0xA7B5, 'V'),
(0xA7B6, 'M', u'ꞷ'),
(0xA7B7, 'V'),
(0xA7B8, 'X'),
(0xA7B9, 'V'),
(0xA7BA, 'X'),
(0xA7F7, 'V'),
(0xA7F8, 'M', u'ħ'),
(0xA7F9, 'M', u'œ'),
(0xA7FA, 'V'),
(0xA82C, 'X'),
(0xA830, 'V'),
(0xA83A, 'X'),
(0xA840, 'V'),
(0xA878, 'X'),
(0xA880, 'V'),
(0xA8C6, 'X'),
(0xA8CE, 'V'),
(0xA8DA, 'X'),
(0xA8E0, 'V'),
(0xA954, 'X'),
(0xA95F, 'V'),
(0xA97D, 'X'),
(0xA980, 'V'),
(0xA9CE, 'X'),
(0xA9CF, 'V'),
(0xA9DA, 'X'),
(0xA9DE, 'V'),
(0xA9FF, 'X'),
(0xAA00, 'V'),
(0xAA37, 'X'),
(0xAA40, 'V'),
(0xAA4E, 'X'),
(0xAA50, 'V'),
(0xAA5A, 'X'),
(0xAA5C, 'V'),
(0xAAC3, 'X'),
(0xAADB, 'V'),
(0xAAF7, 'X'),
(0xAB01, 'V'),
(0xAB07, 'X'),
(0xAB09, 'V'),
(0xAB0F, 'X'),
(0xAB11, 'V'),
(0xAB17, 'X'),
(0xAB20, 'V'),
(0xAB27, 'X'),
(0xAB28, 'V'),
(0xAB2F, 'X'),
(0xAB30, 'V'),
(0xAB5C, 'M', u'ꜧ'),
(0xAB5D, 'M', u'ꬷ'),
(0xAB5E, 'M', u'ɫ'),
(0xAB5F, 'M', u'ꭒ'),
(0xAB60, 'V'),
(0xAB66, 'X'),
(0xAB70, 'M', u'Ꭰ'),
(0xAB71, 'M', u'Ꭱ'),
(0xAB72, 'M', u'Ꭲ'),
(0xAB73, 'M', u'Ꭳ'),
(0xAB74, 'M', u'Ꭴ'),
(0xAB75, 'M', u'Ꭵ'),
(0xAB76, 'M', u'Ꭶ'),
(0xAB77, 'M', u'Ꭷ'),
(0xAB78, 'M', u'Ꭸ'),
(0xAB79, 'M', u'Ꭹ'),
(0xAB7A, 'M', u'Ꭺ'),
]
def _seg_38():
return [
(0xAB7B, 'M', u'Ꭻ'),
(0xAB7C, 'M', u'Ꭼ'),
(0xAB7D, 'M', u'Ꭽ'),
(0xAB7E, 'M', u'Ꭾ'),
(0xAB7F, 'M', u'Ꭿ'),
(0xAB80, 'M', u'Ꮀ'),
(0xAB81, 'M', u'Ꮁ'),
(0xAB82, 'M', u'Ꮂ'),
(0xAB83, 'M', u'Ꮃ'),
(0xAB84, 'M', u'Ꮄ'),
(0xAB85, 'M', u'Ꮅ'),
(0xAB86, 'M', u'Ꮆ'),
(0xAB87, 'M', u'Ꮇ'),
(0xAB88, 'M', u'Ꮈ'),
(0xAB89, 'M', u'Ꮉ'),
(0xAB8A, 'M', u'Ꮊ'),
(0xAB8B, 'M', u'Ꮋ'),
(0xAB8C, 'M', u'Ꮌ'),
(0xAB8D, 'M', u'Ꮍ'),
(0xAB8E, 'M', u'Ꮎ'),
(0xAB8F, 'M', u'Ꮏ'),
(0xAB90, 'M', u'Ꮐ'),
(0xAB91, 'M', u'Ꮑ'),
(0xAB92, 'M', u'Ꮒ'),
(0xAB93, 'M', u'Ꮓ'),
(0xAB94, 'M', u'Ꮔ'),
(0xAB95, 'M', u'Ꮕ'),
(0xAB96, 'M', u'Ꮖ'),
(0xAB97, 'M', u'Ꮗ'),
(0xAB98, 'M', u'Ꮘ'),
(0xAB99, 'M', u'Ꮙ'),
(0xAB9A, 'M', u'Ꮚ'),
(0xAB9B, 'M', u'Ꮛ'),
(0xAB9C, 'M', u'Ꮜ'),
(0xAB9D, 'M', u'Ꮝ'),
(0xAB9E, 'M', u'Ꮞ'),
(0xAB9F, 'M', u'Ꮟ'),
(0xABA0, 'M', u'Ꮠ'),
(0xABA1, 'M', u'Ꮡ'),
(0xABA2, 'M', u'Ꮢ'),
(0xABA3, 'M', u'Ꮣ'),
(0xABA4, 'M', u'Ꮤ'),
(0xABA5, 'M', u'Ꮥ'),
(0xABA6, 'M', u'Ꮦ'),
(0xABA7, 'M', u'Ꮧ'),
(0xABA8, 'M', u'Ꮨ'),
(0xABA9, 'M', u'Ꮩ'),
(0xABAA, 'M', u'Ꮪ'),
(0xABAB, 'M', u'Ꮫ'),
(0xABAC, 'M', u'Ꮬ'),
(0xABAD, 'M', u'Ꮭ'),
(0xABAE, 'M', u'Ꮮ'),
(0xABAF, 'M', u'Ꮯ'),
(0xABB0, 'M', u'Ꮰ'),
(0xABB1, 'M', u'Ꮱ'),
(0xABB2, 'M', u'Ꮲ'),
(0xABB3, 'M', u'Ꮳ'),
(0xABB4, 'M', u'Ꮴ'),
(0xABB5, 'M', u'Ꮵ'),
(0xABB6, 'M', u'Ꮶ'),
(0xABB7, 'M', u'Ꮷ'),
(0xABB8, 'M', u'Ꮸ'),
(0xABB9, 'M', u'Ꮹ'),
(0xABBA, 'M', u'Ꮺ'),
(0xABBB, 'M', u'Ꮻ'),
(0xABBC, 'M', u'Ꮼ'),
(0xABBD, 'M', u'Ꮽ'),
(0xABBE, 'M', u'Ꮾ'),
(0xABBF, 'M', u'Ꮿ'),
(0xABC0, 'V'),
(0xABEE, 'X'),
(0xABF0, 'V'),
(0xABFA, 'X'),
(0xAC00, 'V'),
(0xD7A4, 'X'),
(0xD7B0, 'V'),
(0xD7C7, 'X'),
(0xD7CB, 'V'),
(0xD7FC, 'X'),
(0xF900, 'M', u'豈'),
(0xF901, 'M', u'更'),
(0xF902, 'M', u'車'),
(0xF903, 'M', u'賈'),
(0xF904, 'M', u'滑'),
(0xF905, 'M', u'串'),
(0xF906, 'M', u'句'),
(0xF907, 'M', u'龜'),
(0xF909, 'M', u'契'),
(0xF90A, 'M', u'金'),
(0xF90B, 'M', u'喇'),
(0xF90C, 'M', u'奈'),
(0xF90D, 'M', u'懶'),
(0xF90E, 'M', u'癩'),
(0xF90F, 'M', u'羅'),
(0xF910, 'M', u'蘿'),
(0xF911, 'M', u'螺'),
(0xF912, 'M', u'裸'),
(0xF913, 'M', u'邏'),
(0xF914, 'M', u'樂'),
(0xF915, 'M', u'洛'),
]
def _seg_39():
return [
(0xF916, 'M', u'烙'),
(0xF917, 'M', u'珞'),
(0xF918, 'M', u'落'),
(0xF919, 'M', u'酪'),
(0xF91A, 'M', u'駱'),
(0xF91B, 'M', u'亂'),
(0xF91C, 'M', u'卵'),
(0xF91D, 'M', u'欄'),
(0xF91E, 'M', u'爛'),
(0xF91F, 'M', u'蘭'),
(0xF920, 'M', u'鸞'),
(0xF921, 'M', u'嵐'),
(0xF922, 'M', u'濫'),
(0xF923, 'M', u'藍'),
(0xF924, 'M', u'襤'),
(0xF925, 'M', u'拉'),
(0xF926, 'M', u'臘'),
(0xF927, 'M', u'蠟'),
(0xF928, 'M', u'廊'),
(0xF929, 'M', u'朗'),
(0xF92A, 'M', u'浪'),
(0xF92B, 'M', u'狼'),
(0xF92C, 'M', u'郎'),
(0xF92D, 'M', u'來'),
(0xF92E, 'M', u'冷'),
(0xF92F, 'M', u'勞'),
(0xF930, 'M', u'擄'),
(0xF931, 'M', u'櫓'),
(0xF932, 'M', u'爐'),
(0xF933, 'M', u'盧'),
(0xF934, 'M', u'老'),
(0xF935, 'M', u'蘆'),
(0xF936, 'M', u'虜'),
(0xF937, 'M', u'路'),
(0xF938, 'M', u'露'),
(0xF939, 'M', u'魯'),
(0xF93A, 'M', u'鷺'),
(0xF93B, 'M', u'碌'),
(0xF93C, 'M', u'祿'),
(0xF93D, 'M', u'綠'),
(0xF93E, 'M', u'菉'),
(0xF93F, 'M', u'錄'),
(0xF940, 'M', u'鹿'),
(0xF941, 'M', u'論'),
(0xF942, 'M', u'壟'),
(0xF943, 'M', u'弄'),
(0xF944, 'M', u'籠'),
(0xF945, 'M', u'聾'),
(0xF946, 'M', u'牢'),
(0xF947, 'M', u'磊'),
(0xF948, 'M', u'賂'),
(0xF949, 'M', u'雷'),
(0xF94A, 'M', u'壘'),
(0xF94B, 'M', u'屢'),
(0xF94C, 'M', u'樓'),
(0xF94D, 'M', u'淚'),
(0xF94E, 'M', u'漏'),
(0xF94F, 'M', u'累'),
(0xF950, 'M', u'縷'),
(0xF951, 'M', u'陋'),
(0xF952, 'M', u'勒'),
(0xF953, 'M', u'肋'),
(0xF954, 'M', u'凜'),
(0xF955, 'M', u'凌'),
(0xF956, 'M', u'稜'),
(0xF957, 'M', u'綾'),
(0xF958, 'M', u'菱'),
(0xF959, 'M', u'陵'),
(0xF95A, 'M', u'讀'),
(0xF95B, 'M', u'拏'),
(0xF95C, 'M', u'樂'),
(0xF95D, 'M', u'諾'),
(0xF95E, 'M', u'丹'),
(0xF95F, 'M', u'寧'),
(0xF960, 'M', u'怒'),
(0xF961, 'M', u'率'),
(0xF962, 'M', u'異'),
(0xF963, 'M', u'北'),
(0xF964, 'M', u'磻'),
(0xF965, 'M', u'便'),
(0xF966, 'M', u'復'),
(0xF967, 'M', u'不'),
(0xF968, 'M', u'泌'),
(0xF969, 'M', u'數'),
(0xF96A, 'M', u'索'),
(0xF96B, 'M', u'參'),
(0xF96C, 'M', u'塞'),
(0xF96D, 'M', u'省'),
(0xF96E, 'M', u'葉'),
(0xF96F, 'M', u'說'),
(0xF970, 'M', u'殺'),
(0xF971, 'M', u'辰'),
(0xF972, 'M', u'沈'),
(0xF973, 'M', u'拾'),
(0xF974, 'M', u'若'),
(0xF975, 'M', u'掠'),
(0xF976, 'M', u'略'),
(0xF977, 'M', u'亮'),
(0xF978, 'M', u'兩'),
(0xF979, 'M', u'凉'),
]
def _seg_40():
return [
(0xF97A, 'M', u'梁'),
(0xF97B, 'M', u'糧'),
(0xF97C, 'M', u'良'),
(0xF97D, 'M', u'諒'),
(0xF97E, 'M', u'量'),
(0xF97F, 'M', u'勵'),
(0xF980, 'M', u'呂'),
(0xF981, 'M', u'女'),
(0xF982, 'M', u'廬'),
(0xF983, 'M', u'旅'),
(0xF984, 'M', u'濾'),
(0xF985, 'M', u'礪'),
(0xF986, 'M', u'閭'),
(0xF987, 'M', u'驪'),
(0xF988, 'M', u'麗'),
(0xF989, 'M', u'黎'),
(0xF98A, 'M', u'力'),
(0xF98B, 'M', u'曆'),
(0xF98C, 'M', u'歷'),
(0xF98D, 'M', u'轢'),
(0xF98E, 'M', u'年'),
(0xF98F, 'M', u'憐'),
(0xF990, 'M', u'戀'),
(0xF991, 'M', u'撚'),
(0xF992, 'M', u'漣'),
(0xF993, 'M', u'煉'),
(0xF994, 'M', u'璉'),
(0xF995, 'M', u'秊'),
(0xF996, 'M', u'練'),
(0xF997, 'M', u'聯'),
(0xF998, 'M', u'輦'),
(0xF999, 'M', u'蓮'),
(0xF99A, 'M', u'連'),
(0xF99B, 'M', u'鍊'),
(0xF99C, 'M', u'列'),
(0xF99D, 'M', u'劣'),
(0xF99E, 'M', u'咽'),
(0xF99F, 'M', u'烈'),
(0xF9A0, 'M', u'裂'),
(0xF9A1, 'M', u'說'),
(0xF9A2, 'M', u'廉'),
(0xF9A3, 'M', u'念'),
(0xF9A4, 'M', u'捻'),
(0xF9A5, 'M', u'殮'),
(0xF9A6, 'M', u'簾'),
(0xF9A7, 'M', u'獵'),
(0xF9A8, 'M', u'令'),
(0xF9A9, 'M', u'囹'),
(0xF9AA, 'M', u'寧'),
(0xF9AB, 'M', u'嶺'),
(0xF9AC, 'M', u'怜'),
(0xF9AD, 'M', u'玲'),
(0xF9AE, 'M', u'瑩'),
(0xF9AF, 'M', u'羚'),
(0xF9B0, 'M', u'聆'),
(0xF9B1, 'M', u'鈴'),
(0xF9B2, 'M', u'零'),
(0xF9B3, 'M', u'靈'),
(0xF9B4, 'M', u'領'),
(0xF9B5, 'M', u'例'),
(0xF9B6, 'M', u'禮'),
(0xF9B7, 'M', u'醴'),
(0xF9B8, 'M', u'隸'),
(0xF9B9, 'M', u'惡'),
(0xF9BA, 'M', u'了'),
(0xF9BB, 'M', u'僚'),
(0xF9BC, 'M', u'寮'),
(0xF9BD, 'M', u'尿'),
(0xF9BE, 'M', u'料'),
(0xF9BF, 'M', u'樂'),
(0xF9C0, 'M', u'燎'),
(0xF9C1, 'M', u'療'),
(0xF9C2, 'M', u'蓼'),
(0xF9C3, 'M', u'遼'),
(0xF9C4, 'M', u'龍'),
(0xF9C5, 'M', u'暈'),
(0xF9C6, 'M', u'阮'),
(0xF9C7, 'M', u'劉'),
(0xF9C8, 'M', u'杻'),
(0xF9C9, 'M', u'柳'),
(0xF9CA, 'M', u'流'),
(0xF9CB, 'M', u'溜'),
(0xF9CC, 'M', u'琉'),
(0xF9CD, 'M', u'留'),
(0xF9CE, 'M', u'硫'),
(0xF9CF, 'M', u'紐'),
(0xF9D0, 'M', u'類'),
(0xF9D1, 'M', u'六'),
(0xF9D2, 'M', u'戮'),
(0xF9D3, 'M', u'陸'),
(0xF9D4, 'M', u'倫'),
(0xF9D5, 'M', u'崙'),
(0xF9D6, 'M', u'淪'),
(0xF9D7, 'M', u'輪'),
(0xF9D8, 'M', u'律'),
(0xF9D9, 'M', u'慄'),
(0xF9DA, 'M', u'栗'),
(0xF9DB, 'M', u'率'),
(0xF9DC, 'M', u'隆'),
(0xF9DD, 'M', u'利'),
]
def _seg_41():
return [
(0xF9DE, 'M', u'吏'),
(0xF9DF, 'M', u'履'),
(0xF9E0, 'M', u'易'),
(0xF9E1, 'M', u'李'),
(0xF9E2, 'M', u'梨'),
(0xF9E3, 'M', u'泥'),
(0xF9E4, 'M', u'理'),
(0xF9E5, 'M', u'痢'),
(0xF9E6, 'M', u'罹'),
(0xF9E7, 'M', u'裏'),
(0xF9E8, 'M', u'裡'),
(0xF9E9, 'M', u'里'),
(0xF9EA, 'M', u'離'),
(0xF9EB, 'M', u'匿'),
(0xF9EC, 'M', u'溺'),
(0xF9ED, 'M', u'吝'),
(0xF9EE, 'M', u'燐'),
(0xF9EF, 'M', u'璘'),
(0xF9F0, 'M', u'藺'),
(0xF9F1, 'M', u'隣'),
(0xF9F2, 'M', u'鱗'),
(0xF9F3, 'M', u'麟'),
(0xF9F4, 'M', u'林'),
(0xF9F5, 'M', u'淋'),
(0xF9F6, 'M', u'臨'),
(0xF9F7, 'M', u'立'),
(0xF9F8, 'M', u'笠'),
(0xF9F9, 'M', u'粒'),
(0xF9FA, 'M', u'狀'),
(0xF9FB, 'M', u'炙'),
(0xF9FC, 'M', u'識'),
(0xF9FD, 'M', u'什'),
(0xF9FE, 'M', u'茶'),
(0xF9FF, 'M', u'刺'),
(0xFA00, 'M', u'切'),
(0xFA01, 'M', u'度'),
(0xFA02, 'M', u'拓'),
(0xFA03, 'M', u'糖'),
(0xFA04, 'M', u'宅'),
(0xFA05, 'M', u'洞'),
(0xFA06, 'M', u'暴'),
(0xFA07, 'M', u'輻'),
(0xFA08, 'M', u'行'),
(0xFA09, 'M', u'降'),
(0xFA0A, 'M', u'見'),
(0xFA0B, 'M', u'廓'),
(0xFA0C, 'M', u'兀'),
(0xFA0D, 'M', u'嗀'),
(0xFA0E, 'V'),
(0xFA10, 'M', u'塚'),
(0xFA11, 'V'),
(0xFA12, 'M', u'晴'),
(0xFA13, 'V'),
(0xFA15, 'M', u'凞'),
(0xFA16, 'M', u'猪'),
(0xFA17, 'M', u'益'),
(0xFA18, 'M', u'礼'),
(0xFA19, 'M', u'神'),
(0xFA1A, 'M', u'祥'),
(0xFA1B, 'M', u'福'),
(0xFA1C, 'M', u'靖'),
(0xFA1D, 'M', u'精'),
(0xFA1E, 'M', u'羽'),
(0xFA1F, 'V'),
(0xFA20, 'M', u'蘒'),
(0xFA21, 'V'),
(0xFA22, 'M', u'諸'),
(0xFA23, 'V'),
(0xFA25, 'M', u'逸'),
(0xFA26, 'M', u'都'),
(0xFA27, 'V'),
(0xFA2A, 'M', u'飯'),
(0xFA2B, 'M', u'飼'),
(0xFA2C, 'M', u'館'),
(0xFA2D, 'M', u'鶴'),
(0xFA2E, 'M', u'郞'),
(0xFA2F, 'M', u'隷'),
(0xFA30, 'M', u'侮'),
(0xFA31, 'M', u'僧'),
(0xFA32, 'M', u'免'),
(0xFA33, 'M', u'勉'),
(0xFA34, 'M', u'勤'),
(0xFA35, 'M', u'卑'),
(0xFA36, 'M', u'喝'),
(0xFA37, 'M', u'嘆'),
(0xFA38, 'M', u'器'),
(0xFA39, 'M', u'塀'),
(0xFA3A, 'M', u'墨'),
(0xFA3B, 'M', u'層'),
(0xFA3C, 'M', u'屮'),
(0xFA3D, 'M', u'悔'),
(0xFA3E, 'M', u'慨'),
(0xFA3F, 'M', u'憎'),
(0xFA40, 'M', u'懲'),
(0xFA41, 'M', u'敏'),
(0xFA42, 'M', u'既'),
(0xFA43, 'M', u'暑'),
(0xFA44, 'M', u'梅'),
(0xFA45, 'M', u'海'),
(0xFA46, 'M', u'渚'),
]
def _seg_42():
return [
(0xFA47, 'M', u'漢'),
(0xFA48, 'M', u'煮'),
(0xFA49, 'M', u'爫'),
(0xFA4A, 'M', u'琢'),
(0xFA4B, 'M', u'碑'),
(0xFA4C, 'M', u'社'),
(0xFA4D, 'M', u'祉'),
(0xFA4E, 'M', u'祈'),
(0xFA4F, 'M', u'祐'),
(0xFA50, 'M', u'祖'),
(0xFA51, 'M', u'祝'),
(0xFA52, 'M', u'禍'),
(0xFA53, 'M', u'禎'),
(0xFA54, 'M', u'穀'),
(0xFA55, 'M', u'突'),
(0xFA56, 'M', u'節'),
(0xFA57, 'M', u'練'),
(0xFA58, 'M', u'縉'),
(0xFA59, 'M', u'繁'),
(0xFA5A, 'M', u'署'),
(0xFA5B, 'M', u'者'),
(0xFA5C, 'M', u'臭'),
(0xFA5D, 'M', u'艹'),
(0xFA5F, 'M', u'著'),
(0xFA60, 'M', u'褐'),
(0xFA61, 'M', u'視'),
(0xFA62, 'M', u'謁'),
(0xFA63, 'M', u'謹'),
(0xFA64, 'M', u'賓'),
(0xFA65, 'M', u'贈'),
(0xFA66, 'M', u'辶'),
(0xFA67, 'M', u'逸'),
(0xFA68, 'M', u'難'),
(0xFA69, 'M', u'響'),
(0xFA6A, 'M', u'頻'),
(0xFA6B, 'M', u'恵'),
(0xFA6C, 'M', u'𤋮'),
(0xFA6D, 'M', u'舘'),
(0xFA6E, 'X'),
(0xFA70, 'M', u'並'),
(0xFA71, 'M', u'况'),
(0xFA72, 'M', u'全'),
(0xFA73, 'M', u'侀'),
(0xFA74, 'M', u'充'),
(0xFA75, 'M', u'冀'),
(0xFA76, 'M', u'勇'),
(0xFA77, 'M', u'勺'),
(0xFA78, 'M', u'喝'),
(0xFA79, 'M', u'啕'),
(0xFA7A, 'M', u'喙'),
(0xFA7B, 'M', u'嗢'),
(0xFA7C, 'M', u'塚'),
(0xFA7D, 'M', u'墳'),
(0xFA7E, 'M', u'奄'),
(0xFA7F, 'M', u'奔'),
(0xFA80, 'M', u'婢'),
(0xFA81, 'M', u'嬨'),
(0xFA82, 'M', u'廒'),
(0xFA83, 'M', u'廙'),
(0xFA84, 'M', u'彩'),
(0xFA85, 'M', u'徭'),
(0xFA86, 'M', u'惘'),
(0xFA87, 'M', u'慎'),
(0xFA88, 'M', u'愈'),
(0xFA89, 'M', u'憎'),
(0xFA8A, 'M', u'慠'),
(0xFA8B, 'M', u'懲'),
(0xFA8C, 'M', u'戴'),
(0xFA8D, 'M', u'揄'),
(0xFA8E, 'M', u'搜'),
(0xFA8F, 'M', u'摒'),
(0xFA90, 'M', u'敖'),
(0xFA91, 'M', u'晴'),
(0xFA92, 'M', u'朗'),
(0xFA93, 'M', u'望'),
(0xFA94, 'M', u'杖'),
(0xFA95, 'M', u'歹'),
(0xFA96, 'M', u'殺'),
(0xFA97, 'M', u'流'),
(0xFA98, 'M', u'滛'),
(0xFA99, 'M', u'滋'),
(0xFA9A, 'M', u'漢'),
(0xFA9B, 'M', u'瀞'),
(0xFA9C, 'M', u'煮'),
(0xFA9D, 'M', u'瞧'),
(0xFA9E, 'M', u'爵'),
(0xFA9F, 'M', u'犯'),
(0xFAA0, 'M', u'猪'),
(0xFAA1, 'M', u'瑱'),
(0xFAA2, 'M', u'甆'),
(0xFAA3, 'M', u'画'),
(0xFAA4, 'M', u'瘝'),
(0xFAA5, 'M', u'瘟'),
(0xFAA6, 'M', u'益'),
(0xFAA7, 'M', u'盛'),
(0xFAA8, 'M', u'直'),
(0xFAA9, 'M', u'睊'),
(0xFAAA, 'M', u'着'),
(0xFAAB, 'M', u'磌'),
(0xFAAC, 'M', u'窱'),
]
def _seg_43():
return [
(0xFAAD, 'M', u'節'),
(0xFAAE, 'M', u'类'),
(0xFAAF, 'M', u'絛'),
(0xFAB0, 'M', u'練'),
(0xFAB1, 'M', u'缾'),
(0xFAB2, 'M', u'者'),
(0xFAB3, 'M', u'荒'),
(0xFAB4, 'M', u'華'),
(0xFAB5, 'M', u'蝹'),
(0xFAB6, 'M', u'襁'),
(0xFAB7, 'M', u'覆'),
(0xFAB8, 'M', u'視'),
(0xFAB9, 'M', u'調'),
(0xFABA, 'M', u'諸'),
(0xFABB, 'M', u'請'),
(0xFABC, 'M', u'謁'),
(0xFABD, 'M', u'諾'),
(0xFABE, 'M', u'諭'),
(0xFABF, 'M', u'謹'),
(0xFAC0, 'M', u'變'),
(0xFAC1, 'M', u'贈'),
(0xFAC2, 'M', u'輸'),
(0xFAC3, 'M', u'遲'),
(0xFAC4, 'M', u'醙'),
(0xFAC5, 'M', u'鉶'),
(0xFAC6, 'M', u'陼'),
(0xFAC7, 'M', u'難'),
(0xFAC8, 'M', u'靖'),
(0xFAC9, 'M', u'韛'),
(0xFACA, 'M', u'響'),
(0xFACB, 'M', u'頋'),
(0xFACC, 'M', u'頻'),
(0xFACD, 'M', u'鬒'),
(0xFACE, 'M', u'龜'),
(0xFACF, 'M', u'𢡊'),
(0xFAD0, 'M', u'𢡄'),
(0xFAD1, 'M', u'𣏕'),
(0xFAD2, 'M', u'㮝'),
(0xFAD3, 'M', u'䀘'),
(0xFAD4, 'M', u'䀹'),
(0xFAD5, 'M', u'𥉉'),
(0xFAD6, 'M', u'𥳐'),
(0xFAD7, 'M', u'𧻓'),
(0xFAD8, 'M', u'齃'),
(0xFAD9, 'M', u'龎'),
(0xFADA, 'X'),
(0xFB00, 'M', u'ff'),
(0xFB01, 'M', u'fi'),
(0xFB02, 'M', u'fl'),
(0xFB03, 'M', u'ffi'),
(0xFB04, 'M', u'ffl'),
(0xFB05, 'M', u'st'),
(0xFB07, 'X'),
(0xFB13, 'M', u'մն'),
(0xFB14, 'M', u'մե'),
(0xFB15, 'M', u'մի'),
(0xFB16, 'M', u'վն'),
(0xFB17, 'M', u'մխ'),
(0xFB18, 'X'),
(0xFB1D, 'M', u'יִ'),
(0xFB1E, 'V'),
(0xFB1F, 'M', u'ײַ'),
(0xFB20, 'M', u'ע'),
(0xFB21, 'M', u'א'),
(0xFB22, 'M', u'ד'),
(0xFB23, 'M', u'ה'),
(0xFB24, 'M', u'כ'),
(0xFB25, 'M', u'ל'),
(0xFB26, 'M', u'ם'),
(0xFB27, 'M', u'ר'),
(0xFB28, 'M', u'ת'),
(0xFB29, '3', u'+'),
(0xFB2A, 'M', u'שׁ'),
(0xFB2B, 'M', u'שׂ'),
(0xFB2C, 'M', u'שּׁ'),
(0xFB2D, 'M', u'שּׂ'),
(0xFB2E, 'M', u'אַ'),
(0xFB2F, 'M', u'אָ'),
(0xFB30, 'M', u'אּ'),
(0xFB31, 'M', u'בּ'),
(0xFB32, 'M', u'גּ'),
(0xFB33, 'M', u'דּ'),
(0xFB34, 'M', u'הּ'),
(0xFB35, 'M', u'וּ'),
(0xFB36, 'M', u'זּ'),
(0xFB37, 'X'),
(0xFB38, 'M', u'טּ'),
(0xFB39, 'M', u'יּ'),
(0xFB3A, 'M', u'ךּ'),
(0xFB3B, 'M', u'כּ'),
(0xFB3C, 'M', u'לּ'),
(0xFB3D, 'X'),
(0xFB3E, 'M', u'מּ'),
(0xFB3F, 'X'),
(0xFB40, 'M', u'נּ'),
(0xFB41, 'M', u'סּ'),
(0xFB42, 'X'),
(0xFB43, 'M', u'ףּ'),
(0xFB44, 'M', u'פּ'),
(0xFB45, 'X'),
]
def _seg_44():
return [
(0xFB46, 'M', u'צּ'),
(0xFB47, 'M', u'קּ'),
(0xFB48, 'M', u'רּ'),
(0xFB49, 'M', u'שּ'),
(0xFB4A, 'M', u'תּ'),
(0xFB4B, 'M', u'וֹ'),
(0xFB4C, 'M', u'בֿ'),
(0xFB4D, 'M', u'כֿ'),
(0xFB4E, 'M', u'פֿ'),
(0xFB4F, 'M', u'אל'),
(0xFB50, 'M', u'ٱ'),
(0xFB52, 'M', u'ٻ'),
(0xFB56, 'M', u'پ'),
(0xFB5A, 'M', u'ڀ'),
(0xFB5E, 'M', u'ٺ'),
(0xFB62, 'M', u'ٿ'),
(0xFB66, 'M', u'ٹ'),
(0xFB6A, 'M', u'ڤ'),
(0xFB6E, 'M', u'ڦ'),
(0xFB72, 'M', u'ڄ'),
(0xFB76, 'M', u'ڃ'),
(0xFB7A, 'M', u'چ'),
(0xFB7E, 'M', u'ڇ'),
(0xFB82, 'M', u'ڍ'),
(0xFB84, 'M', u'ڌ'),
(0xFB86, 'M', u'ڎ'),
(0xFB88, 'M', u'ڈ'),
(0xFB8A, 'M', u'ژ'),
(0xFB8C, 'M', u'ڑ'),
(0xFB8E, 'M', u'ک'),
(0xFB92, 'M', u'گ'),
(0xFB96, 'M', u'ڳ'),
(0xFB9A, 'M', u'ڱ'),
(0xFB9E, 'M', u'ں'),
(0xFBA0, 'M', u'ڻ'),
(0xFBA4, 'M', u'ۀ'),
(0xFBA6, 'M', u'ہ'),
(0xFBAA, 'M', u'ھ'),
(0xFBAE, 'M', u'ے'),
(0xFBB0, 'M', u'ۓ'),
(0xFBB2, 'V'),
(0xFBC2, 'X'),
(0xFBD3, 'M', u'ڭ'),
(0xFBD7, 'M', u'ۇ'),
(0xFBD9, 'M', u'ۆ'),
(0xFBDB, 'M', u'ۈ'),
(0xFBDD, 'M', u'ۇٴ'),
(0xFBDE, 'M', u'ۋ'),
(0xFBE0, 'M', u'ۅ'),
(0xFBE2, 'M', u'ۉ'),
(0xFBE4, 'M', u'ې'),
(0xFBE8, 'M', u'ى'),
(0xFBEA, 'M', u'ئا'),
(0xFBEC, 'M', u'ئە'),
(0xFBEE, 'M', u'ئو'),
(0xFBF0, 'M', u'ئۇ'),
(0xFBF2, 'M', u'ئۆ'),
(0xFBF4, 'M', u'ئۈ'),
(0xFBF6, 'M', u'ئې'),
(0xFBF9, 'M', u'ئى'),
(0xFBFC, 'M', u'ی'),
(0xFC00, 'M', u'ئج'),
(0xFC01, 'M', u'ئح'),
(0xFC02, 'M', u'ئم'),
(0xFC03, 'M', u'ئى'),
(0xFC04, 'M', u'ئي'),
(0xFC05, 'M', u'بج'),
(0xFC06, 'M', u'بح'),
(0xFC07, 'M', u'بخ'),
(0xFC08, 'M', u'بم'),
(0xFC09, 'M', u'بى'),
(0xFC0A, 'M', u'بي'),
(0xFC0B, 'M', u'تج'),
(0xFC0C, 'M', u'تح'),
(0xFC0D, 'M', u'تخ'),
(0xFC0E, 'M', u'تم'),
(0xFC0F, 'M', u'تى'),
(0xFC10, 'M', u'تي'),
(0xFC11, 'M', u'ثج'),
(0xFC12, 'M', u'ثم'),
(0xFC13, 'M', u'ثى'),
(0xFC14, 'M', u'ثي'),
(0xFC15, 'M', u'جح'),
(0xFC16, 'M', u'جم'),
(0xFC17, 'M', u'حج'),
(0xFC18, 'M', u'حم'),
(0xFC19, 'M', u'خج'),
(0xFC1A, 'M', u'خح'),
(0xFC1B, 'M', u'خم'),
(0xFC1C, 'M', u'سج'),
(0xFC1D, 'M', u'سح'),
(0xFC1E, 'M', u'سخ'),
(0xFC1F, 'M', u'سم'),
(0xFC20, 'M', u'صح'),
(0xFC21, 'M', u'صم'),
(0xFC22, 'M', u'ضج'),
(0xFC23, 'M', u'ضح'),
(0xFC24, 'M', u'ضخ'),
(0xFC25, 'M', u'ضم'),
(0xFC26, 'M', u'طح'),
]
def _seg_45():
return [
(0xFC27, 'M', u'طم'),
(0xFC28, 'M', u'ظم'),
(0xFC29, 'M', u'عج'),
(0xFC2A, 'M', u'عم'),
(0xFC2B, 'M', u'غج'),
(0xFC2C, 'M', u'غم'),
(0xFC2D, 'M', u'فج'),
(0xFC2E, 'M', u'فح'),
(0xFC2F, 'M', u'فخ'),
(0xFC30, 'M', u'فم'),
(0xFC31, 'M', u'فى'),
(0xFC32, 'M', u'في'),
(0xFC33, 'M', u'قح'),
(0xFC34, 'M', u'قم'),
(0xFC35, 'M', u'قى'),
(0xFC36, 'M', u'قي'),
(0xFC37, 'M', u'كا'),
(0xFC38, 'M', u'كج'),
(0xFC39, 'M', u'كح'),
(0xFC3A, 'M', u'كخ'),
(0xFC3B, 'M', u'كل'),
(0xFC3C, 'M', u'كم'),
(0xFC3D, 'M', u'كى'),
(0xFC3E, 'M', u'كي'),
(0xFC3F, 'M', u'لج'),
(0xFC40, 'M', u'لح'),
(0xFC41, 'M', u'لخ'),
(0xFC42, 'M', u'لم'),
(0xFC43, 'M', u'لى'),
(0xFC44, 'M', u'لي'),
(0xFC45, 'M', u'مج'),
(0xFC46, 'M', u'مح'),
(0xFC47, 'M', u'مخ'),
(0xFC48, 'M', u'مم'),
(0xFC49, 'M', u'مى'),
(0xFC4A, 'M', u'مي'),
(0xFC4B, 'M', u'نج'),
(0xFC4C, 'M', u'نح'),
(0xFC4D, 'M', u'نخ'),
(0xFC4E, 'M', u'نم'),
(0xFC4F, 'M', u'نى'),
(0xFC50, 'M', u'ني'),
(0xFC51, 'M', u'هج'),
(0xFC52, 'M', u'هم'),
(0xFC53, 'M', u'هى'),
(0xFC54, 'M', u'هي'),
(0xFC55, 'M', u'يج'),
(0xFC56, 'M', u'يح'),
(0xFC57, 'M', u'يخ'),
(0xFC58, 'M', u'يم'),
(0xFC59, 'M', u'يى'),
(0xFC5A, 'M', u'يي'),
(0xFC5B, 'M', u'ذٰ'),
(0xFC5C, 'M', u'رٰ'),
(0xFC5D, 'M', u'ىٰ'),
(0xFC5E, '3', u' ٌّ'),
(0xFC5F, '3', u' ٍّ'),
(0xFC60, '3', u' َّ'),
(0xFC61, '3', u' ُّ'),
(0xFC62, '3', u' ِّ'),
(0xFC63, '3', u' ّٰ'),
(0xFC64, 'M', u'ئر'),
(0xFC65, 'M', u'ئز'),
(0xFC66, 'M', u'ئم'),
(0xFC67, 'M', u'ئن'),
(0xFC68, 'M', u'ئى'),
(0xFC69, 'M', u'ئي'),
(0xFC6A, 'M', u'بر'),
(0xFC6B, 'M', u'بز'),
(0xFC6C, 'M', u'بم'),
(0xFC6D, 'M', u'بن'),
(0xFC6E, 'M', u'بى'),
(0xFC6F, 'M', u'بي'),
(0xFC70, 'M', u'تر'),
(0xFC71, 'M', u'تز'),
(0xFC72, 'M', u'تم'),
(0xFC73, 'M', u'تن'),
(0xFC74, 'M', u'تى'),
(0xFC75, 'M', u'تي'),
(0xFC76, 'M', u'ثر'),
(0xFC77, 'M', u'ثز'),
(0xFC78, 'M', u'ثم'),
(0xFC79, 'M', u'ثن'),
(0xFC7A, 'M', u'ثى'),
(0xFC7B, 'M', u'ثي'),
(0xFC7C, 'M', u'فى'),
(0xFC7D, 'M', u'في'),
(0xFC7E, 'M', u'قى'),
(0xFC7F, 'M', u'قي'),
(0xFC80, 'M', u'كا'),
(0xFC81, 'M', u'كل'),
(0xFC82, 'M', u'كم'),
(0xFC83, 'M', u'كى'),
(0xFC84, 'M', u'كي'),
(0xFC85, 'M', u'لم'),
(0xFC86, 'M', u'لى'),
(0xFC87, 'M', u'لي'),
(0xFC88, 'M', u'ما'),
(0xFC89, 'M', u'مم'),
(0xFC8A, 'M', u'نر'),
]
def _seg_46():
return [
(0xFC8B, 'M', u'نز'),
(0xFC8C, 'M', u'نم'),
(0xFC8D, 'M', u'نن'),
(0xFC8E, 'M', u'نى'),
(0xFC8F, 'M', u'ني'),
(0xFC90, 'M', u'ىٰ'),
(0xFC91, 'M', u'ير'),
(0xFC92, 'M', u'يز'),
(0xFC93, 'M', u'يم'),
(0xFC94, 'M', u'ين'),
(0xFC95, 'M', u'يى'),
(0xFC96, 'M', u'يي'),
(0xFC97, 'M', u'ئج'),
(0xFC98, 'M', u'ئح'),
(0xFC99, 'M', u'ئخ'),
(0xFC9A, 'M', u'ئم'),
(0xFC9B, 'M', u'ئه'),
(0xFC9C, 'M', u'بج'),
(0xFC9D, 'M', u'بح'),
(0xFC9E, 'M', u'بخ'),
(0xFC9F, 'M', u'بم'),
(0xFCA0, 'M', u'به'),
(0xFCA1, 'M', u'تج'),
(0xFCA2, 'M', u'تح'),
(0xFCA3, 'M', u'تخ'),
(0xFCA4, 'M', u'تم'),
(0xFCA5, 'M', u'ته'),
(0xFCA6, 'M', u'ثم'),
(0xFCA7, 'M', u'جح'),
(0xFCA8, 'M', u'جم'),
(0xFCA9, 'M', u'حج'),
(0xFCAA, 'M', u'حم'),
(0xFCAB, 'M', u'خج'),
(0xFCAC, 'M', u'خم'),
(0xFCAD, 'M', u'سج'),
(0xFCAE, 'M', u'سح'),
(0xFCAF, 'M', u'سخ'),
(0xFCB0, 'M', u'سم'),
(0xFCB1, 'M', u'صح'),
(0xFCB2, 'M', u'صخ'),
(0xFCB3, 'M', u'صم'),
(0xFCB4, 'M', u'ضج'),
(0xFCB5, 'M', u'ضح'),
(0xFCB6, 'M', u'ضخ'),
(0xFCB7, 'M', u'ضم'),
(0xFCB8, 'M', u'طح'),
(0xFCB9, 'M', u'ظم'),
(0xFCBA, 'M', u'عج'),
(0xFCBB, 'M', u'عم'),
(0xFCBC, 'M', u'غج'),
(0xFCBD, 'M', u'غم'),
(0xFCBE, 'M', u'فج'),
(0xFCBF, 'M', u'فح'),
(0xFCC0, 'M', u'فخ'),
(0xFCC1, 'M', u'فم'),
(0xFCC2, 'M', u'قح'),
(0xFCC3, 'M', u'قم'),
(0xFCC4, 'M', u'كج'),
(0xFCC5, 'M', u'كح'),
(0xFCC6, 'M', u'كخ'),
(0xFCC7, 'M', u'كل'),
(0xFCC8, 'M', u'كم'),
(0xFCC9, 'M', u'لج'),
(0xFCCA, 'M', u'لح'),
(0xFCCB, 'M', u'لخ'),
(0xFCCC, 'M', u'لم'),
(0xFCCD, 'M', u'له'),
(0xFCCE, 'M', u'مج'),
(0xFCCF, 'M', u'مح'),
(0xFCD0, 'M', u'مخ'),
(0xFCD1, 'M', u'مم'),
(0xFCD2, 'M', u'نج'),
(0xFCD3, 'M', u'نح'),
(0xFCD4, 'M', u'نخ'),
(0xFCD5, 'M', u'نم'),
(0xFCD6, 'M', u'نه'),
(0xFCD7, 'M', u'هج'),
(0xFCD8, 'M', u'هم'),
(0xFCD9, 'M', u'هٰ'),
(0xFCDA, 'M', u'يج'),
(0xFCDB, 'M', u'يح'),
(0xFCDC, 'M', u'يخ'),
(0xFCDD, 'M', u'يم'),
(0xFCDE, 'M', u'يه'),
(0xFCDF, 'M', u'ئم'),
(0xFCE0, 'M', u'ئه'),
(0xFCE1, 'M', u'بم'),
(0xFCE2, 'M', u'به'),
(0xFCE3, 'M', u'تم'),
(0xFCE4, 'M', u'ته'),
(0xFCE5, 'M', u'ثم'),
(0xFCE6, 'M', u'ثه'),
(0xFCE7, 'M', u'سم'),
(0xFCE8, 'M', u'سه'),
(0xFCE9, 'M', u'شم'),
(0xFCEA, 'M', u'شه'),
(0xFCEB, 'M', u'كل'),
(0xFCEC, 'M', u'كم'),
(0xFCED, 'M', u'لم'),
(0xFCEE, 'M', u'نم'),
]
def _seg_47():
return [
(0xFCEF, 'M', u'نه'),
(0xFCF0, 'M', u'يم'),
(0xFCF1, 'M', u'يه'),
(0xFCF2, 'M', u'ـَّ'),
(0xFCF3, 'M', u'ـُّ'),
(0xFCF4, 'M', u'ـِّ'),
(0xFCF5, 'M', u'طى'),
(0xFCF6, 'M', u'طي'),
(0xFCF7, 'M', u'عى'),
(0xFCF8, 'M', u'عي'),
(0xFCF9, 'M', u'غى'),
(0xFCFA, 'M', u'غي'),
(0xFCFB, 'M', u'سى'),
(0xFCFC, 'M', u'سي'),
(0xFCFD, 'M', u'شى'),
(0xFCFE, 'M', u'شي'),
(0xFCFF, 'M', u'حى'),
(0xFD00, 'M', u'حي'),
(0xFD01, 'M', u'جى'),
(0xFD02, 'M', u'جي'),
(0xFD03, 'M', u'خى'),
(0xFD04, 'M', u'خي'),
(0xFD05, 'M', u'صى'),
(0xFD06, 'M', u'صي'),
(0xFD07, 'M', u'ضى'),
(0xFD08, 'M', u'ضي'),
(0xFD09, 'M', u'شج'),
(0xFD0A, 'M', u'شح'),
(0xFD0B, 'M', u'شخ'),
(0xFD0C, 'M', u'شم'),
(0xFD0D, 'M', u'شر'),
(0xFD0E, 'M', u'سر'),
(0xFD0F, 'M', u'صر'),
(0xFD10, 'M', u'ضر'),
(0xFD11, 'M', u'طى'),
(0xFD12, 'M', u'طي'),
(0xFD13, 'M', u'عى'),
(0xFD14, 'M', u'عي'),
(0xFD15, 'M', u'غى'),
(0xFD16, 'M', u'غي'),
(0xFD17, 'M', u'سى'),
(0xFD18, 'M', u'سي'),
(0xFD19, 'M', u'شى'),
(0xFD1A, 'M', u'شي'),
(0xFD1B, 'M', u'حى'),
(0xFD1C, 'M', u'حي'),
(0xFD1D, 'M', u'جى'),
(0xFD1E, 'M', u'جي'),
(0xFD1F, 'M', u'خى'),
(0xFD20, 'M', u'خي'),
(0xFD21, 'M', u'صى'),
(0xFD22, 'M', u'صي'),
(0xFD23, 'M', u'ضى'),
(0xFD24, 'M', u'ضي'),
(0xFD25, 'M', u'شج'),
(0xFD26, 'M', u'شح'),
(0xFD27, 'M', u'شخ'),
(0xFD28, 'M', u'شم'),
(0xFD29, 'M', u'شر'),
(0xFD2A, 'M', u'سر'),
(0xFD2B, 'M', u'صر'),
(0xFD2C, 'M', u'ضر'),
(0xFD2D, 'M', u'شج'),
(0xFD2E, 'M', u'شح'),
(0xFD2F, 'M', u'شخ'),
(0xFD30, 'M', u'شم'),
(0xFD31, 'M', u'سه'),
(0xFD32, 'M', u'شه'),
(0xFD33, 'M', u'طم'),
(0xFD34, 'M', u'سج'),
(0xFD35, 'M', u'سح'),
(0xFD36, 'M', u'سخ'),
(0xFD37, 'M', u'شج'),
(0xFD38, 'M', u'شح'),
(0xFD39, 'M', u'شخ'),
(0xFD3A, 'M', u'طم'),
(0xFD3B, 'M', u'ظم'),
(0xFD3C, 'M', u'اً'),
(0xFD3E, 'V'),
(0xFD40, 'X'),
(0xFD50, 'M', u'تجم'),
(0xFD51, 'M', u'تحج'),
(0xFD53, 'M', u'تحم'),
(0xFD54, 'M', u'تخم'),
(0xFD55, 'M', u'تمج'),
(0xFD56, 'M', u'تمح'),
(0xFD57, 'M', u'تمخ'),
(0xFD58, 'M', u'جمح'),
(0xFD5A, 'M', u'حمي'),
(0xFD5B, 'M', u'حمى'),
(0xFD5C, 'M', u'سحج'),
(0xFD5D, 'M', u'سجح'),
(0xFD5E, 'M', u'سجى'),
(0xFD5F, 'M', u'سمح'),
(0xFD61, 'M', u'سمج'),
(0xFD62, 'M', u'سمم'),
(0xFD64, 'M', u'صحح'),
(0xFD66, 'M', u'صمم'),
(0xFD67, 'M', u'شحم'),
(0xFD69, 'M', u'شجي'),
]
def _seg_48():
return [
(0xFD6A, 'M', u'شمخ'),
(0xFD6C, 'M', u'شمم'),
(0xFD6E, 'M', u'ضحى'),
(0xFD6F, 'M', u'ضخم'),
(0xFD71, 'M', u'طمح'),
(0xFD73, 'M', u'طمم'),
(0xFD74, 'M', u'طمي'),
(0xFD75, 'M', u'عجم'),
(0xFD76, 'M', u'عمم'),
(0xFD78, 'M', u'عمى'),
(0xFD79, 'M', u'غمم'),
(0xFD7A, 'M', u'غمي'),
(0xFD7B, 'M', u'غمى'),
(0xFD7C, 'M', u'فخم'),
(0xFD7E, 'M', u'قمح'),
(0xFD7F, 'M', u'قمم'),
(0xFD80, 'M', u'لحم'),
(0xFD81, 'M', u'لحي'),
(0xFD82, 'M', u'لحى'),
(0xFD83, 'M', u'لجج'),
(0xFD85, 'M', u'لخم'),
(0xFD87, 'M', u'لمح'),
(0xFD89, 'M', u'محج'),
(0xFD8A, 'M', u'محم'),
(0xFD8B, 'M', u'محي'),
(0xFD8C, 'M', u'مجح'),
(0xFD8D, 'M', u'مجم'),
(0xFD8E, 'M', u'مخج'),
(0xFD8F, 'M', u'مخم'),
(0xFD90, 'X'),
(0xFD92, 'M', u'مجخ'),
(0xFD93, 'M', u'همج'),
(0xFD94, 'M', u'همم'),
(0xFD95, 'M', u'نحم'),
(0xFD96, 'M', u'نحى'),
(0xFD97, 'M', u'نجم'),
(0xFD99, 'M', u'نجى'),
(0xFD9A, 'M', u'نمي'),
(0xFD9B, 'M', u'نمى'),
(0xFD9C, 'M', u'يمم'),
(0xFD9E, 'M', u'بخي'),
(0xFD9F, 'M', u'تجي'),
(0xFDA0, 'M', u'تجى'),
(0xFDA1, 'M', u'تخي'),
(0xFDA2, 'M', u'تخى'),
(0xFDA3, 'M', u'تمي'),
(0xFDA4, 'M', u'تمى'),
(0xFDA5, 'M', u'جمي'),
(0xFDA6, 'M', u'جحى'),
(0xFDA7, 'M', u'جمى'),
(0xFDA8, 'M', u'سخى'),
(0xFDA9, 'M', u'صحي'),
(0xFDAA, 'M', u'شحي'),
(0xFDAB, 'M', u'ضحي'),
(0xFDAC, 'M', u'لجي'),
(0xFDAD, 'M', u'لمي'),
(0xFDAE, 'M', u'يحي'),
(0xFDAF, 'M', u'يجي'),
(0xFDB0, 'M', u'يمي'),
(0xFDB1, 'M', u'ممي'),
(0xFDB2, 'M', u'قمي'),
(0xFDB3, 'M', u'نحي'),
(0xFDB4, 'M', u'قمح'),
(0xFDB5, 'M', u'لحم'),
(0xFDB6, 'M', u'عمي'),
(0xFDB7, 'M', u'كمي'),
(0xFDB8, 'M', u'نجح'),
(0xFDB9, 'M', u'مخي'),
(0xFDBA, 'M', u'لجم'),
(0xFDBB, 'M', u'كمم'),
(0xFDBC, 'M', u'لجم'),
(0xFDBD, 'M', u'نجح'),
(0xFDBE, 'M', u'جحي'),
(0xFDBF, 'M', u'حجي'),
(0xFDC0, 'M', u'مجي'),
(0xFDC1, 'M', u'فمي'),
(0xFDC2, 'M', u'بحي'),
(0xFDC3, 'M', u'كمم'),
(0xFDC4, 'M', u'عجم'),
(0xFDC5, 'M', u'صمم'),
(0xFDC6, 'M', u'سخي'),
(0xFDC7, 'M', u'نجي'),
(0xFDC8, 'X'),
(0xFDF0, 'M', u'صلے'),
(0xFDF1, 'M', u'قلے'),
(0xFDF2, 'M', u'الله'),
(0xFDF3, 'M', u'اكبر'),
(0xFDF4, 'M', u'محمد'),
(0xFDF5, 'M', u'صلعم'),
(0xFDF6, 'M', u'رسول'),
(0xFDF7, 'M', u'عليه'),
(0xFDF8, 'M', u'وسلم'),
(0xFDF9, 'M', u'صلى'),
(0xFDFA, '3', u'صلى الله عليه وسلم'),
(0xFDFB, '3', u'جل جلاله'),
(0xFDFC, 'M', u'ریال'),
(0xFDFD, 'V'),
(0xFDFE, 'X'),
(0xFE00, 'I'),
(0xFE10, '3', u','),
]
def _seg_49():
return [
(0xFE11, 'M', u'、'),
(0xFE12, 'X'),
(0xFE13, '3', u':'),
(0xFE14, '3', u';'),
(0xFE15, '3', u'!'),
(0xFE16, '3', u'?'),
(0xFE17, 'M', u'〖'),
(0xFE18, 'M', u'〗'),
(0xFE19, 'X'),
(0xFE20, 'V'),
(0xFE30, 'X'),
(0xFE31, 'M', u'—'),
(0xFE32, 'M', u'–'),
(0xFE33, '3', u'_'),
(0xFE35, '3', u'('),
(0xFE36, '3', u')'),
(0xFE37, '3', u'{'),
(0xFE38, '3', u'}'),
(0xFE39, 'M', u'〔'),
(0xFE3A, 'M', u'〕'),
(0xFE3B, 'M', u'【'),
(0xFE3C, 'M', u'】'),
(0xFE3D, 'M', u'《'),
(0xFE3E, 'M', u'》'),
(0xFE3F, 'M', u'〈'),
(0xFE40, 'M', u'〉'),
(0xFE41, 'M', u'「'),
(0xFE42, 'M', u'」'),
(0xFE43, 'M', u'『'),
(0xFE44, 'M', u'』'),
(0xFE45, 'V'),
(0xFE47, '3', u'['),
(0xFE48, '3', u']'),
(0xFE49, '3', u' ̅'),
(0xFE4D, '3', u'_'),
(0xFE50, '3', u','),
(0xFE51, 'M', u'、'),
(0xFE52, 'X'),
(0xFE54, '3', u';'),
(0xFE55, '3', u':'),
(0xFE56, '3', u'?'),
(0xFE57, '3', u'!'),
(0xFE58, 'M', u'—'),
(0xFE59, '3', u'('),
(0xFE5A, '3', u')'),
(0xFE5B, '3', u'{'),
(0xFE5C, '3', u'}'),
(0xFE5D, 'M', u'〔'),
(0xFE5E, 'M', u'〕'),
(0xFE5F, '3', u'#'),
(0xFE60, '3', u'&'),
(0xFE61, '3', u'*'),
(0xFE62, '3', u'+'),
(0xFE63, 'M', u'-'),
(0xFE64, '3', u'<'),
(0xFE65, '3', u'>'),
(0xFE66, '3', u'='),
(0xFE67, 'X'),
(0xFE68, '3', u'\\'),
(0xFE69, '3', u'$'),
(0xFE6A, '3', u'%'),
(0xFE6B, '3', u'@'),
(0xFE6C, 'X'),
(0xFE70, '3', u' ً'),
(0xFE71, 'M', u'ـً'),
(0xFE72, '3', u' ٌ'),
(0xFE73, 'V'),
(0xFE74, '3', u' ٍ'),
(0xFE75, 'X'),
(0xFE76, '3', u' َ'),
(0xFE77, 'M', u'ـَ'),
(0xFE78, '3', u' ُ'),
(0xFE79, 'M', u'ـُ'),
(0xFE7A, '3', u' ِ'),
(0xFE7B, 'M', u'ـِ'),
(0xFE7C, '3', u' ّ'),
(0xFE7D, 'M', u'ـّ'),
(0xFE7E, '3', u' ْ'),
(0xFE7F, 'M', u'ـْ'),
(0xFE80, 'M', u'ء'),
(0xFE81, 'M', u'آ'),
(0xFE83, 'M', u'أ'),
(0xFE85, 'M', u'ؤ'),
(0xFE87, 'M', u'إ'),
(0xFE89, 'M', u'ئ'),
(0xFE8D, 'M', u'ا'),
(0xFE8F, 'M', u'ب'),
(0xFE93, 'M', u'ة'),
(0xFE95, 'M', u'ت'),
(0xFE99, 'M', u'ث'),
(0xFE9D, 'M', u'ج'),
(0xFEA1, 'M', u'ح'),
(0xFEA5, 'M', u'خ'),
(0xFEA9, 'M', u'د'),
(0xFEAB, 'M', u'ذ'),
(0xFEAD, 'M', u'ر'),
(0xFEAF, 'M', u'ز'),
(0xFEB1, 'M', u'س'),
(0xFEB5, 'M', u'ش'),
(0xFEB9, 'M', u'ص'),
]
def _seg_50():
return [
(0xFEBD, 'M', u'ض'),
(0xFEC1, 'M', u'ط'),
(0xFEC5, 'M', u'ظ'),
(0xFEC9, 'M', u'ع'),
(0xFECD, 'M', u'غ'),
(0xFED1, 'M', u'ف'),
(0xFED5, 'M', u'ق'),
(0xFED9, 'M', u'ك'),
(0xFEDD, 'M', u'ل'),
(0xFEE1, 'M', u'م'),
(0xFEE5, 'M', u'ن'),
(0xFEE9, 'M', u'ه'),
(0xFEED, 'M', u'و'),
(0xFEEF, 'M', u'ى'),
(0xFEF1, 'M', u'ي'),
(0xFEF5, 'M', u'لآ'),
(0xFEF7, 'M', u'لأ'),
(0xFEF9, 'M', u'لإ'),
(0xFEFB, 'M', u'لا'),
(0xFEFD, 'X'),
(0xFEFF, 'I'),
(0xFF00, 'X'),
(0xFF01, '3', u'!'),
(0xFF02, '3', u'"'),
(0xFF03, '3', u'#'),
(0xFF04, '3', u'$'),
(0xFF05, '3', u'%'),
(0xFF06, '3', u'&'),
(0xFF07, '3', u'\''),
(0xFF08, '3', u'('),
(0xFF09, '3', u')'),
(0xFF0A, '3', u'*'),
(0xFF0B, '3', u'+'),
(0xFF0C, '3', u','),
(0xFF0D, 'M', u'-'),
(0xFF0E, 'M', u'.'),
(0xFF0F, '3', u'/'),
(0xFF10, 'M', u'0'),
(0xFF11, 'M', u'1'),
(0xFF12, 'M', u'2'),
(0xFF13, 'M', u'3'),
(0xFF14, 'M', u'4'),
(0xFF15, 'M', u'5'),
(0xFF16, 'M', u'6'),
(0xFF17, 'M', u'7'),
(0xFF18, 'M', u'8'),
(0xFF19, 'M', u'9'),
(0xFF1A, '3', u':'),
(0xFF1B, '3', u';'),
(0xFF1C, '3', u'<'),
(0xFF1D, '3', u'='),
(0xFF1E, '3', u'>'),
(0xFF1F, '3', u'?'),
(0xFF20, '3', u'@'),
(0xFF21, 'M', u'a'),
(0xFF22, 'M', u'b'),
(0xFF23, 'M', u'c'),
(0xFF24, 'M', u'd'),
(0xFF25, 'M', u'e'),
(0xFF26, 'M', u'f'),
(0xFF27, 'M', u'g'),
(0xFF28, 'M', u'h'),
(0xFF29, 'M', u'i'),
(0xFF2A, 'M', u'j'),
(0xFF2B, 'M', u'k'),
(0xFF2C, 'M', u'l'),
(0xFF2D, 'M', u'm'),
(0xFF2E, 'M', u'n'),
(0xFF2F, 'M', u'o'),
(0xFF30, 'M', u'p'),
(0xFF31, 'M', u'q'),
(0xFF32, 'M', u'r'),
(0xFF33, 'M', u's'),
(0xFF34, 'M', u't'),
(0xFF35, 'M', u'u'),
(0xFF36, 'M', u'v'),
(0xFF37, 'M', u'w'),
(0xFF38, 'M', u'x'),
(0xFF39, 'M', u'y'),
(0xFF3A, 'M', u'z'),
(0xFF3B, '3', u'['),
(0xFF3C, '3', u'\\'),
(0xFF3D, '3', u']'),
(0xFF3E, '3', u'^'),
(0xFF3F, '3', u'_'),
(0xFF40, '3', u'`'),
(0xFF41, 'M', u'a'),
(0xFF42, 'M', u'b'),
(0xFF43, 'M', u'c'),
(0xFF44, 'M', u'd'),
(0xFF45, 'M', u'e'),
(0xFF46, 'M', u'f'),
(0xFF47, 'M', u'g'),
(0xFF48, 'M', u'h'),
(0xFF49, 'M', u'i'),
(0xFF4A, 'M', u'j'),
(0xFF4B, 'M', u'k'),
(0xFF4C, 'M', u'l'),
(0xFF4D, 'M', u'm'),
(0xFF4E, 'M', u'n'),
]
def _seg_51():
return [
(0xFF4F, 'M', u'o'),
(0xFF50, 'M', u'p'),
(0xFF51, 'M', u'q'),
(0xFF52, 'M', u'r'),
(0xFF53, 'M', u's'),
(0xFF54, 'M', u't'),
(0xFF55, 'M', u'u'),
(0xFF56, 'M', u'v'),
(0xFF57, 'M', u'w'),
(0xFF58, 'M', u'x'),
(0xFF59, 'M', u'y'),
(0xFF5A, 'M', u'z'),
(0xFF5B, '3', u'{'),
(0xFF5C, '3', u'|'),
(0xFF5D, '3', u'}'),
(0xFF5E, '3', u'~'),
(0xFF5F, 'M', u'⦅'),
(0xFF60, 'M', u'⦆'),
(0xFF61, 'M', u'.'),
(0xFF62, 'M', u'「'),
(0xFF63, 'M', u'」'),
(0xFF64, 'M', u'、'),
(0xFF65, 'M', u'・'),
(0xFF66, 'M', u'ヲ'),
(0xFF67, 'M', u'ァ'),
(0xFF68, 'M', u'ィ'),
(0xFF69, 'M', u'ゥ'),
(0xFF6A, 'M', u'ェ'),
(0xFF6B, 'M', u'ォ'),
(0xFF6C, 'M', u'ャ'),
(0xFF6D, 'M', u'ュ'),
(0xFF6E, 'M', u'ョ'),
(0xFF6F, 'M', u'ッ'),
(0xFF70, 'M', u'ー'),
(0xFF71, 'M', u'ア'),
(0xFF72, 'M', u'イ'),
(0xFF73, 'M', u'ウ'),
(0xFF74, 'M', u'エ'),
(0xFF75, 'M', u'オ'),
(0xFF76, 'M', u'カ'),
(0xFF77, 'M', u'キ'),
(0xFF78, 'M', u'ク'),
(0xFF79, 'M', u'ケ'),
(0xFF7A, 'M', u'コ'),
(0xFF7B, 'M', u'サ'),
(0xFF7C, 'M', u'シ'),
(0xFF7D, 'M', u'ス'),
(0xFF7E, 'M', u'セ'),
(0xFF7F, 'M', u'ソ'),
(0xFF80, 'M', u'タ'),
(0xFF81, 'M', u'チ'),
(0xFF82, 'M', u'ツ'),
(0xFF83, 'M', u'テ'),
(0xFF84, 'M', u'ト'),
(0xFF85, 'M', u'ナ'),
(0xFF86, 'M', u'ニ'),
(0xFF87, 'M', u'ヌ'),
(0xFF88, 'M', u'ネ'),
(0xFF89, 'M', u'ノ'),
(0xFF8A, 'M', u'ハ'),
(0xFF8B, 'M', u'ヒ'),
(0xFF8C, 'M', u'フ'),
(0xFF8D, 'M', u'ヘ'),
(0xFF8E, 'M', u'ホ'),
(0xFF8F, 'M', u'マ'),
(0xFF90, 'M', u'ミ'),
(0xFF91, 'M', u'ム'),
(0xFF92, 'M', u'メ'),
(0xFF93, 'M', u'モ'),
(0xFF94, 'M', u'ヤ'),
(0xFF95, 'M', u'ユ'),
(0xFF96, 'M', u'ヨ'),
(0xFF97, 'M', u'ラ'),
(0xFF98, 'M', u'リ'),
(0xFF99, 'M', u'ル'),
(0xFF9A, 'M', u'レ'),
(0xFF9B, 'M', u'ロ'),
(0xFF9C, 'M', u'ワ'),
(0xFF9D, 'M', u'ン'),
(0xFF9E, 'M', u'゙'),
(0xFF9F, 'M', u'゚'),
(0xFFA0, 'X'),
(0xFFA1, 'M', u'ᄀ'),
(0xFFA2, 'M', u'ᄁ'),
(0xFFA3, 'M', u'ᆪ'),
(0xFFA4, 'M', u'ᄂ'),
(0xFFA5, 'M', u'ᆬ'),
(0xFFA6, 'M', u'ᆭ'),
(0xFFA7, 'M', u'ᄃ'),
(0xFFA8, 'M', u'ᄄ'),
(0xFFA9, 'M', u'ᄅ'),
(0xFFAA, 'M', u'ᆰ'),
(0xFFAB, 'M', u'ᆱ'),
(0xFFAC, 'M', u'ᆲ'),
(0xFFAD, 'M', u'ᆳ'),
(0xFFAE, 'M', u'ᆴ'),
(0xFFAF, 'M', u'ᆵ'),
(0xFFB0, 'M', u'ᄚ'),
(0xFFB1, 'M', u'ᄆ'),
(0xFFB2, 'M', u'ᄇ'),
]
def _seg_52():
return [
(0xFFB3, 'M', u'ᄈ'),
(0xFFB4, 'M', u'ᄡ'),
(0xFFB5, 'M', u'ᄉ'),
(0xFFB6, 'M', u'ᄊ'),
(0xFFB7, 'M', u'ᄋ'),
(0xFFB8, 'M', u'ᄌ'),
(0xFFB9, 'M', u'ᄍ'),
(0xFFBA, 'M', u'ᄎ'),
(0xFFBB, 'M', u'ᄏ'),
(0xFFBC, 'M', u'ᄐ'),
(0xFFBD, 'M', u'ᄑ'),
(0xFFBE, 'M', u'ᄒ'),
(0xFFBF, 'X'),
(0xFFC2, 'M', u'ᅡ'),
(0xFFC3, 'M', u'ᅢ'),
(0xFFC4, 'M', u'ᅣ'),
(0xFFC5, 'M', u'ᅤ'),
(0xFFC6, 'M', u'ᅥ'),
(0xFFC7, 'M', u'ᅦ'),
(0xFFC8, 'X'),
(0xFFCA, 'M', u'ᅧ'),
(0xFFCB, 'M', u'ᅨ'),
(0xFFCC, 'M', u'ᅩ'),
(0xFFCD, 'M', u'ᅪ'),
(0xFFCE, 'M', u'ᅫ'),
(0xFFCF, 'M', u'ᅬ'),
(0xFFD0, 'X'),
(0xFFD2, 'M', u'ᅭ'),
(0xFFD3, 'M', u'ᅮ'),
(0xFFD4, 'M', u'ᅯ'),
(0xFFD5, 'M', u'ᅰ'),
(0xFFD6, 'M', u'ᅱ'),
(0xFFD7, 'M', u'ᅲ'),
(0xFFD8, 'X'),
(0xFFDA, 'M', u'ᅳ'),
(0xFFDB, 'M', u'ᅴ'),
(0xFFDC, 'M', u'ᅵ'),
(0xFFDD, 'X'),
(0xFFE0, 'M', u'¢'),
(0xFFE1, 'M', u'£'),
(0xFFE2, 'M', u'¬'),
(0xFFE3, '3', u' ̄'),
(0xFFE4, 'M', u'¦'),
(0xFFE5, 'M', u'¥'),
(0xFFE6, 'M', u'₩'),
(0xFFE7, 'X'),
(0xFFE8, 'M', u'│'),
(0xFFE9, 'M', u'←'),
(0xFFEA, 'M', u'↑'),
(0xFFEB, 'M', u'→'),
(0xFFEC, 'M', u'↓'),
(0xFFED, 'M', u'■'),
(0xFFEE, 'M', u'○'),
(0xFFEF, 'X'),
(0x10000, 'V'),
(0x1000C, 'X'),
(0x1000D, 'V'),
(0x10027, 'X'),
(0x10028, 'V'),
(0x1003B, 'X'),
(0x1003C, 'V'),
(0x1003E, 'X'),
(0x1003F, 'V'),
(0x1004E, 'X'),
(0x10050, 'V'),
(0x1005E, 'X'),
(0x10080, 'V'),
(0x100FB, 'X'),
(0x10100, 'V'),
(0x10103, 'X'),
(0x10107, 'V'),
(0x10134, 'X'),
(0x10137, 'V'),
(0x1018F, 'X'),
(0x10190, 'V'),
(0x1019C, 'X'),
(0x101A0, 'V'),
(0x101A1, 'X'),
(0x101D0, 'V'),
(0x101FE, 'X'),
(0x10280, 'V'),
(0x1029D, 'X'),
(0x102A0, 'V'),
(0x102D1, 'X'),
(0x102E0, 'V'),
(0x102FC, 'X'),
(0x10300, 'V'),
(0x10324, 'X'),
(0x1032D, 'V'),
(0x1034B, 'X'),
(0x10350, 'V'),
(0x1037B, 'X'),
(0x10380, 'V'),
(0x1039E, 'X'),
(0x1039F, 'V'),
(0x103C4, 'X'),
(0x103C8, 'V'),
(0x103D6, 'X'),
(0x10400, 'M', u'𐐨'),
(0x10401, 'M', u'𐐩'),
]
def _seg_53():
return [
(0x10402, 'M', u'𐐪'),
(0x10403, 'M', u'𐐫'),
(0x10404, 'M', u'𐐬'),
(0x10405, 'M', u'𐐭'),
(0x10406, 'M', u'𐐮'),
(0x10407, 'M', u'𐐯'),
(0x10408, 'M', u'𐐰'),
(0x10409, 'M', u'𐐱'),
(0x1040A, 'M', u'𐐲'),
(0x1040B, 'M', u'𐐳'),
(0x1040C, 'M', u'𐐴'),
(0x1040D, 'M', u'𐐵'),
(0x1040E, 'M', u'𐐶'),
(0x1040F, 'M', u'𐐷'),
(0x10410, 'M', u'𐐸'),
(0x10411, 'M', u'𐐹'),
(0x10412, 'M', u'𐐺'),
(0x10413, 'M', u'𐐻'),
(0x10414, 'M', u'𐐼'),
(0x10415, 'M', u'𐐽'),
(0x10416, 'M', u'𐐾'),
(0x10417, 'M', u'𐐿'),
(0x10418, 'M', u'𐑀'),
(0x10419, 'M', u'𐑁'),
(0x1041A, 'M', u'𐑂'),
(0x1041B, 'M', u'𐑃'),
(0x1041C, 'M', u'𐑄'),
(0x1041D, 'M', u'𐑅'),
(0x1041E, 'M', u'𐑆'),
(0x1041F, 'M', u'𐑇'),
(0x10420, 'M', u'𐑈'),
(0x10421, 'M', u'𐑉'),
(0x10422, 'M', u'𐑊'),
(0x10423, 'M', u'𐑋'),
(0x10424, 'M', u'𐑌'),
(0x10425, 'M', u'𐑍'),
(0x10426, 'M', u'𐑎'),
(0x10427, 'M', u'𐑏'),
(0x10428, 'V'),
(0x1049E, 'X'),
(0x104A0, 'V'),
(0x104AA, 'X'),
(0x104B0, 'M', u'𐓘'),
(0x104B1, 'M', u'𐓙'),
(0x104B2, 'M', u'𐓚'),
(0x104B3, 'M', u'𐓛'),
(0x104B4, 'M', u'𐓜'),
(0x104B5, 'M', u'𐓝'),
(0x104B6, 'M', u'𐓞'),
(0x104B7, 'M', u'𐓟'),
(0x104B8, 'M', u'𐓠'),
(0x104B9, 'M', u'𐓡'),
(0x104BA, 'M', u'𐓢'),
(0x104BB, 'M', u'𐓣'),
(0x104BC, 'M', u'𐓤'),
(0x104BD, 'M', u'𐓥'),
(0x104BE, 'M', u'𐓦'),
(0x104BF, 'M', u'𐓧'),
(0x104C0, 'M', u'𐓨'),
(0x104C1, 'M', u'𐓩'),
(0x104C2, 'M', u'𐓪'),
(0x104C3, 'M', u'𐓫'),
(0x104C4, 'M', u'𐓬'),
(0x104C5, 'M', u'𐓭'),
(0x104C6, 'M', u'𐓮'),
(0x104C7, 'M', u'𐓯'),
(0x104C8, 'M', u'𐓰'),
(0x104C9, 'M', u'𐓱'),
(0x104CA, 'M', u'𐓲'),
(0x104CB, 'M', u'𐓳'),
(0x104CC, 'M', u'𐓴'),
(0x104CD, 'M', u'𐓵'),
(0x104CE, 'M', u'𐓶'),
(0x104CF, 'M', u'𐓷'),
(0x104D0, 'M', u'𐓸'),
(0x104D1, 'M', u'𐓹'),
(0x104D2, 'M', u'𐓺'),
(0x104D3, 'M', u'𐓻'),
(0x104D4, 'X'),
(0x104D8, 'V'),
(0x104FC, 'X'),
(0x10500, 'V'),
(0x10528, 'X'),
(0x10530, 'V'),
(0x10564, 'X'),
(0x1056F, 'V'),
(0x10570, 'X'),
(0x10600, 'V'),
(0x10737, 'X'),
(0x10740, 'V'),
(0x10756, 'X'),
(0x10760, 'V'),
(0x10768, 'X'),
(0x10800, 'V'),
(0x10806, 'X'),
(0x10808, 'V'),
(0x10809, 'X'),
(0x1080A, 'V'),
(0x10836, 'X'),
(0x10837, 'V'),
]
def _seg_54():
return [
(0x10839, 'X'),
(0x1083C, 'V'),
(0x1083D, 'X'),
(0x1083F, 'V'),
(0x10856, 'X'),
(0x10857, 'V'),
(0x1089F, 'X'),
(0x108A7, 'V'),
(0x108B0, 'X'),
(0x108E0, 'V'),
(0x108F3, 'X'),
(0x108F4, 'V'),
(0x108F6, 'X'),
(0x108FB, 'V'),
(0x1091C, 'X'),
(0x1091F, 'V'),
(0x1093A, 'X'),
(0x1093F, 'V'),
(0x10940, 'X'),
(0x10980, 'V'),
(0x109B8, 'X'),
(0x109BC, 'V'),
(0x109D0, 'X'),
(0x109D2, 'V'),
(0x10A04, 'X'),
(0x10A05, 'V'),
(0x10A07, 'X'),
(0x10A0C, 'V'),
(0x10A14, 'X'),
(0x10A15, 'V'),
(0x10A18, 'X'),
(0x10A19, 'V'),
(0x10A36, 'X'),
(0x10A38, 'V'),
(0x10A3B, 'X'),
(0x10A3F, 'V'),
(0x10A49, 'X'),
(0x10A50, 'V'),
(0x10A59, 'X'),
(0x10A60, 'V'),
(0x10AA0, 'X'),
(0x10AC0, 'V'),
(0x10AE7, 'X'),
(0x10AEB, 'V'),
(0x10AF7, 'X'),
(0x10B00, 'V'),
(0x10B36, 'X'),
(0x10B39, 'V'),
(0x10B56, 'X'),
(0x10B58, 'V'),
(0x10B73, 'X'),
(0x10B78, 'V'),
(0x10B92, 'X'),
(0x10B99, 'V'),
(0x10B9D, 'X'),
(0x10BA9, 'V'),
(0x10BB0, 'X'),
(0x10C00, 'V'),
(0x10C49, 'X'),
(0x10C80, 'M', u'𐳀'),
(0x10C81, 'M', u'𐳁'),
(0x10C82, 'M', u'𐳂'),
(0x10C83, 'M', u'𐳃'),
(0x10C84, 'M', u'𐳄'),
(0x10C85, 'M', u'𐳅'),
(0x10C86, 'M', u'𐳆'),
(0x10C87, 'M', u'𐳇'),
(0x10C88, 'M', u'𐳈'),
(0x10C89, 'M', u'𐳉'),
(0x10C8A, 'M', u'𐳊'),
(0x10C8B, 'M', u'𐳋'),
(0x10C8C, 'M', u'𐳌'),
(0x10C8D, 'M', u'𐳍'),
(0x10C8E, 'M', u'𐳎'),
(0x10C8F, 'M', u'𐳏'),
(0x10C90, 'M', u'𐳐'),
(0x10C91, 'M', u'𐳑'),
(0x10C92, 'M', u'𐳒'),
(0x10C93, 'M', u'𐳓'),
(0x10C94, 'M', u'𐳔'),
(0x10C95, 'M', u'𐳕'),
(0x10C96, 'M', u'𐳖'),
(0x10C97, 'M', u'𐳗'),
(0x10C98, 'M', u'𐳘'),
(0x10C99, 'M', u'𐳙'),
(0x10C9A, 'M', u'𐳚'),
(0x10C9B, 'M', u'𐳛'),
(0x10C9C, 'M', u'𐳜'),
(0x10C9D, 'M', u'𐳝'),
(0x10C9E, 'M', u'𐳞'),
(0x10C9F, 'M', u'𐳟'),
(0x10CA0, 'M', u'𐳠'),
(0x10CA1, 'M', u'𐳡'),
(0x10CA2, 'M', u'𐳢'),
(0x10CA3, 'M', u'𐳣'),
(0x10CA4, 'M', u'𐳤'),
(0x10CA5, 'M', u'𐳥'),
(0x10CA6, 'M', u'𐳦'),
(0x10CA7, 'M', u'𐳧'),
(0x10CA8, 'M', u'𐳨'),
]
def _seg_55():
return [
(0x10CA9, 'M', u'𐳩'),
(0x10CAA, 'M', u'𐳪'),
(0x10CAB, 'M', u'𐳫'),
(0x10CAC, 'M', u'𐳬'),
(0x10CAD, 'M', u'𐳭'),
(0x10CAE, 'M', u'𐳮'),
(0x10CAF, 'M', u'𐳯'),
(0x10CB0, 'M', u'𐳰'),
(0x10CB1, 'M', u'𐳱'),
(0x10CB2, 'M', u'𐳲'),
(0x10CB3, 'X'),
(0x10CC0, 'V'),
(0x10CF3, 'X'),
(0x10CFA, 'V'),
(0x10D28, 'X'),
(0x10D30, 'V'),
(0x10D3A, 'X'),
(0x10E60, 'V'),
(0x10E7F, 'X'),
(0x10F00, 'V'),
(0x10F28, 'X'),
(0x10F30, 'V'),
(0x10F5A, 'X'),
(0x11000, 'V'),
(0x1104E, 'X'),
(0x11052, 'V'),
(0x11070, 'X'),
(0x1107F, 'V'),
(0x110BD, 'X'),
(0x110BE, 'V'),
(0x110C2, 'X'),
(0x110D0, 'V'),
(0x110E9, 'X'),
(0x110F0, 'V'),
(0x110FA, 'X'),
(0x11100, 'V'),
(0x11135, 'X'),
(0x11136, 'V'),
(0x11147, 'X'),
(0x11150, 'V'),
(0x11177, 'X'),
(0x11180, 'V'),
(0x111CE, 'X'),
(0x111D0, 'V'),
(0x111E0, 'X'),
(0x111E1, 'V'),
(0x111F5, 'X'),
(0x11200, 'V'),
(0x11212, 'X'),
(0x11213, 'V'),
(0x1123F, 'X'),
(0x11280, 'V'),
(0x11287, 'X'),
(0x11288, 'V'),
(0x11289, 'X'),
(0x1128A, 'V'),
(0x1128E, 'X'),
(0x1128F, 'V'),
(0x1129E, 'X'),
(0x1129F, 'V'),
(0x112AA, 'X'),
(0x112B0, 'V'),
(0x112EB, 'X'),
(0x112F0, 'V'),
(0x112FA, 'X'),
(0x11300, 'V'),
(0x11304, 'X'),
(0x11305, 'V'),
(0x1130D, 'X'),
(0x1130F, 'V'),
(0x11311, 'X'),
(0x11313, 'V'),
(0x11329, 'X'),
(0x1132A, 'V'),
(0x11331, 'X'),
(0x11332, 'V'),
(0x11334, 'X'),
(0x11335, 'V'),
(0x1133A, 'X'),
(0x1133B, 'V'),
(0x11345, 'X'),
(0x11347, 'V'),
(0x11349, 'X'),
(0x1134B, 'V'),
(0x1134E, 'X'),
(0x11350, 'V'),
(0x11351, 'X'),
(0x11357, 'V'),
(0x11358, 'X'),
(0x1135D, 'V'),
(0x11364, 'X'),
(0x11366, 'V'),
(0x1136D, 'X'),
(0x11370, 'V'),
(0x11375, 'X'),
(0x11400, 'V'),
(0x1145A, 'X'),
(0x1145B, 'V'),
(0x1145C, 'X'),
(0x1145D, 'V'),
]
def _seg_56():
return [
(0x1145F, 'X'),
(0x11480, 'V'),
(0x114C8, 'X'),
(0x114D0, 'V'),
(0x114DA, 'X'),
(0x11580, 'V'),
(0x115B6, 'X'),
(0x115B8, 'V'),
(0x115DE, 'X'),
(0x11600, 'V'),
(0x11645, 'X'),
(0x11650, 'V'),
(0x1165A, 'X'),
(0x11660, 'V'),
(0x1166D, 'X'),
(0x11680, 'V'),
(0x116B8, 'X'),
(0x116C0, 'V'),
(0x116CA, 'X'),
(0x11700, 'V'),
(0x1171B, 'X'),
(0x1171D, 'V'),
(0x1172C, 'X'),
(0x11730, 'V'),
(0x11740, 'X'),
(0x11800, 'V'),
(0x1183C, 'X'),
(0x118A0, 'M', u'𑣀'),
(0x118A1, 'M', u'𑣁'),
(0x118A2, 'M', u'𑣂'),
(0x118A3, 'M', u'𑣃'),
(0x118A4, 'M', u'𑣄'),
(0x118A5, 'M', u'𑣅'),
(0x118A6, 'M', u'𑣆'),
(0x118A7, 'M', u'𑣇'),
(0x118A8, 'M', u'𑣈'),
(0x118A9, 'M', u'𑣉'),
(0x118AA, 'M', u'𑣊'),
(0x118AB, 'M', u'𑣋'),
(0x118AC, 'M', u'𑣌'),
(0x118AD, 'M', u'𑣍'),
(0x118AE, 'M', u'𑣎'),
(0x118AF, 'M', u'𑣏'),
(0x118B0, 'M', u'𑣐'),
(0x118B1, 'M', u'𑣑'),
(0x118B2, 'M', u'𑣒'),
(0x118B3, 'M', u'𑣓'),
(0x118B4, 'M', u'𑣔'),
(0x118B5, 'M', u'𑣕'),
(0x118B6, 'M', u'𑣖'),
(0x118B7, 'M', u'𑣗'),
(0x118B8, 'M', u'𑣘'),
(0x118B9, 'M', u'𑣙'),
(0x118BA, 'M', u'𑣚'),
(0x118BB, 'M', u'𑣛'),
(0x118BC, 'M', u'𑣜'),
(0x118BD, 'M', u'𑣝'),
(0x118BE, 'M', u'𑣞'),
(0x118BF, 'M', u'𑣟'),
(0x118C0, 'V'),
(0x118F3, 'X'),
(0x118FF, 'V'),
(0x11900, 'X'),
(0x11A00, 'V'),
(0x11A48, 'X'),
(0x11A50, 'V'),
(0x11A84, 'X'),
(0x11A86, 'V'),
(0x11AA3, 'X'),
(0x11AC0, 'V'),
(0x11AF9, 'X'),
(0x11C00, 'V'),
(0x11C09, 'X'),
(0x11C0A, 'V'),
(0x11C37, 'X'),
(0x11C38, 'V'),
(0x11C46, 'X'),
(0x11C50, 'V'),
(0x11C6D, 'X'),
(0x11C70, 'V'),
(0x11C90, 'X'),
(0x11C92, 'V'),
(0x11CA8, 'X'),
(0x11CA9, 'V'),
(0x11CB7, 'X'),
(0x11D00, 'V'),
(0x11D07, 'X'),
(0x11D08, 'V'),
(0x11D0A, 'X'),
(0x11D0B, 'V'),
(0x11D37, 'X'),
(0x11D3A, 'V'),
(0x11D3B, 'X'),
(0x11D3C, 'V'),
(0x11D3E, 'X'),
(0x11D3F, 'V'),
(0x11D48, 'X'),
(0x11D50, 'V'),
(0x11D5A, 'X'),
(0x11D60, 'V'),
]
def _seg_57():
return [
(0x11D66, 'X'),
(0x11D67, 'V'),
(0x11D69, 'X'),
(0x11D6A, 'V'),
(0x11D8F, 'X'),
(0x11D90, 'V'),
(0x11D92, 'X'),
(0x11D93, 'V'),
(0x11D99, 'X'),
(0x11DA0, 'V'),
(0x11DAA, 'X'),
(0x11EE0, 'V'),
(0x11EF9, 'X'),
(0x12000, 'V'),
(0x1239A, 'X'),
(0x12400, 'V'),
(0x1246F, 'X'),
(0x12470, 'V'),
(0x12475, 'X'),
(0x12480, 'V'),
(0x12544, 'X'),
(0x13000, 'V'),
(0x1342F, 'X'),
(0x14400, 'V'),
(0x14647, 'X'),
(0x16800, 'V'),
(0x16A39, 'X'),
(0x16A40, 'V'),
(0x16A5F, 'X'),
(0x16A60, 'V'),
(0x16A6A, 'X'),
(0x16A6E, 'V'),
(0x16A70, 'X'),
(0x16AD0, 'V'),
(0x16AEE, 'X'),
(0x16AF0, 'V'),
(0x16AF6, 'X'),
(0x16B00, 'V'),
(0x16B46, 'X'),
(0x16B50, 'V'),
(0x16B5A, 'X'),
(0x16B5B, 'V'),
(0x16B62, 'X'),
(0x16B63, 'V'),
(0x16B78, 'X'),
(0x16B7D, 'V'),
(0x16B90, 'X'),
(0x16E60, 'V'),
(0x16E9B, 'X'),
(0x16F00, 'V'),
(0x16F45, 'X'),
(0x16F50, 'V'),
(0x16F7F, 'X'),
(0x16F8F, 'V'),
(0x16FA0, 'X'),
(0x16FE0, 'V'),
(0x16FE2, 'X'),
(0x17000, 'V'),
(0x187F2, 'X'),
(0x18800, 'V'),
(0x18AF3, 'X'),
(0x1B000, 'V'),
(0x1B11F, 'X'),
(0x1B170, 'V'),
(0x1B2FC, 'X'),
(0x1BC00, 'V'),
(0x1BC6B, 'X'),
(0x1BC70, 'V'),
(0x1BC7D, 'X'),
(0x1BC80, 'V'),
(0x1BC89, 'X'),
(0x1BC90, 'V'),
(0x1BC9A, 'X'),
(0x1BC9C, 'V'),
(0x1BCA0, 'I'),
(0x1BCA4, 'X'),
(0x1D000, 'V'),
(0x1D0F6, 'X'),
(0x1D100, 'V'),
(0x1D127, 'X'),
(0x1D129, 'V'),
(0x1D15E, 'M', u'𝅗𝅥'),
(0x1D15F, 'M', u'𝅘𝅥'),
(0x1D160, 'M', u'𝅘𝅥𝅮'),
(0x1D161, 'M', u'𝅘𝅥𝅯'),
(0x1D162, 'M', u'𝅘𝅥𝅰'),
(0x1D163, 'M', u'𝅘𝅥𝅱'),
(0x1D164, 'M', u'𝅘𝅥𝅲'),
(0x1D165, 'V'),
(0x1D173, 'X'),
(0x1D17B, 'V'),
(0x1D1BB, 'M', u'𝆹𝅥'),
(0x1D1BC, 'M', u'𝆺𝅥'),
(0x1D1BD, 'M', u'𝆹𝅥𝅮'),
(0x1D1BE, 'M', u'𝆺𝅥𝅮'),
(0x1D1BF, 'M', u'𝆹𝅥𝅯'),
(0x1D1C0, 'M', u'𝆺𝅥𝅯'),
(0x1D1C1, 'V'),
(0x1D1E9, 'X'),
(0x1D200, 'V'),
]
def _seg_58():
return [
(0x1D246, 'X'),
(0x1D2E0, 'V'),
(0x1D2F4, 'X'),
(0x1D300, 'V'),
(0x1D357, 'X'),
(0x1D360, 'V'),
(0x1D379, 'X'),
(0x1D400, 'M', u'a'),
(0x1D401, 'M', u'b'),
(0x1D402, 'M', u'c'),
(0x1D403, 'M', u'd'),
(0x1D404, 'M', u'e'),
(0x1D405, 'M', u'f'),
(0x1D406, 'M', u'g'),
(0x1D407, 'M', u'h'),
(0x1D408, 'M', u'i'),
(0x1D409, 'M', u'j'),
(0x1D40A, 'M', u'k'),
(0x1D40B, 'M', u'l'),
(0x1D40C, 'M', u'm'),
(0x1D40D, 'M', u'n'),
(0x1D40E, 'M', u'o'),
(0x1D40F, 'M', u'p'),
(0x1D410, 'M', u'q'),
(0x1D411, 'M', u'r'),
(0x1D412, 'M', u's'),
(0x1D413, 'M', u't'),
(0x1D414, 'M', u'u'),
(0x1D415, 'M', u'v'),
(0x1D416, 'M', u'w'),
(0x1D417, 'M', u'x'),
(0x1D418, 'M', u'y'),
(0x1D419, 'M', u'z'),
(0x1D41A, 'M', u'a'),
(0x1D41B, 'M', u'b'),
(0x1D41C, 'M', u'c'),
(0x1D41D, 'M', u'd'),
(0x1D41E, 'M', u'e'),
(0x1D41F, 'M', u'f'),
(0x1D420, 'M', u'g'),
(0x1D421, 'M', u'h'),
(0x1D422, 'M', u'i'),
(0x1D423, 'M', u'j'),
(0x1D424, 'M', u'k'),
(0x1D425, 'M', u'l'),
(0x1D426, 'M', u'm'),
(0x1D427, 'M', u'n'),
(0x1D428, 'M', u'o'),
(0x1D429, 'M', u'p'),
(0x1D42A, 'M', u'q'),
(0x1D42B, 'M', u'r'),
(0x1D42C, 'M', u's'),
(0x1D42D, 'M', u't'),
(0x1D42E, 'M', u'u'),
(0x1D42F, 'M', u'v'),
(0x1D430, 'M', u'w'),
(0x1D431, 'M', u'x'),
(0x1D432, 'M', u'y'),
(0x1D433, 'M', u'z'),
(0x1D434, 'M', u'a'),
(0x1D435, 'M', u'b'),
(0x1D436, 'M', u'c'),
(0x1D437, 'M', u'd'),
(0x1D438, 'M', u'e'),
(0x1D439, 'M', u'f'),
(0x1D43A, 'M', u'g'),
(0x1D43B, 'M', u'h'),
(0x1D43C, 'M', u'i'),
(0x1D43D, 'M', u'j'),
(0x1D43E, 'M', u'k'),
(0x1D43F, 'M', u'l'),
(0x1D440, 'M', u'm'),
(0x1D441, 'M', u'n'),
(0x1D442, 'M', u'o'),
(0x1D443, 'M', u'p'),
(0x1D444, 'M', u'q'),
(0x1D445, 'M', u'r'),
(0x1D446, 'M', u's'),
(0x1D447, 'M', u't'),
(0x1D448, 'M', u'u'),
(0x1D449, 'M', u'v'),
(0x1D44A, 'M', u'w'),
(0x1D44B, 'M', u'x'),
(0x1D44C, 'M', u'y'),
(0x1D44D, 'M', u'z'),
(0x1D44E, 'M', u'a'),
(0x1D44F, 'M', u'b'),
(0x1D450, 'M', u'c'),
(0x1D451, 'M', u'd'),
(0x1D452, 'M', u'e'),
(0x1D453, 'M', u'f'),
(0x1D454, 'M', u'g'),
(0x1D455, 'X'),
(0x1D456, 'M', u'i'),
(0x1D457, 'M', u'j'),
(0x1D458, 'M', u'k'),
(0x1D459, 'M', u'l'),
(0x1D45A, 'M', u'm'),
(0x1D45B, 'M', u'n'),
(0x1D45C, 'M', u'o'),
]
def _seg_59():
return [
(0x1D45D, 'M', u'p'),
(0x1D45E, 'M', u'q'),
(0x1D45F, 'M', u'r'),
(0x1D460, 'M', u's'),
(0x1D461, 'M', u't'),
(0x1D462, 'M', u'u'),
(0x1D463, 'M', u'v'),
(0x1D464, 'M', u'w'),
(0x1D465, 'M', u'x'),
(0x1D466, 'M', u'y'),
(0x1D467, 'M', u'z'),
(0x1D468, 'M', u'a'),
(0x1D469, 'M', u'b'),
(0x1D46A, 'M', u'c'),
(0x1D46B, 'M', u'd'),
(0x1D46C, 'M', u'e'),
(0x1D46D, 'M', u'f'),
(0x1D46E, 'M', u'g'),
(0x1D46F, 'M', u'h'),
(0x1D470, 'M', u'i'),
(0x1D471, 'M', u'j'),
(0x1D472, 'M', u'k'),
(0x1D473, 'M', u'l'),
(0x1D474, 'M', u'm'),
(0x1D475, 'M', u'n'),
(0x1D476, 'M', u'o'),
(0x1D477, 'M', u'p'),
(0x1D478, 'M', u'q'),
(0x1D479, 'M', u'r'),
(0x1D47A, 'M', u's'),
(0x1D47B, 'M', u't'),
(0x1D47C, 'M', u'u'),
(0x1D47D, 'M', u'v'),
(0x1D47E, 'M', u'w'),
(0x1D47F, 'M', u'x'),
(0x1D480, 'M', u'y'),
(0x1D481, 'M', u'z'),
(0x1D482, 'M', u'a'),
(0x1D483, 'M', u'b'),
(0x1D484, 'M', u'c'),
(0x1D485, 'M', u'd'),
(0x1D486, 'M', u'e'),
(0x1D487, 'M', u'f'),
(0x1D488, 'M', u'g'),
(0x1D489, 'M', u'h'),
(0x1D48A, 'M', u'i'),
(0x1D48B, 'M', u'j'),
(0x1D48C, 'M', u'k'),
(0x1D48D, 'M', u'l'),
(0x1D48E, 'M', u'm'),
(0x1D48F, 'M', u'n'),
(0x1D490, 'M', u'o'),
(0x1D491, 'M', u'p'),
(0x1D492, 'M', u'q'),
(0x1D493, 'M', u'r'),
(0x1D494, 'M', u's'),
(0x1D495, 'M', u't'),
(0x1D496, 'M', u'u'),
(0x1D497, 'M', u'v'),
(0x1D498, 'M', u'w'),
(0x1D499, 'M', u'x'),
(0x1D49A, 'M', u'y'),
(0x1D49B, 'M', u'z'),
(0x1D49C, 'M', u'a'),
(0x1D49D, 'X'),
(0x1D49E, 'M', u'c'),
(0x1D49F, 'M', u'd'),
(0x1D4A0, 'X'),
(0x1D4A2, 'M', u'g'),
(0x1D4A3, 'X'),
(0x1D4A5, 'M', u'j'),
(0x1D4A6, 'M', u'k'),
(0x1D4A7, 'X'),
(0x1D4A9, 'M', u'n'),
(0x1D4AA, 'M', u'o'),
(0x1D4AB, 'M', u'p'),
(0x1D4AC, 'M', u'q'),
(0x1D4AD, 'X'),
(0x1D4AE, 'M', u's'),
(0x1D4AF, 'M', u't'),
(0x1D4B0, 'M', u'u'),
(0x1D4B1, 'M', u'v'),
(0x1D4B2, 'M', u'w'),
(0x1D4B3, 'M', u'x'),
(0x1D4B4, 'M', u'y'),
(0x1D4B5, 'M', u'z'),
(0x1D4B6, 'M', u'a'),
(0x1D4B7, 'M', u'b'),
(0x1D4B8, 'M', u'c'),
(0x1D4B9, 'M', u'd'),
(0x1D4BA, 'X'),
(0x1D4BB, 'M', u'f'),
(0x1D4BC, 'X'),
(0x1D4BD, 'M', u'h'),
(0x1D4BE, 'M', u'i'),
(0x1D4BF, 'M', u'j'),
(0x1D4C0, 'M', u'k'),
(0x1D4C1, 'M', u'l'),
(0x1D4C2, 'M', u'm'),
(0x1D4C3, 'M', u'n'),
]
def _seg_60():
return [
(0x1D4C4, 'X'),
(0x1D4C5, 'M', u'p'),
(0x1D4C6, 'M', u'q'),
(0x1D4C7, 'M', u'r'),
(0x1D4C8, 'M', u's'),
(0x1D4C9, 'M', u't'),
(0x1D4CA, 'M', u'u'),
(0x1D4CB, 'M', u'v'),
(0x1D4CC, 'M', u'w'),
(0x1D4CD, 'M', u'x'),
(0x1D4CE, 'M', u'y'),
(0x1D4CF, 'M', u'z'),
(0x1D4D0, 'M', u'a'),
(0x1D4D1, 'M', u'b'),
(0x1D4D2, 'M', u'c'),
(0x1D4D3, 'M', u'd'),
(0x1D4D4, 'M', u'e'),
(0x1D4D5, 'M', u'f'),
(0x1D4D6, 'M', u'g'),
(0x1D4D7, 'M', u'h'),
(0x1D4D8, 'M', u'i'),
(0x1D4D9, 'M', u'j'),
(0x1D4DA, 'M', u'k'),
(0x1D4DB, 'M', u'l'),
(0x1D4DC, 'M', u'm'),
(0x1D4DD, 'M', u'n'),
(0x1D4DE, 'M', u'o'),
(0x1D4DF, 'M', u'p'),
(0x1D4E0, 'M', u'q'),
(0x1D4E1, 'M', u'r'),
(0x1D4E2, 'M', u's'),
(0x1D4E3, 'M', u't'),
(0x1D4E4, 'M', u'u'),
(0x1D4E5, 'M', u'v'),
(0x1D4E6, 'M', u'w'),
(0x1D4E7, 'M', u'x'),
(0x1D4E8, 'M', u'y'),
(0x1D4E9, 'M', u'z'),
(0x1D4EA, 'M', u'a'),
(0x1D4EB, 'M', u'b'),
(0x1D4EC, 'M', u'c'),
(0x1D4ED, 'M', u'd'),
(0x1D4EE, 'M', u'e'),
(0x1D4EF, 'M', u'f'),
(0x1D4F0, 'M', u'g'),
(0x1D4F1, 'M', u'h'),
(0x1D4F2, 'M', u'i'),
(0x1D4F3, 'M', u'j'),
(0x1D4F4, 'M', u'k'),
(0x1D4F5, 'M', u'l'),
(0x1D4F6, 'M', u'm'),
(0x1D4F7, 'M', u'n'),
(0x1D4F8, 'M', u'o'),
(0x1D4F9, 'M', u'p'),
(0x1D4FA, 'M', u'q'),
(0x1D4FB, 'M', u'r'),
(0x1D4FC, 'M', u's'),
(0x1D4FD, 'M', u't'),
(0x1D4FE, 'M', u'u'),
(0x1D4FF, 'M', u'v'),
(0x1D500, 'M', u'w'),
(0x1D501, 'M', u'x'),
(0x1D502, 'M', u'y'),
(0x1D503, 'M', u'z'),
(0x1D504, 'M', u'a'),
(0x1D505, 'M', u'b'),
(0x1D506, 'X'),
(0x1D507, 'M', u'd'),
(0x1D508, 'M', u'e'),
(0x1D509, 'M', u'f'),
(0x1D50A, 'M', u'g'),
(0x1D50B, 'X'),
(0x1D50D, 'M', u'j'),
(0x1D50E, 'M', u'k'),
(0x1D50F, 'M', u'l'),
(0x1D510, 'M', u'm'),
(0x1D511, 'M', u'n'),
(0x1D512, 'M', u'o'),
(0x1D513, 'M', u'p'),
(0x1D514, 'M', u'q'),
(0x1D515, 'X'),
(0x1D516, 'M', u's'),
(0x1D517, 'M', u't'),
(0x1D518, 'M', u'u'),
(0x1D519, 'M', u'v'),
(0x1D51A, 'M', u'w'),
(0x1D51B, 'M', u'x'),
(0x1D51C, 'M', u'y'),
(0x1D51D, 'X'),
(0x1D51E, 'M', u'a'),
(0x1D51F, 'M', u'b'),
(0x1D520, 'M', u'c'),
(0x1D521, 'M', u'd'),
(0x1D522, 'M', u'e'),
(0x1D523, 'M', u'f'),
(0x1D524, 'M', u'g'),
(0x1D525, 'M', u'h'),
(0x1D526, 'M', u'i'),
(0x1D527, 'M', u'j'),
(0x1D528, 'M', u'k'),
]
def _seg_61():
return [
(0x1D529, 'M', u'l'),
(0x1D52A, 'M', u'm'),
(0x1D52B, 'M', u'n'),
(0x1D52C, 'M', u'o'),
(0x1D52D, 'M', u'p'),
(0x1D52E, 'M', u'q'),
(0x1D52F, 'M', u'r'),
(0x1D530, 'M', u's'),
(0x1D531, 'M', u't'),
(0x1D532, 'M', u'u'),
(0x1D533, 'M', u'v'),
(0x1D534, 'M', u'w'),
(0x1D535, 'M', u'x'),
(0x1D536, 'M', u'y'),
(0x1D537, 'M', u'z'),
(0x1D538, 'M', u'a'),
(0x1D539, 'M', u'b'),
(0x1D53A, 'X'),
(0x1D53B, 'M', u'd'),
(0x1D53C, 'M', u'e'),
(0x1D53D, 'M', u'f'),
(0x1D53E, 'M', u'g'),
(0x1D53F, 'X'),
(0x1D540, 'M', u'i'),
(0x1D541, 'M', u'j'),
(0x1D542, 'M', u'k'),
(0x1D543, 'M', u'l'),
(0x1D544, 'M', u'm'),
(0x1D545, 'X'),
(0x1D546, 'M', u'o'),
(0x1D547, 'X'),
(0x1D54A, 'M', u's'),
(0x1D54B, 'M', u't'),
(0x1D54C, 'M', u'u'),
(0x1D54D, 'M', u'v'),
(0x1D54E, 'M', u'w'),
(0x1D54F, 'M', u'x'),
(0x1D550, 'M', u'y'),
(0x1D551, 'X'),
(0x1D552, 'M', u'a'),
(0x1D553, 'M', u'b'),
(0x1D554, 'M', u'c'),
(0x1D555, 'M', u'd'),
(0x1D556, 'M', u'e'),
(0x1D557, 'M', u'f'),
(0x1D558, 'M', u'g'),
(0x1D559, 'M', u'h'),
(0x1D55A, 'M', u'i'),
(0x1D55B, 'M', u'j'),
(0x1D55C, 'M', u'k'),
(0x1D55D, 'M', u'l'),
(0x1D55E, 'M', u'm'),
(0x1D55F, 'M', u'n'),
(0x1D560, 'M', u'o'),
(0x1D561, 'M', u'p'),
(0x1D562, 'M', u'q'),
(0x1D563, 'M', u'r'),
(0x1D564, 'M', u's'),
(0x1D565, 'M', u't'),
(0x1D566, 'M', u'u'),
(0x1D567, 'M', u'v'),
(0x1D568, 'M', u'w'),
(0x1D569, 'M', u'x'),
(0x1D56A, 'M', u'y'),
(0x1D56B, 'M', u'z'),
(0x1D56C, 'M', u'a'),
(0x1D56D, 'M', u'b'),
(0x1D56E, 'M', u'c'),
(0x1D56F, 'M', u'd'),
(0x1D570, 'M', u'e'),
(0x1D571, 'M', u'f'),
(0x1D572, 'M', u'g'),
(0x1D573, 'M', u'h'),
(0x1D574, 'M', u'i'),
(0x1D575, 'M', u'j'),
(0x1D576, 'M', u'k'),
(0x1D577, 'M', u'l'),
(0x1D578, 'M', u'm'),
(0x1D579, 'M', u'n'),
(0x1D57A, 'M', u'o'),
(0x1D57B, 'M', u'p'),
(0x1D57C, 'M', u'q'),
(0x1D57D, 'M', u'r'),
(0x1D57E, 'M', u's'),
(0x1D57F, 'M', u't'),
(0x1D580, 'M', u'u'),
(0x1D581, 'M', u'v'),
(0x1D582, 'M', u'w'),
(0x1D583, 'M', u'x'),
(0x1D584, 'M', u'y'),
(0x1D585, 'M', u'z'),
(0x1D586, 'M', u'a'),
(0x1D587, 'M', u'b'),
(0x1D588, 'M', u'c'),
(0x1D589, 'M', u'd'),
(0x1D58A, 'M', u'e'),
(0x1D58B, 'M', u'f'),
(0x1D58C, 'M', u'g'),
(0x1D58D, 'M', u'h'),
(0x1D58E, 'M', u'i'),
]
def _seg_62():
return [
(0x1D58F, 'M', u'j'),
(0x1D590, 'M', u'k'),
(0x1D591, 'M', u'l'),
(0x1D592, 'M', u'm'),
(0x1D593, 'M', u'n'),
(0x1D594, 'M', u'o'),
(0x1D595, 'M', u'p'),
(0x1D596, 'M', u'q'),
(0x1D597, 'M', u'r'),
(0x1D598, 'M', u's'),
(0x1D599, 'M', u't'),
(0x1D59A, 'M', u'u'),
(0x1D59B, 'M', u'v'),
(0x1D59C, 'M', u'w'),
(0x1D59D, 'M', u'x'),
(0x1D59E, 'M', u'y'),
(0x1D59F, 'M', u'z'),
(0x1D5A0, 'M', u'a'),
(0x1D5A1, 'M', u'b'),
(0x1D5A2, 'M', u'c'),
(0x1D5A3, 'M', u'd'),
(0x1D5A4, 'M', u'e'),
(0x1D5A5, 'M', u'f'),
(0x1D5A6, 'M', u'g'),
(0x1D5A7, 'M', u'h'),
(0x1D5A8, 'M', u'i'),
(0x1D5A9, 'M', u'j'),
(0x1D5AA, 'M', u'k'),
(0x1D5AB, 'M', u'l'),
(0x1D5AC, 'M', u'm'),
(0x1D5AD, 'M', u'n'),
(0x1D5AE, 'M', u'o'),
(0x1D5AF, 'M', u'p'),
(0x1D5B0, 'M', u'q'),
(0x1D5B1, 'M', u'r'),
(0x1D5B2, 'M', u's'),
(0x1D5B3, 'M', u't'),
(0x1D5B4, 'M', u'u'),
(0x1D5B5, 'M', u'v'),
(0x1D5B6, 'M', u'w'),
(0x1D5B7, 'M', u'x'),
(0x1D5B8, 'M', u'y'),
(0x1D5B9, 'M', u'z'),
(0x1D5BA, 'M', u'a'),
(0x1D5BB, 'M', u'b'),
(0x1D5BC, 'M', u'c'),
(0x1D5BD, 'M', u'd'),
(0x1D5BE, 'M', u'e'),
(0x1D5BF, 'M', u'f'),
(0x1D5C0, 'M', u'g'),
(0x1D5C1, 'M', u'h'),
(0x1D5C2, 'M', u'i'),
(0x1D5C3, 'M', u'j'),
(0x1D5C4, 'M', u'k'),
(0x1D5C5, 'M', u'l'),
(0x1D5C6, 'M', u'm'),
(0x1D5C7, 'M', u'n'),
(0x1D5C8, 'M', u'o'),
(0x1D5C9, 'M', u'p'),
(0x1D5CA, 'M', u'q'),
(0x1D5CB, 'M', u'r'),
(0x1D5CC, 'M', u's'),
(0x1D5CD, 'M', u't'),
(0x1D5CE, 'M', u'u'),
(0x1D5CF, 'M', u'v'),
(0x1D5D0, 'M', u'w'),
(0x1D5D1, 'M', u'x'),
(0x1D5D2, 'M', u'y'),
(0x1D5D3, 'M', u'z'),
(0x1D5D4, 'M', u'a'),
(0x1D5D5, 'M', u'b'),
(0x1D5D6, 'M', u'c'),
(0x1D5D7, 'M', u'd'),
(0x1D5D8, 'M', u'e'),
(0x1D5D9, 'M', u'f'),
(0x1D5DA, 'M', u'g'),
(0x1D5DB, 'M', u'h'),
(0x1D5DC, 'M', u'i'),
(0x1D5DD, 'M', u'j'),
(0x1D5DE, 'M', u'k'),
(0x1D5DF, 'M', u'l'),
(0x1D5E0, 'M', u'm'),
(0x1D5E1, 'M', u'n'),
(0x1D5E2, 'M', u'o'),
(0x1D5E3, 'M', u'p'),
(0x1D5E4, 'M', u'q'),
(0x1D5E5, 'M', u'r'),
(0x1D5E6, 'M', u's'),
(0x1D5E7, 'M', u't'),
(0x1D5E8, 'M', u'u'),
(0x1D5E9, 'M', u'v'),
(0x1D5EA, 'M', u'w'),
(0x1D5EB, 'M', u'x'),
(0x1D5EC, 'M', u'y'),
(0x1D5ED, 'M', u'z'),
(0x1D5EE, 'M', u'a'),
(0x1D5EF, 'M', u'b'),
(0x1D5F0, 'M', u'c'),
(0x1D5F1, 'M', u'd'),
(0x1D5F2, 'M', u'e'),
]
def _seg_63():
return [
(0x1D5F3, 'M', u'f'),
(0x1D5F4, 'M', u'g'),
(0x1D5F5, 'M', u'h'),
(0x1D5F6, 'M', u'i'),
(0x1D5F7, 'M', u'j'),
(0x1D5F8, 'M', u'k'),
(0x1D5F9, 'M', u'l'),
(0x1D5FA, 'M', u'm'),
(0x1D5FB, 'M', u'n'),
(0x1D5FC, 'M', u'o'),
(0x1D5FD, 'M', u'p'),
(0x1D5FE, 'M', u'q'),
(0x1D5FF, 'M', u'r'),
(0x1D600, 'M', u's'),
(0x1D601, 'M', u't'),
(0x1D602, 'M', u'u'),
(0x1D603, 'M', u'v'),
(0x1D604, 'M', u'w'),
(0x1D605, 'M', u'x'),
(0x1D606, 'M', u'y'),
(0x1D607, 'M', u'z'),
(0x1D608, 'M', u'a'),
(0x1D609, 'M', u'b'),
(0x1D60A, 'M', u'c'),
(0x1D60B, 'M', u'd'),
(0x1D60C, 'M', u'e'),
(0x1D60D, 'M', u'f'),
(0x1D60E, 'M', u'g'),
(0x1D60F, 'M', u'h'),
(0x1D610, 'M', u'i'),
(0x1D611, 'M', u'j'),
(0x1D612, 'M', u'k'),
(0x1D613, 'M', u'l'),
(0x1D614, 'M', u'm'),
(0x1D615, 'M', u'n'),
(0x1D616, 'M', u'o'),
(0x1D617, 'M', u'p'),
(0x1D618, 'M', u'q'),
(0x1D619, 'M', u'r'),
(0x1D61A, 'M', u's'),
(0x1D61B, 'M', u't'),
(0x1D61C, 'M', u'u'),
(0x1D61D, 'M', u'v'),
(0x1D61E, 'M', u'w'),
(0x1D61F, 'M', u'x'),
(0x1D620, 'M', u'y'),
(0x1D621, 'M', u'z'),
(0x1D622, 'M', u'a'),
(0x1D623, 'M', u'b'),
(0x1D624, 'M', u'c'),
(0x1D625, 'M', u'd'),
(0x1D626, 'M', u'e'),
(0x1D627, 'M', u'f'),
(0x1D628, 'M', u'g'),
(0x1D629, 'M', u'h'),
(0x1D62A, 'M', u'i'),
(0x1D62B, 'M', u'j'),
(0x1D62C, 'M', u'k'),
(0x1D62D, 'M', u'l'),
(0x1D62E, 'M', u'm'),
(0x1D62F, 'M', u'n'),
(0x1D630, 'M', u'o'),
(0x1D631, 'M', u'p'),
(0x1D632, 'M', u'q'),
(0x1D633, 'M', u'r'),
(0x1D634, 'M', u's'),
(0x1D635, 'M', u't'),
(0x1D636, 'M', u'u'),
(0x1D637, 'M', u'v'),
(0x1D638, 'M', u'w'),
(0x1D639, 'M', u'x'),
(0x1D63A, 'M', u'y'),
(0x1D63B, 'M', u'z'),
(0x1D63C, 'M', u'a'),
(0x1D63D, 'M', u'b'),
(0x1D63E, 'M', u'c'),
(0x1D63F, 'M', u'd'),
(0x1D640, 'M', u'e'),
(0x1D641, 'M', u'f'),
(0x1D642, 'M', u'g'),
(0x1D643, 'M', u'h'),
(0x1D644, 'M', u'i'),
(0x1D645, 'M', u'j'),
(0x1D646, 'M', u'k'),
(0x1D647, 'M', u'l'),
(0x1D648, 'M', u'm'),
(0x1D649, 'M', u'n'),
(0x1D64A, 'M', u'o'),
(0x1D64B, 'M', u'p'),
(0x1D64C, 'M', u'q'),
(0x1D64D, 'M', u'r'),
(0x1D64E, 'M', u's'),
(0x1D64F, 'M', u't'),
(0x1D650, 'M', u'u'),
(0x1D651, 'M', u'v'),
(0x1D652, 'M', u'w'),
(0x1D653, 'M', u'x'),
(0x1D654, 'M', u'y'),
(0x1D655, 'M', u'z'),
(0x1D656, 'M', u'a'),
]
def _seg_64():
return [
(0x1D657, 'M', u'b'),
(0x1D658, 'M', u'c'),
(0x1D659, 'M', u'd'),
(0x1D65A, 'M', u'e'),
(0x1D65B, 'M', u'f'),
(0x1D65C, 'M', u'g'),
(0x1D65D, 'M', u'h'),
(0x1D65E, 'M', u'i'),
(0x1D65F, 'M', u'j'),
(0x1D660, 'M', u'k'),
(0x1D661, 'M', u'l'),
(0x1D662, 'M', u'm'),
(0x1D663, 'M', u'n'),
(0x1D664, 'M', u'o'),
(0x1D665, 'M', u'p'),
(0x1D666, 'M', u'q'),
(0x1D667, 'M', u'r'),
(0x1D668, 'M', u's'),
(0x1D669, 'M', u't'),
(0x1D66A, 'M', u'u'),
(0x1D66B, 'M', u'v'),
(0x1D66C, 'M', u'w'),
(0x1D66D, 'M', u'x'),
(0x1D66E, 'M', u'y'),
(0x1D66F, 'M', u'z'),
(0x1D670, 'M', u'a'),
(0x1D671, 'M', u'b'),
(0x1D672, 'M', u'c'),
(0x1D673, 'M', u'd'),
(0x1D674, 'M', u'e'),
(0x1D675, 'M', u'f'),
(0x1D676, 'M', u'g'),
(0x1D677, 'M', u'h'),
(0x1D678, 'M', u'i'),
(0x1D679, 'M', u'j'),
(0x1D67A, 'M', u'k'),
(0x1D67B, 'M', u'l'),
(0x1D67C, 'M', u'm'),
(0x1D67D, 'M', u'n'),
(0x1D67E, 'M', u'o'),
(0x1D67F, 'M', u'p'),
(0x1D680, 'M', u'q'),
(0x1D681, 'M', u'r'),
(0x1D682, 'M', u's'),
(0x1D683, 'M', u't'),
(0x1D684, 'M', u'u'),
(0x1D685, 'M', u'v'),
(0x1D686, 'M', u'w'),
(0x1D687, 'M', u'x'),
(0x1D688, 'M', u'y'),
(0x1D689, 'M', u'z'),
(0x1D68A, 'M', u'a'),
(0x1D68B, 'M', u'b'),
(0x1D68C, 'M', u'c'),
(0x1D68D, 'M', u'd'),
(0x1D68E, 'M', u'e'),
(0x1D68F, 'M', u'f'),
(0x1D690, 'M', u'g'),
(0x1D691, 'M', u'h'),
(0x1D692, 'M', u'i'),
(0x1D693, 'M', u'j'),
(0x1D694, 'M', u'k'),
(0x1D695, 'M', u'l'),
(0x1D696, 'M', u'm'),
(0x1D697, 'M', u'n'),
(0x1D698, 'M', u'o'),
(0x1D699, 'M', u'p'),
(0x1D69A, 'M', u'q'),
(0x1D69B, 'M', u'r'),
(0x1D69C, 'M', u's'),
(0x1D69D, 'M', u't'),
(0x1D69E, 'M', u'u'),
(0x1D69F, 'M', u'v'),
(0x1D6A0, 'M', u'w'),
(0x1D6A1, 'M', u'x'),
(0x1D6A2, 'M', u'y'),
(0x1D6A3, 'M', u'z'),
(0x1D6A4, 'M', u'ı'),
(0x1D6A5, 'M', u'ȷ'),
(0x1D6A6, 'X'),
(0x1D6A8, 'M', u'α'),
(0x1D6A9, 'M', u'β'),
(0x1D6AA, 'M', u'γ'),
(0x1D6AB, 'M', u'δ'),
(0x1D6AC, 'M', u'ε'),
(0x1D6AD, 'M', u'ζ'),
(0x1D6AE, 'M', u'η'),
(0x1D6AF, 'M', u'θ'),
(0x1D6B0, 'M', u'ι'),
(0x1D6B1, 'M', u'κ'),
(0x1D6B2, 'M', u'λ'),
(0x1D6B3, 'M', u'μ'),
(0x1D6B4, 'M', u'ν'),
(0x1D6B5, 'M', u'ξ'),
(0x1D6B6, 'M', u'ο'),
(0x1D6B7, 'M', u'π'),
(0x1D6B8, 'M', u'ρ'),
(0x1D6B9, 'M', u'θ'),
(0x1D6BA, 'M', u'σ'),
(0x1D6BB, 'M', u'τ'),
]
def _seg_65():
return [
(0x1D6BC, 'M', u'υ'),
(0x1D6BD, 'M', u'φ'),
(0x1D6BE, 'M', u'χ'),
(0x1D6BF, 'M', u'ψ'),
(0x1D6C0, 'M', u'ω'),
(0x1D6C1, 'M', u'∇'),
(0x1D6C2, 'M', u'α'),
(0x1D6C3, 'M', u'β'),
(0x1D6C4, 'M', u'γ'),
(0x1D6C5, 'M', u'δ'),
(0x1D6C6, 'M', u'ε'),
(0x1D6C7, 'M', u'ζ'),
(0x1D6C8, 'M', u'η'),
(0x1D6C9, 'M', u'θ'),
(0x1D6CA, 'M', u'ι'),
(0x1D6CB, 'M', u'κ'),
(0x1D6CC, 'M', u'λ'),
(0x1D6CD, 'M', u'μ'),
(0x1D6CE, 'M', u'ν'),
(0x1D6CF, 'M', u'ξ'),
(0x1D6D0, 'M', u'ο'),
(0x1D6D1, 'M', u'π'),
(0x1D6D2, 'M', u'ρ'),
(0x1D6D3, 'M', u'σ'),
(0x1D6D5, 'M', u'τ'),
(0x1D6D6, 'M', u'υ'),
(0x1D6D7, 'M', u'φ'),
(0x1D6D8, 'M', u'χ'),
(0x1D6D9, 'M', u'ψ'),
(0x1D6DA, 'M', u'ω'),
(0x1D6DB, 'M', u'∂'),
(0x1D6DC, 'M', u'ε'),
(0x1D6DD, 'M', u'θ'),
(0x1D6DE, 'M', u'κ'),
(0x1D6DF, 'M', u'φ'),
(0x1D6E0, 'M', u'ρ'),
(0x1D6E1, 'M', u'π'),
(0x1D6E2, 'M', u'α'),
(0x1D6E3, 'M', u'β'),
(0x1D6E4, 'M', u'γ'),
(0x1D6E5, 'M', u'δ'),
(0x1D6E6, 'M', u'ε'),
(0x1D6E7, 'M', u'ζ'),
(0x1D6E8, 'M', u'η'),
(0x1D6E9, 'M', u'θ'),
(0x1D6EA, 'M', u'ι'),
(0x1D6EB, 'M', u'κ'),
(0x1D6EC, 'M', u'λ'),
(0x1D6ED, 'M', u'μ'),
(0x1D6EE, 'M', u'ν'),
(0x1D6EF, 'M', u'ξ'),
(0x1D6F0, 'M', u'ο'),
(0x1D6F1, 'M', u'π'),
(0x1D6F2, 'M', u'ρ'),
(0x1D6F3, 'M', u'θ'),
(0x1D6F4, 'M', u'σ'),
(0x1D6F5, 'M', u'τ'),
(0x1D6F6, 'M', u'υ'),
(0x1D6F7, 'M', u'φ'),
(0x1D6F8, 'M', u'χ'),
(0x1D6F9, 'M', u'ψ'),
(0x1D6FA, 'M', u'ω'),
(0x1D6FB, 'M', u'∇'),
(0x1D6FC, 'M', u'α'),
(0x1D6FD, 'M', u'β'),
(0x1D6FE, 'M', u'γ'),
(0x1D6FF, 'M', u'δ'),
(0x1D700, 'M', u'ε'),
(0x1D701, 'M', u'ζ'),
(0x1D702, 'M', u'η'),
(0x1D703, 'M', u'θ'),
(0x1D704, 'M', u'ι'),
(0x1D705, 'M', u'κ'),
(0x1D706, 'M', u'λ'),
(0x1D707, 'M', u'μ'),
(0x1D708, 'M', u'ν'),
(0x1D709, 'M', u'ξ'),
(0x1D70A, 'M', u'ο'),
(0x1D70B, 'M', u'π'),
(0x1D70C, 'M', u'ρ'),
(0x1D70D, 'M', u'σ'),
(0x1D70F, 'M', u'τ'),
(0x1D710, 'M', u'υ'),
(0x1D711, 'M', u'φ'),
(0x1D712, 'M', u'χ'),
(0x1D713, 'M', u'ψ'),
(0x1D714, 'M', u'ω'),
(0x1D715, 'M', u'∂'),
(0x1D716, 'M', u'ε'),
(0x1D717, 'M', u'θ'),
(0x1D718, 'M', u'κ'),
(0x1D719, 'M', u'φ'),
(0x1D71A, 'M', u'ρ'),
(0x1D71B, 'M', u'π'),
(0x1D71C, 'M', u'α'),
(0x1D71D, 'M', u'β'),
(0x1D71E, 'M', u'γ'),
(0x1D71F, 'M', u'δ'),
(0x1D720, 'M', u'ε'),
(0x1D721, 'M', u'ζ'),
]
def _seg_66():
return [
(0x1D722, 'M', u'η'),
(0x1D723, 'M', u'θ'),
(0x1D724, 'M', u'ι'),
(0x1D725, 'M', u'κ'),
(0x1D726, 'M', u'λ'),
(0x1D727, 'M', u'μ'),
(0x1D728, 'M', u'ν'),
(0x1D729, 'M', u'ξ'),
(0x1D72A, 'M', u'ο'),
(0x1D72B, 'M', u'π'),
(0x1D72C, 'M', u'ρ'),
(0x1D72D, 'M', u'θ'),
(0x1D72E, 'M', u'σ'),
(0x1D72F, 'M', u'τ'),
(0x1D730, 'M', u'υ'),
(0x1D731, 'M', u'φ'),
(0x1D732, 'M', u'χ'),
(0x1D733, 'M', u'ψ'),
(0x1D734, 'M', u'ω'),
(0x1D735, 'M', u'∇'),
(0x1D736, 'M', u'α'),
(0x1D737, 'M', u'β'),
(0x1D738, 'M', u'γ'),
(0x1D739, 'M', u'δ'),
(0x1D73A, 'M', u'ε'),
(0x1D73B, 'M', u'ζ'),
(0x1D73C, 'M', u'η'),
(0x1D73D, 'M', u'θ'),
(0x1D73E, 'M', u'ι'),
(0x1D73F, 'M', u'κ'),
(0x1D740, 'M', u'λ'),
(0x1D741, 'M', u'μ'),
(0x1D742, 'M', u'ν'),
(0x1D743, 'M', u'ξ'),
(0x1D744, 'M', u'ο'),
(0x1D745, 'M', u'π'),
(0x1D746, 'M', u'ρ'),
(0x1D747, 'M', u'σ'),
(0x1D749, 'M', u'τ'),
(0x1D74A, 'M', u'υ'),
(0x1D74B, 'M', u'φ'),
(0x1D74C, 'M', u'χ'),
(0x1D74D, 'M', u'ψ'),
(0x1D74E, 'M', u'ω'),
(0x1D74F, 'M', u'∂'),
(0x1D750, 'M', u'ε'),
(0x1D751, 'M', u'θ'),
(0x1D752, 'M', u'κ'),
(0x1D753, 'M', u'φ'),
(0x1D754, 'M', u'ρ'),
(0x1D755, 'M', u'π'),
(0x1D756, 'M', u'α'),
(0x1D757, 'M', u'β'),
(0x1D758, 'M', u'γ'),
(0x1D759, 'M', u'δ'),
(0x1D75A, 'M', u'ε'),
(0x1D75B, 'M', u'ζ'),
(0x1D75C, 'M', u'η'),
(0x1D75D, 'M', u'θ'),
(0x1D75E, 'M', u'ι'),
(0x1D75F, 'M', u'κ'),
(0x1D760, 'M', u'λ'),
(0x1D761, 'M', u'μ'),
(0x1D762, 'M', u'ν'),
(0x1D763, 'M', u'ξ'),
(0x1D764, 'M', u'ο'),
(0x1D765, 'M', u'π'),
(0x1D766, 'M', u'ρ'),
(0x1D767, 'M', u'θ'),
(0x1D768, 'M', u'σ'),
(0x1D769, 'M', u'τ'),
(0x1D76A, 'M', u'υ'),
(0x1D76B, 'M', u'φ'),
(0x1D76C, 'M', u'χ'),
(0x1D76D, 'M', u'ψ'),
(0x1D76E, 'M', u'ω'),
(0x1D76F, 'M', u'∇'),
(0x1D770, 'M', u'α'),
(0x1D771, 'M', u'β'),
(0x1D772, 'M', u'γ'),
(0x1D773, 'M', u'δ'),
(0x1D774, 'M', u'ε'),
(0x1D775, 'M', u'ζ'),
(0x1D776, 'M', u'η'),
(0x1D777, 'M', u'θ'),
(0x1D778, 'M', u'ι'),
(0x1D779, 'M', u'κ'),
(0x1D77A, 'M', u'λ'),
(0x1D77B, 'M', u'μ'),
(0x1D77C, 'M', u'ν'),
(0x1D77D, 'M', u'ξ'),
(0x1D77E, 'M', u'ο'),
(0x1D77F, 'M', u'π'),
(0x1D780, 'M', u'ρ'),
(0x1D781, 'M', u'σ'),
(0x1D783, 'M', u'τ'),
(0x1D784, 'M', u'υ'),
(0x1D785, 'M', u'φ'),
(0x1D786, 'M', u'χ'),
(0x1D787, 'M', u'ψ'),
]
def _seg_67():
return [
(0x1D788, 'M', u'ω'),
(0x1D789, 'M', u'∂'),
(0x1D78A, 'M', u'ε'),
(0x1D78B, 'M', u'θ'),
(0x1D78C, 'M', u'κ'),
(0x1D78D, 'M', u'φ'),
(0x1D78E, 'M', u'ρ'),
(0x1D78F, 'M', u'π'),
(0x1D790, 'M', u'α'),
(0x1D791, 'M', u'β'),
(0x1D792, 'M', u'γ'),
(0x1D793, 'M', u'δ'),
(0x1D794, 'M', u'ε'),
(0x1D795, 'M', u'ζ'),
(0x1D796, 'M', u'η'),
(0x1D797, 'M', u'θ'),
(0x1D798, 'M', u'ι'),
(0x1D799, 'M', u'κ'),
(0x1D79A, 'M', u'λ'),
(0x1D79B, 'M', u'μ'),
(0x1D79C, 'M', u'ν'),
(0x1D79D, 'M', u'ξ'),
(0x1D79E, 'M', u'ο'),
(0x1D79F, 'M', u'π'),
(0x1D7A0, 'M', u'ρ'),
(0x1D7A1, 'M', u'θ'),
(0x1D7A2, 'M', u'σ'),
(0x1D7A3, 'M', u'τ'),
(0x1D7A4, 'M', u'υ'),
(0x1D7A5, 'M', u'φ'),
(0x1D7A6, 'M', u'χ'),
(0x1D7A7, 'M', u'ψ'),
(0x1D7A8, 'M', u'ω'),
(0x1D7A9, 'M', u'∇'),
(0x1D7AA, 'M', u'α'),
(0x1D7AB, 'M', u'β'),
(0x1D7AC, 'M', u'γ'),
(0x1D7AD, 'M', u'δ'),
(0x1D7AE, 'M', u'ε'),
(0x1D7AF, 'M', u'ζ'),
(0x1D7B0, 'M', u'η'),
(0x1D7B1, 'M', u'θ'),
(0x1D7B2, 'M', u'ι'),
(0x1D7B3, 'M', u'κ'),
(0x1D7B4, 'M', u'λ'),
(0x1D7B5, 'M', u'μ'),
(0x1D7B6, 'M', u'ν'),
(0x1D7B7, 'M', u'ξ'),
(0x1D7B8, 'M', u'ο'),
(0x1D7B9, 'M', u'π'),
(0x1D7BA, 'M', u'ρ'),
(0x1D7BB, 'M', u'σ'),
(0x1D7BD, 'M', u'τ'),
(0x1D7BE, 'M', u'υ'),
(0x1D7BF, 'M', u'φ'),
(0x1D7C0, 'M', u'χ'),
(0x1D7C1, 'M', u'ψ'),
(0x1D7C2, 'M', u'ω'),
(0x1D7C3, 'M', u'∂'),
(0x1D7C4, 'M', u'ε'),
(0x1D7C5, 'M', u'θ'),
(0x1D7C6, 'M', u'κ'),
(0x1D7C7, 'M', u'φ'),
(0x1D7C8, 'M', u'ρ'),
(0x1D7C9, 'M', u'π'),
(0x1D7CA, 'M', u'ϝ'),
(0x1D7CC, 'X'),
(0x1D7CE, 'M', u'0'),
(0x1D7CF, 'M', u'1'),
(0x1D7D0, 'M', u'2'),
(0x1D7D1, 'M', u'3'),
(0x1D7D2, 'M', u'4'),
(0x1D7D3, 'M', u'5'),
(0x1D7D4, 'M', u'6'),
(0x1D7D5, 'M', u'7'),
(0x1D7D6, 'M', u'8'),
(0x1D7D7, 'M', u'9'),
(0x1D7D8, 'M', u'0'),
(0x1D7D9, 'M', u'1'),
(0x1D7DA, 'M', u'2'),
(0x1D7DB, 'M', u'3'),
(0x1D7DC, 'M', u'4'),
(0x1D7DD, 'M', u'5'),
(0x1D7DE, 'M', u'6'),
(0x1D7DF, 'M', u'7'),
(0x1D7E0, 'M', u'8'),
(0x1D7E1, 'M', u'9'),
(0x1D7E2, 'M', u'0'),
(0x1D7E3, 'M', u'1'),
(0x1D7E4, 'M', u'2'),
(0x1D7E5, 'M', u'3'),
(0x1D7E6, 'M', u'4'),
(0x1D7E7, 'M', u'5'),
(0x1D7E8, 'M', u'6'),
(0x1D7E9, 'M', u'7'),
(0x1D7EA, 'M', u'8'),
(0x1D7EB, 'M', u'9'),
(0x1D7EC, 'M', u'0'),
(0x1D7ED, 'M', u'1'),
(0x1D7EE, 'M', u'2'),
]
def _seg_68():
return [
(0x1D7EF, 'M', u'3'),
(0x1D7F0, 'M', u'4'),
(0x1D7F1, 'M', u'5'),
(0x1D7F2, 'M', u'6'),
(0x1D7F3, 'M', u'7'),
(0x1D7F4, 'M', u'8'),
(0x1D7F5, 'M', u'9'),
(0x1D7F6, 'M', u'0'),
(0x1D7F7, 'M', u'1'),
(0x1D7F8, 'M', u'2'),
(0x1D7F9, 'M', u'3'),
(0x1D7FA, 'M', u'4'),
(0x1D7FB, 'M', u'5'),
(0x1D7FC, 'M', u'6'),
(0x1D7FD, 'M', u'7'),
(0x1D7FE, 'M', u'8'),
(0x1D7FF, 'M', u'9'),
(0x1D800, 'V'),
(0x1DA8C, 'X'),
(0x1DA9B, 'V'),
(0x1DAA0, 'X'),
(0x1DAA1, 'V'),
(0x1DAB0, 'X'),
(0x1E000, 'V'),
(0x1E007, 'X'),
(0x1E008, 'V'),
(0x1E019, 'X'),
(0x1E01B, 'V'),
(0x1E022, 'X'),
(0x1E023, 'V'),
(0x1E025, 'X'),
(0x1E026, 'V'),
(0x1E02B, 'X'),
(0x1E800, 'V'),
(0x1E8C5, 'X'),
(0x1E8C7, 'V'),
(0x1E8D7, 'X'),
(0x1E900, 'M', u'𞤢'),
(0x1E901, 'M', u'𞤣'),
(0x1E902, 'M', u'𞤤'),
(0x1E903, 'M', u'𞤥'),
(0x1E904, 'M', u'𞤦'),
(0x1E905, 'M', u'𞤧'),
(0x1E906, 'M', u'𞤨'),
(0x1E907, 'M', u'𞤩'),
(0x1E908, 'M', u'𞤪'),
(0x1E909, 'M', u'𞤫'),
(0x1E90A, 'M', u'𞤬'),
(0x1E90B, 'M', u'𞤭'),
(0x1E90C, 'M', u'𞤮'),
(0x1E90D, 'M', u'𞤯'),
(0x1E90E, 'M', u'𞤰'),
(0x1E90F, 'M', u'𞤱'),
(0x1E910, 'M', u'𞤲'),
(0x1E911, 'M', u'𞤳'),
(0x1E912, 'M', u'𞤴'),
(0x1E913, 'M', u'𞤵'),
(0x1E914, 'M', u'𞤶'),
(0x1E915, 'M', u'𞤷'),
(0x1E916, 'M', u'𞤸'),
(0x1E917, 'M', u'𞤹'),
(0x1E918, 'M', u'𞤺'),
(0x1E919, 'M', u'𞤻'),
(0x1E91A, 'M', u'𞤼'),
(0x1E91B, 'M', u'𞤽'),
(0x1E91C, 'M', u'𞤾'),
(0x1E91D, 'M', u'𞤿'),
(0x1E91E, 'M', u'𞥀'),
(0x1E91F, 'M', u'𞥁'),
(0x1E920, 'M', u'𞥂'),
(0x1E921, 'M', u'𞥃'),
(0x1E922, 'V'),
(0x1E94B, 'X'),
(0x1E950, 'V'),
(0x1E95A, 'X'),
(0x1E95E, 'V'),
(0x1E960, 'X'),
(0x1EC71, 'V'),
(0x1ECB5, 'X'),
(0x1EE00, 'M', u'ا'),
(0x1EE01, 'M', u'ب'),
(0x1EE02, 'M', u'ج'),
(0x1EE03, 'M', u'د'),
(0x1EE04, 'X'),
(0x1EE05, 'M', u'و'),
(0x1EE06, 'M', u'ز'),
(0x1EE07, 'M', u'ح'),
(0x1EE08, 'M', u'ط'),
(0x1EE09, 'M', u'ي'),
(0x1EE0A, 'M', u'ك'),
(0x1EE0B, 'M', u'ل'),
(0x1EE0C, 'M', u'م'),
(0x1EE0D, 'M', u'ن'),
(0x1EE0E, 'M', u'س'),
(0x1EE0F, 'M', u'ع'),
(0x1EE10, 'M', u'ف'),
(0x1EE11, 'M', u'ص'),
(0x1EE12, 'M', u'ق'),
(0x1EE13, 'M', u'ر'),
(0x1EE14, 'M', u'ش'),
]
def _seg_69():
return [
(0x1EE15, 'M', u'ت'),
(0x1EE16, 'M', u'ث'),
(0x1EE17, 'M', u'خ'),
(0x1EE18, 'M', u'ذ'),
(0x1EE19, 'M', u'ض'),
(0x1EE1A, 'M', u'ظ'),
(0x1EE1B, 'M', u'غ'),
(0x1EE1C, 'M', u'ٮ'),
(0x1EE1D, 'M', u'ں'),
(0x1EE1E, 'M', u'ڡ'),
(0x1EE1F, 'M', u'ٯ'),
(0x1EE20, 'X'),
(0x1EE21, 'M', u'ب'),
(0x1EE22, 'M', u'ج'),
(0x1EE23, 'X'),
(0x1EE24, 'M', u'ه'),
(0x1EE25, 'X'),
(0x1EE27, 'M', u'ح'),
(0x1EE28, 'X'),
(0x1EE29, 'M', u'ي'),
(0x1EE2A, 'M', u'ك'),
(0x1EE2B, 'M', u'ل'),
(0x1EE2C, 'M', u'م'),
(0x1EE2D, 'M', u'ن'),
(0x1EE2E, 'M', u'س'),
(0x1EE2F, 'M', u'ع'),
(0x1EE30, 'M', u'ف'),
(0x1EE31, 'M', u'ص'),
(0x1EE32, 'M', u'ق'),
(0x1EE33, 'X'),
(0x1EE34, 'M', u'ش'),
(0x1EE35, 'M', u'ت'),
(0x1EE36, 'M', u'ث'),
(0x1EE37, 'M', u'خ'),
(0x1EE38, 'X'),
(0x1EE39, 'M', u'ض'),
(0x1EE3A, 'X'),
(0x1EE3B, 'M', u'غ'),
(0x1EE3C, 'X'),
(0x1EE42, 'M', u'ج'),
(0x1EE43, 'X'),
(0x1EE47, 'M', u'ح'),
(0x1EE48, 'X'),
(0x1EE49, 'M', u'ي'),
(0x1EE4A, 'X'),
(0x1EE4B, 'M', u'ل'),
(0x1EE4C, 'X'),
(0x1EE4D, 'M', u'ن'),
(0x1EE4E, 'M', u'س'),
(0x1EE4F, 'M', u'ع'),
(0x1EE50, 'X'),
(0x1EE51, 'M', u'ص'),
(0x1EE52, 'M', u'ق'),
(0x1EE53, 'X'),
(0x1EE54, 'M', u'ش'),
(0x1EE55, 'X'),
(0x1EE57, 'M', u'خ'),
(0x1EE58, 'X'),
(0x1EE59, 'M', u'ض'),
(0x1EE5A, 'X'),
(0x1EE5B, 'M', u'غ'),
(0x1EE5C, 'X'),
(0x1EE5D, 'M', u'ں'),
(0x1EE5E, 'X'),
(0x1EE5F, 'M', u'ٯ'),
(0x1EE60, 'X'),
(0x1EE61, 'M', u'ب'),
(0x1EE62, 'M', u'ج'),
(0x1EE63, 'X'),
(0x1EE64, 'M', u'ه'),
(0x1EE65, 'X'),
(0x1EE67, 'M', u'ح'),
(0x1EE68, 'M', u'ط'),
(0x1EE69, 'M', u'ي'),
(0x1EE6A, 'M', u'ك'),
(0x1EE6B, 'X'),
(0x1EE6C, 'M', u'م'),
(0x1EE6D, 'M', u'ن'),
(0x1EE6E, 'M', u'س'),
(0x1EE6F, 'M', u'ع'),
(0x1EE70, 'M', u'ف'),
(0x1EE71, 'M', u'ص'),
(0x1EE72, 'M', u'ق'),
(0x1EE73, 'X'),
(0x1EE74, 'M', u'ش'),
(0x1EE75, 'M', u'ت'),
(0x1EE76, 'M', u'ث'),
(0x1EE77, 'M', u'خ'),
(0x1EE78, 'X'),
(0x1EE79, 'M', u'ض'),
(0x1EE7A, 'M', u'ظ'),
(0x1EE7B, 'M', u'غ'),
(0x1EE7C, 'M', u'ٮ'),
(0x1EE7D, 'X'),
(0x1EE7E, 'M', u'ڡ'),
(0x1EE7F, 'X'),
(0x1EE80, 'M', u'ا'),
(0x1EE81, 'M', u'ب'),
(0x1EE82, 'M', u'ج'),
(0x1EE83, 'M', u'د'),
]
def _seg_70():
return [
(0x1EE84, 'M', u'ه'),
(0x1EE85, 'M', u'و'),
(0x1EE86, 'M', u'ز'),
(0x1EE87, 'M', u'ح'),
(0x1EE88, 'M', u'ط'),
(0x1EE89, 'M', u'ي'),
(0x1EE8A, 'X'),
(0x1EE8B, 'M', u'ل'),
(0x1EE8C, 'M', u'م'),
(0x1EE8D, 'M', u'ن'),
(0x1EE8E, 'M', u'س'),
(0x1EE8F, 'M', u'ع'),
(0x1EE90, 'M', u'ف'),
(0x1EE91, 'M', u'ص'),
(0x1EE92, 'M', u'ق'),
(0x1EE93, 'M', u'ر'),
(0x1EE94, 'M', u'ش'),
(0x1EE95, 'M', u'ت'),
(0x1EE96, 'M', u'ث'),
(0x1EE97, 'M', u'خ'),
(0x1EE98, 'M', u'ذ'),
(0x1EE99, 'M', u'ض'),
(0x1EE9A, 'M', u'ظ'),
(0x1EE9B, 'M', u'غ'),
(0x1EE9C, 'X'),
(0x1EEA1, 'M', u'ب'),
(0x1EEA2, 'M', u'ج'),
(0x1EEA3, 'M', u'د'),
(0x1EEA4, 'X'),
(0x1EEA5, 'M', u'و'),
(0x1EEA6, 'M', u'ز'),
(0x1EEA7, 'M', u'ح'),
(0x1EEA8, 'M', u'ط'),
(0x1EEA9, 'M', u'ي'),
(0x1EEAA, 'X'),
(0x1EEAB, 'M', u'ل'),
(0x1EEAC, 'M', u'م'),
(0x1EEAD, 'M', u'ن'),
(0x1EEAE, 'M', u'س'),
(0x1EEAF, 'M', u'ع'),
(0x1EEB0, 'M', u'ف'),
(0x1EEB1, 'M', u'ص'),
(0x1EEB2, 'M', u'ق'),
(0x1EEB3, 'M', u'ر'),
(0x1EEB4, 'M', u'ش'),
(0x1EEB5, 'M', u'ت'),
(0x1EEB6, 'M', u'ث'),
(0x1EEB7, 'M', u'خ'),
(0x1EEB8, 'M', u'ذ'),
(0x1EEB9, 'M', u'ض'),
(0x1EEBA, 'M', u'ظ'),
(0x1EEBB, 'M', u'غ'),
(0x1EEBC, 'X'),
(0x1EEF0, 'V'),
(0x1EEF2, 'X'),
(0x1F000, 'V'),
(0x1F02C, 'X'),
(0x1F030, 'V'),
(0x1F094, 'X'),
(0x1F0A0, 'V'),
(0x1F0AF, 'X'),
(0x1F0B1, 'V'),
(0x1F0C0, 'X'),
(0x1F0C1, 'V'),
(0x1F0D0, 'X'),
(0x1F0D1, 'V'),
(0x1F0F6, 'X'),
(0x1F101, '3', u'0,'),
(0x1F102, '3', u'1,'),
(0x1F103, '3', u'2,'),
(0x1F104, '3', u'3,'),
(0x1F105, '3', u'4,'),
(0x1F106, '3', u'5,'),
(0x1F107, '3', u'6,'),
(0x1F108, '3', u'7,'),
(0x1F109, '3', u'8,'),
(0x1F10A, '3', u'9,'),
(0x1F10B, 'V'),
(0x1F10D, 'X'),
(0x1F110, '3', u'(a)'),
(0x1F111, '3', u'(b)'),
(0x1F112, '3', u'(c)'),
(0x1F113, '3', u'(d)'),
(0x1F114, '3', u'(e)'),
(0x1F115, '3', u'(f)'),
(0x1F116, '3', u'(g)'),
(0x1F117, '3', u'(h)'),
(0x1F118, '3', u'(i)'),
(0x1F119, '3', u'(j)'),
(0x1F11A, '3', u'(k)'),
(0x1F11B, '3', u'(l)'),
(0x1F11C, '3', u'(m)'),
(0x1F11D, '3', u'(n)'),
(0x1F11E, '3', u'(o)'),
(0x1F11F, '3', u'(p)'),
(0x1F120, '3', u'(q)'),
(0x1F121, '3', u'(r)'),
(0x1F122, '3', u'(s)'),
(0x1F123, '3', u'(t)'),
(0x1F124, '3', u'(u)'),
]
def _seg_71():
return [
(0x1F125, '3', u'(v)'),
(0x1F126, '3', u'(w)'),
(0x1F127, '3', u'(x)'),
(0x1F128, '3', u'(y)'),
(0x1F129, '3', u'(z)'),
(0x1F12A, 'M', u'〔s〕'),
(0x1F12B, 'M', u'c'),
(0x1F12C, 'M', u'r'),
(0x1F12D, 'M', u'cd'),
(0x1F12E, 'M', u'wz'),
(0x1F12F, 'V'),
(0x1F130, 'M', u'a'),
(0x1F131, 'M', u'b'),
(0x1F132, 'M', u'c'),
(0x1F133, 'M', u'd'),
(0x1F134, 'M', u'e'),
(0x1F135, 'M', u'f'),
(0x1F136, 'M', u'g'),
(0x1F137, 'M', u'h'),
(0x1F138, 'M', u'i'),
(0x1F139, 'M', u'j'),
(0x1F13A, 'M', u'k'),
(0x1F13B, 'M', u'l'),
(0x1F13C, 'M', u'm'),
(0x1F13D, 'M', u'n'),
(0x1F13E, 'M', u'o'),
(0x1F13F, 'M', u'p'),
(0x1F140, 'M', u'q'),
(0x1F141, 'M', u'r'),
(0x1F142, 'M', u's'),
(0x1F143, 'M', u't'),
(0x1F144, 'M', u'u'),
(0x1F145, 'M', u'v'),
(0x1F146, 'M', u'w'),
(0x1F147, 'M', u'x'),
(0x1F148, 'M', u'y'),
(0x1F149, 'M', u'z'),
(0x1F14A, 'M', u'hv'),
(0x1F14B, 'M', u'mv'),
(0x1F14C, 'M', u'sd'),
(0x1F14D, 'M', u'ss'),
(0x1F14E, 'M', u'ppv'),
(0x1F14F, 'M', u'wc'),
(0x1F150, 'V'),
(0x1F16A, 'M', u'mc'),
(0x1F16B, 'M', u'md'),
(0x1F16C, 'X'),
(0x1F170, 'V'),
(0x1F190, 'M', u'dj'),
(0x1F191, 'V'),
(0x1F1AD, 'X'),
(0x1F1E6, 'V'),
(0x1F200, 'M', u'ほか'),
(0x1F201, 'M', u'ココ'),
(0x1F202, 'M', u'サ'),
(0x1F203, 'X'),
(0x1F210, 'M', u'手'),
(0x1F211, 'M', u'字'),
(0x1F212, 'M', u'双'),
(0x1F213, 'M', u'デ'),
(0x1F214, 'M', u'二'),
(0x1F215, 'M', u'多'),
(0x1F216, 'M', u'解'),
(0x1F217, 'M', u'天'),
(0x1F218, 'M', u'交'),
(0x1F219, 'M', u'映'),
(0x1F21A, 'M', u'無'),
(0x1F21B, 'M', u'料'),
(0x1F21C, 'M', u'前'),
(0x1F21D, 'M', u'後'),
(0x1F21E, 'M', u'再'),
(0x1F21F, 'M', u'新'),
(0x1F220, 'M', u'初'),
(0x1F221, 'M', u'終'),
(0x1F222, 'M', u'生'),
(0x1F223, 'M', u'販'),
(0x1F224, 'M', u'声'),
(0x1F225, 'M', u'吹'),
(0x1F226, 'M', u'演'),
(0x1F227, 'M', u'投'),
(0x1F228, 'M', u'捕'),
(0x1F229, 'M', u'一'),
(0x1F22A, 'M', u'三'),
(0x1F22B, 'M', u'遊'),
(0x1F22C, 'M', u'左'),
(0x1F22D, 'M', u'中'),
(0x1F22E, 'M', u'右'),
(0x1F22F, 'M', u'指'),
(0x1F230, 'M', u'走'),
(0x1F231, 'M', u'打'),
(0x1F232, 'M', u'禁'),
(0x1F233, 'M', u'空'),
(0x1F234, 'M', u'合'),
(0x1F235, 'M', u'満'),
(0x1F236, 'M', u'有'),
(0x1F237, 'M', u'月'),
(0x1F238, 'M', u'申'),
(0x1F239, 'M', u'割'),
(0x1F23A, 'M', u'営'),
(0x1F23B, 'M', u'配'),
]
def _seg_72():
return [
(0x1F23C, 'X'),
(0x1F240, 'M', u'〔本〕'),
(0x1F241, 'M', u'〔三〕'),
(0x1F242, 'M', u'〔二〕'),
(0x1F243, 'M', u'〔安〕'),
(0x1F244, 'M', u'〔点〕'),
(0x1F245, 'M', u'〔打〕'),
(0x1F246, 'M', u'〔盗〕'),
(0x1F247, 'M', u'〔勝〕'),
(0x1F248, 'M', u'〔敗〕'),
(0x1F249, 'X'),
(0x1F250, 'M', u'得'),
(0x1F251, 'M', u'可'),
(0x1F252, 'X'),
(0x1F260, 'V'),
(0x1F266, 'X'),
(0x1F300, 'V'),
(0x1F6D5, 'X'),
(0x1F6E0, 'V'),
(0x1F6ED, 'X'),
(0x1F6F0, 'V'),
(0x1F6FA, 'X'),
(0x1F700, 'V'),
(0x1F774, 'X'),
(0x1F780, 'V'),
(0x1F7D9, 'X'),
(0x1F800, 'V'),
(0x1F80C, 'X'),
(0x1F810, 'V'),
(0x1F848, 'X'),
(0x1F850, 'V'),
(0x1F85A, 'X'),
(0x1F860, 'V'),
(0x1F888, 'X'),
(0x1F890, 'V'),
(0x1F8AE, 'X'),
(0x1F900, 'V'),
(0x1F90C, 'X'),
(0x1F910, 'V'),
(0x1F93F, 'X'),
(0x1F940, 'V'),
(0x1F971, 'X'),
(0x1F973, 'V'),
(0x1F977, 'X'),
(0x1F97A, 'V'),
(0x1F97B, 'X'),
(0x1F97C, 'V'),
(0x1F9A3, 'X'),
(0x1F9B0, 'V'),
(0x1F9BA, 'X'),
(0x1F9C0, 'V'),
(0x1F9C3, 'X'),
(0x1F9D0, 'V'),
(0x1FA00, 'X'),
(0x1FA60, 'V'),
(0x1FA6E, 'X'),
(0x20000, 'V'),
(0x2A6D7, 'X'),
(0x2A700, 'V'),
(0x2B735, 'X'),
(0x2B740, 'V'),
(0x2B81E, 'X'),
(0x2B820, 'V'),
(0x2CEA2, 'X'),
(0x2CEB0, 'V'),
(0x2EBE1, 'X'),
(0x2F800, 'M', u'丽'),
(0x2F801, 'M', u'丸'),
(0x2F802, 'M', u'乁'),
(0x2F803, 'M', u'𠄢'),
(0x2F804, 'M', u'你'),
(0x2F805, 'M', u'侮'),
(0x2F806, 'M', u'侻'),
(0x2F807, 'M', u'倂'),
(0x2F808, 'M', u'偺'),
(0x2F809, 'M', u'備'),
(0x2F80A, 'M', u'僧'),
(0x2F80B, 'M', u'像'),
(0x2F80C, 'M', u'㒞'),
(0x2F80D, 'M', u'𠘺'),
(0x2F80E, 'M', u'免'),
(0x2F80F, 'M', u'兔'),
(0x2F810, 'M', u'兤'),
(0x2F811, 'M', u'具'),
(0x2F812, 'M', u'𠔜'),
(0x2F813, 'M', u'㒹'),
(0x2F814, 'M', u'內'),
(0x2F815, 'M', u'再'),
(0x2F816, 'M', u'𠕋'),
(0x2F817, 'M', u'冗'),
(0x2F818, 'M', u'冤'),
(0x2F819, 'M', u'仌'),
(0x2F81A, 'M', u'冬'),
(0x2F81B, 'M', u'况'),
(0x2F81C, 'M', u'𩇟'),
(0x2F81D, 'M', u'凵'),
(0x2F81E, 'M', u'刃'),
(0x2F81F, 'M', u'㓟'),
(0x2F820, 'M', u'刻'),
(0x2F821, 'M', u'剆'),
]
def _seg_73():
return [
(0x2F822, 'M', u'割'),
(0x2F823, 'M', u'剷'),
(0x2F824, 'M', u'㔕'),
(0x2F825, 'M', u'勇'),
(0x2F826, 'M', u'勉'),
(0x2F827, 'M', u'勤'),
(0x2F828, 'M', u'勺'),
(0x2F829, 'M', u'包'),
(0x2F82A, 'M', u'匆'),
(0x2F82B, 'M', u'北'),
(0x2F82C, 'M', u'卉'),
(0x2F82D, 'M', u'卑'),
(0x2F82E, 'M', u'博'),
(0x2F82F, 'M', u'即'),
(0x2F830, 'M', u'卽'),
(0x2F831, 'M', u'卿'),
(0x2F834, 'M', u'𠨬'),
(0x2F835, 'M', u'灰'),
(0x2F836, 'M', u'及'),
(0x2F837, 'M', u'叟'),
(0x2F838, 'M', u'𠭣'),
(0x2F839, 'M', u'叫'),
(0x2F83A, 'M', u'叱'),
(0x2F83B, 'M', u'吆'),
(0x2F83C, 'M', u'咞'),
(0x2F83D, 'M', u'吸'),
(0x2F83E, 'M', u'呈'),
(0x2F83F, 'M', u'周'),
(0x2F840, 'M', u'咢'),
(0x2F841, 'M', u'哶'),
(0x2F842, 'M', u'唐'),
(0x2F843, 'M', u'啓'),
(0x2F844, 'M', u'啣'),
(0x2F845, 'M', u'善'),
(0x2F847, 'M', u'喙'),
(0x2F848, 'M', u'喫'),
(0x2F849, 'M', u'喳'),
(0x2F84A, 'M', u'嗂'),
(0x2F84B, 'M', u'圖'),
(0x2F84C, 'M', u'嘆'),
(0x2F84D, 'M', u'圗'),
(0x2F84E, 'M', u'噑'),
(0x2F84F, 'M', u'噴'),
(0x2F850, 'M', u'切'),
(0x2F851, 'M', u'壮'),
(0x2F852, 'M', u'城'),
(0x2F853, 'M', u'埴'),
(0x2F854, 'M', u'堍'),
(0x2F855, 'M', u'型'),
(0x2F856, 'M', u'堲'),
(0x2F857, 'M', u'報'),
(0x2F858, 'M', u'墬'),
(0x2F859, 'M', u'𡓤'),
(0x2F85A, 'M', u'売'),
(0x2F85B, 'M', u'壷'),
(0x2F85C, 'M', u'夆'),
(0x2F85D, 'M', u'多'),
(0x2F85E, 'M', u'夢'),
(0x2F85F, 'M', u'奢'),
(0x2F860, 'M', u'𡚨'),
(0x2F861, 'M', u'𡛪'),
(0x2F862, 'M', u'姬'),
(0x2F863, 'M', u'娛'),
(0x2F864, 'M', u'娧'),
(0x2F865, 'M', u'姘'),
(0x2F866, 'M', u'婦'),
(0x2F867, 'M', u'㛮'),
(0x2F868, 'X'),
(0x2F869, 'M', u'嬈'),
(0x2F86A, 'M', u'嬾'),
(0x2F86C, 'M', u'𡧈'),
(0x2F86D, 'M', u'寃'),
(0x2F86E, 'M', u'寘'),
(0x2F86F, 'M', u'寧'),
(0x2F870, 'M', u'寳'),
(0x2F871, 'M', u'𡬘'),
(0x2F872, 'M', u'寿'),
(0x2F873, 'M', u'将'),
(0x2F874, 'X'),
(0x2F875, 'M', u'尢'),
(0x2F876, 'M', u'㞁'),
(0x2F877, 'M', u'屠'),
(0x2F878, 'M', u'屮'),
(0x2F879, 'M', u'峀'),
(0x2F87A, 'M', u'岍'),
(0x2F87B, 'M', u'𡷤'),
(0x2F87C, 'M', u'嵃'),
(0x2F87D, 'M', u'𡷦'),
(0x2F87E, 'M', u'嵮'),
(0x2F87F, 'M', u'嵫'),
(0x2F880, 'M', u'嵼'),
(0x2F881, 'M', u'巡'),
(0x2F882, 'M', u'巢'),
(0x2F883, 'M', u'㠯'),
(0x2F884, 'M', u'巽'),
(0x2F885, 'M', u'帨'),
(0x2F886, 'M', u'帽'),
(0x2F887, 'M', u'幩'),
(0x2F888, 'M', u'㡢'),
(0x2F889, 'M', u'𢆃'),
]
def _seg_74():
return [
(0x2F88A, 'M', u'㡼'),
(0x2F88B, 'M', u'庰'),
(0x2F88C, 'M', u'庳'),
(0x2F88D, 'M', u'庶'),
(0x2F88E, 'M', u'廊'),
(0x2F88F, 'M', u'𪎒'),
(0x2F890, 'M', u'廾'),
(0x2F891, 'M', u'𢌱'),
(0x2F893, 'M', u'舁'),
(0x2F894, 'M', u'弢'),
(0x2F896, 'M', u'㣇'),
(0x2F897, 'M', u'𣊸'),
(0x2F898, 'M', u'𦇚'),
(0x2F899, 'M', u'形'),
(0x2F89A, 'M', u'彫'),
(0x2F89B, 'M', u'㣣'),
(0x2F89C, 'M', u'徚'),
(0x2F89D, 'M', u'忍'),
(0x2F89E, 'M', u'志'),
(0x2F89F, 'M', u'忹'),
(0x2F8A0, 'M', u'悁'),
(0x2F8A1, 'M', u'㤺'),
(0x2F8A2, 'M', u'㤜'),
(0x2F8A3, 'M', u'悔'),
(0x2F8A4, 'M', u'𢛔'),
(0x2F8A5, 'M', u'惇'),
(0x2F8A6, 'M', u'慈'),
(0x2F8A7, 'M', u'慌'),
(0x2F8A8, 'M', u'慎'),
(0x2F8A9, 'M', u'慌'),
(0x2F8AA, 'M', u'慺'),
(0x2F8AB, 'M', u'憎'),
(0x2F8AC, 'M', u'憲'),
(0x2F8AD, 'M', u'憤'),
(0x2F8AE, 'M', u'憯'),
(0x2F8AF, 'M', u'懞'),
(0x2F8B0, 'M', u'懲'),
(0x2F8B1, 'M', u'懶'),
(0x2F8B2, 'M', u'成'),
(0x2F8B3, 'M', u'戛'),
(0x2F8B4, 'M', u'扝'),
(0x2F8B5, 'M', u'抱'),
(0x2F8B6, 'M', u'拔'),
(0x2F8B7, 'M', u'捐'),
(0x2F8B8, 'M', u'𢬌'),
(0x2F8B9, 'M', u'挽'),
(0x2F8BA, 'M', u'拼'),
(0x2F8BB, 'M', u'捨'),
(0x2F8BC, 'M', u'掃'),
(0x2F8BD, 'M', u'揤'),
(0x2F8BE, 'M', u'𢯱'),
(0x2F8BF, 'M', u'搢'),
(0x2F8C0, 'M', u'揅'),
(0x2F8C1, 'M', u'掩'),
(0x2F8C2, 'M', u'㨮'),
(0x2F8C3, 'M', u'摩'),
(0x2F8C4, 'M', u'摾'),
(0x2F8C5, 'M', u'撝'),
(0x2F8C6, 'M', u'摷'),
(0x2F8C7, 'M', u'㩬'),
(0x2F8C8, 'M', u'敏'),
(0x2F8C9, 'M', u'敬'),
(0x2F8CA, 'M', u'𣀊'),
(0x2F8CB, 'M', u'旣'),
(0x2F8CC, 'M', u'書'),
(0x2F8CD, 'M', u'晉'),
(0x2F8CE, 'M', u'㬙'),
(0x2F8CF, 'M', u'暑'),
(0x2F8D0, 'M', u'㬈'),
(0x2F8D1, 'M', u'㫤'),
(0x2F8D2, 'M', u'冒'),
(0x2F8D3, 'M', u'冕'),
(0x2F8D4, 'M', u'最'),
(0x2F8D5, 'M', u'暜'),
(0x2F8D6, 'M', u'肭'),
(0x2F8D7, 'M', u'䏙'),
(0x2F8D8, 'M', u'朗'),
(0x2F8D9, 'M', u'望'),
(0x2F8DA, 'M', u'朡'),
(0x2F8DB, 'M', u'杞'),
(0x2F8DC, 'M', u'杓'),
(0x2F8DD, 'M', u'𣏃'),
(0x2F8DE, 'M', u'㭉'),
(0x2F8DF, 'M', u'柺'),
(0x2F8E0, 'M', u'枅'),
(0x2F8E1, 'M', u'桒'),
(0x2F8E2, 'M', u'梅'),
(0x2F8E3, 'M', u'𣑭'),
(0x2F8E4, 'M', u'梎'),
(0x2F8E5, 'M', u'栟'),
(0x2F8E6, 'M', u'椔'),
(0x2F8E7, 'M', u'㮝'),
(0x2F8E8, 'M', u'楂'),
(0x2F8E9, 'M', u'榣'),
(0x2F8EA, 'M', u'槪'),
(0x2F8EB, 'M', u'檨'),
(0x2F8EC, 'M', u'𣚣'),
(0x2F8ED, 'M', u'櫛'),
(0x2F8EE, 'M', u'㰘'),
(0x2F8EF, 'M', u'次'),
]
def _seg_75():
return [
(0x2F8F0, 'M', u'𣢧'),
(0x2F8F1, 'M', u'歔'),
(0x2F8F2, 'M', u'㱎'),
(0x2F8F3, 'M', u'歲'),
(0x2F8F4, 'M', u'殟'),
(0x2F8F5, 'M', u'殺'),
(0x2F8F6, 'M', u'殻'),
(0x2F8F7, 'M', u'𣪍'),
(0x2F8F8, 'M', u'𡴋'),
(0x2F8F9, 'M', u'𣫺'),
(0x2F8FA, 'M', u'汎'),
(0x2F8FB, 'M', u'𣲼'),
(0x2F8FC, 'M', u'沿'),
(0x2F8FD, 'M', u'泍'),
(0x2F8FE, 'M', u'汧'),
(0x2F8FF, 'M', u'洖'),
(0x2F900, 'M', u'派'),
(0x2F901, 'M', u'海'),
(0x2F902, 'M', u'流'),
(0x2F903, 'M', u'浩'),
(0x2F904, 'M', u'浸'),
(0x2F905, 'M', u'涅'),
(0x2F906, 'M', u'𣴞'),
(0x2F907, 'M', u'洴'),
(0x2F908, 'M', u'港'),
(0x2F909, 'M', u'湮'),
(0x2F90A, 'M', u'㴳'),
(0x2F90B, 'M', u'滋'),
(0x2F90C, 'M', u'滇'),
(0x2F90D, 'M', u'𣻑'),
(0x2F90E, 'M', u'淹'),
(0x2F90F, 'M', u'潮'),
(0x2F910, 'M', u'𣽞'),
(0x2F911, 'M', u'𣾎'),
(0x2F912, 'M', u'濆'),
(0x2F913, 'M', u'瀹'),
(0x2F914, 'M', u'瀞'),
(0x2F915, 'M', u'瀛'),
(0x2F916, 'M', u'㶖'),
(0x2F917, 'M', u'灊'),
(0x2F918, 'M', u'災'),
(0x2F919, 'M', u'灷'),
(0x2F91A, 'M', u'炭'),
(0x2F91B, 'M', u'𠔥'),
(0x2F91C, 'M', u'煅'),
(0x2F91D, 'M', u'𤉣'),
(0x2F91E, 'M', u'熜'),
(0x2F91F, 'X'),
(0x2F920, 'M', u'爨'),
(0x2F921, 'M', u'爵'),
(0x2F922, 'M', u'牐'),
(0x2F923, 'M', u'𤘈'),
(0x2F924, 'M', u'犀'),
(0x2F925, 'M', u'犕'),
(0x2F926, 'M', u'𤜵'),
(0x2F927, 'M', u'𤠔'),
(0x2F928, 'M', u'獺'),
(0x2F929, 'M', u'王'),
(0x2F92A, 'M', u'㺬'),
(0x2F92B, 'M', u'玥'),
(0x2F92C, 'M', u'㺸'),
(0x2F92E, 'M', u'瑇'),
(0x2F92F, 'M', u'瑜'),
(0x2F930, 'M', u'瑱'),
(0x2F931, 'M', u'璅'),
(0x2F932, 'M', u'瓊'),
(0x2F933, 'M', u'㼛'),
(0x2F934, 'M', u'甤'),
(0x2F935, 'M', u'𤰶'),
(0x2F936, 'M', u'甾'),
(0x2F937, 'M', u'𤲒'),
(0x2F938, 'M', u'異'),
(0x2F939, 'M', u'𢆟'),
(0x2F93A, 'M', u'瘐'),
(0x2F93B, 'M', u'𤾡'),
(0x2F93C, 'M', u'𤾸'),
(0x2F93D, 'M', u'𥁄'),
(0x2F93E, 'M', u'㿼'),
(0x2F93F, 'M', u'䀈'),
(0x2F940, 'M', u'直'),
(0x2F941, 'M', u'𥃳'),
(0x2F942, 'M', u'𥃲'),
(0x2F943, 'M', u'𥄙'),
(0x2F944, 'M', u'𥄳'),
(0x2F945, 'M', u'眞'),
(0x2F946, 'M', u'真'),
(0x2F948, 'M', u'睊'),
(0x2F949, 'M', u'䀹'),
(0x2F94A, 'M', u'瞋'),
(0x2F94B, 'M', u'䁆'),
(0x2F94C, 'M', u'䂖'),
(0x2F94D, 'M', u'𥐝'),
(0x2F94E, 'M', u'硎'),
(0x2F94F, 'M', u'碌'),
(0x2F950, 'M', u'磌'),
(0x2F951, 'M', u'䃣'),
(0x2F952, 'M', u'𥘦'),
(0x2F953, 'M', u'祖'),
(0x2F954, 'M', u'𥚚'),
(0x2F955, 'M', u'𥛅'),
]
def _seg_76():
return [
(0x2F956, 'M', u'福'),
(0x2F957, 'M', u'秫'),
(0x2F958, 'M', u'䄯'),
(0x2F959, 'M', u'穀'),
(0x2F95A, 'M', u'穊'),
(0x2F95B, 'M', u'穏'),
(0x2F95C, 'M', u'𥥼'),
(0x2F95D, 'M', u'𥪧'),
(0x2F95F, 'X'),
(0x2F960, 'M', u'䈂'),
(0x2F961, 'M', u'𥮫'),
(0x2F962, 'M', u'篆'),
(0x2F963, 'M', u'築'),
(0x2F964, 'M', u'䈧'),
(0x2F965, 'M', u'𥲀'),
(0x2F966, 'M', u'糒'),
(0x2F967, 'M', u'䊠'),
(0x2F968, 'M', u'糨'),
(0x2F969, 'M', u'糣'),
(0x2F96A, 'M', u'紀'),
(0x2F96B, 'M', u'𥾆'),
(0x2F96C, 'M', u'絣'),
(0x2F96D, 'M', u'䌁'),
(0x2F96E, 'M', u'緇'),
(0x2F96F, 'M', u'縂'),
(0x2F970, 'M', u'繅'),
(0x2F971, 'M', u'䌴'),
(0x2F972, 'M', u'𦈨'),
(0x2F973, 'M', u'𦉇'),
(0x2F974, 'M', u'䍙'),
(0x2F975, 'M', u'𦋙'),
(0x2F976, 'M', u'罺'),
(0x2F977, 'M', u'𦌾'),
(0x2F978, 'M', u'羕'),
(0x2F979, 'M', u'翺'),
(0x2F97A, 'M', u'者'),
(0x2F97B, 'M', u'𦓚'),
(0x2F97C, 'M', u'𦔣'),
(0x2F97D, 'M', u'聠'),
(0x2F97E, 'M', u'𦖨'),
(0x2F97F, 'M', u'聰'),
(0x2F980, 'M', u'𣍟'),
(0x2F981, 'M', u'䏕'),
(0x2F982, 'M', u'育'),
(0x2F983, 'M', u'脃'),
(0x2F984, 'M', u'䐋'),
(0x2F985, 'M', u'脾'),
(0x2F986, 'M', u'媵'),
(0x2F987, 'M', u'𦞧'),
(0x2F988, 'M', u'𦞵'),
(0x2F989, 'M', u'𣎓'),
(0x2F98A, 'M', u'𣎜'),
(0x2F98B, 'M', u'舁'),
(0x2F98C, 'M', u'舄'),
(0x2F98D, 'M', u'辞'),
(0x2F98E, 'M', u'䑫'),
(0x2F98F, 'M', u'芑'),
(0x2F990, 'M', u'芋'),
(0x2F991, 'M', u'芝'),
(0x2F992, 'M', u'劳'),
(0x2F993, 'M', u'花'),
(0x2F994, 'M', u'芳'),
(0x2F995, 'M', u'芽'),
(0x2F996, 'M', u'苦'),
(0x2F997, 'M', u'𦬼'),
(0x2F998, 'M', u'若'),
(0x2F999, 'M', u'茝'),
(0x2F99A, 'M', u'荣'),
(0x2F99B, 'M', u'莭'),
(0x2F99C, 'M', u'茣'),
(0x2F99D, 'M', u'莽'),
(0x2F99E, 'M', u'菧'),
(0x2F99F, 'M', u'著'),
(0x2F9A0, 'M', u'荓'),
(0x2F9A1, 'M', u'菊'),
(0x2F9A2, 'M', u'菌'),
(0x2F9A3, 'M', u'菜'),
(0x2F9A4, 'M', u'𦰶'),
(0x2F9A5, 'M', u'𦵫'),
(0x2F9A6, 'M', u'𦳕'),
(0x2F9A7, 'M', u'䔫'),
(0x2F9A8, 'M', u'蓱'),
(0x2F9A9, 'M', u'蓳'),
(0x2F9AA, 'M', u'蔖'),
(0x2F9AB, 'M', u'𧏊'),
(0x2F9AC, 'M', u'蕤'),
(0x2F9AD, 'M', u'𦼬'),
(0x2F9AE, 'M', u'䕝'),
(0x2F9AF, 'M', u'䕡'),
(0x2F9B0, 'M', u'𦾱'),
(0x2F9B1, 'M', u'𧃒'),
(0x2F9B2, 'M', u'䕫'),
(0x2F9B3, 'M', u'虐'),
(0x2F9B4, 'M', u'虜'),
(0x2F9B5, 'M', u'虧'),
(0x2F9B6, 'M', u'虩'),
(0x2F9B7, 'M', u'蚩'),
(0x2F9B8, 'M', u'蚈'),
(0x2F9B9, 'M', u'蜎'),
(0x2F9BA, 'M', u'蛢'),
]
def _seg_77():
return [
(0x2F9BB, 'M', u'蝹'),
(0x2F9BC, 'M', u'蜨'),
(0x2F9BD, 'M', u'蝫'),
(0x2F9BE, 'M', u'螆'),
(0x2F9BF, 'X'),
(0x2F9C0, 'M', u'蟡'),
(0x2F9C1, 'M', u'蠁'),
(0x2F9C2, 'M', u'䗹'),
(0x2F9C3, 'M', u'衠'),
(0x2F9C4, 'M', u'衣'),
(0x2F9C5, 'M', u'𧙧'),
(0x2F9C6, 'M', u'裗'),
(0x2F9C7, 'M', u'裞'),
(0x2F9C8, 'M', u'䘵'),
(0x2F9C9, 'M', u'裺'),
(0x2F9CA, 'M', u'㒻'),
(0x2F9CB, 'M', u'𧢮'),
(0x2F9CC, 'M', u'𧥦'),
(0x2F9CD, 'M', u'䚾'),
(0x2F9CE, 'M', u'䛇'),
(0x2F9CF, 'M', u'誠'),
(0x2F9D0, 'M', u'諭'),
(0x2F9D1, 'M', u'變'),
(0x2F9D2, 'M', u'豕'),
(0x2F9D3, 'M', u'𧲨'),
(0x2F9D4, 'M', u'貫'),
(0x2F9D5, 'M', u'賁'),
(0x2F9D6, 'M', u'贛'),
(0x2F9D7, 'M', u'起'),
(0x2F9D8, 'M', u'𧼯'),
(0x2F9D9, 'M', u'𠠄'),
(0x2F9DA, 'M', u'跋'),
(0x2F9DB, 'M', u'趼'),
(0x2F9DC, 'M', u'跰'),
(0x2F9DD, 'M', u'𠣞'),
(0x2F9DE, 'M', u'軔'),
(0x2F9DF, 'M', u'輸'),
(0x2F9E0, 'M', u'𨗒'),
(0x2F9E1, 'M', u'𨗭'),
(0x2F9E2, 'M', u'邔'),
(0x2F9E3, 'M', u'郱'),
(0x2F9E4, 'M', u'鄑'),
(0x2F9E5, 'M', u'𨜮'),
(0x2F9E6, 'M', u'鄛'),
(0x2F9E7, 'M', u'鈸'),
(0x2F9E8, 'M', u'鋗'),
(0x2F9E9, 'M', u'鋘'),
(0x2F9EA, 'M', u'鉼'),
(0x2F9EB, 'M', u'鏹'),
(0x2F9EC, 'M', u'鐕'),
(0x2F9ED, 'M', u'𨯺'),
(0x2F9EE, 'M', u'開'),
(0x2F9EF, 'M', u'䦕'),
(0x2F9F0, 'M', u'閷'),
(0x2F9F1, 'M', u'𨵷'),
(0x2F9F2, 'M', u'䧦'),
(0x2F9F3, 'M', u'雃'),
(0x2F9F4, 'M', u'嶲'),
(0x2F9F5, 'M', u'霣'),
(0x2F9F6, 'M', u'𩅅'),
(0x2F9F7, 'M', u'𩈚'),
(0x2F9F8, 'M', u'䩮'),
(0x2F9F9, 'M', u'䩶'),
(0x2F9FA, 'M', u'韠'),
(0x2F9FB, 'M', u'𩐊'),
(0x2F9FC, 'M', u'䪲'),
(0x2F9FD, 'M', u'𩒖'),
(0x2F9FE, 'M', u'頋'),
(0x2FA00, 'M', u'頩'),
(0x2FA01, 'M', u'𩖶'),
(0x2FA02, 'M', u'飢'),
(0x2FA03, 'M', u'䬳'),
(0x2FA04, 'M', u'餩'),
(0x2FA05, 'M', u'馧'),
(0x2FA06, 'M', u'駂'),
(0x2FA07, 'M', u'駾'),
(0x2FA08, 'M', u'䯎'),
(0x2FA09, 'M', u'𩬰'),
(0x2FA0A, 'M', u'鬒'),
(0x2FA0B, 'M', u'鱀'),
(0x2FA0C, 'M', u'鳽'),
(0x2FA0D, 'M', u'䳎'),
(0x2FA0E, 'M', u'䳭'),
(0x2FA0F, 'M', u'鵧'),
(0x2FA10, 'M', u'𪃎'),
(0x2FA11, 'M', u'䳸'),
(0x2FA12, 'M', u'𪄅'),
(0x2FA13, 'M', u'𪈎'),
(0x2FA14, 'M', u'𪊑'),
(0x2FA15, 'M', u'麻'),
(0x2FA16, 'M', u'䵖'),
(0x2FA17, 'M', u'黹'),
(0x2FA18, 'M', u'黾'),
(0x2FA19, 'M', u'鼅'),
(0x2FA1A, 'M', u'鼏'),
(0x2FA1B, 'M', u'鼖'),
(0x2FA1C, 'M', u'鼻'),
(0x2FA1D, 'M', u'𪘀'),
(0x2FA1E, 'X'),
(0xE0100, 'I'),
]
def _seg_78():
return [
(0xE01F0, 'X'),
]
uts46data = tuple(
_seg_0()
+ _seg_1()
+ _seg_2()
+ _seg_3()
+ _seg_4()
+ _seg_5()
+ _seg_6()
+ _seg_7()
+ _seg_8()
+ _seg_9()
+ _seg_10()
+ _seg_11()
+ _seg_12()
+ _seg_13()
+ _seg_14()
+ _seg_15()
+ _seg_16()
+ _seg_17()
+ _seg_18()
+ _seg_19()
+ _seg_20()
+ _seg_21()
+ _seg_22()
+ _seg_23()
+ _seg_24()
+ _seg_25()
+ _seg_26()
+ _seg_27()
+ _seg_28()
+ _seg_29()
+ _seg_30()
+ _seg_31()
+ _seg_32()
+ _seg_33()
+ _seg_34()
+ _seg_35()
+ _seg_36()
+ _seg_37()
+ _seg_38()
+ _seg_39()
+ _seg_40()
+ _seg_41()
+ _seg_42()
+ _seg_43()
+ _seg_44()
+ _seg_45()
+ _seg_46()
+ _seg_47()
+ _seg_48()
+ _seg_49()
+ _seg_50()
+ _seg_51()
+ _seg_52()
+ _seg_53()
+ _seg_54()
+ _seg_55()
+ _seg_56()
+ _seg_57()
+ _seg_58()
+ _seg_59()
+ _seg_60()
+ _seg_61()
+ _seg_62()
+ _seg_63()
+ _seg_64()
+ _seg_65()
+ _seg_66()
+ _seg_67()
+ _seg_68()
+ _seg_69()
+ _seg_70()
+ _seg_71()
+ _seg_72()
+ _seg_73()
+ _seg_74()
+ _seg_75()
+ _seg_76()
+ _seg_77()
+ _seg_78()
)
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/idna-2.8.dist-info/INSTALLER
================================================
pip
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/idna-2.8.dist-info/LICENSE.rst
================================================
License
-------
Copyright (c) 2013-2018, Kim Davies. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
#. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
#. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with
the distribution.
#. Neither the name of the copyright holder nor the names of the
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
#. THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
Portions of the codec implementation and unit tests are derived from the
Python standard library, which carries the `Python Software Foundation
License `_:
Copyright (c) 2001-2014 Python Software Foundation; All Rights Reserved
Portions of the unit tests are derived from the Unicode standard, which
is subject to the Unicode, Inc. License Agreement:
Copyright (c) 1991-2014 Unicode, Inc. All rights reserved.
Distributed under the Terms of Use in
.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Unicode data files and any associated documentation
(the "Data Files") or Unicode software and any associated documentation
(the "Software") to deal in the Data Files or Software
without restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, and/or sell copies of
the Data Files or Software, and to permit persons to whom the Data Files
or Software are furnished to do so, provided that
(a) this copyright and permission notice appear with all copies
of the Data Files or Software,
(b) this copyright and permission notice appear in associated
documentation, and
(c) there is clear notice in each modified Data File or in the Software
as well as in the documentation associated with the Data File(s) or
Software that the data or software has been modified.
THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THE DATA FILES OR SOFTWARE.
Except as contained in this notice, the name of a copyright holder
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in these Data Files or Software without prior
written authorization of the copyright holder.
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/idna-2.8.dist-info/METADATA
================================================
Metadata-Version: 2.1
Name: idna
Version: 2.8
Summary: Internationalized Domain Names in Applications (IDNA)
Home-page: https://github.com/kjd/idna
Author: Kim Davies
Author-email: kim@cynosure.com.au
License: BSD-like
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Topic :: Internet :: Name Service (DNS)
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
Internationalized Domain Names in Applications (IDNA)
=====================================================
Support for the Internationalised Domain Names in Applications
(IDNA) protocol as specified in `RFC 5891 `_.
This is the latest version of the protocol and is sometimes referred to as
“IDNA 2008”.
This library also provides support for Unicode Technical Standard 46,
`Unicode IDNA Compatibility Processing `_.
This acts as a suitable replacement for the “encodings.idna” module that
comes with the Python standard library, but only supports the
old, deprecated IDNA specification (`RFC 3490 `_).
Basic functions are simply executed:
.. code-block:: pycon
# Python 3
>>> import idna
>>> idna.encode('ドメイン.テスト')
b'xn--eckwd4c7c.xn--zckzah'
>>> print(idna.decode('xn--eckwd4c7c.xn--zckzah'))
ドメイン.テスト
# Python 2
>>> import idna
>>> idna.encode(u'ドメイン.テスト')
'xn--eckwd4c7c.xn--zckzah'
>>> print idna.decode('xn--eckwd4c7c.xn--zckzah')
ドメイン.テスト
Packages
--------
The latest tagged release version is published in the PyPI repository:
.. image:: https://badge.fury.io/py/idna.svg
:target: http://badge.fury.io/py/idna
Installation
------------
To install this library, you can use pip:
.. code-block:: bash
$ pip install idna
Alternatively, you can install the package using the bundled setup script:
.. code-block:: bash
$ python setup.py install
This library works with Python 2.7 and Python 3.4 or later.
Usage
-----
For typical usage, the ``encode`` and ``decode`` functions will take a domain
name argument and perform a conversion to A-labels or U-labels respectively.
.. code-block:: pycon
# Python 3
>>> import idna
>>> idna.encode('ドメイン.テスト')
b'xn--eckwd4c7c.xn--zckzah'
>>> print(idna.decode('xn--eckwd4c7c.xn--zckzah'))
ドメイン.テスト
You may use the codec encoding and decoding methods using the
``idna.codec`` module:
.. code-block:: pycon
# Python 2
>>> import idna.codec
>>> print u'домена.испытание'.encode('idna')
xn--80ahd1agd.xn--80akhbyknj4f
>>> print 'xn--80ahd1agd.xn--80akhbyknj4f'.decode('idna')
домена.испытание
Conversions can be applied at a per-label basis using the ``ulabel`` or ``alabel``
functions if necessary:
.. code-block:: pycon
# Python 2
>>> idna.alabel(u'测试')
'xn--0zwm56d'
Compatibility Mapping (UTS #46)
+++++++++++++++++++++++++++++++
As described in `RFC 5895 `_, the IDNA
specification no longer normalizes input from different potential ways a user
may input a domain name. This functionality, known as a “mapping”, is now
considered by the specification to be a local user-interface issue distinct
from IDNA conversion functionality.
This library provides one such mapping, that was developed by the Unicode
Consortium. Known as `Unicode IDNA Compatibility Processing `_,
it provides for both a regular mapping for typical applications, as well as
a transitional mapping to help migrate from older IDNA 2003 applications.
For example, “Königsgäßchen” is not a permissible label as *LATIN CAPITAL
LETTER K* is not allowed (nor are capital letters in general). UTS 46 will
convert this into lower case prior to applying the IDNA conversion.
.. code-block:: pycon
# Python 3
>>> import idna
>>> idna.encode(u'Königsgäßchen')
...
idna.core.InvalidCodepoint: Codepoint U+004B at position 1 of 'Königsgäßchen' not allowed
>>> idna.encode('Königsgäßchen', uts46=True)
b'xn--knigsgchen-b4a3dun'
>>> print(idna.decode('xn--knigsgchen-b4a3dun'))
königsgäßchen
Transitional processing provides conversions to help transition from the older
2003 standard to the current standard. For example, in the original IDNA
specification, the *LATIN SMALL LETTER SHARP S* (ß) was converted into two
*LATIN SMALL LETTER S* (ss), whereas in the current IDNA specification this
conversion is not performed.
.. code-block:: pycon
# Python 2
>>> idna.encode(u'Königsgäßchen', uts46=True, transitional=True)
'xn--knigsgsschen-lcb0w'
Implementors should use transitional processing with caution, only in rare
cases where conversion from legacy labels to current labels must be performed
(i.e. IDNA implementations that pre-date 2008). For typical applications
that just need to convert labels, transitional processing is unlikely to be
beneficial and could produce unexpected incompatible results.
``encodings.idna`` Compatibility
++++++++++++++++++++++++++++++++
Function calls from the Python built-in ``encodings.idna`` module are
mapped to their IDNA 2008 equivalents using the ``idna.compat`` module.
Simply substitute the ``import`` clause in your code to refer to the
new module name.
Exceptions
----------
All errors raised during the conversion following the specification should
raise an exception derived from the ``idna.IDNAError`` base class.
More specific exceptions that may be generated as ``idna.IDNABidiError``
when the error reflects an illegal combination of left-to-right and right-to-left
characters in a label; ``idna.InvalidCodepoint`` when a specific codepoint is
an illegal character in an IDN label (i.e. INVALID); and ``idna.InvalidCodepointContext``
when the codepoint is illegal based on its positional context (i.e. it is CONTEXTO
or CONTEXTJ but the contextual requirements are not satisfied.)
Building and Diagnostics
------------------------
The IDNA and UTS 46 functionality relies upon pre-calculated lookup tables for
performance. These tables are derived from computing against eligibility criteria
in the respective standards. These tables are computed using the command-line
script ``tools/idna-data``.
This tool will fetch relevant tables from the Unicode Consortium and perform the
required calculations to identify eligibility. It has three main modes:
* ``idna-data make-libdata``. Generates ``idnadata.py`` and ``uts46data.py``,
the pre-calculated lookup tables using for IDNA and UTS 46 conversions. Implementors
who wish to track this library against a different Unicode version may use this tool
to manually generate a different version of the ``idnadata.py`` and ``uts46data.py``
files.
* ``idna-data make-table``. Generate a table of the IDNA disposition
(e.g. PVALID, CONTEXTJ, CONTEXTO) in the format found in Appendix B.1 of RFC
5892 and the pre-computed tables published by `IANA `_.
* ``idna-data U+0061``. Prints debugging output on the various properties
associated with an individual Unicode codepoint (in this case, U+0061), that are
used to assess the IDNA and UTS 46 status of a codepoint. This is helpful in debugging
or analysis.
The tool accepts a number of arguments, described using ``idna-data -h``. Most notably,
the ``--version`` argument allows the specification of the version of Unicode to use
in computing the table data. For example, ``idna-data --version 9.0.0 make-libdata``
will generate library data against Unicode 9.0.0.
Note that this script requires Python 3, but all generated library data will work
in Python 2.7.
Testing
-------
The library has a test suite based on each rule of the IDNA specification, as
well as tests that are provided as part of the Unicode Technical Standard 46,
`Unicode IDNA Compatibility Processing `_.
The tests are run automatically on each commit at Travis CI:
.. image:: https://travis-ci.org/kjd/idna.svg?branch=master
:target: https://travis-ci.org/kjd/idna
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/idna-2.8.dist-info/RECORD
================================================
idna-2.8.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
idna-2.8.dist-info/LICENSE.rst,sha256=DUvHq9SNz7FOJCVO5AQGZzf_AWcUTiIpFKIRO4eUaD4,3947
idna-2.8.dist-info/METADATA,sha256=X4QsM_BLMPhl4gC8SEnXjvl5-gj7hvwAl7UCyR418so,8862
idna-2.8.dist-info/RECORD,,
idna-2.8.dist-info/WHEEL,sha256=CihQvCnsGZQBGAHLEUMf0IdA4fRduS_NBUTMgCTtvPM,110
idna-2.8.dist-info/top_level.txt,sha256=jSag9sEDqvSPftxOQy-ABfGV_RSy7oFh4zZJpODV8k0,5
idna/__init__.py,sha256=9Nt7xpyet3DmOrPUGooDdAwmHZZu1qUAy2EaJ93kGiQ,58
idna/__pycache__/__init__.cpython-36.pyc,,
idna/__pycache__/codec.cpython-36.pyc,,
idna/__pycache__/compat.cpython-36.pyc,,
idna/__pycache__/core.cpython-36.pyc,,
idna/__pycache__/idnadata.cpython-36.pyc,,
idna/__pycache__/intranges.cpython-36.pyc,,
idna/__pycache__/package_data.cpython-36.pyc,,
idna/__pycache__/uts46data.cpython-36.pyc,,
idna/codec.py,sha256=lvYb7yu7PhAqFaAIAdWcwgaWI2UmgseUua-1c0AsG0A,3299
idna/compat.py,sha256=R-h29D-6mrnJzbXxymrWUW7iZUvy-26TQwZ0ij57i4U,232
idna/core.py,sha256=JDCZZ_PLESqIgEbU8mPyoEufWwoOiIqygA17-QZIe3s,11733
idna/idnadata.py,sha256=HXaPFw6_YAJ0qppACPu0YLAULtRs3QovRM_CCZHGdY0,40899
idna/intranges.py,sha256=TY1lpxZIQWEP6tNqjZkFA5hgoMWOj1OBmnUG8ihT87E,1749
idna/package_data.py,sha256=kIzeKKXEouXLR4srqwf9Q3zv-NffKSOz5aSDOJARPB0,21
idna/uts46data.py,sha256=oLyNZ1pBaiBlj9zFzLFRd_P7J8MkRcgDisjExZR_4MY,198292
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/idna-2.8.dist-info/WHEEL
================================================
Wheel-Version: 1.0
Generator: bdist_wheel (0.32.2)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/idna-2.8.dist-info/top_level.txt
================================================
idna
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/incremental/__init__.py
================================================
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Versions for Python packages.
See L{Version}.
"""
from __future__ import division, absolute_import
import sys
import warnings
#
# Compat functions
#
if sys.version_info < (3, 0):
_PY3 = False
else:
_PY3 = True
try:
_cmp = cmp
except NameError:
def _cmp(a, b):
"""
Compare two objects.
Returns a negative number if C{a < b}, zero if they are equal, and a
positive number if C{a > b}.
"""
if a < b:
return -1
elif a == b:
return 0
else:
return 1
def _comparable(klass):
"""
Class decorator that ensures support for the special C{__cmp__} method.
On Python 2 this does nothing.
On Python 3, C{__eq__}, C{__lt__}, etc. methods are added to the class,
relying on C{__cmp__} to implement their comparisons.
"""
# On Python 2, __cmp__ will just work, so no need to add extra methods:
if not _PY3:
return klass
def __eq__(self, other):
c = self.__cmp__(other)
if c is NotImplemented:
return c
return c == 0
def __ne__(self, other):
c = self.__cmp__(other)
if c is NotImplemented:
return c
return c != 0
def __lt__(self, other):
c = self.__cmp__(other)
if c is NotImplemented:
return c
return c < 0
def __le__(self, other):
c = self.__cmp__(other)
if c is NotImplemented:
return c
return c <= 0
def __gt__(self, other):
c = self.__cmp__(other)
if c is NotImplemented:
return c
return c > 0
def __ge__(self, other):
c = self.__cmp__(other)
if c is NotImplemented:
return c
return c >= 0
klass.__lt__ = __lt__
klass.__gt__ = __gt__
klass.__le__ = __le__
klass.__ge__ = __ge__
klass.__eq__ = __eq__
klass.__ne__ = __ne__
return klass
#
# Versioning
#
@_comparable
class _inf(object):
"""
An object that is bigger than all other objects.
"""
def __cmp__(self, other):
"""
@param other: Another object.
@type other: any
@return: 0 if other is inf, 1 otherwise.
@rtype: C{int}
"""
if other is _inf:
return 0
return 1
_inf = _inf()
class IncomparableVersions(TypeError):
"""
Two versions could not be compared.
"""
@_comparable
class Version(object):
"""
An encapsulation of a version for a project, with support for outputting
PEP-440 compatible version strings.
This class supports the standard major.minor.micro[rcN] scheme of
versioning.
"""
def __init__(self, package, major, minor, micro, release_candidate=None,
prerelease=None, dev=None):
"""
@param package: Name of the package that this is a version of.
@type package: C{str}
@param major: The major version number.
@type major: C{int} or C{str} (for the "NEXT" symbol)
@param minor: The minor version number.
@type minor: C{int}
@param micro: The micro version number.
@type micro: C{int}
@param release_candidate: The release candidate number.
@type release_candidate: C{int}
@param prerelease: The prerelease number. (Deprecated)
@type prerelease: C{int}
@param dev: The development release number.
@type dev: C{int}
"""
if release_candidate and prerelease:
raise ValueError("Please only return one of these.")
elif prerelease and not release_candidate:
release_candidate = prerelease
warnings.warn(("Passing prerelease to incremental.Version was "
"deprecated in Incremental 16.9.0. Please pass "
"release_candidate instead."),
DeprecationWarning, stacklevel=2)
if major == "NEXT":
if minor or micro or release_candidate or dev:
raise ValueError(("When using NEXT, all other values except "
"Package must be 0."))
self.package = package
self.major = major
self.minor = minor
self.micro = micro
self.release_candidate = release_candidate
self.dev = dev
@property
def prerelease(self):
warnings.warn(("Accessing incremental.Version.prerelease was "
"deprecated in Incremental 16.9.0. Use "
"Version.release_candidate instead."),
DeprecationWarning, stacklevel=2),
return self.release_candidate
def public(self):
"""
Return a PEP440-compatible "public" representation of this L{Version}.
Examples:
- 14.4.0
- 1.2.3rc1
- 14.2.1rc1dev9
- 16.04.0dev0
"""
if self.major == "NEXT":
return self.major
if self.release_candidate is None:
rc = ""
else:
rc = "rc%s" % (self.release_candidate,)
if self.dev is None:
dev = ""
else:
dev = "dev%s" % (self.dev,)
return '%r.%d.%d%s%s' % (self.major,
self.minor,
self.micro,
rc, dev)
base = public
short = public
local = public
def __repr__(self):
if self.release_candidate is None:
release_candidate = ""
else:
release_candidate = ", release_candidate=%r" % (
self.release_candidate,)
if self.dev is None:
dev = ""
else:
dev = ", dev=%r" % (self.dev,)
return '%s(%r, %r, %d, %d%s%s)' % (
self.__class__.__name__,
self.package,
self.major,
self.minor,
self.micro,
release_candidate,
dev)
def __str__(self):
return '[%s, version %s]' % (
self.package,
self.short())
def __cmp__(self, other):
"""
Compare two versions, considering major versions, minor versions, micro
versions, then release candidates. Package names are case insensitive.
A version with a release candidate is always less than a version
without a release candidate. If both versions have release candidates,
they will be included in the comparison.
@param other: Another version.
@type other: L{Version}
@return: NotImplemented when the other object is not a Version, or one
of -1, 0, or 1.
@raise IncomparableVersions: when the package names of the versions
differ.
"""
if not isinstance(other, self.__class__):
return NotImplemented
if self.package.lower() != other.package.lower():
raise IncomparableVersions("%r != %r"
% (self.package, other.package))
if self.major == "NEXT":
major = _inf
else:
major = self.major
if self.release_candidate is None:
release_candidate = _inf
else:
release_candidate = self.release_candidate
if self.dev is None:
dev = _inf
else:
dev = self.dev
if other.major == "NEXT":
othermajor = _inf
else:
othermajor = other.major
if other.release_candidate is None:
otherrc = _inf
else:
otherrc = other.release_candidate
if other.dev is None:
otherdev = _inf
else:
otherdev = other.dev
x = _cmp((major,
self.minor,
self.micro,
release_candidate,
dev),
(othermajor,
other.minor,
other.micro,
otherrc,
otherdev))
return x
def getVersionString(version):
"""
Get a friendly string for the given version object.
@param version: A L{Version} object.
@return: A string containing the package and short version number.
"""
result = '%s %s' % (version.package, version.short())
return result
def _get_version(dist, keyword, value):
"""
Get the version from the package listed in the Distribution.
"""
if not value:
return
from distutils.command import build_py
sp_command = build_py.build_py(dist)
sp_command.finalize_options()
for item in sp_command.find_all_modules():
if item[1] == "_version":
version_file = {}
with open(item[2]) as f:
exec(f.read(), version_file)
dist.metadata.version = version_file["__version__"].public()
return None
raise Exception("No _version.py found.")
from ._version import __version__ # noqa
__all__ = ["__version__", "Version", "getVersionString"]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/incremental/_version.py
================================================
"""
Provides Incremental version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update Incremental` to change this file.
from incremental import Version
__version__ = Version('Incremental', 17, 5, 0)
__all__ = ["__version__"]
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/incremental/tests/__init__.py
================================================
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/incremental/tests/test_update.py
================================================
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for L{incremental.update}.
"""
from __future__ import division, absolute_import
import sys
import os
import datetime
from twisted.python.filepath import FilePath
from twisted.python.compat import NativeStringIO
from twisted.trial.unittest import TestCase
from incremental.update import _run, run
class NonCreatedUpdateTests(TestCase):
def setUp(self):
self.srcdir = FilePath(self.mktemp())
self.srcdir.makedirs()
packagedir = self.srcdir.child('inctestpkg')
packagedir.makedirs()
packagedir.child('__init__.py').setContent(b"""
from incremental import Version
introduced_in = Version('inctestpkg', 'NEXT', 0, 0).short()
next_released_version = "inctestpkg NEXT"
""")
self.getcwd = lambda: self.srcdir.path
self.packagedir = packagedir
class Date(object):
year = 2016
month = 8
self.date = Date()
def test_create(self):
"""
`incremental.update package --create` initialises the version.
"""
self.assertFalse(self.packagedir.child("_version.py").exists())
out = []
_run('inctestpkg', path=None, newversion=None, patch=False, rc=False,
dev=False, create=True, _date=self.date, _getcwd=self.getcwd,
_print=out.append)
self.assertTrue(self.packagedir.child("_version.py").exists())
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 16, 8, 0)
__all__ = ["__version__"]
''')
class MissingTests(TestCase):
def setUp(self):
self.srcdir = FilePath(self.mktemp())
self.srcdir.makedirs()
self.srcdir.child('srca').makedirs()
packagedir = self.srcdir.child('srca').child('inctestpkg')
packagedir.makedirs()
packagedir.child('__init__.py').setContent(b"""
from incremental import Version
introduced_in = Version('inctestpkg', 'NEXT', 0, 0).short()
next_released_version = "inctestpkg NEXT"
""")
packagedir.child('_version.py').setContent(b"""
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 3)
__all__ = ["__version__"]
""")
self.getcwd = lambda: self.srcdir.path
self.packagedir = packagedir
class Date(object):
year = 2016
month = 8
self.date = Date()
def test_path(self):
"""
`incremental.update package --dev` raises and quits if it can't find
the package.
"""
out = []
with self.assertRaises(ValueError):
_run(u'inctestpkg', path=None, newversion=None,
patch=False, rc=False, dev=True, create=False,
_date=self.date, _getcwd=self.getcwd, _print=out.append)
class CreatedUpdateInSrcTests(TestCase):
def setUp(self):
self.srcdir = FilePath(self.mktemp())
self.srcdir.makedirs()
self.srcdir.child('src').makedirs()
packagedir = self.srcdir.child('src').child('inctestpkg')
packagedir.makedirs()
packagedir.child('__init__.py').setContent(b"""
from incremental import Version
introduced_in = Version('inctestpkg', 'NEXT', 0, 0).short()
next_released_version = "inctestpkg NEXT"
""")
packagedir.child('_version.py').setContent(b"""
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 3)
__all__ = ["__version__"]
""")
self.getcwd = lambda: self.srcdir.path
self.packagedir = packagedir
class Date(object):
year = 2016
month = 8
self.date = Date()
def test_path(self):
"""
`incremental.update package --path= --dev` increments the dev
version of the package on the given path
"""
out = []
_run(u'inctestpkg', path=None, newversion=None,
patch=False, rc=False, dev=True, create=False, _date=self.date,
_getcwd=self.getcwd, _print=out.append)
self.assertTrue(self.packagedir.child("_version.py").exists())
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 3, dev=0)
__all__ = ["__version__"]
''')
_run(u'inctestpkg', path=None, newversion=None,
patch=False, rc=False, dev=True, create=False, _date=self.date,
_getcwd=self.getcwd, _print=out.append)
self.assertTrue(self.packagedir.child("_version.py").exists())
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 3, dev=1)
__all__ = ["__version__"]
''')
class CreatedUpdateTests(TestCase):
maxDiff = None
def setUp(self):
self.srcdir = FilePath(self.mktemp())
self.srcdir.makedirs()
packagedir = self.srcdir.child('inctestpkg')
packagedir.makedirs()
packagedir.child('__init__.py').setContent(b"""
from incremental import Version
introduced_in = Version('inctestpkg', 'NEXT', 0, 0).short()
next_released_version = "inctestpkg NEXT"
""")
packagedir.child('_version.py').setContent(b"""
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 3)
__all__ = ["__version__"]
""")
self.getcwd = lambda: self.srcdir.path
self.packagedir = packagedir
class Date(object):
year = 2016
month = 8
self.date = Date()
def test_path(self):
"""
`incremental.update package --path= --dev` increments the dev
version of the package on the given path
"""
out = []
_run(u'inctestpkg', path=self.packagedir.path, newversion=None,
patch=False, rc=False, dev=True, create=False, _date=self.date,
_print=out.append)
self.assertTrue(self.packagedir.child("_version.py").exists())
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 3, dev=0)
__all__ = ["__version__"]
''')
def test_dev(self):
"""
`incremental.update package --dev` increments the dev version.
"""
out = []
_run(u'inctestpkg', path=None, newversion=None, patch=False, rc=False,
dev=True, create=False, _date=self.date, _getcwd=self.getcwd,
_print=out.append)
self.assertTrue(self.packagedir.child("_version.py").exists())
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 3, dev=0)
__all__ = ["__version__"]
''')
def test_patch(self):
"""
`incremental.update package --patch` increments the patch version.
"""
out = []
_run(u'inctestpkg', path=None, newversion=None, patch=True, rc=False,
dev=False, create=False, _date=self.date, _getcwd=self.getcwd,
_print=out.append)
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 4)
__all__ = ["__version__"]
''')
self.assertEqual(self.packagedir.child("__init__.py").getContent(),
b"""
from incremental import Version
introduced_in = Version('inctestpkg', 1, 2, 4).short()
next_released_version = "inctestpkg 1.2.4"
""")
def test_patch_with_prerelease_and_dev(self):
"""
`incremental.update package --patch` increments the patch version, and
disregards any old prerelease/dev versions.
"""
self.packagedir.child('_version.py').setContent(b"""
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 3, release_candidate=1, dev=2)
__all__ = ["__version__"]
""")
out = []
_run(u'inctestpkg', path=None, newversion=None, patch=True, rc=False,
dev=False, create=False, _date=self.date, _getcwd=self.getcwd,
_print=out.append)
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 4)
__all__ = ["__version__"]
''')
def test_rc_patch(self):
"""
`incremental.update package --patch --rc` increments the patch
version and makes it a release candidate.
"""
out = []
_run(u'inctestpkg', path=None, newversion=None, patch=True, rc=True,
dev=False, create=False, _date=self.date, _getcwd=self.getcwd,
_print=out.append)
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 4, release_candidate=1)
__all__ = ["__version__"]
''')
self.assertEqual(self.packagedir.child("__init__.py").getContent(),
b"""
from incremental import Version
introduced_in = Version('inctestpkg', 1, 2, 4, release_candidate=1).short()
next_released_version = "inctestpkg 1.2.4rc1"
""")
def test_rc_with_existing_rc(self):
"""
`incremental.update package --rc` increments the rc version if the
existing version is an rc, and discards any dev version.
"""
self.packagedir.child('_version.py').setContent(b"""
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 3, release_candidate=1, dev=2)
__all__ = ["__version__"]
""")
out = []
_run(u'inctestpkg', path=None, newversion=None, patch=False, rc=True,
dev=False, create=False, _date=self.date, _getcwd=self.getcwd,
_print=out.append)
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 3, release_candidate=2)
__all__ = ["__version__"]
''')
self.assertEqual(self.packagedir.child("__init__.py").getContent(),
b"""
from incremental import Version
introduced_in = Version('inctestpkg', 1, 2, 3, release_candidate=2).short()
next_released_version = "inctestpkg 1.2.3rc2"
""")
def test_rc_with_no_rc(self):
"""
`incremental.update package --rc`, when the package is not a release
candidate, will issue a new major/minor rc, and disregards the micro
and dev.
"""
self.packagedir.child('_version.py').setContent(b"""
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 3, dev=2)
__all__ = ["__version__"]
""")
out = []
_run(u'inctestpkg', path=None, newversion=None, patch=False, rc=True,
dev=False, create=False, _date=self.date, _getcwd=self.getcwd,
_print=out.append)
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 16, 8, 0, release_candidate=1)
__all__ = ["__version__"]
''')
self.assertEqual(self.packagedir.child("__init__.py").getContent(),
b"""
from incremental import Version
introduced_in = Version('inctestpkg', 16, 8, 0, release_candidate=1).short()
next_released_version = "inctestpkg 16.8.0rc1"
""")
def test_full_with_rc(self):
"""
`incremental.update package`, when the package is a release
candidate, will issue the major/minor, sans release candidate or dev.
"""
out = []
_run(u'inctestpkg', path=None, newversion=None, patch=False, rc=True,
dev=False, create=False, _date=self.date, _getcwd=self.getcwd,
_print=out.append)
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 16, 8, 0, release_candidate=1)
__all__ = ["__version__"]
''')
self.assertEqual(self.packagedir.child("__init__.py").getContent(),
b"""
from incremental import Version
introduced_in = Version('inctestpkg', 16, 8, 0, release_candidate=1).short()
next_released_version = "inctestpkg 16.8.0rc1"
""")
_run(u'inctestpkg', path=None, newversion=None, patch=False, rc=False,
dev=False, create=False, _date=self.date, _getcwd=self.getcwd,
_print=out.append)
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 16, 8, 0)
__all__ = ["__version__"]
''')
self.assertEqual(self.packagedir.child("__init__.py").getContent(),
b"""
from incremental import Version
introduced_in = Version('inctestpkg', 16, 8, 0).short()
next_released_version = "inctestpkg 16.8.0"
""")
def test_full_without_rc(self):
"""
`incremental.update package`, when the package is NOT a release
candidate, will raise an error.
"""
out = []
with self.assertRaises(ValueError) as e:
_run(u'inctestpkg', path=None, newversion=None, patch=False,
rc=False, dev=False, create=False, _date=self.date,
_getcwd=self.getcwd, _print=out.append)
self.assertEqual(
e.exception.args[0],
"You need to issue a rc before updating the major/minor")
def test_no_mix_newversion(self):
"""
The `--newversion` flag can't be mixed with --patch, --rc, or --dev.
"""
out = []
with self.assertRaises(ValueError) as e:
_run(u'inctestpkg', path=None, newversion="1", patch=True,
rc=False, dev=False, create=False, _date=self.date,
_getcwd=self.getcwd, _print=out.append)
self.assertEqual(e.exception.args[0], "Only give --newversion")
with self.assertRaises(ValueError) as e:
_run(u'inctestpkg', path=None, newversion="1", patch=False,
rc=True, dev=False, create=False, _date=self.date,
_getcwd=self.getcwd, _print=out.append)
self.assertEqual(e.exception.args[0], "Only give --newversion")
with self.assertRaises(ValueError) as e:
_run(u'inctestpkg', path=None, newversion="1", patch=False,
rc=False, dev=True, create=False, _date=self.date,
_getcwd=self.getcwd, _print=out.append)
self.assertEqual(e.exception.args[0], "Only give --newversion")
def test_no_mix_dev(self):
"""
The `--dev` flag can't be mixed with --patch, or --rc.
"""
out = []
with self.assertRaises(ValueError) as e:
_run(u'inctestpkg', path=None, newversion=None, patch=True,
rc=False, dev=True, create=False, _date=self.date,
_getcwd=self.getcwd, _print=out.append)
self.assertEqual(e.exception.args[0], "Only give --dev")
with self.assertRaises(ValueError) as e:
_run(u'inctestpkg', path=None, newversion=None, patch=False,
rc=True, dev=True, create=False, _date=self.date,
_getcwd=self.getcwd, _print=out.append)
self.assertEqual(e.exception.args[0], "Only give --dev")
def test_no_mix_create(self):
"""
The `--create` flag can't be mixed with --patch, --rc, --dev, or
--newversion.
"""
out = []
with self.assertRaises(ValueError) as e:
_run(u'inctestpkg', path=None, newversion=None, patch=True,
rc=False, dev=False, create=True, _date=self.date,
_getcwd=self.getcwd, _print=out.append)
self.assertEqual(e.exception.args[0], "Only give --create")
with self.assertRaises(ValueError) as e:
_run(u'inctestpkg', path=None, newversion="1", patch=False,
rc=False, dev=False, create=True, _date=self.date,
_getcwd=self.getcwd, _print=out.append)
self.assertEqual(e.exception.args[0], "Only give --create")
with self.assertRaises(ValueError) as e:
_run(u'inctestpkg', path=None, newversion=None, patch=False,
rc=True, dev=False, create=True, _date=self.date,
_getcwd=self.getcwd, _print=out.append)
self.assertEqual(e.exception.args[0], "Only give --create")
with self.assertRaises(ValueError) as e:
_run(u'inctestpkg', path=None, newversion=None, patch=False,
rc=False, dev=True, create=True, _date=self.date,
_getcwd=self.getcwd, _print=out.append)
self.assertEqual(e.exception.args[0], "Only give --create")
def test_newversion(self):
"""
`incremental.update package --newversion=1.2.3rc1dev3`, will set that
version in the package.
"""
out = []
_run(u'inctestpkg', path=None, newversion="1.2.3rc1dev3", patch=False,
rc=False, dev=False, create=False, _date=self.date,
_getcwd=self.getcwd, _print=out.append)
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 3, release_candidate=1, dev=3)
__all__ = ["__version__"]
''')
self.assertEqual(self.packagedir.child("__init__.py").getContent(),
(b"""
from incremental import Version
introduced_in = Version('inctestpkg', 1, 2, 3, """
b"""release_candidate=1, dev=3).short()
next_released_version = "inctestpkg 1.2.3rc1dev3"
"""))
def test_newversion_bare(self):
"""
`incremental.update package --newversion=1`, will set that
version in the package.
"""
out = []
_run(u'inctestpkg', path=None, newversion="1", patch=False,
rc=False, dev=False, create=False, _date=self.date,
_getcwd=self.getcwd, _print=out.append)
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 1, 0, 0)
__all__ = ["__version__"]
''')
self.assertEqual(self.packagedir.child("__init__.py").getContent(),
b"""
from incremental import Version
introduced_in = Version('inctestpkg', 1, 0, 0).short()
next_released_version = "inctestpkg 1.0.0"
""")
class ScriptTests(TestCase):
def setUp(self):
self.srcdir = FilePath(self.mktemp())
self.srcdir.makedirs()
self.srcdir.child('src').makedirs()
packagedir = self.srcdir.child('src').child('inctestpkg')
packagedir.makedirs()
packagedir.child('__init__.py').setContent(b"""
from incremental import Version
introduced_in = Version('inctestpkg', 'NEXT', 0, 0).short()
next_released_version = "inctestpkg NEXT"
""")
packagedir.child('_version.py').setContent(b"""
from incremental import Version
__version__ = Version('inctestpkg', 1, 2, 3)
__all__ = ["__version__"]
""")
self.getcwd = lambda: self.srcdir.path
self.packagedir = packagedir
class Date(object):
year = 2016
month = 8
class DateModule(object):
def today(self):
return Date()
self.date = DateModule()
def test_run(self):
"""
Calling run() with no args will cause it to print help.
"""
stringio = NativeStringIO()
self.patch(sys, 'stdout', stringio)
with self.assertRaises(SystemExit) as e:
run(["--help"])
self.assertEqual(e.exception.args[0], 0)
self.assertIn("Show this message and exit", stringio.getvalue())
def test_insufficient_args(self):
"""
Calling run() with no args will cause it to print help.
"""
stringio = NativeStringIO()
self.patch(sys, 'stdout', stringio)
self.patch(os, 'getcwd', self.getcwd)
self.patch(datetime, 'date', self.date)
with self.assertRaises(SystemExit) as e:
run(["inctestpkg", "--rc"])
self.assertEqual(e.exception.args[0], 0)
self.assertIn("Updating codebase", stringio.getvalue())
self.assertEqual(self.packagedir.child("_version.py").getContent(),
b'''"""
Provides inctestpkg version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update inctestpkg` to change this file.
from incremental import Version
__version__ = Version('inctestpkg', 16, 8, 0, release_candidate=1)
__all__ = ["__version__"]
''')
self.assertEqual(self.packagedir.child("__init__.py").getContent(),
b"""
from incremental import Version
introduced_in = Version('inctestpkg', 16, 8, 0, release_candidate=1).short()
next_released_version = "inctestpkg 16.8.0rc1"
""")
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/incremental/tests/test_version.py
================================================
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for L{incremental}.
"""
from __future__ import division, absolute_import
import operator
from incremental import getVersionString, IncomparableVersions
from incremental import Version, _inf
from twisted.trial.unittest import TestCase
class VersionsTests(TestCase):
def test_localIsShort(self):
"""
The local version is the same as the short version.
"""
va = Version("dummy", 1, 0, 0, release_candidate=1, dev=3)
self.assertEqual(va.local(), va.short())
def test_versionComparison(self):
"""
Versions can be compared for equality and order.
"""
va = Version("dummy", 1, 0, 0)
vb = Version("dummy", 0, 1, 0)
self.assertTrue(va > vb)
self.assertTrue(vb < va)
self.assertTrue(va >= vb)
self.assertTrue(vb <= va)
self.assertTrue(va != vb)
self.assertTrue(vb == Version("dummy", 0, 1, 0))
self.assertTrue(vb == vb)
def test_versionComparisonCaseInsensitive(self):
"""
Version package names are case insensitive.
"""
va = Version("dummy", 1, 0, 0)
vb = Version("DuMmY", 0, 1, 0)
self.assertTrue(va > vb)
self.assertTrue(vb < va)
self.assertTrue(va >= vb)
self.assertTrue(vb <= va)
self.assertTrue(va != vb)
self.assertTrue(vb == Version("dummy", 0, 1, 0))
self.assertTrue(vb == vb)
def test_comparingNEXTReleases(self):
"""
NEXT releases are always larger than numbered releases.
"""
va = Version("whatever", "NEXT", 0, 0)
vb = Version("whatever", 1, 0, 0)
self.assertTrue(va > vb)
self.assertFalse(va < vb)
self.assertNotEquals(vb, va)
def test_NEXTMustBeAlone(self):
"""
NEXT releases must always have the rest of the numbers set to 0.
"""
with self.assertRaises(ValueError):
Version("whatever", "NEXT", 1, 0, release_candidate=0, dev=0)
with self.assertRaises(ValueError):
Version("whatever", "NEXT", 0, 1, release_candidate=0, dev=0)
with self.assertRaises(ValueError):
Version("whatever", "NEXT", 0, 0, release_candidate=1, dev=0)
with self.assertRaises(ValueError):
Version("whatever", "NEXT", 0, 0, release_candidate=0, dev=1)
def test_comparingNEXTReleasesEqual(self):
"""
NEXT releases are equal to each other.
"""
va = Version("whatever", "NEXT", 0, 0)
vb = Version("whatever", "NEXT", 0, 0)
self.assertEquals(vb, va)
def test_comparingPrereleasesWithReleases(self):
"""
Prereleases are always less than versions without prereleases.
"""
va = Version("whatever", 1, 0, 0, prerelease=1)
vb = Version("whatever", 1, 0, 0)
self.assertTrue(va < vb)
self.assertFalse(va > vb)
self.assertNotEquals(vb, va)
def test_prereleaseDeprecated(self):
"""
Passing 'prerelease' to Version is deprecated.
"""
Version("whatever", 1, 0, 0, prerelease=1)
warnings = self.flushWarnings([self.test_prereleaseDeprecated])
self.assertEqual(len(warnings), 1)
self.assertEqual(
warnings[0]['message'],
("Passing prerelease to incremental.Version was deprecated in "
"Incremental 16.9.0. Please pass release_candidate instead."))
def test_prereleaseAttributeDeprecated(self):
"""
Accessing 'prerelease' on a Version is deprecated.
"""
va = Version("whatever", 1, 0, 0, release_candidate=1)
va.prerelease
warnings = self.flushWarnings(
[self.test_prereleaseAttributeDeprecated])
self.assertEqual(len(warnings), 1)
self.assertEqual(
warnings[0]['message'],
("Accessing incremental.Version.prerelease was deprecated in "
"Incremental 16.9.0. Use Version.release_candidate instead."))
def test_comparingReleaseCandidatesWithReleases(self):
"""
Release Candidates are always less than versions without release
candidates.
"""
va = Version("whatever", 1, 0, 0, release_candidate=1)
vb = Version("whatever", 1, 0, 0)
self.assertTrue(va < vb)
self.assertFalse(va > vb)
self.assertNotEquals(vb, va)
def test_comparingDevReleasesWithReleases(self):
"""
Dev releases are always less than versions without dev releases.
"""
va = Version("whatever", 1, 0, 0, dev=1)
vb = Version("whatever", 1, 0, 0)
self.assertTrue(va < vb)
self.assertFalse(va > vb)
self.assertNotEquals(vb, va)
def test_rcEqualspre(self):
"""
Release Candidates are equal to prereleases.
"""
va = Version("whatever", 1, 0, 0, release_candidate=1)
vb = Version("whatever", 1, 0, 0, prerelease=1)
self.assertTrue(va == vb)
self.assertFalse(va != vb)
def test_rcOrpreButNotBoth(self):
"""
Release Candidate and prerelease can't both be given.
"""
with self.assertRaises(ValueError):
Version("whatever", 1, 0, 0,
prerelease=1, release_candidate=1)
def test_comparingReleaseCandidates(self):
"""
The value specified as the release candidate is used in version
comparisons.
"""
va = Version("whatever", 1, 0, 0, release_candidate=1)
vb = Version("whatever", 1, 0, 0, release_candidate=2)
self.assertTrue(va < vb)
self.assertTrue(vb > va)
self.assertTrue(va <= vb)
self.assertTrue(vb >= va)
self.assertTrue(va != vb)
self.assertTrue(vb == Version("whatever", 1, 0, 0,
release_candidate=2))
self.assertTrue(va == va)
def test_comparingDev(self):
"""
The value specified as the dev release is used in version comparisons.
"""
va = Version("whatever", 1, 0, 0, dev=1)
vb = Version("whatever", 1, 0, 0, dev=2)
self.assertTrue(va < vb)
self.assertTrue(vb > va)
self.assertTrue(va <= vb)
self.assertTrue(vb >= va)
self.assertTrue(va != vb)
self.assertTrue(vb == Version("whatever", 1, 0, 0,
dev=2))
self.assertTrue(va == va)
def test_comparingDevAndRC(self):
"""
The value specified as the dev release and release candidate is used in
version comparisons.
"""
va = Version("whatever", 1, 0, 0, release_candidate=1, dev=1)
vb = Version("whatever", 1, 0, 0, release_candidate=1, dev=2)
self.assertTrue(va < vb)
self.assertTrue(vb > va)
self.assertTrue(va <= vb)
self.assertTrue(vb >= va)
self.assertTrue(va != vb)
self.assertTrue(vb == Version("whatever", 1, 0, 0,
release_candidate=1, dev=2))
self.assertTrue(va == va)
def test_comparingDevAndRCDifferent(self):
"""
The value specified as the dev release and release candidate is used in
version comparisons.
"""
va = Version("whatever", 1, 0, 0, release_candidate=1, dev=1)
vb = Version("whatever", 1, 0, 0, release_candidate=2, dev=1)
self.assertTrue(va < vb)
self.assertTrue(vb > va)
self.assertTrue(va <= vb)
self.assertTrue(vb >= va)
self.assertTrue(va != vb)
self.assertTrue(vb == Version("whatever", 1, 0, 0,
release_candidate=2, dev=1))
self.assertTrue(va == va)
def test_infComparison(self):
"""
L{_inf} is equal to L{_inf}.
This is a regression test.
"""
self.assertEqual(_inf, _inf)
def test_disallowBuggyComparisons(self):
"""
The package names of the Version objects need to be the same.
"""
self.assertRaises(IncomparableVersions,
operator.eq,
Version("dummy", 1, 0, 0),
Version("dumym", 1, 0, 0))
def test_notImplementedComparisons(self):
"""
Comparing a L{Version} to some other object type results in
C{NotImplemented}.
"""
va = Version("dummy", 1, 0, 0)
vb = ("dummy", 1, 0, 0) # a tuple is not a Version object
self.assertEqual(va.__cmp__(vb), NotImplemented)
def test_repr(self):
"""
Calling C{repr} on a version returns a human-readable string
representation of the version.
"""
self.assertEqual(repr(Version("dummy", 1, 2, 3)),
"Version('dummy', 1, 2, 3)")
def test_reprWithPrerelease(self):
"""
Calling C{repr} on a version with a prerelease returns a human-readable
string representation of the version including the prerelease as a
release candidate..
"""
self.assertEqual(repr(Version("dummy", 1, 2, 3, prerelease=4)),
"Version('dummy', 1, 2, 3, release_candidate=4)")
def test_reprWithReleaseCandidate(self):
"""
Calling C{repr} on a version with a release candidate returns a
human-readable string representation of the version including the rc.
"""
self.assertEqual(repr(Version("dummy", 1, 2, 3, release_candidate=4)),
"Version('dummy', 1, 2, 3, release_candidate=4)")
def test_devWithReleaseCandidate(self):
"""
Calling C{repr} on a version with a dev release returns a
human-readable string representation of the version including the dev
release.
"""
self.assertEqual(repr(Version("dummy", 1, 2, 3, dev=4)),
"Version('dummy', 1, 2, 3, dev=4)")
def test_str(self):
"""
Calling C{str} on a version returns a human-readable string
representation of the version.
"""
self.assertEqual(str(Version("dummy", 1, 2, 3)),
"[dummy, version 1.2.3]")
def test_strWithPrerelease(self):
"""
Calling C{str} on a version with a prerelease includes the prerelease
as a release candidate.
"""
self.assertEqual(str(Version("dummy", 1, 0, 0, prerelease=1)),
"[dummy, version 1.0.0rc1]")
def test_strWithReleaseCandidate(self):
"""
Calling C{str} on a version with a release candidate includes the
release candidate.
"""
self.assertEqual(str(Version("dummy", 1, 0, 0, release_candidate=1)),
"[dummy, version 1.0.0rc1]")
def test_strWithDevAndReleaseCandidate(self):
"""
Calling C{str} on a version with a release candidate and dev release
includes the release candidate and the dev release.
"""
self.assertEqual(str(Version("dummy", 1, 0, 0,
release_candidate=1, dev=2)),
"[dummy, version 1.0.0rc1dev2]")
def test_strWithDev(self):
"""
Calling C{str} on a version with a dev release includes the dev
release.
"""
self.assertEqual(str(Version("dummy", 1, 0, 0, dev=1)),
"[dummy, version 1.0.0dev1]")
def testShort(self):
self.assertEqual(Version('dummy', 1, 2, 3).short(), '1.2.3')
def test_getVersionString(self):
"""
L{getVersionString} returns a string with the package name and the
short version number.
"""
self.assertEqual(
'Twisted 8.0.0', getVersionString(Version('Twisted', 8, 0, 0)))
def test_getVersionStringWithPrerelease(self):
"""
L{getVersionString} includes the prerelease as a release candidate, if
any.
"""
self.assertEqual(
getVersionString(Version("whatever", 8, 0, 0, prerelease=1)),
"whatever 8.0.0rc1")
def test_getVersionStringWithReleaseCandidate(self):
"""
L{getVersionString} includes the release candidate, if any.
"""
self.assertEqual(
getVersionString(Version("whatever", 8, 0, 0,
release_candidate=1)),
"whatever 8.0.0rc1")
def test_getVersionStringWithDev(self):
"""
L{getVersionString} includes the dev release, if any.
"""
self.assertEqual(
getVersionString(Version("whatever", 8, 0, 0,
dev=1)),
"whatever 8.0.0dev1")
def test_getVersionStringWithDevAndRC(self):
"""
L{getVersionString} includes the dev release and release candidate, if
any.
"""
self.assertEqual(
getVersionString(Version("whatever", 8, 0, 0,
release_candidate=2, dev=1)),
"whatever 8.0.0rc2dev1")
def test_baseWithNEXT(self):
"""
The C{base} method returns just "NEXT" when NEXT is the major version.
"""
self.assertEqual(Version("foo", "NEXT", 0, 0).base(), "NEXT")
def test_base(self):
"""
The C{base} method returns a very simple representation of the version.
"""
self.assertEqual(Version("foo", 1, 0, 0).base(), "1.0.0")
def test_baseWithPrerelease(self):
"""
The base version includes 'rcX' for versions with prereleases.
"""
self.assertEqual(Version("foo", 1, 0, 0, prerelease=8).base(),
"1.0.0rc8")
def test_baseWithDev(self):
"""
The base version includes 'devX' for versions with dev releases.
"""
self.assertEqual(Version("foo", 1, 0, 0, dev=8).base(),
"1.0.0dev8")
def test_baseWithReleaseCandidate(self):
"""
The base version includes 'rcX' for versions with prereleases.
"""
self.assertEqual(Version("foo", 1, 0, 0, release_candidate=8).base(),
"1.0.0rc8")
def test_baseWithDevAndRC(self):
"""
The base version includes 'rcXdevX' for versions with dev releases and
a release candidate.
"""
self.assertEqual(Version("foo", 1, 0, 0,
release_candidate=2, dev=8).base(),
"1.0.0rc2dev8")
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/incremental/update.py
================================================
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
from __future__ import absolute_import, division, print_function
import click
import os
import datetime
from incremental import Version
from twisted.python.filepath import FilePath
_VERSIONPY_TEMPLATE = '''"""
Provides %s version information.
"""
# This file is auto-generated! Do not edit!
# Use `python -m incremental.update %s` to change this file.
from incremental import Version
__version__ = %s
__all__ = ["__version__"]
'''
_YEAR_START = 2000
def _findPath(path, package):
cwd = FilePath(path)
src_dir = cwd.child("src").child(package.lower())
current_dir = cwd.child(package.lower())
if src_dir.isdir():
return src_dir
elif current_dir.isdir():
return current_dir
else:
raise ValueError(("Can't find under `./src` or `./`. Check the "
"package name is right (note that we expect your "
"package name to be lower cased), or pass it using "
"'--path'."))
def _existing_version(path):
version_info = {}
with path.child("_version.py").open('r') as f:
exec(f.read(), version_info)
return version_info["__version__"]
def _run(package, path, newversion, patch, rc, dev, create,
_date=None, _getcwd=None, _print=print):
if not _getcwd:
_getcwd = os.getcwd
if not _date:
_date = datetime.date.today()
if type(package) != str:
package = package.encode('utf8')
if not path:
path = _findPath(_getcwd(), package)
else:
path = FilePath(path)
if newversion and patch or newversion and dev or newversion and rc:
raise ValueError("Only give --newversion")
if dev and patch or dev and rc:
raise ValueError("Only give --dev")
if create and dev or create and patch or create and rc or \
create and newversion:
raise ValueError("Only give --create")
if newversion:
from pkg_resources import parse_version
existing = _existing_version(path)
st_version = parse_version(newversion)._version
release = list(st_version.release)
if len(release) == 1:
release.append(0)
if len(release) == 2:
release.append(0)
v = Version(
package, *release,
release_candidate=st_version.pre[1] if st_version.pre else None,
dev=st_version.dev[1] if st_version.dev else None)
elif create:
v = Version(package, _date.year - _YEAR_START, _date.month, 0)
existing = v
elif rc and not patch:
existing = _existing_version(path)
if existing.release_candidate:
v = Version(package, existing.major, existing.minor,
existing.micro, existing.release_candidate + 1)
else:
v = Version(package, _date.year - _YEAR_START, _date.month, 0, 1)
elif patch:
if rc:
rc = 1
else:
rc = None
existing = _existing_version(path)
v = Version(package, existing.major, existing.minor,
existing.micro + 1, rc)
elif dev:
existing = _existing_version(path)
if existing.dev is None:
_dev = 0
else:
_dev = existing.dev + 1
v = Version(package, existing.major, existing.minor,
existing.micro, existing.release_candidate, dev=_dev)
else:
existing = _existing_version(path)
if existing.release_candidate:
v = Version(package,
existing.major, existing.minor, existing.micro)
else:
raise ValueError(
"You need to issue a rc before updating the major/minor")
NEXT_repr = repr(Version(package, "NEXT", 0, 0)).split("#")[0]
NEXT_repr_bytes = NEXT_repr.encode('utf8')
version_repr = repr(v).split("#")[0]
version_repr_bytes = version_repr.encode('utf8')
existing_version_repr = repr(existing).split("#")[0]
existing_version_repr_bytes = existing_version_repr.encode('utf8')
_print("Updating codebase to %s" % (v.public()))
for x in path.walk():
if not x.isfile():
continue
original_content = x.getContent()
content = original_content
# Replace previous release_candidate calls to the new one
if existing.release_candidate:
content = content.replace(existing_version_repr_bytes,
version_repr_bytes)
content = content.replace(
(package.encode('utf8') + b" " +
existing.public().encode('utf8')),
(package.encode('utf8') + b" " +
v.public().encode('utf8')))
# Replace NEXT Version calls with the new one
content = content.replace(NEXT_repr_bytes,
version_repr_bytes)
content = content.replace(NEXT_repr_bytes.replace(b"'", b'"'),
version_repr_bytes)
# Replace NEXT with
content = content.replace(package.encode('utf8') + b" NEXT",
(package.encode('utf8') + b" " +
v.public().encode('utf8')))
if content != original_content:
_print("Updating %s" % (x.path,))
with x.open('w') as f:
f.write(content)
_print("Updating %s/_version.py" % (path.path))
with path.child("_version.py").open('w') as f:
f.write(
(_VERSIONPY_TEMPLATE % (
package, package, version_repr)).encode('utf8'))
@click.command()
@click.argument('package')
@click.option('--path', default=None)
@click.option('--newversion', default=None)
@click.option('--patch', is_flag=True)
@click.option('--rc', is_flag=True)
@click.option('--dev', is_flag=True)
@click.option('--create', is_flag=True)
def run(*args, **kwargs):
return _run(*args, **kwargs)
if __name__ == '__main__': # pragma: no cover
run()
================================================
FILE: stackoverflow/venv/lib/python3.6/site-packages/incremental-17.5.0.dist-info/DESCRIPTION.rst
================================================
Incremental
===========
|travis|
|pypi|
|coverage|
Incremental is a small library that versions your Python projects.
API documentation can be found `here `_.
Quick Start
-----------
Add this to your ``setup.py``\ 's ``setup()`` call, removing any other versioning arguments:
.. code::
setup(
use_incremental=True,
setup_requires=['incremental'],
install_requires=['incremental'], # along with any other install dependencies
...
}
Then run ``python -m incremental.update --create`` (you will need ``click`` installed from PyPI).
It will create a file in your package named ``_version.py`` and look like this:
.. code::
from incremental import Version
__version__ = Version("widgetbox", 17, 1, 0)
__all__ = ["__version__"]
Then, so users of your project can find your version, in your root package's ``__init__.py`` add:
.. code::
from ._version import __version__
Subsequent installations of your project will then use Incremental for versioning.
Incremental Versions
--------------------
``incremental.Version`` is a class that represents a version of a given project.
It is made up of the following elements (which are given during instantiation):
- ``package`` (required), the name of the package this ``Version`` represents.
- ``major``, ``minor``, ``micro`` (all required), the X.Y.Z of your project's ``Version``.
- ``release_candidate`` (optional), set to 0 or higher to mark this ``Version`` being of a release candidate (also sometimes called a "prerelease").
- ``dev`` (optional), set to 0 or higher to mark this ``Version`` as a development release.
You can extract a PEP-440 compatible version string by using the following methods:
- ``.local()``, which returns a ``str`` containing the full version plus any Git or SVN information, if available. An example output would be ``"17.1.1rc1+r123"`` or ``"3.7.0+rb2e812003b5d5fcf08efd1dffed6afa98d44ac8c"``.
- ``.public()``, which returns a ``str`` containing the full version, without any Git or SVN information. This is the version you should provide to users, or publicly use. An example output would be ``"13.2.0"``, ``"17.1.2dev1"``, or ``"18.8.0rc2"``.
Calling ``repr()`` with a ``Version`` will give a Python-source-code representation of it, and calling ``str()`` with a ``Version`` will provide a string similar to ``'[Incremental, version 16.10.1]'``.
Updating
--------
Incremental includes a tool to automate updating your Incremental-using project's version called ``incremental.update``.
It updates the ``_version.py`` file and automatically updates some uses of Incremental versions from an indeterminate version to the current one.
It requires ``click`` from PyPI.
``python -m incremental.update `` will perform updates on that package.
The commands that can be given after that will determine what the next version is.
- ``--newversion=``, to set the project version to a fully-specified version (like 1.2.3, or 17.1.0dev1).
- ``--rc``, to set the project version to ``..0rc1`` if the current version is not a release candidate, or bump the release candidate number by 1 if it is.
- ``--dev``, to set the project development release number to 0 if it is not a development release, or bump the development release number by 1 if it is.
- ``--patch``, to increment the patch number of the release. This will also reset the release candidate number, pass ``--rc`` at the same time to increment the patch number and make it a release candidate.
If you give no arguments, it will strip the release candidate number, making it a "full release".
Incremental supports "indeterminate" versions, as a stand-in for the next "full" version. This can be used when the version which will be displayed to the end-user is unknown (for example "introduced in" or "deprecated in"). Incremental supports the following indeterminate versions:
- ``Version("