diff --git a/.flake8 b/.flake8 new file mode 100644 index 000000000..5c1184f3e --- /dev/null +++ b/.flake8 @@ -0,0 +1,9 @@ +[flake8] +max-line-length = 88 +# E203: whitespace before ':' — black formats slices this way +# E402: module level import not at top — spyne uses logging setup before imports throughout +# W503: line break before binary operator — black preference +extend-ignore = E203, E402, W503 +per-file-ignores = + # __init__.py files intentionally re-export symbols from submodules + */__init__.py: F401, F403, F811 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..e1e58aba6 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,28 @@ +name: Tests + +on: + push: + pull_request: + +jobs: + unit-tests: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install pipenv + run: pip install pipenv + + - name: Install dependencies + run: | + pipenv install --dev + pipenv run pip install . + + - name: Run tests + run: pipenv run make test-isolated diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..9df87a5dd --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,18 @@ +variables: + KUBERNETES_MEMORY_REQUEST_DEFAULT: "2000Mi" + KUBERNETES_MEMORY_LIMIT_DEFAULT: "2000Mi" + CODE_QUALITY: false + +include: + - component: $CI_SERVER_FQDN/gitlab-ci/ci-toolbox/python-library@1.0.93 + + +unit-tests: + script: + # Install packages + - pip install pipenv + - pipenv install --dev + - pipenv run pip install . + + # Run tests + - pipenv run make test-isolated diff --git a/.pydev/base.conf b/.pydev/base.conf new file mode 100644 index 000000000..ac116845b --- /dev/null +++ b/.pydev/base.conf @@ -0,0 +1,16 @@ +VERSION_FILES=pyproject.toml + +ALIASES = '{ + "install": { + "command": "sh \"pipenv install && pipenv run pip install .\"", + "description": "Build docker image with dependencies and run migrations" + }, + "test": { + "command": "sh \"pipenv run pytest\"", + "description": "Run tests" + }, + "reformat": { + "command": ["sh \"isort src\"", "sh \"autoflake -i --remove-all-unused-imports --recursive src\"", "sh \"black src\""], + "description": "Reformat code" + } +}' diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..bbb1f75f8 --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +.PHONY: test test-isolated + +test: + pytest spyne/test/ -x -q + +test-isolated: + @failed_files=""; \ + for f in $$(find spyne/test -name 'test_*.py' | sort); do \ + printf '\n=== %s ===\n' "$$f"; \ + if ! pytest $$f -x --tb=short -q 2>&1; then \ + failed_files="$$failed_files $$f"; \ + fi; \ + done; \ + echo ""; \ + if [ -z "$$failed_files" ]; then \ + echo "All files passed."; \ + else \ + echo "Failed files:"; \ + for f in $$failed_files; do echo " $$f"; done; \ + exit 1; \ + fi diff --git a/Pipfile b/Pipfile new file mode 100644 index 000000000..a7f71601b --- /dev/null +++ b/Pipfile @@ -0,0 +1,34 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] +pytest = ">=2.9" +pytest-twisted = "*" +pytest-cov = "*" +coverage = "*" +junitxml = "*" +werkzeug = "*" +sqlalchemy = "*" +lxml = ">=3.6" +pyyaml = "*" +pyzmq = "*" +twisted = "*" +colorama = "*" +msgpack = ">=1" +webtest = "*" +pytest-django = "*" +django = "*" +python-subunit = "*" +pyramid = "*" +tox = "*" +pyparsing = ">=2.0.2" +suds-community = "*" +zeep = "*" +pandas = "*" + +[requires] +python_version = "3.10" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 000000000..cf3ca6b3f --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,1617 @@ +{ + "_meta": { + "hash": { + "sha256": "ea974184cf059f0c550554b145d30fee88b33715caef0daf3c7599ea79430b2d" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.10" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": {}, + "develop": { + "asgiref": { + "hashes": [ + "sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce", + "sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133" + ], + "markers": "python_version >= '3.9'", + "version": "==3.11.1" + }, + "attrs": { + "hashes": [ + "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", + "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32" + ], + "markers": "python_version >= '3.9'", + "version": "==26.1.0" + }, + "automat": { + "hashes": [ + "sha256:0017591a5477066e90d26b0e696ddc143baafd87b588cfac8100bc6be9634de0", + "sha256:04e9bce696a8d5671ee698005af6e5a9fa15354140a87f4870744604dcdd3ba1" + ], + "markers": "python_version >= '3.9'", + "version": "==25.4.16" + }, + "beautifulsoup4": { + "hashes": [ + "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", + "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==4.14.3" + }, + "cachetools": { + "hashes": [ + "sha256:4e94956cfdd3086f12042cdd29318f5ced3893014f7d0d059bf3ead3f85b7f8b", + "sha256:e5d524d36d65703a87243a26ff08ad84f73352adbeafb1cde81e207b456aaf24" + ], + "markers": "python_version >= '3.10'", + "version": "==7.0.6" + }, + "certifi": { + "hashes": [ + "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", + "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580" + ], + "markers": "python_version >= '3.7'", + "version": "==2026.4.22" + }, + "charset-normalizer": { + "hashes": [ + "sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc", + "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", + "sha256:07d9e39b01743c3717745f4c530a6349eadbfa043c7577eef86c502c15df2c67", + "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", + "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", + "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", + "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", + "sha256:12a6fff75f6bc66711b73a2f0addfc4c8c15a20e805146a02d147a318962c444", + "sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153", + "sha256:14265bfe1f09498b9d8ec91e9ec9fa52775edf90fcbde092b25f4a33d444fea9", + "sha256:16d971e29578a5e97d7117866d15889a4a07befe0e87e703ed63cd90cb348c01", + "sha256:177a0ba5f0211d488e295aaf82707237e331c24788d8d76c96c5a41594723217", + "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", + "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", + "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", + "sha256:1dc8b0ea451d6e69735094606991f32867807881400f808a106ee1d963c46a83", + "sha256:1efde3cae86c8c273f1eb3b287be7d8499420cf2fe7585c41d370d3e790054a5", + "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", + "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", + "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", + "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", + "sha256:2cd4a60d0e2fb04537162c62bbbb4182f53541fe0ede35cdf270a1c1e723cc42", + "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", + "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", + "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", + "sha256:320ade88cfb846b8cd6b4ddf5ee9e80ee0c1f52401f2456b84ae1ae6a1a5f207", + "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", + "sha256:36836d6ff945a00b88ba1e4572d721e60b5b8c98c155d465f56ad19d68f23734", + "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", + "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", + "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", + "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", + "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", + "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", + "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", + "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", + "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", + "sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53", + "sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790", + "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", + "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", + "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", + "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", + "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", + "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", + "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", + "sha256:6370e8686f662e6a3941ee48ed4742317cafbe5707e36406e9df792cdb535776", + "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", + "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", + "sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008", + "sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943", + "sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374", + "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", + "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", + "sha256:6e0d51f618228538a3e8f46bd246f87a6cd030565e015803691603f55e12afb5", + "sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616", + "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", + "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", + "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", + "sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752", + "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", + "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", + "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", + "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", + "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", + "sha256:813c0e0132266c08eb87469a642cb30aaff57c5f426255419572aaeceeaa7bf4", + "sha256:82b271f5137d07749f7bf32f70b17ab6eaabedd297e75dce75081a24f76eb545", + "sha256:84c018e49c3bf790f9c2771c45e9313a08c2c2a6342b162cd650258b57817706", + "sha256:8751d2787c9131302398b11e6c8068053dcb55d5a8964e114b6e196cf16cb366", + "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", + "sha256:87fad7d9ba98c86bcb41b2dc8dbb326619be2562af1f8ff50776a39e55721c5a", + "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", + "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", + "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", + "sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a", + "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", + "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", + "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", + "sha256:a6c5863edfbe888d9eff9c8b8087354e27618d9da76425c119293f11712a6319", + "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", + "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", + "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", + "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", + "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", + "sha256:aef65cd602a6d0e0ff6f9930fcb1c8fec60dd2cfcb6facaf4bdb0e5873042db0", + "sha256:af21eb4409a119e365397b2adbaca4c9ccab56543a65d5dbd9f920d6ac29f686", + "sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34", + "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", + "sha256:bb8cc7534f51d9a017b93e3e85b260924f909601c3df002bcdb58ddb4dc41a5c", + "sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1", + "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", + "sha256:bd9b23791fe793e4968dba0c447e12f78e425c59fc0e3b97f6450f4781f3ee60", + "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", + "sha256:c0f081d69a6e58272819b70288d3221a6ee64b98df852631c80f293514d3b274", + "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", + "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", + "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", + "sha256:c593052c465475e64bbfe5dbd81680f64a67fdc752c56d7a0ae205dc8aeefe0f", + "sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d", + "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", + "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", + "sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393", + "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", + "sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af", + "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", + "sha256:d61f00a0869d77422d9b2aba989e2d24afa6ffd552af442e0e58de4f35ea6d00", + "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", + "sha256:dca4bbc466a95ba9c0234ef56d7dd9509f63da22274589ebd4ed7f1f4d4c54e3", + "sha256:dd915403e231e6b1809fe9b6d9fc55cf8fb5e02765ac625d9cd623342a7905d7", + "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", + "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", + "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", + "sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8", + "sha256:e5f4d355f0a2b1a31bc3edec6795b46324349c9cb25eed068049e4f472fb4259", + "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", + "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", + "sha256:e80c8378d8f3d83cd3164da1ad2df9e37a666cdde7b1cb2298ed0b558064be30", + "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", + "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", + "sha256:ed065083d0898c9d5b4bbec7b026fd755ff7454e6e8b73a67f8c744b13986e24", + "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", + "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", + "sha256:f22dec1690b584cea26fade98b2435c132c1b5f68e39f5a0b7627cd7ae31f1dc", + "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", + "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", + "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", + "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", + "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", + "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464" + ], + "markers": "python_version >= '3.7'", + "version": "==3.4.7" + }, + "colorama": { + "hashes": [ + "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", + "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" + ], + "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", + "version": "==0.4.6" + }, + "constantly": { + "hashes": [ + "sha256:3fd9b4d1c3dc1ec9757f3c52aef7e53ad9323dbe39f51dfd4c43853b68dfa3f9", + "sha256:aa92b70a33e2ac0bb33cd745eb61776594dc48764b06c35e0efd050b7f1c7cbd" + ], + "markers": "python_version >= '3.8'", + "version": "==23.10.4" + }, + "coverage": { + "extras": [ + "toml" + ], + "hashes": [ + "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256", + "sha256:02ca0eed225b2ff301c474aeeeae27d26e2537942aa0f87491d3e147e784a82b", + "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5", + "sha256:0428cbef5783ad91fe240f673cc1f76b25e74bbfe1a13115e4aa30d3f538162d", + "sha256:04690832cbea4e4663d9149e05dba142546ca05cb1848816760e7f58285c970a", + "sha256:0590e44dd2745c696a778f7bab6aa95256de2cbc8b8cff4f7db8ff09813d6969", + "sha256:0672854dc733c342fa3e957e0605256d2bf5934feeac328da9e0b5449634a642", + "sha256:084b84a8c63e8d6fc7e3931b316a9bcafca1458d753c539db82d31ed20091a87", + "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740", + "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215", + "sha256:0cef0cdec915d11254a7f549c1170afecce708d30610c6abdded1f74e581666d", + "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422", + "sha256:0e3c426ffc4cd952f54ee9ffbdd10345709ecc78a3ecfd796a57236bfad0b9b8", + "sha256:0ecf12ecb326fe2c339d93fc131816f3a7367d223db37817208905c89bded911", + "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b", + "sha256:145ede53ccbafb297c1c9287f788d1bc3efd6c900da23bf6931b09eafc931587", + "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8", + "sha256:1b88c69c8ef5d4b6fe7dea66d6636056a0f6a7527c440e890cf9259011f5e606", + "sha256:258354455f4e86e3e9d0d17571d522e13b4e1e19bf0f8596bcf9476d61e7d8a9", + "sha256:259b69bb83ad9894c4b25be2528139eecba9a82646ebdda2d9db1ba28424a6bf", + "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633", + "sha256:2d3807015f138ffea1ed9afeeb8624fd781703f2858b62a8dd8da5a0994c57b6", + "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43", + "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2", + "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", + "sha256:356e76b46783a98c2a2fe81ec79df4883a1e62895ea952968fb253c114e7f930", + "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc", + "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247", + "sha256:3ad050321264c49c2fa67bb599100456fc51d004b82534f379d16445da40fb75", + "sha256:3e1bb5f6c78feeb1be3475789b14a0f0a5b47d505bfc7267126ccbd50289999e", + "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376", + "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01", + "sha256:48c39bc4a04d983a54a705a6389512883d4a3b9862991b3617d547940e9f52b1", + "sha256:4b59148601efcd2bac8c4dbf1f0ad6391693ccf7a74b8205781751637076aee3", + "sha256:4d2afbc5cc54d286bfb54541aa50b64cdb07a718227168c87b9e2fb8f25e1743", + "sha256:505d7083c8b0c87a8fa8c07370c285847c1f77739b22e299ad75a6af6c32c5c9", + "sha256:52f444e86475992506b32d4e5ca55c24fc88d73bcbda0e9745095b28ef4dc0cf", + "sha256:5b13955d31d1633cf9376908089b7cebe7d15ddad7aeaabcbe969a595a97e95e", + "sha256:5ec4af212df513e399cf11610cc27063f1586419e814755ab362e50a85ea69c1", + "sha256:60365289c3741e4db327e7baff2a4aaacf22f788e80fa4683393891b70a89fbd", + "sha256:631efb83f01569670a5e866ceb80fe483e7c159fac6f167e6571522636104a0b", + "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab", + "sha256:66a80c616f80181f4d643b0f9e709d97bcea413ecd9631e1dedc7401c8e6695d", + "sha256:67e9bc5449801fad0e5dff329499fb090ba4c5800b86805c80617b4e29809b2a", + "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0", + "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510", + "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f", + "sha256:7034b5c56a58ae5e85f23949d52c14aca2cfc6848a31764995b7de88f13a1ea0", + "sha256:704de6328e3d612a8f6c07000a878ff38181ec3263d5a11da1db294fa6a9bdf8", + "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf", + "sha256:7300c8a6d13335b29bb76d7651c66af6bd8658517c43499f110ddc6717bfc209", + "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9", + "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3", + "sha256:78e696e1cc714e57e8b25760b33a8b1026b7048d270140d25dafe1b0a1ee05a3", + "sha256:79060214983769c7ba3f0cee10b54c97609dca4d478fa1aa32b914480fd5738d", + "sha256:7c8d4bc913dd70b93488d6c496c77f3aff5ea99a07e36a18f865bca55adef8bd", + "sha256:7f2c47b36fe7709a6e83bfadf4eefb90bd25fbe4014d715224c4316f808e59a2", + "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882", + "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09", + "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea", + "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c", + "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562", + "sha256:941617e518602e2d64942c88ec8499f7fbd49d3f6c4327d3a71d43a1973032f3", + "sha256:972a9cd27894afe4bc2b1480107054e062df08e671df7c2f18c205e805ccd806", + "sha256:9adb6688e3b53adffefd4a52d72cbd8b02602bfb8f74dcd862337182fd4d1a4e", + "sha256:9b74db26dfea4f4e50d48a4602207cd1e78be33182bc9cbf22da94f332f99878", + "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e", + "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9", + "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45", + "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29", + "sha256:a1a6d79a14e1ec1832cabc833898636ad5f3754a678ef8bb4908515208bf84f4", + "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c", + "sha256:ad14385487393e386e2ea988b09d62dd42c397662ac2dabc3832d71253eee479", + "sha256:ad146744ca4fd09b50c482650e3c1b1f4dfa1d4792e0a04a369c7f23336f0400", + "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c", + "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a", + "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf", + "sha256:be3d4bbad9d4b037791794ddeedd7d64a56f5933a2c1373e18e9e568b9141686", + "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de", + "sha256:bff95879c33ec8da99fc9b6fe345ddb5be6414b41d6d1ad1c8f188d26f36e028", + "sha256:c555b48be1853fe3997c11c4bd521cdd9a9612352de01fa4508f16ec341e6fe0", + "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", + "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16", + "sha256:ce1998c0483007608c8382f4ff50164bfc5bd07a2246dd272aa4043b75e61e85", + "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a", + "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0", + "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810", + "sha256:d7cfad2d6d81dd298ab6b89fe72c3b7b05ec7544bdda3b707ddaecff8d25c161", + "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607", + "sha256:da305e9937617ee95c2e39d8ff9f040e0487cbf1ac174f777ed5eddd7a7c1f26", + "sha256:da86cdcf10d2519e10cabb8ac2de03da1bcb6e4853790b7fbd48523332e3a819", + "sha256:dc022073d063b25a402454e5712ef9e007113e3a676b96c5f29b2bda29352f40", + "sha256:e0723d2c96324561b9aa76fb982406e11d93cdb388a7a7da2b16e04719cf7ca5", + "sha256:e092b9499de38ae0fbfbc603a74660eb6ff3e869e507b50d85a13b6db9863e15", + "sha256:e0b216a19534b2427cc201a26c25da4a48633f29a487c61258643e89d28200c0", + "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90", + "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0", + "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6", + "sha256:eb07647a5738b89baab047f14edd18ded523de60f3b30e75c2acc826f79c839a", + "sha256:eb7fdf1ef130660e7415e0253a01a7d5a88c9c4d158bcf75cbbd922fd65a5b58", + "sha256:ec10e2a42b41c923c2209b846126c6582db5e43a33157e9870ba9fb70dc7854b", + "sha256:ee2aa19e03161671ec964004fb74b2257805d9710bf14a5c704558b9d8dbaf17", + "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5", + "sha256:f4cd16206ad171cbc2470dbea9103cf9a7607d5fe8c242fdf1edf36174020664", + "sha256:f70c9ab2595c56f81a89620e22899eea8b212a4041bd728ac6f4a28bf5d3ddd0", + "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f" + ], + "index": "pypi", + "markers": "python_version >= '3.10'", + "version": "==7.13.5" + }, + "decorator": { + "hashes": [ + "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", + "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a" + ], + "markers": "python_version >= '3.8'", + "version": "==5.2.1" + }, + "distlib": { + "hashes": [ + "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", + "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d" + ], + "version": "==0.4.0" + }, + "django": { + "hashes": [ + "sha256:5788fce61da23788a8ce6f02583765ab060d396720924789f97fa42119d37f7a", + "sha256:a31589db5188d074c63f0945c3888fad104627dfcc236fb2b97f71f89da33bc4" + ], + "index": "pypi", + "markers": "python_version >= '3.10'", + "version": "==5.2.13" + }, + "exceptiongroup": { + "hashes": [ + "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", + "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598" + ], + "markers": "python_version >= '3.7'", + "version": "==1.3.1" + }, + "filelock": { + "hashes": [ + "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", + "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258" + ], + "markers": "python_version >= '3.10'", + "version": "==3.29.0" + }, + "greenlet": { + "hashes": [ + "sha256:04403ac74fe295a361f650818de93be11b5038a78f49ccfb64d3b1be8fbf1267", + "sha256:05fa0803561028f4b2e3b490ee41216a842eaee11aed004cc343a996d9523aa2", + "sha256:06c2d3b89e0c62ba50bd7adf491b14f39da9e7e701647cb7b9ff4c99bee04b19", + "sha256:070b8bac2ff3b4d9e0ff36a0d19e42103331d9737e8504747cd1e659f76297bd", + "sha256:076e21040b3a917d3ce4ad68fb5c3c6b32f1405616c4a57aa83120979649bd3d", + "sha256:0e1254cf0cbaa17b04320c3a78575f29f3c161ef38f59c977108f19ffddaf077", + "sha256:1054c5a3c78e2ab599d452f23f7adafef55062a783a8e241d24f3b633ba6ff82", + "sha256:10a07aca6babdd18c16a3f4f8880acfffc2b88dfe431ad6aa5f5740759d7d75e", + "sha256:16dec271460a9a2b154e3b1c2fa1050ce6280878430320e85e08c166772e3f97", + "sha256:1a4a48f24681300c640f143ba7c404270e1ebbbcf34331d7104a4ff40f8ea705", + "sha256:1a54a921561dd9518d31d2d3db4d7f80e589083063ab4d3e2e950756ef809e1a", + "sha256:1f85f204c4d54134ae850d401fa435c89cd667d5ce9dc567571776b45941af72", + "sha256:207ba5b97ea8b0b60eb43ffcacf26969dd83726095161d676aac03ff913ee50d", + "sha256:227a46251ecba4ff46ae742bc5ce95c91d5aceb4b02f885487aff269c127a729", + "sha256:234582c20af9742583c3b2ddfbdbb58a756cfff803763ffaae1ac7990a9fac31", + "sha256:2d4f0635dc4aa638cda4b2f5a07ae9a2cff9280327b581a3fcb6f317b4fbc38a", + "sha256:43748988b097f9c6f09364f260741aa73c80747f63389824435c7a50bfdfd5c1", + "sha256:439fc2f12b9b512d9dfa681c5afe5f6b3232c708d13e6f02c845e0d9f4c2d8c6", + "sha256:4df3b0b2289ec686d3c821a5fee44259c05cfe824dd5e6e12c8e5f5df23085cf", + "sha256:523677e69cd4711b5a014e37bc1fb3a29947c3e3a5bb6a527e1cc50312e5a398", + "sha256:5434271357be07f3ad0936c312645853b7e689e679e29310e2de09a9ea6c3adf", + "sha256:5566e4e2cd7a880e8c27618e3eab20f3494452d12fd5129edef7b2f7aa9a36d1", + "sha256:5b99e87be7eba788dd5b75ba1cde5639edffdec5f91fe0d734a249535ec3408c", + "sha256:5cb614ace7c27571270354e9c9f696554d073f8aa9319079dcba466bbdead711", + "sha256:636d2f95c309e35f650e421c23297d5011716be15d966e6328b367c9fc513a82", + "sha256:6f0def07ec9a71d72315cf26c061aceee53b306c36ed38c35caba952ea1b319d", + "sha256:7f50c804733b43eded05ae694691c9aa68bca7d0a867d67d4a3f514742a2d53f", + "sha256:805bebb4945094acbab757d34d6e1098be6de8966009ab9ca54f06ff492def58", + "sha256:8424683caf46eb0eb6f626cb95e008e8cc30d0cb675bdfa48200925c79b38a08", + "sha256:849f8bc17acd6295fcb5de8e46d55cc0e52381c56eaf50a2afd258e97bc65940", + "sha256:89995ce5ddcd2896d89615116dd39b9703bfa0c07b583b85b89bf1b5d6eddf81", + "sha256:8a569c2fb840c53c13a2b8967c63621fafbd1a0e015b9c82f408c33d626a2fda", + "sha256:8bff29d586ea415688f4cec96a591fcc3bf762d046a796cdadc1fdb6e7f2d5bf", + "sha256:8c5696c42e6bb5cfb7c6ff4453789081c66b9b91f061e5e9367fa15792644e76", + "sha256:90036ce224ed6fe75508c1907a77e4540176dcf0744473627785dd519c6f9996", + "sha256:9390ad88b652b1903814eaabd629ca184db15e0eeb6fe8a390bbf8b9106ae15a", + "sha256:956215d5e355fffa7c021d168728321fd4d31fd730ac609b1653b450f6a4bc71", + "sha256:98eedd1803353daf1cd9ef23eef23eda5a4d22f99b1f998d273a8b78b70dd47f", + "sha256:9b2d9a138ffa0e306d0e2b72976d2fb10b97e690d40ab36a472acaab0838e2de", + "sha256:a0a53fb071531d003b075c444014ff8f8b1a9898d36bb88abd9ac7b3524648a2", + "sha256:a19093fbad824ed7c0f355b5ff4214bffda5f1a7f35f29b31fcaa240cc0135ab", + "sha256:a1c4f6b453006efb8310affb2d132832e9bbb4fc01ce6df6b70d810d38f1f6dc", + "sha256:a58bec0751f43068cd40cff31bb3ca02ad6000b3a51ca81367af4eb5abc480c8", + "sha256:a70ed1cb0295bee1df57b63bf7f46b4e56a5c93709eea769c1fec1bb23a95875", + "sha256:ac6a5f618be581e1e0713aecec8e54093c235e5fa17d6d8eb7ffc487e2300508", + "sha256:b45e45fe47a19051a396abb22e19e7836a59ee6c5a90f3be427343c37908d65b", + "sha256:b7857e2202aae67bc5725e0c1f6403c20a8ff46094ece015e7d474f5f7020b55", + "sha256:c4cd56a9eb7a6444edbc19062f7b6fbc8f287c663b946e3171d899693b1c19fa", + "sha256:c660bce1940a1acae5f51f0a064f1bc785d07ea16efcb4bc708090afc4d69e83", + "sha256:d18eae9a7fb0f499efcd146b8c9750a2e1f6e0e93b5a382b3481875354a430e6", + "sha256:d336d46878e486de7d9458653c722875547ac8d36a1cff9ffaf4a74a3c1f62eb", + "sha256:d70012e51df2dbbccfaf63a40aaf9b40c8bed37c3e3a38751c926301ce538ece", + "sha256:e60d38719cb80b3ab5e85f9f1aed4960acfde09868af6762ccb27b260d68f4ed", + "sha256:e82689eea4a237e530bb5cb41b180ef81fa2160e1f89422a67be7d90da67f615", + "sha256:ee407d4d1ca9dc632265aee1c8732c4a2d60adff848057cdebfe5fe94eb2c8a2", + "sha256:f38b81880ba28f232f1f675893a39cf7b6db25b31cc0a09bb50787ecf957e85e", + "sha256:f50a96b64dafd6169e595a5c56c9146ef80333e67d4476a65a9c55f400fc22ff", + "sha256:f8296d4e2b92af34ebde81085a01690f26a51eb9ac09a0fcadb331eb36dbc802", + "sha256:f82cb6cddc27dd81c96b1506f4aa7def15070c3b2a67d4e46fd19016aacce6cf" + ], + "markers": "python_version >= '3.10'", + "version": "==3.4.0" + }, + "hupper": { + "hashes": [ + "sha256:06bf54170ff4ecf4c84ad5f188dee3901173ab449c2608ad05b9bfd6b13e32eb", + "sha256:e872b959f09d90be5fb615bd2e62de89a0b57efc037bdf9637fb09cdf8552b19" + ], + "markers": "python_version >= '3.7'", + "version": "==1.12.1" + }, + "hyperlink": { + "hashes": [ + "sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b", + "sha256:e6b14c37ecb73e89c77d78cdb4c2cc8f3fb59a885c5b3f819ff4ed80f25af1b4" + ], + "version": "==21.0.0" + }, + "idna": { + "hashes": [ + "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", + "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3" + ], + "markers": "python_version >= '3.8'", + "version": "==3.13" + }, + "incremental": { + "hashes": [ + "sha256:87d3480dbb083c1d736222511a8cf380012a8176c2456d01ef483242abbbcf8c", + "sha256:a34450716b1c4341fe6676a0598e88a39e04189f4dce5dc96f656e040baa10b3" + ], + "markers": "python_version >= '3.8'", + "version": "==24.11.0" + }, + "iniconfig": { + "hashes": [ + "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", + "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12" + ], + "markers": "python_version >= '3.10'", + "version": "==2.3.0" + }, + "iso8601": { + "hashes": [ + "sha256:6b1d3829ee8921c4301998c909f7829fa9ed3cbdac0d3b16af2d743aed1ba8df", + "sha256:aac4145c4dcb66ad8b648a02830f5e2ff6c24af20f4f482689be402db2429242" + ], + "markers": "python_version >= '3.7' and python_version < '4.0'", + "version": "==2.1.0" + }, + "isodate": { + "hashes": [ + "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15", + "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6" + ], + "markers": "python_version >= '3.7'", + "version": "==0.7.2" + }, + "junitxml": { + "hashes": [ + "sha256:a5901127067ab7f3d11df30727368c129c69b3f5595c697daf4f5ed80b1baaa3" + ], + "index": "pypi", + "version": "==0.7" + }, + "lxml": { + "hashes": [ + "sha256:00750d63ef0031a05331b9223463b1c7c02b9004cef2346a5b2877f0f9494dd2", + "sha256:022981127642fe19866d2907d76241bb07ed21749601f727d5d5dd1ce5d1b773", + "sha256:045e387d1f4f42a418380930fa3f45c73c9b392faf67e495e58902e68e8f44a7", + "sha256:05b9b8787e35bec69e68daf4952b2e6dfcfb0db7ecf1a06f8cdfbbac4eb71aad", + "sha256:07f98f5496f96bf724b1e3c933c107f0cbf2745db18c03d2e13a291c3afd2635", + "sha256:08950a23f296b3f83521577274e3d3b0f3d739bf2e68d01a752e4288bc50d286", + "sha256:0d082495c5fcf426e425a6e28daaba1fcb6d8f854a4ff01effb1f1f381203eb9", + "sha256:0f0f08beb0182e3e9a86fae124b3c47a7b41b7b69b225e1377db983802404e54", + "sha256:1081dd10bc6fa437db2500e13993abf7cc30716d0a2f40e65abb935f02ec559c", + "sha256:11a873c77a181b4fef9c2e357d08ed399542c2af1390101da66720a19c7c9618", + "sha256:183bfb45a493081943be7ea2b5adfc2b611e1cf377cefa8b8a8be404f45ef9a7", + "sha256:19f4164243fc206d12ed3d866e80e74f5bc3627966520da1a5f97e42c32a3f39", + "sha256:1ae225f66e5938f4fa29d37e009a3bb3b13032ac57eb4eb42afa44f6e4054e69", + "sha256:1bc4cc83fb7f66ffb16f74d6dd0162e144333fc36ebcce32246f80c8735b2551", + "sha256:1dd6a1c3ad4cb674f44525d9957f3e9c209bb6dd9213245195167a281fcc2bdc", + "sha256:20cf4d0651987c906a2f5cba4e3a8d6ba4bfdf973cfe2a96c0d6053888ea2ecd", + "sha256:2173a7bffe97667bbf0767f8a99e587740a8c56fdf3befac4b09cb29a80276fd", + "sha256:21c3302068f50d1e8728c67c87ba92aa87043abee517aa2576cca1855326b405", + "sha256:23a5dc68e08ed13331d61815c08f260f46b4a60fdd1640bbeb82cf89a9d90289", + "sha256:23cad0cc86046d4222f7f418910e46b89971c5a45d3c8abfad0f64b7b05e4a9b", + "sha256:2593a0a6621545b9095b71ad74ed4226eba438a7d9fc3712a99bdb15508cf93a", + "sha256:264c605ab9c0e4aa1a679636f4582c4d3313700009fac3ec9c3412ed0d8f3e1d", + "sha256:26c5272c6a4bf4cf32d3f5a7890c942b0e04438691157d341616d02cca74d4bd", + "sha256:26dd9f57ee3bd41e7d35b4c98a2ffd89ed11591649f421f0ec19f67d50ec67ac", + "sha256:28902146ffbe5222df411c5d19e5352490122e14447e98cd118907ee3fd6ee62", + "sha256:29f5c00cb7d752bce2c70ebd2d31b0a42f9499ffdd3ecb2f31a5b73ee43031ad", + "sha256:30e7b2ed63b6c8e97cca8af048589a788ab5c9c905f36d9cf1c2bb549f450d2f", + "sha256:32662519149fd7a9db354175aa5e417d83485a8039b8aaa62f873ceee7ea4cad", + "sha256:363e47283bde87051b821826e71dde47f107e08614e1aa312ba0c5711e77738c", + "sha256:3648f20d25102a22b6061c688beb3a805099ea4beb0a01ce62975d926944d292", + "sha256:37448bf9c7d7adfc5254763901e2bbd6bb876228dfc1fc7f66e58c06368a7544", + "sha256:37fabd1452852636cf38ecdcc9dd5ca4bba7a35d6c53fa09725deeb894a87491", + "sha256:398443df51c538bd578529aa7e5f7afc6c292644174b47961f3bf87fe5741120", + "sha256:3ae5d8d5427f3cc317e7950f2da7ad276df0cfa37b8de2f5658959e618ea8512", + "sha256:3f00972f84450204cd5d93a5395965e348956aaceaadec693a22ec743f8ae3eb", + "sha256:40d9189f80075f2e1f88db21ef815a2b17b28adf8e50aaf5c789bfe737027f32", + "sha256:419c58fc92cc3a2c3fa5f78c63dbf5da70c1fa9c1b25f25727ecee89a96c7de2", + "sha256:41dcc4c7b10484257cbd6c37b83ddb26df2b0e5aff5ac00d095689015af868ec", + "sha256:43e4d297f11080ec9d64a4b1ad7ac02b4484c9f0e2179d9c4ef78e886e747b88", + "sha256:45e9dfbd1b661eb64ba0d4dbe762bd210c42d86dd1e5bd2bdf89d634231beb43", + "sha256:4642e04449a1e164b5ff71ffd901ddb772dfabf5c9adf1b7be5dffe1212bc037", + "sha256:468479e52ecf3ec23799c863336d02c05fc2f7ffd1a1424eeeb9a28d4eb69d13", + "sha256:47024feaae386a92a146af0d2aeed65229bf6fff738e6a11dda6b0015fb8fd03", + "sha256:481d6e2104285d9add34f41b42b247b76b61c5b5c26c303c2e9707bbf8bd9a64", + "sha256:4937460dc5df0cdd2f06a86c285c28afda06aefa3af949f9477d3e8df430c485", + "sha256:4a1503c56e4e2b38dc76f2f2da7bae69670c0f1933e27cfa34b2fa5876410b16", + "sha256:4b89b098105b8599dc57adac95d1813409ac476d3c948a498775d3d0c6124bfb", + "sha256:4bd1bdb8a9e0e2dd229de19b5f8aebac80e916921b4b2c6ef8a52bc131d0c1f9", + "sha256:4e2c54d6b47361d0f1d3bc8d4e082ad87201e56ccdcca4d3b9ee3644ff595ec8", + "sha256:52b0ac6903cf74ebf997eb8c682d2fbac7d1ab7e4c552413eec55868a9b73f39", + "sha256:546b66c0dd1bb8d9fa89d7123e5fa19a8aff3a1f2141eb22df96112afb17b842", + "sha256:56971379bc5ee8037c5a0f09fa88f66cdb7d37c3e38af3e45cf539f41131ac1f", + "sha256:5715e0e28736a070f3f34a7ccc09e2fdcba0e3060abbcf61a1a5718ff6d6b105", + "sha256:5cfa1a34df366d9dc0d5eaf420f4cf2bb1e1bebe1066d1c2fc28c179f8a4004c", + "sha256:5d27bbe326c6b539c64b42638b18bc6003a8d88f76213a97ac9ed4f885efeab7", + "sha256:6262b87f9e5c1e5fe501d6c153247289af42eb44ad7660b9b3de17baaf92d6f6", + "sha256:63aeafc26aac0be8aff14af7871249e87ea1319be92090bfd632ec68e03b16a5", + "sha256:690022c7fae793b0489aa68a658822cea83e0d5933781811cabbf5ea3bcfe73d", + "sha256:6fd8b1df8254ff4fd93fd31da1fc15770bde23ac045be9bb1f87425702f61cc9", + "sha256:73becf6d8c81d4c76b1014dbd3584cb26d904492dcf73ca85dc8bff08dcd6d2d", + "sha256:73d658216fc173cf2c939e90e07b941c5e12736b0bf6a99e7af95459cfe8eabb", + "sha256:75c4c7c619a744f972f4451bf5adf6d0fb00992a1ffc9fd78e13b0bc817cc99f", + "sha256:76b958b4ea3104483c20f74866d55aa056546e15ebe83dd7aecd63698f43b755", + "sha256:77b9f99b17cbf14026d1e618035077060fc7195dd940d025149f3e2e830fbfcb", + "sha256:7ba11752e346bd804ea312ec2eea2532dfa8b8d3261d81a32ef9e6ab16256280", + "sha256:7da13bb6fbadfafb474e0226a30570a3445cfd47c86296f2446dafbd77079ace", + "sha256:7e39ab3a28af7784e206d8606ec0e4bcad0190f63a492bca95e94e5a4aef7f6e", + "sha256:7f4a77d6f7edf9230cee3e1f7f6764722a41604ee5681844f18db9a81ea0ec33", + "sha256:80410c3a7e3c617af04de17caa9f9f20adaa817093293d69eae7d7d0522836f5", + "sha256:81ff55c70b67d19d52b6fd118a114c0a4c97d799cd3089ff9bd9e2ff4b414ee2", + "sha256:857efde87d365706590847b916baff69c0bc9252dc5af030e378c9800c0b10e3", + "sha256:89e8d73d09ac696a5ba42ec69787913d53284f12092f651506779314f10ba585", + "sha256:8c11b984b5ce6add4dccc7144c7be5d364d298f15b0c6a57da1991baedc750ce", + "sha256:8c8984e1d8c4b3949e419158fda14d921ff703a9ed8a47236c6eb7a2b6cb4946", + "sha256:8e369cbd690e788c8d15e56222d91a09c6a417f49cbc543040cba0fe2e25a79e", + "sha256:9147d8e386ec3b82c3b15d88927f734f565b0aaadef7def562b853adca45784a", + "sha256:920354904d1cb86577d4b3cfe2830c2dbe81d6f4449e57ada428f1609b5985f7", + "sha256:942454ff253da14218f972b23dc72fa4edf6c943f37edd19cd697618b626fac5", + "sha256:972a6451204798675407beaad97b868d0c733d9a74dafefc63120b81b8c2de28", + "sha256:976a6b39b1b13e8c354ad8d3f261f3a4ac6609518af91bdb5094760a08f132c4", + "sha256:97faa0860e13b05b15a51fb4986421ef7a30f0b3334061c416e0981e9450ca4c", + "sha256:9c03e048b6ce8e77b09c734e931584894ecd58d08296804ca2d0b184c933ce50", + "sha256:9e7b0a4ca6dcc007a4cef00a761bba2dea959de4bd2df98f926b33c92ca5dfb9", + "sha256:9eb667bf50856c4a58145f8ca2d5e5be160191e79eb9e30855a476191b3c3495", + "sha256:9f93d5b8b07f73e8c77e3c6556a3db269918390c804b5e5fcdd4858232cc8f16", + "sha256:a0092f2b107b69601adf562a57c956fbb596e05e3e6651cabd3054113b007e45", + "sha256:a02ca8fe48815bddcfca3248efe54451abb9dbf2f7d1c5744c8aa4142d476919", + "sha256:a1d9b99e5b2597e4f5aed2484fef835256fa1b68a19e4265c97628ef4bf8bcf4", + "sha256:a2853c8b2170cc6cd54a6b4d50d2c1a8a7aeca201f23804b4898525c7a152cfc", + "sha256:a31286dbb5e74c8e9a5344465b77ab4c5bd511a253b355b5ca2fae7e579fafec", + "sha256:a86f06f059e22a0d574990ee2df24ede03f7f3c68c1336293eee9536c4c776cd", + "sha256:ab863fd37458fed6456525f297d21239d987800c46e67da5ef04fc6b3dd93ac8", + "sha256:ac4db068889f8772a4a698c5980ec302771bb545e10c4b095d4c8be26749616f", + "sha256:b6c2f225662bc5ad416bdd06f72ca301b31b39ce4261f0e0097017fc2891b940", + "sha256:bb40648d96157f9081886defe13eac99253e663be969ff938a9289eff6e47b72", + "sha256:bba078de0031c219e5dd06cf3e6bf8fb8e6e64a77819b358f53bb132e3e03366", + "sha256:bc783ee3147e60a25aa0445ea82b3e8aabb83b240f2b95d32cb75587ff781814", + "sha256:be10838781cb3be19251e276910cd508fe127e27c3242e50521521a0f3781690", + "sha256:bfd57d8008c4965709a919c3e9a98f76c2c7cb319086b3d26858250620023b13", + "sha256:c08da09dc003c9e8c70e06b53a11db6fb3b250c21c4236b03c7d7b443c318e7a", + "sha256:c3592631e652afa34999a088f98ba7dfc7d6aff0d535c410bea77a71743f3819", + "sha256:c4a699432846df86cc3de502ee85f445ebad748a1c6021d445f3e514d2cd4b1c", + "sha256:c4e425db0c5445ef0ad56b0eec54f89b88b2d884656e536a90b2f52aecb4ca86", + "sha256:c53fa3a5a52122d590e847a57ccf955557b9634a7f99ff5a35131321b0a85317", + "sha256:c6854e9cf99c84beb004eecd7d3a3868ef1109bf2b1df92d7bc11e96a36c2180", + "sha256:c748ebcb6877de89f48ab90ca96642ac458fff5dec291a2b9337cd4d0934e383", + "sha256:c871299c595ee004d186f61840f0bfc4941aa3f17c8ba4a565ead7e4f4f820ee", + "sha256:cbd7b79cdcb4986ad78a2662625882747f09db5e4cd7b2ae178a88c9c51b3dfe", + "sha256:cc16682cc987a3da00aa56a3aa3075b08edb10d9b1e476938cfdbee8f3b67181", + "sha256:cec05be8c876f92a5aa07b01d60bbb4d11cfbdd654cad0561c0d7b5c043a61b9", + "sha256:d036ee7b99d5148072ac7c9b847193decdfeac633db350363f7bce4fff108f0e", + "sha256:d0d799ff958655781296ec870d5e2448e75150da2b3d07f13ff5b0c2c35beefd", + "sha256:d1392c569c032f78a11a25d1de1c43fff13294c793b39e19d84fade3045cbbc3", + "sha256:d2f17a16cd8751e8eb233a7e41aecdf8e511712e00088bf9be455f604cd0d28d", + "sha256:d3829a6e6fd550a219564912d4002c537f65da4c6ae4e093cc34462f4fa027ad", + "sha256:d43aa26dcda363f21e79afa0668f5029ed7394b3bb8c92a6927a3d34e8b610ea", + "sha256:d6d8efe71429635f0559579092bb5e60560d7b9115ee38c4adbea35632e7fa24", + "sha256:dabecc48db5f42ba348d1f5d5afdc54c6c4cc758e676926c7cd327045749517d", + "sha256:db88156fcf544cdbf0d95588051515cfdfd4c876fc66444eb98bceb5d6db76de", + "sha256:de550d129f18d8ab819651ffe4f38b1b713c7e116707de3c0c6400d0ef34fbc1", + "sha256:e0af85773850417d994d019741239b901b22c6680206f46a34766926e466141d", + "sha256:e3c4f84b24a1fcba435157d111c4b755099c6ff00a3daee1ad281817de75ed11", + "sha256:e3dd5fe19c9e0ac818a9c7f132a5e43c1339ec1cbbfecb1a938bd3a47875b7c9", + "sha256:e69aa6805905807186eb00e66c6d97a935c928275182eb02ee40ba00da9623b2", + "sha256:e80807d72f96b96ad5588cb85c75616e4f2795a7737d4630784c51497beb7776", + "sha256:ebe33f4ec1b2de38ceb225a1749a2965855bffeef435ba93cd2d5d540783bf2f", + "sha256:f0cea5b1d3e6e77d71bd2b9972eb2446221a69dc52bb0b9c3c6f6e5700592d93", + "sha256:f15401d8d3dbf239e23c818afc10c7207f7b95f9a307e092122b6f86dd43209a", + "sha256:f504d861d9f2a8f94020130adac88d66de93841707a23a86244263d1e54682f5", + "sha256:fc46da94826188ed45cb53bd8e3fc076ae22675aea2087843d4735627f867c6d", + "sha256:fc7140d7a7386e6b545d41b7358f4d02b656d4053f5fa6859f92f4b9c2572c4d", + "sha256:fcf3da95e93349e0647d48d4b36a12783105bcc74cb0c416952f9988410846a3", + "sha256:fe022f20bc4569ec66b63b3fb275a3d628d9d32da6326b2982584104db6d3086", + "sha256:ffb34ea45a82dd637c2c97ae1bbb920850c1e59bcae79ce1c15af531d83e7215" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==6.1.0" + }, + "markupsafe": { + "hashes": [ + "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", + "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", + "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", + "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", + "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", + "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c", + "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", + "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", + "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", + "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", + "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", + "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26", + "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", + "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", + "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", + "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", + "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", + "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", + "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", + "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", + "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", + "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", + "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", + "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", + "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", + "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758", + "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", + "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8", + "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", + "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", + "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", + "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", + "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", + "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", + "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", + "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", + "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2", + "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", + "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", + "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", + "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", + "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", + "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", + "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", + "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", + "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e", + "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", + "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", + "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", + "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", + "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", + "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", + "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b", + "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", + "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", + "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", + "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d", + "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", + "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", + "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", + "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", + "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", + "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", + "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", + "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", + "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", + "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", + "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", + "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", + "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", + "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", + "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", + "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", + "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7", + "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", + "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", + "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", + "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", + "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", + "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42", + "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", + "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", + "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", + "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", + "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", + "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", + "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc", + "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", + "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50" + ], + "markers": "python_version >= '3.9'", + "version": "==3.0.3" + }, + "msgpack": { + "hashes": [ + "sha256:0051fffef5a37ca2cd16978ae4f0aef92f164df86823871b5162812bebecd8e2", + "sha256:04fb995247a6e83830b62f0b07bf36540c213f6eac8e851166d8d86d83cbd014", + "sha256:180759d89a057eab503cf62eeec0aa61c4ea1200dee709f3a8e9397dbb3b6931", + "sha256:1d1418482b1ee984625d88aa9585db570180c286d942da463533b238b98b812b", + "sha256:1de460f0403172cff81169a30b9a92b260cb809c4cb7e2fc79ae8d0510c78b6b", + "sha256:1fdf7d83102bf09e7ce3357de96c59b627395352a4024f6e2458501f158bf999", + "sha256:1fff3d825d7859ac888b0fbda39a42d59193543920eda9d9bea44d958a878029", + "sha256:283ae72fc89da59aa004ba147e8fc2f766647b1251500182fac0350d8af299c0", + "sha256:2929af52106ca73fcb28576218476ffbb531a036c2adbcf54a3664de124303e9", + "sha256:2e86a607e558d22985d856948c12a3fa7b42efad264dca8a3ebbcfa2735d786c", + "sha256:350ad5353a467d9e3b126d8d1b90fe05ad081e2e1cef5753f8c345217c37e7b8", + "sha256:354e81bcdebaab427c3df4281187edc765d5d76bfb3a7c125af9da7a27e8458f", + "sha256:365c0bbe981a27d8932da71af63ef86acc59ed5c01ad929e09a0b88c6294e28a", + "sha256:372839311ccf6bdaf39b00b61288e0557916c3729529b301c52c2d88842add42", + "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", + "sha256:41d1a5d875680166d3ac5c38573896453bbbea7092936d2e107214daf43b1d4f", + "sha256:42eefe2c3e2af97ed470eec850facbe1b5ad1d6eacdbadc42ec98e7dcf68b4b7", + "sha256:446abdd8b94b55c800ac34b102dffd2f6aa0ce643c55dfc017ad89347db3dbdb", + "sha256:454e29e186285d2ebe65be34629fa0e8605202c60fbc7c4c650ccd41870896ef", + "sha256:4efd7b5979ccb539c221a4c4e16aac1a533efc97f3b759bb5a5ac9f6d10383bf", + "sha256:5559d03930d3aa0f3aacb4c42c776af1a2ace2611871c84a75afe436695e6245", + "sha256:5928604de9b032bc17f5099496417f113c45bc6bc21b5c6920caf34b3c428794", + "sha256:59415c6076b1e30e563eb732e23b994a61c159cec44deaf584e5cc1dd662f2af", + "sha256:5a46bf7e831d09470ad92dff02b8b1ac92175ca36b087f904a0519857c6be3ff", + "sha256:602b6740e95ffc55bfb078172d279de3773d7b7db1f703b2f1323566b878b90e", + "sha256:61c8aa3bd513d87c72ed0b37b53dd5c5a0f58f2ff9f26e1555d3bd7948fb7296", + "sha256:67016ae8c8965124fdede9d3769528ad8284f14d635337ffa6a713a580f6c030", + "sha256:6bde749afe671dc44893f8d08e83bf475a1a14570d67c4bb5cec5573463c8833", + "sha256:6c15b7d74c939ebe620dd8e559384be806204d73b4f9356320632d783d1f7939", + "sha256:70a0dff9d1f8da25179ffcf880e10cf1aad55fdb63cd59c9a49a1b82290062aa", + "sha256:70c5a7a9fea7f036b716191c29047374c10721c389c21e9ffafad04df8c52c90", + "sha256:7bc8813f88417599564fafa59fd6f95be417179f76b40325b500b3c98409757c", + "sha256:80a0ff7d4abf5fecb995fcf235d4064b9a9a8a40a3ab80999e6ac1e30b702717", + "sha256:86f8136dfa5c116365a8a651a7d7484b65b13339731dd6faebb9a0242151c406", + "sha256:897c478140877e5307760b0ea66e0932738879e7aa68144d9b78ea4c8302a84a", + "sha256:8b696e83c9f1532b4af884045ba7f3aa741a63b2bc22617293a2c6a7c645f251", + "sha256:8e22ab046fa7ede9e36eeb4cfad44d46450f37bb05d5ec482b02868f451c95e2", + "sha256:94fd7dc7d8cb0a54432f296f2246bc39474e017204ca6f4ff345941d4ed285a7", + "sha256:99e2cb7b9031568a2a5c73aa077180f93dd2e95b4f8d3b8e14a73ae94a9e667e", + "sha256:9ade919fac6a3e7260b7f64cea89df6bec59104987cbea34d34a2fa15d74310b", + "sha256:9fba231af7a933400238cb357ecccf8ab5d51535ea95d94fc35b7806218ff844", + "sha256:a465f0dceb8e13a487e54c07d04ae3ba131c7c5b95e2612596eafde1dccf64a9", + "sha256:a605409040f2da88676e9c9e5853b3449ba8011973616189ea5ee55ddbc5bc87", + "sha256:a668204fa43e6d02f89dbe79a30b0d67238d9ec4c5bd8a940fc3a004a47b721b", + "sha256:a7787d353595c7c7e145e2331abf8b7ff1e6673a6b974ded96e6d4ec09f00c8c", + "sha256:a8f6e7d30253714751aa0b0c84ae28948e852ee7fb0524082e6716769124bc23", + "sha256:ad09b984828d6b7bb52d1d1d0c9be68ad781fa004ca39216c8a1e63c0f34ba3c", + "sha256:bafca952dc13907bdfdedfc6a5f579bf4f292bdd506fadb38389afa3ac5b208e", + "sha256:be52a8fc79e45b0364210eef5234a7cf8d330836d0a64dfbb878efa903d84620", + "sha256:be5980f3ee0e6bd44f3a9e9dea01054f175b50c3e6cdb692bc9424c0bbb8bf69", + "sha256:c63eea553c69ab05b6747901b97d620bb2a690633c77f23feb0c6a947a8a7b8f", + "sha256:d198d275222dc54244bf3327eb8cbe00307d220241d9cec4d306d49a44e85f68", + "sha256:d62ce1f483f355f61adb5433ebfd8868c5f078d1a52d042b0a998682b4fa8c27", + "sha256:d99ef64f349d5ec3293688e91486c5fdb925ed03807f64d98d205d2713c60b46", + "sha256:db6192777d943bdaaafb6ba66d44bf65aa0e9c5616fa1d2da9bb08828c6b39aa", + "sha256:e23ce8d5f7aa6ea6d2a2b326b4ba46c985dbb204523759984430db7114f8aa00", + "sha256:e64c8d2f5e5d5fda7b842f55dec6133260ea8f53c4257d64494c534f306bf7a9", + "sha256:e69b39f8c0aa5ec24b57737ebee40be647035158f14ed4b40e6f150077e21a84", + "sha256:ea5405c46e690122a76531ab97a079e184c0daf491e588592d6a23d3e32af99e", + "sha256:f2cb069d8b981abc72b41aea1c580ce92d57c673ec61af4c500153a626cb9e20", + "sha256:fac4be746328f90caa3cd4bc67e6fe36ca2bf61d5c6eb6d895b6527e3f05071e", + "sha256:fffee09044073e69f2bad787071aeec727183e7580443dfeb8556cbf1978d162" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==1.1.2" + }, + "numpy": { + "hashes": [ + "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", + "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", + "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", + "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", + "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", + "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", + "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", + "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", + "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", + "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", + "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", + "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", + "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", + "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", + "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", + "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", + "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", + "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", + "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", + "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", + "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", + "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", + "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", + "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", + "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", + "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", + "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", + "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", + "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", + "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", + "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", + "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", + "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", + "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", + "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", + "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", + "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", + "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", + "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", + "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", + "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", + "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", + "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", + "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", + "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", + "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", + "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", + "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", + "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", + "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", + "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", + "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", + "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", + "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", + "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8" + ], + "markers": "python_version >= '3.10'", + "version": "==2.2.6" + }, + "packaging": { + "hashes": [ + "sha256:5d9c0669c6285e491e0ced2eee587eaf67b670d94a19e94e3984a481aba6802f", + "sha256:f042152b681c4bfac5cae2742a55e103d27ab2ec0f3d88037136b6bfe7c9c5de" + ], + "markers": "python_version >= '3.8'", + "version": "==26.1" + }, + "pandas": { + "hashes": [ + "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", + "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", + "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", + "sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791", + "sha256:23ebd657a4d38268c7dfbdf089fbc31ea709d82e4923c5ffd4fbd5747133ce73", + "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", + "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4", + "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", + "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac", + "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", + "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c", + "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", + "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", + "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250", + "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c", + "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826", + "sha256:5554c929ccc317d41a5e3d1234f3be588248e61f08a74dd17c9eabb535777dc9", + "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713", + "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1", + "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523", + "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", + "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78", + "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", + "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", + "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21", + "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5", + "sha256:854d00d556406bffe66a4c0802f334c9ad5a96b4f1f868adf036a21b11ef13ff", + "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45", + "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", + "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493", + "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", + "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", + "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", + "sha256:a637c5cdfa04b6d6e2ecedcb81fc52ffb0fd78ce2ebccc9ea964df9f658de8c8", + "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", + "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", + "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66", + "sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b", + "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8", + "sha256:bf1f8a81d04ca90e32a0aceb819d34dbd378a98bf923b6398b9a3ec0bf44de29", + "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", + "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", + "sha256:c503ba5216814e295f40711470446bc3fd00f0faea8a086cbc688808e26f92a2", + "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", + "sha256:d3e28b3e83862ccf4d85ff19cf8c20b2ae7e503881711ff2d534dc8f761131aa", + "sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151", + "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838", + "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", + "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a", + "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d", + "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", + "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", + "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", + "sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c", + "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==2.3.3" + }, + "pastedeploy": { + "hashes": [ + "sha256:76388ad53a661448d436df28c798063108f70e994ddc749540d733cdbd1b38cf", + "sha256:9ddbaf152f8095438a9fe81f82c78a6714b92ae8e066bed418b6a7ff6a095a95" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.0" + }, + "plaster": { + "hashes": [ + "sha256:42992ab1f4865f1278e2ad740e8ad145683bb4022e03534265528f0c23c0df2d", + "sha256:f8befc54bf8c1147c10ab40297ec84c2676fa2d4ea5d6f524d9436a80074ef98" + ], + "markers": "python_version >= '3.7'", + "version": "==1.1.2" + }, + "plaster-pastedeploy": { + "hashes": [ + "sha256:ad3550cc744648969ed3b810f33c9344f515ee8d8a8cec18e8f2c4a643c2181f", + "sha256:be262e6d2e41a7264875daa2fe2850cbb0615728bcdc92828fdc72736e381412" + ], + "markers": "python_version >= '3.7'", + "version": "==1.0.1" + }, + "platformdirs": { + "hashes": [ + "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", + "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917" + ], + "markers": "python_version >= '3.10'", + "version": "==4.9.6" + }, + "pluggy": { + "hashes": [ + "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", + "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746" + ], + "markers": "python_version >= '3.9'", + "version": "==1.6.0" + }, + "pygments": { + "hashes": [ + "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", + "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176" + ], + "markers": "python_version >= '3.9'", + "version": "==2.20.0" + }, + "pyparsing": { + "hashes": [ + "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", + "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==3.3.2" + }, + "pyproject-api": { + "hashes": [ + "sha256:40c6f2d82eebdc4afee61c773ed208c04c19db4c4a60d97f8d7be3ebc0bbb330", + "sha256:8757c41a79c0f4ab71b99abed52b97ecf66bd20b04fa59da43b5840bac105a09" + ], + "markers": "python_version >= '3.10'", + "version": "==1.10.0" + }, + "pyramid": { + "hashes": [ + "sha256:0aa62604221f6a8ac6e77a0faa02a5b7a294d6675f15581d8d416dffe2ac98e7", + "sha256:5a24bc1b5f9e0f0d1c0b6ddd1111e84c15dac44a07e3c1d24e74dd9bb4fc22eb" + ], + "index": "pypi", + "markers": "python_version >= '3.10'", + "version": "==2.1" + }, + "pytest": { + "hashes": [ + "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", + "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c" + ], + "index": "pypi", + "markers": "python_version >= '3.10'", + "version": "==9.0.3" + }, + "pytest-cov": { + "hashes": [ + "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", + "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==7.1.0" + }, + "pytest-django": { + "hashes": [ + "sha256:3ff300c49f8350ba2953b90297d23bf5f589db69545f56f1ec5f8cff5da83e85", + "sha256:df94ec819a83c8979c8f6de13d9cdfbe76e8c21d39473cfe2b40c9fc9be3c758" + ], + "index": "pypi", + "markers": "python_version >= '3.10'", + "version": "==4.12.0" + }, + "pytest-twisted": { + "hashes": [ + "sha256:37e150cbbc0edba6592d36c53f44fc1196f3a9e93e7bef6a25bb10d9963f7f3e", + "sha256:f2e3f3f6f12f78df17c028fe16d87af09c76b95a7a85bc378b2d3e73a086e81a" + ], + "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==1.14.3" + }, + "python-dateutil": { + "hashes": [ + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==2.9.0.post0" + }, + "python-discovery": { + "hashes": [ + "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb", + "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a" + ], + "markers": "python_version >= '3.8'", + "version": "==1.2.2" + }, + "python-subunit": { + "hashes": [ + "sha256:254f85a144d8c4e62bf02cc53c834d2f36177056353fcd90a60a2745e229cf17", + "sha256:a57d61f0ba2c0a8657c61329301ada6ad8e30b26fb47ca3bb37481463e75aabf" + ], + "index": "pypi", + "markers": "python_version >= '3.10'", + "version": "==1.4.5" + }, + "pytz": { + "hashes": [ + "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", + "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a" + ], + "version": "==2026.1.post1" + }, + "pyyaml": { + "hashes": [ + "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", + "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a", + "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", + "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", + "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", + "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", + "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", + "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", + "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0", + "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", + "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", + "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6", + "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7", + "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", + "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007", + "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", + "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", + "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9", + "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295", + "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", + "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", + "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", + "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", + "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", + "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", + "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", + "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", + "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b", + "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", + "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5", + "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", + "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", + "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369", + "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", + "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", + "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", + "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", + "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", + "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", + "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", + "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", + "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", + "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", + "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", + "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", + "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", + "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", + "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", + "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", + "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4", + "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", + "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", + "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", + "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", + "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", + "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", + "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da", + "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", + "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", + "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", + "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", + "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f", + "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917", + "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", + "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", + "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", + "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", + "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", + "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", + "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3", + "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", + "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926", + "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==6.0.3" + }, + "pyzmq": { + "hashes": [ + "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d", + "sha256:01f9437501886d3a1dd4b02ef59fb8cc384fa718ce066d52f175ee49dd5b7ed8", + "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", + "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", + "sha256:0790a0161c281ca9723f804871b4027f2e8b5a528d357c8952d08cd1a9c15581", + "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05", + "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", + "sha256:0c996ded912812a2fcd7ab6574f4ad3edc27cb6510349431e4930d4196ade7db", + "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", + "sha256:15c8bd0fe0dabf808e2d7a681398c4e5ded70a551ab47482067a572c054c8e2e", + "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea", + "sha256:18339186c0ed0ce5835f2656cdfb32203125917711af64da64dbaa3d949e5a1b", + "sha256:18770c8d3563715387139060d37859c02ce40718d1faf299abddcdcc6a649066", + "sha256:190cbf120fbc0fc4957b56866830def56628934a9d112aec0e2507aa6a032b97", + "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0", + "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", + "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92", + "sha256:1f8426a01b1c4098a750973c37131cf585f61c7911d735f729935a0c701b68d3", + "sha256:226b091818d461a3bef763805e75685e478ac17e9008f49fce2d3e52b3d58b86", + "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", + "sha256:346e9ba4198177a07e7706050f35d733e08c1c1f8ceacd5eb6389d653579ffbc", + "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", + "sha256:3970778e74cb7f85934d2b926b9900e92bfe597e62267d7499acc39c9c28e345", + "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", + "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", + "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", + "sha256:49d3980544447f6bd2968b6ac913ab963a49dcaa2d4a2990041f16057b04c429", + "sha256:4a19387a3dddcc762bfd2f570d14e2395b2c9701329b266f83dd87a2b3cbd381", + "sha256:4c618fbcd069e3a29dcd221739cacde52edcc681f041907867e0f5cc7e85f172", + "sha256:50081a4e98472ba9f5a02850014b4c9b629da6710f8f14f3b15897c666a28f1b", + "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", + "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", + "sha256:510869f9df36ab97f89f4cff9d002a89ac554c7ac9cadd87d444aa4cf66abd27", + "sha256:53b40f8ae006f2734ee7608d59ed661419f087521edbfc2149c3932e9c14808c", + "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd", + "sha256:5bbf8d3630bf96550b3be8e1fc0fea5cbdc8d5466c1192887bd94869da17a63e", + "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", + "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", + "sha256:6df079c47d5902af6db298ec92151db82ecb557af663098b92f2508c398bb54f", + "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128", + "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96", + "sha256:722ea791aa233ac0a819fc2c475e1292c76930b31f1d828cb61073e2fe5e208f", + "sha256:726b6a502f2e34c6d2ada5e702929586d3ac948a4dbbb7fed9854ec8c0466027", + "sha256:753d56fba8f70962cd8295fb3edb40b9b16deaa882dd2b5a3a2039f9ff7625aa", + "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", + "sha256:7be883ff3d722e6085ee3f4afc057a50f7f2e0c72d289fd54df5706b4e3d3a50", + "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", + "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", + "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146", + "sha256:849ca054d81aa1c175c49484afaaa5db0622092b5eccb2055f9f3bb8f703782d", + "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97", + "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5", + "sha256:9541c444cfe1b1c0156c5c86ece2bb926c7079a18e7b47b0b1b3b1b875e5d098", + "sha256:96c71c32fff75957db6ae33cd961439f386505c6e6b377370af9b24a1ef9eafb", + "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", + "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", + "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", + "sha256:a1aa0ee920fb3825d6c825ae3f6c508403b905b698b6460408ebd5bb04bbb312", + "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", + "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", + "sha256:ac25465d42f92e990f8d8b0546b01c391ad431c3bf447683fdc40565941d0604", + "sha256:ad68808a61cbfbbae7ba26d6233f2a4aa3b221de379ce9ee468aa7a83b9c36b0", + "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db", + "sha256:b1267823d72d1e40701dcba7edc45fd17f71be1285557b7fe668887150a14b78", + "sha256:b2e592db3a93128daf567de9650a2f3859017b3f7a66bc4ed6e4779d6034976f", + "sha256:b721c05d932e5ad9ff9344f708c96b9e1a485418c6618d765fca95d4daacfbef", + "sha256:bafcb3dd171b4ae9f19ee6380dfc71ce0390fefaf26b504c0e5f628d7c8c54f2", + "sha256:bd67e7c8f4654bef471c0b1ca6614af0b5202a790723a58b79d9584dc8022a78", + "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", + "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", + "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", + "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39", + "sha256:c895a6f35476b0c3a54e3eb6ccf41bf3018de937016e6e18748317f25d4e925f", + "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355", + "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a", + "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a", + "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", + "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9", + "sha256:da96ecdcf7d3919c3be2de91a8c513c186f6762aa6cf7c01087ed74fad7f0968", + "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7", + "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", + "sha256:df7cd397ece96cf20a76fae705d40efbab217d217897a5053267cd88a700c266", + "sha256:e2687c2d230e8d8584fbea433c24382edfeda0c60627aca3446aa5e58d5d1831", + "sha256:e30a74a39b93e2e1591b58eb1acef4902be27c957a8720b0e368f579b82dc22f", + "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7", + "sha256:e829529fcaa09937189178115c49c504e69289abd39967cd8a4c215761373394", + "sha256:eca6b47df11a132d1745eb3b5b5e557a7dae2c303277aa0e69c6ba91b8736e07", + "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", + "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", + "sha256:f605d884e7c8be8fe1aa94e0a783bf3f591b84c24e4bc4f3e7564c82ac25e271", + "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6", + "sha256:ff8d114d14ac671d88c89b9224c63d6c4e5a613fe8acd5594ce53d752a3aafe9" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==27.1.0" + }, + "requests": { + "hashes": [ + "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", + "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a" + ], + "markers": "python_version >= '3.10'", + "version": "==2.33.1" + }, + "requests-file": { + "hashes": [ + "sha256:d0f5eb94353986d998f80ac63c7f146a307728be051d4d1cd390dbdb59c10fa2", + "sha256:f14243d7796c588f3521bd423c5dea2ee4cc730e54a3cac9574d78aca1272576" + ], + "version": "==3.0.1" + }, + "requests-toolbelt": { + "hashes": [ + "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", + "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.0.0" + }, + "setuptools": { + "hashes": [ + "sha256:487b53915f52501f0a79ccfd0c02c165ffe06631443a886740b91af4b7a5845a", + "sha256:fdd925d5c5d9f62e4b74b30d6dd7828ce236fd6ed998a08d81de62ce5a6310d6" + ], + "markers": "python_version >= '3.9'", + "version": "==81.0.0" + }, + "six": { + "hashes": [ + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==1.17.0" + }, + "soupsieve": { + "hashes": [ + "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349", + "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95" + ], + "markers": "python_version >= '3.9'", + "version": "==2.8.3" + }, + "sqlalchemy": { + "hashes": [ + "sha256:01146546d84185f12721a1d2ce0c6673451a7894d1460b592d378ca4871a0c72", + "sha256:059d7151fff513c53a4638da8778be7fce81a0c4854c7348ebd0c4078ddf28fe", + "sha256:0c98c59075b890df8abfcc6ad632879540f5791c68baebacb4f833713b510e75", + "sha256:0f2fa354ba106eafff2c14b0cc51f22801d1e8b2e4149342023bd6f0955de5f5", + "sha256:12b04d1db2663b421fe072d638a138460a51d5a862403295671c4f3987fb9148", + "sha256:22d8798819f86720bc646ab015baff5ea4c971d68121cb36e2ebc2ee43ead2b7", + "sha256:233088b4b99ebcbc5258c755a097aa52fbf90727a03a5a80781c4b9c54347a2e", + "sha256:24bd94bb301ec672d8f0623eba9226cc90d775d25a0c92b5f8e4965d7f3a1518", + "sha256:275424295f4256fd301744b8f335cff367825d270f155d522b30c7bf49903ee7", + "sha256:32fe6a41ad97302db2931f05bb91abbcc65b5ce4c675cd44b972428dd2947700", + "sha256:334edbcff10514ad1d66e3a70b339c0a29886394892490119dbb669627b17717", + "sha256:3bb9ec6436a820a4c006aad1ac351f12de2f2dbdaad171692ee457a02429b672", + "sha256:3ddcb27fb39171de36e207600116ac9dfd4ae46f86c82a9bf3934043e80ebb88", + "sha256:42e8804962f9e6f4be2cbaedc0c3718f08f60a16910fa3d86da5a1e3b1bfe60f", + "sha256:43d044780732d9e0381ac8d5316f95d7f02ef04d6e4ef6dc82379f09795d993f", + "sha256:46796877b47034b559a593d7e4b549aba151dae73f9e78212a3478161c12ab08", + "sha256:46d51518d53edfbe0563662c96954dc8fcace9832332b914375f45a99b77cc9a", + "sha256:47604cb2159f8bbd5a1ab48a714557156320f20871ee64d550d8bf2683d980d3", + "sha256:4bbccb45260e4ff1b7db0be80a9025bb1e6698bdb808b83fff0000f7a90b2c0b", + "sha256:4d4e5a0ceba319942fa6b585cf82539288a61e314ef006c1209f734551ab9536", + "sha256:55250fe61d6ebfd6934a272ee16ef1244e0f16b7af6cd18ab5b1fc9f08631db0", + "sha256:566df36fd0e901625523a5a1835032f1ebdd7f7886c54584143fa6c668b4df3b", + "sha256:57ca426a48eb2c682dae8204cd89ea8ab7031e2675120a47924fabc7caacbc2a", + "sha256:5e61abbec255be7b122aa461021daa7c3f310f3e743411a67079f9b3cc91ece3", + "sha256:618a308215b6cececb6240b9abde545e3acdabac7ae3e1d4e666896bf5ba44b4", + "sha256:62557958002b69699bdb7f5137c6714ca1133f045f97b3903964f47db97ea339", + "sha256:6270d717b11c5476b0cbb21eedc8d4dbb7d1a956fd6c15a23e96f197a6193158", + "sha256:685e93e9c8f399b0c96a624799820176312f5ceef958c0f88215af4013d29066", + "sha256:69469ce8ce7a8df4d37620e3163b71238719e1e2e5048d114a1b6ce0fbf8c662", + "sha256:6eb188b84269f357669b62cb576b5b918de10fb7c728a005fa0ebb0b758adce1", + "sha256:74ab4ee7794d7ed1b0c37e7333640e0f0a626fc7b398c07a7aef52f484fddde3", + "sha256:77641d299179c37b89cf2343ca9972c88bb6eef0d5fc504a2f86afd15cd5adf5", + "sha256:7c821c47ecfe05cc32140dcf8dc6fd5d21971c86dbd56eabfe5ba07a64910c01", + "sha256:7d6be30b2a75362325176c036d7fb8d19e8846c77e87683ffaa8177b35135613", + "sha256:7f605a456948c35260e7b2a39f8952a26f077fd25653c37740ed186b90aaa68a", + "sha256:83101a6930332b87653886c01d1ee7e294b1fe46a07dd9a2d2b4f91bcc88eec0", + "sha256:88690f4e1f0fbf5339bedbb127e240fec1fd3070e9934c0b7bef83432f779d2f", + "sha256:8a97ac839c2c6672c4865e48f3cbad7152cee85f4233fb4ca6291d775b9b954a", + "sha256:8d6efc136f44a7e8bc8088507eaabbb8c2b55b3dbb63fe102c690da0ddebe55e", + "sha256:8e20e511dc15265fb433571391ba313e10dd8ea7e509d51686a51313b4ac01a2", + "sha256:951d4a210744813be63019f3df343bf233b7432aadf0db54c75802247330d3af", + "sha256:9ac7a3e245fd0310fd31495eb61af772e637bdf7d88ee81e7f10a3f271bff014", + "sha256:9b1c058c171b739e7c330760044803099c7fff11511e3ab3573e5327116a9c33", + "sha256:9c04bff9a5335eb95c6ecf1c117576a0aa560def274876fd156cfe5510fccc61", + "sha256:9c4969a86e41454f2858256c39bdfb966a20961e9b58bf8749b65abf447e9a8d", + "sha256:9e0400fa22f79acc334d9a6b185dc00a44a8e6578aa7e12d0ddcd8434152b187", + "sha256:a05977bffe9bffd2229f477fa75eabe3192b1b05f408961d1bebff8d1cd4d401", + "sha256:a143af2ea6672f2af3f44ed8f9cd020e9cc34c56f0e8db12019d5d9ecf41cb3b", + "sha256:a51d3db74ba489266ef55c7a4534eb0b8db9a326553df481c11e5d7660c8364d", + "sha256:b95b2f470c1b2683febd2e7eab1d3f0e078c91dbdd0b00e9c645d07a413bb99f", + "sha256:b9870d15ef00e4d0559ae10ee5bc71b654d1f20076dbe8bc7ed19b4c0625ceba", + "sha256:c1dc3368794d522f43914e03312202523cc89692f5389c32bea0233924f8d977", + "sha256:c338ec6ec01c0bc8e735c58b9f5d51e75bacb6ff23296658826d7cfdfdb8678a", + "sha256:c5070135e1b7409c4161133aa525419b0062088ed77c92b1da95366ec5cbebbe", + "sha256:cc992c6ed024c8c3c592c5fc9846a03dd68a425674900c70122c77ea16c5fb0b", + "sha256:d15950a57a210e36dd4cec1aac22787e2a4d57ba9318233e2ef8b2daf9ff2d5f", + "sha256:d898cc2c76c135ef65517f4ddd7a3512fb41f23087b0650efb3418b8389a3cd1", + "sha256:d99945830a6f3e9638d89a28ed130b1eb24c91255e4f24366fbe699b983f29e4", + "sha256:da9b91bca419dc9b9267ffadde24eae9b1a6bffcd09d0a207e5e3af99a03ce0d", + "sha256:df2d441bacf97022e81ad047e1597552eb3f83ca8a8f1a1fdd43cd7fe3898120", + "sha256:e06e617e3d4fd9e51d385dfe45b077a41e9d1b033a7702551e3278ac597dc750", + "sha256:ec44cfa7ef1a728e88ad41674de50f6db8cfdb3e2af84af86e0041aaf02d43d0", + "sha256:fb37f15714ec2652d574f021d479e78cd4eb9d04396dca36568fdfffb3487982" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==2.0.49" + }, + "sqlparse": { + "hashes": [ + "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", + "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e" + ], + "markers": "python_version >= '3.8'", + "version": "==0.5.5" + }, + "suds-community": { + "hashes": [ + "sha256:505b191865bca125f12e8ff9598b24d9c0108b98826671bdd700ed51def44e36", + "sha256:ab3b24dc9ba06b5e6598e2a5d34d2a7d06c79e613d81cedc028475bfbd3bb90c" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==1.2.0" + }, + "testtools": { + "hashes": [ + "sha256:32e2f96be68e2a0ed8a3ad14d9923848b8a53cbd2eaf6c3b2a2061753f8ab7c3", + "sha256:eb562d1a2157c6d443c8c118861eb452b3655d1842f9b61b8567ad01b32826e3" + ], + "markers": "python_version >= '3.10'", + "version": "==2.9.0" + }, + "tomli": { + "hashes": [ + "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", + "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", + "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", + "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", + "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", + "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", + "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", + "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", + "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", + "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", + "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", + "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", + "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", + "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", + "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", + "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", + "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", + "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", + "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", + "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", + "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", + "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", + "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", + "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", + "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", + "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", + "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", + "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", + "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", + "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", + "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", + "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", + "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", + "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", + "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", + "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", + "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", + "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", + "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", + "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", + "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", + "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", + "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", + "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", + "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", + "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", + "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049" + ], + "markers": "python_version >= '3.8'", + "version": "==2.4.1" + }, + "tomli-w": { + "hashes": [ + "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", + "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021" + ], + "markers": "python_version >= '3.9'", + "version": "==1.2.0" + }, + "tox": { + "hashes": [ + "sha256:62c780e42f87d34ee60f2ea20342156253794fdcbd6885fd797d98ee05009f22", + "sha256:cc4e716d18c4889aa179d785175c438fa60c35deef20ce689ec288d8fb656096" + ], + "index": "pypi", + "markers": "python_version >= '3.10'", + "version": "==4.53.0" + }, + "translationstring": { + "hashes": [ + "sha256:5f4dc4d939573db851c8d840551e1a0fb27b946afe3b95aafc22577eed2d6262", + "sha256:bf947538d76e69ba12ab17283b10355a9ecfbc078e6123443f43f2107f6376f3" + ], + "version": "==1.4" + }, + "twisted": { + "hashes": [ + "sha256:1deb272358cb6be1e3e8fc6f9c8b36f78eb0fa7c2233d2dbe11ec6fee04ea316", + "sha256:8559f654d01a54a8c3efe66d533d43f383531ebf8d81d9f9ab4769d91ca15df7" + ], + "index": "pypi", + "markers": "python_full_version >= '3.8.0'", + "version": "==25.5.0" + }, + "typing-extensions": { + "hashes": [ + "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", + "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" + ], + "markers": "python_version >= '3.9'", + "version": "==4.15.0" + }, + "tzdata": { + "hashes": [ + "sha256:4b1d2be7ac37ceafd7327b961aa3a54e467efbdb563a23655fbfe0d39cfc42a9", + "sha256:67658a1903c75917309e753fdc349ac0efd8c27db7a0cb406a25be4840f87f98" + ], + "markers": "python_version >= '2'", + "version": "==2026.1" + }, + "urllib3": { + "hashes": [ + "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", + "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4" + ], + "markers": "python_version >= '3.9'", + "version": "==2.6.3" + }, + "venusian": { + "hashes": [ + "sha256:0845808a985976acbceaa1fbb871c7fac4fb28ae75453232970e9c2c2866dbf4", + "sha256:534fb3b355669283eb3954581931e5d1d071fce61d029d58f3219a5e3a6f0c41" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.1" + }, + "virtualenv": { + "hashes": [ + "sha256:29d21e941795206138d0f22f4e45ff7050e5da6c6472299fb7103318763861ac", + "sha256:b294ef68192638004d72524ce7ef303e9d0cf5a44c95ce2e54a7500a6381cada" + ], + "markers": "python_version >= '3.8'", + "version": "==21.2.4" + }, + "waitress": { + "hashes": [ + "sha256:682aaaf2af0c44ada4abfb70ded36393f0e307f4ab9456a215ce0020baefc31f", + "sha256:c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e" + ], + "markers": "python_full_version >= '3.9.0'", + "version": "==3.0.2" + }, + "webob": { + "hashes": [ + "sha256:45e34c58ed0c7e2ecd238ffd34432487ff13d9ad459ddfd77895e67abba7c1f9", + "sha256:ad6078e2edb6766d1334ec3dee072ac6a7f95b1e32ce10def8ff7f0f02d56589" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==1.8.9" + }, + "webtest": { + "hashes": [ + "sha256:2f51a0844f3a8beaef89bc23d225fe05ad816f7e429ffcc655a13013a799ac6c", + "sha256:7aeab50f970d46c068e7a36dd162cb242591edf72a1d04efd21374772b931741" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==3.0.7" + }, + "werkzeug": { + "hashes": [ + "sha256:63a77fb8892bf28ebc3178683445222aa500e48ebad5ec77b0ad80f8726b1f50", + "sha256:9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==3.1.8" + }, + "zeep": { + "hashes": [ + "sha256:1a23a667ce9d73a0dbfdf15745bfa2b7ab0b6402135c0cd5067574838398e0e6", + "sha256:ed08c3179709172bfaaa9b76a6a545f8a57043ec6218e64e9deb81ff1e0ff79b" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==4.3.2" + }, + "zope-interface": { + "hashes": [ + "sha256:12a33bb596ca20520e44f97918950cfc66a632ac0278a7f40608217cc4269948", + "sha256:1aa0e1d72212cedc38b2156bbca08cf24625c057135a7947ef6b19bc732b2772", + "sha256:301db4049c79a15a3b29d89795e150daf0e9ae701404b112ad6585ea863f6ef5", + "sha256:33a13acba79ef693fb64ceb6193ece913d39586f184797f133c1bc549da86851", + "sha256:34d6c10fa790005487c471e0e4ab537b0fa9a70e55a96994e51ffeef92205fa4", + "sha256:3853bfb808084e1b4a3a769b00bd8b58a52b0c4a4fc5c23de26d283cd8beb627", + "sha256:54ab83218a8f6947ba4b6cb1a121f1e1abe2e418b838ccdac71639d0f97e734e", + "sha256:568b97cb701fd2830b52198a2885e851317a019e1912eaad107860e3cca71964", + "sha256:5a5b50d0dcdb4200f1936f75b6688bd86de5c14c5d20bed2e004300a04521826", + "sha256:5e9861493457268f923d8aae4052383922162c3d56094c4e3a9ff83173d64be3", + "sha256:62839e4201869a29f99742df7f7139cac4ce301850d3787da37f84e271ad9b95", + "sha256:731eaf0a0f2a683315a2dfc2953ef831ae51e062b87cff6220e0e5102a83b612", + "sha256:8ce49d43366e12aeccd14fcaebb3ef110f50f5795e0d4a95383ea057365cedf2", + "sha256:8f81d90f80b9fbf36602549e2f187861c9d7139837f8c9dd685ce3b933c6360f", + "sha256:93108d5f8dee20177a637438bf4df4c6faf8a317c9d4a8b1d5e78123854e3317", + "sha256:96106a5f609bb355e1aec6ab0361213c8af0843ca1e1ba9c42eacfbd0910914e", + "sha256:961af756797e36c1e77f7d0dc8ac1322de0c071eaa1a641dbe3b790061968dd9", + "sha256:96f0001b49227d756770fc70ecde49f19332ae98ec98e1bbbf2fd7a87e9d4e45", + "sha256:99c84e12efe0e17f03c6bb5a8ea18fb2841e6666ee0b8331d5967fec84337884", + "sha256:a6329f296b70f62043bf2df06eb91b4be040baee32ec4a3e0314f3893fa5c51c", + "sha256:a918f8e73c35a1352a4b49db67b90b37d33fb7651c834def3f0e3784437bb3a8", + "sha256:b361b7ce566bc024e55f74eb1e88afc14039d7bd8ea13eeff3b7a8400dc59683", + "sha256:c8a2f9c4ee0f2ad4817e9481684993d33b66d9b815f9157a716a189af483bc34", + "sha256:d287183767926bc9841e51471a28b77c7b49fddf65016aa7faf5a1447e2b6558", + "sha256:e1a9de7d0b5b5c249a73b91aebf4598ce05e334303af6aa94865893283e9ff10", + "sha256:e8964f1a13b07c8770eab88b7a6cd0870c3e36442e4ef4937f36fd0b6d1cea2c", + "sha256:e9f7e4b46741a11a9e1fab8b68710f08dec700e9f1b877cdca02480fbebe4846", + "sha256:ec2728e3cf685126ccd2e0f7635fb60edf116f76f402dd66f4df13d9d9348b4b", + "sha256:f420f6c96307ff265981c510782f0ed97475107b78ca9fca0bb04fe36f363eb4", + "sha256:f5be73ca1304daa3046ee5835f7fa6b3badadf02102b570532dd57cd25dd72d6", + "sha256:ffeae9102aa6ba5bd2f9a547016347bd87c9cf01aea564936c0d165fff0b1242" + ], + "markers": "python_version >= '3.10'", + "version": "==8.3" + }, + "zope.deprecation": { + "hashes": [ + "sha256:18727ebda8e63a6d4bd28a290e8b46852e9f14473debb5cc40a0a2dccfadf15f", + "sha256:ff72d51c88b516b9ddf2cfb826381cc49f99a6a89b7d35c97faca7bee3b46da6" + ], + "markers": "python_version >= '3.9'", + "version": "==6.0" + } + } +} diff --git a/examples/authentication/http_cookie/server_soap.py b/examples/authentication/http_cookie/server_soap.py index 426f56704..47c9e0cbb 100755 --- a/examples/authentication/http_cookie/server_soap.py +++ b/examples/authentication/http_cookie/server_soap.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -#encoding: utf8 +# encoding: utf8 # # Copyright © Burak Arslan , # Arskom Ltd. http://www.arskom.com.tr @@ -36,7 +36,7 @@ from pprint import pformat -from spyne.util.six.moves.http_cookies import SimpleCookie +from http.cookies import SimpleCookie # bcrypt seems to be among the latest consensus around cryptograpic circles on # storing passwords. @@ -45,7 +45,7 @@ try: import bcrypt except ImportError: - print('easy_install --user py-bcrypt to get it.') + print("easy_install --user py-bcrypt to get it.") raise from spyne import Unicode, Application, rpc, Service @@ -56,46 +56,47 @@ class PublicKeyError(Fault): - __namespace__ = 'spyne.examples.authentication' + __namespace__ = "spyne.examples.authentication" def __init__(self, value): super(PublicKeyError, self).__init__( - faultcode='Client.KeyError', - faultstring='Value %r not found' % value - ) + faultcode="Client.KeyError", faultstring="Value %r not found" % value + ) class AuthenticationError(Fault): - __namespace__ = 'spyne.examples.authentication' + __namespace__ = "spyne.examples.authentication" def __init__(self, user_name): # TODO: self.transport.http.resp_code = HTTP_401 super(AuthenticationError, self).__init__( - faultcode='Client.AuthenticationError', - faultstring='Invalid authentication request for %r' % user_name - ) + faultcode="Client.AuthenticationError", + faultstring="Invalid authentication request for %r" % user_name, + ) class AuthorizationError(Fault): - __namespace__ = 'spyne.examples.authentication' + __namespace__ = "spyne.examples.authentication" def __init__(self): # TODO: self.transport.http.resp_code = HTTP_401 super(AuthorizationError, self).__init__( - faultcode='Client.AuthorizationError', - faultstring='You are not authorized to access this resource.' - ) + faultcode="Client.AuthorizationError", + faultstring="You are not authorized to access this resource.", + ) + class UnauthenticatedError(Fault): - __namespace__ = 'spyne.examples.authentication' + __namespace__ = "spyne.examples.authentication" def __init__(self): super(UnauthenticatedError, self).__init__( - faultcode='Client.UnauthenticatedError', - faultstring='This resource can only be accessed after authentication.' - ) + faultcode="Client.UnauthenticatedError", + faultstring="This resource can only be accessed after authentication.", + ) + class SpyneDict(dict): def __getitem__(self, key): @@ -106,33 +107,35 @@ def __getitem__(self, key): class Preferences(ComplexModel): - __namespace__ = 'spyne.examples.authentication' + __namespace__ = "spyne.examples.authentication" language = String(max_len=2) time_zone = String user_db = { - 'neo': bcrypt.hashpw(b'Wh1teR@bbit', bcrypt.gensalt()), + "neo": bcrypt.hashpw(b"Wh1teR@bbit", bcrypt.gensalt()), } session_db = set() -preferences_db = SpyneDict({ - 'neo': Preferences(language='en', time_zone='Underground/Zion'), - 'smith': Preferences(language='xx', time_zone='Matrix/Core'), -}) +preferences_db = SpyneDict( + { + "neo": Preferences(language="en", time_zone="Underground/Zion"), + "smith": Preferences(language="xx", time_zone="Matrix/Core"), + } +) class Encoding: - SESSION_ID = 'ascii' - USER_NAME = PASSWORD = CREDENTIALS = 'utf8' + SESSION_ID = "ascii" + USER_NAME = PASSWORD = CREDENTIALS = "utf8" class UserService(Service): - __tns__ = 'spyne.examples.authentication' + __tns__ = "spyne.examples.authentication" - @rpc(M(Unicode), M(Unicode), _throws=AuthenticationError) + @rpc(M(Unicode), M(Unicode), _throws=AuthenticationError) def authenticate(ctx, user_name, password): ENC_C = Encoding.CREDENTIALS ENC_SID = Encoding.SESSION_ID @@ -140,13 +143,13 @@ def authenticate(ctx, user_name, password): password_hash = user_db.get(user_name, None) if password_hash is None: - raise AuthenticationError(user_name) + raise AuthenticationError(user_name) password_b = password.encode(ENC_C) if bcrypt.hashpw(password_b, password_hash) != password_hash: - raise AuthenticationError(user_name) + raise AuthenticationError(user_name) - session_id = '%x' % (random.randint(1<<128, (1<<132)-1)) + session_id = "%x" % (random.randint(1 << 128, (1 << 132) - 1)) session_key = ( user_name.encode(ENC_C), session_id.encode(ENC_SID), @@ -154,9 +157,9 @@ def authenticate(ctx, user_name, password): session_db.add(session_key) cookie = SimpleCookie() - cookie["session-id"] = \ - base64.urlsafe_b64encode(b"\0".join(session_key)) \ - .decode('ascii') # find out how to do urlsafe_b64encodestring + cookie["session-id"] = base64.urlsafe_b64encode(b"\0".join(session_key)).decode( + "ascii" + ) # find out how to do urlsafe_b64encodestring cookie["session-id"]["max-age"] = 3600 header_name, header_value = cookie.output().split(":", 1) @@ -164,7 +167,6 @@ def authenticate(ctx, user_name, password): logging.debug("Response headers: %s", pformat(ctx.transport.resp_headers)) - @rpc(M(String), _throws=PublicKeyError, _returns=Preferences) def get_preferences(ctx, user_name): # Only allow access to the users own preferences. @@ -193,8 +195,7 @@ def _on_method_call(ctx): session_cookie = cookie["session-id"].value - user_name, session_id = base64.urlsafe_b64decode(session_cookie) \ - .split(b"\0", 1) + user_name, session_id = base64.urlsafe_b64decode(session_cookie).split(b"\0", 1) session_id = tuple(base64.urlsafe_b64decode(session_cookie).split(b"\0", 1)) if not session_id in session_db: @@ -203,26 +204,27 @@ def _on_method_call(ctx): ctx.udc = session_id[0].decode(Encoding.USER_NAME) -UserService.event_manager.add_listener('method_call', _on_method_call) +UserService.event_manager.add_listener("method_call", _on_method_call) -if __name__=='__main__': +if __name__ == "__main__": from spyne.util.wsgi_wrapper import run_twisted logging.basicConfig(level=logging.DEBUG) - logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG) - logging.getLogger('twisted').setLevel(logging.DEBUG) - - application = Application([UserService], - tns='spyne.examples.authentication', - in_protocol=Soap11(validator='lxml'), - out_protocol=Soap11() + logging.getLogger("spyne.protocol.xml").setLevel(logging.DEBUG) + logging.getLogger("twisted").setLevel(logging.DEBUG) + + application = Application( + [UserService], + tns="spyne.examples.authentication", + in_protocol=Soap11(validator="lxml"), + out_protocol=Soap11(), ) wsgi_app = WsgiApplication(application) wsgi_app.doc.wsdl11.xsl_href = "wsdl-viewer.xsl" twisted_apps = [ - (wsgi_app, b'app'), + (wsgi_app, b"app"), ] sys.exit(run_twisted(twisted_apps, 8000)) diff --git a/examples/custom_type.py b/examples/custom_type.py index 415e4071e..551e545da 100644 --- a/examples/custom_type.py +++ b/examples/custom_type.py @@ -31,7 +31,6 @@ from spyne import ComplexModel, AnyDict, ValidationError, Array, Any -from spyne.util import six from spyne.util.dictdoc import json_loads from spyne.util.web import log_repr @@ -41,7 +40,7 @@ class DictOfUniformArray(AnyDict): @staticmethod def validate_native(cls, inst): for k, v in inst.items(): - if not isinstance(k, six.string_types): + if not isinstance(k, str): raise ValidationError(type(k), "Invalid key type %r") if not isinstance(v, list): raise ValidationError(type(v), "Invalid value type %r") diff --git a/examples/django/rpctest/urls.py b/examples/django/rpctest/urls.py index c909e8849..1670cde18 100644 --- a/examples/django/rpctest/urls.py +++ b/examples/django/rpctest/urls.py @@ -29,22 +29,33 @@ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -from django.conf.urls import url +from django.urls import re_path from spyne.protocol.soap import Soap11 from spyne.server.django import DjangoView from rpctest.core.views import hello_world_service, app, HelloWorldService - urlpatterns = [ - url(r'^hello_world/', hello_world_service), - url(r'^say_hello/', DjangoView.as_view( - services=[HelloWorldService], tns='spyne.examples.django', - in_protocol=Soap11(validator='lxml'), out_protocol=Soap11())), - url(r'^say_hello_not_cached/', DjangoView.as_view( - services=[HelloWorldService], tns='spyne.examples.django', - in_protocol=Soap11(validator='lxml'), out_protocol=Soap11(), - cache_wsdl=False)), - url(r'^api/', DjangoView.as_view(application=app)), + re_path(r"^hello_world/", hello_world_service), + re_path( + r"^say_hello/", + DjangoView.as_view( + services=[HelloWorldService], + tns="spyne.examples.django", + in_protocol=Soap11(validator="lxml"), + out_protocol=Soap11(), + ), + ), + re_path( + r"^say_hello_not_cached/", + DjangoView.as_view( + services=[HelloWorldService], + tns="spyne.examples.django", + in_protocol=Soap11(validator="lxml"), + out_protocol=Soap11(), + cache_wsdl=False, + ), + ), + re_path(r"^api/", DjangoView.as_view(application=app)), ] diff --git a/examples/msgpack_transport/client_json_document.py b/examples/msgpack_transport/client_json_document.py index 151721340..b896d04dd 100755 --- a/examples/msgpack_transport/client_json_document.py +++ b/examples/msgpack_transport/client_json_document.py @@ -50,8 +50,6 @@ import json import msgpack -from spyne.util.six import BytesIO - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("localhost", 5551)) diff --git a/examples/msgpack_transport/client_msgpack_document.py b/examples/msgpack_transport/client_msgpack_document.py index ea80fd388..dda7ada1d 100755 --- a/examples/msgpack_transport/client_msgpack_document.py +++ b/examples/msgpack_transport/client_msgpack_document.py @@ -48,8 +48,6 @@ import socket import msgpack -from spyne.util.six import BytesIO - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("localhost", 5550)) diff --git a/examples/xml/polymorphic_roundtrip.py b/examples/xml/polymorphic_roundtrip.py index 75d49e39a..4dd5377f9 100644 --- a/examples/xml/polymorphic_roundtrip.py +++ b/examples/xml/polymorphic_roundtrip.py @@ -7,11 +7,8 @@ from lxml import etree from spyne.interface.xml_schema.parser import hier_repr -from spyne.util import six from spyne import ComplexModel, Unicode -from spyne.util.xml import get_object_as_xml_polymorphic, \ - get_xml_as_object_polymorphic - +from spyne.util.xml import get_object_as_xml_polymorphic, get_xml_as_object_polymorphic # uncomment to see what's going on under the hood # import logging @@ -20,9 +17,9 @@ class B(ComplexModel): - __namespace__ = 'some_ns' + __namespace__ = "some_ns" _type_info = { - '_b': Unicode, + "_b": Unicode, } def __init__(self): @@ -31,9 +28,9 @@ def __init__(self): class C(B): - __namespace__ = 'some_ns' + __namespace__ = "some_ns" _type_info = { - '_c': Unicode, + "_c": Unicode, } def __init__(self): @@ -42,25 +39,22 @@ def __init__(self): class A(ComplexModel): - __namespace__ = 'some_ns' + __namespace__ = "some_ns" _type_info = { - '_a': Unicode, - '_b': B, + "_a": Unicode, + "_b": B, } def __init__(self, b=None): super(A, self).__init__() - self._a = 'a' + self._a = "a" self._b = b a = A(b=C()) elt = get_object_as_xml_polymorphic(a, A) xml_string = etree.tostring(elt, pretty_print=True) -if six.PY2: - print(xml_string, end="") -else: - sys.stdout.buffer.write(xml_string) +sys.stdout.buffer.write(xml_string) element_tree = etree.fromstring(xml_string) new_a = get_xml_as_object_polymorphic(elt, A) diff --git a/examples/xml/utils_poly.py b/examples/xml/utils_poly.py index 890122c61..a4a542b57 100755 --- a/examples/xml/utils_poly.py +++ b/examples/xml/utils_poly.py @@ -5,7 +5,6 @@ import sys from lxml import etree -from spyne.util import six from spyne import ComplexModel, Unicode from spyne.util.xml import get_object_as_xml_polymorphic @@ -13,27 +12,24 @@ class B(ComplexModel): _type_info = [ - ('_b', Unicode(default="b")), + ("_b", Unicode(default="b")), ] class C(B): _type_info = [ - ('_c', Unicode(default="c")), + ("_c", Unicode(default="c")), ] class A(ComplexModel): _type_info = [ - ('a', Unicode(subname="_a")), - ('b', B.customize(subname="_b")), + ("a", Unicode(subname="_a")), + ("b", B.customize(subname="_b")), ] a = A(b=C()) elt = get_object_as_xml_polymorphic(a, A, no_namespace=True) xml_string = etree.tostring(elt, pretty_print=True) -if six.PY2: - print(xml_string, end="") -else: - sys.stdout.buffer.write(xml_string) +sys.stdout.buffer.write(xml_string) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..14b807c0c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,68 @@ +[project] +name = "spyne" +version = "3.0.0" +description = "A transport and architecture agnostic rpc library that focuses on exposing public services with a well-defined API." +readme = "README.rst" +keywords = [ + "soap", + "wsdl", + "wsgi", + "zeromq", + "rest", + "rpc", + "json", + "http", + "msgpack", + "xml", + "django", + "pyramid", + "postgresql", + "sqlalchemy", + "twisted", + "yaml", +] +classifiers = [ + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Operating System :: OS Independent", + "Natural Language :: English", + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Topic :: Internet :: WWW/HTTP :: Dynamic Content", +] +requires-python = ">=3.10" +dependencies = [ + "pytz", +] +[[project.authors]] +name = "Burak Arslan" +email = "burak+package@spyne.io" + +[[project.maintainers]] +name = "Burak Arslan" +email = "burak+package@spyne.io" + +[project.license] +text = "LGPL-2.1-or-later" + +[project.urls] +Homepage = "http://spyne.io" + +[project.scripts] +sort_wsdl = "spyne.test.sort_wsdl:main" + +[tool.isort] +profile = "black" + +[tool.black] +line-length = 88 + +[tool.setuptools.packages.find] +where = [ + ".", +] diff --git a/pytest.ini b/pytest.ini index 56711bbf7..5e1a8c17d 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,2 +1,8 @@ [pytest] junit_family=xunit1 +norecursedirs = examples build +filterwarnings = + ignore:.*was deprecated in Twisted.*:DeprecationWarning + ignore::UserWarning:pyramid.asset + ignore::DeprecationWarning:pkg_resources + ignore::sqlalchemy.exc.SAWarning diff --git a/setup.py b/setup.py deleted file mode 100755 index 2f29fc2c9..000000000 --- a/setup.py +++ /dev/null @@ -1,309 +0,0 @@ -#!/usr/bin/env python -#encoding: utf8 - -from __future__ import print_function - -import io -import os -import re -import sys -import inspect - -from glob import glob -from itertools import chain -from os.path import join, dirname, abspath - -from setuptools import setup -from setuptools import find_packages -from setuptools.command.test import test as TestCommand - -try: - import colorama - colorama.init() - from colorama import Fore - RESET = Fore.RESET - GREEN = Fore.GREEN - RED = Fore.RED -except ImportError: - RESET = '' - GREEN = '' - RED = '' - -IS_PYPY = '__pypy__' in sys.builtin_module_names -OWN_PATH = abspath(inspect.getfile(inspect.currentframe())) -EXAMPLES_DIR = join(dirname(OWN_PATH), 'examples') -PYVER = ''.join([str(i) for i in sys.version_info[:2]]) - -with io.open(os.path.join(os.path.dirname(__file__), 'spyne', '__init__.py'), 'r') as v: - VERSION = re.match(r".*__version__ = '(.*?)'", v.read(), re.S).group(1) - -SHORT_DESC="A transport and architecture agnostic rpc library that focuses on" \ -" exposing public services with a well-defined API." - -LONG_DESC = """Homepage: http://spyne.io - -Spyne aims to save the protocol implementers the hassle of -implementing their own remote procedure call api and the application programmers -the hassle of jumping through hoops just to expose their services using multiple -protocols and transports. -""" - -try: - os.stat('CHANGELOG.rst') - with io.open('CHANGELOG.rst', 'rb') as f: - LONG_DESC += u"\n\n" + f.read().decode('utf8') -except OSError: - pass - - -############################### -# Testing stuff - -def call_test(f, a, tests, env={}): - import spyne.test - from multiprocessing import Process, Queue - - tests_dir = os.path.dirname(spyne.test.__file__) - if len(tests) > 0: - a.extend(chain(*[glob(join(tests_dir, test)) for test in tests])) - - queue = Queue() - p = Process(target=_wrapper(f), args=[a, queue, env]) - p.start() - p.join() - - ret = queue.get() - if ret == 0: - print(tests or a, "OK") - else: - print(tests or a, "FAIL") - - print() - - return ret - - -def _wrapper(f): - import traceback - def _(args, queue, env): - print("env:", env) - for k, v in env.items(): - os.environ[k] = v - try: - retval = f(args) - except SystemExit as e: - retval = e.code - except BaseException as e: - print(traceback.format_exc()) - retval = 1 - - queue.put(retval) - - return _ - - -def run_tests_and_create_report(report_name, *tests, **kwargs): - import spyne.test - import pytest - - if os.path.isfile(report_name): - os.unlink(report_name) - - tests_dir = os.path.dirname(spyne.test.__file__) - - args = [ - '--verbose', - '--cov-report=', '--cov', 'spyne', - '--cov-append', - '--tb=short', - '--junitxml=%s' % report_name, - ] - args.extend('--{0}={1}'.format(k, v) for k, v in kwargs.items()) - args.extend(chain(*[glob("%s/%s" % (tests_dir, test)) for test in tests])) - - return pytest.main(args) - - -_ctr = 0 - - -def call_pytest(*tests, **kwargs): - global _ctr - - _ctr += 1 - file_name = 'test_result.%d.xml' % _ctr - os.environ['COVERAGE_FILE'] = '.coverage.%d' % _ctr - - return run_tests_and_create_report(file_name, *tests, **kwargs) - - -def call_pytest_subprocess(*tests, **kwargs): - global _ctr - import pytest - - _ctr += 1 - file_name = 'test_result.%d.xml' % _ctr - if os.path.isfile(file_name): - os.unlink(file_name) - - # env = {'COVERAGE_FILE': '.coverage.%d' % _ctr} - env = {} - - args = [ - '--verbose', - '--cov-append', - '--cov-report=', - '--cov', 'spyne', - '--tb=line', - '--junitxml=%s' % file_name - ] - args.extend('--{0}={1}'.format(k, v) for k, v in kwargs.items()) - return call_test(pytest.main, args, tests, env) - - -def call_tox_subprocess(env): - import tox.session - - args = ['-e', env] - - return call_test(tox.session.main, args, []) - -def call_coverage(): - import coverage.cmdline - - # coverage.cmdline.main(['combine']) - # call_test(coverage.cmdline.main, ['combine'], []) - call_test(coverage.cmdline.main, ['xml', '-i'], []) - - return 0 - - -class ExtendedTestCommand(TestCommand): - """TestCommand customized to project needs.""" - - user_options = TestCommand.user_options + [ - ('capture=', 'k', "py.test output capture control (see py.test " - "--capture)"), - ] - - def initialize_options(self): - TestCommand.initialize_options(self) - self.capture = 'fd' - - def finalize_options(self): - TestCommand.finalize_options(self) - - self.test_args = [] - self.test_suite = True - - -class RunTests(ExtendedTestCommand): - def run_tests(self): - cfn = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), - 'tox.ini') - from collections import OrderedDict - djenvs = tuple(OrderedDict(((k, None) for k in - re.findall('py%s-dj[0-9]+' % PYVER, - open(cfn, 'rb').read().decode('utf8')))).keys()) - - ret = 0 - tests = [ - 'interface', 'model', 'multipython', 'protocol', 'util', - - 'interop/test_pyramid.py', - 'interop/test_soap_client_http_twisted.py', - - 'transport/test_msgpack.py' - - 'test_null_server.py', - 'test_service.py', - 'test_soft_validation.py', - 'test_sqlalchemy.py', - 'test_sqlalchemy_deprecated.py', - ] - - print("Test stage 1: Unit tests") - ret = call_pytest_subprocess(*tests, capture=self.capture) or ret - - print("\nTest stage 2: End-to-end tests") - ret = call_pytest_subprocess('interop/test_httprpc.py', - capture=self.capture) or ret - ret = call_pytest_subprocess('interop/test_soap_client_http.py', - capture=self.capture) or ret - ret = call_pytest_subprocess('interop/test_soap_client_zeromq.py', - capture=self.capture) or ret - - # excluding PyPy as it chokes here on LXML - if not IS_PYPY: - ret = call_pytest_subprocess('interop/test_suds.py', - capture=self.capture) or ret - ret = call_pytest_subprocess('interop/test_zeep.py', - capture=self.capture) or ret - - print("\nTest stage 3: Tox-managed tests") - for djenv in djenvs: - ret = call_tox_subprocess(djenv) or ret - - if ret == 0: - print(GREEN + "All that glisters is not gold." + RESET) - else: - print(RED + "Something is rotten in the state of Denmark." + RESET) - - print ("Generating coverage.xml") - call_coverage() - - raise SystemExit(ret) - - -# Testing stuff ends here. -############################### - -setup( - name='spyne', - packages=find_packages(), - - version=VERSION, - description=SHORT_DESC, - long_description=LONG_DESC, - classifiers=[ - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: Implementation :: CPython', - #'Programming Language :: Python :: Implementation :: Jython', - 'Programming Language :: Python :: Implementation :: PyPy', - 'Operating System :: OS Independent', - 'Natural Language :: English', - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', - ], - keywords='soap wsdl wsgi zeromq rest rpc json http msgpack xml' - ' django pyramid postgresql sqlalchemy twisted yaml'.split(), - author='Burak Arslan', - author_email='burak+package@spyne.io', - maintainer='Burak Arslan', - maintainer_email='burak+package@spyne.io', - url='http://spyne.io', - license='LGPL-2.1-or-later', - zip_safe=False, - install_requires=[ - 'pytz', - ], - - entry_points={ - 'console_scripts': [ - 'sort_wsdl=spyne.test.sort_wsdl:main', - ] - }, - - cmdclass={ - 'test': RunTests, - }, -) diff --git a/spyne/__init__.py b/spyne/__init__.py index f7e01853b..99fd1476b 100644 --- a/spyne/__init__.py +++ b/spyne/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -21,66 +20,64 @@ class LogicError(Exception): pass -__version__ = '2.15.0-alpha' - -from pytz import utc as LOCAL_TZ -from decimal import Decimal as D - -DEFAULT_LANGUAGE = 'en' - -from spyne._base import Address -from spyne.context import AuxMethodContext -from spyne.context import TransportContext -from spyne.context import ProtocolContext -from spyne.context import EventContext -from spyne.context import MethodContext +__version__ = "2.15.0-alpha" -from spyne.evmgr import EventManager - -from spyne.descriptor import MethodDescriptor -from spyne.descriptor import BODY_STYLE_WRAPPED -from spyne.descriptor import BODY_STYLE_BARE -from spyne.descriptor import BODY_STYLE_OUT_BARE -from spyne.descriptor import BODY_STYLE_EMPTY -from spyne.descriptor import BODY_STYLE_EMPTY_OUT_BARE - -# decorator imports descriptor, so this needs to come after -from spyne.decorator import rpc -from spyne.decorator import srpc -from spyne.decorator import mrpc +from decimal import Decimal as D -from spyne.service import ServiceBase as Service -from spyne.service import ServiceBase # DEPRECATED +from pytz import utc as LOCAL_TZ -from spyne.interface import Interface -from spyne.interface import InterfaceDocuments -from spyne.interface import InterfaceDocumentsBase +DEFAULT_LANGUAGE = "en" +from spyne._base import Address from spyne.application import Application +from spyne.client import ClientBase, RemoteProcedureBase, RemoteService +from spyne.context import ( + AuxMethodContext, + EventContext, + MethodContext, + ProtocolContext, + TransportContext, +) -from spyne.model import * +# decorator imports descriptor, so this needs to come after +from spyne.decorator import mrpc, rpc, srpc +from spyne.descriptor import ( + BODY_STYLE_BARE, + BODY_STYLE_EMPTY, + BODY_STYLE_EMPTY_OUT_BARE, + BODY_STYLE_OUT_BARE, + BODY_STYLE_WRAPPED, + MethodDescriptor, +) +from spyne.error import ( + ArgumentError, + InternalError, + InvalidCredentialsError, + InvalidInputError, + MissingFieldError, + Redirect, + RequestNotAllowed, + RequestTooLongError, + ResourceAlreadyExistsError, + ResourceNotFoundError, + RespawnError, + ValidationError, +) +from spyne.evmgr import EventManager +from spyne.interface import Interface, InterfaceDocuments, InterfaceDocumentsBase from spyne.model import Mandatory as M - -from spyne.error import InvalidCredentialsError -from spyne.error import RequestTooLongError -from spyne.error import RequestNotAllowed -from spyne.error import ArgumentError -from spyne.error import InvalidInputError -from spyne.error import MissingFieldError -from spyne.error import ValidationError -from spyne.error import InternalError -from spyne.error import ResourceNotFoundError -from spyne.error import RespawnError -from spyne.error import ResourceAlreadyExistsError -from spyne.error import Redirect - -from spyne.client import ClientBase, RemoteProcedureBase, RemoteService -from spyne.server import ServerBase, NullServer +from spyne.model import * +from spyne.server import NullServer, ServerBase +from spyne.service import ServiceBase # DEPRECATED +from spyne.service import ServiceBase as Service def _vercheck(): import sys + if not hasattr(sys, "version_info") or sys.version_info < (2, 6): raise RuntimeError("Spyne requires Python 2.6 or later. Trust us.") + + _vercheck() diff --git a/spyne/_base.py b/spyne/_base.py index 7f558fce3..bff2258d5 100644 --- a/spyne/_base.py +++ b/spyne/_base.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,7 +17,8 @@ # import logging -logger = logging.getLogger('spyne') + +logger = logging.getLogger("spyne") from collections import namedtuple @@ -27,11 +27,11 @@ Address = namedtuple("Address", ["type", "host", "port"]) -class _add_address_types(): - Address.TCP4 = 'TCP4' - Address.TCP6 = 'TCP6' - Address.UDP4 = 'UDP4' - Address.UDP6 = 'UDP6' +class _add_address_types: + Address.TCP4 = "TCP4" + Address.TCP6 = "TCP6" + Address.UDP4 = "UDP4" + Address.UDP6 = "UDP6" def address_str(self): return ":".join((self.type, self.host, str(self.port))) @@ -42,6 +42,7 @@ def address_str(self): @staticmethod def _fta(*a, **kw): from spyne.server.twisted._base import _address_from_twisted_address + return _address_from_twisted_address(*a, **kw) Address.from_twisted_address = _fta diff --git a/spyne/application.py b/spyne/application.py index 5583f0b8a..f3316fa61 100644 --- a/spyne/application.py +++ b/spyne/application.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,24 +17,23 @@ # import logging -logger = logging.getLogger(__name__) -logger_client = logging.getLogger('.'.join([__name__, 'client'])) -logger_server = logging.getLogger('.'.join([__name__, 'server'])) -from pprint import pformat +logger = logging.getLogger(__name__) +logger_client = logging.getLogger(".".join([__name__, "client"])) +logger_server = logging.getLogger(".".join([__name__, "server"])) -from spyne import BODY_STYLE_EMPTY, BODY_STYLE_BARE, BODY_STYLE_WRAPPED, \ - EventManager -from spyne.error import Fault, Redirect, RespawnError, InvalidRequestError +from spyne.descriptor import BODY_STYLE_BARE, BODY_STYLE_EMPTY, BODY_STYLE_WRAPPED +from spyne.error import Fault, InvalidRequestError, Redirect, RespawnError +from spyne.evmgr import EventManager from spyne.interface import Interface, InterfaceDocuments -from spyne.util import six from spyne.util.appreg import register_application class MethodAlreadyExistsError(Exception): def __init__(self, what): - super(MethodAlreadyExistsError, self) \ - .__init__("Method key %r already exists", what) + super(MethodAlreadyExistsError, self).__init__( + "Method key %r already exists", what + ) def get_fault_string_from_exception(e): @@ -51,8 +49,10 @@ def return_traceback_in_unhandled_exceptions(): global get_fault_string_from_exception import traceback + def _get_fault_string_from_exception(e): return traceback.format_exc() + get_fault_string_from_exception = _get_fault_string_from_exception @@ -102,10 +102,17 @@ class Application(object): transport = None - def __init__(self, services, tns, name=None, - in_protocol=None, out_protocol=None, - config=None, classes=(), - documents_container=InterfaceDocuments): + def __init__( + self, + services, + tns, + name=None, + in_protocol=None, + out_protocol=None, + config=None, + classes=(), + documents_container=InterfaceDocuments, + ): self.services = tuple(services) self.tns = tns self.name = name @@ -113,7 +120,7 @@ def __init__(self, services, tns, name=None, self.classes = classes if self.name is None: - self.name = self.__class__.__name__.split('.')[-1] + self.name = self.__class__.__name__.split(".")[-1] logger.info("Initializing application {%s}%s...", self.tns, self.name) @@ -125,10 +132,12 @@ def __init__(self, services, tns, name=None, if self.in_protocol is None: from spyne.protocol import ProtocolBase + self.in_protocol = ProtocolBase() if self.out_protocol is None: from spyne.protocol import ProtocolBase + self.out_protocol = ProtocolBase() self.check_unique_method_keys() # is this really necessary nowadays? @@ -160,7 +169,7 @@ def process_request(self, ctx): """ try: - ctx.fire_event('method_call') + ctx.fire_event("method_call") # in object is always a sequence of incoming values. We need to fix # that for bare mode. @@ -174,8 +183,10 @@ def process_request(self, ctx): # out object is always a sequence of return values. see # MethodContext docstrings for more info - if ctx.descriptor.body_style is not BODY_STYLE_WRAPPED or \ - len(ctx.descriptor.out_message._type_info) <= 1: + if ( + ctx.descriptor.body_style is not BODY_STYLE_WRAPPED + or len(ctx.descriptor.out_message._type_info) <= 1 + ): # if it's not a wrapped method, OR there's just one return type # we wrap it ourselves ctx.out_object = [ctx.out_object] @@ -184,7 +195,7 @@ def process_request(self, ctx): # point ctx.protocol to ctx.out_protocol ctx.protocol = ctx.outprot_ctx - ctx.fire_event('method_return_object') + ctx.fire_event("method_return_object") except Redirect as e: try: @@ -196,34 +207,33 @@ def process_request(self, ctx): # point ctx.protocol to ctx.out_protocol ctx.protocol = ctx.outprot_ctx - ctx.fire_event('method_redirect') + ctx.fire_event("method_redirect") except Exception as e: logger_server.exception(e) - ctx.out_error = Fault('Server', - get_fault_string_from_exception(e)) + ctx.out_error = Fault("Server", get_fault_string_from_exception(e)) - ctx.fire_event('method_redirect_exception') + ctx.fire_event("method_redirect_exception") except Fault as e: - if e.faultcode == 'Client' or e.faultcode.startswith('Client.'): + if e.faultcode == "Client" or e.faultcode.startswith("Client."): logger_client.exception(e) else: logger.exception(e) ctx.out_error = e - ctx.fire_event('method_exception_object') + ctx.fire_event("method_exception_object") # we don't catch BaseException because we actually don't want to catch # "system-exiting" exceptions. See: # https://docs.python.org/2/library/exceptions.html#exceptions.Exception except Exception as e: - logger_server.critical(e, **{'exc_info': 1}) + logger_server.critical(e, **{"exc_info": 1}) - ctx.out_error = Fault('Server', get_fault_string_from_exception(e)) + ctx.out_error = Fault("Server", get_fault_string_from_exception(e)) - ctx.fire_event('method_exception_object') + ctx.fire_event("method_exception_object") def call_wrapper(self, ctx): """This method calls the call_wrapper method in the service definition. @@ -249,8 +259,10 @@ def call_wrapper(self, ctx): filters = {} inst = cls.__respawn__(ctx, filters) if inst is None: - raise RespawnError('{%s}%s with params %r' % - (cls.get_namespace(), cls.get_type_name(), filters)) + raise RespawnError( + "{%s}%s with params %r" + % (cls.get_namespace(), cls.get_type_name(), filters) + ) in_cls = ctx.descriptor.in_message @@ -258,8 +270,10 @@ def call_wrapper(self, ctx): if args is None: args = () - elif ctx.descriptor.body_style is BODY_STYLE_WRAPPED and \ - len(in_cls.get_flat_type_info(in_cls)) <= 1: + elif ( + ctx.descriptor.body_style is BODY_STYLE_WRAPPED + and len(in_cls.get_flat_type_info(in_cls)) <= 1 + ): args = () else: @@ -274,7 +288,10 @@ def call_wrapper(self, ctx): if ctx.descriptor.no_ctx: args = (inst,) + args else: - args = (inst, ctx,) + args + args = ( + inst, + ctx, + ) + args if ctx.descriptor.service_class is None: retval = ctx.function(*args) @@ -293,6 +310,7 @@ def reinitialize(self, server): seen = set() from spyne import MethodDescriptor + for d in self.interface.method_id_map.values(): assert isinstance(d, MethodDescriptor) @@ -315,10 +333,11 @@ def check_unique_method_keys(self): if other_mdesc is not None: logger.error( 'Methods keys for "%s.%s" and "%s.%s" conflict', - mdesc.function.__module__, - six.get_function_name(mdesc.function), - other_mdesc.function.__module__, - six.get_function_name(other_mdesc.function)) + mdesc.function.__module__, + mdesc.function.__name__, + other_mdesc.function.__module__, + other_mdesc.function.__name__, + ) raise MethodAlreadyExistsError(mdesc.internal_key) keys[mdesc.internal_key] = mdesc diff --git a/spyne/auxproc/__init__.py b/spyne/auxproc/__init__.py index 19e90b3e0..a472f9848 100644 --- a/spyne/auxproc/__init__.py +++ b/spyne/auxproc/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -38,5 +37,4 @@ This package is DEPRECATED. Get rid of this ASAP. """ -from spyne.auxproc._base import process_contexts -from spyne.auxproc._base import AuxProcBase +from spyne.auxproc._base import AuxProcBase, process_contexts diff --git a/spyne/auxproc/_base.py b/spyne/auxproc/_base.py index 565e6ef20..2ad9579c1 100644 --- a/spyne/auxproc/_base.py +++ b/spyne/auxproc/_base.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -24,6 +23,7 @@ """ import logging + logger = logging.getLogger(__name__) from spyne import AuxMethodContext diff --git a/spyne/auxproc/sync.py b/spyne/auxproc/sync.py index 4299fa70a..8d7c78e85 100644 --- a/spyne/auxproc/sync.py +++ b/spyne/auxproc/sync.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,6 +17,7 @@ # import logging + logger = logging.getLogger(__name__) from spyne.auxproc import AuxProcBase diff --git a/spyne/auxproc/thread.py b/spyne/auxproc/thread.py index dd076e2da..b0823e017 100644 --- a/spyne/auxproc/thread.py +++ b/spyne/auxproc/thread.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,6 +17,7 @@ # import logging + logger = logging.getLogger(__name__) from multiprocessing.pool import ThreadPool diff --git a/spyne/client/__init__.py b/spyne/client/__init__.py index 21025e981..8d2e4125e 100644 --- a/spyne/client/__init__.py +++ b/spyne/client/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -19,7 +18,4 @@ """The ``spyne.client`` package contains the client transports.""" -from spyne.client._base import Factory -from spyne.client._base import RemoteService -from spyne.client._base import ClientBase -from spyne.client._base import RemoteProcedureBase +from spyne.client._base import ClientBase, Factory, RemoteProcedureBase, RemoteService diff --git a/spyne/client/_base.py b/spyne/client/_base.py index a68c0b1a7..543ec68db 100644 --- a/spyne/client/_base.py +++ b/spyne/client/_base.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -41,8 +40,9 @@ def __init__(self, rpc_class, url, app, *args, **kwargs): self.kwargs = kwargs def __getattr__(self, key): - return self.rpc_class(self.__url, self.__app, key, self.out_header, - *self.args, **self.kwargs) + return self.rpc_class( + self.__url, self.__app, key, self.out_header, *self.args, **self.kwargs + ) class RemoteProcedureBase(object): @@ -67,8 +67,7 @@ def __init__(self, url, app, name, out_header=None): initial_ctx.method_request_string = name initial_ctx.out_header = out_header - self.contexts = initial_ctx.out_protocol.generate_method_contexts( - initial_ctx) + self.contexts = initial_ctx.out_protocol.generate_method_contexts(initial_ctx) def __call__(self, *args, **kwargs): """Serializes its arguments, sends them, receives and deserializes the @@ -110,16 +109,16 @@ def get_out_string(self, ctx): ctx.out_protocol.serialize(ctx, ctx.out_protocol.REQUEST) if ctx.out_error is None: - ctx.fire_event('method_return_document') + ctx.fire_event("method_return_document") else: - ctx.fire_event('method_exception_document') + ctx.fire_event("method_exception_document") ctx.out_protocol.create_out_string(ctx, string_encoding) if ctx.out_error is None: - ctx.fire_event('method_return_string') + ctx.fire_event("method_return_string") else: - ctx.fire_event('method_exception_string') + ctx.fire_event("method_exception_string") if ctx.out_string is None: ctx.out_string = [""] @@ -133,15 +132,15 @@ def get_in_object(self, ctx): assert ctx.in_document is None self.app.in_protocol.create_in_document(ctx) - ctx.fire_event('method_accept_document') + ctx.fire_event("method_accept_document") # sets the ctx.in_body_doc and ctx.in_header_doc properties - self.app.in_protocol.decompose_incoming_envelope(ctx, - message=self.app.in_protocol.RESPONSE) + self.app.in_protocol.decompose_incoming_envelope( + ctx, message=self.app.in_protocol.RESPONSE + ) # this sets ctx.in_object - self.app.in_protocol.deserialize(ctx, - message=self.app.in_protocol.RESPONSE) + self.app.in_protocol.deserialize(ctx, message=self.app.in_protocol.RESPONSE) type_info = ctx.descriptor.out_message._type_info @@ -167,10 +166,12 @@ def set_options(self, **kwargs): :param soapheaders: A suds-compatible alias for out_header. """ - if ('soapheaders' in kwargs) and ('out_header' in kwargs): - raise ValueError('you should specify only one of "soapheaders" or ' - '"out_header" keyword arguments.') + if ("soapheaders" in kwargs) and ("out_header" in kwargs): + raise ValueError( + 'you should specify only one of "soapheaders" or ' + '"out_header" keyword arguments.' + ) - self.service.out_header = kwargs.get('soapheaders', None) + self.service.out_header = kwargs.get("soapheaders", None) if self.service.out_header is None: - self.service.out_header = kwargs.get('out_header', None) + self.service.out_header = kwargs.get("out_header", None) diff --git a/spyne/client/django.py b/spyne/client/django.py index 35e1eed59..52e39a154 100644 --- a/spyne/client/django.py +++ b/spyne/client/django.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -21,19 +20,18 @@ """The Django client transport for testing Spyne apps the way you'd test Django apps.""" - from __future__ import absolute_import -from spyne import RemoteService, ClientBase, RemoteProcedureBase - from django.test.client import Client +from spyne import ClientBase, RemoteProcedureBase, RemoteService + class _RemoteProcedure(RemoteProcedureBase): def __init__(self, url, app, name, out_header=None, *args, **kwargs): super(_RemoteProcedure, self).__init__(url, app, name, out_header=out_header) - self.secure = kwargs.get('secure', False) + self.secure = kwargs.get("secure", False) def __call__(self, *args, **kwargs): response = self.get_django_response(*args, **kwargs) @@ -58,7 +56,7 @@ def get_django_response(self, *args, **kwargs): # the comma-in-assignment trick is a general way of getting the first # and the only variable from an iterable. so if there's more than one # element in the iterable, it'll fail miserably. - self.ctx, = self.contexts + (self.ctx,) = self.contexts # sets ctx.out_object self.get_out_object(self.ctx, args, kwargs) @@ -66,10 +64,12 @@ def get_django_response(self, *args, **kwargs): # sets ctx.out_string self.get_out_string(self.ctx) - out_string = b''.join(self.ctx.out_string) + out_string = b"".join(self.ctx.out_string) # Hack client = Client() - return client.post(self.url, content_type='text/xml', data=out_string, secure=self.secure) + return client.post( + self.url, content_type="text/xml", data=out_string, secure=self.secure + ) class DjangoTestClient(ClientBase): diff --git a/spyne/client/http.py b/spyne/client/http.py index 2101c3aa7..2bf789f38 100644 --- a/spyne/client/http.py +++ b/spyne/client/http.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -19,10 +18,10 @@ """The HTTP (urllib2) client transport.""" -from spyne import RemoteService, ClientBase, RemoteProcedureBase +from urllib.error import HTTPError +from urllib.request import Request, urlopen -from spyne.util.six.moves.urllib.request import Request, urlopen -from spyne.util.six.moves.urllib.error import HTTPError +from spyne import ClientBase, RemoteProcedureBase, RemoteService class _RemoteProcedure(RemoteProcedureBase): @@ -32,7 +31,7 @@ def __call__(self, *args, **kwargs): # the comma-in-assignment trick is a general way of getting the first # and the only variable from an iterable. so if there's more than one # element in the iterable, it'll fail miserably. - self.ctx, = self.contexts + (self.ctx,) = self.contexts # sets ctx.out_object self.get_out_object(self.ctx, args, kwargs) @@ -40,7 +39,9 @@ def __call__(self, *args, **kwargs): # sets ctx.out_string self.get_out_string(self.ctx) - out_string = b''.join(self.ctx.out_string) # FIXME: just send the iterable to the http stream. + out_string = b"".join( + self.ctx.out_string + ) # FIXME: just send the iterable to the http stream. request = Request(self.url, out_string) code = 200 try: diff --git a/spyne/client/twisted/__init__.py b/spyne/client/twisted/__init__.py index 6609e82c8..141d09e5b 100644 --- a/spyne/client/twisted/__init__.py +++ b/spyne/client/twisted/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -19,31 +18,19 @@ """The Twisted Http Client transport.""" -from spyne import __version__ as VERSION -from spyne.util import six - -from spyne.client import RemoteService -from spyne.client import RemoteProcedureBase -from spyne.client import ClientBase - -from zope.interface import implements - from twisted.internet import reactor from twisted.internet.defer import Deferred from twisted.internet.protocol import Protocol - from twisted.web import error as werror -from twisted.web.client import Agent -from twisted.web.client import ResponseDone -from twisted.web.iweb import IBodyProducer -from twisted.web.iweb import UNKNOWN_LENGTH +from twisted.web.client import Agent, ResponseDone from twisted.web.http_headers import Headers +from twisted.web.iweb import UNKNOWN_LENGTH, IBodyProducer + +from spyne import __version__ as VERSION +from spyne.client import ClientBase, RemoteProcedureBase, RemoteService class _Producer(object): - if six.PY2: - implements(IBodyProducer) - _deferred = None def __init__(self, body): @@ -53,7 +40,7 @@ def __init__(self, body): # check to see if we can determine the length try: - len(body) # iterator? + len(body) # iterator? self.length = sum([len(fragment) for fragment in body]) self.body = iter(body) @@ -76,7 +63,7 @@ def resumeProducing(self): if self.__paused: break else: - self._deferred.callback(None) # done producing forever + self._deferred.callback(None) # done producing forever def pauseProducing(self): self.__paused = True @@ -107,7 +94,7 @@ def __call__(self, *args, **kwargs): # The comma-in-assignment trick is a pedantic way of getting the first # and the only variable from an iterable. so if there's more than one # element in the iterable, it'll fail miserably. - self.ctx, = self.contexts + (self.ctx,) = self.contexts self.get_out_object(self.ctx, args, kwargs) self.get_out_string(self.ctx) @@ -116,10 +103,12 @@ def __call__(self, *args, **kwargs): agent = Agent(reactor) d = agent.request( - b'POST', self.url, - Headers({b'User-Agent': - [b'Spyne Twisted Http Client %s' % VERSION.encode()]}), - _Producer(self.ctx.out_string) + b"POST", + self.url, + Headers( + {b"User-Agent": [b"Spyne Twisted Http Client %s" % VERSION.encode()]} + ), + _Producer(self.ctx.out_string), ) def _process_response(_, response): diff --git a/spyne/client/zeromq.py b/spyne/client/zeromq.py index 70c97968a..6b855939b 100644 --- a/spyne/client/zeromq.py +++ b/spyne/client/zeromq.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -21,7 +20,7 @@ import zmq -from spyne import RemoteService, ClientBase, RemoteProcedureBase +from spyne import ClientBase, RemoteProcedureBase, RemoteService context = zmq.Context() @@ -32,7 +31,7 @@ def __call__(self, *args, **kwargs): self.get_out_object(self.ctx, args, kwargs) self.get_out_string(self.ctx) - out_string = b''.join(self.ctx.out_string) + out_string = b"".join(self.ctx.out_string) socket = context.socket(zmq.REQ) socket.connect(self.url) diff --git a/spyne/const/__init__.py b/spyne/const/__init__.py index eb5ca9043..583efd3ac 100644 --- a/spyne/const/__init__.py +++ b/spyne/const/__init__.py @@ -1,5 +1,3 @@ - - # # spyne - Copyright (C) Spyne contributors. # @@ -21,7 +19,6 @@ """The ``spyne.const`` package contains miscellanous constant values needed in various parts of Spyne.""" - MAX_STRING_FIELD_LENGTH = 64 """Maximum length of a string field for :func:`spyne.util.log_repr`""" @@ -34,41 +31,41 @@ MAX_FIELD_NUM = 10 """Maximum number of complex model fields for :func:`spyne.util.log_repr`""" -ARRAY_PREFIX = '' +ARRAY_PREFIX = "" """The prefix for Array wrapper objects. You may want to set this to 'ArrayOf' and the ARRAY_SUFFIX to '' for compatibility with some SOAP deployments.""" -ARRAY_SUFFIX = 'Array' +ARRAY_SUFFIX = "Array" """The suffix for Array wrapper objects.""" -REQUEST_SUFFIX = '' +REQUEST_SUFFIX = "" """The suffix for function response objects.""" -RESPONSE_SUFFIX = 'Response' +RESPONSE_SUFFIX = "Response" """The suffix for function response objects.""" -RESULT_SUFFIX = 'Result' +RESULT_SUFFIX = "Result" """The suffix for function response wrapper objects.""" -TYPE_SUFFIX = 'Type' +TYPE_SUFFIX = "Type" """The suffix for primitives with unnamed constraints.""" -PARENT_SUFFIX = 'Parent' +PARENT_SUFFIX = "Parent" """The suffix for parent classes of primitives with unnamed constraints.""" -MANDATORY_PREFIX = 'Mandatory' +MANDATORY_PREFIX = "Mandatory" """The prefix for types created with the :func:`spyne.model.Mandatory`.""" -MANDATORY_SUFFIX = '' +MANDATORY_SUFFIX = "" """The suffix for types created with the :func:`spyne.model.Mandatory`.""" -DEFAULT_DECLARE_ORDER = 'random' +DEFAULT_DECLARE_ORDER = "random" """Order of complex type attrs of :class:`spyne.model.complex.ComplexModel`.""" MIN_GC_INTERVAL = 1.0 """Minimum time in seconds between gc.collect() calls.""" -DEFAULT_LOCALE = 'en_US' +DEFAULT_LOCALE = "en_US" """Locale code to use for the translation subsystem when locale information is missing in an incoming request.""" diff --git a/spyne/const/ansi_color.py b/spyne/const/ansi_color.py index 98935ba25..02452bc4d 100644 --- a/spyne/const/ansi_color.py +++ b/spyne/const/ansi_color.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -41,6 +40,7 @@ """ANSI colour value for end color marker if colours are enabled, empty string otherwise.""" + def enable_color(): """Enable colors by setting colour code constants to ANSI color codes.""" @@ -78,4 +78,5 @@ def disable_color(): global END_COLOR END_COLOR = "" + enable_color() diff --git a/spyne/const/http.py b/spyne/const/http.py index e6a002520..25d13d843 100644 --- a/spyne/const/http.py +++ b/spyne/const/http.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -19,98 +18,103 @@ """The ``spyne.const.http module contains the Http response status codes.""" -HTTP_200 = '200 OK' -HTTP_201 = '201 Created' -HTTP_202 = '202 Accepted' -HTTP_203 = '203 Non-Authoritative Information' # (since HTTP/1.1) -HTTP_204 = '204 No Content' -HTTP_205 = '205 Reset Content' -HTTP_206 = '206 Partial Content' -HTTP_207 = '207 Multi-Status' # (WebDAV; RFC 4918) -HTTP_208 = '208 Already Reported' # (WebDAV; RFC 5842) -HTTP_226 = '226 IM Used' # (RFC 3229) +HTTP_200 = "200 OK" +HTTP_201 = "201 Created" +HTTP_202 = "202 Accepted" +HTTP_203 = "203 Non-Authoritative Information" # (since HTTP/1.1) +HTTP_204 = "204 No Content" +HTTP_205 = "205 Reset Content" +HTTP_206 = "206 Partial Content" +HTTP_207 = "207 Multi-Status" # (WebDAV; RFC 4918) +HTTP_208 = "208 Already Reported" # (WebDAV; RFC 5842) +HTTP_226 = "226 IM Used" # (RFC 3229) -HTTP_300 = '300 Multiple Choices' -HTTP_301 = '301 Moved Permanently' -HTTP_302 = '302 Found' -HTTP_303 = '303 See Other' # (since HTTP/1.1) -HTTP_304 = '304 Not Modified' -HTTP_305 = '305 Use Proxy' # (since HTTP/1.1) -HTTP_306 = '306 Switch Proxy' -HTTP_307 = '307 Temporary Redirect' # (since HTTP/1.1) -HTTP_308 = '308 Permanent Redirect' # (approved as experimental RFC])[11] +HTTP_300 = "300 Multiple Choices" +HTTP_301 = "301 Moved Permanently" +HTTP_302 = "302 Found" +HTTP_303 = "303 See Other" # (since HTTP/1.1) +HTTP_304 = "304 Not Modified" +HTTP_305 = "305 Use Proxy" # (since HTTP/1.1) +HTTP_306 = "306 Switch Proxy" +HTTP_307 = "307 Temporary Redirect" # (since HTTP/1.1) +HTTP_308 = "308 Permanent Redirect" # (approved as experimental RFC])[11] -HTTP_400 = '400 Bad Request' -HTTP_401 = '401 Unauthorized' -HTTP_402 = '402 Payment Required' -HTTP_403 = '403 Forbidden' -HTTP_404 = '404 Not Found' -HTTP_405 = '405 Method Not Allowed' -HTTP_406 = '406 Not Acceptable' -HTTP_407 = '407 Proxy Authentication Required' -HTTP_408 = '408 Request Timeout' -HTTP_409 = '409 Conflict' -HTTP_410 = '410 Gone' -HTTP_411 = '411 Length Required' -HTTP_412 = '412 Precondition Failed' -HTTP_413 = '413 Request Entity Too Large' -HTTP_414 = '414 Request-URI Too Long' -HTTP_415 = '415 Unsupported Media Type' -HTTP_416 = '416 Requested Range Not Satisfiable' -HTTP_417 = '417 Expectation Failed' -HTTP_418 = "418 I'm a teapot" # (RFC 2324) +HTTP_400 = "400 Bad Request" +HTTP_401 = "401 Unauthorized" +HTTP_402 = "402 Payment Required" +HTTP_403 = "403 Forbidden" +HTTP_404 = "404 Not Found" +HTTP_405 = "405 Method Not Allowed" +HTTP_406 = "406 Not Acceptable" +HTTP_407 = "407 Proxy Authentication Required" +HTTP_408 = "408 Request Timeout" +HTTP_409 = "409 Conflict" +HTTP_410 = "410 Gone" +HTTP_411 = "411 Length Required" +HTTP_412 = "412 Precondition Failed" +HTTP_413 = "413 Request Entity Too Large" +HTTP_414 = "414 Request-URI Too Long" +HTTP_415 = "415 Unsupported Media Type" +HTTP_416 = "416 Requested Range Not Satisfiable" +HTTP_417 = "417 Expectation Failed" +HTTP_418 = "418 I'm a teapot" # (RFC 2324) -HTTP_420 = '420 Enhance Your Calm' # (Twitter) -HTTP_422 = '422 Unprocessable Entity' # (WebDAV; RFC 4918) -HTTP_423 = '423 Locked' # (WebDAV; RFC 4918) -HTTP_424 = '424 Failed Dependency' # (WebDAV; RFC 4918) +HTTP_420 = "420 Enhance Your Calm" # (Twitter) +HTTP_422 = "422 Unprocessable Entity" # (WebDAV; RFC 4918) +HTTP_423 = "423 Locked" # (WebDAV; RFC 4918) +HTTP_424 = "424 Failed Dependency" # (WebDAV; RFC 4918) -HTTP_425 = '425 Unordered Collection' # (Internet draft) -HTTP_426 = '426 Upgrade Required' # (RFC 2817) -HTTP_428 = '428 Precondition Required' # (RFC 6585) -HTTP_429 = '429 Too Many Requests' # (RFC 6585) -HTTP_431 = '431 Request Header Fields Too Large' # (RFC 6585) -HTTP_444 = '444 No Response' # (Nginx) -HTTP_449 = '449 Retry With' # (Microsoft) -HTTP_450 = '450 Blocked by Windows Parental Controls' # (Microsoft) -HTTP_451 = '451 Unavailable For Legal Reasons' # (Internet draft) -HTTP_494 = '494 Request Header Too Large' # (Nginx) -HTTP_495 = '495 Cert Error' # (Nginx) -HTTP_496 = '496 No Cert' # (Nginx) -HTTP_497 = '497 HTTP to HTTPS' # (Nginx) -HTTP_499 = '499 Client Closed Request' # (Nginx) +HTTP_425 = "425 Unordered Collection" # (Internet draft) +HTTP_426 = "426 Upgrade Required" # (RFC 2817) +HTTP_428 = "428 Precondition Required" # (RFC 6585) +HTTP_429 = "429 Too Many Requests" # (RFC 6585) +HTTP_431 = "431 Request Header Fields Too Large" # (RFC 6585) +HTTP_444 = "444 No Response" # (Nginx) +HTTP_449 = "449 Retry With" # (Microsoft) +HTTP_450 = "450 Blocked by Windows Parental Controls" # (Microsoft) +HTTP_451 = "451 Unavailable For Legal Reasons" # (Internet draft) +HTTP_494 = "494 Request Header Too Large" # (Nginx) +HTTP_495 = "495 Cert Error" # (Nginx) +HTTP_496 = "496 No Cert" # (Nginx) +HTTP_497 = "497 HTTP to HTTPS" # (Nginx) +HTTP_499 = "499 Client Closed Request" # (Nginx) -HTTP_500 = '500 Internal Server Error' -HTTP_501 = '501 Not Implemented' -HTTP_502 = '502 Bad Gateway' -HTTP_503 = '503 Service Unavailable' -HTTP_504 = '504 Gateway Timeout' -HTTP_505 = '505 HTTP Version Not Supported' -HTTP_506 = '506 Variant Also Negotiates' # (RFC 2295) -HTTP_507 = '507 Insufficient Storage' # (WebDAV; RFC 4918) -HTTP_508 = '508 Loop Detected' # (WebDAV; RFC 5842) -HTTP_509 = '509 Bandwidth Limit Exceeded' # (Apache bw/limited extension) -HTTP_510 = '510 Not Extended' # (RFC 2774) -HTTP_511 = '511 Network Authentication Required' # (RFC 6585) -HTTP_598 = '598 Network read timeout error' # (Unknown) -HTTP_599 = '599 Network connect timeout error' # (Unknown) +HTTP_500 = "500 Internal Server Error" +HTTP_501 = "501 Not Implemented" +HTTP_502 = "502 Bad Gateway" +HTTP_503 = "503 Service Unavailable" +HTTP_504 = "504 Gateway Timeout" +HTTP_505 = "505 HTTP Version Not Supported" +HTTP_506 = "506 Variant Also Negotiates" # (RFC 2295) +HTTP_507 = "507 Insufficient Storage" # (WebDAV; RFC 4918) +HTTP_508 = "508 Loop Detected" # (WebDAV; RFC 5842) +HTTP_509 = "509 Bandwidth Limit Exceeded" # (Apache bw/limited extension) +HTTP_510 = "510 Not Extended" # (RFC 2774) +HTTP_511 = "511 Network Authentication Required" # (RFC 6585) +HTTP_598 = "598 Network read timeout error" # (Unknown) +HTTP_599 = "599 Network connect timeout error" # (Unknown) def gen_body_redirect(code, location): - from lxml.html.builder import E from lxml.html import tostring - return tostring(E.HTML( - E.HEAD( - E.meta(**{ - "http-equiv": "content-type", - "content": "text/html;charset=utf-8", - }), - E.TITLE(code), - ), - E.BODY( - E.H1(code), - E.P("The document has moved"), - E.A("here", HREF=location), - ".", + from lxml.html.builder import E + + return tostring( + E.HTML( + E.HEAD( + E.meta( + **{ + "http-equiv": "content-type", + "content": "text/html;charset=utf-8", + } + ), + E.TITLE(code), + ), + E.BODY( + E.H1(code), + E.P("The document has moved"), + E.A("here", HREF=location), + ".", + ), ) - )) + ) diff --git a/spyne/const/xml.py b/spyne/const/xml.py index e320e0b06..76a71c2b9 100644 --- a/spyne/const/xml.py +++ b/spyne/const/xml.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -21,59 +20,64 @@ namespace prefixes, namespace values and schema uris. """ -NS_XML = 'http://www.w3.org/XML/1998/namespace' -NS_XSD = 'http://www.w3.org/2001/XMLSchema' -NS_XSI = 'http://www.w3.org/2001/XMLSchema-instance' -NS_WSA = 'http://schemas.xmlsoap.org/ws/2003/03/addressing' -NS_XOP = 'http://www.w3.org/2004/08/xop/include' -NS_XHTML = 'http://www.w3.org/1999/xhtml' -NS_PLINK = 'http://schemas.xmlsoap.org/ws/2003/05/partner-link/' -NS_SOAP11_ENC = 'http://schemas.xmlsoap.org/soap/encoding/' -NS_SOAP11_ENV = 'http://schemas.xmlsoap.org/soap/envelope/' -NS_SOAP12_ENC = 'http://www.w3.org/2003/05/soap-encoding' -NS_SOAP12_ENV = 'http://www.w3.org/2003/05/soap-envelope' - -NS_WSDL11 = 'http://schemas.xmlsoap.org/wsdl/' -NS_WSDL11_SOAP = 'http://schemas.xmlsoap.org/wsdl/soap/' -NS_WSDL11_SOAP12 = 'http://schemas.xmlsoap.org/wsdl/soap12/' -NS_WSDL11_HTTP = 'http://schemas.xmlsoap.org/wsdl/http/' +NS_XML = "http://www.w3.org/XML/1998/namespace" +NS_XSD = "http://www.w3.org/2001/XMLSchema" +NS_XSI = "http://www.w3.org/2001/XMLSchema-instance" +NS_WSA = "http://schemas.xmlsoap.org/ws/2003/03/addressing" +NS_XOP = "http://www.w3.org/2004/08/xop/include" +NS_XHTML = "http://www.w3.org/1999/xhtml" +NS_PLINK = "http://schemas.xmlsoap.org/ws/2003/05/partner-link/" +NS_SOAP11_ENC = "http://schemas.xmlsoap.org/soap/encoding/" +NS_SOAP11_ENV = "http://schemas.xmlsoap.org/soap/envelope/" +NS_SOAP12_ENC = "http://www.w3.org/2003/05/soap-encoding" +NS_SOAP12_ENV = "http://www.w3.org/2003/05/soap-envelope" + +NS_WSDL11 = "http://schemas.xmlsoap.org/wsdl/" +NS_WSDL11_SOAP = "http://schemas.xmlsoap.org/wsdl/soap/" +NS_WSDL11_SOAP12 = "http://schemas.xmlsoap.org/wsdl/soap12/" +NS_WSDL11_HTTP = "http://schemas.xmlsoap.org/wsdl/http/" NSMAP = { - 'xml': NS_XML, - 'xs': NS_XSD, - 'xsi': NS_XSI, - 'plink': NS_PLINK, - 'wsdlsoap11': NS_WSDL11_SOAP, - 'wsdlsoap12': NS_WSDL11_SOAP12, - 'wsdl': NS_WSDL11, - 'soap11enc': NS_SOAP11_ENC, - 'soap11env': NS_SOAP11_ENV, - 'soap12env': NS_SOAP12_ENV, - 'soap12enc': NS_SOAP12_ENC, - 'wsa': NS_WSA, - 'xop': NS_XOP, - 'http': NS_WSDL11_HTTP, + "xml": NS_XML, + "xs": NS_XSD, + "xsi": NS_XSI, + "plink": NS_PLINK, + "wsdlsoap11": NS_WSDL11_SOAP, + "wsdlsoap12": NS_WSDL11_SOAP12, + "wsdl": NS_WSDL11, + "soap11enc": NS_SOAP11_ENC, + "soap11env": NS_SOAP11_ENV, + "soap12env": NS_SOAP12_ENV, + "soap12enc": NS_SOAP12_ENC, + "wsa": NS_WSA, + "xop": NS_XOP, + "http": NS_WSDL11_HTTP, } PREFMAP = None + + def _regen_prefmap(): global PREFMAP PREFMAP = dict([(b, a) for a, b in NSMAP.items()]) + + _regen_prefmap() schema_location = { - NS_XSD: 'http://www.w3.org/2001/XMLSchema.xsd', + NS_XSD: "http://www.w3.org/2001/XMLSchema.xsd", } -class DEFAULT_NS(object): pass +class DEFAULT_NS(object): + pass def get_binding_ns(protocol_type): "Returns the wsdl binding namespace based on the protocol type" - if 'soap12' in protocol_type: + if "soap12" in protocol_type: return WSDL11_SOAP12 - elif 'http' in protocol_type: + elif "http" in protocol_type: return WSDL11_HTTP else: # Bind to Soap1.1 namespace by default for backwards compatibility @@ -101,87 +105,94 @@ def Tnswrap(ns): WSDL11_HTTP = Tnswrap(NS_WSDL11_HTTP) # names starting with underscore need () around to be used as proper regexps -_PATT_BASE_CHAR = \ - u"[\u0041-\u005A]|[\u0061-\u007A]|[\u00C0-\u00D6]|[\u00D8-\u00F6]" \ - u"|[\u00F8-\u00FF]|[\u0100-\u0131]|[\u0134-\u013E]|[\u0141-\u0148]" \ - u"|[\u014A-\u017E]|[\u0180-\u01C3]|[\u01CD-\u01F0]|[\u01F4-\u01F5]" \ - u"|[\u01FA-\u0217]|[\u0250-\u02A8]|[\u02BB-\u02C1]|\u0386|[\u0388-\u038A]" \ - u"|\u038C|[\u038E-\u03A1]|[\u03A3-\u03CE]|[\u03D0-\u03D6]" \ - u"|\u03DA|\u03DC|\u03DE|\u03E0|[\u03E2-\u03F3]|[\u0401-\u040C]" \ - u"|[\u040E-\u044F]|[\u0451-\u045C]|[\u045E-\u0481]|[\u0490-\u04C4]" \ - u"|[\u04C7-\u04C8]|[\u04CB-\u04CC]|[\u04D0-\u04EB]|[\u04EE-\u04F5]" \ - u"|[\u04F8-\u04F9]|[\u0531-\u0556]|\u0559|[\u0561-\u0586]|[\u05D0-\u05EA]" \ - u"|[\u05F0-\u05F2]|[\u0621-\u063A]|[\u0641-\u064A]|[\u0671-\u06B7]" \ - u"|[\u06BA-\u06BE]|[\u06C0-\u06CE]|[\u06D0-\u06D3]|\u06D5|[\u06E5-\u06E6]" \ - u"|[\u0905-\u0939]|\u093D|[\u0958-\u0961]|[\u0985-\u098C]|[\u098F-\u0990]" \ - u"|[\u0993-\u09A8]|[\u09AA-\u09B0]|\u09B2|[\u09B6-\u09B9]|[\u09DC-\u09DD]" \ - u"|[\u09DF-\u09E1]|[\u09F0-\u09F1]|[\u0A05-\u0A0A]|[\u0A0F-\u0A10]" \ - u"|[\u0A13-\u0A28]|[\u0A2A-\u0A30]|[\u0A32-\u0A33]|[\u0A35-\u0A36]" \ - u"|[\u0A38-\u0A39]|[\u0A59-\u0A5C]|\u0A5E|[\u0A72-\u0A74]|[\u0A85-\u0A8B]" \ - u"|\u0A8D|[\u0A8F-\u0A91]|[\u0A93-\u0AA8]|[\u0AAA-\u0AB0]|[\u0AB2-\u0AB3]" \ - u"|[\u0AB5-\u0AB9]|\u0ABD|\u0AE0|[\u0B05-\u0B0C]|[\u0B0F-\u0B10]" \ - u"|[\u0B13-\u0B28]|[\u0B2A-\u0B30]|[\u0B32-\u0B33]|[\u0B36-\u0B39]|\u0B3D" \ - u"|[\u0B5C-\u0B5D]|[\u0B5F-\u0B61]|[\u0B85-\u0B8A]|[\u0B8E-\u0B90]" \ - u"|[\u0B92-\u0B95]|[\u0B99-\u0B9A]|\u0B9C|[\u0B9E-\u0B9F]|[\u0BA3-\u0BA4]" \ - u"|[\u0BA8-\u0BAA]|[\u0BAE-\u0BB5]|[\u0BB7-\u0BB9]|[\u0C05-\u0C0C]" \ - u"|[\u0C0E-\u0C10]|[\u0C12-\u0C28]|[\u0C2A-\u0C33]|[\u0C35-\u0C39]" \ - u"|[\u0C60-\u0C61]|[\u0C85-\u0C8C]|[\u0C8E-\u0C90]|[\u0C92-\u0CA8]" \ - u"|[\u0CAA-\u0CB3]|[\u0CB5-\u0CB9]|\u0CDE|[\u0CE0-\u0CE1]|[\u0D05-\u0D0C]" \ - u"|[\u0D0E-\u0D10]|[\u0D12-\u0D28]|[\u0D2A-\u0D39]|[\u0D60-\u0D61]" \ - u"|[\u0E01-\u0E2E]|\u0E30|[\u0E32-\u0E33]|[\u0E40-\u0E45]|[\u0E81-\u0E82]" \ - u"|\u0E84|[\u0E87-\u0E88]|\u0E8A|\u0E8D|[\u0E94-\u0E97]|[\u0E99-\u0E9F]" \ - u"|[\u0EA1-\u0EA3]|\u0EA5|\u0EA7|[\u0EAA-\u0EAB]|[\u0EAD-\u0EAE]|\u0EB0" \ - u"|[\u0EB2-\u0EB3]|\u0EBD|[\u0EC0-\u0EC4]|[\u0F40-\u0F47]|[\u0F49-\u0F69]" \ - u"|[\u10A0-\u10C5]|[\u10D0-\u10F6]|\u1100|[\u1102-\u1103]|[\u1105-\u1107]" \ - u"|\u1109|[\u110B-\u110C]|[\u110E-\u1112]|\u113C|\u113E|\u1140|\u114C" \ - u"|\u114E|\u1150|[\u1154-\u1155]|\u1159|[\u115F-\u1161]|\u1163|\u1165" \ - u"|\u1167|\u1169|[\u116D-\u116E]|[\u1172-\u1173]|\u1175|\u119E|\u11A8" \ - u"|\u11AB|[\u11AE-\u11AF]|[\u11B7-\u11B8]|\u11BA|[\u11BC-\u11C2]|\u11EB" \ - u"|\u11F0|\u11F9|[\u1E00-\u1E9B]|[\u1EA0-\u1EF9]|[\u1F00-\u1F15]" \ - u"|[\u1F18-\u1F1D]|[\u1F20-\u1F45]|[\u1F48-\u1F4D]|[\u1F50-\u1F57]|\u1F59" \ - u"|\u1F5B|\u1F5D|[\u1F5F-\u1F7D]|[\u1F80-\u1FB4]|[\u1FB6-\u1FBC]|\u1FBE" \ - u"|[\u1FC2-\u1FC4]|[\u1FC6-\u1FCC]|[\u1FD0-\u1FD3]|[\u1FD6-\u1FDB]" \ - u"|[\u1FE0-\u1FEC]|[\u1FF2-\u1FF4]|[\u1FF6-\u1FFC]|\u2126|[\u212A-\u212B]" \ - u"|\u212E|[\u2180-\u2182]|[\u3041-\u3094]|[\u30A1-\u30FA]|[\u3105-\u312C]" \ - u"|[\uAC00-\uD7A3]" - -_PATT_IDEOGRAPHIC = u"[\u4E00-\u9FA5]|\u3007|[\u3021-\u3029]" - -_PATT_COMBINING_CHAR = u"[\u0300-\u0345]|[\u0360-\u0361]|[\u0483-\u0486]" \ - u"|[\u0591-\u05A1]|[\u05A3-\u05B9]|[\u05BB-\u05BD]|\u05BF|[\u05C1-\u05C2]" \ - u"|\u05C4|[\u064B-\u0652]|\u0670|[\u06D6-\u06DC]|[\u06DD-\u06DF]" \ - u"|[\u06E0-\u06E4]|[\u06E7-\u06E8]|[\u06EA-\u06ED]|[\u0901-\u0903]|\u093C" \ - u"|[\u093E-\u094C]|\u094D|[\u0951-\u0954]|[\u0962-\u0963]|[\u0981-\u0983]" \ - u"|\u09BC|\u09BE|\u09BF|[\u09C0-\u09C4]|[\u09C7-\u09C8]|[\u09CB-\u09CD]" \ - u"|\u09D7|[\u09E2-\u09E3]|\u0A02|\u0A3C|\u0A3E|\u0A3F|[\u0A40-\u0A42]" \ - u"|[\u0A47-\u0A48]|[\u0A4B-\u0A4D]|[\u0A70-\u0A71]|[\u0A81-\u0A83]|\u0ABC" \ - u"|[\u0ABE-\u0AC5]|[\u0AC7-\u0AC9]|[\u0ACB-\u0ACD]|[\u0B01-\u0B03]|\u0B3C" \ - u"|[\u0B3E-\u0B43]|[\u0B47-\u0B48]|[\u0B4B-\u0B4D]|[\u0B56-\u0B57]" \ - u"|[\u0B82-\u0B83]|[\u0BBE-\u0BC2]|[\u0BC6-\u0BC8]|[\u0BCA-\u0BCD]|\u0BD7" \ - u"|[\u0C01-\u0C03]|[\u0C3E-\u0C44]|[\u0C46-\u0C48]|[\u0C4A-\u0C4D]" \ - u"|[\u0C55-\u0C56]|[\u0C82-\u0C83]|[\u0CBE-\u0CC4]|[\u0CC6-\u0CC8]" \ - u"|[\u0CCA-\u0CCD]|[\u0CD5-\u0CD6]|[\u0D02-\u0D03]|[\u0D3E-\u0D43]" \ - u"|[\u0D46-\u0D48]|[\u0D4A-\u0D4D]|\u0D57|\u0E31|[\u0E34-\u0E3A]" \ - u"|[\u0E47-\u0E4E]|\u0EB1|[\u0EB4-\u0EB9]|[\u0EBB-\u0EBC]|[\u0EC8-\u0ECD]" \ - u"|[\u0F18-\u0F19]|\u0F35|\u0F37|\u0F39|\u0F3E|\u0F3F|[\u0F71-\u0F84]" \ - u"|[\u0F86-\u0F8B]|[\u0F90-\u0F95]|\u0F97|[\u0F99-\u0FAD]|[\u0FB1-\u0FB7]" \ - u"|\u0FB9|[\u20D0-\u20DC]|\u20E1|[\u302A-\u302F]|\u3099|\u309A" - -_PATT_DIGIT = u"[\u0030-\u0039]|[\u0660-\u0669]|[\u06F0-\u06F9]|[\u0966-\u096F]" \ - u"|[\u09E6-\u09EF]|[\u0A66-\u0A6F]|[\u0AE6-\u0AEF]|[\u0B66-\u0B6F]" \ - u"|[\u0BE7-\u0BEF]|[\u0C66-\u0C6F]|[\u0CE6-\u0CEF]|[\u0D66-\u0D6F]" \ - u"|[\u0E50-\u0E59]|[\u0ED0-\u0ED9]|[\u0F20-\u0F29]" - -_PATT_EXTENDER = u"\u00B7|\u02D0|\u02D1|\u0387|\u0640|\u0E46|\u0EC6|\u3005" \ - u"|[\u3031-\u3035]|[\u309D-\u309E]|[\u30FC-\u30FE]" - - -PATT_LETTER = u"(%s)" % u'|'.join([_PATT_BASE_CHAR, _PATT_IDEOGRAPHIC]) - -PATT_NAMECHAR = u"(%s)" % u'|'.join([PATT_LETTER, _PATT_DIGIT, - u'.', u'-', u'_', u':', _PATT_COMBINING_CHAR, _PATT_EXTENDER]) - -PATT_NAME = u"(%s)(%s)+" % (u'|'.join([PATT_LETTER, u'_', u':']), - u"(%s)*" % PATT_NAMECHAR) - -PATT_NMTOKEN = u"(%s)+" % PATT_NAMECHAR +_PATT_BASE_CHAR = ( + "[\u0041-\u005a]|[\u0061-\u007a]|[\u00c0-\u00d6]|[\u00d8-\u00f6]" + "|[\u00f8-\u00ff]|[\u0100-\u0131]|[\u0134-\u013e]|[\u0141-\u0148]" + "|[\u014a-\u017e]|[\u0180-\u01c3]|[\u01cd-\u01f0]|[\u01f4-\u01f5]" + "|[\u01fa-\u0217]|[\u0250-\u02a8]|[\u02bb-\u02c1]|\u0386|[\u0388-\u038a]" + "|\u038c|[\u038e-\u03a1]|[\u03a3-\u03ce]|[\u03d0-\u03d6]" + "|\u03da|\u03dc|\u03de|\u03e0|[\u03e2-\u03f3]|[\u0401-\u040c]" + "|[\u040e-\u044f]|[\u0451-\u045c]|[\u045e-\u0481]|[\u0490-\u04c4]" + "|[\u04c7-\u04c8]|[\u04cb-\u04cc]|[\u04d0-\u04eb]|[\u04ee-\u04f5]" + "|[\u04f8-\u04f9]|[\u0531-\u0556]|\u0559|[\u0561-\u0586]|[\u05d0-\u05ea]" + "|[\u05f0-\u05f2]|[\u0621-\u063a]|[\u0641-\u064a]|[\u0671-\u06b7]" + "|[\u06ba-\u06be]|[\u06c0-\u06ce]|[\u06d0-\u06d3]|\u06d5|[\u06e5-\u06e6]" + "|[\u0905-\u0939]|\u093d|[\u0958-\u0961]|[\u0985-\u098c]|[\u098f-\u0990]" + "|[\u0993-\u09a8]|[\u09aa-\u09b0]|\u09b2|[\u09b6-\u09b9]|[\u09dc-\u09dd]" + "|[\u09df-\u09e1]|[\u09f0-\u09f1]|[\u0a05-\u0a0a]|[\u0a0f-\u0a10]" + "|[\u0a13-\u0a28]|[\u0a2a-\u0a30]|[\u0a32-\u0a33]|[\u0a35-\u0a36]" + "|[\u0a38-\u0a39]|[\u0a59-\u0a5c]|\u0a5e|[\u0a72-\u0a74]|[\u0a85-\u0a8b]" + "|\u0a8d|[\u0a8f-\u0a91]|[\u0a93-\u0aa8]|[\u0aaa-\u0ab0]|[\u0ab2-\u0ab3]" + "|[\u0ab5-\u0ab9]|\u0abd|\u0ae0|[\u0b05-\u0b0c]|[\u0b0f-\u0b10]" + "|[\u0b13-\u0b28]|[\u0b2a-\u0b30]|[\u0b32-\u0b33]|[\u0b36-\u0b39]|\u0b3d" + "|[\u0b5c-\u0b5d]|[\u0b5f-\u0b61]|[\u0b85-\u0b8a]|[\u0b8e-\u0b90]" + "|[\u0b92-\u0b95]|[\u0b99-\u0b9a]|\u0b9c|[\u0b9e-\u0b9f]|[\u0ba3-\u0ba4]" + "|[\u0ba8-\u0baa]|[\u0bae-\u0bb5]|[\u0bb7-\u0bb9]|[\u0c05-\u0c0c]" + "|[\u0c0e-\u0c10]|[\u0c12-\u0c28]|[\u0c2a-\u0c33]|[\u0c35-\u0c39]" + "|[\u0c60-\u0c61]|[\u0c85-\u0c8c]|[\u0c8e-\u0c90]|[\u0c92-\u0ca8]" + "|[\u0caa-\u0cb3]|[\u0cb5-\u0cb9]|\u0cde|[\u0ce0-\u0ce1]|[\u0d05-\u0d0c]" + "|[\u0d0e-\u0d10]|[\u0d12-\u0d28]|[\u0d2a-\u0d39]|[\u0d60-\u0d61]" + "|[\u0e01-\u0e2e]|\u0e30|[\u0e32-\u0e33]|[\u0e40-\u0e45]|[\u0e81-\u0e82]" + "|\u0e84|[\u0e87-\u0e88]|\u0e8a|\u0e8d|[\u0e94-\u0e97]|[\u0e99-\u0e9f]" + "|[\u0ea1-\u0ea3]|\u0ea5|\u0ea7|[\u0eaa-\u0eab]|[\u0ead-\u0eae]|\u0eb0" + "|[\u0eb2-\u0eb3]|\u0ebd|[\u0ec0-\u0ec4]|[\u0f40-\u0f47]|[\u0f49-\u0f69]" + "|[\u10a0-\u10c5]|[\u10d0-\u10f6]|\u1100|[\u1102-\u1103]|[\u1105-\u1107]" + "|\u1109|[\u110b-\u110c]|[\u110e-\u1112]|\u113c|\u113e|\u1140|\u114c" + "|\u114e|\u1150|[\u1154-\u1155]|\u1159|[\u115f-\u1161]|\u1163|\u1165" + "|\u1167|\u1169|[\u116d-\u116e]|[\u1172-\u1173]|\u1175|\u119e|\u11a8" + "|\u11ab|[\u11ae-\u11af]|[\u11b7-\u11b8]|\u11ba|[\u11bc-\u11c2]|\u11eb" + "|\u11f0|\u11f9|[\u1e00-\u1e9b]|[\u1ea0-\u1ef9]|[\u1f00-\u1f15]" + "|[\u1f18-\u1f1d]|[\u1f20-\u1f45]|[\u1f48-\u1f4d]|[\u1f50-\u1f57]|\u1f59" + "|\u1f5b|\u1f5d|[\u1f5f-\u1f7d]|[\u1f80-\u1fb4]|[\u1fb6-\u1fbc]|\u1fbe" + "|[\u1fc2-\u1fc4]|[\u1fc6-\u1fcc]|[\u1fd0-\u1fd3]|[\u1fd6-\u1fdb]" + "|[\u1fe0-\u1fec]|[\u1ff2-\u1ff4]|[\u1ff6-\u1ffc]|\u2126|[\u212a-\u212b]" + "|\u212e|[\u2180-\u2182]|[\u3041-\u3094]|[\u30a1-\u30fa]|[\u3105-\u312c]" + "|[\uac00-\ud7a3]" +) + +_PATT_IDEOGRAPHIC = "[\u4e00-\u9fa5]|\u3007|[\u3021-\u3029]" + +_PATT_COMBINING_CHAR = ( + "[\u0300-\u0345]|[\u0360-\u0361]|[\u0483-\u0486]" + "|[\u0591-\u05a1]|[\u05a3-\u05b9]|[\u05bb-\u05bd]|\u05bf|[\u05c1-\u05c2]" + "|\u05c4|[\u064b-\u0652]|\u0670|[\u06d6-\u06dc]|[\u06dd-\u06df]" + "|[\u06e0-\u06e4]|[\u06e7-\u06e8]|[\u06ea-\u06ed]|[\u0901-\u0903]|\u093c" + "|[\u093e-\u094c]|\u094d|[\u0951-\u0954]|[\u0962-\u0963]|[\u0981-\u0983]" + "|\u09bc|\u09be|\u09bf|[\u09c0-\u09c4]|[\u09c7-\u09c8]|[\u09cb-\u09cd]" + "|\u09d7|[\u09e2-\u09e3]|\u0a02|\u0a3c|\u0a3e|\u0a3f|[\u0a40-\u0a42]" + "|[\u0a47-\u0a48]|[\u0a4b-\u0a4d]|[\u0a70-\u0a71]|[\u0a81-\u0a83]|\u0abc" + "|[\u0abe-\u0ac5]|[\u0ac7-\u0ac9]|[\u0acb-\u0acd]|[\u0b01-\u0b03]|\u0b3c" + "|[\u0b3e-\u0b43]|[\u0b47-\u0b48]|[\u0b4b-\u0b4d]|[\u0b56-\u0b57]" + "|[\u0b82-\u0b83]|[\u0bbe-\u0bc2]|[\u0bc6-\u0bc8]|[\u0bca-\u0bcd]|\u0bd7" + "|[\u0c01-\u0c03]|[\u0c3e-\u0c44]|[\u0c46-\u0c48]|[\u0c4a-\u0c4d]" + "|[\u0c55-\u0c56]|[\u0c82-\u0c83]|[\u0cbe-\u0cc4]|[\u0cc6-\u0cc8]" + "|[\u0cca-\u0ccd]|[\u0cd5-\u0cd6]|[\u0d02-\u0d03]|[\u0d3e-\u0d43]" + "|[\u0d46-\u0d48]|[\u0d4a-\u0d4d]|\u0d57|\u0e31|[\u0e34-\u0e3a]" + "|[\u0e47-\u0e4e]|\u0eb1|[\u0eb4-\u0eb9]|[\u0ebb-\u0ebc]|[\u0ec8-\u0ecd]" + "|[\u0f18-\u0f19]|\u0f35|\u0f37|\u0f39|\u0f3e|\u0f3f|[\u0f71-\u0f84]" + "|[\u0f86-\u0f8b]|[\u0f90-\u0f95]|\u0f97|[\u0f99-\u0fad]|[\u0fb1-\u0fb7]" + "|\u0fb9|[\u20d0-\u20dc]|\u20e1|[\u302a-\u302f]|\u3099|\u309a" +) + +_PATT_DIGIT = ( + "[\u0030-\u0039]|[\u0660-\u0669]|[\u06f0-\u06f9]|[\u0966-\u096f]" + "|[\u09e6-\u09ef]|[\u0a66-\u0a6f]|[\u0ae6-\u0aef]|[\u0b66-\u0b6f]" + "|[\u0be7-\u0bef]|[\u0c66-\u0c6f]|[\u0ce6-\u0cef]|[\u0d66-\u0d6f]" + "|[\u0e50-\u0e59]|[\u0ed0-\u0ed9]|[\u0f20-\u0f29]" +) + +_PATT_EXTENDER = ( + "\u00b7|\u02d0|\u02d1|\u0387|\u0640|\u0e46|\u0ec6|\u3005" + "|[\u3031-\u3035]|[\u309d-\u309e]|[\u30fc-\u30fe]" +) + + +PATT_LETTER = "(%s)" % "|".join([_PATT_BASE_CHAR, _PATT_IDEOGRAPHIC]) + +PATT_NAMECHAR = "(%s)" % "|".join( + [PATT_LETTER, _PATT_DIGIT, ".", "-", "_", ":", _PATT_COMBINING_CHAR, _PATT_EXTENDER] +) + +PATT_NAME = "(%s)(%s)+" % ("|".join([PATT_LETTER, "_", ":"]), "(%s)*" % PATT_NAMECHAR) + +PATT_NMTOKEN = "(%s)+" % PATT_NAMECHAR diff --git a/spyne/const/xml_ns.py b/spyne/const/xml_ns.py index f3949b274..47ee2af20 100644 --- a/spyne/const/xml_ns.py +++ b/spyne/const/xml_ns.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -19,45 +18,49 @@ # This module is DEPRECATED. Use ``spyne.const.xml``. -xml = 'http://www.w3.org/XML/1998/namespace' -xsd = 'http://www.w3.org/2001/XMLSchema' -xsi = 'http://www.w3.org/2001/XMLSchema-instance' -wsa = 'http://schemas.xmlsoap.org/ws/2003/03/addressing' -xop = 'http://www.w3.org/2004/08/xop/include' -soap = 'http://schemas.xmlsoap.org/wsdl/soap/' -wsdl = 'http://schemas.xmlsoap.org/wsdl/' -xhtml = 'http://www.w3.org/1999/xhtml' -plink = 'http://schemas.xmlsoap.org/ws/2003/05/partner-link/' -soap11_enc = 'http://schemas.xmlsoap.org/soap/encoding/' -soap11_env = 'http://schemas.xmlsoap.org/soap/envelope/' -soap12_env = 'http://www.w3.org/2003/05/soap-envelope' -soap12_enc = 'http://www.w3.org/2003/05/soap-encoding' +xml = "http://www.w3.org/XML/1998/namespace" +xsd = "http://www.w3.org/2001/XMLSchema" +xsi = "http://www.w3.org/2001/XMLSchema-instance" +wsa = "http://schemas.xmlsoap.org/ws/2003/03/addressing" +xop = "http://www.w3.org/2004/08/xop/include" +soap = "http://schemas.xmlsoap.org/wsdl/soap/" +wsdl = "http://schemas.xmlsoap.org/wsdl/" +xhtml = "http://www.w3.org/1999/xhtml" +plink = "http://schemas.xmlsoap.org/ws/2003/05/partner-link/" +soap11_enc = "http://schemas.xmlsoap.org/soap/encoding/" +soap11_env = "http://schemas.xmlsoap.org/soap/envelope/" +soap12_env = "http://www.w3.org/2003/05/soap-envelope" +soap12_enc = "http://www.w3.org/2003/05/soap-encoding" const_nsmap = { - 'xml': xml, - 'xs': xsd, - 'xsi': xsi, - 'plink': plink, - 'soap': soap, - 'wsdl': wsdl, - 'soap11enc': soap11_enc, - 'soap11env': soap11_env, - 'soap12env': soap12_env, - 'soap12enc': soap12_enc, - 'wsa': wsa, - 'xop': xop, + "xml": xml, + "xs": xsd, + "xsi": xsi, + "plink": plink, + "soap": soap, + "wsdl": wsdl, + "soap11enc": soap11_enc, + "soap11env": soap11_env, + "soap12env": soap12_env, + "soap12enc": soap12_enc, + "wsa": wsa, + "xop": xop, } const_prefmap = None + + def regen_prefmap(): global const_prefmap const_prefmap = dict([(b, a) for a, b in const_nsmap.items()]) + regen_prefmap() schema_location = { - xsd: 'http://www.w3.org/2001/XMLSchema.xsd', + xsd: "http://www.w3.org/2001/XMLSchema.xsd", } + class DEFAULT_NS(object): pass diff --git a/spyne/context.py b/spyne/context.py index 3f255d9b5..4f78ea662 100644 --- a/spyne/context.py +++ b/spyne/context.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -17,21 +16,23 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # -import gc, logging -logger = logging.getLogger('spyne') +import gc +import logging -from time import time +logger = logging.getLogger("spyne") + +from collections import defaultdict, deque from copy import copy -from collections import deque, defaultdict +from time import time from spyne import const - _LAST_GC_RUN = 0.0 class AuxMethodContext(object): """Generic object that holds information specific to auxiliary methods""" + def __init__(self, parent, error): self.parent = parent """Primary context that this method was bound to.""" @@ -42,6 +43,7 @@ def __init__(self, parent, error): class TransportContext(object): """Generic object that holds transport-specific context information""" + def __init__(self, parent, transport, type=None): self.parent = parent """The MethodContext this object belongs to""" @@ -61,7 +63,7 @@ def __init__(self, parent, transport, type=None): self.remote_addr = None """The address of the other end of the connection.""" - self.sessid = '' + self.sessid = "" """The session id.""" def get_peer(self): @@ -73,6 +75,7 @@ def get_peer(self): class ProtocolContext(object): """Generic object that holds protocol-specific context information""" + def __init__(self, parent, transport, type=None): self.parent = parent """The MethodContext this object belongs to""" @@ -84,8 +87,7 @@ def __init__(self, parent, transport, type=None): self.type = type """The protocol the transport uses.""" - self._subctx = defaultdict( - lambda: self.__class__(parent, transport, type)) + self._subctx = defaultdict(lambda: self.__class__(parent, transport, type)) def __getitem__(self, item): return self._subctx[item] @@ -93,6 +95,7 @@ def __getitem__(self, item): class EventContext(object): """Generic object that holds event-specific context information""" + def __init__(self, parent, event_id=None): self.parent = parent self.event_id = event_id @@ -357,33 +360,33 @@ def service_class(self): return self.descriptor.service_class def __setattr__(self, k, v): - if not self.frozen or k in self.__dict__ or k in \ - ('descriptor', 'out_protocol'): + if not self.frozen or k in self.__dict__ or k in ("descriptor", "out_protocol"): object.__setattr__(self, k, v) else: - raise ValueError("use the udc member for storing arbitrary data " - "in the method context") + raise ValueError( + "use the udc member for storing arbitrary data " "in the method context" + ) def __repr__(self): retval = deque() for k, v in self.__dict__.items(): if isinstance(v, dict): - ret = deque(['{']) + ret = deque(["{"]) for k2, v2 in sorted(v.items()): - ret.append('\t\t%r: %r,' % (k2, v2)) + ret.append("\t\t%r: %r," % (k2, v2)) - ret.append('\t}') - ret = '\n'.join(ret) + ret.append("\t}") + ret = "\n".join(ret) retval.append("\n\t%s=%s" % (k, ret)) else: retval.append("\n\t%s=%r" % (k, v)) - retval.append('\n)') + retval.append("\n)") - return ''.join((self.__class__.__name__, '(', ', '.join(retval), ')')) + return "".join((self.__class__.__name__, "(", ", ".join(retval), ")")) def close(self): global _LAST_GC_RUN @@ -400,7 +403,7 @@ def close(self): if (t - _LAST_GC_RUN) > const.MIN_GC_INTERVAL: gc.collect() - dt = (time() - t) + dt = time() - t _LAST_GC_RUN = t logger.debug("gc.collect() took around %dms.", round(dt, 2) * 1000) @@ -426,10 +429,22 @@ def get_in_protocol(self): class FakeContext(object): - def __init__(self, app=None, descriptor=None, in_header=None, - in_object=None, in_error=None, in_document=None, in_string=None, - out_object=None, out_error=None, out_document=None, out_string=None, - in_protocol=None, out_protocol=None): + def __init__( + self, + app=None, + descriptor=None, + in_header=None, + in_object=None, + in_error=None, + in_document=None, + in_string=None, + out_object=None, + out_error=None, + out_document=None, + out_string=None, + in_protocol=None, + out_protocol=None, + ): self.app = app self.descriptor = descriptor self.in_header = in_header diff --git a/spyne/decorator.py b/spyne/decorator.py index 38ad8ccf7..fb1b37f2d 100644 --- a/spyne/decorator.py +++ b/spyne/decorator.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -26,31 +25,39 @@ decorator is a simple example of this. """ -import spyne.const.xml - from copy import copy from inspect import isclass -from spyne import MethodDescriptor +import spyne.const.xml # Empty means empty input, bare output. Doesn't say anything about response # being empty from spyne import LogicError -from spyne import BODY_STYLE_EMPTY -from spyne import BODY_STYLE_WRAPPED -from spyne import BODY_STYLE_BARE -from spyne import BODY_STYLE_OUT_BARE -from spyne import BODY_STYLE_EMPTY_OUT_BARE - -from spyne.model import ModelBase, ComplexModel, ComplexModelBase -from spyne.model.complex import TypeInfo, recust_selfref, SelfReference - from spyne.const import add_request_suffix - - -def _produce_input_message(f, params, in_message_name, in_variable_names, - no_ctx, no_self, argnames, body_style_str, self_ref_cls, - in_wsdl_part_name): +from spyne.descriptor import ( + BODY_STYLE_BARE, + BODY_STYLE_EMPTY, + BODY_STYLE_EMPTY_OUT_BARE, + BODY_STYLE_OUT_BARE, + BODY_STYLE_WRAPPED, + MethodDescriptor, +) +from spyne.model import ComplexModel, ComplexModelBase, ModelBase +from spyne.model.complex import SelfReference, TypeInfo, recust_selfref + + +def _produce_input_message( + f, + params, + in_message_name, + in_variable_names, + no_ctx, + no_self, + argnames, + body_style_str, + self_ref_cls, + in_wsdl_part_name, +): arg_start = 0 if no_ctx is False: arg_start += 1 @@ -72,21 +79,25 @@ def _produce_input_message(f, params, in_message_name, in_variable_names, if no_self is False: params = [self_ref_cls.novalidate_freq()] + params - argnames = ('self',) + argnames + argnames = ("self",) + argnames if len(params) != len(argnames): - raise LogicError("%r function has %d argument(s) but its decorator " - "has %d." % (f.__name__, len(argnames), len(params))) + raise LogicError( + "%r function has %d argument(s) but its decorator " + "has %d." % (f.__name__, len(argnames), len(params)) + ) else: argnames = copy(argnames) if len(params) != len(argnames): - raise LogicError("%r function has %d argument(s) but the _args " - "argument has %d." % ( - f.__name__, len(argnames), len(params))) + raise LogicError( + "%r function has %d argument(s) but the _args " + "argument has %d." % (f.__name__, len(argnames), len(params)) + ) in_params = TypeInfo() from spyne import SelfReference + for k, v in zip(argnames, params): try: is_self_ref = issubclass(v, SelfReference) @@ -106,7 +117,7 @@ def _produce_input_message(f, params, in_message_name, in_variable_names, ns, _, in_message_name = in_message_name[1:].partition("}") message = None - if body_style_str == 'bare': + if body_style_str == "bare": if len(in_params) > 1: # The soap Body elt contains 1 elt (called "body entry" in the soap # standard) per method call. If bare methods were allowed to have >1 @@ -114,28 +125,33 @@ def _produce_input_message(f, params, in_message_name, in_variable_names, # which would violate the standard. It's easy to work around this # restriction by creating a ComplexModel that contains all the # required parameters. - raise LogicError("body_style='bare' can handle at most one " - "function argument.") + raise LogicError( + "body_style='bare' can handle at most one " "function argument." + ) if len(in_params) == 0: - message = ComplexModel.produce(type_name=in_message_name, - namespace=ns, members=in_params) + message = ComplexModel.produce( + type_name=in_message_name, namespace=ns, members=in_params + ) else: - message, = in_params.values() + (message,) = in_params.values() message = message.customize(sub_name=in_message_name, sub_ns=ns) if issubclass(message, ComplexModelBase) and not message._type_info: - raise LogicError("body_style='bare' does not allow empty " - "model as param") + raise LogicError( + "body_style='bare' does not allow empty " "model as param" + ) # there can't be multiple arguments here. if message.__type_name__ is ModelBase.Empty: - message._fill_empty_type_name(ns, in_message_name, - "%s_arg0" % in_message_name) + message._fill_empty_type_name( + ns, in_message_name, "%s_arg0" % in_message_name + ) else: - message = ComplexModel.produce(type_name=in_message_name, - namespace=ns, members=in_params) + message = ComplexModel.produce( + type_name=in_message_name, namespace=ns, members=in_params + ) message.__namespace__ = ns if in_wsdl_part_name: @@ -145,22 +161,21 @@ def _produce_input_message(f, params, in_message_name, in_variable_names, def _validate_body_style(kparams): - _body_style = kparams.pop('_body_style', None) - _soap_body_style = kparams.pop('_soap_body_style', None) + _body_style = kparams.pop("_body_style", None) + _soap_body_style = kparams.pop("_soap_body_style", None) - allowed_body_styles = ('wrapped', 'bare', 'out_bare') + allowed_body_styles = ("wrapped", "bare", "out_bare") if _body_style is None: - _body_style = 'wrapped' + _body_style = "wrapped" elif not (_body_style in allowed_body_styles): - raise ValueError("body_style must be one of %r" % - (allowed_body_styles,)) + raise ValueError("body_style must be one of %r" % (allowed_body_styles,)) - elif _soap_body_style == 'document': - _body_style = 'wrapped' + elif _soap_body_style == "document": + _body_style = "wrapped" - elif _soap_body_style == 'rpc': - _body_style = 'bare' + elif _soap_body_style == "rpc": + _body_style = "bare" elif _soap_body_style is None: pass @@ -168,19 +183,18 @@ def _validate_body_style(kparams): else: raise ValueError("soap_body_style must be one of ('rpc', 'document')") - assert _body_style in ('wrapped', 'bare', 'out_bare') + assert _body_style in ("wrapped", "bare", "out_bare") return _body_style -def _produce_output_message(func_name, body_style_str, self_ref_cls, - no_self, kparams): +def _produce_output_message(func_name, body_style_str, self_ref_cls, no_self, kparams): """Generate an output message for "rpc"-style API methods. This message is a wrapper to the declared return type. """ - _returns = kparams.pop('_returns', None) + _returns = kparams.pop("_returns", None) try: is_self_ref = issubclass(_returns, SelfReference) @@ -193,35 +207,38 @@ def _produce_output_message(func_name, body_style_str, self_ref_cls, _returns = recust_selfref(_returns, self_ref_cls) - _is_out_message_name_overridden = not ('_out_message_name' in kparams) - _out_message_name = kparams.pop('_out_message_name', '%s%s' % - (func_name, spyne.const.RESPONSE_SUFFIX)) + _is_out_message_name_overridden = not ("_out_message_name" in kparams) + _out_message_name = kparams.pop( + "_out_message_name", "%s%s" % (func_name, spyne.const.RESPONSE_SUFFIX) + ) - if no_self is False and \ - (body_style_str == 'wrapped' or _is_out_message_name_overridden): - _out_message_name = '%s.%s' % \ - (self_ref_cls.get_type_name(), _out_message_name) + if no_self is False and ( + body_style_str == "wrapped" or _is_out_message_name_overridden + ): + _out_message_name = "%s.%s" % (self_ref_cls.get_type_name(), _out_message_name) - _out_wsdl_part_name = kparams.pop('_wsdl_part_name', None) + _out_wsdl_part_name = kparams.pop("_wsdl_part_name", None) out_params = TypeInfo() - if _returns and body_style_str == 'wrapped': + if _returns and body_style_str == "wrapped": if isinstance(_returns, (list, tuple)): - default_names = ['%s%s%d'% (func_name, spyne.const.RESULT_SUFFIX, i) - for i in range(len(_returns))] + default_names = [ + "%s%s%d" % (func_name, spyne.const.RESULT_SUFFIX, i) + for i in range(len(_returns)) + ] - _out_variable_names = kparams.pop('_out_variable_names', - default_names) + _out_variable_names = kparams.pop("_out_variable_names", default_names) - assert (len(_returns) == len(_out_variable_names)) + assert len(_returns) == len(_out_variable_names) var_pair = zip(_out_variable_names, _returns) out_params = TypeInfo(var_pair) else: - _out_variable_name = kparams.pop('_out_variable_name', - '%s%s' % (func_name, spyne.const.RESULT_SUFFIX)) + _out_variable_name = kparams.pop( + "_out_variable_name", "%s%s" % (func_name, spyne.const.RESULT_SUFFIX) + ) out_params[_out_variable_name] = _returns @@ -231,14 +248,15 @@ def _produce_output_message(func_name, body_style_str, self_ref_cls, ns = _out_message_name_parts[0] # skip index 1, it is the closing '}' _out_message_name = _out_message_name_parts[2] - if body_style_str.endswith('bare') and _returns is not None: + if body_style_str.endswith("bare") and _returns is not None: message = _returns.customize(sub_name=_out_message_name, sub_ns=ns) if message.__type_name__ is ModelBase.Empty: message.__type_name__ = _out_message_name else: - message = ComplexModel.produce(type_name=_out_message_name, - namespace=ns, members=out_params) + message = ComplexModel.produce( + type_name=_out_message_name, namespace=ns, members=out_params + ) message.Attributes._wrapper = True message.__namespace__ = ns # FIXME: is this necessary? @@ -283,15 +301,18 @@ def _get_event_managers(kparams): _event_managers = kparams.pop("_event_managers", None) if _event_manager is not None and _event_managers is not None: - raise LogicError("Pass one of _event_manager or " - "_event_managers but not both") + raise LogicError( + "Pass one of _event_manager or " "_event_managers but not both" + ) if _event_manager is not None: _event_managers = [_event_manager] if _evmgrs is not None and _event_managers is not None: - raise LogicError("You must pass at most one of _evmgr* " - "arguments or _event_manager* arguments") + raise LogicError( + "You must pass at most one of _evmgr* " + "arguments or _event_manager* arguments" + ) elif _evmgrs is not None: _event_managers = _evmgrs @@ -384,19 +405,19 @@ def explain_method(**kwargs): # contains information about the method context like the service # class that contains the method at hand. - function_name = kwargs['_default_function_name'] + function_name = kwargs["_default_function_name"] _service_class = kwargs.pop("_service_class", None) _self_ref_replacement = None # this block is passed straight to the descriptor - _is_callback = kparams.pop('_is_callback', False) - _is_async = kparams.pop('_is_async', False) - _mtom = kparams.pop('_mtom', False) - _in_header = kparams.pop('_in_header', None) - _out_header = kparams.pop('_out_header', None) - _port_type = kparams.pop('_port_type', None) - _no_ctx = kparams.pop('_no_ctx', False) - _aux = kparams.pop('_aux', None) + _is_callback = kparams.pop("_is_callback", False) + _is_async = kparams.pop("_is_async", False) + _mtom = kparams.pop("_mtom", False) + _in_header = kparams.pop("_in_header", None) + _out_header = kparams.pop("_out_header", None) + _port_type = kparams.pop("_port_type", None) + _no_ctx = kparams.pop("_no_ctx", False) + _aux = kparams.pop("_aux", None) _pattern = kparams.pop("_pattern", None) _patterns = kparams.pop("_patterns", []) _args = kparams.pop("_args", None) @@ -405,132 +426,162 @@ def explain_method(**kwargs): _static_when = kparams.pop("_static_when", None) _href = kparams.pop("_href", None) _logged = kparams.pop("_logged", True) - _internal_key_suffix = kparams.pop('_internal_key_suffix', '') - if '_service' in kparams and '_service_class' in kparams: - raise LogicError("Please pass only one of '_service' and " - "'_service_class'") - if '_service' in kparams: + _internal_key_suffix = kparams.pop("_internal_key_suffix", "") + if "_service" in kparams and "_service_class" in kparams: + raise LogicError( + "Please pass only one of '_service' and " "'_service_class'" + ) + if "_service" in kparams: _service_class = kparams.pop("_service") - if '_service_class' in kparams: + if "_service_class" in kparams: _service_class = kparams.pop("_service_class") - _no_self = kparams.pop('_no_self', True) + _no_self = kparams.pop("_no_self", True) _event_managers = _get_event_managers(kparams) # mrpc-specific - _self_ref_replacement = kwargs.pop('_self_ref_replacement', None) - _default_on_null = kparams.pop('_default_on_null', False) - _substitute_self_reference(params, kparams, _self_ref_replacement, - _no_self) + _self_ref_replacement = kwargs.pop("_self_ref_replacement", None) + _default_on_null = kparams.pop("_default_on_null", False) + _substitute_self_reference(params, kparams, _self_ref_replacement, _no_self) _faults = None - if ('_faults' in kparams) and ('_throws' in kparams): - raise ValueError("only one of '_throws ' or '_faults' arguments" - "must be given -- they're synonyms.") + if ("_faults" in kparams) and ("_throws" in kparams): + raise ValueError( + "only one of '_throws ' or '_faults' arguments" + "must be given -- they're synonyms." + ) - elif '_faults' in kparams: - _faults = kparams.pop('_faults') + elif "_faults" in kparams: + _faults = kparams.pop("_faults") - elif '_throws' in kparams: - _faults = kparams.pop('_throws') + elif "_throws" in kparams: + _faults = kparams.pop("_throws") - _is_in_message_name_overridden = not ('_in_message_name' in kparams) - _in_message_name = kparams.pop('_in_message_name', function_name) + _is_in_message_name_overridden = not ("_in_message_name" in kparams) + _in_message_name = kparams.pop("_in_message_name", function_name) if _no_self is False and _is_in_message_name_overridden: - _in_message_name = '%s.%s' % \ - (_self_ref_replacement.get_type_name(), _in_message_name) + _in_message_name = "%s.%s" % ( + _self_ref_replacement.get_type_name(), + _in_message_name, + ) - _operation_name = kparams.pop('_operation_name', function_name) + _operation_name = kparams.pop("_operation_name", function_name) - if _operation_name != function_name and \ - _in_message_name != function_name: + if _operation_name != function_name and _in_message_name != function_name: raise ValueError( "only one of '_operation_name' and '_in_message_name' " - "arguments should be given") + "arguments should be given" + ) if _in_message_name == function_name: _in_message_name = add_request_suffix(_operation_name) - if '_in_arg_names' in kparams and '_in_variable_names' in kparams: - raise LogicError("Use either '_in_arg_names' or " - "'_in_variable_names', not both.") - elif '_in_arg_names' in kparams: - _in_arg_names = kparams.pop('_in_arg_names') + if "_in_arg_names" in kparams and "_in_variable_names" in kparams: + raise LogicError( + "Use either '_in_arg_names' or " "'_in_variable_names', not both." + ) + elif "_in_arg_names" in kparams: + _in_arg_names = kparams.pop("_in_arg_names") - elif '_in_variable_names' in kparams: - _in_arg_names = kparams.pop('_in_variable_names') + elif "_in_variable_names" in kparams: + _in_arg_names = kparams.pop("_in_variable_names") else: _in_arg_names = {} - if '_udd' in kparams and '_udp' in kparams: + if "_udd" in kparams and "_udp" in kparams: raise LogicError("Use either '_udd' or '_udp', not both.") - elif '_udd' in kparams: - _udd = kparams.pop('_udd') + elif "_udd" in kparams: + _udd = kparams.pop("_udd") - elif '_udp' in kparams: - _udd = kparams.pop('_udp') + elif "_udp" in kparams: + _udd = kparams.pop("_udp") else: _udd = {} - _wsdl_part_name = kparams.get('_wsdl_part_name', None) + _wsdl_part_name = kparams.get("_wsdl_part_name", None) body_style = BODY_STYLE_WRAPPED body_style_str = _validate_body_style(kparams) - if body_style_str.endswith('bare'): - if body_style_str == 'out_bare': + if body_style_str.endswith("bare"): + if body_style_str == "out_bare": body_style = BODY_STYLE_OUT_BARE else: body_style = BODY_STYLE_BARE - in_message = _produce_input_message(f, params, - _in_message_name, _in_arg_names, _no_ctx, _no_self, - _args, body_style_str, _self_ref_replacement, - _wsdl_part_name) + in_message = _produce_input_message( + f, + params, + _in_message_name, + _in_arg_names, + _no_ctx, + _no_self, + _args, + body_style_str, + _self_ref_replacement, + _wsdl_part_name, + ) - out_message = _produce_output_message(function_name, - body_style_str, _self_ref_replacement, _no_self, kparams) + out_message = _produce_output_message( + function_name, body_style_str, _self_ref_replacement, _no_self, kparams + ) if _logged != True: in_message.Attributes.logged = _logged out_message.Attributes.logged = _logged - doc = getattr(f, '__doc__') + doc = getattr(f, "__doc__") if _pattern is not None and _patterns != []: - raise ValueError("only one of '_pattern' and '_patterns' " - "arguments should be given") + raise ValueError( + "only one of '_pattern' and '_patterns' " + "arguments should be given" + ) if _pattern is not None: _patterns = [_pattern] - if body_style_str.endswith('bare'): + if body_style_str.endswith("bare"): from spyne.model import ComplexModelBase ti = in_message to = out_message if issubclass(ti, ComplexModelBase) and len(ti._type_info) == 0: - if not issubclass(to, ComplexModelBase) or \ - len(to._type_info) > 0: + if not issubclass(to, ComplexModelBase) or len(to._type_info) > 0: body_style = BODY_STYLE_EMPTY_OUT_BARE else: body_style = BODY_STYLE_EMPTY assert _in_header is None or isinstance(_in_header, tuple) - retval = MethodDescriptor(f, - in_message, out_message, doc, - is_callback=_is_callback, is_async=_is_async, mtom=_mtom, - in_header=_in_header, out_header=_out_header, faults=_faults, + retval = MethodDescriptor( + f, + in_message, + out_message, + doc, + is_callback=_is_callback, + is_async=_is_async, + mtom=_mtom, + in_header=_in_header, + out_header=_out_header, + faults=_faults, parent_class=_self_ref_replacement, - port_type=_port_type, no_ctx=_no_ctx, udd=_udd, - class_key=function_name, aux=_aux, patterns=_patterns, - body_style=body_style, args=_args, - operation_name=_operation_name, no_self=_no_self, + port_type=_port_type, + no_ctx=_no_ctx, + udd=_udd, + class_key=function_name, + aux=_aux, + patterns=_patterns, + body_style=body_style, + args=_args, + operation_name=_operation_name, + no_self=_no_self, translations=_translations, - when=_when, static_when=_static_when, - service_class=_service_class, href=_href, + when=_when, + static_when=_static_when, + service_class=_service_class, + href=_href, internal_key_suffix=_internal_key_suffix, default_on_null=_default_on_null, event_managers=_event_managers, diff --git a/spyne/descriptor.py b/spyne/descriptor.py index 41804e955..4b2c5be99 100644 --- a/spyne/descriptor.py +++ b/spyne/descriptor.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,20 +17,33 @@ # import logging -logger = logging.getLogger('spyne') + +logger = logging.getLogger("spyne") from spyne import LogicError -from spyne.util import six -from spyne.util import DefaultAttrDict -from spyne.service import Service, ServiceBaseBase from spyne.const.xml import DEFAULT_NS +from spyne.service import Service, ServiceBaseBase +from spyne.util import DefaultAttrDict + + +class BODY_STYLE_WRAPPED: + pass -class BODY_STYLE_WRAPPED: pass -class BODY_STYLE_EMPTY: pass -class BODY_STYLE_BARE: pass -class BODY_STYLE_OUT_BARE: pass -class BODY_STYLE_EMPTY_OUT_BARE: pass +class BODY_STYLE_EMPTY: + pass + + +class BODY_STYLE_BARE: + pass + + +class BODY_STYLE_OUT_BARE: + pass + + +class BODY_STYLE_EMPTY_OUT_BARE: + pass class MethodDescriptor(object): @@ -39,12 +51,39 @@ class MethodDescriptor(object): produced by the :func:`spyne.decorator.srpc` decorator. """ - def __init__(self, function, in_message, out_message, doc, - is_callback, is_async, mtom, in_header, out_header, faults, - parent_class, port_type, no_ctx, udd, class_key, aux, patterns, - body_style, args, operation_name, no_self, translations, - when, static_when, service_class, href, internal_key_suffix, - default_on_null, event_managers, logged): + def __init__( + self, + function, + in_message, + out_message, + doc, + is_callback, + is_async, + mtom, + in_header, + out_header, + faults, + parent_class, + port_type, + no_ctx, + udd, + class_key, + aux, + patterns, + body_style, + args, + operation_name, + no_self, + translations, + when, + static_when, + service_class, + href, + internal_key_suffix, + default_on_null, + event_managers, + logged, + ): self.__real_function = function """The original callable for the user code.""" @@ -86,9 +125,9 @@ def __init__(self, function, in_message, out_message, doc, self.is_callback = is_callback self.is_async = is_async self.mtom = mtom - #"""Flag to indicate whether to use MTOM transport with SOAP.""" + # """Flag to indicate whether to use MTOM transport with SOAP.""" self.port_type = port_type - #"""The portType this function belongs to.""" + # """The portType this function belongs to.""" self.in_header = in_header """An iterable of :class:`spyne.model.complex.ComplexModel` @@ -194,7 +233,7 @@ def translate(self, locale, default): """ if locale is None: - locale = 'en_US' + locale = "en_US" if self.translations is not None: return self.translations.get(locale, default) return default @@ -205,8 +244,10 @@ def key(self): assert not (self.in_message.get_namespace() is DEFAULT_NS) - return '{%s}%s' % ( - self.in_message.get_namespace(), self.in_message.get_type_name()) + return "{%s}%s" % ( + self.in_message.get_namespace(), + self.in_message.get_type_name(), + ) @property def internal_key(self): @@ -220,16 +261,18 @@ def internal_key(self): dn = self.name # prevent duplicate class name. this happens when the class is a # direct subclass of ComplexModel - if dn.split('.', 1)[0] != on: + if dn.split(".", 1)[0] != on: return "{%s}%s.%s" % (mn, on, dn) return "{%s}%s" % (mn, dn) sc = self.service_class if sc is not None: - return '{%s}%s%s' % (sc.get_internal_key(), - six.get_function_name(self.function), - self.internal_key_suffix) + return "{%s}%s%s" % ( + sc.get_internal_key(), + self.function.__name__, + self.internal_key_suffix, + ) @staticmethod def get_owner_name(cls): @@ -240,32 +283,36 @@ def get_owner_name(cls): def gen_interface_key(self, cls): # this is a regular service method decorated by @rpc if issubclass(cls, ServiceBaseBase): - return u'{}.{}.{}'.format(cls.__module__, - self.get_owner_name(cls), self.name) + return "{}.{}.{}".format( + cls.__module__, self.get_owner_name(cls), self.name + ) # this is a member method decorated by @mrpc else: - mn = cls.get_namespace() or '__none__' + mn = cls.get_namespace() or "__none__" on = cls.get_type_name() dn = self.name # prevent duplicate class name. this happens when the class is a # direct subclass of ComplexModel - if dn.split(u'.', 1)[0] != on: - return u'.'.join( (mn, on, dn) ) + if dn.split(".", 1)[0] != on: + return ".".join((mn, on, dn)) - return u'.'.join( (mn, dn) ) + return ".".join((mn, dn)) @staticmethod def _get_class_module_name(cls): - return '.'.join([frag for frag in cls.__module__.split('.') - if not frag.startswith('_')]) + return ".".join( + [frag for frag in cls.__module__.split(".") if not frag.startswith("_")] + ) def is_out_bare(self): - return self.body_style in (BODY_STYLE_EMPTY_OUT_BARE, - BODY_STYLE_EMPTY, - BODY_STYLE_BARE, - BODY_STYLE_OUT_BARE) + return self.body_style in ( + BODY_STYLE_EMPTY_OUT_BARE, + BODY_STYLE_EMPTY, + BODY_STYLE_BARE, + BODY_STYLE_OUT_BARE, + ) def reset_function(self, val=None): if val != None: @@ -279,6 +326,7 @@ def in_header(self): @in_header.setter def in_header(self, in_header): from spyne.model._base import ModelBase + try: is_model = issubclass(in_header, ModelBase) except TypeError: @@ -297,6 +345,7 @@ def out_header(self): @out_header.setter def out_header(self, out_header): from spyne.model._base import ModelBase + try: is_model = issubclass(out_header, ModelBase) except TypeError: diff --git a/spyne/error.py b/spyne/error.py index 20cfd793c..35102f393 100644 --- a/spyne/error.py +++ b/spyne/error.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -22,24 +21,25 @@ code can throw. """ -from spyne.model.fault import Fault +from spyne.model.fault import Fault, ValidationError class InvalidCredentialsError(Fault): """Raised when requested resource is forbidden.""" - CODE = 'Client.InvalidCredentialsError' + CODE = "Client.InvalidCredentialsError" STR = "You do not have permission to access this resource." def __init__(self, fault_string=STR, params=None): - super(InvalidCredentialsError, self) \ - .__init__(self.CODE, fault_string, detail=params) + super(InvalidCredentialsError, self).__init__( + self.CODE, fault_string, detail=params + ) class RequestTooLongError(Fault): """Raised when request is too long.""" - CODE = 'Client.RequestTooLong' + CODE = "Client.RequestTooLong" def __init__(self, faultstring="Request too long"): super(RequestTooLongError, self).__init__(self.CODE, faultstring) @@ -48,7 +48,7 @@ def __init__(self, faultstring="Request too long"): class RequestNotAllowed(Fault): """Raised when request is incomplete.""" - CODE = 'Client.RequestNotAllowed' + CODE = "Client.RequestNotAllowed" def __init__(self, faultstring=""): super(RequestNotAllowed, self).__init__(self.CODE, faultstring) @@ -57,7 +57,7 @@ def __init__(self, faultstring=""): class ArgumentError(Fault): """Raised when there is a general problem with input data.""" - CODE = 'Client.ArgumentError' + CODE = "Client.ArgumentError" def __init__(self, faultstring=""): super(ArgumentError, self).__init__(self.CODE, faultstring) @@ -67,8 +67,9 @@ class InvalidInputError(Fault): """Raised when there is a general problem with input data.""" def __init__(self, faultstring="", data=""): - super(InvalidInputError, self) \ - .__init__('Client.InvalidInput', repr((faultstring, data))) + super(InvalidInputError, self).__init__( + "Client.InvalidInput", repr((faultstring, data)) + ) InvalidRequestError = InvalidInputError @@ -77,7 +78,7 @@ def __init__(self, faultstring="", data=""): class MissingFieldError(InvalidInputError): """Raised when a mandatory value is missing.""" - CODE = 'Client.InvalidInput' + CODE = "Client.InvalidInput" def __init__(self, field_name, message="Field '%s' is missing."): try: @@ -88,39 +89,26 @@ def __init__(self, field_name, message="Field '%s' is missing."): super(MissingFieldError, self).__init__(self.CODE, message) -class ValidationError(Fault): - """Raised when the input stream does not adhere to type constraints.""" - - CODE = 'Client.ValidationError' - - def __init__(self, obj, custom_msg='The value %r could not be validated.'): - try: - msg = custom_msg % (obj,) - except TypeError: - msg = custom_msg - - super(ValidationError, self).__init__(self.CODE, msg) - - class InternalError(Fault): """Raised to communicate server-side errors.""" - CODE = 'Server' + CODE = "Server" def __init__(self, error): - super(InternalError, self) \ - .__init__(self.CODE, "InternalError: An unknown error has occured.") + super(InternalError, self).__init__( + self.CODE, "InternalError: An unknown error has occured." + ) class ResourceNotFoundError(Fault): """Raised when requested resource is not found.""" - CODE = 'Client.ResourceNotFound' + CODE = "Client.ResourceNotFound" - def __init__(self, fault_object, - fault_string="Requested resource %r not found"): - super(ResourceNotFoundError, self) \ - .__init__(self.CODE, fault_string % (fault_object,)) + def __init__(self, fault_object, fault_string="Requested resource %r not found"): + super(ResourceNotFoundError, self).__init__( + self.CODE, fault_string % (fault_object,) + ) class RespawnError(ResourceNotFoundError): @@ -130,18 +118,19 @@ class RespawnError(ResourceNotFoundError): class ResourceAlreadyExistsError(Fault): """Raised when requested resource already exists on server side.""" - CODE = 'Client.ResourceAlreadyExists' + CODE = "Client.ResourceAlreadyExists" def __init__(self, fault_object, fault_string="Resource %r already exists"): - super(ResourceAlreadyExistsError, self) \ - .__init__(self.CODE, fault_string % fault_object) + super(ResourceAlreadyExistsError, self).__init__( + self.CODE, fault_string % fault_object + ) class Redirect(Fault): """Raised when client needs to make another request for the same resource.""" - CODE = 'Client.Redirect' + CODE = "Client.Redirect" def __init__(self, ctx, location, orig_exc=None): super(Redirect, self).__init__(self.CODE, faultstring=location) diff --git a/spyne/evmgr.py b/spyne/evmgr.py index 6b2250dcc..d9ac9c9bf 100644 --- a/spyne/evmgr.py +++ b/spyne/evmgr.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -68,7 +67,6 @@ def del_listener(self, event_name, handler=None): else: self.handlers[event_name].remove(handler) - def fire_event(self, event_name, ctx, *args, **kwargs): """Run all the handlers for a given event name. diff --git a/spyne/interface/__init__.py b/spyne/interface/__init__.py index dd88cdb21..2510faa41 100644 --- a/spyne/interface/__init__.py +++ b/spyne/interface/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -24,22 +23,23 @@ to generate those documents. """ - from __future__ import print_function -from spyne.interface._base import Interface -from spyne.interface._base import InterfaceDocumentBase -from spyne.interface._base import InterfaceDocumentsBase -from spyne.interface._base import InterfaceDocuments - +from spyne.interface._base import ( + Interface, + InterfaceDocumentBase, + InterfaceDocuments, + InterfaceDocumentsBase, +) try: - from spyne.interface.xml_schema import XmlSchema from spyne.interface.wsdl.wsdl11 import Wsdl11 + from spyne.interface.xml_schema import XmlSchema + HAS_WSDL = True except ImportError as e: - if 'No module named lxml' in e.args or "No module named 'lxml'" in e.args: + if "No module named lxml" in e.args or "No module named 'lxml'" in e.args: HAS_WSDL = False else: raise diff --git a/spyne/interface/_base.py b/spyne/interface/_base.py index cadc6c5dc..53cf95ad4 100644 --- a/spyne/interface/_base.py +++ b/spyne/interface/_base.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,40 +17,44 @@ # import logging + logger = logging.getLogger(__name__) -from collections import deque, defaultdict +from collections import defaultdict, deque import spyne.interface - -from spyne import EventManager, MethodDescriptor -from spyne.util import six -from spyne.model import ModelBase, Array, Iterable, ComplexModelBase -from spyne.model.complex import XmlModifier from spyne.const import xml as namespace +from spyne.descriptor import MethodDescriptor +from spyne.evmgr import EventManager +from spyne.model import Array, ComplexModelBase, Iterable, ModelBase +from spyne.model.complex import XmlModifier class InterfaceDocumentsBase(object): - def __init__(self, interface, - # *, # kwargs start here, commented due to py2 compat - wsdl11): + def __init__( + self, + interface, + # *, # kwargs start here, commented due to py2 compat + wsdl11, + ): self.interface = interface self.wsdl11 = wsdl11 @property def xml_schema(self): from spyne.interface import XmlSchema + assert isinstance(self.wsdl11, XmlSchema) return self.wsdl11 class InterfaceDocuments(InterfaceDocumentsBase): def __init__(self, interface): - super(InterfaceDocuments, self).__init__(interface, - wsdl11=None) + super(InterfaceDocuments, self).__init__(interface, wsdl11=None) if spyne.interface.HAS_WSDL: from spyne.interface.wsdl import Wsdl11 + self.wsdl11 = Wsdl11(interface) @@ -62,8 +65,12 @@ class Interface(object): :param app: A :class:`spyne.application.Application` instance. """ - def __init__(self, app=None, import_base_namespaces=False, - documents_container=InterfaceDocuments): + def __init__( + self, + app=None, + import_base_namespaces=False, + documents_container=InterfaceDocuments, + ): self.__ns_counter = 0 self.__app = None self.url = None @@ -92,8 +99,9 @@ def documents(self, what): self.docs = what def set_app(self, value): - assert self.__app is None, "One interface instance can belong to only " \ - "one application instance." + assert self.__app is None, ( + "One interface instance can belong to only " "one application instance." + ) self.__app = value self.reset_interface() @@ -119,8 +127,8 @@ def reset_interface(self): self.prefmap = dict(namespace.PREFMAP) self.member_methods = deque() - self.nsmap['tns'] = self.get_tns() - self.prefmap[self.get_tns()] = 'tns' + self.nsmap["tns"] = self.get_tns() + self.prefmap[self.get_tns()] = "tns" self.deps = defaultdict(set) def has_class(self, cls): @@ -130,15 +138,14 @@ def has_class(self, cls): ns = cls.get_namespace() tn = cls.get_type_name() - key = '{%s}%s' % (ns, tn) + key = "{%s}%s" % (ns, tn) c = self.classes.get(key) if c is None: return False - if issubclass(c, ComplexModelBase) and \ - issubclass(cls, ComplexModelBase): - o1 = getattr(cls, '__orig__', None) or cls - o2 = getattr(c, '__orig__', None) or c + if issubclass(c, ComplexModelBase) and issubclass(cls, ComplexModelBase): + o1 = getattr(cls, "__orig__", None) or cls + o2 = getattr(c, "__orig__", None) or c if o1 is o2: return True @@ -147,8 +154,9 @@ def has_class(self, cls): if set((o1, o2)) == set((Array, Iterable)): return True - raise ValueError("classes %r and %r have conflicting names: '%s'" % - (cls, c, key)) + raise ValueError( + "classes %r and %r have conflicting names: '%s'" % (cls, c, key) + ) return True def get_class(self, key): @@ -204,8 +212,9 @@ def add_method(self, method): if method.aux is None: yield in_header in_header_ns = in_header.get_namespace() - if in_header_ns != self.get_tns() and \ - self.is_valid_import(in_header_ns): + if in_header_ns != self.get_tns() and self.is_valid_import( + in_header_ns + ): self.imports[self.get_tns()].add(in_header_ns) if not (method.out_header is None): @@ -217,8 +226,9 @@ def add_method(self, method): if method.aux is None: yield out_header out_header_ns = out_header.get_namespace() - if out_header_ns != self.get_tns() and \ - self.is_valid_import(out_header_ns): + if out_header_ns != self.get_tns() and self.is_valid_import( + out_header_ns + ): self.imports[self.get_tns()].add(out_header_ns) if method.faults is None: @@ -234,8 +244,7 @@ def add_method(self, method): method.in_message.resolve_namespace(method.in_message, self.get_tns()) in_message_ns = method.in_message.get_namespace() - if in_message_ns != self.get_tns() and \ - self.is_valid_import(in_message_ns): + if in_message_ns != self.get_tns() and self.is_valid_import(in_message_ns): self.imports[self.get_tns()].add(method.in_message.get_namespace()) if method.aux is None: @@ -245,8 +254,7 @@ def add_method(self, method): assert not method.out_message.get_type_name() is method.out_message.Empty out_message_ns = method.out_message.get_namespace() - if out_message_ns != self.get_tns() and \ - self.is_valid_import(out_message_ns): + if out_message_ns != self.get_tns() and self.is_valid_import(out_message_ns): self.imports[self.get_tns()].add(out_message_ns) if method.aux is None: @@ -258,13 +266,16 @@ def add_method(self, method): def process_method(self, s, method): assert isinstance(method, MethodDescriptor) - method_key = u'{%s}%s' % (self.app.tns, method.name) + method_key = "{%s}%s" % (self.app.tns, method.name) if issubclass(s, ComplexModelBase): - method_object_name = method.name.split('.', 1)[0] + method_object_name = method.name.split(".", 1)[0] if s.get_type_name() != method_object_name: - method_key = u'{%s}%s.%s' % (self.app.tns, s.get_type_name(), - method.name) + method_key = "{%s}%s.%s" % ( + self.app.tns, + s.get_type_name(), + method.name, + ) key = method.gen_interface_key(s) if key in self.method_id_map: @@ -276,19 +287,34 @@ def process_method(self, s, method): pass elif c.__orig__ is None: - assert c is s.__orig__, "%r.%s conflicts with %r.%s" % \ - (c, key, s.__orig__, key) + assert c is s.__orig__, "%r.%s conflicts with %r.%s" % ( + c, + key, + s.__orig__, + key, + ) elif s.__orig__ is None: - assert c.__orig__ is s, "%r.%s conflicts with %r.%s" % \ - (c.__orig__, key, s, key) + assert c.__orig__ is s, "%r.%s conflicts with %r.%s" % ( + c.__orig__, + key, + s, + key, + ) else: - assert c.__orig__ is s.__orig__, "%r.%s conflicts with %r.%s" % \ - (c.__orig__, key, s.__orig__, key) + assert c.__orig__ is s.__orig__, "%r.%s conflicts with %r.%s" % ( + c.__orig__, + key, + s.__orig__, + key, + ) return - logger.debug(' adding method %s.%s to match %r tag.', - method.get_owner_name(s), six.get_function_name(method.function), - method_key) + logger.debug( + " adding method %s.%s to match %r tag.", + method.get_owner_name(s), + method.function.__name__, + method_key, + ) self.method_id_map[key] = method @@ -310,10 +336,11 @@ def process_method(self, s, method): os = om.service_class if os is None: os = om.parent_class - raise ValueError("\nThe message %r defined in both '%s.%s'" - " and '%s.%s'" - % (method.name, s.__module__, s.__name__, - os.__module__, os.__name__)) + raise ValueError( + "\nThe message %r defined in both '%s.%s'" + " and '%s.%s'" + % (method.name, s.__module__, s.__name__, os.__module__, os.__name__) + ) def check_method(self, method): """Override this if you need to cherry-pick methods added to the @@ -345,12 +372,12 @@ def populate_interface(self, types=None): method.aux.methods.append(method.gen_interface_key(s)) if not self.check_method(method): - logger.debug("method %s' discarded by check_method", - method.class_key) + logger.debug( + "method %s' discarded by check_method", method.class_key + ) continue - logger.debug(" enumerating classes for method '%s'", - method.class_key) + logger.debug(" enumerating classes for method '%s'", method.class_key) for cls in self.add_method(method): self.add_class(cls) @@ -360,9 +387,8 @@ def populate_interface(self, types=None): # populate call routes for service methods for s in self.services: - self.service_attrs[s]['tns'] = self.get_tns() - logger.debug("populating '%s.%s' routes...", s.__module__, - s.__name__) + self.service_attrs[s]["tns"] = self.get_tns() + logger.debug("populating '%s.%s' routes...", s.__module__, s.__name__) for method in s.public_methods.values(): self.process_method(s, method) @@ -371,8 +397,11 @@ def populate_interface(self, types=None): should_we = True if method.static_when is not None: should_we = method.static_when(self.app) - logger.debug("static_when returned %r for %s " - "while populating methods", should_we, method.internal_key) + logger.debug( + "static_when returned %r for %s " "while populating methods", + should_we, + method.internal_key, + ) if should_we: s = method.service_class @@ -390,12 +419,15 @@ def populate_interface(self, types=None): self.process_method(cls.__orig__ or cls, method) # populate method descriptor id to method key map - self.method_descriptor_id_to_key = dict(((id(v[0]), k) - for k,v in self.service_method_map.items())) + self.method_descriptor_id_to_key = dict( + ((id(v[0]), k) for k, v in self.service_method_map.items()) + ) - logger.debug("From this point on, you're not supposed to make any " - "changes to the class and method structure of the exposed " - "services.") + logger.debug( + "From this point on, you're not supposed to make any " + "changes to the class and method structure of the exposed " + "services." + ) tns = property(get_tns) @@ -406,7 +438,7 @@ def get_namespace_prefix(self, ns): Not meant to be overridden. """ - if not (isinstance(ns, str) or isinstance(ns, six.text_type)): + if not isinstance(ns, str): raise TypeError(ns) if not (ns in self.prefmap): @@ -432,18 +464,24 @@ def add_class(self, cls, add_parent=True): ns = cls.get_namespace() tn = cls.get_type_name() - assert ns is not None, ('either assign a namespace to the class or call' - ' cls.resolve_namespace(cls, "some_default_ns") on it.') + assert ns is not None, ( + "either assign a namespace to the class or call" + ' cls.resolve_namespace(cls, "some_default_ns") on it.' + ) if not (ns in self.imports) and self.is_valid_import(ns): self.imports[ns] = set() - class_key = '{%s}%s' % (ns, tn) - logger.debug(' adding class %r for %r', repr(cls), class_key) + class_key = "{%s}%s" % (ns, tn) + logger.debug(" adding class %r for %r", repr(cls), class_key) - assert class_key not in self.classes, ("Somehow, you're trying to " - "overwrite %r by %r for class key %r." % - (self.classes[class_key], cls, class_key)) + assert ( + class_key not in self.classes + ), "Somehow, you're trying to " "overwrite %r by %r for class key %r." % ( + self.classes[class_key], + cls, + class_key, + ) assert not (cls.get_type_name() is cls.Empty), cls @@ -453,22 +491,28 @@ def add_class(self, cls, add_parent=True): self.classes[tn] = cls # add parent class - extends = getattr(cls, '__extends__', None) - while extends is not None and \ - (extends.get_type_name() is ModelBase.Empty): - extends = getattr(extends, '__extends__', None) + extends = getattr(cls, "__extends__", None) + while extends is not None and (extends.get_type_name() is ModelBase.Empty): + extends = getattr(extends, "__extends__", None) if add_parent and extends is not None: assert issubclass(extends, ModelBase) self.deps[cls].add(extends) self.add_class(extends) parent_ns = extends.get_namespace() - if parent_ns != ns and not parent_ns in self.imports[ns] and \ - self.is_valid_import(parent_ns): + if ( + parent_ns != ns + and not parent_ns in self.imports[ns] + and self.is_valid_import(parent_ns) + ): self.imports[ns].add(parent_ns) - logger.debug(" importing %r to %r because %r extends %r", - parent_ns, ns, cls.get_type_name(), - extends.get_type_name()) + logger.debug( + " importing %r to %r because %r extends %r", + parent_ns, + ns, + cls.get_type_name(), + extends.get_type_name(), + ) # add fields if issubclass(cls, ComplexModelBase): @@ -488,25 +532,46 @@ def add_class(self, cls, add_parent=True): v.resolve_namespace(v, cls.get_namespace()) child_ns = v.get_namespace() - if child_ns != ns and not child_ns in self.imports[ns] and \ - self.is_valid_import(child_ns): + if ( + child_ns != ns + and not child_ns in self.imports[ns] + and self.is_valid_import(child_ns) + ): self.imports[ns].add(child_ns) - logger.debug(" importing %r to %r for %s.%s(%r)", - child_ns, ns, cls.get_type_name(), k, v) + logger.debug( + " importing %r to %r for %s.%s(%r)", + child_ns, + ns, + cls.get_type_name(), + k, + v, + ) if issubclass(v, XmlModifier): self.add_class(v.type) child_ns = v.type.get_namespace() - if child_ns != ns and not child_ns in self.imports[ns] and \ - self.is_valid_import(child_ns): + if ( + child_ns != ns + and not child_ns in self.imports[ns] + and self.is_valid_import(child_ns) + ): self.imports[ns].add(child_ns) - logger.debug(" importing %r to %r for %s.%s(%r)", - child_ns, ns, v.get_type_name(), k, v.type) + logger.debug( + " importing %r to %r for %s.%s(%r)", + child_ns, + ns, + v.get_type_name(), + k, + v.type, + ) if cls.Attributes.methods is not None: - logger.debug(" populating member methods for '%s.%s'...", - cls.get_namespace(), cls.get_type_name()) + logger.debug( + " populating member methods for '%s.%s'...", + cls.get_namespace(), + cls.get_type_name(), + ) for method_key, descriptor in cls.Attributes.methods.items(): assert hasattr(cls, method_key) @@ -514,9 +579,12 @@ def add_class(self, cls, add_parent=True): should_we = True if descriptor.static_when is not None: should_we = descriptor.static_when(self.app) - logger.debug("static_when returned %r for %s " + logger.debug( + "static_when returned %r for %s " "while populating classes", - should_we, descriptor.internal_key) + should_we, + descriptor.internal_key, + ) if should_we: self.member_methods.append((cls, descriptor)) @@ -524,8 +592,11 @@ def add_class(self, cls, add_parent=True): self.add_class(c) if cls.Attributes._subclasses is not None: - logger.debug(" adding subclasses of '%s.%s'...", - cls.get_namespace(), cls.get_type_name()) + logger.debug( + " adding subclasses of '%s.%s'...", + cls.get_namespace(), + cls.get_type_name(), + ) for c in cls.Attributes._subclasses: c.resolve_namespace(c, ns) @@ -536,10 +607,15 @@ def add_class(self, cls, add_parent=True): self.add_class(c, add_parent=False) self.deps[c].add(cls) else: - logger.debug(" not adding %r to %r because it would " + logger.debug( + " not adding %r to %r because it would " "cause circular imports because %r extends %r and " - "they don't have the same namespace", child_ns, - ns, c.get_type_name(), cls.get_type_name()) + "they don't have the same namespace", + child_ns, + ns, + c.get_type_name(), + cls.get_type_name(), + ) def is_valid_import(self, ns): """This will return False for base namespaces unless told otherwise.""" @@ -567,7 +643,7 @@ def build_interface_document(self): function as this may result in the same event firing more than once. """ - raise NotImplementedError('Extend and override.') + raise NotImplementedError("Extend and override.") def get_interface_document(self): """This function is called by server transports that try to satisfy the @@ -575,4 +651,4 @@ def get_interface_document(self): cached interface document. """ - raise NotImplementedError('Extend and override.') + raise NotImplementedError("Extend and override.") diff --git a/spyne/interface/wsdl/__init__.py b/spyne/interface/wsdl/__init__.py index c7868e5c9..ec1b82a0f 100644 --- a/spyne/interface/wsdl/__init__.py +++ b/spyne/interface/wsdl/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # diff --git a/spyne/interface/wsdl/defn.py b/spyne/interface/wsdl/defn.py index e072b283f..7b0484321 100644 --- a/spyne/interface/wsdl/defn.py +++ b/spyne/interface/wsdl/defn.py @@ -1,22 +1,14 @@ - -from spyne.util.six import add_metaclass - from spyne.const import xml - +from spyne.interface.xml_schema.defn import XmlSchema10 +from spyne.model.complex import ComplexModelBase, ComplexModelMeta, XmlAttribute from spyne.model.primitive import Unicode -from spyne.model.complex import XmlAttribute -from spyne.model.complex import ComplexModelBase -from spyne.model.complex import ComplexModelMeta -from spyne.interface.xml_schema.defn import XmlSchema10 -@add_metaclass(ComplexModelMeta) -class Wsdl11Base(ComplexModelBase): +class Wsdl11Base(ComplexModelBase, metaclass=ComplexModelMeta): __namespace__ = xml.NS_WSDL11 -@add_metaclass(ComplexModelMeta) -class Soap11Base(ComplexModelBase): +class Soap11Base(ComplexModelBase, metaclass=ComplexModelMeta): __namespace__ = xml.NS_WSDL11_SOAP @@ -47,10 +39,10 @@ class SoapHeaderDefinition(Wsdl11Base): class OperationMode(Wsdl11Base): name = XmlAttribute(Unicode) message = XmlAttribute(Unicode) - soap_body = SoapBodyDefinition.customize(sub_ns=xml.NS_WSDL11_SOAP, - sub_name="body") - soap_header = SoapHeaderDefinition.customize(sub_ns=xml.NS_WSDL11_SOAP, - sub_name="header") + soap_body = SoapBodyDefinition.customize(sub_ns=xml.NS_WSDL11_SOAP, sub_name="body") + soap_header = SoapHeaderDefinition.customize( + sub_ns=xml.NS_WSDL11_SOAP, sub_name="header" + ) class SoapOperation(Wsdl11Base): @@ -61,10 +53,12 @@ class SoapOperation(Wsdl11Base): class Operation(Wsdl11Base): input = OperationMode output = OperationMode - soap_operation = SoapOperation.customize(sub_ns=xml.NS_WSDL11_SOAP, - sub_name="operation") + soap_operation = SoapOperation.customize( + sub_ns=xml.NS_WSDL11_SOAP, sub_name="operation" + ) parameterOrder = XmlAttribute(Unicode) + class PortType(Wsdl11Base): name = XmlAttribute(Unicode) operation = Operation.customize(max_occurs="unbounded") @@ -79,8 +73,7 @@ class Binding(Wsdl11Base): name = XmlAttribute(Unicode) type = XmlAttribute(Unicode) location = XmlAttribute(Unicode) - soap_binding = SoapBinding.customize(sub_ns=xml.NS_WSDL11_SOAP, - sub_name="binding") + soap_binding = SoapBinding.customize(sub_ns=xml.NS_WSDL11_SOAP, sub_name="binding") class PortAddress(Soap11Base): @@ -100,9 +93,9 @@ class Service(Wsdl11Base): class Wsdl11(Wsdl11Base): _type_info = [ - ('types', Types), - ('message', Message.customize(max_occurs="unbounded")), - ('service', Service), - ('portType', PortType), - ('binding', Binding), + ("types", Types), + ("message", Message.customize(max_occurs="unbounded")), + ("service", Service), + ("portType", PortType), + ("binding", Binding), ] diff --git a/spyne/interface/wsdl/wsdl11.py b/spyne/interface/wsdl/wsdl11.py index 71a430dfe..ddba0c43d 100644 --- a/spyne/interface/wsdl/wsdl11.py +++ b/spyne/interface/wsdl/wsdl11.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -22,26 +21,24 @@ """ import logging + logger = logging.getLogger(__name__) import re -import spyne.const.xml as ns - -from spyne.util import six - from lxml import etree from lxml.builder import E from lxml.etree import SubElement -from spyne.const.xml import WSDL11, XSD, NS_WSA, PLINK +import spyne.const.xml as ns +from spyne.const.xml import NS_WSA, PLINK, WSDL11, XSD from spyne.interface.xml_schema import XmlSchema -REGEX_WSDL = re.compile('[.?]wsdl$') +REGEX_WSDL = re.compile("[.?]wsdl$") PREF_WSA = ns.PREFMAP[NS_WSA] -_in_header_msg_suffix = 'InHeaderMsg' -_out_header_msg_suffix = 'OutHeaderMsg' +_in_header_msg_suffix = "InHeaderMsg" +_out_header_msg_suffix = "OutHeaderMsg" def check_method_port(service, method): @@ -60,7 +57,7 @@ class declares a list of ports or add a list of ports to the service class """) try: - if (not method.port_type is None): + if not method.port_type is None: index = service.__port_types__.index(method.port_type) except ValueError as e: @@ -92,10 +89,16 @@ class Wsdl11(XmlSchema): #:param import_base_namespaces: Include imports for base namespaces like # xsd, xsi, wsdl, etc. - def __init__(self, interface=None, xsl_href=None, _with_partnerlink=False, - element_form_default='qualified'): + def __init__( + self, + interface=None, + xsl_href=None, + _with_partnerlink=False, + element_form_default="qualified", + ): super(Wsdl11, self).__init__( - interface, element_form_default=element_form_default) + interface, element_form_default=element_form_default + ) self._with_plink = _with_partnerlink self.xsl_href = xsl_href @@ -110,7 +113,7 @@ def __init__(self, interface=None, xsl_href=None, _with_partnerlink=False, self.validation_schema = None def _get_binding_name(self, port_type_name): - return port_type_name # subclasses override to control port names. + return port_type_name # subclasses override to control port names. def _get_or_create_port_type(self, pt_name): """Creates a wsdl:portType element.""" @@ -119,7 +122,7 @@ def _get_or_create_port_type(self, pt_name): if not pt_name in self.port_type_dict: pt = SubElement(self.root_elt, WSDL11("portType")) - pt.set('name', pt_name) + pt.set("name", pt_name) self.port_type_dict[pt_name] = pt else: @@ -133,7 +136,7 @@ def _get_or_create_service_node(self, service_name): ser = None if not service_name in self.service_elt_dict: ser = SubElement(self.root_elt, WSDL11("service")) - ser.set('name', service_name) + ser.set("name", service_name) self.service_elt_dict[service_name] = ser else: @@ -149,30 +152,32 @@ def build_interface_document(self, url): self.build_schema_nodes() - self.url = REGEX_WSDL.sub('', url) + self.url = REGEX_WSDL.sub("", url) service_name = self.interface.get_name() # create wsdl root node - self.root_elt = root = etree.Element(WSDL11("definitions"), - nsmap=self.interface.nsmap) + self.root_elt = root = etree.Element( + WSDL11("definitions"), nsmap=self.interface.nsmap + ) if self.xsl_href is not None: # example: # " # pi.attrib.__setitem__ is ignored, so we get a proper list of # attributes to pass with the following hack. - pitext = etree.tostring(etree.Element("dummy", - dict(type='text/xsl', href=self.xsl_href)), encoding='unicode') \ - .split(" ", 1)[-1][:-2] + pitext = etree.tostring( + etree.Element("dummy", dict(type="text/xsl", href=self.xsl_href)), + encoding="unicode", + ).split(" ", 1)[-1][:-2] pi = etree.ProcessingInstruction("xml-stylesheet", pitext) self.root_elt.addprevious(pi) self.root_tree = root.getroottree() - root.set('targetNamespace', self.interface.tns) - root.set('name', service_name) + root.set("targetNamespace", self.interface.tns) + root.set("name", service_name) # create types node types = SubElement(root, WSDL11("types")) @@ -185,7 +190,7 @@ def build_interface_document(self, url): if self._with_plink: plink = SubElement(root, PLINK("partnerLinkType")) - plink.set('name', service_name) + plink.set("name", service_name) self.__add_partner_link(service_name, plink) # create service nodes in advance. they're to be filled in subsequent @@ -202,18 +207,22 @@ def build_interface_document(self, url): cb_binding = None for s in self.interface.services: if not s.is_auxiliary(): - cb_binding = self.add_bindings_for_methods(s, root, - service_name, cb_binding) + cb_binding = self.add_bindings_for_methods( + s, root, service_name, cb_binding + ) if self.interface.app.transport is None: - raise Exception("You must set the 'transport' property of the " - "parent 'Application' instance") + raise Exception( + "You must set the 'transport' property of the " + "parent 'Application' instance" + ) - self.event_manager.fire_event('document_built', self) - self.event_manager.fire_event('wsdl_document_built', self) + self.event_manager.fire_event("document_built", self) + self.event_manager.fire_event("wsdl_document_built", self) - self.__wsdl = etree.tostring(self.root_tree, xml_declaration=True, - encoding="UTF-8") + self.__wsdl = etree.tostring( + self.root_tree, xml_declaration=True, encoding="UTF-8" + ) def __add_partner_link(self, service_name, plink): """Add the partnerLinkType node to the wsdl.""" @@ -222,32 +231,32 @@ def __add_partner_link(self, service_name, plink): pref_tns = self.interface.get_namespace_prefix(ns_tns) role = SubElement(plink, PLINK("role")) - role.set('name', service_name) + role.set("name", service_name) plink_port_type = SubElement(role, PLINK("portType")) - plink_port_type.set('name', '%s:%s' % (pref_tns, service_name)) + plink_port_type.set("name", "%s:%s" % (pref_tns, service_name)) if self._has_callbacks(): role = SubElement(plink, PLINK("role")) - role.set('name', '%sCallback' % service_name) + role.set("name", "%sCallback" % service_name) plink_port_type = SubElement(role, PLINK("portType")) - plink_port_type.set('name', '%s:%sCallback' % - (pref_tns, service_name)) + plink_port_type.set("name", "%s:%sCallback" % (pref_tns, service_name)) def _add_port_to_service(self, service, port_name, binding_name): - """ Builds a wsdl:port for a service and binding""" + """Builds a wsdl:port for a service and binding""" pref_tns = self.interface.get_namespace_prefix(self.interface.tns) wsdl_port = SubElement(service, WSDL11("port")) - wsdl_port.set('name', port_name) - wsdl_port.set('binding', '%s:%s' % (pref_tns, binding_name)) + wsdl_port.set("name", port_name) + wsdl_port.set("binding", "%s:%s" % (pref_tns, binding_name)) - addr = SubElement(wsdl_port, - ns.get_binding_ns(self.interface.app.in_protocol.type)("address")) + addr = SubElement( + wsdl_port, ns.get_binding_ns(self.interface.app.in_protocol.type)("address") + ) - addr.set('location', self.url) + addr.set("location", self.url) def _has_callbacks(self): for s in self.interface.services: @@ -271,8 +280,7 @@ def _get_applied_service_name(self, service): def add_port_type(self, service, root, service_name, types, url): # FIXME: I don't think this call is working. - cb_port_type = self._add_callbacks(service, root, types, - service_name, url) + cb_port_type = self._add_callbacks(service, root, types, service_name, url) applied_service_name = self._get_applied_service_name(service) port_binding_names = [] @@ -280,14 +288,14 @@ def add_port_type(self, service, root, service_name, types, url): if len(port_type_list) > 0: for port_type_name in port_type_list: port_type = self._get_or_create_port_type(port_type_name) - port_type.set('name', port_type_name) + port_type.set("name", port_type_name) binding_name = self._get_binding_name(port_type_name) port_binding_names.append((port_type_name, binding_name)) else: port_type = self._get_or_create_port_type(service_name) - port_type.set('name', service_name) + port_type.set("name", service_name) binding_name = self._get_binding_name(service_name) port_binding_names.append((service_name, binding_name)) @@ -300,31 +308,38 @@ def add_port_type(self, service, root, service_name, types, url): else: operation = SubElement(port_type, WSDL11("operation")) - operation.set('name', method.operation_name) + operation.set("name", method.operation_name) if method.doc is not None: operation.append(E(WSDL11("documentation"), method.doc)) - operation.set('parameterOrder', method.in_message.get_element_name()) + operation.set("parameterOrder", method.in_message.get_element_name()) op_input = SubElement(operation, WSDL11("input")) - op_input.set('name', method.in_message.get_element_name()) - op_input.set('message', - method.in_message.get_element_name_ns(self.interface)) + op_input.set("name", method.in_message.get_element_name()) + op_input.set( + "message", method.in_message.get_element_name_ns(self.interface) + ) if (not method.is_callback) and (not method.is_async): op_output = SubElement(operation, WSDL11("output")) - op_output.set('name', method.out_message.get_element_name()) - op_output.set('message', method.out_message.get_element_name_ns( - self.interface)) + op_output.set("name", method.out_message.get_element_name()) + op_output.set( + "message", method.out_message.get_element_name_ns(self.interface) + ) if not (method.faults is None): for f in method.faults: fault = SubElement(operation, WSDL11("fault")) - fault.set('name', f.get_type_name()) - fault.set('message', '%s:%s' % ( - f.get_namespace_prefix(self.interface), - f.get_type_name())) + fault.set("name", f.get_type_name()) + fault.set( + "message", + "%s:%s" + % ( + f.get_namespace_prefix(self.interface), + f.get_type_name(), + ), + ) ser = self.service_elt_dict[applied_service_name] for port_name, binding_name in port_binding_names: @@ -335,7 +350,7 @@ def _add_message_for_object(self, root, messages, obj, message_name): messages.add(message_name) message = SubElement(root, WSDL11("message")) - message.set('name', message_name) + message.set("name", message_name) if isinstance(obj, (list, tuple)): objs = obj @@ -344,40 +359,59 @@ def _add_message_for_object(self, root, messages, obj, message_name): for obj in objs: part = SubElement(message, WSDL11("part")) - part.set('name', obj.get_wsdl_part_name()) - part.set('element', obj.get_element_name_ns(self.interface)) + part.set("name", obj.get_wsdl_part_name()) + part.set("element", obj.get_element_name_ns(self.interface)) def add_messages_for_methods(self, service, root, messages): for method in service.public_methods.values(): - self._add_message_for_object(root, messages, method.in_message, - method.in_message.get_element_name()) - self._add_message_for_object(root, messages, method.out_message, - method.out_message.get_element_name()) - - if method.in_header is not None: - if len(method.in_header) > 1: - in_header_message_name = ''.join((method.name, - _in_header_msg_suffix)) + self._add_message_for_object( + root, messages, method.in_message, method.in_message.get_element_name() + ) + self._add_message_for_object( + root, + messages, + method.out_message, + method.out_message.get_element_name(), + ) + + in_header = method.in_header + if in_header is None and service.__in_header__ is not None: + svc_hdr = service.__in_header__ + in_header = svc_hdr if isinstance(svc_hdr, tuple) else (svc_hdr,) + + if in_header is not None: + if len(in_header) > 1: + in_header_message_name = "".join( + (method.name, _in_header_msg_suffix) + ) else: - in_header_message_name = method.in_header[0].get_type_name() - self._add_message_for_object(root, messages, - method.in_header, in_header_message_name) - - if method.out_header is not None: - if len(method.out_header) > 1: - out_header_message_name = ''.join((method.name, - _out_header_msg_suffix)) + in_header_message_name = in_header[0].get_type_name() + self._add_message_for_object( + root, messages, in_header, in_header_message_name + ) + + out_header = method.out_header + if out_header is None and service.__out_header__ is not None: + svc_hdr = service.__out_header__ + out_header = svc_hdr if isinstance(svc_hdr, tuple) else (svc_hdr,) + + if out_header is not None: + if len(out_header) > 1: + out_header_message_name = "".join( + (method.name, _out_header_msg_suffix) + ) else: - out_header_message_name = method.out_header[0].get_type_name() - self._add_message_for_object(root, messages, - method.out_header, out_header_message_name) + out_header_message_name = out_header[0].get_type_name() + self._add_message_for_object( + root, messages, out_header, out_header_message_name + ) for fault in method.faults: - self._add_message_for_object(root, messages, fault, - fault.get_type_name()) + self._add_message_for_object( + root, messages, fault, fault.get_type_name() + ) - def add_bindings_for_methods(self, service, root, service_name, - cb_binding): + def add_bindings_for_methods(self, service, root, service_name, cb_binding): pref_tns = self.interface.get_namespace_prefix(self.interface.get_tns()) input_binding_ns = ns.get_binding_ns(self.interface.app.in_protocol.type) @@ -385,18 +419,18 @@ def add_bindings_for_methods(self, service, root, service_name, def inner(method, binding): operation = etree.Element(WSDL11("operation")) - operation.set('name', method.operation_name) + operation.set("name", method.operation_name) soap_operation = SubElement(operation, input_binding_ns("operation")) - soap_operation.set('soapAction', method.operation_name) - soap_operation.set('style', 'document') + soap_operation.set("soapAction", method.operation_name) + soap_operation.set("style", "document") # get input input = SubElement(operation, WSDL11("input")) - input.set('name', method.in_message.get_element_name()) + input.set("name", method.in_message.get_element_name()) soap_body = SubElement(input, input_binding_ns("body")) - soap_body.set('use', 'literal') + soap_body.set("use", "literal") # get input soap header in_header = method.in_header @@ -410,25 +444,31 @@ def inner(method, binding): in_headers = (in_header,) if len(in_headers) > 1: - in_header_message_name = ''.join((method.name, - _in_header_msg_suffix)) + in_header_message_name = "".join( + (method.name, _in_header_msg_suffix) + ) else: in_header_message_name = in_headers[0].get_type_name() for header in in_headers: - soap_header = SubElement(input, input_binding_ns('header')) - soap_header.set('use', 'literal') - soap_header.set('message', '%s:%s' % ( - header.get_namespace_prefix(self.interface), - in_header_message_name)) - soap_header.set('part', header.get_type_name()) + soap_header = SubElement(input, input_binding_ns("header")) + soap_header.set("use", "literal") + soap_header.set( + "message", + "%s:%s" + % ( + header.get_namespace_prefix(self.interface), + in_header_message_name, + ), + ) + soap_header.set("part", header.get_type_name()) if not (method.is_async or method.is_callback): output = SubElement(operation, WSDL11("output")) - output.set('name', method.out_message.get_element_name()) + output.set("name", method.out_message.get_element_name()) soap_body = SubElement(output, output_binding_ns("body")) - soap_body.set('use', 'literal') + soap_body.set("use", "literal") # get output soap header out_header = method.out_header @@ -442,48 +482,54 @@ def inner(method, binding): out_headers = (out_header,) if len(out_headers) > 1: - out_header_message_name = ''.join((method.name, - _out_header_msg_suffix)) + out_header_message_name = "".join( + (method.name, _out_header_msg_suffix) + ) else: out_header_message_name = out_headers[0].get_type_name() for header in out_headers: soap_header = SubElement(output, output_binding_ns("header")) - soap_header.set('use', 'literal') - soap_header.set('message', '%s:%s' % ( + soap_header.set("use", "literal") + soap_header.set( + "message", + "%s:%s" + % ( header.get_namespace_prefix(self.interface), - out_header_message_name)) - soap_header.set('part', header.get_type_name()) + out_header_message_name, + ), + ) + soap_header.set("part", header.get_type_name()) if not (method.faults is None): for f in method.faults: wsdl_fault = SubElement(operation, WSDL11("fault")) - wsdl_fault.set('name', f.get_type_name()) + wsdl_fault.set("name", f.get_type_name()) soap_fault = SubElement(wsdl_fault, input_binding_ns("fault")) - soap_fault.set('name', f.get_type_name()) - soap_fault.set('use', 'literal') + soap_fault.set("name", f.get_type_name()) + soap_fault.set("use", "literal") if method.is_callback: relates_to = SubElement(input, input_binding_ns("header")) - relates_to.set('message', '%s:RelatesToHeader' % pref_tns) - relates_to.set('part', 'RelatesTo') - relates_to.set('use', 'literal') + relates_to.set("message", "%s:RelatesToHeader" % pref_tns) + relates_to.set("part", "RelatesTo") + relates_to.set("use", "literal") cb_binding.append(operation) else: if method.is_async: rt_header = SubElement(input, input_binding_ns("header")) - rt_header.set('message', '%s:ReplyToHeader' % pref_tns) - rt_header.set('part', 'ReplyTo') - rt_header.set('use', 'literal') + rt_header.set("message", "%s:ReplyToHeader" % pref_tns) + rt_header.set("part", "ReplyTo") + rt_header.set("use", "literal") mid_header = SubElement(input, input_binding_ns("header")) - mid_header.set('message', '%s:MessageIDHeader' % pref_tns) - mid_header.set('part', 'MessageID') - mid_header.set('use', 'literal') + mid_header.set("message", "%s:MessageIDHeader" % pref_tns) + mid_header.set("part", "MessageID") + mid_header.set("use", "literal") binding.append(operation) @@ -493,12 +539,12 @@ def inner(method, binding): # create binding nodes binding = SubElement(root, WSDL11("binding")) - binding.set('name', self._get_binding_name(port_type_name)) - binding.set('type', '%s:%s'% (pref_tns, port_type_name)) + binding.set("name", self._get_binding_name(port_type_name)) + binding.set("type", "%s:%s" % (pref_tns, port_type_name)) transport = SubElement(binding, input_binding_ns("binding")) - transport.set('style', 'document') - transport.set('transport', self.interface.app.transport) + transport.set("style", "document") + transport.set("transport", self.interface.app.transport) for m in service.public_methods.values(): if m.port_type == port_type_name: @@ -508,12 +554,12 @@ def inner(method, binding): # here is the default port. if cb_binding is None: cb_binding = SubElement(root, WSDL11("binding")) - cb_binding.set('name', service_name) - cb_binding.set('type', '%s:%s'% (pref_tns, service_name)) + cb_binding.set("name", service_name) + cb_binding.set("type", "%s:%s" % (pref_tns, service_name)) transport = SubElement(cb_binding, input_binding_ns("binding")) - transport.set('style', 'document') - transport.set('transport', self.interface.app.transport) + transport.set("style", "document") + transport.set("transport", self.interface.app.transport) for m in service.public_methods.values(): inner(m, cb_binding) @@ -523,7 +569,7 @@ def inner(method, binding): # FIXME: I don't think this is working. def _add_callbacks(self, service, root, types, service_name, url): ns_tns = self.interface.get_tns() - pref_tns = 'tns' + pref_tns = "tns" input_binding_ns = ns.get_binding_ns(self.interface.app.in_protocol.type) cb_port_type = None @@ -533,7 +579,7 @@ def _add_callbacks(self, service, root, types, service_name, url): # callback porttype if service._has_callbacks(): wsa_schema = SubElement(types, XSD("schema")) - wsa_schema.set("targetNamespace", '%sCallback' % ns_tns) + wsa_schema.set("targetNamespace", "%sCallback" % ns_tns) wsa_schema.set("elementFormDefault", "qualified") import_ = SubElement(wsa_schema, XSD("import")) @@ -541,37 +587,37 @@ def _add_callbacks(self, service, root, types, service_name, url): import_.set("schemaLocation", NS_WSA) relt_message = SubElement(root, WSDL11("message")) - relt_message.set('name', 'RelatesToHeader') + relt_message.set("name", "RelatesToHeader") relt_part = SubElement(relt_message, WSDL11("part")) - relt_part.set('name', 'RelatesTo') - relt_part.set('element', '%s:RelatesTo' % PREF_WSA) + relt_part.set("name", "RelatesTo") + relt_part.set("element", "%s:RelatesTo" % PREF_WSA) reply_message = SubElement(root, WSDL11("message")) - reply_message.set('name', 'ReplyToHeader') + reply_message.set("name", "ReplyToHeader") reply_part = SubElement(reply_message, WSDL11("part")) - reply_part.set('name', 'ReplyTo') - reply_part.set('element', '%s:ReplyTo' % PREF_WSA) + reply_part.set("name", "ReplyTo") + reply_part.set("element", "%s:ReplyTo" % PREF_WSA) id_header = SubElement(root, WSDL11("message")) - id_header.set('name', 'MessageIDHeader') + id_header.set("name", "MessageIDHeader") id_part = SubElement(id_header, WSDL11("part")) - id_part.set('name', 'MessageID') - id_part.set('element', '%s:MessageID' % PREF_WSA) + id_part.set("name", "MessageID") + id_part.set("element", "%s:MessageID" % PREF_WSA) # make portTypes cb_port_type = SubElement(root, WSDL11("portType")) - cb_port_type.set('name', '%sCallback' % service_name) + cb_port_type.set("name", "%sCallback" % service_name) - cb_service_name = '%sCallback' % service_name + cb_service_name = "%sCallback" % service_name cb_service = SubElement(root, WSDL11("service")) - cb_service.set('name', cb_service_name) + cb_service.set("name", cb_service_name) cb_wsdl_port = SubElement(cb_service, WSDL11("port")) - cb_wsdl_port.set('name', cb_service_name) - cb_wsdl_port.set('binding', '%s:%s' % (pref_tns, cb_service_name)) + cb_wsdl_port.set("name", cb_service_name) + cb_wsdl_port.set("binding", "%s:%s" % (pref_tns, cb_service_name)) cb_address = SubElement(cb_wsdl_port, input_binding_ns("address")) - cb_address.set('location', url) + cb_address.set("location", url) return cb_port_type diff --git a/spyne/interface/xml_schema/__init__.py b/spyne/interface/xml_schema/__init__.py index 3e157f54c..7ea7a3e2d 100644 --- a/spyne/interface/xml_schema/__init__.py +++ b/spyne/interface/xml_schema/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # diff --git a/spyne/interface/xml_schema/_base.py b/spyne/interface/xml_schema/_base.py index 4c45a85af..178283d4a 100644 --- a/spyne/interface/xml_schema/_base.py +++ b/spyne/interface/xml_schema/_base.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,55 +17,66 @@ # import logging -logger = logging.getLogger('.'.join(__name__.split(".")[:-1])) + +logger = logging.getLogger(".".join(__name__.split(".")[:-1])) import os import shutil import tempfile - -import spyne.const.xml as ns +from itertools import chain from lxml import etree -from itertools import chain +import spyne.const.xml as ns +from spyne.interface import InterfaceDocumentBase +from spyne.interface.xml_schema.model import ( + Tget_range_restriction_tag, + byte_array_add, + complex_add, + enum_add, + fault_add, + simple_add, + simple_get_restriction_tag, + unicode_get_restriction_tag, +) +from spyne.model import ( + ByteArray, + ComplexModelBase, + Date, + DateTime, + Decimal, + Fault, + SimpleModel, + Time, + Unicode, +) +from spyne.model.enum import EnumBase from spyne.util.cdict import cdict from spyne.util.odict import odict from spyne.util.toposort import toposort2 -from spyne.model import SimpleModel, ByteArray, ComplexModelBase, Fault, \ - Decimal, DateTime, Date, Time, Unicode -from spyne.model.enum import EnumBase -from spyne.interface import InterfaceDocumentBase - -from spyne.interface.xml_schema.model import byte_array_add -from spyne.interface.xml_schema.model import simple_add -from spyne.interface.xml_schema.model import complex_add -from spyne.interface.xml_schema.model import fault_add -from spyne.interface.xml_schema.model import enum_add - -from spyne.interface.xml_schema.model import simple_get_restriction_tag -from spyne.interface.xml_schema.model import unicode_get_restriction_tag -from spyne.interface.xml_schema.model import Tget_range_restriction_tag - - -_add_handlers = cdict({ - object: lambda interface, cls, tags: None, - ByteArray: byte_array_add, - SimpleModel: simple_add, - ComplexModelBase: complex_add, - Fault: fault_add, - EnumBase: enum_add, -}) - -_get_restriction_tag_handlers = cdict({ - object: lambda self, cls: None, - SimpleModel: simple_get_restriction_tag, - Unicode: unicode_get_restriction_tag, - Decimal: Tget_range_restriction_tag(Decimal), - DateTime: Tget_range_restriction_tag(DateTime), - Time: Tget_range_restriction_tag(Time), - Date: Tget_range_restriction_tag(Date), -}) +_add_handlers = cdict( + { + object: lambda interface, cls, tags: None, + ByteArray: byte_array_add, + SimpleModel: simple_add, + ComplexModelBase: complex_add, + Fault: fault_add, + EnumBase: enum_add, + } +) + +_get_restriction_tag_handlers = cdict( + { + object: lambda self, cls: None, + SimpleModel: simple_get_restriction_tag, + Unicode: unicode_get_restriction_tag, + Decimal: Tget_range_restriction_tag(Decimal), + DateTime: Tget_range_restriction_tag(DateTime), + Time: Tget_range_restriction_tag(Time), + Date: Tget_range_restriction_tag(Date), + } +) _ns_xsd = ns.NS_XSD _ns_wsa = ns.NS_WSA @@ -103,11 +113,11 @@ class XmlSchema(InterfaceDocumentBase): class. """ - def __init__(self, interface, element_form_default='qualified'): + def __init__(self, interface, element_form_default="qualified"): super(XmlSchema, self).__init__(interface) self.element_form_default = element_form_default - assert element_form_default in ('qualified', 'unqualified') + assert element_form_default in ("qualified", "unqualified") self.schema_dict = {} self.validation_schema = None @@ -139,18 +149,17 @@ def build_schema_nodes(self, with_schema_location=False): schema = self.get_schema_node(pref) # append import tags - for namespace in self.interface.imports[self.interface.nsmap[pref]]: - import_ = etree.SubElement(schema, ns.XSD('import')) + for namespace in self.interface.imports.get(self.interface.nsmap[pref], []): + import_ = etree.SubElement(schema, ns.XSD("import")) import_.set("namespace", namespace) import_pref = self.interface.get_namespace_prefix(namespace) - if with_schema_location and \ - self.namespaces.get(import_pref, False): - import_.set('schemaLocation', "%s.xsd" % import_pref) + if with_schema_location and self.namespaces.get(import_pref, False): + import_.set("schemaLocation", "%s.xsd" % import_pref) sl = ns.schema_location.get(namespace, None) if not (sl is None): - import_.set('schemaLocation', sl) + import_.set("schemaLocation", sl) # append simpleType and complexType tags for node in self.namespaces[pref].types.values(): @@ -162,8 +171,8 @@ def build_schema_nodes(self, with_schema_location=False): self.add_missing_elements_for_methods() - self.event_manager.fire_event('document_built', self) - self.event_manager.fire_event('xml_document_built', self) + self.event_manager.fire_event("document_built", self) + self.event_manager.fire_event("xml_document_built", self) def add_missing_elements_for_methods(self): def missing_methods(): @@ -182,10 +191,9 @@ def missing_methods(): name = method.in_message.get_type_name() if not name in elements: - element = etree.Element(ns.XSD('element')) - element.set('name', name) - element.set('type', method.in_message.get_type_name_ns( - self.interface)) + element = etree.Element(ns.XSD("element")) + element.set("name", name) + element.set("type", method.in_message.get_type_name_ns(self.interface)) elements[name] = element schema_root.append(element) @@ -194,10 +202,11 @@ def missing_methods(): if name is None: name = method.out_message.get_type_name() if not name in elements: - element = etree.Element(ns.XSD('element')) - element.set('name', name) - element.set('type', method.out_message \ - .get_type_name_ns(self.interface)) + element = etree.Element(ns.XSD("element")) + element.set("name", name) + element.set( + "type", method.out_message.get_type_name_ns(self.interface) + ) elements[name] = element schema_root.append(element) @@ -207,30 +216,35 @@ def build_validation_schema(self): self.build_schema_nodes(with_schema_location=True) pref_tns = self.interface.get_namespace_prefix(self.interface.tns) - tmp_dir_name = tempfile.mkdtemp(prefix='spyne') - logger.debug("generating schema for targetNamespace=%r, prefix: " - "%r in dir %r" % (self.interface.tns, pref_tns, tmp_dir_name)) + tmp_dir_name = tempfile.mkdtemp(prefix="spyne") + logger.debug( + "generating schema for targetNamespace=%r, prefix: " + "%r in dir %r" % (self.interface.tns, pref_tns, tmp_dir_name) + ) try: # serialize nodes to files for k, v in self.schema_dict.items(): file_name = os.path.join(tmp_dir_name, "%s.xsd" % k) - with open(file_name, 'wb') as f: + with open(file_name, "wb") as f: etree.ElementTree(v).write(f, pretty_print=True) - logger.debug("writing %r for ns %s" % - (file_name, self.interface.nsmap[k])) + logger.debug( + "writing %r for ns %s" % (file_name, self.interface.nsmap[k]) + ) - with open(os.path.join(tmp_dir_name, "%s.xsd" % pref_tns), 'r') as f: + with open(os.path.join(tmp_dir_name, "%s.xsd" % pref_tns), "r") as f: try: self.validation_schema = etree.XMLSchema(etree.parse(f)) except Exception: f.seek(0) - logger.error("This could be a Spyne error. Unless you're " - "sure the reason for this error is outside " - "Spyne, please open a new issue with a " - "minimal test case that reproduces it.") + logger.error( + "This could be a Spyne error. Unless you're " + "sure the reason for this error is outside " + "Spyne, please open a new issue with a " + "minimal test case that reproduces it." + ) raise shutil.rmtree(tmp_dir_name) @@ -245,8 +259,7 @@ def get_schema_node(self, pref): """Return schema node for the given namespace prefix.""" if not (pref in self.schema_dict): - schema = etree.Element(ns.XSD('schema'), - nsmap=self.interface.nsmap) + schema = etree.Element(ns.XSD("schema"), nsmap=self.interface.nsmap) schema.set("targetNamespace", self.interface.nsmap[pref]) schema.set("elementFormDefault", self.element_form_default) diff --git a/spyne/interface/xml_schema/defn.py b/spyne/interface/xml_schema/defn.py index a22fb7c54..f2cec17e4 100644 --- a/spyne/interface/xml_schema/defn.py +++ b/spyne/interface/xml_schema/defn.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -17,19 +16,12 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # -from spyne.util.six import add_metaclass - from spyne.const import xml -from spyne.model.primitive import Boolean, AnyHtml -from spyne.model.primitive import Unicode -from spyne.model.primitive import UnsignedInteger -from spyne.model.complex import XmlAttribute -from spyne.model.complex import ComplexModelBase -from spyne.model.complex import ComplexModelMeta +from spyne.model.complex import ComplexModelBase, ComplexModelMeta, XmlAttribute +from spyne.model.primitive import AnyHtml, Boolean, Unicode, UnsignedInteger -@add_metaclass(ComplexModelMeta) -class SchemaBase(ComplexModelBase): +class SchemaBase(ComplexModelBase, metaclass=ComplexModelMeta): __namespace__ = xml.NS_XSD @@ -59,39 +51,42 @@ class StringAttribute(SchemaBase): class List(SchemaBase): _type_info = [ - ('item_type', XmlAttribute(Unicode(sub_name='itemType'))), + ("item_type", XmlAttribute(Unicode(sub_name="itemType"))), ] class SimpleType(SchemaBase): _type_info = [ - ('name', XmlAttribute(Unicode)), - ('list', List), - ('union', Unicode), + ("name", XmlAttribute(Unicode)), + ("list", List), + ("union", Unicode), ] class Attribute(SchemaBase): - use = XmlAttribute(Unicode) - ref = XmlAttribute(Unicode) - name = XmlAttribute(Unicode) - type = XmlAttribute(Unicode) - default = XmlAttribute(Unicode) - simple_type = SimpleType.customize(sub_name='simpleType') + use = XmlAttribute(Unicode) + ref = XmlAttribute(Unicode) + name = XmlAttribute(Unicode) + type = XmlAttribute(Unicode) + default = XmlAttribute(Unicode) + simple_type = SimpleType.customize(sub_name="simpleType") class Restriction(SchemaBase): _type_info = [ - ('base', XmlAttribute(Unicode)), - ('max_length', IntegerAttribute.customize(sub_name="maxLength")), - ('min_length', IntegerAttribute.customize(sub_name="minLength")), - ('pattern', StringAttribute), - ('enumeration', StringAttribute.customize(max_occurs="unbounded")), - ('attributes', Attribute.customize(max_occurs="unbounded", - sub_name="attribute")), + ("base", XmlAttribute(Unicode)), + ("max_length", IntegerAttribute.customize(sub_name="maxLength")), + ("min_length", IntegerAttribute.customize(sub_name="minLength")), + ("pattern", StringAttribute), + ("enumeration", StringAttribute.customize(max_occurs="unbounded")), + ( + "attributes", + Attribute.customize(max_occurs="unbounded", sub_name="attribute"), + ), ] -SimpleType.append_field('restriction', Restriction) + +SimpleType.append_field("restriction", Restriction) class Choice(SchemaBase): @@ -105,8 +100,7 @@ class Sequence(SchemaBase): class Extension(SchemaBase): base = XmlAttribute(Unicode) - attributes = Attribute.customize(max_occurs="unbounded", - sub_name="attribute") + attributes = Attribute.customize(max_occurs="unbounded", sub_name="attribute") class SimpleContent(SchemaBase): @@ -118,8 +112,7 @@ class ComplexType(SchemaBase): name = XmlAttribute(Unicode) sequence = Sequence simple_content = SimpleContent.customize(sub_name="simpleContent") - attributes = Attribute.customize(max_occurs="unbounded", - sub_name="attribute") + attributes = Attribute.customize(max_occurs="unbounded", sub_name="attribute") choice = Choice @@ -129,60 +122,69 @@ class Include(SchemaBase): class XmlSchema10(SchemaBase): _type_info = [ - ('target_namespace', XmlAttribute(Unicode(sub_name="targetNamespace"))), - ('element_form_default', XmlAttribute(Unicode( - sub_name="elementFormDefault"))), - - ('imports', Import.customize(max_occurs="unbounded", - sub_name="import")), - ('includes', Include.customize(max_occurs="unbounded", - sub_name="include")), - ('elements', Element.customize(max_occurs="unbounded", - sub_name="element")), - ('simple_types', SimpleType.customize(max_occurs="unbounded", - sub_name="simpleType")), - ('complex_types', ComplexType.customize(max_occurs="unbounded", - sub_name="complexType")), - ('attributes', Attribute.customize(max_occurs="unbounded", - sub_name="attribute")), + ("target_namespace", XmlAttribute(Unicode(sub_name="targetNamespace"))), + ("element_form_default", XmlAttribute(Unicode(sub_name="elementFormDefault"))), + ("imports", Import.customize(max_occurs="unbounded", sub_name="import")), + ("includes", Include.customize(max_occurs="unbounded", sub_name="include")), + ("elements", Element.customize(max_occurs="unbounded", sub_name="element")), + ( + "simple_types", + SimpleType.customize(max_occurs="unbounded", sub_name="simpleType"), + ), + ( + "complex_types", + ComplexType.customize(max_occurs="unbounded", sub_name="complexType"), + ), + ( + "attributes", + Attribute.customize(max_occurs="unbounded", sub_name="attribute"), + ), ] -from itertools import chain from inspect import isclass +from itertools import chain -from spyne.model import ModelBase -from spyne.model import primitive -from spyne.model import binary +from spyne.model import ModelBase, binary, primitive from spyne.model.fault import Fault - -TYPE_MAP = dict([ - ("{%s}%s" % (cls.get_namespace(), cls.get_type_name()), cls) for cls in - chain( - [v for v in vars(primitive).values() - if getattr(v, '__type_name__', None) is not None], +TYPE_MAP = dict( + [ + ("{%s}%s" % (cls.get_namespace(), cls.get_type_name()), cls) + for cls in chain( + [ + v + for v in vars(primitive).values() + if getattr(v, "__type_name__", None) is not None + ], [ - binary.ByteArray(encoding='base64'), - binary.ByteArray(encoding='hex'), + binary.ByteArray(encoding="base64"), + binary.ByteArray(encoding="hex"), ], [ - primitive.Point(2), primitive.Point(3), - primitive.Line(2), primitive.Line(3), - primitive.Polygon(2), primitive.Polygon(3), - primitive.MultiPoint(2), primitive.MultiPoint(3), - primitive.MultiLine(2), primitive.MultiLine(3), - primitive.MultiPolygon(2), primitive.MultiPolygon(3), - ] + primitive.Point(2), + primitive.Point(3), + primitive.Line(2), + primitive.Line(3), + primitive.Polygon(2), + primitive.Polygon(3), + primitive.MultiPoint(2), + primitive.MultiPoint(3), + primitive.MultiLine(2), + primitive.MultiLine(3), + primitive.MultiPolygon(2), + primitive.MultiPolygon(3), + ], ) - if isclass(cls) - and issubclass(cls, ModelBase) - and not issubclass(cls, (Fault, AnyHtml)) - and not cls in (ModelBase,) -]) + and issubclass(cls, ModelBase) + and not issubclass(cls, (Fault, AnyHtml)) + and not cls in (ModelBase,) + ] +) -if __name__ == '__main__': +if __name__ == "__main__": from pprint import pprint + pprint(TYPE_MAP) diff --git a/spyne/interface/xml_schema/genpy.py b/spyne/interface/xml_schema/genpy.py index 21784f8dd..d1a4f1561 100644 --- a/spyne/interface/xml_schema/genpy.py +++ b/spyne/interface/xml_schema/genpy.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -26,28 +25,28 @@ """ import logging -logger = logging.getLogger(__name__) -import spyne +logger = logging.getLogger(__name__) +from collections import defaultdict from datetime import datetime from itertools import chain -from collections import defaultdict +import spyne from spyne.model import SimpleModel -from spyne.model.complex import XmlModifier -from spyne.model.complex import ComplexModelBase +from spyne.model.complex import ComplexModelBase, XmlModifier def gen_fn_from_tns(tns): - return tns \ - .replace('http://', '') \ - .replace('https://', '') \ - .replace('/', '') \ - .replace('.', '_') \ - .replace(':', '_') \ - .replace('#', '') \ - .replace('-', '_') + return ( + tns.replace("http://", "") + .replace("https://", "") + .replace("/", "") + .replace(".", "_") + .replace(":", "_") + .replace("#", "") + .replace("-", "_") + ) class CodeGenerator(object): @@ -59,7 +58,7 @@ def __init__(self, fn_tns_mapper=gen_fn_from_tns): self.fn_tns_mapper = fn_tns_mapper def gen_modifier(self, t): - return '%s(%s)' % (t.__name__, self.gen_dispatch(t.type)) + return "%s(%s)" % (t.__name__, self.gen_dispatch(t.type)) def gen_simple(self, t): return t.__name__ @@ -71,11 +70,13 @@ def gen_complex(self, t): class %s(_ComplexBase): _type_info = [""" % (t.get_type_name())) - for k,v in t._type_info.items(): - if not issubclass(v, ComplexModelBase) or \ - v.get_namespace() != self.tns or \ - v in self.classes or \ - getattr(v, '__orig__', None) in self.classes: + for k, v in t._type_info.items(): + if ( + not issubclass(v, ComplexModelBase) + or v.get_namespace() != self.tns + or v in self.classes + or getattr(v, "__orig__", None) in self.classes + ): retval.append(" ('%s', %s)," % (k, self.gen_dispatch(v))) else: self.pending[v.get_type_name()].append((k, t.get_type_name())) @@ -84,7 +85,7 @@ class %s(_ComplexBase): self.classes.add(t) - for k,orig_t in self.pending[t.get_type_name()]: + for k, orig_t in self.pending[t.get_type_name()]: retval.append('%s._type_info["%s"] = %s' % (orig_t, k, t.get_type_name())) return retval @@ -106,26 +107,27 @@ def gen_dispatch(self, t): def genpy(self, tns, s): self.tns = tns - retval = [u"""# encoding: utf8 + retval = [ + """# encoding: utf8 # Automatically generated by Spyne %s at %s. # Modify at your own risk. from spyne.model import * -""" % (spyne.__version__, datetime.now().replace(microsecond=0).isoformat(' ')), -"", # imports -""" +""" % (spyne.__version__, datetime.now().replace(microsecond=0).isoformat(" ")), + "", # imports + """ class _ComplexBase(ComplexModelBase): __namespace__ = '%s' - __metaclass__ = ComplexModelMeta""" % tns -] + __metaclass__ = ComplexModelMeta""" % tns, + ] for n, t in s.types.items(): if issubclass(t, ComplexModelBase): retval.extend(self.gen_complex(t)) else: - retval.append('%s = %s' % (n, self.gen_dispatch(t))) + retval.append("%s = %s" % (n, self.gen_dispatch(t))) self.simples.add(n) for i in self.imports: @@ -134,11 +136,10 @@ class _ComplexBase(ComplexModelBase): retval.append("") retval.append("") - retval.append('__all__ = [') - for c in sorted(chain([c.get_type_name() for c in self.classes], - self.simples)): - retval.append(" '%s'," % c) - retval.append(']') + retval.append("__all__ = [") + for c in sorted(chain([c.get_type_name() for c in self.classes], self.simples)): + retval.append(" '%s'," % c) + retval.append("]") retval.append("") - return '\n'.join(retval) + return "\n".join(retval) diff --git a/spyne/interface/xml_schema/model.py b/spyne/interface/xml_schema/model.py index 6b491baab..d50023c39 100644 --- a/spyne/interface/xml_schema/model.py +++ b/spyne/interface/xml_schema/model.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -20,23 +19,30 @@ """The ``spyne.interface.xml_schema.model`` module contains type-specific logic for schema generation.""" - import logging + logger = logging.getLogger(__name__) +from collections import defaultdict, deque from decimal import Decimal as D -from collections import deque, defaultdict from lxml import etree -from spyne.model import ModelBase, XmlAttribute, AnyXml, Unicode, XmlData, \ - Decimal, Integer from spyne.const.xml import NS_XSD, XSD +from spyne.model import ( + AnyXml, + Decimal, + Integer, + ModelBase, + Unicode, + XmlAttribute, + XmlData, +) +from spyne.protocol.xml import XmlDocument from spyne.util import memoize from spyne.util.cdict import cdict from spyne.util.etreeconv import dict_to_etree -from spyne.util.six import string_types -from spyne.protocol.xml import XmlDocument + _prot = XmlDocument() # In Xml Schema, some customizations do not need a class to be extended -- they @@ -44,25 +50,38 @@ # min_occurs. The dict below contains list of parameters that do warrant a # proper subclass definition for each type. This must be updated as the Xml # Schema implementation makes progress. -ATTR_NAMES = cdict({ - ModelBase: set(['values']), - Decimal: set(['pattern', 'gt', 'ge', 'lt', 'le', 'values', 'total_digits', - 'fraction_digits']), - Integer: set(['pattern', 'gt', 'ge', 'lt', 'le', 'values', 'total_digits']), - Unicode: set(['values', 'min_len', 'max_len', 'pattern']), -}) +ATTR_NAMES = cdict( + { + ModelBase: set(["values"]), + Decimal: set( + [ + "pattern", + "gt", + "ge", + "lt", + "le", + "values", + "total_digits", + "fraction_digits", + ] + ), + Integer: set(["pattern", "gt", "ge", "lt", "le", "values", "total_digits"]), + Unicode: set(["values", "min_len", "max_len", "pattern"]), + } +) + def xml_attribute_add(cls, name, element, document): - element.set('name', name) - element.set('type', cls.type.get_type_name_ns(document.interface)) + element.set("name", name) + element.set("type", cls.type.get_type_name_ns(document.interface)) if cls._use is not None: - element.set('use', cls._use) + element.set("use", cls._use) d = cls.type.Attributes.default if d is not None: - element.set('default', _prot.to_unicode(cls.type, d)) + element.set("default", _prot.to_unicode(cls.type, d)) def _check_extension_attrs(cls): @@ -73,12 +92,12 @@ def _check_extension_attrs(cls): eattrs = extends.Attributes cattrs = cls.Attributes - ckeys = set([k for k in vars(cls.Attributes) if not k.startswith('_')]) - ekeys = set([k for k in vars(extends.Attributes) if not k.startswith('_')]) + ckeys = set([k for k in vars(cls.Attributes) if not k.startswith("_")]) + ekeys = set([k for k in vars(extends.Attributes) if not k.startswith("_")]) # get the attributes different from the parent class diff = set() - for k in (ckeys | ekeys): + for k in ckeys | ekeys: if getattr(eattrs, k, None) != getattr(cattrs, k, None): diff.add(k) @@ -93,23 +112,24 @@ def _check_extension_attrs(cls): return retval + # noinspection PyDefaultArgument def simple_get_restriction_tag(document, cls): extends = _check_extension_attrs(cls) if extends is None: return - simple_type = etree.Element(XSD('simpleType')) + simple_type = etree.Element(XSD("simpleType")) - simple_type.set('name', cls.get_type_name()) + simple_type.set("name", cls.get_type_name()) document.add_simple_type(cls, simple_type) - restriction = etree.SubElement(simple_type, XSD('restriction')) - restriction.set('base', extends.get_type_name_ns(document.interface)) + restriction = etree.SubElement(simple_type, XSD("restriction")) + restriction.set("base", extends.get_type_name_ns(document.interface)) for v in cls.Attributes.values: - enumeration = etree.SubElement(restriction, XSD('enumeration')) - enumeration.set('value', XmlDocument().to_unicode(cls, v)) + enumeration = etree.SubElement(restriction, XSD("enumeration")) + enumeration.set("value", XmlDocument().to_unicode(cls, v)) return restriction @@ -118,28 +138,29 @@ def simple_add(document, cls, tags): if not cls.is_default(cls): document.get_restriction_tag(cls) + def byte_array_add(document, cls, tags): simple_add(document, cls, tags) def complex_add(document, cls, tags): - complex_type = etree.Element(XSD('complexType')) - complex_type.set('name', cls.get_type_name()) + complex_type = etree.Element(XSD("complexType")) + complex_type.set("name", cls.get_type_name()) doc_text = cls.get_documentation() if doc_text or cls.Annotations.appinfo is not None: - annotation = etree.SubElement(complex_type, XSD('annotation')) + annotation = etree.SubElement(complex_type, XSD("annotation")) if doc_text: - doc = etree.SubElement(annotation, XSD('documentation')) + doc = etree.SubElement(annotation, XSD("documentation")) doc.text = doc_text _ai = cls.Annotations.appinfo if _ai is not None: - appinfo = etree.SubElement(annotation, XSD('appinfo')) + appinfo = etree.SubElement(annotation, XSD("appinfo")) if isinstance(_ai, dict): dict_to_etree(_ai, appinfo) - elif isinstance(_ai, string_types): + elif isinstance(_ai, str): appinfo.text = _ai elif isinstance(_ai, etree._Element): @@ -151,14 +172,18 @@ def complex_add(document, cls, tags): appinfo.append(get_object_as_xml(_ai)) sequence_parent = complex_type - extends = getattr(cls, '__extends__', None) + extends = getattr(cls, "__extends__", None) type_info = cls._type_info if extends is not None: - if (extends.get_type_name() == cls.get_type_name() and - extends.get_namespace() == cls.get_namespace()): - raise Exception("%r can't extend %r because they are both '{%s}%s'" - % (cls, extends, cls.get_namespace(), cls.get_type_name())) + if ( + extends.get_type_name() == cls.get_type_name() + and extends.get_namespace() == cls.get_namespace() + ): + raise Exception( + "%r can't extend %r because they are both '{%s}%s'" + % (cls, extends, cls.get_namespace(), cls.get_type_name()) + ) if extends.Attributes.exc_interface: # If the parent class is private, it won't be in the schema, so we @@ -166,26 +191,26 @@ def complex_add(document, cls, tags): type_info = cls.get_simple_type_info(cls) else: - complex_content = etree.SubElement(complex_type, - XSD('complexContent')) - extension = etree.SubElement(complex_content, XSD('extension')) - extension.set('base', extends.get_type_name_ns(document.interface)) + complex_content = etree.SubElement(complex_type, XSD("complexContent")) + extension = etree.SubElement(complex_content, XSD("extension")) + extension.set("base", extends.get_type_name_ns(document.interface)) sequence_parent = extension if cls.Attributes._xml_tag_body_as is not None: for xtba_key, xtba_type in cls.Attributes._xml_tag_body_as: - _sc = etree.SubElement(sequence_parent, XSD('simpleContent')) - xtba_ext = etree.SubElement(_sc, XSD('extension')) - xtba_ext.attrib['base'] = xtba_type.type.get_type_name_ns( - document.interface) + _sc = etree.SubElement(sequence_parent, XSD("simpleContent")) + xtba_ext = etree.SubElement(_sc, XSD("extension")) + xtba_ext.attrib["base"] = xtba_type.type.get_type_name_ns( + document.interface + ) - sequence = etree.Element(XSD('sequence')) + sequence = etree.Element(XSD("sequence")) deferred = deque() - choice_tags = defaultdict(lambda: etree.Element(XSD('choice'))) + choice_tags = defaultdict(lambda: etree.Element(XSD("choice"))) for k, v in type_info.items(): - assert isinstance(k, string_types) + assert isinstance(k, str) assert issubclass(v, ModelBase) a = v.Attributes @@ -196,7 +221,7 @@ def complex_add(document, cls, tags): continue if issubclass(v, XmlAttribute): - deferred.append((k,v)) + deferred.append((k, v)) continue document.add(v, tags) @@ -204,53 +229,57 @@ def complex_add(document, cls, tags): name = a.sub_name if name is None: name = k - #ns = a.sub_ns - #if ns is not None: + # ns = a.sub_ns + # if ns is not None: # name = "{%s}%s" % (ns, name) type_name_ns = v.get_type_name_ns(document.interface) - if v.__extends__ is not None and v.__orig__ is not None and \ - _check_extension_attrs(v) is None: + if ( + v.__extends__ is not None + and v.__orig__ is not None + and _check_extension_attrs(v) is None + ): type_name_ns = v.__orig__.get_type_name_ns(document.interface) member = etree.Element(a.schema_tag) - if a.schema_tag == XSD('element'): - member.set('name', name) - member.set('type', type_name_ns) + if a.schema_tag == XSD("element"): + member.set("name", name) + member.set("type", type_name_ns) - elif a.schema_tag == XSD('any') and issubclass(v, AnyXml): + elif a.schema_tag == XSD("any") and issubclass(v, AnyXml): if a.namespace is not None: - member.set('namespace', a.namespace) + member.set("namespace", a.namespace) if a.process_contents is not None: - member.set('processContents', a.process_contents) + member.set("processContents", a.process_contents) else: - raise ValueError("Unhandled schema_tag / type combination. %r %r" - % (v, a.schema_tag)) + raise ValueError( + "Unhandled schema_tag / type combination. %r %r" % (v, a.schema_tag) + ) if a.min_occurs != 1: # 1 is the xml schema default - member.set('minOccurs', str(a.min_occurs)) + member.set("minOccurs", str(a.min_occurs)) if a.max_occurs != 1: # 1 is the xml schema default val = a.max_occurs - if val in (D('inf'), float('inf')): - val = 'unbounded' + if val in (D("inf"), float("inf")): + val = "unbounded" else: val = str(val) - member.set('maxOccurs', val) + member.set("maxOccurs", val) if a.default is not None: - member.set('default', _prot.to_unicode(v, a.default)) + member.set("default", _prot.to_unicode(v, a.default)) - if bool(a.nillable) != False: # False is the xml schema default - member.set('nillable', 'true') + if bool(a.nillable) != False: # False is the xml schema default + member.set("nillable", "true") v_doc_text = v.get_documentation() if v_doc_text: # Doesn't support multi-language documentation - annotation = etree.SubElement(member, XSD('annotation')) - doc = etree.SubElement(annotation, XSD('documentation')) + annotation = etree.SubElement(member, XSD("annotation")) + doc = etree.SubElement(annotation, XSD("documentation")) doc.text = v_doc_text if a.xml_choice_group is None: @@ -264,8 +293,8 @@ def complex_add(document, cls, tags): sequence_parent.append(sequence) _ext_elements = dict() - for k,v in deferred: - attribute = etree.Element(XSD('attribute')) + for k, v in deferred: + attribute = etree.Element(XSD("attribute")) xml_attribute_add(v, k, attribute, document) if cls.Attributes._xml_tag_body_as is None: @@ -277,27 +306,29 @@ def complex_add(document, cls, tags): # simple node complex_type_name = cls.Attributes.sub_name or cls.get_type_name() - element = etree.Element(XSD('element')) - element.set('name', complex_type_name) - element.set('type', cls.get_type_name_ns(document.interface)) + element = etree.Element(XSD("element")) + element.set("name", complex_type_name) + element.set("type", cls.get_type_name_ns(document.interface)) document.add_element(cls, element) def enum_add(document, cls, tags): - simple_type = etree.Element(XSD('simpleType')) - simple_type.set('name', cls.get_type_name()) + simple_type = etree.Element(XSD("simpleType")) + simple_type.set("name", cls.get_type_name()) - restriction = etree.SubElement(simple_type, XSD('restriction')) - restriction.set('base', '%s:string' % - document.interface.get_namespace_prefix(NS_XSD)) + restriction = etree.SubElement(simple_type, XSD("restriction")) + restriction.set( + "base", "%s:string" % document.interface.get_namespace_prefix(NS_XSD) + ) for v in cls.__values__: - enumeration = etree.SubElement(restriction, XSD('enumeration')) - enumeration.set('value', v) + enumeration = etree.SubElement(restriction, XSD("enumeration")) + enumeration.set("value", v) document.add_simple_type(cls, simple_type) + fault_add = complex_add @@ -308,22 +339,22 @@ def unicode_get_restriction_tag(document, cls): # length if cls.Attributes.min_len == cls.Attributes.max_len: - length = etree.SubElement(restriction, XSD('length')) - length.set('value', str(cls.Attributes.min_len)) + length = etree.SubElement(restriction, XSD("length")) + length.set("value", str(cls.Attributes.min_len)) else: if cls.Attributes.min_len != Unicode.Attributes.min_len: - min_l = etree.SubElement(restriction, XSD('minLength')) - min_l.set('value', str(cls.Attributes.min_len)) + min_l = etree.SubElement(restriction, XSD("minLength")) + min_l.set("value", str(cls.Attributes.min_len)) if cls.Attributes.max_len != Unicode.Attributes.max_len: - max_l = etree.SubElement(restriction, XSD('maxLength')) - max_l.set('value', str(cls.Attributes.max_len)) + max_l = etree.SubElement(restriction, XSD("maxLength")) + max_l.set("value", str(cls.Attributes.max_len)) # pattern if cls.Attributes.pattern != Unicode.Attributes.pattern: - pattern = etree.SubElement(restriction, XSD('pattern')) - pattern.set('value', cls.Attributes.pattern) + pattern = etree.SubElement(restriction, XSD("pattern")) + pattern.set("value", cls.Attributes.pattern) return restriction @@ -336,32 +367,33 @@ def Tget_range_restriction_tag(T): a function that generates range restriction tags. """ - from spyne.model.primitive import Decimal - from spyne.model.primitive import Integer + from spyne.model.primitive import Decimal, Integer if issubclass(T, Decimal): + def _get_float_restrictions(prot, restriction, cls): if cls.Attributes.fraction_digits != T.Attributes.fraction_digits: - elt = etree.SubElement(restriction, XSD('fractionDigits')) - elt.set('value', prot.to_unicode(cls, - cls.Attributes.fraction_digits)) + elt = etree.SubElement(restriction, XSD("fractionDigits")) + elt.set("value", prot.to_unicode(cls, cls.Attributes.fraction_digits)) def _get_integer_restrictions(prot, restriction, cls): if cls.Attributes.total_digits != T.Attributes.total_digits: - elt = etree.SubElement(restriction, XSD('totalDigits')) - elt.set('value', prot.to_unicode(cls, - cls.Attributes.total_digits)) + elt = etree.SubElement(restriction, XSD("totalDigits")) + elt.set("value", prot.to_unicode(cls, cls.Attributes.total_digits)) if issubclass(T, Integer): + def _get_additional_restrictions(prot, restriction, cls): _get_integer_restrictions(prot, restriction, cls) else: + def _get_additional_restrictions(prot, restriction, cls): _get_integer_restrictions(prot, restriction, cls) _get_float_restrictions(prot, restriction, cls) else: + def _get_additional_restrictions(prot, restriction, cls): pass @@ -371,24 +403,24 @@ def _get_range_restriction_tag(document, cls): return if cls.Attributes.gt != T.Attributes.gt: - elt = etree.SubElement(restriction, XSD('minExclusive')) - elt.set('value', prot.to_unicode(cls, cls.Attributes.gt)) + elt = etree.SubElement(restriction, XSD("minExclusive")) + elt.set("value", prot.to_unicode(cls, cls.Attributes.gt)) if cls.Attributes.ge != T.Attributes.ge: - elt = etree.SubElement(restriction, XSD('minInclusive')) - elt.set('value', prot.to_unicode(cls, cls.Attributes.ge)) + elt = etree.SubElement(restriction, XSD("minInclusive")) + elt.set("value", prot.to_unicode(cls, cls.Attributes.ge)) if cls.Attributes.lt != T.Attributes.lt: - elt = etree.SubElement(restriction, XSD('maxExclusive')) - elt.set('value', prot.to_unicode(cls, cls.Attributes.lt)) + elt = etree.SubElement(restriction, XSD("maxExclusive")) + elt.set("value", prot.to_unicode(cls, cls.Attributes.lt)) if cls.Attributes.le != T.Attributes.le: - elt = etree.SubElement(restriction, XSD('maxInclusive')) - elt.set('value', prot.to_unicode(cls, cls.Attributes.le)) + elt = etree.SubElement(restriction, XSD("maxInclusive")) + elt.set("value", prot.to_unicode(cls, cls.Attributes.le)) if cls.Attributes.pattern != T.Attributes.pattern: - elt = etree.SubElement(restriction, XSD('pattern')) - elt.set('value', cls.Attributes.pattern) + elt = etree.SubElement(restriction, XSD("pattern")) + elt.set("value", cls.Attributes.pattern) _get_additional_restrictions(prot, restriction, cls) diff --git a/spyne/interface/xml_schema/parser.py b/spyne/interface/xml_schema/parser.py index 010c912da..ce8cd0abf 100644 --- a/spyne/interface/xml_schema/parser.py +++ b/spyne/interface/xml_schema/parser.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -25,32 +24,32 @@ # import logging + logger = logging.getLogger(__name__) import os - +from collections import defaultdict from copy import copy -from pprint import pformat from itertools import chain -from collections import defaultdict -from os.path import dirname, abspath, join +from os.path import abspath, dirname, join +from pprint import pformat from lxml import etree -from spyne.util import memoize -from spyne.util.odict import odict - -from spyne.model import Null, XmlData, XmlAttribute, Array, ComplexModelBase, \ - ComplexModelMeta +from spyne.interface.xml_schema.defn import TYPE_MAP, SchemaBase, XmlSchema10 +from spyne.model import ( + Array, + ComplexModelBase, + ComplexModelMeta, + Null, + XmlAttribute, + XmlData, +) from spyne.model.complex import XmlModifier - from spyne.protocol.xml import XmlDocument - -from spyne.interface.xml_schema.defn import TYPE_MAP -from spyne.interface.xml_schema.defn import SchemaBase -from spyne.interface.xml_schema.defn import XmlSchema10 - -from spyne.util.color import R, G, B, MAG, YEL +from spyne.util import memoize +from spyne.util.color import MAG, YEL, B, G, R +from spyne.util.odict import odict PARSER = etree.XMLParser(remove_comments=True) @@ -75,23 +74,26 @@ def Thier_repr(with_ns=False): """ if with_ns is False: + def get_class_name(c): return c.get_type_name() elif with_ns is True or with_ns == 1: + def get_class_name(c): return "{%s}%s" % (c.get_namespace(), c.get_type_name()) else: + def get_class_name(c): return with_ns(c.get_namespace(), c.get_type_name()) - def hier_repr(inst, i0=0, I=' ', tags=None): + def hier_repr(inst, i0=0, I=" ", tags=None): if tags is None: tags = set() cls = inst.__class__ - if not hasattr(cls, '_type_info'): + if not hasattr(cls, "_type_info"): return repr(inst) clsid = "%s" % (get_class_name(cls)) @@ -103,7 +105,7 @@ def hier_repr(inst, i0=0, I=' ', tags=None): i1 = i0 + 1 i2 = i1 + 1 - retval = [clsid, '('] + retval = [clsid, "("] xtba = cls.Attributes._xml_tag_body_as if xtba is not None: @@ -113,32 +115,32 @@ def hier_repr(inst, i0=0, I=' ', tags=None): value = getattr(inst, xtba_key, None) retval.append("%s,\n" % hier_repr(value, i1, I, tags)) else: - retval.append('\n') + retval.append("\n") else: - retval.append('\n') + retval.append("\n") for k, v in inst.get_flat_type_info(cls).items(): value = getattr(inst, k, None) - if (issubclass(v, Array) or v.Attributes.max_occurs > 1) and \ - value is not None: + if ( + issubclass(v, Array) or v.Attributes.max_occurs > 1 + ) and value is not None: retval.append("%s%s=[\n" % (I * i1, k)) for subval in value: - retval.append("%s%s,\n" % (I * i2, - hier_repr(subval, i2, I, tags))) - retval.append('%s],\n' % (I * i1)) + retval.append("%s%s,\n" % (I * i2, hier_repr(subval, i2, I, tags))) + retval.append("%s],\n" % (I * i1)) elif issubclass(v, XmlData): pass else: - retval.append("%s%s=%s,\n" % (I * i1, k, - hier_repr(value, i1, I, tags))) + retval.append("%s%s=%s,\n" % (I * i1, k, hier_repr(value, i1, I, tags))) - retval.append('%s)' % (I * i0)) - return ''.join(retval) + retval.append("%s)" % (I * i0)) + return "".join(retval) return hier_repr + SchemaBase.__repr__ = Thier_repr() hier_repr = Thier_repr() @@ -146,8 +148,9 @@ def hier_repr(inst, i0=0, I=' ', tags=None): class XmlSchemaParser(object): - def __init__(self, files, base_dir=None, repr_=Thier_repr(with_ns=False), - skip_errors=False): + def __init__( + self, files, base_dir=None, repr_=Thier_repr(with_ns=False), skip_errors=False + ): self.retval = {} self.indent = 0 self.files = files @@ -188,7 +191,7 @@ def clone(self, indent=0, base_dir=None): return retval def debug0(self, s, *args, **kwargs): - logger.debug("%s%s" % (" " * self.indent, s), *args, **kwargs) + logger.debug("%s%s" % (" " * self.indent, s), *args, **kwargs) def debug1(self, s, *args, **kwargs): logger.debug("%s%s" % (" " * (self.indent + 1), s), *args, **kwargs) @@ -197,7 +200,7 @@ def debug2(self, s, *args, **kwargs): logger.debug("%s%s" % (" " * (self.indent + 2), s), *args, **kwargs) def parse_schema_file(self, file_name): - elt = etree.fromstring(open(file_name, 'rb').read(), parser=PARSER) + elt = etree.fromstring(open(file_name, "rb").read(), parser=PARSER) return self.parse_schema(elt) def process_includes(self, include): @@ -208,7 +211,7 @@ def process_includes(self, include): self.debug1("including %s %s", self.base_dir, file_name) file_name = abspath(join(self.base_dir, file_name)) - data = open(file_name, 'rb').read() + data = open(file_name, "rb").read() elt = etree.fromstring(data, parser=PARSER) self.nsmap.update(elt.nsmap) self.prefmap = dict([(v, k) for k, v in self.nsmap.items()]) @@ -222,7 +225,7 @@ def process_includes(self, include): self.nsmap.update(child_ctx.nsmap) self.prefmap = dict([(v, k) for k, v in self.nsmap.items()]) - for attr in ('imports', 'simple_types', 'complex_types', 'elements'): + for attr in ("imports", "simple_types", "complex_types", "elements"): sub = getattr(sub_schema, attr) if sub is None: sub = [] @@ -238,20 +241,26 @@ def process_includes(self, include): def process_simple_type_list(self, s, name=None): item_type = s.list.item_type if item_type is None: - self.debug1("skipping simple type: %s because its list itemType " - "could not be found", name) + self.debug1( + "skipping simple type: %s because its list itemType " + "could not be found", + name, + ) return base = self.get_type(item_type) if base is None: self.pending_simple_types[self.get_name(item_type)].add((s, name)) - self.debug1("pending simple type list: %s " - "because of unseen base %s", name, item_type) + self.debug1( + "pending simple type list: %s " "because of unseen base %s", + name, + item_type, + ) return self.debug1("adding simple type list: %s", name) - retval = Array(base, serialize_as='sd-list') # FIXME: to be implemented + retval = Array(base, serialize_as="sd-list") # FIXME: to be implemented retval.__type_name__ = name retval.__namespace__ = self.tns @@ -261,15 +270,19 @@ def process_simple_type_list(self, s, name=None): def process_simple_type_restriction(self, s, name=None): base_name = s.restriction.base if base_name is None: - self.debug1("skipping simple type: %s because its restriction base " - "could not be found", name) + self.debug1( + "skipping simple type: %s because its restriction base " + "could not be found", + name, + ) return base = self.get_type(base_name) if base is None: self.pending_simple_types[self.get_name(base_name)].add((s, name)) - self.debug1("pending simple type: %s because of unseen base %s", - name, base_name) + self.debug1( + "pending simple type: %s because of unseen base %s", name, base_name + ) return @@ -278,19 +291,19 @@ def process_simple_type_restriction(self, s, name=None): kwargs = {} restriction = s.restriction if restriction.enumeration: - kwargs['values'] = [e.value for e in restriction.enumeration] + kwargs["values"] = [e.value for e in restriction.enumeration] if restriction.max_length: if restriction.max_length.value: - kwargs['max_len'] = int(restriction.max_length.value) + kwargs["max_len"] = int(restriction.max_length.value) if restriction.min_length: if restriction.min_length.value: - kwargs['min_len'] = int(restriction.min_length.value) + kwargs["min_len"] = int(restriction.min_length.value) if restriction.pattern: if restriction.pattern.value: - kwargs['pattern'] = restriction.pattern.value + kwargs["pattern"] = restriction.pattern.value retval = base.customize(**kwargs) retval.__type_name__ = name @@ -305,8 +318,9 @@ def process_simple_type_restriction(self, s, name=None): return retval def process_simple_type_union(self, s, name=None): - self.debug1("skipping simple type: %s because is not " - "implemented", name) + self.debug1( + "skipping simple type: %s because is not " "implemented", name + ) def process_simple_type(self, s, name=None): """Returns the simple Spyne type from `` tag.""" @@ -373,20 +387,20 @@ def process_attribute(self, a): t = self.get_type(a.type) if t is None: - raise ValueError(a, 'type %r not found' % a.type) + raise ValueError(a, "type %r not found" % a.type) elif a.simple_type is not None: t = self.process_simple_type(a.simple_type, a.name) if t is None: - raise ValueError(a, 'simple type %r not found' % a.simple_type) + raise ValueError(a, "simple type %r not found" % a.simple_type) else: raise Exception("dunno attr") kwargs = {} if a.default is not None: - kwargs['default'] = _prot.from_unicode(t, a.default) + kwargs["default"] = _prot.from_unicode(t, a.default) if len(kwargs) > 0: t = t.customize(**kwargs) @@ -415,30 +429,30 @@ def process_type(tn, name, wrapper=None, element=None, attribute=None): kwargs = {} if element is not None: if e.min_occurs != "0": # spyne default - kwargs['min_occurs'] = int(e.min_occurs) + kwargs["min_occurs"] = int(e.min_occurs) if e.max_occurs == "unbounded": - kwargs['max_occurs'] = e.max_occurs + kwargs["max_occurs"] = e.max_occurs elif e.max_occurs != "1": - kwargs['max_occurs'] = int(e.max_occurs) + kwargs["max_occurs"] = int(e.max_occurs) if e.nillable != True: # spyne default - kwargs['nillable'] = e.nillable + kwargs["nillable"] = e.nillable if e.default is not None: - kwargs['default'] = _prot.from_unicode(t, e.default) + kwargs["default"] = _prot.from_unicode(t, e.default) if len(kwargs) > 0: t = t.customize(**kwargs) if attribute is not None: if attribute.default is not None: - kwargs['default'] = _prot.from_unicode(t, a.default) + kwargs["default"] = _prot.from_unicode(t, a.default) if len(kwargs) > 0: t = t.customize(**kwargs) - ti.append( (name, wrapper(t)) ) + ti.append((name, wrapper(t))) self.debug2(" found: %r(%s), c: %r", key, tn, kwargs) def process_element(e): @@ -528,13 +542,15 @@ def process_element(e): r._type_info.update(ti) else: - cls_dict = odict({ - '__type_name__': c.name, - '__namespace__': self.tns, - '_type_info': ti, - }) + cls_dict = odict( + { + "__type_name__": c.name, + "__namespace__": self.tns, + "_type_info": ti, + } + ) if self.repr is not None: - cls_dict['__repr__'] = self.repr + cls_dict["__repr__"] = self.repr r = ComplexModelMeta(str(c.name), (base,), cls_dict) self.retval[self.tns].types[c.name] = r @@ -543,7 +559,7 @@ def process_element(e): def get_name(self, tn): if tn.startswith("{"): - ns, qn = tn[1:].split('}', 1) + ns, qn = tn[1:].split("}", 1) elif ":" in tn: ns, qn = tn.split(":", 1) @@ -576,8 +592,7 @@ def get_type(self, tn): else: retval = self.get_type("{%s}%s" % (ns, e.type)) if retval is None and None in self.nsmap: - retval = self.get_type("{%s}%s" % - (self.nsmap[None], e.type)) + retval = self.get_type("{%s}%s" % (self.nsmap[None], e.type)) return retval return TYPE_MAP.get("{%s}%s" % (ns, qn)) @@ -594,8 +609,7 @@ def process_pending(self): def print_pending(self, fail=False): ptt_pending = sum((len(v) for v in self.pending_simple_types.values())) > 0 - if len(self.pending_elements) > 0 or len(self.pending_types) > 0 or \ - ptt_pending: + if len(self.pending_elements) > 0 or len(self.pending_types) > 0 or ptt_pending: if fail: logging.basicConfig(level=logging.DEBUG) self.debug0("%" * 50) @@ -627,7 +641,7 @@ def parse_schema(self, elt): self.tns = tns = schema.target_namespace if self.tns is None: - self.tns = tns = '__no_ns__' + self.tns = tns = "__no_ns__" if tns in self.retval: return self.retval[tns] = _Schema() @@ -640,11 +654,9 @@ def parse_schema(self, elt): if schema.elements: schema.elements = odict([(e.name, e) for e in schema.elements]) if schema.complex_types: - schema.complex_types = odict([(c.name, c) - for c in schema.complex_types]) + schema.complex_types = odict([(c.name, c) for c in schema.complex_types]) if schema.simple_types: - schema.simple_types = odict([(s.name, s) - for s in schema.simple_types]) + schema.simple_types = odict([(s.name, s) for s in schema.simple_types]) if schema.attributes: schema.attributes = odict([(a.name, a) for a in schema.attributes]) @@ -663,8 +675,9 @@ def parse_schema(self, elt): self.process_simple_type(s) # no simple types should have been left behind. - assert sum((len(v) for v in self.pending_simple_types.values())) == 0, \ - self.pending_simple_types.values() + assert ( + sum((len(v) for v in self.pending_simple_types.values())) == 0 + ), self.pending_simple_types.values() self.debug0("4 %s processing attributes", G(tns)) if schema.attributes: @@ -689,7 +702,7 @@ def parse_schema(self, elt): # This is needed for schemas with circular imports for c in chain([self], self.children): c.print_pending() - self.debug0('') + self.debug0("") # FIXME: should put this in a while loop that loops until no # changes occur @@ -697,7 +710,7 @@ def parse_schema(self, elt): c.process_pending() for c in chain([self], self.children): c.process_pending() - self.debug0('') + self.debug0("") for c in chain([self], self.children): c.print_pending(fail=(not self.skip_errors)) diff --git a/spyne/model/__init__.py b/spyne/model/__init__.py index 929a807b1..a70098540 100644 --- a/spyne/model/__init__.py +++ b/spyne/model/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -16,17 +15,21 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # +# fmt: off +# isort: skip_file """The ``spyne.model`` package contains data types that Spyne is able to distinguish. These are just type markers, they are not of much use without protocols. """ -from spyne.model._base import Ignored -from spyne.model._base import ModelBase -from spyne.model._base import PushBase -from spyne.model._base import Null -from spyne.model._base import SimpleModel +from spyne.model._base import ( + Ignored, + ModelBase, + Null, + PushBase, + SimpleModel, +) # Primitives from spyne.model.primitive import * @@ -34,38 +37,29 @@ # store_as values # it's sad that xml the pssm and xml the module conflict. that's why we need # this after import of primitive package -from spyne.model._base import xml -from spyne.model._base import json -from spyne.model._base import jsonb -from spyne.model._base import table -from spyne.model._base import msgpack +from spyne.model._base import json, jsonb, msgpack, table, xml # Classes -from spyne.model.complex import ComplexModelMeta -from spyne.model.complex import ComplexModelBase -from spyne.model.complex import ComplexModel -from spyne.model.complex import TTableModelBase -from spyne.model.complex import TTableModel - -# Iterables -from spyne.model.complex import Array -from spyne.model.complex import Iterable -from spyne.model.complex import PushBase - -# Modifiers -from spyne.model.complex import Mandatory -from spyne.model.complex import XmlAttribute -from spyne.model.complex import XmlData - -# Markers -from spyne.model.complex import SelfReference - -# Binary -from spyne.model.binary import File -from spyne.model.binary import ByteArray +from spyne.model.complex import ( + Array, + ComplexModel, + ComplexModelBase, + ComplexModelMeta, + Iterable, + Mandatory, + PushBase, + SelfReference, + TTableModel, + TTableModelBase, + XmlAttribute, + XmlData, +) # Enum from spyne.model.enum import Enum # Fault -from spyne.model.fault import Fault +from spyne.model.fault import Fault, ValidationError + +# Binary (must come last — depends on primitive, complex and fault being initialized) +from spyne.model.binary import ByteArray, File diff --git a/spyne/model/_base.py b/spyne/model/_base.py index 2a4db3687..f418aafbe 100644 --- a/spyne/model/_base.py +++ b/spyne/model/_base.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -24,43 +23,47 @@ from __future__ import print_function import logging + logger = logging.getLogger(__name__) -import re import decimal +import re import threading - -import spyne.const.xml - -from copy import deepcopy from collections import OrderedDict +from copy import deepcopy +import spyne.const.xml from spyne import const -from spyne.util import Break, six +from spyne.const.xml import DEFAULT_NS +from spyne.util import Break from spyne.util.cdict import cdict from spyne.util.odict import odict -from spyne.const.xml import DEFAULT_NS - class Ignored(object): """When returned as a real rpc response, this is equivalent to returning None. However, direct method invocations (and NullServer) get the return value. It can be used for tests and from hooks.""" - __slots__ = ('args', 'kwargs') + __slots__ = ("args", "kwargs") def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs def __eq__(self, other): - return isinstance(other, Ignored) \ - and self.args == other.args and self.kwargs == other.kwargs + return ( + isinstance(other, Ignored) + and self.args == other.args + and self.kwargs == other.kwargs + ) def __ne__(self, other): - return not (isinstance(other, Ignored) \ - and self.args == other.args and self.kwargs == other.kwargs) + return not ( + isinstance(other, Ignored) + and self.args == other.args + and self.kwargs == other.kwargs + ) def _decode_pa_dict(d): @@ -92,25 +95,24 @@ class AttributesMeta(type(object)): def __new__(cls, cls_name, cls_bases, cls_dict): # Mapper args should not be inherited. - if not 'sqla_mapper_args' in cls_dict: - cls_dict['sqla_mapper_args'] = None + if not "sqla_mapper_args" in cls_dict: + cls_dict["sqla_mapper_args"] = None rd = {} for k in list(cls_dict.keys()): - if k in ('parser', 'cast'): - rd['parser'] = cls_dict.pop(k) + if k in ("parser", "cast"): + rd["parser"] = cls_dict.pop(k) continue - if k in ('sanitize', 'sanitizer'): - rd['sanitizer'] = cls_dict.pop(k) + if k in ("sanitize", "sanitizer"): + rd["sanitizer"] = cls_dict.pop(k) continue - if k == 'logged': - rd['logged'] = cls_dict.pop(k) + if k == "logged": + rd["logged"] = cls_dict.pop(k) continue - retval = super(AttributesMeta, cls).__new__(cls, cls_name, cls_bases, - cls_dict) + retval = super(AttributesMeta, cls).__new__(cls, cls_name, cls_bases, cls_dict) for k, v in rd.items(): if v is None: @@ -122,11 +124,11 @@ def __new__(cls, cls_name, cls_bases, cls_dict): def __init__(self, cls_name, cls_bases, cls_dict): # you will probably want to look at ModelBase._s_customize as well. - if not hasattr(self, '_method_config_do'): + if not hasattr(self, "_method_config_do"): self._method_config_do = None - nullable = cls_dict.get('nullable', None) - nillable = cls_dict.get('nillable', None) + nullable = cls_dict.get("nullable", None) + nillable = cls_dict.get("nillable", None) if nullable is not None: assert nillable is None or nullable == nillable self._nullable = nullable @@ -135,43 +137,40 @@ def __init__(self, cls_name, cls_bases, cls_dict): assert nullable is None or nullable == nillable self._nullable = nillable - if not hasattr(self, '_nullable'): + if not hasattr(self, "_nullable"): self._nullable = None - if not hasattr(self, '_default_factory'): + if not hasattr(self, "_default_factory"): self._default_factory = None - if not hasattr(self, '_html_cloth'): + if not hasattr(self, "_html_cloth"): self._html_cloth = None - if not hasattr(self, '_html_root_cloth'): + if not hasattr(self, "_html_root_cloth"): self._html_root_cloth = None - if 'html_cloth' in cls_dict: - self.set_html_cloth(cls_dict.pop('html_cloth')) - if 'html_root_cloth' in cls_dict: - self.set_html_cloth(cls_dict.pop('html_root_cloth')) + if "html_cloth" in cls_dict: + self.set_html_cloth(cls_dict.pop("html_cloth")) + if "html_root_cloth" in cls_dict: + self.set_html_cloth(cls_dict.pop("html_root_cloth")) - if not hasattr(self, '_xml_cloth'): + if not hasattr(self, "_xml_cloth"): self._xml_cloth = None - if not hasattr(self, '_xml_root_cloth'): + if not hasattr(self, "_xml_root_cloth"): self._xml_root_cloth = None - if 'xml_cloth' in cls_dict: - self.set_xml_cloth(cls_dict.pop('xml_cloth')) + if "xml_cloth" in cls_dict: + self.set_xml_cloth(cls_dict.pop("xml_cloth")) - if 'xml_root_cloth' in cls_dict: - self.set_xml_cloth(cls_dict.pop('xml_root_cloth')) + if "xml_root_cloth" in cls_dict: + self.set_xml_cloth(cls_dict.pop("xml_root_cloth")) - if 'method_config_do' in cls_dict and \ - cls_dict['method_config_do'] is not None: - cls_dict['method_config_do'] = \ - staticmethod(cls_dict['method_config_do']) + if "method_config_do" in cls_dict and cls_dict["method_config_do"] is not None: + cls_dict["method_config_do"] = staticmethod(cls_dict["method_config_do"]) super(AttributesMeta, self).__init__(cls_name, cls_bases, cls_dict) def get_nullable(self): - return (self._nullable if self._nullable is not None else - self.NULLABLE_DEFAULT) + return self._nullable if self._nullable is not None else self.NULLABLE_DEFAULT def set_nullable(self, what): self._nullable = what @@ -196,8 +195,10 @@ def set_default_factory(self, what): def get_html_cloth(self): return self._html_cloth + def set_html_cloth(self, what): from spyne.protocol.cloth.to_cloth import ClothParserMixin + cm = ClothParserMixin.from_html_cloth(what) if cm._root_cloth is not None: self._html_root_cloth = cm._root_cloth @@ -205,16 +206,20 @@ def set_html_cloth(self, what): self._html_cloth = cm._cloth else: raise Exception("%r is not a suitable cloth", what) + html_cloth = property(get_html_cloth, set_html_cloth) def get_html_root_cloth(self): return self._html_root_cloth + html_root_cloth = property(get_html_root_cloth) def get_xml_cloth(self): return self._xml_cloth + def set_xml_cloth(self, what): from spyne.protocol.cloth.to_cloth import ClothParserMixin + cm = ClothParserMixin.from_xml_cloth(what) if cm._root_cloth is not None: self._xml_root_cloth = cm._root_cloth @@ -222,19 +227,23 @@ def set_xml_cloth(self, what): self._xml_cloth = cm._cloth else: raise Exception("%r is not a suitable cloth", what) + xml_cloth = property(get_xml_cloth, set_xml_cloth) def get_xml_root_cloth(self): return self._xml_root_cloth + xml_root_cloth = property(get_xml_root_cloth) def get_method_config_do(self): return self._method_config_do + def set_method_config_do(self, what): if what is None: self._method_config_do = None else: self._method_config_do = staticmethod(what) + method_config_do = property(get_method_config_do, set_method_config_do) @@ -251,8 +260,7 @@ def customize(self, **kwargs): return type(cls_name, cls_bases, cls_dict) -@six.add_metaclass(ModelBaseMeta) -class ModelBase(object): +class ModelBase(metaclass=ModelBaseMeta): """The base class for type markers. It defines the model interface for the interface generators to use and also manages class customizations that are mainly used for defining constraints on input values. @@ -284,8 +292,7 @@ class ModelBase(object): # # Please note that min_occurs and max_occurs must be validated in the # ComplexModelBase deserializer. - @six.add_metaclass(AttributesMeta) - class Attributes(object): + class Attributes(metaclass=AttributesMeta): """The class that holds the constraints for the given type.""" _wrapper = False @@ -336,7 +343,7 @@ class Attributes(object): will imply an iterable of objects as native python type. Can be set to ``decimal.Decimal("inf")`` for arbitrary number of arguments.""" - schema_tag = spyne.const.xml.XSD('element') + schema_tag = spyne.const.xml.XSD("element") """The tag used to add a primitives as child to a complex type in the xml schema.""" @@ -485,7 +492,6 @@ class Attributes(object): """A dict of classes that override polymorphic substitions for classes given as keys to classes given as values.""" - class Annotations(object): """The class that holds the annotations for the given type.""" @@ -549,8 +555,9 @@ def _fill_empty_type_name(cls, parent_ns, parent_tn, k): cls.__type_name__ = "%s_%s%s" % (parent_tn, k, const.TYPE_SUFFIX) extends = cls.__extends__ while extends is not None and extends.__type_name__ is ModelBase.Empty: - cls.__extends__._fill_empty_type_name(cls.get_namespace(), - cls.get_type_name(), k + const.PARENT_SUFFIX) + cls.__extends__._fill_empty_type_name( + cls.get_namespace(), cls.get_type_name(), k + const.PARENT_SUFFIX + ) extends = extends.__extends__ # TODO: rename to "resolve_identifier" @@ -570,19 +577,18 @@ def resolve_namespace(cls, default_ns, tags=None): if cls.__namespace__ is spyne.const.xml.DEFAULT_NS: cls.__namespace__ = default_ns - if (cls.__namespace__ in spyne.const.xml.PREFMAP and - not cls.is_default(cls)): + if cls.__namespace__ in spyne.const.xml.PREFMAP and not cls.is_default(cls): cls.__namespace__ = default_ns if cls.__namespace__ is None: ret = [] - for f in cls.__module__.split('.'): - if f.startswith('_'): + for f in cls.__module__.split("."): + if f.startswith("_"): break else: ret.append(f) - cls.__namespace__ = '.'.join(ret) + cls.__namespace__ = ".".join(ret) if cls.__namespace__ is None or len(cls.__namespace__) == 0: cls.__namespace__ = default_ns @@ -592,15 +598,14 @@ def resolve_namespace(cls, default_ns, tags=None): # print(" resolve ns for %r to %r" % (cls, cls.__namespace__)) - if getattr(cls, '__extends__', None) != None: + if getattr(cls, "__extends__", None) != None: cls.__extends__.resolve_namespace(cls.__extends__, default_ns, tags) return True @classmethod def get_type_name(cls): - """Returns the class name unless the __type_name__ attribute is defined. - """ + """Returns the class name unless the __type_name__ attribute is defined.""" retval = cls.__type_name__ if retval is None: @@ -611,12 +616,10 @@ def get_type_name(cls): # FIXME: Rename this to get_type_name_with_ns_pref @classmethod def get_type_name_ns(cls, interface): - """Returns the type name with a namespace prefix, separated by a column. - """ + """Returns the type name with a namespace prefix, separated by a column.""" if cls.get_namespace() != None: - return "%s:%s" % (cls.get_namespace_prefix(interface), - cls.get_type_name()) + return "%s:%s" % (cls.get_namespace_prefix(interface), cls.get_type_name()) @classmethod def get_element_name(cls): @@ -640,14 +643,14 @@ def to_bytes(cls, value): """ Returns str(value). This should be overridden if this is not enough. """ - return six.binary_type(value) + return bytes(value) @classmethod def to_unicode(cls, value): """ Returns unicode(value). This should be overridden if this is not enough. """ - return six.text_type(value) + return str(value) @classmethod def get_documentation(cls): @@ -656,7 +659,7 @@ def get_documentation(cls): elif cls.Annotations.__use_parent_doc__: return cls.__doc__ else: - return '' + return "" @classmethod def _s_customize(cls, **kwargs): @@ -667,12 +670,12 @@ def _s_customize(cls, **kwargs): def _log_debug(s, *args): logger.debug("\t%s: %s" % (cls.get_type_name(), s), *args) - cls_dict = odict({'__module__': cls.__module__, '__doc__': cls.__doc__}) + cls_dict = odict({"__module__": cls.__module__, "__doc__": cls.__doc__}) - if getattr(cls, '__orig__', None) is None: - cls_dict['__orig__'] = cls + if getattr(cls, "__orig__", None) is None: + cls_dict["__orig__"] = cls else: - cls_dict['__orig__'] = cls.__orig__ + cls_dict["__orig__"] = cls.__orig__ class Attributes(cls.Attributes): _explicit_type_name = False @@ -683,95 +686,106 @@ class Attributes(cls.Attributes): if cls.Attributes.sqla_column_args is None: Attributes.sqla_column_args = (), {} else: - Attributes.sqla_column_args = deepcopy( - cls.Attributes.sqla_column_args) + Attributes.sqla_column_args = deepcopy(cls.Attributes.sqla_column_args) - cls_dict['Attributes'] = Attributes + cls_dict["Attributes"] = Attributes # properties get reset every time a new class is defined. So we need # to reinitialize them explicitly. - for k in ('nillable', '_xml_cloth', '_xml_root_cloth', '_html_cloth', - '_html_root_cloth'): + for k in ( + "nillable", + "_xml_cloth", + "_xml_root_cloth", + "_html_cloth", + "_html_root_cloth", + ): v = getattr(cls.Attributes, k) if v is not None: setattr(Attributes, k, v) class Annotations(cls.Annotations): pass - cls_dict['Annotations'] = Annotations + + cls_dict["Annotations"] = Annotations # get protocol attrs - prot = kwargs.get('protocol', None) + prot = kwargs.get("protocol", None) if prot is None: - prot = kwargs.get('prot', None) + prot = kwargs.get("prot", None) if prot is None: - prot = kwargs.get('p', None) + prot = kwargs.get("p", None) if prot is not None and len(prot.type_attrs) > 0: # if there is a class customization from protocol, do it type_attrs = prot.type_attrs.copy() type_attrs.update(kwargs) - _log_debug("kwargs %r => %r from prot typeattr %r", - kwargs, type_attrs, prot.type_attrs) + _log_debug( + "kwargs %r => %r from prot typeattr %r", + kwargs, + type_attrs, + prot.type_attrs, + ) kwargs = type_attrs # the ones that wrap values in staticmethod() should be added to # AttributesMeta initializer for k, v in kwargs.items(): - if k.startswith('_'): + if k.startswith("_"): _log_debug("ignoring '%s' because of leading underscore", k) continue - if k in ('protocol', 'prot', 'p'): + if k in ("protocol", "prot", "p"): Attributes.prot = v _log_debug("setting prot=%r", v) - elif k in ('voa', 'validate_on_assignment'): + elif k in ("voa", "validate_on_assignment"): Attributes.validate_on_assignment = v _log_debug("setting voa=%r", v) - elif k in ('parser', 'in_cast'): - setattr(Attributes, 'parser', staticmethod(v)) + elif k in ("parser", "in_cast"): + setattr(Attributes, "parser", staticmethod(v)) _log_debug("setting %s=%r", k, v) - elif k in ('sanitize', 'sanitizer', 'out_cast'): - setattr(Attributes, 'sanitizer', staticmethod(v)) + elif k in ("sanitize", "sanitizer", "out_cast"): + setattr(Attributes, "sanitizer", staticmethod(v)) _log_debug("setting %s=%r as sanitizer", k, v) - elif k == 'logged': - setattr(Attributes, 'logged', staticmethod(v)) + elif k == "logged": + setattr(Attributes, "logged", staticmethod(v)) _log_debug("setting %s=%r as log sanitizer", k, v) elif k in ("doc", "appinfo"): setattr(Annotations, k, v) _log_debug("setting Annotations.%s=%r", k, v) - elif k in ('primary_key', 'pk'): - setattr(Attributes, 'primary_key', v) - Attributes.sqla_column_args[-1]['primary_key'] = v + elif k in ("primary_key", "pk"): + setattr(Attributes, "primary_key", v) + Attributes.sqla_column_args[-1]["primary_key"] = v _log_debug("setting primary_key=%r", v) - elif k in ('protocol_attrs', 'prot_attrs', 'pa'): - setattr(Attributes, 'prot_attrs', _decode_pa_dict(v)) + elif k in ("protocol_attrs", "prot_attrs", "pa"): + setattr(Attributes, "prot_attrs", _decode_pa_dict(v)) _log_debug("setting prot_attrs=%r", v) - elif k in ('foreign_key', 'fk'): + elif k in ("foreign_key", "fk"): from sqlalchemy.schema import ForeignKey + t, d = Attributes.sqla_column_args fkt = (ForeignKey(v),) new_v = (t + fkt, d) Attributes.sqla_column_args = new_v _log_debug("setting sqla_column_args=%r", new_v) - elif k in ('autoincrement', 'onupdate', 'server_default'): + elif k in ("autoincrement", "onupdate", "server_default"): Attributes.sqla_column_args[-1][k] = v _log_debug("adding %s=%r to Attributes.sqla_column_args", k, v) - elif k == 'values_dict': - assert not 'values' in v, "`values` and `values_dict` can't be" \ - "specified at the same time" + elif k == "values_dict": + assert not "values" in v, ( + "`values` and `values_dict` can't be" "specified at the same time" + ) if not isinstance(v, dict): # our odict has one nasty implicit behaviour: setitem on @@ -782,23 +796,27 @@ class Annotations(cls.Annotations): Attributes.values = list(v.keys()) Attributes.values_dict = v - _log_debug("setting values=%r, values_dict=%r", - Attributes.values, Attributes.values_dict) + _log_debug( + "setting values=%r, values_dict=%r", + Attributes.values, + Attributes.values_dict, + ) - elif k == 'exc_table': + elif k == "exc_table": Attributes.exc_table = v Attributes.exc_db = v _log_debug("setting exc_table=%r, exc_db=%r", v, v) - elif k == 'max_occurs' and v in ('unbounded', 'inf', float('inf')): - new_v = decimal.Decimal('inf') + elif k == "max_occurs" and v in ("unbounded", "inf", float("inf")): + new_v = decimal.Decimal("inf") setattr(Attributes, k, new_v) _log_debug("setting max_occurs=%r", new_v) - elif k == 'type_name': + elif k == "type_name": Attributes._explicit_type_name = True - _log_debug("setting _explicit_type_name=True because " - "we have 'type_name'") + _log_debug( + "setting _explicit_type_name=True because " "we have 'type_name'" + ) else: setattr(Attributes, k, v) @@ -812,7 +830,7 @@ def validate_string(cls, value): string. This is called before converting the incoming string to the native python value.""" - return (cls.Attributes.nillable or value is not None) + return cls.Attributes.nillable or value is not None @staticmethod def validate_native(cls, value): @@ -820,7 +838,7 @@ def validate_native(cls, value): value. This is called after converting the incoming string to the native python value.""" - return (cls.Attributes.nullable or value is not None) + return cls.Attributes.nullable or value is not None class Null(ModelBase): @@ -829,9 +847,8 @@ class Null(ModelBase): class SimpleModelAttributesMeta(AttributesMeta): def __init__(self, cls_name, cls_bases, cls_dict): - super(SimpleModelAttributesMeta, self).__init__(cls_name, cls_bases, - cls_dict) - if getattr(self, '_pattern', None) is None: + super(SimpleModelAttributesMeta, self).__init__(cls_name, cls_bases, cls_dict) + if getattr(self, "_pattern", None) is None: self._pattern = None def get_pattern(self): @@ -861,8 +878,7 @@ class SimpleModel(ModelBase): __namespace__ = "http://www.w3.org/2001/XMLSchema" - @six.add_metaclass(SimpleModelAttributesMeta) - class Attributes(ModelBase.Attributes): + class Attributes(ModelBase.Attributes, metaclass=SimpleModelAttributesMeta): """The class that holds the constraints for the given type.""" values = set() @@ -897,29 +913,31 @@ def customize(cls, **kwargs): if not retval.is_default(retval): retval.__extends__ = cls retval.__type_name__ = kwargs.get("type_name", ModelBase.Empty) - if 'type_name' in kwargs: - logger.debug("Type name for %r was overridden as '%s'", - retval, retval.__type_name__) + if "type_name" in kwargs: + logger.debug( + "Type name for %r was overridden as '%s'", + retval, + retval.__type_name__, + ) - retval.resolve_namespace(retval, kwargs.get('__namespace__')) + retval.resolve_namespace(retval, kwargs.get("__namespace__")) return retval @staticmethod def is_default(cls): - return (cls.Attributes.values == SimpleModel.Attributes.values) + return cls.Attributes.values == SimpleModel.Attributes.values @staticmethod def validate_native(cls, value): - return (ModelBase.validate_native(cls, value) - and ( - cls.Attributes.values is None or - len(cls.Attributes.values) == 0 or ( - (value is None and cls.Attributes.nillable) or - (value is not None and value in cls.Attributes.values) - ) - ) + return ModelBase.validate_native(cls, value) and ( + cls.Attributes.values is None + or len(cls.Attributes.values) == 0 + or ( + (value is None and cls.Attributes.nillable) + or (value is not None and value in cls.Attributes.values) ) + ) class PushBase(object): @@ -1010,13 +1028,28 @@ class table: :param back_populates: See https://docs.sqlalchemy.org/en/13/orm/relationship_api.html?highlight=lazy#sqlalchemy.orm.relationship.params.back_populates """ - def __init__(self, multi=False, left=None, right=None, backref=None, - id_backref=None, cascade=False, lazy='select', back_populates=None, - fk_left_deferrable=None, fk_left_initially=None, - fk_right_deferrable=None, fk_right_initially=None, - fk_left_ondelete=None, fk_left_onupdate=None, - fk_right_ondelete=None, fk_right_onupdate=None, - explicit_join=False, order_by=False, single_parent=None): + def __init__( + self, + multi=False, + left=None, + right=None, + backref=None, + id_backref=None, + cascade=False, + lazy="select", + back_populates=None, + fk_left_deferrable=None, + fk_left_initially=None, + fk_right_deferrable=None, + fk_right_initially=None, + fk_left_ondelete=None, + fk_left_onupdate=None, + fk_right_ondelete=None, + fk_right_onupdate=None, + explicit_join=False, + order_by=False, + single_parent=None, + ): self.multi = multi self.left = left self.right = right @@ -1070,21 +1103,31 @@ class msgpack: Make sure you don't mix this with the msgpack package when importing. """ + def __init__(self): pass -PSSM_VALUES = {'json': json, 'jsonb': jsonb, 'xml': xml, - 'msgpack': msgpack, 'table': table} +PSSM_VALUES = { + "json": json, + "jsonb": jsonb, + "xml": xml, + "msgpack": msgpack, + "table": table, +} def apply_pssm(val): if val is not None: val_c = PSSM_VALUES.get(val, None) if val_c is None: - assert isinstance(val, tuple(PSSM_VALUES.values())), \ - "'store_as' should be one of: %r or an instance of %r not %r" \ - % (tuple(PSSM_VALUES.keys()), tuple(PSSM_VALUES.values()), val) + assert isinstance( + val, tuple(PSSM_VALUES.values()) + ), "'store_as' should be one of: %r or an instance of %r not %r" % ( + tuple(PSSM_VALUES.keys()), + tuple(PSSM_VALUES.values()), + val, + ) return val return val_c() diff --git a/spyne/model/addtl.py b/spyne/model/addtl.py index 6bc83cfc8..b031bb13c 100644 --- a/spyne/model/addtl.py +++ b/spyne/model/addtl.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,8 +17,8 @@ # import re -from spyne import M, Boolean, DateTime, Date, Time, ComplexModel, \ - ValidationError + +from spyne import Boolean, ComplexModel, Date, DateTime, M, Time, ValidationError from spyne.protocol import InProtocolBase @@ -34,65 +33,57 @@ def from_string(cls, s): print() print(start_incl, start_str, end_str, end_incl) - start_incl = (start_incl == '[') - start = InProtocolBase().from_unicode( - cls._type_info['start'], start_str) - end = InProtocolBase().from_unicode(cls._type_info['start'], end_str) - end_incl = (end_incl == ']') + start_incl = start_incl == "[" + start = InProtocolBase().from_unicode(cls._type_info["start"], start_str) + end = InProtocolBase().from_unicode(cls._type_info["start"], end_str) + end_incl = end_incl == "]" print(start_incl, start, end, end_incl) - return cls(start_inclusive=start_incl, start=start, end=end, - end_inclusive=end_incl) + return cls( + start_inclusive=start_incl, start=start, end=end, end_inclusive=end_incl + ) def to_string(self): - return '[%s,%s]' % (self.start.isoformat(), self.end.isoformat()) + return "[%s,%s]" % (self.start.isoformat(), self.end.isoformat()) class DateTimeSegment(ComplexModel, SegmentBase): _SEGMENT_RE = re.compile( - u"([\\[\\]])" - u"([0-9:\\.T-]+)" - u"," - u"([0-9:\\.T-]+)" - u"([\\[\\]])", re.DEBUG | re.UNICODE) + "([\\[\\]])" "([0-9:\\.T-]+)" "," "([0-9:\\.T-]+)" "([\\[\\]])", + re.DEBUG | re.UNICODE, + ) _type_info = [ - ('start_inclusive', M(Boolean(default=True))), - ('start', M(DateTime)), - ('end', M(DateTime)), - ('end_inclusive', M(Boolean(default=True))), + ("start_inclusive", M(Boolean(default=True))), + ("start", M(DateTime)), + ("end", M(DateTime)), + ("end_inclusive", M(Boolean(default=True))), ] - class DateSegment(ComplexModel, SegmentBase): _SEGMENT_RE = re.compile( - u"([\\[\\]])" - u"([0-9-]+)" - u"," - u"([0-9-]+)" - u"([\\[\\]])", re.DEBUG | re.UNICODE) + "([\\[\\]])" "([0-9-]+)" "," "([0-9-]+)" "([\\[\\]])", re.DEBUG | re.UNICODE + ) _type_info = [ - ('start_inclusive', M(Boolean(default=True))), - ('start', M(Date)), - ('end', M(Date)), - ('end_inclusive', M(Boolean(default=True))), + ("start_inclusive", M(Boolean(default=True))), + ("start", M(Date)), + ("end", M(Date)), + ("end_inclusive", M(Boolean(default=True))), ] class TimeSegment(ComplexModel, SegmentBase): _SEGMENT_RE = re.compile( - u"([\\[\\]])" - u"([0-9:\\.]+)" - u"," - u"([0-9:\\.]+)" - u"([\\[\\]])", re.DEBUG | re.UNICODE) + "([\\[\\]])" "([0-9:\\.]+)" "," "([0-9:\\.]+)" "([\\[\\]])", + re.DEBUG | re.UNICODE, + ) _type_info = [ - ('start_inclusive', M(Boolean(default=True))), - ('start', M(Time)), - ('end', M(Time)), - ('end_inclusive', M(Boolean(default=True))), + ("start_inclusive", M(Boolean(default=True))), + ("start", M(Time)), + ("end", M(Time)), + ("end_inclusive", M(Boolean(default=True))), ] diff --git a/spyne/model/binary.py b/spyne/model/binary.py index 4bc446d9f..640169ba6 100644 --- a/spyne/model/binary.py +++ b/spyne/model/binary.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,34 +17,44 @@ # """The ``spyne.model.binary`` package contains binary type markers.""" + +# isort: skip_file + import logging + logger = logging.getLogger(__name__) -import os import base64 -import tempfile import errno +import os +import tempfile +from base64 import b64decode, b64encode, urlsafe_b64decode, urlsafe_b64encode +from binascii import hexlify, unhexlify +from io import BytesIO, StringIO +from mmap import ACCESS_READ +from mmap import error as MmapError +from mmap import mmap +from os.path import abspath, basename, isdir, isfile + +from spyne.model.fault import ValidationError +from spyne.model import ComplexModel, SimpleModel, Unicode +from spyne.util import _bytes_join -from mmap import mmap, ACCESS_READ, error as MmapError -from base64 import b64encode -from base64 import b64decode -from base64 import urlsafe_b64encode -from base64 import urlsafe_b64decode -from binascii import hexlify -from binascii import unhexlify -from os.path import abspath, isdir, isfile, basename -from spyne.error import ValidationError -from spyne.util import _bytes_join -from spyne.model import ComplexModel, Unicode -from spyne.model import SimpleModel -from spyne.util import six -from spyne.util.six import BytesIO, StringIO +class BINARY_ENCODING_HEX: + pass + + +class BINARY_ENCODING_BASE64: + pass -class BINARY_ENCODING_HEX: pass -class BINARY_ENCODING_BASE64: pass -class BINARY_ENCODING_USE_DEFAULT: pass -class BINARY_ENCODING_URLSAFE_BASE64: pass + +class BINARY_ENCODING_USE_DEFAULT: + pass + + +class BINARY_ENCODING_URLSAFE_BASE64: + pass class ByteArray(SimpleModel): @@ -57,7 +66,7 @@ class ByteArray(SimpleModel): and a sequence of ``bytes`` objects for Python 3.x. """ - __type_name__ = 'base64Binary' + __type_name__ = "base64Binary" __namespace__ = "http://www.w3.org/2001/XMLSchema" class Attributes(SimpleModel.Attributes): @@ -70,31 +79,33 @@ class Attributes(SimpleModel.Attributes): def __new__(cls, **kwargs): tn = None - if 'encoding' in kwargs: - v = kwargs['encoding'] + if "encoding" in kwargs: + v = kwargs["encoding"] if v is None: - kwargs['encoding'] = BINARY_ENCODING_USE_DEFAULT + kwargs["encoding"] = BINARY_ENCODING_USE_DEFAULT - elif v in ('base64', 'base64Binary', BINARY_ENCODING_BASE64): + elif v in ("base64", "base64Binary", BINARY_ENCODING_BASE64): # This string is defined in the Xml Schema Standard - tn = 'base64Binary' - kwargs['encoding'] = BINARY_ENCODING_BASE64 + tn = "base64Binary" + kwargs["encoding"] = BINARY_ENCODING_BASE64 - elif v in ('urlsafe_base64', BINARY_ENCODING_URLSAFE_BASE64): + elif v in ("urlsafe_base64", BINARY_ENCODING_URLSAFE_BASE64): # the Xml Schema Standard does not define urlsafe base64 # FIXME: produce a regexp that validates urlsafe base64 strings - tn = 'string' - kwargs['encoding'] = BINARY_ENCODING_URLSAFE_BASE64 + tn = "string" + kwargs["encoding"] = BINARY_ENCODING_URLSAFE_BASE64 - elif v in ('hex', 'hexBinary', BINARY_ENCODING_HEX): + elif v in ("hex", "hexBinary", BINARY_ENCODING_HEX): # This string is defined in the Xml Schema Standard - tn = 'hexBinary' - kwargs['encoding'] = BINARY_ENCODING_HEX + tn = "hexBinary" + kwargs["encoding"] = BINARY_ENCODING_HEX else: - raise ValueError("'encoding' must be one of: %r" % \ - (tuple(ByteArray._encoding.handlers.values()),)) + raise ValueError( + "'encoding' must be one of: %r" + % (tuple(ByteArray._encoding.handlers.values()),) + ) retval = cls.customize(**kwargs) if tn is not None: @@ -111,10 +122,10 @@ def to_base64(cls, value): # TODO: be smarter about this return b64encode(value[0]) - if isinstance(value, (six.binary_type, memoryview, mmap)): + if isinstance(value, (bytes, memoryview, mmap)): return b64encode(value) - return b64encode(b''.join(value)) + return b64encode(b"".join(value)) @classmethod def from_base64(cls, value): @@ -133,9 +144,9 @@ def to_urlsafe_base64(cls, value): @classmethod def from_urlsafe_base64(cls, value): - #FIXME: Find out why we need to do this. - if isinstance(value, six.text_type): - value = value.encode('utf8') + # FIXME: Find out why we need to do this. + if isinstance(value, str): + value = value.encode("utf8") try: if isinstance(value, (list, tuple)): return (urlsafe_b64decode(_bytes_join(value)),) @@ -160,16 +171,16 @@ def from_hex(cls, value): def _default_binary_encoding(b): - if isinstance(b, (six.binary_type, memoryview)): + if isinstance(b, (bytes, memoryview)): return b if isinstance(b, tuple) and len(b) > 0 and isinstance(b[0], mmap): return b[0] - if isinstance(b, six.text_type): + if isinstance(b, str): raise ValueError(b) - return b''.join(b) + return b"".join(b) binary_encoding_handlers = { @@ -188,7 +199,7 @@ def _default_binary_encoding(b): class HybridFileStore(object): - def __init__(self, store_path, db_format='json', type=None): + def __init__(self, store_path, db_format="json", type=None): """Marker to be passed to File's store_as to denote a hybrid Sql/Filesystem storage scheme. @@ -208,14 +219,13 @@ def __init__(self, store_path, db_format='json', type=None): assert isdir(self.store) -_BINARY = type('FileTypeBinary', (object,), {}) -_TEXT = type('FileTypeText', (object,), {}) +_BINARY = type("FileTypeBinary", (object,), {}) +_TEXT = type("FileTypeText", (object,), {}) class SanitizationError(ValidationError): def __init__(self, obj): - super(SanitizationError, self).__init__( - obj, "%r was not sanitized before use") + super(SanitizationError, self).__init__(obj, "%r was not sanitized before use") class _FileValue(ComplexModel): @@ -226,26 +236,37 @@ class _FileValue(ComplexModel): :param data: Optional sequence of ``str`` or ``bytes`` instances that contain the file's data. """ + # ^ This is the public docstring. __type_name__ = "FileValue" _type_info = [ - ('name', Unicode(encoding='utf8')), - ('type', Unicode), - ('data', ByteArray(logged='len')), + ("name", Unicode(encoding="utf8")), + ("type", Unicode), + ("data", ByteArray(logged="len")), ] - def __init__(self, name=None, path=None, type='application/octet-stream', - data=None, handle=None, move=False, _sanitize=True): + def __init__( + self, + name=None, + path=None, + type="application/octet-stream", + data=None, + handle=None, + move=False, + _sanitize=True, + ): self.name = name """The file basename, no directory information here.""" if self.name is not None and _sanitize: if not os.path.basename(self.name) == self.name: - raise ValidationError(self.name, - "File name %r should not contain any directory information") + raise ValidationError( + self.name, + "File name %r should not contain any directory information", + ) self.sanitized = _sanitize @@ -291,7 +312,7 @@ def rollover(self): self.abspath = self.path = self.handle.name self.name = basename(self.abspath) else: - self.handle = open(self.path, 'wb') + self.handle = open(self.path, "wb") # FIXME: abspath could be None here, how do we make sure it's # the right value? @@ -309,9 +330,7 @@ def rollover(self): except MmapError as e: if e.errno == errno.EACCES: - self.data = ( - mmap(self.handle.fileno(), 0, access=ACCESS_READ), - ) + self.data = (mmap(self.handle.fileno(), 0, access=ACCESS_READ),) else: raise @@ -319,14 +338,16 @@ def rollover(self): if not isfile(self.path): logger.error("File path in %r not found", self) - self.handle = open(self.path, 'rb') + self.handle = open(self.path, "rb") self.data = (mmap(self.handle.fileno(), 0, access=ACCESS_READ),) self.abspath = abspath(self.path) self.name = self.path = basename(self.path) else: - raise ValueError("Invalid file object passed in. All of " - ".data, .handle and .path are None.") + raise ValueError( + "Invalid file object passed in. All of " + ".data, .handle and .path are None." + ) class File(SimpleModel): @@ -334,7 +355,7 @@ class File(SimpleModel): standard way of encoding file metadata along with binary data. (E.g. Http) """ - __type_name__ = 'base64Binary' + __type_name__ = "base64Binary" __namespace__ = "http://www.w3.org/2001/XMLSchema" BINARY = _BINARY @@ -366,12 +387,14 @@ def to_base64(cls, value): if value is None: return - assert value.path, "You need to write data to persistent storage first " \ - "if you want to read it back." - f = open(value.path, 'rb') + assert value.path, ( + "You need to write data to persistent storage first " + "if you want to read it back." + ) + f = open(value.path, "rb") # base64 encodes every 3 bytes to 4 base64 characters - data = f.read(0x4001) # so this needs to be a multiple of 3 + data = f.read(0x4001) # so this needs to be a multiple of 3 while len(data) > 0: yield base64.b64encode(data) data = f.read(0x4001) @@ -385,8 +408,12 @@ def from_base64(cls, value): return File.Value(data=[base64.b64decode(value)]) def __repr__(self): - return "File(name=%r, path=%r, type=%r, data=%r)" % \ - (self.name, self.path, self.type, self.data) + return "File(name=%r, path=%r, type=%r, data=%r)" % ( + self.name, + self.path, + self.type, + self.data, + ) @classmethod def store_as(cls, what): diff --git a/spyne/model/complex.py b/spyne/model/complex.py index a6580abb1..bd937d03c 100644 --- a/spyne/model/complex.py +++ b/spyne/model/complex.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -26,46 +25,52 @@ from __future__ import print_function import logging + logger = logging.getLogger(__name__) import decimal import traceback - +from collections import OrderedDict, deque from copy import copy -from weakref import WeakKeyDictionary -from collections import deque, OrderedDict from inspect import isclass from itertools import chain +from weakref import WeakKeyDictionary from spyne import const from spyne.const.xml import PREFMAP -from spyne.model import Point, Unicode, PushBase, ModelBase +# FIXME: for backwards compatibility, to be removed in Spyne 3 +# noinspection PyUnresolvedReferences +from spyne.model import ( + ModelBase, + Point, + PushBase, + Unicode, + json, + jsonb, + msgpack, + table, + xml, +) from spyne.model._base import PSSM_VALUES, apply_pssm from spyne.model.primitive import NATIVE_MAP from spyne.model.primitive._base import AnyXml - -from spyne.util import six, memoize, memoize_id, sanitize_args, \ - memoize_ignore_none +from spyne.util import memoize, memoize_id, memoize_ignore_none, sanitize_args from spyne.util.color import YEL from spyne.util.meta import Prepareable from spyne.util.odict import odict -from spyne.util.six import add_metaclass, with_metaclass, string_types - -# FIXME: for backwards compatibility, to be removed in Spyne 3 -# noinspection PyUnresolvedReferences -from spyne.model import json, jsonb, xml, msgpack, table def _get_flat_type_info(cls, retval): assert isinstance(retval, TypeInfo) - parent = getattr(cls, '__extends__', None) + parent = getattr(cls, "__extends__", None) if not (parent is None): _get_flat_type_info(parent, retval) retval.update(cls._type_info) retval.alt.update(cls._type_info_alt) # FIXME: move to cls._type_info.alt - retval.attrs.update({k: v for (k, v) in cls._type_info.items() - if issubclass(v, XmlAttribute)}) + retval.attrs.update( + {k: v for (k, v) in cls._type_info.items() if issubclass(v, XmlAttribute)} + ) return retval @@ -78,12 +83,12 @@ def __init__(self, *args, **kwargs): self.attrs = OrderedDict() def __setitem__(self, key, val): - assert isinstance(key, string_types) + assert isinstance(key, str) super(TypeInfo, self).__setitem__(key, val) class _SimpleTypeInfoElement(object): - __slots__ = ['path', 'parent', 'type', 'is_array', 'can_be_empty'] + __slots__ = ["path", "parent", "type", "is_array", "can_be_empty"] def __init__(self, path, parent, type_, is_array, can_be_empty): self.path = path @@ -93,8 +98,12 @@ def __init__(self, path, parent, type_, is_array, can_be_empty): self.can_be_empty = can_be_empty def __repr__(self): - return "SimpleTypeInfoElement(path=%r, parent=%r, type=%r, is_array=%r)" \ - % (self.path, self.parent, self.type, self.is_array) + return "SimpleTypeInfoElement(path=%r, parent=%r, type=%r, is_array=%r)" % ( + self.path, + self.parent, + self.type, + self.is_array, + ) class XmlModifier(ModelBase): @@ -128,13 +137,11 @@ def _fill_empty_type_name(cls, parent_ns, parent_tn, k): child_v.__type_name__ = tn cls._type_info = TypeInfo({tn: child_v}) - cls.__type_name__ = '%s%s%s' % (const.ARRAY_PREFIX, tn, - const.ARRAY_SUFFIX) + cls.__type_name__ = "%s%s%s" % (const.ARRAY_PREFIX, tn, const.ARRAY_SUFFIX) extends = child_v.__extends__ while extends is not None and extends.get_type_name() is cls.Empty: - extends._fill_empty_type_name(parent_ns, parent_tn, - k + const.PARENT_SUFFIX) + extends._fill_empty_type_name(parent_ns, parent_tn, k + const.PARENT_SUFFIX) extends = extends.__extends__ @@ -180,7 +187,7 @@ def __new__(cls, type_, use=None, ns=None): retval = super(XmlAttribute, cls).__new__(cls, type_, ns) retval._use = use if retval.type.Attributes.min_occurs > 0 and retval._use is None: - retval._use = 'required' + retval._use = "required" return retval @@ -192,15 +199,16 @@ def __init__(self, ref, use=None): self._use = use def describe(self, name, element, app): - element.set('ref', self._ref) + element.set("ref", self._ref) if self._use: - element.set('use', self._use) + element.set("use", self._use) class SelfReference(object): """Use this as a placeholder type in classes that contain themselves. See :func:`spyne.test.model.test_complex.TestComplexModel.test_self_reference`. """ + customize_args = [] customize_kwargs = {} __orig__ = None @@ -215,10 +223,14 @@ def customize(cls, *args, **kwargs): if cls.__orig__ is None: cls.__orig__ = cls - return type("SelfReference", (cls,), { - 'customize_args': args, - 'customize_kwargs': kwargs, - }) + return type( + "SelfReference", + (cls,), + { + "customize_args": args, + "customize_kwargs": kwargs, + }, + ) def _get_spyne_type(cls_name, k, v): @@ -234,7 +246,7 @@ def _get_spyne_type(cls_name, k, v): if subc: if issubclass(v, Array) and len(v._type_info) != 1: - raise Exception("Invalid Array definition in %s.%s."% (cls_name, k)) + raise Exception("Invalid Array definition in %s.%s." % (cls_name, k)) elif issubclass(v, Point) and v.Attributes.dim is None: raise Exception("Please specify the number of dimensions") return v @@ -256,13 +268,15 @@ def _join_args(x, y): def _gen_attrs(cls_bases, cls_dict): - attrs = cls_dict.get('Attributes', None) + attrs = cls_dict.get("Attributes", None) if attrs is None: for b in cls_bases: - if hasattr(b, 'Attributes'): + if hasattr(b, "Attributes"): + class Attributes(b.Attributes): pass - attrs = cls_dict['Attributes'] = Attributes + + attrs = cls_dict["Attributes"] = Attributes break else: raise Exception("No ModelBase subclass in bases? Huh?") @@ -273,7 +287,7 @@ class Attributes(b.Attributes): def _get_type_info(cls, cls_name, cls_bases, cls_dict, attrs): base_type_info = TypeInfo() mixin = TypeInfo() - extends = cls_dict.get('__extends__', None) + extends = cls_dict.get("__extends__", None) # user did not specify explicit base class so let's try to derive it from # the actual class hierarchy @@ -281,7 +295,7 @@ def _get_type_info(cls, cls_name, cls_bases, cls_dict, attrs): # we don't want origs end up as base classes orig = cls_dict.get("__orig__", None) if orig is None: - orig = getattr(cls, '__orig__', None) + orig = getattr(cls, "__orig__", None) if orig is not None: bases = orig.__bases__ @@ -298,42 +312,55 @@ def _get_type_info(cls, cls_name, cls_bases, cls_dict, attrs): continue # mixins are simple - if getattr(b, '__mixin__', False) == True: + if getattr(b, "__mixin__", False) == True: logger.debug("Adding fields from mixin %r to '%s'", b, cls_name) mixin.update(b.get_flat_type_info(b)) - if '__mixin__' not in cls_dict: - cls_dict['__mixin__'] = False + if "__mixin__" not in cls_dict: + cls_dict["__mixin__"] = False continue if not (extends in (None, b)): - raise Exception("Spyne objects do not support multiple " + raise Exception( + "Spyne objects do not support multiple " "inheritance. Use mixins if you need to reuse " - "fields from multiple classes.") + "fields from multiple classes." + ) if len(base_types) > 0 and issubclass(b, ModelBase): extends = cls_dict["__extends__"] = b - assert extends.__orig__ is None, "You can't inherit from a " \ - "customized class. You should first get your class " \ + assert extends.__orig__ is None, ( + "You can't inherit from a " + "customized class. You should first get your class " "hierarchy right, then start customizing classes." + ) b.get_subclasses.memo.clear() logger.debug("Registering %r as base of '%s'", b, cls_name) - if not ('_type_info' in cls_dict): - cls_dict['_type_info'] = _type_info = TypeInfo() + if not ("_type_info" in cls_dict): + cls_dict["_type_info"] = _type_info = TypeInfo() _type_info.update(base_type_info) class_fields = [] for k, v in cls_dict.items(): - if k.startswith('_'): + if k.startswith("_"): continue - if isinstance(v, tuple) and len(v) == 1 and \ - _get_spyne_type(cls_name, k, v[0]) is not None: - logger.warning(YEL("There seems to be a stray comma in the" - "definition of '%s.%s'.", cls_name, k)) + if ( + isinstance(v, tuple) + and len(v) == 1 + and _get_spyne_type(cls_name, k, v[0]) is not None + ): + logger.warning( + YEL( + "There seems to be a stray comma in the" + "definition of '%s.%s'.", + cls_name, + k, + ) + ) v = _get_spyne_type(cls_name, k, v) @@ -345,10 +372,10 @@ def _get_type_info(cls, cls_name, cls_bases, cls_dict, attrs): _type_info.update(class_fields) else: - _type_info = cls_dict['_type_info'] + _type_info = cls_dict["_type_info"] if not isinstance(_type_info, TypeInfo): - _type_info = cls_dict['_type_info'] = TypeInfo(_type_info) + _type_info = cls_dict["_type_info"] = TypeInfo(_type_info) for k, v in reversed(mixin.items()): _type_info.insert(0, (k, v)) @@ -366,7 +393,7 @@ def __init__(self, *args, **kwargs): def _gen_methods(cls, cls_dict): methods = _MethodsDict() for k, v in cls_dict.items(): - if not k.startswith('_') and hasattr(v, '_is_rpc'): + if not k.startswith("_") and hasattr(v, "_is_rpc"): logger.debug("Registering %s as member method for %r", k, cls) assert cls is not None @@ -390,15 +417,14 @@ def _get_ordered_attributes(cls_name, cls_dict, attrs): # FIXME: Maybe add a warning here? return cls_dict - SUPPORTED_ORDERS = ('random', 'declared') - if (attrs.declare_order is not None and - not attrs.declare_order in SUPPORTED_ORDERS): + SUPPORTED_ORDERS = ("random", "declared") + if attrs.declare_order is not None and not attrs.declare_order in SUPPORTED_ORDERS: msg = "The declare_order attribute value %r is invalid in %s" raise Exception(msg % (attrs.declare_order, cls_name)) declare_order = attrs.declare_order or const.DEFAULT_DECLARE_ORDER - if declare_order is None or declare_order == 'random': + if declare_order is None or declare_order == "random": # support old behaviour cls_dict = dict(cls_dict) @@ -406,22 +432,22 @@ def _get_ordered_attributes(cls_name, cls_dict, attrs): def _sanitize_sqlalchemy_parameters(cls_dict, attrs): - table_name = cls_dict.get('__tablename__', None) + table_name = cls_dict.get("__tablename__", None) if attrs.table_name is None: attrs.table_name = table_name - _cls_table = cls_dict.get('__table__', None) + _cls_table = cls_dict.get("__table__", None) if attrs.sqla_table is None: attrs.sqla_table = _cls_table - metadata = cls_dict.get('__metadata__', None) + metadata = cls_dict.get("__metadata__", None) if attrs.sqla_metadata is None: attrs.sqla_metadata = metadata - margs = cls_dict.get('__mapper_args__', None) + margs = cls_dict.get("__mapper_args__", None) attrs.sqla_mapper_args = _join_args(attrs.sqla_mapper_args, margs) - targs = cls_dict.get('__table_args__', None) + targs = cls_dict.get("__table_args__", None) attrs.sqla_table_args = _join_args(attrs.sqla_table_args, targs) @@ -429,7 +455,7 @@ def _sanitize_type_info(cls_name, _type_info, _type_info_alt): """Make sure _type_info contents are sane""" for k, v in _type_info.items(): - if not isinstance(k, six.string_types): + if not isinstance(k, str): raise ValueError("Invalid class key", k) if not isclass(v): @@ -441,12 +467,11 @@ def _sanitize_type_info(cls_name, _type_info, _type_info_alt): elif not issubclass(v, ModelBase): v = _get_spyne_type(cls_name, k, v) if v is None: - raise ValueError( (cls_name, k, v) ) + raise ValueError((cls_name, k, v)) _type_info[k] = v elif issubclass(v, Array) and len(v._type_info) != 1: - raise Exception("Invalid Array definition in %s.%s." % - (cls_name, k)) + raise Exception("Invalid Array definition in %s.%s." % (cls_name, k)) sub_ns = v.Attributes.sub_ns sub_name = v.Attributes.sub_name @@ -456,22 +481,19 @@ def _sanitize_type_info(cls_name, _type_info, _type_info_alt): elif sub_ns is not None and sub_name is not None: key = "{%s}%s" % (sub_ns, sub_name) if key in _type_info: - raise Exception("%r is already defined: %r" % - (key, _type_info[key])) + raise Exception("%r is already defined: %r" % (key, _type_info[key])) _type_info_alt[key] = v, k elif sub_ns is None: key = sub_name if sub_ns in _type_info: - raise Exception("%r is already defined: %r" % - (key, _type_info[key])) + raise Exception("%r is already defined: %r" % (key, _type_info[key])) _type_info_alt[key] = v, k elif sub_name is None: key = "{%s}%s" % (sub_ns, k) if key in _type_info: - raise Exception("%r is already defined: %r" % - (key, _type_info[key])) + raise Exception("%r is already defined: %r" % (key, _type_info[key])) _type_info_alt[key] = v, k @@ -479,9 +501,9 @@ def _sanitize_type_info(cls_name, _type_info, _type_info_alt): def _process_child_attrs(cls, retval, kwargs): - child_attrs = copy(kwargs.get('child_attrs', None)) - child_attrs_all = kwargs.get('child_attrs_all', None) - child_attrs_noexc = copy(kwargs.get('child_attrs_noexc', None)) + child_attrs = copy(kwargs.get("child_attrs", None)) + child_attrs_all = kwargs.get("child_attrs_all", None) + child_attrs_noexc = copy(kwargs.get("child_attrs_noexc", None)) # add exc=False to child_attrs_noexc if child_attrs_noexc is not None: @@ -491,19 +513,23 @@ def _process_child_attrs(cls, retval, kwargs): child_attrs_all = D_EXC else: - if 'exc' in child_attrs_all and child_attrs_all['exc'] != D_EXC: - logger.warning("Overriding child_attrs_all['exc'] to True " - "for %r", cls) + if "exc" in child_attrs_all and child_attrs_all["exc"] != D_EXC: + logger.warning( + "Overriding child_attrs_all['exc'] to True " "for %r", cls + ) child_attrs_all.update(D_EXC) # update child_attrs_noexc with exc=False for k, v in child_attrs_noexc.items(): - if 'exc' in v: - logger.warning("Overriding 'exc' for %s.%s from " - "child_attrs_noexc with False", cls.get_type_name(), k) + if "exc" in v: + logger.warning( + "Overriding 'exc' for %s.%s from " "child_attrs_noexc with False", + cls.get_type_name(), + k, + ) - v['exc'] = False + v["exc"] = False # update child_attrs with data from child_attrs_noexc if child_attrs is None: @@ -516,8 +542,11 @@ def _process_child_attrs(cls, retval, kwargs): for k, v in child_attrs_noexc.items(): if k in child_attrs: - logger.warning("Overriding child_attrs for %s.%s from " - "child_attrs_noexc", cls.get_type_name(), k) + logger.warning( + "Overriding child_attrs for %s.%s from " "child_attrs_noexc", + cls.get_type_name(), + k, + ) child_attrs[k] = v @@ -530,7 +559,8 @@ def _process_child_attrs(cls, retval, kwargs): if retval.__extends__ is not None: retval.__extends__ = retval.__extends__.customize( - child_attrs_all=child_attrs_all) + child_attrs_all=child_attrs_all + ) retval.Attributes._delayed_child_attrs_all = child_attrs_all @@ -545,8 +575,7 @@ def _process_child_attrs(cls, retval, kwargs): base_fti = {} if retval.__extends__ is not None: - retval.__extends__ = retval.__extends__.customize( - child_attrs=child_attrs) + retval.__extends__ = retval.__extends__.customize(child_attrs=child_attrs) base_fti = retval.__extends__.get_flat_type_info(retval.__extends__) for k, v in child_attrs.items(): @@ -557,10 +586,13 @@ def _process_child_attrs(cls, retval, kwargs): def recust_selfref(selfref, cls): if len(selfref.customize_args) > 0 or len(selfref.customize_kwargs) > 0: - logger.debug("Replace self reference with %r with *%r and **%r", - cls, selfref.customize_args, selfref.customize_kwargs) - return cls.customize(*selfref.customize_args, - **selfref.customize_kwargs) + logger.debug( + "Replace self reference with %r with *%r and **%r", + cls, + selfref.customize_args, + selfref.customize_kwargs, + ) + return cls.customize(*selfref.customize_args, **selfref.customize_kwargs) logger.debug("Replace self reference with %r", cls) return cls @@ -573,10 +605,6 @@ def _set_member_default(inst, key, cls, attr): return False if def_fac is not None: - if six.PY2 and hasattr(def_fac, 'im_func'): - # unbound-method error workaround. huh. - def_fac = def_fac.im_func - dval = def_fac() # should not check for read-only for default values @@ -595,14 +623,13 @@ def _set_member_default(inst, key, cls, attr): def _is_sqla_array(cls, attr): # inner object is complex - ret1 = issubclass(cls, Array) and \ - hasattr(cls.get_inner_type(), '_sa_class_manager') + ret1 = issubclass(cls, Array) and hasattr(cls.get_inner_type(), "_sa_class_manager") # inner object is primitive ret2 = issubclass(cls, Array) and attr.store_as is not None # object is a bare array - ret3 = attr.max_occurs > 1 and hasattr(cls, '_sa_class_manager') + ret3 = attr.max_occurs > 1 and hasattr(cls, "_sa_class_manager") return ret1 or ret2 or ret3 @@ -614,7 +641,7 @@ def _init_member(inst, key, cls, attr): return # we skip read-only properties if _set_member_default(inst, key, cls, attr): - return + return # sqlalchemy objects do their own init. if _is_sqla_array(cls, attr): @@ -628,7 +655,7 @@ def _init_member(inst, key, cls, attr): return # sqlalchemy objects do their own init. - if hasattr(inst.__class__, '_sa_class_manager'): + if hasattr(inst.__class__, "_sa_class_manager"): # except the attributes that sqlalchemy doesn't know about if attr.exc_db: setattr(inst, key, None) @@ -641,7 +668,7 @@ def _init_member(inst, key, cls, attr): setattr(inst, key, None) -class ComplexModelMeta(with_metaclass(Prepareable, type(ModelBase))): +class ComplexModelMeta(type(ModelBase), metaclass=Prepareable): """This metaclass sets ``_type_info``, ``__type_name__`` and ``__extends__`` which are going to be used for (de)serialization and schema generation. """ @@ -650,8 +677,9 @@ def __new__(cls, cls_name, cls_bases, cls_dict): """This function initializes the class and registers attributes.""" attrs = _gen_attrs(cls_bases, cls_dict) - assert issubclass(attrs, ComplexModelBase.Attributes), \ - ("%r must be a ComplexModelBase.Attributes subclass" % attrs) + assert issubclass(attrs, ComplexModelBase.Attributes), ( + "%r must be a ComplexModelBase.Attributes subclass" % attrs + ) cls_dict = _get_ordered_attributes(cls_name, cls_dict, attrs) @@ -662,16 +690,15 @@ def __new__(cls, cls_name, cls_bases, cls_dict): _type_info = _get_type_info(cls, cls_name, cls_bases, cls_dict, attrs) # used for sub_name and sub_ns - _type_info_alt = cls_dict['_type_info_alt'] = TypeInfo() + _type_info_alt = cls_dict["_type_info_alt"] = TypeInfo() for b in cls_bases: - if hasattr(b, '_type_info_alt'): + if hasattr(b, "_type_info_alt"): _type_info_alt.update(b._type_info_alt) _sanitize_type_info(cls_name, _type_info, _type_info_alt) _sanitize_sqlalchemy_parameters(cls_dict, attrs) - return super(ComplexModelMeta, cls).__new__(cls, - cls_name, cls_bases, cls_dict) + return super(ComplexModelMeta, cls).__new__(cls, cls_name, cls_bases, cls_dict) def __init__(self, cls_name, cls_bases, cls_dict): type_info = self._type_info @@ -700,10 +727,10 @@ def __init__(self, cls_name, cls_bases, cls_dict): # replace SelfRerefence in arrays elif issubclass(v, Array): - v2, = v._type_info.values() + (v2,) = v._type_info.values() while issubclass(v2, Array): v = v2 - v2, = v2._type_info.values() + (v2,) = v2._type_info.values() if issubclass(v2, SelfReference): v._set_serializer(recust_selfref(v2, self)) @@ -732,8 +759,10 @@ def _get_prop(self): def _set_prop(self, val): if not (val is None or isinstance(val, v.Value)): - raise ValueError("Invalid value %r, " - "should be an instance of %r" % (val, v.Value)) + raise ValueError( + "Invalid value %r, " + "should be an instance of %r" % (val, v.Value) + ) self.__dict__[k] = val @@ -758,8 +787,11 @@ def _set_prop(self, val): gen_spyne_info(self) # For spyne objects being converted to a sqlalchemy table - elif meta is not None and (tn is not None or t is not None) and \ - len(self._type_info) > 0: + elif ( + meta is not None + and (tn is not None or t is not None) + and len(self._type_info) > 0 + ): from spyne.store.relational import gen_sqla_info gen_sqla_info(self, cls_bases) @@ -771,9 +803,6 @@ def _set_prop(self, val): # declare them in the same order in the WSDL. # # For Python 3 __prepare__ works out of the box, see PEP 3115. - # But we use `Preparable` metaclass for both Python 2 and Python 3 to - # support six.add_metaclass decorator - # @classmethod def __prepare__(mcs, name, bases, **kwds): return odict() @@ -887,25 +916,27 @@ def __init__(self, *args, **kwargs): fti = cls.get_flat_type_info(cls) if cls.__orig__ is not None: - logger.warning("%r(0x%X) seems to be a customized class. It is not " - "supposed to be instantiated. You have been warned.", - cls, id(cls)) + logger.warning( + "%r(0x%X) seems to be a customized class. It is not " + "supposed to be instantiated. You have been warned.", + cls, + id(cls), + ) logger.debug(traceback.format_stack()) if cls_attr._xml_tag_body_as is not None: - for arg, (xtba_key, xtba_type) in \ - zip(args, cls_attr._xml_tag_body_as): + for arg, (xtba_key, xtba_type) in zip(args, cls_attr._xml_tag_body_as): if xtba_key is not None and len(args) == 1: attr = xtba_type.Attributes _init_member(self, xtba_key, xtba_type, attr) - self._safe_set(xtba_key, arg, xtba_type, - xtba_type.Attributes) + self._safe_set(xtba_key, arg, xtba_type, xtba_type.Attributes) elif len(args) > 0: raise TypeError( - "Positional argument is only for ComplexModels " - "with XmlData field. You must use keyword " - "arguments in any other case.") + "Positional argument is only for ComplexModels " + "with XmlData field. You must use keyword " + "arguments in any other case." + ) for k, v in fti.items(): attr = v.Attributes @@ -930,10 +961,16 @@ def __getitem__(self, i): return retval def __repr__(self): - return "%s(%s)" % (self.get_type_name(), ', '.join( - ['%s=%r' % (k, self.__dict__.get(k)) + return "%s(%s)" % ( + self.get_type_name(), + ", ".join( + [ + "%s=%r" % (k, self.__dict__.get(k)) for k in self.__class__.get_flat_type_info(self.__class__) - if self.__dict__.get(k, None) is not None])) + if self.__dict__.get(k, None) is not None + ] + ), + ) def _safe_set(self, key, value, t, attrs): if attrs.read_only: @@ -943,15 +980,16 @@ def _safe_set(self, key, value, t, attrs): setattr(self, key, value) except AttributeError as e: logger.exception(e) - raise AttributeError("can't set %r attribute %s to %r" % - (self.__class__, key, value)) + raise AttributeError( + "can't set %r attribute %s to %r" % (self.__class__, key, value) + ) return True @classmethod def get_identifiers(cls): for k, v in cls.get_flat_type_info(cls).items(): - if getattr(v.Attributes, 'primary_key', None): + if getattr(v.Attributes, "primary_key", None): yield k, v @classmethod @@ -965,10 +1003,13 @@ def as_dict(self): not nullable attributes. """ - return dict(( - (k, getattr(self, k)) for k in self.get_flat_type_info(self.__class__) - if getattr(self, k) is not None - )) + return dict( + ( + (k, getattr(self, k)) + for k in self.get_flat_type_info(self.__class__) + if getattr(self, k) is not None + ) + ) @classmethod def get_serialization_instance(cls, value): @@ -993,8 +1034,9 @@ def get_serialization_instance(cls, value): keys = cls.get_flat_type_info(cls).keys() if not len(value) <= len(keys): - logger.error("\n\tcls: %r" "\n\tvalue: %r" "\n\tkeys: %r", - cls, value, keys) + logger.error( + "\n\tcls: %r" "\n\tvalue: %r" "\n\tkeys: %r", cls, value, keys + ) raise ValueError("Impossible sequence to instance conversion") cls_orig = cls @@ -1078,7 +1120,8 @@ def get_simple_type_info(cls, hier_delim="."): names. Default is ``'.'``. """ return ComplexModelBase.get_simple_type_info_with_prot( - cls, hier_delim=hier_delim) + cls, hier_delim=hier_delim + ) @staticmethod @memoize @@ -1094,13 +1137,15 @@ def get_simple_type_info_with_prot(cls, prot=None, hier_delim="."): for k, v in fti.items(): sub_name = k - queue.append(( - (k,), - v, - (sub_name,), - (_is_array(v),), - cls, - )) + queue.append( + ( + (k,), + v, + (sub_name,), + (_is_array(v),), + cls, + ) + ) else: for k, v in fti.items(): @@ -1109,13 +1154,15 @@ def get_simple_type_info_with_prot(cls, prot=None, hier_delim="."): if sub_name is None: sub_name = k - queue.append(( - (k,), - v, - (sub_name,), - (_is_array(v),), - cls, - )) + queue.append( + ( + (k,), + v, + (sub_name,), + (_is_array(v),), + cls, + ) + ) tags.add(cls) @@ -1123,7 +1170,7 @@ def get_simple_type_info_with_prot(cls, prot=None, hier_delim="."): keys, v, prefix, is_array, parent = queue.popleft() k = keys[-1] if issubclass(v, Array) and v.Attributes.max_occurs == 1: - v, = v._type_info.values() + (v,) = v._type_info.values() key = hier_delim.join(prefix) if issubclass(v, ComplexModelBase): @@ -1140,13 +1187,15 @@ def get_simple_type_info_with_prot(cls, prot=None, hier_delim="."): if prot is None: for k2, v2 in v.get_flat_type_info(v).items(): sub_name = k2 - queue.append(( - keys + (k2,), - v2, - prefix + (sub_name,), - is_array + (_is_array(v),), - v - )) + queue.append( + ( + keys + (k2,), + v2, + prefix + (sub_name,), + is_array + (_is_array(v),), + v, + ) + ) else: for k2, v2 in v.get_flat_type_info(v).items(): @@ -1155,20 +1204,21 @@ def get_simple_type_info_with_prot(cls, prot=None, hier_delim="."): if sub_name is None: sub_name = k2 - queue.append(( - keys + (k2,), - v2, - prefix + (sub_name,), - is_array + (_is_array(v),), - v, - )) + queue.append( + ( + keys + (k2,), + v2, + prefix + (sub_name,), + is_array + (_is_array(v),), + v, + ) + ) else: value = retval.get(key, None) if value is not None: - raise ValueError("%r.%s conflicts with %r" % - (cls, k, value.path)) + raise ValueError("%r.%s conflicts with %r" % (cls, k, value.path)) retval[key] = _SimpleTypeInfoElement( path=keys, @@ -1195,8 +1245,7 @@ def resolve_namespace(cls, default_ns, tags=None): continue if v.__type_name__ is ModelBase.Empty: - v._fill_empty_type_name(cls.get_namespace(), - cls.get_type_name(), k) + v._fill_empty_type_name(cls.get_namespace(), cls.get_type_name(), k) v.resolve_namespace(v, default_ns, tags) @@ -1214,11 +1263,17 @@ def resolve_namespace(cls, default_ns, tags=None): def produce(namespace, type_name, members): """Lets you create a class programmatically.""" - return ComplexModelMeta(type_name, (ComplexModel,), odict({ - '__namespace__': namespace, - '__type_name__': type_name, - '_type_info': TypeInfo(members), - })) + return ComplexModelMeta( + type_name, + (ComplexModel,), + odict( + { + "__namespace__": namespace, + "__type_name__": type_name, + "_type_info": TypeInfo(members), + } + ), + ) @classmethod def customize(cls, **kwargs): @@ -1230,14 +1285,14 @@ def customize(cls, **kwargs): could cause memory leaks. You have been warned. """ - store_as = apply_pssm(kwargs.get('store_as', None)) + store_as = apply_pssm(kwargs.get("store_as", None)) if store_as is not None: - kwargs['store_as'] = store_as + kwargs["store_as"] = store_as cls_name, cls_bases, cls_dict = cls._s_customize(**kwargs) - cls_dict['__module__'] = cls.__module__ - if '__extends__' not in cls_dict: - cls_dict['__extends__'] = cls.__extends__ + cls_dict["__module__"] = cls.__module__ + if "__extends__" not in cls_dict: + cls_dict["__extends__"] = cls.__extends__ retval = type(cls_name, cls_bases, cls_dict) retval._type_info = TypeInfo(cls._type_info) @@ -1274,7 +1329,7 @@ def customize(cls, **kwargs): @classmethod def _process_variants(cls, retval): - orig = getattr(retval, '__orig__', None) + orig = getattr(retval, "__orig__", None) if orig is not None: if orig.Attributes._variants is None: orig.Attributes._variants = WeakKeyDictionary() @@ -1284,7 +1339,7 @@ def _process_variants(cls, retval): @classmethod def _append_field_impl(cls, field_name, field_type): - assert isinstance(field_name, string_types) + assert isinstance(field_name, str) dcaa = cls.Attributes._delayed_child_attrs_all if dcaa is not None: @@ -1321,7 +1376,7 @@ def _insert_to_variants(cls, index, field_name, field_type): @classmethod def _insert_field_impl(cls, index, field_name, field_type): assert isinstance(index, int) - assert isinstance(field_name, string_types) + assert isinstance(field_name, str) dcaa = cls.Attributes._delayed_child_attrs_all if dcaa is not None: @@ -1351,7 +1406,7 @@ def _replace_in_variants(cls, field_name, field_type): @classmethod def _replace_field_impl(cls, field_name, field_type): - assert isinstance(field_name, string_types) + assert isinstance(field_name, str) cls._type_info[field_name] = field_type @@ -1390,8 +1445,7 @@ def init_from(cls, other, **kwargs): @classmethod def __respawn__(cls, ctx=None, filters=None): - if ctx is not None and ctx.in_object is not None and \ - len(ctx.in_object) > 0: + if ctx is not None and ctx.in_object is not None and len(ctx.in_object) > 0: retval = next(iter(ctx.in_object)) if retval is not None: return retval @@ -1400,8 +1454,7 @@ def __respawn__(cls, ctx=None, filters=None): return cls.get_deserialization_instance(ctx) -@add_metaclass(ComplexModelMeta) -class ComplexModel(ComplexModelBase): +class ComplexModel(ComplexModelBase, metaclass=ComplexModelMeta): """The general complexType factory. The __call__ method of this class will return instances, contrary to primivites where the same call will result in customized duplicates of the original class definition. @@ -1410,8 +1463,7 @@ class ComplexModel(ComplexModelBase): """ -@add_metaclass(ComplexModelMeta) -class Array(ComplexModelBase): +class Array(ComplexModelBase, metaclass=ComplexModelMeta): """This class generates a ComplexModel child that has one attribute that has the same name as the serialized class. It's contained in a Python list. """ @@ -1422,20 +1474,20 @@ class Attributes(ComplexModelBase.Attributes): def __new__(cls, serializer, member_name=None, wrapped=True, **kwargs): if not wrapped: if serializer.Attributes.max_occurs == 1: - kwargs['max_occurs'] = 'unbounded' + kwargs["max_occurs"] = "unbounded" return serializer.customize(**kwargs) retval = cls.customize(**kwargs) - _serializer = _get_spyne_type(cls.__name__, '__serializer__', serializer) + _serializer = _get_spyne_type(cls.__name__, "__serializer__", serializer) if _serializer is None: raise ValueError("serializer=%r is not a valid spyne type" % serializer) if issubclass(_serializer, SelfReference): - # hack to make sure the array passes ComplexModel sanity checks - # that are there to prevent empty arrays. - retval._type_info = {'_bogus': _serializer} + # hack to make sure the array passes ComplexModel sanity checks + # that are there to prevent empty arrays. + retval._type_info = {"_bogus": _serializer} else: retval._set_serializer(_serializer, member_name) @@ -1450,30 +1502,28 @@ def _fill_empty_type_name(cls, parent_ns, parent_tn, k): cls.__namespace__ = parent_ns tn = "%s_%s%s" % (parent_tn, k, const.TYPE_SUFFIX) - child_v, = cls._type_info.values() + (child_v,) = cls._type_info.values() child_v.__type_name__ = tn cls._type_info = TypeInfo({tn: child_v}) - cls.__type_name__ = '%s%s%s' % (const.ARRAY_PREFIX, tn, - const.ARRAY_SUFFIX) + cls.__type_name__ = "%s%s%s" % (const.ARRAY_PREFIX, tn, const.ARRAY_SUFFIX) extends = child_v.__extends__ while extends is not None and extends.get_type_name() is cls.Empty: - extends._fill_empty_type_name(parent_ns, parent_tn, - k + const.PARENT_SUFFIX) + extends._fill_empty_type_name(parent_ns, parent_tn, k + const.PARENT_SUFFIX) extends = extends.__extends__ @classmethod def customize(cls, **kwargs): - serializer_attrs = kwargs.get('serializer_attrs', None) + serializer_attrs = kwargs.get("serializer_attrs", None) if serializer_attrs is None: return super(Array, cls).customize(**kwargs) - del kwargs['serializer_attrs'] + del kwargs["serializer_attrs"] - logger.debug('Pass serializer attrs %r', serializer_attrs) + logger.debug("Pass serializer attrs %r", serializer_attrs) - serializer, = cls._type_info.values() + (serializer,) = cls._type_info.values() return cls(serializer.customize(**serializer_attrs)).customize(**kwargs) @classmethod @@ -1487,16 +1537,18 @@ def _set_serializer(cls, serializer, member_name=None): if member_name is None: member_name = serializer.get_type_name() - cls.__type_name__ = '%s%s%s' % (const.ARRAY_PREFIX, - serializer.get_type_name(), - const.ARRAY_SUFFIX) + cls.__type_name__ = "%s%s%s" % ( + const.ARRAY_PREFIX, + serializer.get_type_name(), + const.ARRAY_SUFFIX, + ) # hack to default to unbounded arrays when the user didn't specify # max_occurs. if serializer.Attributes.max_occurs == 1: - serializer = serializer.customize(max_occurs=decimal.Decimal('inf')) + serializer = serializer.customize(max_occurs=decimal.Decimal("inf")) - assert isinstance(member_name, string_types), member_name + assert isinstance(member_name, str), member_name cls._type_info = TypeInfo({member_name: serializer}) # the array belongs to its child's namespace, it doesn't have its own @@ -1560,6 +1612,7 @@ class Push(PushBase): stuff as `deferToThread` is not guaranteed to restore original thread context. """ + pass @@ -1605,8 +1658,7 @@ def TTableModel(metadata=None, base=None, metaclass=None): if metaclass is None: metaclass = ComplexModelMeta - @add_metaclass(metaclass) - class TableModel(base): + class TableModel(base, metaclass=metaclass): class Attributes(ComplexModelBase.Attributes): sqla_metadata = metadata if metadata is not None else MetaData() @@ -1621,14 +1673,17 @@ def Mandatory(cls, **_kwargs): kwargs = dict(min_occurs=1, nillable=False) if cls.get_type_name() is not cls.Empty: - kwargs['type_name'] = '%s%s%s' % (const.MANDATORY_PREFIX, - cls.get_type_name(), const.MANDATORY_SUFFIX) + kwargs["type_name"] = "%s%s%s" % ( + const.MANDATORY_PREFIX, + cls.get_type_name(), + const.MANDATORY_SUFFIX, + ) kwargs.update(_kwargs) if issubclass(cls, Unicode): kwargs.update(dict(min_len=1)) elif issubclass(cls, Array): - (k,v), = cls._type_info.items() + ((k, v),) = cls._type_info.items() if v.Attributes.min_occurs == 0: cls._type_info[k] = Mandatory(v) diff --git a/spyne/model/enum.py b/spyne/model/enum.py index ec0901d21..1dbc31185 100644 --- a/spyne/model/enum.py +++ b/spyne/model/enum.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -21,6 +20,7 @@ # adapted from: http://code.activestate.com/recipes/413486/ + class EnumBase(SimpleModel): __namespace__ = None @@ -32,9 +32,8 @@ def resolve_namespace(cls, default_ns, tags=None): @staticmethod def validate_string(cls, value): - return ( SimpleModel.validate_string(cls, value) - and value in cls.__values__ - ) + return SimpleModel.validate_string(cls, value) and value in cls.__values__ + def Enum(*values, **kwargs): """The enum type that can only return ``True`` when compared to types of @@ -59,17 +58,17 @@ def Enum(*values, **kwargs): In the above example, ``SomeEnum`` can be used as a regular Spyne model. """ - type_name = kwargs.get('type_name', None) - docstr = kwargs.get('doc', '') + type_name = kwargs.get("type_name", None) + docstr = kwargs.get("doc", "") if type_name is None: raise Exception("Please specify 'type_name' as a keyword argument") assert len(values) > 0, "Empty enums are meaningless" - maximum = len(values) # to make __invert__ work + maximum = len(values) # to make __invert__ work class EnumValue(object): - __slots__ = ('__value',) + __slots__ = ("__value",) def __init__(self, value): self.__value = value @@ -110,10 +109,10 @@ def __getitem__(self, i): return values[i] def __repr__(self): - return 'Enum' + str(enumerate(values)) + return "Enum" + str(enumerate(values)) def __str__(self): - return 'enum ' + str(values) + return "enum " + str(values) for i, v in enumerate(values): setattr(EnumType, v, EnumValue(i)) diff --git a/spyne/model/fault.py b/spyne/model/fault.py index 89c9f2983..ca998315a 100644 --- a/spyne/model/fault.py +++ b/spyne/model/fault.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -17,35 +16,32 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # -from warnings import warn from collections import defaultdict +from warnings import warn import spyne.const - +from spyne.model.complex import ComplexModelBase, ComplexModelMeta from spyne.model.primitive import Any -from spyne.util.six import add_metaclass - -from spyne.model.complex import ComplexModelMeta -from spyne.model.complex import ComplexModelBase - class FaultMeta(ComplexModelMeta): def __init__(self, cls_name, cls_bases, cls_dict): super(FaultMeta, self).__init__(cls_name, cls_bases, cls_dict) - code = cls_dict.get('CODE', None) + code = cls_dict.get("CODE", None) if code is not None: target = Fault.REGISTERED[code] target.add(self) if spyne.const.WARN_ON_DUPLICATE_FAULTCODE and len(target) > 1: - warn("Duplicate faultcode {} detected for classes {}" - .format(code, target)) + warn( + "Duplicate faultcode {} detected for classes {}".format( + code, target + ) + ) -@add_metaclass(FaultMeta) -class Fault(ComplexModelBase, Exception): +class Fault(ComplexModelBase, Exception, metaclass=FaultMeta): """Use this class as a base for all public exceptions. The Fault object adheres to the `SOAP 1.1 Fault definition `_, @@ -80,8 +76,14 @@ class Fault(ComplexModelBase, Exception): CODE = None - def __init__(self, faultcode='Server', faultstring="", faultactor="", - detail=None, lang=spyne.DEFAULT_LANGUAGE): + def __init__( + self, + faultcode="Server", + faultstring="", + faultactor="", + detail=None, + lang=spyne.DEFAULT_LANGUAGE, + ): self.faultcode = faultcode self.faultstring = faultstring or self.get_type_name() self.faultactor = faultactor @@ -96,11 +98,18 @@ def __str__(self): def __repr__(self): if self.detail is None: - return "%s(%s: %r)" % (self.__class__.__name__, - self.faultcode, self.faultstring) - - return "%s(%s: %r detail: %r)" % (self.__class__.__name__, - self.faultcode, self.faultstring, self.detail) + return "%s(%s: %r)" % ( + self.__class__.__name__, + self.faultcode, + self.faultstring, + ) + + return "%s(%s: %r detail: %r)" % ( + self.__class__.__name__, + self.faultcode, + self.faultstring, + self.detail, + ) @staticmethod def to_dict(cls, value, prot): @@ -111,7 +120,7 @@ def to_dict(cls, value, prot): "detail": str(value), } - retval = { + retval = { "faultcode": value.faultcode, "faultstring": value.faultstring, } @@ -138,9 +147,9 @@ def to_list(cls, value, prot=None): if not issubclass(cls, Fault): return [ "Server.Unknown", # faultcode - cls.__name__, # faultstring - "", # faultactor - str(value), # detail + cls.__name__, # faultstring + "", # faultactor + str(value), # detail ] retval = [ @@ -163,9 +172,9 @@ def to_list(cls, value, prot=None): @classmethod def to_bytes_iterable(cls, value): return [ - value.faultcode.encode('utf8'), - b'\n\n', - value.faultstring.encode('utf8'), + value.faultcode.encode("utf8"), + b"\n\n", + value.faultstring.encode("utf8"), ] def detail_to_doc(self, prot): @@ -173,3 +182,17 @@ def detail_to_doc(self, prot): def detail_from_doc(self, prot, doc): self.detail = doc + + +class ValidationError(Fault): + """Raised when the input stream does not adhere to type constraints.""" + + CODE = "Client.ValidationError" + + def __init__(self, obj, custom_msg="The value %r could not be validated."): + try: + msg = custom_msg % (obj,) + except TypeError: + msg = custom_msg + + super(ValidationError, self).__init__(self.CODE, msg) diff --git a/spyne/model/primitive/__init__.py b/spyne/model/primitive/__init__.py index 64f1ba467..c51e5098d 100644 --- a/spyne/model/primitive/__init__.py +++ b/spyne/model/primitive/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,93 +17,96 @@ # NATIVE_MAP = {} -string_encoding = 'UTF-8' # ??? - -from spyne.model.primitive._base import Any -from spyne.model.primitive._base import AnyDict -from spyne.model.primitive._base import AnyHtml -from spyne.model.primitive._base import AnyXml -from spyne.model.primitive._base import Boolean - -from spyne.model.primitive.string import Unicode -from spyne.model.primitive.string import String -from spyne.model.primitive.string import AnyUri -from spyne.model.primitive.string import Uuid -from spyne.model.primitive.string import ImageUri -from spyne.model.primitive.string import Ltree -from spyne.model.primitive.string import MimeType -from spyne.model.primitive.string import MimeTypeStrict -from spyne.model.primitive.string import MediaType -from spyne.model.primitive.string import MediaTypeStrict - -from spyne.model.primitive.xml import ID -from spyne.model.primitive.xml import Token -from spyne.model.primitive.xml import NMToken -from spyne.model.primitive.xml import Name -from spyne.model.primitive.xml import NCName -from spyne.model.primitive.xml import QName -from spyne.model.primitive.xml import Language -from spyne.model.primitive.xml import NormalizedString - -from spyne.model.primitive.spatial import Point -from spyne.model.primitive.spatial import Line -from spyne.model.primitive.spatial import LineString -from spyne.model.primitive.spatial import Polygon -from spyne.model.primitive.spatial import MultiPoint -from spyne.model.primitive.spatial import MultiLine -from spyne.model.primitive.spatial import MultiLineString -from spyne.model.primitive.spatial import MultiPolygon +string_encoding = "UTF-8" # ??? + +from spyne.model.primitive._base import Any, AnyDict, AnyHtml, AnyXml, Boolean # Date/Time types -from spyne.model.primitive.datetime import Date -from spyne.model.primitive.datetime import DateTime -from spyne.model.primitive.datetime import Duration -from spyne.model.primitive.datetime import Time +from spyne.model.primitive.datetime import Date, DateTime, Duration, Time +from spyne.model.primitive.network import ( + IpAddress, + Ipv4Address, + Ipv6Address, + MacAddress, +) # Numbers -from spyne.model.primitive.number import Decimal -from spyne.model.primitive.number import Double -from spyne.model.primitive.number import Float - -from spyne.model.primitive.number import Integer8 -from spyne.model.primitive.number import Byte -from spyne.model.primitive.number import Integer16 -from spyne.model.primitive.number import Short -from spyne.model.primitive.number import Integer32 -from spyne.model.primitive.number import Int -from spyne.model.primitive.number import Integer64 -from spyne.model.primitive.number import Long -from spyne.model.primitive.number import Integer -from spyne.model.primitive.number import NumberLimitsWarning - -from spyne.model.primitive.number import UnsignedInteger8 -from spyne.model.primitive.number import UnsignedByte -from spyne.model.primitive.number import UnsignedInteger16 -from spyne.model.primitive.number import UnsignedShort -from spyne.model.primitive.number import UnsignedInteger32 -from spyne.model.primitive.number import UnsignedInt -from spyne.model.primitive.number import UnsignedInteger64 -from spyne.model.primitive.number import UnsignedLong -from spyne.model.primitive.number import NonNegativeInteger # Xml Schema calls it so -from spyne.model.primitive.number import UnsignedInteger - -from spyne.model.primitive.network import MacAddress -from spyne.model.primitive.network import IpAddress -from spyne.model.primitive.network import Ipv4Address -from spyne.model.primitive.network import Ipv6Address +from spyne.model.primitive.number import NonNegativeInteger # Xml Schema calls it so +from spyne.model.primitive.number import ( + Byte, + Decimal, + Double, + Float, + Int, + Integer, + Integer8, + Integer16, + Integer32, + Integer64, + Long, + NumberLimitsWarning, + Short, + UnsignedByte, + UnsignedInt, + UnsignedInteger, + UnsignedInteger8, + UnsignedInteger16, + UnsignedInteger32, + UnsignedInteger64, + UnsignedLong, + UnsignedShort, +) +from spyne.model.primitive.spatial import ( + Line, + LineString, + MultiLine, + MultiLineString, + MultiPoint, + MultiPolygon, + Point, + Polygon, +) +from spyne.model.primitive.string import ( + AnyUri, + ImageUri, + Ltree, + MediaType, + MediaTypeStrict, + MimeType, + MimeTypeStrict, + String, + Unicode, + Uuid, +) +from spyne.model.primitive.xml import ( + ID, + Language, + Name, + NCName, + NMToken, + NormalizedString, + QName, + Token, +) # This class is DEPRECATED. Use the spyne.model.Mandatory like this: # >>> from spyne.model import Mandatory as M, Unicode # >>> MandatoryEmail = M(Unicode(pattern='[^@]+@[^@]+')) class Mandatory: - Unicode = Unicode(type_name="MandatoryString", min_occurs=1, nillable=False, min_len=1) - String = String(type_name="MandatoryString", min_occurs=1, nillable=False, min_len=1) + Unicode = Unicode( + type_name="MandatoryString", min_occurs=1, nillable=False, min_len=1 + ) + String = String( + type_name="MandatoryString", min_occurs=1, nillable=False, min_len=1 + ) AnyXml = AnyXml(type_name="MandatoryXml", min_occurs=1, nillable=False) AnyDict = AnyDict(type_name="MandatoryDict", min_occurs=1, nillable=False) AnyUri = AnyUri(type_name="MandatoryUri", min_occurs=1, nillable=False, min_len=1) - ImageUri = ImageUri(type_name="MandatoryImageUri", min_occurs=1, nillable=False, min_len=1) + ImageUri = ImageUri( + type_name="MandatoryImageUri", min_occurs=1, nillable=False, min_len=1 + ) Boolean = Boolean(type_name="MandatoryBoolean", min_occurs=1, nillable=False) @@ -128,11 +130,21 @@ class Mandatory: Short = Integer16 Byte = Integer8 - UnsignedInteger = UnsignedInteger(type_name="MandatoryUnsignedInteger", min_occurs=1, nillable=False) - UnsignedInteger64 = UnsignedInteger64(type_name="MandatoryUnsignedLong", min_occurs=1, nillable=False) - UnsignedInteger32 = UnsignedInteger32(type_name="MandatoryUnsignedInt", min_occurs=1, nillable=False) - UnsignedInteger16 = UnsignedInteger16(type_name="MandatoryUnsignedShort", min_occurs=1, nillable=False) - UnsignedInteger8 = UnsignedInteger8(type_name="MandatoryUnsignedByte", min_occurs=1, nillable=False) + UnsignedInteger = UnsignedInteger( + type_name="MandatoryUnsignedInteger", min_occurs=1, nillable=False + ) + UnsignedInteger64 = UnsignedInteger64( + type_name="MandatoryUnsignedLong", min_occurs=1, nillable=False + ) + UnsignedInteger32 = UnsignedInteger32( + type_name="MandatoryUnsignedInt", min_occurs=1, nillable=False + ) + UnsignedInteger16 = UnsignedInteger16( + type_name="MandatoryUnsignedShort", min_occurs=1, nillable=False + ) + UnsignedInteger8 = UnsignedInteger8( + type_name="MandatoryUnsignedByte", min_occurs=1, nillable=False + ) UnsignedLong = UnsignedInteger64 UnsignedInt = UnsignedInteger32 @@ -146,10 +158,16 @@ class Mandatory: LineString = Line Polygon = Polygon(type_name="Polygon", min_len=1, min_occurs=1, nillable=False) - MultiPoint = MultiPoint(type_name="MandatoryMultiPoint", min_len=1, min_occurs=1, nillable=False) - MultiLine = MultiLine(type_name="MandatoryMultiLineString", min_len=1, min_occurs=1, nillable=False) + MultiPoint = MultiPoint( + type_name="MandatoryMultiPoint", min_len=1, min_occurs=1, nillable=False + ) + MultiLine = MultiLine( + type_name="MandatoryMultiLineString", min_len=1, min_occurs=1, nillable=False + ) MultiLineString = MultiLine - MultiPolygon = MultiPolygon(type_name="MandatoryMultiPolygon", min_len=1, min_occurs=1, nillable=False) + MultiPolygon = MultiPolygon( + type_name="MandatoryMultiPolygon", min_len=1, min_occurs=1, nillable=False + ) assert Mandatory.Long == Mandatory.Integer64 diff --git a/spyne/model/primitive/_base.py b/spyne/model/primitive/_base.py index d6ea85fdc..75e7db6d3 100644 --- a/spyne/model/primitive/_base.py +++ b/spyne/model/primitive/_base.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -25,12 +24,11 @@ See :mod:`spyne.protocol._model` for {to,from}_string implementations. """ - from __future__ import absolute_import from spyne.model import SimpleModel +from spyne.model._base import apply_pssm, json, msgpack, xml from spyne.model.primitive import NATIVE_MAP -from spyne.model._base import apply_pssm, msgpack, xml, json def re_match_with_span(attr, value): @@ -49,7 +47,7 @@ class AnyXml(SimpleModel): """An xml node that can contain any number of sub nodes. It's represented by an ElementTree object.""" - __type_name__ = 'anyType' + __type_name__ = "anyType" class Attributes(SimpleModel.Attributes): namespace = None @@ -65,24 +63,24 @@ def customize(cls, **kwargs): """Duplicates cls and overwrites the values in ``cls.Attributes`` with ``**kwargs`` and returns the new class.""" - store_as = apply_pssm(kwargs.get('store_as', None)) + store_as = apply_pssm(kwargs.get("store_as", None)) if store_as is not None: - kwargs['store_as'] = store_as + kwargs["store_as"] = store_as return super(Any, cls).customize(**kwargs) class AnyHtml(SimpleModel): - __type_name__ = 'string' + __type_name__ = "string" @classmethod def customize(cls, **kwargs): """Duplicates cls and overwrites the values in ``cls.Attributes`` with ``**kwargs`` and returns the new class.""" - store_as = apply_pssm(kwargs.get('store_as', None)) + store_as = apply_pssm(kwargs.get("store_as", None)) if store_as is not None: - kwargs['store_as'] = store_as + kwargs["store_as"] = store_as return super(AnyHtml, cls).customize(**kwargs) @@ -92,7 +90,7 @@ class AnyDict(SimpleModel): types. Its serialization is protocol-dependent. """ - __type_name__ = 'anyType' + __type_name__ = "anyType" Value = dict class Attributes(SimpleModel.Attributes): @@ -106,9 +104,9 @@ def customize(cls, **kwargs): """Duplicates cls and overwrites the values in ``cls.Attributes`` with ``**kwargs`` and returns the new class.""" - store_as = apply_pssm(kwargs.get('store_as', None)) + store_as = apply_pssm(kwargs.get("store_as", None)) if store_as is not None: - kwargs['store_as'] = store_as + kwargs["store_as"] = store_as return super(AnyDict, cls).customize(**kwargs) @@ -122,9 +120,11 @@ class Attributes(SimpleModel.Attributes): builtins. It makes sense to specify this only when this object belongs to a `ComplexModel` sublass.""" - __type_name__ = 'boolean' + __type_name__ = "boolean" -NATIVE_MAP.update({ - bool: Boolean, -}) +NATIVE_MAP.update( + { + bool: Boolean, + } +) diff --git a/spyne/model/primitive/datetime.py b/spyne/model/primitive/datetime.py index 161b85ee4..7abc8a9bf 100644 --- a/spyne/model/primitive/datetime.py +++ b/spyne/model/primitive/datetime.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -19,18 +18,18 @@ from __future__ import absolute_import -import re -import spyne import datetime +import re +import spyne from spyne.model import SimpleModel from spyne.model.primitive import NATIVE_MAP -FLOAT_PATTERN = r'-?[0-9]+\.?[0-9]*(e-?[0-9]+)?' -DATE_PATTERN = r'(?P\d{4})-(?P\d{2})-(?P\d{2})' -TIME_PATTERN = r'(?P
\d{2}):(?P\d{2}):(?P\d{2})(?P\.\d+)?' -OFFSET_PATTERN = r'(?P[+-]\d{2}):(?P\d{2})' -DATETIME_PATTERN = DATE_PATTERN + '[T ]' + TIME_PATTERN +FLOAT_PATTERN = r"-?[0-9]+\.?[0-9]*(e-?[0-9]+)?" +DATE_PATTERN = r"(?P\d{4})-(?P\d{2})-(?P\d{2})" +TIME_PATTERN = r"(?P
\d{2}):(?P\d{2}):(?P\d{2})(?P\.\d+)?" +OFFSET_PATTERN = r"(?P[+-]\d{2}):(?P\d{2})" +DATETIME_PATTERN = DATE_PATTERN + "[T ]" + TIME_PATTERN class Time(SimpleModel): @@ -39,7 +38,7 @@ class Time(SimpleModel): Native type is :class:`datetime.time`. """ - __type_name__ = 'time' + __type_name__ = "time" Value = datetime.time class Attributes(SimpleModel.Attributes): @@ -70,23 +69,27 @@ class Attributes(SimpleModel.Attributes): @staticmethod def is_default(cls): - return ( SimpleModel.is_default(cls) - and cls.Attributes.gt == Time.Attributes.gt - and cls.Attributes.ge == Time.Attributes.ge - and cls.Attributes.lt == Time.Attributes.lt - and cls.Attributes.le == Time.Attributes.le - and cls.Attributes.pattern == Time.Attributes.pattern + return ( + SimpleModel.is_default(cls) + and cls.Attributes.gt == Time.Attributes.gt + and cls.Attributes.ge == Time.Attributes.ge + and cls.Attributes.lt == Time.Attributes.lt + and cls.Attributes.le == Time.Attributes.le + and cls.Attributes.pattern == Time.Attributes.pattern ) @staticmethod def validate_native(cls, value): return SimpleModel.validate_native(cls, value) and ( - value is None or ( - (cls.Attributes.gt is None or value > cls.Attributes.gt) + value is None + or ( + (cls.Attributes.gt is None or value > cls.Attributes.gt) and value >= cls.Attributes.ge - and (cls.Attributes.lt is None or value < cls.Attributes.lt) + and (cls.Attributes.lt is None or value < cls.Attributes.lt) and value <= cls.Attributes.le - )) + ) + ) + _min_dt = datetime.datetime.min.replace(tzinfo=spyne.LOCAL_TZ) _max_dt = datetime.datetime.max.replace(tzinfo=spyne.LOCAL_TZ) @@ -102,11 +105,11 @@ class DateTime(SimpleModel): Native type is :class:`datetime.datetime`. """ - __type_name__ = 'dateTime' + __type_name__ = "dateTime" Value = datetime.datetime _local_re = re.compile(DATETIME_PATTERN) - _utc_re = re.compile(DATETIME_PATTERN + 'Z') + _utc_re = re.compile(DATETIME_PATTERN + "Z") _offset_re = re.compile(DATETIME_PATTERN + OFFSET_PATTERN) class Attributes(SimpleModel.Attributes): @@ -185,12 +188,13 @@ class Attributes(SimpleModel.Attributes): @staticmethod def is_default(cls): - return ( SimpleModel.is_default(cls) - and cls.Attributes.gt == DateTime.Attributes.gt - and cls.Attributes.ge == DateTime.Attributes.ge - and cls.Attributes.lt == DateTime.Attributes.lt - and cls.Attributes.le == DateTime.Attributes.le - and cls.Attributes.pattern == DateTime.Attributes.pattern + return ( + SimpleModel.is_default(cls) + and cls.Attributes.gt == DateTime.Attributes.gt + and cls.Attributes.ge == DateTime.Attributes.ge + and cls.Attributes.lt == DateTime.Attributes.lt + and cls.Attributes.le == DateTime.Attributes.le + and cls.Attributes.pattern == DateTime.Attributes.pattern ) @staticmethod @@ -198,14 +202,16 @@ def validate_native(cls, value): if isinstance(value, datetime.datetime) and value.tzinfo is None: value = value.replace(tzinfo=spyne.LOCAL_TZ) return SimpleModel.validate_native(cls, value) and ( - value is None or ( + value is None + or ( # min_dt is also a valid value if gt is intact. - (cls.Attributes.gt is None or value > cls.Attributes.gt) + (cls.Attributes.gt is None or value > cls.Attributes.gt) and value >= cls.Attributes.ge # max_dt is also a valid value if lt is intact. and (cls.Attributes.lt is None or value < cls.Attributes.lt) and value <= cls.Attributes.le - )) + ) + ) class Date(DateTime): @@ -214,9 +220,9 @@ class Date(DateTime): Native type is :class:`datetime.date`. """ - __type_name__ = 'date' + __type_name__ = "date" - _offset_re = re.compile(DATE_PATTERN + '(' + OFFSET_PATTERN + '|Z)') + _offset_re = re.compile(DATE_PATTERN + "(" + OFFSET_PATTERN + "|Z)") Value = datetime.date class Attributes(DateTime.Attributes): @@ -245,15 +251,15 @@ class Attributes(DateTime.Attributes): """A regular expression that matches the whole date. See here for more info: http://www.regular-expressions.info/xml.html""" - @staticmethod def is_default(cls): - return ( SimpleModel.is_default(cls) - and cls.Attributes.gt == Date.Attributes.gt - and cls.Attributes.ge == Date.Attributes.ge - and cls.Attributes.lt == Date.Attributes.lt - and cls.Attributes.le == Date.Attributes.le - and cls.Attributes.pattern == Date.Attributes.pattern + return ( + SimpleModel.is_default(cls) + and cls.Attributes.gt == Date.Attributes.gt + and cls.Attributes.ge == Date.Attributes.ge + and cls.Attributes.lt == Date.Attributes.lt + and cls.Attributes.le == Date.Attributes.le + and cls.Attributes.pattern == Date.Attributes.pattern ) @@ -261,13 +267,15 @@ def is_default(cls): class Duration(SimpleModel): """Native type is :class:`datetime.timedelta`.""" - __type_name__ = 'duration' + __type_name__ = "duration" Value = datetime.timedelta -NATIVE_MAP.update({ - datetime.datetime: DateTime, - datetime.time: Time, - datetime.date: Date, - datetime.timedelta: Duration, -}) +NATIVE_MAP.update( + { + datetime.datetime: DateTime, + datetime.time: Time, + datetime.date: Date, + datetime.timedelta: Duration, + } +) diff --git a/spyne/model/primitive/network.py b/spyne/model/primitive/network.py index dfbc292ed..9627959e4 100644 --- a/spyne/model/primitive/network.py +++ b/spyne/model/primitive/network.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -21,16 +20,18 @@ from spyne.model.primitive._base import re_match_with_span from spyne.model.primitive.string import Unicode - _PATT_MAC = "([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})" def _validate_string(cls, value): - return ( SimpleModel.validate_string(cls, value) - and (value is None or ( + return SimpleModel.validate_string(cls, value) and ( + value is None + or ( cls.Attributes.min_len <= len(value) <= cls.Attributes.max_len and re_match_with_span(cls.Attributes, value) - ))) + ) + ) + _mac_validate = { None: _validate_string, @@ -39,11 +40,13 @@ def _validate_string(cls, value): _MacBase = Unicode(max_len=17, min_len=17, pattern=_PATT_MAC) + + class MacAddress(_MacBase): """Unicode subclass for a MAC address.""" - __namespace__ = 'http://spyne.io/schema' - __type_name__ = 'addr_mac' + __namespace__ = "http://spyne.io/schema" + __type_name__ = "addr_mac" class Attributes(_MacBase.Attributes): serialize_as = None @@ -58,7 +61,7 @@ def validate_native(cls, value): _PATT_IPV4_FRAG = r"(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])" -_PATT_IPV4 = r"(%(P4)s\.){3,3}%(P4)s" % {'P4': _PATT_IPV4_FRAG} +_PATT_IPV4 = r"(%(P4)s\.){3,3}%(P4)s" % {"P4": _PATT_IPV4_FRAG} _ipv4_validate = { @@ -68,11 +71,13 @@ def validate_native(cls, value): _Ipv4Base = Unicode(15, pattern=_PATT_IPV4) + + class Ipv4Address(_Ipv4Base): """Unicode subclass for an IPv4 address.""" - __namespace__ = 'http://spyne.io/schema' - __type_name__ = 'addr_ipv4' + __namespace__ = "http://spyne.io/schema" + __type_name__ = "addr_ipv4" class Attributes(_Ipv4Base.Attributes): serialize_as = None @@ -88,20 +93,22 @@ def validate_native(cls, value): # http://stackoverflow.com/a/1934546 _PATT_IPV6_FRAG = "[0-9a-fA-F]{1,4}" -_PATT_IPV6 = ("(" - "(%(P6)s:){7,7}%(P6)s|" # 1:2:3:4:5:6:7:8 - "(%(P6)s:){1,7}:|" # 1:: 1:2:3:4:5:6:7:: - "(%(P6)s:){1,6}:%(P6)s|" # 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 - "(%(P6)s:){1,5}(:%(P6)s){1,2}|" # 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 - "(%(P6)s:){1,4}(:%(P6)s){1,3}|" # 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 - "(%(P6)s:){1,3}(:%(P6)s){1,4}|" # 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 - "(%(P6)s:){1,2}(:%(P6)s){1,5}|" # 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 - "%(P6)s:((:%(P6)s){1,6})|" # 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 - ":((:%(P6)s){1,7}|:)|" # ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: - "fe80:(:%(P6)s){0,4}%%[0-9a-zA-Z]{1,}|" # fe80::7:8%eth0 fe80::7:8%1 (link-local IPv6 addresses with zone index) +_PATT_IPV6 = ( + "(" + "(%(P6)s:){7,7}%(P6)s|" # 1:2:3:4:5:6:7:8 + "(%(P6)s:){1,7}:|" # 1:: 1:2:3:4:5:6:7:: + "(%(P6)s:){1,6}:%(P6)s|" # 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 + "(%(P6)s:){1,5}(:%(P6)s){1,2}|" # 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 + "(%(P6)s:){1,4}(:%(P6)s){1,3}|" # 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 + "(%(P6)s:){1,3}(:%(P6)s){1,4}|" # 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 + "(%(P6)s:){1,2}(:%(P6)s){1,5}|" # 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 + "%(P6)s:((:%(P6)s){1,6})|" # 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 + ":((:%(P6)s){1,7}|:)|" # ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: + "fe80:(:%(P6)s){0,4}%%[0-9a-zA-Z]{1,}|" # fe80::7:8%eth0 fe80::7:8%1 (link-local IPv6 addresses with zone index) "::(ffff(:0{1,4}){0,1}:){0,1}%(A4)s|" # ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) - "(%(P6)s:){1,4}:%(A4)s" # 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 (IPv4-Embedded IPv6 Address) -")") % {'P6': _PATT_IPV6_FRAG, 'A4': _PATT_IPV4} + "(%(P6)s:){1,4}:%(A4)s" # 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 (IPv4-Embedded IPv6 Address) + ")" +) % {"P6": _PATT_IPV6_FRAG, "A4": _PATT_IPV4} _ipv6_validate = { @@ -111,11 +118,13 @@ def validate_native(cls, value): _Ipv6Base = Unicode(45, pattern=_PATT_IPV6) + + class Ipv6Address(_Ipv6Base): """Unicode subclass for an IPv6 address.""" - __namespace__ = 'http://spyne.io/schema' - __type_name__ = 'addr_ipv6' + __namespace__ = "http://spyne.io/schema" + __type_name__ = "addr_ipv6" class Attributes(_Ipv6Base.Attributes): serialize_as = None @@ -139,11 +148,13 @@ def validate_native(cls, value): _IpAddressBase = Unicode(45, pattern=_PATT_IPV4V6) + + class IpAddress(_IpAddressBase): """Unicode subclass for an IPv4 or IPv6 address.""" - __namespace__ = 'http://spyne.io/schema' - __type_name__ = 'addr_ip' + __namespace__ = "http://spyne.io/schema" + __type_name__ = "addr_ip" class Attributes(_IpAddressBase.Attributes): serialize_as = None diff --git a/spyne/model/primitive/number.py b/spyne/model/primitive/number.py index d78cae7de..9cd76dba1 100644 --- a/spyne/model/primitive/number.py +++ b/spyne/model/primitive/number.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -17,14 +16,14 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # -import math import decimal +import math import platform + from _warnings import warn from spyne.model import SimpleModel from spyne.model.primitive import NATIVE_MAP -from spyne.util import six class NumberLimitsWarning(Warning): @@ -42,7 +41,7 @@ class Decimal(SimpleModel): documentation for more information. """ - __type_name__ = 'decimal' + __type_name__ = "decimal" Value = decimal.Decimal # contrary to popular belief, Decimal hates float. @@ -51,16 +50,16 @@ class Attributes(SimpleModel.Attributes): """Customizable attributes of the :class:`spyne.model.primitive.Decimal` type.""" - gt = decimal.Decimal('-inf') # minExclusive + gt = decimal.Decimal("-inf") # minExclusive """The value should be greater than this number.""" - ge = decimal.Decimal('-inf') # minInclusive + ge = decimal.Decimal("-inf") # minInclusive """The value should be greater than or equal to this number.""" - lt = decimal.Decimal('inf') # maxExclusive + lt = decimal.Decimal("inf") # maxExclusive """The value should be lower than this number.""" - le = decimal.Decimal('inf') # maxInclusive + le = decimal.Decimal("inf") # maxInclusive """The value should be lower than or equal to this number.""" max_str_len = 1024 @@ -79,10 +78,10 @@ class Attributes(SimpleModel.Attributes): """A regular expression that matches the whole field. See here for more info: http://www.regular-expressions.info/xml.html""" - total_digits = decimal.Decimal('inf') + total_digits = decimal.Decimal("inf") """Maximum number of digits.""" - fraction_digits = decimal.Decimal('inf') + fraction_digits = decimal.Decimal("inf") """Maximum number of digits after the decimal separator.""" min_bound = None @@ -97,10 +96,10 @@ def __new__(cls, *args, **kwargs): assert len(args) <= 2 if len(args) >= 1 and args[0] is not None: - kwargs['total_digits'] = args[0] - kwargs['fraction_digits'] = 0 + kwargs["total_digits"] = args[0] + kwargs["fraction_digits"] = 0 if len(args) == 2 and args[1] is not None: - kwargs['fraction_digits'] = args[1] + kwargs["fraction_digits"] = args[1] retval = SimpleModel.__new__(cls, **kwargs) @@ -108,23 +107,24 @@ def __new__(cls, *args, **kwargs): @classmethod def _s_customize(cls, **kwargs): - td = kwargs.get('total_digits', None) - fd = kwargs.get('fraction_digits', None) + td = kwargs.get("total_digits", None) + fd = kwargs.get("fraction_digits", None) if td is not None and fd is not None: assert td > 0, "'total_digits' must be positive." - assert fd <= td, \ - "'total_digits' must be greater than" \ - " or equal to 'fraction_digits'." \ - " %r ! <= %r" % (fd, td) + assert fd <= td, ( + "'total_digits' must be greater than" + " or equal to 'fraction_digits'." + " %r ! <= %r" % (fd, td) + ) - msl = kwargs.get('max_str_len', None) + msl = kwargs.get("max_str_len", None) if msl is None: - kwargs['max_str_len'] = cls.Attributes.total_digits + 2 + kwargs["max_str_len"] = cls.Attributes.total_digits + 2 # + 1 for decimal separator # + 1 for negative sign else: - kwargs['max_str_len'] = msl + kwargs["max_str_len"] = msl minb = cls.Attributes.min_bound maxb = cls.Attributes.max_bound @@ -135,56 +135,67 @@ def _s_customize(cls, **kwargs): if minb is not None: if ge is not None and ge < minb: - warn("'Greater than or equal value' %d smaller than min_bound %d" - % (ge, minb), NumberLimitsWarning) + warn( + "'Greater than or equal value' %d smaller than min_bound %d" + % (ge, minb), + NumberLimitsWarning, + ) if gt is not None and gt < minb: - warn("'Greater than' value %d smaller than min_bound %d" - % (gt, minb), NumberLimitsWarning) + warn( + "'Greater than' value %d smaller than min_bound %d" % (gt, minb), + NumberLimitsWarning, + ) if le is not None and le < minb: raise ValueError( "'Little than or equal' value %d smaller than min_bound %d" - % (le, minb)) + % (le, minb) + ) if lt is not None and lt <= minb: raise ValueError( - "'Little than' value %d smaller than min_bound %d" - % (lt, minb)) + "'Little than' value %d smaller than min_bound %d" % (lt, minb) + ) if maxb is not None: if le is not None and le > maxb: - warn("'Little than or equal' value %d greater than max_bound %d" - % (le, maxb), NumberLimitsWarning) + warn( + "'Little than or equal' value %d greater than max_bound %d" + % (le, maxb), + NumberLimitsWarning, + ) if lt is not None and lt > maxb: - warn("'Little than' value %d greater than max_bound %d" - % (lt, maxb), NumberLimitsWarning) + warn( + "'Little than' value %d greater than max_bound %d" % (lt, maxb), + NumberLimitsWarning, + ) if ge is not None and ge > maxb: raise ValueError( "'Greater than or equal' value %d greater than max_bound %d" - % (ge, maxb)) + % (ge, maxb) + ) if gt is not None and gt >= maxb: raise ValueError( - "'Greater than' value %d greater than max_bound %d" - % (gt, maxb)) + "'Greater than' value %d greater than max_bound %d" % (gt, maxb) + ) return super(Decimal, cls)._s_customize(**kwargs) @staticmethod def is_default(cls): - return ( SimpleModel.is_default(cls) - and cls.Attributes.gt == Decimal.Attributes.gt - and cls.Attributes.ge == Decimal.Attributes.ge - and cls.Attributes.lt == Decimal.Attributes.lt - and cls.Attributes.le == Decimal.Attributes.le - and cls.Attributes.total_digits == - Decimal.Attributes.total_digits - and cls.Attributes.fraction_digits == - Decimal.Attributes.fraction_digits - ) + return ( + SimpleModel.is_default(cls) + and cls.Attributes.gt == Decimal.Attributes.gt + and cls.Attributes.ge == Decimal.Attributes.ge + and cls.Attributes.lt == Decimal.Attributes.lt + and cls.Attributes.le == Decimal.Attributes.le + and cls.Attributes.total_digits == Decimal.Attributes.total_digits + and cls.Attributes.fraction_digits == Decimal.Attributes.fraction_digits + ) @staticmethod def validate_string(cls, value): @@ -195,12 +206,14 @@ def validate_string(cls, value): @staticmethod def validate_native(cls, value): return SimpleModel.validate_native(cls, value) and ( - value is None or ( - value > cls.Attributes.gt and - value >= cls.Attributes.ge and - value < cls.Attributes.lt and - value <= cls.Attributes.le - )) + value is None + or ( + value > cls.Attributes.gt + and value >= cls.Attributes.ge + and value < cls.Attributes.lt + and value <= cls.Attributes.le + ) + ) class Double(Decimal): @@ -217,68 +230,68 @@ class Double(Decimal): return instances of types compatible with designated types. """ - __type_name__ = 'double' + __type_name__ = "double" Value = float - if platform.python_version_tuple()[:2] == ('2','6'): + if platform.python_version_tuple()[:2] == ("2", "6"): + class Attributes(Decimal.Attributes): """Customizable attributes of the :class:`spyne.model.primitive.Double` type. This class is only here for Python 2.6: See this bug report for more info: http://bugs.python.org/issue2531 """ - gt = float('-inf') # minExclusive + gt = float("-inf") # minExclusive """The value should be greater than this number.""" - ge = float('-inf') # minInclusive + ge = float("-inf") # minInclusive """The value should be greater than or equal to this number.""" - lt = float('inf') # maxExclusive + lt = float("inf") # maxExclusive """The value should be lower than this number.""" - le = float('inf') # maxInclusive + le = float("inf") # maxInclusive """The value should be lower than or equal to this number.""" @staticmethod def is_default(cls): - return ( SimpleModel.is_default(cls) - and cls.Attributes.gt == Double.Attributes.gt - and cls.Attributes.ge == Double.Attributes.ge - and cls.Attributes.lt == Double.Attributes.lt - and cls.Attributes.le == Double.Attributes.le - ) + return ( + SimpleModel.is_default(cls) + and cls.Attributes.gt == Double.Attributes.gt + and cls.Attributes.ge == Double.Attributes.ge + and cls.Attributes.lt == Double.Attributes.lt + and cls.Attributes.le == Double.Attributes.le + ) class Float(Double): """Synonym for Double (as far as python side of things are concerned). It's here for compatibility reasons.""" - __type_name__ = 'float' + __type_name__ = "float" class Integer(Decimal): """The arbitrary-size signed integer.""" - __type_name__ = 'integer' + __type_name__ = "integer" Value = int @staticmethod def validate_native(cls, value): - return ( Decimal.validate_native(cls, value) - and (value is None or int(value) == value) - ) + return Decimal.validate_native(cls, value) and ( + value is None or int(value) == value + ) class UnsignedInteger(Integer): """The arbitrary-size unsigned integer, also known as nonNegativeInteger.""" - __type_name__ = 'nonNegativeInteger' + __type_name__ = "nonNegativeInteger" @staticmethod def validate_native(cls, value): - return ( Integer.validate_native(cls, value) - and (value is None or value >= 0) - ) + return Integer.validate_native(cls, value) and (value is None or value >= 0) NonNegativeInteger = UnsignedInteger @@ -286,20 +299,18 @@ def validate_native(cls, value): class PositiveInteger(NonNegativeInteger): - """The arbitrary-size positive integer (natural number).""" - __type_name__ = 'positiveInteger' + __type_name__ = "positiveInteger" @staticmethod def validate_native(cls, value): - return (Integer.validate_native(cls, value) - and (value is None or value > 0)) + return Integer.validate_native(cls, value) and (value is None or value > 0) def TBoundedInteger(num_bits, type_name): - _min_b = -(0x8<<(num_bits-4)) # 0x8 is 4 bits. - _max_b = (0x8<<(num_bits-4)) - 1 # -1? c'est la vie + _min_b = -(0x8 << (num_bits - 4)) # 0x8 is 4 bits. + _max_b = (0x8 << (num_bits - 4)) - 1 # -1? c'est la vie class _BoundedInteger(Integer): __type_name__ = type_name @@ -311,9 +322,8 @@ class Attributes(Integer.Attributes): @staticmethod def validate_native(cls, value): - return ( - Integer.validate_native(cls, value) - and (value is None or (_min_b <= value <= _max_b)) + return Integer.validate_native(cls, value) and ( + value is None or (_min_b <= value <= _max_b) ) return _BoundedInteger @@ -321,7 +331,7 @@ def validate_native(cls, value): def TBoundedUnsignedInteger(num_bits, type_name): _min_b = 0 - _max_b = 2 ** num_bits - 1 # -1? c'est la vie ;) + _max_b = 2**num_bits - 1 # -1? c'est la vie ;) class _BoundedUnsignedInteger(UnsignedInteger): __type_name__ = type_name @@ -333,87 +343,79 @@ class Attributes(UnsignedInteger.Attributes): @staticmethod def validate_native(cls, value): - return ( - UnsignedInteger.validate_native(cls, value) - and (value is None or (_min_b <= value < _max_b)) + return UnsignedInteger.validate_native(cls, value) and ( + value is None or (_min_b <= value < _max_b) ) return _BoundedUnsignedInteger -Integer64 = TBoundedInteger(64, 'long') +Integer64 = TBoundedInteger(64, "long") """The 64-bit signed integer, also known as ``long``.""" Long = Integer64 """The 64-bit signed integer, alias for :class:`Integer64`.""" -Integer32 = TBoundedInteger(32, 'int') +Integer32 = TBoundedInteger(32, "int") """The 64-bit signed integer, also known as ``int``.""" Int = Integer32 """The 32-bit signed integer, alias for :class:`Integer32`.""" -Integer16 = TBoundedInteger(16, 'short') +Integer16 = TBoundedInteger(16, "short") """The 16-bit signed integer, also known as ``short``.""" Short = Integer16 """The 16-bit signed integer, alias for :class:`Integer16`.""" -Integer8 = TBoundedInteger(8, 'byte') +Integer8 = TBoundedInteger(8, "byte") """The 8-bit signed integer, also known as ``byte``.""" Byte = Integer8 """The 8-bit signed integer, alias for :class:`Integer8`.""" -UnsignedInteger64 = TBoundedUnsignedInteger(64, 'unsignedLong') +UnsignedInteger64 = TBoundedUnsignedInteger(64, "unsignedLong") """The 64-bit unsigned integer, also known as ``unsignedLong``.""" UnsignedLong = UnsignedInteger64 """The 64-bit unsigned integer, alias for :class:`UnsignedInteger64`.""" -UnsignedInteger32 = TBoundedUnsignedInteger(32, 'unsignedInt') +UnsignedInteger32 = TBoundedUnsignedInteger(32, "unsignedInt") """The 64-bit unsigned integer, also known as ``unsignedInt``.""" UnsignedInt = UnsignedInteger32 """The 32-bit unsigned integer, alias for :class:`UnsignedInteger32`.""" -UnsignedInteger16 = TBoundedUnsignedInteger(16, 'unsignedShort') +UnsignedInteger16 = TBoundedUnsignedInteger(16, "unsignedShort") """The 16-bit unsigned integer, also known as ``unsignedShort``.""" UnsignedShort = UnsignedInteger16 """The 16-bit unsigned integer, alias for :class:`UnsignedInteger16`.""" -UnsignedInteger8 = TBoundedUnsignedInteger(8, 'unsignedByte') +UnsignedInteger8 = TBoundedUnsignedInteger(8, "unsignedByte") """The 8-bit unsigned integer, also known as ``unsignedByte``.""" UnsignedByte = UnsignedInteger8 """The 8-bit unsigned integer, alias for :class:`UnsignedInteger8`.""" -NATIVE_MAP.update({ - float: Double, - decimal.Decimal: Decimal, -}) +NATIVE_MAP.update( + { + float: Double, + decimal.Decimal: Decimal, + } +) -if not six.PY2: - NATIVE_MAP.update({ +NATIVE_MAP.update( + { int: Integer, - }) - -else: - NATIVE_MAP.update({ - long: Integer, - }) - - if isinstance(0x80000000, long): # 32-bit architecture - NATIVE_MAP[int] = Integer32 - else: # not 32-bit (so most probably 64-bit) architecture - NATIVE_MAP[int] = Integer64 + } +) diff --git a/spyne/model/primitive/spatial.py b/spyne/model/primitive/spatial.py index cf3ada5e9..139bb1075 100644 --- a/spyne/model/primitive/spatial.py +++ b/spyne/model/primitive/spatial.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -27,53 +26,63 @@ from spyne.model import SimpleModel from spyne.model.primitive.string import Unicode +FLOAT_PATTERN = r"-?[0-9]+\.?[0-9]*(e-?[0-9]+)?" + -FLOAT_PATTERN = r'-?[0-9]+\.?[0-9]*(e-?[0-9]+)?' +_rinse_and_repeat = r"\s*\(%s\s*(,\s*%s)*\)\s*" -_rinse_and_repeat = r'\s*\(%s\s*(,\s*%s)*\)\s*' def _get_one_point_pattern(dim): - return ' +'.join([FLOAT_PATTERN] * dim) + return " +".join([FLOAT_PATTERN] * dim) + def _get_point_pattern(dim): - return r'POINT\s*\(%s\)' % _get_one_point_pattern(dim) + return r"POINT\s*\(%s\)" % _get_one_point_pattern(dim) + def _get_one_multipoint_pattern(dim): one_point = _get_one_point_pattern(dim) return _rinse_and_repeat % (one_point, one_point) + def _get_multipoint_pattern(dim): - return r'MULTIPOINT%s' % _get_one_multipoint_pattern(dim) + return r"MULTIPOINT%s" % _get_one_multipoint_pattern(dim) def _get_one_line_pattern(dim): one_point = _get_one_point_pattern(dim) return _rinse_and_repeat % (one_point, one_point) + def _get_linestring_pattern(dim): - return r'LINESTRING%s' % _get_one_line_pattern(dim) + return r"LINESTRING%s" % _get_one_line_pattern(dim) + def _get_one_multilinestring_pattern(dim): one_line = _get_one_line_pattern(dim) return _rinse_and_repeat % (one_line, one_line) + def _get_multilinestring_pattern(dim): - return r'MULTILINESTRING%s' % _get_one_multilinestring_pattern(dim) + return r"MULTILINESTRING%s" % _get_one_multilinestring_pattern(dim) def _get_one_polygon_pattern(dim): one_line = _get_one_line_pattern(dim) return _rinse_and_repeat % (one_line, one_line) + def _get_polygon_pattern(dim): - return r'POLYGON%s' % _get_one_polygon_pattern(dim) + return r"POLYGON%s" % _get_one_polygon_pattern(dim) + def _get_one_multipolygon_pattern(dim): one_line = _get_one_polygon_pattern(dim) return _rinse_and_repeat % (one_line, one_line) + def _get_multipolygon_pattern(dim): - return r'MULTIPOLYGON%s' % _get_one_multipolygon_pattern(dim) + return r"MULTIPOLYGON%s" % _get_one_multipolygon_pattern(dim) class Point(Unicode): @@ -96,19 +105,19 @@ def Value(x, y, prec=15): if isinstance(x, str) or isinstance(y, str): assert isinstance(x, str) assert isinstance(y, str) - return 'POINT(%s %s)' % (x, y) + return "POINT(%s %s)" % (x, y) - return ('POINT(%%3.%(prec)sf %%3.%(prec)sf)' % {'prec': prec}) % (x,y) + return ("POINT(%%3.%(prec)sf %%3.%(prec)sf)" % {"prec": prec}) % (x, y) def __new__(cls, dim=None, **kwargs): assert dim in (None, 2, 3) if dim is not None: - kwargs['dim'] = dim - kwargs['pattern'] = _get_point_pattern(dim) - kwargs['type_name'] = 'point%dd' % dim + kwargs["dim"] = dim + kwargs["pattern"] = _get_point_pattern(dim) + kwargs["type_name"] = "point%dd" % dim retval = SimpleModel.__new__(cls, **kwargs) - retval.__namespace__ = 'http://spyne.io/schema' + retval.__namespace__ = "http://spyne.io/schema" retval.__extends__ = Unicode retval.__orig__ = Unicode return retval @@ -132,16 +141,17 @@ class Attributes(Unicode.Attributes): def __new__(cls, dim=None, **kwargs): assert dim in (None, 2, 3) if dim is not None: - kwargs['dim'] = dim - kwargs['pattern'] = _get_linestring_pattern(dim) - kwargs['type_name'] = 'line%dd' % dim + kwargs["dim"] = dim + kwargs["pattern"] = _get_linestring_pattern(dim) + kwargs["type_name"] = "line%dd" % dim retval = SimpleModel.__new__(cls, **kwargs) - retval.__namespace__ = 'http://spyne.io/schema' + retval.__namespace__ = "http://spyne.io/schema" retval.__extends__ = Unicode retval.__orig__ = Unicode return retval + LineString = Line @@ -154,6 +164,7 @@ class Polygon(Unicode): :param dim: Number of dimensons. """ + __type_name__ = None class Attributes(Unicode.Attributes): @@ -162,12 +173,12 @@ class Attributes(Unicode.Attributes): def __new__(cls, dim=None, **kwargs): assert dim in (None, 2, 3) if dim is not None: - kwargs['dim'] = dim - kwargs['pattern'] = _get_polygon_pattern(dim) - kwargs['type_name'] = 'polygon%dd' % dim + kwargs["dim"] = dim + kwargs["pattern"] = _get_polygon_pattern(dim) + kwargs["type_name"] = "polygon%dd" % dim retval = SimpleModel.__new__(cls, **kwargs) - retval.__namespace__ = 'http://spyne.io/schema' + retval.__namespace__ = "http://spyne.io/schema" retval.__extends__ = Unicode retval.__orig__ = Unicode return retval @@ -191,12 +202,12 @@ class Attributes(Unicode.Attributes): def __new__(cls, dim=None, **kwargs): assert dim in (None, 2, 3) if dim is not None: - kwargs['dim'] = dim - kwargs['pattern'] = _get_multipoint_pattern(dim) - kwargs['type_name'] = 'multiPoint%dd' % dim + kwargs["dim"] = dim + kwargs["pattern"] = _get_multipoint_pattern(dim) + kwargs["type_name"] = "multiPoint%dd" % dim retval = SimpleModel.__new__(cls, **kwargs) - retval.__namespace__ = 'http://spyne.io/schema' + retval.__namespace__ = "http://spyne.io/schema" retval.__extends__ = Unicode retval.__orig__ = Unicode return retval @@ -220,16 +231,17 @@ class Attributes(Unicode.Attributes): def __new__(cls, dim=None, **kwargs): assert dim in (None, 2, 3) if dim is not None: - kwargs['dim'] = dim - kwargs['pattern'] = _get_multilinestring_pattern(dim) - kwargs['type_name'] = 'multiLine%dd' % dim + kwargs["dim"] = dim + kwargs["pattern"] = _get_multilinestring_pattern(dim) + kwargs["type_name"] = "multiLine%dd" % dim retval = SimpleModel.__new__(cls, **kwargs) - retval.__namespace__ = 'http://spyne.io/schema' + retval.__namespace__ = "http://spyne.io/schema" retval.__extends__ = Unicode retval.__orig__ = Unicode return retval + MultiLineString = MultiLine @@ -251,13 +263,12 @@ class Attributes(Unicode.Attributes): def __new__(cls, dim=None, **kwargs): assert dim in (None, 2, 3) if dim is not None: - kwargs['dim'] = dim - kwargs['pattern'] = _get_multipolygon_pattern(dim) - kwargs['type_name'] = 'multipolygon%dd' % dim + kwargs["dim"] = dim + kwargs["pattern"] = _get_multipolygon_pattern(dim) + kwargs["type_name"] = "multipolygon%dd" % dim retval = SimpleModel.__new__(cls, **kwargs) - retval.__namespace__ = 'http://spyne.io/schema' + retval.__namespace__ = "http://spyne.io/schema" retval.__extends__ = Unicode retval.__orig__ = Unicode return retval - diff --git a/spyne/model/primitive/string.py b/spyne/model/primitive/string.py index 6253fef71..e721fda36 100644 --- a/spyne/model/primitive/string.py +++ b/spyne/model/primitive/string.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -22,14 +21,11 @@ import decimal import uuid -from spyne.model.primitive import NATIVE_MAP -from spyne.util import six from spyne.model._base import SimpleModel +from spyne.model.primitive import NATIVE_MAP from spyne.model.primitive._base import re_match_with_span - -UUID_PATTERN = "%(x)s{8}-%(x)s{4}-%(x)s{4}-%(x)s{4}-%(x)s{12}" % \ - {'x': '[a-fA-F0-9]'} +UUID_PATTERN = "%(x)s{8}-%(x)s{4}-%(x)s{4}-%(x)s{4}-%(x)s{12}" % {"x": "[a-fA-F0-9]"} LTREE_PATTERN = r"\w+(\.\w+)*" @@ -38,17 +34,17 @@ LTREE_MAXIMUM_SIZE = 65536 -'[0-9A-Za-z!#$%&\'*+.^_`|~-]+/([0-9A-Za-z!#$%&\'*+.^_`|~-]+);[ \\t]*[0-9A-Za-z!#$%&\'*+.^_`|~-]+=(?:[0-9A-Za-z!#$%&\'*+.^_`|~-]+|"(?:[^"\\\\]|\\.)*");?[ \\t]*([0-9A-Za-z!#$%&\'*+.^_`|~-]+=(?:[0-9A-Za-z!#$%&\'*+.^_`|~-]+|"(?:[^"\\\\]|\\.)*");?[ \\t]*)*' - def _gen_mime_type_pattern(strict, with_params): ows = "[ \\t]*" # Optional WhiteSpace token = "[0-9A-Za-z!#$%&'*+.^_`|~-]+" - quotedString = "\"(?:[^\"\\\\]|\\.)*\"" + quotedString = '"(?:[^"\\\\]|\\.)*"' if strict: - main_type = "(" \ - "application|audio|font|example|image|message|model|multipart" \ - "|text|video|x-(?:" + token + ")" \ + main_type = ( + "(" + "application|audio|font|example|image|message|model|multipart" + "|text|video|x-(?:" + token + ")" ")" + ) else: main_type = token @@ -57,23 +53,16 @@ def _gen_mime_type_pattern(strict, with_params): return main_type + "/" + "(" + token + ")" param = token + "=" + "(?:" + token + "|" + quotedString + ");?" + ows - params = \ - "(" + ";" \ - + "(" + ows + param + "(" + param + ")*" + ")?" \ - + ")?" + params = "(" + ";" + "(" + ows + param + "(" + param + ")*" + ")?" + ")?" return main_type + "/" + "(" + token + ")" + params -MIME_TYPE_PATTERN_STRICT = \ - _gen_mime_type_pattern(strict=True, with_params=False) -MIME_TYPE_PATTERN_PERMISSIVE = \ - _gen_mime_type_pattern(strict=False, with_params=False) +MIME_TYPE_PATTERN_STRICT = _gen_mime_type_pattern(strict=True, with_params=False) +MIME_TYPE_PATTERN_PERMISSIVE = _gen_mime_type_pattern(strict=False, with_params=False) -MEDIA_TYPE_PATTERN_STRICT = \ - _gen_mime_type_pattern(strict=True, with_params=True) -MEDIA_TYPE_PATTERN_PERMISSIVE = \ - _gen_mime_type_pattern(strict=False, with_params=True) +MEDIA_TYPE_PATTERN_STRICT = _gen_mime_type_pattern(strict=True, with_params=True) +MEDIA_TYPE_PATTERN_PERMISSIVE = _gen_mime_type_pattern(strict=False, with_params=True) class Unicode(SimpleModel): @@ -81,8 +70,8 @@ class Unicode(SimpleModel): or `str` with given encoding. """ - __type_name__ = 'string' - Value = six.text_type + __type_name__ = "string" + Value = str class Attributes(SimpleModel.Attributes): """Customizable attributes of the :class:`spyne.model.primitive.Unicode` @@ -91,7 +80,7 @@ class Attributes(SimpleModel.Attributes): min_len = 0 """Minimum length of string. Can be set to any positive integer""" - max_len = decimal.Decimal('inf') + max_len = decimal.Decimal("inf") """Maximum length of string. Can be set to ``decimal.Decimal('inf')`` to accept strings of arbitrary length. You may also need to adjust :const:`spyne.server.wsgi.MAX_CONTENT_LENGTH`.""" @@ -107,7 +96,7 @@ class Attributes(SimpleModel.Attributes): encoding = None """The encoding of binary data this class may have to deal with.""" - unicode_errors = 'strict' + unicode_errors = "strict" """The argument to the ``unicode`` builtin; one of 'strict', 'replace' or 'ignore'.""" @@ -122,46 +111,46 @@ def __new__(cls, *args, **kwargs): assert len(args) <= 1 if len(args) == 1: - kwargs['max_len'] = args[0] + kwargs["max_len"] = args[0] - retval = SimpleModel.__new__(cls, ** kwargs) + retval = SimpleModel.__new__(cls, **kwargs) return retval @staticmethod def is_default(cls): - return ( SimpleModel.is_default(cls) - and cls.Attributes.min_len == Unicode.Attributes.min_len - and cls.Attributes.max_len == Unicode.Attributes.max_len - and cls.Attributes.pattern == Unicode.Attributes.pattern - ) + return ( + SimpleModel.is_default(cls) + and cls.Attributes.min_len == Unicode.Attributes.min_len + and cls.Attributes.max_len == Unicode.Attributes.max_len + and cls.Attributes.pattern == Unicode.Attributes.pattern + ) @staticmethod def validate_string(cls, value): - return ( SimpleModel.validate_string(cls, value) - and (value is None or ( - cls.Attributes.min_len <= len(value) <= cls.Attributes.max_len - ))) + return SimpleModel.validate_string(cls, value) and ( + value is None + or (cls.Attributes.min_len <= len(value) <= cls.Attributes.max_len) + ) @staticmethod def validate_native(cls, value): - return (SimpleModel.validate_native(cls, value) - and (value is None or ( - re_match_with_span(cls.Attributes, value) - ))) + return SimpleModel.validate_native(cls, value) and ( + value is None or (re_match_with_span(cls.Attributes, value)) + ) class String(Unicode): pass -if not six.PY2: - String = Unicode + +String = Unicode class AnyUri(Unicode): """A special kind of String type designed to hold an uri.""" - __type_name__ = 'anyURI' + __type_name__ = "anyURI" class Attributes(String.Attributes): text = None @@ -187,8 +176,9 @@ def __init__(self, href, text=None, content=None): self.content = content def __repr__(self): - return "Uri(href={0!r}, text={1!r}, content={2!r})" \ - .format(self.href, self.text, self.content) + return "Uri(href={0!r}, text={1!r}, content={2!r})".format( + self.href, self.text, self.content + ) class ImageUri(AnyUri): @@ -196,11 +186,13 @@ class ImageUri(AnyUri): def _uuid_validate_string(cls, value): - return ( SimpleModel.validate_string(cls, value) - and (value is None or ( + return SimpleModel.validate_string(cls, value) and ( + value is None + or ( cls.Attributes.min_len <= len(value) <= cls.Attributes.max_len and re_match_with_span(cls.Attributes, value) - ))) + ) + ) def _Tuuid_validate(key): @@ -208,31 +200,32 @@ def _Tuuid_validate(key): def _uvalid(cls, v): try: - UUID(**{key:v}) + UUID(**{key: v}) except ValueError: return False return True + return _uvalid _uuid_validate = { None: _uuid_validate_string, - 'hex': _Tuuid_validate('hex'), - 'urn': _Tuuid_validate('urn'), - six.binary_type: _Tuuid_validate('bytes'), - 'bytes': _Tuuid_validate('bytes'), - 'bytes_le': _Tuuid_validate('bytes_le'), - 'fields': _Tuuid_validate('fields'), - int: _Tuuid_validate('int'), - 'int': _Tuuid_validate('int'), + "hex": _Tuuid_validate("hex"), + "urn": _Tuuid_validate("urn"), + bytes: _Tuuid_validate("bytes"), + "bytes": _Tuuid_validate("bytes"), + "bytes_le": _Tuuid_validate("bytes_le"), + "fields": _Tuuid_validate("fields"), + int: _Tuuid_validate("int"), + "int": _Tuuid_validate("int"), } class Uuid(Unicode(pattern=UUID_PATTERN)): """Unicode subclass for Universially-Unique Identifiers.""" - __namespace__ = 'http://spyne.io/schema' - __type_name__ = 'uuid' + __namespace__ = "http://spyne.io/schema" + __type_name__ = "uuid" Value = uuid.UUID class Attributes(Unicode(pattern=UUID_PATTERN).Attributes): @@ -251,32 +244,32 @@ class Ltree(Unicode(LTREE_OPTIMAL_SIZE, unicode_pattern=LTREE_PATTERN)): """A special kind of String type designed to hold the Ltree type from Postgresql.""" - __namespace__ = 'http://spyne.io/schema' - __type_name__ = 'ltreeString' + __namespace__ = "http://spyne.io/schema" + __type_name__ = "ltreeString" class LtreeLarge(Unicode(LTREE_MAXIMUM_SIZE, unicode_pattern=LTREE_PATTERN)): """A special kind of String type designed to hold the Ltree type from Postgresql.""" - __namespace__ = 'http://spyne.io/schema' - __type_name__ = 'largeLtreeString' + __namespace__ = "http://spyne.io/schema" + __type_name__ = "largeLtreeString" class MimeTypeStrict(Unicode(unicode_pattern=MIME_TYPE_PATTERN_STRICT)): """A special kind of String type designed to hold a mime type as defined by IANA.""" - __namespace__ = 'http://spyne.io/schema' - __type_name__ = 'strictMimeTypeString' + __namespace__ = "http://spyne.io/schema" + __type_name__ = "strictMimeTypeString" class MimeType(Unicode(unicode_pattern=MIME_TYPE_PATTERN_PERMISSIVE)): """A special kind of String type designed to hold a forward-compatible mime type that can have any string as main type.""" - __namespace__ = 'http://spyne.io/schema' - __type_name__ = 'mimeTypeString' + __namespace__ = "http://spyne.io/schema" + __type_name__ = "mimeTypeString" class MediaTypeStrict(Unicode(unicode_pattern=MEDIA_TYPE_PATTERN_STRICT)): @@ -285,8 +278,8 @@ class MediaTypeStrict(Unicode(unicode_pattern=MEDIA_TYPE_PATTERN_STRICT)): See: https://tools.ietf.org/html/rfc7231#section-3.1.1.1""" - __namespace__ = 'http://spyne.io/schema' - __type_name__ = 'strictMediaTypeString' + __namespace__ = "http://spyne.io/schema" + __type_name__ = "strictMediaTypeString" class MediaType(Unicode(unicode_pattern=MEDIA_TYPE_PATTERN_PERMISSIVE)): @@ -296,17 +289,12 @@ class MediaType(Unicode(unicode_pattern=MEDIA_TYPE_PATTERN_PERMISSIVE)): See: https://tools.ietf.org/html/rfc7231#section-3.1.1.1""" - __namespace__ = 'http://spyne.io/schema' - __type_name__ = 'mediaTypeString' + __namespace__ = "http://spyne.io/schema" + __type_name__ = "mediaTypeString" -if not six.PY2: - NATIVE_MAP.update({ +NATIVE_MAP.update( + { str: Unicode, - }) - -else: - NATIVE_MAP.update({ - str: String, - unicode: Unicode, - }) + } +) diff --git a/spyne/model/primitive/xml.py b/spyne/model/primitive/xml.py index d60494a61..1b269ab81 100644 --- a/spyne/model/primitive/xml.py +++ b/spyne/model/primitive/xml.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -22,108 +21,135 @@ from spyne.const.xml import PATT_NMTOKEN from spyne.model.primitive.string import Unicode - RE_BaseChar = re.compile( - u"[\u0041-\u005A]|[\u0061-\u007A]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|" - u"[\u00F8-\u00FF]|[\u0100-\u0131]|[\u0134-\u013E]|[\u0141-\u0148]|" - u"[\u014A-\u017E]|[\u0180-\u01C3]|[\u01CD-\u01F0]|[\u01F4-\u01F5]|" - u"[\u01FA-\u0217]|[\u0250-\u02A8]|[\u02BB-\u02C1]|\u0386|[\u0388-\u038A]|" - u"\u038C|[\u038E-\u03A1]|[\u03A3-\u03CE]|[\u03D0-\u03D6]|" - u"\u03DA|\u03DC|\u03DE|\u03E0|[\u03E2-\u03F3]|[\u0401-\u040C]|" - u"[\u040E-\u044F]|[\u0451-\u045C]|[\u045E-\u0481]|[\u0490-\u04C4]|" - u"[\u04C7-\u04C8]|[\u04CB-\u04CC]|[\u04D0-\u04EB]|[\u04EE-\u04F5]|" - u"[\u04F8-\u04F9]|[\u0531-\u0556]|\u0559|[\u0561-\u0586]|[\u05D0-\u05EA]|" - u"[\u05F0-\u05F2]|[\u0621-\u063A]|[\u0641-\u064A]|[\u0671-\u06B7]|" - u"[\u06BA-\u06BE]|[\u06C0-\u06CE]|[\u06D0-\u06D3]|\u06D5|[\u06E5-\u06E6]|" - u"[\u0905-\u0939]|\u093D|[\u0958-\u0961]|[\u0985-\u098C]|[\u098F-\u0990]|" - u"[\u0993-\u09A8]|[\u09AA-\u09B0]|\u09B2|[\u09B6-\u09B9]|[\u09DC-\u09DD]|" - u"[\u09DF-\u09E1]|[\u09F0-\u09F1]|[\u0A05-\u0A0A]|[\u0A0F-\u0A10]|" - u"[\u0A13-\u0A28]|[\u0A2A-\u0A30]|[\u0A32-\u0A33]|[\u0A35-\u0A36]|" - u"[\u0A38-\u0A39]|[\u0A59-\u0A5C]|\u0A5E|[\u0A72-\u0A74]|[\u0A85-\u0A8B]|" - u"\u0A8D|[\u0A8F-\u0A91]|[\u0A93-\u0AA8]|[\u0AAA-\u0AB0]|[\u0AB2-\u0AB3]|" - u"[\u0AB5-\u0AB9]|\u0ABD|\u0AE0|[\u0B05-\u0B0C]|[\u0B0F-\u0B10]|" - u"[\u0B13-\u0B28]|[\u0B2A-\u0B30]|[\u0B32-\u0B33]|[\u0B36-\u0B39]|\u0B3D|" - u"[\u0B5C-\u0B5D]|[\u0B5F-\u0B61]|[\u0B85-\u0B8A]|[\u0B8E-\u0B90]|" - u"[\u0B92-\u0B95]|[\u0B99-\u0B9A]|\u0B9C|[\u0B9E-\u0B9F]|[\u0BA3-\u0BA4]|" - u"[\u0BA8-\u0BAA]|[\u0BAE-\u0BB5]|[\u0BB7-\u0BB9]|[\u0C05-\u0C0C]|" - u"[\u0C0E-\u0C10]|[\u0C12-\u0C28]|[\u0C2A-\u0C33]|[\u0C35-\u0C39]|" - u"[\u0C60-\u0C61]|[\u0C85-\u0C8C]|[\u0C8E-\u0C90]|[\u0C92-\u0CA8]|" - u"[\u0CAA-\u0CB3]|[\u0CB5-\u0CB9]|\u0CDE|[\u0CE0-\u0CE1]|[\u0D05-\u0D0C]|" - u"[\u0D0E-\u0D10]|[\u0D12-\u0D28]|[\u0D2A-\u0D39]|[\u0D60-\u0D61]|" - u"[\u0E01-\u0E2E]|\u0E30|[\u0E32-\u0E33]|[\u0E40-\u0E45]|[\u0E81-\u0E82]|" - u"\u0E84|[\u0E87-\u0E88]|\u0E8A|\u0E8D|[\u0E94-\u0E97]|[\u0E99-\u0E9F]|" - u"[\u0EA1-\u0EA3]|\u0EA5|\u0EA7|[\u0EAA-\u0EAB]|[\u0EAD-\u0EAE]|\u0EB0|" - u"[\u0EB2-\u0EB3]|\u0EBD|[\u0EC0-\u0EC4]|[\u0F40-\u0F47]|[\u0F49-\u0F69]|" - u"[\u10A0-\u10C5]|[\u10D0-\u10F6]|\u1100|[\u1102-\u1103]|[\u1105-\u1107]|" - u"\u1109|[\u110B-\u110C]|[\u110E-\u1112]|\u113C|\u113E|\u1140|\u114C|" - u"\u114E|\u1150|[\u1154-\u1155]|\u1159|[\u115F-\u1161]|\u1163|\u1165|" - u"\u1167|\u1169|[\u116D-\u116E]|[\u1172-\u1173]|\u1175|\u119E|\u11A8|" - u"\u11AB|[\u11AE-\u11AF]|[\u11B7-\u11B8]|\u11BA|[\u11BC-\u11C2]|\u11EB|" - u"\u11F0|\u11F9|[\u1E00-\u1E9B]|[\u1EA0-\u1EF9]|[\u1F00-\u1F15]|" - u"[\u1F18-\u1F1D]|[\u1F20-\u1F45]|[\u1F48-\u1F4D]|[\u1F50-\u1F57]|\u1F59|" - u"\u1F5B|\u1F5D|[\u1F5F-\u1F7D]|[\u1F80-\u1FB4]|[\u1FB6-\u1FBC]|\u1FBE|" - u"[\u1FC2-\u1FC4]|[\u1FC6-\u1FCC]|[\u1FD0-\u1FD3]|[\u1FD6-\u1FDB]|" - u"[\u1FE0-\u1FEC]|[\u1FF2-\u1FF4]|[\u1FF6-\u1FFC]|\u2126|[\u212A-\u212B]|" - u"\u212E|[\u2180-\u2182]|[\u3041-\u3094]|[\u30A1-\u30FA]|[\u3105-\u312C]|" - u"[\uAC00-\uD7A3]", flags=re.UNICODE) - - -RE_Ideographic = re.compile(u"[\u4E00-\u9FA5]|\u3007|[\u3021-\u3029]", - flags=re.UNICODE) - -RE_CombiningChar= re.compile( - u"[\u0300-\u0345]|[\u0360-\u0361]|[\u0483-\u0486]|[\u0591-\u05A1]|" - u"[\u05A3-\u05B9]|[\u05BB-\u05BD]|\u05BF|[\u05C1-\u05C2]|\u05C4|" - u"[\u064B-\u0652]|\u0670|[\u06D6-\u06DC]|[\u06DD-\u06DF]|[\u06E0-\u06E4]|" - u"[\u06E7-\u06E8]|[\u06EA-\u06ED]|[\u0901-\u0903]|\u093C|[\u093E-\u094C]|" - u"\u094D|[\u0951-\u0954]|[\u0962-\u0963]|[\u0981-\u0983]|\u09BC|\u09BE|" - u"\u09BF|[\u09C0-\u09C4]|[\u09C7-\u09C8]|[\u09CB-\u09CD]|\u09D7|" - u"[\u09E2-\u09E3]|\u0A02|\u0A3C|\u0A3E|\u0A3F|[\u0A40-\u0A42]|" - u"[\u0A47-\u0A48]|[\u0A4B-\u0A4D]|[\u0A70-\u0A71]|[\u0A81-\u0A83]|\u0ABC|" - u"[\u0ABE-\u0AC5]|[\u0AC7-\u0AC9]|[\u0ACB-\u0ACD]|[\u0B01-\u0B03]|\u0B3C|" - u"[\u0B3E-\u0B43]|[\u0B47-\u0B48]|[\u0B4B-\u0B4D]|[\u0B56-\u0B57]|" - u"[\u0B82-\u0B83]|[\u0BBE-\u0BC2]|[\u0BC6-\u0BC8]|[\u0BCA-\u0BCD]|\u0BD7|" - u"[\u0C01-\u0C03]|[\u0C3E-\u0C44]|[\u0C46-\u0C48]|[\u0C4A-\u0C4D]|" - u"[\u0C55-\u0C56]|[\u0C82-\u0C83]|[\u0CBE-\u0CC4]|[\u0CC6-\u0CC8]|" - u"[\u0CCA-\u0CCD]|[\u0CD5-\u0CD6]|[\u0D02-\u0D03]|[\u0D3E-\u0D43]|" - u"[\u0D46-\u0D48]|[\u0D4A-\u0D4D]|\u0D57|\u0E31|[\u0E34-\u0E3A]|" - u"[\u0E47-\u0E4E]|\u0EB1|[\u0EB4-\u0EB9]|[\u0EBB-\u0EBC]|[\u0EC8-\u0ECD]|" - u"[\u0F18-\u0F19]|\u0F35|\u0F37|\u0F39|\u0F3E|\u0F3F|[\u0F71-\u0F84]|" - u"[\u0F86-\u0F8B]|[\u0F90-\u0F95]|\u0F97|[\u0F99-\u0FAD]|[\u0FB1-\u0FB7]|" - u"\u0FB9|[\u20D0-\u20DC]|\u20E1|[\u302A-\u302F]|\u3099|\u309A", - flags=re.UNICODE) + "[\u0041-\u005a]|[\u0061-\u007a]|[\u00c0-\u00d6]|[\u00d8-\u00f6]|" + "[\u00f8-\u00ff]|[\u0100-\u0131]|[\u0134-\u013e]|[\u0141-\u0148]|" + "[\u014a-\u017e]|[\u0180-\u01c3]|[\u01cd-\u01f0]|[\u01f4-\u01f5]|" + "[\u01fa-\u0217]|[\u0250-\u02a8]|[\u02bb-\u02c1]|\u0386|[\u0388-\u038a]|" + "\u038c|[\u038e-\u03a1]|[\u03a3-\u03ce]|[\u03d0-\u03d6]|" + "\u03da|\u03dc|\u03de|\u03e0|[\u03e2-\u03f3]|[\u0401-\u040c]|" + "[\u040e-\u044f]|[\u0451-\u045c]|[\u045e-\u0481]|[\u0490-\u04c4]|" + "[\u04c7-\u04c8]|[\u04cb-\u04cc]|[\u04d0-\u04eb]|[\u04ee-\u04f5]|" + "[\u04f8-\u04f9]|[\u0531-\u0556]|\u0559|[\u0561-\u0586]|[\u05d0-\u05ea]|" + "[\u05f0-\u05f2]|[\u0621-\u063a]|[\u0641-\u064a]|[\u0671-\u06b7]|" + "[\u06ba-\u06be]|[\u06c0-\u06ce]|[\u06d0-\u06d3]|\u06d5|[\u06e5-\u06e6]|" + "[\u0905-\u0939]|\u093d|[\u0958-\u0961]|[\u0985-\u098c]|[\u098f-\u0990]|" + "[\u0993-\u09a8]|[\u09aa-\u09b0]|\u09b2|[\u09b6-\u09b9]|[\u09dc-\u09dd]|" + "[\u09df-\u09e1]|[\u09f0-\u09f1]|[\u0a05-\u0a0a]|[\u0a0f-\u0a10]|" + "[\u0a13-\u0a28]|[\u0a2a-\u0a30]|[\u0a32-\u0a33]|[\u0a35-\u0a36]|" + "[\u0a38-\u0a39]|[\u0a59-\u0a5c]|\u0a5e|[\u0a72-\u0a74]|[\u0a85-\u0a8b]|" + "\u0a8d|[\u0a8f-\u0a91]|[\u0a93-\u0aa8]|[\u0aaa-\u0ab0]|[\u0ab2-\u0ab3]|" + "[\u0ab5-\u0ab9]|\u0abd|\u0ae0|[\u0b05-\u0b0c]|[\u0b0f-\u0b10]|" + "[\u0b13-\u0b28]|[\u0b2a-\u0b30]|[\u0b32-\u0b33]|[\u0b36-\u0b39]|\u0b3d|" + "[\u0b5c-\u0b5d]|[\u0b5f-\u0b61]|[\u0b85-\u0b8a]|[\u0b8e-\u0b90]|" + "[\u0b92-\u0b95]|[\u0b99-\u0b9a]|\u0b9c|[\u0b9e-\u0b9f]|[\u0ba3-\u0ba4]|" + "[\u0ba8-\u0baa]|[\u0bae-\u0bb5]|[\u0bb7-\u0bb9]|[\u0c05-\u0c0c]|" + "[\u0c0e-\u0c10]|[\u0c12-\u0c28]|[\u0c2a-\u0c33]|[\u0c35-\u0c39]|" + "[\u0c60-\u0c61]|[\u0c85-\u0c8c]|[\u0c8e-\u0c90]|[\u0c92-\u0ca8]|" + "[\u0caa-\u0cb3]|[\u0cb5-\u0cb9]|\u0cde|[\u0ce0-\u0ce1]|[\u0d05-\u0d0c]|" + "[\u0d0e-\u0d10]|[\u0d12-\u0d28]|[\u0d2a-\u0d39]|[\u0d60-\u0d61]|" + "[\u0e01-\u0e2e]|\u0e30|[\u0e32-\u0e33]|[\u0e40-\u0e45]|[\u0e81-\u0e82]|" + "\u0e84|[\u0e87-\u0e88]|\u0e8a|\u0e8d|[\u0e94-\u0e97]|[\u0e99-\u0e9f]|" + "[\u0ea1-\u0ea3]|\u0ea5|\u0ea7|[\u0eaa-\u0eab]|[\u0ead-\u0eae]|\u0eb0|" + "[\u0eb2-\u0eb3]|\u0ebd|[\u0ec0-\u0ec4]|[\u0f40-\u0f47]|[\u0f49-\u0f69]|" + "[\u10a0-\u10c5]|[\u10d0-\u10f6]|\u1100|[\u1102-\u1103]|[\u1105-\u1107]|" + "\u1109|[\u110b-\u110c]|[\u110e-\u1112]|\u113c|\u113e|\u1140|\u114c|" + "\u114e|\u1150|[\u1154-\u1155]|\u1159|[\u115f-\u1161]|\u1163|\u1165|" + "\u1167|\u1169|[\u116d-\u116e]|[\u1172-\u1173]|\u1175|\u119e|\u11a8|" + "\u11ab|[\u11ae-\u11af]|[\u11b7-\u11b8]|\u11ba|[\u11bc-\u11c2]|\u11eb|" + "\u11f0|\u11f9|[\u1e00-\u1e9b]|[\u1ea0-\u1ef9]|[\u1f00-\u1f15]|" + "[\u1f18-\u1f1d]|[\u1f20-\u1f45]|[\u1f48-\u1f4d]|[\u1f50-\u1f57]|\u1f59|" + "\u1f5b|\u1f5d|[\u1f5f-\u1f7d]|[\u1f80-\u1fb4]|[\u1fb6-\u1fbc]|\u1fbe|" + "[\u1fc2-\u1fc4]|[\u1fc6-\u1fcc]|[\u1fd0-\u1fd3]|[\u1fd6-\u1fdb]|" + "[\u1fe0-\u1fec]|[\u1ff2-\u1ff4]|[\u1ff6-\u1ffc]|\u2126|[\u212a-\u212b]|" + "\u212e|[\u2180-\u2182]|[\u3041-\u3094]|[\u30a1-\u30fa]|[\u3105-\u312c]|" + "[\uac00-\ud7a3]", + flags=re.UNICODE, +) + + +RE_Ideographic = re.compile("[\u4e00-\u9fa5]|\u3007|[\u3021-\u3029]", flags=re.UNICODE) + +RE_CombiningChar = re.compile( + "[\u0300-\u0345]|[\u0360-\u0361]|[\u0483-\u0486]|[\u0591-\u05a1]|" + "[\u05a3-\u05b9]|[\u05bb-\u05bd]|\u05bf|[\u05c1-\u05c2]|\u05c4|" + "[\u064b-\u0652]|\u0670|[\u06d6-\u06dc]|[\u06dd-\u06df]|[\u06e0-\u06e4]|" + "[\u06e7-\u06e8]|[\u06ea-\u06ed]|[\u0901-\u0903]|\u093c|[\u093e-\u094c]|" + "\u094d|[\u0951-\u0954]|[\u0962-\u0963]|[\u0981-\u0983]|\u09bc|\u09be|" + "\u09bf|[\u09c0-\u09c4]|[\u09c7-\u09c8]|[\u09cb-\u09cd]|\u09d7|" + "[\u09e2-\u09e3]|\u0a02|\u0a3c|\u0a3e|\u0a3f|[\u0a40-\u0a42]|" + "[\u0a47-\u0a48]|[\u0a4b-\u0a4d]|[\u0a70-\u0a71]|[\u0a81-\u0a83]|\u0abc|" + "[\u0abe-\u0ac5]|[\u0ac7-\u0ac9]|[\u0acb-\u0acd]|[\u0b01-\u0b03]|\u0b3c|" + "[\u0b3e-\u0b43]|[\u0b47-\u0b48]|[\u0b4b-\u0b4d]|[\u0b56-\u0b57]|" + "[\u0b82-\u0b83]|[\u0bbe-\u0bc2]|[\u0bc6-\u0bc8]|[\u0bca-\u0bcd]|\u0bd7|" + "[\u0c01-\u0c03]|[\u0c3e-\u0c44]|[\u0c46-\u0c48]|[\u0c4a-\u0c4d]|" + "[\u0c55-\u0c56]|[\u0c82-\u0c83]|[\u0cbe-\u0cc4]|[\u0cc6-\u0cc8]|" + "[\u0cca-\u0ccd]|[\u0cd5-\u0cd6]|[\u0d02-\u0d03]|[\u0d3e-\u0d43]|" + "[\u0d46-\u0d48]|[\u0d4a-\u0d4d]|\u0d57|\u0e31|[\u0e34-\u0e3a]|" + "[\u0e47-\u0e4e]|\u0eb1|[\u0eb4-\u0eb9]|[\u0ebb-\u0ebc]|[\u0ec8-\u0ecd]|" + "[\u0f18-\u0f19]|\u0f35|\u0f37|\u0f39|\u0f3e|\u0f3f|[\u0f71-\u0f84]|" + "[\u0f86-\u0f8b]|[\u0f90-\u0f95]|\u0f97|[\u0f99-\u0fad]|[\u0fb1-\u0fb7]|" + "\u0fb9|[\u20d0-\u20dc]|\u20e1|[\u302a-\u302f]|\u3099|\u309a", + flags=re.UNICODE, +) RE_Digit = re.compile( - u"[\u0030-\u0039]|[\u0660-\u0669]|[\u06F0-\u06F9]|[\u0966-\u096F]|" - u"[\u09E6-\u09EF]|[\u0A66-\u0A6F]|[\u0AE6-\u0AEF]|[\u0B66-\u0B6F]|" - u"[\u0BE7-\u0BEF]|[\u0C66-\u0C6F]|[\u0CE6-\u0CEF]|[\u0D66-\u0D6F]|" - u"[\u0E50-\u0E59]|[\u0ED0-\u0ED9]|[\u0F20-\u0F29]", flags=re.UNICODE) + "[\u0030-\u0039]|[\u0660-\u0669]|[\u06f0-\u06f9]|[\u0966-\u096f]|" + "[\u09e6-\u09ef]|[\u0a66-\u0a6f]|[\u0ae6-\u0aef]|[\u0b66-\u0b6f]|" + "[\u0be7-\u0bef]|[\u0c66-\u0c6f]|[\u0ce6-\u0cef]|[\u0d66-\u0d6f]|" + "[\u0e50-\u0e59]|[\u0ed0-\u0ed9]|[\u0f20-\u0f29]", + flags=re.UNICODE, +) RE_Extender = re.compile( - u"\u00B7|\u02D0|\u02D1|\u0387|\u0640|\u0E46|\u0EC6|\u3005|[\u3031-\u3035]|" - u"[\u309D-\u309E]|[\u30FC-\u30FE]", flags=re.UNICODE) - - -RE_Letter = re.compile(u'|'.join((RE_BaseChar.pattern, RE_Ideographic.pattern)), - flags=re.UNICODE) - - -RE_NameChar = re.compile(u'|'.join(( - RE_Letter.pattern, RE_Digit.pattern, '.', '-', '_', ':', - RE_CombiningChar.pattern, RE_Extender.pattern, - )), flags=re.UNICODE) - - -RE_NCNameChar = re.compile(u'|'.join(( - RE_Letter.pattern, RE_Digit.pattern, '.', '-', '_', # <= no column - RE_CombiningChar.pattern, RE_Extender.pattern, - )), flags=re.UNICODE) + "\u00b7|\u02d0|\u02d1|\u0387|\u0640|\u0e46|\u0ec6|\u3005|[\u3031-\u3035]|" + "[\u309d-\u309e]|[\u30fc-\u30fe]", + flags=re.UNICODE, +) + + +RE_Letter = re.compile( + "|".join((RE_BaseChar.pattern, RE_Ideographic.pattern)), flags=re.UNICODE +) + + +RE_NameChar = re.compile( + "|".join( + ( + RE_Letter.pattern, + RE_Digit.pattern, + ".", + "-", + "_", + ":", + RE_CombiningChar.pattern, + RE_Extender.pattern, + ) + ), + flags=re.UNICODE, +) + + +RE_NCNameChar = re.compile( + "|".join( + ( + RE_Letter.pattern, + RE_Digit.pattern, + ".", + "-", + "_", # <= no column + RE_CombiningChar.pattern, + RE_Extender.pattern, + ) + ), + flags=re.UNICODE, +) class NormalizedString(Unicode): - __type_name__ = 'normalizedString' + __type_name__ = "normalizedString" __extends__ = Unicode class Attributes(Unicode.Attributes): @@ -131,26 +157,28 @@ class Attributes(Unicode.Attributes): class Token(NormalizedString): - __type_name__ = 'token' + __type_name__ = "token" class Attributes(Unicode.Attributes): white_space = "collapse" + # https://www.w3.org/TR/2000/WD-xml-2e-20000814#NT-Name class Name(Token): - __type_name__ = 'Name' + __type_name__ = "Name" class Attributes(Unicode.Attributes): # https://www.w3.org/TR/2000/WD-xml-2e-20000814#NT-Name - pattern = '(%s)(%s)*' % ( - u'|'.join((RE_Letter.pattern, '_', ':')), - RE_NameChar.pattern + pattern = "(%s)(%s)*" % ( + "|".join((RE_Letter.pattern, "_", ":")), + RE_NameChar.pattern, ) # https://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-NCName class NCName(Name): - __type_name__ = 'NCName' + __type_name__ = "NCName" + class Attributes(Unicode.Attributes): pattern = "(%s|_)%s*" % (RE_Letter.pattern, RE_NCNameChar.pattern) @@ -171,6 +199,7 @@ class Attributes(Unicode.Attributes): QName = (NCName:)?NCName """ + pattern = "(%s:)?(%s)" % ( NCName.Attributes.pattern, NCName.Attributes.pattern, @@ -178,18 +207,18 @@ class Attributes(Unicode.Attributes): class NMToken(Unicode): - __type_name__ = 'NMTOKEN' + __type_name__ = "NMTOKEN" class Attributes(Unicode.Attributes): unicode_pattern = PATT_NMTOKEN class ID(NCName): - __type_name__ = 'ID' + __type_name__ = "ID" class Language(Token): - __type_name__ = 'language' + __type_name__ = "language" class Attributes(Unicode.Attributes): - pattern = '[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*' + pattern = "[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*" diff --git a/spyne/model/relational.py b/spyne/model/relational.py index 4f2ab6773..cedd1655a 100644 --- a/spyne/model/relational.py +++ b/spyne/model/relational.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -23,9 +22,9 @@ class FileData(ComplexModel): _type_info = [ - ('name', Unicode), - ('type', Unicode), - ('path', Unicode), + ("name", Unicode), + ("type", Unicode), + ("path", Unicode), ] @property @@ -43,4 +42,3 @@ def handle(self): @handle.setter def handle(self, handle): self._handle = handle - diff --git a/spyne/protocol/__init__.py b/spyne/protocol/__init__.py index a98a9b610..0209b815f 100644 --- a/spyne/protocol/__init__.py +++ b/spyne/protocol/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -28,17 +27,34 @@ class ProtocolBase(InProtocolBase, OutProtocolBase): - def __init__(self, app=None, validator=None, mime_type=None, - ignore_uncap=False, ignore_wrappers=False, binary_encoding=None, - string_encoding='utf8'): - - InProtocolBase.__init__(self, app=app, validator=validator, - mime_type=mime_type, ignore_wrappers=ignore_wrappers, - binary_encoding=binary_encoding) - - OutProtocolBase.__init__(self, app=app, mime_type=mime_type, - ignore_wrappers=ignore_wrappers, ignore_uncap=ignore_uncap, - binary_encoding=binary_encoding) + def __init__( + self, + app=None, + validator=None, + mime_type=None, + ignore_uncap=False, + ignore_wrappers=False, + binary_encoding=None, + string_encoding="utf8", + ): + + InProtocolBase.__init__( + self, + app=app, + validator=validator, + mime_type=mime_type, + ignore_wrappers=ignore_wrappers, + binary_encoding=binary_encoding, + ) + + OutProtocolBase.__init__( + self, + app=app, + mime_type=mime_type, + ignore_wrappers=ignore_wrappers, + ignore_uncap=ignore_uncap, + binary_encoding=binary_encoding, + ) self.default_string_encoding = string_encoding self.ignore_empty_faultactor = True diff --git a/spyne/protocol/_base.py b/spyne/protocol/_base.py index 6c4f6c447..c29419fef 100644 --- a/spyne/protocol/_base.py +++ b/spyne/protocol/_base.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -20,24 +19,24 @@ from __future__ import print_function import logging + logger = logging.getLogger(__name__) from datetime import datetime from weakref import WeakKeyDictionary -from spyne import ProtocolContext, EventManager from spyne.const import DEFAULT_LOCALE -from spyne.model import Array +from spyne.context import ProtocolContext from spyne.error import ResourceNotFoundError +from spyne.evmgr import EventManager +from spyne.model import Array from spyne.util import DefaultAttrDict -from spyne.util.six import string_types - _MISSING = type("_MISSING", (object,), {})() class ProtocolMixin(object): - mime_type = 'application/octet-stream' + mime_type = "application/octet-stream" SOFT_VALIDATION = type("Soft", (object,), {}) REQUEST = type("Request", (object,), {}) @@ -55,8 +54,14 @@ class ProtocolMixin(object): type_attrs = {} """Default customizations to be passed to underlying classes.""" - def __init__(self, app=None, mime_type=None, ignore_wrappers=None, - binary_encoding=None, string_encoding=None): + def __init__( + self, + app=None, + mime_type=None, + ignore_wrappers=None, + binary_encoding=None, + string_encoding=None, + ): self.__app = None self.set_app(app) @@ -158,31 +163,34 @@ def app(self): @staticmethod def strip_wrappers(cls, inst): - ti = getattr(cls, '_type_info', {}) + ti = getattr(cls, "_type_info", {}) while len(ti) == 1 and cls.Attributes._wrapper: # Wrappers are auto-generated objects that have exactly one # child type. - key, = ti.keys() + (key,) = ti.keys() if not issubclass(cls, Array): inst = getattr(inst, key, None) - cls, = ti.values() - ti = getattr(cls, '_type_info', {}) + (cls,) = ti.values() + ti = getattr(cls, "_type_info", {}) return cls, inst def set_app(self, value): - assert self.__app is None, "One protocol instance should belong to one " \ - "application instance. It currently belongs " \ - "to: %r" % self.__app + assert self.__app is None, ( + "One protocol instance should belong to one " + "application instance. It currently belongs " + "to: %r" % self.__app + ) self.__app = value @staticmethod def issubclass(sub, cls): - suborig = getattr(sub, '__orig__', None) - clsorig = getattr(cls, '__orig__', None) - return issubclass(sub if suborig is None else suborig, - cls if clsorig is None else clsorig) + suborig = getattr(sub, "__orig__", None) + clsorig = getattr(cls, "__orig__", None) + return issubclass( + sub if suborig is None else suborig, cls if clsorig is None else clsorig + ) def get_cls_attrs(self, cls): logger.debug("%r attrcache size: %d", self, len(self._attrcache)) @@ -190,10 +198,13 @@ def get_cls_attrs(self, cls): if attr is not None: return attr - self._attrcache[cls] = attr = DefaultAttrDict([ + self._attrcache[cls] = attr = DefaultAttrDict( + [ (k, getattr(cls.Attributes, k)) - for k in dir(cls.Attributes) + META_ATTR - if not k.startswith('__')]) + for k in dir(cls.Attributes) + META_ATTR + if not k.startswith("__") + ] + ) if cls.Attributes.prot_attrs: cls_attrs = cls.Attributes.prot_attrs.get(self.__class__, {}) @@ -240,8 +251,8 @@ def get_call_handles(self, ctx): """ name = ctx.method_request_string - if not name.startswith(u"{"): - name = u'{%s}%s' % (self.app.interface.get_tns(), name) + if not name.startswith("{"): + name = "{%s}%s" % (self.app.interface.get_tns(), name) call_handles = self.app.interface.service_method_map.get(name, []) @@ -259,26 +270,35 @@ def get_polymorphic_target(self, cls, inst): orig_cls = cls.__orig__ or cls if inst.__class__ is orig_cls: - logger.debug("PMORPH Skipped: Instance class %r is the same as " - "designated base class", inst.__class__) + logger.debug( + "PMORPH Skipped: Instance class %r is the same as " + "designated base class", + inst.__class__, + ) return cls, False if not isinstance(inst, orig_cls): - logger.debug("PMORPH Skipped: Instance class %r is not a subclass " - "of designated base class %r", inst.__class__, orig_cls) + logger.debug( + "PMORPH Skipped: Instance class %r is not a subclass " + "of designated base class %r", + inst.__class__, + orig_cls, + ) return cls, False cls_attr = self.get_cls_attrs(cls) polymap_cls = cls_attr.polymap.get(inst.__class__, None) if polymap_cls is not None: - logger.debug("PMORPH OK: cls switch with polymap: %r => %r", - cls, polymap_cls) + logger.debug( + "PMORPH OK: cls switch with polymap: %r => %r", cls, polymap_cls + ) return polymap_cls, True else: - logger.debug("PMORPH OK: cls switch without polymap: %r => %r", - cls, inst.__class__) + logger.debug( + "PMORPH OK: cls switch without polymap: %r => %r", cls, inst.__class__ + ) return inst.__class__, True @staticmethod @@ -309,8 +329,7 @@ def trc_verbose(cls, locale, default): else: _log_tr = "translated to '%s' with" - logger.debug(' '.join(("%r ", _log_tr, _log_locale)), - cls, retval, locale) + logger.debug(" ".join(("%r ", _log_tr, _log_locale)), cls, retval, locale) return retval @@ -350,7 +369,7 @@ def trd_verbose(trdict, locale, default): retval = default _log_tr = "translated to '%s' without any translations at all with" - elif isinstance(trdict, string_types): + elif isinstance(trdict, str): retval = trdict _log_tr = "translated to '%s' regardless of" @@ -362,8 +381,7 @@ def trd_verbose(trdict, locale, default): else: _log_tr = "translated to '%s' with" - logger.debug(' '.join(("%r ", _log_tr, _log_locale)), - trdict, retval, locale) + logger.debug(" ".join(("%r ", _log_tr, _log_locale)), trdict, retval, locale) return retval @@ -381,7 +399,7 @@ def trd(trdict, locale, default): locale = DEFAULT_LOCALE if trdict is None: return default - if isinstance(trdict, string_types): + if isinstance(trdict, str): return trdict return trdict.get(locale, default) @@ -415,4 +433,4 @@ def sort_fields(self, cls=None, items=None): return items -META_ATTR = ['nullable', 'default_factory'] +META_ATTR = ["nullable", "default_factory"] diff --git a/spyne/protocol/_inbase.py b/spyne/protocol/_inbase.py index a2b2ff267..607b49187 100644 --- a/spyne/protocol/_inbase.py +++ b/spyne/protocol/_inbase.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -20,54 +19,68 @@ from __future__ import print_function import logging + logger = logging.getLogger(__name__) import re -import pytz import uuid - +from datetime import date, datetime, time, timedelta +from decimal import Decimal as D +from decimal import InvalidOperation from math import modf -from time import strptime, mktime -from datetime import timedelta, time, datetime, date -from decimal import Decimal as D, InvalidOperation +from time import mktime, strptime +import pytz from pytz import FixedOffset try: - from lxml import etree - from lxml import html + from lxml import etree, html except ImportError: etree = None html = None -from spyne.protocol._base import ProtocolMixin -from spyne.model import ModelBase, XmlAttribute, Array, Null, \ - ByteArray, File, ComplexModelBase, AnyXml, AnyHtml, Unicode, String, \ - Decimal, Double, Integer, Time, DateTime, Uuid, Date, Duration, Boolean, Any - from spyne.error import ValidationError - -from spyne.model.binary import binary_decoding_handlers, BINARY_ENCODING_USE_DEFAULT - -from spyne.util import six +from spyne.model import ( + Any, + AnyHtml, + AnyXml, + Array, + Boolean, + ByteArray, + ComplexModelBase, + Date, + DateTime, + Decimal, + Double, + Duration, + File, + Integer, + ModelBase, + Null, + String, + Time, + Unicode, + Uuid, + XmlAttribute, +) +from spyne.model.binary import BINARY_ENCODING_USE_DEFAULT, binary_decoding_handlers from spyne.model.enum import EnumBase -from spyne.model.primitive.datetime import TIME_PATTERN, DATE_PATTERN - +from spyne.model.primitive.datetime import DATE_PATTERN, TIME_PATTERN +from spyne.protocol._base import ProtocolMixin from spyne.util.cdict import cdict - _date_re = re.compile(DATE_PATTERN) _time_re = re.compile(TIME_PATTERN) _duration_re = re.compile( - r'(?P-?)' - r'P' - r'(?:(?P\d+)Y)?' - r'(?:(?P\d+)M)?' - r'(?:(?P\d+)D)?' - r'(?:T(?:(?P\d+)H)?' - r'(?:(?P\d+)M)?' - r'(?:(?P\d+(.\d+)?)S)?)?' - ) + r"(?P-?)" + r"P" + r"(?:(?P\d+)Y)?" + r"(?:(?P\d+)M)?" + r"(?:(?P\d+)D)?" + r"(?:T(?:(?P\d+)H)?" + r"(?:(?P\d+)M)?" + r"(?:(?P\d+(.\d+)?)S)?)?" +) class InProtocolBase(ProtocolMixin): @@ -96,14 +109,25 @@ class InProtocolBase(ProtocolMixin): default instead of subclassing the releavant protocol implementation. """ - def __init__(self, app=None, validator=None, mime_type=None, - ignore_wrappers=False, binary_encoding=None, string_encoding=None): + def __init__( + self, + app=None, + validator=None, + mime_type=None, + ignore_wrappers=False, + binary_encoding=None, + string_encoding=None, + ): self.validator = None - super(InProtocolBase, self).__init__(app=app, mime_type=mime_type, + super(InProtocolBase, self).__init__( + app=app, + mime_type=mime_type, ignore_wrappers=ignore_wrappers, - binary_encoding=binary_encoding, string_encoding=string_encoding) + binary_encoding=binary_encoding, + string_encoding=string_encoding, + ) self.message = None self.validator = None @@ -128,7 +152,7 @@ def __init__(self, app=None, validator=None, mime_type=None, EnumBase: self.enum_base_from_bytes, ModelBase: self.model_base_from_bytes, XmlAttribute: self.xmlattribute_from_bytes, - ComplexModelBase: self.complex_model_base_from_bytes + ComplexModelBase: self.complex_model_base_from_bytes, } self._from_bytes_handlers = cdict(fsh) @@ -148,14 +172,13 @@ def __init__(self, app=None, validator=None, mime_type=None, self._from_unicode_handlers[DateTime] = self.datetime_from_unicode self._from_unicode_handlers[Duration] = self.duration_from_unicode - self._datetime_dsmap = { None: self._datetime_from_unicode, - 'sec': self._datetime_from_sec, - 'sec_float': self._datetime_from_sec_float, - 'msec': self._datetime_from_msec, - 'msec_float': self._datetime_from_msec_float, - 'usec': self._datetime_from_usec, + "sec": self._datetime_from_sec, + "sec_float": self._datetime_from_sec_float, + "msec": self._datetime_from_msec, + "msec_float": self._datetime_from_msec_float, + "usec": self._datetime_from_usec, } def _datetime_from_sec(self, cls, value): @@ -227,8 +250,11 @@ def from_bytes(self, class_, string, *args, **kwargs): if string is None: return None - if isinstance(string, six.string_types) and \ - len(string) == 0 and class_.Attributes.empty_is_none: + if ( + isinstance(string, str) + and len(string) == 0 + and class_.Attributes.empty_is_none + ): return None handler = self._from_bytes_handlers[class_] @@ -238,15 +264,9 @@ def from_unicode(self, class_, string, *args, **kwargs): if string is None: return None - #if not six.PY2: - # assert isinstance(string, str), \ - # "Invalid type passed to `from_unicode`: {}".format( - # (class_, type(string), string)) - cls_attrs = self.get_cls_attrs(class_) - if isinstance(string, six.string_types) and len(string) == 0 and \ - cls_attrs.empty_is_none: + if isinstance(string, str) and len(string) == 0 and cls_attrs.empty_is_none: return None handler = self._from_unicode_handlers[class_] @@ -283,8 +303,8 @@ def uuid_from_unicode(self, cls, string, suggested_encoding=None): retval = string - if ser_as in ('bytes', 'bytes_le'): - retval, = binary_decoding_handlers[encoding](string) + if ser_as in ("bytes", "bytes_le"): + (retval,) = binary_decoding_handlers[encoding](string) try: retval = _uuid_deserialize[ser_as](retval) @@ -303,10 +323,10 @@ def uuid_from_bytes(self, cls, string, suggested_encoding=None, **_): retval = string - if ser_as in ('bytes', 'bytes_le'): - retval, = binary_decoding_handlers[encoding](string) - elif isinstance(string, six.binary_type): - retval = string.decode('ascii') + if ser_as in ("bytes", "bytes_le"): + (retval,) = binary_decoding_handlers[encoding](string) + elif isinstance(string, bytes): + retval = string.decode("ascii") try: retval = _uuid_deserialize[ser_as](retval) @@ -318,29 +338,31 @@ def uuid_from_bytes(self, cls, string, suggested_encoding=None, **_): def unicode_from_bytes(self, cls, value): retval = value - if isinstance(value, six.binary_type): + if isinstance(value, bytes): cls_attrs = self.get_cls_attrs(cls) if cls_attrs.encoding is not None: - retval = six.text_type(value, cls_attrs.encoding, - errors=cls_attrs.unicode_errors) + retval = str(value, cls_attrs.encoding, errors=cls_attrs.unicode_errors) elif self.string_encoding is not None: - retval = six.text_type(value, self.string_encoding, - errors=cls_attrs.unicode_errors) + retval = str( + value, self.string_encoding, errors=cls_attrs.unicode_errors + ) else: - retval = six.text_type(value, errors=cls_attrs.unicode_errors) + retval = str(value, errors=cls_attrs.unicode_errors) return retval def string_from_bytes(self, cls, value): retval = value cls_attrs = self.get_cls_attrs(cls) - if isinstance(value, six.text_type): + if isinstance(value, str): if cls_attrs.encoding is None: - raise Exception("You need to define a source encoding for " - "decoding incoming unicode values.") + raise Exception( + "You need to define a source encoding for " + "decoding incoming unicode values." + ) else: retval = value.encode(cls_attrs.encoding) @@ -348,10 +370,11 @@ def string_from_bytes(self, cls, value): def decimal_from_unicode(self, cls, string): cls_attrs = self.get_cls_attrs(cls) - if cls_attrs.max_str_len is not None and len(string) > \ - cls_attrs.max_str_len: - raise ValidationError(string, "Decimal %%r longer than %d " - "characters" % cls_attrs.max_str_len) + if cls_attrs.max_str_len is not None and len(string) > cls_attrs.max_str_len: + raise ValidationError( + string, + "Decimal %%r longer than %d " "characters" % cls_attrs.max_str_len, + ) try: return D(string) @@ -359,8 +382,9 @@ def decimal_from_unicode(self, cls, string): raise ValidationError(string, "%%r: %r" % e) def decimal_from_bytes(self, cls, string): - return self.decimal_from_unicode(cls, - string.decode(self.default_string_encoding)) + return self.decimal_from_unicode( + cls, string.decode(self.default_string_encoding) + ) def double_from_bytes(self, cls, string): try: @@ -371,12 +395,14 @@ def double_from_bytes(self, cls, string): def integer_from_bytes(self, cls, string): cls_attrs = self.get_cls_attrs(cls) - if isinstance(string, (six.text_type, six.binary_type)) and \ - cls_attrs.max_str_len is not None and \ - len(string) > cls_attrs.max_str_len: - raise ValidationError(string, - "Integer %%r longer than %d characters" - % cls_attrs.max_str_len) + if ( + isinstance(string, (str, bytes)) + and cls_attrs.max_str_len is not None + and len(string) > cls_attrs.max_str_len + ): + raise ValidationError( + string, "Integer %%r longer than %d characters" % cls_attrs.max_str_len + ) try: return int(string) @@ -388,21 +414,21 @@ def time_from_unicode(self, cls, string): match = _time_re.match(string) if match is None: - raise ValidationError(string, "%%r does not match regex %r " % - _time_re.pattern) + raise ValidationError( + string, "%%r does not match regex %r " % _time_re.pattern + ) fields = match.groupdict(0) - microsec = fields.get('sec_frac') + microsec = fields.get("sec_frac") if microsec is None or microsec == 0: microsec = 0 else: microsec = min(999999, int(round(float(microsec) * 1e6))) - return time(int(fields['hr']), int(fields['min']), - int(fields['sec']), microsec) + return time(int(fields["hr"]), int(fields["min"]), int(fields["sec"]), microsec) def time_from_bytes(self, cls, string): - if isinstance(string, six.binary_type): + if isinstance(string, bytes): string = string.decode(self.default_string_encoding) return self.time_from_unicode(cls, string) @@ -413,15 +439,15 @@ def date_from_unicode_iso(self, cls, string): """ try: - return date(*(strptime(string, u'%Y-%m-%d')[0:3])) + return date(*(strptime(string, "%Y-%m-%d")[0:3])) except ValueError: match = cls._offset_re.match(string) if match: - year = int(match.group('year')) - month = int(match.group('month')) - day = int(match.group('day')) + year = int(match.group("year")) + month = int(match.group("month")) + day = int(match.group("day")) return date(year, month, day) @@ -429,7 +455,8 @@ def date_from_unicode_iso(self, cls, string): def enum_base_from_bytes(self, cls, value): if self.validator is self.SOFT_VALIDATION and not ( - cls.validate_string(cls, value)): + cls.validate_string(cls, value) + ): raise ValidationError(value) return getattr(cls, value) @@ -450,8 +477,7 @@ def datetime_from_unicode_iso(self, cls, string): if match is None: match = cls._offset_re.match(string) if match: - tz_hr, tz_min = [int(match.group(x)) - for x in ("tz_hr", "tz_min")] + tz_hr, tz_min = [int(match.group(x)) for x in ("tz_hr", "tz_min")] tz = FixedOffset(tz_hr * 60 + tz_min, {}) retval = _parse_datetime_iso_match(match, tz=tz) if astz is not None: @@ -473,14 +499,14 @@ def datetime_from_unicode(self, cls, string): return self._datetime_dsmap[serialize_as](cls, string) def datetime_from_bytes(self, cls, string): - if isinstance(string, six.binary_type): + if isinstance(string, bytes): string = string.decode(self.default_string_encoding) serialize_as = self.get_cls_attrs(cls).serialize_as return self._datetime_dsmap[serialize_as](cls, string) def date_from_bytes(self, cls, string): - if isinstance(string, six.binary_type): + if isinstance(string, bytes): string = string.decode(self.default_string_encoding) date_format = self._get_date_format(self.get_cls_attrs(cls)) @@ -494,11 +520,13 @@ def date_from_bytes(self, cls, string): except ValueError as e: match = cls._offset_re.match(string) if match: - return date(int(match.group('year')), - int(match.group('month')), int(match.group('day'))) + return date( + int(match.group("year")), + int(match.group("month")), + int(match.group("day")), + ) else: - raise ValidationError(string, - "%%r: %s" % repr(e).replace("%", "%%")) + raise ValidationError(string, "%%r: %s" % repr(e).replace("%", "%%")) def date_from_unicode(self, cls, string): date_format = self._get_date_format(self.get_cls_attrs(cls)) @@ -512,8 +540,11 @@ def date_from_unicode(self, cls, string): except ValueError as e: match = cls._offset_re.match(string) if match: - return date(int(match.group('year')), - int(match.group('month')), int(match.group('day'))) + return date( + int(match.group("year")), + int(match.group("month")), + int(match.group("day")), + ) else: # the message from ValueError is quite nice already raise ValidationError(e.message, "%s") @@ -521,36 +552,42 @@ def date_from_unicode(self, cls, string): def duration_from_unicode(self, cls, string): duration = _duration_re.match(string).groupdict(0) if duration is None: - raise ValidationError(string, - "Time data '%%s' does not match regex '%s'" % - (_duration_re.pattern,)) - - days = int(duration['days']) - days += int(duration['months']) * 30 - days += int(duration['years']) * 365 - hours = int(duration['hours']) - minutes = int(duration['minutes']) - seconds = float(duration['seconds']) + raise ValidationError( + string, + "Time data '%%s' does not match regex '%s'" % (_duration_re.pattern,), + ) + + days = int(duration["days"]) + days += int(duration["months"]) * 30 + days += int(duration["years"]) * 365 + hours = int(duration["hours"]) + minutes = int(duration["minutes"]) + seconds = float(duration["seconds"]) f, i = modf(seconds) seconds = i microseconds = int(1e6 * f) - delta = timedelta(days=days, hours=hours, minutes=minutes, - seconds=seconds, microseconds=microseconds) + delta = timedelta( + days=days, + hours=hours, + minutes=minutes, + seconds=seconds, + microseconds=microseconds, + ) - if duration['sign'] == "-": + if duration["sign"] == "-": delta *= -1 return delta def duration_from_bytes(self, cls, string): - if isinstance(string, six.binary_type): + if isinstance(string, bytes): string = string.decode(self.default_string_encoding) return self.duration_from_unicode(cls, string) def boolean_from_bytes(self, cls, string): - return string.lower() in ('true', '1') + return string.lower() in ("true", "1") def byte_array_from_bytes(self, cls, value, suggested_encoding=None): encoding = self.get_cls_attrs(cls).encoding @@ -569,12 +606,12 @@ def complex_model_base_from_bytes(self, cls, string, **_): raise TypeError("Only primitives can be deserialized from string.") def array_from_bytes(self, cls, string, **_): - if self.get_cls_attrs(cls).serialize_as != 'sd-list': + if self.get_cls_attrs(cls).serialize_as != "sd-list": raise TypeError("Only primitives can be deserialized from string.") # sd-list being space-delimited list. retval = [] - inner_type, = cls._type_info.values() + (inner_type,) = cls._type_info.values() for s in string.split(): retval.append(self.from_bytes(inner_type, s)) @@ -603,14 +640,6 @@ def _datetime_from_unicode(self, cls, string): retval = parser(self, cls, string) elif dt_format is not None: - if six.PY2: - # FIXME: perhaps it should encode to string's encoding instead - # of utf8 all the time - if isinstance(dt_format, six.text_type): - dt_format = dt_format.encode('utf8') - if isinstance(string, six.text_type): - string = string.encode('utf8') - retval = datetime.strptime(string, dt_format) astz = cls_attrs.as_timezone @@ -624,31 +653,27 @@ def _datetime_from_unicode(self, cls, string): _uuid_deserialize = { - None: lambda s: uuid.UUID(s.decode('ascii') if isinstance(s, bytes) else s), - 'hex': lambda s: uuid.UUID(hex=s), - 'urn': lambda s: uuid.UUID(hex=s), - 'bytes': lambda s: uuid.UUID(bytes=s), - 'bytes_le': lambda s: uuid.UUID(bytes_le=s), - 'fields': lambda s: uuid.UUID(fields=s), - 'int': lambda s: uuid.UUID(int=s), - ('int', int): lambda s: uuid.UUID(int=s), - ('int', str): lambda s: uuid.UUID(int=int(s)), + None: lambda s: uuid.UUID(s.decode("ascii") if isinstance(s, bytes) else s), + "hex": lambda s: uuid.UUID(hex=s), + "urn": lambda s: uuid.UUID(hex=s), + "bytes": lambda s: uuid.UUID(bytes=s), + "bytes_le": lambda s: uuid.UUID(bytes_le=s), + "fields": lambda s: uuid.UUID(fields=s), + "int": lambda s: uuid.UUID(int=s), + ("int", int): lambda s: uuid.UUID(int=s), + ("int", str): lambda s: uuid.UUID(int=int(s)), } -if six.PY2: - _uuid_deserialize[None] = lambda s: uuid.UUID(s) - _uuid_deserialize[('int', long)] = _uuid_deserialize[('int', int)] - def _parse_datetime_iso_match(date_match, tz=None): fields = date_match.groupdict() - year = int(fields.get('year')) - month = int(fields.get('month')) - day = int(fields.get('day')) - hour = int(fields.get('hr')) - minute = int(fields.get('min')) - second = int(fields.get('sec')) + year = int(fields.get("year")) + month = int(fields.get("month")) + day = int(fields.get("day")) + hour = int(fields.get("hr")) + minute = int(fields.get("min")) + second = int(fields.get("sec")) usecond = fields.get("sec_frac") if usecond is None: usecond = 0 @@ -660,50 +685,45 @@ def _parse_datetime_iso_match(date_match, tz=None): return datetime(year, month, day, hour, minute, second, usecond, tz) -_dt_sec = lambda cls, val: \ - int(mktime(val.timetuple())) -_dt_sec_float = lambda cls, val: \ - mktime(val.timetuple()) + (val.microsecond / 1e6) +_dt_sec = lambda cls, val: int(mktime(val.timetuple())) +_dt_sec_float = lambda cls, val: mktime(val.timetuple()) + (val.microsecond / 1e6) -_dt_msec = lambda cls, val: \ - int(mktime(val.timetuple())) * 1000 + (val.microsecond // 1000) -_dt_msec_float = lambda cls, val: \ - mktime(val.timetuple()) * 1000 + (val.microsecond / 1000.0) +_dt_msec = lambda cls, val: int(mktime(val.timetuple())) * 1000 + ( + val.microsecond // 1000 +) +_dt_msec_float = lambda cls, val: mktime(val.timetuple()) * 1000 + ( + val.microsecond / 1000.0 +) -_dt_usec = lambda cls, val: \ - int(mktime(val.timetuple())) * 1000000 + val.microsecond +_dt_usec = lambda cls, val: int(mktime(val.timetuple())) * 1000000 + val.microsecond _datetime_smap = { - 'sec': _dt_sec, - 'secs': _dt_sec, - 'second': _dt_sec, - 'seconds': _dt_sec, - - 'sec_float': _dt_sec_float, - 'secs_float': _dt_sec_float, - 'second_float': _dt_sec_float, - 'seconds_float': _dt_sec_float, - - 'msec': _dt_msec, - 'msecs': _dt_msec, - 'msecond': _dt_msec, - 'mseconds': _dt_msec, - 'millisecond': _dt_msec, - 'milliseconds': _dt_msec, - - 'msec_float': _dt_msec_float, - 'msecs_float': _dt_msec_float, - 'msecond_float': _dt_msec_float, - 'mseconds_float': _dt_msec_float, - 'millisecond_float': _dt_msec_float, - 'milliseconds_float': _dt_msec_float, - - 'usec': _dt_usec, - 'usecs': _dt_usec, - 'usecond': _dt_usec, - 'useconds': _dt_usec, - 'microsecond': _dt_usec, - 'microseconds': _dt_usec, + "sec": _dt_sec, + "secs": _dt_sec, + "second": _dt_sec, + "seconds": _dt_sec, + "sec_float": _dt_sec_float, + "secs_float": _dt_sec_float, + "second_float": _dt_sec_float, + "seconds_float": _dt_sec_float, + "msec": _dt_msec, + "msecs": _dt_msec, + "msecond": _dt_msec, + "mseconds": _dt_msec, + "millisecond": _dt_msec, + "milliseconds": _dt_msec, + "msec_float": _dt_msec_float, + "msecs_float": _dt_msec_float, + "msecond_float": _dt_msec_float, + "mseconds_float": _dt_msec_float, + "millisecond_float": _dt_msec_float, + "milliseconds_float": _dt_msec_float, + "usec": _dt_usec, + "usecs": _dt_usec, + "usecond": _dt_usec, + "useconds": _dt_usec, + "microsecond": _dt_usec, + "microseconds": _dt_usec, } diff --git a/spyne/protocol/_outbase.py b/spyne/protocol/_outbase.py index e9c904eb6..fcb6fa274 100644 --- a/spyne/protocol/_outbase.py +++ b/spyne/protocol/_outbase.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -20,41 +19,61 @@ from __future__ import print_function, unicode_literals import logging + logger = logging.getLogger(__name__) +import errno import re import uuid -import errno - -from os.path import isabs, join, abspath from collections import deque from datetime import datetime from decimal import Decimal as D -from mmap import mmap, ACCESS_READ +from mmap import ACCESS_READ, mmap +from os.path import abspath, isabs, join from time import mktime, strftime try: - from lxml import etree - from lxml import html + from lxml import etree, html except ImportError: etree = None html = None -from spyne.protocol._base import ProtocolMixin -from spyne.model import ModelBase, XmlAttribute, SimpleModel, Null, \ - ByteArray, File, ComplexModelBase, AnyXml, AnyHtml, Unicode, Decimal, \ - Double, Integer, Time, DateTime, Uuid, Duration, Boolean, AnyDict, \ - AnyUri, PushBase, Date +from spyne.const.http import HTTP_400, HTTP_401, HTTP_404, HTTP_405, HTTP_413, HTTP_500 +from spyne.error import ( + Fault, + InternalError, + InvalidCredentialsError, + RequestNotAllowed, + RequestTooLongError, + ResourceNotFoundError, +) +from spyne.model import ( + AnyDict, + AnyHtml, + AnyUri, + AnyXml, + Boolean, + ByteArray, + ComplexModelBase, + Date, + DateTime, + Decimal, + Double, + Duration, + File, + Integer, + ModelBase, + Null, + PushBase, + SimpleModel, + Time, + Unicode, + Uuid, + XmlAttribute, +) +from spyne.model.binary import BINARY_ENCODING_USE_DEFAULT, binary_encoding_handlers from spyne.model.relational import FileData - -from spyne.const.http import HTTP_400, HTTP_401, HTTP_404, HTTP_405, HTTP_413, \ - HTTP_500 -from spyne.error import Fault, InternalError, ResourceNotFoundError, \ - RequestTooLongError, RequestNotAllowed, InvalidCredentialsError -from spyne.model.binary import binary_encoding_handlers, \ - BINARY_ENCODING_USE_DEFAULT - -from spyne.util import six +from spyne.protocol._base import ProtocolMixin from spyne.util.cdict import cdict @@ -83,12 +102,23 @@ class OutProtocolBase(ProtocolMixin): of serializing return values instead of raising a TypeError. """ - def __init__(self, app=None, mime_type=None, ignore_uncap=False, - ignore_wrappers=False, binary_encoding=None, string_encoding=None): - - super(OutProtocolBase, self).__init__(app=app, mime_type=mime_type, + def __init__( + self, + app=None, + mime_type=None, + ignore_uncap=False, + ignore_wrappers=False, + binary_encoding=None, + string_encoding=None, + ): + + super(OutProtocolBase, self).__init__( + app=app, + mime_type=mime_type, ignore_wrappers=ignore_wrappers, - binary_encoding=binary_encoding, string_encoding=string_encoding) + binary_encoding=binary_encoding, + string_encoding=string_encoding, + ) self.ignore_uncap = ignore_uncap self.message = None @@ -96,59 +126,64 @@ def __init__(self, app=None, mime_type=None, ignore_uncap=False, if mime_type is not None: self.mime_type = mime_type - self._to_bytes_handlers = cdict({ - ModelBase: self.model_base_to_bytes, - File: self.file_to_bytes, - Time: self.time_to_bytes, - Uuid: self.uuid_to_bytes, - Null: self.null_to_bytes, - Date: self.date_to_bytes, - Double: self.double_to_bytes, - AnyXml: self.any_xml_to_bytes, - Unicode: self.unicode_to_bytes, - Boolean: self.boolean_to_bytes, - Decimal: self.decimal_to_bytes, - Integer: self.integer_to_bytes, - AnyHtml: self.any_html_to_bytes, - DateTime: self.datetime_to_bytes, - Duration: self.duration_to_bytes, - ByteArray: self.byte_array_to_bytes, - XmlAttribute: self.xmlattribute_to_bytes, - ComplexModelBase: self.complex_model_base_to_bytes, - }) - - self._to_unicode_handlers = cdict({ - ModelBase: self.model_base_to_unicode, - File: self.file_to_unicode, - Time: self.time_to_unicode, - Date: self.date_to_unicode, - Uuid: self.uuid_to_unicode, - Null: self.null_to_unicode, - Double: self.double_to_unicode, - AnyXml: self.any_xml_to_unicode, - AnyUri: self.any_uri_to_unicode, - AnyDict: self.any_dict_to_unicode, - AnyHtml: self.any_html_to_unicode, - Unicode: self.unicode_to_unicode, - Boolean: self.boolean_to_unicode, - Decimal: self.decimal_to_unicode, - Integer: self.integer_to_unicode, - # FIXME: Would we need a to_unicode for localized dates? - DateTime: self.datetime_to_unicode, - Duration: self.duration_to_unicode, - ByteArray: self.byte_array_to_unicode, - XmlAttribute: self.xmlattribute_to_unicode, - ComplexModelBase: self.complex_model_base_to_unicode, - }) - - self._to_bytes_iterable_handlers = cdict({ - File: self.file_to_bytes_iterable, - ByteArray: self.byte_array_to_bytes_iterable, - ModelBase: self.model_base_to_bytes_iterable, - SimpleModel: self.simple_model_to_bytes_iterable, - ComplexModelBase: self.complex_model_to_bytes_iterable, - }) - + self._to_bytes_handlers = cdict( + { + ModelBase: self.model_base_to_bytes, + File: self.file_to_bytes, + Time: self.time_to_bytes, + Uuid: self.uuid_to_bytes, + Null: self.null_to_bytes, + Date: self.date_to_bytes, + Double: self.double_to_bytes, + AnyXml: self.any_xml_to_bytes, + Unicode: self.unicode_to_bytes, + Boolean: self.boolean_to_bytes, + Decimal: self.decimal_to_bytes, + Integer: self.integer_to_bytes, + AnyHtml: self.any_html_to_bytes, + DateTime: self.datetime_to_bytes, + Duration: self.duration_to_bytes, + ByteArray: self.byte_array_to_bytes, + XmlAttribute: self.xmlattribute_to_bytes, + ComplexModelBase: self.complex_model_base_to_bytes, + } + ) + + self._to_unicode_handlers = cdict( + { + ModelBase: self.model_base_to_unicode, + File: self.file_to_unicode, + Time: self.time_to_unicode, + Date: self.date_to_unicode, + Uuid: self.uuid_to_unicode, + Null: self.null_to_unicode, + Double: self.double_to_unicode, + AnyXml: self.any_xml_to_unicode, + AnyUri: self.any_uri_to_unicode, + AnyDict: self.any_dict_to_unicode, + AnyHtml: self.any_html_to_unicode, + Unicode: self.unicode_to_unicode, + Boolean: self.boolean_to_unicode, + Decimal: self.decimal_to_unicode, + Integer: self.integer_to_unicode, + # FIXME: Would we need a to_unicode for localized dates? + DateTime: self.datetime_to_unicode, + Duration: self.duration_to_unicode, + ByteArray: self.byte_array_to_unicode, + XmlAttribute: self.xmlattribute_to_unicode, + ComplexModelBase: self.complex_model_base_to_unicode, + } + ) + + self._to_bytes_iterable_handlers = cdict( + { + File: self.file_to_bytes_iterable, + ByteArray: self.byte_array_to_bytes_iterable, + ModelBase: self.model_base_to_bytes_iterable, + SimpleModel: self.simple_model_to_bytes_iterable, + ComplexModelBase: self.complex_model_to_bytes_iterable, + } + ) def serialize(self, ctx, message): """Serializes ``ctx.out_object``. @@ -181,8 +216,9 @@ def fault_to_http_response_code(self, fault): if isinstance(fault, InvalidCredentialsError): return HTTP_401 - if isinstance(fault, Fault) and (fault.faultcode.startswith('Client.') - or fault.faultcode == 'Client'): + if isinstance(fault, Fault) and ( + fault.faultcode.startswith("Client.") or fault.faultcode == "Client" + ): return HTTP_400 return HTTP_500 @@ -202,11 +238,6 @@ def to_bytes(self, cls, value, *args, **kwargs): handler = self._to_bytes_handlers[cls] retval = handler(cls, value, *args, **kwargs) - # enable this only for testing. we're not as strict for performance - # reasons - # assert isinstance(retval, six.binary_type), \ - # "AssertionError: %r %r %r handler: %r" % \ - # (type(retval), six.binary_type, retval, handler) return retval def to_unicode(self, cls, value, *args, **kwargs): @@ -219,7 +250,7 @@ def to_unicode(self, cls, value, *args, **kwargs): # enable this only for testing. we're not as strict for performance # reasons as well as not to take the joy of dealing with duck typing # from the user - # assert isinstance(retval, six.text_type), \ + # assert isinstance(retval, str), \ # "AssertionError: %r %r handler: %r" % \ # (type(retval), retval, handler) @@ -239,13 +270,13 @@ def null_to_bytes(self, cls, value, **_): return b"" def null_to_unicode(self, cls, value, **_): - return u"" + return "" def any_xml_to_bytes(self, cls, value, **_): return etree.tostring(value) def any_xml_to_unicode(self, cls, value, **_): - return etree.tostring(value, encoding='unicode') + return etree.tostring(value, encoding="unicode") def any_dict_to_unicode(self, cls, value, **_): return repr(value) @@ -254,17 +285,18 @@ def any_html_to_bytes(self, cls, value, **_): return html.tostring(value) def any_html_to_unicode(self, cls, value, **_): - return html.tostring(value, encoding='unicode') + return html.tostring(value, encoding="unicode") def uuid_to_bytes(self, cls, value, suggested_encoding=None, **_): ser_as = self.get_cls_attrs(cls).serialize_as - retval = self.uuid_to_unicode(cls, value, - suggested_encoding=suggested_encoding, **_) + retval = self.uuid_to_unicode( + cls, value, suggested_encoding=suggested_encoding, **_ + ) - if ser_as in ('bytes', 'bytes_le', 'fields', 'int', six.binary_type): + if ser_as in ("bytes", "bytes_le", "fields", "int", bytes): return retval - return retval.encode('ascii') + return retval.encode("ascii") def uuid_to_unicode(self, cls, value, suggested_encoding=None, **_): attr = self.get_cls_attrs(cls) @@ -275,7 +307,7 @@ def uuid_to_unicode(self, cls, value, suggested_encoding=None, **_): encoding = suggested_encoding retval = _uuid_serialize[ser_as](value) - if ser_as in ('bytes', 'bytes_le'): + if ser_as in ("bytes", "bytes_le"): retval = binary_encoding_handlers[encoding]((retval,)) return retval @@ -284,14 +316,18 @@ def unicode_to_bytes(self, cls, value, **_): cls_attrs = self.get_cls_attrs(cls) - if isinstance(value, six.text_type): + if isinstance(value, str): if cls_attrs.encoding is not None: retval = value.encode(cls_attrs.encoding) elif self.default_string_encoding is not None: retval = value.encode(self.default_string_encoding) - elif not six.PY2: - logger.warning("You need to set either an encoding for %r " - "or a default_string_encoding for %r", cls, self) + else: + logger.warning( + "You need to set either an encoding for %r " + "or a default_string_encoding for %r", + cls, + self, + ) if cls_attrs.str_format is not None: return cls_attrs.str_format.format(value) @@ -308,16 +344,20 @@ def unicode_to_unicode(self, cls, value, **_): # :))) retval = value - if isinstance(value, six.binary_type): + if isinstance(value, bytes): if cls_attrs.encoding is not None: retval = value.decode(cls_attrs.encoding) if self.default_string_encoding is not None: retval = value.decode(self.default_string_encoding) - elif not six.PY2: - logger.warning("You need to set either an encoding for %r " - "or a default_string_encoding for %r", cls, self) + else: + logger.warning( + "You need to set either an encoding for %r " + "or a default_string_encoding for %r", + cls, + self, + ) if cls_attrs.str_format is not None: return cls_attrs.str_format.format(value) @@ -327,7 +367,7 @@ def unicode_to_unicode(self, cls, value, **_): # :))) return retval def decimal_to_bytes(self, cls, value, **_): - return self.decimal_to_unicode(cls, value, **_).encode('utf8') + return self.decimal_to_unicode(cls, value, **_).encode("utf8") def decimal_to_unicode(self, cls, value, **_): D(value) # sanity check @@ -341,10 +381,10 @@ def decimal_to_unicode(self, cls, value, **_): return str(value) def double_to_bytes(self, cls, value, **_): - return self.double_to_unicode(cls, value, **_).encode('utf8') + return self.double_to_unicode(cls, value, **_).encode("utf8") def double_to_unicode(self, cls, value, **_): - float(value) # sanity check + float(value) # sanity check cls_attrs = self.get_cls_attrs(cls) if cls_attrs.str_format is not None: @@ -355,7 +395,7 @@ def double_to_unicode(self, cls, value, **_): return repr(value) def integer_to_bytes(self, cls, value, **_): - return self.integer_to_unicode(cls, value, **_).encode('utf8') + return self.integer_to_unicode(cls, value, **_).encode("utf8") def integer_to_unicode(self, cls, value, **_): int(value) # sanity check @@ -386,7 +426,7 @@ def date_to_unicode(self, cls, val, **_): sa = self.get_cls_attrs(cls).serialize_as - if sa is None or sa in (str, 'str'): + if sa is None or sa in (str, "str"): return self._date_to_bytes(cls, val) return _datetime_smap[sa](cls, val) @@ -394,14 +434,14 @@ def date_to_unicode(self, cls, val, **_): def datetime_to_bytes(self, cls, val, **_): retval = self.datetime_to_unicode(cls, val, **_) sa = self.get_cls_attrs(cls).serialize_as - if sa is None or sa in (six.text_type, str, 'str'): - return retval.encode('ascii') + if sa is None or sa in (str, str, "str"): + return retval.encode("ascii") return retval def datetime_to_unicode(self, cls, val, **_): sa = self.get_cls_attrs(cls).serialize_as - if sa is None or sa in (six.text_type, str, 'str'): + if sa is None or sa in (str, str, "str"): return self._datetime_to_unicode(cls, val) return _datetime_smap[sa](cls, val) @@ -433,9 +473,9 @@ def duration_to_unicode(self, cls, value, **_): retval.append("%iD" % value.days) if tot_sec != 0 and tot_sec % 86400 == 0 and useconds == 0: - return ''.join(retval) + return "".join(retval) - retval.append('T') + retval.append("T") if hours > 0: retval.append("%iH" % hours) @@ -450,12 +490,12 @@ def duration_to_unicode(self, cls, value, **_): retval.append("S") if len(retval) == 2: - retval.append('0S') + retval.append("0S") - return ''.join(retval) + return "".join(retval) def boolean_to_bytes(self, cls, value, **_): - return str(bool(value)).lower().encode('ascii') + return str(bool(value)).lower().encode("ascii") def boolean_to_unicode(self, cls, value, **_): return str(bool(value)).lower() @@ -470,16 +510,19 @@ def byte_array_to_bytes(self, cls, value, suggested_encoding=None, **_): else: encoding = suggested_encoding - if encoding is None and isinstance(value, (list, tuple)) \ - and len(value) == 1 and isinstance(value[0], mmap): + if ( + encoding is None + and isinstance(value, (list, tuple)) + and len(value) == 1 + and isinstance(value[0], mmap) + ): return value[0] encoder = binary_encoding_handlers[encoding] - logger.debug("Using binary encoder %r for encoding %r", - encoder, encoding) + logger.debug("Using binary encoder %r for encoding %r", encoder, encoding) retval = encoder(value) - if encoding is not None and isinstance(retval, six.text_type): - retval = retval.encode('ascii') + if encoding is not None and isinstance(retval, str): + retval = retval.encode("ascii") return retval @@ -492,12 +535,11 @@ def byte_array_to_unicode(self, cls, value, suggested_encoding=None, **_): encoding = suggested_encoding if encoding is None: - raise ValueError("Arbitrary binary data can't be serialized to " - "unicode") + raise ValueError("Arbitrary binary data can't be serialized to " "unicode") retval = binary_encoding_handlers[encoding](value) - if not isinstance(retval, six.text_type): - retval = retval.decode('ascii') + if not isinstance(retval, str): + retval = retval.decode("ascii") return retval @@ -524,24 +566,21 @@ def file_to_bytes(self, cls, value, suggested_encoding=None): if value.handle is not None: # maybe we should have used the sweeping except: here. - if hasattr(value.handle, 'fileno'): - if six.PY2: + if hasattr(value.handle, "fileno"): + import io + + try: fileno = value.handle.fileno() - data = (mmap(fileno, 0, access=ACCESS_READ),) - else: - import io - try: - fileno = value.handle.fileno() - data = mmap(fileno, 0, access=ACCESS_READ) - except io.UnsupportedOperation: - data = (value.handle.read(),) + data = mmap(fileno, 0, access=ACCESS_READ) + except io.UnsupportedOperation: + data = (value.handle.read(),) else: data = (value.handle.read(),) return binary_encoding_handlers[encoding](data) if value.path is not None: - handle = open(value.path, 'rb') + handle = open(value.path, "rb") fileno = handle.fileno() data = mmap(fileno, 0, access=ACCESS_READ) @@ -553,15 +592,17 @@ def file_to_bytes(self, cls, value, suggested_encoding=None): try: return binary_encoding_handlers[encoding](value.data) except Exception as e: - logger.error("Error encoding value to binary. Error: %r, Value: %r", - e, value) + logger.error( + "Error encoding value to binary. Error: %r, Value: %r", e, value + ) raise try: return binary_encoding_handlers[encoding](value) except Exception as e: - logger.error("Error encoding value to binary. Error: %r, Value: %r", - e, value) + logger.error( + "Error encoding value to binary. Error: %r, Value: %r", e, value + ) raise def file_to_unicode(self, cls, value, suggested_encoding=None): @@ -577,18 +618,18 @@ def file_to_unicode(self, cls, value, suggested_encoding=None): encoding = suggested_encoding if encoding is None and cls_attrs.mode is File.TEXT: - raise ValueError("Arbitrary binary data can't be serialized to " - "unicode.") + raise ValueError("Arbitrary binary data can't be serialized to " "unicode.") retval = self.file_to_bytes(cls, value, suggested_encoding) - if not isinstance(retval, six.text_type): - retval = retval.decode('ascii') + if not isinstance(retval, str): + retval = retval.decode("ascii") return retval def file_to_bytes_iterable(self, cls, value, **_): if value.data is not None: - if isinstance(value.data, (list, tuple)) and \ - isinstance(value.data[0], mmap): + if isinstance(value.data, (list, tuple)) and isinstance( + value.data[0], mmap + ): return _file_to_iter(value.data[0]) return iter(value.data) @@ -597,16 +638,19 @@ def file_to_bytes_iterable(self, cls, value, **_): f.seek(0) return _file_to_iter(f) - assert value.path is not None, "You need to write data to " \ - "persistent storage first if you want to read it back." + assert value.path is not None, ( + "You need to write data to " + "persistent storage first if you want to read it back." + ) try: path = value.path if not isabs(value.path): path = join(value.store, value.path) - assert abspath(path).startswith(value.store), \ - "No relative paths are allowed" - return _file_to_iter(open(path, 'rb')) + assert abspath(path).startswith( + value.store + ), "No relative paths are allowed" + return _file_to_iter(open(path, "rb")) except IOError as e: if e.errno == errno.ENOENT: @@ -617,7 +661,7 @@ def file_to_bytes_iterable(self, cls, value, **_): def simple_model_to_bytes_iterable(self, cls, value, **kwargs): retval = self.to_bytes(cls, value, **kwargs) if retval is None: - return (b'',) + return (b"",) return (retval,) def complex_model_to_bytes_iterable(self, cls, value, **_): @@ -662,9 +706,6 @@ def _datetime_to_unicode(self, cls, value, **_): if dt_format is None: retval = value.isoformat() - elif six.PY2 and isinstance(dt_format, unicode): - retval = self.strftime(value, dt_format.encode('utf8')).decode('utf8') - else: retval = self.strftime(value, dt_format) @@ -689,10 +730,6 @@ def _date_to_bytes(self, cls, value, **_): if date_format is None: retval = value.isoformat() - elif six.PY2 and isinstance(date_format, unicode): - date_format = date_format.encode('utf8') - retval = self.strftime(value, date_format).decode('utf8') - else: retval = self.strftime(value, date_format) @@ -715,7 +752,6 @@ def _date_to_bytes(self, cls, value, **_): # '1850/00/02 was a Friday' # >>> - # remove the unsupposed "%s" command. But don't # do it if there's an even number of %s before the s # because those are all escaped. Can't simply @@ -727,16 +763,16 @@ def _date_to_bytes(self, cls, value, **_): @staticmethod def _findall_datetime(text, substr): - # Also finds overlaps - sites = [] - i = 0 - while 1: - j = text.find(substr, i) - if j == -1: - break - sites.append(j) - i=j+1 - return sites + # Also finds overlaps + sites = [] + i = 0 + while 1: + j = text.find(substr, i) + if j == -1: + break + sites.append(j) + i = j + 1 + return sites # Every 28 years the calendar repeats, except through century leap # years where it's 6 years. But only if you're using the Gregorian @@ -753,7 +789,7 @@ def strftime(cls, dt, fmt): # For every non-leap year century, advance by # 6 years to get into the 28-year repeat cycle delta = 2000 - year - off = 6*(delta // 100 + delta // 400) + off = 6 * (delta // 100 + delta // 400) year += off # Move to around the year 2000 @@ -762,8 +798,8 @@ def strftime(cls, dt, fmt): s1 = strftime(fmt, (year,) + timetuple[1:]) sites1 = cls._findall_datetime(s1, str(year)) - s2 = strftime(fmt, (year+28,) + timetuple[1:]) - sites2 = cls._findall_datetime(s2, str(year+28)) + s2 = strftime(fmt, (year + 28,) + timetuple[1:]) + sites2 = cls._findall_datetime(s2, str(year + 28)) sites = [] for site in sites1: @@ -773,60 +809,50 @@ def strftime(cls, dt, fmt): s = s1 syear = "%4d" % (dt.year,) for site in sites: - s = s[:site] + syear + s[site+4:] + s = s[:site] + syear + s[site + 4 :] return s _uuid_serialize = { None: str, str: str, - 'str': str, - - 'hex': lambda u: u.hex, - 'urn': lambda u: u.urn, - 'bytes': lambda u: u.bytes, - 'bytes_le': lambda u: u.bytes_le, - 'fields': lambda u: u.fields, - + "str": str, + "hex": lambda u: u.hex, + "urn": lambda u: u.urn, + "bytes": lambda u: u.bytes, + "bytes_le": lambda u: u.bytes_le, + "fields": lambda u: u.fields, int: lambda u: u.int, - 'int': lambda u: u.int, + "int": lambda u: u.int, } _uuid_deserialize = { None: uuid.UUID, str: uuid.UUID, - 'str': uuid.UUID, - - 'hex': lambda s: uuid.UUID(hex=s), - 'urn': lambda s: uuid.UUID(hex=s), - 'bytes': lambda s: uuid.UUID(bytes=s), - 'bytes_le': lambda s: uuid.UUID(bytes_le=s), - 'fields': lambda s: uuid.UUID(fields=s), - + "str": uuid.UUID, + "hex": lambda s: uuid.UUID(hex=s), + "urn": lambda s: uuid.UUID(hex=s), + "bytes": lambda s: uuid.UUID(bytes=s), + "bytes_le": lambda s: uuid.UUID(bytes_le=s), + "fields": lambda s: uuid.UUID(fields=s), int: lambda s: uuid.UUID(int=s), - 'int': lambda s: uuid.UUID(int=s), - + "int": lambda s: uuid.UUID(int=s), (int, int): lambda s: uuid.UUID(int=s), - ('int', int): lambda s: uuid.UUID(int=s), - + ("int", int): lambda s: uuid.UUID(int=s), (int, str): lambda s: uuid.UUID(int=int(s)), - ('int', str): lambda s: uuid.UUID(int=int(s)), + ("int", str): lambda s: uuid.UUID(int=int(s)), } -if six.PY2: - _uuid_deserialize[('int', long)] = _uuid_deserialize[('int', int)] - _uuid_deserialize[(int, long)] = _uuid_deserialize[('int', int)] - def _parse_datetime_iso_match(date_match, tz=None): fields = date_match.groupdict() - year = int(fields.get('year')) - month = int(fields.get('month')) - day = int(fields.get('day')) - hour = int(fields.get('hr')) - minute = int(fields.get('min')) - second = int(fields.get('sec')) + year = int(fields.get("year")) + month = int(fields.get("month")) + day = int(fields.get("day")) + hour = int(fields.get("hr")) + minute = int(fields.get("min")) + second = int(fields.get("sec")) usecond = fields.get("sec_frac") if usecond is None: usecond = 0 @@ -838,50 +864,45 @@ def _parse_datetime_iso_match(date_match, tz=None): return datetime(year, month, day, hour, minute, second, usecond, tz) -_dt_sec = lambda cls, val: \ - int(mktime(val.timetuple())) -_dt_sec_float = lambda cls, val: \ - mktime(val.timetuple()) + (val.microsecond / 1e6) +_dt_sec = lambda cls, val: int(mktime(val.timetuple())) +_dt_sec_float = lambda cls, val: mktime(val.timetuple()) + (val.microsecond / 1e6) -_dt_msec = lambda cls, val: \ - int(mktime(val.timetuple())) * 1000 + (val.microsecond // 1000) -_dt_msec_float = lambda cls, val: \ - mktime(val.timetuple()) * 1000 + (val.microsecond / 1000.0) +_dt_msec = lambda cls, val: int(mktime(val.timetuple())) * 1000 + ( + val.microsecond // 1000 +) +_dt_msec_float = lambda cls, val: mktime(val.timetuple()) * 1000 + ( + val.microsecond / 1000.0 +) -_dt_usec = lambda cls, val: \ - int(mktime(val.timetuple())) * 1000000 + val.microsecond +_dt_usec = lambda cls, val: int(mktime(val.timetuple())) * 1000000 + val.microsecond _datetime_smap = { - 'sec': _dt_sec, - 'secs': _dt_sec, - 'second': _dt_sec, - 'seconds': _dt_sec, - - 'sec_float': _dt_sec_float, - 'secs_float': _dt_sec_float, - 'second_float': _dt_sec_float, - 'seconds_float': _dt_sec_float, - - 'msec': _dt_msec, - 'msecs': _dt_msec, - 'msecond': _dt_msec, - 'mseconds': _dt_msec, - 'millisecond': _dt_msec, - 'milliseconds': _dt_msec, - - 'msec_float': _dt_msec_float, - 'msecs_float': _dt_msec_float, - 'msecond_float': _dt_msec_float, - 'mseconds_float': _dt_msec_float, - 'millisecond_float': _dt_msec_float, - 'milliseconds_float': _dt_msec_float, - - 'usec': _dt_usec, - 'usecs': _dt_usec, - 'usecond': _dt_usec, - 'useconds': _dt_usec, - 'microsecond': _dt_usec, - 'microseconds': _dt_usec, + "sec": _dt_sec, + "secs": _dt_sec, + "second": _dt_sec, + "seconds": _dt_sec, + "sec_float": _dt_sec_float, + "secs_float": _dt_sec_float, + "second_float": _dt_sec_float, + "seconds_float": _dt_sec_float, + "msec": _dt_msec, + "msecs": _dt_msec, + "msecond": _dt_msec, + "mseconds": _dt_msec, + "millisecond": _dt_msec, + "milliseconds": _dt_msec, + "msec_float": _dt_msec_float, + "msecs_float": _dt_msec_float, + "msecond_float": _dt_msec_float, + "mseconds_float": _dt_msec_float, + "millisecond_float": _dt_msec_float, + "milliseconds_float": _dt_msec_float, + "usec": _dt_usec, + "usecs": _dt_usec, + "usecond": _dt_usec, + "useconds": _dt_usec, + "microsecond": _dt_usec, + "microseconds": _dt_usec, } @@ -896,4 +917,4 @@ def _file_to_iter(f): f.close() -META_ATTR = ['nullable', 'default_factory'] +META_ATTR = ["nullable", "default_factory"] diff --git a/spyne/protocol/cloth/__init__.py b/spyne/protocol/cloth/__init__.py index 2bf9b9350..0d00719d5 100644 --- a/spyne/protocol/cloth/__init__.py +++ b/spyne/protocol/cloth/__init__.py @@ -21,6 +21,6 @@ for clothing otherwise boring data. """ -from spyne.protocol.cloth._base import XmlCloth # huge hack to have the last line of microformat.py execute import spyne.protocol.html +from spyne.protocol.cloth._base import XmlCloth diff --git a/spyne/protocol/cloth/_base.py b/spyne/protocol/cloth/_base.py index 4ea7fe636..3b26127e7 100644 --- a/spyne/protocol/cloth/_base.py +++ b/spyne/protocol/cloth/_base.py @@ -20,21 +20,24 @@ from __future__ import print_function import logging + logger = logging.getLogger(__name__) from inspect import isgenerator +from io import BytesIO from lxml import etree from lxml.etree import LxmlSyntaxError -from spyne import ProtocolContext, BODY_STYLE_WRAPPED, ByteArray, File, Array -from spyne.util import Break, coroutine +from spyne.context import ProtocolContext +from spyne.descriptor import BODY_STYLE_WRAPPED +from spyne.model.binary import ByteArray, File +from spyne.model.complex import Array from spyne.protocol import ProtocolMixin - -from spyne.protocol.cloth.to_parent import ToParentMixin from spyne.protocol.cloth.to_cloth import ToClothMixin -from spyne.util.six import BytesIO -from spyne.util.color import R, B +from spyne.protocol.cloth.to_parent import ToParentMixin +from spyne.util import Break, coroutine +from spyne.util.color import B, R from spyne.util.tlist import tlist @@ -48,22 +51,37 @@ def __init__(self, parent, transport, type=None): class XmlCloth(ToParentMixin, ToClothMixin): - mime_type = 'text/xml' + mime_type = "text/xml" HtmlMicroFormat = None - def __init__(self, app=None, encoding='utf8', doctype=None, - mime_type=None, ignore_uncap=False, ignore_wrappers=False, - cloth=None, cloth_parser=None, polymorphic=True, - strip_comments=True, use_ns=None, skip_root_tag=False): - - super(XmlCloth, self).__init__(app=app, mime_type=mime_type, - ignore_uncap=ignore_uncap, ignore_wrappers=ignore_wrappers, - polymorphic=polymorphic) + def __init__( + self, + app=None, + encoding="utf8", + doctype=None, + mime_type=None, + ignore_uncap=False, + ignore_wrappers=False, + cloth=None, + cloth_parser=None, + polymorphic=True, + strip_comments=True, + use_ns=None, + skip_root_tag=False, + ): + + super(XmlCloth, self).__init__( + app=app, + mime_type=mime_type, + ignore_uncap=ignore_uncap, + ignore_wrappers=ignore_wrappers, + polymorphic=polymorphic, + ) self._init_cloth(cloth, cloth_parser, strip_comments) self.developer_mode = False self.encoding = encoding - self.default_method = 'xml' + self.default_method = "xml" self.doctype = doctype self.use_ns = use_ns self.skip_root_tag = skip_root_tag @@ -81,7 +99,7 @@ def serialize(self, ctx, message): assert message in (self.REQUEST, self.RESPONSE) - self.event_manager.fire_event('before_serialize', ctx) + self.event_manager.fire_event("before_serialize", ctx) if ctx.out_stream is None: ctx.out_stream = BytesIO() @@ -110,23 +128,24 @@ def serialize(self, ctx, message): if ctx.descriptor.body_style == BODY_STYLE_WRAPPED: if self.ignore_wrappers: result_inst = ctx.out_object[0] - while result_class.Attributes._wrapper and \ - len(result_class._type_info) == 1: - result_class, = result_class._type_info.values() + while ( + result_class.Attributes._wrapper + and len(result_class._type_info) == 1 + ): + (result_class,) = result_class._type_info.values() else: result_inst = result_class() - for i, attr_name in enumerate( - result_class._type_info.keys()): + for i, attr_name in enumerate(result_class._type_info.keys()): setattr(result_inst, attr_name, ctx.out_object[i]) else: - result_inst, = ctx.out_object + (result_inst,) = ctx.out_object retval = self._incgen(ctx, result_class, result_inst, name) - self.event_manager.fire_event('after_serialize', ctx) + self.event_manager.fire_event("after_serialize", ctx) return retval @@ -159,7 +178,7 @@ def _incgen(self, ctx, cls, inst, name): if isgenerator(ret): # Poor man's yield from try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as b: @@ -169,7 +188,7 @@ def _incgen(self, ctx, cls, inst, name): pass except LxmlSyntaxError as e: - if e.msg == 'no content written': + if e.msg == "no content written": pass else: raise @@ -210,26 +229,24 @@ def get_class_root_cloth(cls): def check_class_cloths(self, ctx, cls, inst, parent, name, **kwargs): c = self.get_class_root_cloth(cls) - eltstack = getattr(ctx.protocol, 'eltstack', []) + eltstack = getattr(ctx.protocol, "eltstack", []) if c is not None and len(eltstack) == 0 and not (eltstack[-1] is c): if not ctx.outprot_ctx.doctype_written: self.write_doctype(ctx, parent, c) logger.debug("to object root cloth") - return True, self.to_root_cloth(ctx, cls, inst, c, parent, name, - **kwargs) + return True, self.to_root_cloth(ctx, cls, inst, c, parent, name, **kwargs) c = self.get_class_cloth(cls) if c is not None: if not ctx.outprot_ctx.doctype_written: self.write_doctype(ctx, parent, c) logger.debug("to object cloth") - return True, self.to_parent_cloth(ctx, cls, inst, c, parent, name, - **kwargs) + return True, self.to_parent_cloth(ctx, cls, inst, c, parent, name, **kwargs) return False, None @coroutine - def subserialize(self, ctx, cls, inst, parent, name='', **kwargs): + def subserialize(self, ctx, cls, inst, parent, name="", **kwargs): """Bridge between multiple XmlCloth-based protocols. Not supposed to be overridden. @@ -248,14 +265,12 @@ def subserialize(self, ctx, cls, inst, parent, name='', **kwargs): elif self._root_cloth is not None: logger.debug("to root cloth for %s", cls.get_type_name()) - ret = self.to_root_cloth(ctx, cls, inst, self._root_cloth, - parent, name) + ret = self.to_root_cloth(ctx, cls, inst, self._root_cloth, parent, name) have_cloth = True elif self._cloth is not None: logger.debug("to parent protocol cloth for %s", cls.get_type_name()) - ret = self.to_parent_cloth(ctx, cls, inst, self._cloth, parent, - name) + ret = self.to_parent_cloth(ctx, cls, inst, self._cloth, parent, name) have_cloth = True else: @@ -265,7 +280,7 @@ def subserialize(self, ctx, cls, inst, parent, name='', **kwargs): if isgenerator(ret): # Poor man's yield from try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as b: @@ -312,8 +327,7 @@ def _gen_attrib_dict(self, inst, fti): sub_name = self._gen_tagname(ns, sub_name) if issubclass(field_type.type, (ByteArray, File)): - valstr = self.to_unicode(field_type.type, val, - self.binary_encoding) + valstr = self.to_unicode(field_type.type, val, self.binary_encoding) else: valstr = self.to_unicode(field_type.type, val) diff --git a/spyne/protocol/cloth/to_cloth.py b/spyne/protocol/cloth/to_cloth.py index 6dd59cd77..1ad6f894c 100644 --- a/spyne/protocol/cloth/to_cloth.py +++ b/spyne/protocol/cloth/to_cloth.py @@ -21,22 +21,32 @@ from __future__ import print_function import logging + logger_c = logging.getLogger("%s.cloth" % __name__) logger_s = logging.getLogger("%s.serializer" % __name__) -from lxml import html, etree from copy import deepcopy from inspect import isgenerator -from spyne.util import Break, coroutine -from spyne.util.oset import oset -from spyne.util.six import string_types -from spyne.util.color import R, B -from spyne.model import Array, AnyXml, AnyHtml, ModelBase, ComplexModelBase, \ - PushBase, XmlAttribute, AnyUri, XmlData, Any - +from lxml import etree, html + +from spyne.model import ( + Any, + AnyHtml, + AnyUri, + AnyXml, + Array, + ComplexModelBase, + ModelBase, + PushBase, + XmlAttribute, + XmlData, +) from spyne.protocol import OutProtocolBase +from spyne.util import Break, coroutine from spyne.util.cdict import cdict +from spyne.util.color import B, R +from spyne.util.oset import oset _revancestors = lambda elt: list(reversed(tuple(elt.iterancestors()))) @@ -56,7 +66,7 @@ def _prevsibls_since(elt, strip_comments, since): break if strip_comments and isinstance(elt, etree.CommentBase): - if elt.text.startswith('[if ') and elt.text.endswith('[endif]'): + if elt.text.startswith("[if ") and elt.text.endswith("[endif]"): pass else: continue @@ -64,20 +74,28 @@ def _prevsibls_since(elt, strip_comments, since): yield prevsibl -def _set_identifier_prefix(obj, prefix, mrpc_id='mrpc', id_attr='id', - data_tag='data', data_attr='data', attr_attr='attr', - root_attr='root', tagbag_attr='tagbag'): +def _set_identifier_prefix( + obj, + prefix, + mrpc_id="mrpc", + id_attr="id", + data_tag="data", + data_attr="data", + attr_attr="attr", + root_attr="root", + tagbag_attr="tagbag", +): obj.ID_PREFIX = prefix - obj.MRPC_ID = '{}{}'.format(prefix, mrpc_id) - obj.ID_ATTR_NAME = '{}{}'.format(prefix, id_attr) - obj.DATA_TAG_NAME = '{}{}'.format(prefix, data_tag) - obj.DATA_ATTR_NAME = '{}{}'.format(prefix, data_attr) - obj.ATTR_ATTR_NAME = '{}{}'.format(prefix, attr_attr) - obj.ROOT_ATTR_NAME = '{}{}'.format(prefix, root_attr) - obj.TAGBAG_ATTR_NAME = '{}{}'.format(prefix, tagbag_attr) + obj.MRPC_ID = "{}{}".format(prefix, mrpc_id) + obj.ID_ATTR_NAME = "{}{}".format(prefix, id_attr) + obj.DATA_TAG_NAME = "{}{}".format(prefix, data_tag) + obj.DATA_ATTR_NAME = "{}{}".format(prefix, data_attr) + obj.ATTR_ATTR_NAME = "{}{}".format(prefix, attr_attr) + obj.ROOT_ATTR_NAME = "{}{}".format(prefix, root_attr) + obj.TAGBAG_ATTR_NAME = "{}{}".format(prefix, tagbag_attr) # FIXME: get rid of this. We don't want logic creep inside cloths - obj.WRITE_CONTENTS_WHEN_NOT_NONE = '{}write-contents'.format(prefix) + obj.WRITE_CONTENTS_WHEN_NOT_NONE = "{}write-contents".format(prefix) obj.SPYNE_ATTRS = { obj.ID_ATTR_NAME, @@ -90,17 +108,17 @@ def _set_identifier_prefix(obj, prefix, mrpc_id='mrpc', id_attr='id', class ClothParserMixin(object): - ID_PREFIX = 'spyne-' + ID_PREFIX = "spyne-" # these are here for documentation purposes. The are all reinitialized with # the call ta _set_identifier_prefix below the class definition - ID_ATTR_NAME = 'spyne-id' - DATA_TAG_NAME = 'spyne-data' - DATA_ATTR_NAME = 'spyne-data' - ATTR_ATTR_NAME = 'spyne-attr' - ROOT_ATTR_NAME = 'spyne-root' - TAGBAG_ATTR_NAME = 'spyne-tagbag' - WRITE_CONTENTS_WHEN_NOT_NONE = 'spyne-write-contents' + ID_ATTR_NAME = "spyne-id" + DATA_TAG_NAME = "spyne-data" + DATA_ATTR_NAME = "spyne-data" + ATTR_ATTR_NAME = "spyne-attr" + ROOT_ATTR_NAME = "spyne-root" + TAGBAG_ATTR_NAME = "spyne-tagbag" + WRITE_CONTENTS_WHEN_NOT_NONE = "spyne-write-contents" def set_identifier_prefix(self, what): _set_identifier_prefix(self, what) @@ -109,15 +127,17 @@ def set_identifier_prefix(self, what): @classmethod def from_xml_cloth(cls, cloth, strip_comments=True): retval = cls() - retval._init_cloth(cloth, cloth_parser=etree.XMLParser(), - strip_comments=strip_comments) + retval._init_cloth( + cloth, cloth_parser=etree.XMLParser(), strip_comments=strip_comments + ) return retval @classmethod def from_html_cloth(cls, cloth, strip_comments=True): retval = cls() - retval._init_cloth(cloth, cloth_parser=html.HTMLParser(), - strip_comments=strip_comments) + retval._init_cloth( + cloth, cloth_parser=html.HTMLParser(), strip_comments=strip_comments + ) return retval @staticmethod @@ -125,8 +145,7 @@ def _strip_comments(root): for elt in root.iter(): if isinstance(elt, etree.CommentBase): if elt.getparent() is not None: - if elt.text.startswith('[if ') \ - and elt.text.endswith('[endif]'): + if elt.text.startswith("[if ") and elt.text.endswith("[endif]"): pass else: elt.getparent().remove(elt) @@ -148,7 +167,7 @@ def _init_cloth(self, cloth, cloth_parser, strip_comments): if cloth is None: return - if isinstance(cloth, string_types): + if isinstance(cloth, str): cloth = self._parse_file(cloth, cloth_parser) if strip_comments: @@ -163,7 +182,7 @@ def _init_cloth(self, cloth, cloth_parser, strip_comments): logger_c.debug("Using %r as plain cloth.", cloth) self._cloth = cloth - self._mrpc_cloth = self._pop_elt(cloth, 'mrpc_entry') + self._mrpc_cloth = self._pop_elt(cloth, "mrpc_entry") def _pop_elt(self, elt, what): query = '//*[@%s="%s"]' % (self.ID_ATTR_NAME, what) @@ -181,27 +200,39 @@ def _pop_elt(self, elt, what): class ToClothMixin(OutProtocolBase, ClothParserMixin): - def __init__(self, app=None, mime_type=None, ignore_uncap=False, - ignore_wrappers=False, polymorphic=True): - super(ToClothMixin, self).__init__(app=app, mime_type=mime_type, - ignore_uncap=ignore_uncap, ignore_wrappers=ignore_wrappers) + def __init__( + self, + app=None, + mime_type=None, + ignore_uncap=False, + ignore_wrappers=False, + polymorphic=True, + ): + super(ToClothMixin, self).__init__( + app=app, + mime_type=mime_type, + ignore_uncap=ignore_uncap, + ignore_wrappers=ignore_wrappers, + ) self.polymorphic = polymorphic - self.rendering_handlers = cdict({ - ModelBase: self.model_base_to_cloth, - AnyXml: self.xml_to_cloth, - Any: self.any_to_cloth, - AnyHtml: self.html_to_cloth, - AnyUri: self.any_uri_to_cloth, - ComplexModelBase: self.complex_to_cloth, - }) + self.rendering_handlers = cdict( + { + ModelBase: self.model_base_to_cloth, + AnyXml: self.xml_to_cloth, + Any: self.any_to_cloth, + AnyHtml: self.html_to_cloth, + AnyUri: self.any_uri_to_cloth, + ComplexModelBase: self.complex_to_cloth, + } + ) def _get_elts(self, elt, tag_id=None): if tag_id is None: - return elt.xpath('.//*[@*[starts-with(name(), "%s")]]' % - self.ID_PREFIX) - return elt.xpath('.//*[@*[starts-with(name(), "%s")]="%s"]' % ( - self.ID_PREFIX, tag_id)) + return elt.xpath('.//*[@*[starts-with(name(), "%s")]]' % self.ID_PREFIX) + return elt.xpath( + './/*[@*[starts-with(name(), "%s")]="%s"]' % (self.ID_PREFIX, tag_id) + ) def _get_outmost_elts(self, tmpl, tag_id=None): ids = set() @@ -250,7 +281,7 @@ def _is_tagbag(self, elt): @staticmethod def _methods(ctx, cls, inst): while cls.Attributes._wrapper and len(cls._type_info) > 0: - cls, = cls._type_info.values() + (cls,) = cls._type_info.values() if cls.Attributes.methods is not None: for k, v in cls.Attributes.methods.items(): @@ -272,19 +303,21 @@ def _actions_to_cloth(self, ctx, cls, inst, template): text = v.translate(ctx.locale, v.in_message.get_type_name()) mrpc_template = deepcopy(self._mrpc_cloth) - anchor = self._get_clean_elt(mrpc_template, 'mrpc_link') - anchor.attrib['href'] = href + anchor = self._get_clean_elt(mrpc_template, "mrpc_link") + anchor.attrib["href"] = href - text_elt = self._get_clean_elt(mrpc_template, 'mrpc_text') + text_elt = self._get_clean_elt(mrpc_template, "mrpc_text") if text_elt is not None: text_elt.text = text else: anchor.text = text elt.append(mrpc_template) - # mutable default ok because readonly - def _enter_cloth(self, ctx, cloth, parent, attrib={}, skip=False, - method=None, skip_dupe=False): + # mutable default ok because readonly + + def _enter_cloth( + self, ctx, cloth, parent, attrib={}, skip=False, method=None, skip_dupe=False + ): """Enters the given tag in the document by using the shortest path from current tag. @@ -314,8 +347,15 @@ def _enter_cloth(self, ctx, cloth, parent, attrib={}, skip=False, (eg. arrays). """ - logger_c.debug("entering %s %r nsmap=%r attrib=%r skip=%s method=%s", - cloth.tag, cloth.attrib, cloth.nsmap, attrib, skip, method) + logger_c.debug( + "entering %s %r nsmap=%r attrib=%r skip=%s method=%s", + cloth.tag, + cloth.attrib, + cloth.nsmap, + attrib, + skip, + method, + ) if not ctx.outprot_ctx.doctype_written: self.write_doctype(ctx, parent, cloth) @@ -352,7 +392,7 @@ def _enter_cloth(self, ctx, cloth, parent, attrib={}, skip=False, # move up in tag stack until the ancestors of both # source and target tags match - while ancestors[:len(cureltstack)] != cureltstack: + while ancestors[: len(cureltstack)] != cureltstack: elt = cureltstack.pop() elt_ctx = curctxstack.pop() @@ -366,37 +406,43 @@ def _enter_cloth(self, ctx, cloth, parent, attrib={}, skip=False, # unless we're at the same level as the relevant ancestor of the # target node - if ancestors[:len(cureltstack)] != cureltstack: + if ancestors[: len(cureltstack)] != cureltstack: # write following siblings before closing parent node for sibl in elt.itersiblings(preceding=False): - logger_c.debug("\twrite exit sibl %s %r %d", - sibl.tag, sibl.attrib, id(sibl)) + logger_c.debug( + "\twrite exit sibl %s %r %d", sibl.tag, sibl.attrib, id(sibl) + ) parent.write(sibl) # write remaining ancestors of the target node. - for anc in ancestors[len(cureltstack):]: + for anc in ancestors[len(cureltstack) :]: # write previous siblings of ancestors (if any) prevsibls = _prevsibls(anc, self.strip_comments, since=last_elt) for elt in prevsibls: if id(elt) in tags: - logger_c.debug("\tskip anc prevsibl %s %r", - elt.tag, elt.attrib) + logger_c.debug("\tskip anc prevsibl %s %r", elt.tag, elt.attrib) continue - logger_c.debug("\twrite anc prevsibl %s %r 0x%x", - elt.tag, elt.attrib, id(elt)) + logger_c.debug( + "\twrite anc prevsibl %s %r 0x%x", elt.tag, elt.attrib, id(elt) + ) parent.write(elt) # enter the ancestor node kwargs = {} if len(cureltstack) == 0: # if this is the first node ever, initialize namespaces as well - kwargs['nsmap'] = anc.nsmap + kwargs["nsmap"] = anc.nsmap anc_ctx = parent.element(anc.tag, anc.attrib, **kwargs) anc_ctx.__enter__() - logger_c.debug("\tenter norm %s %r 0x%x method: %r", anc.tag, - anc.attrib, id(anc), method) + logger_c.debug( + "\tenter norm %s %r 0x%x method: %r", + anc.tag, + anc.attrib, + id(anc), + method, + ) if anc.text is not None: parent.write(anc.text) @@ -414,8 +460,7 @@ def _enter_cloth(self, ctx, cloth, parent, attrib={}, skip=False, continue if id(elt) in tags: - logger_c.debug("\tskip cloth prevsibl %s %r", - elt.tag, elt.attrib) + logger_c.debug("\tskip cloth prevsibl %s %r", elt.tag, elt.attrib) continue logger_c.debug("\twrite cloth prevsibl %s %r", elt.tag, elt.attrib) @@ -433,20 +478,22 @@ def _enter_cloth(self, ctx, cloth, parent, attrib={}, skip=False, else: # finally, enter the target node. - cloth_attrib = dict([(k, v) for k, v in cloth.attrib.items() - if not k in self.SPYNE_ATTRS]) + cloth_attrib = dict( + [(k, v) for k, v in cloth.attrib.items() if not k in self.SPYNE_ATTRS] + ) cloth_attrib.update(attrib) - self.event_manager.fire_event(("before_entry", cloth), ctx, - parent, cloth_attrib) + self.event_manager.fire_event( + ("before_entry", cloth), ctx, parent, cloth_attrib + ) kwargs = {} if len(cureltstack) == 0: # if this is the first node ever, initialize namespaces as well - kwargs['nsmap'] = cloth.nsmap + kwargs["nsmap"] = cloth.nsmap if method is not None: - kwargs['method'] = method + kwargs["method"] = method curtag = parent.element(cloth.tag, cloth_attrib, **kwargs) curtag.__enter__() if cloth.text is not None: @@ -492,19 +539,20 @@ def _close_cloth(self, ctx, parent): rootstack.pop() @coroutine - def to_parent_cloth(self, ctx, cls, inst, cloth, parent, name, - from_arr=False, **kwargs): + def to_parent_cloth( + self, ctx, cls, inst, cloth, parent, name, from_arr=False, **kwargs + ): cls_cloth = self.get_class_cloth(cls) if cls_cloth is not None: logger_c.debug("%r to object cloth", cls) cloth = cls_cloth ctx.protocol[self].rootstack.add(cloth) - ret = self.to_cloth(ctx, cls, inst, cloth, parent, '') + ret = self.to_cloth(ctx, cls, inst, cloth, parent, "") if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as e: try: @@ -524,7 +572,7 @@ def to_root_cloth(self, ctx, cls, inst, cloth, parent, name): if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as e: try: @@ -534,8 +582,19 @@ def to_root_cloth(self, ctx, cls, inst, cloth, parent, name): # TODO: Maybe DRY this with to_parent? @coroutine - def to_cloth(self, ctx, cls, inst, cloth, parent, name=None, - from_arr=False, as_attr=False, as_data=False, **kwargs): + def to_cloth( + self, + ctx, + cls, + inst, + cloth, + parent, + name=None, + from_arr=False, + as_attr=False, + as_data=False, + **kwargs, + ): prot_name = self.__class__.__name__ @@ -573,15 +632,26 @@ def to_cloth(self, ctx, cls, inst, cloth, parent, name=None, # we can't do this because subprotocols don't accept cloths. # so we need to enter the cloth, which make it too late to # set attributes. - assert not as_attr, "No subprot supported for fields " \ - "to be serialized as attributes, use type casting with " \ + assert not as_attr, ( + "No subprot supported for fields " + "to be serialized as attributes, use type casting with " "customized serializers in the current protocol instead." - - self._enter_cloth(ctx, cloth, parent, - method=cls_attrs.method, skip=as_data) - - ret = subprot.subserialize(ctx, cls, inst, parent, name, - as_attr=as_attr, as_data=as_data, **kwargs) + ) + + self._enter_cloth( + ctx, cloth, parent, method=cls_attrs.method, skip=as_data + ) + + ret = subprot.subserialize( + ctx, + cls, + inst, + parent, + name, + as_attr=as_attr, + as_data=as_data, + **kwargs, + ) # if there is no subprotocol, try rendering the value else: @@ -593,20 +663,29 @@ def to_cloth(self, ctx, cls, inst, cloth, parent, name=None, attrs = {} if as_attr: # FIXME: test needed - attrs[name] = '' + attrs[name] = "" - self._enter_cloth(ctx, cloth, parent, attrib=attrs, - method=cls_attrs.method) + self._enter_cloth( + ctx, cloth, parent, attrib=attrs, method=cls_attrs.method + ) identifier = "%s.%s" % (prot_name, "null_to_cloth") - logger_s.debug("Writing '%s' using %s type: %s.", name, - identifier, cls.get_type_name()) + logger_s.debug( + "Writing '%s' using %s type: %s.", + name, + identifier, + cls.get_type_name(), + ) parent.write(cloth) else: - logger_s.debug("Skipping '%s' type: %s because empty.", - name, cls.get_type_name()) - self._enter_cloth(ctx, cloth, parent, skip=True, - method=cls_attrs.method) + logger_s.debug( + "Skipping '%s' type: %s because empty.", + name, + cls.get_type_name(), + ) + self._enter_cloth( + ctx, cloth, parent, skip=True, method=cls_attrs.method + ) elif as_data: # we only support XmlData of a primitive.,. is this a @@ -621,8 +700,9 @@ def to_cloth(self, ctx, cls, inst, cloth, parent, name=None, sub_name = name attrs = {sub_name: self.to_unicode(cls, inst)} - self._enter_cloth(ctx, cloth, parent, attrib=attrs, - method=cls_attrs.method) + self._enter_cloth( + ctx, cloth, parent, attrib=attrs, method=cls_attrs.method + ) else: # push the instance at hand to instance stack. this makes it @@ -634,8 +714,9 @@ def to_cloth(self, ctx, cls, inst, cloth, parent, name=None, # try rendering the array value if not from_arr and cls.Attributes.max_occurs > 1: - ret = self.array_to_cloth(ctx, cls, inst, cloth, parent, - as_attr=as_attr, name=name) + ret = self.array_to_cloth( + ctx, cls, inst, cloth, parent, as_attr=as_attr, name=name + ) else: # try rendering anything else handler = self.rendering_handlers[cls] @@ -647,13 +728,14 @@ def to_cloth(self, ctx, cls, inst, cloth, parent, name=None, # name, identifier, cls.get_type_name(), # log_repr(inst, cls, from_array=from_arr)) - ret = handler(ctx, cls, inst, cloth, parent, name=name, - as_attr=as_attr) + ret = handler( + ctx, cls, inst, cloth, parent, name=name, as_attr=as_attr + ) if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as e: try: @@ -662,8 +744,7 @@ def to_cloth(self, ctx, cls, inst, cloth, parent, name=None, pass finally: if pushed: - logger_c.debug("%s %r popped %r %r", B("#"), - self, cls, inst) + logger_c.debug("%s %r popped %r %r", B("#"), self, cls, inst) ctx.outprot_ctx.inst_stack.pop() else: @@ -671,8 +752,7 @@ def to_cloth(self, ctx, cls, inst, cloth, parent, name=None, logger_c.debug("%s %r popped %r %r", B("#"), self, cls, inst) ctx.outprot_ctx.inst_stack.pop() - def model_base_to_cloth(self, ctx, cls, inst, cloth, parent, name, - **kwargs): + def model_base_to_cloth(self, ctx, cls, inst, cloth, parent, name, **kwargs): cls_attrs = self.get_cls_attrs(cls) self._enter_cloth(ctx, cloth, parent, method=cls_attrs.method) @@ -688,7 +768,7 @@ def model_base_to_cloth(self, ctx, cls, inst, cloth, parent, name, def xml_to_cloth(self, ctx, cls, inst, cloth, parent, name, **_): cls_attrs = self.get_cls_attrs(cls) self._enter_cloth(ctx, cloth, parent, method=cls_attrs.method) - if isinstance(inst, string_types): + if isinstance(inst, str): inst = etree.fromstring(inst) parent.write(inst) @@ -700,7 +780,7 @@ def any_to_cloth(self, ctx, cls, inst, cloth, parent, name, **_): def html_to_cloth(self, ctx, cls, inst, cloth, parent, name, **_): cls_attrs = self.get_cls_attrs(cls) self._enter_cloth(ctx, cloth, parent, method=cls_attrs.method) - if isinstance(inst, string_types): + if isinstance(inst, str): inst = html.fromstring(inst) parent.write(inst) @@ -710,8 +790,9 @@ def any_uri_to_cloth(self, ctx, cls, inst, cloth, parent, name, **kwargs): self.any_uri_to_parent(ctx, cls, inst, parent, name, **kwargs) @coroutine - def complex_to_cloth(self, ctx, cls, inst, cloth, parent, name=None, - as_attr=False, **kwargs): + def complex_to_cloth( + self, ctx, cls, inst, cloth, parent, name=None, as_attr=False, **kwargs + ): fti = cls.get_flat_type_info(cls) cls_attrs = self.get_cls_attrs(cls) @@ -720,8 +801,7 @@ def complex_to_cloth(self, ctx, cls, inst, cloth, parent, name=None, elt_check = set() attrib = self._gen_attrib_dict(inst, fti) - self._enter_cloth(ctx, cloth, parent, attrib=attrib, - method=cls_attrs.method) + self._enter_cloth(ctx, cloth, parent, attrib=attrib, method=cls_attrs.method) for elt in self._get_elts(cloth, self.MRPC_ID): self._actions_to_cloth(ctx, cls, inst, elt) @@ -736,13 +816,27 @@ def complex_to_cloth(self, ctx, cls, inst, cloth, parent, name=None, # Check for xmldata after entering the cloth. as_data_field = cloth.attrib.get(self.DATA_ATTR_NAME, None) if as_data_field is not None: - self._process_field(ctx, cls, inst, parent, cloth, fti, - as_data_field, as_attr, True, fti_check, elt_check, **kwargs) + self._process_field( + ctx, + cls, + inst, + parent, + cloth, + fti, + as_data_field, + as_attr, + True, + fti_check, + elt_check, + **kwargs, + ) for elt in elts: - for k_attr, as_attr, as_data in ((self.ID_ATTR_NAME, False, False), - (self.ATTR_ATTR_NAME, True, False), - (self.DATA_ATTR_NAME, False, True)): + for k_attr, as_attr, as_data in ( + (self.ID_ATTR_NAME, False, False), + (self.ATTR_ATTR_NAME, True, False), + (self.DATA_ATTR_NAME, False, True), + ): field_name = elt.attrib.get(k_attr, None) if field_name is None: continue @@ -750,14 +844,25 @@ def complex_to_cloth(self, ctx, cls, inst, cloth, parent, name=None, if elt.tag == self.DATA_TAG_NAME: as_data = True - ret = self._process_field(ctx, cls, inst, parent, elt, fti, - field_name, as_attr=as_attr, as_data=as_data, - fti_check=fti_check, elt_check=elt_check, **kwargs) + ret = self._process_field( + ctx, + cls, + inst, + parent, + elt, + fti, + field_name, + as_attr=as_attr, + as_data=as_data, + fti_check=fti_check, + elt_check=elt_check, + **kwargs, + ) if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as e: try: @@ -777,15 +882,30 @@ def complex_to_cloth(self, ctx, cls, inst, cloth, parent, name=None, break if len(fti_check) > 0: - logger_s.debug("No element found for the following fields: %r", - list(fti_check.keys())) + logger_s.debug( + "No element found for the following fields: %r", list(fti_check.keys()) + ) if len(elt_check) > 0: - logger_s.debug("No field found for element the following " - "elements: %r", list(elt_check)) - - def _process_field(self, ctx, cls, inst, parent, - elt, fti, field_name, as_attr, as_data, fti_check, elt_check, - **kwargs): + logger_s.debug( + "No field found for element the following " "elements: %r", + list(elt_check), + ) + + def _process_field( + self, + ctx, + cls, + inst, + parent, + elt, + fti, + field_name, + as_attr, + as_data, + fti_check, + elt_check, + **kwargs, + ): field_type = fti.get(field_name, None) fti_check.pop(field_name, None) @@ -797,8 +917,7 @@ def _process_field(self, ctx, cls, inst, parent, cls_attrs = self.get_cls_attrs(field_type) if cls_attrs.exc: - logger_c.debug("Skipping elt id %r because " - "it was excluded", field_name) + logger_c.debug("Skipping elt id %r because " "it was excluded", field_name) return sub_name = cls_attrs.sub_name @@ -814,24 +933,34 @@ def _process_field(self, ctx, cls, inst, parent, val = getattr(inst, field_name, None) if as_data: - self._enter_cloth(ctx, elt, parent, skip=True, skip_dupe=True, - method=cls_attrs.method) - - return self.to_cloth(ctx, field_type, val, elt, parent, - name=sub_name, as_attr=as_attr, as_data=as_data, **kwargs) + self._enter_cloth( + ctx, elt, parent, skip=True, skip_dupe=True, method=cls_attrs.method + ) + + return self.to_cloth( + ctx, + field_type, + val, + elt, + parent, + name=sub_name, + as_attr=as_attr, + as_data=as_data, + **kwargs, + ) @coroutine - def array_to_cloth(self, ctx, cls, inst, cloth, parent, name=None, - **kwargs): + def array_to_cloth(self, ctx, cls, inst, cloth, parent, name=None, **kwargs): if isinstance(inst, PushBase): while True: - sv = (yield) - ret = self.to_cloth(ctx, cls, sv, cloth, parent, - name=name, from_arr=True, **kwargs) + sv = yield + ret = self.to_cloth( + ctx, cls, sv, cloth, parent, name=name, from_arr=True, **kwargs + ) if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as e: try: @@ -845,12 +974,13 @@ def array_to_cloth(self, ctx, cls, inst, cloth, parent, name=None, for sv in inst: was_empty = False - ret = self.to_cloth(ctx, cls, sv, cloth, parent, - from_arr=True, name=name, **kwargs) + ret = self.to_cloth( + ctx, cls, sv, cloth, parent, from_arr=True, name=name, **kwargs + ) if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as e: try: diff --git a/spyne/protocol/cloth/to_parent.py b/spyne/protocol/cloth/to_parent.py index 43092805f..b0298b60b 100644 --- a/spyne/protocol/cloth/to_parent.py +++ b/spyne/protocol/cloth/to_parent.py @@ -20,54 +20,75 @@ from __future__ import print_function import logging + logger = logging.getLogger(__name__) +from collections.abc import Iterable from inspect import isgenerator -from spyne.util.six.moves.collections_abc import Iterable from lxml import etree, html from lxml.builder import E -from spyne.const.xml import NS_XSI, NS_SOAP11_ENV, SOAP11_ENV -from spyne.model import PushBase, ComplexModelBase, AnyXml, Fault, AnyDict, \ - AnyHtml, ModelBase, ByteArray, XmlData, Any, AnyUri, ImageUri, XmlAttribute - +from spyne.const.xml import NS_SOAP11_ENV, NS_XSI, SOAP11_ENV +from spyne.model import ( + Any, + AnyDict, + AnyHtml, + AnyUri, + AnyXml, + ByteArray, + ComplexModelBase, + Fault, + ImageUri, + ModelBase, + PushBase, + XmlAttribute, + XmlData, +) from spyne.model.enum import EnumBase from spyne.protocol import OutProtocolBase from spyne.protocol.xml import SchemaValidationError -from spyne.util import coroutine, Break, six +from spyne.util import Break, coroutine from spyne.util.cdict import cdict +from spyne.util.color import B, R from spyne.util.etreeconv import dict_to_etree -from spyne.util.color import R, B - -from spyne.util.six import string_types class ToParentMixin(OutProtocolBase): - def __init__(self, app=None, mime_type=None, ignore_uncap=False, - ignore_wrappers=False, polymorphic=True): - super(ToParentMixin, self).__init__(app=app, mime_type=mime_type, - ignore_uncap=ignore_uncap, ignore_wrappers=ignore_wrappers) + def __init__( + self, + app=None, + mime_type=None, + ignore_uncap=False, + ignore_wrappers=False, + polymorphic=True, + ): + super(ToParentMixin, self).__init__( + app=app, + mime_type=mime_type, + ignore_uncap=ignore_uncap, + ignore_wrappers=ignore_wrappers, + ) self.polymorphic = polymorphic self.use_global_null_handler = True - self.serialization_handlers = cdict({ - ModelBase: self.model_base_to_parent, - - AnyXml: self.any_xml_to_parent, - AnyUri: self.any_uri_to_parent, - ImageUri: self.imageuri_to_parent, - AnyDict: self.any_dict_to_parent, - AnyHtml: self.any_html_to_parent, - Any: self.any_to_parent, - - Fault: self.fault_to_parent, - EnumBase: self.enum_to_parent, - ByteArray: self.byte_array_to_parent, - ComplexModelBase: self.complex_to_parent, - SchemaValidationError: self.schema_validation_error_to_parent, - }) + self.serialization_handlers = cdict( + { + ModelBase: self.model_base_to_parent, + AnyXml: self.any_xml_to_parent, + AnyUri: self.any_uri_to_parent, + ImageUri: self.imageuri_to_parent, + AnyDict: self.any_dict_to_parent, + AnyHtml: self.any_html_to_parent, + Any: self.any_to_parent, + Fault: self.fault_to_parent, + EnumBase: self.enum_to_parent, + ByteArray: self.byte_array_to_parent, + ComplexModelBase: self.complex_to_parent, + SchemaValidationError: self.schema_validation_error_to_parent, + } + ) def start_to_parent(self, ctx, cls, inst, parent, name, **kwargs): """This is what subserialize calls""" @@ -81,8 +102,11 @@ def start_to_parent(self, ctx, cls, inst, parent, name, **kwargs): @staticmethod def get_subprot(ctx, cls_attrs, nosubprot=False): subprot = cls_attrs.prot - if subprot is not None and not nosubprot and not \ - (subprot in ctx.protocol.prot_stack): + if ( + subprot is not None + and not nosubprot + and not (subprot in ctx.protocol.prot_stack) + ): return subprot return None @@ -109,12 +133,12 @@ def to_parent(self, ctx, cls, inst, parent, name, nosubprot=False, **kwargs): subprot = self.get_subprot(ctx, cls_attrs, nosubprot) if subprot is not None: logger.debug("Subprot from %r to %r", self, subprot) - ret = self.to_subprot(ctx, cls, inst, parent, name, subprot, - **kwargs) + ret = self.to_subprot(ctx, cls, inst, parent, name, subprot, **kwargs) else: # if there is a class cloth, switch to it - has_cloth, cor_handle = self.check_class_cloths(ctx, cls, inst, - parent, name, **kwargs) + has_cloth, cor_handle = self.check_class_cloths( + ctx, cls, inst, parent, name, **kwargs + ) if has_cloth: ret = cor_handle @@ -131,9 +155,13 @@ def to_parent(self, ctx, cls, inst, parent, name, nosubprot=False, **kwargs): # if instance is still None, use the global null handler to # serialize it if inst is None and self.use_global_null_handler: - identifier = prot_name + '.null_to_parent' - logger.debug("Writing %s using %s for %s.", name, - identifier, cls.get_type_name()) + identifier = prot_name + ".null_to_parent" + logger.debug( + "Writing %s using %s for %s.", + name, + identifier, + cls.get_type_name(), + ) self.null_to_parent(ctx, cls, inst, parent, name, **kwargs) return @@ -144,12 +172,11 @@ def to_parent(self, ctx, cls, inst, parent, name, nosubprot=False, **kwargs): # if cls is an iterable of values and it's not being iterated # on, do it - from_arr = kwargs.get('from_arr', False) + from_arr = kwargs.get("from_arr", False) # we need cls.Attributes here because we need the ACTUAL attrs # that were set by the Array.__new__ if not from_arr and cls.Attributes.max_occurs > 1: - ret = self.array_to_parent(ctx, cls, inst, parent, name, - **kwargs) + ret = self.array_to_parent(ctx, cls, inst, parent, name, **kwargs) else: # fetch the serializer for the class at hand try: @@ -162,17 +189,20 @@ def to_parent(self, ctx, cls, inst, parent, name, nosubprot=False, **kwargs): return # ignore it if requested # raise the error otherwise - logger.error("%r is missing handler for " - "%r for field %r", self, cls, name) + logger.error( + "%r is missing handler for " "%r for field %r", + self, + cls, + name, + ) raise # push the instance at hand to instance stack. this makes it # easier for protocols to make decisions based on parents # of instances at hand. - ctx.outprot_ctx.inst_stack.append( (cls, inst, from_arr) ) + ctx.outprot_ctx.inst_stack.append((cls, inst, from_arr)) pushed = True - logger.debug("%s %r pushed %r using %r", - R("$"), self, cls, handler) + logger.debug("%s %r pushed %r using %r", R("$"), self, cls, handler) # disabled for performance reasons # from spyne.util.web import log_repr @@ -188,7 +218,7 @@ def to_parent(self, ctx, cls, inst, parent, name, nosubprot=False, **kwargs): if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as e: @@ -203,8 +233,7 @@ def to_parent(self, ctx, cls, inst, parent, name, nosubprot=False, **kwargs): self._close_cloth(ctx, parent) if pushed: - logger.debug("%s %r popped %r %r", B("$"), self, cls, - inst) + logger.debug("%s %r popped %r %r", B("$"), self, cls, inst) ctx.outprot_ctx.inst_stack.pop() else: @@ -232,16 +261,17 @@ def array_to_parent(self, ctx, cls, inst, parent, name, **kwargs): try: while True: - sv = (yield) + sv = yield # disabled because to_parent is supposed to take care of this - #ctx.protocol.inst_stack.append((cls, sv, True)) - kwargs['from_arr'] = True - kwargs['array_index'] = i + # ctx.protocol.inst_stack.append((cls, sv, True)) + kwargs["from_arr"] = True + kwargs["array_index"] = i if ser_subprot is not None: - ser_subprot.column_table_before_row(ctx, cls, inst, - parent, name, **kwargs) + ser_subprot.column_table_before_row( + ctx, cls, inst, parent, name, **kwargs + ) ret = self.to_parent(ctx, cls, sv, parent, name, **kwargs) @@ -249,7 +279,7 @@ def array_to_parent(self, ctx, cls, inst, parent, name, **kwargs): if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as e: @@ -260,43 +290,46 @@ def array_to_parent(self, ctx, cls, inst, parent, name, **kwargs): finally: # disabled because to_parent is supposed to take care of this - #popped_val = ctx.protocol.inst_stack.pop() - #assert popped_val is sv + # popped_val = ctx.protocol.inst_stack.pop() + # assert popped_val is sv if ser_subprot is not None: - ser_subprot.column_table_before_row(ctx, cls, - inst, parent, name, **kwargs) + ser_subprot.column_table_before_row( + ctx, cls, inst, parent, name, **kwargs + ) else: # disabled because to_parent is supposed to take care of this - #popped_val = ctx.protocol.inst_stack.pop() - #assert popped_val is sv + # popped_val = ctx.protocol.inst_stack.pop() + # assert popped_val is sv if ser_subprot is not None: - ser_subprot.column_table_after_row(ctx, cls, inst, - parent, name, **kwargs) + ser_subprot.column_table_after_row( + ctx, cls, inst, parent, name, **kwargs + ) except Break: # pusher is done with pushing pass else: - assert isinstance(inst, Iterable), ("%r is not iterable" % (inst,)) + assert isinstance(inst, Iterable), "%r is not iterable" % (inst,) for i, sv in enumerate(inst): # disabled because to_parent is supposed to take care of this - #ctx.protocol.inst_stack.append((cls, sv, True) - kwargs['from_arr'] = True - kwargs['array_index'] = i + # ctx.protocol.inst_stack.append((cls, sv, True) + kwargs["from_arr"] = True + kwargs["array_index"] = i if ser_subprot is not None: - ser_subprot.column_table_before_row(ctx, cls, inst, parent, - name, **kwargs) + ser_subprot.column_table_before_row( + ctx, cls, inst, parent, name, **kwargs + ) ret = self.to_parent(ctx, cls, sv, parent, name, **kwargs) if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as e: @@ -307,21 +340,23 @@ def array_to_parent(self, ctx, cls, inst, parent, name, **kwargs): finally: # disabled because to_parent is supposed to take care of this - #popped_val = ctx.protocol.inst_stack.pop() - #assert popped_val is sv + # popped_val = ctx.protocol.inst_stack.pop() + # assert popped_val is sv if ser_subprot is not None: - ser_subprot.column_table_after_row(ctx, cls, inst, - parent, name, **kwargs) + ser_subprot.column_table_after_row( + ctx, cls, inst, parent, name, **kwargs + ) else: # disabled because to_parent is supposed to take care of this - #popped_val = ctx.protocol.inst_stack.pop() - #assert popped_val is sv + # popped_val = ctx.protocol.inst_stack.pop() + # assert popped_val is sv if ser_subprot is not None: - ser_subprot.column_table_after_row(ctx, cls, inst, - parent, name, **kwargs) + ser_subprot.column_table_after_row( + ctx, cls, inst, parent, name, **kwargs + ) def not_supported(self, ctx, cls, *args, **kwargs): if not self.ignore_uncap: @@ -340,19 +375,19 @@ def model_base_to_parent(self, ctx, cls, inst, parent, name, **kwargs): parent.write(E(name, self.to_unicode(cls, inst))) def null_to_parent(self, ctx, cls, inst, parent, name, **kwargs): - parent.write(E(name, **{'{%s}nil' % NS_XSI: 'true'})) + parent.write(E(name, **{"{%s}nil" % NS_XSI: "true"})) def enum_to_parent(self, ctx, cls, inst, parent, name, **kwargs): self.model_base_to_parent(ctx, cls, str(inst), parent, name) def any_xml_to_parent(self, ctx, cls, inst, parent, name, **kwargs): - if isinstance(inst, string_types): + if isinstance(inst, str): inst = etree.fromstring(inst) parent.write(E(name, inst)) def any_html_to_unicode(self, cls, inst, **_): - if isinstance(inst, (str, six.text_type)): + if isinstance(inst, str): inst = html.fromstring(inst) return inst @@ -361,11 +396,11 @@ def any_html_to_parent(self, ctx, cls, inst, parent, name, **kwargs): cls_attrs = self.get_cls_attrs(cls) if cls_attrs.as_string: - if not (isinstance(inst, str) or isinstance(inst, six.text_type)): + if not isinstance(inst, str): inst = html.tostring(inst) else: - if isinstance(inst, str) or isinstance(inst, six.text_type): + if isinstance(inst, str): inst = html.fromstring(inst) parent.write(E(name, inst)) @@ -432,12 +467,13 @@ def _write_members(self, ctx, cls, inst, parent, use_ns=None, **kwargs): continue if subvalue is not None or attr.min_occurs > 0: - ret = self.to_parent(ctx, v, subvalue, parent, sub_name, - use_ns=use_ns, **kwargs) + ret = self.to_parent( + ctx, v, subvalue, parent, sub_name, use_ns=use_ns, **kwargs + ) if ret is not None: try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as b: try: @@ -454,7 +490,7 @@ def _complex_to_parent_do(self, ctx, cls, inst, parent, **kwargs): if ret is not None: try: while True: - sv2 = (yield) # may throw Break + sv2 = yield # may throw Break ret.send(sv2) except Break: @@ -463,27 +499,30 @@ def _complex_to_parent_do(self, ctx, cls, inst, parent, **kwargs): except StopIteration: pass - def complex_to_parent(self, ctx, cls, inst, parent, name, - from_arr=False, use_ns=None, **kwargs): + def complex_to_parent( + self, ctx, cls, inst, parent, name, from_arr=False, use_ns=None, **kwargs + ): if not from_arr: inst = cls.get_serialization_instance(inst) attrib = self._gen_attrib_dict(inst, cls.get_flat_type_info(cls)) if self.skip_root_tag: - self._complex_to_parent_do(ctx, cls, inst, parent, - from_arr=from_arr, **kwargs) + self._complex_to_parent_do( + ctx, cls, inst, parent, from_arr=from_arr, **kwargs + ) else: - if name is None or name == '': - name = self._gen_sub_name(cls, self.get_cls_attrs(cls), - cls.get_type_name(), use_ns) - logger.debug("name is empty, long live name: %s, cls: %r", - name, cls) + if name is None or name == "": + name = self._gen_sub_name( + cls, self.get_cls_attrs(cls), cls.get_type_name(), use_ns + ) + logger.debug("name is empty, long live name: %s, cls: %r", name, cls) with parent.element(name, attrib=attrib): - self._complex_to_parent_do(ctx, cls, inst, parent, - from_arr=from_arr, **kwargs) + self._complex_to_parent_do( + ctx, cls, inst, parent, from_arr=from_arr, **kwargs + ) def fault_to_parent(self, ctx, cls, inst, parent, name): PREF_SOAP_ENV = ctx.app.interface.prefmap[NS_SOAP11_ENV] @@ -491,7 +530,7 @@ def fault_to_parent(self, ctx, cls, inst, parent, name): with parent.element(tag_name): parent.write( - E("faultcode", '%s:%s' % (PREF_SOAP_ENV, inst.faultcode)), + E("faultcode", "%s:%s" % (PREF_SOAP_ENV, inst.faultcode)), E("faultstring", inst.faultstring), E("faultactor", inst.faultactor), ) @@ -510,7 +549,7 @@ def schema_validation_error_to_parent(self, ctx, cls, inst, parent, **_): with parent.element(tag_name): parent.write( - E("faultcode", '%s:%s' % (PREF_SOAP_ENV, inst.faultcode)), + E("faultcode", "%s:%s" % (PREF_SOAP_ENV, inst.faultcode)), # HACK: Does anyone know a better way of injecting raw xml entities? E("faultstring", html.fromstring(inst.faultstring).text), E("faultactor", inst.faultactor), diff --git a/spyne/protocol/csv.py b/spyne/protocol/csv.py index 915ca8814..1fc1786fc 100644 --- a/spyne/protocol/csv.py +++ b/spyne/protocol/csv.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -27,26 +26,22 @@ from __future__ import absolute_import import logging + logger = logging.getLogger(__name__) import csv +from io import StringIO from spyne import ComplexModelBase -from spyne.util import six from spyne.protocol.dictdoc import HierDictDocument -if six.PY2: - from StringIO import StringIO -else: - from io import StringIO - def _complex_to_csv(prot, ctx): - cls, = ctx.descriptor.out_message._type_info.values() + (cls,) = ctx.descriptor.out_message._type_info.values() queue = StringIO() - serializer, = cls._type_info.values() + (serializer,) = cls._type_info.values() if issubclass(serializer, ComplexModelBase): type_info = serializer.get_flat_type_info(serializer) @@ -58,7 +53,7 @@ def _complex_to_csv(prot, ctx): if ctx.out_error is not None: writer = csv.writer(queue, dialect=csv.excel) - writer.writerow(['Error in generating the document']) + writer.writerow(["Error in generating the document"]) if ctx.out_error is not None: for r in ctx.out_error.to_bytes_iterable(ctx.out_error): writer.writerow([r]) @@ -82,11 +77,6 @@ def _complex_to_csv(prot, ctx): if ctx.out_object[0] is not None: for v in ctx.out_object[0]: d = prot._to_dict_value(serializer, v, set()) - if six.PY2: - for k in d: - if isinstance(d[k], unicode): - d[k] = d[k].encode('utf8') - writer.writerow(d) yval = queue.getvalue() yield yval @@ -94,20 +84,35 @@ def _complex_to_csv(prot, ctx): class Csv(HierDictDocument): - mime_type = 'text/csv' + mime_type = "text/csv" text_based = True type = set(HierDictDocument.type) - type.add('csv') - - def __init__(self, app=None, validator=None, mime_type=None, - ignore_uncap=False, ignore_wrappers=True, complex_as=dict, - ordered=False, polymorphic=False, header=True): - - super(Csv, self).__init__(app=app, validator=validator, - mime_type=mime_type, ignore_uncap=ignore_uncap, - ignore_wrappers=ignore_wrappers, complex_as=complex_as, - ordered=ordered, polymorphic=polymorphic) + type.add("csv") + + def __init__( + self, + app=None, + validator=None, + mime_type=None, + ignore_uncap=False, + ignore_wrappers=True, + complex_as=dict, + ordered=False, + polymorphic=False, + header=True, + ): + + super(Csv, self).__init__( + app=app, + validator=validator, + mime_type=mime_type, + ignore_uncap=ignore_uncap, + ignore_wrappers=ignore_wrappers, + complex_as=complex_as, + ordered=ordered, + polymorphic=polymorphic, + ) self.header = header @@ -115,20 +120,22 @@ def create_in_document(self, ctx): raise NotImplementedError() def serialize(self, ctx, message): - assert message in (self.RESPONSE, ) + assert message in (self.RESPONSE,) if ctx.out_object is None: ctx.out_object = [] - assert len(ctx.descriptor.out_message._type_info) == 1, \ - "CSV Serializer supports functions with exactly one return type: " \ + assert len(ctx.descriptor.out_message._type_info) == 1, ( + "CSV Serializer supports functions with exactly one return type: " "%r" % ctx.descriptor.out_message._type_info + ) def create_out_string(self, ctx): ctx.out_string = _complex_to_csv(self, ctx) - if 'http' in ctx.transport.type: - ctx.transport.resp_headers['Content-Disposition'] = ( - 'attachment; filename=%s.csv;' % ctx.descriptor.name) + if "http" in ctx.transport.type: + ctx.transport.resp_headers["Content-Disposition"] = ( + "attachment; filename=%s.csv;" % ctx.descriptor.name + ) def any_uri_to_unicode(self, cls, value, **_): if isinstance(value, cls.Value): diff --git a/spyne/protocol/dictdoc/__init__.py b/spyne/protocol/dictdoc/__init__.py index c0cee4d71..26e3e38bc 100644 --- a/spyne/protocol/dictdoc/__init__.py +++ b/spyne/protocol/dictdoc/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # diff --git a/spyne/protocol/dictdoc/_base.py b/spyne/protocol/dictdoc/_base.py index a10b121a4..f3a73d407 100644 --- a/spyne/protocol/dictdoc/_base.py +++ b/spyne/protocol/dictdoc/_base.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,16 +17,25 @@ # import logging + logger = logging.getLogger(__name__) import re + RE_HTTP_ARRAY_INDEX = re.compile("\\[([0-9]+)\\]") from spyne.error import ValidationError - -from spyne.model import Fault, Array, AnyXml, AnyHtml, Uuid, DateTime, Date, \ - Time, Duration - +from spyne.model import ( + AnyHtml, + AnyXml, + Array, + Date, + DateTime, + Duration, + Fault, + Time, + Uuid, +) from spyne.protocol import ProtocolBase @@ -44,22 +52,31 @@ class DictDocument(ProtocolBase): _huge_numbers_as_string = False text_based = False - def __init__(self, app=None, validator=None, mime_type=None, - ignore_uncap=False, ignore_wrappers=True, complex_as=dict, - ordered=False, polymorphic=False, key_encoding=None): - - super(DictDocument, self).__init__(app, validator, mime_type, - ignore_uncap, ignore_wrappers) + def __init__( + self, + app=None, + validator=None, + mime_type=None, + ignore_uncap=False, + ignore_wrappers=True, + complex_as=dict, + ordered=False, + polymorphic=False, + key_encoding=None, + ): + + super(DictDocument, self).__init__( + app, validator, mime_type, ignore_uncap, ignore_wrappers + ) self.key_encoding = key_encoding self.polymorphic = polymorphic self.complex_as = complex_as self.ordered = ordered if ordered: - raise NotImplementedError('ordered=True') + raise NotImplementedError("ordered=True") - self.stringified_types = (DateTime, Date, Time, Uuid, Duration, - AnyXml, AnyHtml) + self.stringified_types = (DateTime, Date, Time, Uuid, Duration, AnyXml, AnyHtml) def set_validator(self, validator): """Sets the validator for the protocol. @@ -67,7 +84,7 @@ def set_validator(self, validator): :param validator: one of ('soft', None) """ - if validator == 'soft' or validator is self.SOFT_VALIDATION: + if validator == "soft" or validator is self.SOFT_VALIDATION: self.validator = self.SOFT_VALIDATION elif validator is None: self.validator = None @@ -82,7 +99,7 @@ def decompose_incoming_envelope(self, ctx, message): assert message in (ProtocolBase.REQUEST, ProtocolBase.RESPONSE) # set ctx.in_header - ctx.transport.in_header_doc = None # use an rpc protocol if you want headers. + ctx.transport.in_header_doc = None # use an rpc protocol if you want headers. doc = ctx.in_document @@ -90,12 +107,13 @@ def decompose_incoming_envelope(self, ctx, message): ctx.in_body_doc = doc if message is ProtocolBase.REQUEST: - #logger.debug('\theader : %r', ctx.in_header_doc) - #logger.debug('\tbody : %r', ctx.in_body_doc) + # logger.debug('\theader : %r', ctx.in_header_doc) + # logger.debug('\tbody : %r', ctx.in_body_doc) if not isinstance(doc, dict) or len(doc) != 1: - raise ValidationError(doc, - "Need a dictionary with exactly one key as method name.") + raise ValidationError( + doc, "Need a dictionary with exactly one key as method name." + ) if len(doc) == 0: raise Fault("Client", "Empty request") @@ -108,8 +126,8 @@ def gen_method_request_string(self, ctx): Returns a string in the form of "{namespaces}method name". """ - mrs, = ctx.in_body_doc.keys() - return '{%s}%s' % (self.app.interface.get_tns(), mrs) + (mrs,) = ctx.in_body_doc.keys() + return "{%s}%s" % (self.app.interface.get_tns(), mrs) def deserialize(self, ctx, message): raise NotImplementedError() @@ -120,7 +138,7 @@ def serialize(self, ctx, message): def create_in_document(self, ctx, in_string_encoding=None): raise NotImplementedError() - def create_out_string(self, ctx, out_string_encoding='utf8'): + def create_out_string(self, ctx, out_string_encoding="utf8"): raise NotImplementedError() def _check_freq_dict(self, cls, d, fti=None): @@ -134,14 +152,18 @@ def _check_freq_dict(self, cls, d, fti=None): min_o, max_o = attrs.min_occurs, attrs.max_occurs if issubclass(v, Array) and v.Attributes.max_occurs == 1: - v, = v._type_info.values() + (v,) = v._type_info.values() attrs = self.get_cls_attrs(v) min_o, max_o = attrs.min_occurs, attrs.max_occurs if val < min_o: - raise ValidationError("%r.%s" % (cls, k), - '%%s member must occur at least %d times.' % min_o) + raise ValidationError( + "%r.%s" % (cls, k), + "%%s member must occur at least %d times." % min_o, + ) elif val > max_o: - raise ValidationError("%r.%s" % (cls, k), - '%%s member must occur at most %d times.' % max_o) + raise ValidationError( + "%r.%s" % (cls, k), + "%%s member must occur at most %d times." % max_o, + ) diff --git a/spyne/protocol/dictdoc/hier.py b/spyne/protocol/dictdoc/hier.py index 1fdf2eacf..7feb4b383 100644 --- a/spyne/protocol/dictdoc/hier.py +++ b/spyne/protocol/dictdoc/hier.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -20,23 +19,29 @@ from __future__ import print_function import logging + logger = logging.getLogger(__name__) import re + RE_HTTP_ARRAY_INDEX = re.compile("\\[([0-9]+)\\]") -from mmap import mmap from collections import defaultdict +from collections.abc import Iterable as AbcIterable +from mmap import mmap -from spyne.util import six -from spyne.util.six.moves.collections_abc import Iterable as AbcIterable - -from spyne.error import ValidationError -from spyne.error import ResourceNotFoundError - -from spyne.model import ByteArray, File, Fault, ComplexModelBase, Array, Any, \ - AnyDict, Uuid, Unicode - +from spyne.error import ResourceNotFoundError, ValidationError +from spyne.model import ( + Any, + AnyDict, + Array, + ByteArray, + ComplexModelBase, + Fault, + File, + Unicode, + Uuid, +) from spyne.protocol.dictdoc import DictDocument @@ -47,17 +52,21 @@ class HierDictDocument(DictDocument): Implement ``create_in_document()`` and ``create_out_string()`` to use this. """ - VALID_UNICODE_SOURCES = (six.text_type, six.binary_type, memoryview, - mmap, bytearray) + VALID_UNICODE_SOURCES = ( + str, + bytes, + memoryview, + mmap, + bytearray, + ) from_serstr = DictDocument.from_unicode to_serstr = DictDocument.to_unicode def get_class_name(self, cls): class_name = cls.get_type_name() - if not six.PY2: - if isinstance(class_name, bytes): - class_name = class_name.decode('utf8') + if isinstance(class_name, bytes): + class_name = class_name.decode("utf8") return class_name @@ -69,7 +78,7 @@ def get_complex_as(self, attr): def deserialize(self, ctx, message): assert message in (self.REQUEST, self.RESPONSE) - self.event_manager.fire_event('before_deserialize', ctx) + self.event_manager.fire_event("before_deserialize", ctx) if ctx.descriptor is None: raise ResourceNotFoundError(ctx.method_request_string) @@ -92,14 +101,13 @@ def deserialize(self, ctx, message): if self.ignore_wrappers: doc = doc.get(class_name, None) - result_message = self._doc_to_object(ctx, body_class, doc, - self.validator) + result_message = self._doc_to_object(ctx, body_class, doc, self.validator) ctx.in_object = result_message else: ctx.in_object = [] - self.event_manager.fire_event('after_deserialize', ctx) + self.event_manager.fire_event("after_deserialize", ctx) def _fault_to_doc(self, inst, cls=None): if cls is None: @@ -118,7 +126,7 @@ def _fault_to_doc(self, inst, cls=None): def serialize(self, ctx, message): assert message in (self.REQUEST, self.RESPONSE) - self.event_manager.fire_event('before_serialize', ctx) + self.event_manager.fire_event("before_serialize", ctx) if ctx.out_error is not None: ctx.out_document = self._fault_to_doc(ctx.out_error) @@ -139,7 +147,7 @@ def serialize(self, ctx, message): # assign raw result to its wrapper, result_message if ctx.descriptor.is_out_bare(): - out_instance, = ctx.out_object + (out_instance,) = ctx.out_object else: out_type_info = out_type.get_flat_type_info(out_type) @@ -151,17 +159,18 @@ def serialize(self, ctx, message): attrs = self.get_cls_attrs(v) out_instance._safe_set(k, ctx.out_object[i], v, attrs) - ctx.out_document = self._object_to_doc(out_type, out_instance, set()), + ctx.out_document = (self._object_to_doc(out_type, out_instance, set()),) logger.debug("Response: %r", ctx.out_document) - self.event_manager.fire_event('after_serialize', ctx) + self.event_manager.fire_event("after_serialize", ctx) def validate(self, key, cls, inst): if inst is None and self.get_cls_attrs(cls).nullable: pass - elif issubclass(cls, Unicode) and not isinstance(inst, - self.VALID_UNICODE_SOURCES): + elif issubclass(cls, Unicode) and not isinstance( + inst, self.VALID_UNICODE_SOURCES + ): raise ValidationError([key, inst]) def _from_dict_value(self, ctx, key, cls, inst, validator): @@ -195,12 +204,14 @@ def _from_dict_value(self, ctx, key, cls, inst, validator): retval = self._doc_to_object(ctx, cls, inst, validator) else: - if cls_attrs.empty_is_none and inst in (u'', b''): + if cls_attrs.empty_is_none and inst in ("", b""): inst = None - if (validator is self.SOFT_VALIDATION - and isinstance(inst, six.string_types) - and not cls.validate_string(cls, inst)): + if ( + validator is self.SOFT_VALIDATION + and isinstance(inst, str) + and not cls.validate_string(cls, inst) + ): raise ValidationError([key, inst]) if issubclass(cls, (ByteArray, Uuid)): @@ -208,24 +219,28 @@ def _from_dict_value(self, ctx, key, cls, inst, validator): elif issubclass(cls, Unicode): if isinstance(inst, bytearray): - retval = six.text_type(inst, - encoding=cls_attrs.encoding or 'ascii', - errors=cls_attrs.unicode_errors) + retval = str( + inst, + encoding=cls_attrs.encoding or "ascii", + errors=cls_attrs.unicode_errors, + ) elif isinstance(inst, memoryview): # FIXME: memoryview needs a .decode() function to avoid # needless copying here retval = inst.tobytes().decode( - cls_attrs.encoding or 'ascii', - errors=cls_attrs.unicode_errors) + cls_attrs.encoding or "ascii", + errors=cls_attrs.unicode_errors, + ) elif isinstance(inst, mmap): # FIXME: mmap needs a .decode() function to avoid # needless copying here - retval = mmap[:].decode(cls_attrs.encoding, - errors=cls_attrs.unicode_errors) + retval = mmap[:].decode( + cls_attrs.encoding, errors=cls_attrs.unicode_errors + ) - elif isinstance(inst, six.binary_type): + elif isinstance(inst, bytes): retval = self.unicode_from_bytes(cls, inst) else: @@ -258,8 +273,9 @@ def _doc_to_object(self, ctx, cls, doc, validator=None): raise ValidationError(doc) for i, child in enumerate(doc): - retval.append(self._from_dict_value(ctx, i, serializer, child, - validator)) + retval.append( + self._from_dict_value(ctx, i, serializer, child, validator) + ) return retval @@ -272,28 +288,35 @@ def _doc_to_object(self, ctx, cls, doc, validator=None): return None if len(doc) > 1: - raise ValidationError(doc, "There can be only one entry in a " - "wrapper dict") + raise ValidationError( + doc, "There can be only one entry in a " "wrapper dict" + ) subclasses = cls.get_subclasses() - (class_name, doc), = doc.items() - if not six.PY2 and isinstance(class_name, bytes): - class_name = class_name.decode('utf8') + ((class_name, doc),) = doc.items() + if isinstance(class_name, bytes): + class_name = class_name.decode("utf8") - if cls.get_type_name() != class_name and subclasses is not None \ - and len(subclasses) > 0: + if ( + cls.get_type_name() != class_name + and subclasses is not None + and len(subclasses) > 0 + ): for subcls in subclasses: if subcls.get_type_name() == class_name: break else: - raise ValidationError(class_name, - "Class name %%r is not registered as a subclass of %r" % - cls.get_type_name()) + raise ValidationError( + class_name, + "Class name %%r is not registered as a subclass of %r" + % cls.get_type_name(), + ) if not self.issubclass(subcls, cls): - raise ValidationError(class_name, - "Class name %%r is not a subclass of %r" % - cls.get_type_name()) + raise ValidationError( + class_name, + "Class name %%r is not a subclass of %r" % cls.get_type_name(), + ) cls = subcls inst = cls.get_deserialization_instance(ctx) @@ -315,8 +338,14 @@ def _doc_to_object(self, ctx, cls, doc, validator=None): # with the incoming sequence with field names. # TODO: cache this try: - items = zip([k for k, v in flat_type_info.items() - if not self.get_cls_attrs(v).exc], doc) + items = zip( + [ + k + for k, v in flat_type_info.items() + if not self.get_cls_attrs(v).exc + ], + doc, + ) except TypeError as e: logger.error("Invalid document %r for %r", doc, cls) raise ValidationError(doc) @@ -347,8 +376,7 @@ def _doc_to_object(self, ctx, cls, doc, validator=None): subinst = [] for a in v: - subinst.append( - self._from_dict_value(ctx, k, member, a, validator)) + subinst.append(self._from_dict_value(ctx, k, member, a, validator)) else: subinst = self._from_dict_value(ctx, k, member, v, validator) @@ -400,16 +428,16 @@ def _object_to_doc(self, cls, inst, tags=None): # cls_attrs = self.get_cls_attrs(cls) if self.ignore_wrappers: - ti = getattr(cls, '_type_info', {}) + ti = getattr(cls, "_type_info", {}) while cls.Attributes._wrapper and len(ti) == 1: # Wrappers are auto-generated objects that have exactly one # child type. - key, = ti.keys() + (key,) = ti.keys() if not issubclass(cls, Array): inst = getattr(inst, key, None) - cls, = ti.values() - ti = getattr(cls, '_type_info', {}) + (cls,) = ti.values() + ti = getattr(cls, "_type_info", {}) # transform the results into a dict: if cls.Attributes.max_occurs > 1: @@ -420,27 +448,31 @@ def _object_to_doc(self, cls, inst, tags=None): if id(subinst) in tags: # even when there is ONE already-serialized instance, # we throw the whole thing away. - logger.debug("Throwing the whole array away because " - "found %d", id(subinst)) + logger.debug( + "Throwing the whole array away because " "found %d", + id(subinst), + ) # this is DANGEROUS - #logger.debug("Said array: %r", inst) + # logger.debug("Said array: %r", inst) return None - retval.append(self._to_dict_value(cls, subinst, tags, - cls_orig=cls_orig or cls)) + retval.append( + self._to_dict_value( + cls, subinst, tags, cls_orig=cls_orig or cls + ) + ) else: - retval = self._to_dict_value(cls, inst, tags, - cls_orig=cls_orig or cls) + retval = self._to_dict_value(cls, inst, tags, cls_orig=cls_orig or cls) return retval def _get_member_pairs(self, cls, inst, tags): old_len = len(tags) tags = tags | {id(inst)} - assert len(tags) > old_len, ("Offending instance: %r" % inst) + assert len(tags) > old_len, "Offending instance: %r" % inst for k, v in self.sort_fields(cls): subattr = self.get_cls_attrs(v) @@ -500,7 +532,7 @@ def _to_dict_value(self, cls, inst, tags, cls_orig=None): return inst if issubclass(cls, Array): - st, = cls._type_info.values() + (st,) = cls._type_info.values() return self._object_to_doc(st, inst, tags) if issubclass(cls, ComplexModelBase): @@ -520,15 +552,18 @@ def _complex_to_doc(self, cls, inst, tags): subinst = getattr(inst, sf, None) - logger.debug("Render complex object %s to the value %r of its " - "field '%s'", cls.get_type_name(), subinst, sf) + logger.debug( + "Render complex object %s to the value %r of its " "field '%s'", + cls.get_type_name(), + subinst, + sf, + ) return self.to_unicode(subcls, subinst) cls_attr = self.get_cls_attrs(cls) complex_as = self.get_complex_as(cls_attr) - if complex_as is list or \ - getattr(cls.Attributes, 'serialize_as', False) is list: + if complex_as is list or getattr(cls.Attributes, "serialize_as", False) is list: return list(self._complex_to_list(cls, inst, tags)) return self._complex_to_dict(cls, inst, tags) @@ -540,28 +575,31 @@ def _complex_to_dict(self, cls, inst, tags): if self.key_encoding is None: d = complex_as(self._get_member_pairs(cls, inst, tags)) - if (self.ignore_wrappers or cls_attr.not_wrapped) \ - and not bool(cls_attr.wrapper): + if (self.ignore_wrappers or cls_attr.not_wrapped) and not bool( + cls_attr.wrapper + ): return d else: - if isinstance(cls_attr.wrapper, - (six.text_type, six.binary_type)): + if isinstance(cls_attr.wrapper, (str, bytes)): return {cls_attr.wrapper: d} else: return {cls.get_type_name(): d} else: - d = complex_as( (k.encode(self.key_encoding), v) for k, v in - self._get_member_pairs(cls, inst, tags) ) - - if (self.ignore_wrappers or cls_attr.not_wrapped) \ - and not bool(cls_attr.wrapper): + d = complex_as( + (k.encode(self.key_encoding), v) + for k, v in self._get_member_pairs(cls, inst, tags) + ) + + if (self.ignore_wrappers or cls_attr.not_wrapped) and not bool( + cls_attr.wrapper + ): return d else: - if isinstance(cls_attr.wrapper, six.text_type): + if isinstance(cls_attr.wrapper, str): return {cls_attr.wrapper.encode(self.key_encoding): d} - elif isinstance(cls_attr.wrapper, six.binary_type): + elif isinstance(cls_attr.wrapper, bytes): return {cls_attr.wrapper: d} else: return {cls.get_type_name().encode(self.key_encoding): d} diff --git a/spyne/protocol/dictdoc/simple.py b/spyne/protocol/dictdoc/simple.py index 01d58dafb..0d31ef252 100644 --- a/spyne/protocol/dictdoc/simple.py +++ b/spyne/protocol/dictdoc/simple.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,22 +17,26 @@ # import logging + logger = logging.getLogger(__name__) import re +from collections import defaultdict, deque -from collections import deque -from collections import defaultdict - -from spyne.util import six from spyne.error import ValidationError - -from spyne.model import ByteArray, String, File, ComplexModelBase, Array, \ - SimpleModel, Any, AnyDict, Unicode - +from spyne.model import ( + Any, + AnyDict, + Array, + ByteArray, + ComplexModelBase, + File, + SimpleModel, + String, + Unicode, +) from spyne.protocol.dictdoc import DictDocument - RE_HTTP_ARRAY_INDEX = re.compile(r"\[([0-9]+)]") @@ -81,13 +84,27 @@ class SimpleDictDocument(DictDocument): flat dictionaries. The only example as of now is Http. """ - def __init__(self, app=None, validator=None, mime_type=None, - ignore_uncap=False, ignore_wrappers=True, complex_as=dict, - ordered=False, hier_delim='.', strict_arrays=False): - super(SimpleDictDocument, self).__init__(app=app, validator=validator, - mime_type=mime_type, ignore_uncap=ignore_uncap, - ignore_wrappers=ignore_wrappers, complex_as=complex_as, - ordered=ordered) + def __init__( + self, + app=None, + validator=None, + mime_type=None, + ignore_uncap=False, + ignore_wrappers=True, + complex_as=dict, + ordered=False, + hier_delim=".", + strict_arrays=False, + ): + super(SimpleDictDocument, self).__init__( + app=app, + validator=validator, + mime_type=mime_type, + ignore_uncap=ignore_uncap, + ignore_wrappers=ignore_wrappers, + complex_as=complex_as, + ordered=ordered, + ) self.hier_delim = hier_delim self.strict_arrays = strict_arrays @@ -98,10 +115,13 @@ def _to_native_values(self, cls, member, orig_k, k, v, req_enc, validator): for v2 in v: # some wsgi implementations pass unicode strings, some pass str # strings. we get unicode here when we can and should. - if v2 is not None and req_enc is not None \ - and not issubclass(member.type, String) \ - and issubclass(member.type, Unicode) \ - and not isinstance(v2, six.text_type): + if ( + v2 is not None + and req_enc is not None + and not issubclass(member.type, String) + and issubclass(member.type, Unicode) + and not isinstance(v2, str) + ): try: v2 = v2.decode(req_enc) except UnicodeDecodeError as e: @@ -109,8 +129,10 @@ def _to_native_values(self, cls, member, orig_k, k, v, req_enc, validator): # validate raw data (before deserialization) try: - if (validator is self.SOFT_VALIDATION and not - member.type.validate_string(member.type, v2)): + if ( + validator is self.SOFT_VALIDATION + and not member.type.validate_string(member.type, v2) + ): raise ValidationError([orig_k, v2]) except TypeError: @@ -124,19 +146,18 @@ def _to_native_values(self, cls, member, orig_k, k, v, req_enc, validator): if isinstance(v2, File.Value): native_v2 = v2 else: - native_v2 = self.from_unicode(member.type, v2, - self.binary_encoding) + native_v2 = self.from_unicode(member.type, v2, self.binary_encoding) elif issubclass(member.type, ByteArray): - native_v2 = self.from_unicode(member.type, v2, - self.binary_encoding) + native_v2 = self.from_unicode(member.type, v2, self.binary_encoding) else: try: native_v2 = self.from_unicode(member.type, v2) except ValidationError as e: ns = "%s.%s" % (cls.get_namespace(), cls.get_type_name()) - raise ValidationError(e.faultstring, - "Validation failed for %s.%s: %%s" % (ns, k)) + raise ValidationError( + e.faultstring, "Validation failed for %s.%s: %%s" % (ns, k) + ) # validate native data (after deserialization) native_v2 = self._sanitize(cls_attrs, native_v2) @@ -158,10 +179,12 @@ def simple_dict_to_object(self, ctx, doc, cls, validator=None, req_enc=None): return doc if not issubclass(cls, ComplexModelBase): - raise NotImplementedError("Interestingly, deserializing non complex" - " types is not yet implemented. You can" - " use a ComplexModel to wrap that field." - " Otherwise, patches are welcome.") + raise NotImplementedError( + "Interestingly, deserializing non complex" + " types is not yet implemented. You can" + " use a ComplexModel to wrap that field." + " Otherwise, patches are welcome." + ) # this is for validating cls.Attributes.{min,max}_occurs frequencies = defaultdict(lambda: defaultdict(int)) @@ -174,8 +197,9 @@ def simple_dict_to_object(self, ctx, doc, cls, validator=None, req_enc=None): else: retval = cls.get_deserialization_instance(ctx) - simple_type_info = cls.get_simple_type_info_with_prot(cls, self, - hier_delim=self.hier_delim) + simple_type_info = cls.get_simple_type_info_with_prot( + cls, self, hier_delim=self.hier_delim + ) logger.debug("Simple type info key: %r", simple_type_info.keys()) @@ -189,7 +213,7 @@ def simple_dict_to_object(self, ctx, doc, cls, validator=None, req_enc=None): continue if member.can_be_empty: - if v != ['empty']: # maybe raise a ValidationError instead? + if v != ["empty"]: # maybe raise a ValidationError instead? # 'empty' is the only valid value at this point after all continue @@ -208,9 +232,9 @@ def simple_dict_to_object(self, ctx, doc, cls, validator=None, req_enc=None): else: # extract native values from the list of strings in the flat dict # entries. - value = self._to_native_values(cls, member, orig_k, k, v, - req_enc, validator) - + value = self._to_native_values( + cls, member, orig_k, k, v, req_enc, validator + ) # assign the native value to the relevant class in the nested object # structure. @@ -230,7 +254,7 @@ def simple_dict_to_object(self, ctx, doc, cls, validator=None, req_enc=None): ncls, ninst = ctype_info[pkey], getattr(cinst, pkey, None) nattrs = self.get_cls_attrs(ncls) if issubclass(ncls, Array): - ncls, = ncls._type_info.values() + (ncls,) = ncls._type_info.values() ncls_attrs = self.get_cls_attrs(ncls) mo = ncls_attrs.max_occurs @@ -251,8 +275,9 @@ def simple_dict_to_object(self, ctx, doc, cls, validator=None, req_enc=None): frequencies[cfreq_key][pkey] += 1 if nidx > len(ninst): - raise ValidationError(orig_k, - "%%r Invalid array index %d." % idx) + raise ValidationError( + orig_k, "%%r Invalid array index %d." % idx + ) if nidx == len(ninst): ninst.append(ncls.get_deserialization_instance(ctx)) frequencies[cfreq_key][pkey] += 1 @@ -290,22 +315,26 @@ def simple_dict_to_object(self, ctx, doc, cls, validator=None, req_enc=None): _v = getattr(cinst, member.path[-1], None) is_set = True if _v is None: - is_set = cinst._safe_set(member.path[-1], value, - member.type, member_attrs) + is_set = cinst._safe_set( + member.path[-1], value, member.type, member_attrs + ) else: _v.extend(value) - set_skip = 'set ' if is_set else 'SKIP' - logger.debug("\t%s arr %r(%r) = %r" % - (set_skip, member.path, pkey, value)) + set_skip = "set " if is_set else "SKIP" + logger.debug( + "\t%s arr %r(%r) = %r" % (set_skip, member.path, pkey, value) + ) else: - is_set = cinst._safe_set(member.path[-1], value[0], - member.type, member_attrs) + is_set = cinst._safe_set( + member.path[-1], value[0], member.type, member_attrs + ) - set_skip = 'set ' if is_set else 'SKIP' - logger.debug("\t%s val %r(%r) = %r" % - (set_skip, member.path, pkey, value[0])) + set_skip = "set " if is_set else "SKIP" + logger.debug( + "\t%s val %r(%r) = %r" % (set_skip, member.path, pkey, value[0]) + ) if validator is self.SOFT_VALIDATION: logger.debug("\tvalidate_freq: \n%r", frequencies) @@ -313,7 +342,7 @@ def simple_dict_to_object(self, ctx, doc, cls, validator=None, req_enc=None): for i, path_cls in enumerate(k[:-1:2]): attrs = self.get_cls_attrs(path_cls) if not attrs.validate_freq: - logger.debug("\t\tskip validate_freq: %r", k[:i*2]) + logger.debug("\t\tskip validate_freq: %r", k[: i * 2]) break else: path_cls = k[-2] @@ -322,13 +351,20 @@ def simple_dict_to_object(self, ctx, doc, cls, validator=None, req_enc=None): if issubclass(cls, Array): # unwrap the request object - array_name, = cls._type_info.keys() + (array_name,) = cls._type_info.keys() retval = getattr(retval, array_name) return retval - def object_to_simple_dict(self, cls, inst, retval=None, - prefix=None, subinst_eater=lambda prot, v, t: v, tags=None): + def object_to_simple_dict( + self, + cls, + inst, + retval=None, + prefix=None, + subinst_eater=lambda prot, v, t: v, + tags=None, + ): """Converts a native python object to a flat dict. See :func:`spyne.model.complex.ComplexModelBase.get_flat_type_info`. @@ -361,10 +397,11 @@ def object_to_simple_dict(self, cls, inst, retval=None, new_prefix.append(sub_name) subinst = getattr(inst, k, None) - if (issubclass(v, Array) or v.Attributes.max_occurs > 1) and \ - subinst is not None: + if ( + issubclass(v, Array) or v.Attributes.max_occurs > 1 + ) and subinst is not None: if issubclass(v, Array): - subtype, = v._type_info.values() + (subtype,) = v._type_info.values() else: subtype = v @@ -382,25 +419,37 @@ def object_to_simple_dict(self, cls, inst, retval=None, last_prefix = new_prefix[-1] i = -1 for i, ssv in enumerate(subinst): - new_prefix[-1] = '%s[%d]' % (last_prefix, i) - self.object_to_simple_dict(subtype, ssv, - retval, new_prefix, - subinst_eater=subinst_eater, tags=tags) + new_prefix[-1] = "%s[%d]" % (last_prefix, i) + self.object_to_simple_dict( + subtype, + ssv, + retval, + new_prefix, + subinst_eater=subinst_eater, + tags=tags, + ) if i == -1: key = self.hier_delim.join(new_prefix) - retval[key] = 'empty' + retval[key] = "empty" else: - self.object_to_simple_dict(v, subinst, retval, new_prefix, - subinst_eater=subinst_eater, tags=tags) + self.object_to_simple_dict( + v, + subinst, + retval, + new_prefix, + subinst_eater=subinst_eater, + tags=tags, + ) else: key = self.hier_delim.join(prefix) if key in retval: - raise ValueError("%r.%s conflicts with previous value %r" % - (cls, key, retval[key])) + raise ValueError( + "%r.%s conflicts with previous value %r" % (cls, key, retval[key]) + ) retval[key] = subinst_eater(self, inst, cls) diff --git a/spyne/protocol/html/__init__.py b/spyne/protocol/html/__init__.py index 43b6c5caa..532b22e8a 100644 --- a/spyne/protocol/html/__init__.py +++ b/spyne/protocol/html/__init__.py @@ -21,14 +21,10 @@ This package contains some basic html output protocols. """ -from spyne.protocol.html._base import HtmlBase -from spyne.protocol.html._base import HtmlCloth -from spyne.protocol.html._base import parse_html_fragment_file -from spyne.protocol.html.table import HtmlColumnTable -from spyne.protocol.html.table import HtmlRowTable +from spyne.protocol.html._base import HtmlBase, HtmlCloth, parse_html_fragment_file +from spyne.protocol.html.addtl import BooleanListProtocol, PrettyFormat from spyne.protocol.html.microformat import HtmlMicroFormat -from spyne.protocol.html.addtl import PrettyFormat -from spyne.protocol.html.addtl import BooleanListProtocol +from spyne.protocol.html.table import HtmlColumnTable, HtmlRowTable # FIXME: REMOVE ME diff --git a/spyne/protocol/html/_base.py b/spyne/protocol/html/_base.py index 142118ea1..bb4eca41c 100644 --- a/spyne/protocol/html/_base.py +++ b/spyne/protocol/html/_base.py @@ -18,6 +18,7 @@ # import logging + logger = logging.getLogger(__name__) from collections import defaultdict @@ -25,12 +26,10 @@ from lxml import etree, html from lxml.html.builder import E -from spyne.util import coroutine, Break, six -from spyne.util.oset import oset +from spyne.protocol.cloth._base import XmlCloth, XmlClothProtocolContext +from spyne.util import Break, coroutine from spyne.util.etreeconv import dict_to_etree - -from spyne.protocol.cloth import XmlCloth -from spyne.protocol.cloth._base import XmlClothProtocolContext +from spyne.util.oset import oset def parse_html_fragment_file(T_FILES): @@ -57,22 +56,38 @@ def __init__(self, parent, transport, type=None): class HtmlCloth(XmlCloth): - mime_type = 'text/html; charset=UTF-8' - - def __init__(self, app=None, encoding='utf8', - mime_type=None, ignore_uncap=False, ignore_wrappers=False, - cloth=None, cloth_parser=None, polymorphic=True, - strip_comments=True, hier_delim='.', doctype=None): - - super(HtmlCloth, self).__init__(app=app, encoding=encoding, - mime_type=mime_type, ignore_uncap=ignore_uncap, - ignore_wrappers=ignore_wrappers, cloth=cloth, - cloth_parser=cloth_parser, polymorphic=polymorphic, - strip_comments=strip_comments) + mime_type = "text/html; charset=UTF-8" + + def __init__( + self, + app=None, + encoding="utf8", + mime_type=None, + ignore_uncap=False, + ignore_wrappers=False, + cloth=None, + cloth_parser=None, + polymorphic=True, + strip_comments=True, + hier_delim=".", + doctype=None, + ): + + super(HtmlCloth, self).__init__( + app=app, + encoding=encoding, + mime_type=mime_type, + ignore_uncap=ignore_uncap, + ignore_wrappers=ignore_wrappers, + cloth=cloth, + cloth_parser=cloth_parser, + polymorphic=polymorphic, + strip_comments=strip_comments, + ) self.hier_delim = hier_delim self.doctype = doctype - self.default_method = 'html' + self.default_method = "html" def _parse_file(self, file_name, cloth_parser): if cloth_parser is None: @@ -102,38 +117,35 @@ def dict_to_parent(self, ctx, cls, inst, parent, name, **kwargs): @staticmethod def add_html_attr(attr_name, attr_dict, class_name): if attr_name in attr_dict: - attr_dict[attr_name] = ' '.join( - (attr_dict.get('class', ''), class_name)) + attr_dict[attr_name] = " ".join((attr_dict.get("class", ""), class_name)) else: attr_dict[attr_name] = class_name @staticmethod def add_style(attr_dict, data): - style = attr_dict.get('style', None) + style = attr_dict.get("style", None) if style is not None: - attr_dict['style'] = ';'.join(style, data) + attr_dict["style"] = ";".join(style, data) else: - attr_dict['style'] = data + attr_dict["style"] = data @staticmethod def selsafe(s): - return s.replace('[', '').replace(']', '').replace('.', '__') + return s.replace("[", "").replace("]", "").replace(".", "__") @coroutine - def complex_to_parent(self, ctx, cls, inst, parent, name, use_ns=False, - **kwargs): + def complex_to_parent(self, ctx, cls, inst, parent, name, use_ns=False, **kwargs): inst = cls.get_serialization_instance(inst) # TODO: Put xml attributes as well in the below element() call. with parent.element(name): - ret = self._write_members(ctx, cls, inst, parent, use_ns=False, - **kwargs) + ret = self._write_members(ctx, cls, inst, parent, use_ns=False, **kwargs) if ret is not None: try: while True: - sv2 = (yield) # may throw Break + sv2 = yield # may throw Break ret.send(sv2) except Break: @@ -146,16 +158,16 @@ def gen_anchor(self, cls, inst, name, anchor_class=None): assert name is not None cls_attrs = self.get_cls_attrs(cls) - href = getattr(inst, 'href', None) - if href is None: # this is not a AnyUri.Value instance. + href = getattr(inst, "href", None) + if href is None: # this is not a AnyUri.Value instance. href = inst content = None text = cls_attrs.text else: - content = getattr(inst, 'content', None) - text = getattr(inst, 'text', None) + content = getattr(inst, "content", None) + text = getattr(inst, "text", None) if text is None: text = cls_attrs.text @@ -168,10 +180,10 @@ def gen_anchor(self, cls, inst, name, anchor_class=None): retval = E.a(text) if href is not None: - retval.attrib['href'] = href + retval.attrib["href"] = href if anchor_class is not None: - retval.attrib['class'] = anchor_class + retval.attrib["class"] = anchor_class if content is not None: retval.append(content) @@ -184,19 +196,19 @@ def any_uri_to_parent(self, ctx, cls, inst, parent, name, **kwargs): def imageuri_to_parent(self, ctx, cls, inst, parent, name, **kwargs): # with ImageUri, content is ignored. - href = getattr(inst, 'href', None) - if href is None: # this is not a AnyUri.Value instance. + href = getattr(inst, "href", None) + if href is None: # this is not a AnyUri.Value instance. href = inst - text = getattr(cls.Attributes, 'text', None) + text = getattr(cls.Attributes, "text", None) else: - text = getattr(inst, 'text', None) + text = getattr(inst, "text", None) if text is None: - text = getattr(cls.Attributes, 'text', None) + text = getattr(cls.Attributes, "text", None) retval = E.img(src=href) if text is not None: - retval.attrib['alt'] = text + retval.attrib["alt"] = text parent.write(retval) @@ -216,7 +228,7 @@ def null_to_parent(self, ctx, cls, inst, parent, name, **kwargs): pass def any_xml_to_parent(self, ctx, cls, inst, parent, name, **kwargs): - if isinstance(inst, (six.text_type, six.binary_type)): + if isinstance(inst, (str, bytes)): inst = etree.fromstring(inst) parent.write(inst) @@ -225,11 +237,11 @@ def any_html_to_parent(self, ctx, cls, inst, parent, name, **kwargs): cls_attrs = self.get_cls_attrs(cls) if cls_attrs.as_string: - if not (isinstance(inst, str) or isinstance(inst, six.text_type)): + if not isinstance(inst, str): inst = html.tostring(inst) else: - if isinstance(inst, str) or isinstance(inst, six.text_type): + if isinstance(inst, str): inst = html.fromstring(inst) parent.write(inst) @@ -238,7 +250,7 @@ def any_to_parent(self, ctx, cls, inst, parent, name, **kwargs): parent.write(inst) def any_dict_to_parent(self, ctx, cls, inst, parent, name, **kwargs): - elt = E('foo') + elt = E("foo") dict_to_etree(inst, elt) parent.write(elt[0]) diff --git a/spyne/protocol/html/addtl.py b/spyne/protocol/html/addtl.py index c89af8aac..1ebf7195e 100644 --- a/spyne/protocol/html/addtl.py +++ b/spyne/protocol/html/addtl.py @@ -17,9 +17,10 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # -from lxml.builder import E from pprint import pformat +from lxml.builder import E + from spyne import Boolean from spyne.protocol.html import HtmlBase diff --git a/spyne/protocol/html/microformat.py b/spyne/protocol/html/microformat.py index b78e1e1c5..74a77c01e 100644 --- a/spyne/protocol/html/microformat.py +++ b/spyne/protocol/html/microformat.py @@ -21,22 +21,38 @@ from lxml.html.builder import E -from spyne.util import six, coroutine, Break -from spyne.util.cdict import cdict - -from spyne.model import Array, AnyHtml, ComplexModelBase, ByteArray, \ - ModelBase, PushBase, ImageUri, AnyUri - +from spyne.model import ( + AnyHtml, + AnyUri, + Array, + ByteArray, + ComplexModelBase, + ImageUri, + ModelBase, + PushBase, +) from spyne.protocol.html import HtmlBase +from spyne.util import Break, coroutine +from spyne.util.cdict import cdict class HtmlMicroFormat(HtmlBase): - def __init__(self, app=None, ignore_uncap=False, ignore_wrappers=False, - cloth=None, cloth_parser=None, polymorphic=True, - doctype="", - root_tag='div', child_tag='div', field_name_attr='class', - field_name_tag=None, field_name_class='field_name', - before_first_root=None): + def __init__( + self, + app=None, + ignore_uncap=False, + ignore_wrappers=False, + cloth=None, + cloth_parser=None, + polymorphic=True, + doctype="", + root_tag="div", + child_tag="div", + field_name_attr="class", + field_name_tag=None, + field_name_class="field_name", + before_first_root=None, + ): """Protocol that returns the response object according to the "html microformat" specification. See https://en.wikipedia.org/wiki/Microformats for more info. @@ -53,15 +69,18 @@ def __init__(self, app=None, ignore_uncap=False, ignore_wrappers=False, field names of the complex object children. """ - super(HtmlMicroFormat, self).__init__(app=app, - ignore_uncap=ignore_uncap, ignore_wrappers=ignore_wrappers, - cloth=cloth, cloth_parser=cloth_parser, polymorphic=polymorphic, - hier_delim=None, doctype=doctype) + super(HtmlMicroFormat, self).__init__( + app=app, + ignore_uncap=ignore_uncap, + ignore_wrappers=ignore_wrappers, + cloth=cloth, + cloth_parser=cloth_parser, + polymorphic=polymorphic, + hier_delim=None, + doctype=doctype, + ) - if six.PY2: - text_type = basestring - else: - text_type = str + text_type = str assert isinstance(root_tag, text_type) assert isinstance(child_tag, text_type) @@ -76,18 +95,19 @@ def __init__(self, app=None, ignore_uncap=False, ignore_wrappers=False, self.field_name_tag = E(field_name_tag) self._field_name_class = field_name_class if before_first_root is not None: - self.event_manager.add_listener("before_first_root", - before_first_root) - - self.serialization_handlers = cdict({ - Array: self.array_to_parent, - AnyUri: self.any_uri_to_parent, - AnyHtml: self.any_html_to_parent, - ImageUri: self.imageuri_to_parent, - ByteArray: self.not_supported, - ModelBase: self.model_base_to_parent, - ComplexModelBase: self.complex_model_to_parent, - }) + self.event_manager.add_listener("before_first_root", before_first_root) + + self.serialization_handlers = cdict( + { + Array: self.array_to_parent, + AnyUri: self.any_uri_to_parent, + AnyHtml: self.any_html_to_parent, + ImageUri: self.imageuri_to_parent, + ByteArray: self.not_supported, + ModelBase: self.model_base_to_parent, + ComplexModelBase: self.complex_model_to_parent, + } + ) def anyuri_to_parent(self, ctx, cls, inst, parent, name, **kwargs): retval = self.gen_anchor(cls, inst, parent) @@ -99,9 +119,10 @@ def model_base_to_parent(self, ctx, cls, inst, parent, name, **kwargs): data_str = self.to_unicode(cls, inst) if self.field_name_tag is not None: - field_name = cls.Attributes.translations.get( name) - field_name_tag = self.field_name_tag(field_name, - **{'class':self._field_name_class}) + field_name = cls.Attributes.translations.get(name) + field_name_tag = self.field_name_tag( + field_name, **{"class": self._field_name_class} + ) field_name_tag.tail = data_str retval.append(field_name_tag) @@ -114,7 +135,7 @@ def start_to_parent(self, ctx, cls, inst, parent, name, **kwargs): """This is what subserialize calls""" # if no doctype was written, write it - if not getattr(ctx.outprot_ctx, 'doctype_written', False): + if not getattr(ctx.outprot_ctx, "doctype_written", False): if len(ctx.protocol.prot_stack) == 1: if self.doctype is not None: parent.write_doctype(self.doctype) @@ -126,22 +147,23 @@ def start_to_parent(self, ctx, cls, inst, parent, name, **kwargs): return self.to_parent(ctx, cls, inst, parent, name, **kwargs) @coroutine - def complex_model_to_parent(self, ctx, cls, inst, parent, name, - use_ns=False, **kwargs): + def complex_model_to_parent( + self, ctx, cls, inst, parent, name, use_ns=False, **kwargs + ): attrs = {self.field_name_attr: name} - if not getattr(ctx.protocol, 'before_first_root', False): - self.event_manager.fire_event("before_first_root", - ctx, cls, inst, parent, name, **kwargs) + if not getattr(ctx.protocol, "before_first_root", False): + self.event_manager.fire_event( + "before_first_root", ctx, cls, inst, parent, name, **kwargs + ) ctx.protocol.before_first_root = True with parent.element(self.root_tag, attrs): - ret = self._write_members(ctx, cls, inst, parent, use_ns=False, - **kwargs) + ret = self._write_members(ctx, cls, inst, parent, use_ns=False, **kwargs) if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as e: try: @@ -154,19 +176,20 @@ def array_to_parent(self, ctx, cls, inst, parent, name, from_arr=False, **kwargs attrs = {self.field_name_attr: name} if issubclass(cls, Array): - cls, = cls._type_info.values() + (cls,) = cls._type_info.values() name = cls.get_type_name() with parent.element(self.root_tag, attrs): if isinstance(inst, PushBase): while True: - sv = (yield) - ret = self.to_parent(ctx, cls, sv, parent, name, - from_arr=True, **kwargs) + sv = yield + ret = self.to_parent( + ctx, cls, sv, parent, name, from_arr=True, **kwargs + ) if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as e: try: @@ -176,12 +199,13 @@ def array_to_parent(self, ctx, cls, inst, parent, name, from_arr=False, **kwargs else: for sv in inst: - ret = self.to_parent(ctx, cls, sv, parent, name, - from_arr=True, **kwargs) + ret = self.to_parent( + ctx, cls, sv, parent, name, from_arr=True, **kwargs + ) if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as e: try: @@ -190,8 +214,10 @@ def array_to_parent(self, ctx, cls, inst, parent, name, from_arr=False, **kwargs pass def null_to_parent(self, ctx, cls, inst, parent, name, **kwargs): - return [ E(self.child_tag, **{self.field_name_attr: name}) ] + return [E(self.child_tag, **{self.field_name_attr: name})] + # FIXME: yuck. -from spyne.protocol.cloth import XmlCloth +from spyne.protocol.cloth._base import XmlCloth + XmlCloth.HtmlMicroFormat = HtmlMicroFormat diff --git a/spyne/protocol/html/table/__init__.py b/spyne/protocol/html/table/__init__.py index 0c52d5792..3b43d9a70 100644 --- a/spyne/protocol/html/table/__init__.py +++ b/spyne/protocol/html/table/__init__.py @@ -1,4 +1,3 @@ - from spyne.protocol.html.table._base import HtmlTableBase -from spyne.protocol.html.table.row import HtmlRowTable from spyne.protocol.html.table.column import HtmlColumnTable +from spyne.protocol.html.table.row import HtmlRowTable diff --git a/spyne/protocol/html/table/_base.py b/spyne/protocol/html/table/_base.py index 347141931..87973c7b7 100644 --- a/spyne/protocol/html/table/_base.py +++ b/spyne/protocol/html/table/_base.py @@ -22,18 +22,41 @@ class HtmlTableBase(HtmlBase): - def __init__(self, app=None, ignore_uncap=False, ignore_wrappers=True, - cloth=None, cloth_parser=None, header=True, table_name_attr='class', - table_name=None, table_class=None, border=0, row_class=None, - field_name_attr='class', field_type_name_attr='class', - cell_class=None, header_cell_class=None, polymorphic=True, - hier_delim='.', doctype=None, link_gen=None, mrpc_delim_text='|', - table_width=None): + def __init__( + self, + app=None, + ignore_uncap=False, + ignore_wrappers=True, + cloth=None, + cloth_parser=None, + header=True, + table_name_attr="class", + table_name=None, + table_class=None, + border=0, + row_class=None, + field_name_attr="class", + field_type_name_attr="class", + cell_class=None, + header_cell_class=None, + polymorphic=True, + hier_delim=".", + doctype=None, + link_gen=None, + mrpc_delim_text="|", + table_width=None, + ): - super(HtmlTableBase, self).__init__(app=app, - ignore_uncap=ignore_uncap, ignore_wrappers=ignore_wrappers, - cloth=cloth, cloth_parser=cloth_parser, polymorphic=polymorphic, - hier_delim=hier_delim, doctype=doctype) + super(HtmlTableBase, self).__init__( + app=app, + ignore_uncap=ignore_uncap, + ignore_wrappers=ignore_wrappers, + cloth=cloth, + cloth_parser=cloth_parser, + polymorphic=polymorphic, + hier_delim=hier_delim, + doctype=doctype, + ) self.header = header self.table_name_attr = table_name_attr @@ -65,5 +88,4 @@ def add_field_attrs(self, attr_dict, name, cls): c = c.__extends__ - self.add_html_attr(self.field_type_name_attr, attr_dict, - ' '.join(types)) + self.add_html_attr(self.field_type_name_attr, attr_dict, " ".join(types)) diff --git a/spyne/protocol/html/table/column.py b/spyne/protocol/html/table/column.py index 8ac9abfa8..764612eda 100644 --- a/spyne/protocol/html/table/column.py +++ b/spyne/protocol/html/table/column.py @@ -20,16 +20,17 @@ from __future__ import print_function import logging + logger = logging.getLogger(__name__) from inspect import isgenerator from lxml.html.builder import E -from spyne import ModelBase, ComplexModelBase, Array -from spyne.util import coroutine, Break, urlencode -from spyne.util.oset import oset +from spyne import Array, ComplexModelBase, ModelBase from spyne.protocol.html.table import HtmlTableBase +from spyne.util import Break, coroutine, urlencode +from spyne.util.oset import oset class HtmlColumnTableRowProtocol(object): @@ -43,7 +44,6 @@ def column_table_after_row(self, ctx, cls, inst, parent, name, **kwargs): pass - class HtmlColumnTable(HtmlTableBase, HtmlColumnTableRowProtocol): """Protocol that returns the response object as a html table. @@ -78,22 +78,25 @@ class HtmlColumnTable(HtmlTableBase, HtmlColumnTableRowProtocol): """ def __init__(self, *args, **kwargs): - before_table = kwargs.pop('before_table', None) + before_table = kwargs.pop("before_table", None) super(HtmlColumnTable, self).__init__(*args, **kwargs) - self.serialization_handlers.update({ - ModelBase: self.model_base_to_parent, - ComplexModelBase: self.complex_model_to_parent, - Array: self.array_to_parent, - }) + self.serialization_handlers.update( + { + ModelBase: self.model_base_to_parent, + ComplexModelBase: self.complex_model_to_parent, + Array: self.array_to_parent, + } + ) if before_table is not None: self.event_manager.add_listener("before_table", before_table) - def model_base_to_parent(self, ctx, cls, inst, parent, name, - from_arr=False, **kwargs): - inst_str = '' + def model_base_to_parent( + self, ctx, cls, inst, parent, name, from_arr=False, **kwargs + ): + inst_str = "" if inst is not None: inst_str = self.to_unicode(cls, inst) @@ -108,8 +111,9 @@ def model_base_to_parent(self, ctx, cls, inst, parent, name, parent.write(inst_str) @coroutine - def _gen_row(self, ctx, cls, inst, parent, name, from_arr=False, - array_index=None, **kwargs): + def _gen_row( + self, ctx, cls, inst, parent, name, from_arr=False, array_index=None, **kwargs + ): # because HtmlForm* protocols don't use the global null handler, it's # possible for null values to reach here. @@ -118,18 +122,16 @@ def _gen_row(self, ctx, cls, inst, parent, name, from_arr=False, logger.debug("Generate row for %r", cls) - mrpc_delim_elt = '' + mrpc_delim_elt = "" if self.mrpc_delim_text is not None: - mrpc_delim_elt = E.span(self.mrpc_delim_text, - **{'class': 'mrpc-delimiter'}) - mrpc_delim_elt.tail = ' ' + mrpc_delim_elt = E.span(self.mrpc_delim_text, **{"class": "mrpc-delimiter"}) + mrpc_delim_elt.tail = " " - with parent.element('tr'): + with parent.element("tr"): for k, v in self.sort_fields(cls): cls_attr = self.get_cls_attrs(v) if cls_attr.exc: - logger.debug("\tExclude table cell %r type %r for %r", - k, v, cls) + logger.debug("\tExclude table cell %r type %r for %r", k, v, cls) continue try: @@ -145,27 +147,40 @@ def _gen_row(self, ctx, cls, inst, parent, name, from_arr=False, if array_index is None: sub_name = "%s%s%s" % (name, self.hier_delim, sub_name) else: - sub_name = "%s[%d]%s%s" % (name, array_index, - self.hier_delim, sub_name) + sub_name = "%s[%d]%s%s" % ( + name, + array_index, + self.hier_delim, + sub_name, + ) - logger.debug("\tGenerate table cell %r type %r for %r", - sub_name, v, cls) + logger.debug( + "\tGenerate table cell %r type %r for %r", sub_name, v, cls + ) td_attrs = {} self.add_field_attrs(td_attrs, cls_attr.sub_name or k, v) if cls_attr.hidden: - self.add_style(td_attrs, 'display:None') - - with parent.element('td', td_attrs): - ret = self.to_parent(ctx, v, sub_value, parent, sub_name, - from_arr=from_arr, array_index=array_index, **kwargs) + self.add_style(td_attrs, "display:None") + + with parent.element("td", td_attrs): + ret = self.to_parent( + ctx, + v, + sub_value, + parent, + sub_name, + from_arr=from_arr, + array_index=array_index, + **kwargs, + ) if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as b: @@ -176,9 +191,9 @@ def _gen_row(self, ctx, cls, inst, parent, name, from_arr=False, m = cls.Attributes.methods if m is not None and len(m) > 0: - td_attrs = {'class': 'mrpc-cell'} + td_attrs = {"class": "mrpc-cell"} - with parent.element('td', td_attrs): + with parent.element("td", td_attrs): first = True for mn, md in self._methods(ctx, cls, inst): @@ -190,7 +205,7 @@ def _gen_row(self, ctx, cls, inst, parent, name, from_arr=False, pd = {} for k, v in self.sort_fields(cls): - if getattr(v.Attributes, 'primary_key', None): + if getattr(v.Attributes, "primary_key", None): r = self.to_unicode(v, getattr(inst, k, None)) if r is not None: pd[k] = r @@ -199,23 +214,25 @@ def _gen_row(self, ctx, cls, inst, parent, name, from_arr=False, mdid2key = ctx.app.interface.method_descriptor_id_to_key href = mdid2key[id(md)].rsplit("}", 1)[-1] - text = md.translate(ctx.locale, - md.in_message.get_type_name()) - parent.write(E.a( - text, - href="%s?%s" % (href, params), - **{'class': 'mrpc-operation'} - )) + text = md.translate(ctx.locale, md.in_message.get_type_name()) + parent.write( + E.a( + text, + href="%s?%s" % (href, params), + **{"class": "mrpc-operation"}, + ) + ) logger.debug("Generate row for %r done.", cls) - self.extend_data_row(ctx, cls, inst, parent, name, - array_index=array_index, **kwargs) + self.extend_data_row( + ctx, cls, inst, parent, name, array_index=array_index, **kwargs + ) def _gen_thead(self, ctx, cls, parent, name): logger.debug("Generate header for %r", cls) - with parent.element('thead'): - with parent.element('tr'): + with parent.element("thead"): + with parent.element("tr"): if issubclass(cls, ComplexModelBase): fti = self.sort_fields(cls) for k, v in fti: @@ -227,14 +244,14 @@ def _gen_thead(self, ctx, cls, parent, name): self.add_field_attrs(th_attrs, k, cls) if cls_attr.hidden: - self.add_style(th_attrs, 'display:None') + self.add_style(th_attrs, "display:None") header_name = self.trc(v, ctx.locale, k) parent.write(E.th(header_name, **th_attrs)) m = cls.Attributes.methods if m is not None and len(m) > 0: - th_attrs = {'class': 'mrpc-cell'} + th_attrs = {"class": "mrpc-cell"} parent.write(E.th(**th_attrs)) else: @@ -258,22 +275,22 @@ def _gen_table(self, ctx, cls, inst, parent, name, gen_rows, **kwargs): table_class.add(self.table_class) if self.table_name_attr is not None: - tn = (self.table_name - if self.table_name is not None else cls.get_type_name()) + tn = self.table_name if self.table_name is not None else cls.get_type_name() - if self.table_name_attr == 'class': + if self.table_name_attr == "class": table_class.add(tn) else: attrib[self.table_name_attr] = tn - attrib['class'] = ' '.join(table_class) + attrib["class"] = " ".join(table_class) if self.table_width is not None: - attrib['width'] = self.table_width + attrib["width"] = self.table_width - self.event_manager.fire_event('before_table', ctx, cls, inst, parent, - name, prot=self, **kwargs) + self.event_manager.fire_event( + "before_table", ctx, cls, inst, parent, name, prot=self, **kwargs + ) - with parent.element('table', attrib): + with parent.element("table", attrib): write_header = self.header if cls_attrs.header is False: write_header = cls_attrs.header @@ -283,17 +300,16 @@ def _gen_table(self, ctx, cls, inst, parent, name, gen_rows, **kwargs): subprot = self.get_subprot(ctx, cls_attrs) if subprot is not None: - ret = subprot.column_table_gen_header(ctx, cls, parent, - name) + ret = subprot.column_table_gen_header(ctx, cls, parent, name) if not ret: self._gen_thead(ctx, cls, parent, name) - with parent.element('tbody'): + with parent.element("tbody"): ret = gen_rows(ctx, cls, inst, parent, name, **kwargs) if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as b: try: @@ -303,19 +319,28 @@ def _gen_table(self, ctx, cls, inst, parent, name, gen_rows, **kwargs): self.extend_table(ctx, cls, parent, name, **kwargs) - def complex_model_to_parent(self, ctx, cls, inst, parent, name, - from_arr=False, **kwargs): + def complex_model_to_parent( + self, ctx, cls, inst, parent, name, from_arr=False, **kwargs + ): # If this is direct child of an array, table is already set up in # array_to_parent. if from_arr: return self._gen_row(ctx, cls, inst, parent, name, **kwargs) else: - return self.wrap_table(ctx, cls, inst, parent, name, self._gen_row, - **kwargs) + return self.wrap_table( + ctx, cls, inst, parent, name, self._gen_row, **kwargs + ) def array_to_parent(self, ctx, cls, inst, parent, name, **kwargs): - return self.wrap_table(ctx, cls, inst, parent, name, - super(HtmlColumnTable, self).array_to_parent, **kwargs) + return self.wrap_table( + ctx, + cls, + inst, + parent, + name, + super(HtmlColumnTable, self).array_to_parent, + **kwargs, + ) def wrap_table(self, ctx, cls, inst, parent, name, gen_rows, **kwargs): return self._gen_table(ctx, cls, inst, parent, name, gen_rows, **kwargs) diff --git a/spyne/protocol/html/table/row.py b/spyne/protocol/html/table/row.py index 5a33e1a0a..e00c07203 100644 --- a/spyne/protocol/html/table/row.py +++ b/spyne/protocol/html/table/row.py @@ -20,17 +20,17 @@ from __future__ import print_function import logging + logger = logging.getLogger(__name__) from inspect import isgenerator from lxml.html.builder import E -from spyne import ModelBase, ByteArray, ComplexModelBase, Array, AnyUri, \ - ImageUri -from spyne.util import coroutine, Break -from spyne.util.cdict import cdict +from spyne import AnyUri, Array, ByteArray, ComplexModelBase, ImageUri, ModelBase from spyne.protocol.html.table import HtmlTableBase +from spyne.util import Break, coroutine +from spyne.util.cdict import cdict class HtmlRowTable(HtmlTableBase): @@ -63,17 +63,20 @@ class HtmlRowTable(HtmlTableBase): def __init__(self, *args, **kwargs): super(HtmlRowTable, self).__init__(*args, **kwargs) - self.serialization_handlers = cdict({ - ModelBase: self.model_base_to_parent, - AnyUri: self.any_uri_to_parent, - ImageUri: self.imageuri_to_parent, - ByteArray: self.not_supported, - ComplexModelBase: self.complex_model_to_parent, - Array: self.array_to_parent, - }) - - def model_base_to_parent(self, ctx, cls, inst, parent, name, from_arr=False, - **kwargs): + self.serialization_handlers = cdict( + { + ModelBase: self.model_base_to_parent, + AnyUri: self.any_uri_to_parent, + ImageUri: self.imageuri_to_parent, + ByteArray: self.not_supported, + ComplexModelBase: self.complex_model_to_parent, + Array: self.array_to_parent, + } + ) + + def model_base_to_parent( + self, ctx, cls, inst, parent, name, from_arr=False, **kwargs + ): if from_arr: td_attrib = {} if False and self.field_name_attr: @@ -84,21 +87,23 @@ def model_base_to_parent(self, ctx, cls, inst, parent, name, from_arr=False, parent.write(self.to_unicode(cls, inst)) @coroutine - def complex_model_to_parent(self, ctx, cls, inst, parent, name, - from_arr=False, **kwargs): + def complex_model_to_parent( + self, ctx, cls, inst, parent, name, from_arr=False, **kwargs + ): attrib = {} if self.table_name_attr is not None: attrib[self.table_name_attr] = cls.get_type_name() if self.table_width is not None: - attrib['width'] = self.table_width + attrib["width"] = self.table_width - with parent.element('table', attrib): - with parent.element('tbody'): + with parent.element("table", attrib): + with parent.element("tbody"): for k, v in self.sort_fields(cls): sub_attrs = self.get_cls_attrs(v) if sub_attrs.exc: - logger.debug("\tExclude table cell %r type %r for %r", - k, v, cls) + logger.debug( + "\tExclude table cell %r type %r for %r", k, v, cls + ) continue try: sub_value = getattr(inst, k, None) @@ -111,43 +116,43 @@ def complex_model_to_parent(self, ctx, cls, inst, parent, name, tr_attrs = {} if self.row_class is not None: - self.add_html_attr('class', tr_attrs, self.row_class) + self.add_html_attr("class", tr_attrs, self.row_class) - with parent.element('tr', tr_attrs): + with parent.element("tr", tr_attrs): th_attrs = {} if self.header_cell_class is not None: - self.add_html_attr('class', th_attrs, - self.header_cell_class) + self.add_html_attr( + "class", th_attrs, self.header_cell_class + ) self.add_field_attrs(th_attrs, sub_name, v) if sub_attrs.hidden: - self.add_style(th_attrs, 'display:None') + self.add_style(th_attrs, "display:None") if self.header: - parent.write(E.th( - self.trc(v, ctx.locale, sub_name), - **th_attrs - )) + parent.write( + E.th(self.trc(v, ctx.locale, sub_name), **th_attrs) + ) td_attrs = {} if self.cell_class is not None: - self.add_html_attr('class', td_attrs, - self.cell_class) + self.add_html_attr("class", td_attrs, self.cell_class) self.add_field_attrs(td_attrs, sub_name, v) if sub_attrs.hidden: - self.add_style(td_attrs, 'display:None') + self.add_style(td_attrs, "display:None") - with parent.element('td', td_attrs): - ret = self.to_parent(ctx, v, sub_value, parent, - sub_name, **kwargs) + with parent.element("td", td_attrs): + ret = self.to_parent( + ctx, v, sub_value, parent, sub_name, **kwargs + ) if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as b: try: @@ -157,14 +162,15 @@ def complex_model_to_parent(self, ctx, cls, inst, parent, name, @coroutine def array_to_parent(self, ctx, cls, inst, parent, name, **kwargs): - with parent.element('div'): + with parent.element("div"): if issubclass(cls, ComplexModelBase): ret = super(HtmlRowTable, self).array_to_parent( - ctx, cls, inst, parent, name, **kwargs) + ctx, cls, inst, parent, name, **kwargs + ) if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as b: try: @@ -176,38 +182,38 @@ def array_to_parent(self, ctx, cls, inst, parent, name, **kwargs): if self.table_name_attr: table_attrib = {self.table_name_attr: name} if self.table_width is not None: - table_attrib['width'] = self.table_width + table_attrib["width"] = self.table_width - with parent.element('table', table_attrib): + with parent.element("table", table_attrib): tr_attrib = {} if self.row_class is not None: - tr_attrib['class'] = self.row_class - with parent.element('tr', tr_attrib): + tr_attrib["class"] = self.row_class + with parent.element("tr", tr_attrib): if self.header: - parent.write(E.th(self.trc(cls, ctx.locale, - cls.get_type_name()))) + parent.write( + E.th(self.trc(cls, ctx.locale, cls.get_type_name())) + ) td_attrs = {} if self.cell_class is not None: - self.add_html_attr('class', td_attrs, - self.cell_class) + self.add_html_attr("class", td_attrs, self.cell_class) self.add_field_attrs(td_attrs, name, cls) cls_attrs = self.get_cls_attrs(cls) if cls_attrs.hidden: - self.add_style(td_attrs, 'display:None') + self.add_style(td_attrs, "display:None") - with parent.element('td', td_attrs): - with parent.element('table'): - ret = super(HtmlRowTable, self) \ - .array_to_parent(ctx, cls, inst, parent, - name, **kwargs) + with parent.element("td", td_attrs): + with parent.element("table"): + ret = super(HtmlRowTable, self).array_to_parent( + ctx, cls, inst, parent, name, **kwargs + ) if isgenerator(ret): try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as b: try: diff --git a/spyne/protocol/http.py b/spyne/protocol/http.py index b351d8169..b05b79082 100644 --- a/spyne/protocol/http.py +++ b/spyne/protocol/http.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -27,20 +26,22 @@ from __future__ import print_function import logging + logger = logging.getLogger(__name__) import re -import pytz import tempfile +from io import BytesIO + +import pytz -from spyne import BODY_STYLE_WRAPPED, MethodDescriptor, PushBase -from spyne.util import six, coroutine, Break -from spyne.util.six import string_types, BytesIO +from spyne.descriptor import BODY_STYLE_WRAPPED, MethodDescriptor from spyne.error import ResourceNotFoundError +from spyne.model._base import PushBase from spyne.model.binary import BINARY_ENCODING_URLSAFE_BASE64, File from spyne.model.primitive import DateTime from spyne.protocol.dictdoc import SimpleDictDocument - +from spyne.util import Break, coroutine TEMPORARY_DIR = None STREAM_READ_BLOCK_SIZE = 0x4000 @@ -49,7 +50,7 @@ _OctalPatt = re.compile(r"\\[0-3][0-7][0-7]") _QuotePatt = re.compile(r"[\\].") -_nulljoin = ''.join +_nulljoin = "".join # this is twisted's _idnaBytes. it's not possible to import twisted at this @@ -92,7 +93,7 @@ def _unquote_cookie(str): while 0 <= i < n: o_match = _OctalPatt.search(str, i) q_match = _QuotePatt.search(str, i) - if not o_match and not q_match: # Neither matched + if not o_match and not q_match: # Neither matched res.append(str[i:]) break # else: @@ -101,13 +102,13 @@ def _unquote_cookie(str): j = o_match.start(0) if q_match: k = q_match.start(0) - if q_match and (not o_match or k < j): # QuotePatt matched + if q_match and (not o_match or k < j): # QuotePatt matched res.append(str[i:k]) - res.append(str[k+1]) + res.append(str[k + 1]) i = k + 2 - else: # OctalPatt matched + else: # OctalPatt matched res.append(str[i:j]) - res.append(chr(int(str[j+1:j+4], 8))) + res.append(chr(int(str[j + 1 : j + 4], 8))) i = j + 4 return _nulljoin(res) @@ -122,13 +123,13 @@ def _parse_cookie(cookie): retval = {} - for chunk in cookie.split(';'): - if '=' in chunk: - key, val = chunk.split('=', 1) + for chunk in cookie.split(";"): + if "=" in chunk: + key, val = chunk.split("=", 1) else: # Assume an empty name per # https://bugzilla.mozilla.org/show_bug.cgi?id=169091 - key, val = '', chunk + key, val = "", chunk key, val = key.strip(), val.strip() if key or val: @@ -139,16 +140,15 @@ def _parse_cookie(cookie): def get_stream_factory(dir=None, delete=True): - def stream_factory(total_content_length, filename, content_type, - content_length=None): - if total_content_length >= SWAP_DATA_TO_FILE_THRESHOLD or \ - delete == False: + def stream_factory( + total_content_length, filename, content_type, content_length=None + ): + if total_content_length >= SWAP_DATA_TO_FILE_THRESHOLD or delete == False: if delete == False: # You need python >= 2.6 for this. - retval = tempfile.NamedTemporaryFile('wb+', dir=dir, - delete=delete) + retval = tempfile.NamedTemporaryFile("wb+", dir=dir, delete=delete) else: - retval = tempfile.NamedTemporaryFile('wb+', dir=dir) + retval = tempfile.NamedTemporaryFile("wb+", dir=dir) else: retval = BytesIO() @@ -156,9 +156,24 @@ def stream_factory(total_content_length, filename, content_type, return stream_factory + _weekday = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] -_month = ['w00t', "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", - "Oct", "Nov", "Dec"] +_month = [ + "w00t", + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", +] + def _header_to_bytes(prot, val, cls): if issubclass(cls, DateTime): @@ -168,8 +183,14 @@ def _header_to_bytes(prot, val, cls): val = val.replace(tzinfo=pytz.utc) return "%s, %02d %s %04d %02d:%02d:%02d GMT" % ( - _weekday[val.weekday()], val.day, _month[val.month], - val.year, val.hour, val.minute, val.second) + _weekday[val.weekday()], + val.day, + _month[val.month], + val.year, + val.hour, + val.minute, + val.second, + ) else: # because wsgi_ref wants header values in unicode. return prot.to_unicode(cls, val) @@ -194,19 +215,33 @@ class HttpRpc(SimpleDictDocument): value. """ - mime_type = 'text/plain' + mime_type = "text/plain" default_binary_encoding = BINARY_ENCODING_URLSAFE_BASE64 - default_string_encoding = 'UTF-8' + default_string_encoding = "UTF-8" type = set(SimpleDictDocument.type) - type.add('http') - - def __init__(self, app=None, validator=None, mime_type=None, - tmp_dir=None, tmp_delete_on_close=True, ignore_uncap=False, - parse_cookie=True, hier_delim=".", strict_arrays=False): - super(HttpRpc, self).__init__(app, validator, mime_type, - ignore_uncap=ignore_uncap, hier_delim=hier_delim, - strict_arrays=strict_arrays) + type.add("http") + + def __init__( + self, + app=None, + validator=None, + mime_type=None, + tmp_dir=None, + tmp_delete_on_close=True, + ignore_uncap=False, + parse_cookie=True, + hier_delim=".", + strict_arrays=False, + ): + super(HttpRpc, self).__init__( + app, + validator, + mime_type, + ignore_uncap=ignore_uncap, + hier_delim=hier_delim, + strict_arrays=strict_arrays, + ) self.tmp_dir = tmp_dir self.tmp_delete_on_close = tmp_delete_on_close @@ -217,14 +252,14 @@ def get_tmp_delete_on_close(self): def set_tmp_delete_on_close(self, val): self.__tmp_delete_on_close = val - self.stream_factory = get_stream_factory(self.tmp_dir, - self.__tmp_delete_on_close) + self.stream_factory = get_stream_factory( + self.tmp_dir, self.__tmp_delete_on_close + ) - tmp_delete_on_close = property(get_tmp_delete_on_close, - set_tmp_delete_on_close) + tmp_delete_on_close = property(get_tmp_delete_on_close, set_tmp_delete_on_close) def set_validator(self, validator): - if validator == 'soft' or validator is self.SOFT_VALIDATION: + if validator == "soft" or validator is self.SOFT_VALIDATION: self.validator = self.SOFT_VALIDATION elif validator is None: self.validator = None @@ -232,9 +267,12 @@ def set_validator(self, validator): raise ValueError(validator) def create_in_document(self, ctx, in_string_encoding=None): - assert ctx.transport.type.endswith('http'), \ - ("This protocol only works with an http transport, not %r, (in %r)" - % (ctx.transport.type, ctx.transport)) + assert ctx.transport.type.endswith( + "http" + ), "This protocol only works with an http transport, not %r, (in %r)" % ( + ctx.transport.type, + ctx.transport, + ) ctx.in_document = ctx.transport.req ctx.transport.request_encoding = in_string_encoding @@ -242,13 +280,12 @@ def create_in_document(self, ctx, in_string_encoding=None): def decompose_incoming_envelope(self, ctx, message_type): assert message_type == SimpleDictDocument.REQUEST - ctx.transport.itself.decompose_incoming_envelope( - self, ctx, message_type) + ctx.transport.itself.decompose_incoming_envelope(self, ctx, message_type) if self.parse_cookie: - cookies = ctx.in_header_doc.get('cookie', None) + cookies = ctx.in_header_doc.get("cookie", None) if cookies is None: - cookies = ctx.in_header_doc.get('Cookie', None) + cookies = ctx.in_header_doc.get("Cookie", None) if cookies is not None: for cookie_string in cookies: @@ -259,32 +296,38 @@ def decompose_incoming_envelope(self, ctx, message_type): l.append(v) ctx.in_header_doc[k] = l - logger.debug('\theader : %r' % (ctx.in_header_doc)) - logger.debug('\tbody : %r' % (ctx.in_body_doc)) + logger.debug("\theader : %r" % (ctx.in_header_doc)) + logger.debug("\tbody : %r" % (ctx.in_body_doc)) def deserialize(self, ctx, message): assert message in (self.REQUEST,) - self.event_manager.fire_event('before_deserialize', ctx) + self.event_manager.fire_event("before_deserialize", ctx) if ctx.descriptor is None: raise ResourceNotFoundError(ctx.method_request_string) - req_enc = getattr(ctx.transport, 'request_encoding', None) + req_enc = getattr(ctx.transport, "request_encoding", None) if req_enc is None: req_enc = ctx.in_protocol.default_string_encoding if ctx.descriptor.in_header is not None: # HttpRpc supports only one header class in_header_class = ctx.descriptor.in_header[0] - ctx.in_header = self.simple_dict_to_object(ctx, ctx.in_header_doc, - in_header_class, self.validator, req_enc=req_enc) + ctx.in_header = self.simple_dict_to_object( + ctx, ctx.in_header_doc, in_header_class, self.validator, req_enc=req_enc + ) if ctx.descriptor.in_message is not None: - ctx.in_object = self.simple_dict_to_object(ctx, ctx.in_body_doc, - ctx.descriptor.in_message, self.validator, req_enc=req_enc) + ctx.in_object = self.simple_dict_to_object( + ctx, + ctx.in_body_doc, + ctx.descriptor.in_message, + self.validator, + req_enc=req_enc, + ) - self.event_manager.fire_event('after_deserialize', ctx) + self.event_manager.fire_event("after_deserialize", ctx) def serialize(self, ctx, message): retval = None @@ -295,13 +338,13 @@ def serialize(self, ctx, message): return if ctx.out_error is not None: - ctx.transport.mime_type = 'text/plain' + ctx.transport.mime_type = "text/plain" ctx.out_document = ctx.out_error.to_bytes_iterable(ctx.out_error) else: retval = self._handle_rpc(ctx) - self.event_manager.fire_event('serialize', ctx) + self.event_manager.fire_event("serialize", ctx) return retval @@ -316,21 +359,25 @@ def _handle_rpc_nonempty(self, ctx): fti = result_class.get_flat_type_info(result_class) if len(fti) > 1 and not self.ignore_uncap: - raise TypeError("HttpRpc protocol can only serialize " - "functions with a single return type.") + raise TypeError( + "HttpRpc protocol can only serialize " + "functions with a single return type." + ) if len(fti) == 1: - out_class, = fti.values() - out_object, = ctx.out_object + (out_class,) = fti.values() + (out_object,) = ctx.out_object else: out_class = result_class - out_object, = ctx.out_object + (out_object,) = ctx.out_object if out_class is not None: - if issubclass(out_class, File) and not \ - isinstance(out_object, (list, tuple, string_types)) \ - and out_object.type is not None: + if ( + issubclass(out_class, File) + and not isinstance(out_object, (list, tuple, str)) + and out_object.type is not None + ): ctx.transport.set_mime_type(str(out_object.type)) ret = self.to_bytes_iterable(out_class, out_object) @@ -349,7 +396,7 @@ def _handle_rpc(self, ctx): # assign raw result to its wrapper, result_message if ctx.out_object is None or len(ctx.out_object) < 1: - ctx.out_document = [''] + ctx.out_document = [""] else: retval = self._handle_rpc_nonempty(ctx) @@ -365,33 +412,34 @@ def _handle_rpc(self, ctx): if isinstance(ctx.out_header, (list, tuple)): out_header = ctx.out_header[0] - ctx.out_header_doc = self.object_to_simple_dict(header_class, - out_header, subinst_eater=_header_to_bytes) + ctx.out_header_doc = self.object_to_simple_dict( + header_class, out_header, subinst_eater=_header_to_bytes + ) return retval - def create_out_string(self, ctx, out_string_encoding='utf8'): + def create_out_string(self, ctx, out_string_encoding="utf8"): if ctx.out_string is not None: return ctx.out_string = ctx.out_document def boolean_from_bytes(self, cls, string): - return string.lower() in ('true', '1', 'checked', 'on') + return string.lower() in ("true", "1", "checked", "on") def integer_from_bytes(self, cls, string): - if string == '': + if string == "": return None return super(HttpRpc, self).integer_from_bytes(cls, string) -_fragment_pattern_re = re.compile('<([A-Za-z0-9_]+)>') -_full_pattern_re = re.compile('{([A-Za-z0-9_]+)}') +_fragment_pattern_re = re.compile("<([A-Za-z0-9_]+)>") +_full_pattern_re = re.compile("{([A-Za-z0-9_]+)}") -_fragment_pattern_b_re = re.compile(b'<([A-Za-z0-9_]+)>') -_full_pattern_b_re = re.compile(b'{([A-Za-z0-9_]+)}') +_fragment_pattern_b_re = re.compile(b"<([A-Za-z0-9_]+)>") +_full_pattern_b_re = re.compile(b"{([A-Za-z0-9_]+)}") class HttpPattern(object): @@ -402,9 +450,9 @@ class HttpPattern(object): :param host: HTTP "Host:" header pattern """ - URL_ENCODING = 'utf8' - HOST_ENCODING = 'idna' - VERB_ENCODING = 'latin1' # actually ascii but latin1 is what pep 333 needs + URL_ENCODING = "utf8" + HOST_ENCODING = "idna" + VERB_ENCODING = "latin1" # actually ascii but latin1 is what pep 333 needs @classmethod def _compile_url_pattern(cls, pattern_s): @@ -413,14 +461,13 @@ def _compile_url_pattern(cls, pattern_s): if pattern_s is None: return None, None - if not six.PY2: - assert isinstance(pattern_s, six.text_type) - pattern = _fragment_pattern_re.sub(r'(?P<\1>[^/]*)', pattern_s) - pattern = _full_pattern_re.sub(r'(?P<\1>[^/]*)', pattern) + assert isinstance(pattern_s, str) + pattern = _fragment_pattern_re.sub(r"(?P<\1>[^/]*)", pattern_s) + pattern = _full_pattern_re.sub(r"(?P<\1>[^/]*)", pattern) pattern_b = pattern_s.encode(cls.URL_ENCODING) - pattern_b = _fragment_pattern_b_re.sub(b'(?P<\\1>[^/]*)', pattern_b) - pattern_b = _full_pattern_b_re.sub(b'(?P<\\1>[^/]*)', pattern_b) + pattern_b = _fragment_pattern_b_re.sub(b"(?P<\\1>[^/]*)", pattern_b) + pattern_b = _full_pattern_b_re.sub(b"(?P<\\1>[^/]*)", pattern_b) return re.compile(pattern), re.compile(pattern_b) @@ -431,12 +478,12 @@ def _compile_host_pattern(cls, pattern): if pattern is None: return None, None - pattern = _fragment_pattern_re.sub(r'(?P<\1>[^\.]*)', pattern) - pattern = _full_pattern_re.sub(r'(?P<\1>.*)', pattern) + pattern = _fragment_pattern_re.sub(r"(?P<\1>[^\.]*)", pattern) + pattern = _full_pattern_re.sub(r"(?P<\1>.*)", pattern) pattern_b = pattern.encode(cls.HOST_ENCODING) - pattern_b = _fragment_pattern_b_re.sub(b'(?P<\\1>[^\.]*)', pattern_b) - pattern_b = _full_pattern_b_re.sub(b'(?P<\\1>.*)', pattern_b) + pattern_b = _fragment_pattern_b_re.sub(rb"(?P<\1>[^.]*)", pattern_b) + pattern_b = _full_pattern_b_re.sub(b"(?P<\\1>.*)", pattern_b) return re.compile(pattern), re.compile(pattern_b) @@ -447,12 +494,12 @@ def _compile_verb_pattern(cls, pattern): if pattern is None: return None, None - pattern = _fragment_pattern_re.sub(r'(?P<\1>.*)', pattern) - pattern = _full_pattern_re.sub(r'(?P<\1>.*)', pattern) + pattern = _fragment_pattern_re.sub(r"(?P<\1>.*)", pattern) + pattern = _full_pattern_re.sub(r"(?P<\1>.*)", pattern) pattern_b = pattern.encode(cls.VERB_ENCODING) - pattern_b = _fragment_pattern_b_re.sub(b'(?P<\\1>.*)', pattern_b) - pattern_b = _full_pattern_b_re.sub(b'(?P<\\1>.*)', pattern_b) + pattern_b = _fragment_pattern_b_re.sub(b"(?P<\\1>.*)", pattern_b) + pattern_b = _full_pattern_b_re.sub(b"(?P<\\1>.*)", pattern_b) return re.compile(pattern), re.compile(pattern_b) @@ -477,8 +524,8 @@ def address(self): @address.setter def address(self, what): - if what is not None and not what.startswith('/'): - what = '/{}'.format(what) + if what is not None and not what.startswith("/"): + what = "/{}".format(what) self.__address = what self.address_re, self.address_b_re = self._compile_url_pattern(what) @@ -503,6 +550,7 @@ def verb(self, what): def as_werkzeug_rule(self): from werkzeug.routing import Rule + from spyne.util.invregexp import invregexp methods = None @@ -511,13 +559,17 @@ def as_werkzeug_rule(self): host = self.host if host is None: - host = '<__ignored>' # for some reason, this is necessary when - # host_matching is enabled. + host = "<__ignored>" # for some reason, this is necessary when + # host_matching is enabled. - return Rule(self.address, host=host, endpoint=self.endpoint.name, - methods=methods) + return Rule( + self.address, host=host, endpoint=self.endpoint.name, methods=methods + ) def __repr__(self): return "HttpPattern(address=%r, host=%r, verb=%r, endpoint=%r)" % ( - self.address, self.host, self.verb, - None if self.endpoint is None else self.endpoint.name) + self.address, + self.host, + self.verb, + None if self.endpoint is None else self.endpoint.name, + ) diff --git a/spyne/protocol/json.py b/spyne/protocol/json.py index 16acb11f3..28d08cc94 100644 --- a/spyne/protocol/json.py +++ b/spyne/protocol/json.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -27,17 +26,17 @@ The JSON standard does not define every type that Spyne supports. These include Date/Time types as well as arbitrary-length integers and arbitrary-precision -decimals. Integers are parsed to ``int``\s or ``long``\s seamlessly but -``Decimal``\s are only parsed correctly when they come off as strings. +decimals. Integers are parsed to ``int``\\s or ``long``\\s seamlessly but +``Decimal``\\s are only parsed correctly when they come off as strings. -While it's possible to e.g. (de)serialize floats to ``Decimal``\s by adding +While it's possible to e.g. (de)serialize floats to ``Decimal``\\s by adding hooks to ``parse_float`` [#]_ (and convert later as necessary), such customizations apply to the whole incoming document which pretty much messes up ``AnyDict`` serialization and deserialization. It also wasn't possible to work with ``object_pairs_hook`` as Spyne's parsing is always "from outside to inside" whereas ``object_pairs_hook`` is passed -``dict``\s basically in any order "from inside to outside". +``dict``\\s basically in any order "from inside to outside". .. [#] http://docs.python.org/2/library/json.html#json.loads """ @@ -45,30 +44,23 @@ from __future__ import absolute_import import logging + logger = logging.getLogger(__name__) from itertools import chain -from spyne.util import six - try: import simplejson as json from simplejson.decoder import JSONDecodeError except ImportError: import json - JSONDecodeError = ValueError -from spyne.error import ValidationError -from spyne.error import ResourceNotFoundError + JSONDecodeError = ValueError +from spyne.error import ResourceNotFoundError, ValidationError from spyne.model.binary import BINARY_ENCODING_BASE64 -from spyne.model.primitive import Date -from spyne.model.primitive import Time -from spyne.model.primitive import DateTime -from spyne.model.primitive import Double -from spyne.model.primitive import Integer -from spyne.model.primitive import Boolean from spyne.model.fault import Fault +from spyne.model.primitive import Boolean, Date, DateTime, Double, Integer, Time from spyne.protocol.dictdoc import HierDictDocument @@ -86,7 +78,7 @@ def default(self, o): return list(o) -NON_NUMBER_TYPES = tuple({list, dict, six.text_type, six.binary_type}) +NON_NUMBER_TYPES = tuple({list, dict, str, bytes}) class JsonDocument(HierDictDocument): @@ -98,30 +90,46 @@ class JsonDocument(HierDictDocument): serialized to a list of values instead of a dict of key/value pairs. """ - mime_type = 'application/json' + mime_type = "application/json" text_based = True type = set(HierDictDocument.type) - type.add('json') + type.add("json") default_binary_encoding = BINARY_ENCODING_BASE64 # flags used just for tests _decimal_as_string = True - def __init__(self, app=None, validator=None, mime_type=None, - ignore_uncap=False, - # DictDocument specific - ignore_wrappers=True, complex_as=dict, ordered=False, - default_string_encoding=None, polymorphic=False, - **kwargs): - - super(JsonDocument, self).__init__(app, validator, mime_type, ignore_uncap, - ignore_wrappers, complex_as, ordered, polymorphic) + def __init__( + self, + app=None, + validator=None, + mime_type=None, + ignore_uncap=False, + # DictDocument specific + ignore_wrappers=True, + complex_as=dict, + ordered=False, + default_string_encoding=None, + polymorphic=False, + **kwargs, + ): + + super(JsonDocument, self).__init__( + app, + validator, + mime_type, + ignore_uncap, + ignore_wrappers, + complex_as, + ordered, + polymorphic, + ) # this is needed when we're overriding a regular instance attribute # with a property. - self.__message = HierDictDocument.__getattribute__(self, 'message') + self.__message = HierDictDocument.__getattribute__(self, "message") self._from_unicode_handlers[Double] = self._ret_number self._from_unicode_handlers[Boolean] = self._ret_bool @@ -153,8 +161,8 @@ def validate(self, key, cls, val): super(JsonDocument, self).validate(key, cls, val) if issubclass(cls, (DateTime, Date, Time)) and not ( - isinstance(val, six.string_types) and - cls.validate_string(cls, val)): + isinstance(val, str) and cls.validate_string(cls, val) + ): raise ValidationError(key, val) @property @@ -163,16 +171,16 @@ def message(self): @message.setter def message(self, val): - if val is self.RESPONSE and not ('cls' in self.kwargs): - self.kwargs['cls'] = JsonEncoder + if val is self.RESPONSE and not ("cls" in self.kwargs): + self.kwargs["cls"] = JsonEncoder self.__message = val def create_in_document(self, ctx, in_string_encoding=None): """Sets ``ctx.in_document`` using ``ctx.in_string``.""" try: - in_string = b''.join(ctx.in_string) - if not isinstance(in_string, six.text_type): + in_string = b"".join(ctx.in_string) + if not isinstance(in_string, str): if in_string_encoding is None: in_string_encoding = self.default_string_encoding if in_string_encoding is not None: @@ -180,17 +188,17 @@ def create_in_document(self, ctx, in_string_encoding=None): ctx.in_document = json.loads(in_string, **self.kwargs) except JSONDecodeError as e: - raise Fault('Client.JsonDecodeError', repr(e)) + raise Fault("Client.JsonDecodeError", repr(e)) - def create_out_string(self, ctx, out_string_encoding='utf8'): + def create_out_string(self, ctx, out_string_encoding="utf8"): """Sets ``ctx.out_string`` using ``ctx.out_document``.""" if out_string_encoding is None: - ctx.out_string = (json.dumps(o, **self.kwargs) - for o in ctx.out_document) + ctx.out_string = (json.dumps(o, **self.kwargs) for o in ctx.out_document) else: ctx.out_string = ( json.dumps(o, **self.kwargs).encode(out_string_encoding) - for o in ctx.out_document) + for o in ctx.out_document + ) # Continuation of http://stackoverflow.com/a/24184379/1520211 @@ -227,12 +235,11 @@ class HybridHttpJsonDocument(JsonDocument): def create_in_document(self, ctx, in_string_encoding=None): super(HybridHttpJsonDocument, self).create_in_document(ctx) - url_fragment = ctx.transport.get_path().split('/')[-1] + url_fragment = ctx.transport.get_path().split("/")[-1] ctx.in_document = {url_fragment: ctx.in_document} - class JsonP(JsonDocument): """The JsonP protocol puts the reponse document inside a designated javascript function call. The input protocol is identical to the @@ -245,36 +252,37 @@ class JsonP(JsonDocument): """ type = set(HierDictDocument.type) - type.add('jsonp') + type.add("jsonp") def __init__(self, callback_name, *args, **kwargs): super(JsonP, self).__init__(*args, **kwargs) self.callback_name = callback_name - def create_out_string(self, ctx, out_string_encoding='utf8'): - super(JsonP, self).create_out_string(ctx, - out_string_encoding=out_string_encoding) + def create_out_string(self, ctx, out_string_encoding="utf8"): + super(JsonP, self).create_out_string( + ctx, out_string_encoding=out_string_encoding + ) if out_string_encoding is None: ctx.out_string = chain( - (self.callback_name, '('), - ctx.out_string, - (');',), - ) + (self.callback_name, "("), + ctx.out_string, + (");",), + ) else: ctx.out_string = chain( - [self.callback_name.encode(out_string_encoding), b'('], - ctx.out_string, - [b');'], - ) + [self.callback_name.encode(out_string_encoding), b"("], + ctx.out_string, + [b");"], + ) class _SpyneJsonRpc1(JsonDocument): version = 1 - VERSION = 'ver' - BODY = 'body' - HEAD = 'head' - FAULT = 'fault' + VERSION = "ver" + BODY = "body" + HEAD = "head" + FAULT = "fault" def decompose_incoming_envelope(self, ctx, message=JsonDocument.REQUEST): indoc = ctx.in_document @@ -304,12 +312,12 @@ def decompose_incoming_envelope(self, ctx, message=JsonDocument.REQUEST): if not isinstance(ctx.in_header_doc, list): ctx.in_header_doc = [ctx.in_header_doc] - (ctx.method_request_string,ctx.in_body_doc), = body.items() + ((ctx.method_request_string, ctx.in_body_doc),) = body.items() def deserialize(self, ctx, message): assert message in (self.REQUEST, self.RESPONSE) - self.event_manager.fire_event('before_deserialize', ctx) + self.event_manager.fire_event("before_deserialize", ctx) if ctx.descriptor is None: raise ResourceNotFoundError(ctx.method_request_string) @@ -328,13 +336,13 @@ def deserialize(self, ctx, message): body_class = ctx.descriptor.out_message # decode header objects - if (ctx.in_header_doc is not None and header_class is not None): + if ctx.in_header_doc is not None and header_class is not None: headers = [None] * len(header_class) for i, (header_doc, head_class) in enumerate( - zip(ctx.in_header_doc, header_class)): + zip(ctx.in_header_doc, header_class) + ): if header_doc is not None and i < len(header_doc): - headers[i] = self._doc_to_object(ctx, head_class, - header_doc) + headers[i] = self._doc_to_object(ctx, head_class, header_doc) if len(headers) == 1: ctx.in_header = headers[0] @@ -344,22 +352,20 @@ def deserialize(self, ctx, message): if ctx.in_body_doc is None: ctx.in_object = [None] * len(body_class._type_info) else: - ctx.in_object = self._doc_to_object(ctx, body_class, - ctx.in_body_doc) + ctx.in_object = self._doc_to_object(ctx, body_class, ctx.in_body_doc) - self.event_manager.fire_event('after_deserialize', ctx) + self.event_manager.fire_event("after_deserialize", ctx) def serialize(self, ctx, message): assert message in (self.REQUEST, self.RESPONSE) - self.event_manager.fire_event('before_serialize', ctx) + self.event_manager.fire_event("before_serialize", ctx) ctx.out_document = { "ver": self.version, } if ctx.out_error is not None: - ctx.out_document[self.FAULT] = Fault.to_dict(Fault, - ctx.out_error, self) + ctx.out_document[self.FAULT] = Fault.to_dict(Fault, ctx.out_error, self) else: if message is self.REQUEST: @@ -389,8 +395,9 @@ def serialize(self, ctx, message): out_object._safe_set(k, v, body_message_class, bm_attrs) - ctx.out_document[self.BODY] = ctx.out_body_doc = \ - self._object_to_doc(body_message_class, out_object) + ctx.out_document[self.BODY] = ctx.out_body_doc = self._object_to_doc( + body_message_class, out_object + ) # header if ctx.out_header is not None and header_message_class is not None: @@ -401,25 +408,23 @@ def serialize(self, ctx, message): ctx.out_header_doc = out_header_doc = [] - for header_class, out_header in zip(header_message_class, - out_headers): - out_header_doc.append(self._object_to_doc(header_class, - out_header)) + for header_class, out_header in zip(header_message_class, out_headers): + out_header_doc.append(self._object_to_doc(header_class, out_header)) if len(out_header_doc) > 1: ctx.out_document[self.HEAD] = out_header_doc else: ctx.out_document[self.HEAD] = out_header_doc[0] - self.event_manager.fire_event('after_serialize', ctx) + self.event_manager.fire_event("after_serialize", ctx) + +_json_rpc_flavors = {"spyne": _SpyneJsonRpc1} -_json_rpc_flavors = { - 'spyne': _SpyneJsonRpc1 -} def JsonRpc(flavour, *args, **kwargs): - assert flavour in _json_rpc_flavors, "Unknown JsonRpc flavor. " \ - "Accepted ones are: %r" % tuple(_json_rpc_flavors) + assert ( + flavour in _json_rpc_flavors + ), "Unknown JsonRpc flavor. " "Accepted ones are: %r" % tuple(_json_rpc_flavors) return _json_rpc_flavors[flavour](*args, **kwargs) diff --git a/spyne/protocol/msgpack.py b/spyne/protocol/msgpack.py index d30d59f22..aead93ed6 100644 --- a/spyne/protocol/msgpack.py +++ b/spyne/protocol/msgpack.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -27,16 +26,23 @@ from __future__ import absolute_import import logging + logger = logging.getLogger(__name__) import msgpack -from spyne import ValidationError -from spyne.util import six -from spyne.model.fault import Fault -from spyne.model.primitive import Double -from spyne.model.primitive import Boolean -from spyne.model.primitive import Integer +from spyne.model.enum import EnumBase +from spyne.model.fault import Fault, ValidationError +from spyne.model.primitive import ( + Boolean, + Date, + DateTime, + Double, + Duration, + Integer, + Time, + Unicode, +) from spyne.protocol.dictdoc import HierDictDocument @@ -44,23 +50,22 @@ class MessagePackDecodeError(Fault): CODE = "Client.MessagePackDecodeError" def __init__(self, data=None): - super(MessagePackDecodeError, self) \ - .__init__(self.CODE, data) + super(MessagePackDecodeError, self).__init__(self.CODE, data) -NON_NUMBER_TYPES = tuple({list, dict, six.text_type, six.binary_type}) +NON_NUMBER_TYPES = tuple({list, dict, str, bytes}) class MessagePackDocument(HierDictDocument): """An integration class for the msgpack protocol.""" - mime_type = 'application/x-msgpack' + mime_type = "application/x-msgpack" text_based = False type = set(HierDictDocument.type) - type.add('msgpack') + type.add("msgpack") - default_string_encoding = 'UTF-8' + default_string_encoding = "UTF-8" from_serstr = HierDictDocument.from_bytes to_serstr = HierDictDocument.to_bytes @@ -68,41 +73,62 @@ class MessagePackDocument(HierDictDocument): _decimal_as_string = True _huge_numbers_as_string = True - def __init__(self, app=None, validator=None, mime_type=None, - ignore_uncap=False, - # DictDocument specific - ignore_wrappers=True, - complex_as=dict, - ordered=False, - polymorphic=False, - key_encoding='utf8', - # MessagePackDocument specific - mw_packer=msgpack.Packer, - mw_unpacker=msgpack.Unpacker, - use_list=False, - raw=False, - use_bin_type=True, - **kwargs): - super(MessagePackDocument, self).__init__(app, validator, mime_type, - ignore_uncap, ignore_wrappers, complex_as, ordered, polymorphic, - key_encoding) + def __init__( + self, + app=None, + validator=None, + mime_type=None, + ignore_uncap=False, + # DictDocument specific + ignore_wrappers=True, + complex_as=dict, + ordered=False, + polymorphic=False, + key_encoding="utf8", + # MessagePackDocument specific + mw_packer=msgpack.Packer, + mw_unpacker=msgpack.Unpacker, + use_list=False, + raw=False, + use_bin_type=True, + **kwargs, + ): + super(MessagePackDocument, self).__init__( + app, + validator, + mime_type, + ignore_uncap, + ignore_wrappers, + complex_as, + ordered, + polymorphic, + key_encoding, + ) self.mw_packer = mw_packer self.mw_unpacker = mw_unpacker - # unpacker + # unpacker / packer string handling if not raw: self.from_serstr = self.from_unicode if use_bin_type: self.from_serstr = self.from_unicode + # with use_bin_type=True, bytes are binary; text types must stay as + # Python str so msgpack encodes them as str type (fixstr/str8) + self._to_bytes_handlers[Unicode] = self.unicode_to_unicode + self._to_unicode_handlers[Unicode] = self.unicode_to_unicode + self._to_bytes_handlers[Date] = self.date_to_unicode + self._to_bytes_handlers[DateTime] = self.datetime_to_unicode + self._to_bytes_handlers[Time] = self.time_to_unicode + self._to_bytes_handlers[Duration] = self.duration_to_unicode + self._to_bytes_handlers[EnumBase] = self.model_base_to_unicode self.kwargs_packer = dict(kwargs) self.kwargs_unpacker = dict(kwargs) - self.kwargs_packer['raw'] = self.kwargs_unpacker['raw'] = raw - self.kwargs_packer['use_list'] = self.kwargs_unpacker['use_list'] \ - = use_list - self.kwargs_packer['use_bin_type'] = use_bin_type + self.kwargs_packer["raw"] = self.kwargs_unpacker["raw"] = raw + self.kwargs_packer["use_list"] = self.kwargs_unpacker["use_list"] = use_list + self.kwargs_packer["use_bin_type"] = use_bin_type self._from_bytes_handlers[Double] = self._ret_number self._from_bytes_handlers[Boolean] = self._ret_bool @@ -137,10 +163,12 @@ def _ret_bool(self, _, value): def get_class_name(self, cls): class_name = cls.get_type_name() - if not six.PY2: + if self.kwargs_unpacker.get("raw", False): if not isinstance(class_name, bytes): class_name = class_name.encode(self.default_string_encoding) - + else: + if isinstance(class_name, bytes): + class_name = class_name.decode("utf8") return class_name def create_in_document(self, ctx, in_string_encoding=None): @@ -153,18 +181,20 @@ def create_in_document(self, ctx, in_string_encoding=None): # handle mmap objects from in ctx.in_string as returned by # TwistedWebResource.handle_rpc. - if isinstance(ctx.in_string, (list, tuple)) \ - and len(ctx.in_string) == 1 \ - and isinstance(ctx.in_string[0], memoryview): + if ( + isinstance(ctx.in_string, (list, tuple)) + and len(ctx.in_string) == 1 + and isinstance(ctx.in_string[0], memoryview) + ): unpacker = self.mw_unpacker(**self.kwargs_unpacker) unpacker.feed(ctx.in_string[0]) ctx.in_document = next(x for x in unpacker) else: try: - ctx.in_document = msgpack.unpackb(b''.join(ctx.in_string)) + ctx.in_document = msgpack.unpackb(b"".join(ctx.in_string)) except ValueError as e: - raise MessagePackDecodeError(' '.join(e.args)) + raise MessagePackDecodeError(" ".join(e.args)) def gen_method_request_string(self, ctx): """Uses information in context object to return a method_request_string. @@ -172,24 +202,23 @@ def gen_method_request_string(self, ctx): Returns a string in the form of "{namespaces}method name". """ - mrs, = ctx.in_body_doc.keys() - if not six.PY2 and isinstance(mrs, bytes): + (mrs,) = ctx.in_body_doc.keys() + if isinstance(mrs, bytes): mrs = mrs.decode(self.key_encoding) - return '{%s}%s' % (self.app.interface.get_tns(), mrs) + return "{%s}%s" % (self.app.interface.get_tns(), mrs) - def create_out_string(self, ctx, out_string_encoding='utf8'): + def create_out_string(self, ctx, out_string_encoding="utf8"): ctx.out_string = (msgpack.packb(o) for o in ctx.out_document) def integer_from_bytes(self, cls, value): - if isinstance(value, (six.text_type, six.binary_type)): - return super(MessagePackDocument, self) \ - .integer_from_bytes(cls, value) + if isinstance(value, (str, bytes)): + return super(MessagePackDocument, self).integer_from_bytes(cls, value) return value def integer_to_bytes(self, cls, value, **_): # if it's inside the range msgpack can deal with - if -1<<63 <= value < 1<<64: + if -1 << 63 <= value < 1 << 64: return value else: return super(MessagePackDocument, self).integer_to_bytes(cls, value) @@ -198,14 +227,14 @@ def integer_to_bytes(self, cls, value, **_): class MessagePackRpc(MessagePackDocument): """An integration class for the msgpack-rpc protocol.""" - mime_type = 'application/x-msgpack' + mime_type = "application/x-msgpack" MSGPACK_REQUEST = 0 MSGPACK_RESPONSE = 1 MSGPACK_NOTIFY = 2 MSGPACK_ERROR = 3 - def create_out_string(self, ctx, out_string_encoding='utf8'): + def create_out_string(self, ctx, out_string_encoding="utf8"): ctx.out_string = (msgpack.packb(o) for o in ctx.out_document) def create_in_document(self, ctx, in_string_encoding=None): @@ -218,12 +247,12 @@ def create_in_document(self, ctx, in_string_encoding=None): # TODO: Use feed api try: - ctx.in_document = msgpack.unpackb(b''.join(ctx.in_string), - **self.kwargs_unpacker) - + ctx.in_document = msgpack.unpackb( + b"".join(ctx.in_string), **self.kwargs_unpacker + ) except ValueError as e: - raise MessagePackDecodeError(''.join(e.args)) + raise MessagePackDecodeError("".join(e.args)) try: len(ctx.in_document) @@ -231,8 +260,9 @@ def create_in_document(self, ctx, in_string_encoding=None): raise MessagePackDecodeError("Input must be a sequence.") if not (3 <= len(ctx.in_document) <= 4): - raise MessagePackDecodeError("Length of input iterable must be " - "either 3 or 4") + raise MessagePackDecodeError( + "Length of input iterable must be " "either 3 or 4" + ) def decompose_incoming_envelope(self, ctx, message): # FIXME: For example: {0: 0, 1: 0, 2: "some_call", 3: [1,2,3]} will also @@ -246,10 +276,8 @@ def decompose_incoming_envelope(self, ctx, message): else: msgtype, msgid, msgname_or_error, msgparams = ctx.in_document - if not six.PY2: - if isinstance(msgname_or_error, bytes): - msgname_or_error = msgname_or_error.decode( - self.default_string_encoding) + if isinstance(msgname_or_error, bytes): + msgname_or_error = msgname_or_error.decode(self.default_string_encoding) if msgtype == MessagePackRpc.MSGPACK_REQUEST: assert message == MessagePackRpc.REQUEST @@ -260,11 +288,16 @@ def decompose_incoming_envelope(self, ctx, message): elif msgtype == MessagePackRpc.MSGPACK_NOTIFY: raise NotImplementedError() + elif msgtype == MessagePackRpc.MSGPACK_ERROR: + assert message == MessagePackRpc.RESPONSE + else: raise MessagePackDecodeError("Unknown message type %r" % msgtype) - ctx.method_request_string = '{%s}%s' % (self.app.interface.get_tns(), - msgname_or_error) + ctx.method_request_string = "{%s}%s" % ( + self.app.interface.get_tns(), + msgname_or_error, + ) # MessagePackRpc does not seem to have Header support ctx.in_header_doc = None @@ -281,11 +314,10 @@ def decompose_incoming_envelope(self, ctx, message): def deserialize(self, ctx, message): assert message in (self.REQUEST, self.RESPONSE) - self.event_manager.fire_event('before_deserialize', ctx) + self.event_manager.fire_event("before_deserialize", ctx) if ctx.descriptor is None: - raise Fault("Client", "Method %r not found." % - ctx.method_request_string) + raise Fault("Client", "Method %r not found." % ctx.method_request_string) # instantiate the result message if message is self.REQUEST: @@ -299,23 +331,27 @@ def deserialize(self, ctx, message): ctx.in_error = Fault(**ctx.in_error) elif body_class: - ctx.in_object = self._doc_to_object(ctx, - body_class, ctx.in_body_doc, self.validator) + ctx.in_object = self._doc_to_object( + ctx, body_class, ctx.in_body_doc, self.validator + ) else: ctx.in_object = [] - self.event_manager.fire_event('after_deserialize', ctx) + self.event_manager.fire_event("after_deserialize", ctx) def serialize(self, ctx, message): assert message in (self.REQUEST, self.RESPONSE) - self.event_manager.fire_event('before_serialize', ctx) + self.event_manager.fire_event("before_serialize", ctx) if ctx.out_error is not None: ctx.out_document = [ - [MessagePackRpc.MSGPACK_ERROR, 0, - Fault.to_dict(ctx.out_error.__class__, ctx.out_error, self)] + [ + MessagePackRpc.MSGPACK_ERROR, + 0, + Fault.to_dict(ctx.out_error.__class__, ctx.out_error, self), + ] ] return @@ -348,11 +384,12 @@ def serialize(self, ctx, message): # transform the results into a dict: if out_type.Attributes.max_occurs > 1: - params = (self._to_dict_value(out_type, inst, set()) - for inst in out_instance) + params = ( + self._to_dict_value(out_type, inst, set()) for inst in out_instance + ) else: params = self._to_dict_value(out_type, out_instance, set()) ctx.out_document = [[msgtype, 0, method_name_or_error, params]] - self.event_manager.fire_event('after_serialize', ctx) + self.event_manager.fire_event("after_serialize", ctx) diff --git a/spyne/protocol/soap/__init__.py b/spyne/protocol/soap/__init__.py index 754461f3e..0cd166cb4 100644 --- a/spyne/protocol/soap/__init__.py +++ b/spyne/protocol/soap/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -24,7 +23,5 @@ Patches are welcome. """ -from spyne.protocol.soap.soap11 import Soap11 -from spyne.protocol.soap.soap11 import _from_soap -from spyne.protocol.soap.soap11 import _parse_xml_string -from spyne.protocol.soap.soap12 import Soap12 \ No newline at end of file +from spyne.protocol.soap.soap11 import Soap11, _from_soap, _parse_xml_string +from spyne.protocol.soap.soap12 import Soap12 diff --git a/spyne/protocol/soap/mime.py b/spyne/protocol/soap/mime.py index 90b536020..abd7bbd84 100644 --- a/spyne/protocol/soap/mime.py +++ b/spyne/protocol/soap/mime.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -29,30 +28,22 @@ from __future__ import print_function, unicode_literals import logging + logger = logging.getLogger(__name__) import re - from base64 import b64encode +from email import generator, message_from_bytes +from email.encoders import encode_7or8bit +from email.mime.application import MIMEApplication +from email.mime.multipart import MIMEMultipart from itertools import chain from lxml import etree -from email import generator -from email.mime.multipart import MIMEMultipart -from email.mime.application import MIMEApplication -from email.encoders import encode_7or8bit - -from spyne import ValidationError -from spyne.util import six -from spyne.model.binary import ByteArray, File from spyne.const.xml import NS_XOP - -if six.PY2: - from email import message_from_string as message_from_bytes -else: - from email import message_from_bytes - +from spyne.model.binary import ByteArray, File +from spyne.model.fault import ValidationError XPATH_NSDICT = dict(xop=NS_XOP) @@ -84,14 +75,17 @@ def _join_attachment(ns_soap_env, href_id, envelope, payload, prefix=True): message = child break - idprefix = '' + idprefix = "" if prefix: idprefix = "cid:" - href_id = "%s%s" % (idprefix, href_id,) + href_id = "%s%s" % ( + idprefix, + href_id, + ) num = 0 - xpath = ".//xop:Include[@href=\"{}\"]".format(href_id) + xpath = './/xop:Include[@href="{}"]'.format(href_id) for num, node in enumerate(message.xpath(xpath, namespaces=XPATH_NSDICT)): parent = node.getparent() @@ -122,53 +116,54 @@ def collapse_swa(ctx, content_type, ns_soap_env): envelope = ctx.in_string # convert multipart messages back to pure SOAP mime_type, content_data = content_type - if not six.PY2: - assert isinstance(mime_type, six.text_type) + assert isinstance(mime_type, str) - if u'multipart/related' not in mime_type: + if "multipart/related" not in mime_type: return envelope - charset = content_data.get('charset', None) + charset = content_data.get("charset", None) if charset is None: - charset = 'ascii' + charset = "ascii" - boundary = content_data.get('boundary', None) + boundary = content_data.get("boundary", None) if boundary is None: - raise ValidationError(None, u"Missing 'boundary' value from " - u"Content-Type header") + raise ValidationError( + None, "Missing 'boundary' value from " "Content-Type header" + ) envelope = list(envelope) # What an ugly hack... - request = MIMEMultipart('related', boundary=boundary) - msg_string = re.sub(r"\n\n.*", '', request.as_string()) + request = MIMEMultipart("related", boundary=boundary) + msg_string = re.sub(r"\n\n.*", "", request.as_string()) msg_string = chain( - (msg_string.encode(charset), generator.NL.encode('ascii')), + (msg_string.encode(charset), generator.NL.encode("ascii")), (e for e in envelope), ) - msg_string = b''.join(msg_string) + msg_string = b"".join(msg_string) msg = message_from_bytes(msg_string) # our message soapmsg = None - root = msg.get_param('start') + root = msg.get_param("start") # walk through sections, reconstructing pure SOAP for part in msg.walk(): # skip the multipart container section - if part.get_content_maintype() == 'multipart': + if part.get_content_maintype() == "multipart": continue # detect main soap section - if (part.get('Content-ID') and part.get('Content-ID') == root) or \ - (root is None and part == msg.get_payload()[0]): + if (part.get("Content-ID") and part.get("Content-ID") == root) or ( + root is None and part == msg.get_payload()[0] + ): soapmsg = part.get_payload() continue # binary packages cte = part.get("Content-Transfer-Encoding") - if cte != 'base64': + if cte != "base64": payload = b64encode(part.get_payload(decode=True)) else: payload = part.get_payload() @@ -179,14 +174,13 @@ def collapse_swa(ctx, content_type, ns_soap_env): # Check for Content-ID and make replacement if cid: - soapmsg, numreplaces = _join_attachment( - ns_soap_env, cid, soapmsg, payload) + soapmsg, numreplaces = _join_attachment(ns_soap_env, cid, soapmsg, payload) # Check for Content-Location and make replacement if cloc and not cid and not numreplaces: soapmsg, numreplaces = _join_attachment( - ns_soap_env, cloc, soapmsg, payload, - False) + ns_soap_env, cloc, soapmsg, payload, False + ) if soapmsg is None: raise ValidationError(None, "Invalid MtoM request") @@ -215,7 +209,7 @@ def apply_mtom(headers, envelope, params, paramvals): """ # grab the XML element of the message in the SOAP body - envelope = ''.join(envelope) + envelope = "".join(envelope) soaptree = etree.fromstring(envelope) soapbody = soaptree.find("{%s}Body" % _ns_soap_env) @@ -231,36 +225,36 @@ def apply_mtom(headers, envelope, params, paramvals): # Get additional parameters from original Content-Type ctarray = [] for n, v in headers.items(): - if n.lower() == 'content-type': - ctarray = v.split(';') + if n.lower() == "content-type": + ctarray = v.split(";") break roottype = ctarray[0].strip() rootparams = {} for ctparam in ctarray[1:]: - n, v = ctparam.strip().split('=') + n, v = ctparam.strip().split("=") rootparams[n] = v.strip("\"'") # Set up initial MIME parts. - mtompkg = MIMEMultipart('related', boundary='?//<><>spyne_MIME_boundary<>') - rootpkg = MIMEApplication(envelope, 'xop+xml', encode_7or8bit) + mtompkg = MIMEMultipart("related", boundary="?//<><>spyne_MIME_boundary<>") + rootpkg = MIMEApplication(envelope, "xop+xml", encode_7or8bit) # Set up multipart headers. - del mtompkg['mime-version'] - mtompkg.set_param('start-info', roottype) - mtompkg.set_param('start', '') - if 'SOAPAction' in headers: - mtompkg.add_header('SOAPAction', headers.get('SOAPAction')) + del mtompkg["mime-version"] + mtompkg.set_param("start-info", roottype) + mtompkg.set_param("start", "") + if "SOAPAction" in headers: + mtompkg.add_header("SOAPAction", headers.get("SOAPAction")) # Set up root SOAP part headers. - del rootpkg['mime-version'] + del rootpkg["mime-version"] - rootpkg.add_header('Content-ID', '') + rootpkg.add_header("Content-ID", "") for n, v in rootparams.items(): rootpkg.set_param(n, v) - rootpkg.set_param('type', roottype) + rootpkg.set_param("type", roottype) mtompkg.attach(rootpkg) @@ -269,7 +263,7 @@ def apply_mtom(headers, envelope, params, paramvals): name, typ = params[i] if issubclass(typ, (ByteArray, File)): - id = "SpyneAttachment_%s" % (len(mtompkg.get_payload()), ) + id = "SpyneAttachment_%s" % (len(mtompkg.get_payload()),) param = message[i] param.text = "" @@ -283,20 +277,20 @@ def apply_mtom(headers, envelope, params, paramvals): if issubclass(type, File): data = paramvals[i].data else: - data = ''.join(paramvals[i]) + data = "".join(paramvals[i]) attachment = MIMEApplication(data, _encoder=encode_7or8bit) - del attachment['mime-version'] + del attachment["mime-version"] - attachment.add_header('Content-ID', '<%s>' % (id, )) + attachment.add_header("Content-ID", "<%s>" % (id,)) mtompkg.attach(attachment) # Update SOAP envelope. rootpkg.set_payload(etree.tostring(soaptree)) # extract body string from MIMEMultipart message - bound = '--%s' % (mtompkg.get_boundary(), ) + bound = "--%s" % (mtompkg.get_boundary(),) marray = mtompkg.as_string().split(bound) mtombody = bound mtombody += bound.join(marray[1:]) diff --git a/spyne/protocol/soap/soap11.py b/spyne/protocol/soap/soap11.py index 21a02b890..7dc33a787 100644 --- a/spyne/protocol/soap/soap11.py +++ b/spyne/protocol/soap/soap11.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -35,49 +34,43 @@ """ % (__name__, __name__ + ".invalid") import logging + logger = logging.getLogger(__name__) logger_invalid = logging.getLogger(__name__ + ".invalid") from itertools import chain -import spyne.const.xml as ns - from lxml import etree -from lxml.etree import XMLSyntaxError -from lxml.etree import XMLParser +from lxml.etree import XMLParser, XMLSyntaxError -from spyne import BODY_STYLE_WRAPPED -from spyne.util import six -from spyne.util.http import parse_content_type_header -from spyne.const.xml import DEFAULT_NS +import spyne.const.xml as ns from spyne.const.http import HTTP_405, HTTP_500 +from spyne.const.xml import DEFAULT_NS +from spyne.descriptor import BODY_STYLE_WRAPPED from spyne.error import RequestNotAllowed from spyne.model.fault import Fault -from spyne.model.primitive import Date, Time, DateTime -from spyne.protocol.xml import XmlDocument +from spyne.model.primitive import Date, DateTime, Time from spyne.protocol.soap.mime import collapse_swa +from spyne.protocol.xml import XmlDocument from spyne.server.http import HttpTransportContext +from spyne.util.http import parse_content_type_header def _from_soap(in_envelope_xml, xmlids=None, **kwargs): - """Parses the xml string into the header and payload. - """ - ns_soap = kwargs.pop('ns', ns.NS_SOAP11_ENV) + """Parses the xml string into the header and payload.""" + ns_soap = kwargs.pop("ns", ns.NS_SOAP11_ENV) if xmlids: resolve_hrefs(in_envelope_xml, xmlids) - if in_envelope_xml.tag != '{%s}Envelope' % ns_soap: - raise Fault('Client.SoapError', 'No {%s}Envelope element was found!' % - ns_soap) + if in_envelope_xml.tag != "{%s}Envelope" % ns_soap: + raise Fault("Client.SoapError", "No {%s}Envelope element was found!" % ns_soap) - header_envelope = in_envelope_xml.xpath('e:Header', - namespaces={'e': ns_soap}) - body_envelope = in_envelope_xml.xpath('e:Body', - namespaces={'e': ns_soap}) + header_envelope = in_envelope_xml.xpath("e:Header", namespaces={"e": ns_soap}) + body_envelope = in_envelope_xml.xpath("e:Body", namespaces={"e": ns_soap}) if len(header_envelope) == 0 and len(body_envelope) == 0: - raise Fault('Client.SoapError', 'Soap envelope is empty!') + raise Fault("Client.SoapError", "Soap envelope is empty!") header = None if len(header_envelope) > 0: @@ -93,10 +86,10 @@ def _from_soap(in_envelope_xml, xmlids=None, **kwargs): def _parse_xml_string(xml_string, parser, charset=None): xml_string = iter(xml_string) chunk = next(xml_string) - if isinstance(chunk, six.binary_type): - string = b''.join(chain( (chunk,), xml_string )) + if isinstance(chunk, bytes): + string = b"".join(chain((chunk,), xml_string)) else: - string = ''.join(chain( (chunk,), xml_string )) + string = "".join(chain((chunk,), xml_string)) if charset: string = string.decode(charset) @@ -106,13 +99,15 @@ def _parse_xml_string(xml_string, parser, charset=None): root, xmlids = etree.XMLID(string, parser) except ValueError as e: - logger.debug('ValueError: Deserializing from unicode strings with ' - 'encoding declaration is not supported by lxml.') + logger.debug( + "ValueError: Deserializing from unicode strings with " + "encoding declaration is not supported by lxml." + ) root, xmlids = etree.XMLID(string.encode(charset), parser) except XMLSyntaxError as e: logger_invalid.error("%r in string %r", e, string) - raise Fault('Client.XMLSyntaxError', str(e)) + raise Fault("Client.XMLSyntaxError", str(e)) return root, xmlids @@ -121,11 +116,11 @@ def _parse_xml_string(xml_string, parser, charset=None): # section 5.2.1 for an example of how the id and href attributes are used. def resolve_hrefs(element, xmlids): for e in element: - if e.get('id'): - continue # don't need to resolve this element + if e.get("id"): + continue # don't need to resolve this element - elif e.get('href'): - resolved_element = xmlids[e.get('href').replace('#', '')] + elif e.get("href"): + resolved_element = xmlids[e.get("href").replace("#", "")] if resolved_element is None: continue resolve_hrefs(resolved_element, xmlids) @@ -164,10 +159,10 @@ class Soap11(XmlDocument): format. """ - mime_type = 'text/xml; charset=utf-8' + mime_type = "text/xml; charset=utf-8" type = set(XmlDocument.type) - type.update(('soap', 'soap11')) + type.update(("soap", "soap11")) ns_soap_env = ns.NS_SOAP11_ENV ns_soap_enc = ns.NS_SOAP11_ENC @@ -193,24 +188,26 @@ def create_in_document(self, ctx, charset=None): if content_type is None or http_verb != "POST": ctx.transport.resp_code = HTTP_405 raise RequestNotAllowed( - "You must issue a POST request with the Content-Type " - "header properly set.") + "You must issue a POST request with the Content-Type " + "header properly set." + ) content_type = parse_content_type_header(content_type) ctx.in_string = collapse_swa(ctx, content_type, self.ns_soap_env) - ctx.in_document = _parse_xml_string(ctx.in_string, - XMLParser(**self.parser_kwargs), - charset) + ctx.in_document = _parse_xml_string( + ctx.in_string, XMLParser(**self.parser_kwargs), charset + ) def decompose_incoming_envelope(self, ctx, message=XmlDocument.REQUEST): envelope_xml, xmlids = ctx.in_document - header_document, body_document = _from_soap(envelope_xml, xmlids, - ns=self.ns_soap_env) + header_document, body_document = _from_soap( + envelope_xml, xmlids, ns=self.ns_soap_env + ) ctx.in_document = envelope_xml - if body_document.tag == '{%s}Fault' % self.ns_soap_env: + if body_document.tag == "{%s}Fault" % self.ns_soap_env: ctx.in_body_doc = body_document else: @@ -229,7 +226,7 @@ def deserialize(self, ctx, message): assert message in (self.REQUEST, self.RESPONSE) - self.event_manager.fire_event('before_deserialize', ctx) + self.event_manager.fire_event("before_deserialize", ctx) if ctx.in_body_doc.tag == "{%s}Fault" % self.ns_soap_env: ctx.in_object = None @@ -246,18 +243,20 @@ def deserialize(self, ctx, message): # decode header objects # header elements are returned in header_class order which need not match the incoming XML - if (ctx.in_header_doc is not None and header_class is not None): + if ctx.in_header_doc is not None and header_class is not None: headers = [None] * len(header_class) - in_header_dict = dict( [(element.tag, element) - for element in ctx.in_header_doc]) + in_header_dict = dict( + [(element.tag, element) for element in ctx.in_header_doc] + ) for i, head_class in enumerate(header_class): if i < len(header_class): - nsval = "{%s}%s" % (head_class.__namespace__, - head_class.__type_name__) + nsval = "{%s}%s" % ( + head_class.__namespace__, + head_class.__type_name__, + ) header_doc = in_header_dict.get(nsval, None) if header_doc is not None: - headers[i] = self.from_element(ctx, head_class, - header_doc) + headers[i] = self.from_element(ctx, head_class, header_doc) if len(headers) == 1: ctx.in_header = headers[0] @@ -268,10 +267,9 @@ def deserialize(self, ctx, message): if ctx.in_body_doc is None: ctx.in_object = [None] * len(body_class._type_info) else: - ctx.in_object = self.from_element(ctx, body_class, - ctx.in_body_doc) + ctx.in_object = self.from_element(ctx, body_class, ctx.in_body_doc) - self.event_manager.fire_event('after_deserialize', ctx) + self.event_manager.fire_event("after_deserialize", ctx) def serialize(self, ctx, message): """Uses ctx.out_object, ctx.out_header or ctx.out_error to set @@ -283,18 +281,23 @@ def serialize(self, ctx, message): assert message in (self.REQUEST, self.RESPONSE) - self.event_manager.fire_event('before_serialize', ctx) + self.event_manager.fire_event("before_serialize", ctx) # construct the soap response, and serialize it nsmap = self.app.interface.nsmap - ctx.out_document = etree.Element('{%s}Envelope' % self.ns_soap_env, - nsmap=nsmap) + ctx.out_document = etree.Element("{%s}Envelope" % self.ns_soap_env, nsmap=nsmap) if ctx.out_error is not None: # FIXME: There's no way to alter soap response headers for the user. - ctx.out_body_doc = out_body_doc = etree.SubElement(ctx.out_document, - '{%s}Body' % self.ns_soap_env, nsmap=nsmap) - self.to_parent(ctx, ctx.out_error.__class__, ctx.out_error, - out_body_doc, self.app.interface.get_tns()) + ctx.out_body_doc = out_body_doc = etree.SubElement( + ctx.out_document, "{%s}Body" % self.ns_soap_env, nsmap=nsmap + ) + self.to_parent( + ctx, + ctx.out_error.__class__, + ctx.out_error, + out_body_doc, + self.app.interface.get_tns(), + ) else: if message is self.REQUEST: @@ -307,7 +310,8 @@ def serialize(self, ctx, message): # body ctx.out_body_doc = out_body_doc = etree.Element( - '{%s}Body' % self.ns_soap_env) + "{%s}Body" % self.ns_soap_env + ) # assign raw result to its wrapper, result_message if ctx.descriptor.body_style is BODY_STYLE_WRAPPED: @@ -329,8 +333,13 @@ def serialize(self, ctx, message): out_object._safe_set(k, v, body_message_class, bm_attrs) - self.to_parent(ctx, body_message_class, out_object, - out_body_doc, body_message_class.get_namespace()) + self.to_parent( + ctx, + body_message_class, + out_object, + out_body_doc, + body_message_class.get_namespace(), + ) else: out_object = ctx.out_object[0] @@ -345,23 +354,26 @@ def serialize(self, ctx, message): if sub_name is None: sub_name = body_message_class.get_type_name() - self.to_parent(ctx, body_message_class, out_object, out_body_doc, - sub_ns, sub_name) + self.to_parent( + ctx, body_message_class, out_object, out_body_doc, sub_ns, sub_name + ) # header if ctx.out_header is not None and header_message_class is not None: ctx.out_header_doc = soap_header_elt = etree.SubElement( - ctx.out_document, '{%s}Header' % self.ns_soap_env) + ctx.out_document, "{%s}Header" % self.ns_soap_env + ) if isinstance(ctx.out_header, (list, tuple)): out_headers = ctx.out_header else: out_headers = (ctx.out_header,) - for header_class, out_header in zip(header_message_class, - out_headers): - self.to_parent(ctx, - header_class, out_header, + for header_class, out_header in zip(header_message_class, out_headers): + self.to_parent( + ctx, + header_class, + out_header, soap_header_elt, header_class.get_namespace(), header_class.get_type_name(), @@ -372,7 +384,7 @@ def serialize(self, ctx, message): if self.cleanup_namespaces: etree.cleanup_namespaces(ctx.out_document) - self.event_manager.fire_event('after_serialize', ctx) + self.event_manager.fire_event("after_serialize", ctx) def fault_to_http_response_code(self, fault): return HTTP_500 diff --git a/spyne/protocol/soap/soap12.py b/spyne/protocol/soap/soap12.py index 53e656a69..59280a02f 100644 --- a/spyne/protocol/soap/soap12.py +++ b/spyne/protocol/soap/soap12.py @@ -28,12 +28,10 @@ from lxml.builder import E +from spyne.const.xml import NS_SOAP12_ENV, NS_XML, PREFMAP from spyne.protocol.soap.soap11 import Soap11 from spyne.protocol.xml import _append -from spyne.util.six import string_types from spyne.util.etreeconv import root_dict_to_etree -from spyne.const.xml import NS_SOAP12_ENV, NS_XML, PREFMAP - logger = logging.getLogger(__name__) logger_invalid = logging.getLogger(__name__ + ".invalid") @@ -44,49 +42,55 @@ class Soap12(Soap11): The base implementation of a subset of the Soap 1.2 standard. The document is available here: http://www.w3.org/TR/soap12/ """ - mime_type = 'application/soap+xml; charset=utf-8' + + mime_type = "application/soap+xml; charset=utf-8" soap_env = PREFMAP[NS_SOAP12_ENV] ns_soap_env = NS_SOAP12_ENV type = set(Soap11.type) - type.discard('soap11') - type.update(('soap', 'soap12')) + type.discard("soap11") + type.update(("soap", "soap12")) def generate_subcode(self, value, subcode=None): subcode_node = E("{%s}Subcode" % self.ns_soap_env) subcode_node.append(E("{%s}Value" % self.ns_soap_env, value)) - if subcode: + if subcode is not None: subcode_node.append(subcode) return subcode_node def gen_fault_codes(self, faultstring): - faultstrings = faultstring.split('.') + faultstrings = faultstring.split(".") value = faultstrings.pop(0) - if value == 'Client': - value = '%s:Sender' % self.soap_env - elif value == 'Server': - value = '%s:Receiver' % self.soap_env + if value == "Client": + value = "%s:Sender" % self.soap_env + elif value == "Server": + value = "%s:Receiver" % self.soap_env else: - raise TypeError('Wrong fault code, got', type(faultstring)) + raise TypeError("Wrong fault code, got", type(faultstring)) return value, faultstrings def generate_faultcode(self, element): nsmap = element.nsmap faultcode = [] - faultcode.append(element.find('soap:Code/soap:Value', namespaces=nsmap).text) - subcode = element.find('soap:Code/soap:Subcode', namespaces=nsmap) + faultcode.append(element.find("soap:Code/soap:Value", namespaces=nsmap).text) + subcode = element.find("soap:Code/soap:Subcode", namespaces=nsmap) while subcode is not None: - faultcode.append(subcode.find('soap:Value', namespaces=nsmap).text) - subcode = subcode.find('soap:Subcode', namespaces=nsmap) + faultcode.append(subcode.find("soap:Value", namespaces=nsmap).text) + subcode = subcode.find("soap:Subcode", namespaces=nsmap) - return '.'.join(faultcode) + return ".".join(faultcode) def fault_to_parent(self, ctx, cls, inst, parent, ns, **_): reason = E("{%s}Reason" % self.ns_soap_env) - reason.append(E("{%s}Text" % self.ns_soap_env, inst.faultstring, - **{'{%s}lang' % NS_XML: inst.lang})) + reason.append( + E( + "{%s}Text" % self.ns_soap_env, + inst.faultstring, + **{"{%s}lang" % NS_XML: inst.lang}, + ) + ) subelts = [ None, # The code tag is put here down the road @@ -101,15 +105,15 @@ def _fault_to_parent_impl(self, ctx, cls, inst, parent, ns, subelts, **_): tag_name = "{%s}Fault" % self.ns_soap_env - if isinstance(inst.faultcode, string_types): + if isinstance(inst.faultcode, str): value, faultcodes = self.gen_fault_codes(inst.faultcode) code = E("{%s}Code" % self.ns_soap_env) code.append(E("{%s}Value" % self.ns_soap_env, value)) - child_subcode = False + child_subcode = None for value in faultcodes[::-1]: - if child_subcode: + if child_subcode is not None: child_subcode = self.generate_subcode(value, child_subcode) else: child_subcode = self.generate_subcode(value) @@ -120,17 +124,20 @@ def _fault_to_parent_impl(self, ctx, cls, inst, parent, ns, subelts, **_): subelts[0] = code if isinstance(inst.detail, dict): - _append(subelts, E('{%s}Detail' % self.ns_soap_env, - root_dict_to_etree(inst.detail))) + _append( + subelts, + E("{%s}Detail" % self.ns_soap_env, root_dict_to_etree(inst.detail)), + ) elif inst.detail is None: pass else: - raise TypeError('Fault detail Must be dict, got', type(inst.detail)) + raise TypeError("Fault detail Must be dict, got", type(inst.detail)) - return self.gen_members_parent(ctx, cls, inst, parent, tag_name, - subelts, add_type=False) + return self.gen_members_parent( + ctx, cls, inst, parent, tag_name, subelts, add_type=False + ) def schema_validation_error_to_parent(self, ctx, cls, inst, parent, ns, **_): subelts = [ @@ -148,10 +155,11 @@ def fault_from_element(self, ctx, cls, element): role = element.find("soap:Role", namespaces=nsmap) node = element.find("soap:Node", namespaces=nsmap) detail = element.find("soap:Detail", namespaces=nsmap) - faultactor = '' + faultactor = "" if role is not None: faultactor += role.text.strip() if node is not None: faultactor += node.text.strip() - return cls(faultcode=code, faultstring=reason, - faultactor=faultactor, detail=detail) + return cls( + faultcode=code, faultstring=reason, faultactor=faultactor, detail=detail + ) diff --git a/spyne/protocol/xml.py b/spyne/protocol/xml.py index ecdd048f9..cb5e00fff 100644 --- a/spyne/protocol/xml.py +++ b/spyne/protocol/xml.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -29,59 +28,54 @@ to turn it on for a production system. """ - import logging -logger = logging.getLogger('spyne.protocol.xml') -logger_invalid = logging.getLogger('spyne.protocol.xml.invalid') -from inspect import isgenerator +logger = logging.getLogger("spyne.protocol.xml") +logger_invalid = logging.getLogger("spyne.protocol.xml.invalid") + from collections import defaultdict +from inspect import isgenerator -from lxml import etree -from lxml import html +from lxml import etree, html from lxml.builder import E -from lxml.etree import XMLSyntaxError -from lxml.etree import XMLParser - -from spyne import BODY_STYLE_WRAPPED - -from spyne.util import Break, coroutine -from spyne.util.six import text_type, string_types -from spyne.util.cdict import cdict -from spyne.util.etreeconv import etree_to_dict, dict_to_etree,\ - root_dict_to_etree -from spyne.const.xml import XSI, NS_SOAP11_ENC - -from spyne.error import Fault -from spyne.error import ValidationError -from spyne.const.ansi_color import LIGHT_GREEN -from spyne.const.ansi_color import LIGHT_RED -from spyne.const.ansi_color import END_COLOR -from spyne.const.xml import NS_SOAP11_ENV -from spyne.const.xml import PREFMAP, DEFAULT_NS - -from spyne.model import Any, ModelBase, Array, Iterable, ComplexModelBase, \ - AnyHtml, AnyXml, AnyDict, Unicode, PushBase, File, ByteArray, XmlData, \ - XmlAttribute +from lxml.etree import XMLParser, XMLSyntaxError + +from spyne.const.ansi_color import END_COLOR, LIGHT_GREEN, LIGHT_RED +from spyne.const.xml import DEFAULT_NS, NS_SOAP11_ENC, NS_SOAP11_ENV, PREFMAP, XSI +from spyne.descriptor import BODY_STYLE_WRAPPED +from spyne.error import Fault, ValidationError +from spyne.model import ( + Any, + AnyDict, + AnyHtml, + AnyXml, + Array, + ByteArray, + ComplexModelBase, + File, + Iterable, + ModelBase, + PushBase, + Unicode, + XmlAttribute, + XmlData, +) from spyne.model.binary import BINARY_ENCODING_BASE64 from spyne.model.enum import EnumBase - from spyne.protocol import ProtocolBase +from spyne.util import Break, coroutine +from spyne.util.cdict import cdict +from spyne.util.etreeconv import dict_to_etree, etree_to_dict, root_dict_to_etree -from spyne.util import six - -if six.PY2: - STR_TYPES = (str, unicode) -else: - STR_TYPES = (str, bytes) +STR_TYPES = (str, bytes) -NIL_ATTR = {XSI('nil'): 'true'} -XSI_TYPE = XSI('type') +NIL_ATTR = {XSI("nil"): "true"} +XSI_TYPE = XSI("type") def _append(parent, child_elt): - if hasattr(parent, 'append'): + if hasattr(parent, "append"): parent.append(child_elt) else: parent.write(child_elt) @@ -96,7 +90,7 @@ def _gen_tagname(ns, name): class SchemaValidationError(Fault): """Raised when the input stream could not be validated by the Xml Schema.""" - CODE = 'Client.SchemaValidationError' + CODE = "Client.SchemaValidationError" def __init__(self, faultstring): super(SchemaValidationError, self).__init__(self.CODE, faultstring) @@ -273,39 +267,45 @@ class XmlDocument(SubXmlBase): SCHEMA_VALIDATION = type("Schema", (object,), {}) - mime_type = 'text/xml' + mime_type = "text/xml" default_binary_encoding = BINARY_ENCODING_BASE64 type = set(ProtocolBase.type) - type.add('xml') + type.add("xml") soap_env = PREFMAP[NS_SOAP11_ENV] ns_soap_env = NS_SOAP11_ENV ns_soap_enc = NS_SOAP11_ENC - def __init__(self, app=None, validator=None, - replace_null_with_default=True, - xml_declaration=True, - cleanup_namespaces=True, encoding=None, pretty_print=False, - attribute_defaults=False, - dtd_validation=False, - load_dtd=False, - no_network=True, - ns_clean=False, - recover=False, - remove_blank_text=False, - remove_pis=True, - strip_cdata=True, - resolve_entities=False, - huge_tree=False, - compact=True, - binary_encoding=None, - parse_xsi_type=True, - polymorphic=False, - ): - - super(XmlDocument, self).__init__(app, validator, - binary_encoding=binary_encoding) + def __init__( + self, + app=None, + validator=None, + replace_null_with_default=True, + xml_declaration=True, + cleanup_namespaces=True, + encoding=None, + pretty_print=False, + attribute_defaults=False, + dtd_validation=False, + load_dtd=False, + no_network=True, + ns_clean=False, + recover=False, + remove_blank_text=False, + remove_pis=True, + strip_cdata=True, + resolve_entities=False, + huge_tree=False, + compact=True, + binary_encoding=None, + parse_xsi_type=True, + polymorphic=False, + ): + + super(XmlDocument, self).__init__( + app, validator, binary_encoding=binary_encoding + ) self.validation_schema = None self.xml_declaration = xml_declaration @@ -313,7 +313,7 @@ def __init__(self, app=None, validator=None, self.replace_null_with_default = replace_null_with_default if encoding is None: - self.encoding = 'UTF-8' + self.encoding = "UTF-8" else: self.encoding = encoding @@ -321,35 +321,39 @@ def __init__(self, app=None, validator=None, self.pretty_print = pretty_print self.parse_xsi_type = parse_xsi_type - self.serialization_handlers = cdict({ - Any: self.any_to_parent, - Fault: self.fault_to_parent, - EnumBase: self.enum_to_parent, - AnyXml: self.any_xml_to_parent, - XmlData: self.xmldata_to_parent, - AnyDict: self.any_dict_to_parent, - AnyHtml: self.any_html_to_parent, - ModelBase: self.modelbase_to_parent, - ByteArray: self.byte_array_to_parent, - ComplexModelBase: self.complex_to_parent, - XmlAttribute: self.xmlattribute_to_parent, - SchemaValidationError: self.schema_validation_error_to_parent, - }) - - self.deserialization_handlers = cdict({ - AnyHtml: self.html_from_element, - AnyXml: self.xml_from_element, - Any: self.xml_from_element, - Array: self.array_from_element, - Fault: self.fault_from_element, - AnyDict: self.dict_from_element, - EnumBase: self.enum_from_element, - ModelBase: self.base_from_element, - Unicode: self.unicode_from_element, - Iterable: self.iterable_from_element, - ByteArray: self.byte_array_from_element, - ComplexModelBase: self.complex_from_element, - }) + self.serialization_handlers = cdict( + { + Any: self.any_to_parent, + Fault: self.fault_to_parent, + EnumBase: self.enum_to_parent, + AnyXml: self.any_xml_to_parent, + XmlData: self.xmldata_to_parent, + AnyDict: self.any_dict_to_parent, + AnyHtml: self.any_html_to_parent, + ModelBase: self.modelbase_to_parent, + ByteArray: self.byte_array_to_parent, + ComplexModelBase: self.complex_to_parent, + XmlAttribute: self.xmlattribute_to_parent, + SchemaValidationError: self.schema_validation_error_to_parent, + } + ) + + self.deserialization_handlers = cdict( + { + AnyHtml: self.html_from_element, + AnyXml: self.xml_from_element, + Any: self.xml_from_element, + Array: self.array_from_element, + Fault: self.fault_from_element, + AnyDict: self.dict_from_element, + EnumBase: self.enum_from_element, + ModelBase: self.base_from_element, + Unicode: self.unicode_from_element, + Iterable: self.iterable_from_element, + ByteArray: self.byte_array_from_element, + ComplexModelBase: self.complex_from_element, + } + ) self.parser_kwargs = dict( attribute_defaults=attribute_defaults, @@ -369,12 +373,11 @@ def __init__(self, app=None, validator=None, ) def set_validator(self, validator): - if validator in ('lxml', 'schema') or \ - validator is self.SCHEMA_VALIDATION: + if validator in ("lxml", "schema") or validator is self.SCHEMA_VALIDATION: self.validate_document = self.__validate_lxml self.validator = self.SCHEMA_VALIDATION - elif validator == 'soft' or validator is self.SOFT_VALIDATION: + elif validator == "soft" or validator is self.SOFT_VALIDATION: self.validator = self.SOFT_VALIDATION elif validator is None: @@ -418,34 +421,35 @@ def __validate_lxml(self, payload): logger.debug("Validated ? %r" % ret) if ret == False: - error_text = text_type(self.validation_schema.error_log.last_error) - raise SchemaValidationError(error_text.encode('ascii', - 'xmlcharrefreplace')) + error_text = str(self.validation_schema.error_log.last_error) + raise SchemaValidationError(error_text.encode("ascii", "xmlcharrefreplace")) def create_in_document(self, ctx, charset=None): """Uses the iterable of string fragments in ``ctx.in_string`` to set ``ctx.in_document``.""" - string = b''.join(ctx.in_string) + string = b"".join(ctx.in_string) try: try: - ctx.in_document = etree.fromstring(string, - parser=XMLParser(**self.parser_kwargs)) + ctx.in_document = etree.fromstring( + string, parser=XMLParser(**self.parser_kwargs) + ) except ValueError: - logger.debug('ValueError: Deserializing from unicode strings ' - 'with encoding declaration is not supported by ' - 'lxml.') - ctx.in_document = etree.fromstring(string.decode(charset), - self.parser) + logger.debug( + "ValueError: Deserializing from unicode strings " + "with encoding declaration is not supported by " + "lxml." + ) + ctx.in_document = etree.fromstring(string.decode(charset), self.parser) except XMLSyntaxError as e: logger_invalid.error("%r in string %r", e, string) - raise Fault('Client.XMLSyntaxError', str(e)) + raise Fault("Client.XMLSyntaxError", str(e)) def decompose_incoming_envelope(self, ctx, message): assert message in (self.REQUEST, self.RESPONSE) - ctx.in_header_doc = None # If you need header support, you should use Soap + ctx.in_header_doc = None # If you need header support, you should use Soap ctx.in_body_doc = ctx.in_document ctx.method_request_string = ctx.in_body_doc.tag self.validate_body(ctx, message) @@ -453,9 +457,8 @@ def decompose_incoming_envelope(self, ctx, message): def from_element(self, ctx, cls, element): cls_attrs = self.get_cls_attrs(cls) - if bool(element.get(XSI('nil'))): - if self.validator is self.SOFT_VALIDATION and not \ - cls_attrs.nillable: + if bool(element.get(XSI("nil"))): + if self.validator is self.SOFT_VALIDATION and not cls_attrs.nillable: raise ValidationError(None) if self.replace_null_with_default: @@ -469,7 +472,7 @@ def from_element(self, ctx, cls, element): xsi_type = element.get(XSI_TYPE, None) if xsi_type is not None: if ":" in xsi_type: - prefix, objtype = xsi_type.split(':', 1) + prefix, objtype = xsi_type.split(":", 1) else: prefix, objtype = None, xsi_type @@ -478,21 +481,29 @@ def from_element(self, ctx, cls, element): classkey = "{%s}%s" % (ns, objtype) else: - logger.error("xsi:type namespace prefix " - "'%s' in '%s' not found in %r", - ns, xsi_type, element.nsmap) + logger.error( + "xsi:type namespace prefix " "'%s' in '%s' not found in %r", + ns, + xsi_type, + element.nsmap, + ) raise ValidationError(xsi_type) newclass = ctx.app.interface.classes.get(classkey, None) if newclass is None: - logger.error("xsi:type '%s' interpreted as class key '%s' " - "is not recognized", xsi_type, classkey) + logger.error( + "xsi:type '%s' interpreted as class key '%s' " + "is not recognized", + xsi_type, + classkey, + ) raise ValidationError(xsi_type) cls = newclass - logger.debug("xsi:type '%s' overrides %r to %r", xsi_type, - cls, newclass) + logger.debug( + "xsi:type '%s' overrides %r to %r", xsi_type, cls, newclass + ) handler = self.deserialization_handlers[cls] return handler(ctx, cls, element) @@ -503,8 +514,7 @@ def to_parent(self, ctx, cls, inst, parent, ns, *args, **kwargs): subprot = cls_attrs.prot if subprot is not None and isinstance(subprot, SubXmlBase): - return subprot.subserialize(ctx, cls, inst, parent, ns, - *args, **kwargs) + return subprot.subserialize(ctx, cls, inst, parent, ns, *args, **kwargs) handler = self.serialization_handlers[cls] @@ -512,13 +522,12 @@ def to_parent(self, ctx, cls, inst, parent, ns, *args, **kwargs): inst = cls_attrs.default if inst is None: - return self.null_to_parent(ctx, cls, inst, parent, ns, - *args, **kwargs) + return self.null_to_parent(ctx, cls, inst, parent, ns, *args, **kwargs) if cls_attrs.exc: return - kwargs['add_type'] = add_type + kwargs["add_type"] = add_type return handler(ctx, cls, inst, parent, ns, *args, **kwargs) def deserialize(self, ctx, message): @@ -532,12 +541,13 @@ def deserialize(self, ctx, message): assert message in (self.REQUEST, self.RESPONSE) - self.event_manager.fire_event('before_deserialize', ctx) + self.event_manager.fire_event("before_deserialize", ctx) if ctx.descriptor is None: if ctx.in_error is None: - raise Fault("Client", "Method %r not found." % - ctx.method_request_string) + raise Fault( + "Client", "Method %r not found." % ctx.method_request_string + ) else: raise ctx.in_error @@ -553,16 +563,19 @@ def deserialize(self, ctx, message): ctx.in_object = self.from_element(ctx, body_class, ctx.in_body_doc) if logger.level == logging.DEBUG and message is self.REQUEST: - line_header = '%sRequest%s' % (LIGHT_GREEN, END_COLOR) + line_header = "%sRequest%s" % (LIGHT_GREEN, END_COLOR) outdoc_str = None if ctx.out_document is not None: - outdoc_str = etree.tostring(ctx.out_document, - xml_declaration=self.xml_declaration, pretty_print=True) + outdoc_str = etree.tostring( + ctx.out_document, + xml_declaration=self.xml_declaration, + pretty_print=True, + ) logger.debug("%s %s" % (line_header, outdoc_str)) - self.event_manager.fire_event('after_deserialize', ctx) + self.event_manager.fire_event("after_deserialize", ctx) def serialize(self, ctx, message): """Uses ``ctx.out_object``, ``ctx.out_header`` or ``ctx.out_error`` to @@ -574,12 +587,17 @@ def serialize(self, ctx, message): assert message in (self.REQUEST, self.RESPONSE) - self.event_manager.fire_event('before_serialize', ctx) + self.event_manager.fire_event("before_serialize", ctx) if ctx.out_error is not None: - tmp_elt = etree.Element('punk') - retval = self.to_parent(ctx, ctx.out_error.__class__, ctx.out_error, - tmp_elt, self.app.interface.get_tns()) + tmp_elt = etree.Element("punk") + retval = self.to_parent( + ctx, + ctx.out_error.__class__, + ctx.out_error, + tmp_elt, + self.app.interface.get_tns(), + ) ctx.out_document = tmp_elt[0] else: @@ -592,8 +610,7 @@ def serialize(self, ctx, message): if ctx.descriptor.body_style == BODY_STYLE_WRAPPED: result_inst = result_message_class() - for i, (k, v) in enumerate( - result_message_class._type_info.items()): + for i, (k, v) in enumerate(result_message_class._type_info.items()): attrs = self.get_cls_attrs(v) result_inst._safe_set(k, ctx.out_object[i], v, attrs) @@ -601,19 +618,25 @@ def serialize(self, ctx, message): result_inst = ctx.out_object if ctx.out_stream is None: - tmp_elt = etree.Element('punk') - retval = self.to_parent(ctx, result_message_class, - result_inst, tmp_elt, self.app.interface.get_tns()) + tmp_elt = etree.Element("punk") + retval = self.to_parent( + ctx, + result_message_class, + result_inst, + tmp_elt, + self.app.interface.get_tns(), + ) ctx.out_document = tmp_elt[0] else: - retval = self.incgen(ctx, result_message_class, - result_inst, self.app.interface.get_tns()) + retval = self.incgen( + ctx, result_message_class, result_inst, self.app.interface.get_tns() + ) if self.cleanup_namespaces and ctx.out_document is not None: etree.cleanup_namespaces(ctx.out_document) - self.event_manager.fire_event('after_serialize', ctx) + self.event_manager.fire_event("after_serialize", ctx) return retval @@ -623,15 +646,26 @@ def create_out_string(self, ctx, charset=None): if charset is None: charset = self.encoding - ctx.out_string = [etree.tostring(ctx.out_document, - encoding=charset, - pretty_print=self.pretty_print, - xml_declaration=self.xml_declaration)] + ctx.out_string = [ + etree.tostring( + ctx.out_document, + encoding=charset, + pretty_print=self.pretty_print, + xml_declaration=self.xml_declaration, + ) + ] if logger.level == logging.DEBUG: - logger.debug('%sResponse%s %s' % (LIGHT_RED, END_COLOR, - etree.tostring(ctx.out_document, - pretty_print=True, encoding='UTF-8'))) + logger.debug( + "%sResponse%s %s" + % ( + LIGHT_RED, + END_COLOR, + etree.tostring( + ctx.out_document, pretty_print=True, encoding="UTF-8" + ), + ) + ) @coroutine def incgen(self, ctx, cls, inst, ns, name=None): @@ -642,7 +676,7 @@ def incgen(self, ctx, cls, inst, ns, name=None): if isgenerator(ret): try: while True: - y = (yield) # may throw Break + y = yield # may throw Break ret.send(y) except Break: @@ -651,7 +685,7 @@ def incgen(self, ctx, cls, inst, ns, name=None): except StopIteration: pass - if hasattr(ctx.out_stream, 'finish'): + if hasattr(ctx.out_stream, "finish"): ctx.out_stream.finish() def _gen_tag(self, cls, ns, name, add_type=False, **_): @@ -664,20 +698,17 @@ def _gen_tag(self, cls, ns, name, add_type=False, **_): return retval - def byte_array_to_parent(self, ctx, cls, inst, parent, ns, name='retval', - **kwargs): + def byte_array_to_parent(self, ctx, cls, inst, parent, ns, name="retval", **kwargs): elt = self._gen_tag(cls, ns, name, **kwargs) elt.text = self.to_unicode(cls, inst, self.binary_encoding) _append(parent, elt) - def modelbase_to_parent(self, ctx, cls, inst, parent, ns, name='retval', - **kwargs): + def modelbase_to_parent(self, ctx, cls, inst, parent, ns, name="retval", **kwargs): elt = self._gen_tag(cls, ns, name, **kwargs) elt.text = self.to_unicode(cls, inst) _append(parent, elt) - def null_to_parent(self, ctx, cls, inst, parent, ns, name='retval', - **kwargs): + def null_to_parent(self, ctx, cls, inst, parent, ns, name="retval", **kwargs): if issubclass(cls, XmlAttribute): return @@ -692,8 +723,7 @@ def null_to_parent(self, ctx, cls, inst, parent, ns, name='retval', def null_from_element(self, ctx, cls, element): return None - def xmldata_to_parent(self, ctx, cls, inst, parent, ns, name, - add_type=False, **_): + def xmldata_to_parent(self, ctx, cls, inst, parent, ns, name, add_type=False, **_): cls_attrs = self.get_cls_attrs(cls) ns = cls._ns @@ -717,14 +747,12 @@ def xmlattribute_to_parent(self, ctx, cls, inst, parent, ns, name, **_): if inst is not None: if issubclass(cls.type, (ByteArray, File)): - parent.set(name, self.to_unicode(cls.type, inst, - self.binary_encoding)) + parent.set(name, self.to_unicode(cls.type, inst, self.binary_encoding)) else: parent.set(name, self.to_unicode(cls.type, inst)) @coroutine - def gen_members_parent(self, ctx, cls, inst, parent, tag_name, subelts, - add_type): + def gen_members_parent(self, ctx, cls, inst, parent, tag_name, subelts, add_type): attrib = {} if add_type: tnn = cls.get_type_name_ns(self.app.interface) @@ -744,7 +772,7 @@ def gen_members_parent(self, ctx, cls, inst, parent, tag_name, subelts, if isgenerator(ret): try: while True: - y = (yield) # may throw Break + y = yield # may throw Break ret.send(y) except Break: @@ -761,7 +789,7 @@ def gen_members_parent(self, ctx, cls, inst, parent, tag_name, subelts, if isgenerator(ret): try: while True: - y = (yield) + y = yield ret.send(y) except Break: @@ -773,14 +801,14 @@ def gen_members_parent(self, ctx, cls, inst, parent, tag_name, subelts, @coroutine def _get_members_etree(self, ctx, cls, inst, parent): try: - parent_cls = getattr(cls, '__extends__', None) + parent_cls = getattr(cls, "__extends__", None) if not (parent_cls is None): ret = self._get_members_etree(ctx, parent_cls, inst, parent) if ret is not None: try: while True: - sv2 = (yield) # may throw Break + sv2 = yield # may throw Break ret.send(sv2) except Break: @@ -814,13 +842,12 @@ def _get_members_etree(self, ctx, cls, inst, parent): if subvalue is not None and mo > 1: if isinstance(subvalue, PushBase): while True: - sv = (yield) - ret = self.to_parent(ctx, v, sv, parent, sub_ns, - sub_name) + sv = yield + ret = self.to_parent(ctx, v, sv, parent, sub_ns, sub_name) if ret is not None: try: while True: - sv2 = (yield) # may throw Break + sv2 = yield # may throw Break ret.send(sv2) except Break: @@ -831,13 +858,12 @@ def _get_members_etree(self, ctx, cls, inst, parent): else: for sv in subvalue: - ret = self.to_parent(ctx, v, sv, parent, sub_ns, - sub_name) + ret = self.to_parent(ctx, v, sv, parent, sub_ns, sub_name) if ret is not None: try: while True: - sv2 = (yield) # may throw Break + sv2 = yield # may throw Break ret.send(sv2) except Break: @@ -849,12 +875,11 @@ def _get_members_etree(self, ctx, cls, inst, parent): # Don't include empty values for # non-nillable optional attributes. elif subvalue is not None or v.Attributes.min_occurs > 0: - ret = self.to_parent(ctx, v, subvalue, parent, sub_ns, - sub_name) + ret = self.to_parent(ctx, v, subvalue, parent, sub_ns, sub_name) if ret is not None: try: while True: - sv2 = (yield) + sv2 = yield ret.send(sv2) except Break as b: try: @@ -865,8 +890,9 @@ def _get_members_etree(self, ctx, cls, inst, parent): except Break: pass - def complex_to_parent(self, ctx, cls, inst, parent, ns, name=None, - add_type=False, **_): + def complex_to_parent( + self, ctx, cls, inst, parent, ns, name=None, add_type=False, **_ + ): cls_attrs = self.get_cls_attrs(cls) sub_name = cls_attrs.sub_name @@ -883,54 +909,54 @@ def complex_to_parent(self, ctx, cls, inst, parent, ns, name=None, inst = cls.get_serialization_instance(inst) - return self.gen_members_parent(ctx, cls, inst, parent, tag_name, [], - add_type) + return self.gen_members_parent(ctx, cls, inst, parent, tag_name, [], add_type) def _fault_to_parent_impl(self, ctx, cls, inst, parent, ns, subelts, **_): tag_name = "{%s}Fault" % self.ns_soap_env # Accepting raw lxml objects as detail is DEPRECATED. It's also not # documented. It's kept for backwards-compatibility purposes. - if isinstance(inst.detail, string_types + (etree._Element,)): - _append(subelts, E('detail', inst.detail)) + if isinstance(inst.detail, (str, etree._Element)): + _append(subelts, E("detail", inst.detail)) elif isinstance(inst.detail, dict): if len(inst.detail) > 0: - _append(subelts, root_dict_to_etree({'detail':inst.detail})) + _append(subelts, root_dict_to_etree({"detail": inst.detail})) elif inst.detail is None: pass else: - raise TypeError('Fault detail Must be dict, got', type(inst.detail)) + raise TypeError("Fault detail Must be dict, got", type(inst.detail)) # add other nonstandard fault subelements with get_members_etree - return self.gen_members_parent(ctx, cls, inst, parent, tag_name, - subelts, add_type=False) + return self.gen_members_parent( + ctx, cls, inst, parent, tag_name, subelts, add_type=False + ) def fault_to_parent(self, ctx, cls, inst, parent, ns, *args, **kwargs): subelts = [ - E("faultcode", '%s:%s' % (self.soap_env, inst.faultcode)), + E("faultcode", "%s:%s" % (self.soap_env, inst.faultcode)), E("faultstring", inst.faultstring), E("faultactor", inst.faultactor), ] return self._fault_to_parent_impl(ctx, cls, inst, parent, ns, subelts) - def schema_validation_error_to_parent(self, ctx, cls, inst, parent, ns,**_): + def schema_validation_error_to_parent(self, ctx, cls, inst, parent, ns, **_): subelts = [ - E("faultcode", '%s:%s' % (self.soap_env, inst.faultcode)), + E("faultcode", "%s:%s" % (self.soap_env, inst.faultcode)), # HACK: Does anyone know a better way of injecting raw xml entities? E("faultstring", html.fromstring(inst.faultstring).text), E("faultactor", inst.faultactor), ] if inst.detail != None: - _append(subelts, E('detail', inst.detail)) + _append(subelts, E("detail", inst.detail)) # add other nonstandard fault subelements with get_members_etree return self._fault_to_parent_impl(ctx, cls, inst, parent, ns, subelts) - def enum_to_parent(self, ctx, cls, inst, parent, ns, name='retval', **kwargs): + def enum_to_parent(self, ctx, cls, inst, parent, ns, name="retval", **kwargs): self.modelbase_to_parent(ctx, cls, str(inst), parent, ns, name, **kwargs) def any_xml_to_parent(self, ctx, cls, inst, parent, ns, name, **_): @@ -943,7 +969,7 @@ def any_to_parent(self, ctx, cls, inst, parent, ns, name, **_): _append(parent, E(_gen_tagname(ns, name), inst)) def any_html_to_parent(self, ctx, cls, inst, parent, ns, name, **_): - if isinstance(inst, string_types) and len(inst) > 0: + if isinstance(inst, str) and len(inst) > 0: inst = html.fromstring(inst) _append(parent, E(_gen_tagname(ns, name), inst)) @@ -967,8 +993,9 @@ def complex_from_element(self, ctx, cls, elt): for xtba_key, xtba_type in cls_attrs._xml_tag_body_as: xtba_attrs = self.get_cls_attrs(xtba_type.type) if issubclass(xtba_type.type, (ByteArray, File)): - value = self.from_unicode(xtba_type.type, elt.text, - self.binary_encoding) + value = self.from_unicode( + xtba_type.type, elt.text, self.binary_encoding + ) else: value = self.from_unicode(xtba_type.type, elt.text) @@ -979,7 +1006,7 @@ def complex_from_element(self, ctx, cls, elt): if isinstance(c, etree._Comment): continue - key = c.tag.split('}', 1)[-1] + key = c.tag.split("}", 1)[-1] frequencies[key] += 1 member = flat_type_info.get(key, None) @@ -1037,8 +1064,7 @@ def complex_from_element(self, ctx, cls, elt): continue if issubclass(member.type, (ByteArray, File)): - value = self.from_unicode(member.type, value_str, - self.binary_encoding) + value = self.from_unicode(member.type, value_str, self.binary_encoding) else: value = self.from_unicode(member.type, value_str) @@ -1050,13 +1076,15 @@ def complex_from_element(self, ctx, cls, elt): val = frequencies.get(key, 0) attr = self.get_cls_attrs(c) if val < attr.min_occurs or val > attr.max_occurs: - raise Fault('Client.ValidationError', '%r member does not ' - 'respect frequency constraints.' % key) + raise Fault( + "Client.ValidationError", + "%r member does not " "respect frequency constraints." % key, + ) return inst def array_from_element(self, ctx, cls, element): - retval = [ ] + retval = [] (serializer,) = cls._type_info.values() for child in element.getchildren(): @@ -1072,20 +1100,20 @@ def iterable_from_element(self, ctx, cls, element): def enum_from_element(self, ctx, cls, element): if self.validator is self.SOFT_VALIDATION and not ( - cls.validate_string(cls, element.text)): + cls.validate_string(cls, element.text) + ): raise ValidationError(element.text) return getattr(cls, element.text) def fault_from_element(self, ctx, cls, element): - code = element.find('faultcode').text - string = element.find('faultstring').text - factor = element.find('faultactor') + code = element.find("faultcode").text + string = element.find("faultstring").text + factor = element.find("faultactor") if factor is not None: factor = factor.text - detail = element.find('detail') + detail = element.find("detail") - return cls(faultcode=code, faultstring=string, faultactor=factor, - detail=detail) + return cls(faultcode=code, faultstring=string, faultactor=factor, detail=detail) def xml_from_element(self, ctx, cls, element): children = element.getchildren() @@ -1118,43 +1146,49 @@ def dict_from_element(self, ctx, cls, element): def unicode_from_element(self, ctx, cls, element): if self.validator is self.SOFT_VALIDATION and not ( - cls.validate_string(cls, element.text)): + cls.validate_string(cls, element.text) + ): raise ValidationError(element.text) s = element.text if s is None: - s = '' + s = "" retval = self.from_unicode(cls, s) if self.validator is self.SOFT_VALIDATION and not ( - cls.validate_native(cls, retval)): + cls.validate_native(cls, retval) + ): raise ValidationError(retval) return retval def base_from_element(self, ctx, cls, element): if self.validator is self.SOFT_VALIDATION and not ( - cls.validate_string(cls, element.text)): + cls.validate_string(cls, element.text) + ): raise ValidationError(element.text) retval = self.from_unicode(cls, element.text) if self.validator is self.SOFT_VALIDATION and not ( - cls.validate_native(cls, retval)): + cls.validate_native(cls, retval) + ): raise ValidationError(retval) return retval def byte_array_from_element(self, ctx, cls, element): if self.validator is self.SOFT_VALIDATION and not ( - cls.validate_string(cls, element.text)): + cls.validate_string(cls, element.text) + ): raise ValidationError(element.text) retval = self.from_unicode(cls, element.text, self.binary_encoding) if self.validator is self.SOFT_VALIDATION and not ( - cls.validate_native(cls, retval)): + cls.validate_native(cls, retval) + ): raise ValidationError(retval) return retval diff --git a/spyne/protocol/yaml.py b/spyne/protocol/yaml.py index 1a9a46a1a..c7f4337e0 100644 --- a/spyne/protocol/yaml.py +++ b/spyne/protocol/yaml.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -26,34 +25,28 @@ from __future__ import absolute_import import logging + logger = logging.getLogger(__name__) -from spyne import ValidationError -from spyne.util import six +import yaml +from yaml.parser import ParserError + from spyne.model.binary import BINARY_ENCODING_BASE64 -from spyne.model.primitive import Boolean -from spyne.model.primitive import Integer -from spyne.model.primitive import Double -from spyne.model.fault import Fault +from spyne.model.fault import Fault, ValidationError +from spyne.model.primitive import Boolean, Double, Integer from spyne.protocol.dictdoc import HierDictDocument -import yaml - -from yaml.parser import ParserError try: - from yaml import CLoader as Loader from yaml import CDumper as Dumper - from yaml import CSafeLoader as SafeLoader + from yaml import CLoader as Loader from yaml import CSafeDumper as SafeDumper + from yaml import CSafeLoader as SafeLoader except ImportError: - from yaml import Loader - from yaml import Dumper - from yaml import SafeLoader - from yaml import SafeDumper + from yaml import Dumper, Loader, SafeDumper, SafeLoader -NON_NUMBER_TYPES = tuple({list, dict, six.text_type, six.binary_type}) +NON_NUMBER_TYPES = tuple({list, dict, str, bytes}) class YamlDocument(HierDictDocument): @@ -72,10 +65,10 @@ class YamlDocument(HierDictDocument): ``indent=4`` by default. """ - mime_type = 'text/yaml' + mime_type = "text/yaml" type = set(HierDictDocument.type) - type.add('yaml') + type.add("yaml") text_based = True @@ -84,21 +77,34 @@ class YamlDocument(HierDictDocument): # for test classes _decimal_as_string = True - def __init__(self, app=None, validator=None, mime_type=None, - ignore_uncap=False, - # DictDocument specific - ignore_wrappers=True, - complex_as=dict, - ordered=False, - polymorphic=False, - # YamlDocument specific - safe=True, - encoding='UTF-8', - allow_unicode=True, - **kwargs): - - super(YamlDocument, self).__init__(app, validator, mime_type, - ignore_uncap, ignore_wrappers, complex_as, ordered, polymorphic) + def __init__( + self, + app=None, + validator=None, + mime_type=None, + ignore_uncap=False, + # DictDocument specific + ignore_wrappers=True, + complex_as=dict, + ordered=False, + polymorphic=False, + # YamlDocument specific + safe=True, + encoding="UTF-8", + allow_unicode=True, + **kwargs, + ): + + super(YamlDocument, self).__init__( + app, + validator, + mime_type, + ignore_uncap, + ignore_wrappers, + complex_as, + ordered, + polymorphic, + ) self._from_unicode_handlers[Double] = self._ret_number self._from_unicode_handlers[Boolean] = self._ret_bool @@ -112,25 +118,24 @@ def __init__(self, app=None, validator=None, mime_type=None, dumper = Dumper if safe: loader = SafeLoader - dumper = SafeDumper + dumper = SafeDumper self.in_kwargs = dict(kwargs) self.out_kwargs = dict(kwargs) - self.in_kwargs['Loader'] = loader - self.out_kwargs['Dumper'] = dumper + self.in_kwargs["Loader"] = loader + self.out_kwargs["Dumper"] = dumper - loader.add_constructor('tag:yaml.org,2002:python/unicode', - _unicode_loader) + loader.add_constructor("tag:yaml.org,2002:python/unicode", _unicode_loader) - self.out_kwargs['encoding'] = encoding - self.out_kwargs['allow_unicode'] = allow_unicode + self.out_kwargs["encoding"] = encoding + self.out_kwargs["allow_unicode"] = allow_unicode - if not 'indent' in self.out_kwargs: - self.out_kwargs['indent'] = 4 + if not "indent" in self.out_kwargs: + self.out_kwargs["indent"] = 4 - if not 'default_flow_style' in self.out_kwargs: - self.out_kwargs['default_flow_style'] = False + if not "default_flow_style" in self.out_kwargs: + self.out_kwargs["default_flow_style"] = False def _ret(self, _, value): return value @@ -151,28 +156,23 @@ def create_in_document(self, ctx, in_string_encoding=None): """Sets ``ctx.in_document`` using ``ctx.in_string``.""" if in_string_encoding is None: - in_string_encoding = 'UTF-8' + in_string_encoding = "UTF-8" try: try: - s = b''.join(ctx.in_string).decode(in_string_encoding) + s = b"".join(ctx.in_string).decode(in_string_encoding) except TypeError: - s = ''.join(ctx.in_string) + s = "".join(ctx.in_string) ctx.in_document = yaml.load(s, **self.in_kwargs) except ParserError as e: - raise Fault('Client.YamlDecodeError', repr(e)) + raise Fault("Client.YamlDecodeError", repr(e)) - def create_out_string(self, ctx, out_string_encoding='utf8'): + def create_out_string(self, ctx, out_string_encoding="utf8"): """Sets ``ctx.out_string`` using ``ctx.out_document``.""" - ctx.out_string = (yaml.dump(o, **self.out_kwargs) - for o in ctx.out_document) - if six.PY2 and out_string_encoding is not None: - ctx.out_string = ( - yaml.dump(o, **self.out_kwargs).encode(out_string_encoding) - for o in ctx.out_document) + ctx.out_string = (yaml.dump(o, **self.out_kwargs) for o in ctx.out_document) def _unicode_loader(loader, node): diff --git a/spyne/server/__init__.py b/spyne/server/__init__.py index 5ab65844f..ef5bfd84a 100644 --- a/spyne/server/__init__.py +++ b/spyne/server/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # diff --git a/spyne/server/_base.py b/spyne/server/_base.py index d73468d41..f195c1795 100644 --- a/spyne/server/_base.py +++ b/spyne/server/_base.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,13 +17,15 @@ # import logging + logger = logging.getLogger(__name__) from inspect import isgenerator -from spyne import EventManager, Ignored from spyne.auxproc import process_contexts +from spyne.evmgr import EventManager from spyne.model import Fault, PushBase +from spyne.model._base import Ignored from spyne.protocol import ProtocolBase from spyne.util import Break, coroutine @@ -70,8 +71,7 @@ def generate_contexts(self, ctx, in_string_charset=None): # sets ctx.in_body_doc, ctx.in_header_doc and # ctx.method_request_string - self.app.in_protocol.decompose_incoming_envelope(ctx, - ProtocolBase.REQUEST) + self.app.in_protocol.decompose_incoming_envelope(ctx, ProtocolBase.REQUEST) # returns a list of contexts. multiple contexts can be returned # when the requested method also has bound auxiliary methods. @@ -84,7 +84,7 @@ def generate_contexts(self, ctx, in_string_charset=None): retval = (ctx,) - ctx.fire_event('method_exception_object') + ctx.fire_event("method_exception_object") return retval @@ -94,8 +94,7 @@ def get_in_object(self, ctx): try: # sets ctx.in_object and ctx.in_header - self.app.in_protocol.deserialize(ctx, - message=self.app.in_protocol.REQUEST) + self.app.in_protocol.deserialize(ctx, message=self.app.in_protocol.REQUEST) except Fault as e: logger.exception(e) @@ -105,7 +104,7 @@ def get_in_object(self, ctx): ctx.in_error = e ctx.out_error = e - ctx.fire_event('method_exception_object') + ctx.fire_event("method_exception_object") def get_out_object(self, ctx): """Calls the matched user function by passing it the ``ctx.in_object`` @@ -117,16 +116,18 @@ def get_out_object(self, ctx): else: raise ctx.in_error - if isinstance(ctx.out_object, (list, tuple)) \ - and len(ctx.out_object) > 0 \ - and isinstance(ctx.out_object[0], Ignored): + if ( + isinstance(ctx.out_object, (list, tuple)) + and len(ctx.out_object) > 0 + and isinstance(ctx.out_object[0], Ignored) + ): ctx.out_object = (None,) elif isinstance(ctx.out_object, Ignored): ctx.out_object = () def convert_pull_to_push(self, ctx, gen): - oobj, = ctx.out_object + (oobj,) = ctx.out_object if oobj is None: gen.throw(Break()) @@ -155,8 +156,11 @@ def get_out_string_pull(self, ctx): if ctx.out_document is None: ret = ctx.out_protocol.serialize(ctx, message=ProtocolBase.RESPONSE) - if isgenerator(ret) and ctx.out_object is not None and \ - len(ctx.out_object) == 1: + if ( + isgenerator(ret) + and ctx.out_object is not None + and len(ctx.out_object) == 1 + ): if len(ctx.pusher_stack) > 0: # we suspend request processing here because there now # seems to be a PushBase waiting for input. @@ -166,19 +170,19 @@ def get_out_string_pull(self, ctx): def finalize_context(self, ctx): if ctx.out_error is None: - ctx.fire_event('method_return_document') + ctx.fire_event("method_return_document") else: - ctx.fire_event('method_exception_document') + ctx.fire_event("method_exception_document") ctx.out_protocol.create_out_string(ctx) if ctx.out_error is None: - ctx.fire_event('method_return_string') + ctx.fire_event("method_return_string") else: - ctx.fire_event('method_exception_string') + ctx.fire_event("method_exception_string") if ctx.out_string is None: - ctx.out_string = (b'',) + ctx.out_string = (b"",) # for backwards compatibility get_out_string = get_out_string_pull @@ -191,7 +195,7 @@ def get_out_string_push(self, ctx): if isgenerator(ret): try: while True: - y = (yield) + y = yield ret.send(y) except Break: @@ -217,7 +221,7 @@ def init_interim_push(self, ret, p_ctx, gen): # the machinery in ServerBase can initialize them using this function. # fire events - p_ctx.fire_event('method_return_push') + p_ctx.fire_event("method_return_push") def _cb_push_finish(): process_contexts(self, (), p_ctx) @@ -239,25 +243,25 @@ def init_root_push(self, ret, p_ctx, others): assert isinstance(ret, PushBase) if ret in p_ctx.pusher_stack: - logger.warning('PushBase reinit avoided.') + logger.warning("PushBase reinit avoided.") return p_ctx.pusher_stack.append(ret) # fire events - p_ctx.fire_event('method_return_push') + p_ctx.fire_event("method_return_push") # start push serialization gen = self.get_out_string_push(p_ctx) - assert isgenerator(gen), "It looks like this protocol is not " \ - "async-compliant yet." + assert isgenerator(gen), ( + "It looks like this protocol is not " "async-compliant yet." + ) def _cb_push_finish(): process_contexts(self, others, p_ctx) - retval = self.pusher_init(p_ctx, gen, _cb_push_finish, ret, - interim=False) + retval = self.pusher_init(p_ctx, gen, _cb_push_finish, ret, interim=False) self.pusher_try_close(p_ctx, ret, retval) diff --git a/spyne/server/django.py b/spyne/server/django.py index e6d07cbc7..855a95f6d 100644 --- a/spyne/server/django.py +++ b/spyne/server/django.py @@ -25,28 +25,30 @@ from __future__ import absolute_import import logging + logger = logging.getLogger(__name__) from functools import update_wrapper +from django.http import Http404, HttpResponse, HttpResponseNotAllowed +from django.views.decorators.csrf import csrf_exempt + from spyne import Address -from spyne.application import get_fault_string_from_exception, Application +from spyne.application import Application, get_fault_string_from_exception from spyne.auxproc import process_contexts from spyne.model.fault import Fault -from spyne.protocol.soap import Soap11 from spyne.protocol.http import HttpRpc +from spyne.protocol.soap import Soap11 from spyne.server.http import HttpBase, HttpMethodContext, HttpTransportContext from spyne.server.wsgi import WsgiApplication from spyne.util import _bytes_join from spyne.util.address import address_parser -from django.http import HttpResponse, HttpResponseNotAllowed, Http404 -from django.views.decorators.csrf import csrf_exempt - try: from django.http import StreamingHttpResponse except ImportError as _import_error: _local_import_error = _import_error + def StreamingHttpResponse(*args, **kwargs): raise _local_import_error @@ -64,7 +66,7 @@ def __call__(self, request): def start_response(status, headers): # Status is one of spyne.const.http - status, reason = status.split(' ', 1) + status, reason = status.split(" ", 1) retval.status_code = int(status) for header, value in headers: @@ -82,8 +84,8 @@ def start_response(status, headers): # would hang waiting for extra request data. Use DjangoServer instead # of monkeypatching wsgi.inpu. - #environ['wsgi.input'] = request - #environ['wsgi.multithread'] = False + # environ['wsgi.input'] = request + # environ['wsgi.multithread'] = False response = WsgiApplication.__call__(self, environ, start_response) self.set_response(retval, response) @@ -114,7 +116,7 @@ def get_request_method(self): return self.req.method def get_request_content_type(self): - return self.req.META['CONTENT_TYPE'] + return self.req.META["CONTENT_TYPE"] def get_path_and_qs(self): return self.req.get_full_path() @@ -123,8 +125,9 @@ def get_cookie(self, key): return self.req.COOKIES[key] def get_peer(self): - addr, port = address_parser.get_ip(self.req.META),\ - address_parser.get_port(self.req.META) + addr, port = address_parser.get_ip(self.req.META), address_parser.get_port( + self.req.META + ) if address_parser.is_valid_ipv4(addr, port): return Address(type=Address.TCP4, host=addr, port=port) @@ -175,12 +178,12 @@ def handle_rpc(self, request, *args, **kwargs): except Exception as e: logger.exception(e) - p_ctx.out_error = Fault('Server', - get_fault_string_from_exception(e)) + p_ctx.out_error = Fault("Server", get_fault_string_from_exception(e)) return self.handle_error(p_ctx, others, p_ctx.out_error) - have_protocol_headers = (isinstance(p_ctx.out_protocol, HttpRpc) and - p_ctx.out_header_doc is not None) + have_protocol_headers = ( + isinstance(p_ctx.out_protocol, HttpRpc) and p_ctx.out_header_doc is not None + ) if have_protocol_headers: p_ctx.transport.resp_headers.update(p_ctx.out_header_doc) @@ -191,17 +194,16 @@ def handle_rpc(self, request, *args, **kwargs): if self.chunked: response = StreamingHttpResponse(p_ctx.out_string) else: - response = HttpResponse(b''.join(p_ctx.out_string)) + response = HttpResponse(b"".join(p_ctx.out_string)) return self.response(response, p_ctx, others) def handle_wsdl(self, request, *args, **kwargs): """Return services WSDL.""" - ctx = HttpMethodContext(self, request, - 'text/xml; charset=utf-8') + ctx = HttpMethodContext(self, request, "text/xml; charset=utf-8") if self.doc.wsdl11 is None: - raise Http404('WSDL is not available') + raise Http404("WSDL is not available") if self._wsdl is None: # Interface document building is not thread safe so we don't use @@ -231,11 +233,12 @@ def handle_error(self, p_ctx, others, error): """ if p_ctx.transport.resp_code is None: - p_ctx.transport.resp_code = \ - p_ctx.out_protocol.fault_to_http_response_code(error) + p_ctx.transport.resp_code = p_ctx.out_protocol.fault_to_http_response_code( + error + ) self.get_out_string(p_ctx) - resp = HttpResponse(b''.join(p_ctx.out_string)) + resp = HttpResponse(b"".join(p_ctx.out_string)) return self.response(resp, p_ctx, others, error) def get_contexts(self, request): @@ -245,8 +248,9 @@ def get_contexts(self, request): :returns: generated contexts """ - initial_ctx = DjangoHttpMethodContext(self, request, - self.app.out_protocol.mime_type) + initial_ctx = DjangoHttpMethodContext( + self, request, self.app.out_protocol.mime_type + ) initial_ctx.in_string = [request.body] return self.generate_contexts(initial_ctx) @@ -285,16 +289,24 @@ class DjangoView(object): application = None server = None services = () - tns = 'spyne.application' - name = 'Application' - in_protocol = Soap11(validator='lxml') + tns = "spyne.application" + name = "Application" + in_protocol = Soap11(validator="lxml") out_protocol = Soap11() interface = None chunked = False cache_wsdl = True - http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', - 'options', 'trace'] + http_method_names = [ + "get", + "post", + "put", + "patch", + "delete", + "head", + "options", + "trace", + ] def __init__(self, server, **kwargs): self.server = server @@ -312,14 +324,16 @@ def as_view(cls, **initkwargs): # sanitize keyword arguments for key in initkwargs: if key in cls.http_method_names: - raise TypeError("You tried to pass in the %s method name as a " - "keyword argument to %s(). Don't do that." - % (key, cls.__name__)) + raise TypeError( + "You tried to pass in the %s method name as a " + "keyword argument to %s(). Don't do that." % (key, cls.__name__) + ) if not hasattr(cls, key): - raise TypeError("%s() received an invalid keyword %r. as_view " - "only accepts arguments that are already " - "attributes of the class." % (cls.__name__, - key)) + raise TypeError( + "%s() received an invalid keyword %r. as_view " + "only accepts arguments that are already " + "attributes of the class." % (cls.__name__, key) + ) def get(key): value = initkwargs.get(key) @@ -329,20 +343,20 @@ def pop(key): value = initkwargs.pop(key, None) return value if value is not None else getattr(cls, key) - application = get('application') or Application( - services=get('services'), - tns=get('tns'), - name=get('name'), - in_protocol=get('in_protocol'), - out_protocol=get('out_protocol'), + application = get("application") or Application( + services=get("services"), + tns=get("tns"), + name=get("name"), + in_protocol=get("in_protocol"), + out_protocol=get("out_protocol"), + ) + server = pop("server") or DjangoServer( + application, chunked=get("chunked"), cache_wsdl=get("cache_wsdl") ) - server = pop('server') or DjangoServer(application, - chunked=get('chunked'), - cache_wsdl=get('cache_wsdl')) def view(request, *args, **kwargs): self = cls(server=server, **initkwargs) - if hasattr(self, 'get') and not hasattr(self, 'head'): + if hasattr(self, "get") and not hasattr(self, "head"): self.head = self.get self.request = request self.args = args @@ -363,8 +377,9 @@ def dispatch(self, request, *args, **kwargs): # defer to the error handler. Also defer to the error handler if the # request method isn't on the approved list. if request.method.lower() in self.http_method_names: - handler = getattr(self, request.method.lower(), - self.http_method_not_allowed) + handler = getattr( + self, request.method.lower(), self.http_method_not_allowed + ) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs) @@ -376,17 +391,20 @@ def post(self, request, *args, **kwargs): return self.server.handle_rpc(request, *args, **kwargs) def http_method_not_allowed(self, request, *args, **kwargs): - logger.warning('Method Not Allowed (%s): %s', request.method, - request.path, extra={'status_code': 405, 'request': - self.request}) + logger.warning( + "Method Not Allowed (%s): %s", + request.method, + request.path, + extra={"status_code": 405, "request": self.request}, + ) return HttpResponseNotAllowed(self._allowed_methods()) def options(self, request, *args, **kwargs): """Handle responding to requests for the OPTIONS HTTP verb.""" response = HttpResponse() - response['Allow'] = ', '.join(self._allowed_methods()) - response['Content-Length'] = '0' + response["Allow"] = ", ".join(self._allowed_methods()) + response["Content-Length"] = "0" return response def _allowed_methods(self): diff --git a/spyne/server/http.py b/spyne/server/http.py index e80dbde76..eecd01e0e 100644 --- a/spyne/server/http.py +++ b/spyne/server/http.py @@ -18,22 +18,21 @@ # from collections import defaultdict - from email import utils -from email.utils import encode_rfc2231 from email.message import tspecials +from email.utils import encode_rfc2231 -from spyne import TransportContext, MethodDescriptor, MethodContext, Redirect -from spyne.server import ServerBase +from spyne.const.http import HTTP_301, HTTP_302, HTTP_303, HTTP_307, gen_body_redirect +from spyne.context import MethodContext, TransportContext +from spyne.descriptor import MethodDescriptor +from spyne.error import Redirect from spyne.protocol.http import HttpPattern -from spyne.const.http import gen_body_redirect, HTTP_301, HTTP_302, HTTP_303, \ - HTTP_307 +from spyne.server import ServerBase class HttpRedirect(Redirect): def __init__(self, ctx, location, orig_exc=None, code=HTTP_302): - super(HttpRedirect, self) \ - .__init__(ctx, location, orig_exc=orig_exc) + super(HttpRedirect, self).__init__(ctx, location, orig_exc=orig_exc) self.ctx = ctx self.location = location @@ -48,6 +47,7 @@ def do_redirect(self): self.ctx.transport.respond(self.code, location=self.location) + # # Plagiarized HttpTransport.add_header() and _formatparam() function from # Python 2.7 stdlib. @@ -73,24 +73,24 @@ def _formatparam(param, value=None, quote=True): # instance. RFC 2231 encoded values are never quoted, per RFC. if isinstance(value, tuple): # Encode as per RFC 2231 - param += '*' + param += "*" value = encode_rfc2231(value[2], value[0], value[1]) - return '%s=%s' % (param, value) + return "%s=%s" % (param, value) try: - value.encode('ascii') + value.encode("ascii") except UnicodeEncodeError: - param += '*' - value = encode_rfc2231(value, 'utf-8', '') - return '%s=%s' % (param, value) + param += "*" + value = encode_rfc2231(value, "utf-8", "") + return "%s=%s" % (param, value) # BAW: Please check this. I think that if quote is set it should # force quoting even if not necessary. if quote or tspecials.search(value): return '%s="%s"' % (param, utils.quote(value)) - return '%s=%s' % (param, value) + return "%s=%s" % (param, value) class HttpTransportContext(TransportContext): @@ -98,7 +98,7 @@ class HttpTransportContext(TransportContext): :class:`HttpMethodContext` class and its subclasses.""" def __init__(self, parent, transport, request, content_type): - super(HttpTransportContext, self).__init__(parent, transport, 'http') + super(HttpTransportContext, self).__init__(parent, transport, "http") self.req = request """HTTP Request. This is transport-specific""" @@ -119,18 +119,18 @@ def __init__(self, parent, transport, request, content_type): """The error when handling WSDL requests.""" def get_mime_type(self): - return self.resp_headers.get('Content-Type', None) + return self.resp_headers.get("Content-Type", None) def set_mime_type(self, what): - self.resp_headers['Content-Type'] = what + self.resp_headers["Content-Type"] = what def respond(self, resp_code, **kwargs): self.resp_code = resp_code if resp_code in (HTTP_301, HTTP_302, HTTP_303, HTTP_307): - l = kwargs.pop('location') - self.resp_headers['Location'] = l + l = kwargs.pop("location") + self.resp_headers["Location"] = l self.parent.out_string = [gen_body_redirect(resp_code, l)] - self.mime_type = 'text/html' + self.mime_type = "text/html" else: # So that deserialization is skipped. @@ -163,15 +163,15 @@ def gen_header(_value, **kwargs): for k, v in kwargs.items(): if v is None: - parts.append(k.replace('_', '-')) + parts.append(k.replace("_", "-")) else: - parts.append(_formatparam(k.replace('_', '-'), v)) + parts.append(_formatparam(k.replace("_", "-"), v)) if _value is not None: parts.insert(0, _value) - return '; '.join(parts) + return "; ".join(parts) def add_header(self, _name, _value, **kwargs): """Extended header setting. @@ -221,8 +221,9 @@ class HttpMethodContext(MethodContext): def __init__(self, transport, req_env, content_type): super(HttpMethodContext, self).__init__(transport, MethodContext.SERVER) - self.transport = self.HttpTransportContext(self, transport, - req_env, content_type) + self.transport = self.HttpTransportContext( + self, transport, req_env, content_type + ) """Holds the HTTP-specific information""" def set_out_protocol(self, what): @@ -237,14 +238,18 @@ def set_out_protocol(self, what): class HttpBase(ServerBase): - transport = 'http://schemas.xmlsoap.org/soap/http' - - SLASH = '/' - SLASHPER = '/%s' - - def __init__(self, app, chunked=False, - max_content_length=2 * 1024 * 1024, - block_length=8 * 1024): + transport = "http://schemas.xmlsoap.org/soap/http" + + SLASH = "/" + SLASHPER = "/%s" + + def __init__( + self, + app, + chunked=False, + max_content_length=2 * 1024 * 1024, + block_length=8 * 1024, + ): super(HttpBase, self).__init__(app) self.chunked = chunked @@ -263,8 +268,9 @@ def __init__(self, app, chunked=False, # this makes sure similar addresses with patterns are evaluated after # addresses with wildcards, which puts the more specific addresses to # the front. - self._http_patterns = list(reversed(sorted(self._http_patterns, - key=lambda x: (x.address, x.host) ))) + self._http_patterns = list( + reversed(sorted(self._http_patterns, key=lambda x: (x.address, x.host))) + ) @classmethod def get_patt_verb(cls, patt): @@ -278,7 +284,7 @@ def get_patt_host(cls, patt): def get_patt_address(cls, patt): return patt.address_re - def match_pattern(self, ctx, method='', path='', host=''): + def match_pattern(self, ctx, method="", path="", host=""): """Sets ctx.method_request_string if there's a match. It's O(n) which means you should keep your number of patterns as low as possible. @@ -303,7 +309,7 @@ def match_pattern(self, ctx, method='', path='', host=''): if not (match.span() == (0, len(method))): continue - for k,v in match.groupdict().items(): + for k, v in match.groupdict().items(): params[k].append(v) if patt.host is not None: @@ -328,7 +334,7 @@ def match_pattern(self, ctx, method='', path='', host=''): if not (match.span() == (0, len(path))): continue - for k,v in match.groupdict().items(): + for k, v in match.groupdict().items(): params[k].append(v) d = patt.endpoint diff --git a/spyne/server/msgpack.py b/spyne/server/msgpack.py index 1c0fd4d63..4ed802a03 100644 --- a/spyne/server/msgpack.py +++ b/spyne/server/msgpack.py @@ -20,23 +20,25 @@ from __future__ import absolute_import import logging -logger = logging.getLogger(__name__) -import msgpack +logger = logging.getLogger(__name__) -from mmap import mmap from collections import OrderedDict +from mmap import mmap + +import msgpack -from spyne import MethodContext, TransportContext, Address +from spyne import Address, MethodContext, TransportContext from spyne.auxproc import process_contexts -from spyne.error import ValidationError, InternalError +from spyne.error import InternalError, ValidationError from spyne.server import ServerBase -from spyne.util.six import binary_type try: from twisted.internet.defer import Deferred except ImportError as e: - def Deferred(*_, **__): raise e + + def Deferred(*_, **__): + raise e MSGPACK_SHELL_OVERHEAD = 10 @@ -45,7 +47,7 @@ def Deferred(*_, **__): raise e def _process_v1_msg(prot, msg): header = None body = msg[1] - if not isinstance(body, (binary_type, mmap, memoryview)): + if not isinstance(body, (bytes, mmap, memoryview)): raise ValidationError(body, "Body must be a bytestream.") if len(msg) > 2: @@ -78,7 +80,7 @@ def get_peer(self): class MessagePackOobMethodContext(object): - __slots__ = 'd' + __slots__ = "d" def __init__(self): if Deferred is not None: @@ -120,9 +122,7 @@ class MessagePackTransportBase(ServerBase): def __init__(self, app): super(MessagePackTransportBase, self).__init__(app) - self._version_map = { - self.IN_REQUEST: _process_v1_msg - } + self._version_map = {self.IN_REQUEST: _process_v1_msg} def produce_contexts(self, msg): """Produce contexts based on incoming message. @@ -136,13 +136,15 @@ def produce_contexts(self, msg): if not len(msg) >= 2: logger.debug("Incoming request: %r", msg) - raise ValidationError(len(msg), "Request must have at least two " - "elements. It has %r") + raise ValidationError( + len(msg), "Request must have at least two " "elements. It has %r" + ) if not isinstance(msg[0], int): logger.debug("Incoming request: %r", msg) - raise ValidationError(msg[0], "Request version must be an integer. " - "It was %r") + raise ValidationError( + msg[0], "Request version must be an integer. " "It was %r" + ) processor = self._version_map.get(msg[0], None) if processor is None: @@ -200,8 +202,9 @@ def handle_transport_error(self, error): return msgpack.dumps(str(error)) def pack(self, ctx): - ctx.out_string = msgpack.packb([self.OUT_RESPONSE_NO_ERROR, - b''.join(ctx.out_string)]), + ctx.out_string = ( + msgpack.packb([self.OUT_RESPONSE_NO_ERROR, b"".join(ctx.out_string)]), + ) class MessagePackServerBase(MessagePackTransportBase): diff --git a/spyne/server/null.py b/spyne/server/null.py index 27b1f0780..a81dad092 100644 --- a/spyne/server/null.py +++ b/spyne/server/null.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -26,22 +25,21 @@ from __future__ import absolute_import import logging -logger = logging.getLogger(__name__) -from spyne import MethodContext, BODY_STYLE_BARE, ComplexModelBase, \ - BODY_STYLE_EMPTY, Ignored +logger = logging.getLogger(__name__) from spyne.client import Factory -from spyne.const.ansi_color import LIGHT_RED -from spyne.const.ansi_color import LIGHT_BLUE -from spyne.const.ansi_color import END_COLOR +from spyne.const.ansi_color import END_COLOR, LIGHT_BLUE, LIGHT_RED +from spyne.context import MethodContext +from spyne.descriptor import BODY_STYLE_BARE, BODY_STYLE_EMPTY +from spyne.model._base import Ignored +from spyne.model.complex import ComplexModelBase from spyne.server import ServerBase - -_big_header = ('=' * 40) + LIGHT_RED -_big_footer = END_COLOR + ('=' * 40) -_small_header = ('-' * 20) + LIGHT_BLUE -_small_footer = END_COLOR + ('-' * 20) +_big_header = ("=" * 40) + LIGHT_RED +_big_footer = END_COLOR + ("=" * 40) +_small_header = ("-" * 20) + LIGHT_BLUE +_small_footer = END_COLOR + ("-" * 20) class NullServer(ServerBase): @@ -57,10 +55,10 @@ class NullServer(ServerBase): to hide context delimiters in logs. """ - transport = 'noconn://null.spyne' + transport = "noconn://null.spyne" MethodContext = MethodContext - def __init__(self, app, ostr=False, locale='C', appinit=True): + def __init__(self, app, ostr=False, locale="C", appinit=True): self.do_appinit = appinit super(NullServer, self).__init__(app) @@ -80,8 +78,7 @@ def get_wsdl(self): return self.app.get_interface_document(self.url) def set_options(self, **kwargs): - self.service.in_header = kwargs.get('soapheaders', - self.service.in_header) + self.service.in_header = kwargs.get("soapheaders", self.service.in_header) def get_services(self): return self.app.interface.service_method_map @@ -95,8 +92,15 @@ def __init__(self, server, app, is_async): self.is_async = is_async def __getattr__(self, key): - return _FunctionCall(self._app, self._server, key, self.in_header, - self._server.ostr, self._server.locale, self.is_async) + return _FunctionCall( + self._app, + self._server, + key, + self.in_header, + self._server.ostr, + self._server.locale, + self.is_async, + ) def __getitem__(self, key): return self.__getattr__(key) @@ -143,8 +147,9 @@ def __call__(self, *args, **kwargs): ctx.in_object[i] = val if ctx.descriptor.body_style == BODY_STYLE_BARE: - ctx.in_object = ctx.descriptor.in_message \ - .get_serialization_instance(ctx.in_object) + ctx.in_object = ctx.descriptor.in_message.get_serialization_instance( + ctx.in_object + ) if cnt == 0: p_ctx = ctx @@ -154,15 +159,12 @@ def __call__(self, *args, **kwargs): # do # logging.getLogger('spyne.server.null').setLevel(logging.CRITICAL) # to hide the following - logger.warning("%s start context %s" % (_small_header, - _small_footer)) - logger.info("%r.%r" % (ctx.service_class, - ctx.descriptor.function)) + logger.warning("%s start context %s" % (_small_header, _small_footer)) + logger.info("%r.%r" % (ctx.service_class, ctx.descriptor.function)) try: self.app.process_request(ctx) finally: - logger.warning("%s end context %s" % (_small_header, - _small_footer)) + logger.warning("%s end context %s" % (_small_header, _small_footer)) if cnt == 0: if self._async and isinstance(ctx.out_object[0], Deferred): @@ -204,9 +206,11 @@ def _cb_sync(ctx, cnt, fc): raise ctx.out_error else: - if isinstance(ctx.out_object, (list, tuple)) \ - and len(ctx.out_object) > 0 \ - and isinstance(ctx.out_object[0], Ignored): + if ( + isinstance(ctx.out_object, (list, tuple)) + and len(ctx.out_object) > 0 + and isinstance(ctx.out_object[0], Ignored) + ): retval = ctx.out_object[0] elif ctx.descriptor.is_out_bare(): diff --git a/spyne/server/pyramid.py b/spyne/server/pyramid.py index 7319da2db..56c2311c4 100644 --- a/spyne/server/pyramid.py +++ b/spyne/server/pyramid.py @@ -25,6 +25,7 @@ from __future__ import absolute_import from pyramid.response import Response + from spyne.server.wsgi import WsgiApplication @@ -35,14 +36,13 @@ def __call__(self, request): retval = Response() def start_response(status, headers): - status, reason = status.split(' ', 1) + status, reason = status.split(" ", 1) retval.status_int = int(status) for header, value in headers: retval.headers[header] = value - response = WsgiApplication.__call__(self, request.environ, - start_response) + response = WsgiApplication.__call__(self, request.environ, start_response) retval.body = b"".join(response) return retval diff --git a/spyne/server/twisted/__init__.py b/spyne/server/twisted/__init__.py index c22dcaa11..1e4f3bb93 100644 --- a/spyne/server/twisted/__init__.py +++ b/spyne/server/twisted/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # diff --git a/spyne/server/twisted/_base.py b/spyne/server/twisted/_base.py index 98a386c88..c60ff5c21 100644 --- a/spyne/server/twisted/_base.py +++ b/spyne/server/twisted/_base.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -20,7 +19,6 @@ from twisted.internet.defer import Deferred from twisted.internet.interfaces import IPullProducer from twisted.web.iweb import UNKNOWN_LENGTH - from zope.interface import implementer @@ -33,7 +31,7 @@ def __init__(self, body, consumer): # check to see if we can determine the length try: - len(body) # iterator? + len(body) # iterator? self.length = sum([len(fragment) for fragment in body]) self.body = iter(body) @@ -63,17 +61,22 @@ def pauseProducing(self): def stopProducing(self): if self.deferred is not None: - self.deferred.errback( - Exception("Consumer asked us to stop producing")) + self.deferred.errback(Exception("Consumer asked us to stop producing")) self.deferred = None from spyne import Address -_TYPE_MAP = {'TCP': Address.TCP4, 'TCP6': Address.TCP6, - 'UDP': Address.UDP4, 'UDP6': Address.UDP6} + +_TYPE_MAP = { + "TCP": Address.TCP4, + "TCP6": Address.TCP6, + "UDP": Address.UDP4, + "UDP6": Address.UDP6, +} + def _address_from_twisted_address(peer): - return Address( - type=_TYPE_MAP.get(peer.type, None), host=peer.host, port=peer.port) + return Address(type=_TYPE_MAP.get(peer.type, None), host=peer.host, port=peer.port) + Address.from_twisted_address = staticmethod(_address_from_twisted_address) diff --git a/spyne/server/twisted/http.py b/spyne/server/twisted/http.py index fda93d152..477647fcd 100644 --- a/spyne/server/twisted/http.py +++ b/spyne/server/twisted/http.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -40,59 +39,46 @@ from __future__ import absolute_import import logging + logger = logging.getLogger(__name__) -import re import cgi import gzip +import re import shutil import threading - -from os import fstat -from mmap import mmap -from inspect import isclass from collections import namedtuple +from inspect import isclass +from mmap import mmap +from os import fstat from tempfile import TemporaryFile +from urllib.parse import unquote +from urllib.request import unquote_to_bytes -from twisted.web import static -from twisted.web.server import NOT_DONE_YET, Request -from twisted.web.resource import Resource, NoResource, ForbiddenResource -from twisted.web.static import getTypeAndEncoding -from twisted.python.log import err -from twisted.python.failure import Failure from twisted.internet import reactor -from twisted.internet.task import deferLater from twisted.internet.defer import Deferred +from twisted.internet.task import deferLater from twisted.internet.threads import deferToThread +from twisted.python.failure import Failure +from twisted.python.log import err +from twisted.web import static +from twisted.web.resource import ForbiddenResource, NoResource, Resource +from twisted.web.server import NOT_DONE_YET, Request +from twisted.web.static import getTypeAndEncoding -from spyne import Redirect, Address -from spyne.application import logger_server -from spyne.application import get_fault_string_from_exception - -from spyne.util import six -from spyne.error import InternalError, ValidationError +from spyne import Address, Redirect +from spyne.application import get_fault_string_from_exception, logger_server from spyne.auxproc import process_contexts -from spyne.const.ansi_color import LIGHT_GREEN -from spyne.const.ansi_color import END_COLOR -from spyne.const.http import HTTP_404, HTTP_200 - -from spyne.model import PushBase, File, ComplexModelBase +from spyne.const.ansi_color import END_COLOR, LIGHT_GREEN +from spyne.const.http import HTTP_200, HTTP_404 +from spyne.error import InternalError, ValidationError +from spyne.model import ComplexModelBase, File, PushBase from spyne.model.fault import Fault - from spyne.protocol.http import HttpRpc - -from spyne.server.http import HttpBase -from spyne.server.http import HttpMethodContext -from spyne.server.http import HttpTransportContext -from spyne.server.twisted._base import Producer +from spyne.server.http import HttpBase, HttpMethodContext, HttpTransportContext from spyne.server.twisted import log_and_let_go - +from spyne.server.twisted._base import Producer from spyne.util.address import address_parser -from spyne.util.six import text_type, string_types -from spyne.util.six.moves.urllib.parse import unquote - -if not six.PY2: - from urllib.request import unquote_to_bytes def _render_file(file, request): @@ -103,10 +89,9 @@ def _render_file(file, request): file.restat(False) if file.type is None: - file.type, file.encoding = getTypeAndEncoding(file.basename(), - file.contentTypes, - file.contentEncodings, - file.defaultType) + file.type, file.encoding = getTypeAndEncoding( + file.basename(), file.contentTypes, file.contentEncodings, file.defaultType + ) if not file.exists(): return file.childNotFound.render(request) @@ -114,7 +99,7 @@ def _render_file(file, request): if file.isdir(): return file.redirect(request) - request.setHeader('accept-ranges', 'bytes') + request.setHeader("accept-ranges", "bytes") try: fileForReading = file.openForReading() @@ -126,13 +111,13 @@ def _render_file(file, request): else: raise - #if request.setLastModified(file.getmtime()) is CACHED: + # if request.setLastModified(file.getmtime()) is CACHED: # return '' producer = file.makeProducer(request, fileForReading) - if request.method == 'HEAD': - return '' + if request.method == "HEAD": + return "" producer.start() # and make sure the connection doesn't get closed @@ -165,25 +150,25 @@ def _reconstruct_url(request): is_secure = request.getHeader(b"x-forwarded-proto") if is_secure is not None: - is_secure = is_secure == 'https' + is_secure = is_secure == "https" if server_name is None: - server_name = request.getRequestHostname().decode('ascii') + server_name = request.getRequestHostname().decode("ascii") if server_port is None: server_port = request.getHost().port if is_secure is None: is_secure = bool(request.isSecure()) if (is_secure, server_port) not in ((True, 443), (False, 80)): - server_name = '%s:%d' % (server_name, server_port) + server_name = "%s:%d" % (server_name, server_port) if is_secure: - url_scheme = 'https' + url_scheme = "https" else: - url_scheme = 'http' + url_scheme = "http" uri = _decode_path(request.uri) - return ''.join([url_scheme, "://", server_name, uri]) + return "".join([url_scheme, "://", server_name, uri]) class _Transformer(object): @@ -192,16 +177,12 @@ def __init__(self, req): def get(self, key, default): key = key.lower() - if six.PY2: - if key.startswith((b'http_', b'http-')): + if isinstance(key, bytes): + if key.startswith((b"http_", b"http-")): key = key[5:] else: - if isinstance(key, bytes): - if key.startswith((b'http_', b'http-')): - key = key[5:] - else: - if key.startswith(('http_', 'http-')): - key = key[5:] + if key.startswith(("http_", "http-")): + key = key[5:] retval = self.req.getHeader(key) if retval is None: @@ -211,10 +192,10 @@ def get(self, key, default): class TwistedHttpTransportContext(HttpTransportContext): def set_mime_type(self, what): - if isinstance(what, text_type): - what = what.encode('ascii', errors='replace') + if isinstance(what, str): + what = what.encode("ascii", errors="replace") super(TwistedHttpTransportContext, self).set_mime_type(what) - self.req.setHeader('Content-Type', what) + self.req.setHeader("Content-Type", what) def get_cookie(self, key): return self.req.getCookie(key) @@ -250,17 +231,14 @@ class TwistedHttpMethodContext(HttpMethodContext): def _decode_path(fragment): - if six.PY2: - return unquote(fragment) - return unquote_to_bytes(fragment) class TwistedHttpTransport(HttpBase): - SLASH = b'/' - SLASHPER = b'/%s' + SLASH = b"/" + SLASHPER = b"/%s" - KEY_ENCODING = 'utf8' + KEY_ENCODING = "utf8" @classmethod def get_patt_verb(cls, patt): @@ -274,12 +252,22 @@ def get_patt_host(cls, patt): def get_patt_address(cls, patt): return patt.address_b_re - def __init__(self, app, chunked=False, max_content_length=2 * 1024 * 1024, - block_length=8 * 1024): - super(TwistedHttpTransport, self).__init__(app, chunked=chunked, - max_content_length=max_content_length, block_length=block_length) + def __init__( + self, + app, + chunked=False, + max_content_length=2 * 1024 * 1024, + block_length=8 * 1024, + ): + super(TwistedHttpTransport, self).__init__( + app, + chunked=chunked, + max_content_length=max_content_length, + block_length=block_length, + ) self.reactor_thread = None + def _cb(): self.reactor_thread = threading.current_thread() @@ -287,17 +275,25 @@ def _cb(): def pusher_init(self, p_ctx, gen, _cb_push_finish, pusher, interim): if pusher.orig_thread != self.reactor_thread: - return deferToThread(super(TwistedHttpTransport, self).pusher_init, - p_ctx, gen, _cb_push_finish, pusher, interim) + return deferToThread( + super(TwistedHttpTransport, self).pusher_init, + p_ctx, + gen, + _cb_push_finish, + pusher, + interim, + ) return super(TwistedHttpTransport, self).pusher_init( - p_ctx, gen, _cb_push_finish, pusher, interim) + p_ctx, gen, _cb_push_finish, pusher, interim + ) @staticmethod def set_out_document_push(ctx): class _ISwearImAGenerator(object): def send(self, data): - if not data: return + if not data: + return ctx.out_stream.write(data) ctx.out_document = _ISwearImAGenerator() @@ -307,13 +303,15 @@ def pusher_try_close(self, ctx, pusher, retval): # when a *root* pusher has no more data to send. interim pushers don't # have to close anything. if isinstance(retval, Deferred): + def _eb_push_close(f): assert isinstance(f, Failure) logger.error(f.getTraceback()) - subretval = super(TwistedHttpTransport, self) \ - .pusher_try_close(ctx, pusher, retval) + subretval = super(TwistedHttpTransport, self).pusher_try_close( + ctx, pusher, retval + ) if not pusher.interim: ctx.out_stream.finish() @@ -328,22 +326,25 @@ def _eb_inner(f): return f if not isinstance(r, Deferred): - retval = super(TwistedHttpTransport, self) \ - .pusher_try_close(ctx, pusher, r) + retval = super(TwistedHttpTransport, self).pusher_try_close( + ctx, pusher, r + ) if not pusher.interim: ctx.out_stream.finish() return retval - return r \ - .addCallback(_cb_push_close) \ - .addErrback(_eb_inner) \ + return ( + r.addCallback(_cb_push_close) + .addErrback(_eb_inner) .addErrback(log_and_let_go, logger) + ) - return retval \ - .addCallback(_cb_push_close) \ - .addErrback(_eb_push_close) \ + return ( + retval.addCallback(_cb_push_close) + .addErrback(_eb_push_close) .addErrback(log_and_let_go, logger) + ) super(TwistedHttpTransport, self).pusher_try_close(ctx, pusher, retval) @@ -358,7 +359,7 @@ def _decode_dict_py2(self, d): for k, v in d.items(): l = [] for v2 in v: - if isinstance(v2, string_types): + if isinstance(v2, str): l.append(unquote(v2)) else: l.append(v2) @@ -409,30 +410,30 @@ def decompose_incoming_envelope(self, prot, ctx, message): if l is None: l = ctx.in_body_doc[fi.field_name] = [] - l.append( - File.Value(name=fi.file_name, type=fi.file_type, data=fi.data) - ) + l.append(File.Value(name=fi.file_name, type=fi.file_type, data=fi.data)) # this is a huge hack because twisted seems to take the slashes in urls # too seriously. - postpath = getattr(request, 'realpostpath', None) + postpath = getattr(request, "realpostpath", None) if postpath is None: postpath = request.path if postpath is not None: postpath = _decode_path(postpath) - params = self.match_pattern(ctx, request.method, postpath, - request.getHeader(b'Host')) + params = self.match_pattern( + ctx, request.method, postpath, request.getHeader(b"Host") + ) - if ctx.method_request_string is None: # no pattern match - ctx.method_request_string = u'{%s}%s' % ( + if ctx.method_request_string is None: # no pattern match + ctx.method_request_string = "{%s}%s" % ( self.app.interface.get_tns(), - _decode_path(request.path.rsplit(b'/', 1)[-1]).decode("utf8"), + _decode_path(request.path.rsplit(b"/", 1)[-1]).decode("utf8"), ) - logger.debug(u"%sMethod name: %r%s" % (LIGHT_GREEN, - ctx.method_request_string, END_COLOR)) + logger.debug( + "%sMethod name: %r%s" % (LIGHT_GREEN, ctx.method_request_string, END_COLOR) + ) for k, v in params.items(): val = ctx.in_body_doc.get(k, []) @@ -440,18 +441,13 @@ def decompose_incoming_envelope(self, prot, ctx, message): ctx.in_body_doc[k] = val r = {} - if six.PY2: - ctx.in_header_doc = self._decode_dict_py2(ctx.in_header_doc) - ctx.in_body_doc = self._decode_dict_py2(ctx.in_body_doc) - - else: - ctx.in_header_doc = self._decode_dict(ctx.in_header_doc) - ctx.in_body_doc = self._decode_dict(ctx.in_body_doc) + ctx.in_header_doc = self._decode_dict(ctx.in_header_doc) + ctx.in_body_doc = self._decode_dict(ctx.in_body_doc) # This is consistent with what server.wsgi does. - if request.method in ('POST', 'PUT', 'PATCH'): + if request.method in ("POST", "PUT", "PATCH"): for k, v in ctx.in_body_doc.items(): - if v == ['']: + if v == [""]: ctx.in_body_doc[k] = [None] logger.debug("%r", ctx.in_body_doc) @@ -471,14 +467,14 @@ def _get_file_info(ctx): request = ctx.transport.req headers = request.getAllHeaders() - content_type = headers.get('content-type', None) + content_type = headers.get("content-type", None) if content_type is None: return retval content = request.content - content_encoding = headers.get('content-encoding', None) - if content_encoding == b'gzip': + content_encoding = headers.get("content-encoding", None) + if content_encoding == b"gzip": request.content.seek(0) content = TemporaryFile() with gzip.GzipFile(fileobj=request.content) as ifstr: @@ -489,9 +485,9 @@ def _get_file_info(ctx): fp=content, headers=ctx.in_header_doc, environ={ - 'REQUEST_METHOD': request.method, - 'CONTENT_TYPE': content_type, - } + "REQUEST_METHOD": request.method, + "CONTENT_TYPE": content_type, + }, ) try: @@ -507,16 +503,17 @@ def _get_file_info(ctx): for field in fields: file_type = field.type - file_name = field.disposition_options.get('filename', None) + file_name = field.disposition_options.get("filename", None) if file_name is not None: - retval.append(_FileInfo(k, file_name, file_type, - [mmap(field.file.fileno(), 0)])) + retval.append( + _FileInfo(k, file_name, file_type, [mmap(field.file.fileno(), 0)]) + ) return retval def _has_fd(istr): - if not hasattr(istr, 'fileno'): + if not hasattr(istr, "fileno"): return False try: istr.fileno() @@ -531,10 +528,10 @@ def get_twisted_child_with_default(res, path, request): # http requests too seriously. i.e. it insists that a leaf node can only # handle the last path fragment. if res.prepath is None: - request.realprepath = b'/' + b'/'.join(request.prepath) + request.realprepath = b"/" + b"/".join(request.prepath) else: - if not res.prepath.startswith(b'/'): - request.realprepath = b'/' + res.prepath + if not res.prepath.startswith(b"/"): + request.realprepath = b"/" + res.prepath else: request.realprepath = res.prepath @@ -547,7 +544,8 @@ def get_twisted_child_with_default(res, path, request): retval = res else: request.realpostpath = request.path[ - len(path) + (0 if path.startswith(b'/') else 1):] + len(path) + (0 if path.startswith(b"/") else 1) : + ] return retval @@ -557,13 +555,20 @@ class TwistedWebResource(Resource): Resource. """ - def __init__(self, app, chunked=False, max_content_length=2 * 1024 * 1024, - block_length=8 * 1024, prepath=None): + def __init__( + self, + app, + chunked=False, + max_content_length=2 * 1024 * 1024, + block_length=8 * 1024, + prepath=None, + ): Resource.__init__(self) self.app = app - self.http_transport = TwistedHttpTransport(app, chunked, - max_content_length, block_length) + self.http_transport = TwistedHttpTransport( + app, chunked, max_content_length, block_length + ) self._wsdl = None self.prepath = prepath @@ -571,8 +576,9 @@ def getChildWithDefault(self, path, request): return get_twisted_child_with_default(self, path, request) def render(self, request): - if request.method == b'GET' and ( - request.uri.endswith(b'.wsdl') or request.uri.endswith(b'?wsdl')): + if request.method == b"GET" and ( + request.uri.endswith(b".wsdl") or request.uri.endswith(b"?wsdl") + ): return self.__handle_wsdl_request(request) return self.handle_rpc(request) @@ -594,7 +600,7 @@ def handle_rpc_error(self, p_ctx, others, error, request): p_ctx.out_object = error self.http_transport.get_out_string(p_ctx) - retval = b''.join(p_ctx.out_string) + retval = b"".join(p_ctx.out_string) p_ctx.close() @@ -603,15 +609,16 @@ def handle_rpc_error(self, p_ctx, others, error, request): return retval def handle_rpc(self, request): - initial_ctx = TwistedHttpMethodContext(self.http_transport, request, - self.http_transport.app.out_protocol.mime_type) + initial_ctx = TwistedHttpMethodContext( + self.http_transport, request, self.http_transport.app.out_protocol.mime_type + ) if _has_fd(request.content): f = request.content # it's best to avoid empty mappings. if fstat(f.fileno()).st_size == 0: - initial_ctx.in_string = [''] + initial_ctx.in_string = [""] else: initial_ctx.in_string = [mmap(f.fileno(), 0)] else: @@ -635,13 +642,11 @@ def handle_rpc(self, request): self.http_transport.get_in_object(p_ctx) if p_ctx.in_error: - return self.handle_rpc_error(p_ctx, others, p_ctx.in_error, - request) + return self.handle_rpc_error(p_ctx, others, p_ctx.in_error, request) self.http_transport.get_out_object(p_ctx) if p_ctx.out_error: - return self.handle_rpc_error(p_ctx, others, p_ctx.out_error, - request) + return self.handle_rpc_error(p_ctx, others, p_ctx.out_error, request) ret = p_ctx.out_object[0] retval = NOT_DONE_YET @@ -655,13 +660,13 @@ def handle_rpc(self, request): else: try: - retval = _cb_deferred(p_ctx.out_object, request, p_ctx, others, - self, cb=False) + retval = _cb_deferred( + p_ctx.out_object, request, p_ctx, others, self, cb=False + ) except Exception as e: logger_server.exception(e) try: - _eb_deferred(Failure(), request, p_ctx, others, - resource=self) + _eb_deferred(Failure(), request, p_ctx, others, resource=self) except Exception as e: logger_server.exception(e) @@ -672,8 +677,9 @@ def __handle_wsdl_request(self, request): # logger.debug("WSDL request headers: %r", # list(request.requestHeaders.getAllRawHeaders())) - ctx = TwistedHttpMethodContext(self.http_transport, request, - "text/xml; charset=utf-8") + ctx = TwistedHttpMethodContext( + self.http_transport, request, "text/xml; charset=utf-8" + ) url = _reconstruct_url(request) if self.http_transport.doc.wsdl11 is None: @@ -688,18 +694,19 @@ def __handle_wsdl_request(self, request): try: if self._wsdl is None: self.http_transport.doc.wsdl11.build_interface_document(url) - ctx.transport.wsdl = self._wsdl = \ - self.http_transport.doc.wsdl11.get_interface_document() + ctx.transport.wsdl = self._wsdl = ( + self.http_transport.doc.wsdl11.get_interface_document() + ) assert ctx.transport.wsdl is not None - self.http_transport.event_manager.fire_event('wsdl', ctx) + self.http_transport.event_manager.fire_event("wsdl", ctx) return ctx.transport.wsdl except Exception as e: ctx.transport.wsdl_error = e - self.http_transport.event_manager.fire_event('wsdl_exception', ctx) + self.http_transport.event_manager.fire_event("wsdl_exception", ctx) raise finally: @@ -738,7 +745,7 @@ def _cb_deferred(ret, request, p_ctx, others, resource, cb=True): elif (not issubclass(om, ComplexModelBase)) or len(om._type_info) <= 1: p_ctx.out_object = [ret] if len(om._type_info) == 1: - single_class, = om._type_info.values() + (single_class,) = om._type_info.values() else: p_ctx.out_object = ret else: @@ -750,36 +757,42 @@ def _cb_deferred(ret, request, p_ctx, others, resource, cb=True): if isinstance(ret, PushBase): resource.http_transport.init_root_push(ret, p_ctx, others) - elif ((isclass(om) and issubclass(om, File)) or - (isclass(single_class) and issubclass(single_class, File))) and \ - isinstance(p_ctx.out_protocol, HttpRpc) and \ - getattr(ret, 'abspath', None) is not None: - - file = static.File(ret.abspath, - defaultType=str(ret.type) or 'application/octet-stream') + elif ( + ( + (isclass(om) and issubclass(om, File)) + or (isclass(single_class) and issubclass(single_class, File)) + ) + and isinstance(p_ctx.out_protocol, HttpRpc) + and getattr(ret, "abspath", None) is not None + ): + + file = static.File( + ret.abspath, defaultType=str(ret.type) or "application/octet-stream" + ) retval = _render_file(file, request) if retval != NOT_DONE_YET and cb: request.write(retval) request.finish() p_ctx.close() else: + def _close_only_context(ret): p_ctx.close() - request.notifyFinish() \ - .addCallback(_close_only_context) \ - .addErrback(_eb_request_finished, request, p_ctx) \ - .addErrback(log_and_let_go, logger) + request.notifyFinish().addCallback(_close_only_context).addErrback( + _eb_request_finished, request, p_ctx + ).addErrback(log_and_let_go, logger) else: ret = resource.http_transport.get_out_string(p_ctx) if not isinstance(ret, Deferred): producer = Producer(p_ctx.out_string, request) - producer.deferred \ - .addCallback(_cb_request_finished, request, p_ctx) \ - .addErrback(_eb_request_finished, request, p_ctx) \ - .addErrback(log_and_let_go, logger) + producer.deferred.addCallback( + _cb_request_finished, request, p_ctx + ).addErrback(_eb_request_finished, request, p_ctx).addErrback( + log_and_let_go, logger + ) try: request.registerProducer(producer, False) @@ -792,19 +805,20 @@ def _close_only_context(ret): raise else: + def _cb(ret): if isinstance(ret, Deferred): - return ret \ - .addCallback(_cb) \ - .addErrback(_eb_request_finished, request, p_ctx) \ + return ( + ret.addCallback(_cb) + .addErrback(_eb_request_finished, request, p_ctx) .addErrback(log_and_let_go, logger) + ) else: return _cb_request_finished(ret, request, p_ctx) - ret \ - .addCallback(_cb) \ - .addErrback(_eb_request_finished, request, p_ctx) \ - .addErrback(log_and_let_go, logger) + ret.addCallback(_cb).addErrback( + _eb_request_finished, request, p_ctx + ).addErrback(log_and_let_go, logger) process_contexts(resource.http_transport, others, p_ctx) @@ -823,20 +837,20 @@ def _eb_deferred(ret, request, p_ctx, others, resource): _cb_deferred(None, request, p_ctx, others, resource, cb=False) - p_ctx.fire_event('method_redirect') + p_ctx.fire_event("method_redirect") except Exception as e: logger_server.exception(e) - p_ctx.out_error = Fault('Server', get_fault_string_from_exception(e)) + p_ctx.out_error = Fault("Server", get_fault_string_from_exception(e)) - p_ctx.fire_event('method_redirect_exception') + p_ctx.fire_event("method_redirect_exception") elif ret.check(Fault): p_ctx.out_error = ret.value ret = resource.handle_rpc_error(p_ctx, others, p_ctx.out_error, request) - p_ctx.fire_event('method_exception_object') + p_ctx.fire_event("method_exception_object") request.write(ret) @@ -846,7 +860,7 @@ def _eb_deferred(ret, request, p_ctx, others, resource): ret = resource.handle_rpc_error(p_ctx, others, p_ctx.out_error, request) - p_ctx.fire_event('method_exception_object') + p_ctx.fire_event("method_exception_object") request.write(ret) diff --git a/spyne/server/twisted/msgpack.py b/spyne/server/twisted/msgpack.py index bdabf1416..9a55d93c9 100644 --- a/spyne/server/twisted/msgpack.py +++ b/spyne/server/twisted/msgpack.py @@ -20,25 +20,23 @@ from __future__ import absolute_import import logging + logger = logging.getLogger(__name__) import io - -import msgpack - -from time import time +from collections import OrderedDict, deque from hashlib import md5 -from collections import deque, OrderedDict from itertools import chain +from time import time +import msgpack from twisted.internet import reactor +from twisted.internet.defer import CancelledError, Deferred +from twisted.internet.protocol import ClientFactory, Factory, Protocol, connectionDone from twisted.internet.task import deferLater -from twisted.internet.defer import Deferred, CancelledError -from twisted.internet.protocol import Protocol, Factory, connectionDone, \ - ClientFactory from twisted.python.failure import Failure -from spyne import EventManager, Address, ServerBase, Fault +from spyne import Address, EventManager, Fault, ServerBase from spyne.auxproc import process_contexts from spyne.error import InternalError from spyne.server.twisted import log_and_let_go @@ -61,21 +59,22 @@ def buildProtocol(self, address): return retval + TwistedMessagePackProtocolServerFactory = TwistedMessagePackProtocolFactory class TwistedMessagePackProtocolClientFactory(ClientFactory): def __init__(self, tpt, max_buffer_size=2 * 1024 * 1024): - assert isinstance(tpt, ServerBase), \ - "%r is not a ServerBase instance" % tpt + assert isinstance(tpt, ServerBase), "%r is not a ServerBase instance" % tpt self.tpt = tpt self.max_buffer_size = max_buffer_size self.event_manager = EventManager(self) def buildProtocol(self, address): - return TwistedMessagePackProtocol(self.tpt, - max_buffer_size=self.max_buffer_size, factory=self) + return TwistedMessagePackProtocol( + self.tpt, max_buffer_size=self.max_buffer_size, factory=self + ) def _cha(*args): @@ -84,11 +83,18 @@ def _cha(*args): class TwistedMessagePackProtocol(Protocol): IDLE_TIMEOUT_SEC = 0 - IDLE_TIMEOUT_MSG = 'idle timeout' - MAX_INACTIVE_CONTEXTS = float('inf') - - def __init__(self, tpt, max_buffer_size=2 * 1024 * 1024, out_chunk_size=0, - out_chunk_delay_sec=1, max_in_queue_size=0, factory=None): + IDLE_TIMEOUT_MSG = "idle timeout" + MAX_INACTIVE_CONTEXTS = float("inf") + + def __init__( + self, + tpt, + max_buffer_size=2 * 1024 * 1024, + out_chunk_size=0, + out_chunk_delay_sec=1, + max_in_queue_size=0, + factory=None, + ): """Twisted protocol implementation for Spyne's MessagePack transport. :param tpt: Spyne transport. It's an app-wide instance. @@ -106,18 +112,19 @@ def __init__(self, tpt, max_buffer_size=2 * 1024 * 1024, out_chunk_size=0, """ from spyne.server.msgpack import MessagePackTransportBase - assert isinstance(tpt, MessagePackTransportBase), \ - "Expected {!r} got {!r}".format(MessagePackTransportBase, type(tpt)) + + assert isinstance( + tpt, MessagePackTransportBase + ), "Expected {!r} got {!r}".format(MessagePackTransportBase, type(tpt)) self.spyne_tpt = tpt - self._buffer = msgpack.Unpacker(raw=True, - max_buffer_size=max_buffer_size) + self._buffer = msgpack.Unpacker(raw=True, max_buffer_size=max_buffer_size) self.out_chunk_size = out_chunk_size self.out_chunk_delay_sec = out_chunk_delay_sec self.max_in_queue_size = max_in_queue_size self.factory = factory - self.sessid = '' + self.sessid = "" self._delaying = None self.sent_bytes = 0 self.recv_bytes = 0 @@ -126,7 +133,7 @@ def __init__(self, tpt, max_buffer_size=2 * 1024 * 1024, out_chunk_size=0, self.inreq_queue = OrderedDict() self.inactive_queue = deque() self.disconnecting = False # FIXME: should we use this to raise an - # invalid connection state exception ? + # invalid connection state exception ? @staticmethod def gen_chunks(l, n): @@ -141,22 +148,20 @@ def gen_chunks(l, n): else: for i in range(0, len(l), n): - yield l[i:i+n] + yield l[i : i + n] def gen_sessid(self, *args): """It's up to you to use this in a subclass.""" retval = _cha( - Address.from_twisted_address(self.transport.getPeer()), - time(), - *args + Address.from_twisted_address(self.transport.getPeer()), time(), *args ) - return md5(repr(retval).encode('utf8')).hexdigest() + return md5(repr(retval).encode("utf8")).hexdigest() def connectionMade(self): logger.debug("%08x connection made", id(self)) - self.sessid = '' + self.sessid = "" self._delaying = None self.sent_bytes = 0 self.recv_bytes = 0 @@ -166,7 +171,7 @@ def connectionMade(self): self.inactive_queue = deque() self.active_queue = dict() self.disconnecting = False # FIXME: should we use this to raise an - # invalid connection state exception ? + # invalid connection state exception ? self._reset_idle_timer() if self.factory is not None: @@ -208,8 +213,7 @@ def dataReceived(self, data): except Exception as e: # If you get this error, you are in serious trouble # This needs to be fixed ASAP - logger.error( - "Error %r while processing incoming data %r", e, msg) + logger.error("Error %r while processing incoming data %r", e, msg) raise if self.disconnecting: @@ -223,10 +227,16 @@ def _reset_idle_timer(self): t.cancel() if self.IDLE_TIMEOUT_SEC is not None and self.IDLE_TIMEOUT_SEC > 0: - self.idle_timer = deferLater(reactor, self.IDLE_TIMEOUT_SEC, - self.loseConnection, self.IDLE_TIMEOUT_MSG) \ - .addErrback(self._err_idle_cancelled) \ + self.idle_timer = ( + deferLater( + reactor, + self.IDLE_TIMEOUT_SEC, + self.loseConnection, + self.IDLE_TIMEOUT_MSG, + ) + .addErrback(self._err_idle_cancelled) .addErrback(self._err_idle_cancelled_unknown_error) + ) def _err_idle_cancelled(self, err): err.trap(CancelledError) @@ -234,8 +244,9 @@ def _err_idle_cancelled(self, err): # do nothing. def _err_idle_cancelled_unknown_error(self, err): - logger.error("Sessid %s error cancelling idle timer: %s", - self.sessid, err.getTraceback()) + logger.error( + "Sessid %s error cancelling idle timer: %s", self.sessid, err.getTraceback() + ) self.idle_timer = None def loseConnection(self, reason=None): @@ -248,7 +259,8 @@ def process_incoming_message(self, msg, oob=None): p_ctx, others = self.spyne_tpt.produce_contexts(msg) p_ctx.oob_ctx = oob p_ctx.transport.remote_addr = Address.from_twisted_address( - self.transport.getPeer()) + self.transport.getPeer() + ) p_ctx.transport.protocol = self p_ctx.transport.sessid = self.sessid @@ -276,8 +288,10 @@ def process_inactive(self): self.process_contexts(p_ctx, others) else: - while self.num_active_contexts < self.max_in_queue_size and \ - self.num_inactive_contexts > 0: + while ( + self.num_active_contexts < self.max_in_queue_size + and self.num_inactive_contexts > 0 + ): p_ctx, others = self.inactive_queue.popleft() self.active_queue[id(p_ctx)] = p_ctx @@ -285,12 +299,17 @@ def process_inactive(self): self.process_contexts(p_ctx, others) if self.num_active_contexts > self.MAX_INACTIVE_CONTEXTS: - logger.error("%s Too many inactive contexts. " - "Closing connection.", addr_str) + logger.error( + "%s Too many inactive contexts. " "Closing connection.", addr_str + ) self.loseConnection("Too many inactive contexts") - logger.debug("%s active %d inactive %d", addr_str, - self.num_active_contexts, self.num_inactive_contexts) + logger.debug( + "%s active %d inactive %d", + addr_str, + self.num_active_contexts, + self.num_inactive_contexts, + ) def enqueue_outresp_data(self, ctxid, data): assert self.inreq_queue[ctxid] is None @@ -301,8 +320,7 @@ def enqueue_outresp_data(self, ctxid, data): break self.out_write(v) - self.spyne_tpt.event_manager.fire_event('outresp_flushed', - None, k, v) + self.spyne_tpt.event_manager.fire_event("outresp_flushed", None, k, v) del self.inreq_queue[k] self.active_queue[k].close() del self.active_queue[k] @@ -330,8 +348,7 @@ def out_write(self, reqdata): deferLater(reactor, 0, self._write_single_chunk) def _wait_for_next_chunk(self): - return deferLater(reactor, self.out_chunk_delay_sec, - self._write_single_chunk) + return deferLater(reactor, self.out_chunk_delay_sec, self._write_single_chunk) def _write_single_chunk(self): try: @@ -352,12 +369,18 @@ def _write_single_chunk(self): if self.connected and not self.disconnecting: self._delaying = self._wait_for_next_chunk() - logger.debug("%s One chunk of %d bytes written. Delaying " - "before next chunk write...", self.sessid, len(chunk)) + logger.debug( + "%s One chunk of %d bytes written. Delaying " + "before next chunk write...", + self.sessid, + len(chunk), + ) else: - logger.debug("%s Disconnection detected, discarding " - "remaining chunks", self.sessid) + logger.debug( + "%s Disconnection detected, discarding " "remaining chunks", + self.sessid, + ) self.out_chunks.clear() def handle_error(self, p_ctx, others, exc): @@ -373,7 +396,7 @@ def handle_error(self, p_ctx, others, exc): data = list(data.values()) # tag debug responses with the one from the relevant request - tag = getattr(p_ctx.transport, 'tag', None) + tag = getattr(p_ctx.transport, "tag", None) if tag is None: out_object = (error, msgpack.packb(data)) else: @@ -397,10 +420,11 @@ def handle_error(self, p_ctx, others, exc): logger.exception(e) def _register_callbacks(self, d, p_ctx, others): - return d \ - .addCallback(self._cb_deferred, p_ctx, others) \ - .addErrback(self._eb_deferred, p_ctx, others) \ + return ( + d.addCallback(self._cb_deferred, p_ctx, others) + .addErrback(self._eb_deferred, p_ctx, others) .addErrback(log_and_let_go, logger) + ) def process_contexts(self, p_ctx, others): if p_ctx.in_error: @@ -438,7 +462,7 @@ def _eb_deferred(self, fail, p_ctx, others): else: p_ctx.out_error = InternalError(fail.value) - if not getattr(fail, 'logged', False): + if not getattr(fail, "logged", False): logger.error(fail.getTraceback()) try: @@ -475,7 +499,7 @@ def _cb_deferred(self, ret, p_ctx, others, nowrap=False): self.spyne_tpt.get_out_string(p_ctx) self.spyne_tpt.pack(p_ctx) - out_string = b''.join(p_ctx.out_string) + out_string = b"".join(p_ctx.out_string) p_ctx.transport.resp_length = len(out_string) self.enqueue_outresp_data(id(p_ctx), out_string) diff --git a/spyne/server/twisted/websocket.py b/spyne/server/twisted/websocket.py index 2e74cabaf..50a74a48f 100644 --- a/spyne/server/twisted/websocket.py +++ b/spyne/server/twisted/websocket.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -40,31 +39,27 @@ This module is EXPERIMENTAL. Your mileage may vary. Patches are welcome. """ - from __future__ import absolute_import import logging + logger = logging.getLogger(__name__) from twisted.internet.defer import Deferred from twisted.internet.protocol import Factory -# FIXME: Switch to: -# from twisted.web.websockets import WebSocketsProtocol -# from twisted.web.websockets import WebSocketsResource -# from twisted.web.websockets import CONTROLS - -from spyne.util._twisted_ws import WebSocketsProtocol -from spyne.util._twisted_ws import WebSocketsResource -from spyne.util._twisted_ws import CONTROLS - - -from spyne import MethodContext, TransportContext, Address +from spyne import Address, MethodContext, TransportContext from spyne.auxproc import process_contexts from spyne.model import PushBase from spyne.model.complex import ComplexModel from spyne.model.fault import Fault from spyne.server import ServerBase +from spyne.util._twisted_ws import CONTROLS, WebSocketsProtocol, WebSocketsResource + +# FIXME: Switch to: +# from twisted.web.websockets import WebSocketsProtocol +# from twisted.web.websockets import WebSocketsResource +# from twisted.web.websockets import CONTROLS class WebSocketTransportContext(TransportContext): @@ -87,8 +82,7 @@ class WebSocketMethodContext(MethodContext): def __init__(self, transport, client_handle): MethodContext.__init__(self, transport, MethodContext.SERVER) - self.transport = WebSocketTransportContext(self, transport, 'ws', - client_handle) + self.transport = WebSocketTransportContext(self, transport, "ws", client_handle) class TwistedWebSocketProtocol(WebSocketsProtocol): @@ -124,7 +118,6 @@ def _connectionMade(self): def _connectionLost(self, reason): del self._clients[id(self)] - def frameReceived(self, opcode, data, fin): tpt = self._spyne_transport @@ -155,7 +148,7 @@ def _cb_deferred(retval, cb=True): p_ctx.out_object = retval tpt.get_out_string(p_ctx) - self.sendFrame(opcode, ''.join(p_ctx.out_string), fin) + self.sendFrame(opcode, "".join(p_ctx.out_string), fin) p_ctx.close() process_contexts(tpt, others, p_ctx) @@ -165,7 +158,7 @@ def _eb_deferred(err): logger.error(err.getTraceback()) tpt.get_out_string(p_ctx) - self.sendFrame(opcode, ''.join(p_ctx.out_string), fin) + self.sendFrame(opcode, "".join(p_ctx.out_string), fin) p_ctx.close() ret = p_ctx.out_object @@ -193,8 +186,8 @@ def __init__(self, app, bookkeep=False, _clients=None): self._clients = {} def buildProtocol(self, addr): - return TwistedWebSocketProtocol(self.transport, self.bookkeep, - self._clients) + return TwistedWebSocketProtocol(self.transport, self.bookkeep, self._clients) + class _Fake(object): pass @@ -229,12 +222,14 @@ def __init__(self, app, bookkeep=False, clients=None): if bookkeep: self.propagate = self.do_propagate - WebSocketsResource.__init__(self, TwistedWebSocketFactory(app, - bookkeep, self.clients)) + WebSocketsResource.__init__( + self, TwistedWebSocketFactory(app, bookkeep, self.clients) + ) def propagate(self): - raise InvalidRequestError("You must enable bookkeeping to have " - "message propagation work.") + raise InvalidRequestError( + "You must enable bookkeeping to have " "message propagation work." + ) def get_doc(self, obj, cls=None): if cls is None: @@ -245,11 +240,11 @@ def get_doc(self, obj, cls=None): op.serialize(ctx, op.RESPONSE) op.create_out_string(ctx) - return ''.join(ctx.out_string) + return "".join(ctx.out_string) def do_propagate(self, obj, cls=None): doc = self.get_doc(obj, cls) for c in self.clients.itervalues(): - print('sending to', c) + print("sending to", c) c.sendFrame(CONTROLS.TEXT, doc, True) diff --git a/spyne/server/wsgi.py b/spyne/server/wsgi.py index 6275ae404..3e344fa5e 100644 --- a/spyne/server/wsgi.py +++ b/spyne/server/wsgi.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -23,39 +22,35 @@ logic. """ - import logging + logger = logging.getLogger(__name__) import threading - +from http.cookies import SimpleCookie from inspect import isgenerator from itertools import chain +from urllib.parse import quote, unquote -from spyne import Address, File, Fault -from spyne.util.six.moves.http_cookies import SimpleCookie -from spyne.util.six.moves.urllib.parse import unquote, quote - +from spyne._base import Address from spyne.application import get_fault_string_from_exception from spyne.auxproc import process_contexts +from spyne.const.ansi_color import END_COLOR, LIGHT_GREEN +from spyne.const.http import HTTP_200, HTTP_404, HTTP_500 from spyne.error import RequestTooLongError +from spyne.model.binary import File +from spyne.model.fault import Fault from spyne.protocol.http import HttpRpc from spyne.server.http import HttpBase, HttpMethodContext, HttpTransportContext -from spyne.util.odict import odict from spyne.util.address import address_parser from spyne.util.http import parse_content_type_header - -from spyne.const.ansi_color import LIGHT_GREEN -from spyne.const.ansi_color import END_COLOR -from spyne.const.http import HTTP_200 -from spyne.const.http import HTTP_404 -from spyne.const.http import HTTP_500 - +from spyne.util.odict import odict try: from spyne.protocol.soap.mime import apply_mtom except ImportError as _import_error_1: _local_import_error_1 = _import_error_1 # python 3 workaround + def apply_mtom(*args, **kwargs): raise _local_import_error_1 @@ -64,12 +59,14 @@ def apply_mtom(*args, **kwargs): from werkzeug.formparser import parse_form_data except ImportError as _import_error_2: _local_import_error_2 = _import_error_2 # python 3 workaround + def parse_form_data(*args, **kwargs): raise _local_import_error_2 -def _reconstruct_url(environ, protocol=True, server_name=True, path=True, - query_string=True): +def _reconstruct_url( + environ, protocol=True, server_name=True, path=True, query_string=True +): """Rebuilds the calling url from values found in the environment. @@ -77,64 +74,66 @@ def _reconstruct_url(environ, protocol=True, server_name=True, path=True, contributed by Ian Bicking. """ - url = '' + url = "" if protocol: - url = environ['wsgi.url_scheme'] + '://' + url = environ["wsgi.url_scheme"] + "://" if server_name: - if environ.get('HTTP_HOST'): - url += environ['HTTP_HOST'] + if environ.get("HTTP_HOST"): + url += environ["HTTP_HOST"] else: - url += environ['SERVER_NAME'] + url += environ["SERVER_NAME"] - if environ['wsgi.url_scheme'] == 'https': - if environ['SERVER_PORT'] != '443': - url += ':' + environ['SERVER_PORT'] + if environ["wsgi.url_scheme"] == "https": + if environ["SERVER_PORT"] != "443": + url += ":" + environ["SERVER_PORT"] else: - if environ['SERVER_PORT'] != '80': - url += ':' + environ['SERVER_PORT'] + if environ["SERVER_PORT"] != "80": + url += ":" + environ["SERVER_PORT"] if path: - if (quote(environ.get('SCRIPT_NAME', '')) == '/' and - quote(environ.get('PATH_INFO', ''))[0] == '/'): - #skip this if it is only a slash + if ( + quote(environ.get("SCRIPT_NAME", "")) == "/" + and quote(environ.get("PATH_INFO", ""))[0] == "/" + ): + # skip this if it is only a slash pass - elif quote(environ.get('SCRIPT_NAME', ''))[0:2] == '//': - url += quote(environ.get('SCRIPT_NAME', ''))[1:] + elif quote(environ.get("SCRIPT_NAME", ""))[0:2] == "//": + url += quote(environ.get("SCRIPT_NAME", ""))[1:] else: - url += quote(environ.get('SCRIPT_NAME', '')) + url += quote(environ.get("SCRIPT_NAME", "")) - url += quote(environ.get('PATH_INFO', '')) + url += quote(environ.get("PATH_INFO", "")) if query_string: - if environ.get('QUERY_STRING'): - url += '?' + environ['QUERY_STRING'] + if environ.get("QUERY_STRING"): + url += "?" + environ["QUERY_STRING"] return url def _parse_qs(qs): - pairs = (s2 for s1 in qs.split('&') for s2 in s1.split(';')) + pairs = (s2 for s1 in qs.split("&") for s2 in s1.split(";")) retval = odict() for name_value in pairs: if name_value is None or len(name_value) == 0: continue - nv = name_value.split('=', 1) + nv = name_value.split("=", 1) if len(nv) != 2: # Handle case of a control-name with no equal sign nv.append(None) - name = unquote(nv[0].replace('+', ' ')) + name = unquote(nv[0].replace("+", " ")) value = None if nv[1] is not None: - value = unquote(nv[1].replace('+', ' ')) + value = unquote(nv[1].replace("+", " ")) l = retval.get(name, None) if l is None: @@ -151,7 +150,7 @@ def _get_http_headers(req_env): if k.startswith("HTTP_"): key = k[5:].lower() val = [v] - retval[key]= val + retval[key] = val logger.debug("Add http header %r = %r", key, val) return retval @@ -160,7 +159,7 @@ def _get_http_headers(req_env): def _gen_http_headers(headers): retval = [] - for k,v in headers.items(): + for k, v in headers.items(): if isinstance(v, (list, tuple)): for v2 in v: retval.append((k, v2)) @@ -175,13 +174,14 @@ class WsgiTransportContext(HttpTransportContext): :class:`WsgiMethodContext` class.""" def __init__(self, parent, transport, req_env, content_type): - super(WsgiTransportContext, self).__init__(parent, transport, - req_env, content_type) + super(WsgiTransportContext, self).__init__( + parent, transport, req_env, content_type + ) self.req_env = self.req """WSGI Request environment""" - self.req_method = req_env.get('REQUEST_METHOD', None) + self.req_method = req_env.get("REQUEST_METHOD", None) """HTTP Request verb, as a convenience to users.""" self.headers = _get_http_headers(self.req_env) @@ -190,17 +190,17 @@ def get_url(self): return _reconstruct_url(self.req_env) def get_path(self): - return self.req_env['PATH_INFO'] + return self.req_env["PATH_INFO"] def get_path_and_qs(self): - retval = quote(self.req_env.get('PATH_INFO', '')) - qs = self.req_env.get('QUERY_STRING', None) + retval = quote(self.req_env.get("PATH_INFO", "")) + qs = self.req_env.get("QUERY_STRING", None) if qs is not None: - retval += '?' + qs + retval += "?" + qs return retval def get_cookie(self, key): - cookie_string = self.req_env.get('HTTP_COOKIE', None) + cookie_string = self.req_env.get("HTTP_COOKIE", None) if cookie_string is None: return @@ -210,14 +210,13 @@ def get_cookie(self, key): return cookie.get(key, None).value def get_request_method(self): - return self.req['REQUEST_METHOD'].upper() + return self.req["REQUEST_METHOD"].upper() def get_request_content_type(self): return self.req.get("CONTENT_TYPE", None) def get_peer(self): - addr, port = address_parser.get_ip(self.req),\ - address_parser.get_port(self.req) + addr, port = address_parser.get_ip(self.req), address_parser.get_port(self.req) if address_parser.is_valid_ipv4(addr): return Address(type=Address.TCP4, host=addr, port=port) @@ -279,10 +278,16 @@ class WsgiApplication(HttpBase): called both from success and error cases. """ - def __init__(self, app, chunked=True, max_content_length=2 * 1024 * 1024, - block_length=8 * 1024): - super(WsgiApplication, self).__init__(app, chunked, max_content_length, - block_length) + def __init__( + self, + app, + chunked=True, + max_content_length=2 * 1024 * 1024, + block_length=8 * 1024, + ): + super(WsgiApplication, self).__init__( + app, chunked, max_content_length, block_length + ) self._mtx_build_interface_document = threading.Lock() @@ -299,11 +304,11 @@ def __call__(self, req_env, start_response, wsgi_url=None): url = wsgi_url if url is None: - url = _reconstruct_url(req_env).split('.wsdl')[0] + url = _reconstruct_url(req_env).split(".wsdl")[0] if self.is_wsdl_request(req_env): # Format the url for location - url = url.split('?')[0].split('.wsdl')[0] + url = url.split("?")[0].split(".wsdl")[0] return self.handle_wsdl_request(req_env, start_response, url) else: @@ -314,23 +319,19 @@ def is_wsdl_request(self, req_env): # /stuff/stuff/stuff/serviceName.wsdl or # /stuff/stuff/stuff/serviceName/?wsdl - return ( - req_env['REQUEST_METHOD'].upper() == 'GET' - and ( - ( - 'QUERY_STRING' in req_env - and req_env['QUERY_STRING'].split('=')[0].lower() == 'wsdl' - ) - or req_env['PATH_INFO'].endswith('.wsdl') + return req_env["REQUEST_METHOD"].upper() == "GET" and ( + ( + "QUERY_STRING" in req_env + and req_env["QUERY_STRING"].split("=")[0].lower() == "wsdl" ) + or req_env["PATH_INFO"].endswith(".wsdl") ) def handle_wsdl_request(self, req_env, start_response, url): - ctx = WsgiMethodContext(self, req_env, 'text/xml; charset=utf-8') + ctx = WsgiMethodContext(self, req_env, "text/xml; charset=utf-8") if self.doc.wsdl11 is None: - start_response(HTTP_404, - _gen_http_headers(ctx.transport.resp_headers)) + start_response(HTTP_404, _gen_http_headers(ctx.transport.resp_headers)) return [HTTP_404] if self._wsdl is None: @@ -346,27 +347,26 @@ def handle_wsdl_request(self, req_env, start_response, url): if ctx.transport.wsdl is None: self.doc.wsdl11.build_interface_document(url) - ctx.transport.wsdl = self._wsdl = \ - self.doc.wsdl11.get_interface_document() + ctx.transport.wsdl = self._wsdl = ( + self.doc.wsdl11.get_interface_document() + ) except Exception as e: logger.exception(e) ctx.transport.wsdl_error = e - self.event_manager.fire_event('wsdl_exception', ctx) + self.event_manager.fire_event("wsdl_exception", ctx) - start_response(HTTP_500, - _gen_http_headers(ctx.transport.resp_headers)) + start_response(HTTP_500, _gen_http_headers(ctx.transport.resp_headers)) return [HTTP_500] finally: self._mtx_build_interface_document.release() - self.event_manager.fire_event('wsdl', ctx) + self.event_manager.fire_event("wsdl", ctx) - ctx.transport.resp_headers['Content-Length'] = \ - str(len(ctx.transport.wsdl)) + ctx.transport.resp_headers["Content-Length"] = str(len(ctx.transport.wsdl)) start_response(HTTP_200, _gen_http_headers(ctx.transport.resp_headers)) retval = ctx.transport.wsdl @@ -385,20 +385,23 @@ def handle_error(self, p_ctx, others, error, start_response): """ if p_ctx.transport.resp_code is None: - p_ctx.transport.resp_code = \ - p_ctx.out_protocol.fault_to_http_response_code(error) + p_ctx.transport.resp_code = p_ctx.out_protocol.fault_to_http_response_code( + error + ) self.get_out_string(p_ctx) # consume the generator to get the length p_ctx.out_string = list(p_ctx.out_string) - p_ctx.transport.resp_headers['Content-Length'] = \ - str(sum((len(s) for s in p_ctx.out_string))) - self.event_manager.fire_event('wsgi_exception', p_ctx) + p_ctx.transport.resp_headers["Content-Length"] = str( + sum((len(s) for s in p_ctx.out_string)) + ) + self.event_manager.fire_event("wsgi_exception", p_ctx) - start_response(p_ctx.transport.resp_code, - _gen_http_headers(p_ctx.transport.resp_headers)) + start_response( + p_ctx.transport.resp_code, _gen_http_headers(p_ctx.transport.resp_headers) + ) try: process_contexts(self, others, p_ctx, error=error) @@ -409,12 +412,12 @@ def handle_error(self, p_ctx, others, error, start_response): return chain(p_ctx.out_string, self.__finalize(p_ctx)) def handle_rpc(self, req_env, start_response): - initial_ctx = WsgiMethodContext(self, req_env, - self.app.out_protocol.mime_type) + initial_ctx = WsgiMethodContext(self, req_env, self.app.out_protocol.mime_type) - self.event_manager.fire_event('wsgi_call', initial_ctx) - initial_ctx.in_string, in_string_charset = \ - self.__reconstruct_wsgi_request(req_env) + self.event_manager.fire_event("wsgi_call", initial_ctx) + initial_ctx.in_string, in_string_charset = self.__reconstruct_wsgi_request( + req_env + ) contexts = self.generate_contexts(initial_ctx, in_string_charset) p_ctx, others = contexts[0], contexts[1:] @@ -423,19 +426,16 @@ def handle_rpc(self, req_env, start_response): p_ctx.active = True if p_ctx.in_error: - return self.handle_error(p_ctx, others, p_ctx.in_error, - start_response) + return self.handle_error(p_ctx, others, p_ctx.in_error, start_response) self.get_in_object(p_ctx) if p_ctx.in_error: logger.error(p_ctx.in_error) - return self.handle_error(p_ctx, others, p_ctx.in_error, - start_response) + return self.handle_error(p_ctx, others, p_ctx.in_error, start_response) self.get_out_object(p_ctx) if p_ctx.out_error: - return self.handle_error(p_ctx, others, p_ctx.out_error, - start_response) + return self.handle_error(p_ctx, others, p_ctx.out_error, start_response) assert p_ctx.out_object is not None g = next(iter(p_ctx.out_object)) @@ -448,7 +448,7 @@ def handle_rpc(self, req_env, start_response): # protocol. Is there a better way? if is_generator: first_obj = next(g) - p_ctx.out_object = ( chain((first_obj,), g), ) + p_ctx.out_object = (chain((first_obj,), g),) if p_ctx.transport.resp_code is None: p_ctx.transport.resp_code = HTTP_200 @@ -458,13 +458,10 @@ def handle_rpc(self, req_env, start_response): except Exception as e: logger.exception(e) - p_ctx.out_error = Fault('Server', get_fault_string_from_exception(e)) - return self.handle_error(p_ctx, others, p_ctx.out_error, - start_response) + p_ctx.out_error = Fault("Server", get_fault_string_from_exception(e)) + return self.handle_error(p_ctx, others, p_ctx.out_error, start_response) - - if isinstance(p_ctx.out_protocol, HttpRpc) and \ - p_ctx.out_header_doc is not None: + if isinstance(p_ctx.out_protocol, HttpRpc) and p_ctx.out_header_doc is not None: p_ctx.transport.resp_headers.update(p_ctx.out_header_doc) if p_ctx.descriptor and p_ctx.descriptor.mtom: @@ -478,31 +475,34 @@ def handle_rpc(self, req_env, start_response): p_ctx.out_object = [p_ctx.out_object] p_ctx.transport.resp_headers, p_ctx.out_string = apply_mtom( - p_ctx.transport.resp_headers, p_ctx.out_string, - p_ctx.descriptor.out_message._type_info.values(), - p_ctx.out_object, - ) + p_ctx.transport.resp_headers, + p_ctx.out_string, + p_ctx.descriptor.out_message._type_info.values(), + p_ctx.out_object, + ) - self.event_manager.fire_event('wsgi_return', p_ctx) + self.event_manager.fire_event("wsgi_return", p_ctx) if self.chunked: # the user has not set a content-length, so we delete it as the # input is just an iterable. - if 'Content-Length' in p_ctx.transport.resp_headers: - del p_ctx.transport.resp_headers['Content-Length'] + if "Content-Length" in p_ctx.transport.resp_headers: + del p_ctx.transport.resp_headers["Content-Length"] else: - p_ctx.out_string = [''.join(p_ctx.out_string)] + p_ctx.out_string = ["".join(p_ctx.out_string)] try: len(p_ctx.out_string) - p_ctx.transport.resp_headers['Content-Length'] = \ - str(sum([len(a) for a in p_ctx.out_string])) + p_ctx.transport.resp_headers["Content-Length"] = str( + sum([len(a) for a in p_ctx.out_string]) + ) except TypeError: pass - start_response(p_ctx.transport.resp_code, - _gen_http_headers(p_ctx.transport.resp_headers)) + start_response( + p_ctx.transport.resp_code, _gen_http_headers(p_ctx.transport.resp_headers) + ) retval = chain(p_ctx.out_string, self.__finalize(p_ctx)) @@ -516,7 +516,7 @@ def handle_rpc(self, req_env, start_response): def __finalize(self, p_ctx): p_ctx.close() - self.event_manager.fire_event('wsgi_close', p_ctx) + self.event_manager.fire_event("wsgi_close", p_ctx) return () @@ -530,14 +530,14 @@ def __reconstruct_wsgi_request(self, http_env): # >>> parse_content_type_header("text/xml; charset=utf-8") # ('text/xml', {'charset': 'utf-8'}) content_type = parse_content_type_header(content_type) - charset = content_type[1].get('charset', None) + charset = content_type[1].get("charset", None) return self.__wsgi_input_to_iterable(http_env), charset def __wsgi_input_to_iterable(self, http_env): - istream = http_env.get('wsgi.input') + istream = http_env.get("wsgi.input") - length = str(http_env.get('CONTENT_LENGTH', self.max_content_length)) + length = str(http_env.get("CONTENT_LENGTH", self.max_content_length)) if len(length) == 0: length = 0 else: @@ -571,39 +571,43 @@ def decompose_incoming_envelope(self, prot, ctx, message): if self.has_patterns: # http://legacy.python.org/dev/peps/pep-0333/#url-reconstruction - domain = wsgi_env.get('HTTP_HOST', None) + domain = wsgi_env.get("HTTP_HOST", None) if domain is None: - domain = wsgi_env['SERVER_NAME'] + domain = wsgi_env["SERVER_NAME"] else: - domain = domain.partition(':')[0] # strip port info + domain = domain.partition(":")[0] # strip port info - params = self.match_pattern(ctx, - wsgi_env.get('REQUEST_METHOD', ''), - wsgi_env.get('PATH_INFO', ''), - domain, - ) + params = self.match_pattern( + ctx, + wsgi_env.get("REQUEST_METHOD", ""), + wsgi_env.get("PATH_INFO", ""), + domain, + ) if ctx.method_request_string is None: - ctx.method_request_string = '{%s}%s' % ( - prot.app.interface.get_tns(), - wsgi_env['PATH_INFO'].split('/')[-1]) + ctx.method_request_string = "{%s}%s" % ( + prot.app.interface.get_tns(), + wsgi_env["PATH_INFO"].split("/")[-1], + ) - logger.debug("%sMethod name: %r%s" % (LIGHT_GREEN, - ctx.method_request_string, END_COLOR)) + logger.debug( + "%sMethod name: %r%s" % (LIGHT_GREEN, ctx.method_request_string, END_COLOR) + ) ctx.in_header_doc = ctx.transport.headers - ctx.in_body_doc = _parse_qs(wsgi_env['QUERY_STRING']) + ctx.in_body_doc = _parse_qs(wsgi_env["QUERY_STRING"]) for k, v in params.items(): - if k in ctx.in_body_doc: - ctx.in_body_doc[k].extend(v) - else: - ctx.in_body_doc[k] = list(v) + if k in ctx.in_body_doc: + ctx.in_body_doc[k].extend(v) + else: + ctx.in_body_doc[k] = list(v) - verb = wsgi_env['REQUEST_METHOD'].upper() - if verb in ('POST', 'PUT', 'PATCH'): - stream, form, files = parse_form_data(wsgi_env, - stream_factory=prot.stream_factory) + verb = wsgi_env["REQUEST_METHOD"].upper() + if verb in ("POST", "PUT", "PATCH"): + stream, form, files = parse_form_data( + wsgi_env, stream_factory=prot.stream_factory + ) for k, v in form.lists(): val = ctx.in_body_doc.get(k, []) @@ -613,20 +617,25 @@ def decompose_incoming_envelope(self, prot, ctx, message): for k, v in files.items(): val = ctx.in_body_doc.get(k, []) - mime_type = v.headers.get('Content-Type', - 'application/octet-stream') + mime_type = v.headers.get("Content-Type", "application/octet-stream") - path = getattr(v.stream, 'name', None) + path = getattr(v.stream, "name", None) if path is None: - val.append(File.Value(name=v.filename, type=mime_type, - data=[v.stream.getvalue()])) + val.append( + File.Value( + name=v.filename, type=mime_type, data=[v.stream.getvalue()] + ) + ) else: v.stream.seek(0) - val.append(File.Value(name=v.filename, type=mime_type, - path=path, handle=v.stream)) + val.append( + File.Value( + name=v.filename, type=mime_type, path=path, handle=v.stream + ) + ) ctx.in_body_doc[k] = val for k, v in ctx.in_body_doc.items(): - if v == ['']: + if v == [""]: ctx.in_body_doc[k] = [None] diff --git a/spyne/server/zeromq.py b/spyne/server/zeromq.py index f897d55ca..70890fd95 100644 --- a/spyne/server/zeromq.py +++ b/spyne/server/zeromq.py @@ -19,6 +19,7 @@ """The ``spyne.server.zeromq`` module contains a server implementation that uses ZeroMQ (zmq.REP) as transport. """ + import threading import zmq @@ -31,12 +32,13 @@ class ZmqMethodContext(MethodContext): def __init__(self, app): super(ZmqMethodContext, self).__init__(app, MethodContext.SERVER) - self.transport.type = 'zmq' + self.transport.type = "zmq" class ZeroMQServer(ServerBase): """The ZeroMQ server transport.""" - transport = 'http://rfc.zeromq.org/' + + transport = "http://rfc.zeromq.org/" def __init__(self, app, app_url, wsdl_url=None, ctx=None, socket=None): if ctx and socket and ctx is not socket.context: @@ -63,9 +65,10 @@ def __handle_wsdl_request(self): return self.app.get_interface_document(self.url) # FIXME: Add suport for binary-only transports - def generate_contexts(self, ctx, in_string_charset='utf8'): - return super(ZeroMQServer, self).generate_contexts(ctx, - in_string_charset=in_string_charset) + def generate_contexts(self, ctx, in_string_charset="utf8"): + return super(ZeroMQServer, self).generate_contexts( + ctx, in_string_charset=in_string_charset + ) def serve_forever(self): """Runs the ZeroMQ server.""" @@ -102,7 +105,7 @@ def serve_forever(self): process_contexts(self, others, error) - self.zmq_socket.send(b''.join(p_ctx.out_string)) + self.zmq_socket.send(b"".join(p_ctx.out_string)) p_ctx.close() @@ -111,7 +114,8 @@ class ZeroMQThreadPoolServer(object): """Create a ZeroMQ server transport with several background workers, allowing asynchronous calls. - More details on the pattern http://zguide.zeromq.org/page:all#Shared-Queue-DEALER-and-ROUTER-sockets""" + More details on the pattern http://zguide.zeromq.org/page:all#Shared-Queue-DEALER-and-ROUTER-sockets + """ def __init__(self, app, app_url, pool_size, wsdl_url=None, ctx=None, socket=None): if ctx and socket and ctx is not socket.context: @@ -132,7 +136,7 @@ def __init__(self, app, app_url, pool_size, wsdl_url=None, ctx=None, socket=None self.frontend = self.ctx.socket(zmq.ROUTER) self.frontend.bind(app_url) - be_url = 'inproc://{tns}.{name}'.format(tns=self.app.tns, name=self.app.name) + be_url = "inproc://{tns}.{name}".format(tns=self.app.tns, name=self.app.name) self.pool = [] self.background_jobs = [] for i in range(pool_size): diff --git a/spyne/service.py b/spyne/service.py index 5b02c3abe..ca337bde0 100644 --- a/spyne/service.py +++ b/spyne/service.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -22,12 +21,12 @@ """ import logging + logger = logging.getLogger(__name__) -from spyne.util.six.moves.collections_abc import Sequence +from collections.abc import Sequence from spyne.evmgr import EventManager -from spyne.util import six from spyne.util.oset import oset @@ -38,14 +37,15 @@ def __init__(self, cls_name, cls_bases, cls_dict): super(ServiceBaseMeta, self).__init__(cls_name, cls_bases, cls_dict) self.public_methods = {} - self.event_manager = EventManager(self, - self.__get_base_event_handlers(cls_bases)) + self.event_manager = EventManager( + self, self.__get_base_event_handlers(cls_bases) + ) def __get_base_event_handlers(self, cls_bases): handlers = {} for base in cls_bases: - evmgr = getattr(base, 'event_manager', None) + evmgr = getattr(base, "event_manager", None) if evmgr is None: continue @@ -57,6 +57,7 @@ def __get_base_event_handlers(self, cls_bases): return handlers + class ServiceMeta(ServiceBaseMeta): """Creates the :class:`spyne.MethodDescriptor` objects by iterating over tagged methods. @@ -69,7 +70,7 @@ def __init__(self, cls_name, cls_bases, cls_dict): has_nonaux_methods = None for k, v in cls_dict.items(): - if not hasattr(v, '_is_rpc'): + if not hasattr(v, "_is_rpc"): continue descriptor = v(_default_function_name=k, _service_class=self) @@ -92,16 +93,17 @@ def __init__(self, cls_name, cls_bases, cls_dict): self.__has_aux_methods = True if self.__has_aux_methods and has_nonaux_methods: - raise Exception("You can't mix primary and " - "auxiliary methods in a single service definition.") + raise Exception( + "You can't mix primary and " + "auxiliary methods in a single service definition." + ) def is_auxiliary(self): return self.__has_aux_methods # FIXME: To be renamed to ServiceBase in Spyne 3 -@six.add_metaclass(ServiceBaseMeta) -class ServiceBaseBase(object): +class ServiceBaseBase(metaclass=ServiceBaseMeta): __in_header__ = None """The incoming header object that the methods under this service definition accept.""" @@ -182,7 +184,7 @@ def call_wrapper(cls, ctx, args=None): if args is None: args = ctx.in_object - assert not isinstance(args, six.string_types) + assert not isinstance(args, str) # python3 wants a proper sequence as *args if not isinstance(args, Sequence): @@ -198,8 +200,7 @@ def initialize(cls, app): pass -@six.add_metaclass(ServiceMeta) -class Service(ServiceBaseBase): +class Service(ServiceBaseBase, metaclass=ServiceMeta): """The ``Service`` class is the base class for all service definitions. The convention is to have public methods defined under a subclass of this diff --git a/spyne/store/__init__.py b/spyne/store/__init__.py index c597ee328..01ae947be 100644 --- a/spyne/store/__init__.py +++ b/spyne/store/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # diff --git a/spyne/store/relational/__init__.py b/spyne/store/relational/__init__.py index 642d3f354..014d321b5 100644 --- a/spyne/store/relational/__init__.py +++ b/spyne/store/relational/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -22,14 +21,21 @@ Uses SQLAlchemy for mapping objects to relations. """ -from spyne.store.relational._base import add_column -from spyne.store.relational._base import gen_sqla_info -from spyne.store.relational._base import gen_spyne_info -from spyne.store.relational._base import get_pk_columns - -from spyne.store.relational.document import PGXml, PGObjectXml, PGHtml, \ - PGJson, PGJsonB, PGObjectJson, PGFileJson -from spyne.store.relational.simple import PGLTree, PGLQuery, PGLTxtQuery -from spyne.store.relational.spatial import PGGeometry - from spyne.store.relational import override +from spyne.store.relational._base import ( + add_column, + gen_spyne_info, + gen_sqla_info, + get_pk_columns, +) +from spyne.store.relational.document import ( + PGFileJson, + PGHtml, + PGJson, + PGJsonB, + PGObjectJson, + PGObjectXml, + PGXml, +) +from spyne.store.relational.simple import PGLQuery, PGLTree, PGLTxtQuery +from spyne.store.relational.spatial import PGGeometry diff --git a/spyne/store/relational/_base.py b/spyne/store/relational/_base.py index 66fca3219..ad909f177 100644 --- a/spyne/store/relational/_base.py +++ b/spyne/store/relational/_base.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -21,6 +20,7 @@ from __future__ import absolute_import, print_function import logging + logger = logging.getLogger(__name__) import sqlalchemy @@ -30,61 +30,87 @@ except ImportError: import json -from os.path import isabs from inspect import isclass +from os.path import isabs from sqlalchemy import event -from sqlalchemy.schema import Column -from sqlalchemy.schema import Index -from sqlalchemy.schema import Table -from sqlalchemy.schema import ForeignKey - -from sqlalchemy.dialects.postgresql import FLOAT -from sqlalchemy.dialects.postgresql import DOUBLE_PRECISION -from sqlalchemy.dialects.postgresql.base import PGUuid, PGInet - -from sqlalchemy.orm import relationship -from sqlalchemy.orm import mapper +from sqlalchemy.dialects.postgresql import DOUBLE_PRECISION, FLOAT +from sqlalchemy.dialects.postgresql.base import PGInet, PGUuid from sqlalchemy.ext.associationproxy import association_proxy +from sqlalchemy.orm import registry as _registry +from sqlalchemy.orm import relationship -# TODO: find the latest way of checking whether a class is already mapped -try: - from sqlalchemy.orm import mapperlib - _mapper_registries = mapperlib._mapper_registries - -except (ImportError, AttributeError): - from sqlalchemy.orm import _mapper_registry as _mapper_registries - -from spyne.store.relational.simple import PGLTree -from spyne.store.relational.document import PGXml, PGObjectXml, PGObjectJson, \ - PGFileJson, PGJsonB, PGHtml, PGJson -from spyne.store.relational.spatial import PGGeometry - -# internal types -from spyne.model.enum import EnumBase -from spyne.model.complex import XmlModifier +_mapper_registry = _registry() +from sqlalchemy import inspect as sa_inspect +from sqlalchemy.exc import NoInspectionAvailable +from sqlalchemy.schema import Column, ForeignKey, Index, Table +# public types # Config types -from spyne.model import xml as c_xml +from spyne.model import ( + Any, + AnyDict, + AnyHtml, + AnyXml, + Array, + Boolean, + ByteArray, + ComplexModelBase, + Date, + DateTime, + Decimal, + Double, + Duration, + Enum, + File, + Float, + Integer, + Integer8, + Integer16, + Integer32, + Integer64, + IpAddress, + Ipv4Address, + Ipv6Address, + Line, + Ltree, + MultiLine, + MultiPoint, + MultiPolygon, + Point, + Polygon, + SimpleModel, + String, + Time, + Unicode, + UnsignedInteger, + UnsignedInteger8, + UnsignedInteger16, + UnsignedInteger32, + UnsignedInteger64, + Uuid, +) from spyne.model import json as c_json from spyne.model import jsonb as c_jsonb -from spyne.model import table as c_table from spyne.model import msgpack as c_msgpack +from spyne.model import table as c_table +from spyne.model import xml as c_xml from spyne.model.binary import HybridFileStore +from spyne.model.complex import XmlModifier -# public types -from spyne.model import SimpleModel, Enum, Array, ComplexModelBase, \ - Any, AnyDict, AnyXml, AnyHtml, \ - Date, Time, DateTime, Duration, \ - ByteArray, String, Unicode, Uuid, Boolean, \ - Point, Line, Polygon, MultiPoint, MultiLine, MultiPolygon, \ - Float, Double, Decimal, \ - Integer, Integer8, Integer16, Integer32, Integer64, \ - UnsignedInteger, UnsignedInteger8, UnsignedInteger16, UnsignedInteger32, \ - UnsignedInteger64, \ - Ipv6Address, Ipv4Address, IpAddress, \ - File, Ltree - +# internal types +from spyne.model.enum import EnumBase +from spyne.store.relational.document import ( + PGFileJson, + PGHtml, + PGJson, + PGJsonB, + PGObjectJson, + PGObjectXml, + PGXml, +) +from spyne.store.relational.simple import PGLTree +from spyne.store.relational.spatial import PGGeometry from spyne.util import sanitize_args @@ -92,6 +118,7 @@ class _SINGLE: pass + class _JOINED: pass @@ -101,44 +128,33 @@ class _JOINED: # distinguish between floats and doubles. sqlalchemy.Float: Double, sqlalchemy.FLOAT: Double, - sqlalchemy.Numeric: Decimal, sqlalchemy.NUMERIC: Decimal, - sqlalchemy.BigInteger: Integer64, sqlalchemy.BIGINT: Integer64, - sqlalchemy.Integer: Integer32, sqlalchemy.INTEGER: Integer32, - sqlalchemy.SmallInteger: Integer16, sqlalchemy.SMALLINT: Integer16, - sqlalchemy.LargeBinary: ByteArray, - sqlalchemy.Boolean: Boolean, sqlalchemy.BOOLEAN: Boolean, - sqlalchemy.DateTime: DateTime, sqlalchemy.TIMESTAMP: DateTime, sqlalchemy.dialects.postgresql.base.TIMESTAMP: DateTime, sqlalchemy.DATETIME: DateTime, sqlalchemy.dialects.postgresql.base.INTERVAL: Duration, - sqlalchemy.Date: Date, sqlalchemy.DATE: Date, - sqlalchemy.Time: Time, sqlalchemy.TIME: Time, - PGUuid: Uuid, PGLTree: Ltree, PGInet: IpAddress, } -sqlalchemy_BINARY = \ - getattr(sqlalchemy, 'Binary', getattr(sqlalchemy, 'BINARY', None)) +sqlalchemy_BINARY = getattr(sqlalchemy, "Binary", getattr(sqlalchemy, "BINARY", None)) if sqlalchemy_BINARY is not None: _sq2sp_type_map[sqlalchemy_BINARY] = ByteArray @@ -149,13 +165,13 @@ def _sp_attrs_to_sqla_constraints(cls, subcls, col_kwargs=None, col=None): # cls is the parent class of v if subcls.Attributes.nullable == False and cls.__extends__ is None: if col is None: - col_kwargs['nullable'] = False + col_kwargs["nullable"] = False else: col.nullable = False if subcls.Attributes.db_default is not None: if col is None: - col_kwargs['default'] = subcls.Attributes.db_default + col_kwargs["default"] = subcls.Attributes.db_default else: col.default = subcls.Attributes.db_default @@ -203,13 +219,17 @@ def _get_sqlalchemy_type(cls): # must be above Unicode, because String is Unicode's subclass if issubclass(cls, String): - if cls.Attributes.max_len == String.Attributes.max_len: # Default is arbitrary-length + if ( + cls.Attributes.max_len == String.Attributes.max_len + ): # Default is arbitrary-length return sqlalchemy.Text else: return sqlalchemy.String(cls.Attributes.max_len) if issubclass(cls, Unicode): - if cls.Attributes.max_len == Unicode.Attributes.max_len: # Default is arbitrary-length + if ( + cls.Attributes.max_len == Unicode.Attributes.max_len + ): # Default is arbitrary-length return sqlalchemy.UnicodeText else: return sqlalchemy.Unicode(cls.Attributes.max_len) @@ -266,8 +286,9 @@ def _get_sqlalchemy_type(cls): if cls.Attributes.store_as is int: return sqlalchemy.SmallInteger - raise ValueError("Boolean.store_as has invalid value %r" % - cls.Attributes.store_as) + raise ValueError( + "Boolean.store_as has invalid value %r" % cls.Attributes.store_as + ) if issubclass(cls, Date): return sqlalchemy.Date @@ -292,50 +313,61 @@ def _get_sqlalchemy_type(cls): return retval -def _get_col_o2o(parent, subname, subcls, fk_col_name, deferrable=None, - initially=None, ondelete=None, onupdate=None): +def _get_col_o2o( + parent, + subname, + subcls, + fk_col_name, + deferrable=None, + initially=None, + ondelete=None, + onupdate=None, +): """Gets key and child type and returns a column that points to the primary key of the child. """ - assert subcls.Attributes.table_name is not None, \ - "%r has no table name." % subcls + assert subcls.Attributes.table_name is not None, "%r has no table name." % subcls col_args, col_kwargs = sanitize_args(subcls.Attributes.sqla_column_args) _sp_attrs_to_sqla_constraints(parent, subcls, col_kwargs) # get pkeys from child class - pk_column, = get_pk_columns(subcls) # FIXME: Support multi-col keys + (pk_column,) = get_pk_columns(subcls) # FIXME: Support multi-col keys pk_key, pk_spyne_type = pk_column pk_sqla_type = _get_sqlalchemy_type(pk_spyne_type) # generate a fk to it from the current object (cls) - if 'name' in col_kwargs: - colname = col_kwargs.pop('name') + if "name" in col_kwargs: + colname = col_kwargs.pop("name") else: colname = subname if fk_col_name is None: fk_col_name = colname + "_" + pk_key - assert fk_col_name != colname, \ - "The column name for the foreign key must be different from the " \ + assert fk_col_name != colname, ( + "The column name for the foreign key must be different from the " "column name for the object itself." + ) fk = ForeignKey( - '%s.%s' % (subcls.Attributes.table_name, pk_key), + "%s.%s" % (subcls.Attributes.table_name, pk_key), use_alter=True, - name='%s_%s_fkey' % (subcls.Attributes.table_name, fk_col_name), - deferrable=deferrable, initially=initially, - ondelete=ondelete, onupdate=onupdate, + name="%s_%s_fkey" % (subcls.Attributes.table_name, fk_col_name), + deferrable=deferrable, + initially=initially, + ondelete=ondelete, + onupdate=onupdate, ) return Column(fk_col_name, pk_sqla_type, fk, **col_kwargs) -def _get_col_o2m(cls, fk_col_name, deferrable=None, initially=None, - ondelete=None, onupdate=None): +def _get_col_o2m( + cls, fk_col_name, deferrable=None, initially=None, ondelete=None, onupdate=None +): """Gets the parent class and returns a column that points to the primary key of the parent. """ @@ -344,42 +376,68 @@ def _get_col_o2m(cls, fk_col_name, deferrable=None, initially=None, col_args, col_kwargs = sanitize_args(cls.Attributes.sqla_column_args) # get pkeys from current class - pk_column, = get_pk_columns(cls) # FIXME: Support multi-col keys + (pk_column,) = get_pk_columns(cls) # FIXME: Support multi-col keys pk_key, pk_spyne_type = pk_column pk_sqla_type = _get_sqlalchemy_type(pk_spyne_type) # generate a fk from child to the current class if fk_col_name is None: - fk_col_name = '_'.join([cls.Attributes.table_name, pk_key]) + fk_col_name = "_".join([cls.Attributes.table_name, pk_key]) # we jump through all these hoops because we must instantiate the Column # only after we're sure that it doesn't already exist and also because # tinkering with functors is always fun :) yield [(fk_col_name, pk_sqla_type)] - fk = ForeignKey('%s.%s' % (cls.Attributes.table_name, pk_key), - deferrable=deferrable, initially=initially, - ondelete=ondelete, onupdate=onupdate) + fk = ForeignKey( + "%s.%s" % (cls.Attributes.table_name, pk_key), + deferrable=deferrable, + initially=initially, + ondelete=ondelete, + onupdate=onupdate, + ) col = Column(fk_col_name, pk_sqla_type, fk, **col_kwargs) yield col -def _get_cols_m2m(cls, k, child, fk_left_col_name, fk_right_col_name, - fk_left_deferrable, fk_left_initially, - fk_right_deferrable, fk_right_initially, - fk_left_ondelete, fk_left_onupdate, - fk_right_ondelete, fk_right_onupdate): +def _get_cols_m2m( + cls, + k, + child, + fk_left_col_name, + fk_right_col_name, + fk_left_deferrable, + fk_left_initially, + fk_right_deferrable, + fk_right_initially, + fk_left_ondelete, + fk_left_onupdate, + fk_right_ondelete, + fk_right_onupdate, +): """Gets the parent and child classes and returns foreign keys to both tables. These columns can be used to create a relation table.""" - col_info, left_col = _get_col_o2m(cls, fk_left_col_name, - ondelete=fk_left_ondelete, onupdate=fk_left_onupdate, - deferrable=fk_left_deferrable, initially=fk_left_initially) - right_col = _get_col_o2o(cls, k, child, fk_right_col_name, - ondelete=fk_right_ondelete, onupdate=fk_right_onupdate, - deferrable=fk_right_deferrable, initially=fk_right_initially) + col_info, left_col = _get_col_o2m( + cls, + fk_left_col_name, + ondelete=fk_left_ondelete, + onupdate=fk_left_onupdate, + deferrable=fk_left_deferrable, + initially=fk_left_initially, + ) + right_col = _get_col_o2o( + cls, + k, + child, + fk_right_col_name, + ondelete=fk_right_ondelete, + onupdate=fk_right_onupdate, + deferrable=fk_right_deferrable, + initially=fk_right_initially, + ) left_col.primary_key = right_col.primary_key = True return left_col, right_col @@ -413,7 +471,7 @@ def _gen_index_info(table, col, k, v): index_name, index_method = index except (TypeError, ValueError): - index_name = "%s_%s%s" % (table.name, k, '_unique' if unique else '') + index_name = "%s_%s%s" % (table.name, k, "_unique" if unique else "") index_method = index if index in (False, None): @@ -422,8 +480,9 @@ def _gen_index_info(table, col, k, v): if index is True: index_args = (index_name, col), dict(unique=unique) else: - index_args = (index_name, col), dict(unique=unique, - postgresql_using=index_method) + index_args = (index_name, col), dict( + unique=unique, postgresql_using=index_method + ) if isinstance(table, _FakeTable): table.indexes.append(index_args) @@ -435,27 +494,31 @@ def _gen_index_info(table, col, k, v): Index(*index_args[0], **index_args[1]) else: - assert existing_idx.unique == unique, \ - "Uniqueness flag differ between existing and current values. " \ + assert existing_idx.unique == unique, ( + "Uniqueness flag differ between existing and current values. " "Existing: {!r}, New: {!r}".format(existing_idx.unique, unique) + ) - existing_val = existing_idx.kwargs.get('postgresql_using') + existing_val = existing_idx.kwargs.get("postgresql_using") - assert existing_val == index_method, \ - "Indexing methods differ between existing and current index " \ + assert existing_val == index_method, ( + "Indexing methods differ between existing and current index " "directives. Existing: {!r}, New: {!r}".format( - existing_val, index_method) + existing_val, index_method + ) + ) + def _check_inheritance(cls, cls_bases): table_name = cls.Attributes.table_name inc = [] inheritance = None - base_class = getattr(cls, '__extends__', None) + base_class = getattr(cls, "__extends__", None) if base_class is None: for b in cls_bases: - if getattr(b, '_type_info', None) is not None and b.__mixin__: + if getattr(b, "_type_info", None) is not None and b.__mixin__: base_class = b if base_class is not None: @@ -465,8 +528,9 @@ def _check_inheritance(cls, cls_bases): inheritance = _SINGLE else: inheritance = _JOINED - raise NotImplementedError("Joined table inheritance is not yet " - "implemented.") + raise NotImplementedError( + "Joined table inheritance is not yet " "implemented." + ) # check whether the base classes are already mapped base_mapper = None @@ -475,7 +539,10 @@ def _check_inheritance(cls, cls_bases): if base_mapper is None: for b in cls_bases: - bm = _mapper_registries.get(b, None) + try: + bm = sa_inspect(b).mapper + except (NoInspectionAvailable, Exception): + bm = None if bm is not None: assert base_mapper is None, "There can be only one base mapper." base_mapper = bm @@ -505,10 +572,10 @@ def _add_simple_type(cls, props, table, subname, subcls, sqla_type): col_args, col_kwargs = sanitize_args(subcls.Attributes.sqla_column_args) _sp_attrs_to_sqla_constraints(cls, subcls, col_kwargs) - mp = getattr(subcls.Attributes, 'mapper_property', None) + mp = getattr(subcls.Attributes, "mapper_property", None) - if 'name' in col_kwargs: - colname = col_kwargs.pop('name') + if "name" in col_kwargs: + colname = col_kwargs.pop("name") else: colname = subname @@ -542,12 +609,21 @@ def _gen_array_m2m(cls, props, subname, arrser, storage): metadata = cls.Attributes.sqla_metadata - col_own, col_child = _get_cols_m2m(cls, subname, arrser, - storage.left, storage.right, - storage.fk_left_deferrable, storage.fk_left_initially, - storage.fk_right_deferrable, storage.fk_right_initially, - storage.fk_left_ondelete, storage.fk_left_onupdate, - storage.fk_right_ondelete, storage.fk_right_onupdate) + col_own, col_child = _get_cols_m2m( + cls, + subname, + arrser, + storage.left, + storage.right, + storage.fk_left_deferrable, + storage.fk_left_initially, + storage.fk_right_deferrable, + storage.fk_right_initially, + storage.fk_left_ondelete, + storage.fk_left_onupdate, + storage.fk_right_ondelete, + storage.fk_right_onupdate, + ) storage.left = col_own.key storage.right = col_child.key @@ -555,7 +631,7 @@ def _gen_array_m2m(cls, props, subname, arrser, storage): # noinspection PySimplifyBooleanCheck because literal True means # "generate table name automatically" here if storage.multi is True: - rel_table_name = '_'.join([cls.Attributes.table_name, subname]) + rel_table_name = "_".join([cls.Attributes.table_name, subname]) else: rel_table_name = storage.multi @@ -582,10 +658,11 @@ def _gen_array_m2m(cls, props, subname, arrser, storage): rel_kwargs = dict( lazy=storage.lazy, backref=storage.backref, - cascade=storage.cascade, - order_by=storage.order_by, + order_by=storage.order_by or None, back_populates=storage.back_populates, ) + if storage.cascade is not False: + rel_kwargs["cascade"] = storage.cascade if storage.explicit_join: # Specify primaryjoin and secondaryjoin when requested. @@ -596,27 +673,31 @@ def _gen_array_m2m(cls, props, subname, arrser, storage): assert own_t is not None and len(get_pk_columns(cls)) > 0 # FIXME: support more than one pk - (col_pk_key, _), = get_pk_columns(cls) + ((col_pk_key, _),) = get_pk_columns(cls) col_pk = own_t.c[col_pk_key] - rel_kwargs.update(dict( - secondary=rel_t, - primaryjoin=(col_pk == rel_t.c[col_own.key]), - secondaryjoin=(col_pk == rel_t.c[col_child.key]), - )) + rel_kwargs.update( + dict( + secondary=rel_t, + primaryjoin=(col_pk == rel_t.c[col_own.key]), + secondaryjoin=(col_pk == rel_t.c[col_child.key]), + ) + ) if storage.single_parent is not None: - rel_kwargs['single_parent'] = storage.single_parent + rel_kwargs["single_parent"] = storage.single_parent props[subname] = relationship(arrser, **rel_kwargs) else: - rel_kwargs.update(dict( - secondary=rel_t, - )) + rel_kwargs.update( + dict( + secondary=rel_t, + ) + ) if storage.single_parent is not None: - rel_kwargs['single_parent'] = storage.single_parent + rel_kwargs["single_parent"] = storage.single_parent props[subname] = relationship(arrser, **rel_kwargs) @@ -636,12 +717,16 @@ def _gen_array_simple(cls, props, subname, arrser_cust, storage): metadata = cls.Attributes.sqla_metadata # get left (fk) column info - _gen_col = _get_col_o2m(cls, storage.left, - ondelete=storage.fk_left_ondelete, onupdate=storage.fk_left_onupdate, + _gen_col = _get_col_o2m( + cls, + storage.left, + ondelete=storage.fk_left_ondelete, + onupdate=storage.fk_left_onupdate, deferrable=storage.fk_left_deferrable, - initially=storage.fk_left_initially) + initially=storage.fk_left_initially, + ) - col_info = next(_gen_col) # gets the column name + col_info = next(_gen_col) # gets the column name # FIXME: Add support for multi-column primary keys. storage.left, child_left_col_type = col_info[0] child_left_col_name = storage.left @@ -655,22 +740,29 @@ def _gen_array_simple(cls, props, subname, arrser_cust, storage): # get table name child_table_name = arrser_cust.Attributes.table_name if child_table_name is None: - child_table_name = '_'.join([table_name, subname]) + child_table_name = "_".join([table_name, subname]) if child_table_name in metadata.tables: child_t = metadata.tables[child_table_name] # if we have the table, make sure have the right column (data column) - assert child_right_col_type.__class__ is \ - child_t.c[child_right_col_name].type.__class__, "%s.%s: %r != %r" % \ - (cls, child_right_col_name, child_right_col_type.__class__, - child_t.c[child_right_col_name].type.__class__) + assert ( + child_right_col_type.__class__ + is child_t.c[child_right_col_name].type.__class__ + ), "%s.%s: %r != %r" % ( + cls, + child_right_col_name, + child_right_col_type.__class__, + child_t.c[child_right_col_name].type.__class__, + ) if child_left_col_name in child_t.c: - assert child_left_col_type is \ - child_t.c[child_left_col_name].type.__class__, "%r != %r" % \ - (child_left_col_type, - child_t.c[child_left_col_name].type.__class__) + assert ( + child_left_col_type is child_t.c[child_left_col_name].type.__class__ + ), "%r != %r" % ( + child_left_col_type, + child_t.c[child_left_col_name].type.__class__, + ) else: # Table exists but our own foreign key doesn't. child_left_col = next(_gen_col) @@ -685,53 +777,62 @@ def _gen_array_simple(cls, props, subname, arrser_cust, storage): child_left_col = next(_gen_col) _sp_attrs_to_sqla_constraints(cls, arrser_cust, col=child_left_col) - child_t = Table(child_table_name , metadata, - Column('id', sqlalchemy.Integer, primary_key=True), + child_t = Table( + child_table_name, + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), child_left_col, child_right_col, ) - _gen_index_info(child_t, child_right_col, child_right_col_name, - arrser_cust) + _gen_index_info(child_t, child_right_col, child_right_col_name, arrser_cust) # generate temporary class for association proxy - cls_name = ''.join(x.capitalize() or '_' for x in - child_table_name.split('_')) - # generates camelcase class name. + cls_name = "".join(x.capitalize() or "_" for x in child_table_name.split("_")) + # generates camelcase class name. def _i(self, *args): setattr(self, child_right_col_name, args[0]) - cls_ = type("_" + cls_name, (object,), {'__init__': _i}) - mapper(cls_, child_t) + cls_ = type("_" + cls_name, (object,), {"__init__": _i}) + _mapper_registry.map_imperatively(cls_, child_t) props["_" + subname] = relationship(cls_) # generate association proxy - setattr(cls, subname, - association_proxy("_" + subname, child_right_col_name)) + setattr(cls, subname, association_proxy("_" + subname, child_right_col_name)) def _gen_array_o2m(cls, props, subname, arrser, arrser_cust, storage): - _gen_col = _get_col_o2m(cls, storage.right, - ondelete=storage.fk_right_ondelete, onupdate=storage.fk_right_onupdate, + _gen_col = _get_col_o2m( + cls, + storage.right, + ondelete=storage.fk_right_ondelete, + onupdate=storage.fk_right_onupdate, deferrable=storage.fk_right_deferrable, - initially=storage.fk_right_initially) + initially=storage.fk_right_initially, + ) col_info = next(_gen_col) # gets the column name - storage.right, col_type = col_info[0] # FIXME: Add support for multi-column primary keys. + storage.right, col_type = col_info[ + 0 + ] # FIXME: Add support for multi-column primary keys. - assert storage.left is None, \ - "'left' is ignored in one-to-many relationships " \ - "with complex types (because they already have a " \ + assert storage.left is None, ( + "'left' is ignored in one-to-many relationships " + "with complex types (because they already have a " "table). You probably meant to use 'right'." + ) child_t = arrser.__table__ if storage.right in child_t.c: # TODO: This branch MUST be tested. new_col_type = child_t.c[storage.right].type.__class__ - assert col_type is child_t.c[storage.right].type.__class__, \ - "Existing column type %r disagrees with new column type %r" % \ - (col_type, new_col_type) + assert ( + col_type is child_t.c[storage.right].type.__class__ + ), "Existing column type %r disagrees with new column type %r" % ( + col_type, + new_col_type, + ) # if the column is already there, the decision about whether # it should be in child's mapper or not should also have been @@ -749,18 +850,18 @@ def _gen_array_o2m(cls, props, subname, arrser, arrser_cust, storage): child_t.append_column(col) arrser.__mapper__.add_property(col.name, col) - rel_kwargs = dict( lazy=storage.lazy, backref=storage.backref, - cascade=storage.cascade, - order_by=storage.order_by, + order_by=storage.order_by or None, foreign_keys=[col], back_populates=storage.back_populates, ) + if storage.cascade is not False: + rel_kwargs["cascade"] = storage.cascade if storage.single_parent is not None: - rel_kwargs['single_parent'] = storage.single_parent + rel_kwargs["single_parent"] = storage.single_parent props[subname] = relationship(arrser, **rel_kwargs) @@ -772,7 +873,7 @@ def _is_array(v): def _add_array_to_complex(cls, props, subname, subcls, storage): arrser_cust = subcls if issubclass(subcls, Array): - arrser_cust, = subcls._type_info.values() + (arrser_cust,) = subcls._type_info.values() arrser = arrser_cust if arrser_cust.__orig__ is not None: @@ -788,8 +889,9 @@ def _add_array_to_complex(cls, props, subname, subcls, storage): _gen_array_o2m(cls, props, subname, arrser, arrser_cust, storage) -def _add_simple_type_to_complex(cls, props, table, subname, subcls, storage, - col_kwargs): +def _add_simple_type_to_complex( + cls, props, table, subname, subcls, storage, col_kwargs +): # v has the Attribute values we need whereas real_v is what the # user instantiates (thus what sqlalchemy needs) if subcls.__orig__ is None: # vanilla class @@ -797,22 +899,28 @@ def _add_simple_type_to_complex(cls, props, table, subname, subcls, storage, else: # customized class real_v = subcls.__orig__ - assert not getattr(storage, 'multi', False), \ - 'Storing a single element-type using a relation table is pointless.' + assert not getattr( + storage, "multi", False + ), "Storing a single element-type using a relation table is pointless." - assert storage.right is None, \ - "'right' is ignored in a one-to-one relationship" + assert storage.right is None, "'right' is ignored in a one-to-one relationship" - col = _get_col_o2o(cls, subname, subcls, storage.left, - ondelete=storage.fk_left_ondelete, onupdate=storage.fk_left_onupdate, + col = _get_col_o2o( + cls, + subname, + subcls, + storage.left, + ondelete=storage.fk_left_ondelete, + onupdate=storage.fk_left_onupdate, deferrable=storage.fk_left_deferrable, - initially=storage.fk_left_initially) + initially=storage.fk_left_initially, + ) storage.left = col.name if col.name in table.c: col = table.c[col.name] - if col_kwargs.get('nullable') is False: + if col_kwargs.get("nullable") is False: col.nullable = False else: table.append_column(col) @@ -820,19 +928,18 @@ def _add_simple_type_to_complex(cls, props, table, subname, subcls, storage, rel_kwargs = dict( lazy=storage.lazy, backref=storage.backref, - order_by=storage.order_by, + order_by=storage.order_by or None, back_populates=storage.back_populates, ) if storage.single_parent is not None: - rel_kwargs['single_parent'] = storage.single_parent + rel_kwargs["single_parent"] = storage.single_parent if real_v is (cls.__orig__ or cls): - (pk_col_name, pk_col_type), = get_pk_columns(cls) - rel_kwargs['remote_side'] = [table.c[pk_col_name]] + ((pk_col_name, pk_col_type),) = get_pk_columns(cls) + rel_kwargs["remote_side"] = [table.c[pk_col_name]] - rel = relationship(real_v, uselist=False, foreign_keys=[col], - **rel_kwargs) + rel = relationship(real_v, uselist=False, foreign_keys=[col], **rel_kwargs) _gen_index_info(table, col, subname, subcls) @@ -840,30 +947,32 @@ def _add_simple_type_to_complex(cls, props, table, subname, subcls, storage, props[col.name] = col -def _add_complex_type_as_table(cls, props, table, subname, subcls, storage, - col_args, col_kwargs): +def _add_complex_type_as_table( + cls, props, table, subname, subcls, storage, col_args, col_kwargs +): # add one to many relation if _is_array(subcls): _add_array_to_complex(cls, props, subname, subcls, storage) # add one to one relation else: - _add_simple_type_to_complex(cls, props, table, subname, subcls, - storage, col_kwargs) + _add_simple_type_to_complex( + cls, props, table, subname, subcls, storage, col_kwargs + ) -def _add_complex_type_as_xml(cls, props, table, subname, subcls, storage, - col_args, col_kwargs): - if 'name' in col_kwargs: - colname = col_kwargs.pop('name') +def _add_complex_type_as_xml( + cls, props, table, subname, subcls, storage, col_args, col_kwargs +): + if "name" in col_kwargs: + colname = col_kwargs.pop("name") else: colname = subname if colname in table.c: col = table.c[colname] else: - t = PGObjectXml(subcls, storage.root_tag, storage.no_ns, - storage.pretty_print) + t = PGObjectXml(subcls, storage.root_tag, storage.no_ns, storage.pretty_print) col = Column(colname, t, **col_kwargs) props[subname] = col @@ -871,10 +980,11 @@ def _add_complex_type_as_xml(cls, props, table, subname, subcls, storage, table.append_column(col) -def _add_complex_type_as_json(cls, props, table, subname, subcls, storage, - col_args, col_kwargs, dbt): - if 'name' in col_kwargs: - colname = col_kwargs.pop('name') +def _add_complex_type_as_json( + cls, props, table, subname, subcls, storage, col_args, col_kwargs, dbt +): + if "name" in col_kwargs: + colname = col_kwargs.pop("name") else: colname = subname @@ -882,8 +992,12 @@ def _add_complex_type_as_json(cls, props, table, subname, subcls, storage, col = table.c[colname] else: - t = PGObjectJson(subcls, ignore_wrappers=storage.ignore_wrappers, - complex_as=storage.complex_as, dbt=dbt) + t = PGObjectJson( + subcls, + ignore_wrappers=storage.ignore_wrappers, + complex_as=storage.complex_as, + dbt=dbt, + ) col = Column(colname, t, **col_kwargs) props[subname] = col @@ -895,22 +1009,26 @@ def _add_complex_type(cls, props, table, subname, subcls): if issubclass(subcls, File): return _add_file_type(cls, props, table, subname, subcls) - storage = getattr(subcls.Attributes, 'store_as', None) + storage = getattr(subcls.Attributes, "store_as", None) col_args, col_kwargs = sanitize_args(subcls.Attributes.sqla_column_args) _sp_attrs_to_sqla_constraints(cls, subcls, col_kwargs) if isinstance(storage, c_table): - return _add_complex_type_as_table(cls, props, table, subname, subcls, - storage, col_args, col_kwargs) + return _add_complex_type_as_table( + cls, props, table, subname, subcls, storage, col_args, col_kwargs + ) if isinstance(storage, c_xml): - return _add_complex_type_as_xml(cls, props, table, subname, subcls, - storage, col_args, col_kwargs) + return _add_complex_type_as_xml( + cls, props, table, subname, subcls, storage, col_args, col_kwargs + ) if isinstance(storage, c_json): - return _add_complex_type_as_json(cls, props, table, subname, subcls, - storage, col_args, col_kwargs, 'json') + return _add_complex_type_as_json( + cls, props, table, subname, subcls, storage, col_args, col_kwargs, "json" + ) if isinstance(storage, c_jsonb): - return _add_complex_type_as_json(cls, props, table, subname, subcls, - storage, col_args, col_kwargs, 'jsonb') + return _add_complex_type_as_json( + cls, props, table, subname, subcls, storage, col_args, col_kwargs, "jsonb" + ) if isinstance(storage, c_msgpack): raise NotImplementedError(c_msgpack) @@ -926,8 +1044,9 @@ def _convert_fake_table(cls, table): _table = table table_args, table_kwargs = sanitize_args(cls.Attributes.sqla_table_args) - table = Table(table_name, metadata, - *(tuple(table.columns) + table_args), **table_kwargs) + table = Table( + table_name, metadata, *(tuple(table.columns) + table_args), **table_kwargs + ) for index_args, index_kwargs in _table.indexes: Index(*index_args, **index_kwargs) @@ -947,29 +1066,28 @@ def _gen_mapper(cls, props, table, cls_bases): inheritance, base_class, base_mapper, inc = _check_inheritance(cls, cls_bases) mapper_args, mapper_kwargs = sanitize_args(cls.Attributes.sqla_mapper_args) - _props = mapper_kwargs.get('properties', None) + _props = mapper_kwargs.get("properties", None) if _props is None: - mapper_kwargs['properties'] = props + mapper_kwargs["properties"] = props else: props.update(_props) - mapper_kwargs['properties'] = props + mapper_kwargs["properties"] = props - po = mapper_kwargs.get('polymorphic_on', None) + po = mapper_kwargs.get("polymorphic_on", None) if po is not None: if not isinstance(po, Column): - mapper_kwargs['polymorphic_on'] = table.c[po] + mapper_kwargs["polymorphic_on"] = table.c[po] else: - logger.warning("Deleted invalid 'polymorphic_on' value %r for %r.", - po, cls) - del mapper_kwargs['polymorphic_on'] + logger.warning("Deleted invalid 'polymorphic_on' value %r for %r.", po, cls) + del mapper_kwargs["polymorphic_on"] if base_mapper is not None: - mapper_kwargs['inherits'] = base_mapper + mapper_kwargs["inherits"] = base_mapper if inheritance is not _SINGLE: mapper_args = (table,) + mapper_args - cls_mapper = mapper(cls, *mapper_args, **mapper_kwargs) + cls_mapper = _mapper_registry.map_imperatively(cls, *mapper_args, **mapper_kwargs) def on_load(target, context): d = target.__dict__ @@ -981,13 +1099,13 @@ def on_load(target, context): else: d[k] = None - event.listen(cls, 'load', on_load) + event.listen(cls, "load", on_load) return cls_mapper def _add_file_type(cls, props, table, subname, subcls): - storage = getattr(subcls.Attributes, 'store_as', None) + storage = getattr(subcls.Attributes, "store_as", None) col_args, col_kwargs = sanitize_args(subcls.Attributes.sqla_column_args) _sp_attrs_to_sqla_constraints(cls, subcls, col_kwargs) @@ -997,12 +1115,12 @@ def _add_file_type(cls, props, table, subname, subcls): else: assert isabs(storage.store) - #FIXME: Add support for storage markers from spyne.model.complex - if storage.db_format == 'json': + # FIXME: Add support for storage markers from spyne.model.complex + if storage.db_format == "json": t = PGFileJson(storage.store, storage.type) - elif storage.db_format == 'jsonb': - t = PGFileJson(storage.store, storage.type, dbt='jsonb') + elif storage.db_format == "jsonb": + t = PGFileJson(storage.store, storage.type, dbt="jsonb") else: raise NotImplementedError(storage.db_format) @@ -1048,7 +1166,7 @@ def _parent_mapper_has_property(cls, cls_bases, k): return False for b in cls_bases: - if not hasattr(b, 'Attributes'): + if not hasattr(b, "Attributes"): continue mapper = b.Attributes.sqla_mapper @@ -1087,8 +1205,7 @@ def gen_sqla_info(cls, cls_bases=()): else: # when no parents, use all fields anyway. - assert set(cls._type_info.items()) == \ - set(cls.get_flat_type_info(cls).items()) + assert set(cls._type_info.items()) == set(cls.get_flat_type_info(cls).items()) fields = cls.get_flat_type_info(cls).items() @@ -1099,11 +1216,12 @@ def gen_sqla_info(cls, cls_bases=()): t = _get_sqlalchemy_type(v) if t is None: # complex model - p = getattr(v.Attributes, 'store_as', None) + p = getattr(v.Attributes, "store_as", None) if p is None: - logger.debug("Skipping %s.%s.%s: %r, store_as: %r" % ( - cls.get_namespace(), - cls.get_type_name(), k, v, p)) + logger.debug( + "Skipping %s.%s.%s: %r, store_as: %r" + % (cls.get_namespace(), cls.get_type_name(), k, v, p) + ) else: _add_complex_type(cls, mapper_props, table, k, v) else: @@ -1126,24 +1244,23 @@ def _get_spyne_type(v): cust = {} if v.primary_key: - cust['primary_key'] = True + cust["primary_key"] = True if not v.nullable: - cust['nullable'] = False - cust['min_occurs'] = 1 + cust["nullable"] = False + cust["min_occurs"] = 1 if isinstance(v.type, sqlalchemy.Enum): if v.type.convert_unicode: return Unicode(values=v.type.enums, **cust) else: - cust['type_name'] = v.type.name + cust["type_name"] = v.type.name return Enum(*v.type.enums, **cust) if isinstance(v.type, (sqlalchemy.UnicodeText, sqlalchemy.Text)): return Unicode(**cust) - if isinstance(v.type, (sqlalchemy.Unicode, sqlalchemy.String, - sqlalchemy.VARCHAR)): + if isinstance(v.type, (sqlalchemy.Unicode, sqlalchemy.String, sqlalchemy.VARCHAR)): return Unicode(v.type.length, **cust) if isinstance(v.type, sqlalchemy.Numeric): @@ -1182,8 +1299,10 @@ def _get_spyne_type(v): else: return retval - raise Exception("Spyne type was not found. Probably _sq2sp_type_map " - "needs a new entry. %r" % v) + raise Exception( + "Spyne type was not found. Probably _sq2sp_type_map " + "needs a new entry. %r" % v + ) def gen_spyne_info(cls): @@ -1195,10 +1314,12 @@ def gen_spyne_info(cls): for c in table.c: _type_info[c.name] = _get_spyne_type(c) else: - mapper_kwargs['include_properties'] = _type_info.keys() + mapper_kwargs["include_properties"] = _type_info.keys() # Map the table to the object - cls_mapper = mapper(cls, table, *mapper_args, **mapper_kwargs) + cls_mapper = _mapper_registry.map_imperatively( + cls, table, *mapper_args, **mapper_kwargs + ) cls.Attributes.table_name = cls.__tablename__ = table.name cls.Attributes.sqla_mapper = cls.__mapper__ = cls_mapper @@ -1209,8 +1330,9 @@ def get_pk_columns(cls): retval = [] for k, v in cls.get_flat_type_info(cls).items(): - if v.Attributes.sqla_column_args is not None and \ - v.Attributes.sqla_column_args[-1].get('primary_key', False): + if v.Attributes.sqla_column_args is not None and v.Attributes.sqla_column_args[ + -1 + ].get("primary_key", False): retval.append((k, v)) return tuple(retval) if len(retval) > 0 else None diff --git a/spyne/store/relational/document.py b/spyne/store/relational/document.py index 21e49d8ac..f780e1166 100644 --- a/spyne/store/relational/document.py +++ b/spyne/store/relational/document.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,22 +17,22 @@ # import logging + logger = logging.getLogger(__name__) -import os import json +import os import shutil +from contextlib import closing +from mmap import ACCESS_READ, mmap +from os.path import abspath, basename, dirname, isfile, join +from uuid import uuid1 import sqlalchemy.dialects -from uuid import uuid1 -from mmap import mmap, ACCESS_READ -from contextlib import closing -from os.path import join, abspath, dirname, basename, isfile - try: - from lxml import etree - from lxml import html + from lxml import etree, html + from spyne.util.xml import get_object_as_xml, get_xml_as_object except ImportError as _import_error: @@ -41,24 +40,25 @@ html = None _local_import_error = _import_error + def get_object_as_xml(*_, **__): raise _local_import_error + def get_xml_as_object(*_, **__): raise _local_import_error + +from io import BytesIO, StringIO + from sqlalchemy.sql.type_api import UserDefinedType from spyne import ValidationError from spyne.model.relational import FileData - -from spyne.util import six -from spyne.util.six import binary_type, text_type, BytesIO, StringIO from spyne.util.fileproxy import SeekableFileProxy class PGXml(UserDefinedType): - def __init__(self, pretty_print=False, xml_declaration=False, - encoding='UTF-8'): + def __init__(self, pretty_print=False, xml_declaration=False, encoding="UTF-8"): super(PGXml, self).__init__() self.xml_declaration = xml_declaration self.pretty_print = pretty_print @@ -69,16 +69,15 @@ def get_col_spec(self, **_): def bind_processor(self, dialect): def process(value): - if value is None or \ - isinstance(value, (six.text_type, six.binary_type)): + if value is None or isinstance(value, (str, bytes)): return value - if six.PY2: - return etree.tostring(value, pretty_print=self.pretty_print, - encoding=self.encoding, xml_declaration=False) - - return etree.tostring(value, pretty_print=self.pretty_print, - encoding="unicode", xml_declaration=False) + return etree.tostring( + value, + pretty_print=self.pretty_print, + encoding="unicode", + xml_declaration=False, + ) return process @@ -88,13 +87,15 @@ def process(value): return etree.fromstring(value) else: return value + return process -sqlalchemy.dialects.postgresql.base.ischema_names['xml'] = PGXml + +sqlalchemy.dialects.postgresql.base.ischema_names["xml"] = PGXml class PGHtml(UserDefinedType): - def __init__(self, pretty_print=False, encoding='UTF-8'): + def __init__(self, pretty_print=False, encoding="UTF-8"): super(PGHtml, self).__init__() self.pretty_print = pretty_print @@ -105,12 +106,13 @@ def get_col_spec(self, **_): def bind_processor(self, dialect): def process(value): - if isinstance(value, (six.text_type, six.binary_type)) \ - or value is None: + if isinstance(value, (str, bytes)) or value is None: return value else: - return html.tostring(value, pretty_print=self.pretty_print, - encoding=self.encoding) + return html.tostring( + value, pretty_print=self.pretty_print, encoding=self.encoding + ) + return process def result_processor(self, dialect, col_type): @@ -119,11 +121,12 @@ def process(value): return html.fromstring(value) else: return None + return process class PGJson(UserDefinedType): - def __init__(self, encoding='UTF-8'): + def __init__(self, encoding="UTF-8"): self.encoding = encoding def get_col_spec(self, **_): @@ -131,24 +134,24 @@ def get_col_spec(self, **_): def bind_processor(self, dialect): def process(value): - if isinstance(value, (text_type, binary_type)) or value is None: + if isinstance(value, (str, bytes)) or value is None: return value else: - if six.PY2: - return json.dumps(value, encoding=self.encoding) - else: - return json.dumps(value) + return json.dumps(value) + return process def result_processor(self, dialect, col_type): def process(value): - if isinstance(value, (text_type, binary_type)): + if isinstance(value, (str, bytes)): return json.loads(value) else: return value + return process -sqlalchemy.dialects.postgresql.base.ischema_names['json'] = PGJson + +sqlalchemy.dialects.postgresql.base.ischema_names["json"] = PGJson class PGJsonB(PGJson): @@ -156,12 +159,11 @@ def get_col_spec(self, **_): return "jsonb" -sqlalchemy.dialects.postgresql.base.ischema_names['jsonb'] = PGJsonB +sqlalchemy.dialects.postgresql.base.ischema_names["jsonb"] = PGJsonB class PGObjectXml(UserDefinedType): - def __init__(self, cls, root_tag_name=None, no_namespace=False, - pretty_print=False): + def __init__(self, cls, root_tag_name=None, no_namespace=False, pretty_print=False): self.cls = cls self.root_tag_name = root_tag_name self.no_namespace = no_namespace @@ -173,29 +175,37 @@ def get_col_spec(self, **_): def bind_processor(self, dialect): def process(value): if value is not None: - return etree.tostring(get_object_as_xml(value, self.cls, - self.root_tag_name, self.no_namespace), encoding='utf8', - pretty_print=self.pretty_print, xml_declaration=False) + return etree.tostring( + get_object_as_xml( + value, self.cls, self.root_tag_name, self.no_namespace + ), + encoding="utf8", + pretty_print=self.pretty_print, + xml_declaration=False, + ) + return process def result_processor(self, dialect, col_type): def process(value): if value is not None: return get_xml_as_object(etree.fromstring(value), self.cls) + return process class PGObjectJson(UserDefinedType): - def __init__(self, cls, ignore_wrappers=True, complex_as=dict, dbt='json', - encoding='utf8'): + def __init__( + self, cls, ignore_wrappers=True, complex_as=dict, dbt="json", encoding="utf8" + ): self.cls = cls self.ignore_wrappers = ignore_wrappers self.complex_as = complex_as self.dbt = dbt self.encoding = encoding - from spyne.util.dictdoc import get_dict_as_object - from spyne.util.dictdoc import get_object_as_json + from spyne.util.dictdoc import get_dict_as_object, get_object_as_json + self.get_object_as_json = get_object_as_json self.get_dict_as_object = get_dict_as_object @@ -206,7 +216,9 @@ def bind_processor(self, dialect): def process(value): if value is not None: try: - return self.get_object_as_json(value, self.cls, + return self.get_object_as_json( + value, + self.cls, ignore_wrappers=self.ignore_wrappers, complex_as=self.complex_as, ).decode(self.encoding) @@ -224,32 +236,37 @@ def process(value): if value is None: return None - if isinstance(value, six.binary_type): + if isinstance(value, bytes): value = value.decode(self.encoding) - if isinstance(value, six.text_type): - return self.get_dict_as_object(json.loads(value), self.cls, - ignore_wrappers=self.ignore_wrappers, - complex_as=self.complex_as, - protocol=JsonDocument, - ) - - return self.get_dict_as_object(value, self.cls, + if isinstance(value, str): + return self.get_dict_as_object( + json.loads(value), + self.cls, ignore_wrappers=self.ignore_wrappers, complex_as=self.complex_as, protocol=JsonDocument, ) + return self.get_dict_as_object( + value, + self.cls, + ignore_wrappers=self.ignore_wrappers, + complex_as=self.complex_as, + protocol=JsonDocument, + ) + return process class PGFileJson(PGObjectJson): - def __init__(self, store, type=None, dbt='json'): + def __init__(self, store, type=None, dbt="json"): if type is None: type = FileData - super(PGFileJson, self).__init__(type, ignore_wrappers=True, - complex_as=list, dbt=dbt) + super(PGFileJson, self).__init__( + type, ignore_wrappers=True, complex_as=list, dbt=dbt + ) self.store = store def bind_processor(self, dialect): @@ -259,10 +276,12 @@ def process(value): value.path = uuid1().hex fp = join(self.store, value.path) if not abspath(fp).startswith(self.store): - raise ValidationError(value.path, "Path %r contains " - "relative path operators (e.g. '..')") + raise ValidationError( + value.path, + "Path %r contains " "relative path operators (e.g. '..')", + ) - with open(fp, 'wb') as file: + with open(fp, "wb") as file: for d in value.data: file.write(d) @@ -270,16 +289,19 @@ def process(value): value.path = uuid1().hex fp = join(self.store, value.path) if not abspath(fp).startswith(self.store): - raise ValidationError(value.path, "Path %r contains " - "relative path operators (e.g. '..')") + raise ValidationError( + value.path, + "Path %r contains " "relative path operators (e.g. '..')", + ) if isinstance(value.handle, (StringIO, BytesIO)): - with open(fp, 'wb') as out_file: + with open(fp, "wb") as out_file: out_file.write(value.handle.getvalue()) else: - with closing(mmap(value.handle.fileno(), 0, - access=ACCESS_READ)) as data: - with open(fp, 'wb') as out_file: + with closing( + mmap(value.handle.fileno(), 0, access=ACCESS_READ) + ) as data: + with open(fp, "wb") as out_file: out_file.write(data) elif value.path is not None: @@ -293,25 +315,27 @@ def process(value): if value.move: shutil.move(in_file_path, dest) - logger.debug("move '%s' => '%s'", - in_file_path, dest) + logger.debug("move '%s' => '%s'", in_file_path, dest) else: shutil.copy(in_file_path, dest) - logger.debug("copy '%s' => '%s'", - in_file_path, dest) + logger.debug("copy '%s' => '%s'", in_file_path, dest) value.path = basename(dest) value.abspath = dest else: - raise ValueError("Invalid file object passed in. All of " - ".data, .handle and .path are None.") + raise ValueError( + "Invalid file object passed in. All of " + ".data, .handle and .path are None." + ) value.store = self.store value.abspath = join(self.store, value.path) - return self.get_object_as_json(value, self.cls, + return self.get_object_as_json( + value, + self.cls, ignore_wrappers=self.ignore_wrappers, complex_as=self.complex_as, ) @@ -323,28 +347,32 @@ def process(value): if value is None: return None - if isinstance(value, six.text_type): + if isinstance(value, str): value = json.loads(value) - elif isinstance(value, six.binary_type): - value = json.loads(value.decode('utf8')) + elif isinstance(value, bytes): + value = json.loads(value.decode("utf8")) - retval = self.get_dict_as_object(value, self.cls, - ignore_wrappers=self.ignore_wrappers, - complex_as=self.complex_as) + retval = self.get_dict_as_object( + value, + self.cls, + ignore_wrappers=self.ignore_wrappers, + complex_as=self.complex_as, + ) retval.store = self.store retval.abspath = path = join(self.store, retval.path) retval.handle = None - retval.data = [b''] + retval.data = [b""] if not os.access(path, os.R_OK): import traceback + traceback.print_stack() logger.error("File '%s' is not readable", path) return retval - h = retval.handle = SeekableFileProxy(open(path, 'rb')) + h = retval.handle = SeekableFileProxy(open(path, "rb")) if os.fstat(retval.handle.fileno()).st_size > 0: h.mmap = mmap(h.fileno(), 0, access=ACCESS_READ) retval.data = (h.mmap,) diff --git a/spyne/store/relational/override.py b/spyne/store/relational/override.py index e04f2fb5c..a4c851f78 100644 --- a/spyne/store/relational/override.py +++ b/spyne/store/relational/override.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,11 +17,17 @@ # +from sqlalchemy.dialects.postgresql import INET from sqlalchemy.ext.compiler import compiles -from sqlalchemy.dialects.postgresql import INET -from spyne.store.relational import PGXml, PGJson, PGHtml, PGJsonB, \ - PGObjectJson, PGFileJson +from spyne.store.relational.document import ( + PGFileJson, + PGHtml, + PGJson, + PGJsonB, + PGObjectJson, + PGXml, +) @compiles(PGXml) @@ -60,7 +65,6 @@ def compile_inet(type_, compiler, **kw): return "inet" - @compiles(PGXml, "firebird") def compile_xml_firebird(type_, compiler, **kw): return "blob" diff --git a/spyne/store/relational/simple.py b/spyne/store/relational/simple.py index 0b2aeba96..828fa4f80 100644 --- a/spyne/store/relational/simple.py +++ b/spyne/store/relational/simple.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,10 +17,10 @@ # from sqlalchemy import sql +from sqlalchemy.dialects.postgresql import ARRAY as PGArray +from sqlalchemy.dialects.postgresql import UUID as PGUuid +from sqlalchemy.dialects.postgresql.base import PGTypeCompiler, ischema_names from sqlalchemy.ext.compiler import compiles -from sqlalchemy.dialects.postgresql.base import ischema_names, PGTypeCompiler -from sqlalchemy.dialects.postgresql import ARRAY as PGArray, UUID as PGUuid - from sqlalchemy.sql.sqltypes import Concatenable from sqlalchemy.sql.type_api import UserDefinedType @@ -31,64 +30,63 @@ def compile_uuid_sqlite(type_, compiler, **kw): return "BLOB" - class PGLTree(Concatenable, UserDefinedType): """Postgresql `ltree` type.""" class Comparator(Concatenable.Comparator): def ancestor_of(self, other): if isinstance(other, list): - return self.op('@>')(sql.cast(other, PGArray(PGLTree))) + return self.op("@>")(sql.cast(other, PGArray(PGLTree))) else: - return self.op('@>')(other) + return self.op("@>")(other) def descendant_of(self, other): if isinstance(other, list): - return self.op('<@')(sql.cast(other, PGArray(PGLTree))) + return self.op("<@")(sql.cast(other, PGArray(PGLTree))) else: - return self.op('<@')(other) + return self.op("<@")(other) def lquery(self, other): if isinstance(other, list): - return self.op('?')(sql.cast(other, PGArray(PGLQuery))) + return self.op("?")(sql.cast(other, PGArray(PGLQuery))) else: - return self.op('~')(other) + return self.op("~")(other) def ltxtquery(self, other): - return self.op('@')(other) + return self.op("@")(other) comparator_factory = Comparator - __visit_name__ = 'LTREE' + __visit_name__ = "LTREE" class PGLQuery(UserDefinedType): """Postresql `lquery` type.""" - __visit_name__ = 'LQUERY' + __visit_name__ = "LQUERY" class PGLTxtQuery(UserDefinedType): """Postresql `ltxtquery` type.""" - __visit_name__ = 'LTXTQUERY' + __visit_name__ = "LTXTQUERY" -ischema_names['ltree'] = PGLTree -ischema_names['lquery'] = PGLQuery -ischema_names['ltxtquery'] = PGLTxtQuery +ischema_names["ltree"] = PGLTree +ischema_names["lquery"] = PGLQuery +ischema_names["ltxtquery"] = PGLTxtQuery def visit_LTREE(self, type_, **kw): - return 'LTREE' + return "LTREE" def visit_LQUERY(self, type_, **kw): - return 'LQUERY' + return "LQUERY" def visit_LTXTQUERY(self, type_, **kw): - return 'LTXTQUERY' + return "LTXTQUERY" PGTypeCompiler.visit_LTREE = visit_LTREE diff --git a/spyne/store/relational/spatial.py b/spyne/store/relational/spatial.py index 152362beb..645e7d5b6 100644 --- a/spyne/store/relational/spatial.py +++ b/spyne/store/relational/spatial.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -31,21 +30,20 @@ class PlainWkt: class PlainWkb: pass - def __init__(self, geometry_type='GEOMETRY', srid=4326, dimension=2, - format='wkt'): + def __init__(self, geometry_type="GEOMETRY", srid=4326, dimension=2, format="wkt"): self.geometry_type = geometry_type.upper() - self.name = 'geometry' + self.name = "geometry" self.srid = int(srid) self.dimension = dimension self.format = format - if self.format == 'wkt': + if self.format == "wkt": self.format = PGGeometry.PlainWkt - elif self.format == 'wkb': + elif self.format == "wkb": self.format = PGGeometry.PlainWkb def get_col_spec(self): - return '%s(%s,%d)' % (self.name, self.geometry_type, self.srid) + return "%s(%s,%d)" % (self.name, self.geometry_type, self.srid) def column_expression(self, col): if self.format is PGGeometry.PlainWkb: @@ -55,11 +53,13 @@ def column_expression(self, col): def result_processor(self, dialect, coltype): if self.format is PGGeometry.PlainWkt: + def process(value): if value is not None: return value if self.format is PGGeometry.PlainWkb: + def process(value): if value is not None: return sql.func.ST_AsBinary(value, self.srid) @@ -76,7 +76,7 @@ def bind_expression(self, bindvalue): @compiles(PGGeometry) def compile_geometry(type_, compiler, **kw): - return '%s(%s,%d)' % (type_.name, type_.geometry_type, type_.srid) + return "%s(%s,%d)" % (type_.name, type_.geometry_type, type_.srid) @compiles(PGGeometry, "sqlite") diff --git a/spyne/store/relational/util.py b/spyne/store/relational/util.py index e30633f32..4ae4f2189 100644 --- a/spyne/store/relational/util.py +++ b/spyne/store/relational/util.py @@ -31,9 +31,8 @@ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -import os import cProfile - +import os from copy import copy from sqlalchemy.engine import Dialect, create_engine @@ -53,7 +52,7 @@ def get_bind(obj): get_bind(session) # Connection object get_bind(user) """ - if hasattr(obj, 'bind'): + if hasattr(obj, "bind"): conn = obj.bind else: try: @@ -61,10 +60,10 @@ def get_bind(obj): except UnmappedInstanceError: conn = obj - if not hasattr(conn, 'execute'): + if not hasattr(conn, "execute"): raise TypeError( - 'This method accepts only Session, Engine, Connection and ' - 'declarative model objects.' + "This method accepts only Session, Engine, Connection and " + "declarative model objects." ) return conn @@ -112,27 +111,29 @@ def database_exists(url): url = copy(make_url(url)) database = url.database - if url.drivername.startswith('postgres'): - url.database = 'postgres' - elif not url.drivername.startswith('sqlite'): + if url.drivername.startswith("postgres"): + url.database = "postgres" + elif not url.drivername.startswith("sqlite"): url.database = None engine = create_engine(url) - if engine.dialect.name == 'postgresql': + if engine.dialect.name == "postgresql": text = "SELECT 1 FROM pg_database WHERE datname='%s'" % database return bool(engine.execute(text).scalar()) - elif engine.dialect.name == 'mysql': - text = ("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA " - "WHERE SCHEMA_NAME = '%s'" % database) + elif engine.dialect.name == "mysql": + text = ( + "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA " + "WHERE SCHEMA_NAME = '%s'" % database + ) return bool(engine.execute(text).scalar()) - elif engine.dialect.name == 'sqlite': - return database == ':memory:' or os.path.exists(database) + elif engine.dialect.name == "sqlite": + return database == ":memory:" or os.path.exists(database) else: - text = 'SELECT 1' + text = "SELECT 1" try: url.database = database engine = create_engine(url) @@ -143,7 +144,7 @@ def database_exists(url): return False -def create_database(url, encoding='utf8', psql_template='template1'): +def create_database(url, encoding="utf8", psql_template="template1"): """Issue the appropriate CREATE DATABASE statement. :param url: A SQLAlchemy engine URL. @@ -170,39 +171,35 @@ def create_database(url, encoding='utf8', psql_template='template1'): database = url.database - if url.drivername.startswith('postgres'): - url.database = 'postgres' - elif not url.drivername.startswith('sqlite'): + if url.drivername.startswith("postgres"): + url.database = "postgres" + elif not url.drivername.startswith("sqlite"): url.database = None engine = create_engine(url) - if engine.dialect.name == 'postgresql': - if engine.driver == 'psycopg2': + if engine.dialect.name == "postgresql": + if engine.driver == "psycopg2": from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT - engine.raw_connection().set_isolation_level( - ISOLATION_LEVEL_AUTOCOMMIT - ) + + engine.raw_connection().set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) text = "CREATE DATABASE {0} ENCODING '{1}' TEMPLATE {2}".format( - quote(engine, database), - encoding, - quote(engine, psql_template) + quote(engine, database), encoding, quote(engine, psql_template) ) engine.execute(text) - elif engine.dialect.name == 'mysql': + elif engine.dialect.name == "mysql": text = "CREATE DATABASE {0} CHARACTER SET = '{1}'".format( - quote(engine, database), - encoding + quote(engine, database), encoding ) engine.execute(text) - elif engine.dialect.name == 'sqlite' and database != ':memory:': - open(database, 'w').close() + elif engine.dialect.name == "sqlite" and database != ":memory:": + open(database, "w").close() else: - text = 'CREATE DATABASE {0}'.format(quote(engine, database)) + text = "CREATE DATABASE {0}".format(quote(engine, database)) engine.execute(text) @@ -223,44 +220,40 @@ def drop_database(url): database = url.database - if url.drivername.startswith('postgresql'): - url.database = 'template1' - elif not url.drivername.startswith('sqlite'): + if url.drivername.startswith("postgresql"): + url.database = "template1" + elif not url.drivername.startswith("sqlite"): url.database = None engine = create_engine(url) - if engine.dialect.name == 'sqlite' and url.database != ':memory:': + if engine.dialect.name == "sqlite" and url.database != ":memory:": os.remove(url.database) - elif engine.dialect.name == 'postgresql' and engine.driver == 'psycopg2': + elif engine.dialect.name == "postgresql" and engine.driver == "psycopg2": from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT + engine.raw_connection().set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) # Disconnect all users from the database we are dropping. version = list( - map( - int, - engine.execute('SHOW server_version').first()[0].split('.') - ) - ) - pid_column = ( - 'pid' if (version[0] >= 9 and version[1] >= 2) else 'procpid' + map(int, engine.execute("SHOW server_version").first()[0].split(".")) ) - text = ''' + pid_column = "pid" if (version[0] >= 9 and version[1] >= 2) else "procpid" + text = """ SELECT pg_terminate_backend(pg_stat_activity.%(pid_column)s) FROM pg_stat_activity WHERE pg_stat_activity.datname = '%(database)s' AND %(pid_column)s <> pg_backend_pid(); - ''' % {'pid_column': pid_column, 'database': database} + """ % {"pid_column": pid_column, "database": database} engine.execute(text) # Drop the database. - text = 'DROP DATABASE {0}'.format(quote(engine, database)) + text = "DROP DATABASE {0}".format(quote(engine, database)) engine.execute(text) else: - text = 'DROP DATABASE {0}'.format(quote(engine, database)) + text = "DROP DATABASE {0}".format(quote(engine, database)) engine.execute(text) @@ -274,6 +267,6 @@ def profiled_func(*args, **kwargs): profile.disable() return result finally: - profile.print_stats(sort='time') + profile.print_stats(sort="time") return profiled_func diff --git a/spyne/test/__init__.py b/spyne/test/__init__.py index 51fda37c1..053d288a8 100644 --- a/spyne/test/__init__.py +++ b/spyne/test/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -17,15 +16,18 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # + class FakeApp(object): - transport = 'transport' - tns = 'tns' - name = 'name' + transport = "transport" + tns = "tns" + name = "name" services = [] classes = () + import logging + logging.basicConfig(level=logging.DEBUG) -logging.getLogger('spyne.util.appreg').setLevel(logging.INFO) +logging.getLogger("spyne.util.appreg").setLevel(logging.INFO) from spyne.context import FakeContext diff --git a/spyne/test/conftest.py b/spyne/test/conftest.py new file mode 100644 index 000000000..cf5541ba3 --- /dev/null +++ b/spyne/test/conftest.py @@ -0,0 +1,9 @@ +import pytest + +import spyne.util.appreg as appreg + + +@pytest.fixture(autouse=True) +def clear_app_registry(): + yield + appreg.applications.clear() diff --git a/spyne/test/interface/test_interface.py b/spyne/test/interface/test_interface.py index a47c7c5bb..6dfdb0483 100755 --- a/spyne/test/interface/test_interface.py +++ b/spyne/test/interface/test_interface.py @@ -21,8 +21,16 @@ import unittest from spyne import Application, Service, rpc -from spyne.model import Array, ComplexModel, AnyXml, UnsignedLong, \ - UnsignedInteger16, Integer, DateTime, Unicode +from spyne.model import ( + AnyXml, + Array, + ComplexModel, + DateTime, + Integer, + Unicode, + UnsignedInteger16, + UnsignedLong, +) from spyne.protocol.http import HttpRpc from spyne.protocol.soap import Soap11 @@ -30,6 +38,7 @@ class TestInterface(unittest.TestCase): def test_imports(self): import logging + logging.basicConfig(level=logging.DEBUG) class KeyValuePair(ComplexModel): @@ -62,10 +71,12 @@ class Service2(Service): def some_other_call(ctx, sth): pass - application = Application([Service1, Service2], + application = Application( + [Service1, Service2], in_protocol=HttpRpc(), out_protocol=Soap11(), - name='Service', tns='target_namespace' + name="Service", + tns="target_namespace", ) imports = application.interface.imports @@ -73,20 +84,20 @@ def some_other_call(ctx, sth): smm = application.interface.service_method_map print(imports) - assert imports[tns] == set(['1', '3', '4']) - assert imports['3'] == set(['2']) - assert imports['4'] == set(['2']) + assert imports[tns] == set(["1", "3", "4"]) + assert imports["3"] == set(["2"]) + assert imports["4"] == set(["2"]) - assert smm['{%s}some_call' % tns] - assert smm['{%s}some_call' % tns][0].service_class == Service1 - assert smm['{%s}some_call' % tns][0].function == Service1.some_call + assert smm["{%s}some_call" % tns] + assert smm["{%s}some_call" % tns][0].service_class == Service1 + assert smm["{%s}some_call" % tns][0].function == Service1.some_call - assert smm['{%s}some_other_call' % tns] - assert smm['{%s}some_other_call' % tns][0].service_class == Service2 - assert smm['{%s}some_other_call' % tns][0].function == Service2.some_other_call + assert smm["{%s}some_other_call" % tns] + assert smm["{%s}some_other_call" % tns][0].service_class == Service2 + assert smm["{%s}some_other_call" % tns][0].function == Service2.some_other_call def test_custom_primitive_in_array(self): - RequestStatus = Unicode(values=['new', 'processed'], zonta='bonta') + RequestStatus = Unicode(values=["new", "processed"], zonta="bonta") class DataRequest(ComplexModel): status = Array(RequestStatus) @@ -96,12 +107,15 @@ class HelloWorldService(Service): def some_call(ctx, dgrntcl): pass - Application([HelloWorldService], 'spyne.examples.hello.soap', - in_protocol=Soap11(validator='lxml'), - out_protocol=Soap11()) + Application( + [HelloWorldService], + "spyne.examples.hello.soap", + in_protocol=Soap11(validator="lxml"), + out_protocol=Soap11(), + ) # test passes if instantiating Application doesn't fail -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/interface/test_wsgi.py b/spyne/test/interface/test_wsgi.py index e27f3c88c..a7e3799cc 100755 --- a/spyne/test/interface/test_wsgi.py +++ b/spyne/test/interface/test_wsgi.py @@ -18,16 +18,14 @@ # import unittest +from io import StringIO -from spyne.util import six -from spyne.util.six import StringIO - -from spyne.protocol.soap.soap11 import Soap11 -from spyne.server.wsgi import WsgiApplication from spyne.application import Application -from spyne.model.primitive import Unicode -from spyne.decorator import rpc from spyne.const.xml import WSDL11 +from spyne.decorator import rpc +from spyne.model.primitive import Unicode +from spyne.protocol.soap.soap11 import Soap11 +from spyne.server.wsgi import WsgiApplication from spyne.service import Service @@ -42,9 +40,9 @@ class SomeService(Service): def some_call(ctx, some_str): print(some_str) - - app = Application([SomeService], "some_tns", in_protocol=Soap11(), - out_protocol=Soap11()) + app = Application( + [SomeService], "some_tns", in_protocol=Soap11(), out_protocol=Soap11() + ) self.wsgi_app = WsgiApplication(app) def test_document_built(self): @@ -54,38 +52,46 @@ def on_wsdl_document_built(doc): self.h += 1 self.wsgi_app.doc.wsdl11.event_manager.add_listener( - "wsdl_document_built", on_wsdl_document_built) + "wsdl_document_built", on_wsdl_document_built + ) self.wsgi_app.doc.wsdl11.build_interface_document("http://some_url/") assert self.h == 1 def test_document_manipulation(self): def on_wsdl_document_built(doc): - doc.root_elt.tag = 'ehe' + doc.root_elt.tag = "ehe" self.wsgi_app.doc.wsdl11.event_manager.add_listener( - "wsdl_document_built", on_wsdl_document_built) + "wsdl_document_built", on_wsdl_document_built + ) self.wsgi_app.doc.wsdl11.build_interface_document("http://some_url/") d = self.wsgi_app.doc.wsdl11.get_interface_document() from lxml import etree - assert etree.fromstring(d).tag == 'ehe' + assert etree.fromstring(d).tag == "ehe" def test_wsgi(self): - retval = b''.join(self.wsgi_app({ - 'PATH_INFO': '/', - 'QUERY_STRING': 'wsdl', - 'SERVER_NAME': 'localhost', - 'SERVER_PORT': '7000', - 'REQUEST_METHOD': 'GET', - 'wsgi.url_scheme': 'http', - 'wsgi.input': StringIO(), - }, start_response)) + retval = b"".join( + self.wsgi_app( + { + "PATH_INFO": "/", + "QUERY_STRING": "wsdl", + "SERVER_NAME": "localhost", + "SERVER_PORT": "7000", + "REQUEST_METHOD": "GET", + "wsgi.url_scheme": "http", + "wsgi.input": StringIO(), + }, + start_response, + ) + ) from lxml import etree - assert etree.fromstring(retval).tag == WSDL11('definitions') + assert etree.fromstring(retval).tag == WSDL11("definitions") + -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/interface/test_xml_schema.py b/spyne/test/interface/test_xml_schema.py index 416353905..ed23e2dd6 100755 --- a/spyne/test/interface/test_xml_schema.py +++ b/spyne/test/interface/test_xml_schema.py @@ -19,32 +19,25 @@ import logging import unittest - from pprint import pprint + from lxml import etree -from spyne import Application -from spyne import rpc +from spyne import Application, rpc from spyne.const import xml as ns from spyne.const.xml import NS_XSD -from spyne.model import ByteArray -from spyne.model import ComplexModel -from spyne.model import XmlAttribute -from spyne.model import XmlData -from spyne.model import AnyXml -from spyne.model import Integer +from spyne.interface.xml_schema import XmlSchema +from spyne.interface.xml_schema.genpy import CodeGenerator +from spyne.model import AnyXml, Boolean, ByteArray, ComplexModel, Integer from spyne.model import Mandatory as M -from spyne.model import Unicode -from spyne.model import Uuid -from spyne.model import Boolean +from spyne.model import Unicode, Uuid, XmlAttribute, XmlData from spyne.protocol.soap import Soap11, Soap12 from spyne.service import Service -from spyne.util.xml import get_schema_documents -from spyne.util.xml import parse_schema_element -from spyne.util.xml import parse_schema_string - -from spyne.interface.xml_schema import XmlSchema -from spyne.interface.xml_schema.genpy import CodeGenerator +from spyne.util.xml import ( + get_schema_documents, + parse_schema_element, + parse_schema_string, +) class TestXmlSchema(unittest.TestCase): @@ -61,68 +54,95 @@ class KickassService(Service): def wooo(ctx): return SomeObject() - Application([KickassService], - tns='kickass.ns', - in_protocol=Soap11(validator='lxml'), - out_protocol=Soap11() + Application( + [KickassService], + tns="kickass.ns", + in_protocol=Soap11(validator="lxml"), + out_protocol=Soap11(), ) docs = get_schema_documents([SomeObject]) - doc = docs['tns'] + doc = docs["tns"] print(etree.tostring(doc, pretty_print=True)) - assert len(doc.xpath('/xs:schema/xs:complexType[@name="SomeObject"]' - '/xs:sequence/xs:element[@name="punk"]', - namespaces={'xs': NS_XSD})) > 0 - assert len(doc.xpath('/xs:schema/xs:complexType[@name="SomeObject"]' + assert ( + len( + doc.xpath( + '/xs:schema/xs:complexType[@name="SomeObject"]' + '/xs:sequence/xs:element[@name="punk"]', + namespaces={"xs": NS_XSD}, + ) + ) + > 0 + ) + assert ( + len( + doc.xpath( + '/xs:schema/xs:complexType[@name="SomeObject"]' '/xs:sequence/xs:choice/xs:element[@name="one"]', - namespaces={'xs': NS_XSD})) > 0 + namespaces={"xs": NS_XSD}, + ) + ) + > 0 + ) def test_customized_class_with_empty_subclass(self): class SummaryStatsOfDouble(ComplexModel): - _type_info = [('Min', XmlAttribute(Integer, use='required')), - ('Max', XmlAttribute(Integer, use='required')), - ('Avg', XmlAttribute(Integer, use='required'))] + _type_info = [ + ("Min", XmlAttribute(Integer, use="required")), + ("Max", XmlAttribute(Integer, use="required")), + ("Avg", XmlAttribute(Integer, use="required")), + ] class SummaryStats(SummaryStatsOfDouble): - ''' this is an empty base class ''' + """this is an empty base class""" class Payload(ComplexModel): - _type_info = [('Stat1', SummaryStats.customize(nillable=False)), - ('Stat2', SummaryStats), - ('Stat3', SummaryStats), - ('Dummy', Unicode)] + _type_info = [ + ("Stat1", SummaryStats.customize(nillable=False)), + ("Stat2", SummaryStats), + ("Stat3", SummaryStats), + ("Dummy", Unicode), + ] class JackedUpService(Service): @rpc(_returns=Payload) def GetPayload(ctx): return Payload() - Application([JackedUpService], - tns='kickass.ns', - in_protocol=Soap11(validator='lxml'), - out_protocol=Soap11() + Application( + [JackedUpService], + tns="kickass.ns", + in_protocol=Soap11(validator="lxml"), + out_protocol=Soap11(), ) # if no exceptions while building the schema, no problem. # see: https://github.com/arskom/spyne/issues/226 - def test_namespaced_xml_attribute(self): class Release(ComplexModel): __namespace__ = "http://usefulinc.com/ns/doap#" _type_info = [ - ('about', XmlAttribute(Unicode, - ns="http://www.w3.org/1999/02/22-rdf-syntax-ns#")), + ( + "about", + XmlAttribute( + Unicode, ns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + ), + ), ] class Project(ComplexModel): __namespace__ = "http://usefulinc.com/ns/doap#" _type_info = [ - ('about', XmlAttribute(Unicode, - ns="http://www.w3.org/1999/02/22-rdf-syntax-ns#")), - ('release', Release.customize(max_occurs=float('inf'))), + ( + "about", + XmlAttribute( + Unicode, ns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + ), + ), + ("release", Release.customize(max_occurs=float("inf"))), ] class RdfService(Service): @@ -130,17 +150,18 @@ class RdfService(Service): def some_call(ctx, a, b): pass - Application([RdfService], - tns='spynepi', - in_protocol=Soap11(validator='lxml'), - out_protocol=Soap11() + Application( + [RdfService], + tns="spynepi", + in_protocol=Soap11(validator="lxml"), + out_protocol=Soap11(), ) # if no exceptions while building the schema, no problem. def test_customized_simple_type_in_xml_attribute(self): class Product(ComplexModel): - __namespace__ = 'some_ns' + __namespace__ = "some_ns" id = XmlAttribute(Uuid) edition = Unicode @@ -148,63 +169,73 @@ class Product(ComplexModel): class SomeService(Service): @rpc(Product, _returns=Product) def echo_product(ctx, product): - logging.info('edition_id: %r', product.edition_id) + logging.info("edition_id: %r", product.edition_id) return product - Application([SomeService], tns='some_ns', - in_protocol=Soap11(validator='lxml'), - out_protocol=Soap11() + Application( + [SomeService], + tns="some_ns", + in_protocol=Soap11(validator="lxml"), + out_protocol=Soap11(), ) # if no exceptions while building the schema, no problem. def test_binary_encodings(self): class Product(ComplexModel): - __namespace__ = 'some_ns' + __namespace__ = "some_ns" - hex = ByteArray(encoding='hex') - base64_1 = ByteArray(encoding='base64') + hex = ByteArray(encoding="hex") + base64_1 = ByteArray(encoding="base64") base64_2 = ByteArray class SomeService(Service): @rpc(Product, _returns=Product) def echo_product(ctx, product): - logging.info('edition_id: %r', product.edition_id) + logging.info("edition_id: %r", product.edition_id) return product - app = Application([SomeService], - tns='some_ns', - in_protocol=Soap11(validator='lxml'), - out_protocol=Soap11() + app = Application( + [SomeService], + tns="some_ns", + in_protocol=Soap11(validator="lxml"), + out_protocol=Soap11(), ) - _ns = {'xs': NS_XSD} + _ns = {"xs": NS_XSD} pref_xs = ns.PREFMAP[NS_XSD] xs = XmlSchema(app.interface) xs.build_interface_document() - elt = xs.get_interface_document()['tns'].xpath( - '//xs:complexType[@name="Product"]', - namespaces=_ns)[0] + elt = xs.get_interface_document()["tns"].xpath( + '//xs:complexType[@name="Product"]', namespaces=_ns + )[0] - assert elt.xpath('//xs:element[@name="base64_1"]/@type', - namespaces=_ns)[0] == '%s:base64Binary' % pref_xs - assert elt.xpath('//xs:element[@name="base64_2"]/@type', - namespaces=_ns)[0] == '%s:base64Binary' % pref_xs - assert elt.xpath('//xs:element[@name="hex"]/@type', - namespaces=_ns)[0] == '%s:hexBinary' % pref_xs + assert ( + elt.xpath('//xs:element[@name="base64_1"]/@type', namespaces=_ns)[0] + == "%s:base64Binary" % pref_xs + ) + assert ( + elt.xpath('//xs:element[@name="base64_2"]/@type', namespaces=_ns)[0] + == "%s:base64Binary" % pref_xs + ) + assert ( + elt.xpath('//xs:element[@name="hex"]/@type', namespaces=_ns)[0] + == "%s:hexBinary" % pref_xs + ) def test_multilevel_customized_simple_type(self): class ExampleService(Service): - __tns__ = 'http://xml.company.com/ns/example/' + __tns__ = "http://xml.company.com/ns/example/" @rpc(M(Uuid), _returns=Unicode) def say_my_uuid(ctx, uuid): - return 'Your UUID: %s' % uuid + return "Your UUID: %s" % uuid - Application([ExampleService], - tns='kickass.ns', - in_protocol=Soap11(validator='lxml'), - out_protocol=Soap11() + Application( + [ExampleService], + tns="kickass.ns", + in_protocol=Soap11(validator="lxml"), + out_protocol=Soap11(), ) # if no exceptions while building the schema, no problem. @@ -216,19 +247,22 @@ def test_any_tag(self): class SomeType(ComplexModel): __namespace__ = "zo" - anything = AnyXml(schema_tag='{%s}any' % NS_XSD, namespace='##other', - process_contents='lax') + anything = AnyXml( + schema_tag="{%s}any" % NS_XSD, + namespace="##other", + process_contents="lax", + ) docs = get_schema_documents([SomeType]) - print(etree.tostring(docs['tns'], pretty_print=True)) - _any = docs['tns'].xpath('//xsd:any', namespaces={'xsd': NS_XSD}) + print(etree.tostring(docs["tns"], pretty_print=True)) + _any = docs["tns"].xpath("//xsd:any", namespaces={"xsd": NS_XSD}) assert len(_any) == 1 - assert _any[0].attrib['namespace'] == '##other' - assert _any[0].attrib['processContents'] == 'lax' + assert _any[0].attrib["namespace"] == "##other" + assert _any[0].attrib["processContents"] == "lax" def _build_xml_data_test_schema(self, custom_root): - tns = 'kickass.ns' + tns = "kickass.ns" class ProductEdition(ComplexModel): __namespace__ = tns @@ -248,27 +282,34 @@ class ExampleService(Service): def say_my_uuid(ctx, product): pass - app = Application([ExampleService], - tns='kickass.ns', - in_protocol=Soap11(validator='lxml'), - out_protocol=Soap11() + app = Application( + [ExampleService], + tns="kickass.ns", + in_protocol=Soap11(validator="lxml"), + out_protocol=Soap11(), ) schema = XmlSchema(app.interface) schema.build_interface_document() schema.build_validation_schema() - doc = schema.get_interface_document()['tns'] + doc = schema.get_interface_document()["tns"] print(etree.tostring(doc, pretty_print=True)) return schema def test_xml_data_schema_doc(self): schema = self._build_xml_data_test_schema(custom_root=False) - assert len(schema.get_interface_document()['tns'].xpath( - '/xs:schema/xs:complexType[@name="ProductEdition"]' - '/xs:simpleContent/xs:extension/xs:attribute[@name="id"]' - ,namespaces={'xs': NS_XSD})) == 1 + assert ( + len( + schema.get_interface_document()["tns"].xpath( + '/xs:schema/xs:complexType[@name="ProductEdition"]' + '/xs:simpleContent/xs:extension/xs:attribute[@name="id"]', + namespaces={"xs": NS_XSD}, + ) + ) + == 1 + ) def _test_xml_data_validation(self): schema = self._build_xml_data_test_schema(custom_root=False) @@ -290,10 +331,11 @@ def _test_xml_data_validation_custom_root(self): """)), schema.validation_schema.error_log.last_error - def test_subs(self): from lxml import etree + from spyne.util.xml import get_schema_documents + xpath = lambda o, x: o.xpath(x, namespaces={"xs": NS_XSD}) m = { @@ -309,10 +351,10 @@ class C(ComplexModel): c = Integer(sub_ns="cc") d = Integer(sub_ns="dd", sub_name="dd") - elt = get_schema_documents([C], "aa")['tns'] + elt = get_schema_documents([C], "aa")["tns"] print(etree.tostring(elt, pretty_print=True)) - seq, = xpath(elt, "xs:complexType/xs:sequence") + (seq,) = xpath(elt, "xs:complexType/xs:sequence") assert len(seq) == 4 assert len(xpath(seq, 'xs:element[@name="a"]')) == 1 @@ -321,8 +363,8 @@ class C(ComplexModel): # FIXME: this doesn't feel right. # check the spec to see whether it should it be prefixed. # - #assert len(xpath(seq, 'xs:element[@name="{cc}c"]')) == 1 - #assert len(xpath(seq, 'xs:element[@name="{dd}dd"]')) == 1 + # assert len(xpath(seq, 'xs:element[@name="{cc}c"]')) == 1 + # assert len(xpath(seq, 'xs:element[@name="{dd}dd"]')) == 1 def test_mandatory(self): xpath = lambda o, x: o.xpath(x, namespaces={"xs": NS_XSD}) @@ -331,35 +373,37 @@ class C(ComplexModel): __namespace__ = "aa" foo = XmlAttribute(M(Unicode)) - elt = get_schema_documents([C])['tns'] + elt = get_schema_documents([C])["tns"] print(etree.tostring(elt, pretty_print=True)) - foo, = xpath(elt, 'xs:complexType/xs:attribute[@name="foo"]') + (foo,) = xpath(elt, 'xs:complexType/xs:attribute[@name="foo"]') attrs = foo.attrib - assert 'use' in attrs and attrs['use'] == 'required' + assert "use" in attrs and attrs["use"] == "required" def test_annotation(self): - tns = 'some_ns' + tns = "some_ns" doc = "Some Doc" class SomeClass(ComplexModel): __namespace__ = tns some_attr = Unicode(doc=doc) - schema = get_schema_documents([SomeClass], tns)['tns'] + schema = get_schema_documents([SomeClass], tns)["tns"] print(etree.tostring(schema, pretty_print=True)) - assert schema.xpath("//xs:documentation/text()", - namespaces={'xs': NS_XSD}) == [doc] + assert schema.xpath("//xs:documentation/text()", namespaces={"xs": NS_XSD}) == [ + doc + ] class TestParseOwnXmlSchema(unittest.TestCase): def test_simple(self): - tns = 'some_ns' + tns = "some_ns" + class SomeGuy(ComplexModel): - __namespace__ = 'some_ns' + __namespace__ = "some_ns" id = Integer - schema = get_schema_documents([SomeGuy], tns)['tns'] + schema = get_schema_documents([SomeGuy], tns)["tns"] print(etree.tostring(schema, pretty_print=True)) objects = parse_schema_element(schema) @@ -371,103 +415,111 @@ class SomeGuy(ComplexModel): assert dict(NewGuy._type_info) == dict(SomeGuy._type_info) def test_customized_unicode(self): - tns = 'some_ns' + tns = "some_ns" + class SomeGuy(ComplexModel): __namespace__ = tns name = Unicode(max_len=10, pattern="a", min_len=5, default="aa") - schema = get_schema_documents([SomeGuy], tns)['tns'] + schema = get_schema_documents([SomeGuy], tns)["tns"] print(etree.tostring(schema, pretty_print=True)) objects = parse_schema_element(schema) pprint(objects[tns].types) - NewGuy = objects['some_ns'].types["SomeGuy"] - assert NewGuy._type_info['name'].Attributes.max_len == 10 - assert NewGuy._type_info['name'].Attributes.min_len == 5 - assert NewGuy._type_info['name'].Attributes.pattern == "a" - assert NewGuy._type_info['name'].Attributes.default == "aa" + NewGuy = objects["some_ns"].types["SomeGuy"] + assert NewGuy._type_info["name"].Attributes.max_len == 10 + assert NewGuy._type_info["name"].Attributes.min_len == 5 + assert NewGuy._type_info["name"].Attributes.pattern == "a" + assert NewGuy._type_info["name"].Attributes.default == "aa" def test_boolean_default(self): - tns = 'some_ns' + tns = "some_ns" + class SomeGuy(ComplexModel): __namespace__ = tns bald = Boolean(default=True) - schema = get_schema_documents([SomeGuy], tns)['tns'] + schema = get_schema_documents([SomeGuy], tns)["tns"] print(etree.tostring(schema, pretty_print=True)) objects = parse_schema_element(schema) pprint(objects[tns].types) - NewGuy = objects['some_ns'].types["SomeGuy"] - assert NewGuy._type_info['bald'].Attributes.default == True + NewGuy = objects["some_ns"].types["SomeGuy"] + assert NewGuy._type_info["bald"].Attributes.default == True def test_boolean_attribute_default(self): - tns = 'some_ns' + tns = "some_ns" + class SomeGuy(ComplexModel): __namespace__ = tns bald = XmlAttribute(Boolean(default=True)) - schema = get_schema_documents([SomeGuy], tns)['tns'] + schema = get_schema_documents([SomeGuy], tns)["tns"] print(etree.tostring(schema, pretty_print=True)) objects = parse_schema_element(schema) pprint(objects[tns].types) - NewGuy = objects['some_ns'].types["SomeGuy"] - assert NewGuy._type_info['bald'].Attributes.default == True + NewGuy = objects["some_ns"].types["SomeGuy"] + assert NewGuy._type_info["bald"].Attributes.default == True def test_attribute(self): - tns = 'some_ns' + tns = "some_ns" + class SomeGuy(ComplexModel): __namespace__ = tns name = XmlAttribute(Unicode) - schema = get_schema_documents([SomeGuy], tns)['tns'] + schema = get_schema_documents([SomeGuy], tns)["tns"] print(etree.tostring(schema, pretty_print=True)) objects = parse_schema_element(schema) pprint(objects) pprint(objects[tns].types) - NewGuy = objects['some_ns'].types["SomeGuy"] - assert NewGuy._type_info['name'].type is Unicode + NewGuy = objects["some_ns"].types["SomeGuy"] + assert NewGuy._type_info["name"].type is Unicode def test_attribute_with_customized_type(self): - tns = 'some_ns' + tns = "some_ns" + class SomeGuy(ComplexModel): __namespace__ = tns name = XmlAttribute(Unicode(default="aa")) - schema = get_schema_documents([SomeGuy], tns)['tns'] + schema = get_schema_documents([SomeGuy], tns)["tns"] print(etree.tostring(schema, pretty_print=True)) objects = parse_schema_element(schema) pprint(objects[tns].types) - NewGuy = objects['some_ns'].types["SomeGuy"] - assert NewGuy._type_info['name'].type.__orig__ is Unicode - assert NewGuy._type_info['name'].type.Attributes.default == "aa" + NewGuy = objects["some_ns"].types["SomeGuy"] + assert NewGuy._type_info["name"].type.__orig__ is Unicode + assert NewGuy._type_info["name"].type.Attributes.default == "aa" def test_inherited_attribute(self): class DeviceEntity(ComplexModel): - token = XmlAttribute(Unicode, use='required') + token = XmlAttribute(Unicode, use="required") class DigitalInput(DeviceEntity): IdleState = XmlAttribute(Unicode) class SomeService(Service): - @rpc(_returns=DigitalInput, _body_style='bare') + @rpc(_returns=DigitalInput, _body_style="bare") def GetDigitalInput(ctx): return DigitalInput() - Application([SomeService], 'some_tns', - in_protocol=Soap11(validator='lxml'), - out_protocol=Soap11()) + Application( + [SomeService], + "some_tns", + in_protocol=Soap11(validator="lxml"), + out_protocol=Soap11(), + ) def test_simple_type_explicit_customization(self): class Header(ComplexModel): @@ -480,20 +532,21 @@ class Params(ComplexModel): class DummyService(Service): @rpc(Params, _returns=Unicode) def loadServices(ctx, serviceParams): - return '42' - - Application([DummyService], - tns='dummy', - name='DummyService', - in_protocol=Soap11(validator='lxml'), - out_protocol=Soap11() + return "42" + + Application( + [DummyService], + tns="dummy", + name="DummyService", + in_protocol=Soap11(validator="lxml"), + out_protocol=Soap11(), ) # if instantiation doesn't fail, test is green. class TestParseForeignXmlSchema(unittest.TestCase): def test_simple_content(self): - tns = 'some_ns' + tns = "some_ns" schema = """ need 2 service, 3 port and 3 bindings - services = interface_doc.root_elt.xpath( - '/wsdl:definitions/wsdl:service', - namespaces = { - 'wsdl':'http://schemas.xmlsoap.org/wsdl/' }) + services = interface_doc.root_elt.xpath( + "/wsdl:definitions/wsdl:service", + namespaces={"wsdl": "http://schemas.xmlsoap.org/wsdl/"}, + ) self.assertEqual(len(services), 2) - portTypes = interface_doc.root_elt.xpath( - '/wsdl:definitions/wsdl:portType', - namespaces = { - 'wsdl':'http://schemas.xmlsoap.org/wsdl/' }) + portTypes = interface_doc.root_elt.xpath( + "/wsdl:definitions/wsdl:portType", + namespaces={"wsdl": "http://schemas.xmlsoap.org/wsdl/"}, + ) self.assertEqual(len(portTypes), 3) - - bindings = interface_doc.root_elt.xpath( - '/wsdl:definitions/wsdl:binding', - namespaces = { - 'wsdl':'http://schemas.xmlsoap.org/wsdl/' }) + bindings = interface_doc.root_elt.xpath( + "/wsdl:definitions/wsdl:binding", + namespaces={"wsdl": "http://schemas.xmlsoap.org/wsdl/"}, + ) self.assertEqual(len(bindings), 3) - ports = interface_doc.root_elt.xpath( - '/wsdl:definitions/wsdl:service[@name="%s"]/wsdl:port' % - SinglePortService.__service_name__, - namespaces = { - 'wsdl':'http://schemas.xmlsoap.org/wsdl/' }) + ports = interface_doc.root_elt.xpath( + '/wsdl:definitions/wsdl:service[@name="%s"]/wsdl:port' + % SinglePortService.__service_name__, + namespaces={"wsdl": "http://schemas.xmlsoap.org/wsdl/"}, + ) self.assertEqual(len(ports), 1) - ports = interface_doc.root_elt.xpath( - '/wsdl:definitions/wsdl:service[@name="%s"]/wsdl:port' % - "DoublePortService", - namespaces = { - 'wsdl':'http://schemas.xmlsoap.org/wsdl/' }) + ports = interface_doc.root_elt.xpath( + '/wsdl:definitions/wsdl:service[@name="%s"]/wsdl:port' + % "DoublePortService", + namespaces={"wsdl": "http://schemas.xmlsoap.org/wsdl/"}, + ) self.assertEqual(len(ports), 2) # checking name and type - #service SinglePortService + # service SinglePortService for srv in (SinglePortService, DoublePortService): for port in srv.__port_types__: - bindings = interface_doc.root_elt.xpath( - '/wsdl:definitions/wsdl:binding[@name="%s"]' % - port, - namespaces = { - 'wsdl':'http://schemas.xmlsoap.org/wsdl/' }) - self.assertEqual(bindings[0].get('type'), "tns:%s" % port) + bindings = interface_doc.root_elt.xpath( + '/wsdl:definitions/wsdl:binding[@name="%s"]' % port, + namespaces={"wsdl": "http://schemas.xmlsoap.org/wsdl/"}, + ) + self.assertEqual(bindings[0].get("type"), "tns:%s" % port) diff --git a/spyne/test/interface/wsdl/test_default_wsdl.py b/spyne/test/interface/wsdl/test_default_wsdl.py index c81046e73..8c0442f9f 100755 --- a/spyne/test/interface/wsdl/test_default_wsdl.py +++ b/spyne/test/interface/wsdl/test_default_wsdl.py @@ -19,6 +19,7 @@ import logging + logging.basicConfig(level=logging.DEBUG) import unittest @@ -26,26 +27,21 @@ from lxml import etree from spyne.application import Application - -from spyne.test.interface.wsdl import AppTestWrapper -from spyne.test.interface.wsdl import build_app -from spyne.test.interface.wsdl.defult_services import TDefaultPortService -from spyne.test.interface.wsdl.defult_services import \ - TDefaultPortServiceMultipleMethods - -from spyne.const import REQUEST_SUFFIX -from spyne.const import RESPONSE_SUFFIX -from spyne.const import ARRAY_SUFFIX - +from spyne.const import ARRAY_SUFFIX, REQUEST_SUFFIX, RESPONSE_SUFFIX from spyne.decorator import srpc -from spyne.service import Service from spyne.interface.wsdl import Wsdl11 from spyne.model.complex import Array from spyne.model.primitive import String +from spyne.service import Service +from spyne.test.interface.wsdl import AppTestWrapper, build_app +from spyne.test.interface.wsdl.defult_services import ( + TDefaultPortService, + TDefaultPortServiceMultipleMethods, +) ns = { - 'wsdl': 'http://schemas.xmlsoap.org/wsdl/', - 'xs': 'http://www.w3.org/2001/XMLSchema', + "wsdl": "http://schemas.xmlsoap.org/wsdl/", + "xs": "http://www.w3.org/2001/XMLSchema", } @@ -58,7 +54,7 @@ def _default_service(self, app_wrapper, service_name): # the default behavior requires that there be only a single service self.assertEqual(1, len(services)) - self.assertEqual(service_name, service.get('name')) + self.assertEqual(service_name, service.get("name")) # Test the default service has the correct number of ports # the default behavior requires that there be only a single port @@ -75,7 +71,7 @@ def _default_port_type(self, app_wrapper, portType_name, op_count): # Verify the portType name portType = portTypes[0] # Check the name of the port - self.assertEqual(portType_name, portType.get('name')) + self.assertEqual(portType_name, portType.get("name")) # verify that the portType definition has the correct # number of operations @@ -89,7 +85,7 @@ def _default_binding(self, wrapper, binding_name, opp_count): # check for the correct binding name binding = bindings[0] - name = binding.get('name') + name = binding.get("name") self.assertEqual(binding_name, name) # Test that the default service contains the soap binding @@ -109,25 +105,21 @@ def _default_binding_methods(self, wrapper, op_count, op_names): # Check the operation names are correct for op in operations: - self.assertTrue(op.get('name') in op_names) + self.assertTrue(op.get("name") in op_names) def test_default_port_type(self): # Test the default port is created # Test the default port has the correct name - app = build_app( - [TDefaultPortService()], - 'DefaultPortTest', - 'DefaultPortName' - ) + app = build_app([TDefaultPortService()], "DefaultPortTest", "DefaultPortName") wrapper = AppTestWrapper(app) - self._default_port_type(wrapper, 'DefaultPortName', 1) + self._default_port_type(wrapper, "DefaultPortName", 1) def test_default_port_type_multiple(self): app = build_app( [TDefaultPortServiceMultipleMethods()], - 'DefaultServiceTns', - 'MultipleDefaultPortServiceApp' + "DefaultServiceTns", + "MultipleDefaultPortServiceApp", ) wrapper = AppTestWrapper(app) @@ -136,9 +128,7 @@ def test_default_port_type_multiple(self): def test_default_binding(self): app = build_app( - [TDefaultPortService()], - 'DefaultPortTest', - 'DefaultBindingName' + [TDefaultPortService()], "DefaultPortTest", "DefaultBindingName" ) wrapper = AppTestWrapper(app) @@ -148,40 +138,34 @@ def test_default_binding(self): def test_default_binding_multiple(self): app = build_app( [TDefaultPortServiceMultipleMethods()], - 'DefaultPortTest', - 'MultipleDefaultBindingNameApp' + "DefaultPortTest", + "MultipleDefaultBindingNameApp", ) wrapper = AppTestWrapper(app) - self._default_binding(wrapper, 'MultipleDefaultBindingNameApp', 3) + self._default_binding(wrapper, "MultipleDefaultBindingNameApp", 3) def test_default_binding_methods(self): app = build_app( - [TDefaultPortService()], - 'DefaultPortTest', - 'DefaultPortMethods' + [TDefaultPortService()], "DefaultPortTest", "DefaultPortMethods" ) wrapper = AppTestWrapper(app) - self._default_binding_methods( - wrapper, - 1, - ['echo_default_port_service'] - ) + self._default_binding_methods(wrapper, 1, ["echo_default_port_service"]) def test_bare_simple(self): class SomeService(Service): - @srpc(String, _returns=String, _body_style='bare') + @srpc(String, _returns=String, _body_style="bare") def whatever(ss): return ss - app = Application([SomeService], tns='tns') - app.transport = 'None' + app = Application([SomeService], tns="tns") + app.transport = "None" wsdl = Wsdl11(app.interface) - wsdl.build_interface_document('url') + wsdl.build_interface_document("url") wsdl = etree.fromstring(wsdl.get_interface_document()) schema = wsdl.xpath( @@ -193,14 +177,16 @@ def whatever(ss): print(etree.tostring(wsdl, pretty_print=True)) elts = schema[0].xpath( - 'xs:element[@name="whatever%s"]' % REQUEST_SUFFIX, namespaces=ns) + 'xs:element[@name="whatever%s"]' % REQUEST_SUFFIX, namespaces=ns + ) assert len(elts) > 0 - assert elts[0].attrib['type'] == 'xs:string' + assert elts[0].attrib["type"] == "xs:string" elts = schema[0].xpath( - 'xs:element[@name="whatever%s"]' % RESPONSE_SUFFIX, namespaces=ns) + 'xs:element[@name="whatever%s"]' % RESPONSE_SUFFIX, namespaces=ns + ) assert len(elts) > 0 - assert elts[0].attrib['type'] == 'xs:string' + assert elts[0].attrib["type"] == "xs:string" def test_bare_with_conflicting_types(self): class SomeService(Service): @@ -208,41 +194,46 @@ class SomeService(Service): def whatever(sa): return sa - @srpc(Array(String), _returns=Array(String), _body_style='bare') + @srpc(Array(String), _returns=Array(String), _body_style="bare") def whatever_bare(sa): return sa - app = Application([SomeService], tns='tns') - app.transport = 'None' + app = Application([SomeService], tns="tns") + app.transport = "None" wsdl = Wsdl11(app.interface) - wsdl.build_interface_document('url') + wsdl.build_interface_document("url") wsdl = etree.fromstring(wsdl.get_interface_document()) - schema, = wsdl.xpath( + (schema,) = wsdl.xpath( '/wsdl:definitions/wsdl:types/xs:schema[@targetNamespace="tns"]', namespaces=ns, ) print(etree.tostring(schema, pretty_print=True)) - assert len(schema.xpath( - 'xs:complexType[@name="string%s"]' % ARRAY_SUFFIX, - namespaces=ns)) > 0 + assert ( + len( + schema.xpath( + 'xs:complexType[@name="string%s"]' % ARRAY_SUFFIX, namespaces=ns + ) + ) + > 0 + ) elts = schema.xpath( - 'xs:element[@name="whatever_bare%s"]' % REQUEST_SUFFIX, - namespaces=ns) + 'xs:element[@name="whatever_bare%s"]' % REQUEST_SUFFIX, namespaces=ns + ) assert len(elts) > 0 - assert elts[0].attrib['type'] == 'tns:string%s' % ARRAY_SUFFIX + assert elts[0].attrib["type"] == "tns:string%s" % ARRAY_SUFFIX elts = schema.xpath( - 'xs:element[@name="whatever_bare%s"]' % RESPONSE_SUFFIX, - namespaces=ns) + 'xs:element[@name="whatever_bare%s"]' % RESPONSE_SUFFIX, namespaces=ns + ) assert len(elts) > 0 - assert elts[0].attrib['type'] == 'tns:string%s' % ARRAY_SUFFIX + assert elts[0].attrib["type"] == "tns:string%s" % ARRAY_SUFFIX -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/interface/wsdl/test_op_req_suffix.py b/spyne/test/interface/wsdl/test_op_req_suffix.py index 141395b74..00d986b5b 100755 --- a/spyne/test/interface/wsdl/test_op_req_suffix.py +++ b/spyne/test/interface/wsdl/test_op_req_suffix.py @@ -21,19 +21,19 @@ from webtest import TestApp as _TestApp # avoid confusing py.test from spyne.application import Application +from spyne.const.xml import NS_WSDL11_SOAP, PREFMAP from spyne.decorator import srpc -from spyne.service import Service -from spyne.model.primitive import Integer, Unicode from spyne.model.complex import Iterable -from spyne.protocol.soap import Soap11 +from spyne.model.primitive import Integer, Unicode from spyne.protocol.http import HttpRpc from spyne.protocol.json import JsonDocument +from spyne.protocol.soap import Soap11 from spyne.server.wsgi import WsgiApplication +from spyne.service import Service -from spyne.const.xml import PREFMAP, NS_WSDL11_SOAP def strip_whitespace(string): - return ''.join(string.split()) + return "".join(string.split()) class TestOperationRequestSuffix(unittest.TestCase): @@ -42,10 +42,10 @@ class TestOperationRequestSuffix(unittest.TestCase): _in_message_name is a concern, will test that as well """ - default_function_name = 'echo' + default_function_name = "echo" # output is not affected, will use soap output for all tests - result_body = ''' + result_body = """ @@ -53,10 +53,9 @@ class TestOperationRequestSuffix(unittest.TestCase): Echo, test - ''' + """ - def get_function_names(self, suffix, _operation_name=None, - _in_message_name=None): + def get_function_names(self, suffix, _operation_name=None, _in_message_name=None): """This tests the logic of how names are produced. Its logic should match expected behavior of the decorator. returns operation name, in message name, service name depending on @@ -75,37 +74,38 @@ def get_function_names(self, suffix, _operation_name=None, return function_name, operation_name, request_name - def get_app(self, in_protocol, suffix, _operation_name=None, - _in_message_name=None): + def get_app(self, in_protocol, suffix, _operation_name=None, _in_message_name=None): """setup testapp dependent on suffix and _in_message_name""" import spyne.const + spyne.const.REQUEST_SUFFIX = suffix class EchoService(Service): - srpc_kparams = {'_returns': Iterable(Unicode)} + srpc_kparams = {"_returns": Iterable(Unicode)} if _in_message_name: - srpc_kparams['_in_message_name'] = _in_message_name + srpc_kparams["_in_message_name"] = _in_message_name if _operation_name: - srpc_kparams['_operation_name'] = _operation_name + srpc_kparams["_operation_name"] = _operation_name @srpc(Unicode, Integer, **srpc_kparams) def echo(string, times): for i in range(times): - yield 'Echo, %s' % string + yield "Echo, %s" % string - application = Application([EchoService], - tns='spyne.examples.echo', + application = Application( + [EchoService], + tns="spyne.examples.echo", in_protocol=in_protocol, - out_protocol=Soap11() + out_protocol=Soap11(), ) app = WsgiApplication(application) testapp = _TestApp(app) # so that it doesn't interfere with other tests. - spyne.const.REQUEST_SUFFIX = '' + spyne.const.REQUEST_SUFFIX = "" return testapp @@ -114,32 +114,42 @@ def assert_response_ok(self, resp): self.assertEqual(resp.status_int, 200, resp) self.assertTrue( strip_whitespace(self.result_body) in strip_whitespace(str(resp)), - '{0} not in {1}'.format(self.result_body, resp)) + "{0} not in {1}".format(self.result_body, resp), + ) ### application error tests ### - def assert_application_error(self, suffix, _operation_name=None, - _in_message_name=None): - self.assertRaises(ValueError, - self.get_app, Soap11(validator='lxml'), suffix, - _operation_name, _in_message_name) + def assert_application_error( + self, suffix, _operation_name=None, _in_message_name=None + ): + self.assertRaises( + ValueError, + self.get_app, + Soap11(validator="lxml"), + suffix, + _operation_name, + _in_message_name, + ) def test_assert_application_error(self): """check error when op namd and in name are both used""" - self.assert_application_error(suffix='', - _operation_name='TestOperationName', - _in_message_name='TestMessageName') + self.assert_application_error( + suffix="", + _operation_name="TestOperationName", + _in_message_name="TestMessageName", + ) ### soap tests ### - def assert_soap_ok(self, suffix, _operation_name=None, - _in_message_name=None): + def assert_soap_ok(self, suffix, _operation_name=None, _in_message_name=None): """helper to test soap requests""" # setup - app = self.get_app(Soap11(validator='lxml'), suffix, _operation_name, - _in_message_name) + app = self.get_app( + Soap11(validator="lxml"), suffix, _operation_name, _in_message_name + ) function_name, operation_name, request_name = self.get_function_names( - suffix, _operation_name, _in_message_name) + suffix, _operation_name, _in_message_name + ) soap_input_body = """ """.format(request_name) # check wsdl - wsdl = app.get('/?wsdl') + wsdl = app.get("/?wsdl") self.assertEqual(wsdl.status_int, 200, wsdl) - self.assertTrue(request_name in wsdl, - '{0} not found in wsdl'.format(request_name)) + self.assertTrue( + request_name in wsdl, "{0} not found in wsdl".format(request_name) + ) soap_strings = [ ''.format(request_name), ''.format(request_name), ] for soap_string in soap_strings: - self.assertTrue(soap_string in wsdl, - '{0} not in {1}'.format(soap_string, wsdl)) + self.assertTrue( + soap_string in wsdl, "{0} not in {1}".format(soap_string, wsdl) + ) if request_name != operation_name: wrong_string = '= 2.5") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/spyne/test/interop/server/httprpc_pod_basic_twisted.py b/spyne/test/interop/server/httprpc_pod_basic_twisted.py index 6e824f408..fb349f96c 100755 --- a/spyne/test/interop/server/httprpc_pod_basic_twisted.py +++ b/spyne/test/interop/server/httprpc_pod_basic_twisted.py @@ -20,28 +20,34 @@ """pod being plain old data""" import logging + logging.basicConfig(level=logging.DEBUG) -logger = logging.getLogger('spyne.protocol.xml') +logger = logging.getLogger("spyne.protocol.xml") logger.setLevel(logging.DEBUG) -from spyne.test.interop.server import get_open_port from spyne.application import Application -from spyne.test.interop.server._service import services from spyne.protocol.http import HttpRpc from spyne.server.twisted import TwistedWebResource +from spyne.test.interop.server import get_open_port +from spyne.test.interop.server._service import services -httprpc_soap_application = Application(services, - 'spyne.test.interop.server.httprpc.pod', - in_protocol=HttpRpc(), out_protocol=HttpRpc()) +httprpc_soap_application = Application( + services, + "spyne.test.interop.server.httprpc.pod", + in_protocol=HttpRpc(), + out_protocol=HttpRpc(), +) -host = '127.0.0.1' +host = "127.0.0.1" port = [0] + def main(argv): - from twisted.web.server import Site from twisted.internet import reactor from twisted.python import log - observer = log.PythonLoggingObserver('twisted') + from twisted.web.server import Site + + observer = log.PythonLoggingObserver("twisted") log.startLoggingWithObserver(observer.emit, setStdout=False) if port[0] == 0: @@ -51,11 +57,12 @@ def main(argv): site = Site(wr) reactor.listenTCP(port[0], site) - logging.info("listening on: %s:%d" % (host,port[0])) + logging.info("listening on: %s:%d" % (host, port[0])) return reactor.run() -if __name__ == '__main__': +if __name__ == "__main__": import sys + sys.exit(main(sys.argv)) diff --git a/spyne/test/interop/server/msgpackrpc_http_basic.py b/spyne/test/interop/server/msgpackrpc_http_basic.py index d19e869f9..53880b911 100644 --- a/spyne/test/interop/server/msgpackrpc_http_basic.py +++ b/spyne/test/interop/server/msgpackrpc_http_basic.py @@ -18,39 +18,46 @@ # import logging + logging.basicConfig(level=logging.DEBUG) -logging.getLogger('spyne.protocol.msgpack').setLevel(logging.DEBUG) -logger = logging.getLogger('spyne.test.interop.server.msgpackrpc_http_basic') +logging.getLogger("spyne.protocol.msgpack").setLevel(logging.DEBUG) +logger = logging.getLogger("spyne.test.interop.server.msgpackrpc_http_basic") -from spyne.test.interop.server import get_open_port -from spyne.server.wsgi import WsgiApplication -from spyne.test.interop.server._service import services from spyne.application import Application from spyne.protocol.msgpack import MessagePackRpc +from spyne.server.wsgi import WsgiApplication +from spyne.test.interop.server import get_open_port +from spyne.test.interop.server._service import services -msgpackrpc_application = Application(services, 'spyne.test.interop.server', - in_protocol=MessagePackRpc(validator='soft'), - out_protocol=MessagePackRpc()) +msgpackrpc_application = Application( + services, + "spyne.test.interop.server", + in_protocol=MessagePackRpc(validator="soft"), + out_protocol=MessagePackRpc(), +) -host = '127.0.0.1' +host = "127.0.0.1" port = [0] + def main(): try: from wsgiref.simple_server import make_server from wsgiref.validate import validator + if port[0] == 0: port[0] = get_open_port() wsgi_application = WsgiApplication(msgpackrpc_application) server = make_server(host, port[0], validator(wsgi_application)) - logger.info('Starting interop server at %s:%s.' % (host, port[0])) - logger.info('WSDL is at: /?wsdl') + logger.info("Starting interop server at %s:%s." % (host, port[0])) + logger.info("WSDL is at: /?wsdl") server.serve_forever() except ImportError: print("Error: example server code requires Python >= 2.5") -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/spyne/test/interop/server/soap11/httprpc_soap_basic.py b/spyne/test/interop/server/soap11/httprpc_soap_basic.py index 3969598bc..595b9a11f 100755 --- a/spyne/test/interop/server/soap11/httprpc_soap_basic.py +++ b/spyne/test/interop/server/soap11/httprpc_soap_basic.py @@ -18,38 +18,43 @@ # import logging + logging.basicConfig(level=logging.DEBUG) -logger = logging.getLogger('spyne.protocol.xml') +logger = logging.getLogger("spyne.protocol.xml") logger.setLevel(logging.DEBUG) from spyne.application import Application -from spyne.test.interop.server._service import services from spyne.protocol.http import HttpRpc from spyne.protocol.soap import Soap11 from spyne.server.wsgi import WsgiApplication from spyne.test.interop.server import get_open_port +from spyne.test.interop.server._service import services - -httprpc_soap_application = Application(services, - 'spyne.test.interop.server.httprpc.soap', in_protocol=HttpRpc(), out_protocol=Soap11()) +httprpc_soap_application = Application( + services, + "spyne.test.interop.server.httprpc.soap", + in_protocol=HttpRpc(), + out_protocol=Soap11(), +) -host = '127.0.0.1' +host = "127.0.0.1" port = [0] -if __name__ == '__main__': +if __name__ == "__main__": try: from wsgiref.simple_server import make_server from wsgiref.validate import validator + if port[0] == 0: port[0] = get_open_port() wsgi_application = WsgiApplication(httprpc_soap_application) server = make_server(host, port[0], validator(wsgi_application)) - logger.info('Starting interop server at %s:%s.' % ('0.0.0.0', port[0])) - logger.info('WSDL is at: /?wsdl') + logger.info("Starting interop server at %s:%s." % ("0.0.0.0", port[0])) + logger.info("WSDL is at: /?wsdl") server.serve_forever() except ImportError: diff --git a/spyne/test/interop/server/soap11/soap_http_basic.py b/spyne/test/interop/server/soap11/soap_http_basic.py index 65a86057d..433e57d7f 100755 --- a/spyne/test/interop/server/soap11/soap_http_basic.py +++ b/spyne/test/interop/server/soap11/soap_http_basic.py @@ -20,23 +20,25 @@ import logging logging.basicConfig(level=logging.DEBUG) -logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG) -logger = logging.getLogger('spyne.test.interop.server.soap_http_basic') +logging.getLogger("spyne.protocol.xml").setLevel(logging.DEBUG) +logger = logging.getLogger("spyne.test.interop.server.soap_http_basic") -from spyne.test.interop.server import get_open_port -from spyne.server.wsgi import WsgiApplication -from spyne.test.interop.server._service import services from spyne.application import Application from spyne.protocol.soap import Soap11 +from spyne.server.wsgi import WsgiApplication +from spyne.test.interop.server import get_open_port +from spyne.test.interop.server._service import services - -soap11_application = Application(services, 'spyne.test.interop.server', - in_protocol=Soap11(validator='lxml', cleanup_namespaces=True), - out_protocol=Soap11()) +soap11_application = Application( + services, + "spyne.test.interop.server", + in_protocol=Soap11(validator="lxml", cleanup_namespaces=True), + out_protocol=Soap11(), +) -host = '127.0.0.1' +host = "127.0.0.1" port = [0] @@ -44,19 +46,20 @@ def main(): try: from wsgiref.simple_server import make_server from wsgiref.validate import validator + if port[0] == 0: port[0] = get_open_port() wsgi_application = WsgiApplication(soap11_application) server = make_server(host, port[0], validator(wsgi_application)) - logger.info('Starting interop server at %s:%s.' % ('0.0.0.0', port[0])) - logger.info('WSDL is at: /?wsdl') + logger.info("Starting interop server at %s:%s." % ("0.0.0.0", port[0])) + logger.info("WSDL is at: /?wsdl") server.serve_forever() except ImportError: print("Error: example server code requires Python >= 2.5") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/spyne/test/interop/server/soap11/soap_http_basic_twisted.py b/spyne/test/interop/server/soap11/soap_http_basic_twisted.py index b9d502b49..734608621 100755 --- a/spyne/test/interop/server/soap11/soap_http_basic_twisted.py +++ b/spyne/test/interop/server/soap11/soap_http_basic_twisted.py @@ -18,25 +18,25 @@ # import logging + logging.basicConfig(level=logging.DEBUG) -logger = logging.getLogger('spyne.wsgi') +logger = logging.getLogger("spyne.wsgi") logger.setLevel(logging.DEBUG) +from spyne.server.twisted import TwistedWebResource from spyne.test.interop.server import get_open_port from spyne.test.interop.server.soap_http_basic import soap11_application -from spyne.server.twisted import TwistedWebResource - -host = '127.0.0.1' +host = "127.0.0.1" port = [0] def main(argv): - from twisted.web.server import Site from twisted.internet import reactor from twisted.python import log + from twisted.web.server import Site - observer = log.PythonLoggingObserver('twisted') + observer = log.PythonLoggingObserver("twisted") log.startLoggingWithObserver(observer.emit, setStdout=False) wr = TwistedWebResource(soap11_application) @@ -45,10 +45,12 @@ def main(argv): if port[0] == 0: port[0] = get_open_port() reactor.listenTCP(port[0], site) - logging.info("listening on: %s:%d" % (host,port[0])) + logging.info("listening on: %s:%d" % (host, port[0])) return reactor.run() -if __name__ == '__main__': + +if __name__ == "__main__": import sys + sys.exit(main(sys.argv)) diff --git a/spyne/test/interop/server/soap11/soap_http_static.py b/spyne/test/interop/server/soap11/soap_http_static.py index 0e8e26ed9..ee7164ba0 100755 --- a/spyne/test/interop/server/soap11/soap_http_static.py +++ b/spyne/test/interop/server/soap11/soap_http_static.py @@ -18,33 +18,32 @@ # import logging + logging.basicConfig(level=logging.DEBUG) -logger = logging.getLogger('spyne.wsgi') +logger = logging.getLogger("spyne.wsgi") logger.setLevel(logging.DEBUG) import os +from spyne.server.twisted import TwistedWebResource from spyne.test.interop.server import get_open_port from spyne.test.interop.server.soap_http_basic import soap11_application -from spyne.server.twisted import TwistedWebResource - -host = '127.0.0.1' +host = "127.0.0.1" port = [0] -url = 'app' +url = "app" def main(argv): + from twisted.internet import reactor from twisted.python import log from twisted.web.server import Site from twisted.web.static import File - from twisted.internet import reactor - from twisted.python import log - observer = log.PythonLoggingObserver('twisted') + observer = log.PythonLoggingObserver("twisted") log.startLoggingWithObserver(observer.emit, setStdout=False) - static_dir = os.path.abspath('.') + static_dir = os.path.abspath(".") logging.info("registering static folder %r on /" % static_dir) root = File(static_dir) @@ -57,11 +56,12 @@ def main(argv): if port[0] == 0: port[0] = get_open_port() reactor.listenTCP(port[0], site) - logging.info("listening on: %s:%d" % (host,port)) + logging.info("listening on: %s:%d" % (host, port)) return reactor.run() -if __name__ == '__main__': +if __name__ == "__main__": import sys + sys.exit(main(sys.argv)) diff --git a/spyne/test/interop/server/soap11/soap_zeromq.py b/spyne/test/interop/server/soap11/soap_zeromq.py index 5cb7f4d49..e61eeef26 100755 --- a/spyne/test/interop/server/soap11/soap_zeromq.py +++ b/spyne/test/interop/server/soap11/soap_zeromq.py @@ -19,13 +19,11 @@ import logging +from spyne.server.zeromq import ZeroMQServer from spyne.test.interop.server import get_open_port from spyne.test.interop.server.soap11.soap_http_basic import soap11_application -from spyne.server.zeromq import ZeroMQServer - - -host = '127.0.0.1' +host = "127.0.0.1" port = [0] @@ -35,18 +33,20 @@ def main(): url = "tcp://%s:%d" % (host, port[0]) logging.basicConfig(level=logging.DEBUG) - logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG) + logging.getLogger("spyne.protocol.xml").setLevel(logging.DEBUG) server = ZeroMQServer(soap11_application, url) logging.info("************************") logging.info("Use Ctrl+\\ to exit if Ctrl-C does not work.") - logging.info("See the 'I can't Ctrl-C my Python/Ruby application. Help!' " - "question in http://www.zeromq.org/area:faq for more info.") + logging.info( + "See the 'I can't Ctrl-C my Python/Ruby application. Help!' " + "question in http://www.zeromq.org/area:faq for more info." + ) logging.info("listening on %r" % url) logging.info("************************") server.serve_forever() -if __name__ == '__main__': - main() \ No newline at end of file +if __name__ == "__main__": + main() diff --git a/spyne/test/interop/server/soap12/httprpc_soap_basic.py b/spyne/test/interop/server/soap12/httprpc_soap_basic.py index c3bc5b190..5cbd8f429 100755 --- a/spyne/test/interop/server/soap12/httprpc_soap_basic.py +++ b/spyne/test/interop/server/soap12/httprpc_soap_basic.py @@ -18,23 +18,28 @@ # import logging + logging.basicConfig(level=logging.DEBUG) -logger = logging.getLogger('spyne.protocol.xml') +logger = logging.getLogger("spyne.protocol.xml") logger.setLevel(logging.DEBUG) from spyne.application import Application -from spyne.test.interop.server._service import services from spyne.protocol.http import HttpRpc from spyne.protocol.soap import Soap12 from spyne.server.wsgi import WsgiApplication +from spyne.test.interop.server._service import services -httprpc_soap_application = Application(services, - 'spyne.test.interop.server.httprpc.soap', in_protocol=HttpRpc(), out_protocol=Soap12()) +httprpc_soap_application = Application( + services, + "spyne.test.interop.server.httprpc.soap", + in_protocol=HttpRpc(), + out_protocol=Soap12(), +) -host = '127.0.0.1' +host = "127.0.0.1" port = 9753 -if __name__ == '__main__': +if __name__ == "__main__": try: from wsgiref.simple_server import make_server from wsgiref.validate import validator @@ -42,8 +47,8 @@ wsgi_application = WsgiApplication(httprpc_soap_application) server = make_server(host, port, validator(wsgi_application)) - logger.info('Starting interop server at %s:%s.' % ('0.0.0.0', 9753)) - logger.info('WSDL is at: /?wsdl') + logger.info("Starting interop server at %s:%s." % ("0.0.0.0", 9753)) + logger.info("WSDL is at: /?wsdl") server.serve_forever() except ImportError: diff --git a/spyne/test/interop/server/soap12/soap_http_basic.py b/spyne/test/interop/server/soap12/soap_http_basic.py index 27fe6f037..a8d9a24aa 100755 --- a/spyne/test/interop/server/soap12/soap_http_basic.py +++ b/spyne/test/interop/server/soap12/soap_http_basic.py @@ -20,22 +20,25 @@ import logging logging.basicConfig(level=logging.DEBUG) -logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG) -logger = logging.getLogger('spyne.test.interop.server.soap_http_basic') +logging.getLogger("spyne.protocol.xml").setLevel(logging.DEBUG) +logger = logging.getLogger("spyne.test.interop.server.soap_http_basic") -from spyne.server.wsgi import WsgiApplication -from spyne.test.interop.server._service import services from spyne.application import Application from spyne.protocol.soap import Soap12 +from spyne.server.wsgi import WsgiApplication +from spyne.test.interop.server._service import services +soap12_application = Application( + services, + "spyne.test.interop.server", + in_protocol=Soap12(validator="lxml", cleanup_namespaces=True), + out_protocol=Soap12(), +) -soap12_application = Application(services, 'spyne.test.interop.server', - in_protocol=Soap12(validator='lxml', cleanup_namespaces=True), - out_protocol=Soap12()) - -host = '127.0.0.1' +host = "127.0.0.1" port = 9754 + def main(): try: from wsgiref.simple_server import make_server @@ -44,12 +47,13 @@ def main(): wsgi_application = WsgiApplication(soap12_application) server = make_server(host, port, validator(wsgi_application)) - logger.info('Starting interop server at %s:%s.' % ('0.0.0.0', 9754)) - logger.info('WSDL is at: /?wsdl') + logger.info("Starting interop server at %s:%s." % ("0.0.0.0", 9754)) + logger.info("WSDL is at: /?wsdl") server.serve_forever() except ImportError: print("Error: example server code requires Python >= 2.5") -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/spyne/test/interop/server/soap12/soap_http_basic_twisted.py b/spyne/test/interop/server/soap12/soap_http_basic_twisted.py index d115e2f97..fbaa34744 100755 --- a/spyne/test/interop/server/soap12/soap_http_basic_twisted.py +++ b/spyne/test/interop/server/soap12/soap_http_basic_twisted.py @@ -18,32 +18,36 @@ # import logging + logging.basicConfig(level=logging.DEBUG) -logger = logging.getLogger('spyne.wsgi') +logger = logging.getLogger("spyne.wsgi") logger.setLevel(logging.DEBUG) -from spyne.test.interop.server.soap12.soap_http_basic import soap12_application from spyne.server.twisted import TwistedWebResource +from spyne.test.interop.server.soap12.soap_http_basic import soap12_application -host = '127.0.0.1' +host = "127.0.0.1" port = 9755 + def main(argv): - from twisted.web.server import Site from twisted.internet import reactor from twisted.python import log + from twisted.web.server import Site - observer = log.PythonLoggingObserver('twisted') + observer = log.PythonLoggingObserver("twisted") log.startLoggingWithObserver(observer.emit, setStdout=False) wr = TwistedWebResource(soap12_application) site = Site(wr) reactor.listenTCP(port, site) - logging.info("listening on: %s:%d" % (host,port)) + logging.info("listening on: %s:%d" % (host, port)) return reactor.run() -if __name__ == '__main__': + +if __name__ == "__main__": import sys + sys.exit(main(sys.argv)) diff --git a/spyne/test/interop/server/soap12/soap_http_static.py b/spyne/test/interop/server/soap12/soap_http_static.py index 6cc742fda..f1b72d753 100755 --- a/spyne/test/interop/server/soap12/soap_http_static.py +++ b/spyne/test/interop/server/soap12/soap_http_static.py @@ -18,30 +18,31 @@ # import logging + logging.basicConfig(level=logging.DEBUG) -logger = logging.getLogger('spyne.wsgi') +logger = logging.getLogger("spyne.wsgi") logger.setLevel(logging.DEBUG) import os -from spyne.test.interop.server.soap12.soap_http_basic import soap12_application from spyne.server.twisted import TwistedWebResource +from spyne.test.interop.server.soap12.soap_http_basic import soap12_application -host = '127.0.0.1' +host = "127.0.0.1" port = 9756 -url = 'app' +url = "app" + def main(argv): + from twisted.internet import reactor from twisted.python import log from twisted.web.server import Site from twisted.web.static import File - from twisted.internet import reactor - from twisted.python import log - observer = log.PythonLoggingObserver('twisted') + observer = log.PythonLoggingObserver("twisted") log.startLoggingWithObserver(observer.emit, setStdout=False) - static_dir = os.path.abspath('.') + static_dir = os.path.abspath(".") logging.info("registering static folder %r on /" % static_dir) root = File(static_dir) @@ -52,11 +53,12 @@ def main(argv): site = Site(root) reactor.listenTCP(port, site) - logging.info("listening on: %s:%d" % (host,port)) + logging.info("listening on: %s:%d" % (host, port)) return reactor.run() -if __name__ == '__main__': +if __name__ == "__main__": import sys + sys.exit(main(sys.argv)) diff --git a/spyne/test/interop/server/soap12/soap_zeromq.py b/spyne/test/interop/server/soap12/soap_zeromq.py index 62c2b730c..b7ceb1d89 100755 --- a/spyne/test/interop/server/soap12/soap_zeromq.py +++ b/spyne/test/interop/server/soap12/soap_zeromq.py @@ -19,28 +19,31 @@ import logging -from spyne.test.interop.server.soap12.soap_http_basic import soap12_application - from spyne.server.zeromq import ZeroMQServer +from spyne.test.interop.server.soap12.soap_http_basic import soap12_application -host = '127.0.0.1' +host = "127.0.0.1" port = 55555 + def main(): - url = "tcp://%s:%d" % (host,port) + url = "tcp://%s:%d" % (host, port) logging.basicConfig(level=logging.DEBUG) - logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG) + logging.getLogger("spyne.protocol.xml").setLevel(logging.DEBUG) server = ZeroMQServer(soap12_application, url) logging.info("************************") logging.info("Use Ctrl+\\ to exit if Ctrl-C does not work.") - logging.info("See the 'I can't Ctrl-C my Python/Ruby application. Help!' " - "question in http://www.zeromq.org/area:faq for more info.") + logging.info( + "See the 'I can't Ctrl-C my Python/Ruby application. Help!' " + "question in http://www.zeromq.org/area:faq for more info." + ) logging.info("listening on %r" % url) logging.info("************************") server.serve_forever() -if __name__ == '__main__': - main() \ No newline at end of file + +if __name__ == "__main__": + main() diff --git a/spyne/test/interop/test_django.py b/spyne/test/interop/test_django.py index b5df8b511..ad92142f6 100755 --- a/spyne/test/interop/test_django.py +++ b/spyne/test/interop/test_django.py @@ -23,99 +23,95 @@ import datetime import re + from django.core.exceptions import ImproperlyConfigured -from django.test import TestCase, TransactionTestCase, Client +from django.test import Client, TestCase, TransactionTestCase +from rpctest.core.models import FieldContainer, RelatedFieldContainer +from rpctest.core.models import UserProfile as DjUserProfile +from rpctest.core.views import Container, app, hello_world_service from spyne.client.django import DjangoTestClient -from spyne.model.fault import Fault from spyne.model.complex import ComplexModelBase -from spyne.util.django import (DjangoComplexModel, DjangoComplexModelMeta, - email_re) -from spyne.util.six import add_metaclass - -from rpctest.core.models import (FieldContainer, RelatedFieldContainer, - UserProfile as DjUserProfile) -from rpctest.core.views import app, hello_world_service, Container +from spyne.model.fault import Fault +from spyne.util.django import DjangoComplexModel, DjangoComplexModelMeta, email_re class SpyneTestCase(TransactionTestCase): def setUp(self): - self.client = DjangoTestClient('/hello_world/', hello_world_service.app) + self.client = DjangoTestClient("/hello_world/", hello_world_service.app) def _test_say_hello(self): - resp = self.client.service.say_hello('Joe', 5) + resp = self.client.service.say_hello("Joe", 5) list_resp = list(resp) self.assertEqual(len(list_resp), 5) - self.assertEqual(list_resp, ['Hello, Joe'] * 5) + self.assertEqual(list_resp, ["Hello, Joe"] * 5) class DjangoViewTestCase(TestCase): def test_say_hello(self): - client = DjangoTestClient('/say_hello/', app) - resp = client.service.say_hello('Joe', 5) + client = DjangoTestClient("/say_hello/", app) + resp = client.service.say_hello("Joe", 5) list_resp = list(resp) self.assertEqual(len(list_resp), 5) - self.assertEqual(list_resp, ['Hello, Joe'] * 5) + self.assertEqual(list_resp, ["Hello, Joe"] * 5) def test_response_encoding(self): - client = DjangoTestClient('/say_hello/', app) - response = client.service.say_hello.get_django_response('Joe', 5) - self.assertTrue('Content-Type' in response) - self.assertTrue(response['Content-Type'].startswith('text/xml')) + client = DjangoTestClient("/say_hello/", app) + response = client.service.say_hello.get_django_response("Joe", 5) + self.assertTrue("Content-Type" in response) + self.assertTrue(response["Content-Type"].startswith("text/xml")) def test_error(self): client = Client() - response = client.post('/say_hello/', {}) - self.assertContains(response, 'faultstring', status_code=500) + response = client.post("/say_hello/", {}) + self.assertContains(response, "faultstring", status_code=500) def test_cached_wsdl(self): """Test if wsdl is cached.""" client = Client() - response = client.get('/say_hello/') - self.assertContains(response, - 'location="http://testserver/say_hello/"') - response = client.get('/say_hello/', HTTP_HOST='newtestserver') - self.assertNotContains(response, - 'location="http://newtestserver/say_hello/"') + response = client.get("/say_hello/") + self.assertContains(response, 'location="http://testserver/say_hello/"') + response = client.get("/say_hello/", HTTP_HOST="newtestserver") + self.assertNotContains(response, 'location="http://newtestserver/say_hello/"') def test_not_cached_wsdl(self): """Test if wsdl is not cached.""" client = Client() - response = client.get('/say_hello_not_cached/') + response = client.get("/say_hello_not_cached/") self.assertContains( - response, 'location="http://testserver/say_hello_not_cached/"') - response = client.get('/say_hello_not_cached/', - HTTP_HOST='newtestserver') + response, 'location="http://testserver/say_hello_not_cached/"' + ) + response = client.get("/say_hello_not_cached/", HTTP_HOST="newtestserver") self.assertContains( - response, 'location="http://newtestserver/say_hello_not_cached/"') + response, 'location="http://newtestserver/say_hello_not_cached/"' + ) class ModelTestCase(TestCase): - """Test mapping between django and spyne models.""" def setUp(self): - self.client = DjangoTestClient('/api/', app) + self.client = DjangoTestClient("/api/", app) def test_exclude(self): """Test if excluded field is not mapped.""" type_info = Container.get_flat_type_info(Container) - self.assertIn('id', type_info) - self.assertNotIn('excluded_field', type_info) + self.assertIn("id", type_info) + self.assertNotIn("excluded_field", type_info) def test_pk_mapping(self): """Test if primary key is mapped as optional but not nillable.""" type_info = Container.get_flat_type_info(Container) - pk_field = type_info['id'] + pk_field = type_info["id"] self.assertEqual(pk_field.Attributes.min_occurs, 0) self.assertFalse(pk_field.Attributes.nullable) def test_regex_pattern_mapping(self): """Test if regex pattern is mapped from django model.""" type_info = Container.get_flat_type_info(Container) - email_field = type_info['email_field'] - self.assertEqual(email_field.__name__, 'Unicode') + email_field = type_info["email_field"] + self.assertEqual(email_field.__name__, "Unicode") self.assertIsNotNone(email_field.Attributes.pattern) self.assertEqual(email_field.Attributes.min_occurs, 1) self.assertFalse(email_field.Attributes.nullable) @@ -123,8 +119,8 @@ def test_regex_pattern_mapping(self): def test_blank_field(self): """Test if blank fields are optional but not null.""" type_info = Container.get_flat_type_info(Container) - blank_field = type_info['blank_field'] - self.assertEqual(blank_field.__name__, 'NormalizedString') + blank_field = type_info["blank_field"] + self.assertEqual(blank_field.__name__, "NormalizedString") self.assertEqual(blank_field.Attributes.min_occurs, 0) self.assertFalse(blank_field.Attributes.nullable) @@ -132,13 +128,13 @@ def test_blank_as_dict(self): """Test if blank field is omitted in as_dict representation.""" container = Container() container_dict = container.as_dict() - self.assertNotIn('blank_field', container_dict) + self.assertNotIn("blank_field", container_dict) def test_length_validators_field(self): """Test if length validators are correctly mapped.""" type_info = Container.get_flat_type_info(Container) - length_validators_field = type_info['length_validators_field'] - self.assertEqual(length_validators_field.__name__, 'NormalizedString') + length_validators_field = type_info["length_validators_field"] + self.assertEqual(length_validators_field.__name__, "NormalizedString") self.assertEqual(length_validators_field.Attributes.min_occurs, 1) self.assertTrue(length_validators_field.Attributes.nullable) self.assertEqual(length_validators_field.Attributes.min_len, 3) @@ -148,75 +144,79 @@ def test_get_container(self): """Test mapping from Django model to spyne model.""" get_container = lambda: self.client.service.get_container(2) self.assertRaises(Fault, get_container) - container = FieldContainer.objects.create(slug_field='container') - FieldContainer.objects.create(slug_field='container2', - foreign_key=container, - one_to_one_field=container, - email_field='email@example.com', - char_field='yo') + container = FieldContainer.objects.create(slug_field="container") + FieldContainer.objects.create( + slug_field="container2", + foreign_key=container, + one_to_one_field=container, + email_field="email@example.com", + char_field="yo", + ) c = get_container() self.assertIsInstance(c, Container) def test_create_container(self): """Test complex input to create Django model.""" - related_container = RelatedFieldContainer(id='related') - new_container = FieldContainer(slug_field='container', - date_field=datetime.date.today(), - datetime_field=datetime.datetime.now(), - email_field='email@example.com', - time_field=datetime.time(), - custom_foreign_key=related_container, - custom_one_to_one_field=related_container) - create_container = (lambda: self.client.service.create_container( - new_container)) + related_container = RelatedFieldContainer(id="related") + new_container = FieldContainer( + slug_field="container", + date_field=datetime.date.today(), + datetime_field=datetime.datetime.now(), + email_field="email@example.com", + time_field=datetime.time(), + custom_foreign_key=related_container, + custom_one_to_one_field=related_container, + ) + create_container = lambda: self.client.service.create_container(new_container) c = create_container() self.assertIsInstance(c, Container) - self.assertEqual(c.custom_one_to_one_field_id, 'related') - self.assertEqual(c.custom_foreign_key_id, 'related') + self.assertEqual(c.custom_one_to_one_field_id, "related") + self.assertEqual(c.custom_foreign_key_id, "related") self.assertRaises(Fault, create_container) def test_create_container_unicode(self): """Test complex unicode input to create Django model.""" new_container = FieldContainer( - char_field=u'спайн', - text_field=u'спайн', - slug_field='spyne', - email_field='email@example.com', + char_field="спайн", + text_field="спайн", + slug_field="spyne", + email_field="email@example.com", date_field=datetime.date.today(), datetime_field=datetime.datetime.now(), - time_field=datetime.time() + time_field=datetime.time(), ) - create_container = (lambda: self.client.service.create_container( - new_container)) + create_container = lambda: self.client.service.create_container(new_container) c = create_container() self.assertIsInstance(c, Container) self.assertRaises(Fault, create_container) def test_optional_relation_fields(self): """Test if optional_relations flag makes fields optional.""" + class UserProfile(DjangoComplexModel): class Attributes(DjangoComplexModel.Attributes): django_model = DjUserProfile - self.assertFalse(UserProfile._type_info['user_id'].Attributes.nullable) + self.assertFalse(UserProfile._type_info["user_id"].Attributes.nullable) class UserProfile(DjangoComplexModel): class Attributes(DjangoComplexModel.Attributes): django_model = DjUserProfile django_optional_relations = True - self.assertEqual( - UserProfile._type_info['user_id'].Attributes.min_occurs, 0) + self.assertEqual(UserProfile._type_info["user_id"].Attributes.min_occurs, 0) def test_abstract_custom_djangomodel(self): """Test if can create custom DjangoComplexModel.""" - @add_metaclass(DjangoComplexModelMeta) - class OrderedDjangoComplexModel(ComplexModelBase): + + class OrderedDjangoComplexModel( + ComplexModelBase, metaclass=DjangoComplexModelMeta + ): __abstract__ = True class Attributes(ComplexModelBase.Attributes): - declare_order = 'declared' + declare_order = "declared" class OrderedFieldContainer(OrderedDjangoComplexModel): class Attributes(OrderedDjangoComplexModel.Attributes): @@ -224,70 +224,69 @@ class Attributes(OrderedDjangoComplexModel.Attributes): field_container = OrderedFieldContainer() type_info_fields = field_container._type_info.keys() - django_field_names = [field.get_attname() for field in - FieldContainer._meta.fields] + django_field_names = [ + field.get_attname() for field in FieldContainer._meta.fields + ] # file field is not mapped - django_field_names.remove('file_field') + django_field_names.remove("file_field") # check if ordering is the same as defined in Django model self.assertEqual(type_info_fields, django_field_names) def test_nonabstract_custom_djangomodel(self): """Test if can't create non abstract custom model.""" with self.assertRaises( - ImproperlyConfigured, msg='Can create non abstract custom model' + ImproperlyConfigured, msg="Can create non abstract custom model" ): - @add_metaclass(DjangoComplexModelMeta) - class CustomNotAbstractDjangoComplexModel(ComplexModelBase): + + class CustomNotAbstractDjangoComplexModel( + ComplexModelBase, metaclass=DjangoComplexModelMeta + ): class Attributes(ComplexModelBase.Attributes): - declare_order = 'declared' + declare_order = "declared" # in XmlSchema ^ and $ are set implicitly -python_email_re = '^' + email_re.pattern + '$' +python_email_re = "^" + email_re.pattern + "$" class EmailRegexTestCase(TestCase): - """Tests for email_re.""" def test_empty(self): """Empty string is invalid email.""" - self.assertIsNone(re.match(python_email_re, '')) + self.assertIsNone(re.match(python_email_re, "")) def test_valid(self): """Test valid email.""" - self.assertIsNotNone( - re.match(python_email_re, 'valid.email@example.com') - ) + self.assertIsNotNone(re.match(python_email_re, "valid.email@example.com")) def test_valid_single_letter_domain(self): """Test valid email.""" - self.assertIsNotNone(re.match(python_email_re, 'valid.email@e.x.com')) + self.assertIsNotNone(re.match(python_email_re, "valid.email@e.x.com")) def test_invalid(self): """Test invalid email.""" - self.assertIsNone(re.match(python_email_re, '@example.com')) + self.assertIsNone(re.match(python_email_re, "@example.com")) def test_invalid_tld(self): """Test if email from Top Level Domain is invalid.""" - self.assertIsNone(re.match(python_email_re, 'babushka@email')) - self.assertIsNone(re.match(python_email_re, 'babushka@domain.email-')) + self.assertIsNone(re.match(python_email_re, "babushka@email")) + self.assertIsNone(re.match(python_email_re, "babushka@domain.email-")) class DjangoServiceTestCase(TestCase): - """Tests for Django specific service.""" def test_handle_does_not_exist(self): """Test if Django service handles `ObjectDoesNotExist` exceptions.""" - client = DjangoTestClient('/api/', app) - with self.assertRaisesRegexp(Fault, 'Client.FieldContainerNotFound'): + client = DjangoTestClient("/api/", app) + with self.assertRaisesRegex(Fault, "Client.FieldContainerNotFound"): client.service.raise_does_not_exist() def test_handle_validation_error(self): """Test if Django service handles `ValidationError` exceptions.""" - client = DjangoTestClient('/api/', app) - with self.assertRaisesRegexp(Fault, 'Client.ValidationError'): + client = DjangoTestClient("/api/", app) + with self.assertRaisesRegex(Fault, "Client.ValidationError"): client.service.raise_validation_error() @@ -295,11 +294,11 @@ class FromUnicodeAssertionTestCase(TestCase): def test_from_unicode_does_not_assert(self): client = Client() - url = '/synchro/1/' + url = "/synchro/1/" msg = b"""TestModel 2015-09-23T13:54:51.796366+00:00 """ - hdrs = {'SOAPAction': b'"sync"', 'Content-Type': 'text/xml; charset=utf-8'} - client.post(url, msg, 'text/xml', True, **hdrs) + hdrs = {"SOAPAction": b'"sync"', "Content-Type": "text/xml; charset=utf-8"} + client.post(url, msg, "text/xml", True, **hdrs) diff --git a/spyne/test/interop/test_httprpc.py b/spyne/test/interop/test_httprpc.py index 4d72bc480..eba37376a 100755 --- a/spyne/test/interop/test_httprpc.py +++ b/spyne/test/interop/test_httprpc.py @@ -17,17 +17,14 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # -import unittest - import time +import unittest +from datetime import datetime import pytz -from datetime import datetime - from spyne.test.interop._test_soap_client_base import server_started -from spyne.util import thread, urlencode, urlopen, Request, HTTPError - +from spyne.util import HTTPError, Request, thread, urlencode, urlopen _server_started = False @@ -38,6 +35,7 @@ def setUp(self): from spyne.test.interop.server.httprpc_pod_basic import main, port if not _server_started: + def run_server(): main() @@ -48,10 +46,10 @@ def run_server(): _server_started = True - self.base_url = 'http://localhost:%d' % port[0] + self.base_url = "http://localhost:%d" % port[0] def test_404(self): - url = '%s/404' % self.base_url + url = "%s/404" % self.base_url try: data = urlopen(url).read() except HTTPError as e: @@ -60,60 +58,64 @@ def test_404(self): def test_413(self): url = self.base_url try: - data = Request(url,("foo"*3*1024*1024)) + data = Request(url, ("foo" * 3 * 1024 * 1024)) except HTTPError as e: assert e.code == 413 def test_500(self): - url = '%s/python_exception' % self.base_url + url = "%s/python_exception" % self.base_url try: data = urlopen(url).read() except HTTPError as e: assert e.code == 500 def test_500_2(self): - url = '%s/soap_exception' % self.base_url + url = "%s/soap_exception" % self.base_url try: data = urlopen(url).read() except HTTPError as e: assert e.code == 500 def test_echo_string(self): - url = '%s/echo_string?s=punk' % self.base_url + url = "%s/echo_string?s=punk" % self.base_url data = urlopen(url).read() - assert data == b'punk' + assert data == b"punk" def test_echo_integer(self): - url = '%s/echo_integer?i=444' % self.base_url + url = "%s/echo_integer?i=444" % self.base_url data = urlopen(url).read() - assert data == b'444' + assert data == b"444" def test_echo_datetime(self): - dt = datetime.now(pytz.utc).isoformat().encode('ascii') - params = urlencode({ - 'dt': dt, - }) + dt = datetime.now(pytz.utc).isoformat().encode("ascii") + params = urlencode( + { + "dt": dt, + } + ) print(params) - url = '%s/echo_datetime?%s' % (self.base_url, str(params)) + url = "%s/echo_datetime?%s" % (self.base_url, str(params)) data = urlopen(url).read() assert dt == data def test_echo_datetime_tz(self): - dt = datetime.now(pytz.utc).isoformat().encode('ascii') - params = urlencode({ - 'dt': dt, - }) + dt = datetime.now(pytz.utc).isoformat().encode("ascii") + params = urlencode( + { + "dt": dt, + } + ) print(params) - url = '%s/echo_datetime?%s' % (self.base_url, str(params)) + url = "%s/echo_datetime?%s" % (self.base_url, str(params)) data = urlopen(url).read() assert dt == data -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/interop/test_msgpackrpc_client_http.py b/spyne/test/interop/test_msgpackrpc_client_http.py index ab39ff63d..c6a08b586 100644 --- a/spyne/test/interop/test_msgpackrpc_client_http.py +++ b/spyne/test/interop/test_msgpackrpc_client_http.py @@ -24,12 +24,14 @@ from spyne.test.interop.server.msgpackrpc_http_basic import msgpackrpc_application, port from spyne.util.etreeconv import root_dict_to_etree + class TestSpyneHttpClient(SpyneClientTestBase, unittest.TestCase): def setUp(self): - SpyneClientTestBase.setUp(self, 'msgpack_rpc_http') + SpyneClientTestBase.setUp(self, "msgpack_rpc_http") - self.client = HttpClient('http://localhost:%d/' % port[0], - msgpackrpc_application) + self.client = HttpClient( + "http://localhost:%d/" % port[0], msgpackrpc_application + ) self.ns = "spyne.test.interop.server" @unittest.skip("MessagePackRpc does not support header") @@ -41,5 +43,5 @@ def test_send_out_header(self): pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/interop/test_pyramid.py b/spyne/test/interop/test_pyramid.py index 2dd3b044c..c2256a733 100755 --- a/spyne/test/interop/test_pyramid.py +++ b/spyne/test/interop/test_pyramid.py @@ -25,21 +25,22 @@ from pyramid.config import Configurator from pyramid.request import Request -from spyne.protocol.soap import Soap11 -from spyne.service import Service -from spyne.decorator import srpc from spyne import Application -from spyne.model import Unicode, Integer, Iterable +from spyne.decorator import srpc +from spyne.model import Integer, Iterable, Unicode +from spyne.protocol.soap import Soap11 from spyne.server.pyramid import PyramidApplication +from spyne.service import Service class SpyneIntegrationTest(unittest.TestCase): """Tests for integration of Spyne into Pyramid view callable""" + class HelloWorldService(Service): @srpc(Unicode, Integer, _returns=Iterable(Unicode)) def say_hello(name, times): for i in range(times): - yield 'Hello, %s' % name + yield "Hello, %s" % name def setUp(self): request = testing.DummyRequest() @@ -51,26 +52,28 @@ def tearDown(self): def testGetWsdl(self): """Simple test for serving of WSDL by spyne through pyramid route""" application = PyramidApplication( - Application([self.HelloWorldService], - tns='spyne.examples.hello', - in_protocol=Soap11(validator='lxml'), - out_protocol=Soap11())) + Application( + [self.HelloWorldService], + tns="spyne.examples.hello", + in_protocol=Soap11(validator="lxml"), + out_protocol=Soap11(), + ) + ) - config = Configurator(settings={'debug_all': True}) - config.add_route('home', '/') - config.add_view(application, route_name='home') + config = Configurator(settings={"debug_all": True}) + config.add_route("home", "/") + config.add_view(application, route_name="home") wsgi_app = validator(config.make_wsgi_app()) env = { - 'SCRIPT_NAME': '', - 'REQUEST_METHOD': 'GET', - 'PATH_INFO': '/', - 'QUERY_STRING': 'wsdl', + "SCRIPT_NAME": "", + "REQUEST_METHOD": "GET", + "PATH_INFO": "/", + "QUERY_STRING": "wsdl", } setup_testing_defaults(env) request = Request(env) resp = request.get_response(wsgi_app) - self.assert_(resp.status.startswith("200 ")) + self.assertTrue(resp.status.startswith("200 ")) node = etree.XML(resp.body) # will throw exception if non well formed - diff --git a/spyne/test/interop/test_soap_client_http.py b/spyne/test/interop/test_soap_client_http.py index b1e88e220..6c2f48bb5 100755 --- a/spyne/test/interop/test_soap_client_http.py +++ b/spyne/test/interop/test_soap_client_http.py @@ -20,20 +20,22 @@ import unittest from spyne.client.http import HttpClient -from spyne.test.interop._test_soap_client_base import SpyneClientTestBase, \ - server_started +from spyne.test.interop._test_soap_client_base import ( + SpyneClientTestBase, + server_started, +) from spyne.test.interop.server.soap11.soap_http_basic import soap11_application + class TestSpyneHttpClient(SpyneClientTestBase, unittest.TestCase): def setUp(self): - SpyneClientTestBase.setUp(self, 'http') + SpyneClientTestBase.setUp(self, "http") - port, = server_started.keys() + (port,) = server_started.keys() - self.client = HttpClient('http://localhost:%d/' % port, - soap11_application) + self.client = HttpClient("http://localhost:%d/" % port, soap11_application) self.ns = "spyne.test.interop.server" -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/interop/test_soap_client_http_twisted.py b/spyne/test/interop/test_soap_client_http_twisted.py index 84022e9c1..3e1783e59 100755 --- a/spyne/test/interop/test_soap_client_http_twisted.py +++ b/spyne/test/interop/test_soap_client_http_twisted.py @@ -18,20 +18,22 @@ # from twisted.trial import unittest -from spyne.test.interop._test_soap_client_base import run_server, server_started from spyne.client.twisted import TwistedHttpClient +from spyne.test.interop._test_soap_client_base import run_server, server_started from spyne.test.interop.server.soap11.soap_http_basic import soap11_application + class TestSpyneHttpClient(unittest.TestCase): def setUp(self): - run_server('http') + run_server("http") - port, = server_started.keys() + (port,) = server_started.keys() self.ns = b"spyne.test.interop.server._service" - self.client = TwistedHttpClient(b'http://localhost:%d/' % port, - soap11_application) + self.client = TwistedHttpClient( + b"http://localhost:%d/" % port, soap11_application + ) def test_echo_boolean(self): def eb(ret): diff --git a/spyne/test/interop/test_soap_client_zeromq.py b/spyne/test/interop/test_soap_client_zeromq.py index 944c2b069..282ab9c58 100755 --- a/spyne/test/interop/test_soap_client_zeromq.py +++ b/spyne/test/interop/test_soap_client_zeromq.py @@ -20,22 +20,22 @@ import unittest from spyne.client.zeromq import ZeroMQClient - -from spyne.test.interop._test_soap_client_base import SpyneClientTestBase, \ - server_started +from spyne.test.interop._test_soap_client_base import ( + SpyneClientTestBase, + server_started, +) from spyne.test.interop.server.soap11.soap_http_basic import soap11_application class TestSpyneZmqClient(SpyneClientTestBase, unittest.TestCase): def setUp(self): - SpyneClientTestBase.setUp(self, 'zeromq') + SpyneClientTestBase.setUp(self, "zeromq") - port, = server_started.keys() + (port,) = server_started.keys() - self.client = ZeroMQClient('tcp://localhost:%d' % port, - soap11_application) + self.client = ZeroMQClient("tcp://localhost:%d" % port, soap11_application) self.ns = "spyne.test.interop.server._service" -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/interop/test_suds.py b/spyne/test/interop/test_suds.py index f77f89ce3..0a0dee9a5 100755 --- a/spyne/test/interop/test_suds.py +++ b/spyne/test/interop/test_suds.py @@ -18,23 +18,23 @@ # import logging -suds_logger = logging.getLogger('suds') + +suds_logger = logging.getLogger("suds") suds_logger.setLevel(logging.INFO) import unittest - +from base64 import b64decode, b64encode from datetime import datetime -from base64 import b64encode, b64decode -from suds.sax.parser import Parser +from suds import WebFault from suds.client import Client from suds.plugin import MessagePlugin -from suds import WebFault - -from spyne.util import six +from suds.sax.parser import Parser -from spyne.test.interop._test_soap_client_base import SpyneClientTestBase, \ - server_started +from spyne.test.interop._test_soap_client_base import ( + SpyneClientTestBase, + server_started, +) class LastReceivedPlugin(MessagePlugin): @@ -45,12 +45,15 @@ def received(self, context): class TestSuds(SpyneClientTestBase, unittest.TestCase): def setUp(self): - SpyneClientTestBase.setUp(self, 'http') + from spyne.test.interop.server.soap11.soap_http_basic import port as _port - port, = server_started.keys() + SpyneClientTestBase.setUp(self, "http") - self.client = Client("http://localhost:%d/?wsdl" % port, cache=None, - plugins=[LastReceivedPlugin()]) + self.client = Client( + "http://localhost:%d/?wsdl" % _port[0], + cache=None, + plugins=[LastReceivedPlugin()], + ) self.ns = "spyne.test.interop.server" def test_echo_datetime(self): @@ -120,8 +123,7 @@ def test_bytearray(self): assert val == b64decode(ret) def test_validation(self): - non_nillable_class = self.client.factory.create( - "{hunk.sunk}NonNillableClass") + non_nillable_class = self.client.factory.create("{hunk.sunk}NonNillableClass") non_nillable_class.i = 6 non_nillable_class.s = None @@ -133,13 +135,13 @@ def test_validation(self): raise Exception("must fail") def test_echo_integer_array(self): - ia = self.client.factory.create('integerArray') + ia = self.client.factory.create("integerArray") ia.integer.extend([1, 2, 3, 4, 5]) self.client.service.echo_integer_array(ia) def test_echo_in_header(self): - in_header = self.client.factory.create('InHeader') - in_header.s = 'a' + in_header = self.client.factory.create("InHeader") + in_header.s = "a" in_header.i = 3 self.client.set_options(soapheaders=in_header) @@ -152,13 +154,14 @@ def test_echo_in_header(self): self.assertEqual(in_header.i, ret.i) def test_echo_in_complex_header(self): - in_header = self.client.factory.create('InHeader') - in_header.s = 'a' + in_header = self.client.factory.create("InHeader") + in_header.s = "a" in_header.i = 3 - in_trace_header = self.client.factory.create('InTraceHeader') - in_trace_header.client = 'suds' - in_trace_header.callDate = datetime(year=2000, month=1, day=1, hour=0, - minute=0, second=0, microsecond=0) + in_trace_header = self.client.factory.create("InTraceHeader") + in_trace_header.client = "suds" + in_trace_header.callDate = datetime( + year=2000, month=1, day=1, hour=0, minute=0, second=0, microsecond=0 + ) self.client.set_options(soapheaders=(in_header, in_trace_header)) ret = self.client.service.echo_in_complex_header() @@ -172,7 +175,7 @@ def test_echo_in_complex_header(self): self.assertEqual(in_trace_header.callDate, ret[1].callDate) def test_send_out_header(self): - out_header = self.client.factory.create('OutHeader') + out_header = self.client.factory.create("OutHeader") out_header.dt = datetime(year=2000, month=1, day=1) out_header.f = 3.141592653 @@ -183,14 +186,16 @@ def test_send_out_header(self): self.assertEqual(ret.f, out_header.f) def test_send_out_complex_header(self): - out_header = self.client.factory.create('OutHeader') + out_header = self.client.factory.create("OutHeader") out_header.dt = datetime(year=2000, month=1, day=1) out_header.f = 3.141592653 - out_trace_header = self.client.factory.create('OutTraceHeader') - out_trace_header.receiptDate = datetime(year=2000, month=1, day=1, - hour=1, minute=1, second=1, microsecond=1) - out_trace_header.returnDate = datetime(year=2000, month=1, day=1, - hour=1, minute=1, second=1, microsecond=100) + out_trace_header = self.client.factory.create("OutTraceHeader") + out_trace_header.receiptDate = datetime( + year=2000, month=1, day=1, hour=1, minute=1, second=1, microsecond=1 + ) + out_trace_header.returnDate = datetime( + year=2000, month=1, day=1, hour=1, minute=1, second=1, microsecond=100 + ) ret = self.client.service.send_out_complex_header() @@ -202,19 +207,36 @@ def test_send_out_complex_header(self): self.assertEqual(ret[1].returnDate, out_trace_header.returnDate) # Control the reply soap header (in an unelegant way but this is the # only way with suds) - soapheaders = self.client.options.plugins[0].reply.getChild("Envelope").getChild("Header") - soap_out_header = soapheaders.getChild('OutHeader') - self.assertEqual('T'.join((out_header.dt.date().isoformat(), - out_header.dt.time().isoformat())), - soap_out_header.getChild('dt').getText()) - self.assertEqual(six.text_type(out_header.f), soap_out_header.getChild('f').getText()) - soap_out_trace_header = soapheaders.getChild('OutTraceHeader') - self.assertEqual('T'.join((out_trace_header.receiptDate.date().isoformat(), - out_trace_header.receiptDate.time().isoformat())), - soap_out_trace_header.getChild('receiptDate').getText()) - self.assertEqual('T'.join((out_trace_header.returnDate.date().isoformat(), - out_trace_header.returnDate.time().isoformat())), - soap_out_trace_header.getChild('returnDate').getText()) + soapheaders = ( + self.client.options.plugins[0].reply.getChild("Envelope").getChild("Header") + ) + soap_out_header = soapheaders.getChild("OutHeader") + self.assertEqual( + "T".join( + (out_header.dt.date().isoformat(), out_header.dt.time().isoformat()) + ), + soap_out_header.getChild("dt").getText(), + ) + self.assertEqual(str(out_header.f), soap_out_header.getChild("f").getText()) + soap_out_trace_header = soapheaders.getChild("OutTraceHeader") + self.assertEqual( + "T".join( + ( + out_trace_header.receiptDate.date().isoformat(), + out_trace_header.receiptDate.time().isoformat(), + ) + ), + soap_out_trace_header.getChild("receiptDate").getText(), + ) + self.assertEqual( + "T".join( + ( + out_trace_header.returnDate.date().isoformat(), + out_trace_header.returnDate.time().isoformat(), + ) + ), + soap_out_trace_header.getChild("returnDate").getText(), + ) def test_echo_string(self): test_string = "OK" @@ -225,24 +247,17 @@ def test_echo_string(self): def __get_xml_test_val(self): return { "test_sub": { - "test_subsub1": { - "test_subsubsub1": ["subsubsub1 value"] - }, + "test_subsub1": {"test_subsubsub1": ["subsubsub1 value"]}, "test_subsub2": ["subsub2 value 1", "subsub2 value 2"], "test_subsub3": [ - { - "test_subsub3sub1": ["subsub3sub1 value"] - }, - { - "test_subsub3sub2": ["subsub3sub2 value"] - }, + {"test_subsub3sub1": ["subsub3sub1 value"]}, + {"test_subsub3sub2": ["subsub3sub2 value"]}, ], "test_subsub4": [], "test_subsub5": ["x"], } } - def test_echo_simple_class(self): val = self.client.factory.create("{spyne.test.interop.server}SimpleClass") @@ -255,10 +270,14 @@ def test_echo_simple_class(self): assert ret.s == val.s def test_echo_class_with_self_reference(self): - val = self.client.factory.create("{spyne.test.interop.server}ClassWithSelfReference") + val = self.client.factory.create( + "{spyne.test.interop.server}ClassWithSelfReference" + ) val.i = 45 - val.sr = self.client.factory.create("{spyne.test.interop.server}ClassWithSelfReference") + val.sr = self.client.factory.create( + "{spyne.test.interop.server}ClassWithSelfReference" + ) val.sr.i = 50 val.sr.sr = None @@ -268,7 +287,7 @@ def test_echo_class_with_self_reference(self): assert ret.sr.i == val.sr.i def test_echo_nested_class(self): - val = self.client.factory.create("{punk.tunk}NestedClass"); + val = self.client.factory.create("{punk.tunk}NestedClass") val.i = 45 val.s = "asd" @@ -276,17 +295,23 @@ def test_echo_nested_class(self): val.ai = self.client.factory.create("integerArray") val.ai.integer.extend([1, 2, 3, 45, 5, 3, 2, 1, 4]) - val.simple = self.client.factory.create("{spyne.test.interop.server}SimpleClassArray") + val.simple = self.client.factory.create( + "{spyne.test.interop.server}SimpleClassArray" + ) - val.simple.SimpleClass.append(self.client.factory.create("{spyne.test.interop.server}SimpleClass")) - val.simple.SimpleClass.append(self.client.factory.create("{spyne.test.interop.server}SimpleClass")) + val.simple.SimpleClass.append( + self.client.factory.create("{spyne.test.interop.server}SimpleClass") + ) + val.simple.SimpleClass.append( + self.client.factory.create("{spyne.test.interop.server}SimpleClass") + ) val.simple.SimpleClass[0].i = 45 val.simple.SimpleClass[0].s = "asd" val.simple.SimpleClass[1].i = 12 val.simple.SimpleClass[1].s = "qwe" - val.other = self.client.factory.create("{spyne.test.interop.server}OtherClass"); + val.other = self.client.factory.create("{spyne.test.interop.server}OtherClass") val.other.dt = datetime.now() val.other.d = 123.456 val.other.b = True @@ -302,8 +327,9 @@ def test_huge_number(self): self.assertEqual(self.client.service.huge_number(), 2 ** int(1e4)) def test_long_string(self): - self.assertEqual(self.client.service.long_string(), - ('0123456789abcdef' * 16384)) + self.assertEqual( + self.client.service.long_string(), ("0123456789abcdef" * 16384) + ) def test_empty(self): self.client.service.test_empty() @@ -315,22 +341,28 @@ def test_echo_extension_class(self): val.s = "asd" val.f = 12.34 - val.simple = self.client.factory.create("{spyne.test.interop.server}SimpleClassArray") + val.simple = self.client.factory.create( + "{spyne.test.interop.server}SimpleClassArray" + ) - val.simple.SimpleClass.append(self.client.factory.create("{spyne.test.interop.server}SimpleClass")) - val.simple.SimpleClass.append(self.client.factory.create("{spyne.test.interop.server}SimpleClass")) + val.simple.SimpleClass.append( + self.client.factory.create("{spyne.test.interop.server}SimpleClass") + ) + val.simple.SimpleClass.append( + self.client.factory.create("{spyne.test.interop.server}SimpleClass") + ) val.simple.SimpleClass[0].i = 45 val.simple.SimpleClass[0].s = "asd" val.simple.SimpleClass[1].i = 12 val.simple.SimpleClass[1].s = "qwe" - val.other = self.client.factory.create("{spyne.test.interop.server}OtherClass"); + val.other = self.client.factory.create("{spyne.test.interop.server}OtherClass") val.other.dt = datetime.now() val.other.d = 123.456 val.other.b = True - val.p = self.client.factory.create("{hunk.sunk}NonNillableClass"); + val.p = self.client.factory.create("{hunk.sunk}NonNillableClass") val.p.dt = datetime(2010, 6, 2) val.p.i = 123 val.p.s = "punk" @@ -348,7 +380,6 @@ def test_echo_extension_class(self): self.assertEqual(ret.other.dt, val.other.dt) self.assertEqual(ret.p.s, val.p.s) - def test_python_exception(self): try: self.client.service.python_exception() @@ -381,18 +412,18 @@ def test_return_invalid_data(self): def test_custom_messages(self): ret = self.client.service.custom_messages("test") - assert ret == 'test' + assert ret == "test" def test_echo_simple_bare(self): ret = self.client.service.echo_simple_bare("test") - assert ret == 'test' + assert ret == "test" # # This test is disabled because suds does not create the right request # object. Opening the first tag below is wrong. # - # # # - # + # # # The right request looks like this: # @@ -416,13 +447,13 @@ def test_echo_simple_bare(self): # # def _test_echo_complex_bare(self): - val = ['abc','def'] - ia = self.client.factory.create('stringArray') + val = ["abc", "def"] + ia = self.client.factory.create("stringArray") ia.string.extend(val) ret = self.client.service.echo_complex_bare(ia) assert ret == val -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/interop/test_zeep.py b/spyne/test/interop/test_zeep.py index fa5486003..a1ccaf325 100755 --- a/spyne/test/interop/test_zeep.py +++ b/spyne/test/interop/test_zeep.py @@ -18,33 +18,30 @@ # import logging - -zeep_logger = logging.getLogger('zeep') +zeep_logger = logging.getLogger("zeep") zeep_logger.setLevel(logging.INFO) import unittest - from datetime import datetime -from base64 import b64encode, b64decode - -from spyne.test.interop._test_soap_client_base import server_started -from spyne.util import six from zeep import Client -from zeep.transports import Transport from zeep.exceptions import Error as ZeepError +from zeep.transports import Transport + +from spyne.test.interop._test_soap_client_base import server_started class TestZeep(unittest.TestCase): def setUp(self): from spyne.test.interop._test_soap_client_base import run_server - run_server('http') + from spyne.test.interop.server.soap11.soap_http_basic import port as _port - port, = server_started.keys() + run_server("http") transport = Transport(cache=False) - self.client = Client("http://localhost:%d/?wsdl" % port, - transport=transport) + self.client = Client( + "http://localhost:%d/?wsdl" % _port[0], transport=transport + ) self.ns = "spyne.test.interop.server" def get_inst(self, what): @@ -102,7 +99,7 @@ def test_echo_boolean(self): self.assertEqual(val, ret) def test_enum(self): - val = self.client.get_type("{%s}DaysOfWeekEnum" % self.ns)('Monday') + val = self.client.get_type("{%s}DaysOfWeekEnum" % self.ns)("Monday") ret = self.client.service.echo_enum(val) @@ -127,18 +124,20 @@ def test_validation(self): raise Exception("must fail") def test_echo_integer_array(self): - ia = self.client.get_type('{%s}integerArray' % self.ns)() + ia = self.client.get_type("{%s}integerArray" % self.ns)() ia.integer.extend([1, 2, 3, 4, 5]) self.client.service.echo_integer_array(ia) def test_echo_in_header(self): - in_header = self.client.get_type('{%s}InHeader' % self.ns)() - in_header.s = 'a' + in_header = self.client.get_type("{%s}InHeader" % self.ns)() + in_header.s = "a" in_header.i = 3 - ret = self.client.service.echo_in_header(_soapheaders={ - 'InHeader': in_header, - }) + ret = self.client.service.echo_in_header( + _soapheaders={ + "InHeader": in_header, + } + ) print(ret) @@ -147,18 +146,18 @@ def test_echo_in_header(self): self.assertEqual(in_header.i, out_header.i) def test_echo_in_complex_header(self): - in_header = self.client.get_type('{%s}InHeader' % self.ns)() - in_header.s = 'a' + in_header = self.client.get_type("{%s}InHeader" % self.ns)() + in_header.s = "a" in_header.i = 3 - in_trace_header = self.client.get_type('{%s}InTraceHeader' % self.ns)() - in_trace_header.client = 'suds' - in_trace_header.callDate = datetime(year=2000, month=1, day=1, hour=0, - minute=0, second=0, microsecond=0) + in_trace_header = self.client.get_type("{%s}InTraceHeader" % self.ns)() + in_trace_header.client = "suds" + in_trace_header.callDate = datetime( + year=2000, month=1, day=1, hour=0, minute=0, second=0, microsecond=0 + ) - ret = self.client.service.echo_in_complex_header(_soapheaders={ - 'InHeader': in_header, - 'InTraceHeader': in_trace_header - }) + ret = self.client.service.echo_in_complex_header( + _soapheaders={"InHeader": in_header, "InTraceHeader": in_trace_header} + ) print(ret) @@ -171,7 +170,7 @@ def test_echo_in_complex_header(self): self.assertEqual(in_trace_header.callDate, out_trace_header.callDate) def test_send_out_header(self): - out_header = self.client.get_type('{%s}OutHeader' % self.ns)() + out_header = self.client.get_type("{%s}OutHeader" % self.ns)() out_header.dt = datetime(year=2000, month=1, day=1) out_header.f = 3.141592653 @@ -181,21 +180,27 @@ def test_send_out_header(self): self.assertEqual(ret.header.OutHeader.f, out_header.f) def test_send_out_complex_header(self): - out_header = self.client.get_type('{%s}OutHeader' % self.ns)() + out_header = self.client.get_type("{%s}OutHeader" % self.ns)() out_header.dt = datetime(year=2000, month=1, day=1) out_header.f = 3.141592653 - out_trace_header = self.client.get_type('{%s}OutTraceHeader' % self.ns)() - out_trace_header.receiptDate = datetime(year=2000, month=1, day=1, - hour=1, minute=1, second=1, microsecond=1) - out_trace_header.returnDate = datetime(year=2000, month=1, day=1, - hour=1, minute=1, second=1, microsecond=100) + out_trace_header = self.client.get_type("{%s}OutTraceHeader" % self.ns)() + out_trace_header.receiptDate = datetime( + year=2000, month=1, day=1, hour=1, minute=1, second=1, microsecond=1 + ) + out_trace_header.returnDate = datetime( + year=2000, month=1, day=1, hour=1, minute=1, second=1, microsecond=100 + ) ret = self.client.service.send_out_complex_header() self.assertEqual(ret.header.OutHeader.dt, out_header.dt) self.assertEqual(ret.header.OutHeader.f, out_header.f) - self.assertEqual(ret.header.OutTraceHeader.receiptDate, out_trace_header.receiptDate) - self.assertEqual(ret.header.OutTraceHeader.returnDate, out_trace_header.returnDate) + self.assertEqual( + ret.header.OutTraceHeader.receiptDate, out_trace_header.receiptDate + ) + self.assertEqual( + ret.header.OutTraceHeader.returnDate, out_trace_header.returnDate + ) def test_echo_string(self): test_string = "OK" @@ -206,24 +211,17 @@ def test_echo_string(self): def __get_xml_test_val(self): return { "test_sub": { - "test_subsub1": { - "test_subsubsub1": ["subsubsub1 value"] - }, + "test_subsub1": {"test_subsubsub1": ["subsubsub1 value"]}, "test_subsub2": ["subsub2 value 1", "subsub2 value 2"], "test_subsub3": [ - { - "test_subsub3sub1": ["subsub3sub1 value"] - }, - { - "test_subsub3sub2": ["subsub3sub2 value"] - }, + {"test_subsub3sub1": ["subsub3sub1 value"]}, + {"test_subsub3sub2": ["subsub3sub2 value"]}, ], "test_subsub4": [], "test_subsub5": ["x"], } } - def test_echo_simple_class(self): val = self.client.get_type("{%s}SimpleClass" % self.ns)() @@ -259,8 +257,12 @@ def test_echo_nested_class(self): val.simple = self.client.get_type("{%s}SimpleClassArray" % self.ns)() - val.simple.SimpleClass.append(self.client.get_type("{%s}SimpleClass" % self.ns)()) - val.simple.SimpleClass.append(self.client.get_type("{%s}SimpleClass" % self.ns)()) + val.simple.SimpleClass.append( + self.client.get_type("{%s}SimpleClass" % self.ns)() + ) + val.simple.SimpleClass.append( + self.client.get_type("{%s}SimpleClass" % self.ns)() + ) val.simple.SimpleClass[0].i = 45 val.simple.SimpleClass[0].s = "asd" @@ -284,8 +286,9 @@ def test_huge_number(self): self.assertEqual(self.client.service.huge_number(), 2 ** int(1e4)) def test_long_string(self): - self.assertEqual(self.client.service.long_string(), - ('0123456789abcdef' * 16384)) + self.assertEqual( + self.client.service.long_string(), ("0123456789abcdef" * 16384) + ) def test_empty(self): self.client.service.test_empty() @@ -299,8 +302,12 @@ def test_echo_extension_class(self): val.simple = self.client.get_type("{%s}SimpleClassArray" % self.ns)() - val.simple.SimpleClass.append(self.client.get_type("{%s}SimpleClass" % self.ns)()) - val.simple.SimpleClass.append(self.client.get_type("{%s}SimpleClass" % self.ns)()) + val.simple.SimpleClass.append( + self.client.get_type("{%s}SimpleClass" % self.ns)() + ) + val.simple.SimpleClass.append( + self.client.get_type("{%s}SimpleClass" % self.ns)() + ) val.simple.SimpleClass[0].i = 45 val.simple.SimpleClass[0].s = "asd" @@ -330,7 +337,6 @@ def test_echo_extension_class(self): self.assertEqual(ret.other.dt, val.other.dt) self.assertEqual(ret.p.s, val.p.s) - def test_python_exception(self): try: self.client.service.python_exception() @@ -363,18 +369,19 @@ def test_return_invalid_data(self): def test_custom_messages(self): ret = self.client.service.custom_messages("test") - assert ret == 'test' + assert ret == "test" def test_echo_simple_bare(self): ret = self.client.service.echo_simple_bare("test") - assert ret == 'test' + assert ret == "test" def test_echo_complex_bare(self): - val = ['abc','def'] + val = ["abc", "def"] ret = self.client.service.echo_complex_bare(val) assert ret == val -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/interop/test_wsi.py b/spyne/test/interop/wsi_analyzer.py similarity index 65% rename from spyne/test/interop/test_wsi.py rename to spyne/test/interop/wsi_analyzer.py index cb0aefeba..b8556fbd4 100755 --- a/spyne/test/interop/test_wsi.py +++ b/spyne/test/interop/wsi_analyzer.py @@ -12,14 +12,15 @@ import os import string + from lxml import etree -CONFIG_FILE = 'config.xml' -SPYNE_TEST_NS = 'spyne.test.interop.server' -SPYNE_TEST_PORT = 'Application' -SPYNE_REPORT_FILE = 'wsi-report-spyne.xml' +CONFIG_FILE = "config.xml" +SPYNE_TEST_NS = "spyne.test.interop.server" +SPYNE_TEST_PORT = "Application" +SPYNE_REPORT_FILE = "wsi-report-spyne.xml" -WSI_ANALYZER_CONFIG_TEMPLATE=string.Template(""" +WSI_ANALYZER_CONFIG_TEMPLATE = string.Template(""" @@ -66,33 +67,33 @@ """) -#This must be changed to point to the physical root of the wsi-installation +# This must be changed to point to the physical root of the wsi-installation WSI_HOME_TAG = "WSI_HOME" WSI_HOME_VAL = "wsi-test-tools" WSI_JAVA_HOME_TAG = "WSI_JAVA_HOME" -WSI_JAVA_HOME_VAL = WSI_HOME_VAL+"/java" +WSI_JAVA_HOME_VAL = WSI_HOME_VAL + "/java" WSI_JAVA_OPTS_TAG = "WSI_JAVA_OPTS" WSI_JAVA_OPTS_VAL = " -Dorg.xml.sax.driver=org.apache.xerces.parsers.SAXParser" -WSI_TEST_ASSERTIONS_FILE = WSI_HOME_VAL+"/common/profiles/SSBP10_BP11_TAD.xml" -WSI_STYLESHEET_FILE = WSI_HOME_VAL+"/common/xsl/report.xsl" +WSI_TEST_ASSERTIONS_FILE = WSI_HOME_VAL + "/common/profiles/SSBP10_BP11_TAD.xml" +WSI_STYLESHEET_FILE = WSI_HOME_VAL + "/common/xsl/report.xsl" WSI_EXECUTION_COMMAND = "java ${WSI_JAVA_OPTS} -Dwsi.home=${WSI_HOME} -cp ${WSI_CP}\ org.wsi.test.analyzer.BasicProfileAnalyzer -config " -WSIClasspath=[ - WSI_JAVA_HOME_VAL+"/lib/wsi-test-tools.jar", - WSI_JAVA_HOME_VAL+"/lib", - WSI_JAVA_HOME_VAL+"/lib/xercesImpl.jar", - WSI_JAVA_HOME_VAL+"/lib/xmlParserAPIs.jar", - WSI_JAVA_HOME_VAL+"/lib/wsdl4j.jar", - WSI_JAVA_HOME_VAL+"/lib/uddi4j.jar", - WSI_JAVA_HOME_VAL+"/lib/axis.jar", - WSI_JAVA_HOME_VAL+"/lib/jaxrpc.jar", - WSI_JAVA_HOME_VAL+"/lib/saaj.jar", - WSI_JAVA_HOME_VAL+"/lib/commons-discovery.jar", - WSI_JAVA_HOME_VAL+"/lib/commons-logging.jar" +WSIClasspath = [ + WSI_JAVA_HOME_VAL + "/lib/wsi-test-tools.jar", + WSI_JAVA_HOME_VAL + "/lib", + WSI_JAVA_HOME_VAL + "/lib/xercesImpl.jar", + WSI_JAVA_HOME_VAL + "/lib/xmlParserAPIs.jar", + WSI_JAVA_HOME_VAL + "/lib/wsdl4j.jar", + WSI_JAVA_HOME_VAL + "/lib/uddi4j.jar", + WSI_JAVA_HOME_VAL + "/lib/axis.jar", + WSI_JAVA_HOME_VAL + "/lib/jaxrpc.jar", + WSI_JAVA_HOME_VAL + "/lib/saaj.jar", + WSI_JAVA_HOME_VAL + "/lib/commons-discovery.jar", + WSI_JAVA_HOME_VAL + "/lib/commons-logging.jar", ] WSI_CLASSPATH_TAG = "WSI_CP" -WSI_CLASSPATH_VAL = ':'.join(WSIClasspath) +WSI_CLASSPATH_VAL = ":".join(WSIClasspath) def configure_env(): @@ -101,24 +102,28 @@ def configure_env(): os.environ[WSI_JAVA_OPTS_TAG] = WSI_JAVA_OPTS_VAL os.environ[WSI_CLASSPATH_TAG] = WSI_CLASSPATH_VAL + def create_config(wsdl_uri, config_file): - print(("Creating config for wsdl at %s ...\n" %wsdl_uri)) + print(("Creating config for wsdl at %s ...\n" % wsdl_uri)) # extract target elements - service = 'ValidatingApplication' - port = 'ValidatingApplication' + service = "ValidatingApplication" + port = "ValidatingApplication" # for wsdl service declarations: # create config(service, port) - vars = {'REPORT_FILE':SPYNE_REPORT_FILE, - 'STYLESHEET_FILE':WSI_STYLESHEET_FILE, - 'ASSERTIONS_FILE':WSI_TEST_ASSERTIONS_FILE, - 'WSDL_NAMESPACE':SPYNE_TEST_NS, - 'PORT_NAME':SPYNE_TEST_PORT, - 'WSDL_URI':wsdl_uri} + vars = { + "REPORT_FILE": SPYNE_REPORT_FILE, + "STYLESHEET_FILE": WSI_STYLESHEET_FILE, + "ASSERTIONS_FILE": WSI_TEST_ASSERTIONS_FILE, + "WSDL_NAMESPACE": SPYNE_TEST_NS, + "PORT_NAME": SPYNE_TEST_PORT, + "WSDL_URI": wsdl_uri, + } config = WSI_ANALYZER_CONFIG_TEMPLATE.substitute(vars) - f = open(config_file, 'w') + f = open(config_file, "w") f.write(config) f.close() + def analyze_wsdl(config_file): # execute ws-i tests # don't execute Analyzer.sh directly since it needs bash @@ -126,15 +131,15 @@ def analyze_wsdl(config_file): # parse result e = etree.parse(SPYNE_REPORT_FILE).getroot() - summary = etree.ETXPath('{%s}summary' %e.nsmap['wsi-report'])(e) + summary = etree.ETXPath("{%s}summary" % e.nsmap["wsi-report"])(e) if summary: # retrieve overall result of the test - result = summary[0].get('result') - if result == 'failed': - outs = etree.ETXPath('{%s}artifact' %(e.nsmap['wsi-report'],))(e) + result = summary[0].get("result") + if result == "failed": + outs = etree.ETXPath("{%s}artifact" % (e.nsmap["wsi-report"],))(e) # filter for the object describing the wsdl test - desc = [o for o in outs if o.get('type') == 'description'][0] + desc = [o for o in outs if o.get("type") == "description"][0] # loop over every group test for entry in desc.iterchildren(): @@ -142,20 +147,25 @@ def analyze_wsdl(config_file): for test in entry.iterchildren(): # simply print the error if there is one # an html can be generated using files in wsi-test-tools/common/xsl - if test.get('result') == 'failed': - fail_msg = etree.ETXPath('{%s}failureMessage' %e.nsmap['wsi-report'])(test) - fail_det = etree.ETXPath('{%s}failureDetail' %e.nsmap['wsi-report'])(test) + if test.get("result") == "failed": + fail_msg = etree.ETXPath( + "{%s}failureMessage" % e.nsmap["wsi-report"] + )(test) + fail_det = etree.ETXPath( + "{%s}failureDetail" % e.nsmap["wsi-report"] + )(test) if fail_msg: - print(('\nFAILURE in test %s\n' %test.get('id'))) + print(("\nFAILURE in test %s\n" % test.get("id"))) print((fail_msg[0].text)) if fail_det: - print('\nFAILURE MSG\n') + print("\nFAILURE MSG\n") print((fail_det[0].text)) + from spyne.test.interop._test_soap_client_base import run_server -if __name__ == '__main__': - run_server('http') +if __name__ == "__main__": + run_server("http") configure_env() - create_config('http://localhost:9754/?wsdl', CONFIG_FILE) + create_config("http://localhost:9754/?wsdl", CONFIG_FILE) analyze_wsdl(CONFIG_FILE) diff --git a/spyne/test/model/__init__.py b/spyne/test/model/__init__.py index 7b899d595..d55474f4e 100644 --- a/spyne/test/model/__init__.py +++ b/spyne/test/model/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # diff --git a/spyne/test/model/test_binary.py b/spyne/test/model/test_binary.py index 06a4841c9..78217101a 100755 --- a/spyne/test/model/test_binary.py +++ b/spyne/test/model/test_binary.py @@ -18,23 +18,23 @@ # import unittest + from lxml import etree -from spyne.protocol.soap import Soap11 -from spyne.model.binary import ByteArray -from spyne.model.binary import _bytes_join import spyne.const.xml +from spyne.model.binary import ByteArray, _bytes_join +from spyne.protocol.soap import Soap11 ns_xsd = spyne.const.xml.NS_XSD -ns_test = 'test_namespace' +ns_test = "test_namespace" class TestBinary(unittest.TestCase): def setUp(self): - self.data = bytes(bytearray(range(0xff))) + self.data = bytes(bytearray(range(0xFF))) def test_data(self): - element = etree.Element('test') + element = etree.Element("test") Soap11().to_parent(None, ByteArray, [self.data], element, ns_test) print(etree.tostring(element, pretty_print=True)) element = element[0] @@ -42,5 +42,6 @@ def test_data(self): a2 = Soap11().from_element(None, ByteArray, element) self.assertEqual(self.data, _bytes_join(a2)) -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/model/test_complex.py b/spyne/test/model/test_complex.py index 0bc56e0d0..70fd77363 100755 --- a/spyne/test/model/test_complex.py +++ b/spyne/test/model/test_complex.py @@ -19,35 +19,45 @@ from __future__ import print_function -import pytz import datetime import unittest - +from base64 import b64encode +from decimal import Decimal as D from pprint import pprint +import pytz from lxml import etree -from base64 import b64encode -from decimal import Decimal as D - -from spyne import Application, rpc, mrpc, Service, ByteArray, Array, \ - ComplexModel, SelfReference, XmlData, XmlAttribute, Unicode, DateTime, \ - Float, Integer, String +from spyne import ( + Application, + Array, + ByteArray, + ComplexModel, + DateTime, + Float, + Integer, + SelfReference, + Service, + String, + Unicode, + XmlAttribute, + XmlData, + mrpc, + rpc, +) from spyne.const import xml from spyne.error import ResourceNotFoundError from spyne.interface import Interface from spyne.interface.wsdl import Wsdl11 -from spyne.model.addtl import TimeSegment, DateSegment, DateTimeSegment +from spyne.model.addtl import DateSegment, DateTimeSegment, TimeSegment from spyne.protocol import ProtocolBase -from spyne.protocol.soap import Soap11 -from spyne.server.null import NullServer - from spyne.protocol.dictdoc import SimpleDictDocument +from spyne.protocol.soap import Soap11 from spyne.protocol.xml import XmlDocument - +from spyne.server.null import NullServer from spyne.test import FakeApp -ns_test = 'test_namespace' +ns_test = "test_namespace" class Address(ComplexModel): @@ -58,6 +68,7 @@ class Address(ComplexModel): lattitude = Float longitude = Float + Address.resolve_namespace(Address, __name__) @@ -68,6 +79,7 @@ class Person(ComplexModel): addresses = Array(Address) titles = Array(String) + Person.resolve_namespace(Person, __name__) @@ -75,24 +87,29 @@ class Employee(Person): employee_id = Integer salary = Float + Employee.resolve_namespace(Employee, __name__) + class Level2(ComplexModel): arg1 = String arg2 = Float + Level2.resolve_namespace(Level2, __name__) class Level3(ComplexModel): arg1 = Integer + Level3.resolve_namespace(Level3, __name__) class Level4(ComplexModel): arg1 = String + Level4.resolve_namespace(Level4, __name__) @@ -101,6 +118,7 @@ class Level1(ComplexModel): level3 = Array(Level3) level4 = Array(Level4) + Level1.resolve_namespace(Level1, __name__) @@ -110,11 +128,11 @@ class C(ComplexModel): i = Integer(voa=True) try: - C().i = 'a' + C().i = "a" except ValueError: pass else: - raise Exception('must fail with ValueError') + raise Exception("must fail with ValueError") def test_validate_on_assignment_success(self): class C(ComplexModel): @@ -130,19 +148,19 @@ class C(ComplexModel): def test_simple_class(self): a = Address() - a.street = '123 happy way' - a.city = 'badtown' + a.street = "123 happy way" + a.city = "badtown" a.zip = 32 a.lattitude = 4.3 a.longitude = 88.0 - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, Address, a, element, ns_test) element = element[0] self.assertEqual(5, len(element.getchildren())) a.since = datetime.datetime(year=2011, month=12, day=31, tzinfo=pytz.utc) - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, Address, a, element, ns_test) element = element[0] self.assertEqual(6, len(element.getchildren())) @@ -156,9 +174,9 @@ def test_simple_class(self): self.assertEqual(a.longitude, r.longitude) self.assertEqual(a.since, r.since) - def test_nested_class(self): # FIXME: this test is incomplete + def test_nested_class(self): # FIXME: this test is incomplete p = Person() - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, Person, p, element, ns_test) element = element[0] @@ -169,7 +187,7 @@ def test_nested_class(self): # FIXME: this test is incomplete def test_class_array(self): peeps = [] - names = ['bob', 'jim', 'peabody', 'mumblesleeves'] + names = ["bob", "jim", "peabody", "mumblesleeves"] dob = datetime.datetime(1979, 1, 1, tzinfo=pytz.utc) for name in names: a = Person() @@ -181,7 +199,7 @@ def test_class_array(self): type = Array(Person) type.resolve_namespace(type, __name__) - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, type, peeps, element, ns_test) element = element[0] @@ -195,7 +213,7 @@ def test_class_array(self): def test_class_nested_array(self): peeps = [] - names = ['bob', 'jim', 'peabody', 'mumblesleves'] + names = ["bob", "jim", "peabody", "mumblesleves"] for name in names: a = Person() @@ -206,14 +224,14 @@ def test_class_nested_array(self): for i in range(0, 25): addr = Address() - addr.street = '555 downtown' - addr.city = 'funkytown' + addr.street = "555 downtown" + addr.city = "funkytown" a.addresses.append(addr) peeps.append(a) arr = Array(Person) arr.resolve_namespace(arr, __name__) - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, arr, peeps, element, ns_test) element = element[0] @@ -223,12 +241,12 @@ def test_class_nested_array(self): for peep in peeps2: self.assertEqual(27, peep.age) self.assertEqual(25, len(peep.addresses)) - self.assertEqual('funkytown', peep.addresses[18].city) + self.assertEqual("funkytown", peep.addresses[18].city) def test_complex_class(self): l = Level1() l.level2 = Level2() - l.level2.arg1 = 'abcd' + l.level2.arg1 = "abcd" l.level2.arg2 = 1.444 l.level3 = [] l.level4 = [] @@ -243,7 +261,7 @@ def test_complex_class(self): a.arg1 = str(i) l.level4.append(a) - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, Level1, l, element, ns_test) element = element[0] l1 = XmlDocument().from_element(None, Level1, element) @@ -255,12 +273,12 @@ def test_complex_class(self): class X(ComplexModel): - __namespace__ = 'tns' - x = Integer(nillable=True, max_occurs='unbounded') + __namespace__ = "tns" + x = Integer(nillable=True, max_occurs="unbounded") class Y(X): - __namespace__ = 'tns' + __namespace__ = "tns" y = Integer @@ -268,8 +286,8 @@ class TestIncompleteInput(unittest.TestCase): def test_x(self): x = X() x.x = [1, 2] - element = etree.Element('test') - XmlDocument().to_parent(None, X, x, element, 'tns') + element = etree.Element("test") + XmlDocument().to_parent(None, X, x, element, "tns") msg = element[0] r = XmlDocument().from_element(None, X, msg) self.assertEqual(r.x, [1, 2]) @@ -277,8 +295,8 @@ def test_x(self): def test_y_fromxml(self): x = X() x.x = [1, 2] - element = etree.Element('test') - XmlDocument().to_parent(None, X, x, element, 'tns') + element = etree.Element("test") + XmlDocument().to_parent(None, X, x, element, "tns") msg = element[0] r = XmlDocument().from_element(None, Y, msg) self.assertEqual(r.x, [1, 2]) @@ -287,16 +305,13 @@ def test_y_toxml(self): y = Y() y.x = [1, 2] y.y = 38 - element = etree.Element('test') - XmlDocument().to_parent(None, Y, y, element, 'tns') + element = etree.Element("test") + XmlDocument().to_parent(None, Y, y, element, "tns") msg = element[0] r = XmlDocument().from_element(None, Y, msg) def test_serialization_instance_on_subclass(self): - test_values = { - 'x': [1, 2], - 'y': 38 - } + test_values = {"x": [1, 2], "y": 38} instance = Y.get_serialization_instance(test_values) self.assertEqual(instance.x, [1, 2]) @@ -317,34 +332,35 @@ class EncExtractXs(ComplexModel): enc_idn = Integer(nillable=False, min_occurs=1, max_occurs=1, max_len=18) hist_idn = Integer(nillable=False, min_occurs=1, max_occurs=1, max_len=18) + class TestComplex(unittest.TestCase): def test_array_type_name(self): - assert Array(String, type_name='punk').__type_name__ == 'punk' + assert Array(String, type_name="punk").__type_name__ == "punk" def test_ctor_kwargs(self): class Category(ComplexModel): id = Integer(min_occurs=1, max_occurs=1, nillable=False) children = Array(Unicode) - v = Category(id=5, children=['a','b']) + v = Category(id=5, children=["a", "b"]) assert v.id == 5 - assert v.children == ['a', 'b'] + assert v.children == ["a", "b"] def test_ctor_args(self): class Category(ComplexModel): id = XmlData(Integer(min_occurs=1, max_occurs=1, nillable=False)) children = Array(Unicode) - v = Category(id=5, children=['a','b']) + v = Category(id=5, children=["a", "b"]) assert v.id == 5 - assert v.children == ['a', 'b'] + assert v.children == ["a", "b"] - v = Category(5, children=['a','b']) + v = Category(5, children=["a", "b"]) assert v.id == 5 - assert v.children == ['a', 'b'] + assert v.children == ["a", "b"] def test_ctor_args_2(self): class Category(ComplexModel): @@ -353,10 +369,10 @@ class Category(ComplexModel): class BetterCategory(Category): sub_category = Unicode - v = BetterCategory(children=['a','b'], sub_category='aaa') + v = BetterCategory(children=["a", "b"], sub_category="aaa") - assert v.children == ['a', 'b'] - assert v.sub_category == 'aaa' + assert v.children == ["a", "b"] + assert v.sub_category == "aaa" def test_flat_type_info(self): class A(ComplexModel): @@ -365,8 +381,8 @@ class A(ComplexModel): class B(A): s = String - assert 's' in B.get_flat_type_info(B) - assert 'i' in B.get_flat_type_info(B) + assert "s" in B.get_flat_type_info(B) + assert "i" in B.get_flat_type_info(B) def test_flat_type_info_attr(self): class A(ComplexModel): @@ -377,12 +393,12 @@ class B(A): s = String sa = XmlAttribute(String) - assert 's' in B.get_flat_type_info(B) - assert 'i' in B.get_flat_type_info(B) - assert 'sa' in B.get_flat_type_info(B) - assert 'ia' in B.get_flat_type_info(B) - assert 'sa' in B.get_flat_type_info(B).attrs - assert 'ia' in B.get_flat_type_info(B).attrs + assert "s" in B.get_flat_type_info(B) + assert "i" in B.get_flat_type_info(B) + assert "sa" in B.get_flat_type_info(B) + assert "ia" in B.get_flat_type_info(B) + assert "sa" in B.get_flat_type_info(B).attrs + assert "ia" in B.get_flat_type_info(B).attrs class TestXmlAttribute(unittest.TestCase): @@ -390,7 +406,7 @@ def assertIsNotNone(self, obj, msg=None): """Stolen from Python 2.7 stdlib.""" if obj is None: - standardMsg = 'unexpectedly None' + standardMsg = "unexpectedly None" self.fail(self._formatMessage(msg, standardMsg)) def test_add_to_schema(self): @@ -400,58 +416,60 @@ class CM(ComplexModel): a = XmlAttribute(String) app = FakeApp() - app.tns = 'tns' + app.tns = "tns" CM.resolve_namespace(CM, app.tns) interface = Interface(app) interface.add_class(CM) wsdl = Wsdl11(interface) - wsdl.build_interface_document('http://a-aaaa.com') + wsdl.build_interface_document("http://a-aaaa.com") pref = CM.get_namespace_prefix(interface) type_def = wsdl.get_schema_info(pref).types[CM.get_type_name()] - attribute_def = type_def.find(xml.XSD('attribute')) + attribute_def = type_def.find(xml.XSD("attribute")) print(etree.tostring(type_def, pretty_print=True)) self.assertIsNotNone(attribute_def) - self.assertEqual(attribute_def.get('name'), 'a') - self.assertEqual(attribute_def.get('type'), CM.a.type.get_type_name_ns(interface)) + self.assertEqual(attribute_def.get("name"), "a") + self.assertEqual( + attribute_def.get("type"), CM.a.type.get_type_name_ns(interface) + ) def test_b64_non_attribute(self): class PacketNonAttribute(ComplexModel): - __namespace__ = 'myns' + __namespace__ = "myns" Data = ByteArray - test_string = b'yo test data' + test_string = b"yo test data" b64string = b64encode(test_string) gg = PacketNonAttribute(Data=[test_string]) - element = etree.Element('test') + element = etree.Element("test") Soap11().to_parent(None, PacketNonAttribute, gg, element, gg.get_namespace()) element = element[0] - #print etree.tostring(element, pretty_print=True) - data = element.find('{%s}Data' % gg.get_namespace()).text - self.assertEqual(data, b64string.decode('ascii')) + # print etree.tostring(element, pretty_print=True) + data = element.find("{%s}Data" % gg.get_namespace()).text + self.assertEqual(data, b64string.decode("ascii")) s1 = Soap11().from_element(None, PacketNonAttribute, element) assert s1.Data[0] == test_string def test_b64_attribute(self): class PacketAttribute(ComplexModel): - __namespace__ = 'myns' - Data = XmlAttribute(ByteArray, use='required') + __namespace__ = "myns" + Data = XmlAttribute(ByteArray, use="required") - test_string = b'yo test data' + test_string = b"yo test data" b64string = b64encode(test_string) gg = PacketAttribute(Data=[test_string]) - element = etree.Element('test') + element = etree.Element("test") Soap11().to_parent(None, PacketAttribute, gg, element, gg.get_namespace()) element = element[0] print(etree.tostring(element, pretty_print=True)) print(element.attrib) - self.assertEqual(element.attrib['Data'], b64string.decode('ascii')) + self.assertEqual(element.attrib["Data"], b64string.decode("ascii")) s1 = Soap11().from_element(None, PacketAttribute, element) assert s1.Data[0] == test_string @@ -459,11 +477,13 @@ class PacketAttribute(ComplexModel): def test_customized_type(self): class SomeClass(ComplexModel): a = XmlAttribute(Integer(ge=4)) + class SomeService(Service): @rpc(SomeClass) def some_call(ctx, some_class): pass - app = Application([SomeService], 'some_tns') + + app = Application([SomeService], "some_tns") class TestSimpleTypeRestrictions(unittest.TestCase): @@ -481,20 +501,20 @@ class CCM(ComplexModel): pprint(sti) assert "i" in sti - assert sti["i"].path == ('i',) + assert sti["i"].path == ("i",) assert sti["i"].type is Integer assert sti["s"].parent is CCM assert "s" in sti - assert sti["s"].path == ('s',) + assert sti["s"].path == ("s",) assert sti["s"].type is String assert sti["s"].parent is CCM assert "c.i" in sti - assert sti["c.i"].path == ('c','i') + assert sti["c.i"].path == ("c", "i") assert sti["c.i"].type is Integer assert sti["c.i"].parent is CM assert "c.s" in sti - assert sti["c.s"].path == ('c','s') + assert sti["c.s"].path == ("c", "s") assert sti["c.s"].type is String assert sti["c.s"].parent is CM @@ -508,12 +528,13 @@ class CCM(ComplexModel): c_i = Float try: - CCM.get_simple_type_info(CCM, hier_delim='_') + CCM.get_simple_type_info(CCM, hier_delim="_") except ValueError: pass else: raise Exception("must fail") + class TestFlatDict(unittest.TestCase): def test_basic(self): class CM(ComplexModel): @@ -525,46 +546,46 @@ class CCM(ComplexModel): i = Integer s = String - val = CCM(i=5, s='a', c=CM(i=7, s='b')) + val = CCM(i=5, s="a", c=CM(i=7, s="b")) d = SimpleDictDocument().object_to_simple_dict(CCM, val) - assert d['i'] == 5 - assert d['s'] == 'a' - assert d['c.i'] == 7 - assert d['c.s'] == 'b' + assert d["i"] == 5 + assert d["s"] == "a" + assert d["c.i"] == 7 + assert d["c.s"] == "b" assert len(d) == 4 def test_sub_name_ser(self): class CM(ComplexModel): - integer = Integer(sub_name='i') - string = String(sub_name='s') + integer = Integer(sub_name="i") + string = String(sub_name="s") - val = CM(integer=7, string='b') + val = CM(integer=7, string="b") d = SimpleDictDocument().object_to_simple_dict(CM, val) pprint(d) - assert d['i'] == 7 - assert d['s'] == 'b' + assert d["i"] == 7 + assert d["s"] == "b" assert len(d) == 2 def test_sub_name_deser(self): class CM(ComplexModel): - integer = Integer(sub_name='i') - string = String(sub_name='s') + integer = Integer(sub_name="i") + string = String(sub_name="s") - d = {'i': [7], 's': ['b']} + d = {"i": [7], "s": ["b"]} val = SimpleDictDocument().simple_dict_to_object(None, d, CM) pprint(d) assert val.integer == 7 - assert val.string == 'b' + assert val.string == "b" def test_array_not_none(self): class CM(ComplexModel): @@ -574,15 +595,15 @@ class CM(ComplexModel): class CCM(ComplexModel): c = Array(CM) - val = CCM(c=[CM(i=i, s='b'*(i+1)) for i in range(2)]) + val = CCM(c=[CM(i=i, s="b" * (i + 1)) for i in range(2)]) d = SimpleDictDocument().object_to_simple_dict(CCM, val) print(d) - assert d['c[0].i'] == 0 - assert d['c[0].s'] == 'b' - assert d['c[1].i'] == 1 - assert d['c[1].s'] == 'bb' + assert d["c[0].i"] == 0 + assert d["c[0].s"] == "b" + assert d["c[1].i"] == 1 + assert d["c[1].s"] == "bb" assert len(d) == 4 @@ -613,8 +634,8 @@ class CCM(ComplexModel): d = SimpleDictDocument().object_to_simple_dict(CCM, val) pprint(d) - assert d['c[0].i'] == [0, 1] - assert d['c[1].i'] == [0, 1, 2] + assert d["c[0].i"] == [0, 1] + assert d["c[1].i"] == [0, 1, 2] assert len(d) == 2 @@ -622,7 +643,7 @@ def test_array_nonwrapped(self): i = Array(Integer, wrapped=False) assert issubclass(i, Integer), i - assert i.Attributes.max_occurs == D('infinity') + assert i.Attributes.max_occurs == D("infinity") class TestSelfRefence(unittest.TestCase): @@ -630,7 +651,7 @@ def test_canonical_case(self): class TestSelfReference(ComplexModel): self_reference = SelfReference - c = TestSelfReference._type_info['self_reference'] + c = TestSelfReference._type_info["self_reference"] c = c.__orig__ or c assert c is TestSelfReference @@ -640,31 +661,35 @@ class SoapService(Service): def view_categories(ctx): pass - Application([SoapService], 'service.soap') + Application([SoapService], "service.soap") def test_self_referential_array_workaround(self): from spyne.util.dictdoc import get_object_as_dict + class Category(ComplexModel): id = Integer(min_occurs=1, max_occurs=1, nillable=False) - Category._type_info['children'] = Array(Category) + Category._type_info["children"] = Array(Category) parent = Category() parent.children = [Category(id=0), Category(id=1)] d = get_object_as_dict(parent, Category) pprint(d) - assert d['children'][0]['id'] == 0 - assert d['children'][1]['id'] == 1 + assert d["children"][0]["id"] == 0 + assert d["children"][1]["id"] == 1 class SoapService(Service): @rpc(_returns=Category) def view_categories(ctx): pass - Application([SoapService], 'service.soap', - in_protocol=ProtocolBase(), - out_protocol=ProtocolBase()) + Application( + [SoapService], + "service.soap", + in_protocol=ProtocolBase(), + out_protocol=ProtocolBase(), + ) def test_canonical_array(self): class Category(ComplexModel): @@ -674,7 +699,7 @@ class Category(ComplexModel): parent = Category() parent.children = [Category(id=1), Category(id=2)] - sr, = Category._type_info['children']._type_info.values() + (sr,) = Category._type_info["children"]._type_info.values() assert issubclass(sr, Category) @@ -687,7 +712,7 @@ def put(self, ctx): methods = SomeComplexModel.Attributes.methods print(methods) - assert 'put' in methods + assert "put" in methods def test_simple_customize(self): class SomeComplexModel(ComplexModel): @@ -695,34 +720,36 @@ class SomeComplexModel(ComplexModel): def put(self, ctx): return "PUNK!!!" - methods = SomeComplexModel.customize(zart='zurt').Attributes.methods + methods = SomeComplexModel.customize(zart="zurt").Attributes.methods print(methods) - assert 'put' in methods + assert "put" in methods def test_simple_with_fields(self): class SomeComplexModel(ComplexModel): a = Integer + @mrpc() def put(self, ctx): return "PUNK!!!" methods = SomeComplexModel.Attributes.methods print(methods) - assert 'put' in methods + assert "put" in methods def test_simple_with_explicit_fields(self): class SomeComplexModel(ComplexModel): - _type_info = [('a', Integer)] + _type_info = [("a", Integer)] + @mrpc() def put(self, ctx): return "PUNK!!!" methods = SomeComplexModel.Attributes.methods print(methods) - assert 'put' in methods + assert "put" in methods def test_native_call(self): - v = 'whatever' + v = "whatever" class SomeComplexModel(ComplexModel): @mrpc() @@ -739,16 +766,16 @@ def member_method(self, ctx): methods = SomeComplexModel.Attributes.methods print(methods) - assert 'member_method' in methods + assert "member_method" in methods class SomeService(Service): @rpc(_returns=SomeComplexModel) def service_method(ctx): return SomeComplexModel() - app = Application([SomeService], 'some_ns') + app = Application([SomeService], "some_ns") - mmm = __name__ + '.SomeComplexModel.member_method' + mmm = __name__ + ".SomeComplexModel.member_method" assert mmm in app.interface.method_id_map def test_interface_mult(self): @@ -759,25 +786,26 @@ def member_method(self, ctx): methods = SomeComplexModel.Attributes.methods print(methods) - assert 'member_method' in methods + assert "member_method" in methods class SomeService(Service): @rpc(_returns=SomeComplexModel) def service_method(ctx): return SomeComplexModel() - @rpc(_returns=SomeComplexModel.customize(type_name='zon')) + @rpc(_returns=SomeComplexModel.customize(type_name="zon")) def service_method_2(ctx): return SomeComplexModel() - app = Application([SomeService], 'some_ns') + app = Application([SomeService], "some_ns") - mmm = __name__ + '.SomeComplexModel.member_method' + mmm = __name__ + ".SomeComplexModel.member_method" assert mmm in app.interface.method_id_map def test_remote_call_error(self): from spyne import mrpc - v = 'deger' + + v = "deger" class SomeComplexModel(ComplexModel): @mrpc(_returns=SelfReference) @@ -789,15 +817,17 @@ class SomeService(Service): def get(ctx): return SomeComplexModel() - null = NullServer(Application([SomeService], tns='some_tns')) + null = NullServer(Application([SomeService], tns="some_tns")) try: null.service.put() except ResourceNotFoundError: pass else: - raise Exception("Must fail with: \"Requested resource " - "'{spyne.test.model.test_complex}SomeComplexModel' not found\"") + raise Exception( + 'Must fail with: "Requested resource ' + "'{spyne.test.model.test_complex}SomeComplexModel' not found\"" + ) def test_signature(self): class SomeComplexModel(ComplexModel): @@ -808,7 +838,10 @@ def member_method(self, ctx): methods = SomeComplexModel.Attributes.methods # we use __orig__ because implicit classes are .customize(validate_freq=False)'d - assert methods['member_method'].in_message._type_info[0].__orig__ is SomeComplexModel + assert ( + methods["member_method"].in_message._type_info[0].__orig__ + is SomeComplexModel + ) def test_self_reference(self): from spyne import mrpc @@ -819,13 +852,14 @@ def method(self, ctx): pass methods = SomeComplexModel.Attributes.methods - assert methods['method'].out_message._type_info[0] is SomeComplexModel + assert methods["method"].out_message._type_info[0] is SomeComplexModel def test_remote_call_success(self): from spyne import mrpc class SomeComplexModel(ComplexModel): i = Integer + @mrpc(_returns=SelfReference) def echo(self, ctx): return self @@ -835,55 +869,63 @@ class SomeService(Service): def get(ctx): return SomeComplexModel() - null = NullServer(Application([SomeService], tns='some_tns')) + null = NullServer(Application([SomeService], tns="some_tns")) v = SomeComplexModel(i=5) - assert null.service['SomeComplexModel.echo'](v) is v + assert null.service["SomeComplexModel.echo"](v) is v def test_order(self): class CM(ComplexModel): - _type_info = [ - ('a', Integer), - ('c', Integer(order=0)) - ] + _type_info = [("a", Integer), ("c", Integer(order=0))] - assert CM._type_info.keys() == ['c', 'a'] + assert CM._type_info.keys() == ["c", "a"] class TestDoc(unittest.TestCase): def test_parent_doc(self): class SomeComplexModel(ComplexModel): """Some docstring""" + some_field = Unicode + class Annotations(ComplexModel.Annotations): __use_parent_doc__ = True + assert "Some docstring" == SomeComplexModel.get_documentation() def test_annotation(self): class SomeComplexModel(ComplexModel): """Some docstring""" + class Annotations(ComplexModel.Annotations): doc = "Some annotations" some_field = Unicode + assert "Some annotations" == SomeComplexModel.get_documentation() def test_no_parent_doc(self): class SomeComplexModel(ComplexModel): """Some docstring""" + class Annotations(ComplexModel.Annotations): __use_parent_doc__ = False some_field = Unicode + assert "" == SomeComplexModel.get_documentation() def test_parent_doc_customize(self): """Check that we keep the documentation when we use customize""" + class SomeComplexModel(ComplexModel): """Some docstring""" + some_field = Unicode + class Annotations(ComplexModel.Annotations): __use_parent_doc__ = True + assert "Some docstring" == SomeComplexModel.customize().get_documentation() @@ -913,7 +955,7 @@ def test_noop(self): class A(ComplexModel): s = Unicode - assert A.get_flat_type_info(A)['s'].Attributes.max_len == D('inf') + assert A.get_flat_type_info(A)["s"].Attributes.max_len == D("inf") def test_cust_simple(self): # simple types are different from complex ones for __extends__ handling. @@ -940,15 +982,9 @@ def test_cust_complex(self): class A(ComplexModel): s = Unicode - A2 = A.customize( - child_attrs=dict( - s=dict( - max_len=10 - ) - ) - ) + A2 = A.customize(child_attrs=dict(s=dict(max_len=10))) - assert A2.get_flat_type_info(A2)['s'].Attributes.max_len == 10 + assert A2.get_flat_type_info(A2)["s"].Attributes.max_len == 10 def test_cust_base_class(self): class A(ComplexModel): @@ -965,7 +1001,7 @@ class B(A): ), ) - assert B2.get_flat_type_info(B2)['s'].Attributes.max_len == 10 + assert B2.get_flat_type_info(B2)["s"].Attributes.max_len == 10 def test_cust_again_base_class(self): class A(ComplexModel): @@ -973,8 +1009,10 @@ class A(ComplexModel): A2 = A.customize() try: + class B(A2): i = Integer + except AssertionError: pass else: @@ -990,9 +1028,9 @@ def test_cust_array(self): def test_cust_array_again(self): A = Array(Unicode) - A = A.customize(foo='bar') + A = A.customize(foo="bar") - assert A.Attributes.foo == 'bar' + assert A.Attributes.foo == "bar" assert A.__orig__ is Array assert A.__extends__ is None assert issubclass(A, Array) @@ -1006,7 +1044,7 @@ def test_cust_array_serializer(self): ), ) - serializer, = A._type_info.values() + (serializer,) = A._type_info.values() assert serializer.Attributes.max_len == 10 assert serializer.__orig__ is Unicode @@ -1014,6 +1052,7 @@ def test_cust_array_serializer(self): def test_cust_sub_array(self): """vanilla class is passed as base""" + class A(ComplexModel): s = Array(Unicode) @@ -1029,7 +1068,7 @@ class A(ComplexModel): A2 = A.customize(**d) - ser, = A2._type_info['s']._type_info.values() + (ser,) = A2._type_info["s"]._type_info.values() assert ser.Attributes.max_len == 10 class B(A): @@ -1038,7 +1077,7 @@ class B(A): B2 = B.customize(**d) b2_fti = B2.get_flat_type_info(B2) - ser, = b2_fti['s']._type_info.values() + (ser,) = b2_fti["s"]._type_info.values() assert ser.Attributes.max_len == 10 @@ -1051,10 +1090,10 @@ class B(A): d = DateTime B2 = B.customize(child_attrs=dict(s=dict(max_len=10))) - assert B2.get_flat_type_info(B2)['s'].Attributes.max_len == 10 + assert B2.get_flat_type_info(B2)["s"].Attributes.max_len == 10 B3 = B2.customize(child_attrs=dict(d=dict(dt_format="%y"))) - assert B3.get_flat_type_info(B3)['s'].Attributes.max_len == 10 + assert B3.get_flat_type_info(B3)["s"].Attributes.max_len == 10 def test_cust_all(self): class A(ComplexModel): @@ -1065,8 +1104,8 @@ class B(A): d = DateTime B2 = B.customize(child_attrs_all=dict(max_len=10)) - assert B2.get_flat_type_info(B2)['s'].Attributes.max_len == 10 - assert B2.get_flat_type_info(B2)['i'].Attributes.max_len == 10 + assert B2.get_flat_type_info(B2)["s"].Attributes.max_len == 10 + assert B2.get_flat_type_info(B2)["i"].Attributes.max_len == 10 def test_cust_noexc(self): class A(ComplexModel): @@ -1077,10 +1116,9 @@ class B(A): d = DateTime B2 = B.customize(child_attrs_noexc=dict(s=dict(max_len=10))) - assert B2.get_flat_type_info(B2)['s'].Attributes.max_len == 10 - assert B2.get_flat_type_info(B2)['s'].Attributes.exc == False - assert B2.get_flat_type_info(B2)['i'].Attributes.exc == True - + assert B2.get_flat_type_info(B2)["s"].Attributes.max_len == 10 + assert B2.get_flat_type_info(B2)["s"].Attributes.exc == False + assert B2.get_flat_type_info(B2)["i"].Attributes.exc == True def test_complex_type_name_clashes(self): class TestComplexModel(ComplexModel): @@ -1103,16 +1141,18 @@ def test2(ctx, obj): pass try: - Application([TestService], 'tns') + Application([TestService], "tns") except Exception as e: print(e) else: - raise Exception("must fail with: " + raise Exception( + "must fail with: " "ValueError: classes " - " " - "and " - " " - "have conflicting names.") + " " + "and " + " " + "have conflicting names." + ) class TestAdditional(unittest.TestCase): @@ -1133,14 +1173,15 @@ def test_date_segment(self): assert data.end_inclusive == False def test_datetime_segment(self): - data = DateTimeSegment.from_string("]2016-03-03T10:20:30.405060," - "2016-05-07T00:01:02.030405]") + data = DateTimeSegment.from_string( + "]2016-03-03T10:20:30.405060," "2016-05-07T00:01:02.030405]" + ) assert data.start_inclusive == False assert data.start == datetime.datetime(2016, 3, 3, 10, 20, 30, 405060) - assert data.end == datetime.datetime(2016, 5, 7, 0, 1, 2, 30405) + assert data.end == datetime.datetime(2016, 5, 7, 0, 1, 2, 30405) assert data.end_inclusive == True -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/model/test_enum.py b/spyne/test/model/test_enum.py index 7d8fd4f5b..3aadbd410 100755 --- a/spyne/test/model/test_enum.py +++ b/spyne/test/model/test_enum.py @@ -18,46 +18,43 @@ # import unittest - from pprint import pprint +from lxml import etree + from spyne.application import Application from spyne.const.xml import XSD +from spyne.decorator import rpc from spyne.interface.wsdl.wsdl11 import Wsdl11 -from spyne.model.complex import Array -from spyne.model.complex import ComplexModel -from spyne.protocol.xml import XmlDocument +from spyne.model.complex import Array, ComplexModel +from spyne.model.enum import Enum from spyne.protocol.soap.soap11 import Soap11 - +from spyne.protocol.xml import XmlDocument from spyne.server.wsgi import WsgiApplication from spyne.service import Service -from spyne.decorator import rpc - -from spyne.model.enum import Enum - -from lxml import etree vals = [ - 'Monday', - 'Tuesday', - 'Wednesday', - 'Thursday', - 'Friday', - 'Saturday', - 'Sunday', + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Sunday", ] DaysOfWeekEnum = Enum( - 'Monday', - 'Tuesday', - 'Wednesday', - 'Thursday', - 'Friday', - 'Saturday', - 'Sunday', - type_name = 'DaysOfWeekEnum', + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Sunday", + type_name="DaysOfWeekEnum", ) + class SomeService(Service): @rpc(DaysOfWeekEnum, _returns=DaysOfWeekEnum) def get_the_day(self, day): @@ -70,33 +67,36 @@ class SomeClass(ComplexModel): class TestEnum(unittest.TestCase): def setUp(self): - self.app = Application([SomeService], 'tns', - in_protocol=Soap11(), out_protocol=Soap11()) - self.app.transport = 'test' + self.app = Application( + [SomeService], "tns", in_protocol=Soap11(), out_protocol=Soap11() + ) + self.app.transport = "test" self.server = WsgiApplication(self.app) self.wsdl = Wsdl11(self.app.interface) - self.wsdl.build_interface_document('prot://url') + self.wsdl.build_interface_document("prot://url") def test_wsdl(self): wsdl = self.wsdl.get_interface_document() elt = etree.fromstring(wsdl) - simple_type = elt.xpath('//xs:simpleType', namespaces=self.app.interface.nsmap)[0] + simple_type = elt.xpath("//xs:simpleType", namespaces=self.app.interface.nsmap)[ + 0 + ] print((etree.tostring(elt, pretty_print=True))) print(simple_type) - self.assertEqual(simple_type.attrib['name'], 'DaysOfWeekEnum') + self.assertEqual(simple_type.attrib["name"], "DaysOfWeekEnum") self.assertEqual(simple_type[0].tag, XSD("restriction")) - self.assertEqual([e.attrib['value'] for e in simple_type[0]], vals) + self.assertEqual([e.attrib["value"] for e in simple_type[0]], vals) def test_serialize(self): mo = DaysOfWeekEnum.Monday print((repr(mo))) - elt = etree.Element('test') - XmlDocument().to_parent(None, DaysOfWeekEnum, mo, elt, 'test_namespace') + elt = etree.Element("test") + XmlDocument().to_parent(None, DaysOfWeekEnum, mo, elt, "test_namespace") elt = elt[0] ret = XmlDocument().from_element(None, DaysOfWeekEnum, elt) @@ -104,31 +104,30 @@ def test_serialize(self): def test_serialize_complex_array(self): days = [ - DaysOfWeekEnum.Monday, - DaysOfWeekEnum.Tuesday, - DaysOfWeekEnum.Wednesday, - DaysOfWeekEnum.Thursday, - DaysOfWeekEnum.Friday, - DaysOfWeekEnum.Saturday, - DaysOfWeekEnum.Sunday, - ] + DaysOfWeekEnum.Monday, + DaysOfWeekEnum.Tuesday, + DaysOfWeekEnum.Wednesday, + DaysOfWeekEnum.Thursday, + DaysOfWeekEnum.Friday, + DaysOfWeekEnum.Saturday, + DaysOfWeekEnum.Sunday, + ] days_xml = [ - ('{tns}DaysOfWeekEnum', 'Monday'), - ('{tns}DaysOfWeekEnum', 'Tuesday'), - ('{tns}DaysOfWeekEnum', 'Wednesday'), - ('{tns}DaysOfWeekEnum', 'Thursday'), - ('{tns}DaysOfWeekEnum', 'Friday'), - ('{tns}DaysOfWeekEnum', 'Saturday'), - ('{tns}DaysOfWeekEnum', 'Sunday'), + ("{tns}DaysOfWeekEnum", "Monday"), + ("{tns}DaysOfWeekEnum", "Tuesday"), + ("{tns}DaysOfWeekEnum", "Wednesday"), + ("{tns}DaysOfWeekEnum", "Thursday"), + ("{tns}DaysOfWeekEnum", "Friday"), + ("{tns}DaysOfWeekEnum", "Saturday"), + ("{tns}DaysOfWeekEnum", "Sunday"), ] DaysOfWeekEnumArray = Array(DaysOfWeekEnum) - DaysOfWeekEnumArray.__namespace__ = 'tns' + DaysOfWeekEnumArray.__namespace__ = "tns" - elt = etree.Element('test') - XmlDocument().to_parent(None, DaysOfWeekEnumArray, days, - elt, 'test_namespace') + elt = etree.Element("test") + XmlDocument().to_parent(None, DaysOfWeekEnumArray, days, elt, "test_namespace") elt = elt[0] ret = XmlDocument().from_element(None, Array(DaysOfWeekEnum), elt) @@ -137,11 +136,16 @@ def test_serialize_complex_array(self): print((etree.tostring(elt, pretty_print=True))) pprint(self.app.interface.nsmap) - assert days_xml == [ (e.tag, e.text) for e in - elt.xpath('//tns:DaysOfWeekEnum', namespaces=self.app.interface.nsmap)] + assert days_xml == [ + (e.tag, e.text) + for e in elt.xpath( + "//tns:DaysOfWeekEnum", namespaces=self.app.interface.nsmap + ) + ] def test_serialize_simple_array(self): - t = SomeClass(days=[ + t = SomeClass( + days=[ DaysOfWeekEnum.Monday, DaysOfWeekEnum.Tuesday, DaysOfWeekEnum.Wednesday, @@ -149,12 +153,13 @@ def test_serialize_simple_array(self): DaysOfWeekEnum.Friday, DaysOfWeekEnum.Saturday, DaysOfWeekEnum.Sunday, - ]) + ] + ) - SomeClass.resolve_namespace(SomeClass, 'tns') + SomeClass.resolve_namespace(SomeClass, "tns") - elt = etree.Element('test') - XmlDocument().to_parent(None, SomeClass, t, elt, 'test_namespace') + elt = etree.Element("test") + XmlDocument().to_parent(None, SomeClass, t, elt, "test_namespace") elt = elt[0] print((etree.tostring(elt, pretty_print=True))) @@ -162,5 +167,6 @@ def test_serialize_simple_array(self): ret = XmlDocument().from_element(None, SomeClass, elt) self.assertEqual(t.days, ret.days) -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/model/test_exception.py b/spyne/test/model/test_exception.py index 1b436a389..33e2d655b 100755 --- a/spyne/test/model/test_exception.py +++ b/spyne/test/model/test_exception.py @@ -18,97 +18,102 @@ # import unittest -from spyne.test import FakeApp + from spyne.interface import Interface from spyne.interface.wsdl import Wsdl11 -from spyne.protocol.xml import XmlDocument from spyne.model.fault import Fault +from spyne.protocol.xml import XmlDocument +from spyne.test import FakeApp + class FaultTests(unittest.TestCase): def test_ctor_defaults(self): fault = Fault() - self.assertEqual(fault.faultcode, 'Server') - self.assertEqual(fault.faultstring, 'Fault') - self.assertEqual(fault.faultactor, '') + self.assertEqual(fault.faultcode, "Server") + self.assertEqual(fault.faultstring, "Fault") + self.assertEqual(fault.faultactor, "") self.assertEqual(fault.detail, None) self.assertEqual(repr(fault), "Fault(Server: 'Fault')") def test_ctor_faultcode_w_senv_prefix(self): - fault = Fault(faultcode='Other') - self.assertEqual(fault.faultcode, 'Other') + fault = Fault(faultcode="Other") + self.assertEqual(fault.faultcode, "Other") self.assertEqual(repr(fault), "Fault(Other: 'Fault')") def test_ctor_explicit_faultstring(self): - fault = Fault(faultstring='Testing') - self.assertEqual(fault.faultstring, 'Testing') + fault = Fault(faultstring="Testing") + self.assertEqual(fault.faultstring, "Testing") self.assertEqual(repr(fault), "Fault(Server: 'Testing')") def test_to_parent_wo_detail(self): from lxml.etree import Element + import spyne.const.xml + ns_soap_env = spyne.const.xml.NS_SOAP11_ENV soap_env = spyne.const.xml.PREFMAP[spyne.const.xml.NS_SOAP11_ENV] - element = Element('testing') + element = Element("testing") fault = Fault() cls = Fault - XmlDocument().to_parent(None, cls, fault, element, 'urn:ignored') + XmlDocument().to_parent(None, cls, fault, element, "urn:ignored") (child,) = element.getchildren() - self.assertEqual(child.tag, '{%s}Fault' % ns_soap_env) - self.assertEqual(child.find('faultcode').text, '%s:Server' % soap_env) - self.assertEqual(child.find('faultstring').text, 'Fault') - self.assertEqual(child.find('faultactor').text, '') - self.assertFalse(child.findall('detail')) + self.assertEqual(child.tag, "{%s}Fault" % ns_soap_env) + self.assertEqual(child.find("faultcode").text, "%s:Server" % soap_env) + self.assertEqual(child.find("faultstring").text, "Fault") + self.assertEqual(child.find("faultactor").text, "") + self.assertFalse(child.findall("detail")) def test_to_parent_w_detail(self): from lxml.etree import Element - element = Element('testing') - detail = Element('something') + + element = Element("testing") + detail = Element("something") fault = Fault(detail=detail) cls = Fault - XmlDocument().to_parent(None, cls, fault, element, 'urn:ignored') + XmlDocument().to_parent(None, cls, fault, element, "urn:ignored") (child,) = element.getchildren() - self.assertTrue(child.find('detail').find('something') is detail) + self.assertTrue(child.find("detail").find("something") is detail) def test_from_xml_wo_detail(self): - from lxml.etree import Element - from lxml.etree import SubElement - from spyne.const.xml import PREFMAP, SOAP11_ENV, NS_SOAP11_ENV + from lxml.etree import Element, SubElement + + from spyne.const.xml import NS_SOAP11_ENV, PREFMAP, SOAP11_ENV soap_env = PREFMAP[NS_SOAP11_ENV] - element = Element(SOAP11_ENV('Fault')) + element = Element(SOAP11_ENV("Fault")) - fcode = SubElement(element, 'faultcode') - fcode.text = '%s:other' % soap_env - fstr = SubElement(element, 'faultstring') - fstr.text = 'Testing' - actor = SubElement(element, 'faultactor') - actor.text = 'phreddy' + fcode = SubElement(element, "faultcode") + fcode.text = "%s:other" % soap_env + fstr = SubElement(element, "faultstring") + fstr.text = "Testing" + actor = SubElement(element, "faultactor") + actor.text = "phreddy" fault = XmlDocument().from_element(None, Fault, element) - self.assertEqual(fault.faultcode, '%s:other' % soap_env) - self.assertEqual(fault.faultstring, 'Testing') - self.assertEqual(fault.faultactor, 'phreddy') + self.assertEqual(fault.faultcode, "%s:other" % soap_env) + self.assertEqual(fault.faultstring, "Testing") + self.assertEqual(fault.faultactor, "phreddy") self.assertEqual(fault.detail, None) def test_from_xml_w_detail(self): - from lxml.etree import Element - from lxml.etree import SubElement + from lxml.etree import Element, SubElement + from spyne.const.xml import SOAP11_ENV - element = Element(SOAP11_ENV('Fault')) - fcode = SubElement(element, 'faultcode') - fcode.text = 'soap11env:other' - fstr = SubElement(element, 'faultstring') - fstr.text = 'Testing' - actor = SubElement(element, 'faultactor') - actor.text = 'phreddy' - detail = SubElement(element, 'detail') + element = Element(SOAP11_ENV("Fault")) + fcode = SubElement(element, "faultcode") + fcode.text = "soap11env:other" + fstr = SubElement(element, "faultstring") + fstr.text = "Testing" + actor = SubElement(element, "faultactor") + actor.text = "phreddy" + detail = SubElement(element, "detail") fault = XmlDocument().from_element(None, Fault, element) @@ -118,55 +123,57 @@ def test_add_to_schema_no_extends(self): from spyne.const.xml import XSD class cls(Fault): - __namespace__='ns' + __namespace__ = "ns" + @classmethod def get_type_name_ns(self, app): - return 'testing:My' + return "testing:My" interface = Interface(FakeApp()) interface.add_class(cls) pref = cls.get_namespace_prefix(interface) wsdl = Wsdl11(interface) - wsdl.build_interface_document('prot://addr') + wsdl.build_interface_document("prot://addr") schema = wsdl.get_schema_info(pref) self.assertEqual(len(schema.types), 1) - c_cls = interface.classes['{ns}cls'] + c_cls = interface.classes["{ns}cls"] c_elt = schema.types[0] self.assertTrue(c_cls is cls) - self.assertEqual(c_elt.tag, XSD('complexType')) - self.assertEqual(c_elt.get('name'), 'cls') + self.assertEqual(c_elt.tag, XSD("complexType")) + self.assertEqual(c_elt.get("name"), "cls") self.assertEqual(len(schema.elements), 1) e_elt = schema.elements.values()[0] - self.assertEqual(e_elt.tag, XSD('element')) - self.assertEqual(e_elt.get('name'), 'cls') - self.assertEqual(e_elt.get('type'), 'testing:My') + self.assertEqual(e_elt.tag, XSD("element")) + self.assertEqual(e_elt.get("name"), "cls") + self.assertEqual(e_elt.get("type"), "testing:My") self.assertEqual(len(e_elt), 0) def test_add_to_schema_w_extends(self): from spyne.const.xml import XSD class base(Fault): - __namespace__ = 'ns' + __namespace__ = "ns" @classmethod def get_type_name_ns(self, app): - return 'testing:Base' + return "testing:Base" class cls(Fault): - __namespace__ = 'ns' + __namespace__ = "ns" + @classmethod def get_type_name_ns(self, app): - return 'testing:My' + return "testing:My" interface = Interface(FakeApp()) interface.add_class(cls) pref = cls.get_namespace_prefix(interface) wsdl = Wsdl11(interface) - wsdl.build_interface_document('prot://addr') + wsdl.build_interface_document("prot://addr") schema = wsdl.get_schema_info(pref) self.assertEqual(len(schema.types), 1) @@ -176,13 +183,15 @@ def get_type_name_ns(self, app): c_elt = next(iter(schema.types.values())) self.assertTrue(c_cls is cls) - self.assertEqual(c_elt.tag, XSD('complexType')) - self.assertEqual(c_elt.get('name'), 'cls') + self.assertEqual(c_elt.tag, XSD("complexType")) + self.assertEqual(c_elt.get("name"), "cls") from lxml import etree + print(etree.tostring(c_elt, pretty_print=True)) self.assertEqual(len(c_elt), 0) + class DummySchemaEntries: def __init__(self, app): self.app = app @@ -196,5 +205,5 @@ def add_element(self, cls, elt): self._elements.append((cls, elt)) -if __name__ == '__main__': #pragma NO COVERAGE +if __name__ == "__main__": # pragma NO COVERAGE unittest.main() diff --git a/spyne/test/model/test_primitive.py b/spyne/test/model/test_primitive.py index a42a8171a..8e108514e 100755 --- a/spyne/test/model/test_primitive.py +++ b/spyne/test/model/test_primitive.py @@ -20,31 +20,46 @@ from __future__ import print_function -import re -import uuid import datetime +import re import unittest +import uuid import warnings - -import pytz -import spyne - from datetime import timedelta +import pytz from lxml import etree -from spyne.model.primitive._base import re_match_with_span as rmws -from spyne.util import six +import spyne +from spyne import ( + AnyDict, + Array, + Boolean, + ComplexModel, + Date, + DateTime, + Decimal, + Duration, + Float, + Integer, + Integer16, + MediaType, + MimeType, + MimeTypeStrict, + ModelBase, + Null, + NumberLimitsWarning, + String, + Time, + Unicode, + Uuid, +) from spyne.const import xml as ns - -from spyne import Null, AnyDict, Uuid, Array, ComplexModel, Date, Time, \ - Boolean, DateTime, Duration, Float, Integer, NumberLimitsWarning, Unicode, \ - String, Decimal, Integer16, ModelBase, MimeType, MimeTypeStrict, MediaType - +from spyne.model.primitive._base import re_match_with_span as rmws from spyne.protocol import ProtocolBase from spyne.protocol.xml import XmlDocument -ns_test = 'test_namespace' +ns_test = "test_namespace" class TestCast(unittest.TestCase): @@ -55,52 +70,56 @@ class TestPrimitive(unittest.TestCase): def test_mime_type_family(self): mime_attr = MimeType.Attributes mime_strict_attr = MimeTypeStrict.Attributes - assert rmws(mime_attr, u'application/foo') - assert not rmws(mime_attr, u'application/ foo') - assert not rmws(mime_attr, u'application/') - assert rmws(mime_attr, u'foo/bar') - assert not rmws(mime_attr, u'foo/bar ') - assert not rmws(mime_strict_attr, u'foo/bar') + assert rmws(mime_attr, "application/foo") + assert not rmws(mime_attr, "application/ foo") + assert not rmws(mime_attr, "application/") + assert rmws(mime_attr, "foo/bar") + assert not rmws(mime_attr, "foo/bar ") + assert not rmws(mime_strict_attr, "foo/bar") media_attr = MediaType.Attributes media_strict_attr = MediaType.Attributes print(media_attr.pattern) - assert rmws(media_attr, u'text/plain') - assert not rmws(media_attr, u' text/plain') - assert rmws(media_attr, u'text/plain;') - assert rmws(media_attr, u'text/plain;charset=utf-8') - assert rmws(media_attr, u'text/plain; charset="utf-8"') - assert rmws(media_attr, u'text/plain; charset=utf-8') - assert rmws(media_attr, u'text/plain; charset=utf-8 ') - assert rmws(media_attr, u'text/plain; charset=utf-8;') - assert rmws(media_attr, u'text/plain; charset=utf-8; ') - assert not rmws(media_attr, u'text/plain; charset=utf-8; foo') - assert not rmws(media_attr, u'text/plain; charset=utf-8; foo=') - assert rmws(media_attr, u'text/plain; charset=utf-8; foo=""') - assert rmws(media_attr, u'text/plain; charset=utf-8; foo="";') - assert rmws(media_attr, u'text/plain; charset=utf-8; foo=""; ') - assert rmws(media_attr, u'text/plain; charset=utf-8; foo=""; ') - assert not rmws(media_attr, u'text/plain;; charset=utf-8; foo=""') - assert not rmws(media_attr, u'text/plain;;; charset=utf-8; foo=""') - assert not rmws(media_attr, u'text/plain; charset=utf-8;; foo=""') - assert not rmws(media_attr, u'text/plain; charset=utf-8;;; foo=""') - assert not rmws(media_attr, u'text/plain; charset=utf-8;;; foo="";') - assert not rmws(media_attr, u'text/plain; charset=utf-8;;; foo=""; ; ') - - assert not rmws(media_strict_attr, u' applicaton/json;') + assert rmws(media_attr, "text/plain") + assert not rmws(media_attr, " text/plain") + assert rmws(media_attr, "text/plain;") + assert rmws(media_attr, "text/plain;charset=utf-8") + assert rmws(media_attr, 'text/plain; charset="utf-8"') + assert rmws(media_attr, "text/plain; charset=utf-8") + assert rmws(media_attr, "text/plain; charset=utf-8 ") + assert rmws(media_attr, "text/plain; charset=utf-8;") + assert rmws(media_attr, "text/plain; charset=utf-8; ") + assert not rmws(media_attr, "text/plain; charset=utf-8; foo") + assert not rmws(media_attr, "text/plain; charset=utf-8; foo=") + assert rmws(media_attr, 'text/plain; charset=utf-8; foo=""') + assert rmws(media_attr, 'text/plain; charset=utf-8; foo="";') + assert rmws(media_attr, 'text/plain; charset=utf-8; foo=""; ') + assert rmws(media_attr, 'text/plain; charset=utf-8; foo=""; ') + assert not rmws(media_attr, 'text/plain;; charset=utf-8; foo=""') + assert not rmws(media_attr, 'text/plain;;; charset=utf-8; foo=""') + assert not rmws(media_attr, 'text/plain; charset=utf-8;; foo=""') + assert not rmws(media_attr, 'text/plain; charset=utf-8;;; foo=""') + assert not rmws(media_attr, 'text/plain; charset=utf-8;;; foo="";') + assert not rmws(media_attr, 'text/plain; charset=utf-8;;; foo=""; ; ') + + assert not rmws(media_strict_attr, " applicaton/json;") assert MediaType - def test_getitem_cust(self): assert Unicode[dict(max_len=2)].Attributes.max_len def test_ancestors(self): - class A(ComplexModel): i = Integer - class B(A): i2 = Integer - class C(B): i3 = Integer + class A(ComplexModel): + i = Integer + + class B(A): + i2 = Integer + + class C(B): + i3 = Integer assert C.ancestors() == [B, A] assert B.ancestors() == [A] @@ -174,28 +193,29 @@ def test_decimal(self): def test_decimal_format(self): f = 123456 - str_format = '${0}' - element = etree.Element('test') - XmlDocument().to_parent(None, Decimal(str_format=str_format), f, - element, ns_test) + str_format = "${0}" + element = etree.Element("test") + XmlDocument().to_parent( + None, Decimal(str_format=str_format), f, element, ns_test + ) element = element[0] - self.assertEqual(element.text, '$123456') + self.assertEqual(element.text, "$123456") def test_string(self): s = String() - element = etree.Element('test') - XmlDocument().to_parent(None, String, 'value', element, ns_test) + element = etree.Element("test") + XmlDocument().to_parent(None, String, "value", element, ns_test) element = element[0] - self.assertEqual(element.text, 'value') + self.assertEqual(element.text, "value") value = XmlDocument().from_element(None, String, element) - self.assertEqual(value, 'value') + self.assertEqual(value, "value") def test_datetime(self): n = datetime.datetime.now(pytz.utc) - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, DateTime, n, element, ns_test) element = element[0] @@ -207,53 +227,43 @@ def test_datetime_format(self): n = datetime.datetime.now().replace(microsecond=0) format = "%Y %m %d %H %M %S" - element = etree.Element('test') - XmlDocument().to_parent(None, DateTime(dt_format=format), n, element, - ns_test) + element = etree.Element("test") + XmlDocument().to_parent(None, DateTime(dt_format=format), n, element, ns_test) element = element[0] assert element.text == datetime.datetime.strftime(n, format) - dt = XmlDocument().from_element(None, DateTime(dt_format=format), - element) + dt = XmlDocument().from_element(None, DateTime(dt_format=format), element) assert n == dt def test_datetime_unicode_format(self): n = datetime.datetime.now().replace(microsecond=0) - format = u"%Y %m %d\u00a0%H %M %S" + format = "%Y %m %d\u00a0%H %M %S" - element = etree.Element('test') - XmlDocument().to_parent(None, DateTime(dt_format=format), n, - element, ns_test) + element = etree.Element("test") + XmlDocument().to_parent(None, DateTime(dt_format=format), n, element, ns_test) element = element[0] - if six.PY2: - assert element.text == n.strftime(format.encode('utf8')) \ - .decode('utf8') - else: - assert element.text == n.strftime(format) + assert element.text == n.strftime(format) - dt = XmlDocument().from_element(None, DateTime(dt_format=format), - element) + dt = XmlDocument().from_element(None, DateTime(dt_format=format), element) assert n == dt def test_date_format(self): t = datetime.date.today() format = "%Y-%m-%d" - element = etree.Element('test') - XmlDocument().to_parent(None, - Date(date_format=format), t, element, ns_test) + element = etree.Element("test") + XmlDocument().to_parent(None, Date(date_format=format), t, element, ns_test) assert element[0].text == datetime.date.strftime(t, format) - dt = XmlDocument().from_element(None, - Date(date_format=format), element[0]) + dt = XmlDocument().from_element(None, Date(date_format=format), element[0]) assert t == dt def test_datetime_timezone(self): import pytz - n = datetime.datetime.now(pytz.timezone('EST')) - element = etree.Element('test') + n = datetime.datetime.now(pytz.timezone("EST")) + element = etree.Element("test") cls = DateTime(as_timezone=pytz.utc, timezone=False) XmlDocument().to_parent(None, cls, n, element, ns_test) element = element[0] @@ -266,11 +276,11 @@ def test_datetime_timezone(self): self.assertEqual(c, dt) def test_date_timezone(self): - elt = etree.Element('wot') - elt.text = '2013-08-09+02:00' + elt = etree.Element("wot") + elt.text = "2013-08-09+02:00" dt = XmlDocument().from_element(None, Date, elt) print("ok without validation.") - dt = XmlDocument(validator='soft').from_element(None, Date, elt) + dt = XmlDocument(validator="soft").from_element(None, Date, elt) print(dt) def test_time(self): @@ -320,8 +330,8 @@ def test_date(self): self.assertEqual(n, dt) def test_utcdatetime(self): - datestring = '2007-05-15T13:40:44Z' - e = etree.Element('test') + datestring = "2007-05-15T13:40:44Z" + e = etree.Element("test") e.text = datestring dt = XmlDocument().from_element(None, DateTime, e) @@ -330,8 +340,8 @@ def test_utcdatetime(self): self.assertEqual(dt.month, 5) self.assertEqual(dt.day, 15) - datestring = '2007-05-15T13:40:44.003Z' - e = etree.Element('test') + datestring = "2007-05-15T13:40:44.003Z" + e = etree.Element("test") e.text = datestring dt = XmlDocument().from_element(None, DateTime, e) @@ -341,74 +351,79 @@ def test_utcdatetime(self): self.assertEqual(dt.day, 15) def test_date_exclusive_boundaries(self): - test_model = Date.customize(gt=datetime.date(2016, 1, 1), - lt=datetime.date(2016, 2, 1)) + test_model = Date.customize( + gt=datetime.date(2016, 1, 1), lt=datetime.date(2016, 2, 1) + ) self.assertFalse( - test_model.validate_native(test_model, datetime.date(2016, 1, 1))) + test_model.validate_native(test_model, datetime.date(2016, 1, 1)) + ) self.assertFalse( - test_model.validate_native(test_model, datetime.date(2016, 2, 1))) + test_model.validate_native(test_model, datetime.date(2016, 2, 1)) + ) def test_date_inclusive_boundaries(self): - test_model = Date.customize(ge=datetime.date(2016, 1, 1), - le=datetime.date(2016, 2, 1)) + test_model = Date.customize( + ge=datetime.date(2016, 1, 1), le=datetime.date(2016, 2, 1) + ) self.assertTrue( - test_model.validate_native(test_model, datetime.date(2016, 1, 1))) + test_model.validate_native(test_model, datetime.date(2016, 1, 1)) + ) self.assertTrue( - test_model.validate_native(test_model, datetime.date(2016, 2, 1))) + test_model.validate_native(test_model, datetime.date(2016, 2, 1)) + ) def test_datetime_exclusive_boundaries(self): test_model = DateTime.customize( - gt=datetime.datetime(2016, 1, 1, 12, 00) - .replace(tzinfo=spyne.LOCAL_TZ), - lt=datetime.datetime(2016, 2, 1, 12, 00) - .replace(tzinfo=spyne.LOCAL_TZ), + gt=datetime.datetime(2016, 1, 1, 12, 00).replace(tzinfo=spyne.LOCAL_TZ), + lt=datetime.datetime(2016, 2, 1, 12, 00).replace(tzinfo=spyne.LOCAL_TZ), + ) + self.assertFalse( + test_model.validate_native( + test_model, datetime.datetime(2016, 1, 1, 12, 00) + ) + ) + self.assertFalse( + test_model.validate_native( + test_model, datetime.datetime(2016, 2, 1, 12, 00) + ) ) - self.assertFalse(test_model.validate_native(test_model, - datetime.datetime(2016, 1, 1, 12, 00))) - self.assertFalse(test_model.validate_native(test_model, - datetime.datetime(2016, 2, 1, 12, 00))) def test_datetime_inclusive_boundaries(self): test_model = DateTime.customize( - ge=datetime.datetime(2016, 1, 1, 12, 00) - .replace(tzinfo=spyne.LOCAL_TZ), - le=datetime.datetime(2016, 2, 1, 12, 00) - .replace(tzinfo=spyne.LOCAL_TZ) + ge=datetime.datetime(2016, 1, 1, 12, 00).replace(tzinfo=spyne.LOCAL_TZ), + le=datetime.datetime(2016, 2, 1, 12, 00).replace(tzinfo=spyne.LOCAL_TZ), ) - self.assertTrue(test_model.validate_native(test_model, - datetime.datetime(2016, 1, 1, 12, 00))) - self.assertTrue(test_model.validate_native(test_model, - datetime.datetime(2016, 2, 1, 12, 00))) + self.assertTrue( + test_model.validate_native( + test_model, datetime.datetime(2016, 1, 1, 12, 00) + ) + ) + self.assertTrue( + test_model.validate_native( + test_model, datetime.datetime(2016, 2, 1, 12, 00) + ) + ) def test_time_exclusive_boundaries(self): - test_model = Time.customize(gt=datetime.time(12, 00), - lt=datetime.time(13, 00)) + test_model = Time.customize(gt=datetime.time(12, 00), lt=datetime.time(13, 00)) - self.assertFalse( - test_model.validate_native(test_model, datetime.time(12, 00))) - self.assertFalse( - test_model.validate_native(test_model, datetime.time(13, 00))) + self.assertFalse(test_model.validate_native(test_model, datetime.time(12, 00))) + self.assertFalse(test_model.validate_native(test_model, datetime.time(13, 00))) def test_time_inclusive_boundaries(self): - test_model = Time.customize(ge=datetime.time(12, 00), - le=datetime.time(13, 00)) + test_model = Time.customize(ge=datetime.time(12, 00), le=datetime.time(13, 00)) - self.assertTrue( - test_model.validate_native(test_model, datetime.time(12, 00))) - self.assertTrue( - test_model.validate_native(test_model, datetime.time(13, 00))) + self.assertTrue(test_model.validate_native(test_model, datetime.time(12, 00))) + self.assertTrue(test_model.validate_native(test_model, datetime.time(13, 00))) def test_datetime_extreme_boundary(self): - self.assertTrue( - DateTime.validate_native(DateTime, datetime.datetime.min)) - self.assertTrue( - DateTime.validate_native(DateTime, datetime.datetime.max)) + self.assertTrue(DateTime.validate_native(DateTime, datetime.datetime.min)) + self.assertTrue(DateTime.validate_native(DateTime, datetime.datetime.max)) def test_time_extreme_boundary(self): self.assertTrue(Time.validate_native(Time, datetime.time(0, 0, 0, 0))) - self.assertTrue( - Time.validate_native(Time, datetime.time(23, 59, 59, 999999))) + self.assertTrue(Time.validate_native(Time, datetime.time(23, 59, 59, 999999))) def test_date_extreme_boundary(self): self.assertTrue(Date.validate_native(Date, datetime.date.min)) @@ -418,11 +433,11 @@ def test_integer(self): i = 12 integer = Integer() - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, Integer, i, element, ns_test) element = element[0] - self.assertEqual(element.text, '12') + self.assertEqual(element.text, "12") value = XmlDocument().from_element(None, integer, element) self.assertEqual(value, i) @@ -469,18 +484,18 @@ def test_large_integer(self): i = 128375873458473 integer = Integer() - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, Integer, i, element, ns_test) element = element[0] - self.assertEqual(element.text, '128375873458473') + self.assertEqual(element.text, "128375873458473") value = XmlDocument().from_element(None, integer, element) self.assertEqual(value, i) def test_float(self): f = 1.22255645 - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, Float, f, element, ns_test) element = element[0] @@ -493,9 +508,9 @@ def test_array(self): type = Array(String) type.resolve_namespace(type, "zbank") - values = ['a', 'b', 'c', 'd', 'e', 'f'] + values = ["a", "b", "c", "d", "e", "f"] - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, type, values, element, ns_test) element = element[0] @@ -510,7 +525,7 @@ def test_array_empty(self): values = [] - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, type, values, element, ns_test) element = element[0] @@ -520,25 +535,25 @@ def test_array_empty(self): self.assertEqual(len(values2), 0) def test_unicode(self): - s = u'\x34\x55\x65\x34' + s = "\x34\x55\x65\x34" self.assertEqual(4, len(s)) - element = etree.Element('test') - XmlDocument().to_parent(None, String, s, element, 'test_ns') + element = etree.Element("test") + XmlDocument().to_parent(None, String, s, element, "test_ns") element = element[0] value = XmlDocument().from_element(None, String, element) self.assertEqual(value, s) def test_unicode_pattern_mult_cust(self): - assert Unicode(pattern='a').Attributes.pattern == 'a' - assert Unicode(pattern='a')(5).Attributes.pattern == 'a' + assert Unicode(pattern="a").Attributes.pattern == "a" + assert Unicode(pattern="a")(5).Attributes.pattern == "a" def test_unicode_upattern(self): - patt = r'[\w .-]+' + patt = r"[\w .-]+" attr = Unicode(unicode_pattern=patt).Attributes assert attr.pattern == patt assert attr._pattern_re.flags & re.UNICODE - assert attr._pattern_re.match(u"Ğ Ğ ç .-") - assert attr._pattern_re.match(u"\t") is None + assert attr._pattern_re.match("Ğ Ğ ç .-") + assert attr._pattern_re.match("\t") is None def test_unicode_nullable_mult_cust_false(self): assert Unicode(nullable=False).Attributes.nullable == False @@ -549,12 +564,12 @@ def test_unicode_nullable_mult_cust_true(self): assert Unicode(nullable=True)(5).Attributes.nullable == True def test_null(self): - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, Null, None, element, ns_test) print(etree.tostring(element)) element = element[0] - self.assertTrue(bool(element.attrib.get(ns.XSI('nil')))) + self.assertTrue(bool(element.attrib.get(ns.XSI("nil")))) value = XmlDocument().from_element(None, Null, element) self.assertEqual(None, value) @@ -562,17 +577,17 @@ def test_point(self): from spyne.model.primitive.spatial import _get_point_pattern a = re.compile(_get_point_pattern(2)) - assert a.match('POINT (10 40)') is not None - assert a.match('POINT(10 40)') is not None + assert a.match("POINT (10 40)") is not None + assert a.match("POINT(10 40)") is not None - assert a.match('POINT(10.0 40)') is not None - assert a.match('POINT(1.310e4 40)') is not None + assert a.match("POINT(10.0 40)") is not None + assert a.match("POINT(1.310e4 40)") is not None def test_multipoint(self): from spyne.model.primitive.spatial import _get_multipoint_pattern a = re.compile(_get_multipoint_pattern(2)) - assert a.match('MULTIPOINT (10 40, 40 30, 20 20, 30 10)') is not None + assert a.match("MULTIPOINT (10 40, 40 30, 20 20, 30 10)") is not None # FIXME: # assert a.match('MULTIPOINT ((10 40), (40 30), (20 20), (30 10))') is not None @@ -580,70 +595,69 @@ def test_linestring(self): from spyne.model.primitive.spatial import _get_linestring_pattern a = re.compile(_get_linestring_pattern(2)) - assert a.match('LINESTRING (30 10, 10 30, 40 40)') is not None + assert a.match("LINESTRING (30 10, 10 30, 40 40)") is not None def test_multilinestring(self): from spyne.model.primitive.spatial import _get_multilinestring_pattern a = re.compile(_get_multilinestring_pattern(2)) - assert a.match('''MULTILINESTRING ((10 10, 20 20, 10 40), - (40 40, 30 30, 40 20, 30 10))''') is not None + assert a.match("""MULTILINESTRING ((10 10, 20 20, 10 40), + (40 40, 30 30, 40 20, 30 10))""") is not None def test_polygon(self): from spyne.model.primitive.spatial import _get_polygon_pattern a = re.compile(_get_polygon_pattern(2)) - assert a.match( - 'POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))') is not None + assert a.match("POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))") is not None def test_multipolygon(self): from spyne.model.primitive.spatial import _get_multipolygon_pattern a = re.compile(_get_multipolygon_pattern(2)) - assert a.match('''MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), - ((15 5, 40 10, 10 20, 5 10, 15 5)))''') is not None - assert a.match('''MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), + assert a.match("""MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), + ((15 5, 40 10, 10 20, 5 10, 15 5)))""") is not None + assert a.match("""MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), ((20 35, 45 20, 30 5, 10 10, 10 30, 20 35), - (30 20, 20 25, 20 15, 30 20)))''') is not None + (30 20, 20 25, 20 15, 30 20)))""") is not None def test_boolean(self): - b = etree.Element('test') + b = etree.Element("test") XmlDocument().to_parent(None, Boolean, True, b, ns_test) b = b[0] - self.assertEqual('true', b.text) + self.assertEqual("true", b.text) - b = etree.Element('test') + b = etree.Element("test") XmlDocument().to_parent(None, Boolean, 0, b, ns_test) b = b[0] - self.assertEqual('false', b.text) + self.assertEqual("false", b.text) - b = etree.Element('test') + b = etree.Element("test") XmlDocument().to_parent(None, Boolean, 1, b, ns_test) b = b[0] - self.assertEqual('true', b.text) + self.assertEqual("true", b.text) b = XmlDocument().from_element(None, Boolean, b) self.assertEqual(b, True) - b = etree.Element('test') + b = etree.Element("test") XmlDocument().to_parent(None, Boolean, False, b, ns_test) b = b[0] - self.assertEqual('false', b.text) + self.assertEqual("false", b.text) b = XmlDocument().from_element(None, Boolean, b) self.assertEqual(b, False) - b = etree.Element('test') + b = etree.Element("test") XmlDocument().to_parent(None, Boolean, None, b, ns_test) b = b[0] - self.assertEqual('true', b.get(ns.XSI('nil'))) + self.assertEqual("true", b.get(ns.XSI("nil"))) b = XmlDocument().from_element(None, Boolean, b) self.assertEqual(b, None) def test_new_type(self): """Customized primitives go into namespace based on module name.""" - custom_type = Unicode(pattern='123') + custom_type = Unicode(pattern="123") self.assertEqual(custom_type.get_namespace(), custom_type.__module__) def test_default_nullable(self): @@ -664,89 +678,137 @@ def test_simple_type_explicit_customization(self): def test_anydict_customization(self): from spyne.model import json - assert isinstance( - AnyDict.customize(store_as='json').Attributes.store_as, json) + + assert isinstance(AnyDict.customize(store_as="json").Attributes.store_as, json) def test_uuid_serialize(self): - value = uuid.UUID('12345678123456781234567812345678') - - assert ProtocolBase().to_unicode(Uuid, value) \ - == '12345678-1234-5678-1234-567812345678' - assert ProtocolBase().to_unicode(Uuid(serialize_as='hex'), value) \ - == '12345678123456781234567812345678' - assert ProtocolBase().to_unicode(Uuid(serialize_as='urn'), value) \ - == 'urn:uuid:12345678-1234-5678-1234-567812345678' - assert ProtocolBase().to_unicode(Uuid(serialize_as='bytes'), value) \ - == b'\x124Vx\x124Vx\x124Vx\x124Vx' - assert ProtocolBase().to_unicode(Uuid(serialize_as='bytes_le'), value) \ - == b'xV4\x124\x12xV\x124Vx\x124Vx' - assert ProtocolBase().to_unicode(Uuid(serialize_as='fields'), value) \ - == (305419896, 4660, 22136, 18, 52, 95073701484152) - assert ProtocolBase().to_unicode(Uuid(serialize_as='int'), value) \ - == 24197857161011715162171839636988778104 + value = uuid.UUID("12345678123456781234567812345678") + + assert ( + ProtocolBase().to_unicode(Uuid, value) + == "12345678-1234-5678-1234-567812345678" + ) + assert ( + ProtocolBase().to_unicode(Uuid(serialize_as="hex"), value) + == "12345678123456781234567812345678" + ) + assert ( + ProtocolBase().to_unicode(Uuid(serialize_as="urn"), value) + == "urn:uuid:12345678-1234-5678-1234-567812345678" + ) + assert ( + ProtocolBase().to_unicode(Uuid(serialize_as="bytes"), value) + == b"\x124Vx\x124Vx\x124Vx\x124Vx" + ) + assert ( + ProtocolBase().to_unicode(Uuid(serialize_as="bytes_le"), value) + == b"xV4\x124\x12xV\x124Vx\x124Vx" + ) + assert ProtocolBase().to_unicode(Uuid(serialize_as="fields"), value) == ( + 305419896, + 4660, + 22136, + 18, + 52, + 95073701484152, + ) + assert ( + ProtocolBase().to_unicode(Uuid(serialize_as="int"), value) + == 24197857161011715162171839636988778104 + ) def test_uuid_deserialize(self): - value = uuid.UUID('12345678123456781234567812345678') - - assert ProtocolBase().from_unicode(Uuid, - '12345678-1234-5678-1234-567812345678') == value - assert ProtocolBase().from_unicode(Uuid(serialize_as='hex'), - '12345678123456781234567812345678') == value - assert ProtocolBase().from_unicode(Uuid(serialize_as='urn'), - 'urn:uuid:12345678-1234-5678-1234-567812345678') == value - assert ProtocolBase().from_bytes(Uuid(serialize_as='bytes'), - b'\x124Vx\x124Vx\x124Vx\x124Vx') == value - assert ProtocolBase().from_bytes(Uuid(serialize_as='bytes_le'), - b'xV4\x124\x12xV\x124Vx\x124Vx') == value - assert ProtocolBase().from_unicode(Uuid(serialize_as='fields'), - (305419896, 4660, 22136, 18, 52, 95073701484152)) == value - assert ProtocolBase().from_unicode(Uuid(serialize_as='int'), - 24197857161011715162171839636988778104) == value + value = uuid.UUID("12345678123456781234567812345678") + + assert ( + ProtocolBase().from_unicode(Uuid, "12345678-1234-5678-1234-567812345678") + == value + ) + assert ( + ProtocolBase().from_unicode( + Uuid(serialize_as="hex"), "12345678123456781234567812345678" + ) + == value + ) + assert ( + ProtocolBase().from_unicode( + Uuid(serialize_as="urn"), + "urn:uuid:12345678-1234-5678-1234-567812345678", + ) + == value + ) + assert ( + ProtocolBase().from_bytes( + Uuid(serialize_as="bytes"), b"\x124Vx\x124Vx\x124Vx\x124Vx" + ) + == value + ) + assert ( + ProtocolBase().from_bytes( + Uuid(serialize_as="bytes_le"), b"xV4\x124\x12xV\x124Vx\x124Vx" + ) + == value + ) + assert ( + ProtocolBase().from_unicode( + Uuid(serialize_as="fields"), + (305419896, 4660, 22136, 18, 52, 95073701484152), + ) + == value + ) + assert ( + ProtocolBase().from_unicode( + Uuid(serialize_as="int"), 24197857161011715162171839636988778104 + ) + == value + ) def test_uuid_validate(self): - assert Uuid.validate_string(Uuid, - '12345678-1234-5678-1234-567812345678') - assert Uuid.validate_native(Uuid, - uuid.UUID('12345678-1234-5678-1234-567812345678')) + assert Uuid.validate_string(Uuid, "12345678-1234-5678-1234-567812345678") + assert Uuid.validate_native( + Uuid, uuid.UUID("12345678-1234-5678-1234-567812345678") + ) def test_datetime_serialize_as(self): i = 1234567890123456 v = datetime.datetime.fromtimestamp(i / 1e6) - assert ProtocolBase().to_unicode( - DateTime(serialize_as='sec'), v) == i//1e6 - assert ProtocolBase().to_unicode( - DateTime(serialize_as='sec_float'), v) == i/1e6 - assert ProtocolBase().to_unicode( - DateTime(serialize_as='msec'), v) == i//1e3 - assert ProtocolBase().to_unicode( - DateTime(serialize_as='msec_float'), v) == i/1e3 - assert ProtocolBase().to_unicode( - DateTime(serialize_as='usec'), v) == i + assert ProtocolBase().to_unicode(DateTime(serialize_as="sec"), v) == i // 1e6 + assert ( + ProtocolBase().to_unicode(DateTime(serialize_as="sec_float"), v) == i / 1e6 + ) + assert ProtocolBase().to_unicode(DateTime(serialize_as="msec"), v) == i // 1e3 + assert ( + ProtocolBase().to_unicode(DateTime(serialize_as="msec_float"), v) == i / 1e3 + ) + assert ProtocolBase().to_unicode(DateTime(serialize_as="usec"), v) == i def test_datetime_deserialize(self): i = 1234567890123456 v = datetime.datetime.fromtimestamp(i / 1e6) assert ProtocolBase().from_unicode( - DateTime(serialize_as='sec'), i//1e6) == \ - datetime.datetime.fromtimestamp(i//1e6) - assert ProtocolBase().from_unicode( - DateTime(serialize_as='sec_float'), i/1e6) == v + DateTime(serialize_as="sec"), i // 1e6 + ) == datetime.datetime.fromtimestamp(i // 1e6) + assert ( + ProtocolBase().from_unicode(DateTime(serialize_as="sec_float"), i / 1e6) + == v + ) assert ProtocolBase().from_unicode( - DateTime(serialize_as='msec'), i//1e3) == \ - datetime.datetime.fromtimestamp(i/1e3//1000) - assert ProtocolBase().from_unicode( - DateTime(serialize_as='msec_float'), i/1e3) == v + DateTime(serialize_as="msec"), i // 1e3 + ) == datetime.datetime.fromtimestamp(i / 1e3 // 1000) + assert ( + ProtocolBase().from_unicode(DateTime(serialize_as="msec_float"), i / 1e3) + == v + ) - assert ProtocolBase().from_unicode( - DateTime(serialize_as='usec'), i) == v + assert ProtocolBase().from_unicode(DateTime(serialize_as="usec"), i) == v def test_datetime_ancient(self): t = DateTime(dt_format="%Y-%m-%d %H:%M:%S") # to trigger strftime v = datetime.datetime(1881, 1, 1) - vs = '1881-01-01 00:00:00' + vs = "1881-01-01 00:00:00" dt = ProtocolBase().from_unicode(t, vs) self.assertEqual(v, dt) @@ -755,8 +817,9 @@ def test_datetime_ancient(self): self.assertEqual(vs, dt) def test_custom_strftime(self): - s = ProtocolBase.strftime(datetime.date(1800, 9, 23), - "%Y has the same days as 1980 and 2008") + s = ProtocolBase.strftime( + datetime.date(1800, 9, 23), "%Y has the same days as 1980 and 2008" + ) if s != "1800 has the same days as 1980 and 2008": raise AssertionError(s) @@ -777,8 +840,7 @@ def test_custom_strftime(self): testdate = startdate + one_day while testdate < enddate: - if (testdate.day == 1 and testdate.month == 1 and - (testdate.year % 100 == 0)): + if testdate.day == 1 and testdate.month == 1 and (testdate.year % 100 == 0): print("Testing century", testdate.year) day = ProtocolBase.strftime(testdate, "%A") if nextday[prevday] != day: @@ -790,29 +852,24 @@ def test_datetime_usec(self): # see the comments on time test for why the rounding here is weird # rounding 0.1 µsec down - dt = ProtocolBase().from_unicode(DateTime, - "2015-01-01 12:12:12.0000001") + dt = ProtocolBase().from_unicode(DateTime, "2015-01-01 12:12:12.0000001") self.assertEqual(datetime.datetime(2015, 1, 1, 12, 12, 12), dt) # rounding 1.5 µsec up. 0.5 is rounded down by python 3 and up by # python 2 so we test with 1.5 µsec instead. frikkin' nonsense. - dt = ProtocolBase().from_unicode(DateTime, - "2015-01-01 12:12:12.0000015") + dt = ProtocolBase().from_unicode(DateTime, "2015-01-01 12:12:12.0000015") self.assertEqual(datetime.datetime(2015, 1, 1, 12, 12, 12, 2), dt) # rounding 999998.8 µsec up - dt = ProtocolBase().from_unicode(DateTime, - "2015-01-01 12:12:12.9999988") + dt = ProtocolBase().from_unicode(DateTime, "2015-01-01 12:12:12.9999988") self.assertEqual(datetime.datetime(2015, 1, 1, 12, 12, 12, 999999), dt) # rounding 999999.1 µsec down - dt = ProtocolBase().from_unicode(DateTime, - "2015-01-01 12:12:12.9999991") + dt = ProtocolBase().from_unicode(DateTime, "2015-01-01 12:12:12.9999991") self.assertEqual(datetime.datetime(2015, 1, 1, 12, 12, 12, 999999), dt) # rounding 999999.8 µsec down, not up. - dt = ProtocolBase().from_unicode(DateTime, - "2015-01-01 12:12:12.9999998") + dt = ProtocolBase().from_unicode(DateTime, "2015-01-01 12:12:12.9999998") self.assertEqual(datetime.datetime(2015, 1, 1, 12, 12, 12, 999999), dt) @@ -830,18 +887,19 @@ def test_datetime_usec(self): # nM indicates the number of minutes # nS indicates the number of seconds + class SomeBlob(ComplexModel): - __namespace__ = 'myns' + __namespace__ = "myns" howlong = Duration() class TestDurationPrimitive(unittest.TestCase): def test_onehour_oneminute_onesecond(self): - answer = 'PT1H1M1S' + answer = "PT1H1M1S" gg = SomeBlob() gg.howlong = timedelta(hours=1, minutes=1, seconds=1) - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, SomeBlob, gg, element, gg.get_namespace()) element = element[0] @@ -849,7 +907,7 @@ def test_onehour_oneminute_onesecond(self): print(etree.tostring(element, pretty_print=True)) assert element[0].text == answer - data = element.find('{%s}howlong' % gg.get_namespace()).text + data = element.find("{%s}howlong" % gg.get_namespace()).text self.assertEqual(data, answer) s1 = XmlDocument().from_element(None, SomeBlob, element) assert s1.howlong.total_seconds() == gg.howlong.total_seconds() @@ -857,32 +915,31 @@ def test_onehour_oneminute_onesecond(self): def test_4suite(self): # borrowed from 4Suite tests_seconds = [ - (0, u'PT0S'), - (1, u'PT1S'), - (59, u'PT59S'), - (60, u'PT1M'), - (3599, u'PT59M59S'), - (3600, u'PT1H'), - (86399, u'PT23H59M59S'), - (86400, u'P1D'), - (86400 * 60, u'P60D'), - (86400 * 400, u'P400D') + (0, "PT0S"), + (1, "PT1S"), + (59, "PT59S"), + (60, "PT1M"), + (3599, "PT59M59S"), + (3600, "PT1H"), + (86399, "PT23H59M59S"), + (86400, "P1D"), + (86400 * 60, "P60D"), + (86400 * 400, "P400D"), ] for secs, answer in tests_seconds: gg = SomeBlob() gg.howlong = timedelta(seconds=secs) - element = etree.Element('test') - XmlDocument()\ - .to_parent(None, SomeBlob, gg, element, gg.get_namespace()) + element = etree.Element("test") + XmlDocument().to_parent(None, SomeBlob, gg, element, gg.get_namespace()) element = element[0] print(gg.howlong) print(etree.tostring(element, pretty_print=True)) assert element[0].text == answer - data = element.find('{%s}howlong' % gg.get_namespace()).text + data = element.find("{%s}howlong" % gg.get_namespace()).text self.assertEqual(data, answer) s1 = XmlDocument().from_element(None, SomeBlob, element) assert s1.howlong.total_seconds() == secs @@ -890,30 +947,29 @@ def test_4suite(self): for secs, answer in tests_seconds: if secs > 0: secs *= -1 - answer = '-' + answer + answer = "-" + answer gg = SomeBlob() gg.howlong = timedelta(seconds=secs) - element = etree.Element('test') - XmlDocument()\ - .to_parent(None, SomeBlob, gg, element, gg.get_namespace()) + element = etree.Element("test") + XmlDocument().to_parent(None, SomeBlob, gg, element, gg.get_namespace()) element = element[0] print(gg.howlong) print(etree.tostring(element, pretty_print=True)) assert element[0].text == answer - data = element.find('{%s}howlong' % gg.get_namespace()).text + data = element.find("{%s}howlong" % gg.get_namespace()).text self.assertEqual(data, answer) s1 = XmlDocument().from_element(None, SomeBlob, element) assert s1.howlong.total_seconds() == secs def test_duration_positive_seconds_only(self): - answer = 'PT35S' + answer = "PT35S" gg = SomeBlob() gg.howlong = timedelta(seconds=35) - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, SomeBlob, gg, element, gg.get_namespace()) element = element[0] @@ -921,17 +977,17 @@ def test_duration_positive_seconds_only(self): print(etree.tostring(element, pretty_print=True)) assert element[0].text == answer - data = element.find('{%s}howlong' % gg.get_namespace()).text + data = element.find("{%s}howlong" % gg.get_namespace()).text self.assertEqual(data, answer) s1 = XmlDocument().from_element(None, SomeBlob, element) assert s1.howlong.total_seconds() == gg.howlong.total_seconds() def test_duration_positive_minutes_and_seconds_only(self): - answer = 'PT5M35S' + answer = "PT5M35S" gg = SomeBlob() gg.howlong = timedelta(minutes=5, seconds=35) - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, SomeBlob, gg, element, gg.get_namespace()) element = element[0] @@ -939,17 +995,17 @@ def test_duration_positive_minutes_and_seconds_only(self): print(etree.tostring(element, pretty_print=True)) assert element[0].text == answer - data = element.find('{%s}howlong' % gg.get_namespace()).text + data = element.find("{%s}howlong" % gg.get_namespace()).text self.assertEqual(data, answer) s1 = XmlDocument().from_element(None, SomeBlob, element) assert s1.howlong.total_seconds() == gg.howlong.total_seconds() def test_duration_positive_milliseconds_only(self): - answer = 'PT0.666000S' + answer = "PT0.666000S" gg = SomeBlob() gg.howlong = timedelta(milliseconds=666) - element = etree.Element('test') + element = etree.Element("test") XmlDocument().to_parent(None, SomeBlob, gg, element, gg.get_namespace()) element = element[0] @@ -957,24 +1013,29 @@ def test_duration_positive_milliseconds_only(self): print(etree.tostring(element, pretty_print=True)) assert element[0].text == answer - data = element.find('{%s}howlong' % gg.get_namespace()).text + data = element.find("{%s}howlong" % gg.get_namespace()).text self.assertEqual(data, answer) s1 = XmlDocument().from_element(None, SomeBlob, element) assert s1.howlong.total_seconds() == gg.howlong.total_seconds() def test_duration_xml_duration(self): - dur = datetime.timedelta(days=5 + 30 + 365, hours=1, minutes=1, - seconds=12, microseconds=8e5) + dur = datetime.timedelta( + days=5 + 30 + 365, hours=1, minutes=1, seconds=12, microseconds=8e5 + ) - str1 = 'P400DT3672.8S' - str2 = 'P1Y1M5DT1H1M12.8S' + str1 = "P400DT3672.8S" + str2 = "P1Y1M5DT1H1M12.8S" self.assertEqual(dur, ProtocolBase().from_unicode(Duration, str1)) self.assertEqual(dur, ProtocolBase().from_unicode(Duration, str2)) - self.assertEqual(dur, ProtocolBase().from_unicode(Duration, - ProtocolBase().to_unicode(Duration, dur))) + self.assertEqual( + dur, + ProtocolBase().from_unicode( + Duration, ProtocolBase().to_unicode(Duration, dur) + ), + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/multipython/model/test_complex.py b/spyne/test/multipython/model/test_complex.py index 9aa8d1cb2..9cf9a61dc 100644 --- a/spyne/test/multipython/model/test_complex.py +++ b/spyne/test/multipython/model/test_complex.py @@ -22,13 +22,11 @@ import unittest -from spyne.model.complex import (ComplexModel, ComplexModelMeta, - ComplexModelBase, Array) -from spyne.model.primitive import Unicode, Integer, String -from spyne.util.six import add_metaclass +from spyne.model.complex import Array, ComplexModel, ComplexModelBase, ComplexModelMeta +from spyne.model.primitive import Integer, String, Unicode -class DeclareOrder_declare(ComplexModel.customize(declare_order='declared')): +class DeclareOrder_declare(ComplexModel.customize(declare_order="declared")): field3 = Integer field1 = Integer field2 = Integer @@ -38,24 +36,24 @@ class MyComplexModelMeta(ComplexModelMeta): """Custom complex model metaclass.""" def __new__(mcs, name, bases, attrs): - attrs['new_field'] = Unicode - attrs['field1'] = Unicode - new_cls = super(MyComplexModelMeta, mcs).__new__(mcs, name, bases, - attrs) + attrs["new_field"] = Unicode + attrs["field1"] = Unicode + new_cls = super(MyComplexModelMeta, mcs).__new__(mcs, name, bases, attrs) return new_cls -@add_metaclass(MyComplexModelMeta) -class MyComplexModel(ComplexModelBase): +class MyComplexModel(ComplexModelBase, metaclass=MyComplexModelMeta): """Custom complex model class.""" + class Attributes(ComplexModelBase.Attributes): - declare_order = 'declared' + declare_order = "declared" class MyModelWithDeclaredOrder(MyComplexModel): """Test model for complex model with custom metaclass.""" + class Attributes(MyComplexModel.Attributes): - declare_order = 'declared' + declare_order = "declared" field3 = Integer field1 = Integer @@ -66,71 +64,75 @@ class TestComplexModel(unittest.TestCase): def test_add_field(self): class C(ComplexModel): u = Unicode - C.append_field('i', Integer) - assert C._type_info['i'] is Integer + + C.append_field("i", Integer) + assert C._type_info["i"] is Integer def test_insert_field(self): class C(ComplexModel): u = Unicode - C.insert_field(0, 'i', Integer) - assert C._type_info.keys() == ['i', 'u'] + + C.insert_field(0, "i", Integer) + assert C._type_info.keys() == ["i", "u"] def test_variants(self): class C(ComplexModel): u = Unicode + CC = C.customize(child_attrs=dict(u=dict(min_len=5))) print(dict(C.Attributes._variants.items())) - r, = C.Attributes._variants + (r,) = C.Attributes._variants assert r is CC assert CC.Attributes.parent_variant is C - C.append_field('i', Integer) - assert C._type_info['i'] is Integer - assert CC._type_info['i'] is Integer + C.append_field("i", Integer) + assert C._type_info["i"] is Integer + assert CC._type_info["i"] is Integer def test_child_customization(self): class C(ComplexModel): u = Unicode + CC = C.customize(child_attrs=dict(u=dict(min_len=5))) - assert CC._type_info['u'].Attributes.min_len == 5 - assert C._type_info['u'].Attributes.min_len != 5 + assert CC._type_info["u"].Attributes.min_len == 5 + assert C._type_info["u"].Attributes.min_len != 5 def test_array_customization(self): CC = Array(Unicode).customize( - serializer_attrs=dict(min_len=5), punks='roll', + serializer_attrs=dict(min_len=5), + punks="roll", ) - assert CC.Attributes.punks == 'roll' + assert CC.Attributes.punks == "roll" assert CC._type_info[0].Attributes.min_len == 5 def test_array_customization_complex(self): class C(ComplexModel): u = Unicode - CC = Array(C).customize( - punks='roll', - serializer_attrs=dict(bidik=True) - ) - assert CC.Attributes.punks == 'roll' + CC = Array(C).customize(punks="roll", serializer_attrs=dict(bidik=True)) + assert CC.Attributes.punks == "roll" assert CC._type_info[0].Attributes.bidik == True def test_delayed_child_customization_append(self): class C(ComplexModel): u = Unicode + CC = C.customize(child_attrs=dict(i=dict(ge=5))) - CC.append_field('i', Integer) - assert CC._type_info['i'].Attributes.ge == 5 - assert not 'i' in C._type_info + CC.append_field("i", Integer) + assert CC._type_info["i"].Attributes.ge == 5 + assert not "i" in C._type_info def test_delayed_child_customization_insert(self): class C(ComplexModel): u = Unicode + CC = C.customize(child_attrs=dict(i=dict(ge=5))) - CC.insert_field(1, 'i', Integer) - assert CC._type_info['i'].Attributes.ge == 5 - assert not 'i' in C._type_info + CC.insert_field(1, "i", Integer) + assert CC._type_info["i"].Attributes.ge == 5 + assert not "i" in C._type_info def test_array_member_name(self): print(Array(String, member_name="punk")._type_info) - assert 'punk' in Array(String, member_name="punk")._type_info + assert "punk" in Array(String, member_name="punk")._type_info def test_customize(self): class Base(ComplexModel): @@ -140,7 +142,7 @@ class Attributes(ComplexModel.Attributes): Base2 = Base.customize(prop1=4) - self.assertNotEquals(Base.Attributes.prop1, Base2.Attributes.prop1) + self.assertNotEqual(Base.Attributes.prop1, Base2.Attributes.prop1) self.assertEqual(Base.Attributes.prop2, Base2.Attributes.prop2) class Derived(Base): @@ -156,7 +158,7 @@ class Attributes(Base.Attributes): self.assertEqual(Derived.Attributes.prop1, 3) self.assertEqual(Derived2.Attributes.prop1, 5) - self.assertNotEquals(Derived.Attributes.prop3, Derived2.Attributes.prop3) + self.assertNotEqual(Derived.Attributes.prop3, Derived2.Attributes.prop3) self.assertEqual(Derived.Attributes.prop4, Derived2.Attributes.prop4) Derived3 = Derived.customize(prop3=12) @@ -164,16 +166,20 @@ class Attributes(Base.Attributes): # changes made to bases propagate, unless overridden self.assertEqual(Derived.Attributes.prop1, Base.Attributes.prop1) - self.assertNotEquals(Derived2.Attributes.prop1, Base.Attributes.prop1) + self.assertNotEqual(Derived2.Attributes.prop1, Base.Attributes.prop1) self.assertEqual(Derived3.Attributes.prop1, Base.Attributes.prop1) def test_declare_order(self): - self.assertEqual(["field3", "field1", "field2"], - list(DeclareOrder_declare._type_info)) - self.assertEqual(["field3", "field1", "field2", "new_field"], - list(MyModelWithDeclaredOrder._type_info)) + self.assertEqual( + ["field3", "field1", "field2"], list(DeclareOrder_declare._type_info) + ) + self.assertEqual( + ["field3", "field1", "field2", "new_field"], + list(MyModelWithDeclaredOrder._type_info), + ) -if __name__ == '__main__': +if __name__ == "__main__": import sys + sys.exit(unittest.main()) diff --git a/spyne/test/protocol/__init__.py b/spyne/test/protocol/__init__.py index 725080664..898794071 100644 --- a/spyne/test/protocol/__init__.py +++ b/spyne/test/protocol/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # diff --git a/spyne/test/protocol/_test_dictdoc.py b/spyne/test/protocol/_test_dictdoc.py index 7e4af3dfa..2ccc39888 100644 --- a/spyne/test/protocol/_test_dictdoc.py +++ b/spyne/test/protocol/_test_dictdoc.py @@ -25,63 +25,58 @@ logger = logging.getLogger(__name__) +import decimal import unittest - import uuid + import pytz -import decimal -from spyne.util import six + from spyne.util.dictdoc import get_object_as_dict -if not six.PY2: - long = int +long = int -from datetime import datetime -from datetime import date -from datetime import time -from datetime import timedelta +from datetime import date, datetime, time, timedelta import lxml.etree import lxml.html - from lxml.builder import E -from spyne import MethodContext, Ignored -from spyne.service import Service -from spyne.server import ServerBase +from spyne import Ignored, MethodContext from spyne.application import Application -from spyne.decorator import srpc, rpc +from spyne.decorator import rpc, srpc from spyne.error import ValidationError -from spyne.model.binary import binary_encoding_handlers, File -from spyne.model.complex import ComplexModel -from spyne.model.complex import Iterable +from spyne.model.binary import ByteArray, File, binary_encoding_handlers +from spyne.model.complex import ComplexModel, Iterable from spyne.model.fault import Fault +from spyne.model.primitive import ( + AnyDict, + AnyHtml, + AnyUri, + AnyXml, + Boolean, + Date, + DateTime, + Decimal, + Double, + Duration, + ImageUri, + Integer, + Integer8, + Line, + Mandatory, + MultiLine, + MultiPoint, + MultiPolygon, + Point, + Polygon, + String, + Time, + Unicode, + Uuid, +) from spyne.protocol import ProtocolBase -from spyne.model.binary import ByteArray -from spyne.model.primitive import Decimal -from spyne.model.primitive import Integer -from spyne.model.primitive import String -from spyne.model.primitive import DateTime -from spyne.model.primitive import Mandatory -from spyne.model.primitive import AnyXml -from spyne.model.primitive import AnyHtml -from spyne.model.primitive import AnyDict -from spyne.model.primitive import Unicode -from spyne.model.primitive import AnyUri -from spyne.model.primitive import ImageUri -from spyne.model.primitive import Double -from spyne.model.primitive import Integer8 -from spyne.model.primitive import Time -from spyne.model.primitive import Date -from spyne.model.primitive import Duration -from spyne.model.primitive import Boolean -from spyne.model.primitive import Uuid -from spyne.model.primitive import Point -from spyne.model.primitive import Line -from spyne.model.primitive import Polygon -from spyne.model.primitive import MultiPoint -from spyne.model.primitive import MultiLine -from spyne.model.primitive import MultiPolygon +from spyne.server import ServerBase +from spyne.service import Service def _unbyte(d): @@ -91,7 +86,7 @@ def _unbyte(d): for k, v in list(d.items()): if isinstance(k, bytes): del d[k] - d[k.decode('utf8')] = v + d[k.decode("utf8")] = v if isinstance(v, dict): _unbyte(v) @@ -113,7 +108,7 @@ def _unbyte(d): elif isinstance(v, bytes): try: - d[k] = v.decode('utf8') + d[k] = v.decode("utf8") except UnicodeDecodeError: d[k] = v @@ -124,28 +119,41 @@ def TDry(serializer, _DictDocumentChild, dumps_kwargs=None): if not dumps_kwargs: dumps_kwargs = {} - def _dry_me(services, d, ignore_wrappers=False, complex_as=dict, - just_ctx=False, just_in_object=False, validator=None, - polymorphic=False): - - app = Application(services, 'tns', - in_protocol=_DictDocumentChild( - ignore_wrappers=ignore_wrappers, complex_as=complex_as, - polymorphic=polymorphic, validator=validator, - ), - out_protocol=_DictDocumentChild( - ignore_wrappers=ignore_wrappers, complex_as=complex_as, - polymorphic=polymorphic), - ) + def _dry_me( + services, + d, + ignore_wrappers=False, + complex_as=dict, + just_ctx=False, + just_in_object=False, + validator=None, + polymorphic=False, + ): + + app = Application( + services, + "tns", + in_protocol=_DictDocumentChild( + ignore_wrappers=ignore_wrappers, + complex_as=complex_as, + polymorphic=polymorphic, + validator=validator, + ), + out_protocol=_DictDocumentChild( + ignore_wrappers=ignore_wrappers, + complex_as=complex_as, + polymorphic=polymorphic, + ), + ) server = ServerBase(app) initial_ctx = MethodContext(server, MethodContext.SERVER) in_string = serializer.dumps(d, **dumps_kwargs) if not isinstance(in_string, bytes): - in_string = in_string.encode('utf8') + in_string = in_string.encode("utf8") initial_ctx.in_string = [in_string] - ctx, = server.generate_contexts(initial_ctx, in_string_charset='utf8') + (ctx,) = server.generate_contexts(initial_ctx, in_string_charset="utf8") if not just_ctx: server.get_in_object(ctx) if not just_in_object: @@ -153,10 +161,17 @@ def _dry_me(services, d, ignore_wrappers=False, complex_as=dict, server.get_out_string(ctx) return ctx + return _dry_me -def TDictDocumentTest(serializer, _DictDocumentChild, dumps_kwargs=None, - loads_kwargs=None, convert_dict=None): + +def TDictDocumentTest( + serializer, + _DictDocumentChild, + dumps_kwargs=None, + loads_kwargs=None, + convert_dict=None, +): if not dumps_kwargs: dumps_kwargs = {} if not loads_kwargs: @@ -175,7 +190,9 @@ def loads(self, o): try: return _unbyte(serializer.loads(o, **loads_kwargs)) except TypeError: - return _unbyte(serializer.loads(o, Loader=yaml.FullLoader, **loads_kwargs)) + return _unbyte( + serializer.loads(o, Loader=yaml.FullLoader, **loads_kwargs) + ) def test_complex_with_only_primitive_fields(self): class SomeComplexModel(ComplexModel): @@ -185,11 +202,11 @@ class SomeComplexModel(ComplexModel): class SomeService(Service): @srpc(SomeComplexModel, _returns=SomeComplexModel) def some_call(scm): - return SomeComplexModel(i=5, s='5x') + return SomeComplexModel(i=5, s="5x") - ctx = _dry_me([SomeService], {"some_call":[]}) + ctx = _dry_me([SomeService], {"some_call": []}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) s = s["some_callResponse"]["some_callResult"]["SomeComplexModel"] assert s["i"] == 5 @@ -210,49 +227,62 @@ class SomeService(Service): def some_call(ccm): return CCM(c=ccm.c, i=ccm.i, s=ccm.s) - ctx = _dry_me([SomeService], {"some_call": - {"ccm": {"CCM":{ - "c":{"CM":{"i":3, "s": "3x"}}, - "i":4, - "s": "4x", - }}} - }) + ctx = _dry_me( + [SomeService], + { + "some_call": { + "ccm": { + "CCM": { + "c": {"CM": {"i": 3, "s": "3x"}}, + "i": 4, + "s": "4x", + } + } + } + }, + ) - ret = self.loads(b''.join(ctx.out_string)) + ret = self.loads(b"".join(ctx.out_string)) print(ret) - d = ret['some_callResponse']['some_callResult']['CCM'] - assert d['i'] == 4 - assert d['s'] in ('4x', b'4x') - assert d['c']['CM']['i'] == 3 - assert d['c']['CM']['s'] in ('3x', b'3x') + d = ret["some_callResponse"]["some_callResult"]["CCM"] + assert d["i"] == 4 + assert d["s"] in ("4x", b"4x") + assert d["c"]["CM"]["i"] == 3 + assert d["c"]["CM"]["s"] in ("3x", b"3x") def test_multiple_list(self): class SomeService(Service): - @srpc(Unicode(max_occurs=decimal.Decimal('inf')), - _returns=Unicode(max_occurs=decimal.Decimal('inf'))) + @srpc( + Unicode(max_occurs=decimal.Decimal("inf")), + _returns=Unicode(max_occurs=decimal.Decimal("inf")), + ) def some_call(s): return s - ctx = _dry_me([SomeService], {"some_call":[["a","b"]]}) + ctx = _dry_me([SomeService], {"some_call": [["a", "b"]]}) - data = b''.join(ctx.out_string) + data = b"".join(ctx.out_string) print(data) - assert self.loads(data) == \ - {"some_callResponse": {"some_callResult": ("a", "b")}} + assert self.loads(data) == { + "some_callResponse": {"some_callResult": ("a", "b")} + } def test_multiple_dict(self): class SomeService(Service): - @srpc(Unicode(max_occurs=decimal.Decimal('inf')), - _returns=Unicode(max_occurs=decimal.Decimal('inf'))) + @srpc( + Unicode(max_occurs=decimal.Decimal("inf")), + _returns=Unicode(max_occurs=decimal.Decimal("inf")), + ) def some_call(s): return s - ctx = _dry_me([SomeService], {"some_call":{"s":["a","b"]}}) + ctx = _dry_me([SomeService], {"some_call": {"s": ["a", "b"]}}) - assert self.loads(b''.join(ctx.out_string)) == \ - {"some_callResponse": {"some_callResult": ("a", "b")}} + assert self.loads(b"".join(ctx.out_string)) == { + "some_callResponse": {"some_callResult": ("a", "b")} + } def test_multiple_dict_array(self): class SomeService(Service): @@ -260,10 +290,11 @@ class SomeService(Service): def some_call(s): return s - ctx = _dry_me([SomeService], {"some_call":{"s":["a","b"]}}) + ctx = _dry_me([SomeService], {"some_call": {"s": ["a", "b"]}}) - assert self.loads(b''.join(ctx.out_string)) == \ - {"some_callResponse": {"some_callResult": ("a", "b")}} + assert self.loads(b"".join(ctx.out_string)) == { + "some_callResponse": {"some_callResult": ("a", "b")} + } def test_multiple_dict_complex_array(self): class CM(ComplexModel): @@ -283,61 +314,87 @@ class SomeService(Service): def some_call(ecm): return ecm - ctx = _dry_me([SomeService], { - "some_call": {"ecm": [{"ECM": { - "c": {"CM":{"i":3, "s": "3x"}}, - "i":4, - "s": "4x", - "d": "2011-12-13T14:15:16Z" - }}] - }}) + ctx = _dry_me( + [SomeService], + { + "some_call": { + "ecm": [ + { + "ECM": { + "c": {"CM": {"i": 3, "s": "3x"}}, + "i": 4, + "s": "4x", + "d": "2011-12-13T14:15:16Z", + } + } + ] + } + }, + ) print(ctx.in_object) - ret = self.loads(b''.join(ctx.out_string)) + ret = self.loads(b"".join(ctx.out_string)) print(ret) - assert ret["some_callResponse"]['some_callResult'] - assert ret["some_callResponse"]['some_callResult'][0] - assert ret["some_callResponse"]['some_callResult'][0]["ECM"]["c"] - assert ret["some_callResponse"]['some_callResult'][0]["ECM"]["c"]["CM"]["i"] == 3 - assert ret["some_callResponse"]['some_callResult'][0]["ECM"]["c"]["CM"]["s"] in ("3x", b"3x") - assert ret["some_callResponse"]['some_callResult'][0]["ECM"]["i"] == 4 - assert ret["some_callResponse"]['some_callResult'][0]["ECM"]["s"] in ("4x", b"4x") - assert ret["some_callResponse"]['some_callResult'][0]["ECM"]["d"] == "2011-12-13T14:15:16+00:00" + assert ret["some_callResponse"]["some_callResult"] + assert ret["some_callResponse"]["some_callResult"][0] + assert ret["some_callResponse"]["some_callResult"][0]["ECM"]["c"] + assert ( + ret["some_callResponse"]["some_callResult"][0]["ECM"]["c"]["CM"]["i"] + == 3 + ) + assert ret["some_callResponse"]["some_callResult"][0]["ECM"]["c"]["CM"][ + "s" + ] in ("3x", b"3x") + assert ret["some_callResponse"]["some_callResult"][0]["ECM"]["i"] == 4 + assert ret["some_callResponse"]["some_callResult"][0]["ECM"]["s"] in ( + "4x", + b"4x", + ) + assert ( + ret["some_callResponse"]["some_callResult"][0]["ECM"]["d"] + == "2011-12-13T14:15:16+00:00" + ) def test_invalid_request(self): class SomeService(Service): @srpc(Integer, String, DateTime) - def yay(i,s,d): - print(i,s,d) + def yay(i, s, d): + print(i, s, d) - ctx = _dry_me([SomeService], {"some_call": {"yay": []}}, - just_in_object=True) + ctx = _dry_me( + [SomeService], {"some_call": {"yay": []}}, just_in_object=True + ) print(ctx.in_error) - assert ctx.in_error.faultcode == 'Client.ResourceNotFound' + assert ctx.in_error.faultcode == "Client.ResourceNotFound" def test_invalid_string(self): class SomeService(Service): @srpc(Integer, String, DateTime) - def yay(i,s,d): + def yay(i, s, d): print(i, s, d) - ctx = _dry_me([SomeService], {"yay": {"s": 1}}, validator='soft', - just_in_object=True) + ctx = _dry_me( + [SomeService], {"yay": {"s": 1}}, validator="soft", just_in_object=True + ) - assert ctx.in_error.faultcode == 'Client.ValidationError' + assert ctx.in_error.faultcode == "Client.ValidationError" def test_invalid_number(self): class SomeService(Service): @srpc(Integer, String, DateTime) - def yay(i,s,d): - print(i,s,d) + def yay(i, s, d): + print(i, s, d) - ctx = _dry_me([SomeService], {"yay": ["s", "B"]}, validator='soft', - just_in_object=True) + ctx = _dry_me( + [SomeService], + {"yay": ["s", "B"]}, + validator="soft", + just_in_object=True, + ) - assert ctx.in_error.faultcode == 'Client.ValidationError' + assert ctx.in_error.faultcode == "Client.ValidationError" def test_missing_value(self): class SomeService(Service): @@ -345,23 +402,28 @@ class SomeService(Service): def yay(i, s, d): print(i, s, d) - ctx = _dry_me([SomeService], {"yay": [1, "B"]}, validator='soft', - just_in_object=True) + ctx = _dry_me( + [SomeService], {"yay": [1, "B"]}, validator="soft", just_in_object=True + ) print(ctx.in_error.faultstring) - assert ctx.in_error.faultcode == 'Client.ValidationError' + assert ctx.in_error.faultcode == "Client.ValidationError" assert ctx.in_error.faultstring.endswith("at least 1 times.") def test_invalid_datetime(self): class SomeService(Service): @srpc(Integer, String, Mandatory.DateTime) - def yay(i,s,d): - print(i,s,d) + def yay(i, s, d): + print(i, s, d) - ctx = _dry_me([SomeService],{"yay": {"d":"a2011"}},validator='soft', - just_in_object=True) + ctx = _dry_me( + [SomeService], + {"yay": {"d": "a2011"}}, + validator="soft", + just_in_object=True, + ) - assert ctx.in_error.faultcode == 'Client.ValidationError' + assert ctx.in_error.faultcode == "Client.ValidationError" def test_fault_to_dict(self): class SomeService(Service): @@ -369,7 +431,7 @@ class SomeService(Service): def some_call(): raise Fault() - _dry_me([SomeService], {"some_call":[]}) + _dry_me([SomeService], {"some_call": []}) def test_prune_none_and_optional(self): class SomeObject(ComplexModel): @@ -381,16 +443,18 @@ class SomeService(Service): def some_call(): return SomeObject() - ctx = _dry_me([SomeService], {"some_call":[]}) + ctx = _dry_me([SomeService], {"some_call": []}) - ret = self.loads(b''.join(ctx.out_string)) + ret = self.loads(b"".join(ctx.out_string)) - assert ret == {"some_callResponse": {'some_callResult': - {'SomeObject': {'s': None}}}} + assert ret == { + "some_callResponse": {"some_callResult": {"SomeObject": {"s": None}}} + } def test_any_xml(self): - d = lxml.etree.tostring(E('{ns1}x', E('{ns2}Y', "some data")), - encoding='unicode') + d = lxml.etree.tostring( + E("{ns1}x", E("{ns2}Y", "some data")), encoding="unicode" + ) class SomeService(Service): @srpc(AnyXml, _returns=AnyXml) @@ -400,17 +464,16 @@ def some_call(p): assert type(p) == lxml.etree._Element return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_any_html(self): - d = lxml.html.tostring(E('div', E('span', "something")), - encoding='unicode') + d = lxml.html.tostring(E("div", E("span", "something")), encoding="unicode") class SomeService(Service): @srpc(AnyHtml, _returns=AnyHtml) @@ -422,7 +485,7 @@ def some_call(p): ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) @@ -430,7 +493,7 @@ def some_call(p): assert s == d def test_any_dict(self): - d = {'helo': 213, 'data': {'nested': [12, 0.3]}} + d = {"helo": 213, "data": {"nested": [12, 0.3]}} class SomeService(Service): @srpc(AnyDict, _returns=AnyDict) @@ -440,9 +503,9 @@ def some_call(p): assert type(p) == dict return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = b''.join(ctx.out_string) + s = b"".join(ctx.out_string) d = self.dumps({"some_callResponse": {"some_callResult": d}}) print(s) @@ -450,64 +513,64 @@ def some_call(p): assert self.loads(s) == self.loads(d) def test_unicode(self): - d = u'some string' + d = "some string" class SomeService(Service): @srpc(Unicode, _returns=Unicode) def some_call(p): print(p) print(type(p)) - assert type(p) == six.text_type + assert type(p) == str return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_any_uri(self): - d = 'http://example.com/?asd=b12&df=aa#tag' + d = "http://example.com/?asd=b12&df=aa#tag" class SomeService(Service): @srpc(AnyUri, _returns=AnyUri) def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return p ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_image_uri(self): - d = 'http://example.com/funny.gif' + d = "http://example.com/funny.gif" class SomeService(Service): @srpc(ImageUri, _returns=ImageUri) def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return p ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_decimal(self): - d = decimal.Decimal('1e100') + d = decimal.Decimal("1e100") if _DictDocumentChild._decimal_as_string: d = str(d) @@ -521,7 +584,7 @@ def some_call(p): ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) @@ -538,9 +601,9 @@ def some_call(p): assert type(p) == float return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) @@ -557,16 +620,16 @@ def some_call(p): assert type(p) == int return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_integer_way_small(self): - d = -1<<1000 + d = -1 << 1000 if _DictDocumentChild._huge_numbers_as_string: d = str(d) @@ -578,9 +641,9 @@ def some_call(p): assert type(p) == long return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) @@ -588,7 +651,7 @@ def some_call(p): assert s == d def test_integer_way_big(self): - d = 1<<1000 + d = 1 << 1000 if _DictDocumentChild._huge_numbers_as_string: d = str(d) @@ -600,9 +663,9 @@ def some_call(p): assert type(p) == long return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) @@ -620,9 +683,9 @@ def some_call(p): assert p.isoformat() == d return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) @@ -646,14 +709,14 @@ def some_call_dt(): return vdt ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) rd = {"some_callResponse": {"some_callResult": d}} print(s) print(rd) assert s == rd ctx = _dry_me([SomeService], {"some_call_dt": []}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) rd = {"some_call_dtResponse": {"some_call_dtResult": d}} print(s) print(rd) @@ -671,9 +734,9 @@ def some_call(p): assert p.replace(tzinfo=None).isoformat() == d return p - ctx = _dry_me([SomeService], {"some_call":[d]}, validator='soft') + ctx = _dry_me([SomeService], {"some_call": [d]}, validator="soft") - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) @@ -683,7 +746,10 @@ def test_datetime_tz(self): d = datetime(2010, 9, 8, 7, 6, 5, tzinfo=pytz.utc).isoformat() class SomeService(Service): - @srpc(DateTime, _returns=DateTime(ge=datetime(2010,1,1,tzinfo=pytz.utc))) + @srpc( + DateTime, + _returns=DateTime(ge=datetime(2010, 1, 1, tzinfo=pytz.utc)), + ) def some_call(p): print(p) print(type(p)) @@ -691,9 +757,9 @@ def some_call(p): assert p.isoformat() == d return p - ctx = _dry_me([SomeService], {"some_call":[d]}, validator='soft') + ctx = _dry_me([SomeService], {"some_call": [d]}, validator="soft") - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) @@ -710,9 +776,9 @@ def some_call(p): assert type(p) == timedelta return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) @@ -729,16 +795,16 @@ def some_call(p): assert type(p) == bool return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_uuid(self): - d = '7d2a6330-eb64-4900-8a10-38ebef415e9d' + d = "7d2a6330-eb64-4900-8a10-38ebef415e9d" class SomeService(Service): @srpc(Uuid, _returns=Uuid) @@ -748,239 +814,241 @@ def some_call(p): assert type(p) == uuid.UUID return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_point2d(self): - d = 'POINT(1 2)' + d = "POINT(1 2)" class SomeService(Service): @srpc(Point, _returns=Point) def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_point3d(self): - d = 'POINT(1 2 3)' + d = "POINT(1 2 3)" class SomeService(Service): @srpc(Point, _returns=Point) def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_line2d(self): - d = 'LINESTRING(1 2, 3 4)' + d = "LINESTRING(1 2, 3 4)" class SomeService(Service): @srpc(Line, _returns=Line) def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_line3d(self): - d = 'LINESTRING(1 2 3, 4 5 6)' + d = "LINESTRING(1 2 3, 4 5 6)" class SomeService(Service): @srpc(Line, _returns=Line) def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_polygon2d(self): - d = 'POLYGON((1 1, 1 2, 2 2, 2 1, 1 1))' + d = "POLYGON((1 1, 1 2, 2 2, 2 1, 1 1))" class SomeService(Service): @srpc(Polygon(2), _returns=Polygon(2)) def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_polygon3d(self): - d = 'POLYGON((1 1 0, 1 2 0, 2 2 0, 2 1 0, 1 1 0))' + d = "POLYGON((1 1 0, 1 2 0, 2 2 0, 2 1 0, 1 1 0))" class SomeService(Service): @srpc(Polygon(3), _returns=Polygon(3)) def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_multipoint2d(self): - d = 'MULTIPOINT ((10 40), (40 30), (20 20), (30 10))' + d = "MULTIPOINT ((10 40), (40 30), (20 20), (30 10))" class SomeService(Service): @srpc(MultiPoint(2), _returns=MultiPoint(2)) def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_multipoint3d(self): - d = 'MULTIPOINT (10 40 30, 40 30 10,)' + d = "MULTIPOINT (10 40 30, 40 30 10,)" class SomeService(Service): @srpc(MultiPoint(3), _returns=MultiPoint(3)) def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_multiline2d(self): - d = 'MULTILINESTRING ((10 10, 20 20, 10 40), (40 40, 30 30, 40 20, 30 10))' + d = "MULTILINESTRING ((10 10, 20 20, 10 40), (40 40, 30 30, 40 20, 30 10))" class SomeService(Service): @srpc(MultiLine(2), _returns=MultiLine(2)) def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_multiline3d(self): - d = 'MULTILINESTRING ((10 10, 20 20, 10 40), (40 40, 30 30, 40 20, 30 10))' + d = "MULTILINESTRING ((10 10, 20 20, 10 40), (40 40, 30 30, 40 20, 30 10))" class SomeService(Service): @srpc(MultiLine(3), _returns=MultiLine(3)) def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_multipolygon2d(self): - d = 'MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))' + d = "MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))" class SomeService(Service): @srpc(MultiPolygon(2), _returns=MultiPolygon(2)) def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) assert s == d def test_multipolygon3d(self): - d = 'MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)),' \ - '((20 35, 45 20, 30 5, 10 10, 10 30, 20 35),' \ - '(30 20, 20 25, 20 15, 30 20)))' + d = ( + "MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40))," + "((20 35, 45 20, 30 5, 10 10, 10 30, 20 35)," + "(30 20, 20 25, 20 15, 30 20)))" + ) class SomeService(Service): @srpc(MultiPolygon(3), _returns=MultiPolygon(3)) def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return p - ctx = _dry_me([SomeService], {"some_call":[d]}) + ctx = _dry_me([SomeService], {"some_call": [d]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": d}} print(s) print(d) @@ -992,9 +1060,9 @@ class SomeService(Service): def some_call(): return iter(range(1000)) - ctx = _dry_me([SomeService], {"some_call":[]}) + ctx = _dry_me([SomeService], {"some_call": []}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": tuple(range(1000))}} print(s) print(d) @@ -1004,10 +1072,10 @@ def test_bytearray(self): dbe = _DictDocumentChild.default_binary_encoding beh = binary_encoding_handlers[dbe] - data = bytes(bytearray(range(0xff))) + data = bytes(bytearray(range(0xFF))) encoded_data = beh([data]) if _DictDocumentChild.text_based: - encoded_data = encoded_data.decode('latin1') + encoded_data = encoded_data.decode("latin1") class SomeService(Service): @srpc(ByteArray, _returns=ByteArray) @@ -1020,7 +1088,7 @@ def some_call(ba): ctx = _dry_me([SomeService], {"some_call": [encoded_data]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": encoded_data}} print(repr(s)) @@ -1034,10 +1102,10 @@ def test_file_data(self): dbe = _DictDocumentChild.default_binary_encoding beh = binary_encoding_handlers[dbe] - data = bytes(bytearray(range(0xff))) + data = bytes(bytearray(range(0xFF))) encoded_data = beh([data]) if _DictDocumentChild.text_based: - encoded_data = encoded_data.decode('latin1') + encoded_data = encoded_data.decode("latin1") class SomeService(Service): @srpc(File, _returns=File) @@ -1051,7 +1119,7 @@ def some_call(p): # we put the encoded data in the list of arguments. ctx = _dry_me([SomeService], {"some_call": [encoded_data]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {"some_callResult": encoded_data}} print(s) @@ -1065,14 +1133,14 @@ def test_file_value(self): # Prepare data v = File.Value( - name='some_file.bin', - type='application/octet-stream', + name="some_file.bin", + type="application/octet-stream", ) - file_data = bytes(bytearray(range(0xff))) + file_data = bytes(bytearray(range(0xFF))) v.data = (file_data,) beh([file_data]) if _DictDocumentChild.text_based: - test_data = beh(v.data).decode('latin1') + test_data = beh(v.data).decode("latin1") else: test_data = beh(v.data) @@ -1089,15 +1157,22 @@ def some_call(p): assert p.name == v.name return p - d = get_object_as_dict(v, File, protocol=_DictDocumentChild, - ignore_wrappers=False) - ctx = _dry_me([SomeService], {"some_call": {'p': d}}) - s = b''.join(ctx.out_string) - d = self.dumps({"some_callResponse": {"some_callResult": { - 'name': v.name, - 'type': v.type, - 'data': test_data, - }}}) + d = get_object_as_dict( + v, File, protocol=_DictDocumentChild, ignore_wrappers=False + ) + ctx = _dry_me([SomeService], {"some_call": {"p": d}}) + s = b"".join(ctx.out_string) + d = self.dumps( + { + "some_callResponse": { + "some_callResult": { + "name": v.name, + "type": v.type, + "data": test_data, + } + } + } + ) print(self.loads(s)) print(self.loads(d)) @@ -1110,12 +1185,12 @@ class SomeService(Service): def some_call(p): print(p) print(type(p)) - assert isinstance(p, six.string_types) + assert isinstance(p, str) return Ignored("aaa", b=1, c=2) ctx = _dry_me([SomeService], {"some_call": ["some string"]}) - s = self.loads(b''.join(ctx.out_string)) + s = self.loads(b"".join(ctx.out_string)) d = {"some_callResponse": {}} assert s == d @@ -1126,7 +1201,7 @@ def some_call(p): pass try: - _dry_me([SomeService], {"some_call": []}, validator='soft') + _dry_me([SomeService], {"some_call": []}, validator="soft") except ValidationError: pass else: @@ -1139,8 +1214,7 @@ def some_call(p): pass try: - _dry_me([SomeService], {"some_call": [None]}, - validator='soft') + _dry_me([SomeService], {"some_call": [None]}, validator="soft") except ValidationError: pass @@ -1154,8 +1228,7 @@ def some_call(p): pass try: - _dry_me([SomeService], {"some_call": ["duduk"]}, - validator='soft') + _dry_me([SomeService], {"some_call": ["duduk"]}, validator="soft") except ValidationError as e: print(e) pass @@ -1170,8 +1243,7 @@ def some_call(p): pass try: - _dry_me([SomeService], {"some_call": [10]}, - validator='soft') + _dry_me([SomeService], {"some_call": [10]}, validator="soft") except ValidationError: pass @@ -1185,8 +1257,7 @@ def some_call(p): pass try: - _dry_me([SomeService], {"some_call": [-129]}, - validator='soft') + _dry_me([SomeService], {"some_call": [-129]}, validator="soft") except ValidationError: pass @@ -1200,7 +1271,7 @@ def some_call(p): pass try: - _dry_me([SomeService], {"some_call": [1.2]}, validator='soft') + _dry_me([SomeService], {"some_call": [1.2]}, validator="soft") except ValidationError: pass @@ -1219,22 +1290,24 @@ class SomeClass(ComplexModel): c = SomeInnerClass.customize(not_wrapped=True) class SomeService(Service): - @srpc(SomeClass.customize(not_wrapped=True), - _returns=SomeClass.customize(not_wrapped=True)) + @srpc( + SomeClass.customize(not_wrapped=True), + _returns=SomeClass.customize(not_wrapped=True), + ) def some_call(p): assert p.a == 1 - assert p.b == 's' + assert p.b == "s" assert p.c.d == date(2018, 11, 22) return p - inner = {"a": 1, "b": "s", "c": {"d": '2018-11-22'}} + inner = {"a": 1, "b": "s", "c": {"d": "2018-11-22"}} doc = {"some_call": [inner]} - ctx = _dry_me([SomeService], doc, validator='soft') + ctx = _dry_me([SomeService], doc, validator="soft") print(ctx.out_document) d = convert_dict({"some_callResponse": {"some_callResult": inner}}) - self.assertEquals(ctx.out_document[0], d) + self.assertEqual(ctx.out_document[0], d) def test_validation_freq_parent(self): class C(ComplexModel): @@ -1248,8 +1321,11 @@ def some_call(p): try: # must raise validation error for missing i - _dry_me([SomeService], {"some_call": {'p': {'C': {'s': 'a'}}}}, - validator='soft') + _dry_me( + [SomeService], + {"some_call": {"p": {"C": {"s": "a"}}}}, + validator="soft", + ) except ValidationError as e: logger.exception(e) pass @@ -1260,7 +1336,7 @@ def some_call(p): raise Exception("must raise ValidationError") # must not raise anything for missing p because C has min_occurs=0 - _dry_me([SomeService], {"some_call": {}}, validator='soft') + _dry_me([SomeService], {"some_call": {}}, validator="soft") def test_inheritance(self): class P(ComplexModel): @@ -1276,20 +1352,26 @@ class SomeService(Service): def some_call(ctx): result = C() result.identifier = uuid.UUID(int=0) - result.signature = 'yyyyyyyyyyy' - result.foo = 'zzzzzz' + result.signature = "yyyyyyyyyyy" + result.foo = "zzzzzz" result.bar = uuid.UUID(int=1) return result ctx = _dry_me([SomeService], {"some_call": []}) - s = self.loads(b''.join(ctx.out_string)) - d = {"some_callResponse": {"some_callResult": {"C": { - 'identifier': '00000000-0000-0000-0000-000000000000', - 'bar': '00000000-0000-0000-0000-000000000001', - 'foo': 'zzzzzz', - 'signature': 'yyyyyyyyyyy' - }}}} + s = self.loads(b"".join(ctx.out_string)) + d = { + "some_callResponse": { + "some_callResult": { + "C": { + "identifier": "00000000-0000-0000-0000-000000000000", + "bar": "00000000-0000-0000-0000-000000000001", + "foo": "zzzzzz", + "signature": "yyyyyyyyyyy", + } + } + } + } assert s == d @@ -1305,11 +1387,14 @@ def some_call(sc): assert sc.s2 == "s2" return C(s1="s1", s2="s2") - doc = [{"C": {"s1": "s1","s2": "s2"}}] + doc = [{"C": {"s1": "s1", "s2": "s2"}}] ctx = _dry_me([SomeService], {"some_call": doc}) - self.assertEquals(ctx.out_document[0], convert_dict( - {'some_callResponse': {'some_callResult': {'C': {'s2': 's2'}}}}) + self.assertEqual( + ctx.out_document[0], + convert_dict( + {"some_callResponse": {"some_callResult": {"C": {"s2": "s2"}}}} + ), ) def test_polymorphic_deserialization(self): @@ -1327,23 +1412,27 @@ class SomeService(Service): def typeof(ctx, p): return type(p).__name__ - ctx = _dry_me([SomeService], - {"typeof": [{'C':{'sig':'a', 'foo': 'f'}}]}, - polymorphic=True) + ctx = _dry_me( + [SomeService], + {"typeof": [{"C": {"sig": "a", "foo": "f"}}]}, + polymorphic=True, + ) - s = self.loads(b''.join(ctx.out_string)) - d = {"typeofResponse": {"typeofResult": 'C'}} + s = self.loads(b"".join(ctx.out_string)) + d = {"typeofResponse": {"typeofResult": "C"}} print(s) print(d) assert s == d - ctx = _dry_me([SomeService], - {"typeof": [{'D':{'sig':'b', 'bar': 5}}]}, - polymorphic=True) + ctx = _dry_me( + [SomeService], + {"typeof": [{"D": {"sig": "b", "bar": 5}}]}, + polymorphic=True, + ) - s = self.loads(b''.join(ctx.out_string)) - d = {"typeofResponse": {"typeofResult": 'D'}} + s = self.loads(b"".join(ctx.out_string)) + d = {"typeofResponse": {"typeofResult": "D"}} print(s) print(d) @@ -1352,8 +1441,8 @@ def typeof(ctx, p): def test_default(self): class SomeComplexModel(ComplexModel): _type_info = [ - ('a', Unicode), - ('b', Unicode(default='default')), + ("a", Unicode), + ("b", Unicode(default="default")), ] class SomeService(Service): @@ -1361,24 +1450,27 @@ class SomeService(Service): def some_method(s): pass - ctx = _dry_me([SomeService], - {"some_method": [{"s": {"a": "x", "b": None}}]}, - polymorphic=True) + ctx = _dry_me( + [SomeService], + {"some_method": [{"s": {"a": "x", "b": None}}]}, + polymorphic=True, + ) assert ctx.in_object.s.b == None assert ctx.in_error is None - ctx = _dry_me([SomeService], {"some_method": {"s": {"a": "x"}}}, - polymorphic=True) + ctx = _dry_me( + [SomeService], {"some_method": {"s": {"a": "x"}}}, polymorphic=True + ) - assert ctx.in_object.s.b == 'default' + assert ctx.in_object.s.b == "default" assert ctx.in_error is None def test_nillable_default(self): class SomeComplexModel(ComplexModel): _type_info = [ - ('a', Unicode), - ('b', Unicode(min_occurs=1, default='default', nillable=True)), + ("a", Unicode), + ("b", Unicode(min_occurs=1, default="default", nillable=True)), ] class SomeService(Service): @@ -1386,17 +1478,21 @@ class SomeService(Service): def some_method(s): pass - ctx = _dry_me([SomeService], - {"some_method": [{"s": {"a": "x", "b": None}}]}, - polymorphic=True, validator='soft') + ctx = _dry_me( + [SomeService], + {"some_method": [{"s": {"a": "x", "b": None}}]}, + polymorphic=True, + validator="soft", + ) assert ctx.in_object.s.b == None assert ctx.in_error is None - ctx = _dry_me([SomeService], {"some_method": {"s": {"a": "x"}}}, - polymorphic=True) + ctx = _dry_me( + [SomeService], {"some_method": {"s": {"a": "x"}}}, polymorphic=True + ) - assert ctx.in_object.s.b == 'default' + assert ctx.in_object.s.b == "default" assert ctx.in_error is None return Test diff --git a/spyne/test/protocol/test_cloth.py b/spyne/test/protocol/test_cloth.py index 965d852d2..c01e2a93b 100755 --- a/spyne/test/protocol/test_cloth.py +++ b/spyne/test/protocol/test_cloth.py @@ -20,18 +20,26 @@ from __future__ import print_function import logging + logger = logging.getLogger(__name__) import unittest +from io import BytesIO from lxml import etree, html from lxml.builder import E -from spyne import ComplexModel, XmlAttribute, Unicode, Array, Integer, \ - SelfReference, XmlData +from spyne import ( + Array, + ComplexModel, + Integer, + SelfReference, + Unicode, + XmlAttribute, + XmlData, +) from spyne.protocol.cloth import XmlCloth from spyne.test import FakeContext -from spyne.util.six import BytesIO class TestModelCloth(unittest.TestCase): @@ -79,8 +87,7 @@ def _run(self, inst, cls=None): cls = inst.__class__ with etree.xmlfile(self.stream) as parent: - XmlCloth().subserialize(self.ctx, cls, inst, parent, - name=cls.__name__) + XmlCloth().subserialize(self.ctx, cls, inst, parent, name=cls.__name__) elt = etree.fromstring(self.stream.getvalue()) @@ -88,7 +95,7 @@ def _run(self, inst, cls=None): return elt def test_simple(self): - v = 'punk.' + v = "punk." elt = self._run(v, Unicode) assert elt.text == v @@ -97,7 +104,7 @@ def test_complex_primitive(self): class SomeObject(ComplexModel): s = Unicode - v = 'punk.' + v = "punk." elt = self._run(SomeObject(s=v)) assert elt[0].text == v @@ -110,7 +117,7 @@ class B(A): s = Unicode i = 42 - s = 'punk.' + s = "punk." elt = self._run(B(i=i, s=s)) # order is important @@ -142,8 +149,9 @@ def _run(self, inst, spid=None, cloth=None): assert spid is None with etree.xmlfile(self.stream) as parent: - XmlCloth(cloth=cloth).set_identifier_prefix('spyne_') \ - .subserialize(self.ctx, cls, inst, parent) + XmlCloth(cloth=cloth).set_identifier_prefix("spyne_").subserialize( + self.ctx, cls, inst, parent + ) elt = etree.fromstring(self.stream.getvalue()) @@ -154,8 +162,8 @@ def test_simple_value(self): class SomeObject(ComplexModel): s = Unicode - v = 'punk.' - elt = self._run(SomeObject(s=v), spid='s') + v = "punk." + elt = self._run(SomeObject(s=v), spid="s") assert elt[0].text == v @@ -163,7 +171,7 @@ def test_simple_empty(self): class SomeObject(ComplexModel): s = Unicode - elt = self._run(SomeObject(), spid='s') + elt = self._run(SomeObject(), spid="s") assert len(elt) == 0 @@ -172,7 +180,7 @@ def _test_simple_empty_nonoptional(self): class SomeObject(ComplexModel): s = Unicode(min_occurs=1) - elt = self._run(SomeObject(), spid='s') + elt = self._run(SomeObject(), spid="s") assert elt[0].text is None @@ -193,9 +201,9 @@ class SomeObject(ComplexModel): cloth = etree.fromstring('') - elt = self._run(SomeObject(d='data'), cloth=cloth) + elt = self._run(SomeObject(d="data"), cloth=cloth) - assert elt.text == 'data' + assert elt.text == "data" def test_xml_data_attr(self): class SomeObject(ComplexModel): @@ -203,9 +211,9 @@ class SomeObject(ComplexModel): cloth = etree.fromstring('') - elt = self._run(SomeObject(d='data'), cloth=cloth) + elt = self._run(SomeObject(d="data"), cloth=cloth) - assert elt.text == 'data' + assert elt.text == "data" def test_xml_data_attr_undesignated(self): class SomeObject(ComplexModel): @@ -213,12 +221,12 @@ class SomeObject(ComplexModel): cloth = etree.fromstring('') - elt = self._run(SomeObject(d='data'), cloth=cloth) + elt = self._run(SomeObject(d="data"), cloth=cloth) - assert elt.text == 'data' + assert elt.text == "data" def test_simple_value_xmlattribute(self): - v = 'punk.' + v = "punk." class SomeObject(ComplexModel): s = XmlAttribute(Unicode(min_occurs=1)) @@ -226,42 +234,42 @@ class SomeObject(ComplexModel): cloth = etree.fromstring("""""") elt = self._run(SomeObject(s=v), cloth=cloth) - assert elt.attrib['s'] == v + assert elt.attrib["s"] == v def test_simple_value_xmlattribute_subname(self): - v = 'punk.' + v = "punk." class SomeObject(ComplexModel): - s = XmlAttribute(Unicode(min_occurs=1, sub_name='foo')) + s = XmlAttribute(Unicode(min_occurs=1, sub_name="foo")) cloth = etree.fromstring("""""") elt = self._run(SomeObject(s=v), cloth=cloth) - assert elt.attrib['foo'] == v + assert elt.attrib["foo"] == v def test_simple_value_xmlattribute_non_immediate(self): - v = 'punk.' + v = "punk." class SomeObject(ComplexModel): - s = XmlAttribute(Unicode(min_occurs=1, sub_name='foo')) + s = XmlAttribute(Unicode(min_occurs=1, sub_name="foo")) cloth = etree.fromstring("""""") elt = self._run(SomeObject(s=v), cloth=cloth) - assert elt.attrib['foo'] == v - assert elt[0].attrib['foo'] == v + assert elt.attrib["foo"] == v + assert elt[0].attrib["foo"] == v def test_simple_value_xmlattribute_non_immediate_non_designated(self): - v = 'punk.' + v = "punk." class SomeObject(ComplexModel): - s = Unicode(min_occurs=1, sub_name='foo') + s = Unicode(min_occurs=1, sub_name="foo") cloth = etree.fromstring("""""") elt = self._run(SomeObject(s=v), cloth=cloth) - assert not 'foo' in elt.attrib - assert elt[0].attrib['foo'] == v + assert not "foo" in elt.attrib + assert elt[0].attrib["foo"] == v def test_non_tagbag(self): cloth = E.a( @@ -274,7 +282,7 @@ def test_non_tagbag(self): ), spyne_id="i", ), - spyne_tagbag='', + spyne_tagbag="", ) class C2(ComplexModel): @@ -285,9 +293,9 @@ class C1(ComplexModel): c = C2 elt = self._run(C1(i=1, c=C2(i=2)), cloth=cloth) - assert elt.xpath('//b/text()') == ['1'] + assert elt.xpath("//b/text()") == ["1"] # no order guarantee is given - assert set(elt.xpath('//d/text()')) == set(['1', '2']) + assert set(elt.xpath("//d/text()")) == set(["1", "2"]) def test_array(self): v = range(3) @@ -304,7 +312,7 @@ class SomeObject(ComplexModel): elt = self._run(SomeObject(s=v), cloth=cloth) - assert elt.xpath('//c/text()') == [str(i) for i in v] + assert elt.xpath("//c/text()") == [str(i) for i in v] def test_array_empty(self): class SomeObject(ComplexModel): @@ -315,7 +323,7 @@ class SomeObject(ComplexModel): elt = self._run(SomeObject(), cloth=cloth) - assert elt.xpath('//c') == [] + assert elt.xpath("//c") == [] # FIXME: just fix it def _test_array_empty_nonoptional(self): @@ -327,14 +335,14 @@ class SomeObject(ComplexModel): elt = self._run(SomeObject(), cloth=cloth) - assert elt.xpath('//c') == [cloth[0][0]] + assert elt.xpath("//c") == [cloth[0][0]] def test_simple_two_tags(self): class SomeObject(ComplexModel): s = Unicode i = Integer - v = SomeObject(s='s', i=5) + v = SomeObject(s="s", i=5) cloth = E.a( E.b1(), @@ -352,22 +360,22 @@ class SomeObject(ComplexModel): elt = self._run(v, cloth=cloth) print(etree.tostring(elt, pretty_print=True)) - assert elt[0].tag == 'b1' - assert elt[1].tag == 'b2' - assert elt[1][0].tag == 'c1' - assert elt[1][0].text == 's' - assert elt[1][1].tag == 'c2' - assert elt[2].tag == 'e' - assert elt[2][0].tag == 'g1' - assert elt[2][1].tag == 'g2' - assert elt[2][1].text == '5' - assert elt[2][2].tag == 'g3' + assert elt[0].tag == "b1" + assert elt[1].tag == "b2" + assert elt[1][0].tag == "c1" + assert elt[1][0].text == "s" + assert elt[1][1].tag == "c2" + assert elt[2].tag == "e" + assert elt[2][0].tag == "g1" + assert elt[2][1].tag == "g2" + assert elt[2][1].text == "5" + assert elt[2][2].tag == "g3" def test_sibling_order(self): class SomeObject(ComplexModel): s = Unicode - v = SomeObject(s='s') + v = SomeObject(s="s") cloth = E.a( E.b1(), @@ -382,20 +390,20 @@ class SomeObject(ComplexModel): elt = self._run(v, cloth=cloth) print(etree.tostring(elt, pretty_print=True)) - assert elt[0].tag == 'b1' - assert elt[1].tag == 'b2' - assert elt[1][0].tag == 'c0' - assert elt[1][1].tag == 'c1' - assert elt[1][2].tag == 'c2' - assert elt[1][2].text == 's' - assert elt[1][3].tag == 'c3' - assert elt[1][4].tag == 'c4' + assert elt[0].tag == "b1" + assert elt[1].tag == "b2" + assert elt[1][0].tag == "c0" + assert elt[1][1].tag == "c1" + assert elt[1][2].tag == "c2" + assert elt[1][2].text == "s" + assert elt[1][3].tag == "c3" + assert elt[1][4].tag == "c4" def test_parent_text(self): class SomeObject(ComplexModel): s = Unicode - v = SomeObject(s='s') + v = SomeObject(s="s") cloth = E.a( "text 0", @@ -406,17 +414,17 @@ class SomeObject(ComplexModel): elt = self._run(v, cloth=cloth) print(etree.tostring(elt, pretty_print=True)) - assert elt.tag == 'a' - assert elt.text == 'text 0' + assert elt.tag == "a" + assert elt.text == "text 0" - assert elt[0].tag == 'b1' - assert elt[0].text == 's' + assert elt[0].tag == "b1" + assert elt[0].text == "s" def test_anc_text(self): class SomeObject(ComplexModel): s = Unicode - v = SomeObject(s='s') + v = SomeObject(s="s") cloth = E.a( E.b1( @@ -429,16 +437,16 @@ class SomeObject(ComplexModel): elt = self._run(v, cloth=cloth) print(etree.tostring(elt, pretty_print=True)) - assert elt[0].tag == 'b1' - assert elt[0].text == 'text 1' - assert elt[0][0].tag == 'c1' - assert elt[0][0].text == 's' + assert elt[0].tag == "b1" + assert elt[0].text == "text 1" + assert elt[0][0].tag == "c1" + assert elt[0][0].text == "s" def test_prevsibl_tail(self): class SomeObject(ComplexModel): s = Unicode - v = SomeObject(s='s') + v = SomeObject(s="s") cloth = E.a( E.b1( @@ -452,16 +460,16 @@ class SomeObject(ComplexModel): elt = self._run(v, cloth=cloth) print(etree.tostring(elt, pretty_print=True)) - assert elt[0].tag == 'b1' - assert elt[0][0].tag == 'c1' - assert elt[0][0].tail == 'text 2' - assert elt[0][1].text == 's' + assert elt[0].tag == "b1" + assert elt[0][0].tag == "c1" + assert elt[0][0].tail == "text 2" + assert elt[0][1].text == "s" def test_sibling_tail_close(self): class SomeObject(ComplexModel): s = Unicode - v = SomeObject(s='s') + v = SomeObject(s="s") cloth = E.a( E.b0(spyne_id="s"), @@ -472,16 +480,16 @@ class SomeObject(ComplexModel): elt = self._run(v, cloth=cloth) print(etree.tostring(elt, pretty_print=True)) - assert elt[0].tag == 'b0' - assert elt[0].text == 's' - assert elt[0].tail == 'text 3' + assert elt[0].tag == "b0" + assert elt[0].text == "s" + assert elt[0].tail == "text 3" def test_sibling_tail_close_sibling(self): class SomeObject(ComplexModel): s = Unicode i = Integer - v = SomeObject(s='s', i=5) + v = SomeObject(s="s", i=5) cloth = E.a( E.b0(spyne_id="s"), @@ -493,16 +501,16 @@ class SomeObject(ComplexModel): elt = self._run(v, cloth=cloth) print(etree.tostring(elt, pretty_print=True)) - assert elt[0].tag == 'b0' - assert elt[0].text == 's' - assert elt[0].tail == 'text 3' + assert elt[0].tag == "b0" + assert elt[0].text == "s" + assert elt[0].tail == "text 3" def test_sibling_tail_close_anc(self): class SomeObject(ComplexModel): s = Unicode i = Integer - v = SomeObject(s='s', i=5) + v = SomeObject(s="s", i=5) cloth = E.a( E.b0(), @@ -517,16 +525,16 @@ class SomeObject(ComplexModel): E.b2( E.c1(spyne_id="i"), "text 4", - ) + ), ) print(etree.tostring(cloth, pretty_print=True)) elt = self._run(v, cloth=cloth) print(etree.tostring(elt, pretty_print=True)) - assert elt.xpath('/a/b1/c0')[0].tail == 'text 1' - assert elt.xpath('/a/b1/c1')[0].tail == 'text 2' - assert elt.xpath('/a/b2/c1')[0].tail == 'text 4' + assert elt.xpath("/a/b1/c0")[0].tail == "text 1" + assert elt.xpath("/a/b1/c1")[0].tail == "text 2" + assert elt.xpath("/a/b2/c1")[0].tail == "text 4" def test_nested_conflicts(self): class SomeObject(ComplexModel): @@ -534,7 +542,7 @@ class SomeObject(ComplexModel): i = Integer c = SelfReference - v = SomeObject(s='x', i=1, c=SomeObject(s='y', i=2)) + v = SomeObject(s="x", i=1, c=SomeObject(s="y", i=2)) cloth = E.a( E.b0(), @@ -553,18 +561,18 @@ class SomeObject(ComplexModel): E.b2( E.c2(spyne_id="i"), "text 4", - ) + ), ) print(etree.tostring(cloth, pretty_print=True)) elt = self._run(v, cloth=cloth) print(etree.tostring(elt, pretty_print=True)) - assert elt.xpath('/a/b1/c0')[0].text == str(v.s) - assert elt.xpath('/a/b1/c1/d0')[0].text == str(v.c.s) - assert elt.xpath('/a/b1/c1/d1')[0].text == str(v.c.i) - assert elt.xpath('/a/b2/c2')[0].text == str(v.i) + assert elt.xpath("/a/b1/c0")[0].text == str(v.s) + assert elt.xpath("/a/b1/c1/d0")[0].text == str(v.c.s) + assert elt.xpath("/a/b1/c1/d1")[0].text == str(v.c.i) + assert elt.xpath("/a/b2/c2")[0].text == str(v.i) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/protocol/test_html_microformat.py b/spyne/test/protocol/test_html_microformat.py index 8a0df4916..8a26a8516 100755 --- a/spyne/test/protocol/test_html_microformat.py +++ b/spyne/test/protocol/test_html_microformat.py @@ -18,6 +18,7 @@ # import logging + logging.basicConfig(level=logging.DEBUG) import unittest @@ -26,16 +27,13 @@ from spyne.application import Application from spyne.decorator import srpc -from spyne.model.primitive import Integer -from spyne.model.primitive import String -from spyne.model.complex import Array -from spyne.model.complex import ComplexModel -from spyne.protocol.http import HttpRpc +from spyne.model.complex import Array, ComplexModel +from spyne.model.primitive import Integer, String from spyne.protocol.html import HtmlMicroFormat +from spyne.protocol.http import HttpRpc +from spyne.server.wsgi import WsgiApplication, WsgiMethodContext from spyne.service import Service -from spyne.server.wsgi import WsgiMethodContext -from spyne.server.wsgi import WsgiApplication -from spyne.util.test import show, call_wsgi_app_kwargs +from spyne.util.test import call_wsgi_app_kwargs, show class TestHtmlMicroFormat(unittest.TestCase): @@ -45,56 +43,73 @@ class SomeService(Service): def some_call(s): return s - app = Application([SomeService], 'tns', - in_protocol=HttpRpc(hier_delim='_'), - out_protocol=HtmlMicroFormat(doctype=None)) + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(hier_delim="_"), + out_protocol=HtmlMicroFormat(doctype=None), + ) server = WsgiApplication(app) - initial_ctx = WsgiMethodContext(server, { - 'QUERY_STRING': 's=s', - 'PATH_INFO': '/some_call', - 'REQUEST_METHOD': 'GET', - 'SERVER_NAME': 'localhost', - }, 'some-content-type') - - ctx, = server.generate_contexts(initial_ctx) + initial_ctx = WsgiMethodContext( + server, + { + "QUERY_STRING": "s=s", + "PATH_INFO": "/some_call", + "REQUEST_METHOD": "GET", + "SERVER_NAME": "localhost", + }, + "some-content-type", + ) + + (ctx,) = server.generate_contexts(initial_ctx) assert ctx.in_error is None server.get_in_object(ctx) server.get_out_object(ctx) server.get_out_string(ctx) - assert b''.join(ctx.out_string) == b'
' \ - b'
s
' + assert ( + b"".join(ctx.out_string) == b'
' + b'
s
' + ) def test_multiple_return(self): class SomeService(Service): @srpc(_returns=[Integer, String]) def some_call(): - return 1, 's' - - app = Application([SomeService], 'tns', - in_protocol=HttpRpc(hier_delim='_'), - out_protocol=HtmlMicroFormat(doctype=None)) + return 1, "s" + + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(hier_delim="_"), + out_protocol=HtmlMicroFormat(doctype=None), + ) server = WsgiApplication(app) - initial_ctx = WsgiMethodContext(server, { - 'QUERY_STRING': '', - 'PATH_INFO': '/some_call', - 'REQUEST_METHOD': 'GET', - 'SERVER_NAME': 'localhost', - }, 'some-content-type') - - ctx, = server.generate_contexts(initial_ctx) + initial_ctx = WsgiMethodContext( + server, + { + "QUERY_STRING": "", + "PATH_INFO": "/some_call", + "REQUEST_METHOD": "GET", + "SERVER_NAME": "localhost", + }, + "some-content-type", + ) + + (ctx,) = server.generate_contexts(initial_ctx) server.get_in_object(ctx) server.get_out_object(ctx) server.get_out_string(ctx) - assert b''.join(ctx.out_string) == b'
' \ - b'
1
' \ - b'
s
' - + assert ( + b"".join(ctx.out_string) == b'
' + b'
1
' + b'
s
' + ) def test_complex(self): class CM(ComplexModel): @@ -109,21 +124,28 @@ class CCM(ComplexModel): class SomeService(Service): @srpc(CCM, _returns=CCM) def some_call(ccm): - return CCM(c=ccm.c,i=ccm.i, s=ccm.s) - - app = Application([SomeService], 'tns', - in_protocol=HttpRpc(hier_delim='_'), - out_protocol=HtmlMicroFormat(doctype=None)) + return CCM(c=ccm.c, i=ccm.i, s=ccm.s) + + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(hier_delim="_"), + out_protocol=HtmlMicroFormat(doctype=None), + ) server = WsgiApplication(app) - initial_ctx = WsgiMethodContext(server, { - 'QUERY_STRING': 'ccm_c_s=abc&ccm_c_i=123&ccm_i=456&ccm_s=def', - 'PATH_INFO': '/some_call', - 'REQUEST_METHOD': 'GET', - 'SERVER_NAME': 'localhost', - }, 'some-content-type') - - ctx, = server.generate_contexts(initial_ctx) + initial_ctx = WsgiMethodContext( + server, + { + "QUERY_STRING": "ccm_c_s=abc&ccm_c_i=123&ccm_i=456&ccm_s=def", + "PATH_INFO": "/some_call", + "REQUEST_METHOD": "GET", + "SERVER_NAME": "localhost", + }, + "some-content-type", + ) + + (ctx,) = server.generate_contexts(initial_ctx) server.get_in_object(ctx) server.get_out_object(ctx) server.get_out_string(ctx) @@ -143,67 +165,78 @@ def some_call(ccm): # # - elt = html.fromstring(b''.join(ctx.out_string)) + elt = html.fromstring(b"".join(ctx.out_string)) print(html.tostring(elt, pretty_print=True)) - resp = elt.find_class('some_callResponse') + resp = elt.find_class("some_callResponse") assert len(resp) == 1 - res = resp[0].find_class('some_callResult') + res = resp[0].find_class("some_callResult") assert len(res) == 1 i = res[0].findall('div[@class="i"]') assert len(i) == 1 - assert i[0].text == '456' + assert i[0].text == "456" c = res[0].findall('div[@class="c"]') assert len(c) == 1 c_i = c[0].findall('div[@class="i"]') assert len(c_i) == 1 - assert c_i[0].text == '123' + assert c_i[0].text == "123" c_s = c[0].findall('div[@class="s"]') assert len(c_s) == 1 - assert c_s[0].text == 'abc' + assert c_s[0].text == "abc" s = res[0].findall('div[@class="s"]') assert len(s) == 1 - assert s[0].text == 'def' + assert s[0].text == "def" def test_multiple(self): class SomeService(Service): - @srpc(String(max_occurs='unbounded'), _returns=String) + @srpc(String(max_occurs="unbounded"), _returns=String) def some_call(s): print(s) - return '\n'.join(s) - - app = Application([SomeService], 'tns', - in_protocol=HttpRpc(hier_delim='_'), - out_protocol=HtmlMicroFormat(doctype=None)) + return "\n".join(s) + + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(hier_delim="_"), + out_protocol=HtmlMicroFormat(doctype=None), + ) server = WsgiApplication(app) - initial_ctx = WsgiMethodContext(server, { - 'QUERY_STRING': 's=1&s=2', - 'PATH_INFO': '/some_call', - 'REQUEST_METHOD': 'GET', - 'SERVER_NAME': 'localhost', - }, 'some-content-type') - - ctx, = server.generate_contexts(initial_ctx) + initial_ctx = WsgiMethodContext( + server, + { + "QUERY_STRING": "s=1&s=2", + "PATH_INFO": "/some_call", + "REQUEST_METHOD": "GET", + "SERVER_NAME": "localhost", + }, + "some-content-type", + ) + + (ctx,) = server.generate_contexts(initial_ctx) server.get_in_object(ctx) server.get_out_object(ctx) server.get_out_string(ctx) - assert b''.join(ctx.out_string) == (b'
' - b'
1\n2
') + assert b"".join(ctx.out_string) == ( + b'
' + b'
1\n2
' + ) - ctx, = server.generate_contexts(initial_ctx) + (ctx,) = server.generate_contexts(initial_ctx) server.get_in_object(ctx) server.get_out_object(ctx) server.get_out_string(ctx) - assert b''.join(ctx.out_string) == b'
' \ - b'
1\n2
' + assert ( + b"".join(ctx.out_string) == b'
' + b'
1\n2
' + ) def test_before_first_root(self): class CM(ComplexModel): @@ -218,21 +251,23 @@ class CCM(ComplexModel): class SomeService(Service): @srpc(CCM, _returns=Array(CCM)) def some_call(ccm): - return [CCM(c=ccm.c,i=ccm.i, s=ccm.s)] * 2 + return [CCM(c=ccm.c, i=ccm.i, s=ccm.s)] * 2 cb_called = [False] + def _cb(ctx, cls, inst, parent, name, **kwargs): assert not cb_called[0] cb_called[0] = True - app = Application([SomeService], 'tns', - in_protocol=HttpRpc(hier_delim='_'), - out_protocol=HtmlMicroFormat( - doctype=None, before_first_root=_cb)) + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(hier_delim="_"), + out_protocol=HtmlMicroFormat(doctype=None, before_first_root=_cb), + ) server = WsgiApplication(app) - call_wsgi_app_kwargs(server, - ccm_c_s='abc', ccm_c_i=123, ccm_i=456, ccm_s='def') + call_wsgi_app_kwargs(server, ccm_c_s="abc", ccm_c_i=123, ccm_i=456, ccm_s="def") assert cb_called[0] @@ -249,15 +284,19 @@ class CCM(ComplexModel): class SomeService(Service): @srpc(CCM, _returns=Array(CCM)) def some_call(ccm): - return [CCM(c=ccm.c,i=ccm.i, s=ccm.s)] * 2 - - app = Application([SomeService], 'tns', - in_protocol=HttpRpc(hier_delim='_'), - out_protocol=HtmlMicroFormat(doctype=None)) + return [CCM(c=ccm.c, i=ccm.i, s=ccm.s)] * 2 + + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(hier_delim="_"), + out_protocol=HtmlMicroFormat(doctype=None), + ) server = WsgiApplication(app) - out_string = call_wsgi_app_kwargs(server, - ccm_c_s='abc', ccm_c_i=123, ccm_i=456, ccm_s='def') + out_string = call_wsgi_app_kwargs( + server, ccm_c_s="abc", ccm_c_i=123, ccm_i=456, ccm_s="def" + ) # # Here's what this is supposed to return: @@ -286,9 +325,9 @@ def some_call(ccm): elt = html.fromstring(out_string) show(elt, "TestHtmlMicroFormat.test_complex_array") - resp = elt.find_class('some_callResponse') + resp = elt.find_class("some_callResponse") assert len(resp) == 1 - res = resp[0].find_class('some_callResult') + res = resp[0].find_class("some_callResult") assert len(res) == 1 assert len(res[0].find_class("CCM")) == 2 @@ -296,5 +335,6 @@ def some_call(ccm): # We don't need to test the rest as the test_complex test takes care of # that -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/protocol/test_html_table.py b/spyne/test/protocol/test_html_table.py index d979356e3..9f15bd425 100755 --- a/spyne/test/protocol/test_html_table.py +++ b/spyne/test/protocol/test_html_table.py @@ -18,6 +18,7 @@ # import logging + logging.basicConfig(level=logging.DEBUG) import unittest @@ -26,30 +27,27 @@ from spyne.application import Application from spyne.decorator import srpc -from spyne.model.primitive import Integer, Unicode -from spyne.model.primitive import String -from spyne.model.primitive import AnyUri -from spyne.model.complex import Array -from spyne.model.complex import ComplexModel -from spyne.protocol.http import HttpRpc +from spyne.model.complex import Array, ComplexModel +from spyne.model.primitive import AnyUri, Integer, String, Unicode from spyne.protocol.html.table import HtmlColumnTable, HtmlRowTable -from spyne.service import Service +from spyne.protocol.http import HttpRpc from spyne.server.wsgi import WsgiApplication -from spyne.util.test import show, call_wsgi_app_kwargs, call_wsgi_app +from spyne.service import Service +from spyne.util.test import call_wsgi_app, call_wsgi_app_kwargs, show class CM(ComplexModel): _type_info = [ - ('i', Integer), - ('s', String), + ("i", Integer), + ("s", String), ] class CCM(ComplexModel): _type_info = [ - ('c', CM), - ('i', Integer), - ('s', String), + ("c", CM), + ("i", Integer), + ("s", String), ] @@ -60,72 +58,83 @@ class SomeService(Service): def some_call(ccm): return [ccm] * 5 - app = Application([SomeService], 'tns', in_protocol=HttpRpc(), - out_protocol=HtmlColumnTable(field_type_name_attr=None)) + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(), + out_protocol=HtmlColumnTable(field_type_name_attr=None), + ) server = WsgiApplication(app) - out_string = call_wsgi_app_kwargs(server, - ccm_i='456', - ccm_s='def', - ccm_c_i='123', - ccm_c_s='abc', - ) + out_string = call_wsgi_app_kwargs( + server, + ccm_i="456", + ccm_s="def", + ccm_c_i="123", + ccm_c_s="abc", + ) elt = etree.fromstring(out_string) - show(elt, 'TestHtmlColumnTable.test_complex_array') + show(elt, "TestHtmlColumnTable.test_complex_array") elt = html.fromstring(out_string) - row, = elt[0] # thead + (row,) = elt[0] # thead cell = row.findall('th[@class="i"]') assert len(cell) == 1 - assert cell[0].text == 'i' + assert cell[0].text == "i" cell = row.findall('th[@class="s"]') assert len(cell) == 1 - assert cell[0].text == 's' + assert cell[0].text == "s" - for row in elt[1]: # tbody + for row in elt[1]: # tbody cell = row.xpath('td[@class="i"]') assert len(cell) == 1 - assert cell[0].text == '456' + assert cell[0].text == "456" cell = row.xpath('td[@class="c"]//td[@class="i"]') assert len(cell) == 1 - assert cell[0].text == '123' + assert cell[0].text == "123" cell = row.xpath('td[@class="c"]//td[@class="s"]') assert len(cell) == 1 - assert cell[0].text == 'abc' + assert cell[0].text == "abc" cell = row.xpath('td[@class="s"]') assert len(cell) == 1 - assert cell[0].text == 'def' + assert cell[0].text == "def" def test_string_array(self): class SomeService(Service): - @srpc(String(max_occurs='unbounded'), _returns=Array(String)) + @srpc(String(max_occurs="unbounded"), _returns=Array(String)) def some_call(s): return s - app = Application([SomeService], 'tns', in_protocol=HttpRpc(), - out_protocol=HtmlColumnTable( - field_name_attr=None, field_type_name_attr=None)) + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(), + out_protocol=HtmlColumnTable( + field_name_attr=None, field_type_name_attr=None + ), + ) server = WsgiApplication(app) - out_string = call_wsgi_app(server, body_pairs=(('s', '1'), ('s', '2'))) + out_string = call_wsgi_app(server, body_pairs=(("s", "1"), ("s", "2"))) elt = etree.fromstring(out_string) show(elt, "TestHtmlColumnTable.test_string_array") - assert out_string.decode('utf8') == \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '
some_callResponse
1
2
' + assert ( + out_string.decode("utf8") == '' + "" + "" + "" + "" + "" + "" + "" + "
some_callResponse
1
2
" + ) def test_anyuri_string(self): _link = "http://arskom.com.tr/" @@ -138,16 +147,20 @@ class SomeService(Service): def some_call(): return [C(c=_link)] - app = Application([SomeService], 'tns', in_protocol=HttpRpc(), - out_protocol=HtmlColumnTable(field_type_name_attr=None)) + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(), + out_protocol=HtmlColumnTable(field_type_name_attr=None), + ) server = WsgiApplication(app) out_string = call_wsgi_app_kwargs(server) elt = html.fromstring(out_string) show(elt, "TestHtmlColumnTable.test_anyuri_string") - assert elt.xpath('//td[@class="c"]')[0][0].tag == 'a' - assert elt.xpath('//td[@class="c"]')[0][0].attrib['href'] == _link + assert elt.xpath('//td[@class="c"]')[0][0].tag == "a" + assert elt.xpath('//td[@class="c"]')[0][0].attrib["href"] == _link def test_anyuri_uri_value(self): _link = "http://arskom.com.tr/" @@ -161,52 +174,55 @@ class SomeService(Service): def some_call(): return [C(c=AnyUri.Value(_link, text=_text))] - app = Application([SomeService], 'tns', in_protocol=HttpRpc(), - out_protocol=HtmlColumnTable(field_type_name_attr=None)) + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(), + out_protocol=HtmlColumnTable(field_type_name_attr=None), + ) server = WsgiApplication(app) out_string = call_wsgi_app_kwargs(server) elt = html.fromstring(out_string) print(html.tostring(elt, pretty_print=True)) - assert elt.xpath('//td[@class="c"]')[0][0].tag == 'a' + assert elt.xpath('//td[@class="c"]')[0][0].tag == "a" assert elt.xpath('//td[@class="c"]')[0][0].text == _text - assert elt.xpath('//td[@class="c"]')[0][0].attrib['href'] == _link + assert elt.xpath('//td[@class="c"]')[0][0].attrib["href"] == _link def test_row_subprot(self): + from urllib.parse import urlencode + from lxml.html.builder import E - from spyne.protocol.html import HtmlBase - from spyne.util.six.moves.urllib.parse import urlencode - from spyne.protocol.html import HtmlMicroFormat + + from spyne.protocol.html import HtmlBase, HtmlMicroFormat class SearchProtocol(HtmlBase): def to_parent(self, ctx, cls, inst, parent, name, **kwargs): - s = self.to_unicode(cls._type_info['query'], inst.query) + s = self.to_unicode(cls._type_info["query"], inst.query) q = urlencode({"q": s}) - parent.write(E.a("Search %s" % inst.query, - href="{}?{}".format(inst.uri, q))) + parent.write( + E.a("Search %s" % inst.query, href="{}?{}".format(inst.uri, q)) + ) def column_table_gen_header(self, ctx, cls, parent, name): - parent.write(E.thead(E.th("Search", - **{'class': 'search-link'}))) + parent.write(E.thead(E.th("Search", **{"class": "search-link"}))) - def column_table_before_row(self, ctx, cls, inst, parent, name,**_): - ctxstack = getattr(ctx.protocol[self], - 'array_subprot_ctxstack', []) + def column_table_before_row(self, ctx, cls, inst, parent, name, **_): + ctxstack = getattr(ctx.protocol[self], "array_subprot_ctxstack", []) - tr_ctx = parent.element('tr') + tr_ctx = parent.element("tr") tr_ctx.__enter__() ctxstack.append(tr_ctx) - td_ctx = parent.element('td', **{'class': "search-link"}) + td_ctx = parent.element("td", **{"class": "search-link"}) td_ctx.__enter__() ctxstack.append(td_ctx) ctx.protocol[self].array_subprot_ctxstack = ctxstack - def column_table_after_row(self, ctx, cls, inst, parent, name, - **kwargs): + def column_table_after_row(self, ctx, cls, inst, parent, name, **kwargs): ctxstack = ctx.protocol[self].array_subprot_ctxstack for elt_ctx in reversed(ctxstack): @@ -227,12 +243,13 @@ class SomeService(Service): @srpc(_returns=SearchTable) def some_call(): return [ - Search(query='Arskom', uri='https://www.google.com/search'), - Search(query='Spyne', uri='https://www.bing.com/search'), + Search(query="Arskom", uri="https://www.google.com/search"), + Search(query="Spyne", uri="https://www.bing.com/search"), ] - app = Application([SomeService], 'tns', in_protocol=HttpRpc(), - out_protocol=HtmlMicroFormat()) + app = Application( + [SomeService], "tns", in_protocol=HttpRpc(), out_protocol=HtmlMicroFormat() + ) server = WsgiApplication(app) out_string = call_wsgi_app_kwargs(server) @@ -240,12 +257,14 @@ def some_call(): elt = html.fromstring(out_string) print(html.tostring(elt, pretty_print=True)) - assert elt.xpath('//td[@class="search-link"]/a/text()') == \ - ['Search Arskom', 'Search Spyne'] + assert elt.xpath('//td[@class="search-link"]/a/text()') == [ + "Search Arskom", + "Search Spyne", + ] assert elt.xpath('//td[@class="search-link"]/a/@href') == [ - 'https://www.google.com/search?q=Arskom', - 'https://www.bing.com/search?q=Spyne', + "https://www.google.com/search?q=Arskom", + "https://www.bing.com/search?q=Spyne", ] assert elt.xpath('//th[@class="search-link"]/text()') == ["Search"] @@ -263,16 +282,20 @@ class SomeService(Service): def some_call(): return C(c=_link) - app = Application([SomeService], 'tns', in_protocol=HttpRpc(), - out_protocol=HtmlRowTable(field_type_name_attr=None)) + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(), + out_protocol=HtmlRowTable(field_type_name_attr=None), + ) server = WsgiApplication(app) out_string = call_wsgi_app_kwargs(server) elt = html.fromstring(out_string) print(html.tostring(elt, pretty_print=True)) - assert elt.xpath('//td[@class="c"]')[0][0].tag == 'a' - assert elt.xpath('//td[@class="c"]')[0][0].attrib['href'] == _link + assert elt.xpath('//td[@class="c"]')[0][0].tag == "a" + assert elt.xpath('//td[@class="c"]')[0][0].attrib["href"] == _link def test_anyuri_uri_value(self): _link = "http://arskom.com.tr/" @@ -286,17 +309,21 @@ class SomeService(Service): def some_call(): return C(c=AnyUri.Value(_link, text=_text)) - app = Application([SomeService], 'tns', in_protocol=HttpRpc(), - out_protocol=HtmlRowTable(field_type_name_attr=None)) + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(), + out_protocol=HtmlRowTable(field_type_name_attr=None), + ) server = WsgiApplication(app) out_string = call_wsgi_app_kwargs(server) elt = html.fromstring(out_string) print(html.tostring(elt, pretty_print=True)) - assert elt.xpath('//td[@class="c"]')[0][0].tag == 'a' + assert elt.xpath('//td[@class="c"]')[0][0].tag == "a" assert elt.xpath('//td[@class="c"]')[0][0].text == _text - assert elt.xpath('//td[@class="c"]')[0][0].attrib['href'] == _link + assert elt.xpath('//td[@class="c"]')[0][0].attrib["href"] == _link def test_complex(self): class SomeService(Service): @@ -304,14 +331,18 @@ class SomeService(Service): def some_call(ccm): return ccm - app = Application([SomeService], 'tns', - in_protocol=HttpRpc(hier_delim="_"), - out_protocol=HtmlRowTable(field_type_name_attr=None)) + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(hier_delim="_"), + out_protocol=HtmlRowTable(field_type_name_attr=None), + ) server = WsgiApplication(app) - out_string = call_wsgi_app_kwargs(server, 'some_call', - ccm_c_s='abc', ccm_c_i='123', ccm_i='456', ccm_s='def') + out_string = call_wsgi_app_kwargs( + server, "some_call", ccm_c_s="abc", ccm_c_i="123", ccm_i="456", ccm_s="def" + ) elt = html.fromstring(out_string) show(elt, "TestHtmlRowTable.test_complex") @@ -350,159 +381,175 @@ def some_call(ccm): """ print(html.tostring(elt, pretty_print=True)) - resp = elt.find_class('CCM') + resp = elt.find_class("CCM") assert len(resp) == 1 - assert elt.xpath('tbody/tr/th[@class="i"]/text()')[0] == 'i' - assert elt.xpath('tbody/tr/td[@class="i"]/text()')[0] == '456' + assert elt.xpath('tbody/tr/th[@class="i"]/text()')[0] == "i" + assert elt.xpath('tbody/tr/td[@class="i"]/text()')[0] == "456" - assert elt.xpath('tbody/tr/td[@class="c"]//th[@class="i"]/text()')[0] == 'i' - assert elt.xpath('tbody/tr/td[@class="c"]//td[@class="i"]/text()')[0] == '123' + assert elt.xpath('tbody/tr/td[@class="c"]//th[@class="i"]/text()')[0] == "i" + assert elt.xpath('tbody/tr/td[@class="c"]//td[@class="i"]/text()')[0] == "123" - assert elt.xpath('tbody/tr/td[@class="c"]//th[@class="s"]/text()')[0] == 's' - assert elt.xpath('tbody/tr/td[@class="c"]//td[@class="s"]/text()')[0] == 'abc' + assert elt.xpath('tbody/tr/td[@class="c"]//th[@class="s"]/text()')[0] == "s" + assert elt.xpath('tbody/tr/td[@class="c"]//td[@class="s"]/text()')[0] == "abc" - assert elt.xpath('tbody/tr/th[@class="s"]/text()')[0] == 's' - assert elt.xpath('tbody/tr/td[@class="s"]/text()')[0] == 'def' + assert elt.xpath('tbody/tr/th[@class="s"]/text()')[0] == "s" + assert elt.xpath('tbody/tr/td[@class="s"]/text()')[0] == "def" def test_string_array(self): class SomeService(Service): - @srpc(String(max_occurs='unbounded'), _returns=Array(String)) + @srpc(String(max_occurs="unbounded"), _returns=Array(String)) def some_call(s): return s - app = Application([SomeService], 'tns', in_protocol=HttpRpc(), - out_protocol=HtmlRowTable(field_name_attr=None, - field_type_name_attr=None)) + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(), + out_protocol=HtmlRowTable(field_name_attr=None, field_type_name_attr=None), + ) server = WsgiApplication(app) - out_string = call_wsgi_app(server, body_pairs=(('s', '1'), ('s', '2')) ) - show(html.fromstring(out_string), 'TestHtmlRowTable.test_string_array') - assert out_string.decode('utf8') == \ - '
' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '
string' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '
1
2
' \ - '
' \ - '
' + out_string = call_wsgi_app(server, body_pairs=(("s", "1"), ("s", "2"))) + show(html.fromstring(out_string), "TestHtmlRowTable.test_string_array") + assert ( + out_string.decode("utf8") == "
" + '' + "" + "" + "" + "" + "
string" + "" + "" + "" + "" + "" + "" + "" + "
1
2
" + "
" + "
" + ) def test_string_array_no_header(self): class SomeService(Service): - @srpc(String(max_occurs='unbounded'), _returns=Array(String)) + @srpc(String(max_occurs="unbounded"), _returns=Array(String)) def some_call(s): return s - app = Application([SomeService], 'tns', in_protocol=HttpRpc(), - out_protocol=HtmlRowTable(header=False, - field_name_attr=None, field_type_name_attr=None)) + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(), + out_protocol=HtmlRowTable( + header=False, field_name_attr=None, field_type_name_attr=None + ), + ) server = WsgiApplication(app) - out_string = call_wsgi_app(server, body_pairs=(('s', '1'), ('s', '2')) ) - #FIXME: Needs a proper test with xpaths and all. - show(html.fromstring(out_string), 'TestHtmlRowTable.test_string_array_no_header') - assert out_string.decode('utf8') == \ - '
' \ - '' \ - '' \ - '' \ - '' \ - '
' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '
1
2
' \ - '
' \ - '
' - + out_string = call_wsgi_app(server, body_pairs=(("s", "1"), ("s", "2"))) + # FIXME: Needs a proper test with xpaths and all. + show( + html.fromstring(out_string), "TestHtmlRowTable.test_string_array_no_header" + ) + assert ( + out_string.decode("utf8") == "
" + '' + "" + "" + "" + "
" + "" + "" + "" + "" + "" + "" + "" + "
1
2
" + "
" + "
" + ) def test_complex_array(self): v = [ - CM(i=1, s='a'), - CM(i=2, s='b'), - CM(i=3, s='c'), - CM(i=4, s='d'), + CM(i=1, s="a"), + CM(i=2, s="b"), + CM(i=3, s="c"), + CM(i=4, s="d"), ] + class SomeService(Service): @srpc(_returns=Array(CM)) def some_call(): return v - app = Application([SomeService], 'tns', in_protocol=HttpRpc(), - out_protocol=HtmlRowTable(field_type_name_attr=None)) + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(), + out_protocol=HtmlRowTable(field_type_name_attr=None), + ) server = WsgiApplication(app) out_string = call_wsgi_app_kwargs(server) - show(html.fromstring(out_string), 'TestHtmlRowTable.test_complex_array') - #FIXME: Needs a proper test with xpaths and all. - assert out_string.decode('utf8') == \ - '
' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '
i1
sa
' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '
i2
sb
' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '
i3
sc
' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '' \ - '
i4
sd
' \ - '
' - - - -if __name__ == '__main__': + show(html.fromstring(out_string), "TestHtmlRowTable.test_complex_array") + # FIXME: Needs a proper test with xpaths and all. + assert ( + out_string.decode("utf8") == "
" + '' + "" + "" + '' + '' + "" + "" + '' + '' + "" + "" + "
i1
sa
" + '' + "" + "" + '' + '' + "" + "" + '' + '' + "" + "" + "
i2
sb
" + '' + "" + "" + '' + '' + "" + "" + '' + '' + "" + "" + "
i3
sc
" + '' + "" + "" + '' + '' + "" + "" + '' + '' + "" + "" + "
i4
sd
" + "
" + ) + + +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/protocol/test_http.py b/spyne/test/protocol/test_http.py index 12370ec99..50d7d46ca 100755 --- a/spyne/test/protocol/test_http.py +++ b/spyne/test/protocol/test_http.py @@ -20,28 +20,33 @@ import logging + logging.basicConfig(level=logging.DEBUG) import unittest - -from spyne.util.six import StringIO -from spyne.util.six.moves.http_cookies import SimpleCookie - from datetime import datetime +from http.cookies import SimpleCookie +from io import StringIO from wsgiref.validate import validator as wsgiref_validator -from spyne.server.wsgi import _parse_qs from spyne.application import Application -from spyne.error import ValidationError from spyne.const.http import HTTP_200 -from spyne.decorator import rpc -from spyne.decorator import srpc -from spyne.model import ByteArray, DateTime, Uuid, String, Integer, Integer8, \ - ComplexModel, Array -from spyne.protocol.http import HttpRpc, HttpPattern, _parse_cookie -from spyne.service import Service -from spyne.server.wsgi import WsgiApplication, WsgiMethodContext +from spyne.decorator import rpc, srpc +from spyne.error import ValidationError +from spyne.model import ( + Array, + ByteArray, + ComplexModel, + DateTime, + Integer, + Integer8, + String, + Uuid, +) +from spyne.protocol.http import HttpPattern, HttpRpc, _parse_cookie from spyne.server.http import HttpTransportContext +from spyne.server.wsgi import WsgiApplication, WsgiMethodContext, _parse_qs +from spyne.service import Service from spyne.util.test import call_wsgi_app_kwargs @@ -52,27 +57,29 @@ class SomeService(Service): def echo_string(s): return s - app = Application([SomeService], 'tns', - in_protocol=HttpRpc(validator='soft'), - out_protocol=HttpRpc(), - ) + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(validator="soft"), + out_protocol=HttpRpc(), + ) self.app = WsgiApplication(app) def test_without_content_type(self): headers = None - ret = call_wsgi_app_kwargs(self.app, 'echo_string', headers, s="string") - assert ret == b'string' + ret = call_wsgi_app_kwargs(self.app, "echo_string", headers, s="string") + assert ret == b"string" def test_without_encoding(self): - headers = {'CONTENT_TYPE':'text/plain'} - ret = call_wsgi_app_kwargs(self.app, 'echo_string', headers, s="string") - assert ret == b'string' + headers = {"CONTENT_TYPE": "text/plain"} + ret = call_wsgi_app_kwargs(self.app, "echo_string", headers, s="string") + assert ret == b"string" def test_with_encoding(self): - headers = {'CONTENT_TYPE':'text/plain; charset=utf8'} - ret = call_wsgi_app_kwargs(self.app, 'echo_string', headers, s="string") - assert ret == b'string' + headers = {"CONTENT_TYPE": "text/plain; charset=utf8"} + ret = call_wsgi_app_kwargs(self.app, "echo_string", headers, s="string") + assert ret == b"string" class TestHttpTransportContext(unittest.TestCase): @@ -83,42 +90,60 @@ def test_gen_header(self): class TestSimpleDictDocument(unittest.TestCase): def test_own_parse_qs_01(self): - assert dict(_parse_qs('')) == {} + assert dict(_parse_qs("")) == {} + def test_own_parse_qs_02(self): - assert dict(_parse_qs('p')) == {'p': [None]} + assert dict(_parse_qs("p")) == {"p": [None]} + def test_own_parse_qs_03(self): - assert dict(_parse_qs('p=')) == {'p': ['']} + assert dict(_parse_qs("p=")) == {"p": [""]} + def test_own_parse_qs_04(self): - assert dict(_parse_qs('p=1')) == {'p': ['1']} + assert dict(_parse_qs("p=1")) == {"p": ["1"]} + def test_own_parse_qs_05(self): - assert dict(_parse_qs('p=1&')) == {'p': ['1']} + assert dict(_parse_qs("p=1&")) == {"p": ["1"]} + def test_own_parse_qs_06(self): - assert dict(_parse_qs('p=1&q')) == {'p': ['1'], 'q': [None]} + assert dict(_parse_qs("p=1&q")) == {"p": ["1"], "q": [None]} + def test_own_parse_qs_07(self): - assert dict(_parse_qs('p=1&q=')) == {'p': ['1'], 'q': ['']} + assert dict(_parse_qs("p=1&q=")) == {"p": ["1"], "q": [""]} + def test_own_parse_qs_08(self): - assert dict(_parse_qs('p=1&q=2')) == {'p': ['1'], 'q': ['2']} + assert dict(_parse_qs("p=1&q=2")) == {"p": ["1"], "q": ["2"]} + def test_own_parse_qs_09(self): - assert dict(_parse_qs('p=1&q=2&p')) == {'p': ['1', None], 'q': ['2']} + assert dict(_parse_qs("p=1&q=2&p")) == {"p": ["1", None], "q": ["2"]} + def test_own_parse_qs_10(self): - assert dict(_parse_qs('p=1&q=2&p=')) == {'p': ['1', ''], 'q': ['2']} + assert dict(_parse_qs("p=1&q=2&p=")) == {"p": ["1", ""], "q": ["2"]} + def test_own_parse_qs_11(self): - assert dict(_parse_qs('p=1&q=2&p=3')) == {'p': ['1', '3'], 'q': ['2']} + assert dict(_parse_qs("p=1&q=2&p=3")) == {"p": ["1", "3"], "q": ["2"]} + -def _test(services, qs, validator='soft', strict_arrays=False): - app = Application(services, 'tns', - in_protocol=HttpRpc(validator=validator, strict_arrays=strict_arrays), - out_protocol=HttpRpc()) +def _test(services, qs, validator="soft", strict_arrays=False): + app = Application( + services, + "tns", + in_protocol=HttpRpc(validator=validator, strict_arrays=strict_arrays), + out_protocol=HttpRpc(), + ) server = WsgiApplication(app) - initial_ctx = WsgiMethodContext(server, { - 'QUERY_STRING': qs, - 'PATH_INFO': '/some_call', - 'REQUEST_METHOD': 'GET', - 'SERVER_NAME': "localhost", - }, 'some-content-type') + initial_ctx = WsgiMethodContext( + server, + { + "QUERY_STRING": qs, + "PATH_INFO": "/some_call", + "REQUEST_METHOD": "GET", + "SERVER_NAME": "localhost", + }, + "some-content-type", + ) - ctx, = server.generate_contexts(initial_ctx) + (ctx,) = server.generate_contexts(initial_ctx) server.get_in_object(ctx) if ctx.in_error is not None: @@ -132,6 +157,7 @@ def _test(services, qs, validator='soft', strict_arrays=False): return ctx + class TestValidation(unittest.TestCase): def test_validation_frequency(self): class SomeService(Service): @@ -140,7 +166,7 @@ def some_call(p): pass try: - _test([SomeService], '', validator='soft') + _test([SomeService], "", validator="soft") except ValidationError: pass else: @@ -148,12 +174,12 @@ def some_call(p): def _test_validation_frequency_simple_bare(self): class SomeService(Service): - @srpc(ByteArray(min_occurs=1), _body_style='bare', _returns=ByteArray) + @srpc(ByteArray(min_occurs=1), _body_style="bare", _returns=ByteArray) def some_call(p): pass try: - _test([SomeService], '', validator='soft') + _test([SomeService], "", validator="soft") except ValidationError: pass else: @@ -161,20 +187,20 @@ def some_call(p): def test_validation_frequency_complex_bare_parent(self): class C(ComplexModel): - i=Integer(min_occurs=1) - s=String + i = Integer(min_occurs=1) + s = String class SomeService(Service): - @srpc(C, _body_style='bare') + @srpc(C, _body_style="bare") def some_call(p): pass # must not complain about missing s - _test([SomeService], 'i=5', validator='soft') + _test([SomeService], "i=5", validator="soft") # must raise validation error for missing i try: - _test([SomeService], 's=a', validator='soft') + _test([SomeService], "s=a", validator="soft") except ValidationError: pass else: @@ -182,7 +208,7 @@ def some_call(p): # must raise validation error for missing i try: - _test([SomeService], '', validator='soft') + _test([SomeService], "", validator="soft") except ValidationError: pass else: @@ -190,8 +216,8 @@ def some_call(p): def test_validation_frequency_parent(self): class C(ComplexModel): - i=Integer(min_occurs=1) - s=String + i = Integer(min_occurs=1) + s = String class SomeService(Service): @srpc(C) @@ -199,22 +225,22 @@ def some_call(p): pass # must not complain about missing s - _test([SomeService], 'p.i=5', validator='soft') + _test([SomeService], "p.i=5", validator="soft") try: # must raise validation error for missing i - _test([SomeService], 'p.s=a', validator='soft') + _test([SomeService], "p.s=a", validator="soft") except ValidationError: pass else: raise Exception("must raise ValidationError") # must not raise anything for missing p because C has min_occurs=0 - _test([SomeService], '', validator='soft') + _test([SomeService], "", validator="soft") def test_validation_array(self): class C(ComplexModel): - i=Integer(min_occurs=1) - s=String + i = Integer(min_occurs=1) + s = String class SomeService(Service): @srpc(Array(C)) @@ -222,21 +248,21 @@ def some_call(p): pass # must not complain about missing s - _test([SomeService], 'p[0].i=5', validator='soft') + _test([SomeService], "p[0].i=5", validator="soft") try: # must raise validation error for missing i - _test([SomeService], 'p[0].s=a', validator='soft') + _test([SomeService], "p[0].s=a", validator="soft") except ValidationError: pass else: raise Exception("must raise ValidationError") # must not raise anything for missing p because C has min_occurs=0 - _test([SomeService], '', validator='soft') + _test([SomeService], "", validator="soft") def test_validation_array_index_jump_error(self): class C(ComplexModel): - i=Integer + i = Integer class SomeService(Service): @srpc(Array(C), _returns=String) @@ -246,7 +272,7 @@ def some_call(p): try: # must raise validation error for index jump from 0 to 2 even without # any validation - _test([SomeService], 'p[0].i=42&p[2].i=42&', strict_arrays=True) + _test([SomeService], "p[0].i=42&p[2].i=42&", strict_arrays=True) except ValidationError: pass else: @@ -254,7 +280,7 @@ def some_call(p): def test_validation_array_index_jump_tolerate(self): class C(ComplexModel): - i=Integer + i = Integer class SomeService(Service): @srpc(Array(C), _returns=String) @@ -263,12 +289,12 @@ def some_call(p): # must not raise validation error for index jump from 0 to 2 and ignore # element with index 1 - ret = _test([SomeService], 'p[0].i=0&p[2].i=2&', strict_arrays=False) - assert ret.out_object[0] == '[C(i=0), C(i=2)]' + ret = _test([SomeService], "p[0].i=0&p[2].i=2&", strict_arrays=False) + assert ret.out_object[0] == "[C(i=0), C(i=2)]" # even if they arrive out-of-order. - ret = _test([SomeService], 'p[2].i=2&p[0].i=0&', strict_arrays=False) - assert ret.out_object[0] == '[C(i=0), C(i=2)]' + ret = _test([SomeService], "p[2].i=2&p[0].i=0&", strict_arrays=False) + assert ret.out_object[0] == "[C(i=0), C(i=2)]" def test_validation_nested_array(self): class CC(ComplexModel): @@ -284,17 +310,17 @@ def some_call(p): print(p) # must not complain about missing s - _test([SomeService], 'p[0].i=5', validator='soft') + _test([SomeService], "p[0].i=5", validator="soft") try: # must raise validation error for missing i - _test([SomeService], 'p[0].cc[0].d=2013-01-01', validator='soft') + _test([SomeService], "p[0].cc[0].d=2013-01-01", validator="soft") except ValidationError: pass else: raise Exception("must raise ValidationError") # must not raise anything for missing p because C has min_occurs=0 - _test([SomeService], '', validator='soft') + _test([SomeService], "", validator="soft") def test_validation_nullable(self): class SomeService(Service): @@ -303,7 +329,7 @@ def some_call(p): pass try: - _test([SomeService], 'p', validator='soft') + _test([SomeService], "p", validator="soft") except ValidationError: pass else: @@ -316,7 +342,7 @@ def some_call(p): pass try: - _test([SomeService], "p=duduk", validator='soft') + _test([SomeService], "p=duduk", validator="soft") except ValidationError: pass else: @@ -329,7 +355,7 @@ def some_call(p): pass try: - _test([SomeService], 'p=10', validator='soft') + _test([SomeService], "p=10", validator="soft") except ValidationError: pass else: @@ -342,7 +368,7 @@ def some_call(p): pass try: - _test([SomeService], "p=-129", validator='soft') + _test([SomeService], "p=-129", validator="soft") except ValidationError: pass else: @@ -355,7 +381,7 @@ def some_call(p): pass try: - _test([SomeService], "p=1.2", validator='soft') + _test([SomeService], "p=1.2", validator="soft") except ValidationError: pass else: @@ -367,15 +393,16 @@ def test_multiple_return(self): class SomeService(Service): @srpc(_returns=[Integer, String]) def some_call(): - return 1, 's' + return 1, "s" try: - _test([SomeService], '') + _test([SomeService], "") except TypeError: pass else: - raise Exception("Must fail with: HttpRpc does not support complex " - "return types.") + raise Exception( + "Must fail with: HttpRpc does not support complex " "return types." + ) def test_primitive_only(self): class SomeComplexModel(ComplexModel): @@ -385,15 +412,16 @@ class SomeComplexModel(ComplexModel): class SomeService(Service): @srpc(SomeComplexModel, _returns=SomeComplexModel) def some_call(scm): - return SomeComplexModel(i=5, s='5x') + return SomeComplexModel(i=5, s="5x") try: - _test([SomeService], '') + _test([SomeService], "") except TypeError: pass else: - raise Exception("Must fail with: HttpRpc does not support complex " - "return types.") + raise Exception( + "Must fail with: HttpRpc does not support complex " "return types." + ) def test_complex(self): class CM(ComplexModel): @@ -414,18 +442,18 @@ class SomeService(Service): def some_call(ccm): return repr(CCM(c=ccm.c, i=ccm.i, s=ccm.s)) - ctx = _test([SomeService], '&ccm.i=1&ccm.s=s&ccm.c.i=3&ccm.c.s=cs') + ctx = _test([SomeService], "&ccm.i=1&ccm.s=s&ccm.c.i=3&ccm.c.s=cs") assert ctx.out_string[0] == b"CCM(i=1, c=CM(i=3, s='cs'), s='s')" def test_simple_array(self): class SomeService(Service): - @srpc(String(max_occurs='unbounded'), _returns=String) + @srpc(String(max_occurs="unbounded"), _returns=String) def some_call(s): - return '\n'.join(s) + return "\n".join(s) - ctx = _test([SomeService], '&s=1&s=2') - assert b''.join(ctx.out_string) == b'1\n2' + ctx = _test([SomeService], "&s=1&s=2") + assert b"".join(ctx.out_string) == b"1\n2" def test_complex_array(self): class CM(ComplexModel): @@ -437,17 +465,18 @@ class CM(ComplexModel): class SomeService(Service): @srpc(Array(CM), _returns=String) def some_call(cs): - return '\n'.join([repr(c) for c in cs]) + return "\n".join([repr(c) for c in cs]) - ctx = _test([SomeService], - 'cs[0].i=1&cs[0].s=x' - '&cs[1].i=2&cs[1].s=y' - '&cs[2].i=3&cs[2].s=z') + ctx = _test( + [SomeService], + "cs[0].i=1&cs[0].s=x" "&cs[1].i=2&cs[1].s=y" "&cs[2].i=3&cs[2].s=z", + ) - assert b''.join(ctx.out_string) == \ - b"CM(i=1, s='x')\n" \ - b"CM(i=2, s='y')\n" \ - b"CM(i=3, s='z')" + assert ( + b"".join(ctx.out_string) == b"CM(i=1, s='x')\n" + b"CM(i=2, s='y')\n" + b"CM(i=3, s='z')" + ) def test_complex_array_empty(self): class CM(ComplexModel): @@ -461,9 +490,9 @@ class SomeService(Service): def some_call(cs): return repr(cs) - ctx = _test([SomeService], 'cs=empty') + ctx = _test([SomeService], "cs=empty") - assert b''.join(ctx.out_string) == b'[]' + assert b"".join(ctx.out_string) == b"[]" def test_complex_object_empty(self): class CM(ComplexModel): @@ -477,9 +506,9 @@ class SomeService(Service): def some_call(c): return repr(c) - ctx = _test([SomeService], 'c=empty') + ctx = _test([SomeService], "c=empty") - assert b''.join(ctx.out_string) == b'CM()' + assert b"".join(ctx.out_string) == b"CM()" def test_nested_flatten(self): class CM(ComplexModel): @@ -500,10 +529,10 @@ class SomeService(Service): def some_call(ccm): return repr(ccm) - ctx = _test([SomeService], '&ccm.i=1&ccm.s=s&ccm.c.i=3&ccm.c.s=cs') + ctx = _test([SomeService], "&ccm.i=1&ccm.s=s&ccm.c.i=3&ccm.c.s=cs") print(ctx.out_string) - assert b''.join(ctx.out_string) == b"CCM(i=1, c=CM(i=3, s='cs'), s='s')" + assert b"".join(ctx.out_string) == b"CCM(i=1, c=CM(i=3, s='cs'), s='s')" def test_nested_flatten_with_multiple_values_1(self): class CM(ComplexModel): @@ -524,11 +553,14 @@ class SomeService(Service): def some_call(ccm): return repr(ccm) - ctx = _test([SomeService], 'ccm[0].i=1&ccm[0].s=s' - '&ccm[0].c.i=1&ccm[0].c.s=a' - '&ccm[1].c.i=2&ccm[1].c.s=b') + ctx = _test( + [SomeService], + "ccm[0].i=1&ccm[0].s=s" + "&ccm[0].c.i=1&ccm[0].c.s=a" + "&ccm[1].c.i=2&ccm[1].c.s=b", + ) - s = b''.join(ctx.out_string) + s = b"".join(ctx.out_string) assert s == b"[CCM(i=1, c=CM(i=1, s='a'), s='s'), CCM(c=CM(i=2, s='b'))]" @@ -551,11 +583,12 @@ class SomeService(Service): def some_call(ccm): return repr(ccm) - ctx = _test([SomeService], 'ccm.i=1&ccm.s=s' - '&ccm.c[0].i=1&ccm.c[0].s=a' - '&ccm.c[1].i=2&ccm.c[1].s=b') + ctx = _test( + [SomeService], + "ccm.i=1&ccm.s=s" "&ccm.c[0].i=1&ccm.c[0].s=a" "&ccm.c[1].i=2&ccm.c[1].s=b", + ) - s = b''.join(list(ctx.out_string)) + s = b"".join(list(ctx.out_string)) assert s == b"CCM(i=1, c=[CM(i=1, s='a'), CM(i=2, s='b')], s='s')" def test_nested_flatten_with_complex_array(self): @@ -577,11 +610,12 @@ class SomeService(Service): def some_call(ccm): return repr(ccm) - ctx = _test([SomeService], 'ccm.i=1&ccm.s=s' - '&ccm.c[0].i=1&ccm.c[0].s=a' - '&ccm.c[1].i=2&ccm.c[1].s=b') + ctx = _test( + [SomeService], + "ccm.i=1&ccm.s=s" "&ccm.c[0].i=1&ccm.c[0].s=a" "&ccm.c[1].i=2&ccm.c[1].s=b", + ) - s = b''.join(list(ctx.out_string)) + s = b"".join(list(ctx.out_string)) assert s == b"CCM(i=1, c=[CM(i=1, s='a'), CM(i=2, s='b')], s='s')" def test_nested_2_flatten_with_primitive_array(self): @@ -597,17 +631,15 @@ class SomeService(Service): def some_call(ccm): return repr(ccm) - ctx = _test([SomeService], 'ccm[0].i=1&ccm[0].s=s' - '&ccm[0].c=a' - '&ccm[0].c=b') - s = b''.join(list(ctx.out_string)) + ctx = _test([SomeService], "ccm[0].i=1&ccm[0].s=s" "&ccm[0].c=a" "&ccm[0].c=b") + s = b"".join(list(ctx.out_string)) assert s == b"[CCM(i=1, c=['a', 'b'], s='s')]" def test_default(self): class CM(ComplexModel): _type_info = [ ("i", Integer), - ("s", String(default='default')), + ("s", String(default="default")), ] class SomeService(Service): @@ -616,18 +648,18 @@ def some_call(cm): return repr(cm) # s is missing - ctx = _test([SomeService], 'cm.i=1') - s = b''.join(ctx.out_string) + ctx = _test([SomeService], "cm.i=1") + s = b"".join(ctx.out_string) assert s == b"CM(i=1, s='default')" # s is None - ctx = _test([SomeService], 'cm.i=1&cm.s') - s = b''.join(ctx.out_string) + ctx = _test([SomeService], "cm.i=1&cm.s") + s = b"".join(ctx.out_string) assert s == b"CM(i=1)" # s is empty - ctx = _test([SomeService], 'cm.i=1&cm.s=') - s = b''.join(ctx.out_string) + ctx = _test([SomeService], "cm.i=1&cm.s=") + s = b"".join(ctx.out_string) assert s == b"CM(i=1, s='')" def test_nested_flatten_with_primitive_array(self): @@ -643,34 +675,26 @@ class SomeService(Service): def some_call(ccm): return repr(ccm) - ctx = _test([SomeService], 'ccm.i=1&ccm.s=s' - '&ccm.c=a' - '&ccm.c=b') - s = b''.join(list(ctx.out_string)) + ctx = _test([SomeService], "ccm.i=1&ccm.s=s" "&ccm.c=a" "&ccm.c=b") + s = b"".join(list(ctx.out_string)) assert s == b"CCM(i=1, c=['a', 'b'], s='s')" - ctx = _test([SomeService], 'ccm.i=1' - '&ccm.s=s' - '&ccm.c[1]=b' - '&ccm.c[0]=a') - s = b''.join(list(ctx.out_string)) + ctx = _test([SomeService], "ccm.i=1" "&ccm.s=s" "&ccm.c[1]=b" "&ccm.c[0]=a") + s = b"".join(list(ctx.out_string)) assert s == b"CCM(i=1, c=['a', 'b'], s='s')" - ctx = _test([SomeService], 'ccm.i=1' - '&ccm.s=s' - '&ccm.c[0]=a' - '&ccm.c[1]=b') - s = b''.join(list(ctx.out_string)) + ctx = _test([SomeService], "ccm.i=1" "&ccm.s=s" "&ccm.c[0]=a" "&ccm.c[1]=b") + s = b"".join(list(ctx.out_string)) assert s == b"CCM(i=1, c=['a', 'b'], s='s')" def test_http_headers(self): d = datetime(year=2013, month=1, day=1) - string = ['hey', 'yo'] + string = ["hey", "yo"] class ResponseHeader(ComplexModel): _type_info = { - 'Set-Cookie': String(max_occurs='unbounded'), - 'Expires': DateTime + "Set-Cookie": String(max_occurs="unbounded"), + "Expires": DateTime, } class SomeService(Service): @@ -679,33 +703,34 @@ class SomeService(Service): @rpc(String) def some_call(ctx, s): assert s is not None - ctx.out_header = ResponseHeader(**{'Set-Cookie': string, - 'Expires': d}) + ctx.out_header = ResponseHeader(**{"Set-Cookie": string, "Expires": d}) def start_response(code, headers): print(headers) - assert len([s for s in string - if ('Set-Cookie', s) in headers]) == len(string) - assert dict(headers)['Expires'] == 'Tue, 01 Jan 2013 00:00:00 GMT' + assert len([s for s in string if ("Set-Cookie", s) in headers]) == len( + string + ) + assert dict(headers)["Expires"] == "Tue, 01 Jan 2013 00:00:00 GMT" - app = Application([SomeService], 'tns', - in_protocol=HttpRpc(), out_protocol=HttpRpc()) + app = Application( + [SomeService], "tns", in_protocol=HttpRpc(), out_protocol=HttpRpc() + ) wsgi_app = WsgiApplication(app) req_dict = { - 'SCRIPT_NAME': '', - 'QUERY_STRING': '&s=foo', - 'PATH_INFO': '/some_call', - 'REQUEST_METHOD': 'GET', - 'SERVER_NAME': 'localhost', - 'SERVER_PORT': "9999", - 'wsgi.url_scheme': 'http', - 'wsgi.version': (1,0), - 'wsgi.input': StringIO(), - 'wsgi.errors': StringIO(), - 'wsgi.multithread': False, - 'wsgi.multiprocess': False, - 'wsgi.run_once': True, + "SCRIPT_NAME": "", + "QUERY_STRING": "&s=foo", + "PATH_INFO": "/some_call", + "REQUEST_METHOD": "GET", + "SERVER_NAME": "localhost", + "SERVER_PORT": "9999", + "wsgi.url_scheme": "http", + "wsgi.version": (1, 0), + "wsgi.input": StringIO(), + "wsgi.errors": StringIO(), + "wsgi.multithread": False, + "wsgi.multiprocess": False, + "wsgi.run_once": True, } ret = wsgi_app(req_dict, start_response) @@ -714,37 +739,44 @@ def start_response(code, headers): wsgi_app = wsgiref_validator(wsgi_app) ret = wsgi_app(req_dict, start_response) - - assert list(ret) == [b''] + try: + assert list(ret) == [b""] + finally: + ret.close() class TestHttpPatterns(unittest.TestCase): def test_rules(self): _int = 5 - _fragment = 'some_fragment' + _fragment = "some_fragment" class SomeService(Service): - @srpc(Integer, _returns=Integer, _patterns=[ - HttpPattern('/%s/' % _fragment)]) + @srpc( + Integer, + _returns=Integer, + _patterns=[HttpPattern("/%s/" % _fragment)], + ) def some_call(some_int): assert some_int == _int - app = Application([SomeService], 'tns', in_protocol=HttpRpc(), out_protocol=HttpRpc()) + app = Application( + [SomeService], "tns", in_protocol=HttpRpc(), out_protocol=HttpRpc() + ) server = WsgiApplication(app) environ = { - 'QUERY_STRING': '', - 'PATH_INFO': '/%s/%d' % (_fragment, _int), - 'SERVER_PATH':"/", - 'SERVER_NAME': "localhost", - 'wsgi.url_scheme': 'http', - 'SERVER_PORT': '9000', - 'REQUEST_METHOD': 'GET', + "QUERY_STRING": "", + "PATH_INFO": "/%s/%d" % (_fragment, _int), + "SERVER_PATH": "/", + "SERVER_NAME": "localhost", + "wsgi.url_scheme": "http", + "SERVER_PORT": "9000", + "REQUEST_METHOD": "GET", } - initial_ctx = WsgiMethodContext(server, environ, 'some-content-type') + initial_ctx = WsgiMethodContext(server, environ, "some-content-type") - ctx, = server.generate_contexts(initial_ctx) + (ctx,) = server.generate_contexts(initial_ctx) foo = [] for i in server._http_patterns: @@ -763,7 +795,8 @@ def some_call(some_int): class ParseCookieTest(unittest.TestCase): def test_cookie_parse(self): - string = 'some_string' + string = "some_string" + class RequestHeader(ComplexModel): some_field = String @@ -777,37 +810,44 @@ def some_call(ctx, s): def start_response(code, headers): assert code == HTTP_200 - c = 'some_field=%s'% (string,) + c = "some_field=%s" % (string,) - app = Application([SomeService], 'tns', - in_protocol=HttpRpc(parse_cookie=True), out_protocol=HttpRpc()) + app = Application( + [SomeService], + "tns", + in_protocol=HttpRpc(parse_cookie=True), + out_protocol=HttpRpc(), + ) wsgi_app = WsgiApplication(app) req_dict = { - 'SCRIPT_NAME': '', - 'QUERY_STRING': '', - 'PATH_INFO': '/some_call', - 'REQUEST_METHOD': 'GET', - 'SERVER_NAME': 'localhost', - 'SERVER_PORT': "9999", - 'HTTP_COOKIE': c, - 'wsgi.url_scheme': 'http', - 'wsgi.version': (1,0), - 'wsgi.input': StringIO(), - 'wsgi.errors': StringIO(), - 'wsgi.multithread': False, - 'wsgi.multiprocess': False, - 'wsgi.run_once': True, + "SCRIPT_NAME": "", + "QUERY_STRING": "", + "PATH_INFO": "/some_call", + "REQUEST_METHOD": "GET", + "SERVER_NAME": "localhost", + "SERVER_PORT": "9999", + "HTTP_COOKIE": c, + "wsgi.url_scheme": "http", + "wsgi.version": (1, 0), + "wsgi.input": StringIO(), + "wsgi.errors": StringIO(), + "wsgi.multithread": False, + "wsgi.multiprocess": False, + "wsgi.run_once": True, } ret = wsgi_app(req_dict, start_response) - print(ret) + list(ret) wsgi_app = wsgiref_validator(wsgi_app) ret = wsgi_app(req_dict, start_response) - print(ret) + try: + list(ret) + finally: + ret.close() # These tests copied from Django: # https://github.com/django/django/pull/6277/commits/da810901ada1cae9fc1f018f879f11a7fb467b28 @@ -815,26 +855,37 @@ def test_python_cookies(self): """ Test cases copied from Python's Lib/test/test_http_cookies.py """ - self.assertEqual(_parse_cookie('chips=ahoy; vienna=finger'), {'chips': 'ahoy', 'vienna': 'finger'}) + self.assertEqual( + _parse_cookie("chips=ahoy; vienna=finger"), + {"chips": "ahoy", "vienna": "finger"}, + ) # Here _parse_cookie() differs from Python's cookie parsing in that it # treats all semicolons as delimiters, even within quotes. self.assertEqual( _parse_cookie('keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"'), - {'keebler': '"E=mc2', 'L': '\\"Loves\\"', 'fudge': '\\012', '': '"'} + {"keebler": '"E=mc2', "L": '\\"Loves\\"', "fudge": "\\012", "": '"'}, ) # Illegal cookies that have an '=' char in an unquoted value. - self.assertEqual(_parse_cookie('keebler=E=mc2'), {'keebler': 'E=mc2'}) + self.assertEqual(_parse_cookie("keebler=E=mc2"), {"keebler": "E=mc2"}) # Cookies with ':' character in their name. - self.assertEqual(_parse_cookie('key:term=value:term'), {'key:term': 'value:term'}) + self.assertEqual( + _parse_cookie("key:term=value:term"), {"key:term": "value:term"} + ) # Cookies with '[' and ']'. - self.assertEqual(_parse_cookie('a=b; c=[; d=r; f=h'), {'a': 'b', 'c': '[', 'd': 'r', 'f': 'h'}) + self.assertEqual( + _parse_cookie("a=b; c=[; d=r; f=h"), + {"a": "b", "c": "[", "d": "r", "f": "h"}, + ) def test_cookie_edgecases(self): # Cookies that RFC6265 allows. - self.assertEqual(_parse_cookie('a=b; Domain=example.com'), {'a': 'b', 'Domain': 'example.com'}) + self.assertEqual( + _parse_cookie("a=b; Domain=example.com"), + {"a": "b", "Domain": "example.com"}, + ) # _parse_cookie() has historically kept only the last cookie with the # same name. - self.assertEqual(_parse_cookie('a=b; h=i; a=c'), {'a': 'c', 'h': 'i'}) + self.assertEqual(_parse_cookie("a=b; h=i; a=c"), {"a": "c", "h": "i"}) def test_invalid_cookies(self): """ @@ -843,26 +894,32 @@ def test_invalid_cookies(self): """ # Chunks without an equals sign appear as unnamed values per # https://bugzilla.mozilla.org/show_bug.cgi?id=169091 - self.assertIn('django_language', - _parse_cookie('abc=def; unnamed; django_language=en').keys()) + self.assertIn( + "django_language", + _parse_cookie("abc=def; unnamed; django_language=en").keys(), + ) # Even a double quote may be an unamed value. - self.assertEqual( - _parse_cookie('a=b; "; c=d'), {'a': 'b', '': '"', 'c': 'd'}) + self.assertEqual(_parse_cookie('a=b; "; c=d'), {"a": "b", "": '"', "c": "d"}) # Spaces in names and values, and an equals sign in values. - self.assertEqual(_parse_cookie('a b c=d e = f; gh=i'), - {'a b c': 'd e = f', 'gh': 'i'}) + self.assertEqual( + _parse_cookie("a b c=d e = f; gh=i"), {"a b c": "d e = f", "gh": "i"} + ) # More characters the spec forbids. - self.assertEqual(_parse_cookie('a b,c<>@:/[]?{}=d " =e,f g'), - {'a b,c<>@:/[]?{}': 'd " =e,f g'}) + self.assertEqual( + _parse_cookie('a b,c<>@:/[]?{}=d " =e,f g'), + {"a b,c<>@:/[]?{}": 'd " =e,f g'}, + ) # Unicode characters. The spec only allows ASCII. - self.assertEqual(_parse_cookie(u'saint=André Bessette'), - {u'saint': u'André Bessette'}) + self.assertEqual( + _parse_cookie("saint=André Bessette"), {"saint": "André Bessette"} + ) # Browsers don't send extra whitespace or semicolons in Cookie headers, # but _parse_cookie() should parse whitespace the same way # document.cookie parses whitespace. - self.assertEqual(_parse_cookie(' = b ; ; = ; c = ; '), - {'': 'b', 'c': ''}) + self.assertEqual( + _parse_cookie(" = b ; ; = ; c = ; "), {"": "b", "c": ""} + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/protocol/test_json.py b/spyne/test/protocol/test_json.py index ac162fb0f..589e1e6dc 100755 --- a/spyne/test/protocol/test_json.py +++ b/spyne/test/protocol/test_json.py @@ -18,38 +18,33 @@ # import unittest + try: import simplejson as json except ImportError: import json - -from spyne import MethodContext -from spyne import Application -from spyne import rpc,srpc -from spyne import Service -from spyne.model import Integer, Unicode, ComplexModel -from spyne.protocol.json import JsonP -from spyne.protocol.json import JsonDocument -from spyne.protocol.json import JsonEncoder -from spyne.protocol.json import _SpyneJsonRpc1 +from spyne import Application, MethodContext, Service, rpc, srpc +from spyne.model import ComplexModel, Integer, Unicode +from spyne.protocol.json import JsonDocument, JsonEncoder, JsonP, _SpyneJsonRpc1 from spyne.server import ServerBase from spyne.server.null import NullServer +from spyne.test.protocol._test_dictdoc import TDictDocumentTest, TDry -from spyne.test.protocol._test_dictdoc import TDictDocumentTest -from spyne.test.protocol._test_dictdoc import TDry - -class TestDictDocument(TDictDocumentTest(json, JsonDocument, - dumps_kwargs=dict(cls=JsonEncoder))): +class TestDictDocument( + TDictDocumentTest(json, JsonDocument, dumps_kwargs=dict(cls=JsonEncoder)) +): def dumps(self, o): - return super(TestDictDocument, self).dumps(o).encode('utf8') + return super(TestDictDocument, self).dumps(o).encode("utf8") def loads(self, o): - return super(TestDictDocument, self).loads(o.decode('utf8')) + return super(TestDictDocument, self).loads(o.decode("utf8")) + _dry_sjrpc1 = TDry(json, _SpyneJsonRpc1) + class TestSpyneJsonRpc1(unittest.TestCase): def test_call(self): class SomeService(Service): @@ -58,8 +53,7 @@ def yay(i): print(i) return i - ctx = _dry_sjrpc1([SomeService], - {"ver": 1, "body": {"yay": {"i":5}}}, True) + ctx = _dry_sjrpc1([SomeService], {"ver": 1, "body": {"yay": {"i": 5}}}, True) print(ctx) print(list(ctx.out_string)) @@ -71,13 +65,15 @@ class SomeHeader(ComplexModel): class SomeService(Service): __in_header__ = SomeHeader + @rpc(Integer, _returns=Integer) def yay(ctx, i): print(ctx.in_header) return ctx.in_header.i - ctx = _dry_sjrpc1([SomeService], - {"ver": 1, "body": {"yay": None}, "head": {"i":5}}, True) + ctx = _dry_sjrpc1( + [SomeService], {"ver": 1, "body": {"yay": None}, "head": {"i": 5}}, True + ) print(ctx) print(list(ctx.out_string)) @@ -89,17 +85,19 @@ class SomeHeader(ComplexModel): class SomeService(Service): __in_header__ = SomeHeader + @rpc(Integer, Integer, _returns=Integer) def div(ctx, dividend, divisor): return dividend / divisor - ctx = _dry_sjrpc1([SomeService], - {"ver": 1, "body": {"div": [4,0]}}, True) + ctx = _dry_sjrpc1([SomeService], {"ver": 1, "body": {"div": [4, 0]}}, True) print(ctx) print(list(ctx.out_string)) - assert ctx.out_document == {"ver": 1, "fault": { - 'faultcode': 'Server', 'faultstring': 'Internal Error'}} + assert ctx.out_document == { + "ver": 1, + "fault": {"faultcode": "Server", "faultstring": "Internal Error"}, + } class TestJsonDocument(unittest.TestCase): @@ -109,46 +107,55 @@ class SomeService(Service): def yay(): pass - app = Application([SomeService], 'tns', - in_protocol=JsonDocument(), - out_protocol=JsonDocument()) + app = Application( + [SomeService], + "tns", + in_protocol=JsonDocument(), + out_protocol=JsonDocument(), + ) - assert 'cls' in app.out_protocol.kwargs - assert not ('cls' in app.in_protocol.kwargs) + assert "cls" in app.out_protocol.kwargs + assert not ("cls" in app.in_protocol.kwargs) - app = Application([SomeService], 'tns', - in_protocol=JsonDocument(), - out_protocol=JsonDocument(cls='hey')) + app = Application( + [SomeService], + "tns", + in_protocol=JsonDocument(), + out_protocol=JsonDocument(cls="hey"), + ) - assert app.out_protocol.kwargs['cls'] == 'hey' - assert not ('cls' in app.in_protocol.kwargs) + assert app.out_protocol.kwargs["cls"] == "hey" + assert not ("cls" in app.in_protocol.kwargs) def test_invalid_input(self): class SomeService(Service): pass - app = Application([SomeService], 'tns', - in_protocol=JsonDocument(), - out_protocol=JsonDocument()) + app = Application( + [SomeService], + "tns", + in_protocol=JsonDocument(), + out_protocol=JsonDocument(), + ) server = ServerBase(app) initial_ctx = MethodContext(server, MethodContext.SERVER) - initial_ctx.in_string = [b'{'] - ctx, = server.generate_contexts(initial_ctx, in_string_charset='utf8') - assert ctx.in_error.faultcode == 'Client.JsonDecodeError' + initial_ctx.in_string = [b"{"] + (ctx,) = server.generate_contexts(initial_ctx, in_string_charset="utf8") + assert ctx.in_error.faultcode == "Client.JsonDecodeError" class TestJsonP(unittest.TestCase): def test_callback_name(self): - callback_name = 'some_callback' + callback_name = "some_callback" class SomeComplexModel(ComplexModel): i = Integer s = Unicode v1 = 42 - v2 = SomeComplexModel(i=42, s='foo') + v2 = SomeComplexModel(i=42, s="foo") class SomeService(Service): @srpc(_returns=Integer) @@ -159,54 +166,68 @@ def yay(): def complex(): return v2 - app = Application([SomeService], 'tns', - in_protocol=JsonDocument(), - out_protocol=JsonP(callback_name)) + app = Application( + [SomeService], + "tns", + in_protocol=JsonDocument(), + out_protocol=JsonP(callback_name), + ) server = NullServer(app, ostr=True) ret = server.service.yay() ret = list(ret) - print(b''.join(ret)) - assert b''.join(ret) == b''.join((callback_name.encode('utf8'), b'(', - str(v1).encode('utf8'), b');')) + print(b"".join(ret)) + assert b"".join(ret) == b"".join( + (callback_name.encode("utf8"), b"(", str(v1).encode("utf8"), b");") + ) ret = server.service.complex() ret = list(ret) - print(b''.join(ret)) - assert b''.join(ret) == b''.join((callback_name.encode('utf8'), b'(', - json.dumps({"i": 42, "s": "foo"}).encode('utf-8') , b');')) - + print(b"".join(ret)) + assert b"".join(ret) == b"".join( + ( + callback_name.encode("utf8"), + b"(", + json.dumps({"i": 42, "s": "foo"}).encode("utf-8"), + b");", + ) + ) def test_wrapped_array_in_wrapped_response(self): - from spyne.model.complex import ComplexModel, Array + from spyne.model.complex import Array, ComplexModel from spyne.model.primitive import Unicode class Permission(ComplexModel): _type_info = [ - ('application', Unicode), - ('feature', Unicode), + ("application", Unicode), + ("feature", Unicode), ] class SomeService(Service): @srpc(_returns=Array(Permission)) def yay(): return [ - Permission(application='app', feature='f1'), - Permission(application='app', feature='f2') + Permission(application="app", feature="f1"), + Permission(application="app", feature="f2"), ] - app = Application([SomeService], 'tns', - in_protocol=JsonDocument(), - out_protocol=JsonDocument(ignore_wrappers=False)) + app = Application( + [SomeService], + "tns", + in_protocol=JsonDocument(), + out_protocol=JsonDocument(ignore_wrappers=False), + ) server = NullServer(app, ostr=True) - retstr = b''.join(server.service.yay()).decode('utf-8') + retstr = b"".join(server.service.yay()).decode("utf-8") print(retstr) - assert retstr == '{"yayResponse": {"yayResult": [' \ - '{"Permission": {"application": "app", "feature": "f1"}}, ' \ + assert ( + retstr == '{"yayResponse": {"yayResult": [' + '{"Permission": {"application": "app", "feature": "f1"}}, ' '{"Permission": {"application": "app", "feature": "f2"}}]}}' + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/protocol/test_msgpack.py b/spyne/test/protocol/test_msgpack.py index aa9889235..3331ca760 100755 --- a/spyne/test/protocol/test_msgpack.py +++ b/spyne/test/protocol/test_msgpack.py @@ -19,51 +19,45 @@ import logging -from spyne.util import six - logging.basicConfig(level=logging.DEBUG) import unittest +from io import BytesIO import msgpack from spyne import MethodContext from spyne.application import Application -from spyne.decorator import rpc -from spyne.decorator import srpc -from spyne.service import Service -from spyne.model.complex import Array -from spyne.model.primitive import String -from spyne.model.complex import ComplexModel -from spyne.model.primitive import Unicode -from spyne.protocol.msgpack import MessagePackDocument -from spyne.protocol.msgpack import MessagePackRpc -from spyne.util.six import BytesIO +from spyne.decorator import rpc, srpc +from spyne.model.complex import Array, ComplexModel +from spyne.model.primitive import String, Unicode +from spyne.protocol.msgpack import MessagePackDocument, MessagePackRpc from spyne.server import ServerBase from spyne.server.wsgi import WsgiApplication +from spyne.service import Service from spyne.test.protocol._test_dictdoc import TDictDocumentTest - from spyne.test.test_service import start_response def convert_dict(d): - if isinstance(d, six.text_type): - return d.encode('utf8') - if not isinstance(d, dict): return d r = {} for k, v in d.items(): - r[k.encode('utf8')] = convert_dict(v) + r[k.encode("utf8")] = convert_dict(v) return r # apply spyne defaults to test unpacker -TestMessagePackDocument = TDictDocumentTest(msgpack, MessagePackDocument, - loads_kwargs=dict(use_list=False), convert_dict=convert_dict) +TestMessagePackDocument = TDictDocumentTest( + msgpack, + MessagePackDocument, + loads_kwargs=dict(use_list=False), + convert_dict=convert_dict, +) class TestMessagePackRpc(unittest.TestCase): @@ -73,74 +67,88 @@ class SomeService(Service): def yay(): pass - app = Application([SomeService], 'tns', - in_protocol=MessagePackDocument(), - out_protocol=MessagePackDocument()) + app = Application( + [SomeService], + "tns", + in_protocol=MessagePackDocument(), + out_protocol=MessagePackDocument(), + ) server = ServerBase(app) initial_ctx = MethodContext(server, MethodContext.SERVER) - initial_ctx.in_string = [b'\xdf'] # Invalid input - ctx, = server.generate_contexts(initial_ctx) - assert ctx.in_error.faultcode == 'Client.MessagePackDecodeError' + initial_ctx.in_string = [b"\xdf"] # Invalid input + (ctx,) = server.generate_contexts(initial_ctx) + assert ctx.in_error.faultcode == "Client.MessagePackDecodeError" def test_rpc(self): - data = {"a":"b", "c": "d"} + data = {"a": "b", "c": "d"} class KeyValuePair(ComplexModel): key = Unicode value = Unicode class SomeService(Service): - @rpc(String(max_occurs='unbounded'), - _returns=Array(KeyValuePair), - _in_variable_names={ - 'keys': 'key' - } - ) + @rpc( + String(max_occurs="unbounded"), + _returns=Array(KeyValuePair), + _in_variable_names={"keys": "key"}, + ) def get_values(ctx, keys): for k in keys: yield KeyValuePair(key=k, value=data[k]) - application = Application([SomeService], + application = Application( + [SomeService], in_protocol=MessagePackRpc(), out_protocol=MessagePackRpc(ignore_wrappers=False), - name='Service', tns='tns') + name="Service", + tns="tns", + ) server = WsgiApplication(application) input_string = msgpack.packb([0, 0, "get_values", [["a", "c"]]]) input_stream = BytesIO(input_string) - ret = server({ - 'CONTENT_LENGTH': str(len(input_string)), - 'CONTENT_TYPE': 'application/x-msgpack', - 'HTTP_CONNECTION': 'close', - 'HTTP_CONTENT_LENGTH': str(len(input_string)), - 'HTTP_CONTENT_TYPE': 'application/x-msgpack', - 'PATH_INFO': '/', - 'QUERY_STRING': '', - 'SERVER_NAME': 'localhost', - 'SERVER_PORT': '7000', - 'REQUEST_METHOD': 'POST', - 'wsgi.url_scheme': 'http', - 'wsgi.input': input_stream, - }, start_response) - - ret = b''.join(ret) + ret = server( + { + "CONTENT_LENGTH": str(len(input_string)), + "CONTENT_TYPE": "application/x-msgpack", + "HTTP_CONNECTION": "close", + "HTTP_CONTENT_LENGTH": str(len(input_string)), + "HTTP_CONTENT_TYPE": "application/x-msgpack", + "PATH_INFO": "/", + "QUERY_STRING": "", + "SERVER_NAME": "localhost", + "SERVER_PORT": "7000", + "REQUEST_METHOD": "POST", + "wsgi.url_scheme": "http", + "wsgi.input": input_stream, + }, + start_response, + ) + + ret = b"".join(ret) print(repr(ret)) ret = msgpack.unpackb(ret) print(repr(ret)) - s = [1, 0, None, {b'get_valuesResponse': { - b'get_valuesResult': [ - {b"KeyValuePair": {b'key': b'a', b'value': b'b'}}, - {b"KeyValuePair": {b'key': b'c', b'value': b'd'}}, - ] - }} + s = [ + 1, + 0, + None, + { + b"get_valuesResponse": { + b"get_valuesResult": [ + {b"KeyValuePair": {b"key": "a", b"value": "b"}}, + {b"KeyValuePair": {b"key": "c", b"value": "d"}}, + ] + } + }, ] print(s) assert ret == s -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/protocol/test_soap11.py b/spyne/test/protocol/test_soap11.py index 93af58ae9..7dd330887 100755 --- a/spyne/test/protocol/test_soap11.py +++ b/spyne/test/protocol/test_soap11.py @@ -24,29 +24,21 @@ import datetime import unittest -from lxml import etree import pytz +from lxml import etree from spyne import MethodContext from spyne.application import Application from spyne.decorator import rpc from spyne.interface.wsdl import Wsdl11 -from spyne.model.complex import Array -from spyne.model.complex import ComplexModel -from spyne.model.primitive import Unicode -from spyne.model.primitive import DateTime, Date -from spyne.model.primitive import Float -from spyne.model.primitive import Integer -from spyne.model.primitive import String +from spyne.model.complex import Array, ComplexModel from spyne.model.fault import Fault -from spyne.protocol.soap import Soap11 -from spyne.service import Service +from spyne.model.primitive import Date, DateTime, Float, Integer, String, Unicode +from spyne.protocol.soap import Soap11, _from_soap, _parse_xml_string from spyne.server import ServerBase +from spyne.service import Service -from spyne.protocol.soap import _from_soap -from spyne.protocol.soap import _parse_xml_string - -Application.transport = 'test' +Application.transport = "test" def start_response(code, headers): @@ -63,6 +55,7 @@ class Address(ComplexModel): laditude = Float longitude = Float + class Person(ComplexModel): __namespace__ = "TestService" @@ -72,34 +65,40 @@ class Person(ComplexModel): addresses = Array(Address) titles = Array(String) + class Request(ComplexModel): __namespace__ = "TestService" param1 = String param2 = Integer + class Response(ComplexModel): __namespace__ = "TestService" param1 = Float + class TypeNS1(ComplexModel): __namespace__ = "TestService.NS1" s = String i = Integer + class TypeNS2(ComplexModel): __namespace__ = "TestService.NS2" d = DateTime f = Float + class MultipleNamespaceService(Service): @rpc(TypeNS1, TypeNS2) def a(ctx, t1, t2): return "OK" + class TestService(Service): @rpc(String, _returns=String) def aa(ctx, s): @@ -121,98 +120,108 @@ def d(ctx, Person): def e(ctx, Person): pass - @rpc(String, String, String, _returns=String, - _in_variable_names={'_from': 'from', '_self': 'self', - '_import': 'import'}, - _out_variable_name="return") + @rpc( + String, + String, + String, + _returns=String, + _in_variable_names={"_from": "from", "_self": "self", "_import": "import"}, + _out_variable_name="return", + ) def f(ctx, _from, _self, _import): - return '1234' + return "1234" class MultipleReturnService(Service): @rpc(String, _returns=(String, String, String)) def multi(ctx, s): - return s, 'a', 'b' + return s, "a", "b" class TestSingle(unittest.TestCase): def setUp(self): - self.app = Application([TestService], 'tns', - in_protocol=Soap11(), out_protocol=Soap11()) - self.app.transport = 'null.spyne' + self.app = Application( + [TestService], "tns", in_protocol=Soap11(), out_protocol=Soap11() + ) + self.app.transport = "null.spyne" self.srv = TestService() wsdl = Wsdl11(self.app.interface) - wsdl.build_interface_document('URL') + wsdl.build_interface_document("URL") self.wsdl_str = wsdl.get_interface_document() self.wsdl_doc = etree.fromstring(self.wsdl_str) def test_portypes(self): - porttype = self.wsdl_doc.find('{http://schemas.xmlsoap.org/wsdl/}portType') - self.assertEqual( - len(self.srv.public_methods), len(porttype.getchildren())) + porttype = self.wsdl_doc.find("{http://schemas.xmlsoap.org/wsdl/}portType") + self.assertEqual(len(self.srv.public_methods), len(porttype.getchildren())) def test_override_param_names(self): - for n in [b'self', b'import', b'return', b'from']: + for n in [b"self", b"import", b"return", b"from"]: assert n in self.wsdl_str, '"%s" not in self.wsdl_str' + class TestReturn(unittest.TestCase): def setUp(self): - self.app = Application([MultipleReturnService], 'tns', in_protocol=Soap11(), out_protocol=Soap11()) - self.app.transport = 'none' + self.app = Application( + [MultipleReturnService], "tns", in_protocol=Soap11(), out_protocol=Soap11() + ) + self.app.transport = "none" self.wsdl = Wsdl11(self.app.interface) - self.wsdl.build_interface_document('URL') + self.wsdl.build_interface_document("URL") def test_multiple_return(self): - message_class = list(MultipleReturnService.public_methods.values())[0].out_message + message_class = list(MultipleReturnService.public_methods.values())[ + 0 + ].out_message message = message_class() self.assertEqual(len(message._type_info), 3) - sent_xml = etree.Element('test') - self.app.out_protocol.to_parent(None, message_class, ('a', 'b', 'c'), - sent_xml, self.app.tns) + sent_xml = etree.Element("test") + self.app.out_protocol.to_parent( + None, message_class, ("a", "b", "c"), sent_xml, self.app.tns + ) sent_xml = sent_xml[0] print((etree.tostring(sent_xml, pretty_print=True))) - response_data = self.app.out_protocol.from_element(None, message_class, sent_xml) + response_data = self.app.out_protocol.from_element( + None, message_class, sent_xml + ) self.assertEqual(len(response_data), 3) - self.assertEqual(response_data[0], 'a') - self.assertEqual(response_data[1], 'b') - self.assertEqual(response_data[2], 'c') + self.assertEqual(response_data[0], "a") + self.assertEqual(response_data[1], "b") + self.assertEqual(response_data[2], "c") class TestSoap11(unittest.TestCase): def test_simple_message(self): m = ComplexModel.produce( - namespace=None, - type_name='myMessage', - members={'s': String, 'i': Integer} + namespace=None, type_name="myMessage", members={"s": String, "i": Integer} ) - m.resolve_namespace(m, 'test') + m.resolve_namespace(m, "test") m_inst = m(s="a", i=43) - e = etree.Element('test') + e = etree.Element("test") Soap11().to_parent(None, m, m_inst, e, m.get_namespace()) - e=e[0] + e = e[0] - self.assertEqual(e.tag, '{%s}myMessage' % m.get_namespace()) + self.assertEqual(e.tag, "{%s}myMessage" % m.get_namespace()) - self.assertEqual(e.find('{%s}s' % m.get_namespace()).text, 'a') - self.assertEqual(e.find('{%s}i' % m.get_namespace()).text, '43') + self.assertEqual(e.find("{%s}s" % m.get_namespace()).text, "a") + self.assertEqual(e.find("{%s}i" % m.get_namespace()).text, "43") values = Soap11().from_element(None, m, e) - self.assertEqual('a', values.s) + self.assertEqual("a", values.s) self.assertEqual(43, values.i) def test_href(self): # the template. Start at pos 0, some servers complain if # xml tag is not in the first line. envelope_string = [ -b'''user2 -'''] +""" + ] - root, xmlids = _parse_xml_string(envelope_string, - etree.XMLParser(), 'utf8') + root, xmlids = _parse_xml_string(envelope_string, etree.XMLParser(), "utf8") header, payload = _from_soap(root, xmlids) # quick and dirty test href reconstruction @@ -247,44 +256,44 @@ def test_href(self): def test_namespaces(self): m = ComplexModel.produce( namespace="some_namespace", - type_name='myMessage', - members={'s': String, 'i': Integer}, + type_name="myMessage", + members={"s": String, "i": Integer}, ) mi = m() - mi.s = 'a' + mi.s = "a" - e = etree.Element('test') + e = etree.Element("test") Soap11().to_parent(None, m, mi, e, m.get_namespace()) - e=e[0] + e = e[0] - self.assertEqual(e.tag, '{some_namespace}myMessage') + self.assertEqual(e.tag, "{some_namespace}myMessage") def test_class_to_parent(self): m = ComplexModel.produce( - namespace=None, - type_name='myMessage', - members={'p': Person} + namespace=None, type_name="myMessage", members={"p": Person} ) m.resolve_namespace(m, "punk") m_inst = m() m_inst.p = Person() - m_inst.p.name = 'steve-o' + m_inst.p.name = "steve-o" m_inst.p.age = 2 m_inst.p.addresses = [] - element=etree.Element('test') + element = etree.Element("test") Soap11().to_parent(None, m, m_inst, element, m.get_namespace()) - element=element[0] + element = element[0] - self.assertEqual(element.tag, '{%s}myMessage' % m.get_namespace()) - self.assertEqual(element[0].find('{%s}name' % Person.get_namespace()).text, - 'steve-o') - self.assertEqual(element[0].find('{%s}age' % Person.get_namespace()).text, '2') + self.assertEqual(element.tag, "{%s}myMessage" % m.get_namespace()) self.assertEqual( - len(element[0].find('{%s}addresses' % Person.get_namespace())), 0) + element[0].find("{%s}name" % Person.get_namespace()).text, "steve-o" + ) + self.assertEqual(element[0].find("{%s}age" % Person.get_namespace()).text, "2") + self.assertEqual( + len(element[0].find("{%s}addresses" % Person.get_namespace())), 0 + ) p1 = Soap11().from_element(None, m, element)[0] @@ -297,16 +306,22 @@ def test_datetime_fixed_format(self): n = datetime.datetime.now(pytz.utc).replace(microsecond=0) format = "%Y %m %d %H %M %S" - element = etree.Element('test') - Soap11().to_parent(None, DateTime(dt_format=format), n, - element, 'some_namespace') + element = etree.Element("test") + Soap11().to_parent( + None, DateTime(dt_format=format), n, element, "some_namespace" + ) assert element[0].text == n.isoformat() dt = Soap11().from_element(None, DateTime(dt_format=format), element[0]) assert n == dt def test_date_with_tzoffset(self): - for iso_d in ('2013-04-05', '2013-04-05+02:00', '2013-04-05-02:00', '2013-04-05Z'): + for iso_d in ( + "2013-04-05", + "2013-04-05+02:00", + "2013-04-05-02:00", + "2013-04-05Z", + ): d = Soap11().from_unicode(Date, iso_d) assert isinstance(d, datetime.date) == True assert d.year == 2013 @@ -315,38 +330,37 @@ def test_date_with_tzoffset(self): def test_to_parent_nested(self): m = ComplexModel.produce( - namespace=None, - type_name='myMessage', - members={'p':Person} + namespace=None, type_name="myMessage", members={"p": Person} ) m.resolve_namespace(m, "m") p = Person() - p.name = 'steve-o' + p.name = "steve-o" p.age = 2 p.addresses = [] for i in range(0, 100): a = Address() - a.street = '123 happy way' + a.street = "123 happy way" a.zip = i - a.laditude = '45.22' - a.longitude = '444.234' + a.laditude = "45.22" + a.longitude = "444.234" p.addresses.append(a) m_inst = m(p=p) - element=etree.Element('test') + element = etree.Element("test") Soap11().to_parent(None, m, m_inst, element, m.get_namespace()) - element=element[0] + element = element[0] - self.assertEqual('{%s}myMessage' % m.get_namespace(), element.tag) + self.assertEqual("{%s}myMessage" % m.get_namespace(), element.tag) - addresses = element[0].find('{%s}addresses' % Person.get_namespace()) + addresses = element[0].find("{%s}addresses" % Person.get_namespace()) self.assertEqual(100, len(addresses)) - self.assertEqual('0', addresses[0].find('{%s}zip' % - Address.get_namespace()).text) + self.assertEqual( + "0", addresses[0].find("{%s}zip" % Address.get_namespace()).text + ) def test_fault_deserialization_missing_fault_actor(self): element = etree.fromstring(b""" @@ -371,45 +385,47 @@ def test_fault_deserialization_missing_fault_actor(self): # TestSoapHeader supporting classes. # SOAP Header Elements defined by WS-Addressing. -NAMESPACE_ADDRESSING = 'http://www.w3.org/2005/08/addressing' +NAMESPACE_ADDRESSING = "http://www.w3.org/2005/08/addressing" + -class Action (Unicode): +class Action(Unicode): __type_name__ = "Action" __namespace__ = NAMESPACE_ADDRESSING -class MessageID (Unicode): + +class MessageID(Unicode): __type_name__ = "MessageID" __namespace__ = NAMESPACE_ADDRESSING -class RelatesTo (Unicode): + +class RelatesTo(Unicode): __type_name__ = "RelatesTo" __namespace__ = NAMESPACE_ADDRESSING + class SOAPServiceWithHeader(Service): - @rpc(Unicode, - _in_header=(Action, - MessageID, - RelatesTo), - _out_variable_name= 'status', - _returns=Unicode - ) + @rpc( + Unicode, + _in_header=(Action, MessageID, RelatesTo), + _out_variable_name="status", + _returns=Unicode, + ) def someRequest(ctx, response): - print (response) - return 'OK' + print(response) + return "OK" + class TestSoapHeader(unittest.TestCase): def setUp(self): - self.app = Application([SOAPServiceWithHeader], - 'tns', - in_protocol=Soap11(), - out_protocol=Soap11()) + self.app = Application( + [SOAPServiceWithHeader], "tns", in_protocol=Soap11(), out_protocol=Soap11() + ) def test_soap_input_header(self): server = ServerBase(self.app) initial_ctx = MethodContext(server, MethodContext.SERVER) - initial_ctx.in_string = [ - b''' @@ -422,15 +438,14 @@ def test_soap_input_header(self): OK - ''' - ] + """] - ctx, = server.generate_contexts(initial_ctx, in_string_charset='utf8') + (ctx,) = server.generate_contexts(initial_ctx, in_string_charset="utf8") server.get_in_object(ctx) - self.assertEqual(ctx.in_header[0], '/SomeAction') - self.assertEqual(ctx.in_header[1], 'SomeMessageID') - self.assertEqual(ctx.in_header[2], 'SomeRelatesToID') + self.assertEqual(ctx.in_header[0], "/SomeAction") + self.assertEqual(ctx.in_header[1], "SomeMessageID") + self.assertEqual(ctx.in_header[2], "SomeRelatesToID") def test_soap_input_header_order(self): """ @@ -439,8 +454,7 @@ def test_soap_input_header_order(self): """ server = ServerBase(self.app) initial_ctx = MethodContext(server, MethodContext.SERVER) - initial_ctx.in_string = [ - b''' @@ -453,16 +467,14 @@ def test_soap_input_header_order(self): OK - ''' - ] + """] - ctx, = server.generate_contexts(initial_ctx, in_string_charset='utf8') + (ctx,) = server.generate_contexts(initial_ctx, in_string_charset="utf8") server.get_in_object(ctx) - self.assertEqual(ctx.in_header[0], '/SomeAction') - self.assertEqual(ctx.in_header[1], 'SomeMessageID') - self.assertEqual(ctx.in_header[2], 'SomeRelatesToID') - + self.assertEqual(ctx.in_header[0], "/SomeAction") + self.assertEqual(ctx.in_header[1], "SomeMessageID") + self.assertEqual(ctx.in_header[2], "SomeRelatesToID") def test_soap_input_header_order_and_missing(self): """ @@ -472,8 +484,7 @@ def test_soap_input_header_order_and_missing(self): """ server = ServerBase(self.app) initial_ctx = MethodContext(server, MethodContext.SERVER) - initial_ctx.in_string = [ - b''' @@ -485,16 +496,15 @@ def test_soap_input_header_order_and_missing(self): OK - ''' - ] + """] - ctx, = server.generate_contexts(initial_ctx, in_string_charset='utf8') + (ctx,) = server.generate_contexts(initial_ctx, in_string_charset="utf8") server.get_in_object(ctx) - self.assertEqual(ctx.in_header[0], '/SomeAction') - self.assertEqual(ctx.in_header[1], 'SomeMessageID') + self.assertEqual(ctx.in_header[0], "/SomeAction") + self.assertEqual(ctx.in_header[1], "SomeMessageID") self.assertEqual(ctx.in_header[2], None) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/protocol/test_soap12.py b/spyne/test/protocol/test_soap12.py index 9fc20656a..7e451bcc2 100755 --- a/spyne/test/protocol/test_soap12.py +++ b/spyne/test/protocol/test_soap12.py @@ -3,15 +3,16 @@ from __future__ import unicode_literals import unittest +from io import BytesIO from lxml import etree -from lxml.doctestcompare import LXMLOutputChecker, PARSE_XML +from lxml.doctestcompare import PARSE_XML, LXMLOutputChecker -from spyne import Fault, Unicode, ByteArray +from spyne import ByteArray, Fault, Unicode from spyne.application import Application from spyne.const import xml as ns from spyne.const.xml import NS_SOAP11_ENV -from spyne.decorator import srpc, rpc +from spyne.decorator import rpc, srpc from spyne.interface import Wsdl11 from spyne.model.complex import ComplexModel from spyne.model.primitive import Integer, String @@ -20,9 +21,12 @@ from spyne.protocol.xml import XmlDocument from spyne.server.wsgi import WsgiApplication from spyne.service import Service -from spyne.test.protocol.test_soap11 import TestService, TestSingle, \ - TestReturn, MultipleReturnService -from spyne.util.six import BytesIO +from spyne.test.protocol.test_soap11 import ( + MultipleReturnService, + TestReturn, + TestService, + TestSingle, +) def start_response(code, headers): @@ -67,22 +71,26 @@ class DownloadPartFileResult(ComplexModel): class TestSingleSoap12(TestSingle): def setUp(self): - self.app = Application([TestService], 'tns', in_protocol=Soap12(), out_protocol=Soap12()) - self.app.transport = 'null.spyne' + self.app = Application( + [TestService], "tns", in_protocol=Soap12(), out_protocol=Soap12() + ) + self.app.transport = "null.spyne" self.srv = TestService() wsdl = Wsdl11(self.app.interface) - wsdl.build_interface_document('URL') + wsdl.build_interface_document("URL") self.wsdl_str = wsdl.get_interface_document() self.wsdl_doc = etree.fromstring(self.wsdl_str) class TestMultipleSoap12(TestReturn): def setUp(self): - self.app = Application([MultipleReturnService], 'tns', in_protocol=Soap12(), out_protocol=Soap12()) - self.app.transport = 'none' + self.app = Application( + [MultipleReturnService], "tns", in_protocol=Soap12(), out_protocol=Soap12() + ) + self.app.transport = "none" self.wsdl = Wsdl11(self.app.interface) - self.wsdl.build_interface_document('URL') + self.wsdl.build_interface_document("URL") class TestSoap12(unittest.TestCase): @@ -116,9 +124,15 @@ class SoapException(Service): @srpc() def soap_exception(): raise Fault( - "Client.Plausible.issue", "A plausible fault", 'http://faultactor.example.com', - detail={'some':'extra info'}) - app = Application([SoapException], 'tns', in_protocol=Soap12(), out_protocol=Soap12()) + "Client.Plausible.issue", + "A plausible fault", + "http://faultactor.example.com", + detail={"some": "extra info"}, + ) + + app = Application( + [SoapException], "tns", in_protocol=Soap12(), out_protocol=Soap12() + ) req = b""" @@ -278,10 +330,11 @@ def test_bytes_join_attachment(self): - ''' % href_id + """ % href_id - (joinedmsg, numreplaces) = _join_attachment(NS_SOAP11_ENV, - href_id, envelope, payload) + joinedmsg, numreplaces = _join_attachment( + NS_SOAP11_ENV, href_id, envelope, payload + ) soaptree = etree.fromstring(joinedmsg) @@ -293,5 +346,5 @@ def test_bytes_join_attachment(self): self.assertEqual(payload, r.Data) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/protocol/test_xml.py b/spyne/test/protocol/test_xml.py index fc3cb0ee3..035afe68b 100755 --- a/spyne/test/protocol/test_xml.py +++ b/spyne/test/protocol/test_xml.py @@ -21,36 +21,39 @@ from __future__ import print_function import logging + logging.basicConfig(level=logging.DEBUG) +import datetime +import decimal import sys import unittest -import decimal -import datetime - -from pprint import pprint from base64 import b64encode +from io import BytesIO +from pprint import pprint from lxml import etree from lxml.builder import E -from spyne import MethodContext, rpc, ByteArray, File, AnyXml, Ignored -from spyne.context import FakeContext -from spyne.const import RESULT_SUFFIX -from spyne.service import Service -from spyne.server import ServerBase +from spyne import AnyXml, ByteArray, File, Ignored, MethodContext, rpc from spyne.application import Application +from spyne.const import RESULT_SUFFIX +from spyne.const.xml import NS_XSI +from spyne.context import FakeContext from spyne.decorator import srpc -from spyne.util.six import BytesIO -from spyne.model import Fault, Integer, Decimal, Unicode, Date, DateTime, \ - XmlData, Array, ComplexModel, XmlAttribute, Mandatory as M -from spyne.protocol.xml import XmlDocument, SchemaValidationError - -from spyne.util import six -from spyne.util.xml import get_xml_as_object, get_object_as_xml, \ - get_object_as_xml_polymorphic, get_xml_as_object_polymorphic +from spyne.model import Array, ComplexModel, Date, DateTime, Decimal, Fault, Integer +from spyne.model import Mandatory as M +from spyne.model import Unicode, XmlAttribute, XmlData +from spyne.protocol.xml import SchemaValidationError, XmlDocument +from spyne.server import ServerBase from spyne.server.wsgi import WsgiApplication -from spyne.const.xml import NS_XSI +from spyne.service import Service +from spyne.util.xml import ( + get_object_as_xml, + get_object_as_xml_polymorphic, + get_xml_as_object, + get_xml_as_object_polymorphic, +) class TestXml(unittest.TestCase): @@ -58,16 +61,16 @@ def test_empty_string(self): class a(ComplexModel): b = Unicode - elt = etree.fromstring('') + elt = etree.fromstring("") o = get_xml_as_object(elt, a) - assert o.b == '' + assert o.b == "" def test_ignored(self): - d = decimal.Decimal('1e100') + d = decimal.Decimal("1e100") class SomeService(Service): - @srpc(Decimal(120,4), _returns=Decimal) + @srpc(Decimal(120, 4), _returns=Decimal) def some_call(p): print(p) print(type(p)) @@ -75,27 +78,27 @@ def some_call(p): assert d == p return Ignored(p) - app = Application([SomeService], "tns", in_protocol=XmlDocument(), - out_protocol=XmlDocument()) + app = Application( + [SomeService], "tns", in_protocol=XmlDocument(), out_protocol=XmlDocument() + ) server = ServerBase(app) initial_ctx = MethodContext(server, MethodContext.SERVER) initial_ctx.in_string = [ b'

', - str(d).encode('ascii'), - b'

' + str(d).encode("ascii"), + b"

", ] - ctx, = server.generate_contexts(initial_ctx) + (ctx,) = server.generate_contexts(initial_ctx) server.get_in_object(ctx) server.get_out_object(ctx) server.get_out_string(ctx) - elt = etree.fromstring(b''.join(ctx.out_string)) + elt = etree.fromstring(b"".join(ctx.out_string)) - logging.info(etree.tostring(elt, pretty_print=True).decode('utf8')) + logging.info(etree.tostring(elt, pretty_print=True).decode("utf8")) assert 0 == len(list(elt)) - def test_xml_data(self): class C(ComplexModel): a = XmlData(Unicode) @@ -104,21 +107,24 @@ class C(ComplexModel): class SomeService(Service): @srpc(C, _returns=C) def some_call(c): - assert c.a == 'a' - assert c.b == 'b' + assert c.a == "a" + assert c.b == "b" return c - app = Application([SomeService], "tns", name="test_xml_data", - in_protocol=XmlDocument(), out_protocol=XmlDocument()) + app = Application( + [SomeService], + "tns", + name="test_xml_data", + in_protocol=XmlDocument(), + out_protocol=XmlDocument(), + ) server = ServerBase(app) initial_ctx = MethodContext(server, MethodContext.SERVER) initial_ctx.in_string = [ - b'' - b'a' - b'' + b'' b'a' b"" ] - ctx, = server.generate_contexts(initial_ctx) + (ctx,) = server.generate_contexts(initial_ctx) server.get_in_object(ctx) server.get_out_object(ctx) server.get_out_string(ctx) @@ -126,41 +132,42 @@ def some_call(c): print(ctx.out_string) pprint(app.interface.nsmap) - ret = etree.fromstring(b''.join(ctx.out_string)).xpath( - '//tns:some_call' + RESULT_SUFFIX, namespaces=app.interface.nsmap)[0] + ret = etree.fromstring(b"".join(ctx.out_string)).xpath( + "//tns:some_call" + RESULT_SUFFIX, namespaces=app.interface.nsmap + )[0] print(etree.tostring(ret, pretty_print=True)) assert ret.text == "a" - assert ret.attrib['b'] == "b" + assert ret.attrib["b"] == "b" def test_wrapped_array(self): - parent = etree.Element('parent') - val = ['a', 'b'] - cls = Array(Unicode, namespace='tns') - XmlDocument().to_parent(None, cls, val, parent, 'tns') + parent = etree.Element("parent") + val = ["a", "b"] + cls = Array(Unicode, namespace="tns") + XmlDocument().to_parent(None, cls, val, parent, "tns") print(etree.tostring(parent, pretty_print=True)) - xpath = parent.xpath('//x:stringArray/x:string/text()', - namespaces={'x': 'tns'}) + xpath = parent.xpath("//x:stringArray/x:string/text()", namespaces={"x": "tns"}) assert xpath == val def test_simple_array(self): class cls(ComplexModel): - __namespace__ = 'tns' - s = Unicode(max_occurs='unbounded') - val = cls(s=['a', 'b']) + __namespace__ = "tns" + s = Unicode(max_occurs="unbounded") + + val = cls(s=["a", "b"]) - parent = etree.Element('parent') - XmlDocument().to_parent(None, cls, val, parent, 'tns') + parent = etree.Element("parent") + XmlDocument().to_parent(None, cls, val, parent, "tns") print(etree.tostring(parent, pretty_print=True)) - xpath = parent.xpath('//x:cls/x:s/text()', namespaces={'x': 'tns'}) + xpath = parent.xpath("//x:cls/x:s/text()", namespaces={"x": "tns"}) assert xpath == val.s def test_decimal(self): - d = decimal.Decimal('1e100') + d = decimal.Decimal("1e100") class SomeService(Service): - @srpc(Decimal(120,4), _returns=Decimal) + @srpc(Decimal(120, 4), _returns=Decimal) def some_call(p): print(p) print(type(p)) @@ -168,32 +175,34 @@ def some_call(p): assert d == p return p - app = Application([SomeService], "tns", in_protocol=XmlDocument(), - out_protocol=XmlDocument()) + app = Application( + [SomeService], "tns", in_protocol=XmlDocument(), out_protocol=XmlDocument() + ) server = ServerBase(app) initial_ctx = MethodContext(server, MethodContext.SERVER) initial_ctx.in_string = [ b'

', - str(d).encode('ascii'), - b'

' + str(d).encode("ascii"), + b"

", ] - ctx, = server.generate_contexts(initial_ctx) + (ctx,) = server.generate_contexts(initial_ctx) server.get_in_object(ctx) server.get_out_object(ctx) server.get_out_string(ctx) - elt = etree.fromstring(b''.join(ctx.out_string)) + elt = etree.fromstring(b"".join(ctx.out_string)) print(etree.tostring(elt, pretty_print=True)) - target = elt.xpath('//tns:some_callResult/text()', - namespaces=app.interface.nsmap)[0] + target = elt.xpath( + "//tns:some_callResult/text()", namespaces=app.interface.nsmap + )[0] assert target == str(d) def test_subs(self): from lxml import etree - from spyne.util.xml import get_xml_as_object - from spyne.util.xml import get_object_as_xml + + from spyne.util.xml import get_object_as_xml, get_xml_as_object m = { "s0": "aa", @@ -211,9 +220,9 @@ class C(ComplexModel): elt = get_object_as_xml(C(a=1, b=2, c=3, d=4), C) print(etree.tostring(elt, pretty_print=True)) - assert elt.xpath("s0:a/text()", namespaces=m) == ["1"] + assert elt.xpath("s0:a/text()", namespaces=m) == ["1"] assert elt.xpath("s0:bb/text()", namespaces=m) == ["2"] - assert elt.xpath("s2:c/text()", namespaces=m) == ["3"] + assert elt.xpath("s2:c/text()", namespaces=m) == ["3"] assert elt.xpath("s3:dd/text()", namespaces=m) == ["4"] c = get_xml_as_object(elt, C) @@ -225,8 +234,8 @@ class C(ComplexModel): def test_sub_attributes(self): from lxml import etree - from spyne.util.xml import get_xml_as_object - from spyne.util.xml import get_object_as_xml + + from spyne.util.xml import get_object_as_xml, get_xml_as_object m = { "s0": "aa", @@ -244,9 +253,9 @@ class C(ComplexModel): elt = get_object_as_xml(C(a=1, b=2, c=3, d=4), C) print(etree.tostring(elt, pretty_print=True)) - assert elt.xpath("//*/@a") == ["1"] + assert elt.xpath("//*/@a") == ["1"] assert elt.xpath("//*/@bb") == ["2"] - assert elt.xpath("//*/@s2:c", namespaces=m) == ["3"] + assert elt.xpath("//*/@s2:c", namespaces=m) == ["3"] assert elt.xpath("//*/@s3:dd", namespaces=m) == ["4"] c = get_xml_as_object(elt, C) @@ -259,10 +268,10 @@ class C(ComplexModel): def test_dates(self): d = Date xml_dates = [ - etree.fromstring(b'2013-04-05'), - etree.fromstring(b'2013-04-05+02:00'), - etree.fromstring(b'2013-04-05-02:00'), - etree.fromstring(b'2013-04-05Z'), + etree.fromstring(b"2013-04-05"), + etree.fromstring(b"2013-04-05+02:00"), + etree.fromstring(b"2013-04-05-02:00"), + etree.fromstring(b"2013-04-05Z"), ] for xml_date in xml_dates: @@ -274,29 +283,26 @@ def test_dates(self): def test_datetime_usec(self): fs = etree.fromstring - d = get_xml_as_object(fs('2013-04-05T06:07:08.123456'), DateTime) + d = get_xml_as_object(fs("2013-04-05T06:07:08.123456"), DateTime) assert d.microsecond == 123456 # rounds up - d = get_xml_as_object(fs('2013-04-05T06:07:08.1234567'), DateTime) + d = get_xml_as_object(fs("2013-04-05T06:07:08.1234567"), DateTime) assert d.microsecond == 123457 # rounds down - d = get_xml_as_object(fs('2013-04-05T06:07:08.1234564'), DateTime) + d = get_xml_as_object(fs("2013-04-05T06:07:08.1234564"), DateTime) assert d.microsecond == 123456 # rounds up as well - d = get_xml_as_object(fs('2013-04-05T06:07:08.1234565'), DateTime) + d = get_xml_as_object(fs("2013-04-05T06:07:08.1234565"), DateTime) # FIXME: this is very interesting. why? - if not six.PY2: - assert d.microsecond == 123456 - else: - assert d.microsecond == 123457 + assert d.microsecond == 123456 def _get_ctx(self, server, in_string): initial_ctx = MethodContext(server, MethodContext.SERVER) initial_ctx.in_string = in_string - ctx, = server.generate_contexts(initial_ctx) + (ctx,) = server.generate_contexts(initial_ctx) server.get_in_object(ctx) return ctx @@ -304,65 +310,73 @@ def test_mandatory_elements(self): class SomeService(Service): @srpc(M(Unicode), _returns=Unicode) def some_call(s): - assert s == 'hello' + assert s == "hello" return s - app = Application([SomeService], "tns", name="test_mandatory_elements", - in_protocol=XmlDocument(validator='lxml'), - out_protocol=XmlDocument()) + app = Application( + [SomeService], + "tns", + name="test_mandatory_elements", + in_protocol=XmlDocument(validator="lxml"), + out_protocol=XmlDocument(), + ) server = ServerBase(app) # Valid call with all mandatory elements in - ctx = self._get_ctx(server, [ - b'' - b'hello' - b'' - ]) + ctx = self._get_ctx( + server, [b'' b"hello" b""] + ) server.get_out_object(ctx) server.get_out_string(ctx) - ret = etree.fromstring(b''.join(ctx.out_string)).xpath( - '//tns:some_call%s/text()' % RESULT_SUFFIX, - namespaces=app.interface.nsmap)[0] - assert ret == 'hello' + ret = etree.fromstring(b"".join(ctx.out_string)).xpath( + "//tns:some_call%s/text()" % RESULT_SUFFIX, namespaces=app.interface.nsmap + )[0] + assert ret == "hello" # Invalid call - ctx = self._get_ctx(server, [ - b'' + ctx = self._get_ctx( + server, + [ + b'' # no mandatory elements here... - b'' - ]) + b"" + ], + ) self.assertRaises(SchemaValidationError, server.get_out_object, ctx) def test_unicode_chars_in_exception(self): class SomeService(Service): - @srpc(Unicode(pattern=u'x'), _returns=Unicode) + @srpc(Unicode(pattern="x"), _returns=Unicode) def some_call(s): test(should, never, reach, here) - app = Application([SomeService], "tns", name="test_mandatory_elements", - in_protocol=XmlDocument(validator='lxml'), - out_protocol=XmlDocument()) + app = Application( + [SomeService], + "tns", + name="test_mandatory_elements", + in_protocol=XmlDocument(validator="lxml"), + out_protocol=XmlDocument(), + ) server = WsgiApplication(app) - req = ( - u'' - u'Ğ' - u'' - ).encode('utf8') + req = ('' "Ğ" "").encode("utf8") print("AAA") - resp = server({ - 'QUERY_STRING': '', - 'PATH_INFO': '/', - 'REQUEST_METHOD': 'POST', - 'SERVER_NAME': 'localhost', - 'SERVER_PORT': '80', - 'wsgi.input': BytesIO(req), - "wsgi.url_scheme": 'http', - }, lambda x, y: print(x,y)) + resp = server( + { + "QUERY_STRING": "", + "PATH_INFO": "/", + "REQUEST_METHOD": "POST", + "SERVER_NAME": "localhost", + "SERVER_PORT": "80", + "wsgi.input": BytesIO(req), + "wsgi.url_scheme": "http", + }, + lambda x, y: print(x, y), + ) print("AAA") - assert u'Ğ'.encode('utf8') in b''.join(resp) + assert "Ğ".encode("utf8") in b"".join(resp) def test_mandatory_subelements(self): class C(ComplexModel): @@ -372,29 +386,38 @@ class SomeService(Service): @srpc(C.customize(min_occurs=1), _returns=Unicode) def some_call(c): assert c is not None - assert c.foo == 'hello' + assert c.foo == "hello" return c.foo app = Application( - [SomeService], "tns", name="test_mandatory_subelements", - in_protocol=XmlDocument(validator='lxml'), - out_protocol=XmlDocument()) + [SomeService], + "tns", + name="test_mandatory_subelements", + in_protocol=XmlDocument(validator="lxml"), + out_protocol=XmlDocument(), + ) server = ServerBase(app) - ctx = self._get_ctx(server, [ - b'' + ctx = self._get_ctx( + server, + [ + b'' # no mandatory elements at all... - b'' - ]) + b"" + ], + ) self.assertRaises(SchemaValidationError, server.get_out_object, ctx) - ctx = self._get_ctx(server, [ - b'' - b'' - # no mandatory elements here... - b'' - b'' - ]) + ctx = self._get_ctx( + server, + [ + b'' + b"" + # no mandatory elements here... + b"" + b"" + ], + ) self.assertRaises(SchemaValidationError, server.get_out_object, ctx) def test_mandatory_element_attributes(self): @@ -405,30 +428,39 @@ class SomeService(Service): @srpc(C.customize(min_occurs=1), _returns=Unicode) def some_call(c): assert c is not None - assert hasattr(c, 'foo') - assert c.foo == 'hello' + assert hasattr(c, "foo") + assert c.foo == "hello" return c.foo app = Application( - [SomeService], "tns", name="test_mandatory_element_attributes", - in_protocol=XmlDocument(validator='lxml'), - out_protocol=XmlDocument()) + [SomeService], + "tns", + name="test_mandatory_element_attributes", + in_protocol=XmlDocument(validator="lxml"), + out_protocol=XmlDocument(), + ) server = ServerBase(app) - ctx = self._get_ctx(server, [ - b'' + ctx = self._get_ctx( + server, + [ + b'' # no mandatory elements at all... - b'' - ]) + b"" + ], + ) self.assertRaises(SchemaValidationError, server.get_out_object, ctx) - ctx = self._get_ctx(server, [ - b'' - b'' - # no mandatory elements here... - b'' - b'' - ]) + ctx = self._get_ctx( + server, + [ + b'' + b"" + # no mandatory elements here... + b"" + b"" + ], + ) self.assertRaises(SchemaValidationError, server.get_out_object, ctx) def test_bare_sub_name_ns(self): @@ -436,33 +468,37 @@ class Action(ComplexModel): class Attributes(ComplexModel.Attributes): sub_ns = "SOME_NS" sub_name = "Action" + data = XmlData(Unicode) must_understand = XmlAttribute(Unicode) elt = get_object_as_xml(Action("x", must_understand="y"), Action) eltstr = etree.tostring(elt) print(eltstr) - assert eltstr == b'x' + assert ( + eltstr + == b'x' + ) def test_null_mandatory_attribute(self): - class Action (ComplexModel): + class Action(ComplexModel): data = XmlAttribute(M(Unicode)) elt = get_object_as_xml(Action(), Action) eltstr = etree.tostring(elt) print(eltstr) - assert eltstr == b'' + assert eltstr == b"" def test_bytearray(self): - v = b'aaaa' - elt = get_object_as_xml([v], ByteArray, 'B') + v = b"aaaa" + elt = get_object_as_xml([v], ByteArray, "B") eltstr = etree.tostring(elt) print(eltstr) - assert elt.text == b64encode(v).decode('ascii') + assert elt.text == b64encode(v).decode("ascii") def test_any_xml_text(self): - v = u"" - elt = get_object_as_xml(v, AnyXml, 'B', no_namespace=True) + v = "" + elt = get_object_as_xml(v, AnyXml, "B", no_namespace=True) eltstr = etree.tostring(elt) print(eltstr) assert etree.tostring(elt[0], encoding="unicode") == v @@ -470,78 +506,81 @@ def test_any_xml_text(self): def test_any_xml_bytes(self): v = b"" - elt = get_object_as_xml(v, AnyXml, 'B', no_namespace=True) + elt = get_object_as_xml(v, AnyXml, "B", no_namespace=True) eltstr = etree.tostring(elt) print(eltstr) assert etree.tostring(elt[0]) == v def test_any_xml_elt(self): v = E.roots(E.bloody(E.roots())) - elt = get_object_as_xml(v, AnyXml, 'B') + elt = get_object_as_xml(v, AnyXml, "B") eltstr = etree.tostring(elt) print(eltstr) assert etree.tostring(elt[0]) == etree.tostring(v) def test_file(self): - v = b'aaaa' + v = b"aaaa" f = BytesIO(v) - elt = get_object_as_xml(File.Value(handle=f), File, 'B') + elt = get_object_as_xml(File.Value(handle=f), File, "B") eltstr = etree.tostring(elt) print(eltstr) - assert elt.text == b64encode(v).decode('ascii') + assert elt.text == b64encode(v).decode("ascii") def test_fault_detail_as_dict(self): elt = get_object_as_xml(Fault(detail={"this": "that"}), Fault) eltstr = etree.tostring(elt) print(eltstr) - assert b'that' in eltstr + assert b"that" in eltstr def test_xml_encoding(self): - ctx = FakeContext(out_document=E.rain(u"yağmur")) - XmlDocument(encoding='iso-8859-9').create_out_string(ctx) - s = b''.join(ctx.out_string) - assert u"ğ".encode('iso-8859-9') in s + ctx = FakeContext(out_document=E.rain("yağmur")) + XmlDocument(encoding="iso-8859-9").create_out_string(ctx) + s = b"".join(ctx.out_string) + assert "ğ".encode("iso-8859-9") in s def test_default(self): class SomeComplexModel(ComplexModel): _type_info = [ - ('a', Unicode), - ('b', Unicode(default='default')), + ("a", Unicode), + ("b", Unicode(default="default")), ] obj = XmlDocument().from_element( - None, SomeComplexModel, + None, + SomeComplexModel, etree.fromstring(""" string - """) + """), ) # xml schema says it should be None - assert obj.b == 'default' + assert obj.b == "default" obj = XmlDocument().from_element( - None, SomeComplexModel, + None, + SomeComplexModel, etree.fromstring(""" string - """ % NS_XSI) + """ % NS_XSI), ) # xml schema says it should be 'default' - assert obj.b == 'default' + assert obj.b == "default" obj = XmlDocument(replace_null_with_default=False).from_element( - None, SomeComplexModel, + None, + SomeComplexModel, etree.fromstring(""" string - """ % NS_XSI) + """ % NS_XSI), ) # xml schema says it should be 'default' @@ -550,9 +589,9 @@ class SomeComplexModel(ComplexModel): def test_polymorphic_roundtrip(self): class B(ComplexModel): - __namespace__ = 'some_ns' + __namespace__ = "some_ns" _type_info = { - '_b': Unicode, + "_b": Unicode, } def __init__(self): @@ -560,9 +599,9 @@ def __init__(self): self._b = "b" class C(B): - __namespace__ = 'some_ns' + __namespace__ = "some_ns" _type_info = { - '_c': Unicode, + "_c": Unicode, } def __init__(self): @@ -570,24 +609,21 @@ def __init__(self): self._c = "c" class A(ComplexModel): - __namespace__ = 'some_ns' + __namespace__ = "some_ns" _type_info = { - '_a': Unicode, - '_b': B, + "_a": Unicode, + "_b": B, } def __init__(self, b=None): super(A, self).__init__() - self._a = 'a' + self._a = "a" self._b = b a = A(b=C()) elt = get_object_as_xml_polymorphic(a, A) xml_string = etree.tostring(elt, pretty_print=True) - if six.PY2: - print(xml_string, end="") - else: - sys.stdout.buffer.write(xml_string) + sys.stdout.buffer.write(xml_string) element_tree = etree.fromstring(xml_string) new_a = get_xml_as_object_polymorphic(elt, A) @@ -603,26 +639,25 @@ class SomeComplexModel(ComplexModel): s = Unicode i = Integer - v = SomeComplexModel(s='a', i=1), + v = (SomeComplexModel(s="a", i=1),) class SomeService(Service): @rpc(_returns=SomeComplexModel) def get(ctx): return v - desc = SomeService.public_methods['get'] + desc = SomeService.public_methods["get"] ctx = FakeContext(out_object=v, descriptor=desc) ostr = ctx.out_stream = BytesIO() - XmlDocument(Application([SomeService], __name__)) \ - .serialize(ctx, XmlDocument.RESPONSE) + XmlDocument(Application([SomeService], __name__)).serialize( + ctx, XmlDocument.RESPONSE + ) elt = etree.fromstring(ostr.getvalue()) print(etree.tostring(elt, pretty_print=True)) - assert elt.xpath('x:getResult/x:i/text()', - namespaces={'x':__name__}) == ['1'] - assert elt.xpath('x:getResult/x:s/text()', - namespaces={'x':__name__}) == ['a'] + assert elt.xpath("x:getResult/x:i/text()", namespaces={"x": __name__}) == ["1"] + assert elt.xpath("x:getResult/x:s/text()", namespaces={"x": __name__}) == ["a"] def test_many(self): class SomeComplexModel(ComplexModel): @@ -630,11 +665,11 @@ class SomeComplexModel(ComplexModel): i = Integer v = [ - SomeComplexModel(s='a', i=1), - SomeComplexModel(s='b', i=2), - SomeComplexModel(s='c', i=3), - SomeComplexModel(s='d', i=4), - SomeComplexModel(s='e', i=5), + SomeComplexModel(s="a", i=1), + SomeComplexModel(s="b", i=2), + SomeComplexModel(s="c", i=3), + SomeComplexModel(s="d", i=4), + SomeComplexModel(s="e", i=5), ] class SomeService(Service): @@ -642,20 +677,23 @@ class SomeService(Service): def get(ctx): return v - desc = SomeService.public_methods['get'] + desc = SomeService.public_methods["get"] ctx = FakeContext(out_object=[v], descriptor=desc) ostr = ctx.out_stream = BytesIO() - XmlDocument(Application([SomeService], __name__)) \ - .serialize(ctx, XmlDocument.RESPONSE) + XmlDocument(Application([SomeService], __name__)).serialize( + ctx, XmlDocument.RESPONSE + ) elt = etree.fromstring(ostr.getvalue()) print(etree.tostring(elt, pretty_print=True)) - assert elt.xpath('x:getResult/x:SomeComplexModel/x:i/text()', - namespaces={'x': __name__}) == ['1', '2', '3', '4', '5'] - assert elt.xpath('x:getResult/x:SomeComplexModel/x:s/text()', - namespaces={'x': __name__}) == ['a', 'b', 'c', 'd', 'e'] + assert elt.xpath( + "x:getResult/x:SomeComplexModel/x:i/text()", namespaces={"x": __name__} + ) == ["1", "2", "3", "4", "5"] + assert elt.xpath( + "x:getResult/x:SomeComplexModel/x:s/text()", namespaces={"x": __name__} + ) == ["a", "b", "c", "d", "e"] -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/protocol/test_yaml.py b/spyne/test/protocol/test_yaml.py index 2cb224c8c..a4d1a73a1 100755 --- a/spyne/test/protocol/test_yaml.py +++ b/spyne/test/protocol/test_yaml.py @@ -19,16 +19,14 @@ import unittest -from spyne.test.protocol._test_dictdoc import TDictDocumentTest -from spyne.protocol.yaml import YamlDocument - from spyne import MethodContext from spyne.application import Application from spyne.decorator import srpc -from spyne.service import Service +from spyne.protocol.yaml import YamlDocument, yaml from spyne.server import ServerBase +from spyne.service import Service +from spyne.test.protocol._test_dictdoc import TDictDocumentTest -from spyne.protocol.yaml import yaml yaml.dumps = yaml.dump yaml.loads = yaml.load @@ -42,17 +40,20 @@ class SomeService(Service): def yay(): pass - app = Application([SomeService], 'tns', - in_protocol=YamlDocument(), - out_protocol=YamlDocument()) + app = Application( + [SomeService], + "tns", + in_protocol=YamlDocument(), + out_protocol=YamlDocument(), + ) server = ServerBase(app) initial_ctx = MethodContext(server, MethodContext.SERVER) - initial_ctx.in_string = [b'{'] - ctx, = server.generate_contexts(initial_ctx) - assert ctx.in_error.faultcode == 'Client.YamlDecodeError' + initial_ctx.in_string = [b"{"] + (ctx,) = server.generate_contexts(initial_ctx) + assert ctx.in_error.faultcode == "Client.YamlDecodeError" -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/regen_wsdl.py b/spyne/test/regen_wsdl.py index 2ad5f75d6..b04d0eb7d 100755 --- a/spyne/test/regen_wsdl.py +++ b/spyne/test/regen_wsdl.py @@ -1,16 +1,16 @@ #!/usr/bin/env python from lxml import etree -from spyne.test.sort_wsdl import sort_wsdl -from spyne.interface.wsdl import Wsdl11 -from spyne.test.interop.server._service import services from spyne.application import Application +from spyne.interface.wsdl import Wsdl11 +from spyne.test.interop.server._service import services +from spyne.test.sort_wsdl import sort_wsdl -app = Application(services, 'spyne.test.interop.server') -app.transport = 'http://schemas.xmlsoap.org/soap/http' +app = Application(services, "spyne.test.interop.server") +app.transport = "http://schemas.xmlsoap.org/soap/http" wsdl = Wsdl11(app.interface) -wsdl.build_interface_document('http://localhost:9754/') +wsdl.build_interface_document("http://localhost:9754/") elt = etree.ElementTree(etree.fromstring(wsdl.get_interface_document())) sort_wsdl(elt) s = etree.tostring(elt) @@ -18,9 +18,10 @@ # minidom's serialization seems to put attributes in alphabetic order. # this is exactly what we want here. from xml.dom.minidom import parseString + doc = parseString(s) -s = doc.toprettyxml(indent=' ', newl='\n', encoding='utf8') -s = s.replace(" xmlns:","\n xmlns:") +s = doc.toprettyxml(indent=" ", newl="\n", encoding="utf8") +s = s.replace(" xmlns:", "\n xmlns:") -open('wsdl.xml', 'w').write(s) -print('wsdl.xml written') +open("wsdl.xml", "w").write(s) +print("wsdl.xml written") diff --git a/spyne/test/sort_wsdl.py b/spyne/test/sort_wsdl.py index 96a45810b..4802c89c2 100755 --- a/spyne/test/sort_wsdl.py +++ b/spyne/test/sort_wsdl.py @@ -30,13 +30,13 @@ def cache_order(l, ns): - return dict([ ("{%s}%s" % (ns, a), l.index(a)) for a in l]) + return dict([("{%s}%s" % (ns, a), l.index(a)) for a in l]) -wsdl_order = ('types', 'message', 'service', 'portType', 'binding') +wsdl_order = ("types", "message", "service", "portType", "binding") wsdl_order = cache_order(wsdl_order, ns_wsdl) -schema_order = ('import', 'element', 'simpleType', 'complexType', 'attribute') +schema_order = ("import", "element", "simpleType", "complexType", "attribute") schema_order = cache_order(schema_order, ns_schema) parser = etree.XMLParser(remove_blank_text=True) @@ -62,17 +62,21 @@ def sort_wsdl(tree): l0.append(e) e.getparent().remove(e) - l0.sort(key=lambda e: (wsdl_order[e.tag], e.attrib['name'])) + l0.sort(key=lambda e: (wsdl_order[e.tag], e.attrib["name"])) for e in l0: tree.getroot().append(e) for e in tree.getroot(): - if e.tag in ("{%s}portType" % ns_wsdl, "{%s}binding" % ns_wsdl, "{%s}operation" % ns_wsdl): + if e.tag in ( + "{%s}portType" % ns_wsdl, + "{%s}binding" % ns_wsdl, + "{%s}operation" % ns_wsdl, + ): nodes = [] for p in e.getchildren(): nodes.append(p) - nodes.sort(key=lambda e: e.attrib.get('name', '0')) + nodes.sort(key=lambda e: e.attrib.get("name", "0")) for p in nodes: e.append(p) @@ -94,11 +98,11 @@ def sort_wsdl(tree): nodes.append(e) e.getparent().remove(e) - nodes.sort(key=lambda e: (schema_order[e.tag], e.attrib.get('name', '\0'))) + nodes.sort(key=lambda e: (schema_order[e.tag], e.attrib.get("name", "\0"))) for e in nodes: s.append(e) -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(main()) diff --git a/spyne/test/test_null_server.py b/spyne/test/test_null_server.py index d127e4ec6..0e6323751 100755 --- a/spyne/test/test_null_server.py +++ b/spyne/test/test_null_server.py @@ -22,18 +22,16 @@ from lxml import etree -from spyne import Ignored -from spyne import const -from spyne.interface.wsdl import Wsdl11 -from spyne.protocol.xml import XmlDocument - -from spyne.model.complex import Array -from spyne.model.primitive import Boolean -from spyne.model.primitive import String +from spyne import Ignored, const from spyne.application import Application from spyne.decorator import srpc -from spyne.service import Service +from spyne.interface.wsdl import Wsdl11 +from spyne.model.complex import Array +from spyne.model.primitive import Boolean, String +from spyne.protocol.xml import XmlDocument from spyne.server.null import NullServer +from spyne.service import Service + class TestNullServer(unittest.TestCase): def test_empty_return_type(self): @@ -42,8 +40,12 @@ class MessageService(Service): def send_message(s): return s - application = Application([MessageService], 'some_tns', - in_protocol=XmlDocument(), out_protocol=XmlDocument()) + application = Application( + [MessageService], + "some_tns", + in_protocol=XmlDocument(), + out_protocol=XmlDocument(), + ) assert None == NullServer(application).service.send_message("zabaaa") @@ -61,8 +63,12 @@ def send_message_2(s): def send_message_3(s): return "OK" - application = Application([MessageService], 'some_tns', - in_protocol=XmlDocument(), out_protocol=XmlDocument()) + application = Application( + [MessageService], + "some_tns", + in_protocol=XmlDocument(), + out_protocol=XmlDocument(), + ) server = NullServer(application) assert Ignored("xyz") == server.service.send_message_1("zabaaa") @@ -77,8 +83,12 @@ class MessageService(Service): def send_message(s): queue.add(s) - application = Application([MessageService], 'some_tns', - in_protocol=XmlDocument(), out_protocol=XmlDocument()) + application = Application( + [MessageService], + "some_tns", + in_protocol=XmlDocument(), + out_protocol=XmlDocument(), + ) server = NullServer(application) server.service.send_message("zabaaa") @@ -91,20 +101,24 @@ def test_call_two_args(self): class MessageService(Service): @srpc(String, String) def send_message(s, k): - queue.add((s,k)) + queue.add((s, k)) - application = Application([MessageService], 'some_tns', - in_protocol=XmlDocument(), out_protocol=XmlDocument()) + application = Application( + [MessageService], + "some_tns", + in_protocol=XmlDocument(), + out_protocol=XmlDocument(), + ) server = NullServer(application) queue.clear() server.service.send_message("zabaaa", k="hobaa") - assert set([("zabaaa","hobaa")]) == queue + assert set([("zabaaa", "hobaa")]) == queue queue.clear() server.service.send_message(k="hobaa") - assert set([(None,"hobaa")]) == queue + assert set([(None, "hobaa")]) == queue queue.clear() server.service.send_message("zobaaa", s="hobaa") @@ -119,20 +133,25 @@ def send_message(s, k): queue.add((s, k)) return [s, k] - application = Application([MessageService], 'some_tns', - in_protocol=XmlDocument(), out_protocol=XmlDocument()) + application = Application( + [MessageService], + "some_tns", + in_protocol=XmlDocument(), + out_protocol=XmlDocument(), + ) ostr_server = NullServer(application, ostr=True) queue.clear() ret = ostr_server.service.send_message("zabaaa", k="hobaa") - assert set([("zabaaa","hobaa")]) == queue - assert etree.fromstring(b''.join(ret)).xpath('//tns:string/text()', - namespaces=application.interface.nsmap) == ['zabaaa', 'hobaa'] + assert set([("zabaaa", "hobaa")]) == queue + assert etree.fromstring(b"".join(ret)).xpath( + "//tns:string/text()", namespaces=application.interface.nsmap + ) == ["zabaaa", "hobaa"] queue.clear() ostr_server.service.send_message(k="hobaa") - assert set([(None,"hobaa")]) == queue + assert set([(None, "hobaa")]) == queue queue.clear() ostr_server.service.send_message("zobaaa", s="hobaa") @@ -145,24 +164,27 @@ def ping(): return True application = Application( - [PingService], 'some_tns', - in_protocol=XmlDocument(), out_protocol=XmlDocument()) + [PingService], + "some_tns", + in_protocol=XmlDocument(), + out_protocol=XmlDocument(), + ) server = NullServer(application) origin_collect = gc.collect origin_MIN_GC_INTERVAL = const.MIN_GC_INTERVAL try: - gc.collect = lambda : 1/0 + gc.collect = lambda: 1 / 0 with self.assertRaises(ZeroDivisionError): const.MIN_GC_INTERVAL = 0 server.service.ping() # No raise - const.MIN_GC_INTERVAL = float('inf') + const.MIN_GC_INTERVAL = float("inf") server.service.ping() finally: gc.collect = origin_collect const.MIN_GC_INTERVAL = origin_MIN_GC_INTERVAL -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/test_service.py b/spyne/test/test_service.py index ac09aa3d1..684b46be8 100755 --- a/spyne/test/test_service.py +++ b/spyne/test/test_service.py @@ -22,31 +22,29 @@ # import logging + logging.basicConfig(level=logging.DEBUG) import unittest - -from spyne.util.six import BytesIO +from io import BytesIO from lxml import etree from spyne import LogicError -from spyne.const import RESPONSE_SUFFIX -from spyne.model.primitive import NATIVE_MAP - -from spyne.service import Service -from spyne.decorator import rpc, srpc from spyne.application import Application from spyne.auxproc.sync import SyncAuxProc from spyne.auxproc.thread import ThreadAuxProc +from spyne.const import RESPONSE_SUFFIX +from spyne.decorator import rpc, srpc +from spyne.model import Array, ComplexModel, Iterable, SelfReference, String, Unicode +from spyne.model.primitive import NATIVE_MAP from spyne.protocol.http import HttpRpc from spyne.protocol.soap import Soap11 from spyne.server.null import NullServer from spyne.server.wsgi import WsgiApplication -from spyne.model import Array, SelfReference, Iterable, ComplexModel, String, \ - Unicode +from spyne.service import Service -Application.transport = 'test' +Application.transport = "test" def start_response(code, headers): @@ -74,6 +72,7 @@ def test_method_exception(self): def on_method_exception_object(ctx): assert ctx.out_error is not None from spyne.protocol.xml import SchemaValidationError + assert isinstance(ctx.out_error, SchemaValidationError) logging.error("method_exception_object: %r", repr(ctx.out_error)) h[0] += 1 @@ -81,9 +80,11 @@ def on_method_exception_object(ctx): def on_method_exception_document(ctx): assert ctx.out_error is not None from spyne.protocol.xml import SchemaValidationError + assert isinstance(ctx.out_error, SchemaValidationError) - logging.error("method_exception_document: %r", - etree.tostring(ctx.out_document)) + logging.error( + "method_exception_document: %r", etree.tostring(ctx.out_document) + ) h[0] += 1 class SomeService(Service): @@ -91,14 +92,20 @@ class SomeService(Service): def some_call(ctx, some_str): print(some_str) - app = Application([SomeService], "some_tns", - in_protocol=XmlDocument(validator='lxml'), out_protocol=Soap11()) + app = Application( + [SomeService], + "some_tns", + in_protocol=XmlDocument(validator="lxml"), + out_protocol=Soap11(), + ) app.event_manager.add_listener( - "method_exception_object", on_method_exception_object) + "method_exception_object", on_method_exception_object + ) app.event_manager.add_listener( - "method_exception_document", on_method_exception_document) + "method_exception_document", on_method_exception_document + ) # this shouldn't be called because: # 1. document isn't validated @@ -108,7 +115,8 @@ def some_call(ctx, some_str): # 5. hence; no handlers from the service class is invoked. # 6. hence; the h[0] == 2 check (instead of 3) SomeService.event_manager.add_listener( - "method_exception_object", on_method_exception_object) + "method_exception_object", on_method_exception_object + ) wsgi_app = WsgiApplication(app) @@ -118,14 +126,19 @@ def some_call(ctx, some_str): """ - _ = b''.join(wsgi_app({ - 'PATH_INFO': '/', - 'SERVER_NAME': 'localhost', - 'SERVER_PORT': '7000', - 'REQUEST_METHOD': 'POST', - 'wsgi.url_scheme': 'http', - 'wsgi.input': BytesIO(xml_request), - }, start_response)) + _ = b"".join( + wsgi_app( + { + "PATH_INFO": "/", + "SERVER_NAME": "localhost", + "SERVER_PORT": "7000", + "REQUEST_METHOD": "POST", + "wsgi.url_scheme": "http", + "wsgi.input": BytesIO(xml_request), + }, + start_response, + ) + ) assert h[0] == 2 @@ -133,14 +146,18 @@ def some_call(ctx, some_str): class TestMultipleMethods(unittest.TestCase): def test_single_method(self): try: - Application([MultipleMethods1, MultipleMethods2], 'tns', - in_protocol=Soap11(), out_protocol=Soap11()) + Application( + [MultipleMethods1, MultipleMethods2], + "tns", + in_protocol=Soap11(), + out_protocol=Soap11(), + ) except ValueError: pass else: - raise Exception('must fail.') + raise Exception("must fail.") def test_simple_aux_nullserver(self): data = [] @@ -157,20 +174,19 @@ class AuxService(Service): def call(s): data.append(s) - app = Application([SomeService, AuxService], 'tns', 'name', Soap11(), - Soap11()) + app = Application([SomeService, AuxService], "tns", "name", Soap11(), Soap11()) server = NullServer(app) server.service.call("hey") - assert data == ['hey', 'hey'] + assert data == ["hey", "hey"] def test_namespace_in_message_name(self): class S(Service): - @srpc(String, _in_message_name='{tns}inMessageName') + @srpc(String, _in_message_name="{tns}inMessageName") def call(s): pass - app = Application([S], 'tns', 'name', Soap11(), Soap11()) + app = Application([S], "tns", "name", Soap11(), Soap11()) def test_simple_aux_wsgi(self): data = [] @@ -187,23 +203,32 @@ class AuxService(Service): def call(s): data.append(s) - app = Application([SomeService, AuxService], 'tns', - in_protocol=HttpRpc(), out_protocol=HttpRpc()) + app = Application( + [SomeService, AuxService], + "tns", + in_protocol=HttpRpc(), + out_protocol=HttpRpc(), + ) server = WsgiApplication(app) - server({ - 'QUERY_STRING': 's=hey', - 'PATH_INFO': '/call', - 'REQUEST_METHOD': 'POST', - 'CONTENT_TYPE': 'text/xml; charset=utf8', - 'SERVER_NAME': 'localhost', - 'wsgi.input': BytesIO(), - }, start_response, "http://null") - - assert data == ['hey', 'hey'] + server( + { + "QUERY_STRING": "s=hey", + "PATH_INFO": "/call", + "REQUEST_METHOD": "POST", + "CONTENT_TYPE": "text/xml; charset=utf8", + "SERVER_NAME": "localhost", + "wsgi.input": BytesIO(), + }, + start_response, + "http://null", + ) + + assert data == ["hey", "hey"] def test_thread_aux_wsgi(self): import logging + logging.basicConfig(level=logging.DEBUG) data = set() @@ -220,25 +245,35 @@ class AuxService(Service): def call(s): data.add(s + "aux") - app = Application([SomeService, AuxService], 'tns', - in_protocol=HttpRpc(), out_protocol=HttpRpc()) + app = Application( + [SomeService, AuxService], + "tns", + in_protocol=HttpRpc(), + out_protocol=HttpRpc(), + ) server = WsgiApplication(app) - server({ - 'QUERY_STRING': 's=hey', - 'PATH_INFO': '/call', - 'REQUEST_METHOD': 'POST', - 'CONTENT_TYPE': 'text/xml; charset=utf8', - 'SERVER_NAME': 'localhost', - 'wsgi.input': BytesIO(), - }, start_response, "http://null") + server( + { + "QUERY_STRING": "s=hey", + "PATH_INFO": "/call", + "REQUEST_METHOD": "POST", + "CONTENT_TYPE": "text/xml; charset=utf8", + "SERVER_NAME": "localhost", + "wsgi.input": BytesIO(), + }, + start_response, + "http://null", + ) import time + time.sleep(1) - assert data == set(['hey', 'heyaux']) + assert data == set(["hey", "heyaux"]) def test_mixing_primary_and_aux_methods(self): try: + class SomeService(Service): @srpc(String, _returns=String, _aux=ThreadAuxProc()) def call(s): @@ -247,25 +282,35 @@ def call(s): @srpc(String, _returns=String) def mall(s): pass + except Exception: pass else: - raise Exception("must fail with 'Exception: you can't mix aux and " - "non-aux methods in a single service definition.'") + raise Exception( + "must fail with 'Exception: you can't mix aux and " + "non-aux methods in a single service definition.'" + ) def __run_service(self, service): - app = Application([service], 'tns', in_protocol=HttpRpc(), - out_protocol=Soap11()) + app = Application( + [service], "tns", in_protocol=HttpRpc(), out_protocol=Soap11() + ) server = WsgiApplication(app) - return_string = b''.join(server({ - 'QUERY_STRING': '', - 'PATH_INFO': '/some_call', - 'REQUEST_METHOD': 'POST', - 'CONTENT_TYPE': 'text/xml; charset=utf8', - 'SERVER_NAME': 'localhost', - 'wsgi.input': BytesIO(b""), - }, start_response, "http://null")) + return_string = b"".join( + server( + { + "QUERY_STRING": "", + "PATH_INFO": "/some_call", + "REQUEST_METHOD": "POST", + "CONTENT_TYPE": "text/xml; charset=utf8", + "SERVER_NAME": "localhost", + "wsgi.input": BytesIO(b""), + }, + start_response, + "http://null", + ) + ) elt = etree.fromstring(return_string) print(etree.tostring(elt, pretty_print=True)) @@ -274,7 +319,7 @@ def __run_service(self, service): def test_settings_headers_from_user_code(self): class RespHeader(ComplexModel): - __namespace__ = 'tns' + __namespace__ = "tns" Elem1 = String # test header in service definition @@ -284,74 +329,85 @@ class SomeService(Service): @rpc() def some_call(ctx): ctx.out_header = RespHeader() - ctx.out_header.Elem1 = 'Test1' + ctx.out_header.Elem1 = "Test1" elt, nsmap = self.__run_service(SomeService) - query = '/soap11env:Envelope/soap11env:Header/tns:RespHeader' \ - '/tns:Elem1/text()' + query = ( + "/soap11env:Envelope/soap11env:Header/tns:RespHeader" "/tns:Elem1/text()" + ) - assert elt.xpath(query, namespaces=nsmap)[0] == 'Test1' + assert elt.xpath(query, namespaces=nsmap)[0] == "Test1" # test header in decorator class SomeService(Service): @rpc(_out_header=RespHeader) def some_call(ctx): ctx.out_header = RespHeader() - ctx.out_header.Elem1 = 'Test1' + ctx.out_header.Elem1 = "Test1" elt, nsmap = self.__run_service(SomeService) - query = '/soap11env:Envelope/soap11env:Header/tns:RespHeader/tns' \ - ':Elem1/text()' - assert elt.xpath(query, namespaces=nsmap)[0] == 'Test1' + query = ( + "/soap11env:Envelope/soap11env:Header/tns:RespHeader/tns" ":Elem1/text()" + ) + assert elt.xpath(query, namespaces=nsmap)[0] == "Test1" # test no header class SomeService(Service): @rpc() def some_call(ctx): ctx.out_header = RespHeader() - ctx.out_header.Elem1 = 'Test1' + ctx.out_header.Elem1 = "Test1" elt, nsmap = self.__run_service(SomeService) - query = '/soap11env:Envelope/soap11env:Header/tns:RespHeader' \ - '/tns:Elem1/text()' + query = ( + "/soap11env:Envelope/soap11env:Header/tns:RespHeader" "/tns:Elem1/text()" + ) assert len(elt.xpath(query, namespaces=nsmap)) == 0 class TestNativeTypes(unittest.TestCase): def test_native_types(self): for t in NATIVE_MAP: + class SomeService(Service): @rpc(t) def some_call(ctx, arg): pass - nt, = SomeService.public_methods['some_call'].in_message \ - ._type_info.values() + (nt,) = SomeService.public_methods[ + "some_call" + ].in_message._type_info.values() assert issubclass(nt, NATIVE_MAP[t]) def test_native_types_in_arrays(self): for t in NATIVE_MAP: + class SomeService(Service): @rpc(Array(t)) def some_call(ctx, arg): pass - nt, = SomeService.public_methods['some_call'].in_message \ - ._type_info.values() - nt, = nt._type_info.values() + (nt,) = SomeService.public_methods[ + "some_call" + ].in_message._type_info.values() + (nt,) = nt._type_info.values() assert issubclass(nt, NATIVE_MAP[t]) class TestBodyStyle(unittest.TestCase): def test_soap_bare_empty_output(self): class SomeService(Service): - @rpc(String, _body_style='bare') + @rpc(String, _body_style="bare") def some_call(ctx, s): - assert s == 'abc' + assert s == "abc" - app = Application([SomeService], 'tns', in_protocol=Soap11(), - out_protocol=Soap11(cleanup_namespaces=True)) + app = Application( + [SomeService], + "tns", + in_protocol=Soap11(), + out_protocol=Soap11(cleanup_namespaces=True), + ) req = b""" @@ -170,10 +177,11 @@ def some_method(s): """] - ctx, = server.generate_contexts(ctx) + (ctx,) = server.generate_contexts(ctx) server.get_in_object(ctx) self.assertEqual(isinstance(ctx.in_error, ValidationError), True) -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/test_sqlalchemy.py b/spyne/test/test_sqlalchemy.py index 9d7af0df3..b91bdd41f 100755 --- a/spyne/test/test_sqlalchemy.py +++ b/spyne/test/test_sqlalchemy.py @@ -18,35 +18,39 @@ # import logging + logging.basicConfig(level=logging.DEBUG) import inspect import unittest -import sqlalchemy - from pprint import pprint -from sqlalchemy import create_engine -from sqlalchemy import MetaData -from sqlalchemy import Column -from sqlalchemy import Table +import sqlalchemy +from sqlalchemy import Column, MetaData, Table, create_engine +from sqlalchemy import text as sa_text from sqlalchemy.exc import IntegrityError - -from sqlalchemy.orm import mapper -from sqlalchemy.orm import sessionmaker - -from spyne import M, Any, Double - -from spyne.model import XmlAttribute, File, XmlData, ComplexModel, Array, \ - Integer32, Unicode, Integer, Enum, TTableModel, DateTime, Boolean - +from sqlalchemy.orm import registry as _sa_registry +from sqlalchemy.orm import sessionmaker, with_polymorphic + +from spyne import Any, Double, M +from spyne.model import ( + Array, + Boolean, + ComplexModel, + DateTime, + Enum, + File, + Integer, + Integer32, + TTableModel, + Unicode, + XmlAttribute, + XmlData, +) from spyne.model.binary import HybridFileStore -from spyne.model.complex import xml -from spyne.model.complex import table - +from spyne.model.complex import table, xml from spyne.store.relational import get_pk_columns -from spyne.store.relational.document import PGJsonB, PGJson, PGFileJson, \ - PGObjectJson +from spyne.store.relational.document import PGFileJson, PGJson, PGJsonB, PGObjectJson TableModel = TTableModel() @@ -62,6 +66,7 @@ class SomeClass1(TableModel): e = Unicode(32) from spyne.util.dictdoc import get_dict_as_object + inst = get_dict_as_object(dict(i=4), SomeClass1) assert not sqla_inspect(inst).attrs.e.history.has_changes() @@ -73,16 +78,16 @@ class SomeClass1(TableModel): i = Integer32(pk=True) b = Boolean - assert isinstance(SomeClass1.Attributes.sqla_table.c.b.type, - sqlalchemy.Boolean) + assert isinstance(SomeClass1.Attributes.sqla_table.c.b.type, sqlalchemy.Boolean) class SomeClass2(TableModel): __tablename__ = "%s_%d" % (fn, 2) i = Integer32(pk=True) b = Boolean(store_as=int) - assert isinstance(SomeClass2.Attributes.sqla_table.c.b.type, - sqlalchemy.SmallInteger) + assert isinstance( + SomeClass2.Attributes.sqla_table.c.b.type, sqlalchemy.SmallInteger + ) def test_jsonb(self): fn = inspect.stack()[0][3] @@ -90,24 +95,24 @@ def test_jsonb(self): class SomeClass1(TableModel): __tablename__ = "%s_%d" % (fn, 1) i = Integer32(pk=True) - a = Any(store_as='json') + a = Any(store_as="json") assert isinstance(SomeClass1.Attributes.sqla_table.c.a.type, PGJson) class SomeClass2(TableModel): __tablename__ = "%s_%d" % (fn, 2) i = Integer32(pk=True) - a = Any(store_as='jsonb') + a = Any(store_as="jsonb") assert isinstance(SomeClass2.Attributes.sqla_table.c.a.type, PGJsonB) class SomeClass3(TableModel): __tablename__ = "%s_%d" % (fn, 3) i = Integer32(pk=True) - a = File(store_as=HybridFileStore("path", db_format='jsonb')) + a = File(store_as=HybridFileStore("path", db_format="jsonb")) assert isinstance(SomeClass3.Attributes.sqla_table.c.a.type, PGFileJson) - assert SomeClass3.Attributes.sqla_table.c.a.type.dbt == 'jsonb' + assert SomeClass3.Attributes.sqla_table.c.a.type.dbt == "jsonb" def test_obj_json(self): fn = inspect.stack()[0][3] @@ -119,31 +124,28 @@ class SomeClass(ComplexModel): class SomeClass1(TableModel): __tablename__ = "%s_%d" % (fn, 1) _type_info = [ - ('i', Integer32(pk=True)), - ('a', Array(SomeClass, store_as='json')), + ("i", Integer32(pk=True)), + ("a", Array(SomeClass, store_as="json")), ] - assert isinstance(SomeClass1.Attributes.sqla_table.c.a.type, - PGObjectJson) + assert isinstance(SomeClass1.Attributes.sqla_table.c.a.type, PGObjectJson) class SomeClass2(TableModel): __tablename__ = "%s_%d" % (fn, 2) i = Integer32(pk=True) - a = SomeClass.customize(store_as='json') + a = SomeClass.customize(store_as="json") - assert isinstance(SomeClass2.Attributes.sqla_table.c.a.type, - PGObjectJson) + assert isinstance(SomeClass2.Attributes.sqla_table.c.a.type, PGObjectJson) class TestSqlAlchemySchema(unittest.TestCase): def setUp(self): - logging.getLogger('sqlalchemy').setLevel(logging.DEBUG) + logging.getLogger("sqlalchemy").setLevel(logging.WARNING) - self.engine = create_engine('sqlite:///:memory:') - self.session = sessionmaker(bind=self.engine)() + self.engine = create_engine("sqlite:///:memory:") + self.session = sessionmaker(self.engine)() self.metadata = TableModel.Attributes.sqla_metadata = MetaData() - self.metadata.bind = self.engine - logging.info('Testing against sqlalchemy-%s', sqlalchemy.__version__) + logging.info("Testing against sqlalchemy-%s", sqlalchemy.__version__) def test_obj_json_dirty(self): fn = inspect.stack()[0][3] @@ -155,11 +157,11 @@ class SomeClass(ComplexModel): class SomeClass1(TableModel): __tablename__ = "%s_%d" % (fn, 1) _type_info = [ - ('i', Integer32(pk=True)), - ('a', SomeClass.store_as('jsonb')), + ("i", Integer32(pk=True)), + ("a", SomeClass.store_as("jsonb")), ] - self.metadata.create_all() + self.metadata.create_all(self.engine) sc1 = SomeClass1(i=5, a=SomeClass(s="s", d=42.0)) self.session.add(sc1) @@ -169,7 +171,7 @@ class SomeClass1(TableModel): # TODO: maybe do the flag_modified() on setitem? sc1.a.s = "ss" - flag_modified(sc1, 'a') + flag_modified(sc1, "a") assert sc1 in self.session.dirty @@ -177,13 +179,13 @@ class SomeClass1(TableModel): assert sc1.a.s == "ss" # not implemented - #sc1.a[0].s = "sss" - #flag_modified(sc1.a[0], 's') - #assert sc1.a[0] in self.session.dirty + # sc1.a[0].s = "sss" + # flag_modified(sc1.a[0], 's') + # assert sc1.a[0] in self.session.dirty def test_schema(self): class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True, autoincrement=False) @@ -191,199 +193,196 @@ class SomeClass(TableModel): i = Integer32(64, index=True) t = SomeClass.__table__ - self.metadata.create_all() # not needed, just nice to see. + self.metadata.create_all(self.engine) # not needed, just nice to see. assert t.c.id.primary_key == True assert t.c.id.autoincrement == False indexes = list(t.indexes) indexes.sort(key=lambda idx: idx.name) for idx in indexes: - assert 'i' in idx.columns or 's' in idx.columns - if 's' in idx.columns: + assert "i" in idx.columns or "s" in idx.columns + if "s" in idx.columns: assert idx.unique def test_colname_simple(self): class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True, autoincrement=False) - s = Unicode(64, sqla_column_args=dict(name='ss')) + s = Unicode(64, sqla_column_args=dict(name="ss")) t = SomeClass.__table__ - self.metadata.create_all() # not needed, just nice to see. + self.metadata.create_all(self.engine) # not needed, just nice to see. - assert 'ss' in t.c + assert "ss" in t.c def test_colname_complex_table(self): class SomeOtherClass(TableModel): - __tablename__ = 'some_other_class' + __tablename__ = "some_other_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) s = Unicode(64) class SomeClass(TableModel): - __tablename__ = 'some_class' - __table_args__ = ( - {"sqlite_autoincrement": True}, - ) + __tablename__ = "some_class" + __table_args__ = ({"sqlite_autoincrement": True},) id = Integer32(primary_key=True) - o = SomeOtherClass.customize(store_as='table', - sqla_column_args=dict(name='oo')) + o = SomeOtherClass.customize( + store_as="table", sqla_column_args=dict(name="oo") + ) t = SomeClass.__table__ - self.metadata.create_all() # not needed, just nice to see. + self.metadata.create_all(self.engine) # not needed, just nice to see. - assert 'oo_id' in t.c + assert "oo_id" in t.c def test_colname_complex_json(self): class SomeOtherClass(TableModel): - __tablename__ = 'some_other_class' + __tablename__ = "some_other_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) s = Unicode(64) class SomeClass(TableModel): - __tablename__ = 'some_class' - __table_args__ = ( - {"sqlite_autoincrement": True}, - ) + __tablename__ = "some_class" + __table_args__ = ({"sqlite_autoincrement": True},) id = Integer32(primary_key=True) - o = SomeOtherClass.customize(store_as='json', - sqla_column_args=dict(name='oo')) + o = SomeOtherClass.customize( + store_as="json", sqla_column_args=dict(name="oo") + ) t = SomeClass.__table__ - self.metadata.create_all() # not needed, just nice to see. + self.metadata.create_all(self.engine) # not needed, just nice to see. - assert 'oo' in t.c + assert "oo" in t.c def test_nested_sql(self): class SomeOtherClass(TableModel): - __tablename__ = 'some_other_class' + __tablename__ = "some_other_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) s = Unicode(64) class SomeClass(TableModel): - __tablename__ = 'some_class' - __table_args__ = ( - {"sqlite_autoincrement": True}, - ) + __tablename__ = "some_class" + __table_args__ = ({"sqlite_autoincrement": True},) id = Integer32(primary_key=True) - o = SomeOtherClass.customize(store_as='table') + o = SomeOtherClass.customize(store_as="table") - self.metadata.create_all() + self.metadata.create_all(self.engine) - soc = SomeOtherClass(s='ehe') + soc = SomeOtherClass(s="ehe") sc = SomeClass(o=soc) self.session.add(sc) self.session.commit() self.session.close() - sc_db = self.session.query(SomeClass).get(1) + sc_db = self.session.get(SomeClass, 1) print(sc_db) - assert sc_db.o.s == 'ehe' + assert sc_db.o.s == "ehe" assert sc_db.o_id == 1 sc_db.o = None self.session.commit() self.session.close() - sc_db = self.session.query(SomeClass).get(1) + sc_db = self.session.get(SomeClass, 1) assert sc_db.o == None assert sc_db.o_id == None def test_nested_sql_array_as_table(self): class SomeOtherClass(TableModel): - __tablename__ = 'some_other_class' + __tablename__ = "some_other_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) s = Unicode(64) class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) - others = Array(SomeOtherClass, store_as='table') + others = Array(SomeOtherClass, store_as="table") - self.metadata.create_all() + self.metadata.create_all(self.engine) - soc1 = SomeOtherClass(s='ehe1') - soc2 = SomeOtherClass(s='ehe2') + soc1 = SomeOtherClass(s="ehe1") + soc2 = SomeOtherClass(s="ehe2") sc = SomeClass(others=[soc1, soc2]) self.session.add(sc) self.session.commit() self.session.close() - sc_db = self.session.query(SomeClass).get(1) + sc_db = self.session.get(SomeClass, 1) - assert sc_db.others[0].s == 'ehe1' - assert sc_db.others[1].s == 'ehe2' + assert sc_db.others[0].s == "ehe1" + assert sc_db.others[1].s == "ehe2" self.session.close() def test_nested_sql_array_as_multi_table(self): class SomeOtherClass(TableModel): - __tablename__ = 'some_other_class' + __tablename__ = "some_other_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) s = Unicode(64) class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) others = Array(SomeOtherClass, store_as=table(multi=True)) - self.metadata.create_all() + self.metadata.create_all(self.engine) - soc1 = SomeOtherClass(s='ehe1') - soc2 = SomeOtherClass(s='ehe2') + soc1 = SomeOtherClass(s="ehe1") + soc2 = SomeOtherClass(s="ehe2") sc = SomeClass(others=[soc1, soc2]) self.session.add(sc) self.session.commit() self.session.close() - sc_db = self.session.query(SomeClass).get(1) + sc_db = self.session.get(SomeClass, 1) - assert sc_db.others[0].s == 'ehe1' - assert sc_db.others[1].s == 'ehe2' + assert sc_db.others[0].s == "ehe1" + assert sc_db.others[1].s == "ehe2" self.session.close() def test_nested_sql_array_as_multi_table_with_backref(self): class SomeOtherClass(TableModel): - __tablename__ = 'some_other_class' + __tablename__ = "some_other_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) s = Unicode(64) class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) - others = Array(SomeOtherClass, - store_as=table(multi=True, backref='some_classes')) + others = Array( + SomeOtherClass, store_as=table(multi=True, backref="some_classes") + ) - self.metadata.create_all() + self.metadata.create_all(self.engine) - soc1 = SomeOtherClass(s='ehe1') - soc2 = SomeOtherClass(s='ehe2') + soc1 = SomeOtherClass(s="ehe1") + soc2 = SomeOtherClass(s="ehe2") sc = SomeClass(others=[soc1, soc2]) self.session.add(sc) @@ -403,26 +402,26 @@ class SomeOtherClass(ComplexModel): s = Unicode(64) class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) - others = Array(SomeOtherClass, store_as='xml') + others = Array(SomeOtherClass, store_as="xml") - self.metadata.create_all() + self.metadata.create_all(self.engine) - soc1 = SomeOtherClass(s='ehe1') - soc2 = SomeOtherClass(s='ehe2') + soc1 = SomeOtherClass(s="ehe1") + soc2 = SomeOtherClass(s="ehe2") sc = SomeClass(others=[soc1, soc2]) self.session.add(sc) self.session.commit() self.session.close() - sc_db = self.session.query(SomeClass).get(1) + sc_db = self.session.get(SomeClass, 1) - assert sc_db.others[0].s == 'ehe1' - assert sc_db.others[1].s == 'ehe2' + assert sc_db.others[0].s == "ehe1" + assert sc_db.others[1].s == "ehe2" self.session.close() @@ -432,54 +431,58 @@ class SomeOtherClass(ComplexModel): s = Unicode(64) class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) others = Array(SomeOtherClass, store_as=xml(no_ns=True)) - self.metadata.create_all() + self.metadata.create_all(self.engine) - soc1 = SomeOtherClass(s='ehe1') - soc2 = SomeOtherClass(s='ehe2') + soc1 = SomeOtherClass(s="ehe1") + soc2 = SomeOtherClass(s="ehe2") sc = SomeClass(others=[soc1, soc2]) self.session.add(sc) self.session.commit() self.session.close() - sc_xml = self.session.connection() \ - .execute("select others from some_class") .fetchall()[0][0] + sc_xml = ( + self.session.connection() + .execute(sa_text("select others from some_class")) + .fetchall()[0][0] + ) from lxml import etree - assert etree.fromstring(sc_xml).tag == 'SomeOtherClassArray' + + assert etree.fromstring(sc_xml).tag == "SomeOtherClassArray" self.session.close() def test_inheritance(self): class SomeOtherClass(TableModel): - __tablename__ = 'some_other_class' + __tablename__ = "some_other_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) s = Unicode(64) class SomeClass(SomeOtherClass): - numbers = Array(Integer32).store_as(xml(no_ns=True, root_tag='a')) + numbers = Array(Integer32).store_as(xml(no_ns=True, root_tag="a")) - self.metadata.create_all() + self.metadata.create_all(self.engine) - sc = SomeClass(id=5, s='s', numbers=[1, 2, 3, 4]) + sc = SomeClass(id=5, s="s", numbers=[1, 2, 3, 4]) self.session.add(sc) self.session.commit() self.session.close() - sc_db = self.session.query(SomeClass).get(5) + sc_db = self.session.get(SomeClass, 5) assert sc_db.numbers == [1, 2, 3, 4] self.session.close() - sc_db = self.session.query(SomeOtherClass).get(5) + sc_db = self.session.get(SomeOtherClass, 5) assert sc_db.id == 5 try: sc_db.numbers @@ -492,29 +495,29 @@ class SomeClass(SomeOtherClass): def test_inheritance_with_complex_fields(self): class Foo(TableModel): - __tablename__ = 'foo' + __tablename__ = "foo" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) s = Unicode(64) class Bar(TableModel): - __tablename__ = 'bar' + __tablename__ = "bar" __table_args__ = {"sqlite_autoincrement": True} __mapper_args__ = { - 'polymorphic_on': 'type', - 'polymorphic_identity': 'bar', - 'with_polymorphic': '*', + "polymorphic_on": "type", + "polymorphic_identity": "bar", + "with_polymorphic": "*", } id = Integer32(primary_key=True) s = Unicode(64) type = Unicode(6) - foos = Array(Foo).store_as('table') + foos = Array(Foo).store_as("table") class SubBar(Bar): __mapper_args__ = { - 'polymorphic_identity': 'subbar', + "polymorphic_identity": "subbar", } i = Integer32 @@ -525,38 +528,40 @@ class SubBar(Bar): assert not mapper_subbar.concrete for inheriting in mapper_subbar.iterate_to_root(): - if inheriting is not mapper_subbar \ - and not (mapper_bar.relationships['foos'] is - mapper_subbar.relationships['foos']): - raise Exception("Thou shalt stop children relationships " - "from overriding the ones in parent") + if inheriting is not mapper_subbar and not ( + mapper_bar.relationships["foos"] is mapper_subbar.relationships["foos"] + ): + raise Exception( + "Thou shalt stop children relationships " + "from overriding the ones in parent" + ) def test_mixins_with_complex_fields(self): class Foo(TableModel): - __tablename__ = 'foo' + __tablename__ = "foo" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) s = Unicode(64) class Bar(TableModel): - __tablename__ = 'bar' + __tablename__ = "bar" __table_args__ = {"sqlite_autoincrement": True} __mixin__ = True __mapper_args__ = { - 'polymorphic_on': 'type', - 'polymorphic_identity': 'bar', - 'with_polymorphic': '*', + "polymorphic_on": "type", + "polymorphic_identity": "bar", + "with_polymorphic": "*", } id = Integer32(primary_key=True) s = Unicode(64) type = Unicode(6) - foos = Array(Foo).store_as('table') + foos = Array(Foo).store_as("table") class SubBar(Bar): __mapper_args__ = { - 'polymorphic_identity': 'subbar', + "polymorphic_identity": "subbar", } i = Integer32 @@ -567,11 +572,13 @@ class SubBar(Bar): assert not mapper_subbar.concrete for inheriting in mapper_subbar.iterate_to_root(): - if inheriting is not mapper_subbar \ - and not (mapper_bar.relationships['foos'] is - mapper_subbar.relationships['foos']): - raise Exception("Thou shalt stop children relationships " - "from overriding the ones in parent") + if inheriting is not mapper_subbar and not ( + mapper_bar.relationships["foos"] is mapper_subbar.relationships["foos"] + ): + raise Exception( + "Thou shalt stop children relationships " + "from overriding the ones in parent" + ) def test_sqlalchemy_inheritance(self): # no spyne code is involved here. @@ -591,8 +598,7 @@ def __init__(self, name, manager_data): def __repr__(self): return ( - self.__class__.__name__ + " " + - self.name + " " + self.manager_data + self.__class__.__name__ + " " + self.name + " " + self.manager_data ) class Engineer(Employee): @@ -602,44 +608,50 @@ def __init__(self, name, engineer_info): def __repr__(self): return ( - self.__class__.__name__ + " " + - self.name + " " + self.engineer_info + self.__class__.__name__ + " " + self.name + " " + self.engineer_info ) - employees_table = Table('employees', self.metadata, - Column('employee_id', sqlalchemy.Integer, primary_key=True), - Column('name', sqlalchemy.String(50)), - Column('manager_data', sqlalchemy.String(50)), - Column('engineer_info', sqlalchemy.String(50)), - Column('type', sqlalchemy.String(20), nullable=False), + employees_table = Table( + "employees", + self.metadata, + Column("employee_id", sqlalchemy.Integer, primary_key=True), + Column("name", sqlalchemy.String(50)), + Column("manager_data", sqlalchemy.String(50)), + Column("engineer_info", sqlalchemy.String(50)), + Column("type", sqlalchemy.String(20), nullable=False), ) - employee_mapper = mapper(Employee, employees_table, - polymorphic_on=employees_table.c.type, - polymorphic_identity='employee') + _reg = _sa_registry() + employee_mapper = _reg.map_imperatively( + Employee, + employees_table, + polymorphic_on=employees_table.c.type, + polymorphic_identity="employee", + ) - manager_mapper = mapper(Manager, inherits=employee_mapper, - polymorphic_identity='manager') + manager_mapper = _reg.map_imperatively( + Manager, inherits=employee_mapper, polymorphic_identity="manager" + ) - engineer_mapper = mapper(Engineer, inherits=employee_mapper, - polymorphic_identity='engineer') + engineer_mapper = _reg.map_imperatively( + Engineer, inherits=employee_mapper, polymorphic_identity="engineer" + ) - self.metadata.create_all() + self.metadata.create_all(self.engine) - manager = Manager('name', 'data') + manager = Manager("name", "data") self.session.add(manager) self.session.commit() self.session.close() - assert self.session.query(Employee).with_polymorphic('*') \ - .filter_by(employee_id=1) \ - .one().type == 'manager' + poly = with_polymorphic(Employee, "*") + assert self.session.query(poly).filter_by(employee_id=1).one().type == "manager" def test_inheritance_polymorphic_with_non_nullables_in_subclasses(self): class SomeOtherClass(TableModel): - __tablename__ = 'some_other_class' + __tablename__ = "some_other_class" __table_args__ = {"sqlite_autoincrement": True} - __mapper_args__ = {'polymorphic_on': 't', 'polymorphic_identity': 1} + __mapper_args__ = {"polymorphic_on": "t", "polymorphic_identity": 1} id = Integer32(primary_key=True) t = Integer32(nillable=False) @@ -648,12 +660,12 @@ class SomeOtherClass(TableModel): class SomeClass(SomeOtherClass): __mapper_args__ = ( (), - {'polymorphic_identity': 2}, + {"polymorphic_identity": 2}, ) i = Integer(nillable=False) - self.metadata.create_all() + self.metadata.create_all(self.engine) assert SomeOtherClass.__table__.c.s.nullable == False @@ -663,7 +675,7 @@ class SomeClass(SomeOtherClass): # well. assert SomeOtherClass.__table__.c.i.nullable == True - soc = SomeOtherClass(s='s') + soc = SomeOtherClass(s="s") self.session.add(soc) self.session.commit() soc_id = soc.id @@ -677,41 +689,41 @@ class SomeClass(SomeOtherClass): else: raise Exception("Must fail with IntegrityError.") - sc2 = SomeClass(s='s') # this won't fail. should it? + sc2 = SomeClass(s="s") # this won't fail. should it? self.session.add(sc2) self.session.commit() self.session.expunge_all() - assert self.session.query(SomeOtherClass).with_polymorphic('*') \ - .filter_by(id=soc_id).one().t == 1 + poly = with_polymorphic(SomeOtherClass, "*") + assert self.session.query(poly).filter_by(id=soc_id).one().t == 1 self.session.close() def test_inheritance_polymorphic(self): class SomeOtherClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" __table_args__ = {"sqlite_autoincrement": True} - __mapper_args__ = {'polymorphic_on': 't', 'polymorphic_identity': 1} + __mapper_args__ = {"polymorphic_on": "t", "polymorphic_identity": 1} id = Integer32(primary_key=True) s = Unicode(64) t = Integer32(nillable=False) class SomeClass(SomeOtherClass): - __mapper_args__ = {'polymorphic_identity': 2} - numbers = Array(Integer32).store_as(xml(no_ns=True, root_tag='a')) + __mapper_args__ = {"polymorphic_identity": 2} + numbers = Array(Integer32).store_as(xml(no_ns=True, root_tag="a")) - self.metadata.create_all() + self.metadata.create_all(self.engine) - sc = SomeClass(id=5, s='s', numbers=[1, 2, 3, 4]) + sc = SomeClass(id=5, s="s", numbers=[1, 2, 3, 4]) self.session.add(sc) self.session.commit() self.session.close() - assert self.session.query(SomeOtherClass).with_polymorphic('*') \ - .filter_by(id=5).one().t == 2 + poly = with_polymorphic(SomeOtherClass, "*") + assert self.session.query(poly).filter_by(id=5).one().t == 2 self.session.close() def test_nested_sql_array_as_json(self): @@ -720,45 +732,45 @@ class SomeOtherClass(ComplexModel): s = Unicode(64) class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) - others = Array(SomeOtherClass, store_as='json') + others = Array(SomeOtherClass, store_as="json") - self.metadata.create_all() + self.metadata.create_all(self.engine) - soc1 = SomeOtherClass(s='ehe1') - soc2 = SomeOtherClass(s='ehe2') + soc1 = SomeOtherClass(s="ehe1") + soc2 = SomeOtherClass(s="ehe2") sc = SomeClass(others=[soc1, soc2]) self.session.add(sc) self.session.commit() self.session.close() - sc_db = self.session.query(SomeClass).get(1) + sc_db = self.session.get(SomeClass, 1) - assert sc_db.others[0].s == 'ehe1' - assert sc_db.others[1].s == 'ehe2' + assert sc_db.others[0].s == "ehe1" + assert sc_db.others[1].s == "ehe2" self.session.close() def test_modifiers(self): class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" __table_args__ = {"sqlite_autoincrement": True} i = XmlAttribute(Integer32(pk=True)) s = XmlData(Unicode(64)) - self.metadata.create_all() - self.session.add(SomeClass(s='s')) + self.metadata.create_all(self.engine) + self.session.add(SomeClass(s="s")) self.session.commit() self.session.expunge_all() - ret = self.session.query(SomeClass).get(1) + ret = self.session.get(SomeClass, 1) assert ret.i == 1 # redundant - assert ret.s == 's' + assert ret.s == "s" def test_default_ctor(self): class SomeOtherClass(ComplexModel): @@ -766,29 +778,29 @@ class SomeOtherClass(ComplexModel): s = Unicode(64) class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) - others = Array(SomeOtherClass, store_as='json') - f = Unicode(32, default='uuu') + others = Array(SomeOtherClass, store_as="json") + f = Unicode(32, default="uuu") - self.metadata.create_all() + self.metadata.create_all(self.engine) self.session.add(SomeClass()) self.session.commit() self.session.expunge_all() - assert self.session.query(SomeClass).get(1).f == 'uuu' + assert self.session.get(SomeClass, 1).f == "uuu" def test_default_value(self): class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) - f = Unicode(32, db_default=u'uuu') + f = Unicode(32, db_default="uuu") - self.metadata.create_all() + self.metadata.create_all(self.engine) val = SomeClass() assert val.f is None @@ -797,96 +809,96 @@ class SomeClass(TableModel): self.session.expunge_all() - assert self.session.query(SomeClass).get(1).f == u'uuu' + assert self.session.get(SomeClass, 1).f == "uuu" def test_default_ctor_with_sql_relationship(self): class SomeOtherClass(TableModel): - __tablename__ = 'some_other_class' + __tablename__ = "some_other_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) s = Unicode(64) class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) - o = SomeOtherClass.customize(store_as='table') + o = SomeOtherClass.customize(store_as="table") - self.metadata.create_all() + self.metadata.create_all(self.engine) self.session.add(SomeClass()) self.session.commit() def test_store_as_index(self): class SomeOtherClass(TableModel): - __tablename__ = 'some_other_class' + __tablename__ = "some_other_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) s = Unicode(64) class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" __table_args__ = {"sqlite_autoincrement": True} id = Integer32(primary_key=True) - o = SomeOtherClass.customize(store_as='table', index='btree') + o = SomeOtherClass.customize(store_as="table", index="btree") - self.metadata.create_all() - idx, = SomeClass.__table__.indexes - assert 'o_id' in idx.columns + self.metadata.create_all(self.engine) + (idx,) = SomeClass.__table__.indexes + assert "o_id" in idx.columns def test_scalar_collection(self): class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" id = Integer32(primary_key=True) - values = Array(Unicode).store_as('table') + values = Array(Unicode).store_as("table") - self.metadata.create_all() + self.metadata.create_all(self.engine) - self.session.add(SomeClass(id=1, values=['a', 'b', 'c'])) + self.session.add(SomeClass(id=1, values=["a", "b", "c"])) self.session.commit() - sc = self.session.query(SomeClass).get(1) - assert sc.values == ['a', 'b', 'c'] + sc = self.session.get(SomeClass, 1) + assert sc.values == ["a", "b", "c"] del sc - sc = self.session.query(SomeClass).get(1) - sc.values.append('d') + sc = self.session.get(SomeClass, 1) + sc.values.append("d") self.session.commit() del sc - sc = self.session.query(SomeClass).get(1) - assert sc.values == ['a', 'b', 'c', 'd'] + sc = self.session.get(SomeClass, 1) + assert sc.values == ["a", "b", "c", "d"] - sc = self.session.query(SomeClass).get(1) + sc = self.session.get(SomeClass, 1) sc.values = sc.values[1:] self.session.commit() del sc - sc = self.session.query(SomeClass).get(1) - assert sc.values == ['b', 'c', 'd'] + sc = self.session.get(SomeClass, 1) + assert sc.values == ["b", "c", "d"] def test_multiple_fk(self): class SomeChildClass(TableModel): - __tablename__ = 'some_child_class' + __tablename__ = "some_child_class" id = Integer32(primary_key=True) s = Unicode(64) i = Integer32 class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" id = Integer32(primary_key=True) - children = Array(SomeChildClass).store_as('table') - mirror = SomeChildClass.store_as('table') + children = Array(SomeChildClass).store_as("table") + mirror = SomeChildClass.store_as("table") - self.metadata.create_all() + self.metadata.create_all(self.engine) children = [ - SomeChildClass(s='p', i=600), - SomeChildClass(s='|', i=10), - SomeChildClass(s='q', i=9), + SomeChildClass(s="p", i=600), + SomeChildClass(s="|", i=10), + SomeChildClass(s="q", i=9), ] sc = SomeClass(children=children) @@ -896,111 +908,115 @@ class SomeClass(TableModel): self.session.commit() del sc - sc = self.session.query(SomeClass).get(1) - assert ''.join([scc.s for scc in sc.children]) == 'p|q' + sc = self.session.get(SomeClass, 1) + assert "".join([scc.s for scc in sc.children]) == "p|q" assert sum([scc.i for scc in sc.children]) == 619 def test_simple_fk(self): class SomeChildClass(TableModel): - __tablename__ = 'some_child_class' + __tablename__ = "some_child_class" id = Integer32(primary_key=True) s = Unicode(64) i = Integer32 class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" id = Integer32(primary_key=True) - child_id = Integer32(fk='some_child_class.id') + child_id = Integer32(fk="some_child_class.id") - foreign_keys = SomeClass.__table__.c['child_id'].foreign_keys + foreign_keys = SomeClass.__table__.c["child_id"].foreign_keys assert len(foreign_keys) == 1 - fk, = foreign_keys - assert fk._colspec == 'some_child_class.id' + (fk,) = foreign_keys + assert fk._colspec == "some_child_class.id" def test_multirel_single_table(self): class SomeChildClass(TableModel): - __tablename__ = 'some_child_class' + __tablename__ = "some_child_class" id = Integer32(primary_key=True) s = Unicode(64) class SomeOtherChildClass(TableModel): - __tablename__ = 'some_other_child_class' + __tablename__ = "some_other_child_class" id = Integer32(primary_key=True) i = Integer32 class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" id = Integer32(primary_key=True) - children = Array(SomeChildClass, + children = Array( + SomeChildClass, store_as=table( - multi='children', lazy='joined', - left='parent_id', right='child_id', - fk_left_ondelete='cascade', - fk_right_ondelete='cascade', + multi="children", + lazy="joined", + left="parent_id", + right="child_id", + fk_left_ondelete="cascade", + fk_right_ondelete="cascade", ), ) - other_children = Array(SomeOtherChildClass, + other_children = Array( + SomeOtherChildClass, store_as=table( - multi='children', lazy='joined', - left='parent_id', right='other_child_id', - fk_left_ondelete='cascade', - fk_right_ondelete='cascade', + multi="children", + lazy="joined", + left="parent_id", + right="other_child_id", + fk_left_ondelete="cascade", + fk_right_ondelete="cascade", ), ) - t = SomeClass.Attributes.sqla_metadata.tables['children'] + t = SomeClass.Attributes.sqla_metadata.tables["children"] - fkp, = t.c.parent_id.foreign_keys - assert fkp._colspec == 'some_class.id' + (fkp,) = t.c.parent_id.foreign_keys + assert fkp._colspec == "some_class.id" - fkc, = t.c.child_id.foreign_keys - assert fkc._colspec == 'some_child_class.id' + (fkc,) = t.c.child_id.foreign_keys + assert fkc._colspec == "some_child_class.id" - fkoc, = t.c.other_child_id.foreign_keys - assert fkoc._colspec == 'some_other_child_class.id' + (fkoc,) = t.c.other_child_id.foreign_keys + assert fkoc._colspec == "some_other_child_class.id" def test_reflection(self): class SomeClass(TableModel): - __tablename__ = 'some_class' + __tablename__ = "some_class" id = Integer32(primary_key=True) s = Unicode(32) - TableModel.Attributes.sqla_metadata.create_all() + TableModel.Attributes.sqla_metadata.create_all(self.engine) # create a new table model with empty metadata TM2 = TTableModel() - TM2.Attributes.sqla_metadata.bind = self.engine - # fill it with information from the db - TM2.Attributes.sqla_metadata.reflect() + TM2.Attributes.sqla_metadata.reflect(bind=self.engine) # convert sqla info to spyne info class Reflected(TM2): - __table__ = TM2.Attributes.sqla_metadata.tables['some_class'] + __table__ = TM2.Attributes.sqla_metadata.tables["some_class"] pprint(dict(Reflected._type_info).items()) - assert issubclass(Reflected._type_info['id'], Integer) + assert issubclass(Reflected._type_info["id"], Integer) # this looks at spyne attrs - assert [k for k, v in get_pk_columns(Reflected)] == ['id'] + assert [k for k, v in get_pk_columns(Reflected)] == ["id"] # this looks at sqla attrs - assert [k for k, v in Reflected.get_primary_keys()] == ['id'] + assert [k for k, v in Reflected.get_primary_keys()] == ["id"] - assert issubclass(Reflected._type_info['s'], Unicode) - assert Reflected._type_info['s'].Attributes.max_len == 32 + assert issubclass(Reflected._type_info["s"], Unicode) + assert Reflected._type_info["s"].Attributes.max_len == 32 def _test_sqlalchemy_remapping(self): class SomeTable(TableModel): - __tablename__ = 'some_table' + __tablename__ = "some_table" id = Integer32(pk=True) i = Integer32 s = Unicode(32) @@ -1013,21 +1029,22 @@ class SomeTableSubset(TableModel): class SomeTableOtherSubset(TableModel): __table__ = SomeTable.__table__ - _type_info = [(k, v) for k, v in SomeTable._type_info.items() - if k in ('id', 's')] + _type_info = [ + (k, v) for k, v in SomeTable._type_info.items() if k in ("id", "s") + ] - self.session.add(SomeTable(id=1, i=2, s='s')) + self.session.add(SomeTable(id=1, i=2, s="s")) self.session.commit() - st = self.session.query(SomeTable).get(1) - sts = self.session.query(SomeTableSubset).get(1) - stos = self.session.query(SomeTableOtherSubset).get(1) + st = self.session.get(SomeTable, 1) + sts = self.session.get(SomeTableSubset, 1) + stos = self.session.get(SomeTableOtherSubset, 1) sts.i = 3 - sts.s = 'ss' # will not be flushed to db + sts.s = "ss" # will not be flushed to db self.session.commit() - assert st.s == 's' + assert st.s == "s" assert stos.i == 3 def test_file_storage(self): @@ -1035,15 +1052,15 @@ class C(TableModel): __tablename__ = "c" id = Integer32(pk=True) - f = File(store_as=HybridFileStore('test_file_storage', 'json')) + f = File(store_as=HybridFileStore("test_file_storage", "json")) - self.metadata.create_all() - c = C(f=File.Value(name=u"name", type=u"type", data=[b"data"])) + self.metadata.create_all(self.engine) + c = C(f=File.Value(name="name", type="type", data=[b"data"])) self.session.add(c) self.session.flush() self.session.commit() - c = self.session.query(C).get(1) + c = self.session.get(C, 1) print(c) assert c.f.name == "name" assert c.f.type == "type" @@ -1057,10 +1074,10 @@ class C(TableModel): class D(TableModel): __tablename__ = "d" d = Integer32(pk=True) - c = C.store_as('table') + c = C.store_as("table") - C.append_field('d', D.store_as('table')) - assert C.Attributes.sqla_mapper.get_property('d').argument is D + C.append_field("d", D.store_as("table")) + assert C.Attributes.sqla_mapper.get_property("d").argument is D def test_append_field_complex_delayed(self): class C(TableModel): @@ -1070,9 +1087,9 @@ class C(TableModel): class D(C): i = Integer32 - C.append_field('d', DateTime) + C.append_field("d", DateTime) - assert D.Attributes.sqla_mapper.has_property('d') + assert D.Attributes.sqla_mapper.has_property("d") def _test_append_field_complex_explicit_existing_column(self): # FIXME: Test something! @@ -1086,7 +1103,7 @@ class C(TableModel): class D(TableModel): __tablename__ = "d" id = Integer32(pk=True) - c = C.store_as('table') + c = C.store_as("table") c_id = Integer32(15) def test_append_field_complex_circular_array(self): @@ -1097,10 +1114,10 @@ class C(TableModel): class D(TableModel): __tablename__ = "dd" id = Integer32(pk=True) - c = Array(C).customize(store_as=table(right='dd_id')) + c = Array(C).customize(store_as=table(right="dd_id")) - C.append_field('d', D.customize(store_as=table(left='dd_id'))) - self.metadata.create_all() + C.append_field("d", D.customize(store_as=table(left="dd_id"))) + self.metadata.create_all(self.engine) c1, c2 = C(id=1), C(id=2) d = D(id=1, c=[c1, c2]) @@ -1117,10 +1134,9 @@ class D(TableModel): __tablename__ = "d" id = Integer32(pk=True) - C.append_field('d', D.store_as('table')) - assert C.Attributes.sqla_mapper.get_property('d').argument is D - assert isinstance(C.Attributes.sqla_table.c['d_id'].type, - sqlalchemy.Integer) + C.append_field("d", D.store_as("table")) + assert C.Attributes.sqla_mapper.get_property("d").argument is D + assert isinstance(C.Attributes.sqla_table.c["d_id"].type, sqlalchemy.Integer) def test_append_field_array(self): class C(TableModel): @@ -1131,11 +1147,10 @@ class D(TableModel): __tablename__ = "d" id = Integer32(pk=True) - C.append_field('d', Array(D).store_as('table')) - assert C.Attributes.sqla_mapper.get_property('d').argument is D + C.append_field("d", Array(D).store_as("table")) + assert C.Attributes.sqla_mapper.get_property("d").argument is D print(repr(D.Attributes.sqla_table)) - assert isinstance(D.Attributes.sqla_table.c['c_id'].type, - sqlalchemy.Integer) + assert isinstance(D.Attributes.sqla_table.c["c_id"].type, sqlalchemy.Integer) def test_append_field_array_many(self): class C(TableModel): @@ -1146,11 +1161,11 @@ class D(TableModel): __tablename__ = "d" id = Integer32(pk=True) - C.append_field('d', Array(D).store_as(table(multi='c_d'))) - assert C.Attributes.sqla_mapper.get_property('d').argument is D - rel_table = C.Attributes.sqla_metadata.tables['c_d'] - assert 'c_id' in rel_table.c - assert 'd_id' in rel_table.c + C.append_field("d", Array(D).store_as(table(multi="c_d"))) + assert C.Attributes.sqla_mapper.get_property("d").argument is D + rel_table = C.Attributes.sqla_metadata.tables["c_d"] + assert "c_id" in rel_table.c + assert "d_id" in rel_table.c def test_append_field_complex_cust(self): class C(TableModel): @@ -1160,13 +1175,16 @@ class C(TableModel): class D(TableModel): __tablename__ = "d" id = Integer32(pk=True) - c = Array(C).store_as('table') - - C.append_field('d', D.customize( - nullable=False, - store_as=table(left='d_id'), - )) - assert C.__table__.c['d_id'].nullable == False + c = Array(C).store_as("table") + + C.append_field( + "d", + D.customize( + nullable=False, + store_as=table(left="d_id"), + ), + ) + assert C.__table__.c["d_id"].nullable == False def _test_append_field_cust(self): class C(TableModel): @@ -1179,21 +1197,21 @@ class C(TableModel): C() - self.metadata.create_all() + self.metadata.create_all(self.engine) assert "s" in C2._type_info assert "s" in C2.Attributes.sqla_mapper.columns - self.session.add(C2(s='foo')) + self.session.add(C2(s="foo")) self.session.commit() - assert self.session.query(C).first().s == 'foo' + assert self.session.query(C).first().s == "foo" def test_polymorphic_cust(self): class C(TableModel): __tablename__ = "c" __mapper_args__ = { - 'polymorphic_on': 't', - 'polymorphic_identity': 1, + "polymorphic_on": "t", + "polymorphic_identity": 1, } id = Integer32(pk=True) @@ -1201,7 +1219,7 @@ class C(TableModel): class D(C): __mapper_args__ = { - 'polymorphic_identity': 2, + "polymorphic_identity": 2, } d = Unicode @@ -1216,10 +1234,10 @@ class D(C): def test_base_append_simple(self): class B(TableModel): - __tablename__ = 'b' + __tablename__ = "b" __mapper_args__ = { - 'polymorphic_on': 't', - 'polymorphic_identity': 1, + "polymorphic_on": "t", + "polymorphic_identity": 1, } id = Integer32(pk=True) @@ -1227,29 +1245,29 @@ class B(TableModel): class C(B): __mapper_args__ = { - 'polymorphic_identity': 1, + "polymorphic_identity": 1, } s = Unicode - B.append_field('i', Integer32) + B.append_field("i", Integer32) - self.metadata.create_all() + self.metadata.create_all(self.engine) self.session.add(C(s="foo", i=42)) self.session.commit() c = self.session.query(C).first() - assert c.s == 'foo' + assert c.s == "foo" assert c.i == 42 assert c.t == 1 def test_base_append_complex(self): class B(TableModel): - __tablename__ = 'b' + __tablename__ = "b" __mapper_args__ = { - 'polymorphic_on': 't', - 'polymorphic_identity': 1, + "polymorphic_on": "t", + "polymorphic_identity": 1, } id = Integer32(pk=True) @@ -1257,18 +1275,18 @@ class B(TableModel): class C(B): __mapper_args__ = { - 'polymorphic_identity': 1, + "polymorphic_identity": 1, } s = Unicode class D(TableModel): - __tablename__ = 'd' + __tablename__ = "d" id = Integer32(pk=True) i = M(Integer32) - B.append_field('d', D.store_as('table')) + B.append_field("d", D.store_as("table")) - self.metadata.create_all() + self.metadata.create_all(self.engine) self.session.add(C(d=D(i=42))) self.session.commit() @@ -1285,18 +1303,18 @@ def setUp(self): def test_enum(self): table_name = "test_enum" - enums = ('SUBSCRIBED', 'UNSUBSCRIBED', 'UNCONFIRMED') + enums = ("SUBSCRIBED", "UNSUBSCRIBED", "UNCONFIRMED") class SomeClass(TableModel): __tablename__ = table_name id = Integer32(primary_key=True) - e = Enum(*enums, type_name='status_choices') + e = Enum(*enums, type_name="status_choices") t = self.metadata.tables[table_name] - assert 'e' in t.c + assert "e" in t.c assert tuple(t.c.e.type.enums) == enums -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/test/transport/test_msgpack.py b/spyne/test/transport/test_msgpack.py index c94174a10..96a71c843 100644 --- a/spyne/test/transport/test_msgpack.py +++ b/spyne/test/transport/test_msgpack.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,19 +17,19 @@ # import msgpack +from twisted.trial import unittest from spyne import Application, Service, rpc from spyne.model import Unicode from spyne.protocol.msgpack import MessagePackDocument -from twisted.trial import unittest - class TestMessagePackServer(unittest.TestCase): - def gen_prot(self, app): - from spyne.server.twisted.msgpack import TwistedMessagePackProtocol - from twisted.test.proto_helpers import StringTransportWithDisconnection + def gen_prot(self, app): + from twisted.internet.testing import StringTransportWithDisconnection + from spyne.server.msgpack import MessagePackServerBase + from spyne.server.twisted.msgpack import TwistedMessagePackProtocol prot = TwistedMessagePackProtocol(MessagePackServerBase(app)) transport = StringTransportWithDisconnection() @@ -39,19 +38,23 @@ def gen_prot(self, app): return prot - def test_roundtrip(self): + def test_roundtrip(self): v = "yaaay!" + class SomeService(Service): @rpc(Unicode, _returns=Unicode) def yay(ctx, u): return u - app = Application([SomeService], 'tns', - in_protocol=MessagePackDocument(), - out_protocol=MessagePackDocument()) + app = Application( + [SomeService], + "tns", + in_protocol=MessagePackDocument(), + out_protocol=MessagePackDocument(), + ) prot = self.gen_prot(app) - request = msgpack.packb({'yay': [v]}) + request = msgpack.packb({"yay": [v]}) prot.dataReceived(msgpack.packb([1, request])) val = prot.transport.value() print(repr(val)) @@ -60,26 +63,32 @@ def yay(ctx, u): self.assertEqual(val, [0, msgpack.packb(v)]) - def test_roundtrip_deferred(self): + def test_roundtrip_deferred(self): from twisted.internet import reactor from twisted.internet.task import deferLater v = "yaaay!" p_ctx = [] + class SomeService(Service): @rpc(Unicode, _returns=Unicode) def yay(ctx, u): def _cb(): return u + p_ctx.append(ctx) return deferLater(reactor, 0.1, _cb) - app = Application([SomeService], 'tns', - in_protocol=MessagePackDocument(), - out_protocol=MessagePackDocument()) + app = Application( + [SomeService], + "tns", + in_protocol=MessagePackDocument(), + out_protocol=MessagePackDocument(), + ) prot = self.gen_prot(app) - request = msgpack.packb({'yay': [v]}) + request = msgpack.packb({"yay": [v]}) + def _ccb(_): val = prot.transport.value() print(repr(val)) @@ -91,4 +100,3 @@ def _ccb(_): prot.dataReceived(msgpack.packb([1, request])) return p_ctx[0].out_object[0].addCallback(_ccb) - diff --git a/spyne/test/util/test_address.py b/spyne/test/util/test_address.py index 04f8918cd..36fd11229 100755 --- a/spyne/test/util/test_address.py +++ b/spyne/test/util/test_address.py @@ -42,10 +42,9 @@ from unittest import TestCase - from spyne.util.address import set_address_parser_settings -set_address_parser_settings(trusted_proxies=['177.139.233.100']) +set_address_parser_settings(trusted_proxies=["177.139.233.100"]) from spyne.util.address import address_parser @@ -54,265 +53,264 @@ class IPv4TestCase(TestCase): """IP address Test""" def test_meta_none(self): - request = { - } + request = {} ip = address_parser.get_real_ip(request) self.assertIsNone(ip) def test_http_x_forwarded_for_multiple(self): request = { - 'HTTP_X_FORWARDED_FOR': '192.168.255.182, 10.0.0.0, 127.0.0.1, 198.84.193.157, 177.139.233.139', - 'HTTP_X_REAL_IP': '177.139.233.132', - 'REMOTE_ADDR': '177.139.233.133', + "HTTP_X_FORWARDED_FOR": "192.168.255.182, 10.0.0.0, 127.0.0.1, 198.84.193.157, 177.139.233.139", + "HTTP_X_REAL_IP": "177.139.233.132", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "198.84.193.157") def test_http_x_forwarded_for_multiple_left_most_ip(self): request = { - 'HTTP_X_FORWARDED_FOR': '192.168.255.182, 198.84.193.157, 10.0.0.0, 127.0.0.1, 177.139.233.139', - 'HTTP_X_REAL_IP': '177.139.233.132', - 'REMOTE_ADDR': '177.139.233.133', + "HTTP_X_FORWARDED_FOR": "192.168.255.182, 198.84.193.157, 10.0.0.0, 127.0.0.1, 177.139.233.139", + "HTTP_X_REAL_IP": "177.139.233.132", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "198.84.193.157") def test_http_x_forwarded_for_multiple_right_most_ip(self): request = { - 'HTTP_X_FORWARDED_FOR': '192.168.255.182, 198.84.193.157, 10.0.0.0, 127.0.0.1, 177.139.233.139', - 'HTTP_X_REAL_IP': '177.139.233.132', - 'REMOTE_ADDR': '177.139.233.133', + "HTTP_X_FORWARDED_FOR": "192.168.255.182, 198.84.193.157, 10.0.0.0, 127.0.0.1, 177.139.233.139", + "HTTP_X_REAL_IP": "177.139.233.132", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request, right_most_proxy=True) self.assertEqual(ip, "177.139.233.139") def test_http_x_forwarded_for_multiple_right_most_ip_private(self): request = { - 'HTTP_X_FORWARDED_FOR': '192.168.255.182, 198.84.193.157, 10.0.0.0, 127.0.0.1, 177.139.233.139', - 'HTTP_X_REAL_IP': '177.139.233.132', - 'REMOTE_ADDR': '177.139.233.133', + "HTTP_X_FORWARDED_FOR": "192.168.255.182, 198.84.193.157, 10.0.0.0, 127.0.0.1, 177.139.233.139", + "HTTP_X_REAL_IP": "177.139.233.132", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request, right_most_proxy=True) self.assertEqual(ip, "177.139.233.139") def test_http_x_forwarded_for_multiple_bad_address(self): request = { - 'HTTP_X_FORWARDED_FOR': 'unknown, 192.168.255.182, 10.0.0.0, 127.0.0.1, 198.84.193.157, 177.139.233.139', - 'HTTP_X_REAL_IP': '177.139.233.132', - 'REMOTE_ADDR': '177.139.233.133', + "HTTP_X_FORWARDED_FOR": "unknown, 192.168.255.182, 10.0.0.0, 127.0.0.1, 198.84.193.157, 177.139.233.139", + "HTTP_X_REAL_IP": "177.139.233.132", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "198.84.193.157") def test_http_x_forwarded_for_singleton(self): request = { - 'HTTP_X_FORWARDED_FOR': '177.139.233.139', - 'HTTP_X_REAL_IP': '177.139.233.132', - 'REMOTE_ADDR': '177.139.233.133', + "HTTP_X_FORWARDED_FOR": "177.139.233.139", + "HTTP_X_REAL_IP": "177.139.233.132", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.139") def test_http_x_forwarded_for_singleton_private_address(self): request = { - 'HTTP_X_FORWARDED_FOR': '192.168.255.182', - 'HTTP_X_REAL_IP': '177.139.233.132', - 'REMOTE_ADDR': '177.139.233.133', + "HTTP_X_FORWARDED_FOR": "192.168.255.182", + "HTTP_X_REAL_IP": "177.139.233.132", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.132") def test_bad_http_x_forwarded_for_fallback_on_x_real_ip(self): request = { - 'HTTP_X_FORWARDED_FOR': 'unknown 177.139.233.139', - 'HTTP_X_REAL_IP': '177.139.233.132', - 'REMOTE_ADDR': '177.139.233.133', + "HTTP_X_FORWARDED_FOR": "unknown 177.139.233.139", + "HTTP_X_REAL_IP": "177.139.233.132", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.132") def test_empty_http_x_forwarded_for_fallback_on_x_real_ip(self): request = { - 'HTTP_X_FORWARDED_FOR': '', - 'HTTP_X_REAL_IP': '177.139.233.132', - 'REMOTE_ADDR': '177.139.233.133', + "HTTP_X_FORWARDED_FOR": "", + "HTTP_X_REAL_IP": "177.139.233.132", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.132") def test_empty_http_x_forwarded_for_empty_x_real_ip_fallback_on_remote_addr(self): request = { - 'HTTP_X_FORWARDED_FOR': '', - 'HTTP_X_REAL_IP': '', - 'REMOTE_ADDR': '177.139.233.133', + "HTTP_X_FORWARDED_FOR": "", + "HTTP_X_REAL_IP": "", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.133") def test_empty_http_x_forwarded_for_private_x_real_ip_fallback_on_remote_addr(self): request = { - 'HTTP_X_FORWARDED_FOR': '', - 'HTTP_X_REAL_IP': '192.168.255.182', - 'REMOTE_ADDR': '177.139.233.133', + "HTTP_X_FORWARDED_FOR": "", + "HTTP_X_REAL_IP": "192.168.255.182", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.133") def test_private_http_x_forward_for_ip_addr(self): request = { - 'HTTP_X_FORWARDED_FOR': '127.0.0.1', - 'HTTP_X_REAL_IP': '', - 'REMOTE_ADDR': '', + "HTTP_X_FORWARDED_FOR": "127.0.0.1", + "HTTP_X_REAL_IP": "", + "REMOTE_ADDR": "", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, None) def test_private_remote_addr_for_ip_addr(self): request = { - 'HTTP_X_FORWARDED_FOR': '', - 'REMOTE_ADDR': '127.0.0.1', + "HTTP_X_FORWARDED_FOR": "", + "REMOTE_ADDR": "127.0.0.1", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, None) def test_missing_x_forwarded(self): request = { - 'REMOTE_ADDR': '177.139.233.133', + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.133") def test_missing_x_forwarded_missing_real_ip(self): request = { - 'REMOTE_ADDR': '177.139.233.133', + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.133") def test_best_matched_real_ip(self): request = { - 'HTTP_X_REAL_IP': '127.0.0.1', - 'REMOTE_ADDR': '172.31.233.133', + "HTTP_X_REAL_IP": "127.0.0.1", + "REMOTE_ADDR": "172.31.233.133", } ip = address_parser.get_ip(request) self.assertEqual(ip, "172.31.233.133") def test_best_matched_private_ip(self): request = { - 'HTTP_X_REAL_IP': '127.0.0.1', - 'REMOTE_ADDR': '192.31.233.133', + "HTTP_X_REAL_IP": "127.0.0.1", + "REMOTE_ADDR": "192.31.233.133", } ip = address_parser.get_ip(request) self.assertEqual(ip, "192.31.233.133") def test_best_matched_private_ip_2(self): request = { - 'HTTP_X_REAL_IP': '192.31.233.133', - 'REMOTE_ADDR': '127.0.0.1', + "HTTP_X_REAL_IP": "192.31.233.133", + "REMOTE_ADDR": "127.0.0.1", } ip = address_parser.get_ip(request) self.assertEqual(ip, "192.31.233.133") def test_x_forwarded_for_multiple(self): request = { - 'X_FORWARDED_FOR': '192.168.255.182, 10.0.0.0, 127.0.0.1, 198.84.193.157, 177.139.233.139', - 'REMOTE_ADDR': '177.139.233.133', + "X_FORWARDED_FOR": "192.168.255.182, 10.0.0.0, 127.0.0.1, 198.84.193.157, 177.139.233.139", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "198.84.193.157") def test_x_forwarded_for_multiple_left_most_ip(self): request = { - 'X_FORWARDED_FOR': '192.168.255.182, 198.84.193.157, 10.0.0.0, 127.0.0.1, 177.139.233.139', - 'REMOTE_ADDR': '177.139.233.133', + "X_FORWARDED_FOR": "192.168.255.182, 198.84.193.157, 10.0.0.0, 127.0.0.1, 177.139.233.139", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "198.84.193.157") def test_x_forwarded_for_multiple_right_most_ip(self): request = { - 'X_FORWARDED_FOR': '192.168.255.182, 198.84.193.157, 10.0.0.0, 127.0.0.1, 177.139.233.139', - 'REMOTE_ADDR': '177.139.233.133', + "X_FORWARDED_FOR": "192.168.255.182, 198.84.193.157, 10.0.0.0, 127.0.0.1, 177.139.233.139", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request, right_most_proxy=True) self.assertEqual(ip, "177.139.233.139") def test_x_forwarded_for_multiple_right_most_ip_private(self): request = { - 'X_FORWARDED_FOR': '192.168.255.182, 198.84.193.157, 10.0.0.0, 127.0.0.1, 177.139.233.139', - 'REMOTE_ADDR': '177.139.233.133', + "X_FORWARDED_FOR": "192.168.255.182, 198.84.193.157, 10.0.0.0, 127.0.0.1, 177.139.233.139", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request, right_most_proxy=True) self.assertEqual(ip, "177.139.233.139") def test_x_forwarded_for_multiple_bad_address(self): request = { - 'X_FORWARDED_FOR': 'unknown, 192.168.255.182, 10.0.0.0, 127.0.0.1, 198.84.193.157, 177.139.233.139', - 'REMOTE_ADDR': '177.139.233.133', + "X_FORWARDED_FOR": "unknown, 192.168.255.182, 10.0.0.0, 127.0.0.1, 198.84.193.157, 177.139.233.139", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "198.84.193.157") def test_x_forwarded_for_singleton(self): request = { - 'X_FORWARDED_FOR': '177.139.233.139', - 'REMOTE_ADDR': '177.139.233.133', + "X_FORWARDED_FOR": "177.139.233.139", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.139") def test_x_forwarded_for_singleton_private_address(self): request = { - 'X_FORWARDED_FOR': '192.168.255.182', - 'REMOTE_ADDR': '177.139.233.133', + "X_FORWARDED_FOR": "192.168.255.182", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.133") def test_bad_x_forwarded_for_fallback_on_x_real_ip(self): request = { - 'X_FORWARDED_FOR': 'unknown 177.139.233.139', - 'REMOTE_ADDR': '177.139.233.133', + "X_FORWARDED_FOR": "unknown 177.139.233.139", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.133") def test_empty_x_forwarded_for_fallback_on_x_real_ip(self): request = { - 'X_FORWARDED_FOR': '', - 'REMOTE_ADDR': '177.139.233.133', + "X_FORWARDED_FOR": "", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.133") def test_empty_x_forwarded_for_empty_x_real_ip_fallback_on_remote_addr(self): request = { - 'X_FORWARDED_FOR': '', - 'REMOTE_ADDR': '177.139.233.133', + "X_FORWARDED_FOR": "", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.133") def test_empty_x_forwarded_for_private_x_real_ip_fallback_on_remote_addr(self): request = { - 'X_FORWARDED_FOR': '', - 'REMOTE_ADDR': '177.139.233.133', + "X_FORWARDED_FOR": "", + "REMOTE_ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.133") def test_private_x_forward_for_ip_addr(self): request = { - 'X_FORWARDED_FOR': '127.0.0.1', - 'REMOTE_ADDR': '', + "X_FORWARDED_FOR": "127.0.0.1", + "REMOTE_ADDR": "", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, None) def test_x_forwarded_for_singleton_hyphen_as_delimiter(self): request = { - 'X-FORWARDED-FOR': '177.139.233.139', - 'REMOTE-ADDR': '177.139.233.133', + "X-FORWARDED-FOR": "177.139.233.139", + "REMOTE-ADDR": "177.139.233.133", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "177.139.233.139") @@ -322,14 +320,13 @@ class IPv4TrustedProxiesTestCase(TestCase): """Trusted Proxies - IP address Test""" def test_meta_none(self): - request = { - } + request = {} ip = address_parser.get_trusted_ip(request) self.assertIsNone(ip) def test_http_x_forwarded_for_conf_settings(self): request = { - 'HTTP_X_FORWARDED_FOR': '198.84.193.157, 177.139.200.139, 177.139.233.100', + "HTTP_X_FORWARDED_FOR": "198.84.193.157, 177.139.200.139, 177.139.233.100", } ip = address_parser.get_trusted_ip(request) @@ -337,66 +334,70 @@ def test_http_x_forwarded_for_conf_settings(self): def test_http_x_forwarded_for_no_proxy(self): request = { - 'HTTP_X_FORWARDED_FOR': '198.84.193.157, 177.139.200.139, 177.139.233.139', + "HTTP_X_FORWARDED_FOR": "198.84.193.157, 177.139.200.139, 177.139.233.139", } ip = address_parser.get_trusted_ip(request, trusted_proxies=[]) self.assertIsNone(ip) def test_http_x_forwarded_for_single_proxy(self): request = { - 'HTTP_X_FORWARDED_FOR': '198.84.193.157, 177.139.200.139, 177.139.233.139', + "HTTP_X_FORWARDED_FOR": "198.84.193.157, 177.139.200.139, 177.139.233.139", } - ip = address_parser.get_trusted_ip(request, trusted_proxies=['177.139.233.139']) + ip = address_parser.get_trusted_ip(request, trusted_proxies=["177.139.233.139"]) self.assertEqual(ip, "198.84.193.157") def test_http_x_forwarded_for_single_proxy_with_right_most(self): request = { - 'HTTP_X_FORWARDED_FOR': '177.139.233.139, 177.139.200.139, 198.84.193.157', + "HTTP_X_FORWARDED_FOR": "177.139.233.139, 177.139.200.139, 198.84.193.157", } - ip = address_parser.get_trusted_ip(request, right_most_proxy=True, trusted_proxies=['177.139.233.139']) + ip = address_parser.get_trusted_ip( + request, right_most_proxy=True, trusted_proxies=["177.139.233.139"] + ) self.assertEqual(ip, "198.84.193.157") def test_http_x_forwarded_for_multi_proxy(self): request = { - 'HTTP_X_FORWARDED_FOR': '198.84.193.157, 177.139.200.139, 177.139.233.139', + "HTTP_X_FORWARDED_FOR": "198.84.193.157, 177.139.200.139, 177.139.233.139", } - ip = address_parser.get_trusted_ip(request, trusted_proxies=['177.139.233.138', '177.139.233.139']) + ip = address_parser.get_trusted_ip( + request, trusted_proxies=["177.139.233.138", "177.139.233.139"] + ) self.assertEqual(ip, "198.84.193.157") def test_http_x_forwarded_for_all_proxies_in_subnet(self): request = { - 'HTTP_X_FORWARDED_FOR': '198.84.193.157, 177.139.200.139, 177.139.233.139', + "HTTP_X_FORWARDED_FOR": "198.84.193.157, 177.139.200.139, 177.139.233.139", } - ip = address_parser.get_trusted_ip(request, trusted_proxies=['177.139.233']) + ip = address_parser.get_trusted_ip(request, trusted_proxies=["177.139.233"]) self.assertEqual(ip, "198.84.193.157") def test_http_x_forwarded_for_all_proxies_in_subnet_2(self): request = { - 'HTTP_X_FORWARDED_FOR': '198.84.193.157, 177.139.200.139, 177.139.233.139', + "HTTP_X_FORWARDED_FOR": "198.84.193.157, 177.139.200.139, 177.139.233.139", } - ip = address_parser.get_trusted_ip(request, trusted_proxies=['177.139']) + ip = address_parser.get_trusted_ip(request, trusted_proxies=["177.139"]) self.assertEqual(ip, "198.84.193.157") def test_x_forwarded_for_single_proxy(self): request = { - 'X_FORWARDED_FOR': '198.84.193.157, 177.139.200.139, 177.139.233.139', + "X_FORWARDED_FOR": "198.84.193.157, 177.139.200.139, 177.139.233.139", } - ip = address_parser.get_trusted_ip(request, trusted_proxies=['177.139.233.139']) + ip = address_parser.get_trusted_ip(request, trusted_proxies=["177.139.233.139"]) self.assertEqual(ip, "198.84.193.157") def test_x_forwarded_for_single_proxy_hyphens(self): request = { - 'X-FORWARDED-FOR': '198.84.193.157, 177.139.200.139, 177.139.233.139', + "X-FORWARDED-FOR": "198.84.193.157, 177.139.200.139, 177.139.233.139", } - ip = address_parser.get_trusted_ip(request, trusted_proxies=['177.139.233.139']) + ip = address_parser.get_trusted_ip(request, trusted_proxies=["177.139.233.139"]) self.assertEqual(ip, "198.84.193.157") def test_http_x_forwarded_for_and_x_forward_for_single_proxy(self): request = { - 'HTTP_X_FORWARDED_FOR': '198.84.193.156, 177.139.200.139, 177.139.233.139', - 'X_FORWARDED_FOR': '198.84.193.157, 177.139.200.139, 177.139.233.139', + "HTTP_X_FORWARDED_FOR": "198.84.193.156, 177.139.200.139, 177.139.233.139", + "X_FORWARDED_FOR": "198.84.193.157, 177.139.200.139, 177.139.233.139", } - ip = address_parser.get_trusted_ip(request, trusted_proxies=['177.139.233.139']) + ip = address_parser.get_trusted_ip(request, trusted_proxies=["177.139.233.139"]) self.assertEqual(ip, "198.84.193.156") @@ -405,217 +406,217 @@ class IPv6TestCase(TestCase): def test_http_x_forwarded_for_multiple(self): request = { - 'HTTP_X_FORWARDED_FOR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf, 74dc::02ba', - 'HTTP_X_REAL_IP': '74dc::02ba', - 'REMOTE_ADDR': '74dc::02ba', + "HTTP_X_FORWARDED_FOR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf, 74dc::02ba", + "HTTP_X_REAL_IP": "74dc::02ba", + "REMOTE_ADDR": "74dc::02ba", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "3ffe:1900:4545:3:200:f8ff:fe21:67cf") def test_http_x_forwarded_for_multiple_bad_address(self): request = { - 'HTTP_X_FORWARDED_FOR': 'unknown, ::1/128, 74dc::02ba', - 'HTTP_X_REAL_IP': '3ffe:1900:4545:3:200:f8ff:fe21:67cf', - 'REMOTE_ADDR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf', + "HTTP_X_FORWARDED_FOR": "unknown, ::1/128, 74dc::02ba", + "HTTP_X_REAL_IP": "3ffe:1900:4545:3:200:f8ff:fe21:67cf", + "REMOTE_ADDR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_http_x_forwarded_for_singleton(self): request = { - 'HTTP_X_FORWARDED_FOR': '74dc::02ba', - 'HTTP_X_REAL_IP': '3ffe:1900:4545:3:200:f8ff:fe21:67cf', - 'REMOTE_ADDR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf', + "HTTP_X_FORWARDED_FOR": "74dc::02ba", + "HTTP_X_REAL_IP": "3ffe:1900:4545:3:200:f8ff:fe21:67cf", + "REMOTE_ADDR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_http_x_forwarded_for_singleton_private_address(self): request = { - 'HTTP_X_FORWARDED_FOR': '::1/128', - 'HTTP_X_REAL_IP': '74dc::02ba', - 'REMOTE_ADDR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf', + "HTTP_X_FORWARDED_FOR": "::1/128", + "HTTP_X_REAL_IP": "74dc::02ba", + "REMOTE_ADDR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_bad_http_x_forwarded_for_fallback_on_x_real_ip(self): request = { - 'HTTP_X_FORWARDED_FOR': 'unknown ::1/128', - 'HTTP_X_REAL_IP': '74dc::02ba', - 'REMOTE_ADDR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf', + "HTTP_X_FORWARDED_FOR": "unknown ::1/128", + "HTTP_X_REAL_IP": "74dc::02ba", + "REMOTE_ADDR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_empty_http_x_forwarded_for_fallback_on_x_real_ip(self): request = { - 'HTTP_X_FORWARDED_FOR': '', - 'HTTP_X_REAL_IP': '74dc::02ba', - 'REMOTE_ADDR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf', + "HTTP_X_FORWARDED_FOR": "", + "HTTP_X_REAL_IP": "74dc::02ba", + "REMOTE_ADDR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_empty_http_x_forwarded_for_empty_x_real_ip_fallback_on_remote_addr(self): request = { - 'HTTP_X_FORWARDED_FOR': '', - 'HTTP_X_REAL_IP': '', - 'REMOTE_ADDR': '74dc::02ba', + "HTTP_X_FORWARDED_FOR": "", + "HTTP_X_REAL_IP": "", + "REMOTE_ADDR": "74dc::02ba", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_empty_http_x_forwarded_for_private_x_real_ip_fallback_on_remote_addr(self): request = { - 'HTTP_X_FORWARDED_FOR': '', - 'HTTP_X_REAL_IP': '::1/128', - 'REMOTE_ADDR': '74dc::02ba', + "HTTP_X_FORWARDED_FOR": "", + "HTTP_X_REAL_IP": "::1/128", + "REMOTE_ADDR": "74dc::02ba", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_private_http_x_forward_for_ip_addr(self): request = { - 'HTTP_X_FORWARDED_FOR': '::1/128', - 'HTTP_X_REAL_IP': '', - 'REMOTE_ADDR': '', + "HTTP_X_FORWARDED_FOR": "::1/128", + "HTTP_X_REAL_IP": "", + "REMOTE_ADDR": "", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, None) def test_private_real_ip_for_ip_addr(self): request = { - 'HTTP_X_FORWARDED_FOR': '', - 'HTTP_X_REAL_IP': '::1/128', - 'REMOTE_ADDR': '', + "HTTP_X_FORWARDED_FOR": "", + "HTTP_X_REAL_IP": "::1/128", + "REMOTE_ADDR": "", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, None) def test_private_remote_addr_for_ip_addr(self): request = { - 'HTTP_X_FORWARDED_FOR': '', - 'HTTP_X_REAL_IP': '', - 'REMOTE_ADDR': '::1/128', + "HTTP_X_FORWARDED_FOR": "", + "HTTP_X_REAL_IP": "", + "REMOTE_ADDR": "::1/128", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, None) def test_missing_x_forwarded(self): request = { - 'HTTP_X_REAL_IP': '74dc::02ba', - 'REMOTE_ADDR': '74dc::02ba', + "HTTP_X_REAL_IP": "74dc::02ba", + "REMOTE_ADDR": "74dc::02ba", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_missing_x_forwarded_missing_real_ip(self): request = { - 'REMOTE_ADDR': '74dc::02ba', + "REMOTE_ADDR": "74dc::02ba", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_missing_x_forwarded_missing_real_ip_mix_case(self): request = { - 'REMOTE_ADDR': '74DC::02BA', + "REMOTE_ADDR": "74DC::02BA", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_private_remote_address(self): request = { - 'REMOTE_ADDR': 'fe80::02ba', + "REMOTE_ADDR": "fe80::02ba", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, None) def test_best_matched_real_ip(self): request = { - 'HTTP_X_REAL_IP': '::1', - 'REMOTE_ADDR': 'fe80::02ba', + "HTTP_X_REAL_IP": "::1", + "REMOTE_ADDR": "fe80::02ba", } ip = address_parser.get_ip(request) self.assertEqual(ip, "fe80::02ba") def test_x_forwarded_for_multiple(self): request = { - 'X_FORWARDED_FOR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf, 74dc::02ba', - 'REMOTE_ADDR': '74dc::02ba', + "X_FORWARDED_FOR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf, 74dc::02ba", + "REMOTE_ADDR": "74dc::02ba", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "3ffe:1900:4545:3:200:f8ff:fe21:67cf") def test_x_forwarded_for_multiple_bad_address(self): request = { - 'X_FORWARDED_FOR': 'unknown, ::1/128, 74dc::02ba', - 'REMOTE_ADDR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf', + "X_FORWARDED_FOR": "unknown, ::1/128, 74dc::02ba", + "REMOTE_ADDR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_x_forwarded_for_singleton(self): request = { - 'X_FORWARDED_FOR': '74dc::02ba', - 'REMOTE_ADDR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf', + "X_FORWARDED_FOR": "74dc::02ba", + "REMOTE_ADDR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_x_forwarded_for_singleton_private_address(self): request = { - 'X_FORWARDED_FOR': '::1/128', - 'HTTP_X_REAL_IP': '74dc::02ba', - 'REMOTE_ADDR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf', + "X_FORWARDED_FOR": "::1/128", + "HTTP_X_REAL_IP": "74dc::02ba", + "REMOTE_ADDR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_bad_x_forwarded_for_fallback_on_x_real_ip(self): request = { - 'X_FORWARDED_FOR': 'unknown ::1/128', - 'REMOTE_ADDR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf', + "X_FORWARDED_FOR": "unknown ::1/128", + "REMOTE_ADDR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "3ffe:1900:4545:3:200:f8ff:fe21:67cf") def test_empty_x_forwarded_for_fallback_on_x_real_ip(self): request = { - 'X_FORWARDED_FOR': '', - 'REMOTE_ADDR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf', + "X_FORWARDED_FOR": "", + "REMOTE_ADDR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "3ffe:1900:4545:3:200:f8ff:fe21:67cf") def test_empty_x_forwarded_for_empty_x_real_ip_fallback_on_remote_addr(self): request = { - 'X_FORWARDED_FOR': '', - 'REMOTE_ADDR': '74dc::02ba', + "X_FORWARDED_FOR": "", + "REMOTE_ADDR": "74dc::02ba", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_empty_x_forwarded_for_private_x_real_ip_fallback_on_remote_addr(self): request = { - 'X_FORWARDED_FOR': '', - 'REMOTE_ADDR': '74dc::02ba', + "X_FORWARDED_FOR": "", + "REMOTE_ADDR": "74dc::02ba", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") def test_private_x_forward_for_ip_addr(self): request = { - 'X_FORWARDED_FOR': '::1/128', - 'REMOTE_ADDR': '', + "X_FORWARDED_FOR": "::1/128", + "REMOTE_ADDR": "", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, None) def test_x_forwarded_for_singleton_hyphen_as_delimiter(self): request = { - 'X-FORWARDED-FOR': '74dc::02ba', - 'REMOTE-ADDR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf', + "X-FORWARDED-FOR": "74dc::02ba", + "REMOTE-ADDR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf", } ip = address_parser.get_real_ip(request) self.assertEqual(ip, "74dc::02ba") @@ -626,14 +627,14 @@ class IPv6TrustedProxiesTestCase(TestCase): def test_http_x_forwarded_for_no_proxy(self): request = { - 'HTTP_X_FORWARDED_FOR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf, 74dc::02ba', + "HTTP_X_FORWARDED_FOR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf, 74dc::02ba", } ip = address_parser.get_trusted_ip(request, trusted_proxies=[]) self.assertIsNone(ip) def test_http_x_forwarded_for_single_proxy(self): request = { - 'HTTP_X_FORWARDED_FOR': '3ffe:1900:4545:3:200:f8ff:fe21:67cf, 74dc::02ba', + "HTTP_X_FORWARDED_FOR": "3ffe:1900:4545:3:200:f8ff:fe21:67cf, 74dc::02ba", } - ip = address_parser.get_trusted_ip(request, trusted_proxies=['74dc::02ba']) + ip = address_parser.get_trusted_ip(request, trusted_proxies=["74dc::02ba"]) self.assertEqual(ip, "3ffe:1900:4545:3:200:f8ff:fe21:67cf") diff --git a/spyne/test/util/test_util.py b/spyne/test/util/test_util.py index 3b8b5e740..8f82566ff 100755 --- a/spyne/test/util/test_util.py +++ b/spyne/test/util/test_util.py @@ -2,88 +2,87 @@ from __future__ import print_function -import json import decimal +import json import unittest +from datetime import datetime +from decimal import Decimal as D +from pprint import pprint import pytz import sqlalchemy - -from pprint import pprint -from decimal import Decimal as D -from datetime import datetime - from lxml import etree +from spyne.application import Application from spyne.const import MAX_STRING_FIELD_LENGTH - from spyne.decorator import srpc -from spyne.application import Application - -from spyne.model.complex import XmlAttribute, TypeInfo -from spyne.model.complex import ComplexModel -from spyne.model.complex import Iterable -from spyne.model.complex import Array -from spyne.model.primitive import Decimal -from spyne.model.primitive import DateTime -from spyne.model.primitive import Integer -from spyne.model.primitive import Unicode - +from spyne.model.complex import Array, ComplexModel, Iterable, TypeInfo, XmlAttribute +from spyne.model.primitive import DateTime, Decimal, Integer, Unicode from spyne.service import Service - -from spyne.util import AttrDict, AttrDictColl, get_version -from spyne.util import memoize, memoize_ignore_none, memoize_ignore, memoize_id - +from spyne.util import ( + AttrDict, + AttrDictColl, + get_version, + memoize, + memoize_id, + memoize_ignore, + memoize_ignore_none, +) +from spyne.util.dictdoc import ( + get_dict_as_object, + get_object_as_dict, + get_object_as_json, + get_object_as_yaml, +) from spyne.util.protocol import deserialize_request_string - -from spyne.util.dictdoc import get_dict_as_object, get_object_as_yaml, \ - get_object_as_json -from spyne.util.dictdoc import get_object_as_dict from spyne.util.tdict import tdict from spyne.util.tlist import tlist - -from spyne.util.xml import get_object_as_xml -from spyne.util.xml import get_xml_as_object -from spyne.util.xml import get_schema_documents -from spyne.util.xml import get_validation_schema +from spyne.util.xml import ( + get_object_as_xml, + get_schema_documents, + get_validation_schema, + get_xml_as_object, +) class TestUtil(unittest.TestCase): def test_version(self): - assert get_version('sqlalchemy') == get_version(sqlalchemy) - assert '.'.join([str(i) for i in get_version('sqlalchemy')]) == \ - sqlalchemy.__version__ + assert get_version("sqlalchemy") == get_version(sqlalchemy) + assert ( + ".".join([str(i) for i in get_version("sqlalchemy")]) + == sqlalchemy.__version__ + ) class TestTypeInfo(unittest.TestCase): def test_insert(self): d = TypeInfo() - d['a'] = 1 - assert d[0] == d['a'] == 1 + d["a"] = 1 + assert d[0] == d["a"] == 1 - d.insert(0, ('b', 2)) + d.insert(0, ("b", 2)) - assert d[1] == d['a'] == 1 - assert d[0] == d['b'] == 2 + assert d[1] == d["a"] == 1 + assert d[0] == d["b"] == 2 def test_insert_existing(self): d = TypeInfo() d["a"] = 1 d["b"] = 2 - assert d[1] == d['b'] == 2 + assert d[1] == d["b"] == 2 - d.insert(0, ('b', 3)) - assert d[1] == d['a'] == 1 - assert d[0] == d['b'] == 3 + d.insert(0, ("b", 3)) + assert d[1] == d["a"] == 1 + assert d[0] == d["b"] == 3 def test_update(self): d = TypeInfo() d["a"] = 1 - d.update([('b', 2)]) - assert d[0] == d['a'] == 1 - assert d[1] == d['b'] == 2 + d.update([("b", 2)]) + assert d[0] == d["a"] == 1 + assert d[1] == d["b"] == 2 class TestXml(unittest.TestCase): @@ -114,7 +113,7 @@ class C(ComplexModel): def test_deserialize(self): class Punk(ComplexModel): - __namespace__ = 'some_namespace' + __namespace__ = "some_namespace" a = Unicode b = Integer @@ -122,7 +121,7 @@ class Punk(ComplexModel): d = DateTime class Foo(ComplexModel): - __namespace__ = 'some_other_namespace' + __namespace__ = "some_other_namespace" a = Unicode b = Integer @@ -133,33 +132,38 @@ class Foo(ComplexModel): def __eq__(self, other): # remember that this is a test object assert ( - self.a == other.a and - self.b == other.b and - self.c == other.c and - self.d == other.d and - self.e == other.e + self.a == other.a + and self.b == other.b + and self.c == other.c + and self.d == other.d + and self.e == other.e ) return True docs = get_schema_documents([Punk, Foo]) pprint(docs) - assert docs['s0'].tag == '{http://www.w3.org/2001/XMLSchema}schema' - assert docs['tns'].tag == '{http://www.w3.org/2001/XMLSchema}schema' + assert docs["s0"].tag == "{http://www.w3.org/2001/XMLSchema}schema" + assert docs["tns"].tag == "{http://www.w3.org/2001/XMLSchema}schema" print() - print("the other namespace %r:" % docs['tns'].attrib['targetNamespace']) - assert docs['tns'].attrib['targetNamespace'] == 'some_namespace' - print(etree.tostring(docs['tns'], pretty_print=True)) + print("the other namespace %r:" % docs["tns"].attrib["targetNamespace"]) + assert docs["tns"].attrib["targetNamespace"] == "some_namespace" + print(etree.tostring(docs["tns"], pretty_print=True)) print() - print("the other namespace %r:" % docs['s0'].attrib['targetNamespace']) - assert docs['s0'].attrib['targetNamespace'] == 'some_other_namespace' - print(etree.tostring(docs['s0'], pretty_print=True)) + print("the other namespace %r:" % docs["s0"].attrib["targetNamespace"]) + assert docs["s0"].attrib["targetNamespace"] == "some_other_namespace" + print(etree.tostring(docs["s0"], pretty_print=True)) print() - foo = Foo(a=u'a', b=1, c=decimal.Decimal('3.4'), - d=datetime(2011,2,20,tzinfo=pytz.utc), e=5) + foo = Foo( + a="a", + b=1, + c=decimal.Decimal("3.4"), + d=datetime(2011, 2, 20, tzinfo=pytz.utc), + e=5, + ) doc = get_object_as_xml(foo, Foo) print(etree.tostring(doc, pretty_print=True)) foo_back = get_xml_as_object(doc, Foo) @@ -189,11 +193,11 @@ class F(E): class C(object): pass - d = cdict({A: "fun", F: 'zan'}) + d = cdict({A: "fun", F: "zan"}) - assert d[A] == 'fun' - assert d[B] == 'fun' - assert d[F] == 'zan' + assert d[A] == "fun" + assert d[B] == "fun" + assert d[F] == "zan" try: d[C] except KeyError: @@ -209,7 +213,7 @@ def test_tdict_notype(self): assert d[0] == 1 d = tdict() - d.update({0:1}) + d.update({0: 1}) assert d[0] == 1 d = tdict.fromkeys([0], 1) @@ -225,8 +229,8 @@ def test_tdict_k(self): raise Exception("must fail") d = tdict(str) - d['s'] = 1 - assert d['s'] == 1 + d["s"] = 1 + assert d["s"] == 1 def test_tdict_v(self): d = tdict(vt=str) @@ -238,8 +242,8 @@ def test_tdict_v(self): raise Exception("must fail") d = tdict(vt=str) - d[0] = 's' - assert d[0] == 's' + d[0] = "s" + assert d[0] == "s" class TestLogRepr(unittest.TestCase): @@ -249,31 +253,32 @@ def test_log_repr_simple(self): from spyne.util.web import log_repr class Z(ComplexModel): - z=String + z = String l = MAX_STRING_FIELD_LENGTH + 100 print(log_repr(Z(z="a" * l))) - print("Z(z='%s'(...))" % ('a' * MAX_STRING_FIELD_LENGTH)) + print("Z(z='%s'(...))" % ("a" * MAX_STRING_FIELD_LENGTH)) - assert log_repr(Z(z="a" * l)) == "Z(z='%s'(...))" % \ - ('a' * MAX_STRING_FIELD_LENGTH) - assert log_repr(['a','b','c'], Array(String)) == "['a', 'b', (...)]" + assert log_repr(Z(z="a" * l)) == "Z(z='%s'(...))" % ( + "a" * MAX_STRING_FIELD_LENGTH + ) + assert log_repr(["a", "b", "c"], Array(String)) == "['a', 'b', (...)]" def test_log_repr_complex(self): - from spyne.model import ByteArray - from spyne.model import File + from spyne.model import ByteArray, File from spyne.model.complex import ComplexModel from spyne.model.primitive import String from spyne.util.web import log_repr class Z(ComplexModel): _type_info = [ - ('f', File(logged=False)), - ('t', ByteArray(logged=False)), - ('z', Array(String)), + ("f", File(logged=False)), + ("t", ByteArray(logged=False)), + ("z", Array(String)), ] + l = MAX_STRING_FIELD_LENGTH + 100 - val = Z(z=["abc"] * l, t=['t'], f=File.Value(name='aaa', data=['t'])) + val = Z(z=["abc"] * l, t=["t"], f=File.Value(name="aaa", data=["t"])) print(repr(val)) assert log_repr(val) == "Z(z=['abc', 'abc', (...)])" @@ -296,7 +301,7 @@ def test_log_repr_dict_keys(self): from spyne.model import AnyDict from spyne.util.web import log_repr - t = AnyDict(logged='keys') + t = AnyDict(logged="keys") assert log_repr({1: 1}, t) == "{1: (...)}" @@ -306,7 +311,7 @@ def test_log_repr_dict_values(self): from spyne.model import AnyDict from spyne.util.web import log_repr - t = AnyDict(logged='values') + t = AnyDict(logged="values") assert log_repr({1: 1}, t) == "{(...): 1}" @@ -316,7 +321,7 @@ def test_log_repr_dict_full(self): from spyne.model import AnyDict from spyne.util.web import log_repr - t = AnyDict(logged='full') + t = AnyDict(logged="full") assert log_repr({1: 1, 2: 2, 3: 3}, t) == "{1: 1, 2: 2, 3: 3}" assert log_repr([1, 2, 3], t) == "[1, 2, 3]" @@ -325,7 +330,7 @@ def test_log_repr_dict_keys_full(self): from spyne.model import AnyDict from spyne.util.web import log_repr - t = AnyDict(logged='keys-full') + t = AnyDict(logged="keys-full") assert log_repr({1: 1, 2: 2, 3: 3}, t) == "{1: (...), 2: (...), 3: (...)}" assert log_repr([1, 2, 3], t) == "[1, 2, 3]" @@ -334,7 +339,7 @@ def test_log_repr_dict_values_full(self): from spyne.model import AnyDict from spyne.util.web import log_repr - t = AnyDict(logged='values-full') + t = AnyDict(logged="values-full") assert log_repr({1: 1, 2: 2, 3: 3}, t) == "{(...): 1, (...): 2, (...): 3}" assert log_repr([1, 2, 3], t) == "[1, 2, 3]" @@ -349,8 +354,9 @@ class SomeService(Service): def some_call(yo): return range(yo) - app = Application([SomeService], 'tns', in_protocol=Soap11(), - out_protocol=Soap11()) + app = Application( + [SomeService], "tns", in_protocol=Soap11(), out_protocol=Soap11() + ) meat = 30 @@ -375,36 +381,55 @@ class TestEtreeDict(unittest.TestCase): def test_simple(self): from lxml.etree import tostring - from spyne.util.etreeconv import root_dict_to_etree - assert tostring(root_dict_to_etree({'a':{'b':'c'}})) == b'c' - def test_not_sized(self): - from lxml.etree import tostring from spyne.util.etreeconv import root_dict_to_etree - complex_value = root_dict_to_etree({'a':{'b':1}}) - self.assertEqual(tostring(complex_value), b'1', - "The integer should be properly rendered in the etree") - - complex_none = root_dict_to_etree({'a':{'b':None}}) - self.assertEqual(tostring(complex_none), b'', - "None should not be rendered in the etree") + assert tostring(root_dict_to_etree({"a": {"b": "c"}})) == b"c" - simple_value = root_dict_to_etree({'a': 1}) - self.assertEqual(tostring(simple_value), b'1', - "The integer should be properly rendered in the etree") - - none_value = root_dict_to_etree({'a': None}) - self.assertEqual(tostring(none_value), b'', - "None should not be rendered in the etree") + def test_not_sized(self): + from lxml.etree import tostring - string_value = root_dict_to_etree({'a': 'lol'}) - self.assertEqual(tostring(string_value), b'lol', - "A string should be rendered as a string") + from spyne.util.etreeconv import root_dict_to_etree - complex_string_value = root_dict_to_etree({'a': {'b': 'lol'}}) - self.assertEqual(tostring(complex_string_value), b'lol', - "A string should be rendered as a string") + complex_value = root_dict_to_etree({"a": {"b": 1}}) + self.assertEqual( + tostring(complex_value), + b"1", + "The integer should be properly rendered in the etree", + ) + + complex_none = root_dict_to_etree({"a": {"b": None}}) + self.assertEqual( + tostring(complex_none), + b"", + "None should not be rendered in the etree", + ) + + simple_value = root_dict_to_etree({"a": 1}) + self.assertEqual( + tostring(simple_value), + b"1", + "The integer should be properly rendered in the etree", + ) + + none_value = root_dict_to_etree({"a": None}) + self.assertEqual( + tostring(none_value), b"", "None should not be rendered in the etree" + ) + + string_value = root_dict_to_etree({"a": "lol"}) + self.assertEqual( + tostring(string_value), + b"lol", + "A string should be rendered as a string", + ) + + complex_string_value = root_dict_to_etree({"a": {"b": "lol"}}) + self.assertEqual( + tostring(complex_string_value), + b"lol", + "A string should be rendered as a string", + ) class TestDictDoc(unittest.TestCase): @@ -417,15 +442,13 @@ class C(ComplexModel): def __eq__(self, other): print("Yaaay!") - return self.i == other.i and \ - self.s == other.s and \ - self.a == other.a + return self.i == other.i and self.s == other.s and self.a == other.a - c = C(i=5, s="x", a=[datetime(2011,12,22, tzinfo=pytz.utc)]) + c = C(i=5, s="x", a=[datetime(2011, 12, 22, tzinfo=pytz.utc)]) - for iw, ca in ((False,dict), (True,dict), (False,list), (True, list)): + for iw, ca in ((False, dict), (True, dict), (False, list), (True, list)): print() - print('complex_as:', ca) + print("complex_as:", ca) d = get_object_as_dict(c, C, complex_as=ca) print(d) o = get_dict_as_object(d, C, complex_as=ca) @@ -436,12 +459,12 @@ def __eq__(self, other): class TestAttrDict(unittest.TestCase): def test_attr_dict(self): - assert AttrDict(a=1)['a'] == 1 + assert AttrDict(a=1)["a"] == 1 def test_attr_dict_coll(self): - assert AttrDictColl('SomeDict').SomeDict.NAME == 'SomeDict' - assert AttrDictColl('SomeDict').SomeDict(a=1)['a'] == 1 - assert AttrDictColl('SomeDict').SomeDict(a=1).NAME == 'SomeDict' + assert AttrDictColl("SomeDict").SomeDict.NAME == "SomeDict" + assert AttrDictColl("SomeDict").SomeDict(a=1)["a"] == 1 + assert AttrDictColl("SomeDict").SomeDict(a=1).NAME == "SomeDict" class TestYaml(unittest.TestCase): @@ -450,7 +473,7 @@ class C(ComplexModel): a = Unicode b = Decimal - ret = get_object_as_yaml(C(a='burak', b=D(30)), C) + ret = get_object_as_yaml(C(a="burak", b=D(30)), C) assert ret == b"""C: a: burak b: '30' @@ -461,15 +484,14 @@ class TestJson(unittest.TestCase): def test_deser(self): class C(ComplexModel): _type_info = [ - ('a', Unicode), - ('b', Decimal), + ("a", Unicode), + ("b", Decimal), ] - ret = get_object_as_json(C(a='burak', b=D(30)), C) + ret = get_object_as_json(C(a="burak", b=D(30)), C) assert ret == b'["burak", "30"]' - ret = get_object_as_json(C(a='burak', b=D(30)), C, complex_as=dict) - assert json.loads(ret.decode('utf8')) == \ - json.loads(u'{"a": "burak", "b": "30"}') + ret = get_object_as_json(C(a="burak", b=D(30)), C, complex_as=dict) + assert json.loads(ret.decode("utf8")) == json.loads('{"a": "burak", "b": "30"}') class TestFifo(unittest.TestCase): @@ -515,13 +537,13 @@ def test_tlist(self): a[5:] = [5] try: - tlist([1, 2, 'a'], int) - a.append('a') - a += ['a'] - _ = ['a'] + a - _ = a + ['a'] - a[0] = 'a' - a[0:] = 'a' + tlist([1, 2, "a"], int) + a.append("a") + a += ["a"] + _ = ["a"] + a + _ = a + ["a"] + a[0] = "a" + a[0:] = "a" except TypeError: pass @@ -532,6 +554,7 @@ def test_tlist(self): class TestMemoization(unittest.TestCase): def test_memoize(self): counter = [0] + @memoize def f(arg): counter[0] += 1 @@ -546,6 +569,7 @@ def f(arg): def test_memoize_ignore_none(self): counter = [0] + @memoize_ignore_none def f(arg): counter[0] += 1 @@ -563,6 +587,7 @@ def f(arg): def test_memoize_ignore_values(self): counter = [0] + @memoize_ignore((1,)) def f(arg): counter[0] += 1 @@ -580,6 +605,7 @@ def f(arg): def test_memoize_id(self): counter = [0] + @memoize_id def f(arg): counter[0] += 1 @@ -597,5 +623,5 @@ def f(arg): assert counter[0] == 3 -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/spyne/util/__init__.py b/spyne/util/__init__.py index 794eb8898..1eeaa3818 100644 --- a/spyne/util/__init__.py +++ b/spyne/util/__init__.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,40 +17,31 @@ # import logging -logger = logging.getLogger(__name__) - -from spyne.util import six - -from spyne.util.coopmt import keepfirst -from spyne.util.coopmt import coroutine -from spyne.util.coopmt import Break - -from spyne.util.memo import memoize -from spyne.util.memo import memoize_first -from spyne.util.memo import memoize_ignore -from spyne.util.memo import memoize_ignore_none -from spyne.util.memo import memoize_id -from spyne.util.attrdict import AttrDict -from spyne.util.attrdict import AttrDictColl -from spyne.util.attrdict import DefaultAttrDict - -from spyne.util._base import utctime -from spyne.util._base import get_version +logger = logging.getLogger(__name__) +from spyne.util._base import get_version, utctime +from spyne.util.attrdict import AttrDict, AttrDictColl, DefaultAttrDict +from spyne.util.coopmt import Break, coroutine, keepfirst +from spyne.util.memo import ( + memoize, + memoize_first, + memoize_id, + memoize_ignore, + memoize_ignore_none, +) try: - import thread + from urllib import quote, splithost, splittype, urlencode - from urllib import splittype, splithost, quote, urlencode - from urllib2 import urlopen, Request, HTTPError + import thread + from urllib2 import HTTPError, Request, urlopen -except ImportError: # Python 3 +except ImportError: # Python 3 import _thread as thread - - from urllib.parse import splittype, splithost, quote, urlencode - from urllib.request import urlopen, Request from urllib.error import HTTPError + from urllib.parse import quote, splithost, splittype, urlencode + from urllib.request import Request, urlopen def split_url(url): @@ -85,19 +75,15 @@ def sanitize_args(a): return args, kwargs -if six.PY2: - def _bytes_join(val, joiner=''): - return joiner.join(val) -else: - def _bytes_join(val, joiner=b''): - if isinstance(val, six.binary_type): - return val - return joiner.join(val) +def _bytes_join(val, joiner=b""): + if isinstance(val, bytes): + return val + return joiner.join(val) def utf8(s): if isinstance(s, bytes): - return s.decode('utf8') + return s.decode("utf8") if isinstance(s, list): return [utf8(ss) for ss in s] diff --git a/spyne/util/_base.py b/spyne/util/_base.py index d23dea56f..aefd40385 100644 --- a/spyne/util/_base.py +++ b/spyne/util/_base.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -17,10 +16,10 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # -from time import mktime from datetime import datetime +from time import mktime -from spyne.util import memoize, six +from spyne.util.memo import memoize def utctime(): @@ -29,10 +28,10 @@ def utctime(): @memoize def get_version(package): - if isinstance(package, (six.text_type, six.binary_type)): + if isinstance(package, (str, bytes)): package = __import__(package) - verstr = getattr(package, '__version__') + verstr = getattr(package, "__version__") retval = [] for f in verstr.split("."): diff --git a/spyne/util/_twisted_ws.py b/spyne/util/_twisted_ws.py index df7468ce8..d6b63041b 100644 --- a/spyne/util/_twisted_ws.py +++ b/spyne/util/_twisted_ws.py @@ -10,22 +10,25 @@ factory. """ -__all__ = ["WebSocketsResource", "IWebSocketsProtocol", "IWebSocketsResource", - "WebSocketsProtocol", "WebSocketsProtocolWrapper"] +__all__ = [ + "WebSocketsResource", + "IWebSocketsProtocol", + "IWebSocketsResource", + "WebSocketsProtocol", + "WebSocketsProtocolWrapper", +] +from enum import IntEnum from hashlib import sha1 from struct import pack, unpack -from zope.interface import implementer, Interface, providedBy, directlyProvides - -from twisted.python import log -from twisted.python.constants import Flags, FlagConstant -from twisted.internet.protocol import Protocol from twisted.internet.interfaces import IProtocol +from twisted.internet.protocol import Protocol +from twisted.python import log from twisted.web.resource import IResource from twisted.web.server import NOT_DONE_YET - +from zope.interface import Interface, directlyProvides, implementer, providedBy class _WSException(Exception): @@ -34,25 +37,23 @@ class _WSException(Exception): """ - -class CONTROLS(Flags): +class CONTROLS(IntEnum): """ Control frame specifiers. """ - CONTINUE = FlagConstant(0) - TEXT = FlagConstant(1) - BINARY = FlagConstant(2) - CLOSE = FlagConstant(8) - PING = FlagConstant(9) - PONG = FlagConstant(10) + CONTINUE = 0 + TEXT = 1 + BINARY = 2 + CLOSE = 8 + PING = 9 + PONG = 10 # The GUID for WebSockets, from RFC 6455. _WS_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - def _makeAccept(key): """ Create an B{accept} response for a given key. @@ -66,7 +67,6 @@ def _makeAccept(key): return sha1("%s%s" % (key, _WS_GUID)).digest().encode("base64").strip() - def _mask(buf, key): """ Mask or unmask a buffer of bytes with a masking key. @@ -87,7 +87,6 @@ def _mask(buf, key): return "".join(buf) - def _makeFrame(buf, opcode, fin, mask=None): """ Make a frame. @@ -110,10 +109,10 @@ def _makeFrame(buf, opcode, fin, mask=None): else: lengthMask = 0 - if bufferLength > 0xffff: - length = "%s%s" % (chr(lengthMask | 0x7f), pack(">Q", bufferLength)) - elif bufferLength > 0x7d: - length = "%s%s" % (chr(lengthMask | 0x7e), pack(">H", bufferLength)) + if bufferLength > 0xFFFF: + length = "%s%s" % (chr(lengthMask | 0x7F), pack(">Q", bufferLength)) + elif bufferLength > 0x7D: + length = "%s%s" % (chr(lengthMask | 0x7E), pack(">H", bufferLength)) else: length = chr(lengthMask | bufferLength) @@ -129,7 +128,6 @@ def _makeFrame(buf, opcode, fin, mask=None): return frame - def _parseFrames(frameBuffer, needMask=True): """ Parse frames in a highly compliant manner. @@ -158,9 +156,9 @@ def _parseFrames(frameBuffer, needMask=True): # Get the opcode, and translate it to a local enum which we actually # care about. - opcode = header & 0xf + opcode = header & 0xF try: - opcode = CONTROLS.lookupByValue(opcode) + opcode = CONTROLS(opcode) except ValueError: raise _WSException("Unknown opcode %d in frame" % opcode) @@ -173,27 +171,27 @@ def _parseFrames(frameBuffer, needMask=True): # The client must mask the data sent raise _WSException("Received data not masked") - length &= 0x7f + length &= 0x7F # The offset we'll be using to walk through the frame. We use this # because the offset is variable depending on the length and mask. offset = 2 # Extra length fields. - if length == 0x7e: + if length == 0x7E: if len(payload) - start < 4: break - length = payload[start + 2:start + 4] + length = payload[start + 2 : start + 4] length = unpack(">H", length)[0] offset += 2 - elif length == 0x7f: + elif length == 0x7F: if len(payload) - start < 10: break # Protocol bug: The top bit of this long long *must* be cleared; # that is, it is expected to be interpreted as signed. - length = payload[start + 2:start + 10] + length = payload[start + 2 : start + 10] length = unpack(">Q", length)[0] offset += 8 @@ -203,13 +201,13 @@ def _parseFrames(frameBuffer, needMask=True): # that we don't create an invalid key. break - key = payload[start + offset:start + offset + 4] + key = payload[start + offset : start + offset + 4] offset += 4 if len(payload) - (start + offset) < length: break - data = payload[start + offset:start + offset + length] + data = payload[start + offset : start + offset + length] if masked: data = _mask(data, key) @@ -231,8 +229,6 @@ def _parseFrames(frameBuffer, needMask=True): frameBuffer[:] = [] - - class IWebSocketsProtocol(IProtocol): """ A protocol which understands the WebSockets interface. @@ -245,29 +241,26 @@ def sendFrame(opcode, data, fin): Send a frame. """ - def frameReceived(opcode, data, fin): """ Callback when a frame is received. """ - def loseConnection(): """ Close the connection sending a close frame first. """ - @implementer(IWebSocketsProtocol) class WebSocketsProtocol(Protocol): """ @since: 13.1 """ + _disconnecting = False _buffer = None - def connectionMade(self): """ Log the new connection and initialize the buffer list. @@ -275,7 +268,6 @@ def connectionMade(self): log.msg("Opening connection with %s" % self.transport.getPeer()) self._buffer = [] - def _parseFrames(self): """ Find frames in incoming data and pass them to the underlying protocol. @@ -300,14 +292,12 @@ def _parseFrames(self): # provoking PING. self.transport.write(_makeFrame(data, CONTROLS.PONG, True)) - def frameReceived(self, opcode, data, fin): """ Callback to implement. """ raise NotImplementedError() - def sendFrame(self, opcode, data, fin): """ Build a frame packet and send it over the wire. @@ -315,7 +305,6 @@ def sendFrame(self, opcode, data, fin): packet = _makeFrame(data, opcode, fin) self.transport.write(packet) - def dataReceived(self, data): """ Append the data to the buffer list and parse the whole. @@ -328,7 +317,6 @@ def dataReceived(self, data): log.err() self.transport.loseConnection() - def loseConnection(self): """ Close the connection. @@ -349,7 +337,6 @@ def loseConnection(self): self.transport.loseConnection() - class WebSocketsProtocolWrapper(WebSocketsProtocol): """ A protocol wrapper which provides L{IWebSocketsProtocol} by making messages @@ -362,7 +349,6 @@ def __init__(self, wrappedProtocol, defaultOpcode=CONTROLS.TEXT): self.wrappedProtocol = wrappedProtocol self.defaultOpcode = defaultOpcode - def makeConnection(self, transport): """ Upon connection, provides the transport interface, and forwards ourself @@ -372,7 +358,6 @@ def makeConnection(self, transport): WebSocketsProtocol.makeConnection(self, transport) self.wrappedProtocol.makeConnection(self) - def connectionMade(self): """ Initialize the list of messages. @@ -380,14 +365,12 @@ def connectionMade(self): WebSocketsProtocol.connectionMade(self) self._messages = [] - def write(self, data): """ Write to the websocket protocol, transforming C{data} in a frame. """ self.sendFrame(self.defaultOpcode, data, True) - def writeSequence(self, data): """ Send all chunks from C{data} using C{write}. @@ -395,14 +378,12 @@ def writeSequence(self, data): for chunk in data: self.write(chunk) - def __getattr__(self, name): """ Forward all non-local attributes and methods to C{self.transport}. """ return getattr(self.transport, name) - def frameReceived(self, opcode, data, fin): """ FOr each frame received, accumulate the data (ignoring the opcode), and @@ -414,7 +395,6 @@ def frameReceived(self, opcode, data, fin): self._messages[:] = [] self.wrappedProtocol.dataReceived(content) - def connectionLost(self, reason): """ Forward C{connectionLost} to C{self.wrappedProtocol}. @@ -422,7 +402,6 @@ def connectionLost(self, reason): self.wrappedProtocol.connectionLost(reason) - class IWebSocketsResource(Interface): """ A WebSockets resource. @@ -450,7 +429,6 @@ def lookupProtocol(protocolNames, request): """ - @implementer(IResource, IWebSocketsResource) class WebSocketsResource(object): """ @@ -469,21 +447,19 @@ class WebSocketsResource(object): @since: 13.1 """ + isLeaf = True def __init__(self, factory): self._factory = factory - def getChildWithDefault(self, name, request): """ Reject attempts to retrieve a child resource. All path segments beyond the one which refers to this resource are handled by the WebSocket connection. """ - raise RuntimeError( - "Cannot get IResource children from WebSocketsResource") - + raise RuntimeError("Cannot get IResource children from WebSocketsResource") def putChild(self, path, child): """ @@ -491,9 +467,7 @@ def putChild(self, path, child): WebSocket connection handles all path segments beneath this resource, so L{IResource} children can never be found. """ - raise RuntimeError( - "Cannot put IResource children under WebSocketsResource") - + raise RuntimeError("Cannot put IResource children under WebSocketsResource") def lookupProtocol(self, protocolNames, request): """ @@ -513,7 +487,6 @@ def lookupProtocol(self, protocolNames, request): protocol = self._factory.buildProtocol(request.transport.getPeer()) return protocol, None - def render(self, request): """ Render a request. @@ -533,7 +506,7 @@ def render(self, request): if request.method != "GET": # 4.2.1.1 GET is required. failed = True - print('request.method', request.method) + print("request.method", request.method) upgrade = request.getHeader("Upgrade") if upgrade is None or "websocket" not in upgrade.lower(): @@ -551,7 +524,10 @@ def render(self, request): if key is None: # 4.2.1.5 The challenge key is required. failed = True - print('request.getHeader("Sec-WebSocket-Key")', request.getHeader("Sec-WebSocket-Key")) + print( + 'request.getHeader("Sec-WebSocket-Key")', + request.getHeader("Sec-WebSocket-Key"), + ) version = request.getHeader("Sec-WebSocket-Version") if version != "13": @@ -559,14 +535,16 @@ def render(self, request): failed = True # 4.4 Forward-compatible version checking. request.setHeader("Sec-WebSocket-Version", "13") - print('request.getHeader("Sec-WebSocket-Version")', request.getHeader("Sec-WebSocket-Version")) + print( + 'request.getHeader("Sec-WebSocket-Version")', + request.getHeader("Sec-WebSocket-Version"), + ) if failed: request.setResponseCode(400) return "" - askedProtocols = request.requestHeaders.getRawHeaders( - "Sec-WebSocket-Protocol") + askedProtocols = request.requestHeaders.getRawHeaders("Sec-WebSocket-Protocol") protocol, protocolName = self.lookupProtocol(askedProtocols, request) # If a protocol is not created, we deliver an error status. diff --git a/spyne/util/address.py b/spyne/util/address.py index 55a0da0bc..457bed75e 100644 --- a/spyne/util/address.py +++ b/spyne/util/address.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -42,10 +41,11 @@ from __future__ import print_function +import socket + # Direct plagiarization of https://github.com/un33k/django-ipware/ # at 57897c03026913892e61a164bc8b022778802ab9 -import socket # List of known proxy server(s) TRUSTED_PROXIES = [] @@ -53,16 +53,17 @@ # Search for the real IP address in the following order # Configurable via settings.py PRECEDENCE = ( - 'HTTP_X_FORWARDED_FOR', 'X_FORWARDED_FOR', + "HTTP_X_FORWARDED_FOR", + "X_FORWARDED_FOR", # (client, proxy1, proxy2) OR (proxy2, proxy1, client) - 'HTTP_CLIENT_IP', - 'HTTP_X_REAL_IP', - 'HTTP_X_FORWARDED', - 'HTTP_X_CLUSTER_CLIENT_IP', - 'HTTP_FORWARDED_FOR', - 'HTTP_FORWARDED', - 'HTTP_VIA', - 'REMOTE_ADDR', + "HTTP_CLIENT_IP", + "HTTP_X_REAL_IP", + "HTTP_X_FORWARDED", + "HTTP_X_CLUSTER_CLIENT_IP", + "HTTP_FORWARDED_FOR", + "HTTP_FORWARDED", + "HTTP_VIA", + "REMOTE_ADDR", ) # Private IP addresses @@ -72,36 +73,51 @@ # Regex would be ideal here, but this is keeping it simple # as fields are configurable via settings.py PRIVATE_IP_PREFIXES = ( - '0.', # externally non-routable - '10.', # class A private block - '169.254.', # link-local block - '172.16.', '172.17.', '172.18.', '172.19.', - '172.20.', '172.21.', '172.22.', '172.23.', - '172.24.', '172.25.', '172.26.', '172.27.', - '172.28.', '172.29.', '172.30.', '172.31.', + "0.", # externally non-routable + "10.", # class A private block + "169.254.", # link-local block + "172.16.", + "172.17.", + "172.18.", + "172.19.", + "172.20.", + "172.21.", + "172.22.", + "172.23.", + "172.24.", + "172.25.", + "172.26.", + "172.27.", + "172.28.", + "172.29.", + "172.30.", + "172.31.", # class B private blocks - '192.0.2.', + "192.0.2.", # reserved for documentation and example code - '192.168.', # class C private block - '255.255.255.', # IPv4 broadcast address + "192.168.", # class C private block + "255.255.255.", # IPv4 broadcast address ) + ( - '2001:db8:', + "2001:db8:", # reserved for documentation and example code - 'fc00:', # IPv6 private block - 'fe80:', # link-local unicast - 'ff00:', # IPv6 multicast + "fc00:", # IPv6 private block + "fe80:", # link-local unicast + "ff00:", # IPv6 multicast ) LOOPBACK_PREFIX = ( - '127.', # IPv4 loopback device - '::1', # IPv6 loopback device + "127.", # IPv4 loopback device + "::1", # IPv6 loopback device ) NON_PUBLIC_IP_PREFIXES = PRIVATE_IP_PREFIXES + LOOPBACK_PREFIX -def set_address_parser_settings(trusted_proxies, field_precedence=PRECEDENCE, - private_ip_prefixes=NON_PUBLIC_IP_PREFIXES): +def set_address_parser_settings( + trusted_proxies, + field_precedence=PRECEDENCE, + private_ip_prefixes=NON_PUBLIC_IP_PREFIXES, +): """Changes global parameters for Spyne's residend ip address parser. :param trusted_proxies: Tuple of reverse proxies that are under YOUR control. @@ -113,30 +129,32 @@ def set_address_parser_settings(trusted_proxies, field_precedence=PRECEDENCE, global address_parser - address_parser = AddressParser(trusted_proxies=trusted_proxies, - field_precedence=field_precedence, - private_ip_prefixes=private_ip_prefixes) + address_parser = AddressParser( + trusted_proxies=trusted_proxies, + field_precedence=field_precedence, + private_ip_prefixes=private_ip_prefixes, + ) class AddressParser(object): - def __init__(self, private_ip_prefixes=None, trusted_proxies=(), - field_precedence=PRECEDENCE): + def __init__( + self, private_ip_prefixes=None, trusted_proxies=(), field_precedence=PRECEDENCE + ): if private_ip_prefixes is not None: self.private_ip_prefixes = private_ip_prefixes else: - self.private_ip_prefixes = \ - tuple([ip.lower() for ip in NON_PUBLIC_IP_PREFIXES]) + self.private_ip_prefixes = tuple( + [ip.lower() for ip in NON_PUBLIC_IP_PREFIXES] + ) if len(trusted_proxies) > 0: self.trusted_proxies = trusted_proxies else: - self.trusted_proxies = \ - tuple([ip.lower() for ip in TRUSTED_PROXIES]) + self.trusted_proxies = tuple([ip.lower() for ip in TRUSTED_PROXIES]) self.field_precedence = field_precedence - def get_port(self, wsgi_env): return wsgi_env.get("REMOTE_PORT", 0) @@ -149,19 +167,22 @@ def get_ip(self, wsgi_env, real_ip_only=False, right_most_proxy=False): for key in self.field_precedence: value = wsgi_env.get(key, None) if value is None: - value = wsgi_env.get(key.replace('_', '-'), None) + value = wsgi_env.get(key.replace("_", "-"), None) - if value is None or value == '': + if value is None or value == "": continue - ips = [ip.strip().lower() for ip in value.split(',')] + ips = [ip.strip().lower() for ip in value.split(",")] if right_most_proxy and len(ips) > 1: ips = reversed(ips) for ip_str in ips: - if ip_str is None or ip_str == '' or not \ - AddressParser.is_valid_ip(ip_str): + if ( + ip_str is None + or ip_str == "" + or not AddressParser.is_valid_ip(ip_str) + ): continue if not ip_str.startswith(self.private_ip_prefixes): @@ -173,8 +194,9 @@ def get_ip(self, wsgi_env, real_ip_only=False, right_most_proxy=False): if best_matched_ip is None: best_matched_ip = ip_str - elif best_matched_ip.startswith(loopback) \ - and not ip_str.startswith(loopback): + elif best_matched_ip.startswith(loopback) and not ip_str.startswith( + loopback + ): best_matched_ip = ip_str return best_matched_ip @@ -184,11 +206,11 @@ def get_real_ip(self, wsgi_env, right_most_proxy=False): Returns client's best-matched `real` `externally-routable` ip-address, or None """ - return self.get_ip(wsgi_env, real_ip_only=True, - right_most_proxy=right_most_proxy) + return self.get_ip( + wsgi_env, real_ip_only=True, right_most_proxy=right_most_proxy + ) - def get_trusted_ip(self, wsgi_env, right_most_proxy=False, - trusted_proxies=None): + def get_trusted_ip(self, wsgi_env, right_most_proxy=False, trusted_proxies=None): """ Returns client's ip-address from `trusted` proxy server(s) or None """ @@ -202,17 +224,17 @@ def get_trusted_ip(self, wsgi_env, right_most_proxy=False, if trusted_proxies is None or len(trusted_proxies) == 0: return - meta_keys = ['HTTP_X_FORWARDED_FOR', 'X_FORWARDED_FOR'] + meta_keys = ["HTTP_X_FORWARDED_FOR", "X_FORWARDED_FOR"] for key in meta_keys: value = wsgi_env.get(key, None) if value is None: - value = wsgi_env.get(key.replace('_', '-'), None) + value = wsgi_env.get(key.replace("_", "-"), None) - if value is None or value == '': + if value is None or value == "": continue - ips = [ip.strip().lower() for ip in value.split(',')] + ips = [ip.strip().lower() for ip in value.split(",")] if len(ips) > 1: if right_most_proxy: @@ -239,7 +261,7 @@ def is_valid_ipv4(ip_str): socket.inet_aton(ip_str) except (AttributeError, socket.error): return False - return ip_str.count('.') == 3 + return ip_str.count(".") == 3 except socket.error: return False @@ -269,8 +291,9 @@ def is_valid_ip(ip_str): Check the validity of an IP address """ - return AddressParser.is_valid_ipv4(ip_str) or \ - AddressParser.is_valid_ipv6(ip_str) + return AddressParser.is_valid_ipv4(ip_str) or AddressParser.is_valid_ipv6( + ip_str + ) address_parser = AddressParser() diff --git a/spyne/util/appreg.py b/spyne/util/appreg.py index 31c863798..baa8ad373 100644 --- a/spyne/util/appreg.py +++ b/spyne/util/appreg.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -22,6 +21,7 @@ """ import logging + logger = logging.getLogger(__name__) applications = {} @@ -29,10 +29,12 @@ try: from collections import namedtuple - _ApplicationMetaData = namedtuple("_ApplicationMetaData", - ['app', 'inst_stack', 'null', 'ostr']) + _ApplicationMetaData = namedtuple( + "_ApplicationMetaData", ["app", "inst_stack", "null", "ostr"] + ) + +except ImportError: # python 2.5 -except ImportError: # python 2.5 class _ApplicationMetaData: def __init__(self, app, inst_stack, null, ostr): self.app = app @@ -53,6 +55,7 @@ def register_application(app): try: import traceback + stack = traceback.format_stack() except ImportError: stack = None @@ -61,8 +64,10 @@ def register_application(app): if prev is not None: if hash(prev.app) == hash(app): - logger.debug("Application %r previously registered as %r is the same" - " as %r. Skipping." % (prev.app, key, app)) + logger.debug( + "Application %r previously registered as %r is the same" + " as %r. Skipping." % (prev.app, key, app) + ) prev.inst_stack.append(stack) else: @@ -72,17 +77,21 @@ def register_application(app): stack_traces = [] for s in prev.inst_stack: if s is not None: - stack_traces.append(''.join(s)) - logger.debug("Stack trace of the instantiation:\n%s" % - '====================\n'.join(stack_traces)) - - applications[key] = _ApplicationMetaData(app=app, inst_stack=[stack], - null=NullServer(app, appinit=False), - ostr=NullServer(app, appinit=False, ostr=True) + stack_traces.append("".join(s)) + logger.debug( + "Stack trace of the instantiation:\n%s" + % "====================\n".join(stack_traces) + ) + + applications[key] = _ApplicationMetaData( + app=app, + inst_stack=[stack], + null=NullServer(app, appinit=False), + ostr=NullServer(app, appinit=False, ostr=True), ) logger.debug("Registering %r as %r" % (app, key)) -def get_application(tns, name='Application'): +def get_application(tns, name="Application"): return applications.get((tns, name), None) diff --git a/spyne/util/attrdict.py b/spyne/util/attrdict.py index de996aaaf..cab216ebd 100644 --- a/spyne/util/attrdict.py +++ b/spyne/util/attrdict.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -25,14 +24,14 @@ def __init__(self, *args, **kwargs): def __call__(self, **kwargs): retval = AttrDict(self.__data.items()) - for k,v in kwargs.items(): + for k, v in kwargs.items(): setattr(retval, k, v) return retval def __setattr__(self, key, value): if key == "_AttrDict__data": return object.__setattr__(self, key, value) - if key == 'items': + if key == "items": raise ValueError("'items' is part of dict interface") self.__data[key] = value @@ -52,23 +51,32 @@ def update(self, d): return self.__data.update(d) def __repr__(self): - return "AttrDict(%s)" % ', '.join(['%s=%r' % (k, v) - for k,v in sorted(self.__data.items(), key=lambda x:x[0])]) + return "AttrDict(%s)" % ", ".join( + [ + "%s=%r" % (k, v) + for k, v in sorted(self.__data.items(), key=lambda x: x[0]) + ] + ) if default is None: + def __getattr__(self, key): return self.__data[key] + def __getitem__(self, key): return self.__data[key] + else: + def __getitem__(self, key): if key in self.__data: return self.__data[key] else: return default() + def __getattr__(self, key): - if key in ("_AttrDict__data", 'items', 'get', 'update'): - return object.__getattribute__(self, '__data') + if key in ("_AttrDict__data", "items", "get", "update"): + return object.__getattribute__(self, "__data") if key in self.__data: return self.__data[key] else: @@ -76,12 +84,14 @@ def __getattr__(self, key): return AttrDict + AttrDict = TAttrDict() DefaultAttrDict = TAttrDict(lambda: None) class AttrDictColl(object): AttrDictImpl = DefaultAttrDict + def __init__(self, *args): for a in args: setattr(self, a, AttrDictColl.AttrDictImpl(NAME=a)) diff --git a/spyne/util/autorel.py b/spyne/util/autorel.py index 2fc685ac8..b23a7a44b 100644 --- a/spyne/util/autorel.py +++ b/spyne/util/autorel.py @@ -47,9 +47,12 @@ # import logging + logger = logging.getLogger(__name__) -import os, re, sys +import os +import re +import sys from spyne.util.color import YEL @@ -77,12 +80,11 @@ MAX_FILES = 0 else: try: - MAX_FILES = os.sysconf('SC_OPEN_MAX') + MAX_FILES = os.sysconf("SC_OPEN_MAX") except AttributeError: MAX_FILES = 1024 - class AutoReloader(object): """Monitor which re-executes the process when files change. @@ -103,7 +105,7 @@ class AutoReloader(object): FILES = set() """The set of files to poll for modifications.""" - def __init__(self, frequency=1, match='.*'): + def __init__(self, frequency=1, match=".*"): self.max_cloexec_files = MAX_FILES self.mtimes = {} @@ -125,29 +127,25 @@ def start(self): retval = LoopingCall(self.run) retval.start(self.frequency) - return retval # oh no + return retval # oh no def sysfiles(self): """Return a Set of sys.modules filenames to monitor.""" files = set() for k, m in list(sys.modules.items()): if re.match(self.match, k): - if ( - hasattr(m, '__loader__') and - hasattr(m.__loader__, 'archive') - ): + if hasattr(m, "__loader__") and hasattr(m.__loader__, "archive"): f = m.__loader__.archive else: try: - f = getattr(m, '__file__', None) + f = getattr(m, "__file__", None) except ImportError: f = None if f is not None and not os.path.isabs(f): # ensure absolute paths so a os.chdir() in the app # doesn't break me - f = os.path.normpath( - os.path.join(_module__file__base, f)) + f = os.path.normpath(os.path.join(_module__file__base, f)) files.add(f) return files @@ -155,7 +153,7 @@ def run(self): """Reload the process if registered files have been modified.""" for filename in self.sysfiles() | self.files: if filename: - if filename.endswith('.pyc'): + if filename.endswith(".pyc"): filename = filename[:-1] oldtime = self.mtimes.get(filename, 0) @@ -175,10 +173,10 @@ def run(self): else: if mtime is None or mtime > oldtime: # The file has been deleted or modified. - logger.info("Restarting because '%s' has changed." % - filename) + logger.info("Restarting because '%s' has changed." % filename) from twisted.internet import reactor + reactor.stop() self._do_execv() return @@ -198,12 +196,9 @@ def _extend_pythonpath(env): (This idea filched from tornado.autoreload) """ - path_prefix = '.' + os.pathsep - existing_path = env.get('PYTHONPATH', '') - needs_patch = ( - sys.path[0] == '' and - not existing_path.startswith(path_prefix) - ) + path_prefix = "." + os.pathsep + existing_path = env.get("PYTHONPATH", "") + needs_patch = sys.path[0] == "" and not existing_path.startswith(path_prefix) if needs_patch: env["PYTHONPATH"] = path_prefix + existing_path @@ -236,17 +231,18 @@ def _do_execv(self): self._extend_pythonpath(os.environ) - logger.info('Re-spawning %s' % ' '.join(args)) + logger.info("Re-spawning %s" % " ".join(args)) logger.info("") logger.info("%s Bye! %s", YEL("-" * 35), YEL("-" * 35)) logger.info("") - if sys.platform[:4] == 'java': + if sys.platform[:4] == "java": from _systemrestart import SystemRestart + raise SystemRestart args.insert(0, sys.executable) - if sys.platform == 'win32': + if sys.platform == "win32": args = ['"%s"' % arg for arg in args] os.chdir(_module__file__base) diff --git a/spyne/util/cdict.py b/spyne/util/cdict.py index 8e4d170c5..503c1a85a 100644 --- a/spyne/util/cdict.py +++ b/spyne/util/cdict.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -55,15 +54,17 @@ """ import logging + logger = logging.getLogger(__name__) + class cdict(dict): def __getitem__(self, cls): try: return dict.__getitem__(self, cls) except KeyError as e: - if not hasattr(cls, '__bases__'): + if not hasattr(cls, "__bases__"): cls = cls.__class__ for b in reversed(cls.__bases__): diff --git a/spyne/util/cherry.py b/spyne/util/cherry.py index f5b5cedc2..3fc222aed 100644 --- a/spyne/util/cherry.py +++ b/spyne/util/cherry.py @@ -2,14 +2,23 @@ # Source: https://www.digitalocean.com/community/tutorials/how-to-deploy-python-wsgi-applications-using-a-cherrypy-web-server-behind-nginx import logging + import cherrypy -def cherry_graft_and_start(wsgi_application, host="0.0.0.0", port=8080, - num_threads=30, ssl_module=None, cert=None, key=None, cacert=None): +def cherry_graft_and_start( + wsgi_application, + host="0.0.0.0", + port=8080, + num_threads=30, + ssl_module=None, + cert=None, + key=None, + cacert=None, +): logging.basicConfig(level=logging.DEBUG) - logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG) + logging.getLogger("spyne.protocol.xml").setLevel(logging.DEBUG) # Mount the application cherrypy.tree.graft(wsgi_application, "/") @@ -27,9 +36,9 @@ def cherry_graft_and_start(wsgi_application, host="0.0.0.0", port=8080, # For SSL Support if ssl_module is not None: - server.ssl_module = ssl_module # eg. 'pyopenssl' - server.ssl_certificate = cert # eg. 'ssl/certificate.crt' - server.ssl_private_key = key # eg. 'ssl/private.key' + server.ssl_module = ssl_module # eg. 'pyopenssl' + server.ssl_certificate = cert # eg. 'ssl/certificate.crt' + server.ssl_private_key = key # eg. 'ssl/private.key' server.ssl_certificate_chain = cacert # eg. 'ssl/bundle.crt' # Subscribe this server diff --git a/spyne/util/color.py b/spyne/util/color.py index f12490a84..5655eb58a 100644 --- a/spyne/util/color.py +++ b/spyne/util/color.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -19,33 +18,36 @@ from __future__ import absolute_import - try: import colorama - R = lambda s: ''.join((colorama.Fore.RED, colorama.Style.BRIGHT, s, - colorama.Style.RESET_ALL)) - G = lambda s: ''.join((colorama.Fore.GREEN, colorama.Style.BRIGHT, s, - colorama.Style.RESET_ALL)) - B = lambda s: ''.join((colorama.Fore.BLUE, colorama.Style.BRIGHT, s, - colorama.Style.RESET_ALL)) - DARK_R = lambda s: ''.join((colorama.Fore.RED, s, colorama.Style.RESET_ALL)) - DARK_G = lambda s: ''.join((colorama.Fore.GREEN, s, colorama.Style.RESET_ALL)) - DARK_B = lambda s: ''.join((colorama.Fore.BLUE, s, colorama.Style.RESET_ALL)) + R = lambda s: "".join( + (colorama.Fore.RED, colorama.Style.BRIGHT, s, colorama.Style.RESET_ALL) + ) + G = lambda s: "".join( + (colorama.Fore.GREEN, colorama.Style.BRIGHT, s, colorama.Style.RESET_ALL) + ) + B = lambda s: "".join( + (colorama.Fore.BLUE, colorama.Style.BRIGHT, s, colorama.Style.RESET_ALL) + ) + + DARK_R = lambda s: "".join((colorama.Fore.RED, s, colorama.Style.RESET_ALL)) + DARK_G = lambda s: "".join((colorama.Fore.GREEN, s, colorama.Style.RESET_ALL)) + DARK_B = lambda s: "".join((colorama.Fore.BLUE, s, colorama.Style.RESET_ALL)) - YEL = lambda s: ''.join((colorama.Fore.YELLOW, colorama.Style.BRIGHT, s, - colorama.Style.RESET_ALL)) - MAG = lambda s: ''.join((colorama.Fore.MAGENTA, colorama.Style.BRIGHT, s, - colorama.Style.RESET_ALL)) - CYA = lambda s: ''.join((colorama.Fore.CYAN, colorama.Style.BRIGHT, s, - colorama.Style.RESET_ALL)) + YEL = lambda s: "".join( + (colorama.Fore.YELLOW, colorama.Style.BRIGHT, s, colorama.Style.RESET_ALL) + ) + MAG = lambda s: "".join( + (colorama.Fore.MAGENTA, colorama.Style.BRIGHT, s, colorama.Style.RESET_ALL) + ) + CYA = lambda s: "".join( + (colorama.Fore.CYAN, colorama.Style.BRIGHT, s, colorama.Style.RESET_ALL) + ) - DARK_YEL = lambda s: ''.join((colorama.Fore.YELLOW, s, - colorama.Style.RESET_ALL)) - DARK_MAG = lambda s: ''.join((colorama.Fore.MAGENTA, s, - colorama.Style.RESET_ALL)) - DARK_CYA = lambda s: ''.join((colorama.Fore.CYAN, s, - colorama.Style.RESET_ALL)) + DARK_YEL = lambda s: "".join((colorama.Fore.YELLOW, s, colorama.Style.RESET_ALL)) + DARK_MAG = lambda s: "".join((colorama.Fore.MAGENTA, s, colorama.Style.RESET_ALL)) + DARK_CYA = lambda s: "".join((colorama.Fore.CYAN, s, colorama.Style.RESET_ALL)) except ImportError: R = lambda s: s @@ -62,7 +64,7 @@ DARK_CYA = lambda s: s -if __name__ == '__main__': +if __name__ == "__main__": print(R("RED")) print(G("GREEN")) print(B("BLUE")) diff --git a/spyne/util/coopmt.py b/spyne/util/coopmt.py index 62fb14251..0bb473700 100644 --- a/spyne/util/coopmt.py +++ b/spyne/util/coopmt.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -23,16 +22,17 @@ decorator. """ - import logging + logger = logging.getLogger(__name__) -from itertools import chain from inspect import isgeneratorfunction +from itertools import chain class Break(Exception): """Raised for breaking out of infinite loops inside coroutines.""" + pass @@ -43,8 +43,13 @@ def start(*args, **kwargs): try: ret = func(*args, **kwargs) except TypeError as e: - logger.error("Function %r at %s:%d got error %r", func.func_name, - func.__module__, func.__code__.co_firstlineno, e) + logger.error( + "Function %r at %s:%d got error %r", + func.func_name, + func.__module__, + func.__code__.co_firstlineno, + e, + ) raise try: @@ -54,7 +59,7 @@ def start(*args, **kwargs): return None except Exception as e: - if not hasattr(e, 'logged'): + if not hasattr(e, "logged"): logger.error("Exception in coroutine") logger.exception(e) try: @@ -76,8 +81,13 @@ def start(*args, **kwargs): try: ret = func(*args, **kwargs) except TypeError as e: - logger.error("Function %r at %s:%d got error %r", func.func_name, - func.__module__, func.__code__.co_firstlineno, e) + logger.error( + "Function %r at %s:%d got error %r", + func.func_name, + func.__module__, + func.__code__.co_firstlineno, + e, + ) raise try: @@ -87,7 +97,7 @@ def start(*args, **kwargs): return None except Exception as e: - if not hasattr(e, 'logged'): + if not hasattr(e, "logged"): logger.error("Exception in coroutine") logger.exception(e) try: diff --git a/spyne/util/dictdoc.py b/spyne/util/dictdoc.py index 77571cda2..5cf7b6de9 100644 --- a/spyne/util/dictdoc.py +++ b/spyne/util/dictdoc.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -18,14 +17,13 @@ # from spyne.context import FakeContext - -from spyne.protocol.dictdoc import HierDictDocument -from spyne.protocol.dictdoc import SimpleDictDocument +from spyne.protocol.dictdoc import HierDictDocument, SimpleDictDocument try: from spyne.protocol.json import JsonDocument except ImportError as _import_error: _local_import_error = _import_error + def JsonDocument(*args, **kwargs): raise _local_import_error @@ -34,6 +32,7 @@ def JsonDocument(*args, **kwargs): from spyne.protocol.yaml import YamlDocument except ImportError as _import_error: _local_import_error = _import_error + def YamlDocument(*args, **kwargs): raise _local_import_error @@ -42,26 +41,36 @@ def YamlDocument(*args, **kwargs): from spyne.protocol.msgpack import MessagePackDocument except ImportError as _import_error: _local_import_error = _import_error + def MessagePackDocument(*args, **kwargs): raise _local_import_error -from spyne.model.primitive import Double -from spyne.model.primitive import Boolean -from spyne.model.primitive import Decimal -from spyne.model.primitive import Integer +from spyne.model.primitive import Boolean, Decimal, Double, Integer class _UtilProtocol(HierDictDocument): - def __init__(self, app=None, validator=None, mime_type=None, - ignore_uncap=False, - # DictDocument specific - ignore_wrappers=True, - complex_as=dict, - ordered=False): - - super(_UtilProtocol, self).__init__(app, validator, mime_type, ignore_uncap, - ignore_wrappers, complex_as, ordered) + def __init__( + self, + app=None, + validator=None, + mime_type=None, + ignore_uncap=False, + # DictDocument specific + ignore_wrappers=True, + complex_as=dict, + ordered=False, + ): + + super(_UtilProtocol, self).__init__( + app, + validator, + mime_type, + ignore_uncap, + ignore_wrappers, + complex_as, + ordered, + ) self._from_unicode_handlers[Double] = lambda cls, val: val self._from_unicode_handlers[Boolean] = lambda cls, val: val @@ -74,11 +83,16 @@ def __init__(self, app=None, validator=None, mime_type=None, self._to_unicode_handlers[Integer] = lambda cls, val: val -def get_doc_as_object(d, cls, ignore_wrappers=True, complex_as=list, - protocol=_UtilProtocol, protocol_inst=None): +def get_doc_as_object( + d, + cls, + ignore_wrappers=True, + complex_as=list, + protocol=_UtilProtocol, + protocol_inst=None, +): if protocol_inst is None: - protocol_inst = protocol(ignore_wrappers=ignore_wrappers, - complex_as=complex_as) + protocol_inst = protocol(ignore_wrappers=ignore_wrappers, complex_as=complex_as) return protocol_inst._doc_to_object(None, cls, d) @@ -87,14 +101,19 @@ def get_doc_as_object(d, cls, ignore_wrappers=True, complex_as=list, """DEPRECATED: Use ``get_doc_as_object`` instead""" -def get_object_as_doc(o, cls=None, ignore_wrappers=True, complex_as=dict, - protocol=_UtilProtocol, protocol_inst=None): +def get_object_as_doc( + o, + cls=None, + ignore_wrappers=True, + complex_as=dict, + protocol=_UtilProtocol, + protocol_inst=None, +): if cls is None: cls = o.__class__ if protocol_inst is None: - protocol_inst = protocol(ignore_wrappers=ignore_wrappers, - complex_as=complex_as) + protocol_inst = protocol(ignore_wrappers=ignore_wrappers, complex_as=complex_as) retval = protocol_inst._object_to_doc(cls, o) @@ -107,78 +126,118 @@ def get_object_as_doc(o, cls=None, ignore_wrappers=True, complex_as=dict, get_object_as_dict = get_object_as_doc """DEPRECATED: Use ``get_object_as_doc`` instead.""" -def get_object_as_simple_dict(o, cls=None, hier_delim='.', prefix=None): + +def get_object_as_simple_dict(o, cls=None, hier_delim=".", prefix=None): if cls is None: cls = o.__class__ - return SimpleDictDocument(hier_delim=hier_delim) \ - .object_to_simple_dict(cls, o, prefix=prefix) - - -def get_object_as_json(o, cls=None, ignore_wrappers=True, complex_as=list, - encoding='utf8', polymorphic=False, indent=None, **kwargs): + return SimpleDictDocument(hier_delim=hier_delim).object_to_simple_dict( + cls, o, prefix=prefix + ) + + +def get_object_as_json( + o, + cls=None, + ignore_wrappers=True, + complex_as=list, + encoding="utf8", + polymorphic=False, + indent=None, + **kwargs, +): if cls is None: cls = o.__class__ - prot = JsonDocument(ignore_wrappers=ignore_wrappers, complex_as=complex_as, - polymorphic=polymorphic, indent=indent, **kwargs) + prot = JsonDocument( + ignore_wrappers=ignore_wrappers, + complex_as=complex_as, + polymorphic=polymorphic, + indent=indent, + **kwargs, + ) ctx = FakeContext(out_document=[prot._object_to_doc(cls, o)]) prot.create_out_string(ctx, encoding) - return b''.join(ctx.out_string) - - -def get_object_as_json_doc(o, cls=None, ignore_wrappers=True, complex_as=list, - polymorphic=False, indent=None, **kwargs): + return b"".join(ctx.out_string) + + +def get_object_as_json_doc( + o, + cls=None, + ignore_wrappers=True, + complex_as=list, + polymorphic=False, + indent=None, + **kwargs, +): if cls is None: cls = o.__class__ - prot = JsonDocument(ignore_wrappers=ignore_wrappers, complex_as=complex_as, - polymorphic=polymorphic, indent=indent, **kwargs) + prot = JsonDocument( + ignore_wrappers=ignore_wrappers, + complex_as=complex_as, + polymorphic=polymorphic, + indent=indent, + **kwargs, + ) return prot._object_to_doc(cls, o) -def get_object_as_yaml(o, cls=None, ignore_wrappers=False, complex_as=dict, - encoding='utf8', polymorphic=False): +def get_object_as_yaml( + o, + cls=None, + ignore_wrappers=False, + complex_as=dict, + encoding="utf8", + polymorphic=False, +): if cls is None: cls = o.__class__ - prot = YamlDocument(ignore_wrappers=ignore_wrappers, complex_as=complex_as, - polymorphic=polymorphic) - ctx = FakeContext(out_document=[prot._object_to_doc(cls,o)]) + prot = YamlDocument( + ignore_wrappers=ignore_wrappers, complex_as=complex_as, polymorphic=polymorphic + ) + ctx = FakeContext(out_document=[prot._object_to_doc(cls, o)]) prot.create_out_string(ctx, encoding) - return b''.join(ctx.out_string) + return b"".join(ctx.out_string) -def get_object_as_yaml_doc(o, cls=None, ignore_wrappers=False, complex_as=dict, - polymorphic=False): +def get_object_as_yaml_doc( + o, cls=None, ignore_wrappers=False, complex_as=dict, polymorphic=False +): if cls is None: cls = o.__class__ - prot = YamlDocument(ignore_wrappers=ignore_wrappers, complex_as=complex_as, - polymorphic=polymorphic) + prot = YamlDocument( + ignore_wrappers=ignore_wrappers, complex_as=complex_as, polymorphic=polymorphic + ) return prot._object_to_doc(cls, o) -def get_object_as_msgpack(o, cls=None, ignore_wrappers=False, complex_as=dict, - polymorphic=False): +def get_object_as_msgpack( + o, cls=None, ignore_wrappers=False, complex_as=dict, polymorphic=False +): if cls is None: cls = o.__class__ - prot = MessagePackDocument(ignore_wrappers=ignore_wrappers, - complex_as=complex_as, polymorphic=polymorphic) - ctx = FakeContext(out_document=[prot._object_to_doc(cls,o)]) + prot = MessagePackDocument( + ignore_wrappers=ignore_wrappers, complex_as=complex_as, polymorphic=polymorphic + ) + ctx = FakeContext(out_document=[prot._object_to_doc(cls, o)]) prot.create_out_string(ctx) - return b''.join(ctx.out_string) + return b"".join(ctx.out_string) -def get_object_as_msgpack_doc(o, cls=None, ignore_wrappers=False, - complex_as=dict, polymorphic=False): +def get_object_as_msgpack_doc( + o, cls=None, ignore_wrappers=False, complex_as=dict, polymorphic=False +): if cls is None: cls = o.__class__ - prot = MessagePackDocument(ignore_wrappers=ignore_wrappers, - complex_as=complex_as, polymorphic=polymorphic) + prot = MessagePackDocument( + ignore_wrappers=ignore_wrappers, complex_as=complex_as, polymorphic=polymorphic + ) return prot._object_to_doc(cls, o) @@ -186,13 +245,12 @@ def get_object_as_msgpack_doc(o, cls=None, ignore_wrappers=False, def json_loads(s, cls, protocol=JsonDocument, **kwargs): if s is None: return None - if s == '': + if s == "": return None prot = protocol(**kwargs) ctx = FakeContext(in_string=[s]) prot.create_in_document(ctx) - return prot._doc_to_object(None, cls, ctx.in_document, - validator=prot.validator) + return prot._doc_to_object(None, cls, ctx.in_document, validator=prot.validator) get_json_as_object = json_loads @@ -201,13 +259,12 @@ def json_loads(s, cls, protocol=JsonDocument, **kwargs): def yaml_loads(s, cls, protocol=YamlDocument, ignore_wrappers=False, **kwargs): if s is None: return None - if s == '' or s == b'': + if s == "" or s == b"": return None prot = protocol(ignore_wrappers=ignore_wrappers, **kwargs) ctx = FakeContext(in_string=[s]) prot.create_in_document(ctx) - retval = prot._doc_to_object(None, cls, ctx.in_document, - validator=prot.validator) + retval = prot._doc_to_object(None, cls, ctx.in_document, validator=prot.validator) return retval diff --git a/spyne/util/django.py b/spyne/util/django.py index 688c69efd..b45a43cd8 100644 --- a/spyne/util/django.py +++ b/spyne/util/django.py @@ -27,35 +27,32 @@ from __future__ import absolute_import import logging + logger = logging.getLogger(__name__) import re - from itertools import chain -from django.core.exceptions import (ImproperlyConfigured, ObjectDoesNotExist, - ValidationError as DjValidationError) -from django.core.validators import (slug_re, - MinLengthValidator, MaxLengthValidator) +from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist +from django.core.exceptions import ValidationError as DjValidationError +from django.core.validators import MaxLengthValidator, MinLengthValidator, slug_re + try: from django.core.validators import comma_separated_int_list_re except ImportError: - comma_separated_int_list_re = re.compile(r'^[\d,]+$') + comma_separated_int_list_re = re.compile(r"^[\d,]+$") -from spyne.error import (ResourceNotFoundError, ValidationError as - BaseValidationError, Fault) +from spyne.error import Fault, ResourceNotFoundError +from spyne.error import ValidationError as BaseValidationError from spyne.model import primitive -from spyne.model.complex import ComplexModelMeta, ComplexModelBase +from spyne.model.complex import ComplexModelBase, ComplexModelMeta from spyne.service import Service from spyne.util.cdict import cdict from spyne.util.odict import odict -from spyne.util.six import add_metaclass - # regex is based on http://www.w3.org/TR/xforms20/#xforms:email email_re = re.compile( - r"[A-Za-z0-9!#-'\*\+\-/=\?\^_`\{-~]+" - r"(\.[A-Za-z0-9!#-'\*\+\-/=\?\^_`\{-~]+)*@" + r"[A-Za-z0-9!#-'\*\+\-/=\?\^_`\{-~]+" r"(\.[A-Za-z0-9!#-'\*\+\-/=\?\^_`\{-~]+)*@" # domain part is either a single symbol r"(" # or have at least two symbols @@ -63,29 +60,32 @@ # domain should contain at least 2 parts, the last one is TLD r"[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+" # TLD should contain only letters, at least 2 - r"[A-Za-z]{2,}", re.IGNORECASE) + r"[A-Za-z]{2,}", + re.IGNORECASE, +) def _handle_minlength(validator, params): new_min = validator.limit_value - old_min = params.setdefault('min_len', new_min) - params['min_len'] = max(old_min, new_min) + old_min = params.setdefault("min_len", new_min) + params["min_len"] = max(old_min, new_min) def _handle_maxlength(validator, params): new_max = validator.limit_value - old_max = params.setdefault('max_len', new_max) - params['max_len'] = min(old_max, new_max) + old_max = params.setdefault("max_len", new_max) + params["max_len"] = min(old_max, new_max) class BaseDjangoFieldMapper(object): - """Abstrace base class for field mappers.""" - _VALIDATOR_HANDLERS = cdict({ - MinLengthValidator: _handle_minlength, - MaxLengthValidator: _handle_maxlength, - }) + _VALIDATOR_HANDLERS = cdict( + { + MinLengthValidator: _handle_minlength, + MaxLengthValidator: _handle_maxlength, + } + ) @staticmethod def is_field_nullable(field, **kwargs): @@ -114,11 +114,12 @@ def map(self, field, **kwargs): required = not (field.has_default() or blank or field.primary_key) if field.has_default(): - params['default'] = field.get_default() + params["default"] = field.get_default() spyne_model = self.get_spyne_model(field, **kwargs) - customized_model = spyne_model(nullable=nullable, - min_occurs=int(required), **params) + customized_model = spyne_model( + nullable=nullable, min_occurs=int(required), **params + ) return (field.attname, customized_model) @@ -134,7 +135,6 @@ def _process_validators(self, validators, params): class DjangoFieldMapper(BaseDjangoFieldMapper): - """Basic mapper for django fields.""" def __init__(self, spyne_model): @@ -147,7 +147,6 @@ def get_spyne_model(self, field, **kwargs): class DecimalMapper(DjangoFieldMapper): - """Mapper for DecimalField.""" def map(self, field, **kwargs): @@ -157,15 +156,16 @@ def map(self, field, **kwargs): """ params = kwargs.copy() - params.update({ - 'total_digits': field.max_digits, - 'fraction_digits': field.decimal_places, - }) + params.update( + { + "total_digits": field.max_digits, + "fraction_digits": field.decimal_places, + } + ) return super(DecimalMapper, self).map(field, **params) class RelationMapper(BaseDjangoFieldMapper): - """Mapper for relation fields (ForeignKey, OneToOneField).""" def __init__(self, django_model_mapper): @@ -179,13 +179,18 @@ def is_field_blank(field, **kwargs): Otherwise use basic behaviour. """ - optional_relations = kwargs.get('optional_relations', False) - return (optional_relations or - BaseDjangoFieldMapper.is_field_blank(field, **kwargs)) + optional_relations = kwargs.get("optional_relations", False) + return optional_relations or BaseDjangoFieldMapper.is_field_blank( + field, **kwargs + ) def get_spyne_model(self, field, **kwargs): """Return spyne model configured by related field.""" - related_field = field.rel.get_related_field() if hasattr(field, 'rel') else field.remote_field.get_related_field() + related_field = ( + field.rel.get_related_field() + if hasattr(field, "rel") + else field.remote_field.get_related_field() + ) field_type = related_field.__class__.__name__ field_mapper = self.django_model_mapper.get_field_mapper(field_type) @@ -194,7 +199,6 @@ def get_spyne_model(self, field, **kwargs): class DjangoModelMapper(object): - r"""Mapper from django models to spyne complex models. You can extend it registering new field types: :: @@ -218,7 +222,6 @@ def map(self, field, **kwargs): field_mapper_class = DjangoFieldMapper class UnknownFieldMapperException(Exception): - """Raises when there is no field mapper for given django_type.""" def __init__(self, django_spyne_models=()): @@ -240,7 +243,8 @@ def get_field_mapper(self, django_type): return self._registry[django_type] except KeyError: raise self.UnknownFieldMapperException( - 'No mapper for field type {0}'.format(django_type)) + "No mapper for field type {0}".format(django_type) + ) def register(self, django_type, spyne_model): """Register default field mapper for django_type and spyne_model. @@ -263,32 +267,39 @@ def register_field_mapper(self, django_type, field_mapper): @staticmethod def get_all_field_names(meta): - if hasattr(meta, 'get_all_field_names'): + if hasattr(meta, "get_all_field_names"): return meta.get_all_field_names() - return list(set(chain.from_iterable( - (field.name, field.attname) if hasattr(field, 'attname') else ( - field.name,) - for field in meta.get_fields() - # For complete backwards compatibility, you may want to exclude - # GenericForeignKey from the results. - if not (field.many_to_one and field.related_model is None) - ))) + return list( + set( + chain.from_iterable( + ( + (field.name, field.attname) + if hasattr(field, "attname") + else (field.name,) + ) + for field in meta.get_fields() + # For complete backwards compatibility, you may want to exclude + # GenericForeignKey from the results. + if not (field.many_to_one and field.related_model is None) + ) + ) + ) @staticmethod def _get_fields(django_model, exclude=None): field_names = set(exclude) if exclude is not None else set() meta = django_model._meta # pylint: disable=W0212 - unknown_fields_names = \ - field_names.difference(DjangoModelMapper.get_all_field_names(meta)) + unknown_fields_names = field_names.difference( + DjangoModelMapper.get_all_field_names(meta) + ) if unknown_fields_names: raise ImproperlyConfigured( - 'Unknown field names: {0}' - .format(', '.join(unknown_fields_names))) + "Unknown field names: {0}".format(", ".join(unknown_fields_names)) + ) - return [field for field in meta.fields if field.name not in - field_names] + return [field for field in meta.fields if field.name not in field_names] def map(self, django_model, exclude=None, **kwargs): """Prepare dict of model fields mapped to spyne models. @@ -313,10 +324,11 @@ def map(self, django_model, exclude=None, **kwargs): if not (field.has_default() or field.null): # field is required raise self.UnknownFieldMapperException( - 'No mapper for field type {0}'.format(field_type)) + "No mapper for field type {0}".format(field_type) + ) else: # skip this field - logger.info('Field {0} is skipped from mapping.') + logger.info("Field {0} is skipped from mapping.") continue attr_name, spyne_model = field_mapper.map(field, **kwargs) @@ -337,10 +349,10 @@ def strip_regex_metachars(pattern): start = 0 till = len(pattern) - if pattern.startswith('^'): + if pattern.startswith("^"): start = 1 - if pattern.endswith('$'): + if pattern.endswith("$"): till -= 1 return pattern[start:till] @@ -349,39 +361,48 @@ def strip_regex_metachars(pattern): # django's own slug_re.pattern is invalid according to xml schema -- it doesn't # like the location of the dash character. using the equivalent pattern accepted # by xml schema here. -SLUG_RE_PATTERN = '[a-zA-Z0-9_-]+' +SLUG_RE_PATTERN = "[a-zA-Z0-9_-]+" DEFAULT_FIELD_MAP = ( - ('AutoField', primitive.Integer32), - ('CharField', primitive.NormalizedString), - ('SlugField', primitive.Unicode( - type_name='Slug', pattern=strip_regex_metachars(SLUG_RE_PATTERN))), - ('TextField', primitive.Unicode), - ('EmailField', primitive.Unicode( - type_name='Email', pattern=strip_regex_metachars(email_re.pattern))), - ('CommaSeparatedIntegerField', primitive.Unicode( - type_name='CommaSeparatedField', - pattern=strip_regex_metachars(comma_separated_int_list_re.pattern))), - ('URLField', primitive.AnyUri), - ('FilePathField', primitive.Unicode), - - ('BooleanField', primitive.Boolean), - ('NullBooleanField', primitive.Boolean), - ('IntegerField', primitive.Integer), - ('BigIntegerField', primitive.Integer64), - ('PositiveIntegerField', primitive.UnsignedInteger32), - ('SmallIntegerField', primitive.Integer16), - ('PositiveSmallIntegerField', primitive.UnsignedInteger16), - ('FloatField', primitive.Double), - - ('TimeField', primitive.Time), - ('DateField', primitive.Date), - ('DateTimeField', primitive.DateTime), - + ("AutoField", primitive.Integer32), + ("CharField", primitive.NormalizedString), + ( + "SlugField", + primitive.Unicode( + type_name="Slug", pattern=strip_regex_metachars(SLUG_RE_PATTERN) + ), + ), + ("TextField", primitive.Unicode), + ( + "EmailField", + primitive.Unicode( + type_name="Email", pattern=strip_regex_metachars(email_re.pattern) + ), + ), + ( + "CommaSeparatedIntegerField", + primitive.Unicode( + type_name="CommaSeparatedField", + pattern=strip_regex_metachars(comma_separated_int_list_re.pattern), + ), + ), + ("URLField", primitive.AnyUri), + ("FilePathField", primitive.Unicode), + ("BooleanField", primitive.Boolean), + ("NullBooleanField", primitive.Boolean), + ("IntegerField", primitive.Integer), + ("BigIntegerField", primitive.Integer64), + ("PositiveIntegerField", primitive.UnsignedInteger32), + ("SmallIntegerField", primitive.Integer16), + ("PositiveSmallIntegerField", primitive.UnsignedInteger16), + ("FloatField", primitive.Double), + ("TimeField", primitive.Time), + ("DateField", primitive.Date), + ("DateTimeField", primitive.DateTime), # simple fixed defaults for relation fields - ('ForeignKey', primitive.Integer32), - ('OneToOneField', primitive.Integer32), + ("ForeignKey", primitive.Integer32), + ("OneToOneField", primitive.Integer32), ) @@ -394,59 +415,56 @@ def model_mapper_factory(mapper_class, field_map): model_mapper = mapper_class(field_map) # register relation field mappers that are aware of related field type - model_mapper.register_field_mapper( - 'ForeignKey', RelationMapper(model_mapper)) + model_mapper.register_field_mapper("ForeignKey", RelationMapper(model_mapper)) - model_mapper.register_field_mapper( - 'OneToOneField', RelationMapper(model_mapper)) + model_mapper.register_field_mapper("OneToOneField", RelationMapper(model_mapper)) - model_mapper.register_field_mapper('DecimalField', - DecimalMapper(primitive.Decimal)) + model_mapper.register_field_mapper("DecimalField", DecimalMapper(primitive.Decimal)) return model_mapper -default_model_mapper = model_mapper_factory(DjangoModelMapper, - DEFAULT_FIELD_MAP) +default_model_mapper = model_mapper_factory(DjangoModelMapper, DEFAULT_FIELD_MAP) class DjangoComplexModelMeta(ComplexModelMeta): - """Meta class for complex spyne models representing Django models.""" def __new__(mcs, name, bases, attrs): # pylint: disable=C0202 """Populate new complex type from configured Django model.""" super_new = super(DjangoComplexModelMeta, mcs).__new__ - abstract = bool(attrs.get('__abstract__', False)) + abstract = bool(attrs.get("__abstract__", False)) if abstract: # skip processing of abstract models return super_new(mcs, name, bases, attrs) - attributes = attrs.get('Attributes') + attributes = attrs.get("Attributes") if attributes is None: - raise ImproperlyConfigured('You have to define Attributes and ' - 'specify Attributes.django_model') + raise ImproperlyConfigured( + "You have to define Attributes and " "specify Attributes.django_model" + ) - if getattr(attributes, 'django_model', None) is None: - raise ImproperlyConfigured('You have to define django_model ' - 'attribute in Attributes') + if getattr(attributes, "django_model", None) is None: + raise ImproperlyConfigured( + "You have to define django_model " "attribute in Attributes" + ) - mapper = getattr(attributes, 'django_mapper', default_model_mapper) + mapper = getattr(attributes, "django_mapper", default_model_mapper) attributes.django_mapper = mapper - exclude = getattr(attributes, 'django_exclude', None) - optional_relations = getattr(attributes, 'django_optional_relations', - False) - spyne_attrs = mapper.map(attributes.django_model, exclude=exclude, - optional_relations=optional_relations) + exclude = getattr(attributes, "django_exclude", None) + optional_relations = getattr(attributes, "django_optional_relations", False) + spyne_attrs = mapper.map( + attributes.django_model, + exclude=exclude, + optional_relations=optional_relations, + ) spyne_attrs.update(attrs) return super_new(mcs, name, bases, spyne_attrs) -@add_metaclass(DjangoComplexModelMeta) -class DjangoComplexModel(ComplexModelBase): - +class DjangoComplexModel(ComplexModelBase, metaclass=DjangoComplexModelMeta): """Base class with Django model mapping support. Sample usage: :: @@ -492,7 +510,6 @@ class Attributes(DjangoComplexModel.Attributes): class ObjectNotFoundError(ResourceNotFoundError): - """Fault constructed from `model.DoesNotExist` exception.""" def __init__(self, does_not_exist_exc): @@ -501,12 +518,13 @@ def __init__(self, does_not_exist_exc): object_name = message.split()[0] # we do not want to reuse initialization of ResourceNotFoundError Fault.__init__( - self, faultcode='Client.{0}NotFound'.format(object_name), - faultstring=message) + self, + faultcode="Client.{0}NotFound".format(object_name), + faultstring=message, + ) class ValidationError(BaseValidationError): - """Fault constructed from `ValidationError` exception.""" def __init__(self, validation_error_exc): @@ -514,12 +532,13 @@ def __init__(self, validation_error_exc): message = str(validation_error_exc) # we do not want to reuse initialization of BaseValidationError Fault.__init__( - self, faultcode='Client.{0}'.format( - type(validation_error_exc).__name__), faultstring=message) + self, + faultcode="Client.{0}".format(type(validation_error_exc).__name__), + faultstring=message, + ) class DjangoService(Service): - """Service with common Django exception handling.""" @classmethod diff --git a/spyne/util/dyninit.py b/spyne/util/dyninit.py index 21eb775bc..6412c0acb 100644 --- a/spyne/util/dyninit.py +++ b/spyne/util/dyninit.py @@ -19,30 +19,25 @@ from datetime import date, datetime -from spyne import D, Integer, ModelBase, Date, DateTime, IpAddress, Decimal, \ - Boolean +from spyne import Boolean, D, Date, DateTime, Decimal, Integer, IpAddress, ModelBase from spyne.protocol import ProtocolBase -from spyne.util import six from spyne.util.cdict import cdict +BOOL_VALUES_BYTES_TRUE = (b"t", b"1", b"on", b"yes", b"true") +BOOL_VALUES_STR_TRUE = ("t", "1", "on", "yes", "true") -BOOL_VALUES_BYTES_TRUE = (b't', b'1', b'on', b'yes', b'true') -BOOL_VALUES_STR_TRUE = (u't', u'1', u'on', u'yes', u'true') +BOOL_VALUES_BYTES_FALSE = (b"f", b"0", b"off", b"no", b"false") +BOOL_VALUES_STR_FALSE = ("f", "0", "off", "no", "false") -BOOL_VALUES_BYTES_FALSE = (b'f', b'0', b'off', b'no', b'false') -BOOL_VALUES_STR_FALSE = (u'f', u'0', u'off', u'no', u'false') +BOOL_VALUES_NONE = (None, "") -BOOL_VALUES_NONE = (None, '') - -if six.PY2: - bytes = str -else: - unicode = str +unicode = str _prot = ProtocolBase() + def _bool_from_int(i): if i in (0, 1): return i == 1 @@ -78,60 +73,82 @@ def _bool_from_str(s): raise ValueError(s) -MAP = cdict({ - ModelBase: cdict({ - object: lambda _: _, - bytes: lambda _: _.strip(), - unicode: lambda _: _.strip(), - }), - - Decimal: cdict({ - D: lambda d: d, - int: lambda i: D(i), - bytes: lambda s: None if s.strip() == '' else D(s.strip()), - unicode: lambda s: None if s.strip() == u'' else D(s.strip()), - }), - - Boolean: cdict({ - D: lambda d: _bool_from_int(int(d)), - int: _bool_from_int, - bytes: _bool_from_bytes, - unicode: _bool_from_str, - }), - - Integer: cdict({ - D: lambda _: _, - int: lambda _: _, - bytes: lambda s: None if s.strip() == '' else int(s.strip()), - unicode: lambda s: None if s.strip() == u'' else int(s.strip()), - }), - - Date: cdict({ - date: lambda _: _, - datetime: lambda _: _.date(), - object: lambda _:_, - bytes: lambda s: None if s.strip() in ('', '0000-00-00') - else _prot.date_from_unicode(Date, s.strip()), - unicode: lambda s: None if s.strip() in (u'', u'0000-00-00') - else _prot.date_from_unicode(Date, s.strip()), - }), - - DateTime: cdict({ - date: lambda _: datetime(date.year, date.month, date.day), - datetime: lambda _: _, - object: lambda _:_, - bytes: lambda s: None if s.strip() in ('', '0000-00-00 00:00:00') - else _prot.datetime_from_unicode(DateTime, s.strip()), - unicode: lambda s: None if s.strip() in (u'', u'0000-00-00 00:00:00') - else _prot.datetime_from_unicode(DateTime, s.strip()), - }), - - IpAddress: cdict({ - object: lambda _: _, - bytes: lambda s: None if s.strip() == '' else s.strip(), - unicode: lambda s: None if s.strip() == u'' else s.strip(), - }) -}) +MAP = cdict( + { + ModelBase: cdict( + { + object: lambda _: _, + bytes: lambda _: _.strip(), + unicode: lambda _: _.strip(), + } + ), + Decimal: cdict( + { + D: lambda d: d, + int: lambda i: D(i), + bytes: lambda s: None if s.strip() == "" else D(s.strip()), + unicode: lambda s: None if s.strip() == "" else D(s.strip()), + } + ), + Boolean: cdict( + { + D: lambda d: _bool_from_int(int(d)), + int: _bool_from_int, + bytes: _bool_from_bytes, + unicode: _bool_from_str, + } + ), + Integer: cdict( + { + D: lambda _: _, + int: lambda _: _, + bytes: lambda s: None if s.strip() == "" else int(s.strip()), + unicode: lambda s: None if s.strip() == "" else int(s.strip()), + } + ), + Date: cdict( + { + date: lambda _: _, + datetime: lambda _: _.date(), + object: lambda _: _, + bytes: lambda s: ( + None + if s.strip() in ("", "0000-00-00") + else _prot.date_from_unicode(Date, s.strip()) + ), + unicode: lambda s: ( + None + if s.strip() in ("", "0000-00-00") + else _prot.date_from_unicode(Date, s.strip()) + ), + } + ), + DateTime: cdict( + { + date: lambda _: datetime(date.year, date.month, date.day), + datetime: lambda _: _, + object: lambda _: _, + bytes: lambda s: ( + None + if s.strip() in ("", "0000-00-00 00:00:00") + else _prot.datetime_from_unicode(DateTime, s.strip()) + ), + unicode: lambda s: ( + None + if s.strip() in ("", "0000-00-00 00:00:00") + else _prot.datetime_from_unicode(DateTime, s.strip()) + ), + } + ), + IpAddress: cdict( + { + object: lambda _: _, + bytes: lambda s: None if s.strip() == "" else s.strip(), + unicode: lambda s: None if s.strip() == "" else s.strip(), + } + ), + } +) def dynamic_init(cls, **kwargs): diff --git a/spyne/util/email.py b/spyne/util/email.py index 0da579ceb..224ea8ba7 100644 --- a/spyne/util/email.py +++ b/spyne/util/email.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -20,28 +19,25 @@ from __future__ import absolute_import import logging + logger = logging.getLogger(__name__) import getpass import inspect -import traceback -import smtplib import mimetypes - -from socket import gethostname -from subprocess import Popen, PIPE - -from email.utils import COMMASPACE, formatdate +import smtplib +import traceback from email import message_from_string -from email.mime.text import MIMEText +from email.encoders import encode_base64 +from email.mime.application import MIMEApplication from email.mime.image import MIMEImage from email.mime.message import MIMEMessage from email.mime.multipart import MIMEMultipart -from email.mime.application import MIMEApplication from email.mime.nonmultipart import MIMENonMultipart -from email.encoders import encode_base64 - -from spyne.util import six +from email.mime.text import MIMEText +from email.utils import COMMASPACE, formatdate +from socket import gethostname +from subprocess import PIPE, Popen def email_exception(exception_address, message="", bcc=None): @@ -50,20 +46,20 @@ def email_exception(exception_address, message="", bcc=None): mod = inspect.getmodule(frm[0]) module_name = mod.__name__ if mod else frm[1] - sender = 'robot@spyne.io' + sender = "robot@spyne.io" recipients = [exception_address] if bcc is not None: recipients.extend(bcc) - error_str = ("%s\n\n%s" % (message, traceback.format_exc())) - msg = MIMEText(error_str.encode('utf8'), 'plain', 'utf8') - msg['To'] = exception_address - msg['From'] = 'Spyne ' - msg['Date'] = formatdate() - msg['Subject'] = "(%s@%s) %s" % (getpass.getuser(), gethostname(), module_name) + error_str = "%s\n\n%s" % (message, traceback.format_exc()) + msg = MIMEText(error_str.encode("utf8"), "plain", "utf8") + msg["To"] = exception_address + msg["From"] = "Spyne " + msg["Date"] = formatdate() + msg["Subject"] = "(%s@%s) %s" % (getpass.getuser(), gethostname(), module_name) try: - smtp_object = smtplib.SMTP('localhost') + smtp_object = smtplib.SMTP("localhost") smtp_object.sendmail(sender, recipients, msg.as_string()) logger.error("Error email sent") @@ -72,40 +68,37 @@ def email_exception(exception_address, message="", bcc=None): logger.exception(e) -def email_text_smtp(addresses, sender=None, subject='', message="", - host='localhost', port=25): +def email_text_smtp( + addresses, sender=None, subject="", message="", host="localhost", port=25 +): if sender is None: - sender = 'Spyne ' + sender = "Spyne " exc = traceback.format_exc() if exc is not None: - message = (u"%s\n\n%s" % (message, exc)) - msg = MIMEText(message.encode('utf8'), 'plain', 'utf8') - msg['To'] = COMMASPACE.join(addresses) - msg['From'] = sender - msg['Date'] = formatdate() - msg['Subject'] = subject + message = "%s\n\n%s" % (message, exc) + msg = MIMEText(message.encode("utf8"), "plain", "utf8") + msg["To"] = COMMASPACE.join(addresses) + msg["From"] = sender + msg["Date"] = formatdate() + msg["Subject"] = subject smtp_object = smtplib.SMTP(host, port) - if six.PY2: - smtp_object.sendmail(sender, addresses, msg.as_string()) - else: - smtp_object.sendmail(sender, addresses, msg.as_bytes()) + smtp_object.sendmail(sender, addresses, msg.as_bytes()) logger.info("Text email sent to: %r.", addresses) -def email_text(addresses, sender=None, subject="", message="", bcc=None, - att=None): +def email_text(addresses, sender=None, subject="", message="", bcc=None, att=None): if att is None: att = {} if sender is None: - sender = 'Spyne ' + sender = "Spyne " exc = traceback.format_exc() - if exc is not None and exc != 'None\n' and exc != 'NoneType: None\n': - message = (u"%s\n\n%s" % (message, exc)) - msg = MIMEText(message.encode('utf8'), 'plain', 'utf8') + if exc is not None and exc != "None\n" and exc != "NoneType: None\n": + message = "%s\n\n%s" % (message, exc) + msg = MIMEText(message.encode("utf8"), "plain", "utf8") if len(att) > 0: newmsg = MIMEMultipart() newmsg.attach(msg) @@ -114,9 +107,9 @@ def email_text(addresses, sender=None, subject="", message="", bcc=None, if mime_type == "message/rfc822": part = MIMEMessage(message_from_string(v)) elif mime_type.startswith("image/"): - part = MIMEImage(v, mime_type.rsplit('/', 1)[-1]) + part = MIMEImage(v, mime_type.rsplit("/", 1)[-1]) elif mime_type is not None: - mime_type_main, mime_type_sub = mime_type.split('/', 1) + mime_type_main, mime_type_sub = mime_type.split("/", 1) part = MIMENonMultipart(mime_type_main, mime_type_sub) part.set_payload(v) encode_base64(part) @@ -124,24 +117,21 @@ def email_text(addresses, sender=None, subject="", message="", bcc=None, part = MIMEApplication(v) newmsg.attach(part) - part.add_header('Content-Disposition', 'attachment', filename=k) + part.add_header("Content-Disposition", "attachment", filename=k) msg = newmsg - msg['To'] = COMMASPACE.join(addresses) - msg['From'] = sender - msg['Date'] = formatdate() - msg['Subject'] = subject + msg["To"] = COMMASPACE.join(addresses) + msg["From"] = sender + msg["Date"] = formatdate() + msg["Subject"] = subject - cmd = ["/usr/sbin/sendmail", "-oi", '--'] + cmd = ["/usr/sbin/sendmail", "-oi", "--"] cmd.extend(addresses) if bcc is not None: cmd.extend(bcc) p = Popen(cmd, stdin=PIPE) - if six.PY2: - p.communicate(msg.as_string()) - else: - p.communicate(msg.as_bytes()) + p.communicate(msg.as_bytes()) logger.info("Text email sent to: %r.", addresses) diff --git a/spyne/util/etreeconv.py b/spyne/util/etreeconv.py index ea5a0067e..842818348 100644 --- a/spyne/util/etreeconv.py +++ b/spyne/util/etreeconv.py @@ -27,7 +27,6 @@ from lxml import etree -from spyne.util import six from spyne.util.odict import odict @@ -39,7 +38,7 @@ def root_dict_to_etree(d): assert len(d) == 1, "Incoming dict len must be exactly 1. Data: %r" % d - key, = d.keys() + (key,) = d.keys() retval = etree.Element(key) for val in d.values(): break @@ -49,7 +48,7 @@ def root_dict_to_etree(d): if isinstance(val, dict) or isinstance(val, odict): dict_to_etree(val, retval) - elif not isinstance(val, Sized) or isinstance(val, six.string_types): + elif not isinstance(val, Sized) or isinstance(val, str): retval.text = str(val) else: for a in val: @@ -68,7 +67,7 @@ def dict_to_etree(d, parent): if v is None: etree.SubElement(parent, k) - elif isinstance(v, six.string_types): + elif isinstance(v, str): etree.SubElement(parent, k).text = v elif isinstance(v, dict) or isinstance(v, odict): @@ -121,10 +120,10 @@ def etree_to_dict(element, iterable=(list, list.append)): def etree_strip_namespaces(element): """Removes any namespace information form the given element recursively.""" - retval = etree.Element(element.tag.rpartition('}')[-1]) + retval = etree.Element(element.tag.rpartition("}")[-1]) retval.text = element.text for a in element.attrib: - retval.attrib[a.rpartition('}')[-1]] = element.attrib[a] + retval.attrib[a.rpartition("}")[-1]] = element.attrib[a] for e in element: retval.append(etree_strip_namespaces(e)) diff --git a/spyne/util/fileproxy.py b/spyne/util/fileproxy.py index 878c3a2aa..3fb4360b0 100644 --- a/spyne/util/fileproxy.py +++ b/spyne/util/fileproxy.py @@ -1,4 +1,3 @@ - # # Copyright (C) 2013-2014 by Hong Minhee # @@ -22,10 +21,9 @@ # import os +from collections.abc import Iterator -from spyne.util.six.moves.collections_abc import Iterator - -__all__ = 'FileProxy', 'ReusableFileProxy', 'SeekableFileProxy' +__all__ = "FileProxy", "ReusableFileProxy", "SeekableFileProxy" class FileProxy(Iterator): @@ -41,7 +39,7 @@ def __init__(self, wrapped): def __iter__(self): f = self.wrapped - it = getattr(f, '__iter__', None) + it = getattr(f, "__iter__", None) if callable(it): return it() return self @@ -50,7 +48,7 @@ def __next__(self): """Implementation of :class:`collections.Iterator` protocol.""" line = self.readline() if not line: - raise StopIteration('hit eof') + raise StopIteration("hit eof") return line next = __next__ diff --git a/spyne/util/gencpp.py b/spyne/util/gencpp.py index 01ad20658..2a68cfdb8 100644 --- a/spyne/util/gencpp.py +++ b/spyne/util/gencpp.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -22,7 +21,8 @@ import sys -INDENT = ' ' +INDENT = " " + class Object(object): def __init__(self): @@ -39,10 +39,10 @@ def _comment_before_to_stream(self, ostr, indent): ostr.write("/**\n") ostr.write(INDENT * indent) ostr.write(" *") - for line in self.comment_before.split('\n'): + for line in self.comment_before.split("\n"): ostr.write(" ") ostr.write(line) - ostr.write('\n') + ostr.write("\n") ostr.write(INDENT * indent) ostr.write(" */") ostr.write("\n") @@ -51,7 +51,7 @@ def _comment_after_to_stream(self, ostr, indent): if self.comment_after is None: return - lines = self.comment_after.split('\n') + lines = self.comment_after.split("\n") if len(lines) < 2: ostr.write(" // ") @@ -65,7 +65,7 @@ def _comment_after_to_stream(self, ostr, indent): for line in lines: ostr.write(" ") ostr.write(line) - ostr.write('\n') + ostr.write("\n") ostr.write(INDENT * indent) ostr.write(" */") ostr.write("\n") @@ -116,7 +116,7 @@ def to_decl_stream(self, ostr, indent): ostr.write(" ") ostr.write(self.name) - if self.modifier != 'static' and self.initializer is not None: + if self.modifier != "static" and self.initializer is not None: ostr.write(" = ") self.initializer.to_stream(ostr, indent) @@ -124,7 +124,7 @@ def to_decl_stream(self, ostr, indent): ostr.write("\n") def to_defn_stream(self, ostr, indent): - if self.modifier != 'static': + if self.modifier != "static": return self._comment_before_to_stream(ostr, indent) @@ -162,7 +162,7 @@ def __init__(self): self.name = None self.namespace = None - self.type = 'class' + self.type = "class" self.public_entries = [] self.protected_entries = [] self.private_entries = [] @@ -174,7 +174,13 @@ def to_decl_stream(self, ostr, indent=0): ostr.write(" {\n") ostr.write(INDENT * indent) - ostr.write("%s %s {\n" % (self.type, self.name,)) + ostr.write( + "%s %s {\n" + % ( + self.type, + self.name, + ) + ) if len(self.public_entries) > 0: ostr.write(INDENT * indent) @@ -224,6 +230,7 @@ def to_defn_stream(self, ostr, indent=0): if self.namespace is not None: ostr.write("}\n") + def gen_cpp_class(cls, namespace=None, type_map=None): if type_map is None: type_map = dict() @@ -240,8 +247,7 @@ def gen_cpp_class(cls, namespace=None, type_map=None): for k, v in cls.get_flat_type_info(cls).items(): member = DataMember( - "static", "const std::string", - k, StringLiteral(v.Attributes.sub_name or k) + "static", "const std::string", k, StringLiteral(v.Attributes.sub_name or k) ) member.comment_before = v.Annotations.doc diff --git a/spyne/util/http.py b/spyne/util/http.py index 0330f5fdb..1b93b148d 100644 --- a/spyne/util/http.py +++ b/spyne/util/http.py @@ -22,22 +22,17 @@ import sys import time - -from email.message import EmailMessage -from time import strftime -from time import gmtime from collections import deque +from email.message import EmailMessage +from time import gmtime, strftime -from spyne.util import six +COOKIE_MAX_AGE = sys.maxsize -if six.PY2: - COOKIE_MAX_AGE = sys.maxint -else: - COOKIE_MAX_AGE = sys.maxsize # This is a modified version of twisted's addCookie -def generate_cookie(k, v, max_age=None, domain=None, path=None, - comment=None, secure=False): +def generate_cookie( + k, v, max_age=None, domain=None, path=None, comment=None, secure=False +): """Generate a HTTP response cookie. No sanity check whatsoever is done, don't send anything other than ASCII. @@ -50,19 +45,20 @@ def generate_cookie(k, v, max_age=None, domain=None, path=None, :param secure: If true, appends 'Secure' to the cookie string. """ - if not six.PY2 and isinstance(v, bytes): + if isinstance(v, bytes): v = v.decode("ascii") - retval = deque(['%s=%s' % (k, v)]) + retval = deque(["%s=%s" % (k, v)]) if max_age is not None: retval.append("Max-Age=%d" % max_age) assert time.time() < COOKIE_MAX_AGE expires = time.time() + max_age - expires = min(2<<30, expires) - 1 # FIXME - retval.append("Expires=%s" % strftime("%a, %d %b %Y %H:%M:%S GMT", - gmtime(expires))) + expires = min(2 << 30, expires) - 1 # FIXME + retval.append( + "Expires=%s" % strftime("%a, %d %b %Y %H:%M:%S GMT", gmtime(expires)) + ) if domain is not None: retval.append("Domain=%s" % domain) if path is not None: @@ -72,9 +68,10 @@ def generate_cookie(k, v, max_age=None, domain=None, path=None, if secure: retval.append("Secure") - return '; '.join(retval) + return "; ".join(retval) + def parse_content_type_header(h): msg = EmailMessage() - msg['content-type'] = h - return msg.get_content_type(), msg['content-type'].params + msg["content-type"] = h + return msg.get_content_type(), msg["content-type"].params diff --git a/spyne/util/invregexp.py b/spyne/util/invregexp.py index 1e7f1e52b..769ac8e89 100644 --- a/spyne/util/invregexp.py +++ b/spyne/util/invregexp.py @@ -1,4 +1,3 @@ - # # invRegex.py # @@ -42,20 +41,22 @@ __all__ = ["count", "invregexp"] -from pyparsing import Combine -from pyparsing import Literal -from pyparsing import ParseFatalException -from pyparsing import ParseResults -from pyparsing import ParserElement -from pyparsing import SkipTo -from pyparsing import Suppress -from pyparsing import Word -from pyparsing import nums -from pyparsing import oneOf -from pyparsing import opAssoc -from pyparsing import operatorPrecedence -from pyparsing import printables -from pyparsing import srange +from pyparsing import ( + Combine, + Literal, + ParseFatalException, + ParserElement, + ParseResults, + SkipTo, + Suppress, + Word, + nums, + oneOf, + opAssoc, + operatorPrecedence, + printables, + srange, +) class CharacterRangeEmitter(object): @@ -65,15 +66,16 @@ def __init__(self, chars): self.charset = "".join(seen.add(c) or c for c in chars if c not in seen) def __str__(self): - return '[' + self.charset + ']' + return "[" + self.charset + "]" def __repr__(self): - return '[' + self.charset + ']' + return "[" + self.charset + "]" def make_generator(self): def gen_chars(): for s in self.charset: yield s + return gen_chars @@ -86,6 +88,7 @@ def optional_gen(): yield "" for s in self.expr.make_generator()(): yield s + return optional_gen @@ -94,6 +97,7 @@ def make_generator(self): def dot_gen(): for c in printables: yield c + return dot_gen @@ -111,6 +115,7 @@ def recurse_list(elist): for s in elist[0].make_generator()(): for s2 in recurse_list(elist[1:]): yield s + s2 + if self.exprs: for s in recurse_list(self.exprs): yield s @@ -178,7 +183,7 @@ def handle_literal(toks): for t in toks: if t[0] == "\\": if t[1] == "t": - lit += '\t' + lit += "\t" else: lit += t[1] else: @@ -195,7 +200,9 @@ def handle_macro(toks): elif macroChar == "s": return LiteralEmitter(" ") else: - raise ParseFatalException("", 0, "unsupported macro character (" + macroChar + ")") + raise ParseFatalException( + "", 0, "unsupported macro character (" + macroChar + ")" + ) def handle_sequence(toks): @@ -211,6 +218,8 @@ def handle_alternative(toks): _parser = None + + def parser(): global _parser if _parser is None: @@ -218,29 +227,40 @@ def parser(): lbrack, rbrack, lbrace, rbrace, lparen, rparen = map(Literal, "[]{}()") reMacro = Combine("\\" + oneOf(list("dws"))) - escapedChar = ~ reMacro + Combine("\\" + oneOf(list(printables))) - reLiteralChar = "".join(c for c in printables if c not in r"\[]{}().*?+|") + " \t" + escapedChar = ~reMacro + Combine("\\" + oneOf(list(printables))) + reLiteralChar = ( + "".join(c for c in printables if c not in r"\[]{}().*?+|") + " \t" + ) reRange = Combine(lbrack + SkipTo(rbrack, ignore=escapedChar) + rbrack) - reLiteral = (escapedChar | oneOf(list(reLiteralChar))) + reLiteral = escapedChar | oneOf(list(reLiteralChar)) reDot = Literal(".") repetition = ( - (lbrace + Word(nums).setResultsName("count") + rbrace) | - (lbrace + Word(nums).setResultsName("minCount") + "," + Word(nums).setResultsName("maxCount") + rbrace) | - oneOf(list("*+?")) - ) + (lbrace + Word(nums).setResultsName("count") + rbrace) + | ( + lbrace + + Word(nums).setResultsName("minCount") + + "," + + Word(nums).setResultsName("maxCount") + + rbrace + ) + | oneOf(list("*+?")) + ) reRange.setParseAction(handle_range) reLiteral.setParseAction(handle_literal) reMacro.setParseAction(handle_macro) reDot.setParseAction(handle_dot) - reTerm = (reLiteral | reRange | reMacro | reDot) - reExpr = operatorPrecedence(reTerm, [ + reTerm = reLiteral | reRange | reMacro | reDot + reExpr = operatorPrecedence( + reTerm, + [ (repetition, 1, opAssoc.LEFT, handle_repetition), (None, 2, opAssoc.LEFT, handle_sequence), - (Suppress('|'), 2, opAssoc.LEFT, handle_alternative), - ]) + (Suppress("|"), 2, opAssoc.LEFT, handle_alternative), + ], + ) _parser = reExpr @@ -257,9 +277,9 @@ def count(gen): def invregexp(regex): """Call this routine as a generator to return all the strings that - match the input regular expression. - for s in invregexp("[A-Z]{3}\d{3}"): - print s + match the input regular expression. + for s in invregexp("[A-Z]{3}\d{3}"): + print s """ invReGenerator = GroupEmitter(parser().parseString(regex)).make_generator() return invReGenerator() @@ -296,14 +316,14 @@ def main(): A[cglmrstu]|B[aehikr]?|C[adeflmorsu]?|D[bsy]|E[rsu]|F[emr]?|G[ade]|H[efgos]?|I[nr]?|Kr?|L[airu]|M[dgnot]|N[abdeiop]?|Os?|P[abdmortu]?|R[abefghnu]|S[bcegimnr]?|T[abcehilm]|Uu[bhopqst]|U|V|W|Xe|Yb?|Z[nr] (a|b)|(x|y) (a|b) (x|y) - """.split('\n') + """.split("\n") for t in tests: t = t.strip() if not t: continue - print('-' * 50) + print("-" * 50) print(t) try: print(count(invregexp(t))) diff --git a/spyne/util/memo.py b/spyne/util/memo.py index d64efb5e5..c53384946 100644 --- a/spyne/util/memo.py +++ b/spyne/util/memo.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -26,13 +25,12 @@ behavior in a multithreaded environment, roll your own stuff. """ - import logging + logger = logging.getLogger(__name__) import threading - MEMOIZATION_STATS_LOG_INTERVAL = 60.0 @@ -56,16 +54,19 @@ def _log_func(func): def start_memoization_stats_logger(func=None): - logger.info("Enabling @memoize statistics every %d second(s).", - MEMOIZATION_STATS_LOG_INTERVAL) + logger.info( + "Enabling @memoize statistics every %d second(s).", + MEMOIZATION_STATS_LOG_INTERVAL, + ) if func is None: _log_all() else: _log_func(func) - t = threading.Timer(MEMOIZATION_STATS_LOG_INTERVAL, - start_memoization_stats_logger, (func,)) + t = threading.Timer( + MEMOIZATION_STATS_LOG_INTERVAL, start_memoization_stats_logger, (func,) + ) t.daemon = True t.start() @@ -113,7 +114,7 @@ def __init__(self, func): memoize.registry.append(self) def __call__(self, *args, **kwargs): - if not hasattr(self, 'memo'): + if not hasattr(self, "memo"): value = self.func(*args, **kwargs) self.memo = value return value @@ -130,8 +131,7 @@ def memoize_ignore(values): but the result of `add(5, 5)` (=10) is. """ - assert iter(values), \ - "memoize_ignore requires an iterable of values to ignore" + assert iter(values), "memoize_ignore requires an iterable of values to ignore" class _memoize_ignored(memoize): def __call__(self, *args, **kwargs): @@ -176,5 +176,6 @@ class memoize_id(memoize): types. It works on id()'s of objects instead.""" def get_key(self, args, kwargs): - return tuple([id(a) for a in args]), \ - tuple([(k, id(v)) for k, v in kwargs.items()]) + return tuple([id(a) for a in args]), tuple( + [(k, id(v)) for k, v in kwargs.items()] + ) diff --git a/spyne/util/meta.py b/spyne/util/meta.py index 81f8da025..21d8e1b00 100644 --- a/spyne/util/meta.py +++ b/spyne/util/meta.py @@ -21,9 +21,8 @@ :attr:`spyne.model.complex.ComplexModelBase.Attributes.declare_order` """ -import sys import inspect - +import sys from functools import wraps from itertools import chain from warnings import warn @@ -40,11 +39,7 @@ class AttributeNotFoundException(Exception): class Prepareable(type): - """Implement __prepare__ for Python 2. - - This class is used in Python 2 and Python 3 to support `six.add_metaclass` - decorator that populates attributes of resulting class from plain unordered - attributes dict of decorated class. + """Implement __prepare__ to support ordered class attributes. Based on https://gist.github.com/DasIch/5562625 """ @@ -59,8 +54,9 @@ def preparing_constructor(cls, name, bases, attributes): # Don't bother with this shit unless the user *explicitly* asked for # it for c in chain(bases, [cls]): - if hasattr(c,'Attributes') and not \ - (c.Attributes.declare_order in (None, 'random')): + if hasattr(c, "Attributes") and not ( + c.Attributes.declare_order in (None, "random") + ): break else: return constructor(cls, name, bases, attributes) @@ -90,24 +86,26 @@ def preparing_constructor(cls, name, bases, attributes): current_frame = current_frame.f_back else: raise ClassNotFoundException( - "Can't find class declaration in any frame") + "Can't find class declaration in any frame" + ) - def get_index(attribute_name, - _names=class_declaration.co_names): + def get_index(attribute_name, _names=class_declaration.co_names): try: return _names.index(attribute_name) except ValueError: - if attribute_name.startswith('_'): + if attribute_name.startswith("_"): # we don't care about the order of magic and non # public attributes return 0 else: - msg = ("Can't find {0} in {1} class declaration. " - .format(attribute_name, - class_declaration.co_name)) - msg += ("HINT: use spyne.util.odict.odict for " - "class attributes if you populate them" - " dynamically.") + msg = "Can't find {0} in {1} class declaration. ".format( + attribute_name, class_declaration.co_name + ) + msg += ( + "HINT: use spyne.util.odict.odict for " + "class attributes if you populate them" + " dynamically." + ) raise AttributeNotFoundException(msg) by_appearance = sorted( @@ -121,19 +119,25 @@ def get_index(attribute_name, new_cls = constructor(cls, name, bases, namespace) found_module = inspect.getmodule(class_declaration) - assert found_module is not None, ( - 'Module is not found for class_declaration {0}, name {1}' - .format(class_declaration, name)) - assert found_module.__name__ == new_cls.__module__, ( - 'Found wrong class declaration of {0}: {1} != {2}.' - .format(name, found_module.__name__, new_cls.__module__)) + assert ( + found_module is not None + ), "Module is not found for class_declaration {0}, name {1}".format( + class_declaration, name + ) + assert ( + found_module.__name__ == new_cls.__module__ + ), "Found wrong class declaration of {0}: {1} != {2}.".format( + name, found_module.__name__, new_cls.__module__ + ) return new_cls try: attributes["__new__"] = wraps(constructor)(preparing_constructor) except: - warn("Wrapping class initializer failed. This is normal " - "when running under Nuitka") + warn( + "Wrapping class initializer failed. This is normal " + "when running under Nuitka" + ) return type.__new__(cls, name, bases, attributes) diff --git a/spyne/util/odict.py b/spyne/util/odict.py index d8b996ded..1b99f3bce 100644 --- a/spyne/util/odict.py +++ b/spyne/util/odict.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -57,10 +56,12 @@ def __setitem__(self, key, val): super(odict, self).__setitem__(key, val) assert len(self.__list) == super(odict, self).__len__(), ( - repr(self.__list), super(odict, self).__repr__()) + repr(self.__list), + super(odict, self).__repr__(), + ) def __repr__(self): - return "{%s}" % ','.join(["%r: %r" % (k, v) for k, v in self.items()]) + return "{%s}" % ",".join(["%r: %r" % (k, v) for k, v in self.items()]) def __str__(self): return repr(self) @@ -75,7 +76,7 @@ def __iter__(self): def __delitem__(self, key): if not isinstance(key, int): super(odict, self).__delitem__(key) - key = self.__list.index(key) # ouch. + key = self.__list.index(key) # ouch. else: super(odict, self).__delitem__(self.__list[key]) del self.__list[key] @@ -87,7 +88,7 @@ def __add__(self, other): def items(self): retval = [] for k in self.__list: - retval.append( (k, super(odict, self).__getitem__(k)) ) + retval.append((k, super(odict, self).__getitem__(k))) return retval def iteritems(self): diff --git a/spyne/util/oset.py b/spyne/util/oset.py index 03e7c591e..0028ab1a3 100644 --- a/spyne/util/oset.py +++ b/spyne/util/oset.py @@ -1,19 +1,20 @@ # http://code.activestate.com/recipes/576694/ -from spyne.util.six.moves.collections_abc import MutableSet +from collections.abc import MutableSet KEY, PREV, NEXT = list(range(3)) """This module contains an ordered set implementation from http://code.activestate.com/recipes/576694/ """ + class oset(MutableSet): """An ordered set implementation.""" def __init__(self, iterable=None): self.end = end = [] - end += [None, end, end] # sentinel node for doubly linked list - self.map = {} # key --> [key, prev, next] + end += [None, end, end] # sentinel node for doubly linked list + self.map = {} # key --> [key, prev, next] if iterable is not None: self |= iterable @@ -58,15 +59,15 @@ def __reversed__(self): def pop(self, last=True): if not self: - raise KeyError('set is empty') + raise KeyError("set is empty") key = next(reversed(self)) if last else next(iter(self)) self.discard(key) return key def __repr__(self): if not self: - return '%s()' % (self.__class__.__name__,) - return '%s(%r)' % (self.__class__.__name__, list(self)) + return "%s()" % (self.__class__.__name__,) + return "%s(%r)" % (self.__class__.__name__, list(self)) def __eq__(self, other): if isinstance(other, oset): @@ -77,15 +78,16 @@ def __eq__(self, other): def back(self): return self.end[1][0] -if __name__ == '__main__': - print((oset('abracadabra'))) + +if __name__ == "__main__": + print((oset("abracadabra"))) stuff = oset() stuff.add(1) print(stuff) stuff.add(1) print(stuff) - print((oset('simsalabim'))) - o = oset('abcde') + print((oset("simsalabim"))) + o = oset("abcde") print(o) print(o.end) diff --git a/spyne/util/protocol.py b/spyne/util/protocol.py index 4ae305c85..3f702afc9 100644 --- a/spyne/util/protocol.py +++ b/spyne/util/protocol.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # diff --git a/spyne/util/resource.py b/spyne/util/resource.py index bde03e8a6..10152b523 100644 --- a/spyne/util/resource.py +++ b/spyne/util/resource.py @@ -35,16 +35,16 @@ def get_resource_path(ns, fn): def get_resource_file(ns, fn): - return open(get_resource_path(ns, fn), 'rb') + return open(get_resource_path(ns, fn), "rb") def get_resource_file_contents(ns, fn, enc=None): resfn = get_resource_path(ns, fn) if enc is None: - return open(resfn, 'rb').read() + return open(resfn, "rb").read() else: - return open(resfn, 'rb').read().decode(enc) + return open(resfn, "rb").read().decode(enc) def parse_xml_resource(ns, fn): @@ -66,7 +66,8 @@ def parse_html_resource(ns, fn): def parse_cloth_resource(ns, fn): from lxml import html - retval = html.fragment_fromstring(get_resource_file_contents(ns, fn), - create_parent='spyne-root') - retval.attrib['spyne-tagbag'] = '' + retval = html.fragment_fromstring( + get_resource_file_contents(ns, fn), create_parent="spyne-root" + ) + retval.attrib["spyne-tagbag"] = "" return retval diff --git a/spyne/util/simple.py b/spyne/util/simple.py index 164be684d..0bc05de29 100644 --- a/spyne/util/simple.py +++ b/spyne/util/simple.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -20,12 +19,12 @@ """Contains functions that implement the most common protocol and transport combinations""" - from spyne.application import Application -def wsgi_soap11_application(services, tns='spyne.simple.soap', validator=None, - name=None): +def wsgi_soap11_application( + services, tns="spyne.simple.soap", validator=None, name=None +): """Wraps `services` argument inside a WsgiApplication that uses Soap 1.1 for both input and output protocols. """ @@ -33,17 +32,24 @@ def wsgi_soap11_application(services, tns='spyne.simple.soap', validator=None, from spyne.protocol.soap import Soap11 from spyne.server.wsgi import WsgiApplication - application = Application(services, tns, name=name, - in_protocol=Soap11(validator=validator), out_protocol=Soap11()) + application = Application( + services, + tns, + name=name, + in_protocol=Soap11(validator=validator), + out_protocol=Soap11(), + ) return WsgiApplication(application) + wsgi_soap_application = wsgi_soap11_application """DEPRECATED! Use :func:`wsgi_soap11_application` instead.""" -def pyramid_soap11_application(services, tns='spyne.simple.soap', - validator=None, name=None): +def pyramid_soap11_application( + services, tns="spyne.simple.soap", validator=None, name=None +): """Wraps `services` argument inside a PyramidApplication that uses Soap 1.1 for both input and output protocols. """ @@ -51,7 +57,12 @@ def pyramid_soap11_application(services, tns='spyne.simple.soap', from spyne.protocol.soap import Soap11 from spyne.server.pyramid import PyramidApplication - application = Application(services, tns, name=name, - in_protocol=Soap11(validator=validator), out_protocol=Soap11()) + application = Application( + services, + tns, + name=name, + in_protocol=Soap11(validator=validator), + out_protocol=Soap11(), + ) return PyramidApplication(application) diff --git a/spyne/util/six.py b/spyne/util/six.py deleted file mode 100644 index 84871a9c7..000000000 --- a/spyne/util/six.py +++ /dev/null @@ -1,1003 +0,0 @@ -# Copyright (c) 2010-2020 Benjamin Peterson -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. - -"""Utilities for writing code that runs on Python 2 and 3""" - -from __future__ import absolute_import - -import functools -import itertools -import operator -import sys -import types - -__author__ = "Benjamin Peterson " -__version__ = "1.16.0" - - -# Useful for very coarse version differentiation. -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 -PY34 = sys.version_info[0:2] >= (3, 4) - -if PY3: - string_types = str, - integer_types = int, - class_types = type, - text_type = str - binary_type = bytes - - MAXSIZE = sys.maxsize -else: - string_types = basestring, - integer_types = (int, long) - class_types = (type, types.ClassType) - text_type = unicode - binary_type = str - - if sys.platform.startswith("java"): - # Jython always uses 32 bits. - MAXSIZE = int((1 << 31) - 1) - else: - # It's possible to have sizeof(long) != sizeof(Py_ssize_t). - class X(object): - - def __len__(self): - return 1 << 31 - try: - len(X()) - except OverflowError: - # 32-bit - MAXSIZE = int((1 << 31) - 1) - else: - # 64-bit - MAXSIZE = int((1 << 63) - 1) - del X - -if PY34: - from importlib.util import spec_from_loader -else: - spec_from_loader = None - - -def _add_doc(func, doc): - """Add documentation to a function.""" - func.__doc__ = doc - - -def _import_module(name): - """Import module, returning the module after the last dot.""" - __import__(name) - return sys.modules[name] - - -class _LazyDescr(object): - - def __init__(self, name): - self.name = name - - def __get__(self, obj, tp): - result = self._resolve() - setattr(obj, self.name, result) # Invokes __set__. - try: - # This is a bit ugly, but it avoids running this again by - # removing this descriptor. - delattr(obj.__class__, self.name) - except AttributeError: - pass - return result - - -class MovedModule(_LazyDescr): - - def __init__(self, name, old, new=None): - super(MovedModule, self).__init__(name) - if PY3: - if new is None: - new = name - self.mod = new - else: - self.mod = old - - def _resolve(self): - return _import_module(self.mod) - - def __getattr__(self, attr): - _module = self._resolve() - value = getattr(_module, attr) - setattr(self, attr, value) - return value - - -class _LazyModule(types.ModuleType): - - def __init__(self, name): - super(_LazyModule, self).__init__(name) - self.__doc__ = self.__class__.__doc__ - - def __dir__(self): - attrs = ["__doc__", "__name__"] - attrs += [attr.name for attr in self._moved_attributes] - return attrs - - # Subclasses should override this - _moved_attributes = [] - - -class MovedAttribute(_LazyDescr): - - def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): - super(MovedAttribute, self).__init__(name) - if PY3: - if new_mod is None: - new_mod = name - self.mod = new_mod - if new_attr is None: - if old_attr is None: - new_attr = name - else: - new_attr = old_attr - self.attr = new_attr - else: - self.mod = old_mod - if old_attr is None: - old_attr = name - self.attr = old_attr - - def _resolve(self): - module = _import_module(self.mod) - return getattr(module, self.attr) - - -class _SixMetaPathImporter(object): - - """ - A meta path importer to import six.moves and its submodules. - - This class implements a PEP302 finder and loader. It should be compatible - with Python 2.5 and all existing versions of Python3 - """ - - def __init__(self, six_module_name): - self.name = six_module_name - self.known_modules = {} - - def _add_module(self, mod, *fullnames): - for fullname in fullnames: - self.known_modules[self.name + "." + fullname] = mod - - def _get_module(self, fullname): - return self.known_modules[self.name + "." + fullname] - - def find_module(self, fullname, path=None): - if fullname in self.known_modules: - return self - return None - - def find_spec(self, fullname, path, target=None): - if fullname in self.known_modules: - return spec_from_loader(fullname, self) - return None - - def __get_module(self, fullname): - try: - return self.known_modules[fullname] - except KeyError: - raise ImportError("This loader does not know module " + fullname) - - def load_module(self, fullname): - try: - # in case of a reload - return sys.modules[fullname] - except KeyError: - pass - mod = self.__get_module(fullname) - if isinstance(mod, MovedModule): - mod = mod._resolve() - else: - mod.__loader__ = self - sys.modules[fullname] = mod - return mod - - def is_package(self, fullname): - """ - Return true, if the named module is a package. - - We need this method to get correct spec objects with - Python 3.4 (see PEP451) - """ - return hasattr(self.__get_module(fullname), "__path__") - - def get_code(self, fullname): - """Return None - - Required, if is_package is implemented""" - self.__get_module(fullname) # eventually raises ImportError - return None - get_source = get_code # same as get_code - - def create_module(self, spec): - return self.load_module(spec.name) - - def exec_module(self, module): - pass - -_importer = _SixMetaPathImporter(__name__) - - -class _MovedItems(_LazyModule): - - """Lazy loading of moved objects""" - __path__ = [] # mark as package - - -_moved_attributes = [ - MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), - MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), - MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), - MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), - MovedAttribute("intern", "__builtin__", "sys"), - MovedAttribute("map", "itertools", "builtins", "imap", "map"), - MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), - MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), - MovedAttribute("getoutput", "commands", "subprocess"), - MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), - MovedAttribute("reduce", "__builtin__", "functools"), - MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), - MovedAttribute("StringIO", "StringIO", "io"), - MovedAttribute("UserDict", "UserDict", "collections", "IterableUserDict", "UserDict"), - MovedAttribute("UserList", "UserList", "collections"), - MovedAttribute("UserString", "UserString", "collections"), - MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), - MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), - MovedModule("builtins", "__builtin__"), - MovedModule("configparser", "ConfigParser"), - MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"), - MovedModule("copyreg", "copy_reg"), - MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), - MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"), - MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"), - MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), - MovedModule("http_cookies", "Cookie", "http.cookies"), - MovedModule("html_entities", "htmlentitydefs", "html.entities"), - MovedModule("html_parser", "HTMLParser", "html.parser"), - MovedModule("http_client", "httplib", "http.client"), - MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), - MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), - MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), - MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), - MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), - MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), - MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), - MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), - MovedModule("cPickle", "cPickle", "pickle"), - MovedModule("queue", "Queue"), - MovedModule("reprlib", "repr"), - MovedModule("socketserver", "SocketServer"), - MovedModule("_thread", "thread", "_thread"), - MovedModule("tkinter", "Tkinter"), - MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), - MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), - MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), - MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), - MovedModule("tkinter_tix", "Tix", "tkinter.tix"), - MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), - MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), - MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), - MovedModule("tkinter_colorchooser", "tkColorChooser", - "tkinter.colorchooser"), - MovedModule("tkinter_commondialog", "tkCommonDialog", - "tkinter.commondialog"), - MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), - MovedModule("tkinter_font", "tkFont", "tkinter.font"), - MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), - MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", - "tkinter.simpledialog"), - MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), - MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), - MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), - MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), - MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), - MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), -] -# Add windows specific modules. -if sys.platform == "win32": - _moved_attributes += [ - MovedModule("winreg", "_winreg"), - ] - -for attr in _moved_attributes: - setattr(_MovedItems, attr.name, attr) - if isinstance(attr, MovedModule): - _importer._add_module(attr, "moves." + attr.name) -del attr - -_MovedItems._moved_attributes = _moved_attributes - -moves = _MovedItems(__name__ + ".moves") -_importer._add_module(moves, "moves") - - -class Module_six_moves_urllib_parse(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_parse""" - - -_urllib_parse_moved_attributes = [ - MovedAttribute("ParseResult", "urlparse", "urllib.parse"), - MovedAttribute("SplitResult", "urlparse", "urllib.parse"), - MovedAttribute("parse_qs", "urlparse", "urllib.parse"), - MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), - MovedAttribute("urldefrag", "urlparse", "urllib.parse"), - MovedAttribute("urljoin", "urlparse", "urllib.parse"), - MovedAttribute("urlparse", "urlparse", "urllib.parse"), - MovedAttribute("urlsplit", "urlparse", "urllib.parse"), - MovedAttribute("urlunparse", "urlparse", "urllib.parse"), - MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), - MovedAttribute("quote", "urllib", "urllib.parse"), - MovedAttribute("quote_plus", "urllib", "urllib.parse"), - MovedAttribute("unquote", "urllib", "urllib.parse"), - MovedAttribute("unquote_plus", "urllib", "urllib.parse"), - MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"), - MovedAttribute("urlencode", "urllib", "urllib.parse"), - MovedAttribute("splitquery", "urllib", "urllib.parse"), - MovedAttribute("splittag", "urllib", "urllib.parse"), - MovedAttribute("splituser", "urllib", "urllib.parse"), - MovedAttribute("splitvalue", "urllib", "urllib.parse"), - MovedAttribute("splittype", "urllib", "urllib.parse"), - MovedAttribute("splithost", "urllib", "urllib.parse"), - MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), - MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), - MovedAttribute("uses_params", "urlparse", "urllib.parse"), - MovedAttribute("uses_query", "urlparse", "urllib.parse"), - MovedAttribute("uses_relative", "urlparse", "urllib.parse"), -] -for attr in _urllib_parse_moved_attributes: - setattr(Module_six_moves_urllib_parse, attr.name, attr) -del attr - -Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes - -_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), - "moves.urllib_parse", "moves.urllib.parse") - - -class Module_six_moves_urllib_error(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_error""" - - -_urllib_error_moved_attributes = [ - MovedAttribute("URLError", "urllib2", "urllib.error"), - MovedAttribute("HTTPError", "urllib2", "urllib.error"), - MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), -] -for attr in _urllib_error_moved_attributes: - setattr(Module_six_moves_urllib_error, attr.name, attr) -del attr - -Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes - -_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), - "moves.urllib_error", "moves.urllib.error") - - -class Module_six_moves_urllib_request(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_request""" - - -_urllib_request_moved_attributes = [ - MovedAttribute("urlopen", "urllib2", "urllib.request"), - MovedAttribute("install_opener", "urllib2", "urllib.request"), - MovedAttribute("build_opener", "urllib2", "urllib.request"), - MovedAttribute("pathname2url", "urllib", "urllib.request"), - MovedAttribute("url2pathname", "urllib", "urllib.request"), - MovedAttribute("getproxies", "urllib", "urllib.request"), - MovedAttribute("Request", "urllib2", "urllib.request"), - MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), - MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), - MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), - MovedAttribute("BaseHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), - MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), - MovedAttribute("FileHandler", "urllib2", "urllib.request"), - MovedAttribute("FTPHandler", "urllib2", "urllib.request"), - MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), - MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), - MovedAttribute("urlretrieve", "urllib", "urllib.request"), - MovedAttribute("urlcleanup", "urllib", "urllib.request"), - MovedAttribute("URLopener", "urllib", "urllib.request"), - MovedAttribute("FancyURLopener", "urllib", "urllib.request"), - MovedAttribute("proxy_bypass", "urllib", "urllib.request"), - MovedAttribute("parse_http_list", "urllib2", "urllib.request"), - MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), -] -for attr in _urllib_request_moved_attributes: - setattr(Module_six_moves_urllib_request, attr.name, attr) -del attr - -Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes - -_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), - "moves.urllib_request", "moves.urllib.request") - - -class Module_six_moves_urllib_response(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_response""" - - -_urllib_response_moved_attributes = [ - MovedAttribute("addbase", "urllib", "urllib.response"), - MovedAttribute("addclosehook", "urllib", "urllib.response"), - MovedAttribute("addinfo", "urllib", "urllib.response"), - MovedAttribute("addinfourl", "urllib", "urllib.response"), -] -for attr in _urllib_response_moved_attributes: - setattr(Module_six_moves_urllib_response, attr.name, attr) -del attr - -Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes - -_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), - "moves.urllib_response", "moves.urllib.response") - - -class Module_six_moves_urllib_robotparser(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_robotparser""" - - -_urllib_robotparser_moved_attributes = [ - MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), -] -for attr in _urllib_robotparser_moved_attributes: - setattr(Module_six_moves_urllib_robotparser, attr.name, attr) -del attr - -Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes - -_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), - "moves.urllib_robotparser", "moves.urllib.robotparser") - - -class Module_six_moves_urllib(types.ModuleType): - - """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" - __path__ = [] # mark as package - parse = _importer._get_module("moves.urllib_parse") - error = _importer._get_module("moves.urllib_error") - request = _importer._get_module("moves.urllib_request") - response = _importer._get_module("moves.urllib_response") - robotparser = _importer._get_module("moves.urllib_robotparser") - - def __dir__(self): - return ['parse', 'error', 'request', 'response', 'robotparser'] - -_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), - "moves.urllib") - - -def add_move(move): - """Add an item to six.moves.""" - setattr(_MovedItems, move.name, move) - - -def remove_move(name): - """Remove item from six.moves.""" - try: - delattr(_MovedItems, name) - except AttributeError: - try: - del moves.__dict__[name] - except KeyError: - raise AttributeError("no such move, %r" % (name,)) - - -if PY3: - _meth_func = "__func__" - _meth_self = "__self__" - - _func_closure = "__closure__" - _func_code = "__code__" - _func_defaults = "__defaults__" - _func_globals = "__globals__" - _func_name = "__name__" -else: - _meth_func = "im_func" - _meth_self = "im_self" - - _func_closure = "func_closure" - _func_code = "func_code" - _func_defaults = "func_defaults" - _func_globals = "func_globals" - _func_name = "func_name" - - -try: - advance_iterator = next -except NameError: - def advance_iterator(it): - return it.next() -next = advance_iterator - - -try: - callable = callable -except NameError: - def callable(obj): - return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) - - -if PY3: - def get_unbound_function(unbound): - return unbound - - create_bound_method = types.MethodType - - def create_unbound_method(func, cls): - return func - - Iterator = object -else: - def get_unbound_function(unbound): - return unbound.im_func - - def create_bound_method(func, obj): - return types.MethodType(func, obj, obj.__class__) - - def create_unbound_method(func, cls): - return types.MethodType(func, None, cls) - - class Iterator(object): - - def next(self): - return type(self).__next__(self) - - callable = callable -_add_doc(get_unbound_function, - """Get the function out of a possibly unbound function""") - - -get_method_function = operator.attrgetter(_meth_func) -get_method_self = operator.attrgetter(_meth_self) -get_function_closure = operator.attrgetter(_func_closure) -get_function_code = operator.attrgetter(_func_code) -get_function_defaults = operator.attrgetter(_func_defaults) -get_function_globals = operator.attrgetter(_func_globals) -get_function_name = operator.attrgetter(_func_name) - - -if PY3: - def iterkeys(d, **kw): - return iter(d.keys(**kw)) - - def itervalues(d, **kw): - return iter(d.values(**kw)) - - def iteritems(d, **kw): - return iter(d.items(**kw)) - - def iterlists(d, **kw): - return iter(d.lists(**kw)) - - viewkeys = operator.methodcaller("keys") - - viewvalues = operator.methodcaller("values") - - viewitems = operator.methodcaller("items") -else: - def iterkeys(d, **kw): - return d.iterkeys(**kw) - - def itervalues(d, **kw): - return d.itervalues(**kw) - - def iteritems(d, **kw): - return d.iteritems(**kw) - - def iterlists(d, **kw): - return d.iterlists(**kw) - - viewkeys = operator.methodcaller("viewkeys") - - viewvalues = operator.methodcaller("viewvalues") - - viewitems = operator.methodcaller("viewitems") - -_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") -_add_doc(itervalues, "Return an iterator over the values of a dictionary.") -_add_doc(iteritems, - "Return an iterator over the (key, value) pairs of a dictionary.") -_add_doc(iterlists, - "Return an iterator over the (key, [values]) pairs of a dictionary.") - - -if PY3: - def b(s): - return s.encode("latin-1") - - def u(s): - return s - unichr = chr - import struct - int2byte = struct.Struct(">B").pack - del struct - byte2int = operator.itemgetter(0) - indexbytes = operator.getitem - iterbytes = iter - import io - StringIO = io.StringIO - BytesIO = io.BytesIO - del io - _assertCountEqual = "assertCountEqual" - if sys.version_info[1] <= 1: - _assertRaisesRegex = "assertRaisesRegexp" - _assertRegex = "assertRegexpMatches" - _assertNotRegex = "assertNotRegexpMatches" - else: - _assertRaisesRegex = "assertRaisesRegex" - _assertRegex = "assertRegex" - _assertNotRegex = "assertNotRegex" -else: - def b(s): - return s - # Workaround for standalone backslash - - def u(s): - return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") - unichr = unichr - int2byte = chr - - def byte2int(bs): - return ord(bs[0]) - - def indexbytes(buf, i): - return ord(buf[i]) - iterbytes = functools.partial(itertools.imap, ord) - import StringIO - StringIO = BytesIO = StringIO.StringIO - _assertCountEqual = "assertItemsEqual" - _assertRaisesRegex = "assertRaisesRegexp" - _assertRegex = "assertRegexpMatches" - _assertNotRegex = "assertNotRegexpMatches" -_add_doc(b, """Byte literal""") -_add_doc(u, """Text literal""") - - -def assertCountEqual(self, *args, **kwargs): - return getattr(self, _assertCountEqual)(*args, **kwargs) - - -def assertRaisesRegex(self, *args, **kwargs): - return getattr(self, _assertRaisesRegex)(*args, **kwargs) - - -def assertRegex(self, *args, **kwargs): - return getattr(self, _assertRegex)(*args, **kwargs) - - -def assertNotRegex(self, *args, **kwargs): - return getattr(self, _assertNotRegex)(*args, **kwargs) - - -if PY3: - exec_ = getattr(moves.builtins, "exec") - - def reraise(tp, value, tb=None): - try: - if value is None: - value = tp() - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - finally: - value = None - tb = None - -else: - def exec_(_code_, _globs_=None, _locs_=None): - """Execute code in a namespace.""" - if _globs_ is None: - frame = sys._getframe(1) - _globs_ = frame.f_globals - if _locs_ is None: - _locs_ = frame.f_locals - del frame - elif _locs_ is None: - _locs_ = _globs_ - exec("""exec _code_ in _globs_, _locs_""") - - exec_("""def reraise(tp, value, tb=None): - try: - raise tp, value, tb - finally: - tb = None -""") - - -if sys.version_info[:2] > (3,): - exec_("""def raise_from(value, from_value): - try: - raise value from from_value - finally: - value = None -""") -else: - def raise_from(value, from_value): - raise value - - -print_ = getattr(moves.builtins, "print", None) -if print_ is None: - def print_(*args, **kwargs): - """The new-style print function for Python 2.4 and 2.5.""" - fp = kwargs.pop("file", sys.stdout) - if fp is None: - return - - def write(data): - if not isinstance(data, basestring): - data = str(data) - # If the file has an encoding, encode unicode with it. - if (isinstance(fp, file) and - isinstance(data, unicode) and - fp.encoding is not None): - errors = getattr(fp, "errors", None) - if errors is None: - errors = "strict" - data = data.encode(fp.encoding, errors) - fp.write(data) - want_unicode = False - sep = kwargs.pop("sep", None) - if sep is not None: - if isinstance(sep, unicode): - want_unicode = True - elif not isinstance(sep, str): - raise TypeError("sep must be None or a string") - end = kwargs.pop("end", None) - if end is not None: - if isinstance(end, unicode): - want_unicode = True - elif not isinstance(end, str): - raise TypeError("end must be None or a string") - if kwargs: - raise TypeError("invalid keyword arguments to print()") - if not want_unicode: - for arg in args: - if isinstance(arg, unicode): - want_unicode = True - break - if want_unicode: - newline = unicode("\n") - space = unicode(" ") - else: - newline = "\n" - space = " " - if sep is None: - sep = space - if end is None: - end = newline - for i, arg in enumerate(args): - if i: - write(sep) - write(arg) - write(end) -if sys.version_info[:2] < (3, 3): - _print = print_ - - def print_(*args, **kwargs): - fp = kwargs.get("file", sys.stdout) - flush = kwargs.pop("flush", False) - _print(*args, **kwargs) - if flush and fp is not None: - fp.flush() - -_add_doc(reraise, """Reraise an exception.""") - -if sys.version_info[0:2] < (3, 4): - # This does exactly the same what the :func:`py3:functools.update_wrapper` - # function does on Python versions after 3.2. It sets the ``__wrapped__`` - # attribute on ``wrapper`` object and it doesn't raise an error if any of - # the attributes mentioned in ``assigned`` and ``updated`` are missing on - # ``wrapped`` object. - def _update_wrapper(wrapper, wrapped, - assigned=functools.WRAPPER_ASSIGNMENTS, - updated=functools.WRAPPER_UPDATES): - for attr in assigned: - try: - value = getattr(wrapped, attr) - except AttributeError: - continue - else: - setattr(wrapper, attr, value) - for attr in updated: - getattr(wrapper, attr).update(getattr(wrapped, attr, {})) - wrapper.__wrapped__ = wrapped - return wrapper - _update_wrapper.__doc__ = functools.update_wrapper.__doc__ - - def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, - updated=functools.WRAPPER_UPDATES): - return functools.partial(_update_wrapper, wrapped=wrapped, - assigned=assigned, updated=updated) - wraps.__doc__ = functools.wraps.__doc__ - -else: - wraps = functools.wraps - - -def with_metaclass(meta, *bases): - """Create a base class with a metaclass.""" - # This requires a bit of explanation: the basic idea is to make a dummy - # metaclass for one level of class instantiation that replaces itself with - # the actual metaclass. - class metaclass(type): - - def __new__(cls, name, this_bases, d): - if sys.version_info[:2] >= (3, 7): - # This version introduced PEP 560 that requires a bit - # of extra care (we mimic what is done by __build_class__). - resolved_bases = types.resolve_bases(bases) - if resolved_bases is not bases: - d['__orig_bases__'] = bases - else: - resolved_bases = bases - return meta(name, resolved_bases, d) - - @classmethod - def __prepare__(cls, name, this_bases): - return meta.__prepare__(name, bases) - return type.__new__(metaclass, 'temporary_class', (), {}) - - -def add_metaclass(metaclass): - """Class decorator for creating a class with a metaclass.""" - def wrapper(cls): - orig_vars = cls.__dict__.copy() - slots = orig_vars.get('__slots__') - if slots is not None: - if isinstance(slots, str): - slots = [slots] - for slots_var in slots: - orig_vars.pop(slots_var) - orig_vars.pop('__dict__', None) - orig_vars.pop('__weakref__', None) - if hasattr(cls, '__qualname__'): - orig_vars['__qualname__'] = cls.__qualname__ - return metaclass(cls.__name__, cls.__bases__, orig_vars) - return wrapper - - -def ensure_binary(s, encoding='utf-8', errors='strict'): - """Coerce **s** to six.binary_type. - - For Python 2: - - `unicode` -> encoded to `str` - - `str` -> `str` - - For Python 3: - - `str` -> encoded to `bytes` - - `bytes` -> `bytes` - """ - if isinstance(s, binary_type): - return s - if isinstance(s, text_type): - return s.encode(encoding, errors) - raise TypeError("not expecting type '%s'" % type(s)) - - -def ensure_str(s, encoding='utf-8', errors='strict'): - """Coerce *s* to `str`. - - For Python 2: - - `unicode` -> encoded to `str` - - `str` -> `str` - - For Python 3: - - `str` -> `str` - - `bytes` -> decoded to `str` - """ - # Optimization: Fast return for the common case. - if type(s) is str: - return s - if PY2 and isinstance(s, text_type): - return s.encode(encoding, errors) - elif PY3 and isinstance(s, binary_type): - return s.decode(encoding, errors) - elif not isinstance(s, (text_type, binary_type)): - raise TypeError("not expecting type '%s'" % type(s)) - return s - - -def ensure_text(s, encoding='utf-8', errors='strict'): - """Coerce *s* to six.text_type. - - For Python 2: - - `unicode` -> `unicode` - - `str` -> `unicode` - - For Python 3: - - `str` -> `str` - - `bytes` -> decoded to `str` - """ - if isinstance(s, binary_type): - return s.decode(encoding, errors) - elif isinstance(s, text_type): - return s - else: - raise TypeError("not expecting type '%s'" % type(s)) - - -def python_2_unicode_compatible(klass): - """ - A class decorator that defines __unicode__ and __str__ methods under Python 2. - Under Python 3 it does nothing. - - To support Python 2 and 3 with a single code base, define a __str__ method - returning text and apply this decorator to the class. - """ - if PY2: - if '__str__' not in klass.__dict__: - raise ValueError("@python_2_unicode_compatible cannot be applied " - "to %s because it doesn't define __str__()." % - klass.__name__) - klass.__unicode__ = klass.__str__ - klass.__str__ = lambda self: self.__unicode__().encode('utf-8') - return klass - - -# Complete the moves implementation. -# This code is at the end of this module to speed up module loading. -# Turn this module into a package. -__path__ = [] # required for PEP 302 and PEP 451 -__package__ = __name__ # see PEP 366 @ReservedAssignment -if globals().get("__spec__") is not None: - __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable -# Remove other six meta path importers, since they cause problems. This can -# happen if six is removed from sys.modules and then reloaded. (Setuptools does -# this for some reason.) -if sys.meta_path: - for i, importer in enumerate(sys.meta_path): - # Here's some real nastiness: Another "instance" of the six module might - # be floating around. Therefore, we can't use isinstance() to check for - # the six meta path importer, since the other six instance will have - # inserted an importer with different class. - if (type(importer).__name__ == "_SixMetaPathImporter" and - importer.name == __name__): - del sys.meta_path[i] - break - del i, importer -# Finally, add the importer to the meta path import hook. -sys.meta_path.append(_importer) diff --git a/spyne/util/tdict.py b/spyne/util/tdict.py index 82875e234..14a18428c 100644 --- a/spyne/util/tdict.py +++ b/spyne/util/tdict.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -19,7 +18,6 @@ """The typed dict module""" - from itertools import chain @@ -84,7 +82,7 @@ def fromkeys(cls, S, v=None): kt = vt = None if len(S) > 0: - kt, = set((type(s) for s in S)) + (kt,) = set((type(s) for s in S)) if v is not None: vt = type(v) @@ -97,5 +95,8 @@ def fromkeys(cls, S, v=None): return retval def repr(self): - return "tdict(kt=%s, vt=%s, data=%s)" % \ - (self._kt, self._vt, super(tdict, self).__repr__()) + return "tdict(kt=%s, vt=%s, data=%s)" % ( + self._kt, + self._vt, + super(tdict, self).__repr__(), + ) diff --git a/spyne/util/test.py b/spyne/util/test.py index 48da40922..2ef5b780a 100644 --- a/spyne/util/test.py +++ b/spyne/util/test.py @@ -25,24 +25,26 @@ def _start_response(code, headers): print(code, pformat(headers)) -def call_wsgi_app_kwargs(app, _mn='some_call', _headers=None, **kwargs): + +def call_wsgi_app_kwargs(app, _mn="some_call", _headers=None, **kwargs): return call_wsgi_app(app, _mn, _headers, kwargs.items()) -def call_wsgi_app(app, mn='some_call', headers=None, body_pairs=None): + +def call_wsgi_app(app, mn="some_call", headers=None, body_pairs=None): if headers is None: headers = {} if body_pairs is None: body_pairs = [] - body_pairs = [(k,str(v)) for k,v in body_pairs] + body_pairs = [(k, str(v)) for k, v in body_pairs] request = { - 'QUERY_STRING': urlencode(body_pairs), - 'PATH_INFO': '/%s' % mn, - 'REQUEST_METHOD': 'GET', - 'SERVER_NAME': 'spyne.test', - 'SERVER_PORT': '0', - 'wsgi.url_scheme': 'http', + "QUERY_STRING": urlencode(body_pairs), + "PATH_INFO": "/%s" % mn, + "REQUEST_METHOD": "GET", + "SERVER_NAME": "spyne.test", + "SERVER_PORT": "0", + "wsgi.url_scheme": "http", } print(headers) @@ -55,14 +57,15 @@ def call_wsgi_app(app, mn='some_call', headers=None, body_pairs=None): out_string.append(s) if t == bytes: - out_string = b''.join(out_string) + out_string = b"".join(out_string) else: - out_string = ''.join(out_string) + out_string = "".join(out_string) return out_string -from os import mkdir, getcwd -from os.path import join, basename + +from os import getcwd, mkdir +from os.path import basename, join def show(elt, tn=None, stdout=True): @@ -71,27 +74,28 @@ def show(elt, tn=None, stdout=True): for frame in inspect.stack(): if frame[3].startswith("test_"): - cn = frame[0].f_locals['self'].__class__.__name__ + cn = frame[0].f_locals["self"].__class__.__name__ tn = "%s.%s" % (cn, frame[3]) break else: raise Exception("don't be lazy and pass test name.") - from lxml import html, etree + from lxml import etree, html + out_string = etree.tostring(elt, pretty_print=True) if stdout: print(out_string) - fn = '%s.html' % tn - if basename(getcwd()) != 'test_html': + fn = "%s.html" % tn + if basename(getcwd()) != "test_html": try: - mkdir('test_html') + mkdir("test_html") except OSError: pass - f = open(join("test_html", fn), 'wb') + f = open(join("test_html", fn), "wb") else: - f = open(fn, 'wb') + f = open(fn, "wb") f.write(html.tostring(elt, pretty_print=True, doctype="")) diff --git a/spyne/util/tlist.py b/spyne/util/tlist.py index ee83666f7..e13b7c61b 100644 --- a/spyne/util/tlist.py +++ b/spyne/util/tlist.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -59,7 +58,8 @@ def _type_check(self, val): if not isinstance(val, self._types): raise TypeError( "Wrong type %s, this list can hold only instances of %s" - % (type(val), str(self._types))) + % (type(val), str(self._types)) + ) def __iadd__(self, other): map(self._type_check, other) diff --git a/spyne/util/toposort.py b/spyne/util/toposort.py index 6fba0ce75..2b7c4ae99 100644 --- a/spyne/util/toposort.py +++ b/spyne/util/toposort.py @@ -37,18 +37,23 @@ def toposort2(data): return for k, v in data.items(): - v.discard(k) # Ignore self dependencies + v.discard(k) # Ignore self dependencies # add items that are listed as dependencies but not as dependents to data extra_items_in_deps = reduce(set.union, data.values()) - set(data.keys()) - data.update(dict([(item,set()) for item in extra_items_in_deps])) + data.update(dict([(item, set()) for item in extra_items_in_deps])) while True: - ordered = set(item for item,dep in data.items() if len(dep) == 0) + ordered = set(item for item, dep in data.items() if len(dep) == 0) if len(ordered) == 0: break - yield sorted(ordered, key=lambda x:repr(x)) - data = dict([(item, (dep - ordered)) for item,dep in data.items() - if item not in ordered]) + yield sorted(ordered, key=lambda x: repr(x)) + data = dict( + [ + (item, (dep - ordered)) + for item, dep in data.items() + if item not in ordered + ] + ) assert not data, "A cyclic dependency exists amongst\n%s" % pformat(data) diff --git a/spyne/util/web.py b/spyne/util/web.py index 936ca06d4..d91300c6a 100644 --- a/spyne/util/web.py +++ b/spyne/util/web.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -26,34 +25,51 @@ from __future__ import absolute_import import logging + logger = logging.getLogger(__name__) from inspect import isclass -from spyne import rpc, Any, AnyDict, NATIVE_MAP, M, Array, ComplexModelBase, \ - UnsignedInteger32, PushBase, Iterable, ModelBase, File, Service, \ - ResourceNotFoundError, Unicode - -from spyne.const import MAX_ARRAY_ELEMENT_NUM, MAX_DICT_ELEMENT_NUM, \ - MAX_STRING_FIELD_LENGTH, MAX_FIELD_NUM +from spyne import ( + NATIVE_MAP, + Any, + AnyDict, + Array, + ComplexModelBase, + File, + Iterable, + M, + ModelBase, + PushBase, + ResourceNotFoundError, + Service, + Unicode, + UnsignedInteger32, + rpc, +) +from spyne.const import ( + MAX_ARRAY_ELEMENT_NUM, + MAX_DICT_ELEMENT_NUM, + MAX_FIELD_NUM, + MAX_STRING_FIELD_LENGTH, +) try: - from spyne.store.relational.document import FileData from sqlalchemy.orm.exc import DetachedInstanceError + + from spyne.store.relational.document import FileData except ImportError: # these are used just for isinstance checks. so we just set it to an # anonymous value - FileData = type('__hidden', (object, ), {}) - DetachedInstanceError = type('__hidden', (Exception, ), {}) - -from spyne.util import memoize, six + FileData = type("__hidden", (object,), {}) + DetachedInstanceError = type("__hidden", (Exception,), {}) EXCEPTION_ADDRESS = None try: - from colorama.ansi import Fore - from colorama.ansi import Style + from colorama.ansi import Fore, Style + RED = Fore.RED + Style.BRIGHT GREEN = Fore.GREEN + Style.BRIGHT RESET = Style.RESET_ALL @@ -72,8 +88,9 @@ class WriterService(Service): pass -def log_repr(obj, cls=None, given_len=None, parent=None, from_array=False, - tags=None, prot=None): +def log_repr( + obj, cls=None, given_len=None, parent=None, from_array=False, tags=None, prot=None +): """Use this function if you want to serialize a ComplexModelBase instance to logs. It will: @@ -86,10 +103,10 @@ def log_repr(obj, cls=None, given_len=None, parent=None, from_array=False, tags = set() if obj is None: - return 'None' + return "None" objcls = None - if hasattr(obj, '__class__'): + if hasattr(obj, "__class__"): objcls = obj.__class__ if objcls in (list, tuple): @@ -107,7 +124,7 @@ def log_repr(obj, cls=None, given_len=None, parent=None, from_array=False, cls_attrs = None logged = None - if hasattr(cls, 'Attributes'): + if hasattr(cls, "Attributes"): # init cls_attrs if prot is None: cls_attrs = cls.Attributes @@ -119,11 +136,11 @@ def log_repr(obj, cls=None, given_len=None, parent=None, from_array=False, if not logged: return "%s(...)" % cls.get_type_name() - if logged == '...': + if logged == "...": return "(...)" - if logged == 'len': - l = '?' + if logged == "len": + l = "?" try: if isinstance(obj, (list, tuple)): l = str(sum([len(o) for o in obj])) @@ -148,33 +165,33 @@ def log_repr(obj, cls=None, given_len=None, parent=None, from_array=False, retval = [] if isinstance(obj, dict): - if logged == 'full': + if logged == "full": for i, (k, v) in enumerate(obj.items()): - retval.append('%r: %r' % (k, v)) + retval.append("%r: %r" % (k, v)) - elif logged == 'keys': + elif logged == "keys": for i, k in enumerate(obj.keys()): if i >= MAX_DICT_ELEMENT_NUM: retval.append("(...)") break - retval.append('%r: (...)' % (k,)) + retval.append("%r: (...)" % (k,)) - elif logged == 'values': + elif logged == "values": for i, v in enumerate(obj.values()): if i >= MAX_DICT_ELEMENT_NUM: retval.append("(...)") break - retval.append('(...): %s' % (log_repr(v, tags=tags),)) + retval.append("(...): %s" % (log_repr(v, tags=tags),)) - elif logged == 'keys-full': + elif logged == "keys-full": for k in obj.keys(): - retval.append('%r: (...)' % (k,)) + retval.append("%r: (...)" % (k,)) - elif logged == 'values-full': + elif logged == "values-full": for v in obj.values(): - retval.append('(...): %r' % (v,)) + retval.append("(...): %r" % (v,)) elif logged is True: # default behaviour for i, (k, v) in enumerate(obj.items()): @@ -182,18 +199,17 @@ def log_repr(obj, cls=None, given_len=None, parent=None, from_array=False, retval.append("(...)") break - retval.append('%r: %s' % (k, - log_repr(v, parent=k, tags=tags))) + retval.append("%r: %s" % (k, log_repr(v, parent=k, tags=tags))) elif logged is None: return "(...)" else: raise ValueError("Invalid value logged=%r", logged) - return "{%s}" % ', '.join(retval) + return "{%s}" % ", ".join(retval) else: - if logged in ('full', 'keys-full', 'values-full'): + if logged in ("full", "keys-full", "values-full"): retval = [repr(s) for s in obj] else: @@ -204,11 +220,11 @@ def log_repr(obj, cls=None, given_len=None, parent=None, from_array=False, retval.append(log_repr(v, tags=tags)) - return "[%s]" % ', '.join(retval) + return "[%s]" % ", ".join(retval) - if ( issubclass(cls, Array) - or (cls_attrs is not None and cls_attrs.max_occurs > 1) ) \ - and not from_array: + if ( + issubclass(cls, Array) or (cls_attrs is not None and cls_attrs.max_occurs > 1) + ) and not from_array: if id(obj) in tags: return "%s(...)" % obj.__class__.__name__ @@ -219,22 +235,22 @@ def log_repr(obj, cls=None, given_len=None, parent=None, from_array=False, subcls = cls if issubclass(cls, Array): - subcls, = cls._type_info.values() + (subcls,) = cls._type_info.values() if isinstance(obj, PushBase): - return '[]' + return "[]" if logged is None: logged = cls_attrs.logged for i, o in enumerate(obj): - if logged != 'full' and i >= MAX_ARRAY_ELEMENT_NUM: + if logged != "full" and i >= MAX_ARRAY_ELEMENT_NUM: retval.append("(...)") break retval.append(log_repr(o, subcls, from_array=True, tags=tags)) - return "[%s]" % (', '.join(retval)) + return "[%s]" % (", ".join(retval)) if issubclass(cls, ComplexModelBase): if id(obj) in tags: @@ -253,7 +269,7 @@ def log_repr(obj, cls=None, given_len=None, parent=None, from_array=False, if not t.Attributes.logged: continue - if logged == '...': + if logged == "...": retval.append("%s=(...)" % k) continue @@ -275,11 +291,11 @@ def log_repr(obj, cls=None, given_len=None, parent=None, from_array=False, retval.append("%s=%s" % (k, log_repr(v, t, parent=k, tags=tags))) i += 1 - return "%s(%s)" % (cls.get_type_name(), ', '.join(retval)) + return "%s(%s)" % (cls.get_type_name(), ", ".join(retval)) - if issubclass(cls, Unicode) and isinstance(obj, six.string_types): + if issubclass(cls, Unicode) and isinstance(obj, str): if len(obj) > MAX_STRING_FIELD_LENGTH: - return '%r(...)' % obj[:MAX_STRING_FIELD_LENGTH] + return "%r(...)" % obj[:MAX_STRING_FIELD_LENGTH] return repr(obj) @@ -299,39 +315,46 @@ def log_repr(obj, cls=None, given_len=None, parent=None, from_array=False, def TReaderService(T, T_name): class ReaderService(ReaderService): - @rpc(M(UnsignedInteger32), _returns=T, - _in_message_name='get_%s' % T_name, - _in_variable_names={'obj_id': "%s_id" % T_name}) + @rpc( + M(UnsignedInteger32), + _returns=T, + _in_message_name="get_%s" % T_name, + _in_variable_names={"obj_id": "%s_id" % T_name}, + ) def get(ctx, obj_id): return ctx.udc.session.query(T).filter_by(id=obj_id).one() - @rpc(_returns=Iterable(T), - _in_message_name='get_all_%s' % T_name) + @rpc(_returns=Iterable(T), _in_message_name="get_all_%s" % T_name) def get_all(ctx): return ctx.udc.session.query(T).order_by(T.id) return ReaderService -def TWriterService(T, T_name, put_not_found='raise'): - assert put_not_found in ('raise', 'fix') +def TWriterService(T, T_name, put_not_found="raise"): + assert put_not_found in ("raise", "fix") + + if put_not_found == "raise": - if put_not_found == 'raise': def put_not_found(obj): - raise ResourceNotFoundError('%s.id=%d' % (T_name, obj.id)) + raise ResourceNotFoundError("%s.id=%d" % (T_name, obj.id)) + + elif put_not_found == "fix": - elif put_not_found == 'fix': def put_not_found(obj): obj.id = None class WriterService(WriterService): - @rpc(M(T), _returns=UnsignedInteger32, - _in_message_name='put_%s' % T_name, - _in_variable_names={'obj': T_name}) + @rpc( + M(T), + _returns=UnsignedInteger32, + _in_message_name="put_%s" % T_name, + _in_variable_names={"obj": T_name}, + ) def put(ctx, obj): if obj.id is None: ctx.udc.session.add(obj) - ctx.udc.session.flush() # so that we get the obj.id value + ctx.udc.session.flush() # so that we get the obj.id value else: if ctx.udc.session.query(T).get(obj.id) is None: @@ -349,9 +372,11 @@ def put(ctx, obj): return obj.id - @rpc(M(UnsignedInteger32), - _in_message_name='del_%s' % T_name, - _in_variable_names={'obj_id': '%s_id' % T_name}) + @rpc( + M(UnsignedInteger32), + _in_message_name="del_%s" % T_name, + _in_variable_names={"obj_id": "%s_id" % T_name}, + ) def del_(ctx, obj_id): count = ctx.udc.session.query(T).filter_by(id=obj_id).count() if count == 0: diff --git a/spyne/util/wsgi_wrapper.py b/spyne/util/wsgi_wrapper.py index b15084935..974d02279 100644 --- a/spyne/util/wsgi_wrapper.py +++ b/spyne/util/wsgi_wrapper.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -20,6 +19,7 @@ """A Convenience module for wsgi wrapper routines.""" import logging + logger = logging.getLogger(__name__) import os @@ -54,16 +54,16 @@ def __init__(self, mounts=None): assert callable(v), "%r is not a valid wsgi app." % v app = v - if k in ('', '/'): + if k in ("", "/"): self.default = app else: self.mounts[k] = app def __call__(self, environ, start_response): - path_info = environ.get('PATH_INFO', '') - fragments = [a for a in path_info.split('/') if len(a) > 0] + path_info = environ.get("PATH_INFO", "") + fragments = [a for a in path_info.split("/") if len(a) > 0] - script = '' + script = "" if len(fragments) > 0: script = fragments[0] @@ -71,22 +71,22 @@ def __call__(self, environ, start_response): if app is self.default: return app(environ, start_response) - original_script_name = environ.get('SCRIPT_NAME', '') + original_script_name = environ.get("SCRIPT_NAME", "") if len(script) > 0: script = "/" + script - environ['SCRIPT_NAME'] = ''.join(('/', original_script_name, script)) - pi = ''.join(('/', '/'.join(fragments[1:]))) + environ["SCRIPT_NAME"] = "".join(("/", original_script_name, script)) + pi = "".join(("/", "/".join(fragments[1:]))) - if pi == '/': - environ['PATH_INFO'] = '' + if pi == "/": + environ["PATH_INFO"] = "" else: - environ['PATH_INFO'] = pi + environ["PATH_INFO"] = pi return app(environ, start_response) -def run_twisted(apps, port, static_dir='.', interface='0.0.0.0'): +def run_twisted(apps, port, static_dir=".", interface="0.0.0.0"): """Twisted wrapper for the spyne.server.wsgi.WsgiApplication. Twisted can use one thread per request to run services, so code wrapped this way does not necessarily have to respect twisted way of doing things. @@ -102,10 +102,9 @@ def run_twisted(apps, port, static_dir='.', interface='0.0.0.0'): import twisted.web.server import twisted.web.static - + from twisted.internet import reactor from twisted.web.resource import Resource from twisted.web.wsgi import WSGIResource - from twisted.internet import reactor if static_dir != None: static_dir = os.path.abspath(static_dir) diff --git a/spyne/util/xml.py b/spyne/util/xml.py index d52ada5f4..5cb490e08 100644 --- a/spyne/util/xml.py +++ b/spyne/util/xml.py @@ -1,4 +1,3 @@ - # # spyne - Copyright (C) Spyne contributors. # @@ -21,24 +20,22 @@ """The `spyne.util.xml` module contains various Xml and Xml Schema related utility functions. """ + from inspect import isgenerator +from io import BytesIO +from os.path import abspath, dirname from lxml import etree -from os.path import dirname -from os.path import abspath - -from spyne import ServiceBase, Application, srpc +from spyne import Application, ServiceBase, srpc from spyne.context import FakeContext from spyne.interface import Interface from spyne.interface.xml_schema import XmlSchema -from spyne.interface.xml_schema.parser import XmlSchemaParser, Thier_repr, PARSER +from spyne.interface.xml_schema.parser import PARSER, Thier_repr, XmlSchemaParser from spyne.protocol import ProtocolMixin from spyne.protocol.cloth import XmlCloth - from spyne.protocol.xml import XmlDocument from spyne.util.appreg import unregister_application -from spyne.util.six import BytesIO from spyne.util.tlist import tlist @@ -99,7 +96,7 @@ def get_validation_schema(models, default_namespace=None): def _dig(par): for elt in par: - elt.tag = elt.tag.split('}')[-1] + elt.tag = elt.tag.split("}")[-1] _dig(elt) @@ -121,8 +118,7 @@ def get_object_as_xml(inst, cls=None, root_tag_name=None, no_namespace=False): cls = inst.__class__ parent = etree.Element("parent") - _xml_object.to_parent(None, cls, inst, parent, cls.get_namespace(), - root_tag_name) + _xml_object.to_parent(None, cls, inst, parent, cls.get_namespace(), root_tag_name) if no_namespace: _dig(parent) etree.cleanup_namespaces(parent) @@ -130,8 +126,9 @@ def get_object_as_xml(inst, cls=None, root_tag_name=None, no_namespace=False): return parent[0] -def get_object_as_xml_polymorphic(inst, cls=None, root_tag_name=None, - no_namespace=False): +def get_object_as_xml_polymorphic( + inst, cls=None, root_tag_name=None, no_namespace=False +): """Returns an ElementTree representation of a :class:`spyne.model.complex.ComplexModel` subclass. @@ -146,29 +143,32 @@ def get_object_as_xml_polymorphic(inst, cls=None, root_tag_name=None, cls = inst.__class__ if no_namespace: - app = Application([ServiceBase], tns="", - out_protocol=XmlDocument(polymorphic=True)) + app = Application( + [ServiceBase], tns="", out_protocol=XmlDocument(polymorphic=True) + ) else: tns = cls.get_namespace() if tns is None: raise ValueError( - "Either set a namespace for %r or pass no_namespace=True" - % (cls, )) + "Either set a namespace for %r or pass no_namespace=True" % (cls,) + ) class _DummyService(ServiceBase): @srpc(cls) def f(_): pass - app = Application([_DummyService], tns=tns, - out_protocol=XmlDocument(polymorphic=True)) + app = Application( + [_DummyService], tns=tns, out_protocol=XmlDocument(polymorphic=True) + ) unregister_application(app) parent = etree.Element("parent", nsmap=app.interface.nsmap) - app.out_protocol.to_parent(None, cls, inst, parent, cls.get_namespace(), - root_tag_name) + app.out_protocol.to_parent( + None, cls, inst, parent, cls.get_namespace(), root_tag_name + ) if no_namespace: _dig(parent) @@ -188,22 +188,23 @@ def get_xml_as_object_polymorphic(elt, cls): tns = cls.get_namespace() if tns is None: - raise ValueError("Please set a namespace for %r" % (cls, )) + raise ValueError("Please set a namespace for %r" % (cls,)) class _DummyService(ServiceBase): @srpc(cls) def f(_): pass - app = Application([_DummyService], tns=tns, - in_protocol=XmlDocument(polymorphic=True)) + app = Application( + [_DummyService], tns=tns, in_protocol=XmlDocument(polymorphic=True) + ) unregister_application(app) return app.in_protocol.from_element(FakeContext(app=app), cls, elt) -def get_object_as_xml_cloth(inst, cls=None, no_namespace=False, encoding='utf8'): +def get_object_as_xml_cloth(inst, cls=None, no_namespace=False, encoding="utf8"): """Returns an ElementTree representation of a :class:`spyne.model.complex.ComplexModel` subclass. @@ -247,8 +248,9 @@ def get_xml_as_object(elt, cls): return _xml_object.from_element(None, cls, elt) -def parse_schema_string(s, files={}, repr_=Thier_repr(with_ns=False), - skip_errors=False): +def parse_schema_string( + s, files={}, repr_=Thier_repr(with_ns=False), skip_errors=False +): """Parses a schema string and returns a _Schema object. :param s: The string or bytes object that contains the schema document. @@ -262,12 +264,14 @@ def parse_schema_string(s, files={}, repr_=Thier_repr(with_ns=False), """ elt = etree.fromstring(s, parser=PARSER) - return XmlSchemaParser(files, repr_=repr_, - skip_errors=skip_errors).parse_schema(elt) + return XmlSchemaParser(files, repr_=repr_, skip_errors=skip_errors).parse_schema( + elt + ) -def parse_schema_element(elt, files={}, repr_=Thier_repr(with_ns=False), - skip_errors=False): +def parse_schema_element( + elt, files={}, repr_=Thier_repr(with_ns=False), skip_errors=False +): """Parses a `` element and returns a _Schema object. :param elt: The `` element, an lxml.etree._Element instance. @@ -280,12 +284,14 @@ def parse_schema_element(elt, files={}, repr_=Thier_repr(with_ns=False), :return: :class:`spyne.interface.xml_schema.parser._Schema` instance. """ - return XmlSchemaParser(files, repr_=repr_, - skip_errors=skip_errors).parse_schema(elt) + return XmlSchemaParser(files, repr_=repr_, skip_errors=skip_errors).parse_schema( + elt + ) -def parse_schema_file(file_name, files=None, repr_=Thier_repr(with_ns=False), - skip_errors=False): +def parse_schema_file( + file_name, files=None, repr_=Thier_repr(with_ns=False), skip_errors=False +): """Parses a schema file and returns a _Schema object. Schema files typically have the `*.xsd` extension. @@ -303,7 +309,8 @@ def parse_schema_file(file_name, files=None, repr_=Thier_repr(with_ns=False), if files is None: files = dict() - elt = etree.fromstring(open(file_name, 'rb').read(), parser=PARSER) + elt = etree.fromstring(open(file_name, "rb").read(), parser=PARSER) wd = abspath(dirname(file_name)) - return XmlSchemaParser(files, wd, repr_=repr_, - skip_errors=skip_errors).parse_schema(elt) + return XmlSchemaParser( + files, wd, repr_=repr_, skip_errors=skip_errors + ).parse_schema(elt)