From 919113f3e0b0c8e465fa22d7a22ec4a6245d56d6 Mon Sep 17 00:00:00 2001 From: idziubenko Date: Wed, 23 Jun 2021 14:35:27 +0300 Subject: [PATCH] Add spyne suds to contrib --- pym/calculate/contrib/spyne/__init__.py | 81 + pym/calculate/contrib/spyne/__init__.pyc | Bin 0 -> 2879 bytes pym/calculate/contrib/spyne/_base.py | 47 + pym/calculate/contrib/spyne/_base.pyc | Bin 0 -> 1330 bytes pym/calculate/contrib/spyne/application.py | 321 ++++ pym/calculate/contrib/spyne/application.pyc | Bin 0 -> 10319 bytes .../contrib/spyne/auxproc/__init__.py | 42 + .../contrib/spyne/auxproc/__init__.pyc | Bin 0 -> 1141 bytes pym/calculate/contrib/spyne/auxproc/_base.py | 88 + pym/calculate/contrib/spyne/auxproc/_base.pyc | Bin 0 -> 3298 bytes pym/calculate/contrib/spyne/auxproc/sync.py | 32 + pym/calculate/contrib/spyne/auxproc/sync.pyc | Bin 0 -> 894 bytes pym/calculate/contrib/spyne/auxproc/thread.py | 52 + .../contrib/spyne/auxproc/thread.pyc | Bin 0 -> 2074 bytes .../contrib/spyne/client/__init__.py | 25 + .../contrib/spyne/client/__init__.pyc | Bin 0 -> 462 bytes pym/calculate/contrib/spyne/client/_base.py | 176 ++ pym/calculate/contrib/spyne/client/_base.pyc | Bin 0 -> 7070 bytes pym/calculate/contrib/spyne/client/django.py | 81 + pym/calculate/contrib/spyne/client/django.pyc | Bin 0 -> 2716 bytes pym/calculate/contrib/spyne/client/http.py | 70 + pym/calculate/contrib/spyne/client/http.pyc | Bin 0 -> 2012 bytes .../contrib/spyne/client/twisted/__init__.py | 148 ++ .../contrib/spyne/client/twisted/__init__.pyc | Bin 0 -> 6076 bytes pym/calculate/contrib/spyne/client/zeromq.py | 54 + pym/calculate/contrib/spyne/client/zeromq.pyc | Bin 0 -> 1810 bytes pym/calculate/contrib/spyne/const/__init__.py | 82 + .../contrib/spyne/const/__init__.pyc | Bin 0 -> 1172 bytes .../contrib/spyne/const/ansi_color.py | 81 + .../contrib/spyne/const/ansi_color.pyc | Bin 0 -> 1166 bytes pym/calculate/contrib/spyne/const/http.py | 116 ++ pym/calculate/contrib/spyne/const/http.pyc | Bin 0 -> 4163 bytes pym/calculate/contrib/spyne/const/xml.py | 187 ++ pym/calculate/contrib/spyne/const/xml.pyc | Bin 0 -> 6367 bytes pym/calculate/contrib/spyne/const/xml_ns.py | 63 + pym/calculate/contrib/spyne/const/xml_ns.pyc | Bin 0 -> 1837 bytes pym/calculate/contrib/spyne/context.py | 463 +++++ pym/calculate/contrib/spyne/context.pyc | Bin 0 -> 10859 bytes pym/calculate/contrib/spyne/decorator.py | 572 ++++++ pym/calculate/contrib/spyne/decorator.pyc | Bin 0 -> 17381 bytes pym/calculate/contrib/spyne/descriptor.py | 309 ++++ pym/calculate/contrib/spyne/descriptor.pyc | Bin 0 -> 7831 bytes pym/calculate/contrib/spyne/error.py | 154 ++ pym/calculate/contrib/spyne/error.pyc | Bin 0 -> 7407 bytes pym/calculate/contrib/spyne/evmgr.py | 83 + pym/calculate/contrib/spyne/evmgr.pyc | Bin 0 -> 3248 bytes .../contrib/spyne/interface/__init__.py | 43 + .../contrib/spyne/interface/__init__.pyc | Bin 0 -> 947 bytes .../contrib/spyne/interface/_base.py | 550 ++++++ .../contrib/spyne/interface/_base.pyc | Bin 0 -> 17258 bytes .../contrib/spyne/interface/wsdl/__init__.py | 25 + .../contrib/spyne/interface/wsdl/__init__.pyc | Bin 0 -> 450 bytes .../contrib/spyne/interface/wsdl/defn.py | 108 ++ .../contrib/spyne/interface/wsdl/defn.pyc | Bin 0 -> 5810 bytes .../contrib/spyne/interface/wsdl/wsdl11.py | 576 ++++++ .../contrib/spyne/interface/wsdl/wsdl11.pyc | Bin 0 -> 16606 bytes .../spyne/interface/xml_schema/__init__.py | 25 + .../spyne/interface/xml_schema/__init__.pyc | Bin 0 -> 522 bytes .../spyne/interface/xml_schema/_base.py | 297 +++ .../spyne/interface/xml_schema/_base.pyc | Bin 0 -> 11210 bytes .../spyne/interface/xml_schema/defn.py | 188 ++ .../spyne/interface/xml_schema/defn.pyc | Bin 0 -> 7579 bytes .../spyne/interface/xml_schema/genpy.py | 144 ++ .../spyne/interface/xml_schema/genpy.pyc | Bin 0 -> 4697 bytes .../spyne/interface/xml_schema/model.py | 397 ++++ .../spyne/interface/xml_schema/model.pyc | Bin 0 -> 12152 bytes .../spyne/interface/xml_schema/parser.py | 705 +++++++ .../spyne/interface/xml_schema/parser.pyc | Bin 0 -> 21517 bytes pym/calculate/contrib/spyne/model/__init__.py | 70 + .../contrib/spyne/model/__init__.pyc | Bin 0 -> 1526 bytes pym/calculate/contrib/spyne/model/_base.py | 1070 +++++++++++ pym/calculate/contrib/spyne/model/_base.pyc | Bin 0 -> 32896 bytes pym/calculate/contrib/spyne/model/addtl.py | 98 + pym/calculate/contrib/spyne/model/addtl.pyc | Bin 0 -> 3021 bytes pym/calculate/contrib/spyne/model/binary.py | 386 ++++ pym/calculate/contrib/spyne/model/binary.pyc | Bin 0 -> 12985 bytes pym/calculate/contrib/spyne/model/complex.py | 1631 +++++++++++++++++ pym/calculate/contrib/spyne/model/complex.pyc | Bin 0 -> 51271 bytes pym/calculate/contrib/spyne/model/enum.py | 121 ++ pym/calculate/contrib/spyne/model/enum.pyc | Bin 0 -> 5511 bytes pym/calculate/contrib/spyne/model/fault.py | 175 ++ pym/calculate/contrib/spyne/model/fault.pyc | Bin 0 -> 5977 bytes .../contrib/spyne/model/primitive/__init__.py | 155 ++ .../spyne/model/primitive/__init__.pyc | Bin 0 -> 5261 bytes .../contrib/spyne/model/primitive/_base.py | 130 ++ .../contrib/spyne/model/primitive/_base.pyc | Bin 0 -> 4741 bytes .../contrib/spyne/model/primitive/datetime.py | 273 +++ .../spyne/model/primitive/datetime.pyc | Bin 0 -> 6625 bytes .../contrib/spyne/model/primitive/network.py | 157 ++ .../contrib/spyne/model/primitive/network.pyc | Bin 0 -> 6021 bytes .../contrib/spyne/model/primitive/number.py | 417 +++++ .../contrib/spyne/model/primitive/number.pyc | Bin 0 -> 12574 bytes .../contrib/spyne/model/primitive/spatial.py | 263 +++ .../contrib/spyne/model/primitive/spatial.pyc | Bin 0 -> 11689 bytes .../contrib/spyne/model/primitive/string.py | 307 ++++ .../contrib/spyne/model/primitive/string.pyc | Bin 0 -> 11411 bytes .../contrib/spyne/model/primitive/xml.py | 195 ++ .../contrib/spyne/model/primitive/xml.pyc | Bin 0 -> 7570 bytes .../contrib/spyne/model/relational.py | 46 + .../contrib/spyne/model/relational.pyc | Bin 0 -> 1459 bytes pym/calculate/contrib/spyne/model/table.py | 227 +++ pym/calculate/contrib/spyne/model/table.pyc | Bin 0 -> 7215 bytes .../contrib/spyne/protocol/__init__.py | 44 + .../contrib/spyne/protocol/__init__.pyc | Bin 0 -> 1411 bytes pym/calculate/contrib/spyne/protocol/_base.py | 422 +++++ .../contrib/spyne/protocol/_base.pyc | Bin 0 -> 13554 bytes .../contrib/spyne/protocol/_inbase.py | 716 ++++++++ .../contrib/spyne/protocol/_inbase.pyc | Bin 0 -> 27201 bytes .../contrib/spyne/protocol/_outbase.py | 904 +++++++++ .../contrib/spyne/protocol/_outbase.pyc | Bin 0 -> 33578 bytes .../contrib/spyne/protocol/cloth/__init__.py | 26 + .../contrib/spyne/protocol/cloth/__init__.pyc | Bin 0 -> 433 bytes .../contrib/spyne/protocol/cloth/_base.py | 326 ++++ .../contrib/spyne/protocol/cloth/_base.pyc | Bin 0 -> 11268 bytes .../contrib/spyne/protocol/cloth/to_cloth.py | 865 +++++++++ .../contrib/spyne/protocol/cloth/to_cloth.pyc | Bin 0 -> 25561 bytes .../contrib/spyne/protocol/cloth/to_parent.py | 522 ++++++ .../spyne/protocol/cloth/to_parent.pyc | Bin 0 -> 15038 bytes pym/calculate/contrib/spyne/protocol/csv.py | 136 ++ pym/calculate/contrib/spyne/protocol/csv.pyc | Bin 0 -> 4603 bytes .../spyne/protocol/dictdoc/__init__.py | 137 ++ .../spyne/protocol/dictdoc/__init__.pyc | Bin 0 -> 3403 bytes .../contrib/spyne/protocol/dictdoc/_base.py | 147 ++ .../contrib/spyne/protocol/dictdoc/_base.pyc | Bin 0 -> 5508 bytes .../contrib/spyne/protocol/dictdoc/hier.py | 569 ++++++ .../contrib/spyne/protocol/dictdoc/hier.pyc | Bin 0 -> 14176 bytes .../contrib/spyne/protocol/dictdoc/simple.py | 404 ++++ .../contrib/spyne/protocol/dictdoc/simple.pyc | Bin 0 -> 10435 bytes .../contrib/spyne/protocol/html/__init__.py | 41 + .../contrib/spyne/protocol/html/__init__.pyc | Bin 0 -> 1122 bytes .../contrib/spyne/protocol/html/_base.py | 251 +++ .../contrib/spyne/protocol/html/_base.pyc | Bin 0 -> 10012 bytes .../contrib/spyne/protocol/html/addtl.py | 52 + .../contrib/spyne/protocol/html/addtl.pyc | Bin 0 -> 2037 bytes .../spyne/protocol/html/microformat.py | 197 ++ .../spyne/protocol/html/microformat.pyc | Bin 0 -> 6555 bytes .../spyne/protocol/html/table/__init__.py | 4 + .../spyne/protocol/html/table/__init__.pyc | Bin 0 -> 432 bytes .../spyne/protocol/html/table/_base.py | 69 + .../spyne/protocol/html/table/_base.pyc | Bin 0 -> 2319 bytes .../spyne/protocol/html/table/column.py | 336 ++++ .../spyne/protocol/html/table/column.pyc | Bin 0 -> 11598 bytes .../contrib/spyne/protocol/html/table/row.py | 216 +++ .../contrib/spyne/protocol/html/table/row.pyc | Bin 0 -> 6410 bytes pym/calculate/contrib/spyne/protocol/http.py | 475 +++++ pym/calculate/contrib/spyne/protocol/http.pyc | Bin 0 -> 17096 bytes pym/calculate/contrib/spyne/protocol/json.py | 425 +++++ pym/calculate/contrib/spyne/protocol/json.pyc | Bin 0 -> 14463 bytes .../contrib/spyne/protocol/msgpack.py | 361 ++++ .../contrib/spyne/protocol/msgpack.pyc | Bin 0 -> 11972 bytes .../contrib/spyne/protocol/soap/__init__.py | 30 + .../contrib/spyne/protocol/soap/__init__.pyc | Bin 0 -> 636 bytes .../contrib/spyne/protocol/soap/mime.py | 315 ++++ .../contrib/spyne/protocol/soap/mime.pyc | Bin 0 -> 8537 bytes .../contrib/spyne/protocol/soap/soap11.py | 379 ++++ .../contrib/spyne/protocol/soap/soap11.pyc | Bin 0 -> 11887 bytes .../contrib/spyne/protocol/soap/soap12.py | 152 ++ .../contrib/spyne/protocol/soap/soap12.pyc | Bin 0 -> 5493 bytes pym/calculate/contrib/spyne/protocol/xml.py | 1160 ++++++++++++ pym/calculate/contrib/spyne/protocol/xml.pyc | Bin 0 -> 36304 bytes pym/calculate/contrib/spyne/protocol/yaml.py | 187 ++ pym/calculate/contrib/spyne/protocol/yaml.pyc | Bin 0 -> 6650 bytes .../contrib/spyne/server/__init__.py | 23 + .../contrib/spyne/server/__init__.pyc | Bin 0 -> 389 bytes pym/calculate/contrib/spyne/server/_base.py | 260 +++ pym/calculate/contrib/spyne/server/_base.pyc | Bin 0 -> 8706 bytes pym/calculate/contrib/spyne/server/django.py | 390 ++++ pym/calculate/contrib/spyne/server/django.pyc | Bin 0 -> 14731 bytes pym/calculate/contrib/spyne/server/http.py | 326 ++++ pym/calculate/contrib/spyne/server/http.pyc | Bin 0 -> 12030 bytes pym/calculate/contrib/spyne/server/msgpack.py | 217 +++ .../contrib/spyne/server/msgpack.pyc | Bin 0 -> 8057 bytes pym/calculate/contrib/spyne/server/null.py | 228 +++ pym/calculate/contrib/spyne/server/null.pyc | Bin 0 -> 7647 bytes pym/calculate/contrib/spyne/server/pyramid.py | 58 + .../contrib/spyne/server/pyramid.pyc | Bin 0 -> 2308 bytes .../contrib/spyne/server/twisted/__init__.py | 27 + .../contrib/spyne/server/twisted/__init__.pyc | Bin 0 -> 615 bytes .../contrib/spyne/server/twisted/_base.py | 79 + .../contrib/spyne/server/twisted/_base.pyc | Bin 0 -> 2751 bytes .../contrib/spyne/server/twisted/http.py | 790 ++++++++ .../contrib/spyne/server/twisted/http.pyc | Bin 0 -> 25580 bytes .../contrib/spyne/server/twisted/msgpack.py | 477 +++++ .../contrib/spyne/server/twisted/msgpack.pyc | Bin 0 -> 16603 bytes .../contrib/spyne/server/twisted/websocket.py | 255 +++ .../spyne/server/twisted/websocket.pyc | Bin 0 -> 11090 bytes pym/calculate/contrib/spyne/server/wsgi.py | 624 +++++++ pym/calculate/contrib/spyne/server/wsgi.pyc | Bin 0 -> 19303 bytes pym/calculate/contrib/spyne/server/zeromq.py | 164 ++ pym/calculate/contrib/spyne/server/zeromq.pyc | Bin 0 -> 5503 bytes pym/calculate/contrib/spyne/service.py | 251 +++ pym/calculate/contrib/spyne/service.pyc | Bin 0 -> 8425 bytes pym/calculate/contrib/spyne/store/__init__.py | 20 + .../contrib/spyne/store/__init__.pyc | Bin 0 -> 226 bytes .../spyne/store/relational/__init__.py | 35 + .../spyne/store/relational/__init__.pyc | Bin 0 -> 1011 bytes .../contrib/spyne/store/relational/_base.py | 1203 ++++++++++++ .../contrib/spyne/store/relational/_base.pyc | Bin 0 -> 30824 bytes .../spyne/store/relational/document.py | 353 ++++ .../spyne/store/relational/document.pyc | Bin 0 -> 15162 bytes .../spyne/store/relational/override.py | 98 + .../spyne/store/relational/override.pyc | Bin 0 -> 3852 bytes .../contrib/spyne/store/relational/simple.py | 96 + .../contrib/spyne/store/relational/simple.pyc | Bin 0 -> 4039 bytes .../contrib/spyne/store/relational/spatial.py | 84 + .../spyne/store/relational/spatial.pyc | Bin 0 -> 3890 bytes .../contrib/spyne/store/relational/util.py | 279 +++ .../contrib/spyne/store/relational/util.pyc | Bin 0 -> 7783 bytes pym/calculate/contrib/spyne/test/__init__.py | 31 + pym/calculate/contrib/spyne/test/__init__.pyc | Bin 0 -> 752 bytes .../contrib/spyne/test/interface/__init__.py | 0 .../contrib/spyne/test/interface/__init__.pyc | Bin 0 -> 178 bytes .../spyne/test/interface/test_interface.py | 107 ++ .../spyne/test/interface/test_interface.pyc | Bin 0 -> 5354 bytes .../contrib/spyne/test/interface/test_wsgi.py | 91 + .../spyne/test/interface/test_wsgi.pyc | Bin 0 -> 4150 bytes .../spyne/test/interface/test_xml_schema.py | 551 ++++++ .../spyne/test/interface/test_xml_schema.pyc | Bin 0 -> 28440 bytes .../spyne/test/interface/wsdl/__init__.py | 68 + .../spyne/test/interface/wsdl/__init__.pyc | Bin 0 -> 3704 bytes .../test/interface/wsdl/defult_services.py | 49 + .../test/interface/wsdl/defult_services.pyc | Bin 0 -> 2309 bytes .../interface/wsdl/port_service_services.py | 127 ++ .../interface/wsdl/port_service_services.pyc | Bin 0 -> 7354 bytes .../test/interface/wsdl/test_bindings.py | 133 ++ .../test/interface/wsdl/test_bindings.pyc | Bin 0 -> 3681 bytes .../test/interface/wsdl/test_default_wsdl.py | 248 +++ .../test/interface/wsdl/test_default_wsdl.pyc | Bin 0 -> 8612 bytes .../test/interface/wsdl/test_op_req_suffix.py | 287 +++ .../interface/wsdl/test_op_req_suffix.pyc | Bin 0 -> 13087 bytes .../wsdl/test_wsdl_ports_services.py | 215 +++ .../wsdl/test_wsdl_ports_services.pyc | Bin 0 -> 6579 bytes .../contrib/spyne/test/interop/__init__.py | 0 .../contrib/spyne/test/interop/__init__.pyc | Bin 0 -> 176 bytes .../test/interop/_test_soap_client_base.py | 283 +++ .../test/interop/_test_soap_client_base.pyc | Bin 0 -> 10364 bytes .../spyne/test/interop/server/__init__.py | 29 + .../spyne/test/interop/server/__init__.pyc | Bin 0 -> 555 bytes .../spyne/test/interop/server/_service.py | 394 ++++ .../spyne/test/interop/server/_service.pyc | Bin 0 -> 20145 bytes .../test/interop/server/httprpc_csv_basic.py | 57 + .../test/interop/server/httprpc_csv_basic.pyc | Bin 0 -> 1601 bytes .../test/interop/server/httprpc_pod_basic.py | 61 + .../test/interop/server/httprpc_pod_basic.pyc | Bin 0 -> 1782 bytes .../server/httprpc_pod_basic_twisted.py | 61 + .../server/httprpc_pod_basic_twisted.pyc | Bin 0 -> 1887 bytes .../interop/server/msgpackrpc_http_basic.py | 56 + .../interop/server/msgpackrpc_http_basic.pyc | Bin 0 -> 1810 bytes .../test/interop/server/soap11/__init__.py | 0 .../test/interop/server/soap11/__init__.pyc | Bin 0 -> 190 bytes .../server/soap11/httprpc_soap_basic.py | 56 + .../server/soap11/httprpc_soap_basic.pyc | Bin 0 -> 1548 bytes .../interop/server/soap11/soap_http_basic.py | 62 + .../interop/server/soap11/soap_http_basic.pyc | Bin 0 -> 1837 bytes .../server/soap11/soap_http_basic_twisted.py | 54 + .../server/soap11/soap_http_basic_twisted.pyc | Bin 0 -> 1584 bytes .../interop/server/soap11/soap_http_static.py | 67 + .../server/soap11/soap_http_static.pyc | Bin 0 -> 1928 bytes .../test/interop/server/soap11/soap_zeromq.py | 52 + .../interop/server/soap11/soap_zeromq.pyc | Bin 0 -> 1391 bytes .../test/interop/server/soap12/__init__.py | 0 .../test/interop/server/soap12/__init__.pyc | Bin 0 -> 190 bytes .../server/soap12/httprpc_soap_basic.py | 50 + .../server/soap12/httprpc_soap_basic.pyc | Bin 0 -> 1441 bytes .../interop/server/soap12/soap_http_basic.py | 55 + .../interop/server/soap12/soap_http_basic.pyc | Bin 0 -> 1725 bytes .../server/soap12/soap_http_basic_twisted.py | 49 + .../server/soap12/soap_http_basic_twisted.pyc | Bin 0 -> 1458 bytes .../interop/server/soap12/soap_http_static.py | 62 + .../server/soap12/soap_http_static.pyc | Bin 0 -> 1806 bytes .../test/interop/server/soap12/soap_zeromq.py | 46 + .../interop/server/soap12/soap_zeromq.pyc | Bin 0 -> 1262 bytes .../contrib/spyne/test/interop/test_django.py | 305 +++ .../spyne/test/interop/test_django.pyc | Bin 0 -> 18325 bytes .../spyne/test/interop/test_httprpc.py | 119 ++ .../spyne/test/interop/test_httprpc.pyc | Bin 0 -> 4609 bytes .../interop/test_msgpackrpc_client_http.py | 45 + .../interop/test_msgpackrpc_client_http.pyc | Bin 0 -> 1851 bytes .../spyne/test/interop/test_pyramid.py | 76 + .../spyne/test/interop/test_pyramid.pyc | Bin 0 -> 3404 bytes .../test/interop/test_soap_client_http.py | 39 + .../test/interop/test_soap_client_http.pyc | Bin 0 -> 1248 bytes .../interop/test_soap_client_http_twisted.py | 70 + .../interop/test_soap_client_http_twisted.pyc | Bin 0 -> 4263 bytes .../test/interop/test_soap_client_zeromq.py | 41 + .../test/interop/test_soap_client_zeromq.pyc | Bin 0 -> 1266 bytes .../contrib/spyne/test/interop/test_suds.py | 428 +++++ .../contrib/spyne/test/interop/test_suds.pyc | Bin 0 -> 17174 bytes .../contrib/spyne/test/interop/test_wsi.py | 161 ++ .../contrib/spyne/test/interop/test_wsi.pyc | Bin 0 -> 6033 bytes .../contrib/spyne/test/interop/test_zeep.py | 380 ++++ .../contrib/spyne/test/interop/test_zeep.pyc | Bin 0 -> 16230 bytes .../contrib/spyne/test/model/__init__.py | 18 + .../contrib/spyne/test/model/__init__.pyc | Bin 0 -> 174 bytes .../contrib/spyne/test/model/test_binary.py | 46 + .../contrib/spyne/test/model/test_binary.pyc | Bin 0 -> 1643 bytes .../contrib/spyne/test/model/test_complex.py | 1146 ++++++++++++ .../contrib/spyne/test/model/test_complex.pyc | Bin 0 -> 60965 bytes .../contrib/spyne/test/model/test_enum.py | 166 ++ .../contrib/spyne/test/model/test_enum.pyc | Bin 0 -> 5581 bytes .../spyne/test/model/test_exception.py | 200 ++ .../spyne/test/model/test_exception.pyc | Bin 0 -> 9040 bytes .../spyne/test/model/test_primitive.py | 978 ++++++++++ .../spyne/test/model/test_primitive.pyc | Bin 0 -> 41096 bytes .../spyne/test/multipython/__init__.py | 0 .../spyne/test/multipython/__init__.pyc | Bin 0 -> 180 bytes .../spyne/test/multipython/model/__init__.py | 0 .../spyne/test/multipython/model/__init__.pyc | Bin 0 -> 186 bytes .../test/multipython/model/test_complex.py | 179 ++ .../test/multipython/model/test_complex.pyc | Bin 0 -> 10511 bytes .../contrib/spyne/test/protocol/__init__.py | 24 + .../contrib/spyne/test/protocol/__init__.pyc | Bin 0 -> 353 bytes .../spyne/test/protocol/_test_dictdoc.py | 1381 ++++++++++++++ .../spyne/test/protocol/_test_dictdoc.pyc | Bin 0 -> 71973 bytes .../contrib/spyne/test/protocol/test_cloth.py | 570 ++++++ .../spyne/test/protocol/test_cloth.pyc | Bin 0 -> 26692 bytes .../test/protocol/test_html_microformat.py | 300 +++ .../test/protocol/test_html_microformat.pyc | Bin 0 -> 11692 bytes .../spyne/test/protocol/test_html_table.py | 508 +++++ .../spyne/test/protocol/test_html_table.pyc | Bin 0 -> 20634 bytes .../contrib/spyne/test/protocol/test_http.py | 867 +++++++++ .../contrib/spyne/test/protocol/test_http.pyc | Bin 0 -> 46785 bytes .../contrib/spyne/test/protocol/test_json.py | 212 +++ .../contrib/spyne/test/protocol/test_json.pyc | Bin 0 -> 10904 bytes .../spyne/test/protocol/test_msgpack.py | 146 ++ .../spyne/test/protocol/test_msgpack.pyc | Bin 0 -> 5428 bytes .../spyne/test/protocol/test_soap11.py | 500 +++++ .../spyne/test/protocol/test_soap11.pyc | Bin 0 -> 21870 bytes .../spyne/test/protocol/test_soap12.py | 297 +++ .../spyne/test/protocol/test_soap12.pyc | Bin 0 -> 14391 bytes .../contrib/spyne/test/protocol/test_xml.py | 628 +++++++ .../contrib/spyne/test/protocol/test_xml.pyc | Bin 0 -> 28139 bytes .../contrib/spyne/test/protocol/test_yaml.py | 58 + .../contrib/spyne/test/protocol/test_yaml.pyc | Bin 0 -> 2123 bytes .../contrib/spyne/test/regen_wsdl.py | 26 + .../contrib/spyne/test/regen_wsdl.pyc | Bin 0 -> 1228 bytes pym/calculate/contrib/spyne/test/sort_wsdl.py | 104 ++ .../contrib/spyne/test/sort_wsdl.pyc | Bin 0 -> 3412 bytes .../contrib/spyne/test/test_null_server.py | 134 ++ .../contrib/spyne/test/test_null_server.pyc | Bin 0 -> 5755 bytes .../contrib/spyne/test/test_service.py | 511 ++++++ .../contrib/spyne/test/test_service.pyc | Bin 0 -> 25350 bytes .../spyne/test/test_soft_validation.py | 179 ++ .../spyne/test/test_soft_validation.pyc | Bin 0 -> 8120 bytes .../contrib/spyne/test/test_sqlalchemy.py | 1302 +++++++++++++ .../contrib/spyne/test/test_sqlalchemy.pyc | Bin 0 -> 57549 bytes .../spyne/test/test_sqlalchemy_deprecated.py | 380 ++++ .../spyne/test/test_sqlalchemy_deprecated.pyc | Bin 0 -> 17731 bytes .../contrib/spyne/test/transport/__init__.py | 0 .../contrib/spyne/test/transport/__init__.pyc | Bin 0 -> 178 bytes .../spyne/test/transport/test_msgpack.py | 94 + .../spyne/test/transport/test_msgpack.pyc | Bin 0 -> 4220 bytes .../contrib/spyne/test/util/__init__.py | 0 .../contrib/spyne/test/util/__init__.pyc | Bin 0 -> 173 bytes .../contrib/spyne/test/util/test_address.py | 639 +++++++ .../contrib/spyne/test/util/test_address.pyc | Bin 0 -> 27989 bytes .../contrib/spyne/test/util/test_util.py | 601 ++++++ .../contrib/spyne/test/util/test_util.pyc | Bin 0 -> 27058 bytes pym/calculate/contrib/spyne/util/__init__.py | 112 ++ pym/calculate/contrib/spyne/util/__init__.pyc | Bin 0 -> 3471 bytes pym/calculate/contrib/spyne/util/_base.py | 44 + pym/calculate/contrib/spyne/util/_base.pyc | Bin 0 -> 1104 bytes .../contrib/spyne/util/_twisted_ws.py | 610 ++++++ .../contrib/spyne/util/_twisted_ws.pyc | Bin 0 -> 18890 bytes pym/calculate/contrib/spyne/util/address.py | 276 +++ pym/calculate/contrib/spyne/util/address.pyc | Bin 0 -> 6410 bytes pym/calculate/contrib/spyne/util/appreg.py | 88 + pym/calculate/contrib/spyne/util/appreg.pyc | Bin 0 -> 2690 bytes pym/calculate/contrib/spyne/util/attrdict.py | 87 + pym/calculate/contrib/spyne/util/attrdict.pyc | Bin 0 -> 4824 bytes pym/calculate/contrib/spyne/util/autorel.py | 258 +++ pym/calculate/contrib/spyne/util/autorel.pyc | Bin 0 -> 6600 bytes pym/calculate/contrib/spyne/util/cdict.py | 85 + pym/calculate/contrib/spyne/util/cdict.pyc | Bin 0 -> 2165 bytes pym/calculate/contrib/spyne/util/cherry.py | 41 + pym/calculate/contrib/spyne/util/cherry.pyc | Bin 0 -> 1191 bytes pym/calculate/contrib/spyne/util/color.py | 74 + pym/calculate/contrib/spyne/util/color.pyc | Bin 0 -> 5556 bytes pym/calculate/contrib/spyne/util/coopmt.py | 102 ++ pym/calculate/contrib/spyne/util/coopmt.pyc | Bin 0 -> 2619 bytes pym/calculate/contrib/spyne/util/dictdoc.py | 214 +++ pym/calculate/contrib/spyne/util/dictdoc.pyc | Bin 0 -> 8216 bytes pym/calculate/contrib/spyne/util/django.py | 538 ++++++ pym/calculate/contrib/spyne/util/django.pyc | Bin 0 -> 19878 bytes pym/calculate/contrib/spyne/util/dyninit.py | 147 ++ pym/calculate/contrib/spyne/util/dyninit.pyc | Bin 0 -> 7929 bytes pym/calculate/contrib/spyne/util/email.py | 129 ++ pym/calculate/contrib/spyne/util/email.pyc | Bin 0 -> 3896 bytes pym/calculate/contrib/spyne/util/etreeconv.py | 131 ++ .../contrib/spyne/util/etreeconv.pyc | Bin 0 -> 3933 bytes pym/calculate/contrib/spyne/util/fileproxy.py | 190 ++ .../contrib/spyne/util/fileproxy.pyc | Bin 0 -> 7704 bytes pym/calculate/contrib/spyne/util/gencpp.py | 254 +++ pym/calculate/contrib/spyne/util/gencpp.pyc | Bin 0 -> 8296 bytes pym/calculate/contrib/spyne/util/http.py | 66 + pym/calculate/contrib/spyne/util/http.pyc | Bin 0 -> 1555 bytes pym/calculate/contrib/spyne/util/invregexp.py | 322 ++++ .../contrib/spyne/util/invregexp.pyc | Bin 0 -> 13040 bytes pym/calculate/contrib/spyne/util/memo.py | 180 ++ pym/calculate/contrib/spyne/util/memo.pyc | Bin 0 -> 6954 bytes pym/calculate/contrib/spyne/util/meta.py | 139 ++ pym/calculate/contrib/spyne/util/meta.pyc | Bin 0 -> 4377 bytes pym/calculate/contrib/spyne/util/odict.py | 134 ++ pym/calculate/contrib/spyne/util/odict.pyc | Bin 0 -> 5798 bytes pym/calculate/contrib/spyne/util/oset.py | 96 + pym/calculate/contrib/spyne/util/oset.pyc | Bin 0 -> 4183 bytes pym/calculate/contrib/spyne/util/protocol.py | 38 + pym/calculate/contrib/spyne/util/protocol.pyc | Bin 0 -> 908 bytes pym/calculate/contrib/spyne/util/resource.py | 72 + pym/calculate/contrib/spyne/util/resource.pyc | Bin 0 -> 2396 bytes pym/calculate/contrib/spyne/util/simple.py | 57 + pym/calculate/contrib/spyne/util/simple.pyc | Bin 0 -> 1603 bytes pym/calculate/contrib/spyne/util/six.py | 985 ++++++++++ pym/calculate/contrib/spyne/util/six.pyc | Bin 0 -> 36324 bytes pym/calculate/contrib/spyne/util/tdict.py | 101 + pym/calculate/contrib/spyne/util/tdict.pyc | Bin 0 -> 3947 bytes pym/calculate/contrib/spyne/util/test.py | 97 + pym/calculate/contrib/spyne/util/test.pyc | Bin 0 -> 2735 bytes pym/calculate/contrib/spyne/util/tlist.py | 103 ++ pym/calculate/contrib/spyne/util/tlist.pyc | Bin 0 -> 3776 bytes pym/calculate/contrib/spyne/util/toposort.py | 54 + pym/calculate/contrib/spyne/util/toposort.pyc | Bin 0 -> 1506 bytes pym/calculate/contrib/spyne/util/web.py | 354 ++++ pym/calculate/contrib/spyne/util/web.pyc | Bin 0 -> 9357 bytes .../contrib/spyne/util/wsgi_wrapper.py | 126 ++ .../contrib/spyne/util/wsgi_wrapper.pyc | Bin 0 -> 4402 bytes pym/calculate/contrib/spyne/util/xml.py | 309 ++++ pym/calculate/contrib/spyne/util/xml.pyc | Bin 0 -> 11575 bytes pym/calculate/contrib/suds/__init__.py | 164 ++ pym/calculate/contrib/suds/__init__.pyc | Bin 0 -> 6327 bytes pym/calculate/contrib/suds/argparser.py | 419 +++++ pym/calculate/contrib/suds/argparser.pyc | Bin 0 -> 17516 bytes .../contrib/suds/bindings/__init__.py | 18 + .../contrib/suds/bindings/__init__.pyc | Bin 0 -> 242 bytes .../contrib/suds/bindings/binding.py | 510 ++++++ .../contrib/suds/bindings/binding.pyc | Bin 0 -> 17731 bytes .../contrib/suds/bindings/document.py | 143 ++ .../contrib/suds/bindings/document.pyc | Bin 0 -> 5307 bytes .../contrib/suds/bindings/multiref.py | 124 ++ .../contrib/suds/bindings/multiref.pyc | Bin 0 -> 4288 bytes pym/calculate/contrib/suds/bindings/rpc.py | 91 + pym/calculate/contrib/suds/bindings/rpc.pyc | Bin 0 -> 3419 bytes pym/calculate/contrib/suds/builder.py | 122 ++ pym/calculate/contrib/suds/builder.pyc | Bin 0 -> 3552 bytes pym/calculate/contrib/suds/cache.py | 334 ++++ pym/calculate/contrib/suds/cache.pyc | Bin 0 -> 11326 bytes pym/calculate/contrib/suds/client.py | 950 ++++++++++ pym/calculate/contrib/suds/client.pyc | Bin 0 -> 33062 bytes pym/calculate/contrib/suds/metrics.py | 63 + pym/calculate/contrib/suds/metrics.pyc | Bin 0 -> 2073 bytes pym/calculate/contrib/suds/mx/__init__.py | 60 + pym/calculate/contrib/suds/mx/__init__.pyc | Bin 0 -> 1524 bytes pym/calculate/contrib/suds/mx/appender.py | 282 +++ pym/calculate/contrib/suds/mx/appender.pyc | Bin 0 -> 10901 bytes pym/calculate/contrib/suds/mx/basic.py | 45 + pym/calculate/contrib/suds/mx/basic.pyc | Bin 0 -> 1239 bytes pym/calculate/contrib/suds/mx/core.py | 150 ++ pym/calculate/contrib/suds/mx/core.pyc | Bin 0 -> 5252 bytes pym/calculate/contrib/suds/mx/encoded.py | 131 ++ pym/calculate/contrib/suds/mx/encoded.pyc | Bin 0 -> 3691 bytes pym/calculate/contrib/suds/mx/literal.py | 311 ++++ pym/calculate/contrib/suds/mx/literal.pyc | Bin 0 -> 9850 bytes pym/calculate/contrib/suds/mx/typer.py | 126 ++ pym/calculate/contrib/suds/mx/typer.pyc | Bin 0 -> 3819 bytes pym/calculate/contrib/suds/options.py | 162 ++ pym/calculate/contrib/suds/options.pyc | Bin 0 -> 6864 bytes pym/calculate/contrib/suds/plugin.py | 276 +++ pym/calculate/contrib/suds/plugin.pyc | Bin 0 -> 9198 bytes pym/calculate/contrib/suds/properties.py | 539 ++++++ pym/calculate/contrib/suds/properties.pyc | Bin 0 -> 19774 bytes pym/calculate/contrib/suds/reader.py | 197 ++ pym/calculate/contrib/suds/reader.pyc | Bin 0 -> 6158 bytes pym/calculate/contrib/suds/resolver.py | 493 +++++ pym/calculate/contrib/suds/resolver.pyc | Bin 0 -> 17810 bytes pym/calculate/contrib/suds/sax/__init__.py | 104 ++ pym/calculate/contrib/suds/sax/__init__.pyc | Bin 0 -> 3656 bytes pym/calculate/contrib/suds/sax/attribute.py | 173 ++ pym/calculate/contrib/suds/sax/attribute.pyc | Bin 0 -> 5750 bytes pym/calculate/contrib/suds/sax/date.py | 460 +++++ pym/calculate/contrib/suds/sax/date.pyc | Bin 0 -> 15213 bytes pym/calculate/contrib/suds/sax/document.py | 176 ++ pym/calculate/contrib/suds/sax/document.pyc | Bin 0 -> 5689 bytes pym/calculate/contrib/suds/sax/element.py | 1205 ++++++++++++ pym/calculate/contrib/suds/sax/element.pyc | Bin 0 -> 38445 bytes pym/calculate/contrib/suds/sax/enc.py | 94 + pym/calculate/contrib/suds/sax/enc.pyc | Bin 0 -> 2699 bytes pym/calculate/contrib/suds/sax/parser.py | 137 ++ pym/calculate/contrib/suds/sax/parser.pyc | Bin 0 -> 4904 bytes pym/calculate/contrib/suds/sax/text.py | 116 ++ pym/calculate/contrib/suds/sax/text.pyc | Bin 0 -> 4249 bytes .../contrib/suds/servicedefinition.py | 246 +++ .../contrib/suds/servicedefinition.pyc | Bin 0 -> 9322 bytes pym/calculate/contrib/suds/serviceproxy.py | 80 + pym/calculate/contrib/suds/serviceproxy.pyc | Bin 0 -> 2896 bytes pym/calculate/contrib/suds/soaparray.py | 71 + pym/calculate/contrib/suds/soaparray.pyc | Bin 0 -> 2085 bytes pym/calculate/contrib/suds/store.py | 600 ++++++ pym/calculate/contrib/suds/store.pyc | Bin 0 -> 18861 bytes pym/calculate/contrib/suds/sudsobject.py | 391 ++++ pym/calculate/contrib/suds/sudsobject.pyc | Bin 0 -> 13696 bytes .../contrib/suds/transport/__init__.py | 166 ++ .../contrib/suds/transport/__init__.pyc | Bin 0 -> 6195 bytes pym/calculate/contrib/suds/transport/http.py | 249 +++ pym/calculate/contrib/suds/transport/http.pyc | Bin 0 -> 9227 bytes pym/calculate/contrib/suds/transport/https.py | 99 + .../contrib/suds/transport/https.pyc | Bin 0 -> 3749 bytes .../contrib/suds/transport/options.py | 58 + .../contrib/suds/transport/options.pyc | Bin 0 -> 1798 bytes pym/calculate/contrib/suds/umx/__init__.py | 56 + pym/calculate/contrib/suds/umx/__init__.pyc | Bin 0 -> 1450 bytes pym/calculate/contrib/suds/umx/attrlist.py | 88 + pym/calculate/contrib/suds/umx/attrlist.pyc | Bin 0 -> 2806 bytes pym/calculate/contrib/suds/umx/basic.py | 41 + pym/calculate/contrib/suds/umx/basic.pyc | Bin 0 -> 1047 bytes pym/calculate/contrib/suds/umx/core.py | 214 +++ pym/calculate/contrib/suds/umx/core.pyc | Bin 0 -> 7750 bytes pym/calculate/contrib/suds/umx/encoded.py | 126 ++ pym/calculate/contrib/suds/umx/encoded.pyc | Bin 0 -> 3772 bytes pym/calculate/contrib/suds/umx/typed.py | 140 ++ pym/calculate/contrib/suds/umx/typed.pyc | Bin 0 -> 4758 bytes pym/calculate/contrib/suds/version.py | 26 + pym/calculate/contrib/suds/version.pyc | Bin 0 -> 486 bytes pym/calculate/contrib/suds/wsdl.py | 1005 ++++++++++ pym/calculate/contrib/suds/wsdl.pyc | Bin 0 -> 33180 bytes pym/calculate/contrib/suds/wsse.py | 236 +++ pym/calculate/contrib/suds/wsse.pyc | Bin 0 -> 8342 bytes pym/calculate/contrib/suds/xsd/__init__.py | 75 + pym/calculate/contrib/suds/xsd/__init__.pyc | Bin 0 -> 2412 bytes pym/calculate/contrib/suds/xsd/depsort.py | 71 + pym/calculate/contrib/suds/xsd/depsort.pyc | Bin 0 -> 2057 bytes pym/calculate/contrib/suds/xsd/doctor.py | 223 +++ pym/calculate/contrib/suds/xsd/doctor.pyc | Bin 0 -> 7780 bytes pym/calculate/contrib/suds/xsd/query.py | 208 +++ pym/calculate/contrib/suds/xsd/query.pyc | Bin 0 -> 7584 bytes pym/calculate/contrib/suds/xsd/schema.py | 464 +++++ pym/calculate/contrib/suds/xsd/schema.pyc | Bin 0 -> 15024 bytes pym/calculate/contrib/suds/xsd/sxbase.py | 748 ++++++++ pym/calculate/contrib/suds/xsd/sxbase.pyc | Bin 0 -> 24709 bytes pym/calculate/contrib/suds/xsd/sxbasic.py | 862 +++++++++ pym/calculate/contrib/suds/xsd/sxbasic.pyc | Bin 0 -> 33301 bytes pym/calculate/contrib/suds/xsd/sxbuiltin.py | 347 ++++ pym/calculate/contrib/suds/xsd/sxbuiltin.pyc | Bin 0 -> 11531 bytes 542 files changed, 67248 insertions(+) create mode 100644 pym/calculate/contrib/spyne/__init__.py create mode 100644 pym/calculate/contrib/spyne/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/_base.py create mode 100644 pym/calculate/contrib/spyne/_base.pyc create mode 100644 pym/calculate/contrib/spyne/application.py create mode 100644 pym/calculate/contrib/spyne/application.pyc create mode 100644 pym/calculate/contrib/spyne/auxproc/__init__.py create mode 100644 pym/calculate/contrib/spyne/auxproc/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/auxproc/_base.py create mode 100644 pym/calculate/contrib/spyne/auxproc/_base.pyc create mode 100644 pym/calculate/contrib/spyne/auxproc/sync.py create mode 100644 pym/calculate/contrib/spyne/auxproc/sync.pyc create mode 100644 pym/calculate/contrib/spyne/auxproc/thread.py create mode 100644 pym/calculate/contrib/spyne/auxproc/thread.pyc create mode 100644 pym/calculate/contrib/spyne/client/__init__.py create mode 100644 pym/calculate/contrib/spyne/client/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/client/_base.py create mode 100644 pym/calculate/contrib/spyne/client/_base.pyc create mode 100644 pym/calculate/contrib/spyne/client/django.py create mode 100644 pym/calculate/contrib/spyne/client/django.pyc create mode 100644 pym/calculate/contrib/spyne/client/http.py create mode 100644 pym/calculate/contrib/spyne/client/http.pyc create mode 100644 pym/calculate/contrib/spyne/client/twisted/__init__.py create mode 100644 pym/calculate/contrib/spyne/client/twisted/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/client/zeromq.py create mode 100644 pym/calculate/contrib/spyne/client/zeromq.pyc create mode 100644 pym/calculate/contrib/spyne/const/__init__.py create mode 100644 pym/calculate/contrib/spyne/const/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/const/ansi_color.py create mode 100644 pym/calculate/contrib/spyne/const/ansi_color.pyc create mode 100644 pym/calculate/contrib/spyne/const/http.py create mode 100644 pym/calculate/contrib/spyne/const/http.pyc create mode 100644 pym/calculate/contrib/spyne/const/xml.py create mode 100644 pym/calculate/contrib/spyne/const/xml.pyc create mode 100644 pym/calculate/contrib/spyne/const/xml_ns.py create mode 100644 pym/calculate/contrib/spyne/const/xml_ns.pyc create mode 100644 pym/calculate/contrib/spyne/context.py create mode 100644 pym/calculate/contrib/spyne/context.pyc create mode 100644 pym/calculate/contrib/spyne/decorator.py create mode 100644 pym/calculate/contrib/spyne/decorator.pyc create mode 100644 pym/calculate/contrib/spyne/descriptor.py create mode 100644 pym/calculate/contrib/spyne/descriptor.pyc create mode 100644 pym/calculate/contrib/spyne/error.py create mode 100644 pym/calculate/contrib/spyne/error.pyc create mode 100644 pym/calculate/contrib/spyne/evmgr.py create mode 100644 pym/calculate/contrib/spyne/evmgr.pyc create mode 100644 pym/calculate/contrib/spyne/interface/__init__.py create mode 100644 pym/calculate/contrib/spyne/interface/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/interface/_base.py create mode 100644 pym/calculate/contrib/spyne/interface/_base.pyc create mode 100644 pym/calculate/contrib/spyne/interface/wsdl/__init__.py create mode 100644 pym/calculate/contrib/spyne/interface/wsdl/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/interface/wsdl/defn.py create mode 100644 pym/calculate/contrib/spyne/interface/wsdl/defn.pyc create mode 100644 pym/calculate/contrib/spyne/interface/wsdl/wsdl11.py create mode 100644 pym/calculate/contrib/spyne/interface/wsdl/wsdl11.pyc create mode 100644 pym/calculate/contrib/spyne/interface/xml_schema/__init__.py create mode 100644 pym/calculate/contrib/spyne/interface/xml_schema/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/interface/xml_schema/_base.py create mode 100644 pym/calculate/contrib/spyne/interface/xml_schema/_base.pyc create mode 100644 pym/calculate/contrib/spyne/interface/xml_schema/defn.py create mode 100644 pym/calculate/contrib/spyne/interface/xml_schema/defn.pyc create mode 100644 pym/calculate/contrib/spyne/interface/xml_schema/genpy.py create mode 100644 pym/calculate/contrib/spyne/interface/xml_schema/genpy.pyc create mode 100644 pym/calculate/contrib/spyne/interface/xml_schema/model.py create mode 100644 pym/calculate/contrib/spyne/interface/xml_schema/model.pyc create mode 100644 pym/calculate/contrib/spyne/interface/xml_schema/parser.py create mode 100644 pym/calculate/contrib/spyne/interface/xml_schema/parser.pyc create mode 100644 pym/calculate/contrib/spyne/model/__init__.py create mode 100644 pym/calculate/contrib/spyne/model/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/model/_base.py create mode 100644 pym/calculate/contrib/spyne/model/_base.pyc create mode 100644 pym/calculate/contrib/spyne/model/addtl.py create mode 100644 pym/calculate/contrib/spyne/model/addtl.pyc create mode 100644 pym/calculate/contrib/spyne/model/binary.py create mode 100644 pym/calculate/contrib/spyne/model/binary.pyc create mode 100644 pym/calculate/contrib/spyne/model/complex.py create mode 100644 pym/calculate/contrib/spyne/model/complex.pyc create mode 100644 pym/calculate/contrib/spyne/model/enum.py create mode 100644 pym/calculate/contrib/spyne/model/enum.pyc create mode 100644 pym/calculate/contrib/spyne/model/fault.py create mode 100644 pym/calculate/contrib/spyne/model/fault.pyc create mode 100644 pym/calculate/contrib/spyne/model/primitive/__init__.py create mode 100644 pym/calculate/contrib/spyne/model/primitive/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/model/primitive/_base.py create mode 100644 pym/calculate/contrib/spyne/model/primitive/_base.pyc create mode 100644 pym/calculate/contrib/spyne/model/primitive/datetime.py create mode 100644 pym/calculate/contrib/spyne/model/primitive/datetime.pyc create mode 100644 pym/calculate/contrib/spyne/model/primitive/network.py create mode 100644 pym/calculate/contrib/spyne/model/primitive/network.pyc create mode 100644 pym/calculate/contrib/spyne/model/primitive/number.py create mode 100644 pym/calculate/contrib/spyne/model/primitive/number.pyc create mode 100644 pym/calculate/contrib/spyne/model/primitive/spatial.py create mode 100644 pym/calculate/contrib/spyne/model/primitive/spatial.pyc create mode 100644 pym/calculate/contrib/spyne/model/primitive/string.py create mode 100644 pym/calculate/contrib/spyne/model/primitive/string.pyc create mode 100644 pym/calculate/contrib/spyne/model/primitive/xml.py create mode 100644 pym/calculate/contrib/spyne/model/primitive/xml.pyc create mode 100644 pym/calculate/contrib/spyne/model/relational.py create mode 100644 pym/calculate/contrib/spyne/model/relational.pyc create mode 100644 pym/calculate/contrib/spyne/model/table.py create mode 100644 pym/calculate/contrib/spyne/model/table.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/__init__.py create mode 100644 pym/calculate/contrib/spyne/protocol/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/_base.py create mode 100644 pym/calculate/contrib/spyne/protocol/_base.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/_inbase.py create mode 100644 pym/calculate/contrib/spyne/protocol/_inbase.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/_outbase.py create mode 100644 pym/calculate/contrib/spyne/protocol/_outbase.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/cloth/__init__.py create mode 100644 pym/calculate/contrib/spyne/protocol/cloth/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/cloth/_base.py create mode 100644 pym/calculate/contrib/spyne/protocol/cloth/_base.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/cloth/to_cloth.py create mode 100644 pym/calculate/contrib/spyne/protocol/cloth/to_cloth.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/cloth/to_parent.py create mode 100644 pym/calculate/contrib/spyne/protocol/cloth/to_parent.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/csv.py create mode 100644 pym/calculate/contrib/spyne/protocol/csv.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/dictdoc/__init__.py create mode 100644 pym/calculate/contrib/spyne/protocol/dictdoc/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/dictdoc/_base.py create mode 100644 pym/calculate/contrib/spyne/protocol/dictdoc/_base.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/dictdoc/hier.py create mode 100644 pym/calculate/contrib/spyne/protocol/dictdoc/hier.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/dictdoc/simple.py create mode 100644 pym/calculate/contrib/spyne/protocol/dictdoc/simple.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/html/__init__.py create mode 100644 pym/calculate/contrib/spyne/protocol/html/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/html/_base.py create mode 100644 pym/calculate/contrib/spyne/protocol/html/_base.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/html/addtl.py create mode 100644 pym/calculate/contrib/spyne/protocol/html/addtl.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/html/microformat.py create mode 100644 pym/calculate/contrib/spyne/protocol/html/microformat.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/html/table/__init__.py create mode 100644 pym/calculate/contrib/spyne/protocol/html/table/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/html/table/_base.py create mode 100644 pym/calculate/contrib/spyne/protocol/html/table/_base.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/html/table/column.py create mode 100644 pym/calculate/contrib/spyne/protocol/html/table/column.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/html/table/row.py create mode 100644 pym/calculate/contrib/spyne/protocol/html/table/row.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/http.py create mode 100644 pym/calculate/contrib/spyne/protocol/http.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/json.py create mode 100644 pym/calculate/contrib/spyne/protocol/json.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/msgpack.py create mode 100644 pym/calculate/contrib/spyne/protocol/msgpack.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/soap/__init__.py create mode 100644 pym/calculate/contrib/spyne/protocol/soap/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/soap/mime.py create mode 100644 pym/calculate/contrib/spyne/protocol/soap/mime.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/soap/soap11.py create mode 100644 pym/calculate/contrib/spyne/protocol/soap/soap11.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/soap/soap12.py create mode 100644 pym/calculate/contrib/spyne/protocol/soap/soap12.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/xml.py create mode 100644 pym/calculate/contrib/spyne/protocol/xml.pyc create mode 100644 pym/calculate/contrib/spyne/protocol/yaml.py create mode 100644 pym/calculate/contrib/spyne/protocol/yaml.pyc create mode 100644 pym/calculate/contrib/spyne/server/__init__.py create mode 100644 pym/calculate/contrib/spyne/server/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/server/_base.py create mode 100644 pym/calculate/contrib/spyne/server/_base.pyc create mode 100644 pym/calculate/contrib/spyne/server/django.py create mode 100644 pym/calculate/contrib/spyne/server/django.pyc create mode 100644 pym/calculate/contrib/spyne/server/http.py create mode 100644 pym/calculate/contrib/spyne/server/http.pyc create mode 100644 pym/calculate/contrib/spyne/server/msgpack.py create mode 100644 pym/calculate/contrib/spyne/server/msgpack.pyc create mode 100644 pym/calculate/contrib/spyne/server/null.py create mode 100644 pym/calculate/contrib/spyne/server/null.pyc create mode 100644 pym/calculate/contrib/spyne/server/pyramid.py create mode 100644 pym/calculate/contrib/spyne/server/pyramid.pyc create mode 100644 pym/calculate/contrib/spyne/server/twisted/__init__.py create mode 100644 pym/calculate/contrib/spyne/server/twisted/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/server/twisted/_base.py create mode 100644 pym/calculate/contrib/spyne/server/twisted/_base.pyc create mode 100644 pym/calculate/contrib/spyne/server/twisted/http.py create mode 100644 pym/calculate/contrib/spyne/server/twisted/http.pyc create mode 100644 pym/calculate/contrib/spyne/server/twisted/msgpack.py create mode 100644 pym/calculate/contrib/spyne/server/twisted/msgpack.pyc create mode 100644 pym/calculate/contrib/spyne/server/twisted/websocket.py create mode 100644 pym/calculate/contrib/spyne/server/twisted/websocket.pyc create mode 100644 pym/calculate/contrib/spyne/server/wsgi.py create mode 100644 pym/calculate/contrib/spyne/server/wsgi.pyc create mode 100644 pym/calculate/contrib/spyne/server/zeromq.py create mode 100644 pym/calculate/contrib/spyne/server/zeromq.pyc create mode 100644 pym/calculate/contrib/spyne/service.py create mode 100644 pym/calculate/contrib/spyne/service.pyc create mode 100644 pym/calculate/contrib/spyne/store/__init__.py create mode 100644 pym/calculate/contrib/spyne/store/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/store/relational/__init__.py create mode 100644 pym/calculate/contrib/spyne/store/relational/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/store/relational/_base.py create mode 100644 pym/calculate/contrib/spyne/store/relational/_base.pyc create mode 100644 pym/calculate/contrib/spyne/store/relational/document.py create mode 100644 pym/calculate/contrib/spyne/store/relational/document.pyc create mode 100644 pym/calculate/contrib/spyne/store/relational/override.py create mode 100644 pym/calculate/contrib/spyne/store/relational/override.pyc create mode 100644 pym/calculate/contrib/spyne/store/relational/simple.py create mode 100644 pym/calculate/contrib/spyne/store/relational/simple.pyc create mode 100644 pym/calculate/contrib/spyne/store/relational/spatial.py create mode 100644 pym/calculate/contrib/spyne/store/relational/spatial.pyc create mode 100644 pym/calculate/contrib/spyne/store/relational/util.py create mode 100644 pym/calculate/contrib/spyne/store/relational/util.pyc create mode 100644 pym/calculate/contrib/spyne/test/__init__.py create mode 100644 pym/calculate/contrib/spyne/test/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/test/interface/__init__.py create mode 100644 pym/calculate/contrib/spyne/test/interface/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/test/interface/test_interface.py create mode 100644 pym/calculate/contrib/spyne/test/interface/test_interface.pyc create mode 100644 pym/calculate/contrib/spyne/test/interface/test_wsgi.py create mode 100644 pym/calculate/contrib/spyne/test/interface/test_wsgi.pyc create mode 100644 pym/calculate/contrib/spyne/test/interface/test_xml_schema.py create mode 100644 pym/calculate/contrib/spyne/test/interface/test_xml_schema.pyc create mode 100644 pym/calculate/contrib/spyne/test/interface/wsdl/__init__.py create mode 100644 pym/calculate/contrib/spyne/test/interface/wsdl/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/test/interface/wsdl/defult_services.py create mode 100644 pym/calculate/contrib/spyne/test/interface/wsdl/defult_services.pyc create mode 100644 pym/calculate/contrib/spyne/test/interface/wsdl/port_service_services.py create mode 100644 pym/calculate/contrib/spyne/test/interface/wsdl/port_service_services.pyc create mode 100644 pym/calculate/contrib/spyne/test/interface/wsdl/test_bindings.py create mode 100644 pym/calculate/contrib/spyne/test/interface/wsdl/test_bindings.pyc create mode 100644 pym/calculate/contrib/spyne/test/interface/wsdl/test_default_wsdl.py create mode 100644 pym/calculate/contrib/spyne/test/interface/wsdl/test_default_wsdl.pyc create mode 100644 pym/calculate/contrib/spyne/test/interface/wsdl/test_op_req_suffix.py create mode 100644 pym/calculate/contrib/spyne/test/interface/wsdl/test_op_req_suffix.pyc create mode 100644 pym/calculate/contrib/spyne/test/interface/wsdl/test_wsdl_ports_services.py create mode 100644 pym/calculate/contrib/spyne/test/interface/wsdl/test_wsdl_ports_services.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/__init__.py create mode 100644 pym/calculate/contrib/spyne/test/interop/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/_test_soap_client_base.py create mode 100644 pym/calculate/contrib/spyne/test/interop/_test_soap_client_base.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/__init__.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/_service.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/_service.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/httprpc_csv_basic.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/httprpc_csv_basic.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/httprpc_pod_basic.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/httprpc_pod_basic.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/httprpc_pod_basic_twisted.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/httprpc_pod_basic_twisted.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/msgpackrpc_http_basic.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/msgpackrpc_http_basic.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap11/__init__.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap11/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap11/httprpc_soap_basic.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap11/httprpc_soap_basic.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap11/soap_http_basic.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap11/soap_http_basic.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap11/soap_http_basic_twisted.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap11/soap_http_basic_twisted.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap11/soap_http_static.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap11/soap_http_static.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap11/soap_zeromq.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap11/soap_zeromq.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap12/__init__.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap12/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap12/httprpc_soap_basic.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap12/httprpc_soap_basic.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_basic.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_basic.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_basic_twisted.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_basic_twisted.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_static.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_static.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap12/soap_zeromq.py create mode 100644 pym/calculate/contrib/spyne/test/interop/server/soap12/soap_zeromq.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/test_django.py create mode 100644 pym/calculate/contrib/spyne/test/interop/test_django.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/test_httprpc.py create mode 100644 pym/calculate/contrib/spyne/test/interop/test_httprpc.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/test_msgpackrpc_client_http.py create mode 100644 pym/calculate/contrib/spyne/test/interop/test_msgpackrpc_client_http.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/test_pyramid.py create mode 100644 pym/calculate/contrib/spyne/test/interop/test_pyramid.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/test_soap_client_http.py create mode 100644 pym/calculate/contrib/spyne/test/interop/test_soap_client_http.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/test_soap_client_http_twisted.py create mode 100644 pym/calculate/contrib/spyne/test/interop/test_soap_client_http_twisted.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/test_soap_client_zeromq.py create mode 100644 pym/calculate/contrib/spyne/test/interop/test_soap_client_zeromq.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/test_suds.py create mode 100644 pym/calculate/contrib/spyne/test/interop/test_suds.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/test_wsi.py create mode 100644 pym/calculate/contrib/spyne/test/interop/test_wsi.pyc create mode 100644 pym/calculate/contrib/spyne/test/interop/test_zeep.py create mode 100644 pym/calculate/contrib/spyne/test/interop/test_zeep.pyc create mode 100644 pym/calculate/contrib/spyne/test/model/__init__.py create mode 100644 pym/calculate/contrib/spyne/test/model/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/test/model/test_binary.py create mode 100644 pym/calculate/contrib/spyne/test/model/test_binary.pyc create mode 100644 pym/calculate/contrib/spyne/test/model/test_complex.py create mode 100644 pym/calculate/contrib/spyne/test/model/test_complex.pyc create mode 100644 pym/calculate/contrib/spyne/test/model/test_enum.py create mode 100644 pym/calculate/contrib/spyne/test/model/test_enum.pyc create mode 100644 pym/calculate/contrib/spyne/test/model/test_exception.py create mode 100644 pym/calculate/contrib/spyne/test/model/test_exception.pyc create mode 100644 pym/calculate/contrib/spyne/test/model/test_primitive.py create mode 100644 pym/calculate/contrib/spyne/test/model/test_primitive.pyc create mode 100644 pym/calculate/contrib/spyne/test/multipython/__init__.py create mode 100644 pym/calculate/contrib/spyne/test/multipython/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/test/multipython/model/__init__.py create mode 100644 pym/calculate/contrib/spyne/test/multipython/model/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/test/multipython/model/test_complex.py create mode 100644 pym/calculate/contrib/spyne/test/multipython/model/test_complex.pyc create mode 100644 pym/calculate/contrib/spyne/test/protocol/__init__.py create mode 100644 pym/calculate/contrib/spyne/test/protocol/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/test/protocol/_test_dictdoc.py create mode 100644 pym/calculate/contrib/spyne/test/protocol/_test_dictdoc.pyc create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_cloth.py create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_cloth.pyc create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_html_microformat.py create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_html_microformat.pyc create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_html_table.py create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_html_table.pyc create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_http.py create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_http.pyc create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_json.py create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_json.pyc create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_msgpack.py create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_msgpack.pyc create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_soap11.py create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_soap11.pyc create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_soap12.py create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_soap12.pyc create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_xml.py create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_xml.pyc create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_yaml.py create mode 100644 pym/calculate/contrib/spyne/test/protocol/test_yaml.pyc create mode 100644 pym/calculate/contrib/spyne/test/regen_wsdl.py create mode 100644 pym/calculate/contrib/spyne/test/regen_wsdl.pyc create mode 100644 pym/calculate/contrib/spyne/test/sort_wsdl.py create mode 100644 pym/calculate/contrib/spyne/test/sort_wsdl.pyc create mode 100644 pym/calculate/contrib/spyne/test/test_null_server.py create mode 100644 pym/calculate/contrib/spyne/test/test_null_server.pyc create mode 100644 pym/calculate/contrib/spyne/test/test_service.py create mode 100644 pym/calculate/contrib/spyne/test/test_service.pyc create mode 100644 pym/calculate/contrib/spyne/test/test_soft_validation.py create mode 100644 pym/calculate/contrib/spyne/test/test_soft_validation.pyc create mode 100644 pym/calculate/contrib/spyne/test/test_sqlalchemy.py create mode 100644 pym/calculate/contrib/spyne/test/test_sqlalchemy.pyc create mode 100644 pym/calculate/contrib/spyne/test/test_sqlalchemy_deprecated.py create mode 100644 pym/calculate/contrib/spyne/test/test_sqlalchemy_deprecated.pyc create mode 100644 pym/calculate/contrib/spyne/test/transport/__init__.py create mode 100644 pym/calculate/contrib/spyne/test/transport/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/test/transport/test_msgpack.py create mode 100644 pym/calculate/contrib/spyne/test/transport/test_msgpack.pyc create mode 100644 pym/calculate/contrib/spyne/test/util/__init__.py create mode 100644 pym/calculate/contrib/spyne/test/util/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/test/util/test_address.py create mode 100644 pym/calculate/contrib/spyne/test/util/test_address.pyc create mode 100644 pym/calculate/contrib/spyne/test/util/test_util.py create mode 100644 pym/calculate/contrib/spyne/test/util/test_util.pyc create mode 100644 pym/calculate/contrib/spyne/util/__init__.py create mode 100644 pym/calculate/contrib/spyne/util/__init__.pyc create mode 100644 pym/calculate/contrib/spyne/util/_base.py create mode 100644 pym/calculate/contrib/spyne/util/_base.pyc create mode 100644 pym/calculate/contrib/spyne/util/_twisted_ws.py create mode 100644 pym/calculate/contrib/spyne/util/_twisted_ws.pyc create mode 100644 pym/calculate/contrib/spyne/util/address.py create mode 100644 pym/calculate/contrib/spyne/util/address.pyc create mode 100644 pym/calculate/contrib/spyne/util/appreg.py create mode 100644 pym/calculate/contrib/spyne/util/appreg.pyc create mode 100644 pym/calculate/contrib/spyne/util/attrdict.py create mode 100644 pym/calculate/contrib/spyne/util/attrdict.pyc create mode 100644 pym/calculate/contrib/spyne/util/autorel.py create mode 100644 pym/calculate/contrib/spyne/util/autorel.pyc create mode 100644 pym/calculate/contrib/spyne/util/cdict.py create mode 100644 pym/calculate/contrib/spyne/util/cdict.pyc create mode 100644 pym/calculate/contrib/spyne/util/cherry.py create mode 100644 pym/calculate/contrib/spyne/util/cherry.pyc create mode 100644 pym/calculate/contrib/spyne/util/color.py create mode 100644 pym/calculate/contrib/spyne/util/color.pyc create mode 100644 pym/calculate/contrib/spyne/util/coopmt.py create mode 100644 pym/calculate/contrib/spyne/util/coopmt.pyc create mode 100644 pym/calculate/contrib/spyne/util/dictdoc.py create mode 100644 pym/calculate/contrib/spyne/util/dictdoc.pyc create mode 100644 pym/calculate/contrib/spyne/util/django.py create mode 100644 pym/calculate/contrib/spyne/util/django.pyc create mode 100644 pym/calculate/contrib/spyne/util/dyninit.py create mode 100644 pym/calculate/contrib/spyne/util/dyninit.pyc create mode 100644 pym/calculate/contrib/spyne/util/email.py create mode 100644 pym/calculate/contrib/spyne/util/email.pyc create mode 100644 pym/calculate/contrib/spyne/util/etreeconv.py create mode 100644 pym/calculate/contrib/spyne/util/etreeconv.pyc create mode 100644 pym/calculate/contrib/spyne/util/fileproxy.py create mode 100644 pym/calculate/contrib/spyne/util/fileproxy.pyc create mode 100644 pym/calculate/contrib/spyne/util/gencpp.py create mode 100644 pym/calculate/contrib/spyne/util/gencpp.pyc create mode 100644 pym/calculate/contrib/spyne/util/http.py create mode 100644 pym/calculate/contrib/spyne/util/http.pyc create mode 100644 pym/calculate/contrib/spyne/util/invregexp.py create mode 100644 pym/calculate/contrib/spyne/util/invregexp.pyc create mode 100644 pym/calculate/contrib/spyne/util/memo.py create mode 100644 pym/calculate/contrib/spyne/util/memo.pyc create mode 100644 pym/calculate/contrib/spyne/util/meta.py create mode 100644 pym/calculate/contrib/spyne/util/meta.pyc create mode 100644 pym/calculate/contrib/spyne/util/odict.py create mode 100644 pym/calculate/contrib/spyne/util/odict.pyc create mode 100644 pym/calculate/contrib/spyne/util/oset.py create mode 100644 pym/calculate/contrib/spyne/util/oset.pyc create mode 100644 pym/calculate/contrib/spyne/util/protocol.py create mode 100644 pym/calculate/contrib/spyne/util/protocol.pyc create mode 100644 pym/calculate/contrib/spyne/util/resource.py create mode 100644 pym/calculate/contrib/spyne/util/resource.pyc create mode 100644 pym/calculate/contrib/spyne/util/simple.py create mode 100644 pym/calculate/contrib/spyne/util/simple.pyc create mode 100644 pym/calculate/contrib/spyne/util/six.py create mode 100644 pym/calculate/contrib/spyne/util/six.pyc create mode 100644 pym/calculate/contrib/spyne/util/tdict.py create mode 100644 pym/calculate/contrib/spyne/util/tdict.pyc create mode 100644 pym/calculate/contrib/spyne/util/test.py create mode 100644 pym/calculate/contrib/spyne/util/test.pyc create mode 100644 pym/calculate/contrib/spyne/util/tlist.py create mode 100644 pym/calculate/contrib/spyne/util/tlist.pyc create mode 100644 pym/calculate/contrib/spyne/util/toposort.py create mode 100644 pym/calculate/contrib/spyne/util/toposort.pyc create mode 100644 pym/calculate/contrib/spyne/util/web.py create mode 100644 pym/calculate/contrib/spyne/util/web.pyc create mode 100644 pym/calculate/contrib/spyne/util/wsgi_wrapper.py create mode 100644 pym/calculate/contrib/spyne/util/wsgi_wrapper.pyc create mode 100644 pym/calculate/contrib/spyne/util/xml.py create mode 100644 pym/calculate/contrib/spyne/util/xml.pyc create mode 100644 pym/calculate/contrib/suds/__init__.py create mode 100644 pym/calculate/contrib/suds/__init__.pyc create mode 100644 pym/calculate/contrib/suds/argparser.py create mode 100644 pym/calculate/contrib/suds/argparser.pyc create mode 100644 pym/calculate/contrib/suds/bindings/__init__.py create mode 100644 pym/calculate/contrib/suds/bindings/__init__.pyc create mode 100644 pym/calculate/contrib/suds/bindings/binding.py create mode 100644 pym/calculate/contrib/suds/bindings/binding.pyc create mode 100644 pym/calculate/contrib/suds/bindings/document.py create mode 100644 pym/calculate/contrib/suds/bindings/document.pyc create mode 100644 pym/calculate/contrib/suds/bindings/multiref.py create mode 100644 pym/calculate/contrib/suds/bindings/multiref.pyc create mode 100644 pym/calculate/contrib/suds/bindings/rpc.py create mode 100644 pym/calculate/contrib/suds/bindings/rpc.pyc create mode 100644 pym/calculate/contrib/suds/builder.py create mode 100644 pym/calculate/contrib/suds/builder.pyc create mode 100644 pym/calculate/contrib/suds/cache.py create mode 100644 pym/calculate/contrib/suds/cache.pyc create mode 100644 pym/calculate/contrib/suds/client.py create mode 100644 pym/calculate/contrib/suds/client.pyc create mode 100644 pym/calculate/contrib/suds/metrics.py create mode 100644 pym/calculate/contrib/suds/metrics.pyc create mode 100644 pym/calculate/contrib/suds/mx/__init__.py create mode 100644 pym/calculate/contrib/suds/mx/__init__.pyc create mode 100644 pym/calculate/contrib/suds/mx/appender.py create mode 100644 pym/calculate/contrib/suds/mx/appender.pyc create mode 100644 pym/calculate/contrib/suds/mx/basic.py create mode 100644 pym/calculate/contrib/suds/mx/basic.pyc create mode 100644 pym/calculate/contrib/suds/mx/core.py create mode 100644 pym/calculate/contrib/suds/mx/core.pyc create mode 100644 pym/calculate/contrib/suds/mx/encoded.py create mode 100644 pym/calculate/contrib/suds/mx/encoded.pyc create mode 100644 pym/calculate/contrib/suds/mx/literal.py create mode 100644 pym/calculate/contrib/suds/mx/literal.pyc create mode 100644 pym/calculate/contrib/suds/mx/typer.py create mode 100644 pym/calculate/contrib/suds/mx/typer.pyc create mode 100644 pym/calculate/contrib/suds/options.py create mode 100644 pym/calculate/contrib/suds/options.pyc create mode 100644 pym/calculate/contrib/suds/plugin.py create mode 100644 pym/calculate/contrib/suds/plugin.pyc create mode 100644 pym/calculate/contrib/suds/properties.py create mode 100644 pym/calculate/contrib/suds/properties.pyc create mode 100644 pym/calculate/contrib/suds/reader.py create mode 100644 pym/calculate/contrib/suds/reader.pyc create mode 100644 pym/calculate/contrib/suds/resolver.py create mode 100644 pym/calculate/contrib/suds/resolver.pyc create mode 100644 pym/calculate/contrib/suds/sax/__init__.py create mode 100644 pym/calculate/contrib/suds/sax/__init__.pyc create mode 100644 pym/calculate/contrib/suds/sax/attribute.py create mode 100644 pym/calculate/contrib/suds/sax/attribute.pyc create mode 100644 pym/calculate/contrib/suds/sax/date.py create mode 100644 pym/calculate/contrib/suds/sax/date.pyc create mode 100644 pym/calculate/contrib/suds/sax/document.py create mode 100644 pym/calculate/contrib/suds/sax/document.pyc create mode 100644 pym/calculate/contrib/suds/sax/element.py create mode 100644 pym/calculate/contrib/suds/sax/element.pyc create mode 100644 pym/calculate/contrib/suds/sax/enc.py create mode 100644 pym/calculate/contrib/suds/sax/enc.pyc create mode 100644 pym/calculate/contrib/suds/sax/parser.py create mode 100644 pym/calculate/contrib/suds/sax/parser.pyc create mode 100644 pym/calculate/contrib/suds/sax/text.py create mode 100644 pym/calculate/contrib/suds/sax/text.pyc create mode 100644 pym/calculate/contrib/suds/servicedefinition.py create mode 100644 pym/calculate/contrib/suds/servicedefinition.pyc create mode 100644 pym/calculate/contrib/suds/serviceproxy.py create mode 100644 pym/calculate/contrib/suds/serviceproxy.pyc create mode 100644 pym/calculate/contrib/suds/soaparray.py create mode 100644 pym/calculate/contrib/suds/soaparray.pyc create mode 100644 pym/calculate/contrib/suds/store.py create mode 100644 pym/calculate/contrib/suds/store.pyc create mode 100644 pym/calculate/contrib/suds/sudsobject.py create mode 100644 pym/calculate/contrib/suds/sudsobject.pyc create mode 100644 pym/calculate/contrib/suds/transport/__init__.py create mode 100644 pym/calculate/contrib/suds/transport/__init__.pyc create mode 100644 pym/calculate/contrib/suds/transport/http.py create mode 100644 pym/calculate/contrib/suds/transport/http.pyc create mode 100644 pym/calculate/contrib/suds/transport/https.py create mode 100644 pym/calculate/contrib/suds/transport/https.pyc create mode 100644 pym/calculate/contrib/suds/transport/options.py create mode 100644 pym/calculate/contrib/suds/transport/options.pyc create mode 100644 pym/calculate/contrib/suds/umx/__init__.py create mode 100644 pym/calculate/contrib/suds/umx/__init__.pyc create mode 100644 pym/calculate/contrib/suds/umx/attrlist.py create mode 100644 pym/calculate/contrib/suds/umx/attrlist.pyc create mode 100644 pym/calculate/contrib/suds/umx/basic.py create mode 100644 pym/calculate/contrib/suds/umx/basic.pyc create mode 100644 pym/calculate/contrib/suds/umx/core.py create mode 100644 pym/calculate/contrib/suds/umx/core.pyc create mode 100644 pym/calculate/contrib/suds/umx/encoded.py create mode 100644 pym/calculate/contrib/suds/umx/encoded.pyc create mode 100644 pym/calculate/contrib/suds/umx/typed.py create mode 100644 pym/calculate/contrib/suds/umx/typed.pyc create mode 100644 pym/calculate/contrib/suds/version.py create mode 100644 pym/calculate/contrib/suds/version.pyc create mode 100644 pym/calculate/contrib/suds/wsdl.py create mode 100644 pym/calculate/contrib/suds/wsdl.pyc create mode 100644 pym/calculate/contrib/suds/wsse.py create mode 100644 pym/calculate/contrib/suds/wsse.pyc create mode 100644 pym/calculate/contrib/suds/xsd/__init__.py create mode 100644 pym/calculate/contrib/suds/xsd/__init__.pyc create mode 100644 pym/calculate/contrib/suds/xsd/depsort.py create mode 100644 pym/calculate/contrib/suds/xsd/depsort.pyc create mode 100644 pym/calculate/contrib/suds/xsd/doctor.py create mode 100644 pym/calculate/contrib/suds/xsd/doctor.pyc create mode 100644 pym/calculate/contrib/suds/xsd/query.py create mode 100644 pym/calculate/contrib/suds/xsd/query.pyc create mode 100644 pym/calculate/contrib/suds/xsd/schema.py create mode 100644 pym/calculate/contrib/suds/xsd/schema.pyc create mode 100644 pym/calculate/contrib/suds/xsd/sxbase.py create mode 100644 pym/calculate/contrib/suds/xsd/sxbase.pyc create mode 100644 pym/calculate/contrib/suds/xsd/sxbasic.py create mode 100644 pym/calculate/contrib/suds/xsd/sxbasic.pyc create mode 100644 pym/calculate/contrib/suds/xsd/sxbuiltin.py create mode 100644 pym/calculate/contrib/suds/xsd/sxbuiltin.pyc diff --git a/pym/calculate/contrib/spyne/__init__.py b/pym/calculate/contrib/spyne/__init__.py new file mode 100644 index 0000000..c38cecf --- /dev/null +++ b/pym/calculate/contrib/spyne/__init__.py @@ -0,0 +1,81 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +class LogicError(Exception): + pass + +__version__ = '2.13.16' + +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 + +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 spyne.service import ServiceBase as Service +from spyne.service import ServiceBase # DEPRECATED +from spyne.application import Application + +from spyne.model import * +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 + + +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/pym/calculate/contrib/spyne/__init__.pyc b/pym/calculate/contrib/spyne/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bee0ac06a93c8882abbc5bc4b94e2349802969ac GIT binary patch literal 2879 zcmb`I>rxa)6vxl(BFY^^K#0X3X z@+Ia8@;-T!JVL(Z0g`i0uk2v?Q78`cJEu=y|9!gn@5takfB*Gk0NtM={{IgD^q&QQ z5I_RFbs%)$4}gyVM*^V$q5xqL!ah(%i2FcX0EhSjsD6kqg1Cg-4`P5@T?91<@eqh1 z+v*aiVTeaSj94CE9tAOKd60Pw#F*tF=5Y|?mWP=qKulO30d*PTNf48kM?qbIcnZXn zp$qmal@k0r4`3Wy`amZbFmxbB?~^TOe-R$Td)RATEO_Tb^fL0kL9v zfq50gs^vxIH4tl-mzeK@xNEt@ybfaB@^$74h>GPK%vBIo%gfC7K-{x@lX(NghUHt# zn;w?J$`{0PJ&8!LnQ2I9vc9z*;D#1r(ckm$rykWWc^ zPPht(u7mDv((WZRC|uO4dsxPAD5IFcklXVTKbD@yeRy7+ zh8=}yTX9n|x`C$J(OFeRZ?+y(+o$GTnrv1cRdrorG4sBuT#`B&7|Ma7x7;=FZvIE$~1XHx36OY3)Ey+22t!Q zLs>HE`Dz#CD|L`XZIgB*m$94eSGz~vVe_a__kM6|2M6_Cn?*Cq z#kOm1-3BJl2VT8ydc7d6J(pGAJ7^x+wAn92yz|Ml-C4W4-F*o99K~legt0@J9Y=xO z_O-MFkh9iqt0?eIly(n?j&aq-2k;a3CG>Imr`9!tu9wNNucB}#lOgVMnD*m`Q4xk>&h_7WMIm4SbS@DRD`Rfb1-(h;?zjgav;M_#^+;bqOK%=_tb0wpt?a0 znQ=DZen%_@$MdjEcX*#KxS?&pku^#M>%!YKqB|Y+qtWYV4ylxsGCX@+t}Y#L#VKu8 zwn}MMQa)~arPRzi+LSuF!prG(P$uni@zAH*(3tOh?HiN1TrT+lI;gc+_71?ki_Lmv z@2gilL-O}idh! z$4`Q2yxOTXyr$rFhPFPsya9B0yM`*lZvA=fb))GuYWpu<*Iv}QTQ1fW?+psarKzw= ztTV7h)1|F*S#>mfmjvR{jB@$%IBsPwZ7Gjr^TV?`=d$!hDUq&`OS5tL;!^E1b?Qsa%{EAv1S{LaSt| zXnMNiudgpYI>Tr7asQT|T~gO{vA;0xj2F<-fBT#NcE*eBwb8;Lwmob2seLzV-kB~A G^!*P`ePTQS literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/_base.py b/pym/calculate/contrib/spyne/_base.py new file mode 100644 index 0000000..7f558fc --- /dev/null +++ b/pym/calculate/contrib/spyne/_base.py @@ -0,0 +1,47 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import logging +logger = logging.getLogger('spyne') + +from collections import namedtuple + +# When spyne.server.twisted gets imported, this type gets a static method named +# `from_twisted_address`. Dark magic. +Address = namedtuple("Address", ["type", "host", "port"]) + + +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))) + + Address.__str__ = address_str + + # this gets overwritten once spyne.server.twisted is imported + @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/pym/calculate/contrib/spyne/_base.pyc b/pym/calculate/contrib/spyne/_base.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5d71dda6bca865efb9ad980c28b704c54cddd2e GIT binary patch literal 1330 zcmcIj&1w`u5U%;j&u$_K;z0yGDGWkpiG~$KM2#0gqD)k9F70HycQVQB&M@6EEW}eh z`$oQrkKoM*(C_O>a`KwpuIj3;>guYmYN9_khQELP{4$Y?-xBs0Ae)0}tUziJC`RNc z5FN^SAbIFbk<^jQV##9(Oe`8}N%XSl6)7V*4<(1XDtah-Am2sKMLy>+2eO~6A$;{0 zzdgq%ZM&G8B!J|GVDn;Tv^!~Q<5r-))Ved)x|sGwYrJsSSm%Yd>72U>lPa_((O1#W zUX>NX{0d}0fuWQfr9cQpMa+i+vJbt0q$4jN)tGtbD`K$Vvnpo5B3TSz7>dEd`I=<= z$udIwgg)%P-?;snBY!ZJxLd>3RNfFX+`ku#4nc_=ROYRspmz>~1Cjy=cA zPZM7E(T|#Ho<-0y4-h5mx{UT7QXX4VPZR9onSBFkbYifM(x5KHuFd6laZ~Q z*=mc)aZwsO@_pHQlx{yxx5r!U0v@R;%l>?%4hm~h++{Z}fydMLp<1RYf$sn_BE19I zyI?35U}LamfqV-kI15?oSs*_IMbdT84@aLqZ(Q|t+BGxfPAluoRkJ-T?hd1Kj#6v7 zuck{cyi%WLwh6Nj?cpmN^E*E6k0D+QE(BgpUGWgRr6S>GkgQ{Ot6)lT(3SEtuhgv3 zCpFZJsbw7ej9%G*jGsle0p`C5r2sQ7GL&_Nt0psp4(jX{J;?rx6VCfOuVDx>&i_4- zCDO~mp#O)1Xb^2I`3Do$0QuFb?%&D>@j`5qTK b_0b?)OV2}+#_4o0E=d`yN7JD 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/auxproc/__init__.py b/pym/calculate/contrib/spyne/auxproc/__init__.py new file mode 100644 index 0000000..19e90b3 --- /dev/null +++ b/pym/calculate/contrib/spyne/auxproc/__init__.py @@ -0,0 +1,42 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.auxproc`` package contains backends to process auxiliary method +contexts. + +"Auxiliary Methods" are methods that run asyncronously once the +primary method returns (either successfully or not). There can be only one +primary method for a given method identifier but zero or more auxiliary methods. + +To define multiple auxiliary methods for a given main method, you must use +separate :class:`Service` subclasses that you pass to the +:class:`spyne.application.Application` constructor. + +Auxiliary methods are a useful abstraction for a variety of asyncronous +execution methods like persistent or non-persistent queueing, async execution +in another thread, process or node. + +Classes from this package will have the ``AuxProc`` suffix, short for +"Auxiliary Processor". + +This package is DEPRECATED. Get rid of this ASAP. +""" + +from spyne.auxproc._base import process_contexts +from spyne.auxproc._base import AuxProcBase diff --git a/pym/calculate/contrib/spyne/auxproc/__init__.pyc b/pym/calculate/contrib/spyne/auxproc/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..82fa72be39d963056a3ab4be354361610afdfdf2 GIT binary patch literal 1141 zcmZuw&2AGh5Z)x^M~jdu@dBe>2q@X81r<>tL})8cpsLNOmtDs@n^@i0TaO*Gyc=)A zBXHvZV7%ETDX>x;+w;xmnfYdVzn;cFe|*nm)P7z5|G+vW%))V$$~cSMFN})KOu#NDKb^V_YYOUZ~-&5MBPRM zDo5>9p_q8;9ehJ;0_nmq+uuosK};DdWMFCIUkazrD9y6^bPEer&Kox6rj$j3Yux@TqHv?rqwn=;@>6&4`r4VLP}qYB+~S$>FQy@OW6&j7V@cTi=hk it3$w}G*w!;G)MhKA^K#ByOp)*o6L8xhWm+f}iT|Hf8 zY@=jDX3vTxD?Wl1f5IoQ;{)K_>UP@+nq{zD)%C7h_nvdAs(f>aohqtuD{uRxLs~j1novYK~2WUoMqzAR;YBDoRGeC^3+2 zxsbuk$gtav{=u)`abTy}Lxu(O-5;sM$b|`NXsj3M5x#nWZ1F9fJM{T?$8=Gn^BPTv zCe~>vpI7J{uB(!R58QgTMfz}KP>r(YMzv1o#MR3RInSGf{|P1?cPhNs0kXmw)^HK{ zaV$d-B?4aDIA)Mr+wFH6m}1(-a`VWFkL~ew1D@$?y^TDv`E7 z&7JPaMIciXsYIJy^skzWIURP1;k~rXevp~jLb2%6hC5R)Fbi9fSytG9mJYheX8IeH zdNZB%;%IRHUN2n&3dx=BM?D=Gd64?SnLm=cr_*I35AJkt-|gPMe~>OQqAN$EyuF8G zv1vVT0F-sH1_$w)v09)_vxQXMao%y>b<8U$Bh*hYmEjq1AOG0v50Ui8$RwBnHUREq z;cmkTlrtwP4ENJIg;iT_X-7C@Xb*uSIyaG*`* z2S%_}1!?ry&k*y$QXu#x;=Ap(D1Hx8Kl7(zb?SBG9*Co%82Yi6ABs>(EfQr!f&C5e zIY`#$E%n_*}CHC7%B&0oW%eOz+u`Q>z4g2u^I8r9XSs z*emjWaH1fV~tZnliLYB?HFS53toGmR}(*3?rAJ z(%}Q;zGd25;JPeNH|=GYy?Bh2BevezLfI;y=OzABdY+Ag=S@{Oi@C})|B`Q6mmeSQ zdz>-sUBMYIx3<}qZszIZvclX#((I;&v)yjJ*{Zkd9V?qGUY-}K00wiJ#hbO41p#9J zmDO_hebijm6MHE8^vXkGqp{5$e6svnup9m_N3-t#BzO3yEW7y;E8EU)Wv{y3`WN-+ BGm8KK literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/auxproc/sync.py b/pym/calculate/contrib/spyne/auxproc/sync.py new file mode 100644 index 0000000..4299fa7 --- /dev/null +++ b/pym/calculate/contrib/spyne/auxproc/sync.py @@ -0,0 +1,32 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import logging +logger = logging.getLogger(__name__) + +from spyne.auxproc import AuxProcBase + + +class SyncAuxProc(AuxProcBase): + """SyncAuxProc processes auxiliary methods synchronously. It's useful for + testing purposes. + """ + + def process_context(self, server, ctx): + self.process(server, ctx) diff --git a/pym/calculate/contrib/spyne/auxproc/sync.pyc b/pym/calculate/contrib/spyne/auxproc/sync.pyc new file mode 100644 index 0000000000000000000000000000000000000000..43117251bae1059d93415c5199d5274b7185653a GIT binary patch literal 894 zcmcgq%Z}7A5bPu~0}QN|0}>J!awC^XvTFPUI3o(vuBj;wbH)iL|%n zxA+r2fg2wH)!y*<0kGn--L|W%D-OONEWdsI@~)t%1sI>9%S%9s&!dJYC1Rov9&@5}Q|z}CJ$#BTcL7MBf*j~8D^ftjdK3A2AP4-#5O$zu5tc9?_H|R|{TS}po|{ra zL8kNGv}TZIjKf#6amzWwCWzh27A11}w3Q7HZ9}{zB8<0bIZqphp*Q z#)l73;>w(gy@oTBoJcR*ncn1PYZq?Pf8yTiMq&36267;0m?eYsNmIW+d6aY`#J9)s z<3wu9t1d4-<`qjK-PrQ#I6it9ADyha5hr4LGcNDzn!CS=Qz|&N91ni=8QlMwePkmX)T+vbC!Jqxav5Uh6Bkhb}5_5iI;jWjHO3 zsVe*@djo-r?Q1N#U%PFUr`s_108{5vJo&LkfE@4tD8M=T z?QL`C7x7Q{3EcPr@KxD6BP6bi<*upjYFB;roWWmr4*&e)_jyYFGr;dtEcXk@5^q43 zXhvj+E(0x6S6fF4Je)8GmPcr$5~S4k3Al<-P_1$Qew6 zhHPsY(mO$GhK!DJU^^m!13w%0;D9&oV7cFbsKe6RQ57H<=ZsUj*7w*&Qy(fkUVKuG%Ze2?Mm5Ev7P4`7fH%#=Ee2-9hUnH z#N!R<3TX}L5|v3(hu9}Wx)MQxWD{zRbv&2K^CSMcsZ1TSKEDr=Bw3O9B=JMORu)DW zcGZ8(;(t{{l5Arz5e@v2GxowCfZ55gp$QWggG?J&Pi?k1`*K=I){wNR%e**t1|;BI&jr0nO-k}&Pz z00Ft&1%bseA4^bT_FrJ$Dpn57=U9#-Mq$cnJsU`Q8W2K3R@ zkgf-k-kW5yikMyZJS=oo**1}e^z2+;aT7KoK6<|DO#Rx_oMV}^Cs>Z5j`zpm(fD|HFqkkH!E4La3L{%Oer5a**kYc1z+x^l76bi< sVE=2#^E@E=OOuw5`qqx6Guih4I3w$H%r)*c{4;5cHxCc=T&dgE)83-OG=UneK_C5NAS)E z(357!67r}2cMgBjBtMh!_t$61;W%R4A8^@clp3Hwji8R9iC`Z?5kusC()$F8B=|w^ z2T%-xANGC-#Sr}n*4dfQT%x?~L|T@%?UW$AkwUq$OxudTS6h*Ctz0FQO&xZHYU)g- zY^#m4ME>H)B1~~UZ&h)pO&7ofK`!>%iM22vl8b=Hh@bjn9xHofSO2ZAMsragjPS*m zY=nhAnXy`P#@r=>)2kA;!NwdZ&Pv(ms4TC$k$eTTI&yJBZkB1E=8yC}UDd#~8tsbIe`tb$w{W{WX4D4@U7t43v6|)Ki0&NPG zqI6b$rPOn!e*L(k2A!&Ot}dNZgZZkoTbItO!9rDft}gAW!J^t;TjE@PfMhezY?Nfi zxBJ@POcR~idy&z8oJPj@Q8w@sYy5qkj&$MYI|n+prkDI1KWiSETXysdZTIs5d(zLW zD_&;*wn(zQP-k&IK*r9Y?4u~Qd2v$j3;Vdoy5B^iu`gJz;$*QS*brvgD%f6Y;d9KS zdN$dJgP(fpRH;yQbz27SH!};%@xm|~jieJh!-hKDwLB7*;*XNVJVb7NY>M?X+4!TAaE4$PC;krqzzBP*C!)Q;Nbu&82^sPI++u!Tm{@~W=1T}hkZ_kyl$Fhg(;SP4O zhc4#PX&5G1V#Dw%@`fu=-s_9Gh+?ed0Kc9(XmMfBJscIcsK3V9225-hNrJ5|cB5F^ z3wYbpHk9+iFvdn%tYxVImuk-;apx9h(NIr&xg87_7do=~9puWzuE|W?PH+-oXczD` z42St(oZ>ZLvw&sI{3JJ(GYNPE1f1c#I$pOeFb?!Ew|ZL_M@g(>e376338B&-nsI=S z@t6%Hr|lAa!fDm&`v!&lk+1KHh!S@qkQdQ)YUTwp-03f^LJ zo=LMro}wcWiFc?^ro3q3Y8Zmfk+nq_a$y2d0Dc9DpQYtv2A^gm1Cu6J z@9{j5R9Z46r%LZh{f32^1oeE-l88zZc za~fP?A_9ku5;5HT`Gc+gBg-%DT*E>?9cyDlw>2UbmQ>`jM@4S)I8W^r6zu6t7qEa~ z*)VpVkr7{@dYO>fdUTOvo`LI}WT)c*B!{tm))0Mql1s80YN1GO>jGuB)%9XpK^_MG zieaN5Sn*1~ggv95Lc$wttbzpFVxc)>Qi_b7?S+*#22pt@jI+`0uYQcN|~&2K}`UM zMq}#_@>sA^DmD>NNgI@M!`~(aAxKf$z{*L+L{%rI8-5=|x{<;DbEW)xV0 zCTxW~5QspUFYq6vcCjPhp!gC^dD&9+E_{)?XxL>bj`6kTf2^v*z<6q+IcSM@4%M!P z`U`!QJx77I%E0dqWKoWO9V>f<1+O5UB#8W-6AKH2@M+kym(ixSJQTjLVuxLAKIvz% z9ucR_SGwmfH*^-u(pxM)G|kFy_=G4^C{fw8YB(W9@E$4%(0RnA31mDg0Y$Ceg7jeP zm%rNDek5O5TT_#z?QT-&P#=L20&Ev33TVn63E3ui4Q}!k&oqUbY_Fi}X0eYFBhYPM z@-DSjTg%=`YpHdy{JZRecM_J5K=*582nHPbtUBzzD(Wnpgf0RTfi4h>Ruz%}+VZ9T z4y}cG6*s4B0ZI2fkD-n00mA#{8ko&Fb+D)omeg5`qQ?1EB^VMe_hCyFe^;;#2g@`R z@V!^h+RCm-)$MSg zYs@m(onb`VMkVtbBn{PxjA6@AbRvv1J^#rQhK)UlEpMovJn`$}6(X7ae2f4W z;Z+$lB%j0eDPvfK9iYINx37M_>q5aM9xlT!&WaCR`As~A{x!UOCY&wTUr2K*N<&2bzR+!~leul@4kU(3ZWAtR-7e%e|SRbSi z>w^mpqfM2>D)9>w?}WE40i|3fL3B|LEicllCQkU}nza19XQHAQ8is9+Fo=BIMBYlVoPMCn*N7oCR<334txwX@`jOk={QpnEiBK)RivJM7N; zPn^vH5;cFtTW(*0A1q6lxX$A?xjVg2kZa~QMTvWefqsw2kUpJur`2uu*Eq|7laVWN z`LB*%d1VoxRLO;iE5_x$PJ5#w8RClKNC#9vxjHFhDKapiVF)Ou0f+m4tV;~mD&IR literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/client/django.py b/pym/calculate/contrib/spyne/client/django.py new file mode 100644 index 0000000..35e1eed --- /dev/null +++ b/pym/calculate/contrib/spyne/client/django.py @@ -0,0 +1,81 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +"""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 + + +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) + + def __call__(self, *args, **kwargs): + response = self.get_django_response(*args, **kwargs) + code = response.status_code + self.ctx.in_string = [response.content] + + # this sets ctx.in_error if there's an error, and ctx.in_object if + # there's none. + self.get_in_object(self.ctx) + + if not (self.ctx.in_error is None): + raise self.ctx.in_error + elif code >= 400: + raise self.ctx.in_error + else: + return self.ctx.in_object + + def get_django_response(self, *args, **kwargs): + """Return Django ``HttpResponse`` object as RPC result.""" + # there's no point in having a client making the same request more than + # once, so if there's more than just one context, it is a bug. + # 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 + + # sets ctx.out_object + self.get_out_object(self.ctx, args, kwargs) + + # sets ctx.out_string + self.get_out_string(self.ctx) + + 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) + + +class DjangoTestClient(ClientBase): + """The Django test client transport.""" + + def __init__(self, url, app, secure=False): + super(DjangoTestClient, self).__init__(url, app) + + self.service = RemoteService(_RemoteProcedure, url, app, secure=secure) diff --git a/pym/calculate/contrib/spyne/client/django.pyc b/pym/calculate/contrib/spyne/client/django.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9519dd68af9fd0d07382dddc1c3b5e0e54f9c5ea GIT binary patch literal 2716 zcmcgt-EJFI5T3JZJ9cPE2x_DvkQSsC^AlSwRX_rvs6hw`$&};XU?Db}-4kb>_3moV zF^#44hE(DX@j|=_kH8%-z&CRox2U~MqwILj-<&z$d@~dNdvo)jzyCT)Y4sQ4_uzoY zHc&F638bPdphD3+ph-ZA#~~FV&092S(Y#HQHqARU>G-u46&p0~(xi)Vn@opJaH2!c zh%SkKn)E2!Ak&uF?s|5UvL225o4D3$h{vZU`ev4t(<(}f+>|bIO;XyrYFufRQ*UQpGNnP8>;mDI@87-^DhnZ|xS=i*|K@O|bR}gLsB008Iv2Z5N=WMjkFLyT~ zw3%1Vj7{@vo*Ksv9f|`F6KmYt>kW^ZDmB@nF+A_hcGi2{Hq_W#T5nu~9ANR`0Uml6 ziUG)iDA0bUXc98uzzWa;c2?S?$Nd(zrfrA~e0MpUHJbhFv%qC+r#O*Ki>8oYghCd|WNx&W=WR(dwQ}#-6IT0}A`$jS zXv2kVhDCn7|6o`z-Dy?cAACNvxifoplAa|~V~3V$uy=oO@3Xh2 zu(>TVq)SDL$JpIrq|bWP{IXiZ%x{XyJA~*U)MssKmj7Scyc%|CjKkwT6K0hE2_O6H zxv&tZ$NoWaV~`gm*!cz)txMd(#%Yxq$6-jT(jk2W{M4O0HjtOGbq&%-2+x)Lk1vnWjNjFg&BGG*_qmo<0MmZ?IsV>$f1}+}aU7#~xgFAXj8elcI>@ySUWuK#_CKl%rC>MF!EL1A_ZS0n{vHUV;&fV~QUP#=s#3eo(xrPZ+a^T!qeT!$_gy7h7 z>aT+T;?#;E9Liahm+LCw=QYpEJ#}TBmcl8i{|avCJG_^Z-6!I8vqCco_VHOpi8i*v z-Ecd&74+1|S2V^dj=2P(gfTjCJg>4vfuX*Qq0|Tc9&2psxxb=aQ%z#vB7ByC>Zlv- z-nO(6-vu9|-}yfDavOOE2aInckO3LrL(oiG+&Z{=Sgv+2^i*!2FE!Rd%0cCiT{t|z zu`i&!vcaH_DAW`%z^4k*0<{s{1~k9wE>gBU1=*lx*!9OOxCm*KGx9BkiDP}kl}6`l zi*Sk==}kbn_MR|eM;HK7w*z11IOO^x2&txVoK-1U!j)ED@p`zypnZ=|eCw!AFzSm3 zpR!+`z$Xio5+*RFRy~`0qDPq{p}Dm==JTo#G6x1eBPE+9780M=@+hfDU-`WIdKYe4 Pen= 400: + raise self.ctx.in_error + else: + return self.ctx.in_object + + +class HttpClient(ClientBase): + def __init__(self, url, app): + super(HttpClient, self).__init__(url, app) + + self.service = RemoteService(_RemoteProcedure, url, app) diff --git a/pym/calculate/contrib/spyne/client/http.pyc b/pym/calculate/contrib/spyne/client/http.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6ae766b36c833ddd260d75cf6072e6bd8ac29299 GIT binary patch literal 2012 zcmcgt&5j#I5dL~*Y_FaDG5J|3Qh-GeG#qxUT~KmC2qi+wX^F-w0T$9^GVXZCJAavO zC%cmOlH~z-9whEO1dos#4**rwYXd@p(=u|GyQ{0as=oSa#{X?=@b=fApJljueER>A zhB+fK1tugFrXC7~(!<0<>0{!f3@{0xc+W@CLD|Kmi?WAF&uIe`8z}pj^l9CJ4)B6( zyZ8aP1iqULFzrG6qTN_)Z(!QTI2>>UACWjd(R)vhkDu;^i?%58=ZBx{Wks$lyJy?9 zGELpuDF2NbkBs5`2iGx!l^y0Bxm$A(TjSh{k zX_z~tSpsw5d&QGPN0Z*%6SeY9^^5pLs+LUkX@4m0PpgSICri7{^tR+dAI>F_uV2%aNL0{Jg2ek7zq zhL$n`vbwVR%o@uC$n2TjrvI6?Nxh))e6BP5H&-<*?0q-QgyAGszQomksMbOQ&PBw1P%N%Ahur8m*t@pt{9 zcSqe+UFEAyb=TWbeRVe&dN@vmhO0!mO4oU@FXeg>7t-zd~X%_^`;OrsO-yd zt9O-z@r2TIFNchj@-UkJ)w@g&9$eMOG|V9hA}E!DXix3NUF-VQgCb&5Y1jQr770nDD~>v}vvx#1F`oWX!39 z>g~c{O2qH6V1qwnklA$*Qc#jIxoRGTo8(yVNs?)u5zPcq=D5R;v5wi;en>*dA1!QN zL?%Cr%KDWyk^90#t4`wzyEgzQ^=~Jn$76OVWs>0j2M~lMpSwo-;x@;~AG@x1&)Zc) IfA`}*0Er{8y8r+H literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/client/twisted/__init__.py b/pym/calculate/contrib/spyne/client/twisted/__init__.py new file mode 100644 index 0000000..6609e82 --- /dev/null +++ b/pym/calculate/contrib/spyne/client/twisted/__init__.py @@ -0,0 +1,148 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""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.http_headers import Headers + + +class _Producer(object): + if six.PY2: + implements(IBodyProducer) + + _deferred = None + + def __init__(self, body): + """:param body: an iterable of strings""" + + self.__paused = False + + # check to see if we can determine the length + try: + len(body) # iterator? + self.length = sum([len(fragment) for fragment in body]) + self.body = iter(body) + + except TypeError: + self.length = UNKNOWN_LENGTH + + self._deferred = Deferred() + + def startProducing(self, consumer): + self.consumer = consumer + + self.resumeProducing() + + return self._deferred + + def resumeProducing(self): + self.__paused = False + for chunk in self.body: + self.consumer.write(chunk) + if self.__paused: + break + else: + self._deferred.callback(None) # done producing forever + + def pauseProducing(self): + self.__paused = True + + def stopProducing(self): + self.__paused = True + + +class _Protocol(Protocol): + def __init__(self, ctx): + self.ctx = ctx + self.deferred = Deferred() + + def dataReceived(self, bytes): + self.ctx.in_string.append(bytes) + + def connectionLost(self, reason): + if reason.check(ResponseDone): + self.deferred.callback(None) + else: + self.deferred.errback(reason) + + +class _RemoteProcedure(RemoteProcedureBase): + def __call__(self, *args, **kwargs): + # there's no point in having a client making the same request more than + # once, so if there's more than just one context, it's rather a bug. + # 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.get_out_object(self.ctx, args, kwargs) + self.get_out_string(self.ctx) + + self.ctx.in_string = [] + + 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) + ) + + def _process_response(_, response): + # this sets ctx.in_error if there's an error, and ctx.in_object if + # there's none. + self.get_in_object(self.ctx) + + if self.ctx.in_error is not None: + raise self.ctx.in_error + elif response.code >= 400: + raise werror.Error(response.code) + return self.ctx.in_object + + def _cb_request(response): + p = _Protocol(self.ctx) + response.deliverBody(p) + return p.deferred.addCallback(_process_response, response) + + return d.addCallback(_cb_request) + + +class TwistedHttpClient(ClientBase): + def __init__(self, url, app): + super(TwistedHttpClient, self).__init__(url, app) + + self.service = RemoteService(_RemoteProcedure, url, app) diff --git a/pym/calculate/contrib/spyne/client/twisted/__init__.pyc b/pym/calculate/contrib/spyne/client/twisted/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af98c4371c6250682f6745d47c096361a6920b87 GIT binary patch literal 6076 zcmc&&TX$PW72fCQV#$}-u@mRgw5Um2R3P$7+7%XEkk!TsO&48CICe-Q2&b~nSeAWs zq?{QgF~l!~Max_HKk!fZ3B2(G;QRJSvXk%t4>q=EJbTZ5U%tKP6#ls|`;Wi>?dy(= ze+u~jDT<8(kwm10I*=rkG?0EMt%3xk3z8P4Uy@eI(?v0gr8CD5nEye-?f<+A)y zQIBYIaG1{)a14|$l};DsVduh?ui8uk?9Yd z*)aLjUdMR$%9MRSA9PGI%FV5|9e2*6)9?B!uh$=@rjNr|zsL;6<)+5tjQ^FVwm`ox0Sr=>i-g%Ib!96o;ZV$5Yfq028ZVi%sER~EpX1v`g zupcyk(Y*Jt8Gm`F`T6EuzX;ED*R&Ie#Z}RcC)1|Z9D;ib#r_hNfi(wWLfI`yeo0JG zOi5k_5@fJ(nDPwm9SVod!o=CA((u`srNy%`CrMEo^Ac^;%UHF;J*W!aa2>_|9+eY$ zfdd7ye@9#>F9O}j6{L%fKyE)?mV;1xLiYSNlqWSdIH@SEG@e1SEDy7bQgk!2H!JzB z1VP{`=jg>4BL6TU)zE}KdH5|TF;rhy_K5UV7q2r-pjhS zS*K}XKaroeQ)}F5w5D>5<6(PbO@ecaq);CJ+fm=~;-I^3#}(1!!rI_gs*271p}9lt zM{1bVlvhzQF&i$WbF4|Xqg7HgtL?nqrRmkt7Om{B(OMhXd@b#5-S~KIxbJob+4aVc z*DUtEI&63L+FfJU>~KFbSFbm&ebl&iB&$fRixtIg^oo6(7PeDK)-F)^_JYA z14|$EA*MwTxnbK|E3^=u2T#=&T|g_kL=xqM?oao!uARH-fj%RLI+mas&W0V{Wn$)f z_a+!q6Mue_LcpbOKfWRdDiL_tZgFDu>KXE_wE!cv`e+G)B4?W+|v2_ihBicp7lc1GFW$;mN#8@t~{u>?0rE?B~E zHK=&`O=PI@qf<=fcjWrKfL>=a9~l*a+L7MrA6<_Kl92|kciE!T zMsKlthZVISy~pZ(RENsa)^TH4L{#}9iegt8R<{tA!|GCXrdq8QromCea|grphnKsB zqOrmtxFO^50Wh2dz``T|78&je82ly<60)W^=oAFu;4#)XbZgF3Id=)0CM9{{@Udt9$e+z%VHl}HAuFHLz5-1 z0n^sLGxp?e>1eY_+qEOpF}uhPl zn&c@*A)IkzjK8L{7cswxXqr)t6Mj_)WkD@>r6g)(G(UL)wa`Ai0GxmzL4>^Dsk` zShxVV2L*Y7d;saSU#3Dw=>cqz0ME+q9Mh)NF6e^Xz;Ku=m&M-#XTL1UK~cU5^f^_O zKZ*QVk|* z;uyauI5Xq4z1jN?8mU*Xonvt78izzR9&GKxK0U^;4=jCJd2b?ibq0x1zVKMl zPcX?Zq230+hQVkGg+x@JV0E$%vy9_5WB+$!Xr9NfUP& zFZn6P>(f|8q+Zz0yH=;|J<}#Nfk#{BRH{jIi&Id>ub`=Xk6pAC>>0;=NyPCE+WM-K z@?y9eEQRyoe860)9GnZz78d80OPT^jA7G#l2KRVmlq1z~A36FM+W}{N1TP2bOXCko z{Ep;5==@LkPuF50kgRj%>!{#jP>y#XpY{;*LkVCP(CIV=U_@Lxn(L_@QNeaJG-*CZMf;rsBpv_xl_zH990sheADec`~5?1!bHAUI<@TG6x)kNfIz2GQ$1ltD{lYPzc+85!67Wcr5xhZ0SoKNfBl@Gyu#|$)y35h{|#Ag6axSN literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/client/zeromq.py b/pym/calculate/contrib/spyne/client/zeromq.py new file mode 100644 index 0000000..70c9796 --- /dev/null +++ b/pym/calculate/contrib/spyne/client/zeromq.py @@ -0,0 +1,54 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ZeroMQ (zmq.REQ) client transport.""" + +import zmq + +from spyne import RemoteService, ClientBase, RemoteProcedureBase + +context = zmq.Context() + + +class _RemoteProcedure(RemoteProcedureBase): + def __call__(self, *args, **kwargs): + self.ctx = self.contexts[0] + + self.get_out_object(self.ctx, args, kwargs) + self.get_out_string(self.ctx) + out_string = b''.join(self.ctx.out_string) + + socket = context.socket(zmq.REQ) + socket.connect(self.url) + socket.send(out_string) + + self.ctx.in_string = [socket.recv()] + self.get_in_object(self.ctx) + + if not (self.ctx.in_error is None): + raise self.ctx.in_error + else: + return self.ctx.in_object + + +class ZeroMQClient(ClientBase): + def __init__(self, url, app): + super(ZeroMQClient, self).__init__(url, app) + + self.service = RemoteService(_RemoteProcedure, url, app) diff --git a/pym/calculate/contrib/spyne/client/zeromq.pyc b/pym/calculate/contrib/spyne/client/zeromq.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c300b8fa81acc376debfc154962db84085ef464d GIT binary patch literal 1810 zcmcgs%~I4r5bjC#ho1#j6iQ08_GHBay9HQyu`CP9qpM`SxRH`*N{8^S(r04h+x`qiHIfx$txv79 z9K7ev@R<+6-W_2LSX)H6{(#0TC4y+Dvjq4qNZkUHxD@U}oORzJ zzvuDikXaQ}0lfmLZ(tWhzz#sIK?;P?9m65xap=+|!Cr1@y%Zz>LQ*O9q)IS-bV=7J zsgs_eWY$>VP@!bbxXrUgu->2xcd9Hf)2p!tL`+%Tuj17a`QAdJ*rT)ImN09V9Z;f0>jn;%ulH zt0a#zQzUjR?e*)BxHhoN!(*vUaI}GWqZM@NmT`1Gcv7S$q>@==ghGZVdKO>e>?$-j z2qy+hnHT2|O%?^3i8JcvnY`L%eLOB~89F^Q!k`!`liTqJ7JY6rzX9ffEK~cCIuliN z()eKKac6v{kMeA*{iLH}EjPx4@OUtks-wndncUcFZ*I3YcQ(dn@Mz27(Aqn;-8<(P z155y7aK1qh4$?FT9za%i!ALZnRnZhH&NBFdvjTltEID>6?3QdWl0jgw4uVl0O;V`- zJ#4Nb>%mad4@^= literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/const/__init__.py b/pym/calculate/contrib/spyne/const/__init__.py new file mode 100644 index 0000000..eb5ca90 --- /dev/null +++ b/pym/calculate/contrib/spyne/const/__init__.py @@ -0,0 +1,82 @@ + + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""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`""" + +MAX_ARRAY_ELEMENT_NUM = 2 +"""Maximum number of array elements for :func:`spyne.util.log_repr`""" + +MAX_DICT_ELEMENT_NUM = 2 +"""Maximum number of dict elements for :func:`spyne.util.log_repr`""" + +MAX_FIELD_NUM = 10 +"""Maximum number of complex model fields for :func:`spyne.util.log_repr`""" + +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' +"""The suffix for Array wrapper objects.""" + +REQUEST_SUFFIX = '' +"""The suffix for function response objects.""" + +RESPONSE_SUFFIX = 'Response' +"""The suffix for function response objects.""" + +RESULT_SUFFIX = 'Result' +"""The suffix for function response wrapper objects.""" + +TYPE_SUFFIX = 'Type' +"""The suffix for primitives with unnamed constraints.""" + +PARENT_SUFFIX = 'Parent' +"""The suffix for parent classes of primitives with unnamed constraints.""" + +MANDATORY_PREFIX = 'Mandatory' +"""The prefix for types created with the :func:`spyne.model.Mandatory`.""" + +MANDATORY_SUFFIX = '' +"""The suffix for types created with the :func:`spyne.model.Mandatory`.""" + +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' +"""Locale code to use for the translation subsystem when locale information is +missing in an incoming request.""" + +WARN_ON_DUPLICATE_FAULTCODE = True +"""Warn about duplicate faultcodes in all Fault subclasses globally. Only works +when CODE class attribute is set for every Fault subclass.""" + + +def add_request_suffix(string): + """Concatenates REQUEST_SUFFIX to end of string""" + return string + REQUEST_SUFFIX diff --git a/pym/calculate/contrib/spyne/const/__init__.pyc b/pym/calculate/contrib/spyne/const/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b01cfc2493540c4c752a46f78503151162cc5a38 GIT binary patch literal 1172 zcmcIi&2rN)5Z*RFZPTVL<);TOK5)o^Cey-{3j_5eO394l1ls}Xi((=*^^nTJ+Aw5> zBd^7q@CY23;RRUPZc82jd-Q4bY4z=DSEWDo+OMBK#uF&MHJZ<8=p}&w2np99Tm!KV z;d+K85G4r9Aj%L{KvW>CX7&b%DukOLHXz&ru?b-f#1@3xAZifqWIlBe+Ys)8*nw~l zL>_-DcpS!d*C(d1J!l@_frij}sm zV?B|xS)`JMHmt@-q4g!2Eu^-TltPMHtcXZs<1vp?)K+q7`I&5dMsebG12qDq0azih z(==M*CRv`;bCQ)<%@>OqVwucfInTLaluCuTMO;5pBElqHX3iCt>i9!)u&=6owFd5iN{#mIS+L=H$c5`w4lGxY$uUR++rUxy~5xi74{jR!R01_9?H znQ)GWWcTe4+z-5-d(OK(=5)Bj-1FcKJ}mZZ&$BN$b6B6b0e44zG&1H?r`HZvHtNMj zu47zxh{*+p9;5pGL*xbZO#g6?z+?V!;QFknG#WADM$S#`ahsUnVz}Zlv^|qnE{5g} z_ieXh2Ltbd7a>>4!qeQY!@9PS@36K*GJN25n3v_!@45WE&3kUZymz*f_4mfx8MJMO z=vNPJ96?`_ZJ1DAJ3L#Nla1I9Du_J9OU)>-54;D0><^PFE^Ct@*^uO5-DpAb|_ Pw}1K8y5maKa<%do1ojz{ literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/const/ansi_color.py b/pym/calculate/contrib/spyne/const/ansi_color.py new file mode 100644 index 0000000..98935ba --- /dev/null +++ b/pym/calculate/contrib/spyne/const/ansi_color.py @@ -0,0 +1,81 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""You can use the constants in this package to add colour to your logs. You can +use the "colorama" package to get ANSI colors working on windows. +""" + +DARK_RED = "" +"""ANSI colour value for dark red if colours are enabled, empty string +otherwise.""" + +LIGHT_GREEN = "" +"""ANSI colour value for light green if colours are enabled, empty string +otherwise.""" + +LIGHT_RED = "" +"""ANSI colour value for light red if colours are enabled, empty string +otherwise.""" + +LIGHT_BLUE = "" +"""ANSI colour value for light blue if colours are enabled, empty string +otherwise.""" + +END_COLOR = "" +"""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.""" + + global LIGHT_GREEN + LIGHT_GREEN = "\033[1;32m" + + global LIGHT_RED + LIGHT_RED = "\033[1;31m" + + global LIGHT_BLUE + LIGHT_BLUE = "\033[1;34m" + + global DARK_RED + DARK_RED = "\033[0;31m" + + global END_COLOR + END_COLOR = "\033[0m" + + +def disable_color(): + """Disable colours by setting colour code constants to empty strings.""" + + global LIGHT_GREEN + LIGHT_GREEN = "" + + global LIGHT_RED + LIGHT_RED = "" + + global LIGHT_BLUE + LIGHT_BLUE = "" + + global DARK_RED + DARK_RED = "" + + global END_COLOR + END_COLOR = "" + +enable_color() diff --git a/pym/calculate/contrib/spyne/const/ansi_color.pyc b/pym/calculate/contrib/spyne/const/ansi_color.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c33897d0a07c35249e4c118444bae5f07b9afc2f GIT binary patch literal 1166 zcmcgr&2G~`5Z>61+XN~hkhpMJ<&*=lo1`j-A|P$7QW2$+TMod%Y`iPiYO))7*NSq6 z2jGQx6CQyZFTl(?e^df-0bBk&GdrIBzL~ZAX+GhuHTH<`$tOZ;+#^@*I+pqZ@J^L9Ws;U!P;(<_s-!kd8clNv zfn3u$OK({QtBNwtAz`Y@0=*@^rz+C{T~%qWtF$nyU^CX*{X7$f4#rm(wnm}pLKU~U z%&3xdkxQ-?I%pc;M1E0yhE!Vss29+&s$IfBwMQ7Jt`i2TeUP<>x%fdO*<^}pfQF`% zCDpUAvDlLj-IIQAwza!E_R-otJn2K+v-yX!vF)z82kz+N z{PlHm9!JsGG&X)54NY_7osQl{W*^+)AbykJ8fHf0VRCjkx{TZ4kS*wIaKlm;;WVEd zABFR!xlytgJPUPhL}xWD9qRc~icT-+_Ji(mXTF4tKxA1J5ABpgCUu_J76nk|J`@(V zZB^_k_!?;v&v&c)k8}CmX>?#NF4j5)80LC2nDQ?tBW80012hH9PX{qFs#+Z5PZ2u^ zxIv5qi1B1^+hwhP*RuoIj8~GXroDu~ou-Z3`w%pEnv#U8G)XF=cgQ2}*hj$3|E2)B ZJ)bFFPQ{DIVCx3}zTm7kNdD#EqA`?9NaU zdz>ftwSDVv=~Mqne?s5-16mB06354H1+yOAa2MmCLM*n?r`d|P2$J-VR{z~-w zlD_)y^o9VEo+Xeaz!8umfTJKs0mnd&0iFYS4saagIN$`x3BXB^lYmnorvRrxP6M6? zc^>cr$P0iML0$yB1o9H#WssKvuYkM)copPTz-u6{0bU1r9qQdm!%t-UoRf@BzpNfS-Z<4Dcbyhk&1h{2Wk#6o8LFJ_7s#yt01d@9!L++2k8UWK-K^QkO5!_G6bxHtOL%0oCBN(IS<$X*#P_jqdWnh4I}BIf zVB)-3NC+MFNmVz?Eht9q*Tvd~c%x};1#9FG@9t74mfBg|Qd-|+h9@?%BZXp15#E%* zC4D``9AB(ty%hCDUe&~oQsOm*FV_}Ot!h0ov>W4tnCui{p*1SD^6aEP5UY!woV;M$ce=WiTKB!(uUOsRZqN0qayZy8h9I2 zeTrefL(Z@;X)oXf)f)Mf@5hKLWx&C}i^5Y2AgG37L(y3xySI=e*)eUu#;kflIvQ%l_ z<#}RVrH7_H)OMSN$VCcTmSSv^Osqt4LNFgNuXbjsNoY)8>}Hu*kMcvM@325{Do}p2 zy;g9u^ibbpCLLj_d)*?PC>9t;Vz=K_`Z2TXr+X=Bwxje=aZGl|WqlBHP&kaDo|!6_YZTc9?; zt%zGi5Hx77p~Cn%Hf=p)VT6?V3A-uwEj`8TSld29**0htd6wuR9YZdOBT5L479~8T z&>@L!t4Nc_MUphma^Mu4t7qb8WA1ZYR)M--aEf=&03%GoxRwGK5ZTfcO!HclZ` zv@QKt)Q69wzP2S0QZZWv)XQuOIQ5syCZw_+$etD3L*5e>h<~CkX3NGJ+d0j3eV;|@ z;-@H&Bf`Is=uB*?!;IRoq3pB86H>LWQGFa7#4UDm$50!i%CbE@q#|F>vMyzxq5K*Y zWJo2x7^Qd|Bh~SG+=(fwCoQFr1Z+iwRPq){^Mq~(OSF|1Qt59hbDZVx{%2!hpBnRL za`q|^rsyt0@xj?UDx@PhRYff$C1@W@wMIy4jJ~#}mguYhMh_Z>Xc9^QIwkmR1WI;2 z3dsm`M&Y+nD7_zr_apG@7(dVPa~xtCoOoWU)3ijRQvEN$oC$aj@Sy}BMtC{N{? zs-XdD(hAsj8l!lsdQbAD5)D=##_UGo?#$R*cr*SF{ms|`&e%t@c(v`*WZL90H8U$m z&f5F7Y;60ozS)tWY-{+4bI7O@Gut+uL22){(#^ytE(n)9xp~rqNPN)rR6A_HPU(Z8ICX*IlFaKifajkl6ZHu1^Ggbi$*g3}7NKnJz-pe-GitQ!9 z54}lmvpt>9Ch>kfnCVjQ5*2lLSkPxF zyxPXkbStF5I((?oz5NXPd(>t5Qg0EF?-eLrq0dxloW2vK>5*rTi}X?E}YQa z({T4RTm%i*(}wG5!%$wZZZMx%Jj$<@*4>)wQiY_R3j}rsBha8T3z;xF* zoQAun(b%@L@33|J-}=WSnR!&qrr<6~3mCkhip7ihWM*j;r CdFGt} literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/const/xml.py b/pym/calculate/contrib/spyne/const/xml.py new file mode 100644 index 0000000..e320e0b --- /dev/null +++ b/pym/calculate/contrib/spyne/const/xml.py @@ -0,0 +1,187 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.const.xml`` module contains various XML-related constants like +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/' + +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, +} + +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', +} + + +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: + return WSDL11_SOAP12 + elif 'http' in protocol_type: + return WSDL11_HTTP + else: + # Bind to Soap1.1 namespace by default for backwards compatibility + return WSDL11_SOAP + + +def Tnswrap(ns): + return lambda s: "{%s}%s" % (ns, s) + + +XML = Tnswrap(NS_XML) +XSD = Tnswrap(NS_XSD) +XSI = Tnswrap(NS_XSI) +WSA = Tnswrap(NS_WSA) +XOP = Tnswrap(NS_XOP) +XHTML = Tnswrap(NS_XHTML) +PLINK = Tnswrap(NS_PLINK) +SOAP11_ENC = Tnswrap(NS_SOAP11_ENC) +SOAP11_ENV = Tnswrap(NS_SOAP11_ENV) +SOAP12_ENC = Tnswrap(NS_SOAP12_ENC) +SOAP12_ENV = Tnswrap(NS_SOAP12_ENV) +WSDL11 = Tnswrap(NS_WSDL11) +WSDL11_SOAP = Tnswrap(NS_WSDL11_SOAP) +WSDL11_SOAP12 = Tnswrap(NS_WSDL11_SOAP12) +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 diff --git a/pym/calculate/contrib/spyne/const/xml.pyc b/pym/calculate/contrib/spyne/const/xml.pyc new file mode 100644 index 0000000000000000000000000000000000000000..25aaffe8333b43b01e1b5eb053c79d85a72e3214 GIT binary patch literal 6367 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 Ia9*o?2L2GeJpcdz literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/context.py b/pym/calculate/contrib/spyne/context.py new file mode 100644 index 0000000..bdcebc5 --- /dev/null +++ b/pym/calculate/contrib/spyne/context.py @@ -0,0 +1,463 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import gc, logging +logger = logging.getLogger('spyne') + +from time import time +from copy import copy +from collections import deque, defaultdict + +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.""" + + self.error = error + """Error from primary context (if any).""" + + +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""" + + self.itself = transport + """The transport itself; i.e. a ServerBase instance.""" + + self.type = type + """The protocol the transport uses.""" + + self.app = transport.app + + self.request_encoding = None + """General purpose variable to hold the string identifier of a request + encoding. It's nowadays usually 'utf-8', especially with http data""" + + self.remote_addr = None + """The address of the other end of the connection.""" + + self.sessid = '' + """The session id.""" + + def get_peer(self): + """Returns None when not applicable, otherwise returns + :class:`spyne.Address`""" + + return None + + +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""" + + self.itself = transport + """The protocol itself as passed to the `Application` init. This is a + `ProtocolBase` instance.""" + + self.type = type + """The protocol the transport uses.""" + + self._subctx = defaultdict( + lambda: self.__class__(parent, transport, type)) + + def __getitem__(self, item): + return self._subctx[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 + + +class MethodContext(object): + """The base class for all RPC Contexts. Holds all information about the + current state of execution of a remote procedure call. + """ + + SERVER = type("SERVER", (object,), {}) + CLIENT = type("CLIENT", (object,), {}) + TransportContext = TransportContext + + frozen = False + + def copy(self): + retval = copy(self) + + if retval.transport is not None: + retval.transport.parent = retval + if retval.inprot_ctx is not None: + retval.inprot_ctx.parent = retval + if retval.outprot_ctx is not None: + retval.outprot_ctx.parent = retval + if retval.event is not None: + retval.event.parent = retval + if retval.aux is not None: + retval.aux.parent = retval + + return retval + + def fire_event(self, event, *args, **kwargs): + self.app.event_manager.fire_event(event, self, *args, **kwargs) + + desc = self.descriptor + if desc is not None: + for evmgr in desc.event_managers: + evmgr.fire_event(event, self, *args, **kwargs) + + @property + def method_name(self): + """The public name of the method the ``method_request_string`` was + matched to. + """ + + if self.descriptor is None: + return None + else: + return self.descriptor.name + + def __init__(self, transport, way): + # metadata + self.call_start = time() + """The time the rpc operation was initiated in seconds-since-epoch + format. + + Useful for benchmarking purposes.""" + + self.call_end = None + """The time the rpc operation was completed in seconds-since-epoch + format. + + Useful for benchmarking purposes.""" + + self.is_closed = False + """`True` means response is fully sent and request finalized.""" + + self.app = transport.app + """The parent application.""" + + self.udc = None + """The user defined context. Use it to your liking.""" + + self.transport = None + """The transport-specific context. Transport implementors can use this + to their liking.""" + + if self.TransportContext is not None: + self.transport = self.TransportContext(self, transport) + + self.outprot_ctx = None + """The output-protocol-specific context. Protocol implementors can use + this to their liking.""" + + if self.app.out_protocol is not None: + self.outprot_ctx = self.app.out_protocol.get_context(self, transport) + + self.inprot_ctx = None + """The input-protocol-specific context. Protocol implementors can use + this to their liking.""" + + if self.app.in_protocol is not None: + self.inprot_ctx = self.app.in_protocol.get_context(self, transport) + + self.protocol = None + """The protocol-specific context. This points to the in_protocol when an + incoming message is being processed and out_protocol when an outgoing + message is being processed.""" + + if way is MethodContext.SERVER: + self.protocol = self.inprot_ctx + elif way is MethodContext.CLIENT: + self.protocol = self.outprot_ctx + else: + raise ValueError(way) + + self.event = EventContext(self) + """Event-specific context. Use this as you want, preferably only in + events, as you'd probably want to separate the event data from the + method data.""" + + self.aux = None + """Auxiliary-method specific context. You can use this to share data + between auxiliary sessions. This is not set in primary contexts. + """ + + self.method_request_string = None + """This is used to decide which native method to call. It is set by + the protocol classes.""" + + self.files = [] + """List of stuff to be closed when closing this context. Anything that + has a close() callable can go in.""" + + self.active = False + """Transports may choose to delay incoming requests. When a context + is queued but waiting, this is False.""" + + self.__descriptor = None + + # + # Input + # + + # stream + self.in_string = None + """Incoming bytestream as a sequence of ``str`` or ``bytes`` + instances.""" + + # parsed + self.in_document = None + """Incoming document, what you get when you parse the incoming + stream.""" + self.in_header_doc = None + """Incoming header document of the request.""" + self.in_body_doc = None + """Incoming body document of the request.""" + + # native + self.in_error = None + """Native python error object. If this is set, either there was a + parsing error or the incoming document was representing an exception. + """ + self.in_header = None + """Deserialized incoming header -- a native object.""" + self.in_object = None + """In the request (i.e. server) case, this contains the function + argument sequence for the function in the service definition class. + In the response (i.e. client) case, this contains the object returned + by the remote procedure call. + + It's always a sequence of objects: + * ``[None]`` when the function has no output (client)/input (server) + types. + * A single-element list that wraps the return value when the + function has one return type defined, + * A tuple of return values in case of the function having more than + one return value. + + The order of the argument sequence is in line with + ``self.descriptor.in_message._type_info.keys()``. + """ + + # + # Output + # + + # native + self.out_object = None + """In the response (i.e. server) case, this contains the native python + object(s) returned by the function in the service definition class. + In the request (i.e. client) case, this contains the function arguments + passed to the function call wrapper. + + It's always a sequence of objects: + * ``[None]`` when the function has no output (server)/input (client) + types. + * A single-element list that wraps the return value when the + function has one return type defined, + * A tuple of return values in case of the function having more than + one return value. + + The order of the argument sequence is in line with + ``self.descriptor.out_message._type_info.keys()``. + """ + self.out_header = None + """Native python object set by the function in the service definition + class.""" + self.out_error = None + """Native exception thrown by the function in the service definition + class.""" + + # parsed + self.out_body_doc = None + """Serialized body object.""" + self.out_header_doc = None + """Serialized header object.""" + self.out_document = None + """out_body_doc and out_header_doc wrapped in the outgoing envelope""" + + # stream + self.out_string = None + """The pull interface to the outgoing bytestream. It's a sequence of + strings (which could also be a generator).""" + + self.out_stream = None + """The push interface to the outgoing bytestream. It's a file-like + object.""" + + self.function = None + """The callable of the user code.""" + + self.locale = None + """The locale the request will use when needed for things like date + formatting, html rendering and such.""" + + self._in_protocol = transport.app.in_protocol + """The protocol that will be used to (de)serialize incoming input""" + + self._out_protocol = transport.app.out_protocol + """The protocol that will be used to (de)serialize outgoing input""" + + self.pusher_stack = [] + """Last one is the current PushBase instance writing to the stream.""" + + self.frozen = True + """When this is set, no new attribute can be added to this class + instance. This is mostly for internal use. + """ + + self.fire_event("method_context_created") + + def get_descriptor(self): + return self.__descriptor + + def set_descriptor(self, descriptor): + self.__descriptor = descriptor + self.function = descriptor.function + + descriptor = property(get_descriptor, set_descriptor) + """The :class:``MethodDescriptor`` object representing the current method. + It is only set when the incoming request was successfully mapped to a method + in the public interface. The contents of this property should not be changed + by the user code. + """ + + # FIXME: Deprecated. Use self.descriptor.service_class. + @property + def service_class(self): + if self.descriptor is not None: + 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'): + object.__setattr__(self, k, v) + else: + 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(['{']) + + for k2, v2 in sorted(v.items()): + ret.append('\t\t%r: %r,' % (k2, v2)) + + 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)') + + return ''.join((self.__class__.__name__, '(', ', '.join(retval), ')')) + + def close(self): + global _LAST_GC_RUN + + self.call_end = time() + self.app.event_manager.fire_event("method_context_closed", self) + for f in self.files: + f.close() + + self.is_closed = True + + # this is important to have file descriptors returned in a timely manner + t = time() + if (t - _LAST_GC_RUN) > const.MIN_GC_INTERVAL: + gc.collect() + + dt = (time() - t) + _LAST_GC_RUN = t + + logger.debug("gc.collect() took around %dms.", round(dt, 2) * 1000) + + def set_out_protocol(self, what): + self._out_protocol = what + if self._out_protocol.app is None: + self._out_protocol.set_app(self.app) + + def get_out_protocol(self): + return self._out_protocol + + out_protocol = property(get_out_protocol, set_out_protocol) + + def set_in_protocol(self, what): + self._in_protocol = what + self._in_protocol.app = self.app + + def get_in_protocol(self): + return self._in_protocol + + in_protocol = property(get_in_protocol, set_in_protocol) + + +class FakeContext(object): + def __init__(self, app=None, descriptor=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_object = in_object + self.in_error = in_error + self.in_document = in_document + self.in_string = in_string + self.out_error = out_error + self.out_object = out_object + self.out_document = out_document + self.out_string = out_string + self.in_protocol = in_protocol + self.out_protocol = out_protocol + + if self.in_protocol is not None: + self.inprot_ctx = self.in_protocol.get_context(self, None) + else: + self.inprot_ctx = type("ProtocolContext", (object,), {})() + + from spyne.protocol.html._base import HtmlClothProtocolContext + + if self.out_protocol is not None: + self.outprot_ctx = self.out_protocol.get_context(self, None) + else: + # The outprot_ctx here must contain properties from ALL tested + # protocols' context objects. That's why we use + # HtmlClothProtocolContext here, it's just the one with most + # attributes. + self.outprot_ctx = HtmlClothProtocolContext(self, None) + + self.protocol = self.outprot_ctx + self.transport = type("ProtocolContext", (object,), {})() diff --git a/pym/calculate/contrib/spyne/context.pyc b/pym/calculate/contrib/spyne/context.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4be9555cd711b08ab8f791071227b0756504b875 GIT binary patch literal 10859 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 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 + # argument, it would have to be serialized as multiple body entries, + # 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.") + + if len(in_params) == 0: + message = ComplexModel.produce(type_name=in_message_name, + namespace=ns, members=in_params) + else: + 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") + + # 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) + + else: + message = ComplexModel.produce(type_name=in_message_name, + namespace=ns, members=in_params) + message.__namespace__ = ns + + if in_wsdl_part_name: + message = message.customize(wsdl_part_name=in_wsdl_part_name) + + return message + + +def _validate_body_style(kparams): + _body_style = kparams.pop('_body_style', None) + _soap_body_style = kparams.pop('_soap_body_style', None) + + allowed_body_styles = ('wrapped', 'bare', 'out_bare') + if _body_style is None: + _body_style = 'wrapped' + + elif not (_body_style in 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 == 'rpc': + _body_style = 'bare' + + elif _soap_body_style is None: + pass + + else: + raise ValueError("soap_body_style must be one of ('rpc', 'document')") + + 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): + """Generate an output message for "rpc"-style API methods. + + This message is a wrapper to the declared return type. + """ + + _returns = kparams.pop('_returns', None) + + try: + is_self_ref = issubclass(_returns, SelfReference) + except TypeError: + is_self_ref = False + + if is_self_ref: + if no_self is False: + raise LogicError("SelfReference can't be used in @rpc") + + _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)) + + 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_params = TypeInfo() + + 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))] + + _out_variable_names = kparams.pop('_out_variable_names', + default_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_params[_out_variable_name] = _returns + + ns = spyne.const.xml.DEFAULT_NS + if _out_message_name.startswith("{"): + _out_message_name_parts = _out_message_name[1:].partition("}") + 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: + 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.Attributes._wrapper = True + message.__namespace__ = ns # FIXME: is this necessary? + + if _out_wsdl_part_name: + message = message.customize(wsdl_part_name=_out_wsdl_part_name) + + return message + + +def _substitute_self_reference(params, kparams, self_ref_replacement, _no_self): + from spyne.model import SelfReference + + for i, v in enumerate(params): + if isclass(v) and issubclass(v, SelfReference): + if _no_self: + raise LogicError("SelfReference can't be used in @rpc") + params[i] = recust_selfref(v, self_ref_replacement) + else: + params[i] = v + + for k, v in kparams.items(): + if isclass(v) and issubclass(v, SelfReference): + if _no_self: + raise LogicError("SelfReference can't be used in @rpc") + kparams[k] = recust_selfref(v, self_ref_replacement) + else: + kparams[k] = v + + +def _get_event_managers(kparams): + _evmgr = kparams.pop("_evmgr", None) + _evmgrs = kparams.pop("_evmgrs", None) + + if _evmgr is not None and _evmgrs is not None: + raise LogicError("Pass one of _evmgr or _evmgrs but not both") + + if _evmgr is not None: + _evmgrs = [_evmgr] + + _event_manager = kparams.pop("_event_manager", None) + _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") + + 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") + elif _evmgrs is not None: + _event_managers = _evmgrs + + return _event_managers if _event_managers is not None else [] + + +def rpc(*params, **kparams): + """Method decorator to tag a method as a remote procedure call in a + :class:`spyne.service.Service` subclass. + + You should use the :class:`spyne.server.null.NullServer` transport if you + want to call the methods directly. You can also use the 'function' attribute + of the returned object to call the function itself. + + ``_operation_name`` vs ``_in_message_name``: + Soap clients(SoapUI, Savon, suds) will use the operation name as the + function name. The name of the input message(_in_message_name) is irrelevant + when interfacing in this manner; this is because the clients mostly wrap + around it. However, the soap xml request only uses the input message when + posting with the soap server; the other protocols only use the input message + as well. ``_operation_name`` cannot be used with ``_in_message_name``. + + :param _returns: Denotes The return type of the function. It can be a + type or a sequence of types for functions that have multiple return + values. + :param _in_header: A type or an iterable of types that that this method + accepts as incoming header. + :param _out_header: A type or an iterable of types that that this method + sends as outgoing header. + :param _operation_name: The function's soap operation name. The operation + and SoapAction names will be equal to the value of ``_operation_name``. + Default is the function name. + :param _in_message_name: The public name of the function's input message. + Default is: ``_operation_name + REQUEST_SUFFIX``. + :param _out_message_name: The public name of the function's output message. + Default is: ``_operation_name + RESPONSE_SUFFIX``. + :param _in_arg_names: The public names of the function arguments. It's + a dict that maps argument names in the code to public ones. + :param _in_variable_names: **DEPRECATED** Same as _in_arg_names, kept for + backwards compatibility. + :param _out_variable_name: The public name of the function response object. + It's a string. Ignored when ``_body_style != 'wrapped'`` or ``_returns`` + is a sequence. + :param _out_variable_names: The public name of the function response object. + It's a sequence of strings. Ignored when ``_body_style != 'wrapped'`` or + or ``_returns`` is not a sequence. Must be the same length as + ``_returns``. + :param _body_style: One of ``('bare', 'wrapped')``. Default: ``'wrapped'``. + In wrapped mode, wraps response objects in an additional class. + :param _soap_body_style: One of ('rpc', 'document'). Default ``'document'``. + ``_soap_body_style='document'`` is an alias for + ``_body_style='wrapped'``. ``_soap_body_style='rpc'`` is an alias for + ``_body_style='bare'``. + :param _port_type: Soap port type string. + :param _no_ctx: Don't pass implicit ctx object to the user method. + :param _no_self: This method does not get an implicit 'self' argument + (before any other argument, including ctx). + :param _udd: Short for User Defined Data, you can use this to mark the + method with arbitrary metadata. + :param _udp: **DEPRECATED** synonym of ``_udd``. + :param _aux: The auxiliary backend to run this method. ``None`` if primary. + :param _throws: A sequence of exceptions that this function can throw. This + has no real functionality besides publishing this information in + interface documents. + :param _args: the name of the arguments to expose. + :param _event_managers: An iterable of :class:`spyne.EventManager` + instances. This is useful for adding additional event handlers to + individual functions. + :param _event_manager: An instance of :class:`spyne.EventManager` class. + :param _logged: May be the string '...' to denote that the rpc arguments + will not be logged. + :param _evmgrs: Same as ``_event_managers``. + :param _evmgr: Same as ``_event_manager``. + :param _service_class: A :class:`Service` subclass. It's generally not a + good idea to override it for ``@rpc`` methods. It could be necessary to + override it for ``@mrpc`` methods to add events and other goodies. + :param _service: Same as ``_service``. + :param _wsdl_part_name: Overrides the part name attribute within wsdl + input/output messages eg "parameters" + """ + + params = list(params) + + def explain(f): + def explain_method(**kwargs): + # params and kparams are passed by the user to the @rpc family + # of decorators. + + # kwargs is passed by spyne while sanitizing methods. it mainly + # contains information about the method context like the service + # class that contains the method at hand. + + 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) + _pattern = kparams.pop("_pattern", None) + _patterns = kparams.pop("_patterns", []) + _args = kparams.pop("_args", None) + _translations = kparams.pop("_translations", None) + _when = kparams.pop("_when", None) + _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: + _service_class = kparams.pop("_service") + if '_service_class' in kparams: + _service_class = kparams.pop("_service_class") + + _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) + + _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.") + + elif '_faults' in kparams: + _faults = kparams.pop('_faults') + + 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) + + 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) + + _operation_name = kparams.pop('_operation_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") + + 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') + + 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: + raise LogicError("Use either '_udd' or '_udp', not both.") + elif '_udd' in kparams: + _udd = kparams.pop('_udd') + + elif '_udp' in kparams: + _udd = kparams.pop('_udp') + + else: + _udd = {} + + _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': + 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) + + 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__') + + if _pattern is not None and _patterns != []: + 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'): + 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: + 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, + 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, + translations=_translations, + 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, + logged=_logged, + ) + + if _patterns is not None and _no_self: + for p in _patterns: + p.hello(retval) + + if len(kparams) > 0: + raise ValueError("Unknown kwarg(s) %r passed.", kparams) + return retval + + explain_method.__doc__ = f.__doc__ + explain_method._is_rpc = True + + return explain_method + + return explain + + +def srpc(*params, **kparams): + """Method decorator to tag a method as a remote procedure call. See + :func:`spyne.decorator.rpc` for detailed information. + + The initial "s" stands for "static". In Spyne terms, that means no implicit + first argument is passed to the user callable, which really means the + method is "stateless" rather than static. It's meant to be used for + existing functions that can't be changed. + """ + + kparams["_no_ctx"] = True + return rpc(*params, **kparams) + + +def mrpc(*params, **kparams): + kparams["_no_self"] = False + return rpc(*params, **kparams) diff --git a/pym/calculate/contrib/spyne/decorator.pyc b/pym/calculate/contrib/spyne/decorator.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42f8e720e6d58536a6239bdc53c36c932449951a GIT binary patch literal 17381 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 MRCyWDq@VIX0esSQf&c&j literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/error.py b/pym/calculate/contrib/spyne/error.py new file mode 100644 index 0000000..20cfd79 --- /dev/null +++ b/pym/calculate/contrib/spyne/error.py @@ -0,0 +1,154 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +"""The ``spyne.error`` module contains various common exceptions that the user +code can throw. +""" + +from spyne.model.fault import Fault + + +class InvalidCredentialsError(Fault): + """Raised when requested resource is forbidden.""" + + 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) + + +class RequestTooLongError(Fault): + """Raised when request is too long.""" + + CODE = 'Client.RequestTooLong' + + def __init__(self, faultstring="Request too long"): + super(RequestTooLongError, self).__init__(self.CODE, faultstring) + + +class RequestNotAllowed(Fault): + """Raised when request is incomplete.""" + + CODE = 'Client.RequestNotAllowed' + + def __init__(self, faultstring=""): + super(RequestNotAllowed, self).__init__(self.CODE, faultstring) + + +class ArgumentError(Fault): + """Raised when there is a general problem with input data.""" + + CODE = 'Client.ArgumentError' + + def __init__(self, faultstring=""): + super(ArgumentError, self).__init__(self.CODE, faultstring) + + +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))) + + +InvalidRequestError = InvalidInputError + + +class MissingFieldError(InvalidInputError): + """Raised when a mandatory value is missing.""" + + CODE = 'Client.InvalidInput' + + def __init__(self, field_name, message="Field '%s' is missing."): + try: + message = message % (field_name,) + except TypeError: + pass + + 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' + + def __init__(self, error): + 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' + + 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): + pass + + +class ResourceAlreadyExistsError(Fault): + """Raised when requested resource already exists on server side.""" + + CODE = 'Client.ResourceAlreadyExists' + + def __init__(self, fault_object, fault_string="Resource %r already exists"): + 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' + + def __init__(self, ctx, location, orig_exc=None): + super(Redirect, self).__init__(self.CODE, faultstring=location) + + self.ctx = ctx + self.location = location + self.orig_exc = orig_exc + + def do_redirect(self): + raise NotImplementedError() diff --git a/pym/calculate/contrib/spyne/error.pyc b/pym/calculate/contrib/spyne/error.pyc new file mode 100644 index 0000000000000000000000000000000000000000..03bb796f3da5b87210e0f395d49bb354886362eb GIT binary patch literal 7407 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 a1{=@+VBu0@3>my1bN1O=jEE}rdgm`O@LmZ3 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/interface/__init__.py b/pym/calculate/contrib/spyne/interface/__init__.py new file mode 100644 index 0000000..e0044a2 --- /dev/null +++ b/pym/calculate/contrib/spyne/interface/__init__.py @@ -0,0 +1,43 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +"""The ``spyne.interface`` package contains implementations of various interface +definition document standards along with the +:class:`spyne.interface.Interface` class which holds all the information needed +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 AllYourInterfaceDocuments + + +try: + from spyne.interface.wsdl.wsdl11 import Wsdl11 + HAS_WSDL = True + +except ImportError as e: + if 'No module named lxml' in e.args or "No module named 'lxml'" in e.args: + HAS_WSDL = False + else: + raise diff --git a/pym/calculate/contrib/spyne/interface/__init__.pyc b/pym/calculate/contrib/spyne/interface/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5cd3e98c746efbb725d212dc22997f0b6f050e90 GIT binary patch literal 947 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 Ody!6n`(^5! zf5^FD=@j8G9`}zGPQi&h1#9Q1f80Oqk9pKXrwWYx9fegzC-V`MjeC!v`r*g;I>#4Jka`{Hz7V5ad}iUVGApM~&NNrq2Zp2`)K@qm z4>Y$WVVcrV$)7x29w`^#6)2S_$|sR7mq+njEiaTy<1df<<>TXNN>9qAX7lwNP+@GgL0bNBBHWNU>q$qql;=w{E0VG2FKGYdO`6n(dRhO5pzASdCek_+qXet~e{5o36$C1hre+Sv{xA>9@Bpxv1 zBB7Q5O84mw<5^SQqONG2>mZRUVYBH$(HU<`4slt;a>+}njNC&ym%&x)sE~g+rsgsp z`vhK&dO$-GJbDuenCtqDCv0{7#&d`yMM{zzuN=&|KdF@H_mU2mc`%I(VLx+PjzC5Prf(0TH)`@T_-@0bD}+m zb|Oyl*ak$)p#ORmxB`mc%--zT6bg1d!hLWX@T)lf!bfdmd`+CY(SRGh*zW?r8bOg* zihKZ@1!?ZVIDO&u8bTZh%BJ~n{qIJCSE16md;Qd^^A%^8&VdJKG*J2Le*ut>mG{89 z#e3hX?LvfFUZZ!ntVLxMga&JI!f9HFAfYwBH{{;?x6*`pz93q^D4=dW3Rl7&R}8`3 zI_XOp9Y+oQN`#fdf*w3+z_vF=fIe_ZBKzFv51oOA(a1X&a3W0^hUn2y_0)6Zvxy)_Q)!;cQC}en zzsf96fA}rFzKvIZsginNJm+^Y*92EKf<&o^*hH~ho~LypY8o%t;OvN;#4r z>uf{irrrTpkzlLUuLR}P&}7-i$iv@8Sx8EiOG09NXp>$VH`RsC0kuqSl&VE0;2LH> zu2K%JSDM=%}5hwQ&uIcPT4GFi5;-V?4XZ% zCwW=|&vR_n9)$A|+Jz}Vtk70@&Kpy_ni6;sd^FA@H=et?sh|dOL>D{{3myr9-5eo~ zo+*zjp*Tk4t!eE!rC4rO#zo|d(DJuXbyNo0?RHOdzTAN3ZJ*#_wPj7j#hxWb?uSN} z(6!@`q_3vbeKzPFha_6tP-q>`$o}t1n|CSoK*ucmEBHct*BK}PsY*)eU3E9|x)iC`9 D(mR72 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/interface/wsdl/defn.py b/pym/calculate/contrib/spyne/interface/wsdl/defn.py new file mode 100644 index 0000000..e072b28 --- /dev/null +++ b/pym/calculate/contrib/spyne/interface/wsdl/defn.py @@ -0,0 +1,108 @@ + +from spyne.util.six import add_metaclass + +from spyne.const import xml + +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): + __namespace__ = xml.NS_WSDL11 + + +@add_metaclass(ComplexModelMeta) +class Soap11Base(ComplexModelBase): + __namespace__ = xml.NS_WSDL11_SOAP + + +class Types(Wsdl11Base): + schema = XmlSchema10.customize(max_occurs="unbounded") + + +class MessagePart(Wsdl11Base): + element = XmlAttribute(Unicode) + name = XmlAttribute(Unicode) + + +class Message(Wsdl11Base): + part = MessagePart + name = XmlAttribute(Unicode) + + +class SoapBodyDefinition(Wsdl11Base): + use = XmlAttribute(Unicode) + + +class SoapHeaderDefinition(Wsdl11Base): + use = XmlAttribute(Unicode) + message = XmlAttribute(Unicode) + part = XmlAttribute(Unicode) + + +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") + + +class SoapOperation(Wsdl11Base): + soapAction = XmlAttribute(Unicode) + style = XmlAttribute(Unicode) + + +class Operation(Wsdl11Base): + input = OperationMode + output = OperationMode + 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") + + +class SoapBinding(Soap11Base): + style = XmlAttribute(Unicode) + transport = XmlAttribute(Unicode) + + +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") + + +class PortAddress(Soap11Base): + location = XmlAttribute(Unicode) + + +class ServicePort(Wsdl11Base): + name = XmlAttribute(Unicode) + binding = XmlAttribute(Unicode) + address = PortAddress.customize(sub_ns=xml.NS_WSDL11_SOAP) + + +class Service(Wsdl11Base): + port = ServicePort + name = XmlAttribute(Unicode) + + +class Wsdl11(Wsdl11Base): + _type_info = [ + ('types', Types), + ('message', Message.customize(max_occurs="unbounded")), + ('service', Service), + ('portType', PortType), + ('binding', Binding), + ] diff --git a/pym/calculate/contrib/spyne/interface/wsdl/defn.pyc b/pym/calculate/contrib/spyne/interface/wsdl/defn.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b22a54a1f0d4b2f0876caccebd676e0a1d4dff4c GIT binary patch literal 5810 zcmcgw>2e!I5bl+A+H&GJv2z~~k|=qp(R8P(_X!0RjC{WX;%FvxiE%3O0Yu zYw;#L0{?gb=&wgRTH7(HO2vvY>zUr!nf#CE|6Z#q^F(q6zMaWbje8o^<)X6F%44c2?f5qBQ(W_G1HyHdOV!i2rmJLxQspCvk2UB%Om z#CX+pZpkUW7y@@qfwq~nMN;hs3#n1!OIqbiw;T0B)9uP)-EJ7`QNTkbcxyc2al8Ah z{qXzMRY7m3Cxc#}C)uTV4oNS0#=X`k8MXp{U6@KQ|-j+#P z$zV4!D|ef#A2nC+uMBp1M$>FT>-lSK8y4O_Z-r0`^nl<1#M3gA$YRLEkg(s{jfVQi8CyCCWgJhoxEXfq}n6T zS{N!41%G19V^g75I+^;qvdG@E|pr+yqA27QL-9X4}5nC0L)fGK(-j;s792lQCu)H&Yj z2DgmCcyl29*7UR){vXBRfliD z!E9g~ZFHkV@?U~3d%XC^2GdX`ybxt zNFWo@cx9I5jB%`tyu@3zxFtw1)((qa&0DnA05_dQoHgENd_|Q4=xco#J%yo@bT^o) zS6=5$Kf%T>#v-*MD!FlImm<0X82^t5oeknf0K9r z0(GNnB7qH>&8#1=gIX z!MZ2bwaUAN$=q_6WA!*h@`v0eY(pIbPh0mR?MGWq32)KQ)D7N4h?Wj}Q8HkCPZRSB z@BZCB%qT(*;&uM@4c~l)(Q|cMKG_-TZv04%wr6vGHwRXLNowM2*muL~xq*;(BtstMbKg_8&E1J~Z zeb9tM$LcNjct0fltYQ*hF~gUB-vFM&1v5*)_?SDd;m-aF0r6uNOu4xB}{i>L}Usy`1x`AR~kM5Zj$%EV!XC0l%YR|Pwu zQOU!I35hN5T(Xf;ILd{#^{9N-MHxNFhdXU4J<|y@pX5#NC7LSWp9NIMdF_+Eu!~`FY zb~2wCnV>ls`XPV4y)^c#8sD7x+kJc1Wr>9w5~mRXyWuo!Ps*C zqa>V*Zn3;ouoU3nyFwjhOD0MEqHhW2P`Y(zkX(s1pouAJUMTaqJze_}Zkiy>E)@9Z b$&Y(=Z@GxZzY_n7%jM-7|E" + + # 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] + + 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) + + # create types node + types = SubElement(root, WSDL11("types")) + for s in self.schema_dict.values(): + types.append(s) + + messages = set() + for s in self.interface.services: + self.add_messages_for_methods(s, root, messages) + + if self._with_plink: + plink = SubElement(root, PLINK("partnerLinkType")) + plink.set('name', service_name) + self.__add_partner_link(service_name, plink) + + # create service nodes in advance. they're to be filled in subsequent + # add_port_type calls. + for s in self.interface.services: + if not s.is_auxiliary(): + self._get_or_create_service_node(self._get_applied_service_name(s)) + + # create portType nodes + for s in self.interface.services: + if not s.is_auxiliary(): + self.add_port_type(s, root, service_name, types, 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) + + if self.interface.app.transport is None: + 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.__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.""" + + ns_tns = self.interface.tns + pref_tns = self.interface.get_namespace_prefix(ns_tns) + + role = SubElement(plink, PLINK("role")) + role.set('name', service_name) + + plink_port_type = SubElement(role, PLINK("portType")) + 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) + + plink_port_type = SubElement(role, PLINK("portType")) + 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""" + + 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)) + + addr = SubElement(wsdl_port, + ns.get_binding_ns(self.interface.app.in_protocol.type)("address")) + + addr.set('location', self.url) + + def _has_callbacks(self): + for s in self.interface.services: + if s._has_callbacks(): + return True + + return False + + def _get_applied_service_name(self, service): + if service.get_service_name() is None: + # This is the default behavior. i.e. no service interface is + # defined in the service heading + if len(self.interface.services) == 1: + retval = self.get_name() + else: + retval = service.get_service_class_name() + else: + retval = service.get_service_name() + + return retval + + 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) + applied_service_name = self._get_applied_service_name(service) + + port_binding_names = [] + port_type_list = service.get_port_types() + 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) + + 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) + + binding_name = self._get_binding_name(service_name) + port_binding_names.append((service_name, binding_name)) + + for method in service.public_methods.values(): + check_method_port(service, method) + + if method.is_callback: + operation = SubElement(cb_port_type, WSDL11("operation")) + else: + operation = SubElement(port_type, WSDL11("operation")) + + 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()) + + 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)) + + 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)) + + 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())) + + ser = self.service_elt_dict[applied_service_name] + for port_name, binding_name in port_binding_names: + self._add_port_to_service(ser, port_name, binding_name) + + def _add_message_for_object(self, root, messages, obj, message_name): + if obj is not None and not (message_name in messages): + messages.add(message_name) + + message = SubElement(root, WSDL11("message")) + message.set('name', message_name) + + if isinstance(obj, (list, tuple)): + objs = obj + else: + objs = (obj,) + + 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)) + + 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)) + 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)) + 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) + + for fault in method.faults: + self._add_message_for_object(root, messages, fault, + fault.get_type_name()) + + 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) + output_binding_ns = ns.get_binding_ns(self.interface.app.out_protocol.type) + + def inner(method, binding): + operation = etree.Element(WSDL11("operation")) + 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') + + # get input + input = SubElement(operation, WSDL11("input")) + input.set('name', method.in_message.get_element_name()) + + soap_body = SubElement(input, input_binding_ns("body")) + soap_body.set('use', 'literal') + + # get input soap header + in_header = method.in_header + if in_header is None: + in_header = service.__in_header__ + + if not (in_header is None): + if isinstance(in_header, (list, tuple)): + in_headers = in_header + else: + in_headers = (in_header,) + + if len(in_headers) > 1: + 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()) + + if not (method.is_async or method.is_callback): + output = SubElement(operation, WSDL11("output")) + output.set('name', method.out_message.get_element_name()) + + soap_body = SubElement(output, output_binding_ns("body")) + soap_body.set('use', 'literal') + + # get output soap header + out_header = method.out_header + if out_header is None: + out_header = service.__out_header__ + + if not (out_header is None): + if isinstance(out_header, (list, tuple)): + out_headers = out_header + else: + out_headers = (out_header,) + + if len(out_headers) > 1: + 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' % ( + header.get_namespace_prefix(self.interface), + 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()) + + soap_fault = SubElement(wsdl_fault, input_binding_ns("fault")) + 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') + + 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') + + 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') + + binding.append(operation) + + port_type_list = service.get_port_types() + if len(port_type_list) > 0: + for port_type_name in port_type_list: + + # 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)) + + transport = SubElement(binding, input_binding_ns("binding")) + 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: + inner(m, binding) + + else: + # 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)) + + transport = SubElement(cb_binding, input_binding_ns("binding")) + transport.set('style', 'document') + transport.set('transport', self.interface.app.transport) + + for m in service.public_methods.values(): + inner(m, cb_binding) + + return cb_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' + input_binding_ns = ns.get_binding_ns(self.interface.app.in_protocol.type) + + cb_port_type = None + + # add necessary async headers + # WS-Addressing -> RelatesTo ReplyTo MessageID + # callback porttype + if service._has_callbacks(): + wsa_schema = SubElement(types, XSD("schema")) + wsa_schema.set("targetNamespace", '%sCallback' % ns_tns) + wsa_schema.set("elementFormDefault", "qualified") + + import_ = SubElement(wsa_schema, XSD("import")) + import_.set("namespace", NS_WSA) + import_.set("schemaLocation", NS_WSA) + + relt_message = SubElement(root, WSDL11("message")) + 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) + + reply_message = SubElement(root, WSDL11("message")) + 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) + + id_header = SubElement(root, WSDL11("message")) + 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) + + # make portTypes + cb_port_type = SubElement(root, WSDL11("portType")) + cb_port_type.set('name', '%sCallback' % service_name) + + cb_service_name = '%sCallback' % service_name + + cb_service = SubElement(root, WSDL11("service")) + 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_address = SubElement(cb_wsdl_port, input_binding_ns("address")) + cb_address.set('location', url) + + return cb_port_type diff --git a/pym/calculate/contrib/spyne/interface/wsdl/wsdl11.pyc b/pym/calculate/contrib/spyne/interface/wsdl/wsdl11.pyc new file mode 100644 index 0000000000000000000000000000000000000000..882e3afa28cbfa2230c3bbc193f6f1e0f21f8934 GIT binary patch literal 16606 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/interface/xml_schema/defn.py b/pym/calculate/contrib/spyne/interface/xml_schema/defn.py new file mode 100644 index 0000000..a22fb7c --- /dev/null +++ b/pym/calculate/contrib/spyne/interface/xml_schema/defn.py @@ -0,0 +1,188 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# 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 + + +@add_metaclass(ComplexModelMeta) +class SchemaBase(ComplexModelBase): + __namespace__ = xml.NS_XSD + + +class Import(SchemaBase): + namespace = XmlAttribute(Unicode) + + +class Element(SchemaBase): + name = XmlAttribute(Unicode) + type = XmlAttribute(Unicode) + ref = XmlAttribute(Unicode) + # it can be "unbounded", so it should be of type Unicode + max_occurs = XmlAttribute(Unicode(default="1", sub_name="maxOccurs")) + # Also Unicode for consistency with max_occurs + min_occurs = XmlAttribute(Unicode(default="1", sub_name="minOccurs")) + nillable = XmlAttribute(Boolean(default=False)) + default = XmlAttribute(Unicode) + + +class IntegerAttribute(SchemaBase): + value = XmlAttribute(UnsignedInteger) + + +class StringAttribute(SchemaBase): + value = XmlAttribute(Unicode) + + +class List(SchemaBase): + _type_info = [ + ('item_type', XmlAttribute(Unicode(sub_name='itemType'))), + ] + + +class SimpleType(SchemaBase): + _type_info = [ + ('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') + + +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")), + ] + +SimpleType.append_field('restriction', Restriction) + + +class Choice(SchemaBase): + elements = Element.customize(max_occurs="unbounded", sub_name="element") + + +class Sequence(SchemaBase): + elements = Element.customize(max_occurs="unbounded", sub_name="element") + choices = Choice.customize(max_occurs="unbounded", sub_name="choice") + + +class Extension(SchemaBase): + base = XmlAttribute(Unicode) + attributes = Attribute.customize(max_occurs="unbounded", + sub_name="attribute") + + +class SimpleContent(SchemaBase): + extension = Extension + restriction = Restriction + + +class ComplexType(SchemaBase): + name = XmlAttribute(Unicode) + sequence = Sequence + simple_content = SimpleContent.customize(sub_name="simpleContent") + attributes = Attribute.customize(max_occurs="unbounded", + sub_name="attribute") + choice = Choice + + +class Include(SchemaBase): + schema_location = XmlAttribute(Unicode(sub_name="schemaLocation")) + + +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")), + ] + + +from itertools import chain +from inspect import isclass + +from spyne.model import ModelBase +from spyne.model import primitive +from spyne.model import binary +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], + [ + 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), + ] + ) + + if isclass(cls) + and issubclass(cls, ModelBase) + and not issubclass(cls, (Fault, AnyHtml)) + and not cls in (ModelBase,) +]) + + +if __name__ == '__main__': + from pprint import pprint + pprint(TYPE_MAP) diff --git a/pym/calculate/contrib/spyne/interface/xml_schema/defn.pyc b/pym/calculate/contrib/spyne/interface/xml_schema/defn.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a9618fa276ae47f3d15dcc07cbbe9a4aeb40fead GIT binary patch literal 7579 zcmc&(TXPf16+R1H6zMS zDqE?LzmF#qseJK8OZu%d8`|IyolKvL( z_m_C%e-}kO{BtA_2_30B;&5D$pdevU>P0&)N-!Z|N$MpD%Tg~}=!8Nir9NrLB^_6! zUa{k{1XB`DOMTjoCv`j{^%*;^=y+D@v*H*>%&fe3#G4W`BU|W9%U?v^i@XN3J}2Ic zm^q!8%_iyx#GA{Y2Xg2^@eXFt`5Zbg-k}V-kV6lNcQ}I{$)OA4EoRVa4m~X1(G0qj zLyw4eEQ5ZQL-F}x*{OBFtu}w9bi{6z#p>cO_5e|Tg)BtZpvG%{jVY| z`IZECCA=&3yWrYgG2kz3Ji^Rv*{I!t6Y&3oU(G=;nM2d`yhdn}W-DmMu>}_a-VK9V zfjEUhQi4k{q_+mZ2}M2Tseo}HM*#H%p4mn1!Z zv!A5s^MF3+gx$dGKEoQp{bu|>W}e}Q$u!V6TH7XU60wDm{&@e4<7Zlu>Lw2-iVd9b$Ml9SFECH)9GIq9ZI zsqdrSCHLGJHeAS^K$CC_@e~kRWIdh*xdbftJUwtcH~EPRHN066b2ad3@`Iqc85ox)F@CwyuDNSW0hgUwK853jh-WMeU!JOzMVv63u`(?Tvv#`l4HSGYWZ>r+z#z zRdQcV^(;C@9kGXwnvXR@Yg33}?aV(>#nnLIHNytA-aSlE1r0$j0a241X)?3~{ixwb zTb=QKOR~6{wH*P zLLYZZdF*tkq!7u3q`(pbB!P&vn#+2KtYw|8@K%@3PK%iw02zsA7;dTHxLH;xAs$*S=_3izhQppn`jg#i2c)?FeP3t1{~7-5k-iu!U!r(qG~3}=?4C6Pf+q@-)v;c2I(QF6Z*&y6tQjmDNJ8bO8(&=6zB zV1$pb;g38BX-E|kg(X`Sy8Kn1;!s_b8-GW~aszxAc^8514dB#3-us!^AnUa04*b}p z#=}aQyRd3)bDeyO1p}rvtXtcRC!a!X&`zOvUD0GHpE{6Dp@NO<75P>^HJ?qPj14mx zo?1w!+9`>%j$PW6`p}lG0%`^wYvz(d z=w)0rL^X1*Fw)4?`ZYLELtKrjE9}vTK4pgXE%yI2-k6v6a$!kpAq&XSK7MVfv;@4? zcGHgrHC8_!D$g=2-B&FosN3^HKk?tC1yq{trXMwXdxKRUYq^S+f%+%-nw3H;fFK#_ zcqmq=M45=+xTfW&ZL{ms)O_BGH1hpnHU8sjtl~!f6z4>3l)+BF?BWBBW z;cgoJXQ*TP7Dv^KLq#M{(n*U=IkbXUzw%=gJXJH*hCgsTIV4v!)tHyBUp#6&yZ6G{ za083g@D4Tq{}7_*_}Ui!zo8e5x6sTN=AEiDpFPD{r#gXWR@-v5Qk|;K%oi~#Rm*s% l&|3sHzS5^ybod-|PU8-?P+UUVY@gK$=80A34*t$N{{?#P5Apy2 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/interface/xml_schema/genpy.py b/pym/calculate/contrib/spyne/interface/xml_schema/genpy.py new file mode 100644 index 0000000..21784f8 --- /dev/null +++ b/pym/calculate/contrib/spyne/interface/xml_schema/genpy.py @@ -0,0 +1,144 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +""" +A barely functional Spyne class serializer. If you're using this as part of +anything serious, you're insane. + +TODO: + - Customizations are not serialized. +""" + +import logging +logger = logging.getLogger(__name__) + +import spyne + +from datetime import datetime +from itertools import chain +from collections import defaultdict + +from spyne.model import SimpleModel +from spyne.model.complex import XmlModifier +from spyne.model.complex import ComplexModelBase + + +def gen_fn_from_tns(tns): + return tns \ + .replace('http://', '') \ + .replace('https://', '') \ + .replace('/', '') \ + .replace('.', '_') \ + .replace(':', '_') \ + .replace('#', '') \ + .replace('-', '_') + + +class CodeGenerator(object): + def __init__(self, fn_tns_mapper=gen_fn_from_tns): + self.imports = set() + self.classes = set() + self.pending = defaultdict(list) + self.simples = set() + self.fn_tns_mapper = fn_tns_mapper + + def gen_modifier(self, t): + return '%s(%s)' % (t.__name__, self.gen_dispatch(t.type)) + + def gen_simple(self, t): + return t.__name__ + + def gen_complex(self, t): + retval = [] + retval.append(""" + +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: + retval.append(" ('%s', %s)," % (k, self.gen_dispatch(v))) + else: + self.pending[v.get_type_name()].append((k, t.get_type_name())) + + retval.append(" ]") + + self.classes.add(t) + + 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 + + def gen_dispatch(self, t): + if issubclass(t, XmlModifier): + return self.gen_modifier(t) + + if issubclass(t, SimpleModel): + return self.gen_simple(t) + + if t.get_namespace() == self.tns: + return t.get_type_name() + + i = self.fn_tns_mapper(t.get_namespace()) + self.imports.add(i) + return "%s.%s" % (i, t.get_type_name()) + + def genpy(self, tns, s): + self.tns = tns + + retval = [u"""# 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 +""" + +class _ComplexBase(ComplexModelBase): + __namespace__ = '%s' + __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))) + self.simples.add(n) + + for i in self.imports: + retval.insert(1, "import %s" % i) + + 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("") + + return '\n'.join(retval) diff --git a/pym/calculate/contrib/spyne/interface/xml_schema/genpy.pyc b/pym/calculate/contrib/spyne/interface/xml_schema/genpy.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c55b9876a0a6e445124c81b111cafe752606abe GIT binary patch literal 4697 zcmcgw%W@mX73~?200|N#C0UedE6zkRBS;~EvYjX{Rh&pBt5T_o=>s;Z@=#I^leqXYt;Y! zuYdeLQPZCa{yxQL{sz)jssrk&uCFprbv&g#HSm?Ls0(x#W_RN1l`)>WtO`c;*!sNt&Wth#a3%`tiFXj z8>(AZ`iAOZ`xSC7l=@xgCPh4Ku2S+pgVdh|$8o8%NzfbTiA{?<&Vs|yB-cTb#l{3i zmuZ}(-{`Ux{H7O7it&R|2V;}w{lK22CWuWiic1?5y?UHaz`_6*6=SnAo1W$-&ULF^ z|NOK4&z{tSU^mzs8(R$1Z(^Q_U9f3h*sJ5Zt$O+&{2Vkrh-sH-<=ASQ4z=Sff|H!Y zY3{l!oS=L0IJ4a}u~*E)bU4cN^P;P>E9Mu&44kx=>e4YcuzauJ%rlw#X>4@Dlljrt zd-%*3Aa9f!%zS;}OS?j&PTTPHWgEV(&iJ*t_R`#()(0Q8K6t!4nqWpt_xq0DPIIfv9!_bW4YSB3CwdsS z`#K*@TG((MN1zk+@UJX}5d?SymZ7zkSM^rser*H1J-F%DI@e`vi!$LX{`mMl#b=&@ zXv8-1%V*Mki{ygwJqdWRJR=`wuL!5g#3BdAUzEm@3J;rA?2>TL*(bhz3I;5GAs&vr zxwfxtMcD63VB8U95m@NEP=q^RP+VNy5}Xxgfx@Bi9gr(6LYnJ( zm7oJ@TNiUr(VJI+Zs8{?Jb}c0rOtiz#zCL+rN^|{gg?Erzl(|(#MP(N{?T95m%ci$ zsPhFz`y0?jLgK3VBRd1&qYH|fI;|+jWQ;7S(<-}mnbQENNUw{EgpUlBf1ODHrsJ=0 z<}{`#%Bx+OzAER4gj)rJl`pnyuX0KiZiowm6dn z4g8zmzv7JYs_O9ohdc*n2iC0D-SvuqkEZtyubhXx9D^WYWFyCVMes@Ra+(Q6nf9Z| z+`?+k;ZO6ywt27+TBwr(<$ z%`zOW*1}!DFRO<}22x|j$0B;jfy?DwiOfuN$OA$ODL96$V{1!E*MlP0;kz8Z&EX12 z-0cb+O9D&ii)^K~uj5P-`c&v^VT%Q>Im203FgX%e9PFWM-UH$FRju6c?|K{FZExLs z*SqgO@*Dn!A9(Nkf`U|#pRD;48n|8%QBVj8P~Mf8LLy0w9ZtuPH5mI?#*i*<41Wg5 z8kZi&sy0ljI?YVD_9F32o`M;+TZimpIl?CpTZ5-=nUhhhSS9ae7k0c;g@HWmn| z5w@^y|EMe2u%OOSD*(Vi>*7~n9ySM1VRPUTeChz^)#ozMP~95QiowikO-Tjz(;wBL#tTl0|o!7UXYKy`yAs%-wfW4jGCxI=NV z!=XUZ!FUYM+z)h~;401gPlB=SeO#~K51x(jPQWW6i8H)Xkcuo0bvHPkOy4Qncs*D^ zTMLt=sGqQphe{a~U*|!Ynp3nw0JS@5WC8TG?7DGQYR1xhe`a z3>Bk6W_Udh*3JKYFwD?fiWWh`C<5vdq#dkBfY(^iQwHYOKgWm^|4@fOoic&UGRRcW zZDS~C6u}O%`lXB#^5qr~oIEmIR&VkOkW>};7PUpqD0;0+gBMp6g_z<%I4`~qS$rc@ zahfT5MG1q;O5Q^zd>?!V3xfGHiaxWrJ;D}8encX;zR4ERKyX1Y8&5x7T4@^8z`7e! zLb)J9!id}qg96VurltcBxuZn?@DZo5nak}EwrBn1TCqipf!G^OP(mp8it?71e&SUY z8 0: + return extends + extends = extends.__extends__ + + 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.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)) + + for v in cls.Attributes.values: + enumeration = etree.SubElement(restriction, XSD('enumeration')) + enumeration.set('value', XmlDocument().to_unicode(cls, v)) + + return restriction + + +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()) + + doc_text = cls.get_documentation() + if doc_text or cls.Annotations.appinfo is not None: + annotation = etree.SubElement(complex_type, XSD('annotation')) + if doc_text: + 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')) + if isinstance(_ai, dict): + dict_to_etree(_ai, appinfo) + + elif isinstance(_ai, string_types): + appinfo.text = _ai + + elif isinstance(_ai, etree._Element): + appinfo.append(_ai) + + else: + from spyne.util.xml import get_object_as_xml + + appinfo.append(get_object_as_xml(_ai)) + + sequence_parent = complex_type + 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.Attributes.exc_interface: + # If the parent class is private, it won't be in the schema, so we + # need to act as if its attributes are part of cls as well. + 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)) + 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) + + sequence = etree.Element(XSD('sequence')) + + deferred = deque() + choice_tags = defaultdict(lambda: etree.Element(XSD('choice'))) + + for k, v in type_info.items(): + assert isinstance(k, string_types) + assert issubclass(v, ModelBase) + + a = v.Attributes + if a.exc_interface: + continue + + if issubclass(v, XmlData): + continue + + if issubclass(v, XmlAttribute): + deferred.append((k,v)) + continue + + document.add(v, tags) + + name = a.sub_name + if name is None: + name = k + #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: + 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) + + elif a.schema_tag == XSD('any') and issubclass(v, AnyXml): + if a.namespace is not None: + member.set('namespace', a.namespace) + if a.process_contents is not None: + member.set('processContents', a.process_contents) + + else: + 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)) + + if a.max_occurs != 1: # 1 is the xml schema default + val = a.max_occurs + if val in (D('inf'), float('inf')): + val = 'unbounded' + else: + val = str(val) + + member.set('maxOccurs', val) + + if a.default is not None: + member.set('default', _prot.to_unicode(v, a.default)) + + 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')) + doc.text = v_doc_text + + if a.xml_choice_group is None: + sequence.append(member) + else: + choice_tags[a.xml_choice_group].append(member) + + sequence.extend(choice_tags.values()) + + if len(sequence) > 0: + sequence_parent.append(sequence) + + _ext_elements = dict() + 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: + sequence_parent.append(attribute) + else: + xtba_ext.append(attribute) + + document.add_complex_type(cls, complex_type) + + # 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)) + + 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()) + + 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) + + document.add_simple_type(cls, simple_type) + +fault_add = complex_add + + +def unicode_get_restriction_tag(document, cls): + restriction = simple_get_restriction_tag(document, cls) + if restriction is None: + return + + # length + if cls.Attributes.min_len == cls.Attributes.max_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)) + + 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)) + + # pattern + if cls.Attributes.pattern != Unicode.Attributes.pattern: + pattern = etree.SubElement(restriction, XSD('pattern')) + pattern.set('value', cls.Attributes.pattern) + + return restriction + + +prot = XmlDocument() + + +def Tget_range_restriction_tag(T): + """The get_range_restriction template function. Takes a primitive, returns + a function that generates range restriction tags. + """ + + from spyne.model.primitive import Decimal + from spyne.model.primitive import 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)) + + 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)) + + 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 + + def _get_range_restriction_tag(document, cls): + restriction = simple_get_restriction_tag(document, cls) + if restriction is None: + return + + if cls.Attributes.gt != T.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)) + + if cls.Attributes.lt != T.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)) + + if cls.Attributes.pattern != T.Attributes.pattern: + elt = etree.SubElement(restriction, XSD('pattern')) + elt.set('value', cls.Attributes.pattern) + + _get_additional_restrictions(prot, restriction, cls) + + return restriction + + return _get_range_restriction_tag diff --git a/pym/calculate/contrib/spyne/interface/xml_schema/model.pyc b/pym/calculate/contrib/spyne/interface/xml_schema/model.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be762fef79ada0246cefee3e598dd51f39896690 GIT binary patch literal 12152 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 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)) + + elif issubclass(v, XmlData): + pass + + else: + retval.append("%s%s=%s,\n" % (I * i1, k, + hier_repr(value, i1, I, tags))) + + retval.append('%s)' % (I * i0)) + return ''.join(retval) + + return hier_repr + +SchemaBase.__repr__ = Thier_repr() + +hier_repr = Thier_repr() +hier_repr_ns = Thier_repr(with_ns=True) + + +class XmlSchemaParser(object): + def __init__(self, files, base_dir=None, repr_=Thier_repr(with_ns=False), + skip_errors=False): + self.retval = {} + self.indent = 0 + self.files = files + self.base_dir = base_dir + self.repr = repr_ + if self.base_dir is None: + self.base_dir = os.getcwd() + self.parent = None + self.children = None + self.nsmap = None + self.schema = None + self.prefmap = None + + self.tns = None + self.pending_elements = None + self.pending_types = None + self.skip_errors = skip_errors + + self.pending_simple_types = defaultdict(set) + + def clone(self, indent=0, base_dir=None): + retval = copy(self) + + if retval.parent is None: + retval.parent = self + if self.children is None: + self.children = [retval] + else: + self.children.append(retval) + + else: + retval.parent.children.append(retval) + + retval.indent = self.indent + indent + if base_dir is not None: + retval.base_dir = base_dir + + return retval + + def debug0(self, 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) + + 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) + return self.parse_schema(elt) + + def process_includes(self, include): + file_name = include.schema_location + if file_name is None: + return + + 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() + elt = etree.fromstring(data, parser=PARSER) + self.nsmap.update(elt.nsmap) + self.prefmap = dict([(v, k) for k, v in self.nsmap.items()]) + + sub_schema = _prot.from_element(None, XmlSchema10, elt) + if sub_schema.includes: + for inc in sub_schema.includes: + base_dir = dirname(file_name) + child_ctx = self.clone(base_dir=base_dir) + self.process_includes(inc) + 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'): + sub = getattr(sub_schema, attr) + if sub is None: + sub = [] + + own = getattr(self.schema, attr) + if own is None: + own = [] + + own.extend(sub) + + setattr(self.schema, attr, own) + + 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) + 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) + + return + + self.debug1("adding simple type list: %s", name) + retval = Array(base, serialize_as='sd-list') # FIXME: to be implemented + retval.__type_name__ = name + retval.__namespace__ = self.tns + + assert not retval.get_type_name() is retval.Empty + return retval + + 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) + 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) + + return + + self.debug1("adding simple type: %s", name) + + kwargs = {} + restriction = s.restriction + if 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) + + if restriction.min_length: + if restriction.min_length.value: + kwargs['min_len'] = int(restriction.min_length.value) + + if restriction.pattern: + if restriction.pattern.value: + kwargs['pattern'] = restriction.pattern.value + + retval = base.customize(**kwargs) + retval.__type_name__ = name + retval.__namespace__ = self.tns + if retval.__orig__ is None: + retval.__orig__ = base + + if retval.__extends__ is None: + retval.__extends__ = base + + assert not retval.get_type_name() is retval.Empty + return retval + + def process_simple_type_union(self, s, name=None): + 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.""" + retval = None + + if name is None: + name = s.name + + if s.list is not None: + retval = self.process_simple_type_list(s, name) + + elif s.union is not None: + retval = self.process_simple_type_union(s, name) + + elif s.restriction is not None: + retval = self.process_simple_type_restriction(s, name) + + if retval is None: + self.debug1("skipping simple type: %s", name) + return + + self.retval[self.tns].types[s.name] = retval + + key = self.get_name(name) + dependents = self.pending_simple_types[key] + for s, name in set(dependents): + st = self.process_simple_type(s, name) + if st is not None: + self.retval[self.tns].types[s.name] = st + + self.debug2("added back simple type: %s", s.name) + dependents.remove((s, name)) + + if len(dependents) == 0: + del self.pending_simple_types[key] + + return retval + + def process_schema_element(self, e): + if e.name is None: + return + + self.debug1("adding element: %s", e.name) + + t = self.get_type(e.type) + if t: + if e.name in self.pending_elements: + del self.pending_elements[e.name] + + self.retval[self.tns].elements[e.name] = e + + else: + self.pending_elements[e.name] = e + + def process_attribute(self, a): + if a.ref is not None: + t = self.get_type(a.ref) + return t.type.get_type_name(), t + + if a.type is not None and a.simple_type is not None: + raise ValueError(a, "Both type and simple_type are defined.") + + elif a.type is not None: + t = self.get_type(a.type) + + if t is None: + 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) + + else: + raise Exception("dunno attr") + + kwargs = {} + if a.default is not None: + kwargs['default'] = _prot.from_unicode(t, a.default) + + if len(kwargs) > 0: + t = t.customize(**kwargs) + self.debug2("t = t.customize(**%r)" % kwargs) + return a.name, XmlAttribute(t) + + def process_complex_type(self, c): + def process_type(tn, name, wrapper=None, element=None, attribute=None): + if wrapper is None: + wrapper = lambda x: x + else: + assert issubclass(wrapper, XmlModifier), wrapper + + t = self.get_type(tn) + key = (c.name, name) + if t is None: + self.pending_types[key] = c + self.debug2("not found: %r(%s)", key, tn) + return + + if key in self.pending_types: + del self.pending_types[key] + + assert name is not None, (key, e) + + kwargs = {} + if element is not None: + if e.min_occurs != "0": # spyne default + kwargs['min_occurs'] = int(e.min_occurs) + + if e.max_occurs == "unbounded": + kwargs['max_occurs'] = e.max_occurs + elif e.max_occurs != "1": + kwargs['max_occurs'] = int(e.max_occurs) + + if e.nillable != True: # spyne default + kwargs['nillable'] = e.nillable + + if e.default is not None: + 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) + + if len(kwargs) > 0: + t = t.customize(**kwargs) + + ti.append( (name, wrapper(t)) ) + self.debug2(" found: %r(%s), c: %r", key, tn, kwargs) + + def process_element(e): + if e.ref is not None: + tn = e.ref + name = e.ref.split(":", 1)[-1] + + elif e.name is not None: + tn = e.type + name = e.name + + if tn is None: + # According to http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#element-element + # this means this element is now considered to be a + # http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#ur-type-itself + self.debug2(" skipped: %s ur-type", e.name) + return + + else: + raise Exception("dunno") + + process_type(tn, name, element=e) + + ti = [] + base = ComplexModelBase + if c.name in self.retval[self.tns].types: + self.debug1("modifying existing %r", c.name) + else: + self.debug1("adding complex type: %s", c.name) + + if c.sequence is not None: + if c.sequence.elements is not None: + for e in c.sequence.elements: + process_element(e) + + if c.sequence.choices is not None: + for ch in c.sequence.choices: + if ch.elements is not None: + for e in ch.elements: + process_element(e) + + if c.choice is not None: + if c.choice.elements is not None: + for e in c.choice.elements: + process_element(e) + + if c.attributes is not None: + for a in c.attributes: + if a.name is None: + continue + if a.type is None: + continue + + process_type(a.type, a.name, XmlAttribute, attribute=a) + + if c.simple_content is not None: + sc = c.simple_content + ext = sc.extension + restr = sc.restriction + + if ext is not None: + base_name = ext.base + b = self.get_type(ext.base) + + if ext.attributes is not None: + for a in ext.attributes: + ti.append(self.process_attribute(a)) + + elif restr is not None: + base_name = restr.base + b = self.get_type(restr.base) + + if restr.attributes is not None: + for a in restr.attributes: + ti.append(self.process_attribute(a)) + + else: + raise Exception("Invalid simpleContent tag: %r", sc) + + if issubclass(b, ComplexModelBase): + base = b + else: + process_type(base_name, "_data", XmlData) + + if c.name in self.retval[self.tns].types: + r = self.retval[self.tns].types[c.name] + r._type_info.update(ti) + + else: + cls_dict = odict({ + '__type_name__': c.name, + '__namespace__': self.tns, + '_type_info': ti, + }) + if self.repr is not None: + cls_dict['__repr__'] = self.repr + + r = ComplexModelMeta(str(c.name), (base,), cls_dict) + self.retval[self.tns].types[c.name] = r + + return r + + def get_name(self, tn): + if tn.startswith("{"): + ns, qn = tn[1:].split('}', 1) + + elif ":" in tn: + ns, qn = tn.split(":", 1) + ns = self.nsmap[ns] + + else: + if None in self.nsmap: + ns, qn = self.nsmap[None], tn + else: + ns, qn = self.tns, tn + + return ns, qn + + def get_type(self, tn): + if tn is None: + return Null + + ns, qn = self.get_name(tn) + + ti = self.retval.get(ns) + if ti is not None: + t = ti.types.get(qn) + if t: + return t + + e = ti.elements.get(qn) + if e: + if e.type and ":" in e.type: + return self.get_type(e.type) + 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)) + return retval + + return TYPE_MAP.get("{%s}%s" % (ns, qn)) + + def process_pending(self): + # process pending + self.debug0("6 %s processing pending complex_types", B(self.tns)) + for (c_name, e_name), _v in list(self.pending_types.items()): + self.process_complex_type(_v) + + self.debug0("7 %s processing pending elements", YEL(self.tns)) + for _k, _v in self.pending_elements.items(): + self.process_schema_element(_v) + + 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 fail: + logging.basicConfig(level=logging.DEBUG) + self.debug0("%" * 50) + self.debug0(self.tns) + self.debug0("") + + self.debug0("elements") + self.debug0(pformat(self.pending_elements)) + self.debug0("") + + self.debug0("simple types") + self.debug0(pformat(self.pending_simple_types)) + self.debug0("%" * 50) + + self.debug0("complex types") + self.debug0(pformat(self.pending_types)) + self.debug0("%" * 50) + + if fail: + raise Exception("there are still unresolved elements") + + def parse_schema(self, elt): + self.nsmap = dict(elt.nsmap.items()) + self.prefmap = dict([(v, k) for k, v in self.nsmap.items()]) + self.schema = schema = _prot.from_element(self, XmlSchema10, elt) + + self.pending_types = {} + self.pending_elements = {} + + self.tns = tns = schema.target_namespace + if self.tns is None: + self.tns = tns = '__no_ns__' + if tns in self.retval: + return + self.retval[tns] = _Schema() + + self.debug0("1 %s processing includes", MAG(tns)) + if schema.includes: + for include in schema.includes: + self.process_includes(include) + + 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]) + if 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]) + + self.debug0("2 %s processing imports", R(tns)) + if schema.imports: + for imp in schema.imports: + if not imp.namespace in self.retval: + self.debug1("%s importing %s", tns, imp.namespace) + fname = self.files[imp.namespace] + self.clone(2, dirname(fname)).parse_schema_file(fname) + self.retval[tns].imports.add(imp.namespace) + + self.debug0("3 %s processing simple_types", G(tns)) + if schema.simple_types: + for s in schema.simple_types.values(): + 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() + + self.debug0("4 %s processing attributes", G(tns)) + if schema.attributes: + for s in schema.attributes.values(): + n, t = self.process_attribute(s) + self.retval[self.tns].types[n] = t + + self.debug0("5 %s processing complex_types", B(tns)) + if schema.complex_types: + for c in schema.complex_types.values(): + self.process_complex_type(c) + + self.debug0("6 %s processing elements", YEL(tns)) + if schema.elements: + for e in schema.elements.values(): + self.process_schema_element(e) + + self.process_pending() + + if self.parent is None: # for the top-most schema + if self.children is not None: # if it uses or + # This is needed for schemas with circular imports + for c in chain([self], self.children): + c.print_pending() + self.debug0('') + + # FIXME: should put this in a while loop that loops until no + # changes occur + for c in chain([self], self.children): + c.process_pending() + for c in chain([self], self.children): + c.process_pending() + self.debug0('') + + for c in chain([self], self.children): + c.print_pending(fail=(not self.skip_errors)) + + return self.retval diff --git a/pym/calculate/contrib/spyne/interface/xml_schema/parser.pyc b/pym/calculate/contrib/spyne/interface/xml_schema/parser.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65994236582b96fe5718a972fddfdb7cded14bd0 GIT binary patch literal 21517 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 _decode_pa_dict({}) + cdict({}) + >>> _decode_pa_dict({1: 2)}) + cdict({1: 2}) + >>> _decode_pa_dict({(1,2): 3)}) + cdict({1: 3, 2: 3}) + """ + + retval = cdict() + for k, v in d.items(): + if isinstance(k, (frozenset, tuple)): + for subk in k: + retval[subk] = v + + for k, v in d.items(): + if not isinstance(k, (frozenset, tuple)): + retval[k] = v + + return retval + + +class AttributesMeta(type(object)): + NULLABLE_DEFAULT = True + + 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 + + rd = {} + for k in list(cls_dict.keys()): + if k in ('parser', 'cast'): + rd['parser'] = cls_dict.pop(k) + continue + + if k in ('sanitize', 'sanitizer'): + rd['sanitizer'] = cls_dict.pop(k) + continue + + if k == 'logged': + rd['logged'] = cls_dict.pop(k) + continue + + retval = super(AttributesMeta, cls).__new__(cls, cls_name, cls_bases, + cls_dict) + + for k, v in rd.items(): + if v is None: + setattr(retval, k, None) + else: + setattr(retval, k, staticmethod(v)) + + return retval + + 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'): + self._method_config_do = 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 + + elif nillable is not None: + assert nullable is None or nullable == nillable + self._nullable = nillable + + if not hasattr(self, '_nullable'): + self._nullable = None + + if not hasattr(self, '_default_factory'): + self._default_factory = None + + if not hasattr(self, '_html_cloth'): + self._html_cloth = None + 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 not hasattr(self, '_xml_cloth'): + self._xml_cloth = None + 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_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']) + + 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) + + def set_nullable(self, what): + self._nullable = what + + nullable = property(get_nullable, set_nullable) + + def get_nillable(self): + return self.nullable + + def set_nillable(self, what): + self.nullable = what + + nillable = property(get_nillable, set_nillable) + + def get_default_factory(self): + return self._default_factory + + def set_default_factory(self, what): + self._default_factory = staticmethod(what) + + default_factory = property(get_default_factory, set_default_factory) + + 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 + elif cm._cloth is not None: + 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 + elif cm._cloth is not None: + 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) + + +class ModelBaseMeta(type(object)): + def __getitem__(self, item): + return self.customize(**item) + + def customize(self, **kwargs): + """Duplicates cls and overwrites the values in ``cls.Attributes`` with + ``**kwargs`` and returns the new class.""" + + cls_name, cls_bases, cls_dict = self._s_customize(**kwargs) + + return type(cls_name, cls_bases, cls_dict) + + +@six.add_metaclass(ModelBaseMeta) +class ModelBase(object): + """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. + """ + + __orig__ = None + """This holds the original class the class .customize()d from. Ie if this is + None, the class is not a customize()d one.""" + + __extends__ = None + """This holds the original class the class inherited or .customize()d from. + This is different from __orig__ because it's only set when + ``cls.is_default(cls) == False``""" + + __namespace__ = None + """The public namespace of this class. Use ``get_namespace()`` instead of + accessing it directly.""" + + __type_name__ = None + """The public type name of the class. Use ``get_type_name()`` instead of + accessing it directly.""" + + Value = type(None) + """The value of this type is an instance of this class""" + + # These are not the xml schema defaults. The xml schema defaults are + # considered in XmlSchema's add() method. the defaults here are to reflect + # what people seem to want most. + # + # Please note that min_occurs and max_occurs must be validated in the + # ComplexModelBase deserializer. + @six.add_metaclass(AttributesMeta) + class Attributes(object): + """The class that holds the constraints for the given type.""" + + _wrapper = False + # when skip_wrappers=True is passed to a protocol, these objects + # are skipped. just for internal use. + + _explicit_type_name = False + # set to true when type_name is passed to customize() call. + + out_type = None + """Override serialization type. Usually, this designates the return type + of the callable in the `sanitizer` attribute. If this is a two-way type, + it may be a good idea to also use the `parser` attribute to perform + reverse conversion.""" + + default = None + """The default value if the input is None. + + Please note that this default is UNCONDITIONALLY applied in class + initializer. It's recommended to at least make an effort to use this + only in customized classes and not in original models. + """ + + default_factory = None + """The callable that produces a default value if the value is None. + + The warnings in ``default`` apply here as well.""" + + db_default = None + """The default value used only when persisting the value if it is + ``None``. + + Only works for primitives. Unlike ``default`` this can also be set to a + callable that takes no arguments according to SQLAlchemy docs.""" + + nillable = None + """Set this to false to reject null values. Synonyms with + ``nullable``. True by default. The default value can be changed by + setting ``AttributesMeta.NULLABLE_DEFAULT``.""" + + min_occurs = 0 + """Set this to 1 to make this object mandatory. Can be set to any + positive integer. Note that an object can still be null or empty, even + if it's there.""" + + max_occurs = 1 + """Can be set to any strictly positive integer. Values greater than 1 + 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') + """The tag used to add a primitives as child to a complex type in the + xml schema.""" + + translations = None + """A dict that contains locale codes as keys and translations of field + names to that language as values. + """ + + sub_ns = None + """An Xml-specific attribute that specifies which namespace should be + used for field names in classes. + """ + + sub_name = None + """This specifies which string should be used as field name when this + type is seriazed under a ComplexModel. + """ + + wsdl_part_name = None + """This specifies which string should be used as wsdl message part name when this + type is serialized under a ComplexModel ie."parameters". + """ + + sqla_column_args = None + """A dict that will be passed to SQLAlchemy's ``Column`` constructor as + ``**kwargs``. + """ + + exc_mapper = False + """If true, this field will be excluded from the table mapper of the + parent class. + """ + + exc_table = False + """DEPRECATED !!! Use ``exc_db`` instead.""" + + exc_db = False + """If ``True``, this field will not be persisted to the database. This + attribute only makes sense in a subfield of a ``ComplexModel`` subclass. + """ + + exc_interface = False + """If `True`, this field will be excluded from the interface + document.""" + + exc = False + """If `True`, this field will be excluded from all serialization or + deserialization operations. See `prot_attrs` to make this only apply to + a specific protocol class or instance.""" + + logged = True + """If `False`, this object will be ignored in ``log_repr``, mostly used + for logging purposes. + + * Primitives can have logger=``'...'`` which will + always log the value as ``(...)``. + + * ``AnyDict`` can have one of + ``('keys', 'keys-full', 'values', 'values-full, 'full')`` as logger + value where for ``'keys'`` and ``'values'`` the output of ``keys()`` + and ``values()`` will be logged up to MAX_DICT_ELEMENT_NUM number of + elements and for ``'full'`` variants, all of the contents of the dict + will be logged will be logged + + * ``Array`` can also have ``logger='full'`` where all of the value + will be logged where as for simple ``logger=True`` only + MAX_ARRAY_ELEMENT_NUM elements will be logged. + + * For ``ComplexModel`` subclasses sent as first value to log_repr, + ``logger=False`` means a string of form ``ClassName(...)`` will be + logged. + """ + + sanitizer = None + """A callable that takes the associated native type and returns the + parsed value. Only called during serialization.""" + + parser = None + """A callable that takes the associated native type and returns the + parsed value. Only called during deserialization.""" + + unique = None + """If True, this object will be set as unique in the database schema + with default indexing options. If the value is a string, it will be + used as the indexing method to create the unique index. See sqlalchemy + documentation on how to create multi-column unique constraints. + """ + + db_type = None + """When not None, it overrides Spyne's own mapping from Spyne types to + SQLAlchemy types. It's a standard SQLAlchemy type marker, e.g. + ``sqlalchemy.Integer``. + """ + + table_name = None + """Database table name.""" + + xml_choice_group = None + """When not None, shares the same tag with fields with the same + xml_choice_group value. + """ + + index = None + """Can be ``True``, a string, or a tuple of two strings. + + * If True, this object will be set as indexed in the database schema + with default options. + + * If the value is a string, the value will denote the indexing method + used by the database. Should be one of: + + ('btree', 'gin', 'gist', 'hash', 'spgist') + + See: http://www.postgresql.org/docs/9.2/static/indexes-types.html + + * If the value is a tuple of two strings, the first value will denote + the index name and the second value will denote the indexing method as + above. + """ + + read_only = False + """If True, the attribute won't be initialized from outside values. + Set this to ``True`` for e.g. read-only properties.""" + + prot_attrs = None + """Customize child attributes for protocols. It's a dict of dicts. + The key is either a ProtocolBase subclass or a ProtocolBase instance. + Instances override classes.""" + + pa = None + """Alias for prot_attrs.""" + + empty_is_none = False + """When the incoming object is empty (e.g. '' for strings) treat it as + None. No effect (yet) for outgoing values.""" + + order = None + """An integer that's passed to ``_type_info.insert()`` as first argument + when not None. ``.append()`` is used otherwise.""" + + validate_on_assignment = False + """Perform validation on assignment (i.e. all the time) instead of on + just serialization""" + + polymap = {} + """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.""" + + __use_parent_doc__ = False + """If equal to True and doc is empty, Annotations will use __doc__ + from parent. Set it to False to avoid this mechanism. This is a + convenience option""" + + doc = "" + """The public documentation for the given type.""" + + appinfo = None + """Any object that carries app-specific info.""" + + class Empty(object): + pass + + _force_own_namespace = None + + @classmethod + def ancestors(cls): + """Returns a list of parent classes in child-to-parent order.""" + + retval = [] + + extends = cls.__extends__ + while extends is not None: + retval.append(extends) + extends = extends.__extends__ + + return retval + + @staticmethod + def is_default(cls): + return True + + @classmethod + def get_namespace_prefix(cls, interface): + """Returns the namespace prefix for the given interface. The + get_namespace_prefix of the interface class generates a prefix if none + is defined. + """ + + ns = cls.get_namespace() + + retval = interface.get_namespace_prefix(ns) + + return retval + + @classmethod + def get_namespace(cls): + """Returns the namespace of the class. Defaults to the python module + name.""" + + return cls.__namespace__ + + @classmethod + def _fill_empty_type_name(cls, parent_ns, parent_tn, k): + cls.__namespace__ = parent_ns + + 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) + extends = extends.__extends__ + + # TODO: rename to "resolve_identifier" + @staticmethod + def resolve_namespace(cls, default_ns, tags=None): + """This call finalizes the namespace assignment. The default namespace + is not available until the application calls populate_interface method + of the interface generator. + """ + + if tags is None: + tags = set() + elif cls in tags: + return False + tags.add(cls) + + 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)): + cls.__namespace__ = default_ns + + if cls.__namespace__ is None: + ret = [] + for f in cls.__module__.split('.'): + if f.startswith('_'): + break + else: + ret.append(f) + + cls.__namespace__ = '.'.join(ret) + + if cls.__namespace__ is None or len(cls.__namespace__) == 0: + cls.__namespace__ = default_ns + + if cls.__namespace__ is None or len(cls.__namespace__) == 0: + raise ValueError("You need to explicitly set %r.__namespace__" % cls) + + # print(" resolve ns for %r to %r" % (cls, cls.__namespace__)) + + 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. + """ + + retval = cls.__type_name__ + if retval is None: + retval = cls.__name__ + + return retval + + # 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. + """ + + if cls.get_namespace() != None: + return "%s:%s" % (cls.get_namespace_prefix(interface), + cls.get_type_name()) + + @classmethod + def get_element_name(cls): + return cls.Attributes.sub_name or cls.get_type_name() + + @classmethod + def get_wsdl_part_name(cls): + return cls.Attributes.wsdl_part_name or cls.get_element_name() + + @classmethod + def get_element_name_ns(cls, interface): + ns = cls.Attributes.sub_ns or cls.get_namespace() + if ns is DEFAULT_NS: + ns = interface.get_tns() + if ns is not None: + pref = interface.get_namespace_prefix(ns) + return "%s:%s" % (pref, cls.get_element_name()) + + @classmethod + def to_bytes(cls, value): + """ + Returns str(value). This should be overridden if this is not enough. + """ + return six.binary_type(value) + + @classmethod + def to_unicode(cls, value): + """ + Returns unicode(value). This should be overridden if this is not enough. + """ + return six.text_type(value) + + @classmethod + def get_documentation(cls): + if cls.Annotations.doc: + return cls.Annotations.doc + elif cls.Annotations.__use_parent_doc__: + return cls.__doc__ + else: + return '' + + @classmethod + def _s_customize(cls, **kwargs): + """Sanitizes customization parameters of the class it belongs to. + Doesn't perform any actual customization. + """ + + 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__}) + + if getattr(cls, '__orig__', None) is None: + cls_dict['__orig__'] = cls + else: + cls_dict['__orig__'] = cls.__orig__ + + class Attributes(cls.Attributes): + _explicit_type_name = False + + if cls.Attributes.translations is None: + Attributes.translations = {} + + if cls.Attributes.sqla_column_args is None: + Attributes.sqla_column_args = (), {} + else: + Attributes.sqla_column_args = deepcopy( + cls.Attributes.sqla_column_args) + + 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'): + v = getattr(cls.Attributes, k) + if v is not None: + setattr(Attributes, k, v) + + class Annotations(cls.Annotations): + pass + cls_dict['Annotations'] = Annotations + + # get protocol attrs + prot = kwargs.get('protocol', None) + if prot is None: + prot = kwargs.get('prot', None) + + if prot is 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) + 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('_'): + _log_debug("ignoring '%s' because of leading underscore", k) + continue + + if k in ('protocol', 'prot', 'p'): + Attributes.prot = v + _log_debug("setting prot=%r", v) + + 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)) + _log_debug("setting %s=%r", k, 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)) + _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 + _log_debug("setting primary_key=%r", 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'): + 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'): + 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" + + if not isinstance(v, dict): + # our odict has one nasty implicit behaviour: setitem on + # int keys is treated as array indexes, not dict keys. so + # dicts with int indexes can't work with odict. so we use + # the one from stdlib + v = OrderedDict(v) + + Attributes.values = list(v.keys()) + Attributes.values_dict = v + _log_debug("setting values=%r, values_dict=%r", + Attributes.values, Attributes.values_dict) + + 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') + setattr(Attributes, k, new_v) + _log_debug("setting max_occurs=%r", new_v) + + elif k == 'type_name': + Attributes._explicit_type_name = True + _log_debug("setting _explicit_type_name=True because " + "we have 'type_name'") + + else: + setattr(Attributes, k, v) + _log_debug("setting %s=%r", k, v) + + return (cls.__name__, (cls,), cls_dict) + + @staticmethod + def validate_string(cls, value): + """Override this method to do your own input validation on the input + string. This is called before converting the incoming string to the + native python value.""" + + return (cls.Attributes.nillable or value is not None) + + @staticmethod + def validate_native(cls, value): + """Override this method to do your own input validation on the native + value. This is called after converting the incoming string to the + native python value.""" + + return (cls.Attributes.nullable or value is not None) + + +class Null(ModelBase): + pass + + +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: + self._pattern = None + + def get_pattern(self): + return self._pattern + + def set_pattern(self, pattern): + self._pattern = pattern + if pattern is not None: + self._pattern_re = re.compile(pattern) + + pattern = property(get_pattern, set_pattern) + + def get_unicode_pattern(self): + return self._pattern + + def set_unicode_pattern(self, pattern): + self._pattern = pattern + if pattern is not None: + self._pattern_re = re.compile(pattern, re.UNICODE) + + unicode_pattern = property(get_unicode_pattern, set_unicode_pattern) + upattern = property(get_unicode_pattern, set_unicode_pattern) + + +class SimpleModel(ModelBase): + """The base class for primitives.""" + + __namespace__ = "http://www.w3.org/2001/XMLSchema" + + @six.add_metaclass(SimpleModelAttributesMeta) + class Attributes(ModelBase.Attributes): + """The class that holds the constraints for the given type.""" + + values = set() + """The set of possible values for this type.""" + + # some hacks are done in _s_customize to make `values_dict` + # behave like `values` + values_dict = dict() + """The dict of possible values for this type. Dict keys are values and + dict values are either a single string or a translation dict.""" + + _pattern_re = None + + def __new__(cls, **kwargs): + """Overriden so that any attempt to instantiate a primitive will return + a customized class instead of an instance. + + See spyne.model.base.ModelBase for more information. + """ + + return cls.customize(**kwargs) + + @classmethod + def customize(cls, **kwargs): + """Duplicates cls and overwrites the values in ``cls.Attributes`` with + ``**kwargs`` and returns the new class.""" + + cls_name, cls_bases, cls_dict = cls._s_customize(**kwargs) + + retval = type(cls_name, cls_bases, cls_dict) + + 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__) + + retval.resolve_namespace(retval, kwargs.get('__namespace__')) + + return retval + + @staticmethod + def is_default(cls): + 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) + ) + ) + ) + + +class PushBase(object): + def __init__(self, callback=None, errback=None): + self.orig_thread = threading.current_thread() + + self._cb = callback + self._eb = errback + + self.length = 0 + self.ctx = None + self.app = None + self.gen = None + self._cb_finish = None + self._eb_finish = None + self.interim = False + + def _init(self, ctx, gen, _cb_finish, _eb_finish, interim): + self.length = 0 + + self.ctx = ctx + self.app = ctx.app + + self.gen = gen + + self._cb_finish = _cb_finish + self._eb_finish = _eb_finish + + self.interim = interim + + def init(self, ctx, gen, _cb_finish, _eb_finish, interim): + self._init(ctx, gen, _cb_finish, _eb_finish, interim) + if self._cb is not None: + return self._cb(self) + + def __len__(self): + return self.length + + def append(self, inst): + self.gen.send(inst) + self.length += 1 + + def extend(self, insts): + for inst in insts: + self.gen.send(inst) + self.length += 1 + + def close(self): + try: + self.gen.throw(Break()) + except (Break, StopIteration, GeneratorExit): + pass + self._cb_finish() + + +class xml: + """Compound option object for xml serialization. It's meant to be passed to + :func:`ComplexModelBase.Attributes.store_as`. + + :param root_tag: Root tag of the xml element that contains the field values. + :param no_ns: When true, the xml document is stripped from namespace + information. This is generally a stupid thing to do. Use with caution. + """ + + def __init__(self, root_tag=None, no_ns=False, pretty_print=False): + self.root_tag = root_tag + self.no_ns = no_ns + self.pretty_print = pretty_print + + +class table: + """Compound option object for for storing the class instance as in row in a + table in a relational database. It's meant to be passed to + :func:`ComplexModelBase.Attributes.store_as`. + + :param multi: When False, configures a one-to-many relationship where the + child table has a foreign key to the parent. When not ``False``, + configures a many-to-many relationship by creating an intermediate + relation table that has foreign keys to both parent and child classes + and generates a table name automatically. When ``True``, the table name + is generated automatically. Otherwise, it should be a string, as the + value is used as the name of the intermediate table. + :param left: Name of the left join column. + :param right: Name of the right join column. + :param backref: See https://docs.sqlalchemy.org/en/13/orm/relationship_api.html?highlight=lazy#sqlalchemy.orm.relationship.params.backref + :param cascade: https://docs.sqlalchemy.org/en/13/orm/relationship_api.html?highlight=lazy#sqlalchemy.orm.relationship.params.cascade + :param lazy: See https://docs.sqlalchemy.org/en/13/orm/relationship_api.html?highlight=lazy#sqlalchemy.orm.relationship.params.lazy + :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): + self.multi = multi + self.left = left + self.right = right + self.backref = backref + self.id_backref = id_backref + self.cascade = cascade + self.lazy = lazy + self.back_populates = back_populates + self.fk_left_deferrable = fk_left_deferrable + self.fk_left_initially = fk_left_initially + self.fk_right_deferrable = fk_right_deferrable + self.fk_right_initially = fk_right_initially + self.fk_left_ondelete = fk_left_ondelete + self.fk_left_onupdate = fk_left_onupdate + self.fk_right_ondelete = fk_right_ondelete + self.fk_right_onupdate = fk_right_onupdate + self.explicit_join = explicit_join + self.order_by = order_by + self.single_parent = single_parent + + +class json: + """Compound option object for json serialization. It's meant to be passed to + :func:`ComplexModelBase.Attributes.store_as`. + + Make sure you don't mix this with the json package when importing. + """ + + def __init__(self, ignore_wrappers=True, complex_as=dict): + if ignore_wrappers != True: + raise NotImplementedError("ignore_wrappers != True") + self.ignore_wrappers = ignore_wrappers + self.complex_as = complex_as + + +class jsonb: + """Compound option object for jsonb serialization. It's meant to be passed + to :func:`ComplexModelBase.Attributes.store_as`. + """ + + def __init__(self, ignore_wrappers=True, complex_as=dict): + if ignore_wrappers != True: + raise NotImplementedError("ignore_wrappers != True") + self.ignore_wrappers = ignore_wrappers + self.complex_as = complex_as + + +class msgpack: + """Compound option object for msgpack serialization. It's meant to be passed + to :func:`ComplexModelBase.Attributes.store_as`. + + 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} + + +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) + + return val + return val_c() diff --git a/pym/calculate/contrib/spyne/model/_base.pyc b/pym/calculate/contrib/spyne/model/_base.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9cb01f383e60f45f7c97a191a87c44090558fd1 GIT binary patch literal 32896 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 b6~_*Yof~`C=*Z|JquWP^MhC}pI}86G?iTAc literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/model/addtl.py b/pym/calculate/contrib/spyne/model/addtl.py new file mode 100644 index 0000000..6bc83cf --- /dev/null +++ b/pym/calculate/contrib/spyne/model/addtl.py @@ -0,0 +1,98 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import re +from spyne import M, Boolean, DateTime, Date, Time, ComplexModel, \ + ValidationError +from spyne.protocol import InProtocolBase + + +class SegmentBase(object): + @classmethod + def from_string(cls, s): + match = cls._SEGMENT_RE.match(s) + if match is None: + raise ValidationError(s) + start_incl, start_str, end_str, end_incl = match.groups() + + 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 == ']') + + print(start_incl, start, end, 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()) + + +class DateTimeSegment(ComplexModel, SegmentBase): + _SEGMENT_RE = re.compile( + u"([\\[\\]])" + u"([0-9:\\.T-]+)" + u"," + u"([0-9:\\.T-]+)" + u"([\\[\\]])", re.DEBUG | re.UNICODE) + + _type_info = [ + ('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) + + _type_info = [ + ('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) + + _type_info = [ + ('start_inclusive', M(Boolean(default=True))), + ('start', M(Time)), + ('end', M(Time)), + ('end_inclusive', M(Boolean(default=True))), + ] diff --git a/pym/calculate/contrib/spyne/model/addtl.pyc b/pym/calculate/contrib/spyne/model/addtl.pyc new file mode 100644 index 0000000000000000000000000000000000000000..09c85f80176250935dc3ca85caff88b68f4f2d4d GIT binary patch literal 3021 zcmd5;UvC>l5T8B&jpH;4g(@i(R6yWDYr8E`5eOla#43GAiZ%%nP9k%?TRWHBAM19F z8p(Mfd?gwq@6e%uIr$lj?I%SG0)TvNhrB0Ou?=Mg^Lvf8d zHOz~oW~nDADA8|3=R`ks>J*eoRY=vT=TK0YEX+|*y|gehS-3?(?b5>RWMQ7Y-Er&i zJp32GZMOo}2#_tq?0T9;%1cZY{HABrZWt?598WA`C49g}8V@4%YAX#?Wac6G(Tl>s zGhv#vvn$Xx-Dw%tExI`mst3&nJO(AYaGO_dygwDoEkJWW5(0 zOgN9AAf9r^Wo@6y%y?|zss98S5gp?%Xe8)d(3wLcd(26dvId#LSpKV^1j-H_7dg%c zMLH|c8EA>l${glr-;bbMq)~}RW$G1k0em=dSk;tx+i}_2t5D$3GL+A;R=IKw>R7At zS%93+z*ZQj(8vmN1IPzh#8u%n4u$C|!;ekpRNQeHmu-vJKJ4Sd#>CySy)2Ep!zA>P1*Qf;*PIR%%=A*1fw2zwk+v>sxxgY;oBC;3EuU(W*(8L+UFP|+ z%=2|5?~;6t+;cFbUx2iRI%`GY%cpCt!Kpb)lPAqDTRJqVG4T8oudj4V4^9)+c+!0Q zMf35~#^4khP1Wz`@>a|V-136JL`|H)*=cVD55lDXKHIqmLe4v)F6PCOQxc0#UCfBv z;-08Gi_VhpIn{Y^xHm9t3L{e{sfbKr9?6EBgaL={{xX`2on(W6NC!c(MvRcQG`FsVwH-vqf>y$i_{_$C~}Iwrx1Cz)Tv>F^UgU z+ZULYXdQ)%#tl5V3!@$#QZs;2pu2EKE?9Yun+;FV!l5>qmag8_$BSW>8yT0?@BxUs zf3SaWc)05BKWcpS^+9vDarj{M;cK%C70I<{Yb8)UZy1?rc}VWKw!_O0!O8oq$>3$m zZt&5z!${dG-)yh%J+soi?dKaWHrtZ>xWphi$+q2Ws3adC-vzk|6hDHUH4M#HDT}fw z6mJ)nP;h@)K5BVe%=H&zQW9lVnt+Z5}s; z(JCyqG5!xD{!Dm_G2$Rz0C7=am#ghMapK-|W3}`-jO|^Glgn>on_c;*1ivMxwV#)~ z%_-|JH~#!PfUDBJQk#SEXI=h1z>O?@d8~Y6`>^CPmYgS&ow$L 100: + raise ValidationError(value) + else: + raise ValidationError(value[:100] + "(...)") + + @classmethod + def to_hex(cls, value): + return hexlify(_bytes_join(value)) + + @classmethod + def from_hex(cls, value): + return (unhexlify(_bytes_join(value)),) + + +def _default_binary_encoding(b): + if isinstance(b, (six.binary_type, 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): + raise ValueError(b) + + return b''.join(b) + + +binary_encoding_handlers = { + None: _default_binary_encoding, + BINARY_ENCODING_HEX: ByteArray.to_hex, + BINARY_ENCODING_BASE64: ByteArray.to_base64, + BINARY_ENCODING_URLSAFE_BASE64: ByteArray.to_urlsafe_base64, +} + +binary_decoding_handlers = { + None: lambda x: (x,), + BINARY_ENCODING_HEX: ByteArray.from_hex, + BINARY_ENCODING_BASE64: ByteArray.from_base64, + BINARY_ENCODING_URLSAFE_BASE64: ByteArray.from_urlsafe_base64, +} + + +class HybridFileStore(object): + 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. + + :param store_path: The path where the file contents are stored. This is + converted to an absolute path if it's not already one. + :param db_format: The format (and the relevant column type) used to + store file metadata. Currently only 'json' is implemented. + """ + + self.store = abspath(store_path) + self.db_format = db_format + self.type = type + + if not isdir(self.store): + os.makedirs(self.store) + + assert isdir(self.store) + + +_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") + + +class _FileValue(ComplexModel): + """The class for values marked as ``File``. + + :param name: Original name of the file + :param type: The mime type of the file's contents. + :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')), + ] + + 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") + + self.sanitized = _sanitize + + self.path = path + """Relative path of the file.""" + + self.type = type + """Mime type of the file""" + + self.data = data + """The contents of the file. It's a sequence of str/bytes objects by + contract. It can contain the contents of a the file as a single + instance of `mmap.mmap()` object inside a tuple.""" + + self.handle = handle + """The file handle.""" + + self.move = move + """When True, Spyne can move the file (instead of copy) to its final + location where it will be persisted. Defaults to `False`. See PGFile* + objects to see how it's used.""" + + self.abspath = None + """The absolute path of the file. It can be None even when the data is + file-backed.""" + + if self.path is not None: + self.abspath = abspath(self.path) + + def rollover(self): + """This method normalizes the file object by making ``path``, + ``name`` and ``handle`` properties consistent. It writes + incoming data to the file object and points the ``data`` iterable + to the contents of this file. + """ + + if not self.sanitized: + raise SanitizationError(self) + + if self.data is not None: + if self.path is None: + self.handle = tempfile.NamedTemporaryFile() + self.abspath = self.path = self.handle.name + self.name = basename(self.abspath) + else: + self.handle = open(self.path, 'wb') + # FIXME: abspath could be None here, how do we make sure it's + # the right value? + + # data is a ByteArray, so a sequence of str/bytes objects + for d in self.data: + self.handle.write(d) + + elif self.handle is not None: + try: + if isinstance(self.handle, (StringIO, BytesIO)): + self.data = (self.handle.getvalue(),) + else: + # 0 = whole file + self.data = (mmap(self.handle.fileno(), 0),) + + except MmapError as e: + if e.errno == errno.EACCES: + self.data = ( + mmap(self.handle.fileno(), 0, access=ACCESS_READ), + ) + else: + raise + + elif self.path is not None: + if not isfile(self.path): + logger.error("File path in %r not found", self) + + 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.") + + +class File(SimpleModel): + """A compact way of dealing with incoming files for protocols with a + standard way of encoding file metadata along with binary data. (E.g. Http) + """ + + __type_name__ = 'base64Binary' + __namespace__ = "http://www.w3.org/2001/XMLSchema" + + BINARY = _BINARY + TEXT = _TEXT + Value = _FileValue + + class Attributes(SimpleModel.Attributes): + encoding = BINARY_ENCODING_USE_DEFAULT + """The binary encoding to use when the protocol does not enforce an + encoding for binary data. + + One of (None, 'base64', 'hex') + """ + + type = _FileValue + """The native type used to serialize the information in the file object. + """ + + mode = _BINARY + """Set this to mode=File.TEXT if you're sure you're handling unicode + data. This lets serializers like HtmlCloth avoid base64 encoding. Do + note that you still need to set encoding attribute explicitly to None!.. + + One of (File.BINARY, File.TEXT) + """ + + @classmethod + 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') + + # base64 encodes every 3 bytes to 4 base64 characters + 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) + + f.close() + + @classmethod + def from_base64(cls, value): + if value is None: + return None + 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) + + @classmethod + def store_as(cls, what): + return cls.customize(store_as=what) diff --git a/pym/calculate/contrib/spyne/model/binary.pyc b/pym/calculate/contrib/spyne/model/binary.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be436748181f6eeef106bdd04e137cf7c76b0b13 GIT binary patch literal 12985 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 TW&Mj>Wp-x9nJLd!XM6t(T(Iw` literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/model/complex.py b/pym/calculate/contrib/spyne/model/complex.py new file mode 100644 index 0000000..975418a --- /dev/null +++ b/pym/calculate/contrib/spyne/model/complex.py @@ -0,0 +1,1631 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.model.complex`` module contains +:class:`spyne.model.complex.ComplexBase` class and its helper objects and +subclasses. These are mainly container classes for other simple or +complex objects -- they don't carry any data by themselves. +""" + +from __future__ import print_function + +import logging +logger = logging.getLogger(__name__) + +import decimal +import traceback + +from copy import copy +from weakref import WeakKeyDictionary +from collections import deque, OrderedDict +from inspect import isclass +from itertools import chain + +from spyne import const +from spyne.const.xml import PREFMAP + +from spyne.model import Point, Unicode, PushBase, ModelBase +from spyne.model._base import PSSM_VALUES, apply_pssm +from spyne.model.primitive import NATIVE_MAP + +from spyne.util import six, memoize, memoize_id, sanitize_args, \ + memoize_ignore_none +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) + 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)}) + return retval + + +class TypeInfo(odict): + def __init__(self, *args, **kwargs): + super(TypeInfo, self).__init__(*args, **kwargs) + + self.attributes = {} + self.alt = OrderedDict() + self.attrs = OrderedDict() + + def __setitem__(self, key, val): + assert isinstance(key, string_types) + super(TypeInfo, self).__setitem__(key, val) + + +class _SimpleTypeInfoElement(object): + __slots__ = ['path', 'parent', 'type', 'is_array', 'can_be_empty'] + + def __init__(self, path, parent, type_, is_array, can_be_empty): + self.path = path + self.parent = parent + self.type = type_ + self.is_array = is_array + 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) + + +class XmlModifier(ModelBase): + def __new__(cls, type, ns=None): + retval = cls.customize() + retval.type = type + retval.Attributes = type.Attributes + retval._ns = ns + if type.__type_name__ is ModelBase.Empty: + retval.__type_name__ = ModelBase.Empty + return retval + + @staticmethod + def resolve_namespace(cls, default_ns, tags=None): + cls.type.resolve_namespace(cls.type, default_ns, tags) + + cls.__namespace__ = cls._ns + + if cls.__namespace__ is None: + cls.__namespace__ = cls.type.get_namespace() + + if cls.__namespace__ in PREFMAP: + cls.__namespace__ = default_ns + + @classmethod + 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 + 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) + + 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 = extends.__extends__ + + +class XmlData(XmlModifier): + """Items which are marshalled as data of the parent element.""" + + @classmethod + def marshall(cls, prot, name, value, parent_elt): + if value is not None: + if len(parent_elt) == 0: + parent_elt.text = prot.to_bytes(cls.type, value) + else: + parent_elt[-1].tail = prot.to_bytes(cls.type, value) + + @classmethod + def get_type_name(cls): + return cls.type.get_type_name() + + @classmethod + def get_type_name_ns(cls, interface): + return cls.type.get_type_name_ns(interface) + + @classmethod + def get_namespace(cls): + return cls.type.get_namespace() + + @classmethod + def get_element_name(cls): + return cls.type.get_element_name() + + @classmethod + def get_element_name_ns(cls, interface): + return cls.type.get_element_name_ns(interface) + + +class XmlAttribute(XmlModifier): + """Items which are marshalled as attributes of the parent element.""" + + 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' + return retval + + +class XmlAttributeRef(XmlAttribute): + """Reference to an Xml attribute.""" + + def __init__(self, ref, use=None): + self._ref = ref + self._use = use + + def describe(self, name, element, app): + element.set('ref', self._ref) + if 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 + + def __init__(self): + raise NotImplementedError() + + @classmethod + def customize(cls, *args, **kwargs): + args = list(chain(args, cls.customize_args)) + kwargs = dict(chain(kwargs.items(), cls.customize_kwargs.items())) + if cls.__orig__ is None: + cls.__orig__ = cls + + return type("SelfReference", (cls,), { + 'customize_args': args, + 'customize_kwargs': kwargs, + }) + + +def _get_spyne_type(cls_name, k, v): + try: + v = NATIVE_MAP.get(v, v) + except TypeError: + return + + try: + subc = issubclass(v, ModelBase) or issubclass(v, SelfReference) + except: + subc = False + + if subc: + if issubclass(v, Array) and len(v._type_info) != 1: + 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 + + +def _join_args(x, y): + if x is None: + return y + if y is None: + return x + + xa, xk = sanitize_args(x) + ya, yk = sanitize_args(y) + + xk = dict(xk) + xk.update(yk) + + return xa + ya, xk + + +def _gen_attrs(cls_bases, cls_dict): + attrs = cls_dict.get('Attributes', None) + if attrs is None: + for b in cls_bases: + if hasattr(b, 'Attributes'): + class Attributes(b.Attributes): + pass + attrs = cls_dict['Attributes'] = Attributes + break + else: + raise Exception("No ModelBase subclass in bases? Huh?") + + return attrs + + +def _get_type_info(cls, cls_name, cls_bases, cls_dict, attrs): + base_type_info = TypeInfo() + mixin = TypeInfo() + 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 + if extends is None: + # 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) + + if orig is not None: + bases = orig.__bases__ + logger.debug("Got bases for %s from orig: %r", cls_name, bases) + else: + bases = cls_bases + logger.debug("Got bases for %s from meta: %r", cls_name, bases) + + for b in bases: + base_types = getattr(b, "_type_info", None) + + # we don't care about non-ComplexModel bases + if base_types is None: + continue + + # mixins are simple + 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 + + continue + + if not (extends in (None, b)): + raise Exception("Spyne objects do not support multiple " + "inheritance. Use mixins if you need to reuse " + "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 " \ + "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() + _type_info.update(base_type_info) + + class_fields = [] + for k, v in cls_dict.items(): + 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)) + + v = _get_spyne_type(cls_name, k, v) + + if v is None: + continue + + class_fields.append((k, v)) + + _type_info.update(class_fields) + + else: + _type_info = cls_dict['_type_info'] + + if not isinstance(_type_info, TypeInfo): + _type_info = cls_dict['_type_info'] = TypeInfo(_type_info) + + for k, v in reversed(mixin.items()): + _type_info.insert(0, (k, v)) + + return _type_info + + +class _MethodsDict(dict): + def __init__(self, *args, **kwargs): + super(_MethodsDict, self).__init__(*args, **kwargs) + + self._processed = False + + +def _gen_methods(cls, cls_dict): + methods = _MethodsDict() + for k, v in cls_dict.items(): + 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 + + # generate method descriptor from information in the decorator + descriptor = v(_default_function_name=k, _self_ref_replacement=cls) + + # strip the decorator and put the original function in the class + setattr(cls, k, descriptor.function) + + # modify the descriptor with user-supplied class + if cls.Attributes.method_config_do is not None: + descriptor = cls.Attributes.method_config_do(descriptor) + + methods[k] = descriptor + + return methods + + +def _get_ordered_attributes(cls_name, cls_dict, attrs): + if not isinstance(cls_dict, odict): + # 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): + + 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': + # support old behaviour + cls_dict = dict(cls_dict) + + return cls_dict + + +def _sanitize_sqlalchemy_parameters(cls_dict, attrs): + 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) + if attrs.sqla_table is None: + attrs.sqla_table = _cls_table + + metadata = cls_dict.get('__metadata__', None) + if attrs.sqla_metadata is None: + attrs.sqla_metadata = metadata + + 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) + attrs.sqla_table_args = _join_args(attrs.sqla_table_args, targs) + + +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): + raise ValueError("Invalid class key", k) + + if not isclass(v): + raise ValueError(v) + + if issubclass(v, SelfReference): + continue + + elif not issubclass(v, ModelBase): + v = _get_spyne_type(cls_name, k, v) + if v is None: + 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)) + sub_ns = v.Attributes.sub_ns + sub_name = v.Attributes.sub_name + + if sub_ns is None and sub_name is None: + pass + + 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])) + _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])) + _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])) + _type_info_alt[key] = v, k + + +D_EXC = dict(exc=True) + + +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)) + + # add exc=False to child_attrs_noexc + if child_attrs_noexc is not None: + # if there is _noexc, make sure that child_attrs_all is also used to + # exclude exclude everything else first + if child_attrs_all is None: + 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) + + 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) + + v['exc'] = False + + # update child_attrs with data from child_attrs_noexc + if child_attrs is None: + child_attrs = child_attrs_noexc + + else: + # update with child_attrs_noexc with exc=False + if child_attrs is None: + child_attrs = dict() + + 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) + + child_attrs[k] = v + + if child_attrs_all is not None: + ti = retval._type_info + logger.debug("processing child_attrs_all for %r", cls) + for k, v in ti.items(): + logger.debug(" child_attrs_all set %r=%r", k, child_attrs_all) + ti[k] = ti[k].customize(**child_attrs_all) + + if retval.__extends__ is not None: + retval.__extends__ = retval.__extends__.customize( + child_attrs_all=child_attrs_all) + + retval.Attributes._delayed_child_attrs_all = child_attrs_all + + if child_attrs is not None: + ti = retval._type_info + logger.debug("processing child_attrs for %r", cls) + for k, v in list(child_attrs.items()): + if k in ti: + logger.debug(" child_attr set %r=%r", k, v) + ti[k] = ti[k].customize(**v) + del child_attrs[k] + + base_fti = {} + if retval.__extends__ is not None: + 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(): + if k not in base_fti: + logger.debug(" child_attr delayed %r=%r", k, v) + retval.Attributes._delayed_child_attrs[k] = v + + +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", cls) + return cls + + +def _set_member_default(inst, key, cls, attr): + def_val = attr.default + def_fac = attr.default_factory + + if def_fac is None and def_val is None: + 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 + setattr(inst, key, dval) + + return True + + if def_val is not None: + # should not check for read-only for default values + setattr(inst, key, def_val) + + return True + + assert False, "Invalid application state" + + +def _is_sqla_array(cls, attr): + # inner object is complex + 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') + + return ret1 or ret2 or ret3 + + +def _init_member(inst, key, cls, attr): + cls_getattr_ret = getattr(inst.__class__, key, None) + + if isinstance(cls_getattr_ret, property) and cls_getattr_ret.fset is None: + return # we skip read-only properties + + if _set_member_default(inst, key, cls, attr): + return + + # sqlalchemy objects do their own init. + if _is_sqla_array(cls, attr): + # except the attributes that sqlalchemy doesn't know about + if attr.exc_db: + setattr(inst, key, None) + + elif attr.store_as is None: + setattr(inst, key, None) + + return + + # sqlalchemy objects do their own init. + if hasattr(inst.__class__, '_sa_class_manager'): + # except the attributes that sqlalchemy doesn't know about + if attr.exc_db: + setattr(inst, key, None) + + elif issubclass(cls, ComplexModelBase) and attr.store_as is None: + setattr(inst, key, None) + + return + + setattr(inst, key, None) + + +class ComplexModelMeta(with_metaclass(Prepareable, type(ModelBase))): + """This metaclass sets ``_type_info``, ``__type_name__`` and ``__extends__`` + which are going to be used for (de)serialization and schema generation. + """ + + 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) + + cls_dict = _get_ordered_attributes(cls_name, cls_dict, attrs) + + type_name = cls_dict.get("__type_name__", None) + if type_name is None: + cls_dict["__type_name__"] = cls_name + + _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() + for b in cls_bases: + 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) + + def __init__(self, cls_name, cls_bases, cls_dict): + type_info = self._type_info + + extends = self.__extends__ + if extends is not None and self.__orig__ is None: + eattr = extends.Attributes + if eattr._subclasses is None: + eattr._subclasses = [] + eattr._subclasses.append(self) + if self.Attributes._subclasses is eattr._subclasses: + self.Attributes._subclasses = None + + # sanitize fields + for k, v in type_info.items(): + # replace bare SelfRerefence + if issubclass(v, SelfReference): + self._replace_field(k, recust_selfref(v, self)) + + # cache XmlData for easier access + elif issubclass(v, XmlData): + if self.Attributes._xml_tag_body_as is None: + self.Attributes._xml_tag_body_as = [(k, v)] + else: + self.Attributes._xml_tag_body_as.append((k, v)) + + # replace SelfRerefence in arrays + elif issubclass(v, Array): + v2, = v._type_info.values() + while issubclass(v2, Array): + v = v2 + v2, = v2._type_info.values() + + if issubclass(v2, SelfReference): + v._set_serializer(recust_selfref(v2, self)) + + # apply field order + # FIXME: Implement this better + new_type_info = [] + for k, v in self._type_info.items(): + if v.Attributes.order == None: + new_type_info.append(k) + + for k, v in self._type_info.items(): + if v.Attributes.order is not None: + new_type_info.insert(v.Attributes.order, k) + + assert len(self._type_info) == len(new_type_info) + self._type_info.keys()[:] = new_type_info + + # install checkers for validation on assignment + for k, v in self._type_info.items(): + if not v.Attributes.validate_on_assignment: + continue + + def _get_prop(self): + return self.__dict__[k] + + 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)) + + self.__dict__[k] = val + + setattr(self, k, property(_get_prop, _set_prop)) + + # process member rpc methods + methods = _gen_methods(self, cls_dict) + if len(methods) > 0: + self.Attributes.methods = methods + + # finalize sql table mapping + tn = self.Attributes.table_name + meta = self.Attributes.sqla_metadata + t = self.Attributes.sqla_table + + # For spyne objects reflecting an existing db table + if tn is None: + if t is not None: + self.Attributes.sqla_metadata = t.metadata + from spyne.store.relational import gen_spyne_info + + 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: + from spyne.store.relational import gen_sqla_info + + gen_sqla_info(self, cls_bases) + + super(ComplexModelMeta, self).__init__(cls_name, cls_bases, cls_dict) + + # + # We record the order fields are defined into ordered dict, so we can + # 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() + + +_is_array = lambda v: issubclass(v, Array) or (v.Attributes.max_occurs > 1) + + +class ComplexModelBase(ModelBase): + """If you want to make a better class type, this is what you should inherit + from. + """ + + __mixin__ = False + + class Attributes(ModelBase.Attributes): + """ComplexModel-specific attributes""" + + store_as = None + """Method for serializing to persistent storage. One of %r. It makes + sense to specify this only when this object is a child of another + ComplexModel subclass.""" % (PSSM_VALUES,) + + sqla_metadata = None + """None or :class:`sqlalchemy.MetaData` instance.""" + + sqla_table_args = None + """A dict that will be passed to :class:`sqlalchemy.schema.Table` + constructor as ``**kwargs``. + """ + + sqla_mapper_args = None + """A dict that will be passed to :func:`sqlalchemy.orm.mapper` + constructor as. ``**kwargs``. + """ + + sqla_table = None + """The sqlalchemy table object""" + + sqla_mapper = None + """The sqlalchemy mapper object""" + + validate_freq = True + """When ``False``, soft validation ignores missing mandatory attributes. + """ + + child_attrs = None + """Customize child attributes in one go. It's a dict of dicts. This is + ignored unless used via explicit customization.""" + + child_attrs_all = None + """Customize all child attributes. It's a dict. This is ignored unless + used via explicit customization. `child_attrs` always take precedence. + """ + + declare_order = None + """The order fields of the :class:``ComplexModel`` are to be declared + in the SOAP WSDL. If this is left as None or explicitly set to + ``'random'`` declares then the fields appear in whatever order the + Python's hash map implementation seems fit in the WSDL. This randomised + order can change every time the program is run. This is what Spyne <2.11 + did if you didn't set _type_info as an explicit sequence (e.g. using a + list, odict, etc.). It means that clients who are manually complied or + generated from the WSDL will likely need to be recompiled every time it + changes. The string ``name`` means the field names are alphabetically + sorted in the WSDL declaration. The string ``declared`` means in the + order the field type was declared in Python 2, and the order the + field was declared in Python 3. + + In order to get declared field order in Python 2, the + :class:`spyne.util.meta.Preparable` class inspects the frame stack in + order to locate the class definition, re-parses it to get declaration + order from the AST and uses that information to order elements. + + It's a horrible hack that we tested to work with CPython 2.6 through 3.3 + and PyPy. It breaks in Nuitka as Nuitka does away with code objects. + Other platforms were not tested. + + It's not recommended to use set this to ``'declared'`` in Python 2 + unless you're sure you fully understand the consequences. + """ + + parent_variant = None + """FIXME: document me yo.""" + + methods = None + """A dict of member RPC methods (typically marked with @mrpc).""" + + method_config_do = None + """When not None, it's a callable that accepts a ``@mrpc`` method + descriptor and returns a modified version.""" + + not_wrapped = None + """When True, serializes to non-wrapped object, overriding the protocol + flag.""" + + wrapped = None + """When True, serializes to a wrapped object, overriding the protocol + flag. When a str/bytes/unicode value, uses that value as key wrapper + object name.""" + + _variants = None + _xml_tag_body_as = None + _delayed_child_attrs = None + _delayed_child_attrs_all = None + _subclasses = None + + def __init__(self, *args, **kwargs): + cls = self.__class__ + cls_attr = cls.Attributes + 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.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): + + 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) + elif len(args) > 0: + raise TypeError( + "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 + if not k in self.__dict__: + _init_member(self, k, v, attr) + + if k in kwargs: + self._safe_set(k, kwargs[k], v, attr) + + def __len__(self): + return len(self._type_info) + + def __getitem__(self, i): + if isinstance(i, slice): + retval = [] + for key in self._type_info.keys()[i]: + retval.append(getattr(self, key, None)) + + else: + retval = getattr(self, self._type_info.keys()[i], None) + + return retval + + def __repr__(self): + 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])) + + def _safe_set(self, key, value, t, attrs): + if attrs.read_only: + return False + + try: + 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)) + + 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): + yield k, v + + @classmethod + def get_primary_keys(cls): + return cls.get_identifiers() + + def as_dict(self): + """Represent object as dict. + + Null values are omitted from dict representation to support optional + 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 + )) + + @classmethod + def get_serialization_instance(cls, value): + """Returns the native object corresponding to the serialized form passed + in the ``value`` argument. + + :param value: This argument can be: + * A list or tuple of native types aligned with cls._type_info. + * A dict of native types. + * The native type itself. + + If the value type is not a ``list``, ``tuple`` or ``dict``, the + value is returned untouched. + """ + + # if the instance is a list, convert it to a cls instance. + # this is only useful when deserializing method arguments for a client + # request which is the only time when the member order is not arbitrary + # (as the members are declared and passed around as sequences of + # arguments, unlike dictionaries in a regular class definition). + if isinstance(value, list) or isinstance(value, tuple): + 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) + raise ValueError("Impossible sequence to instance conversion") + + cls_orig = cls + if cls.__orig__ is not None: + cls_orig = cls.__orig__ + + try: + inst = cls_orig() + + except Exception as e: + logger.error("Error instantiating %r: %r", cls_orig, e) + raise + + for i in range(len(value)): + setattr(inst, keys[i], value[i]) + + elif isinstance(value, dict): + cls_orig = cls + if cls.__orig__ is not None: + cls_orig = cls.__orig__ + inst = cls_orig() + + for k in cls.get_flat_type_info(cls): + setattr(inst, k, value.get(k, None)) + + else: + inst = value + + return inst + + @classmethod + def get_deserialization_instance(cls, ctx): + """Get an empty native type so that the deserialization logic can set + its attributes. + """ + if cls.__orig__ is None: + return cls() + return cls.__orig__() + + @classmethod + @memoize_id + def get_subclasses(cls): + retval = [] + subca = cls.Attributes._subclasses + if subca is not None: + retval.extend(subca) + for subc in subca: + retval.extend(subc.get_subclasses()) + return retval + + @staticmethod + @memoize_ignore_none + def get_flat_type_info(cls): + """Returns a _type_info dict that includes members from all base + classes. + + It's called a "flat" dict because it flattens all members from the + inheritance hierarchy into one dict. + """ + return _get_flat_type_info(cls, TypeInfo()) + + @classmethod + def get_orig(cls): + return cls.__orig__ or cls + + @staticmethod + def get_simple_type_info(cls, hier_delim="."): + """Returns a _type_info dict that includes members from all base classes + and whose types are only primitives. It will prefix field names in + non-top-level complex objects with field name of its parent. + + For example, given hier_delim='.'; the following hierarchy: :: + + {'some_object': [{'some_string': ['abc']}]} + + would be transformed to: :: + + {'some_object.some_string': ['abc']} + + :param hier_delim: String that will be used as delimiter between field + names. Default is ``'.'``. + """ + return ComplexModelBase.get_simple_type_info_with_prot( + cls, hier_delim=hier_delim) + + @staticmethod + @memoize + def get_simple_type_info_with_prot(cls, prot=None, hier_delim="."): + """See :func:ComplexModelBase.get_simple_type_info""" + fti = cls.get_flat_type_info(cls) + + retval = TypeInfo() + tags = set() + + queue = deque() + if prot is None: + for k, v in fti.items(): + sub_name = k + + queue.append(( + (k,), + v, + (sub_name,), + (_is_array(v),), + cls, + )) + + else: + for k, v in fti.items(): + cls_attrs = prot.get_cls_attrs(v) + sub_name = cls_attrs.sub_name + if sub_name is None: + sub_name = k + + queue.append(( + (k,), + v, + (sub_name,), + (_is_array(v),), + cls, + )) + + tags.add(cls) + + while len(queue) > 0: + 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() + + key = hier_delim.join(prefix) + if issubclass(v, ComplexModelBase): + retval[key] = _SimpleTypeInfoElement( + path=keys, + parent=parent, + type_=v, + is_array=tuple(is_array), + can_be_empty=True, + ) + + if not (v in tags): + tags.add(v) + 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 + )) + + else: + for k2, v2 in v.get_flat_type_info(v).items(): + cls_attrs = prot.get_cls_attrs(v2) + sub_name = cls_attrs.sub_name + if sub_name is None: + sub_name = k2 + + 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)) + + retval[key] = _SimpleTypeInfoElement( + path=keys, + parent=parent, + type_=v, + is_array=tuple(is_array), + can_be_empty=False, + ) + + return retval + + @staticmethod + def resolve_namespace(cls, default_ns, tags=None): + if tags is None: + tags = set() + elif cls in tags: + return False + + if not ModelBase.resolve_namespace(cls, default_ns, tags): + return False + + for k, v in cls._type_info.items(): + if v is None: + continue + + if v.__type_name__ is ModelBase.Empty: + v._fill_empty_type_name(cls.get_namespace(), + cls.get_type_name(), k) + + v.resolve_namespace(v, default_ns, tags) + + if cls._force_own_namespace is not None: + for c in cls._force_own_namespace: + c.__namespace__ = cls.get_namespace() + ComplexModel.resolve_namespace(c, cls.get_namespace(), tags) + + assert not (cls.__namespace__ is ModelBase.Empty) + assert not (cls.__type_name__ is ModelBase.Empty) + + return True + + @staticmethod + 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), + })) + + @classmethod + def customize(cls, **kwargs): + """Duplicates cls and overwrites the values in ``cls.Attributes`` with + ``**kwargs`` and returns the new class. + + Because each class is registered as a variant of the original (__orig__) + class, using this function to generate classes dynamically on-the-fly + could cause memory leaks. You have been warned. + """ + + store_as = apply_pssm(kwargs.get('store_as', None)) + if store_as is not None: + 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__ + + retval = type(cls_name, cls_bases, cls_dict) + retval._type_info = TypeInfo(cls._type_info) + retval.__type_name__ = cls.__type_name__ + retval.__namespace__ = cls.__namespace__ + retval.Attributes.parent_variant = cls + + dca = retval.Attributes._delayed_child_attrs + if retval.Attributes._delayed_child_attrs is None: + retval.Attributes._delayed_child_attrs = {} + else: + retval.Attributes._delayed_child_attrs = dict(dca.items()) + + tn = kwargs.get("type_name", None) + if tn is not None: + retval.__type_name__ = tn + + ns = kwargs.get("namespace", None) + if ns is not None: + retval.__namespace__ = ns + + if cls is not ComplexModel: + cls._process_variants(retval) + + _process_child_attrs(cls, retval, kwargs) + + # we could be smarter, but customize is supposed to be called only + # during daemon initialization, so it's not really necessary. + ComplexModelBase.get_subclasses.memo.clear() + ComplexModelBase.get_flat_type_info.memo.clear() + ComplexModelBase.get_simple_type_info_with_prot.memo.clear() + + return retval + + @classmethod + def _process_variants(cls, retval): + orig = getattr(retval, '__orig__', None) + if orig is not None: + if orig.Attributes._variants is None: + orig.Attributes._variants = WeakKeyDictionary() + orig.Attributes._variants[retval] = True + # _variants is only for the root class. + retval.Attributes._variants = None + + @classmethod + def _append_field_impl(cls, field_name, field_type): + assert isinstance(field_name, string_types) + + dcaa = cls.Attributes._delayed_child_attrs_all + if dcaa is not None: + field_type = field_type.customize(**dcaa) + + dca = cls.Attributes._delayed_child_attrs + if dca is not None: + d_cust = dca.get(field_name, None) + if d_cust is not None: + field_type = field_type.customize(**d_cust) + + cls._type_info[field_name] = field_type + + ComplexModelBase.get_flat_type_info.memo.clear() + ComplexModelBase.get_simple_type_info_with_prot.memo.clear() + + @classmethod + def _append_to_variants(cls, field_name, field_type): + if cls.Attributes._variants is not None: + for c in cls.Attributes._variants: + c.append_field(field_name, field_type) + + @classmethod + def append_field(cls, field_name, field_type): + cls._append_field_impl(field_name, field_type) + cls._append_to_variants(field_name, field_type) + + @classmethod + def _insert_to_variants(cls, index, field_name, field_type): + if cls.Attributes._variants is not None: + for c in cls.Attributes._variants: + c.insert_field(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) + + dcaa = cls.Attributes._delayed_child_attrs_all + if dcaa is not None: + field_type = field_type.customize(**dcaa) + + dca = cls.Attributes._delayed_child_attrs + if dca is not None: + if field_name in dca: + d_cust = dca.pop(field_name) + field_type = field_type.customize(**d_cust) + + cls._type_info.insert(index, (field_name, field_type)) + + ComplexModelBase.get_flat_type_info.memo.clear() + ComplexModelBase.get_simple_type_info_with_prot.memo.clear() + + @classmethod + def insert_field(cls, index, field_name, field_type): + cls._insert_field_impl(index, field_name, field_type) + cls._insert_to_variants(index, field_name, field_type) + + @classmethod + def _replace_in_variants(cls, field_name, field_type): + if cls.Attributes._variants is not None: + for c in cls.Attributes._variants: + c._replace_field(field_name, field_type) + + @classmethod + def _replace_field_impl(cls, field_name, field_type): + assert isinstance(field_name, string_types) + + cls._type_info[field_name] = field_type + + ComplexModelBase.get_flat_type_info.memo.clear() + ComplexModelBase.get_simple_type_info_with_prot.memo.clear() + + @classmethod + def _replace_field(cls, field_name, field_type): + cls._replace_field_impl(field_name, field_type) + cls._replace_in_variants(field_name, field_type) + + @classmethod + def store_as(cls, what): + return cls.customize(store_as=what) + + @classmethod + def novalidate_freq(cls): + return cls.customize(validate_freq=False) + + @classmethod + def init_from(cls, other, **kwargs): + retval = (cls if cls.__orig__ is None else cls.__orig__)() + + for k, v in cls.get_flat_type_info(cls).items(): + try: + if k in kwargs: + retval._safe_set(k, kwargs[k], v, v.Attributes) + + elif hasattr(other, k): + retval._safe_set(k, getattr(other, k), v, v.Attributes) + + except AttributeError as e: + logger.warning("Error setting %s: %r", k, e) + + return retval + + @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: + retval = next(iter(ctx.in_object)) + if retval is not None: + return retval + + if ctx.descriptor.default_on_null: + return cls.get_deserialization_instance(ctx) + + +@add_metaclass(ComplexModelMeta) +class ComplexModel(ComplexModelBase): + """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. + Those who'd like to customize the class should use the customize method. + (see :class:``spyne.model.ModelBase``). + """ + + +@add_metaclass(ComplexModelMeta) +class Array(ComplexModelBase): + """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. + """ + + class Attributes(ComplexModelBase.Attributes): + _wrapper = True + + def __new__(cls, serializer, member_name=None, wrapped=True, **kwargs): + if not wrapped: + if serializer.Attributes.max_occurs == 1: + kwargs['max_occurs'] = 'unbounded' + + return serializer.customize(**kwargs) + + retval = cls.customize(**kwargs) + + _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} + else: + retval._set_serializer(_serializer, member_name) + + tn = kwargs.get("type_name", None) + if tn is not None: + retval.__type_name__ = tn + + return retval + + @classmethod + 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.__type_name__ = tn + + cls._type_info = TypeInfo({tn: child_v}) + 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 = extends.__extends__ + + @classmethod + def customize(cls, **kwargs): + serializer_attrs = kwargs.get('serializer_attrs', None) + if serializer_attrs is None: + return super(Array, cls).customize(**kwargs) + + del kwargs['serializer_attrs'] + + logger.debug('Pass serializer attrs %r', serializer_attrs) + + serializer, = cls._type_info.values() + return cls(serializer.customize(**serializer_attrs)).customize(**kwargs) + + @classmethod + def _set_serializer(cls, serializer, member_name=None): + if serializer.get_type_name() is ModelBase.Empty: # A customized class + member_name = "OhNoes" + # mark array type name as "to be resolved later". + cls.__type_name__ = ModelBase.Empty + + else: + 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) + + # 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')) + + assert isinstance(member_name, string_types), member_name + cls._type_info = TypeInfo({member_name: serializer}) + + # the array belongs to its child's namespace, it doesn't have its own + # namespace. + @staticmethod + def resolve_namespace(cls, default_ns, tags=None): + (serializer,) = cls._type_info.values() + + serializer.resolve_namespace(serializer, default_ns, tags) + + if cls.__namespace__ is None: + cls.__namespace__ = serializer.get_namespace() + + if cls.__namespace__ in PREFMAP: + cls.__namespace__ = default_ns + + return ComplexModel.resolve_namespace(cls, default_ns, tags) + + @classmethod + def get_serialization_instance(cls, value): + inst = ComplexModel.__new__(Array) + + (member_name,) = cls._type_info.keys() + setattr(inst, member_name, value) + + return inst + + @classmethod + def get_deserialization_instance(cls, ctx): + return [] + + @classmethod + def get_inner_type(cls): + return next(iter(cls._type_info.values())) + + +class Iterable(Array): + """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 + iterable. The distinction with the ``Array`` is made in the protocol + implementation, this is just a marker. + + Whenever you return a generator instead of a list, you should use this type + as this suggests the intermediate machinery to NEVER actually try to iterate + over the value. An ``Array`` could be iterated over for e.g. logging + purposes. + """ + + class Attributes(Array.Attributes): + logged = False + + class Push(PushBase): + """The push interface to the `Iterable`. + + Anything append()'ed to a `Push` instance is serialized and written to + outgoing stream immediately. + + When using Twisted, Push callbacks are called from the reactor thread if + the instantiation is done in a reactor thread. Otherwise, callbacks are + called by `deferToThread`. Make sure to avoid relying on thread-local + stuff as `deferToThread` is not guaranteed to restore original thread + context. + """ + pass + + +def TTableModelBase(): + from spyne.store.relational import add_column + + class TableModelBase(ComplexModelBase): + @classmethod + def append_field(cls, field_name, field_type): + cls._append_field_impl(field_name, field_type) + # There could have been changes to field_type in ComplexModel so we + # should not use field_type directly from above + if cls.__table__ is not None: + add_column(cls, field_name, cls._type_info[field_name]) + cls._append_to_variants(field_name, field_type) + + @classmethod + def replace_field(cls, field_name, field_type): + raise NotImplementedError() + + @classmethod + def insert_field(cls, index, field_name, field_type): + cls._insert_field_impl(index, field_name, field_type) + # There could have been changes to field_type in ComplexModel so we + # should not use field_type directly from above + if cls.__table__ is not None: + add_column(cls, field_name, cls._type_info[field_name]) + cls._insert_to_variants(index, field_name, field_type) + + return TableModelBase + + +# this has docstring repeated in the documentation at reference/model/complex.rst +def TTableModel(metadata=None, base=None, metaclass=None): + """A TableModel template that generates a new TableModel class for each + call. If metadata is not supplied, a new one is instantiated. + """ + + from sqlalchemy import MetaData + + if base is None: + base = TTableModelBase() + if metaclass is None: + metaclass = ComplexModelMeta + + @add_metaclass(metaclass) + class TableModel(base): + class Attributes(ComplexModelBase.Attributes): + sqla_metadata = metadata if metadata is not None else MetaData() + + return TableModel + + +def Mandatory(cls, **_kwargs): + """Customizes the given type to be a mandatory one. Has special cases for + :class:`spyne.model.primitive.Unicode` and + :class:`spyne.model.complex.Array`\\. + """ + + 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.update(_kwargs) + if issubclass(cls, Unicode): + kwargs.update(dict(min_len=1)) + + elif issubclass(cls, Array): + (k,v), = cls._type_info.items() + if v.Attributes.min_occurs == 0: + cls._type_info[k] = Mandatory(v) + + return cls.customize(**kwargs) diff --git a/pym/calculate/contrib/spyne/model/complex.pyc b/pym/calculate/contrib/spyne/model/complex.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a5e695b712d2f53a1c618c8fa9a25570531aa6f4 GIT binary patch literal 51271 zcmc(|3y@sbdEa@udoaM@H6UID2oh|9fG~i_;X@KB!5}G!08LQj5WD~ha!jbF(cJ(V z=$W4B+e6Gqq*pQ}Q&QGSS+b)|B-?Ui$EnznH;L`6<7AUsWwUWgyHf0IY^Ut9x8l^6 zvvO@Eu3g2uu4sS%|GD>e4+PrQdK(L%56(UJ+;h+4dw<_KxAI3@Hh%NB|Iu6{WPjH2 z|NBEJq<^ClLNkO}(o$%aL#Gtx%VD-0O1iFuP9@A%LaP$4j)m5`@MbB@j=L(i)`!{k zd45Bf-QfIK=uCw9i7-16n^+e*8^ipjFuN&UkB83YFux_tZVB^S!|c{rx;}I!!~C`| zyDeUC2%X!){Pr-rJzh_Q&W{Pto7CJ}5{LwIbG+y5pI`0hg_l4Q} z;`R2>xj)QLhuP^c|3H|1Ak04)W*?0AcDU~kh1rL~{KH}P;V}QMF#E1B|L!pR?lAwJ zF#8_r?F=7hl^zMrU7>YfxWwA*R>_+oyfXV}Xx<)L?{(>(qV#>Cxi_@-x%7^r^jK)_ z3$0@=y|XC&p3uB2FWq019uLjCL+iNfR*TZdLi3*dZ3l|d$3yd8UCcfang^YEe`p?Z z=0s?|!t2TA6ln*rZoFZ zXimHQgQ59=GtY+RgU&n`nh!ZM6Pgb@^L%K&E3_U6t)roJMiT-Izgc!C-mMDm#0#PM z9@kDn^O1bk9xZO44Xx?WdO?pi-y2$I{q+0t+d_(SLp6@&HNI!K#*3kOJhWc)qmSh` zW?u@;$8|A#KD1uW{xzQn9|!GT3C;KW)~pcm?9>TxHvKG=q~i@?S*vXu|}t!rpInpd-}=v)CcNmYp&{g)%rrS+U}>- zE3M9At5@w_yxMATN%6*X`J(Hz(&;KaNL$rxc>f9|X&{n`gxt0&v8R`0D&mDPgCU$eEe-0E*4 z_k6F}>b07x6rWsAVLSCmVu9*6t}xW0%kDxtRQ*hH>Z#{WoS9M=-29m?9qg;67Z=(M zR;j;%{F&wSisrjN!Nqf0J6*+2sVisBo_((N(urqZJax9ek?Z>6VrR9sn5Ogb%_^HY zaqjd>r)qke`qhVmhqS%ocg?rvyX_CR{A`x5wVVAds#0HQ_qkWA_b#XX9h4LmE-!R@ zt=d9&p%vev7GF8_Y`k!{daXrPyMD2g)zFK(O--2Uy8U{yS(|V5>z+2R(e-x!%23f} zYNmbG?Q*TZy4Xr%?=@jpQ@~YCDs#~TTAA;}0i~B0>y2x^+t>RWT0p&24?Zat_CsX) zA-rA+ePedIEA-3Z2e_<+*CSs8%PZlHa(KNgW_N8O^q$lzamiBC~)CtUaHCXtYnJd!#M1ExO@WQaYzxSFb8#|0TGd;9}>kydIVOq8b7 zNrPrPg*Nr;3yp{s=KzP(3zxcvniFZ->Itb&^?Kc&f#5P=#lZS%Xa*=X^wub?UFy{P zhNfCu&yQ1Kc@gpvF<|J9CcfV3`wfHQnu@d@YCd(2vCpS*_Vi4nle*PjtN$96^#WnS zLVwf~nY@!%eGk8M8%ZebDs3-qE^XuQj?%s5gr

GZ7Lb50b<=R~aP#lGoalN>hIAy0Rmm@<({p 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 from spyne.model.enum import Enum + >>> SomeEnum = Enum("SomeValue", "SomeOtherValue", type_name="SomeEnum") + >>> SomeEnum.SomeValue == SomeEnum.SomeOtherValue + False + >>> SomeEnum.SomeValue == SomeEnum.SomeValue + True + >>> SomeEnum.SomeValue is SomeEnum.SomeValue + True + >>> SomeEnum.SomeValue == 0 + False + >>> SomeEnum2 = Enum("SomeValue", "SomeOtherValue", type_name="SomeEnum") + >>> SomeEnum2.SomeValue == SomeEnum.SomeValue + False + + In the above example, ``SomeEnum`` can be used as a regular Spyne model. + """ + + 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 + + class EnumValue(object): + __slots__ = ('__value',) + + def __init__(self, value): + self.__value = value + + def __hash__(self): + return hash(self.__value) + + def __cmp__(self, other): + if isinstance(self, type(other)): + return cmp(self.__value, other.__value) + else: + return cmp(id(self), id(other)) + + def __invert__(self): + return values[maximum - self.__value] + + def __nonzero__(self): + return bool(self.__value) + + def __bool__(self): + return bool(self.__value) + + def __repr__(self): + return str(values[self.__value]) + + class EnumType(EnumBase): + __doc__ = docstr + __type_name__ = type_name + __values__ = values + + def __iter__(self): + return iter(values) + + def __len__(self): + return len(values) + + def __getitem__(self, i): + return values[i] + + def __repr__(self): + return 'Enum' + str(enumerate(values)) + + def __str__(self): + return 'enum ' + str(values) + + for i, v in enumerate(values): + setattr(EnumType, v, EnumValue(i)) + + return EnumType diff --git a/pym/calculate/contrib/spyne/model/enum.pyc b/pym/calculate/contrib/spyne/model/enum.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2d9c03b6e1bddceccbac13d6379f27ea2410d103 GIT binary patch literal 5511 zcmcgwTW=dh7@b`wPMWr)q~%g7m2J4xKx?-J6$#ODEjNjP))j~fG}+jbWSjM_*%>Dd zN?&M2+aJR-Py7>Jc;}5D0Ox$;-K0UP3c|5H!%9I)e>PDb~eyB{KRs+>z$IDlj-sh`o(zl~COxCI zo8rSFH`2IXj*Oour)Ad7;c?%rCZo*h+{z@Etl1WZl~i^Kt@=ZotyKQ+81AMU%Y&NxQ!WYv$p2PI|B->V<50LHh2@2E|e}DqIMbS~F+}q`dB+HtI!dh;5WX zi!p@|lTvpCm34_rdjkVa^kX7X_S~gtrdq2^%B_wZ||RqQjXe)3j*8=XVSHRZ8V_d=Ng3!kfJG}NsN%FT>V`|!I(^=+tb zPpR9})W}Xl?M$m35HGadX{g})U)0wa?zTh|KSL?k*G)udM{av)BDbEnsF&nXk!Rac zY22vHqvd6q-tuy^wQlmLR}6+pY5I{XWQ~oA)wu|tVk?({_MCJ-F{L?cqxE7dN*x+@ zG#nPzuiGlhjko-?t5>f^t7S2W#0J}9Yi%J24y!0#L`NkXa%Q&}7!E{NWW2S=fv;!{ zi{~QgeBstjS&fhI z51;(_D?#&xM^Ja^f0fmxM+j?|WG^Qn>QjIM5KC5yO#tmy!YFhOkg7BZSP^e4CK?eO ziH#EAZf%q$Wz?lxjyxn}Ge`GRD;0(WBQ1LHtFYS(sJ_e$LK>iCdgcj)4;nF}MoT^s-~eUq=@n z-z5o*oONXFV{jZ+>GC9C>6-rW9uheuVp@}}#>^0QUGOBrCY`RkXB;Tlb;RGRgJ+bTY3G{@?_$jtfCKvHN={#2J&v8&iIw@jdC=@kZL&KBq z5a)$@M31t?_&|Q(j}cfTfOIhgZZL{4!A3Q^yGMNz*cnVyn1;@i$u{6@-e8%W{KT!9pobcI`m1?Q~ z{TdZ@bNfMZD;t?5kn3%y1VQ*YSU7(szL3EQbKBzWOWB+C1#7kou{ zCdM!cI|zFSiQ*V zWmH1Bw{PC6;;0&%05|ahHvbsK9z(@U`A`Gj<^tX`B3~U7Ljlq4WTAP zLs&dQA(G`AQ%qrbZ&l1+84Z0mkZ!Z;hSHs>x((?fEc(e)(v`4C?^t^oo-JO6a`qV6 z0}cW}Vh3)0<({x{P{81^TCahM{n&mCx(VvczjM1uC!cJP25Azh+efb z$B5b!h$!OJ(;o2&ikbjsdaTh;GO^ERiLBf7!hzeomiJBSDNyUbxeURqJ(@Q=Ml5$*2 z8Ia(PQK30zV80{uvyjE(y#YNV{;EqG9HV&6S1}x)W7TFwcNkwpC0O!rgqR#)5Bh$l z8F5rSo&eNhp1XolxyOJma=zieOFmtvdH_aw_u(%Pw|Zvi(jt#v!y`wny=N^F4Gdi? zOWbtHL$Pwx^qjn^h 1: + warn("Duplicate faultcode {} detected for classes {}" + .format(code, target)) + + +@add_metaclass(FaultMeta) +class Fault(ComplexModelBase, Exception): + """Use this class as a base for all public exceptions. + The Fault object adheres to the + `SOAP 1.1 Fault definition `_, + + which has three main attributes: + + :param faultcode: It's a dot-delimited string whose first fragment is + either 'Client' or 'Server'. Just like HTTP 4xx and 5xx codes, + 'Client' indicates that something was wrong with the input, and 'Server' + indicates something went wrong during the processing of an otherwise + legitimate request. + + Protocol implementors should heed the values in ``faultcode`` to set + proper return codes in the protocol level when necessary. E.g. HttpRpc + protocol will return a HTTP 404 error when a + :class:`spyne.error.ResourceNotFound` is raised, and a general HTTP 400 + when the ``faultcode`` starts with ``'Client.'`` or is ``'Client'``. + + Soap would return Http 500 for any kind of exception, and denote the + nature of the exception in the Soap response body. (because that's what + the standard says... Yes, soap is famous for a reason :)) + :param faultstring: It's the human-readable explanation of the exception. + :param detail: Additional information dict. + :param lang: Language code corresponding to the language of faultstring. + """ + + REGISTERED = defaultdict(set) + """Class-level variable that holds a multimap of all fault codes and the + associated classes.""" + + __type_name__ = "Fault" + + CODE = None + + 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 + self.detail = detail + self.lang = lang + + def __len__(self): + return 1 + + def __str__(self): + return repr(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) + + @staticmethod + def to_dict(cls, value, prot): + if not issubclass(cls, Fault): + return { + "faultcode": "Server.Unknown", + "faultstring": cls.__name__, + "detail": str(value), + } + + retval = { + "faultcode": value.faultcode, + "faultstring": value.faultstring, + } + + if value.faultactor is not None: + if len(value.faultactor) > 0 or (not prot.ignore_empty_faultactor): + retval["faultactor"] = value.faultactor + + if value.detail is not None: + retval["detail"] = value.detail_to_doc(prot) + + return retval + + # + # From http://schemas.xmlsoap.org/soap/envelope/ + # + # + # + # + # + # + @staticmethod + def to_list(cls, value, prot=None): + if not issubclass(cls, Fault): + return [ + "Server.Unknown", # faultcode + cls.__name__, # faultstring + "", # faultactor + str(value), # detail + ] + + retval = [ + value.faultcode, + value.faultstring, + ] + + if value.faultactor is not None: + retval.append(value.faultactor) + else: + retval.append("") + + if value.detail is not None: + retval.append(value.detail_to_doc(prot)) + else: + retval.append("") + + return retval + + @classmethod + def to_bytes_iterable(cls, value): + return [ + value.faultcode.encode('utf8'), + b'\n\n', + value.faultstring.encode('utf8'), + ] + + def detail_to_doc(self, prot): + return self.detail + + def detail_from_doc(self, prot, doc): + self.detail = doc diff --git a/pym/calculate/contrib/spyne/model/fault.pyc b/pym/calculate/contrib/spyne/model/fault.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac265bd0f7a459b8eba76b8b194f9f5e5ba09f4f GIT binary patch literal 5977 zcmcgw-EJGl6`mz2N|Y(fu@kpR(`3@rHC#?PY)hz364%q>s?MK0y0@XDCWZeJe}a(fph_bNpws9{y@RQS{Qz zcIN%soXQr|u%UJueq2}Cq8gr4JLmj(UdBze)5Lf|nR9ACP)S35rPP;7eZI4#OhcI^ z^(AH(m1!z-UhP*@a_$%c3p>jysj9736ZEG4#ZN0h&ykNwT;_gsj?9?-c$~Q;?YXX> ztzvc~Kk|bm4B{k-hQ`IcEVkB9U%>ReVmQjo)6a^;WS?RA#Va4i*0=`1KjJZjn+cT^ zeTdJ#g2pJy5~2i`I~5gf3A!E$uH)nXd-&|1&^Y`B>KVjQQ3n_hZAV_SBzbZ_le zXLRHSMgCs<{f!?QRX6}%oO0#G|KF}s*um^8|@oYNJK6=1(4{w1LsEToz7%3X-{spi?ZL@4mtBtrD@zZJ{$zXmk-qixsgCnR-^PFXlf6DeGuxl$a5;n<@(??1 z3%KS$2mxD@vLHz~l0wyKJ{r60g7Wyx8Nw4hr%;e~k0Tiicf>L(i=MHTXB7KDrVDa3 zNv+o!naoTddO`p(x-?&m5g*!KmRx*P7Ov3k#u*L_JRB|BOAmZZsHU-E^{v=?wQi*&&kXalR+^i*SR6-ae36%o9%vEe*!ZK zN4?YN{GLe)+nr*Kr`lM(rA=8vVS*~2ZCaOjzP>9Ft1Tey(AZ*J_Dr{M9~I*~*@X@0 zGKP>6uYg$hO>W9KJ4U`b!zbv;!FM^gh@=iWr8akWrv}iz3YmZ;V4uxl>Xf**ig=_a zBHSrIWLn=|UG+YiAL&CVpSqkmsV6Zpc>xWAk{M}v3^^OZlD--IvB>2tc<~5+ZuDM} zK+df_(~HLvCSv-{1ZFzJM=angPvR0D6d&1kyRAQmp~H|tHn`f4hs7BGz+()B#1`Ja ze(joIIPIC<{ieQ2w1e?5&R4J_iT5(nI?7^@&*<@e@_k5}Vnf=B(`;RDB#FctXeiBn zI^5)(vIdMPCI5+Bku0R;rdi$!~qJu*oJk}rKQK*fX9z?8s` z>Ea$f`wKLzevrM;si@Hp**`$&#t@TI6|qy5!UY{EUpOPBsV}m+KCd%r&Rol}@I#`G z+|kJR49{xu6rqwdWgPe5vO=sEmLz<#CwRkGu`hg!jb_7y7cx1A@1i+Lvu9QaY~dKo z46iDU;58HgjiAT+?D!K&vZz5a-D**`U8&zZX@n9M&X!U)k8`33MOPI423;u$)Cr+8 zm6H)z15}8FeXKtcDN--ZsFcF_<&g}tjiTSZfMk}jB3o8?p!YyZ<--M4UZ@p_WL~()Ntj>_AX3A1MXOhA>xy01SITSlH5@b>vc?wA#fmpXF*;hY z6su7raT?{`8<;vV(3d8@1soei)L0b7=zALtmV;*S3d+@96>~I8{uep^10An=+|kIO5^TYR*62G zwIAn)c`?aPq%IL51%M9_a&MIglUh686HQ4>6lKZ%1a^07`#ao8-G&#@xF4WN`*~5C z$P7pBC^`vLa*~8MZy=E?qNM1_4Nef_79*D?DLKTeP*pgIZ^)RKeF>3(G$FH4Aofi( zsWq+e58R3f}j45N?x z^7riGw^ZQ4DbomYT!Li^m|$c9w>FNg;E$)k7pJyBp#R%MtDs@O&?CZ$cHad3ucO+>nE{b49Ok%Vq z=Vd{XuVl9qk({w0_^bm%-aEo|B*LYrWaaf&Oj@c-K?v1g#ynG)Fwa=wBmL>@CTjKM zOFcnlo-O$yZRlHkB30$%F-?}L5=vPj@!<(!eEJGRCj2X!r{Y`l~iXLoqKYqON@uobWgg+(B&)AS*$HxuS_Ac%5N?Ii04KCf}5>ZNspRTNN zh2jtIpg9qj^v^-3M};>Gz!6~7D1Z&!omH+T8?SbFOOZCwQc$| zq#e0Svw6R*=igsL33H77{<)B4{O0lVip0*BAV87FUH^dg0Ugvb4POW@RGO6w{0%Nt JFQ0D){{t%NXAl4Y literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/model/primitive/__init__.py b/pym/calculate/contrib/spyne/model/primitive/__init__.py new file mode 100644 index 0000000..64f1ba4 --- /dev/null +++ b/pym/calculate/contrib/spyne/model/primitive/__init__.py @@ -0,0 +1,155 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +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 + +# 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 + +# 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 + + +# 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) + + 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) + + Boolean = Boolean(type_name="MandatoryBoolean", min_occurs=1, nillable=False) + + Date = Date(type_name="MandatoryDate", min_occurs=1, nillable=False) + Time = Time(type_name="MandatoryTime", min_occurs=1, nillable=False) + DateTime = DateTime(type_name="MandatoryDateTime", min_occurs=1, nillable=False) + Duration = Duration(type_name="MandatoryDuration", min_occurs=1, nillable=False) + + Decimal = Decimal(type_name="MandatoryDecimal", min_occurs=1, nillable=False) + Double = Double(type_name="MandatoryDouble", min_occurs=1, nillable=False) + Float = Float(type_name="MandatoryFloat", min_occurs=1, nillable=False) + + Integer = Integer(type_name="MandatoryInteger", min_occurs=1, nillable=False) + Integer64 = Integer64(type_name="MandatoryLong", min_occurs=1, nillable=False) + Integer32 = Integer32(type_name="MandatoryInt", min_occurs=1, nillable=False) + Integer16 = Integer16(type_name="MandatoryShort", min_occurs=1, nillable=False) + Integer8 = Integer8(type_name="MandatoryByte", min_occurs=1, nillable=False) + + Long = Integer64 + Int = Integer32 + 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) + + UnsignedLong = UnsignedInteger64 + UnsignedInt = UnsignedInteger32 + UnsignedShort = UnsignedInteger16 + UnsignedByte = UnsignedInteger8 + + Uuid = Uuid(type_name="MandatoryUuid", min_len=1, min_occurs=1, nillable=False) + + Point = Point(type_name="Point", min_len=1, min_occurs=1, nillable=False) + Line = Line(type_name="LineString", min_len=1, min_occurs=1, nillable=False) + 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) + MultiLineString = MultiLine + MultiPolygon = MultiPolygon(type_name="MandatoryMultiPolygon", min_len=1, min_occurs=1, nillable=False) + + +assert Mandatory.Long == Mandatory.Integer64 diff --git a/pym/calculate/contrib/spyne/model/primitive/__init__.pyc b/pym/calculate/contrib/spyne/model/primitive/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8eb70526f73d2346f6e2461a07bb628fcef74390 GIT binary patch literal 5261 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\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): + """Just that, Time. No time zone support. + + Native type is :class:`datetime.time`. + """ + + __type_name__ = 'time' + Value = datetime.time + + class Attributes(SimpleModel.Attributes): + """Customizable attributes of the :class:`spyne.model.primitive.Time` + type.""" + + gt = None # minExclusive + """The time should be greater than this time.""" + + ge = datetime.time(0, 0, 0, 0) # minInclusive + """The time should be greater than or equal to this time.""" + + lt = None # maxExclusive + """The time should be lower than this time.""" + + le = datetime.time(23, 59, 59, 999999) # maxInclusive + """The time should be lower than or equal to this time.""" + + pattern = None + """A regular expression that matches the whole time. See here for more + info: http://www.regular-expressions.info/xml.html""" + + time_format = None + """Time format fed to the ``strftime`` function. See: + http://docs.python.org/library/datetime.html?highlight=strftime#strftime-strptime-behavior + Ignored by protocols like SOAP which have their own ideas about how + Date objects should be serialized.""" + + @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 + ) + + @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) + and value >= cls.Attributes.ge + 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) + + +class DateTime(SimpleModel): + """A compact way to represent dates and times together. Supports time zones. + Working with timezones is a bit quirky -- Spyne works very hard to have + all datetimes with time zones internally and only strips them when + explicitly requested with ``timezone=False``\\. See + :attr:`DateTime.Attributes.as_timezone` for more information. + + Native type is :class:`datetime.datetime`. + """ + + __type_name__ = 'dateTime' + Value = datetime.datetime + + _local_re = re.compile(DATETIME_PATTERN) + _utc_re = re.compile(DATETIME_PATTERN + 'Z') + _offset_re = re.compile(DATETIME_PATTERN + OFFSET_PATTERN) + + class Attributes(SimpleModel.Attributes): + """Customizable attributes of the :class:`spyne.model.primitive.DateTime` + type.""" + + gt = None # minExclusive + """The datetime should be greater than this datetime. It must always + have a timezone.""" + + ge = _min_dt # minInclusive + """The datetime should be greater than or equal to this datetime. It + must always have a timezone.""" + + lt = None # maxExclusive + """The datetime should be lower than this datetime. It must always have + a timezone.""" + + le = _max_dt # maxInclusive + """The datetime should be lower than or equal to this datetime. It must + always have a timezone.""" + + pattern = None + """A regular expression that matches the whole datetime. See here for + more info: http://www.regular-expressions.info/xml.html""" + + dt_format = None + """DateTime format fed to the ``strftime`` function. See: + http://docs.python.org/library/datetime.html?highlight=strftime#strftime-strptime-behavior + Ignored by protocols like SOAP which have their own ideas about how + DateTime objects should be serialized.""" + + out_format = None + """DateTime format fed to the ``strftime`` function only when + serializing. See: + http://docs.python.org/library/datetime.html?highlight=strftime#strftime-strptime-behavior + Ignored by protocols like SOAP which have their own ideas about how + DateTime objects should be serialized.""" + + string_format = None + """A regular python string formatting string. %s will contain the date + string. See here for more info: + http://docs.python.org/library/stdtypes.html#string-formatting""" + + as_timezone = None + """When not None, converts: + - Outgoing values to the given time zone (by calling + ``.astimezone()``). + - Incoming values without tzinfo to the given time zone by calling + ``.replace(tzinfo=)`` and values with tzinfo to the + given timezone by calling ``.astimezone()``. + + Either None or a return value of pytz.timezone() + + When this is None and a datetime with tzinfo=None comes in, it's + converted to spyne.LOCAL_TZ which defaults to ``pytz.utc``. You can use + `tzlocal `_ to set it to local + time right after ``import spyne``. + """ + + timezone = True + """If False, time zone info is stripped before serialization. Also makes + sqlalchemy schema generator emit 'timestamp without timezone'.""" + + serialize_as = None + """One of (None, 'sec', 'sec_float', 'msec', 'msec_float', 'usec')""" + + # TODO: Move this to ModelBase and make it work with all types in all + # protocols. + parser = None + """Callable for string parser. It must accept exactly four arguments: + `protocol, cls, string` and must return a `datetime.datetime` object. + If this is not None, all other parsing configurations (e.g. + `date_format`) are ignored. + """ + + @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 + ) + + @staticmethod + 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 ( + # min_dt is also a valid value if gt is intact. + (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): + """Just that, Date. No time zone support. + + Native type is :class:`datetime.date`. + """ + + __type_name__ = 'date' + + _offset_re = re.compile(DATE_PATTERN + '(' + OFFSET_PATTERN + '|Z)') + Value = datetime.date + + class Attributes(DateTime.Attributes): + """Customizable attributes of the :class:`spyne.model.primitive.Date` + type.""" + + gt = None # minExclusive + """The date should be greater than this date.""" + + ge = datetime.date(1, 1, 1) # minInclusive + """The date should be greater than or equal to this date.""" + + lt = None # maxExclusive + """The date should be lower than this date.""" + + le = datetime.date(datetime.MAXYEAR, 12, 31) # maxInclusive + """The date should be lower than or equal to this date.""" + + date_format = None + """Date format fed to the ``strftime`` function. See: + http://docs.python.org/library/datetime.html?highlight=strftime#strftime-strptime-behavior + Ignored by protocols like SOAP which have their own ideas about how + Date objects should be serialized.""" + + pattern = None + """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 + ) + + +# this object tries to follow ISO 8601 standard. +class Duration(SimpleModel): + """Native type is :class:`datetime.timedelta`.""" + + __type_name__ = 'duration' + Value = datetime.timedelta + + +NATIVE_MAP.update({ + datetime.datetime: DateTime, + datetime.time: Time, + datetime.date: Date, + datetime.timedelta: Duration, +}) diff --git a/pym/calculate/contrib/spyne/model/primitive/datetime.pyc b/pym/calculate/contrib/spyne/model/primitive/datetime.pyc new file mode 100644 index 0000000000000000000000000000000000000000..07d65cdc1649c1e659928f144372614e54bdfbf6 GIT binary patch literal 6625 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/model/primitive/number.py b/pym/calculate/contrib/spyne/model/primitive/number.py new file mode 100644 index 0000000..e10c08b --- /dev/null +++ b/pym/calculate/contrib/spyne/model/primitive/number.py @@ -0,0 +1,417 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import math +import decimal +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): + pass + + +class Decimal(SimpleModel): + """The primitive that corresponds to the native python Decimal. + + This is also the base class for denoting numbers. + + Note that it is your responsibility to make sure that the scale and + precision constraints set in this type is consistent with the values in the + context of the decimal package. See the :func:`decimal.getcontext` + documentation for more information. + """ + + __type_name__ = 'decimal' + + Value = decimal.Decimal + # contrary to popular belief, Decimal hates float. + + class Attributes(SimpleModel.Attributes): + """Customizable attributes of the :class:`spyne.model.primitive.Decimal` + type.""" + + gt = decimal.Decimal('-inf') # minExclusive + """The value should be greater than this number.""" + + ge = decimal.Decimal('-inf') # minInclusive + """The value should be greater than or equal to this number.""" + + lt = decimal.Decimal('inf') # maxExclusive + """The value should be lower than this number.""" + + le = decimal.Decimal('inf') # maxInclusive + """The value should be lower than or equal to this number.""" + + max_str_len = 1024 + """The maximum length of string to be attempted to convert to number.""" + + format = None + """A regular python string formatting string. See here: + http://docs.python.org/2/library/stdtypes.html#string-formatting""" + + str_format = None + """A regular python string formatting string used by invoking its + ``format()`` function. See here: + http://docs.python.org/2/library/string.html#format-string-syntax""" + + pattern = None + """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') + """Maximum number of digits.""" + + fraction_digits = decimal.Decimal('inf') + """Maximum number of digits after the decimal separator.""" + + min_bound = None + """Hardware limit that determines the lowest value this type can + store.""" + + max_bound = None + """Hardware limit that determines the highest value this type can + store.""" + + 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 + if len(args) == 2 and args[1] is not None: + kwargs['fraction_digits'] = args[1] + + retval = SimpleModel.__new__(cls, **kwargs) + + return retval + + @classmethod + def _s_customize(cls, **kwargs): + 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) + + msl = kwargs.get('max_str_len', None) + if msl is None: + kwargs['max_str_len'] = cls.Attributes.total_digits + 2 + # + 1 for decimal separator + # + 1 for negative sign + + else: + kwargs['max_str_len'] = msl + + minb = cls.Attributes.min_bound + maxb = cls.Attributes.max_bound + ge = kwargs.get("ge", None) + gt = kwargs.get("gt", None) + le = kwargs.get("le", None) + lt = kwargs.get("lt", None) + + 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) + + if gt is not None and gt < minb: + 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)) + + if lt is not None and lt <= minb: + raise ValueError( + "'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) + + if lt is not None and lt > maxb: + 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)) + + if gt is not None and gt >= maxb: + raise ValueError( + "'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 + ) + + @staticmethod + def validate_string(cls, value): + return SimpleModel.validate_string(cls, value) and ( + value is None or (len(value) <= cls.Attributes.max_str_len) + ) + + @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 + )) + + +class Double(Decimal): + """This is serialized as the python ``float``. So this type comes with its + gotchas. Unless you really know what you're doing, you should use a + :class:`Decimal` with a pre-defined number of integer and decimal digits. + + .. NOTE:: + This class is not compatible with :class:`spyne.model.Decimal`. You can + get strange results if you're using a `decimal.Decimal` instance for a + field denoted as `Double` or `Float` and vice versa. Make sure you only + return instances of types compatible with designated types. + """ + + __type_name__ = 'double' + Value = float + + 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 + """The value should be greater than this number.""" + + ge = float('-inf') # minInclusive + """The value should be greater than or equal to this number.""" + + lt = float('inf') # maxExclusive + """The value should be lower than this number.""" + + 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 + ) + + +class Float(Double): + """Synonym for Double (as far as python side of things are concerned). + It's here for compatibility reasons.""" + + __type_name__ = 'float' + + +class Integer(Decimal): + """The arbitrary-size signed 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) + ) + + +class UnsignedInteger(Integer): + """The arbitrary-size unsigned integer, also known as nonNegativeInteger.""" + + __type_name__ = 'nonNegativeInteger' + + @staticmethod + def validate_native(cls, value): + return ( Integer.validate_native(cls, value) + and (value is None or value >= 0) + ) + + +NonNegativeInteger = UnsignedInteger +"""The arbitrary-size unsigned integer, alias for UnsignedInteger.""" + + +class PositiveInteger(NonNegativeInteger): + + """The arbitrary-size positive integer (natural number).""" + + __type_name__ = 'positiveInteger' + + @staticmethod + def validate_native(cls, value): + 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 + + class _BoundedInteger(Integer): + __type_name__ = type_name + + class Attributes(Integer.Attributes): + max_str_len = math.ceil(math.log(2**num_bits, 10)) + min_bound = _min_b + max_bound = _max_b + + @staticmethod + def validate_native(cls, value): + return ( + Integer.validate_native(cls, value) + and (value is None or (_min_b <= value <= _max_b)) + ) + + return _BoundedInteger + + +def TBoundedUnsignedInteger(num_bits, type_name): + _min_b = 0 + _max_b = 2 ** num_bits - 1 # -1? c'est la vie ;) + + class _BoundedUnsignedInteger(UnsignedInteger): + __type_name__ = type_name + + class Attributes(UnsignedInteger.Attributes): + max_str_len = math.ceil(math.log(2**num_bits, 10)) + min_bound = _min_b + max_bound = _max_b + + @staticmethod + def validate_native(cls, value): + return ( + UnsignedInteger.validate_native(cls, value) + and (value is None or (_min_b <= value < _max_b)) + ) + + return _BoundedUnsignedInteger + + +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') +"""The 64-bit signed integer, also known as ``int``.""" + +Int = Integer32 +"""The 32-bit signed integer, alias for :class:`Integer32`.""" + + +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') +"""The 8-bit signed integer, also known as ``byte``.""" + +Byte = Integer8 +"""The 8-bit signed integer, alias for :class:`Integer8`.""" + + +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') +"""The 64-bit unsigned integer, also known as ``unsignedInt``.""" + +UnsignedInt = UnsignedInteger32 +"""The 32-bit unsigned integer, alias for :class:`UnsignedInteger32`.""" + + +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') +"""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, +}) + + +if not six.PY2: + 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/pym/calculate/contrib/spyne/model/primitive/number.pyc b/pym/calculate/contrib/spyne/model/primitive/number.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8db8a368d1c83aef361209f62a24d9f16584dcd6 GIT binary patch literal 12574 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/model/primitive/spatial.py b/pym/calculate/contrib/spyne/model/primitive/spatial.py new file mode 100644 index 0000000..cf3ada5 --- /dev/null +++ b/pym/calculate/contrib/spyne/model/primitive/spatial.py @@ -0,0 +1,263 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +# +# FIXME: Supports e.g. +# MULTIPOINT (10 40, 40 30, 20 20, 30 10) +# +# but not: +# MULTIPOINT ((10 40), (40 30), (20 20), (30 10)) +# +from spyne.model import SimpleModel +from spyne.model.primitive.string import Unicode + + +FLOAT_PATTERN = r'-?[0-9]+\.?[0-9]*(e-?[0-9]+)?' + + +_rinse_and_repeat = r'\s*\(%s\s*(,\s*%s)*\)\s*' +def _get_one_point_pattern(dim): + return ' +'.join([FLOAT_PATTERN] * dim) + +def _get_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) + + +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) + +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) + + +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) + +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) + + +class Point(Unicode): + """A point type whose native format is a WKT string. You can use + :func:`shapely.wkt.loads` to get a proper point type. + + It's a subclass of the :class:`Unicode` type, so regular Unicode constraints + apply. The only additional parameter is the number of dimensions. + + :param dim: Number of dimensons. + """ + + __type_name__ = None + + class Attributes(Unicode.Attributes): + dim = None + + @staticmethod + 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(%%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 + + retval = SimpleModel.__new__(cls, **kwargs) + retval.__namespace__ = 'http://spyne.io/schema' + retval.__extends__ = Unicode + retval.__orig__ = Unicode + return retval + + +class Line(Unicode): + """A line type whose native format is a WKT string. You can use + :func:`shapely.wkt.loads` to get a proper line type. + + It's a subclass of the :class:`Unicode` type, so regular Unicode constraints + apply. The only additional parameter is the number of dimensions. + + :param dim: Number of dimensons. + """ + + __type_name__ = None + + class Attributes(Unicode.Attributes): + dim = None + + 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 + + retval = SimpleModel.__new__(cls, **kwargs) + retval.__namespace__ = 'http://spyne.io/schema' + retval.__extends__ = Unicode + retval.__orig__ = Unicode + return retval + +LineString = Line + + +class Polygon(Unicode): + """A polygon type whose native format is a WKT string. You can use + :func:`shapely.wkt.loads` to get a proper polygon type. + + It's a subclass of the :class:`Unicode` type, so regular Unicode constraints + apply. The only additional parameter is the number of dimensions. + + :param dim: Number of dimensons. + """ + __type_name__ = None + + class Attributes(Unicode.Attributes): + dim = None + + 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 + + retval = SimpleModel.__new__(cls, **kwargs) + retval.__namespace__ = 'http://spyne.io/schema' + retval.__extends__ = Unicode + retval.__orig__ = Unicode + return retval + + +class MultiPoint(Unicode): + """A MultiPoint type whose native format is a WKT string. You can use + :func:`shapely.wkt.loads` to get a proper MultiPoint type. + + It's a subclass of the :class:`Unicode` type, so regular Unicode constraints + apply. The only additional parameter is the number of dimensions. + + :param dim: Number of dimensons. + """ + + __type_name__ = None + + class Attributes(Unicode.Attributes): + dim = None + + 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 + + retval = SimpleModel.__new__(cls, **kwargs) + retval.__namespace__ = 'http://spyne.io/schema' + retval.__extends__ = Unicode + retval.__orig__ = Unicode + return retval + + +class MultiLine(Unicode): + """A MultiLine type whose native format is a WKT string. You can use + :func:`shapely.wkt.loads` to get a proper MultiLine type. + + It's a subclass of the :class:`Unicode` type, so regular Unicode constraints + apply. The only additional parameter is the number of dimensions. + + :param dim: Number of dimensons. + """ + + __type_name__ = None + + class Attributes(Unicode.Attributes): + dim = None + + 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 + + retval = SimpleModel.__new__(cls, **kwargs) + retval.__namespace__ = 'http://spyne.io/schema' + retval.__extends__ = Unicode + retval.__orig__ = Unicode + return retval + +MultiLineString = MultiLine + + +class MultiPolygon(Unicode): + """A MultiPolygon type whose native format is a WKT string. You can use + :func:`shapely.wkt.loads` to get a proper MultiPolygon type. + + It's a subclass of the :class:`Unicode` type, so regular Unicode constraints + apply. The only additional parameter is the number of dimensions. + + :param dim: Number of dimensons. + """ + + __type_name__ = None + + class Attributes(Unicode.Attributes): + dim = None + + 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 + + retval = SimpleModel.__new__(cls, **kwargs) + retval.__namespace__ = 'http://spyne.io/schema' + retval.__extends__ = Unicode + retval.__orig__ = Unicode + return retval + diff --git a/pym/calculate/contrib/spyne/model/primitive/spatial.pyc b/pym/calculate/contrib/spyne/model/primitive/spatial.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b2119a2dc42a3aad1399416cfd50e253a43ec4e3 GIT binary patch literal 11689 zcmeHN-E!N;6<&}M_2WNTwrM-DT{Ni@%8|%8ZrwzqNg^k%qlrvuASE3uZebXJC|D%G z!GdtnO?NtcR+%aoOq_HM1~!c!t(4cw7X}& zv)`VxK>phkliz&(xBISYfAaW!AD5mpl=ARrsJc=OLv0$$U_PhnIn~Ik%{=n>8ByMd z+8kBhsCuf@WE~%9|A7nDUN^a9nxEML40n6C#{c-boQo zDesgBQ_7nX;k5EjD?hKc4CPI;Z_%rc-)0D@D;6wRu)~=Q?%8tnQrh&UZ>L zWTi#rUF?*;l$GMf^J?>g@?P%LUCQb%D(|vdFI~Z`1^>pUgqc&xF(m6jqgnUwM4n$y z3&&9SNf@{&(U&35zxUaj^Y8rTjeF%(xLWc%MYHee3%KK+zIv}Tqw!OkLo%ahuil%5 z;Ib251ndJ``YaNl^$>j8OqHnhuj~dO@RvA0>(Y3{s_~<4QevaO3Bd=5Debg>RLAS=+$Eo?cqMN&+ zKmS(w+V%3a8}rRw+)?&xwY0p_;6zlKanJ~o;E|6~CkdQ-8Lbu3zFqSZI|_Zf$)VY( zO#C=}6*V$=Wjw3%NmN4TL{VEPTkL4dinZ0{>PBb&W<@h=6y>SJIq0K;)96kV+@suU zDD72_AZ38QgiNN{m(UWJ%HLLwiW2;);3--qr;)egAk@C?gq|JyP2WkK)RS(&_Z z*3s}6)R4=wO+yDK({2;wbhlow^ys3WjckTfgnjw zNA%mL+lSQce@Bpd?OUV$Mv%T?hG2U~*#qNks(Jtzx%%3><{m8Ro(u%biyckBPs@*~ zWeR9Q&uxv4p$kDibd+x5(!9+_?16XyX^s&H!xBUJqv~Nn;)Go0trwJ!&?L{O<*7lR zaT5Uwq85ZNkSCP2Ug9RJ7vNtlnc}LL$!^m(A8$w6H$%9rk9>10iW^R12HJGYUw^z| zrkh3Cyc@Ml*9py*_9snz7PeZUyKrA`J59g7TYkKgl>HB69nQ)5m@69-B`f*QB zYm?u3Hb>x}&ujZJEioZ!Sn~;eI=eKtmYZoT(!-_G_)W6PxWC(~Uw5%fXas zY0zmlF$8l1jYMI6*K|A&es~l*b+hTjPQ!=0O^w(~*lIjL4t*jH@I#H;bbDM2ax=>p z%<8_|ZA(+Ojo_hG zXO=fqv0qvgx~wYFQO7A3Js`$HVwD9WI0f0wBjLpXeSk|xNK(%oKKqlL(pMxaE^CVv5+LmRY86a;bNpqo+2Givr zs%UrHZ#aTMPqWgEMIXST%VQOo;8M~RR+ax4tB5X1y222JyI5Bi@sm>v+x9uekfxaA>^bnWt`4U z8x!)amS__eXU}4Y)}8||a-lKjs67$cM7JkG7J9LhfQdZ=4#JmAit-!9|69Xj(UM>35KHDORlbdD|k49HhccaExrs z{Z_vXqgXN-7xZNh%sTpi*aF3bGE}&_1eND*d|g9L7ciNt-=@Yb?)L;ghooQ(1&dlH z2TUrZ34uMWpR(ZKq{(F_q$#W2dX-s1X#I@I3=&~OiwAf@h1Tnoh*cM_BWHzI(A`s9 z&!N9@4lAQSi>Ga=Xmd*VT+_{@s!+>olV}xkQ0k(mI?TrQfm&0 z#M9hI*X3m`i$S+VhtwirCu|^dLff}cu@bJH tag.""" + + class Value(object): + """A special object that is just a better way of carrying the + information carried with a link. + + :param href: The uri string. + :param text: The text data that goes with the link. This is a + ``str`` or a ``unicode`` instance. + :param content: The structured data that goes with the link. This is an + `lxml.etree.Element` instance. + """ + + def __init__(self, href, text=None, content=None): + self.href = href + self.text = text + self.content = content + + def __repr__(self): + return "Uri(href={0!r}, text={1!r}, content={2!r})" \ + .format(self.href, self.text, self.content) + + +class ImageUri(AnyUri): + """A special kind of String that holds the uri of an image.""" + + +def _uuid_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 + and re_match_with_span(cls.Attributes, value) + ))) + + +def _Tuuid_validate(key): + from uuid import UUID + + def _uvalid(cls, v): + try: + 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'), +} + + +class Uuid(Unicode(pattern=UUID_PATTERN)): + """Unicode subclass for Universially-Unique Identifiers.""" + + __namespace__ = 'http://spyne.io/schema' + __type_name__ = 'uuid' + Value = uuid.UUID + + class Attributes(Unicode(pattern=UUID_PATTERN).Attributes): + serialize_as = None + + @staticmethod + def validate_string(cls, value): + return _uuid_validate[cls.Attributes.serialize_as](cls, value) + + @staticmethod + def validate_native(cls, value): + return SimpleModel.validate_native(cls, value) + + +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' + + +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' + + +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' + + +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' + + +class MediaTypeStrict(Unicode(unicode_pattern=MEDIA_TYPE_PATTERN_STRICT)): + """A special kind of String type designed to hold a mime type as defined + by IANA followed by arbitrary parameters. + + See: https://tools.ietf.org/html/rfc7231#section-3.1.1.1""" + + __namespace__ = 'http://spyne.io/schema' + __type_name__ = 'strictMediaTypeString' + + +class MediaType(Unicode(unicode_pattern=MEDIA_TYPE_PATTERN_PERMISSIVE)): + """A special kind of String type designed to hold a forward-compatible + media type that can have any string as main type. A media type is + essentially a mime type plus parameters. + + See: https://tools.ietf.org/html/rfc7231#section-3.1.1.1""" + + __namespace__ = 'http://spyne.io/schema' + __type_name__ = 'mediaTypeString' + + +if not six.PY2: + NATIVE_MAP.update({ + str: Unicode, + }) + +else: + NATIVE_MAP.update({ + str: String, + unicode: Unicode, + }) diff --git a/pym/calculate/contrib/spyne/model/primitive/string.pyc b/pym/calculate/contrib/spyne/model/primitive/string.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3d5c3b4c86bc9b6d5377ef967aa151706e4ba72 GIT binary patch literal 11411 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/model/primitive/xml.py b/pym/calculate/contrib/spyne/model/primitive/xml.py new file mode 100644 index 0000000..d60494a --- /dev/null +++ b/pym/calculate/contrib/spyne/model/primitive/xml.py @@ -0,0 +1,195 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import re + +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) + + +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) + + +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) + + +class NormalizedString(Unicode): + __type_name__ = 'normalizedString' + __extends__ = Unicode + + class Attributes(Unicode.Attributes): + white_space = "replace" + + +class Token(NormalizedString): + __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' + + 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 + ) + + +# https://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-NCName +class NCName(Name): + __type_name__ = 'NCName' + class Attributes(Unicode.Attributes): + pattern = "(%s|_)%s*" % (RE_Letter.pattern, RE_NCNameChar.pattern) + + +# https://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-QName +class QName(Token): + __type_name__ = "QName" + + class Attributes(Unicode.Attributes): + """ + QName = (PrefixedName | UnprefixedName) + PrefixedName ::= Prefix ':' LocalPart + UnprefixedName ::= LocalPart + Prefix ::= NCName + LocalPart ::= NCName + + i.e. + + QName = (NCName:)?NCName + """ + pattern = "(%s:)?(%s)" % ( + NCName.Attributes.pattern, + NCName.Attributes.pattern, + ) + + +class NMToken(Unicode): + __type_name__ = 'NMTOKEN' + + class Attributes(Unicode.Attributes): + unicode_pattern = PATT_NMTOKEN + + +class ID(NCName): + __type_name__ = 'ID' + + +class Language(Token): + __type_name__ = 'language' + + class Attributes(Unicode.Attributes): + pattern = '[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*' diff --git a/pym/calculate/contrib/spyne/model/primitive/xml.pyc b/pym/calculate/contrib/spyne/model/primitive/xml.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b4fcdf4965f3f2a762823720a10bb7ed9b6a4c13 GIT binary patch literal 7570 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/model/table.py b/pym/calculate/contrib/spyne/model/table.py new file mode 100644 index 0000000..82cdfe4 --- /dev/null +++ b/pym/calculate/contrib/spyne/model/table.py @@ -0,0 +1,227 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""This module is DEPRECATED. Create your own TableModel using +:func:`spyne.model.complex.TTableModel` + +Here's an example way of using the :class:`spyne.model.table.TableModel`: :: + + class User(TableModel, DeclarativeBase): + __namespace__ = 'spyne.examples.user_manager' + __tablename__ = 'spyne_user' + + user_id = Column(sqlalchemy.Integer, primary_key=True) + user_name = Column(sqlalchemy.String(256)) + first_name = Column(sqlalchemy.String(256)) + last_name = Column(sqlalchemy.String(256)) + +Defined this way, SQLAlchemy objects are regular Spyne objects that can be +used anywhere the regular Spyne types go. The definition for the `User` object +is quite similar to vanilla SQLAlchemy declarative syntax, save for two +elements: + +#. The object also bases on :class:`spyne.model.table.TableModel`, which + bridges SQLAlchemy and Spyne types. +#. It has a namespace declaration, which is just so the service looks good + on wsdl. + +The SQLAlchemy integration is far from perfect at the moment: + +* SQL constraints are not reflected to the interface document. +* It's not possible to define additional constraints for the Spyne schema. +* Object attributes defined by mechanisms other than Column and limited + uses of `relationship` (no string arguments) are not supported. + +If you need any of the above features, you need to separate the Spyne and +SQLAlchemy object definitions. + +Spyne makes it easy (to an extent) with the following syntax: :: + + class AlternativeUser(TableModel, DeclarativeBase): + __namespace__ = 'spyne.examples.user_manager' + __table__ = User.__table__ + +Here, The AlternativeUser object is automatically populated using columns from +the table definition. +""" + +import warnings +warnings.warn("%r module is deprecated. Please switch to " + "spyne.model.complex.TTableModel.\nHere's where the import " + "comes from:" % __name__) +import traceback +traceback.print_stack() + + +import logging +logger = logging.getLogger(__name__) + +import sqlalchemy + +from spyne.util.six import add_metaclass + +from sqlalchemy import Column +from sqlalchemy.orm import RelationshipProperty +from sqlalchemy.ext.declarative import DeclarativeMeta +from sqlalchemy.dialects.postgresql import UUID + +from spyne.model import primitive +from spyne.model import binary +from spyne.model import complex +from spyne.model.complex import Array +from spyne.model.complex import TypeInfo +from spyne.model.complex import ComplexModelBase +from spyne.model.complex import ComplexModelMeta + + +_type_map = { + sqlalchemy.Text: primitive.String, + sqlalchemy.String: primitive.String, + sqlalchemy.Unicode: primitive.String, + sqlalchemy.UnicodeText: primitive.String, + + sqlalchemy.Float: primitive.Float, + sqlalchemy.Numeric: primitive.Decimal, + sqlalchemy.BigInteger: primitive.Integer, + sqlalchemy.Integer: primitive.Integer, + sqlalchemy.SmallInteger: primitive.Integer, + + sqlalchemy.Binary: binary.ByteArray, + sqlalchemy.LargeBinary: binary.ByteArray, + sqlalchemy.Boolean: primitive.Boolean, + sqlalchemy.DateTime: primitive.DateTime, + sqlalchemy.Date: primitive.Date, + sqlalchemy.Time: primitive.Time, + + sqlalchemy.orm.relation: complex.Array, + + UUID: primitive.String(pattern="%(x)s{8}-" + "%(x)s{4}-" + "%(x)s{4}-" + "%(x)s{4}-" + "%(x)s{12}" % {'x': '[a-fA-F0-9]'}, + name='uuid') +} + + +def _process_item(v): + """This function maps sqlalchemy types to spyne types.""" + + rpc_type = None + if isinstance(v, Column): + if isinstance(v.type, sqlalchemy.Enum): + if v.type.convert_unicode: + rpc_type = primitive.Unicode(values=v.type.enums) + else: + rpc_type = primitive.String(values=v.type.enums) + + elif v.type in _type_map: + rpc_type = _type_map[v.type] + + elif type(v.type) in _type_map: + rpc_type = _type_map[type(v.type)] + + else: + raise Exception("soap_type was not found. maybe _type_map needs a " + "new entry. %r" % v) + + elif isinstance(v, RelationshipProperty): + v.enable_typechecks = False + # FIXME: Distinguish between *ToMany and *ToOne relationship. + # rpc_type = v.argument + rpc_type = Array(v.argument) + + return rpc_type + + +def _is_interesting(k, v): + if k.startswith('__'): + return False + + if isinstance(v, Column): + return True + + if isinstance(v, RelationshipProperty): + if getattr(v.argument, '_type_info', None) is None: + logger.warning("the argument to relationship should be a reference " + "to the real column, not a string.") + return False + + else: + return True + + +class TableModelMeta(DeclarativeMeta, ComplexModelMeta): + """This class uses the information in class definition dictionary to build + the _type_info dictionary that spyne relies on. It otherwise leaves + SQLAlchemy and its information alone. + """ + + def __new__(cls, cls_name, cls_bases, cls_dict): + if cls_dict.get("__type_name__", None) is None: + cls_dict["__type_name__"] = cls_name + + if cls_dict.get("_type_info", None) is None: + cls_dict["_type_info"] = _type_info = TypeInfo() + + def check_mixin_inheritance(bases): + for b in bases: + check_mixin_inheritance(b.__bases__) + + for k, v in vars(b).items(): + if _is_interesting(k, v): + _type_info[k] = _process_item(v) + + check_mixin_inheritance(cls_bases) + + def check_same_table_inheritance(bases): + for b in bases: + check_same_table_inheritance(b.__bases__) + + table = getattr(b, '__table__', None) + + if not (table is None): + for c in table.c: + _type_info[c.name] = _process_item(c) + + check_same_table_inheritance(cls_bases) + + # include from table + table = cls_dict.get('__table__', None) + if not (table is None): + for c in table.c: + _type_info[c.name] = _process_item(c) + + # own attributes + for k, v in cls_dict.items(): + if _is_interesting(k, v): + _type_info[k] = _process_item(v) + + return super(TableModelMeta, cls).__new__(cls, cls_name, cls_bases, cls_dict) + + +@add_metaclass(TableModelMeta) +class TableModel(ComplexModelBase): + """The main base class for complex types shared by both SQLAlchemy and + spyne. Classes that inherit from this class should also inherit from + an sqlalchemy.declarative base class. See the :ref:`manual-sqlalchemy` + section for more info. + """ + + _decl_class_registry = {} diff --git a/pym/calculate/contrib/spyne/model/table.pyc b/pym/calculate/contrib/spyne/model/table.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a04529ab08b59312a02d0fe0e12ecf65d90a680 GIT binary patch literal 7215 zcmcgxOLG+06+S&91~f<@1jq=8eI0@sVX0-XO=1;(AcQMa*|OadZX{jGW z-yTU*hE1GG?8-05U&tbrRkBK|l0~Yr$scfjLUvwcnSAHm9?kfXls8zYTYc{1+;h+Q z&f{L{Uraau_0KC-}AqV^?n;xnYr(e7o^leGIix-}v$j}y<16VF*f z$sA>g=Y{ybC9VkZgK^@@IB^xkdD?wJhFu#cT6Wli^ekB7x)9eb@uCnfT4GU%MG$ke zdqIdL+I4N`Wr}7fIzusRKTFYBx-}P_qv$-WThp_2tG!Io9Q^|Lc!{EC5J6C$E9I6qvB--*hcFzRGLTqL@Ru) z-Fx4=clXZby){?eEp$+7HOTvg$`3NN8Ehx|-8|BX>YF&*X|8noS-7%gdV@^6;Gq*Y z%+p??58cht;H_r!$GXthj0!TP4+9>c4uXNoJC=_syIQS;Nnp&EnU%btJH}~6t*kVg z3O_PhJutdxjrteWnnp(vl<~e^4UAq`k-0?rWb_T_top_nw7ee$GCm4^3xy- zc64!VY?jEtQ^#icJouUwgn7%{I0DzZdD2g_mU)x}N!Zotz`dW98Y~x8uZYv282Ed7 z@cL%a*9%9B$aG%f8yRer1$5oI`Rc8O(UeYHm{NB1?dL$h-*!rKO?ToIjg8F}mr7y(Wl=&DoXsp{#X1N$kMh`FXY>j7%G&XZM`XQnIyOtuEj@)Abw zB$&Z?u#zzAq61e_Q6BbrzKiMiOZYgC@8!nCa9tiQ2GuHvBC%?ad})QDjV*i(yG+2W z-V=yHM1X(0UqYdlPo%a7D%D{Z7B?v@gdH$S05$7+Kw6{{Km*c3I{+UBb<|d&6VZg} z#=R}o%5sHW!mj}09oc|c5InQ^rr+!31sFi5_d6W_RHiM6nHMW9*v=VCh>!h3o5j%> z?AYiYhaih}yD0Y5j=H;sQ6X+8j1Pz8z zA&m6@bCx?yS)-^Grwj@Rge)TBth5{~Sx(~xbo;3;1IbFZ8L5@3Y#_tVf%e8g_Vrecat0Zh2j-laBQ3O^0 z36Przx%ab9ZU@Yu<*rTJlH56Qesd3tRq_HoI3@sQmhgSGb+}+Y{?U^q`|-;E{6Q${{UGUUW8PpsdC>EDB+|N# z)}6ec!9~(wu&tGJp$_Uv$de4E4-}$LF>uw@V!bsB9%82TJkwi z@&eL15>F=G%lc`_U`LwS2mJkh7KbPtJw~ZO>w#@3xj|#Jkqy`)sAT*fNhs94!%+8F z8y=%YX1$FJuFEqrp9@HtfXou^8IRFl@@p9OTQZI1-k0{G7s~h+T1Z~zJ$x?hVRrp51hRxNMMQmQYacp=LD85>b|Jx;I{SZ`@ky4KTvhJ3F?0S*qh@30^KZ zaM193MIOQ`KG>umqroV=sNQf+JLjD#=Thxb?X)vfJMYY)Z5rQ`_1Rj;0`tRa7SBlV z!Pu13BY;z!WqfVGK>!}$kv-xCw%M@BI!TwHS&YDe5%7#~fT;6(?*tVALASeb3^_!51T2lf;N9W)rQFAgi>>v35N7D$~vT3DP)nDAyIJ2?3m8U4a7! z*9RQ(7p0O2sxi^gE~B(5A;E9ZWOyqC>rcSe{9J<7C+dg}@cg5* z7YE^x2l5XCcNLF$1}}{xB941_!=8>D6zk+|$mYzSF+jqHJvm8X#D-$46`X&$O3bQr z)u=L2Q7pj*`Gt+N-H#KgI;9L5+5JnyxcC=uV9Uo`fMrtgO0jkjBM&1R?`tCmps})u zOSc$h=eS5gf-vLC$Z!H%VBh7?P{(7IvHiyg^Y-2Z2o@YOg0C{N(FHZ!<|t|hS(qOU znsGRZz>|1jjc$KN^eg;2a;C1+FNr>L=u_~)C|tjAUrqWZq_0Mw!o_S~wZJjfKBRau zL60Z+dvB78f6(DICXtZV9?sK~W9*BM;e=og(T;J}y8Y;P^dSU2d{bm?uvlvkUHTb# zHR#E4j*XAuuE)ijKNk-8wj3Im{yE{7IUtI`c@YmF23!~)tO*DTUxp92I329p_+!my z&$iwbw1*5Q)-r4OEFQCi*Wng(S$p^sPD!i|#0;>9Mh;gclQ~S_s%lJTh>e7d9BCIu z1X>cAC7|%Gq3%aZgx?Pz9j6bWsSPPP)?2)^jq|=7!VqFuqWu5|Uhd;yX}s(B@}9>_ za-(#}XsIW*y#?+TM`p*Cy_M`Ck_G%UK8!OsAC3;OJHjUKrh14Kh^th%F@kiVAmbr~FCOgD=P#4~dOmb4e zO_DzF{T7EJKpY!QjMNVJD_1h2S0*eZc^p$5NxfG=*wscDMH97{kpNXN#&fXEBZncD1$W^K0Ftk0tGm~k%F=Yi6THS1lx0egKm%=bRZ8C)2Gvd|uHPIepyM#kegQjLa%uPsO%(u=eM8tZf^OT8kr# zmFon)s)Ef(QeeVk;l<-{YZdBkl;b#t$uT)AeVj``Gf27UL!Bif;rs7M4d`7%kH`Bh zIlNip^~*SMO?>E~rK&8Yb9ASRg2~pH7kSdC9rrZjmh#xAORhb~#zb+zcWK7OC0V(H z>hDqFF^)xOD}bC8LmV`CVn7>~E^&GQ6ix(SIqPJF_>I$Cj~ z#I?7R9Mv&%$JGNarxW>J$8}hNP{r-{?d7%j*J`{oBssKhV0zU2CI`}hT#pV`P9u#d)W!1%r#|pP`nxnJCWRD^9 z9Y9kAxordA8w@&w|F5G4a?51x1fpiMKINRQP1R; We9zRTCQdoi6O+$Qo|(Tf<@^^Tb}nxK literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/__init__.py b/pym/calculate/contrib/spyne/protocol/__init__.py new file mode 100644 index 0000000..a98a9b6 --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/__init__.py @@ -0,0 +1,44 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.protocol`` package contains the +:class:`spyne.protocol.ProtocolBase`` abstract base class. Every protocol +implementation is a subclass of ``ProtocolBase``. +""" + +from spyne.protocol._base import ProtocolMixin +from spyne.protocol._inbase import InProtocolBase +from spyne.protocol._outbase import OutProtocolBase + + +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) + + self.default_string_encoding = string_encoding + self.ignore_empty_faultactor = True diff --git a/pym/calculate/contrib/spyne/protocol/__init__.pyc b/pym/calculate/contrib/spyne/protocol/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0986794798aa0e1824dd323b28f0fbfb058b68c3 GIT binary patch literal 1411 zcmcgs&2G~`5FY=;p`nEy5O4yYP%d@Uf(oh-LPa2PARxCK$Yry!H|c`Cw!G_tCEwbI z;U#zz9)TMV05j`^rWIGPy<^YpH$VH$B;L=h!H@6XrU@)B58uym=_3>=zyzfOsSB9{ zxeF5)9MV0=Jji{R_?_-U)`L8NNq~9}gbyNsxeI9k=KyB_A0~ZB`*1Y8M!~}?+tjty1C%hGJ%`;=!g<))~tmdji))0DyxHFBYfO0drrf<>jR zZ6+138YWayq*5&`T}xc85?&4ibc}5?=%|cIB@JV-i;B5}A{BF9XNKV+0v_DYf=+QAC_9=}Glu11-h z?LQiojX5dQUi5gRr4c*J8P_8_{X2Wn?!#zzf2V8^5sAg3vyaNgn~oaAk!@zEZpQK=tus=Ih;gBWA>=EbX< %r", + cls, polymap_cls) + return polymap_cls, True + + else: + logger.debug("PMORPH OK: cls switch without polymap: %r => %r", + cls, inst.__class__) + return inst.__class__, True + + @staticmethod + def trc_verbose(cls, locale, default): + """Translate a class. + + :param cls: class + :param locale: locale string + :param default: default string if no translation found + :returns: translated string + """ + + if locale is None: + locale = DEFAULT_LOCALE + _log_locale = "default locale '%s'" + else: + _log_locale = "given locale '%s'" + + if cls.Attributes.translations is None: + retval = default + _log_tr = "translated to '%s' without any translations at all with" + + else: + retval = cls.Attributes.translations.get(locale, _MISSING) + if retval is _MISSING: + retval = default + _log_tr = "translated to '%s': No translation for" + else: + _log_tr = "translated to '%s' with" + + logger.debug(' '.join(("%r ", _log_tr, _log_locale)), + cls, retval, locale) + + return retval + + @staticmethod + def trc(cls, locale, default): + """Translate a class. + + :param cls: class + :param locale: locale string + :param default: default string if no translation found + :returns: translated string + """ + + if locale is None: + locale = DEFAULT_LOCALE + if cls.Attributes.translations is not None: + return cls.Attributes.translations.get(locale, default) + return default + + @staticmethod + def trd_verbose(trdict, locale, default): + """Translate from a translations dict. + + :param trdict: translation dict + :param locale: locale string + :param default: default string if no translation found + :returns: translated string + """ + + if locale is None: + locale = DEFAULT_LOCALE + _log_locale = "default locale '%s'" + else: + _log_locale = "given locale '%s'" + + if trdict is None: + retval = default + _log_tr = "translated to '%s' without any translations at all with" + + elif isinstance(trdict, string_types): + retval = trdict + _log_tr = "translated to '%s' regardless of" + + else: + retval = trdict.get(locale, _MISSING) + if retval is _MISSING: + retval = default + _log_tr = "translated to '%s': No translation for" + else: + _log_tr = "translated to '%s' with" + + logger.debug(' '.join(("%r ", _log_tr, _log_locale)), + trdict, retval, locale) + + return retval + + @staticmethod + def trd(trdict, locale, default): + """Translate from a translations dict. + + :param trdict: translation dict + :param locale: locale string + :param default: default string if no translation found + :returns: translated string + """ + + if locale is None: + locale = DEFAULT_LOCALE + if trdict is None: + return default + if isinstance(trdict, string_types): + return trdict + + return trdict.get(locale, default) + + def sort_fields(self, cls=None, items=None): + logger.debug("%r sortcache size: %d", self, len(self._sortcache)) + retval = self._sortcache.get(cls, None) + if retval is not None: + return retval + + if items is None: + items = list(cls.get_flat_type_info(cls).items()) + + indexes = {} + for k, v in items: + order = self.get_cls_attrs(v).order + if order is not None: + if order < 0: + indexes[k] = len(items) + order + else: + indexes[k] = order + + for k, v in items: + order = self.get_cls_attrs(v).order + if order is None: + indexes[k] = len(indexes) + + items.sort(key=lambda x: indexes[x[0]]) + self._sortcache[cls] = items + + return items + + +META_ATTR = ['nullable', 'default_factory'] diff --git a/pym/calculate/contrib/spyne/protocol/_base.pyc b/pym/calculate/contrib/spyne/protocol/_base.pyc new file mode 100644 index 0000000000000000000000000000000000000000..adfd928804ea167084e7f8baaab4c7fd473e23e1 GIT binary patch literal 13554 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/_inbase.py b/pym/calculate/contrib/spyne/protocol/_inbase.py new file mode 100644 index 0000000..c124aaa --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/_inbase.py @@ -0,0 +1,716 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from __future__ import print_function + +import logging +logger = logging.getLogger(__name__) + +import re +import pytz +import uuid + +from math import modf +from time import strptime, mktime +from datetime import timedelta, time, datetime, date +from decimal import Decimal as D, InvalidOperation + +from pytz import FixedOffset + +try: + from lxml import etree + from lxml import 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.enum import EnumBase +from spyne.model.primitive.datetime import TIME_PATTERN, DATE_PATTERN + +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)?)?' + ) + + +class InProtocolBase(ProtocolMixin): + """This is the abstract base class for all input protocol implementations. + Child classes can implement only the required subset of the public methods. + + An output protocol must implement :func:`serialize` and + :func:`create_out_string`. + + An input protocol must implement :func:`create_in_document`, + :func:`decompose_incoming_envelope` and :func:`deserialize`. + + The ProtocolBase class supports the following events: + + * ``before_deserialize``: + Called before the deserialization operation is attempted. + + * ``after_deserialize``: + Called after the deserialization operation is finished. + + The arguments the constructor takes are as follows: + + :param app: The application this protocol belongs to. + :param mime_type: The mime_type this protocol should set for transports + that support this. This is a quick way to override the mime_type by + 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): + + self.validator = None + + super(InProtocolBase, self).__init__(app=app, mime_type=mime_type, + ignore_wrappers=ignore_wrappers, + binary_encoding=binary_encoding, string_encoding=string_encoding) + + self.message = None + self.validator = None + self.set_validator(validator) + + if mime_type is not None: + self.mime_type = mime_type + + fsh = { + Any: self.any_from_bytes, + Null: self.null_from_bytes, + File: self.file_from_bytes, + Array: self.array_from_bytes, + Double: self.double_from_bytes, + String: self.string_from_bytes, + AnyXml: self.any_xml_from_bytes, + Boolean: self.boolean_from_bytes, + Integer: self.integer_from_bytes, + Unicode: self.unicode_from_bytes, + AnyHtml: self.any_html_from_bytes, + ByteArray: self.byte_array_from_bytes, + EnumBase: self.enum_base_from_bytes, + ModelBase: self.model_base_from_bytes, + XmlAttribute: self.xmlattribute_from_bytes, + ComplexModelBase: self.complex_model_base_from_bytes + } + + self._from_bytes_handlers = cdict(fsh) + self._from_unicode_handlers = cdict(fsh) + + self._from_bytes_handlers[Date] = self.date_from_bytes + self._from_bytes_handlers[Time] = self.time_from_bytes + self._from_bytes_handlers[Uuid] = self.uuid_from_bytes + self._from_bytes_handlers[Decimal] = self.decimal_from_bytes + self._from_bytes_handlers[DateTime] = self.datetime_from_bytes + self._from_bytes_handlers[Duration] = self.duration_from_bytes + + self._from_unicode_handlers[Date] = self.date_from_unicode + self._from_unicode_handlers[Uuid] = self.uuid_from_unicode + self._from_unicode_handlers[Time] = self.time_from_unicode + self._from_unicode_handlers[Decimal] = self.decimal_from_unicode + 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, + } + + def _datetime_from_sec(self, cls, value): + try: + return datetime.fromtimestamp(value) + except TypeError: + logger.error("Invalid value %r", value) + raise + + def _datetime_from_sec_float(self, cls, value): + try: + return datetime.fromtimestamp(value) + except TypeError: + logger.error("Invalid value %r", value) + raise + + def _datetime_from_msec(self, cls, value): + try: + return datetime.fromtimestamp(value // 1000) + except TypeError: + logger.error("Invalid value %r", value) + raise + + def _datetime_from_msec_float(self, cls, value): + try: + return datetime.fromtimestamp(value / 1000) + except TypeError: + logger.error("Invalid value %r", value) + raise + + def _datetime_from_usec(self, cls, value): + try: + return datetime.fromtimestamp(value / 1e6) + except TypeError: + logger.error("Invalid value %r", value) + raise + + def create_in_document(self, ctx, in_string_encoding=None): + """Uses ``ctx.in_string`` to set ``ctx.in_document``.""" + + def decompose_incoming_envelope(self, ctx, message): + """Sets the ``ctx.method_request_string``, ``ctx.in_body_doc``, + ``ctx.in_header_doc`` and ``ctx.service`` properties of the ctx object, + if applicable. + """ + + def deserialize(self, ctx, message): + """Takes a MethodContext instance and a string containing ONE document + instance in the ``ctx.in_string`` attribute. + + Returns the corresponding native python object in the ctx.in_object + attribute. + """ + + def validate_document(self, payload): + """Method to be overriden to perform any sort of custom input + validation on the parsed input document. + """ + + def set_validator(self, validator): + """You must override this function if you want your protocol to support + validation.""" + + assert validator is None + + self.validator = None + + 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: + return None + + handler = self._from_bytes_handlers[class_] + return handler(class_, string, *args, **kwargs) + + 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: + return None + + handler = self._from_unicode_handlers[class_] + return handler(class_, string, *args, **kwargs) + + def null_from_bytes(self, cls, value): + return None + + def any_from_bytes(self, cls, value): + return value + + def any_xml_from_bytes(self, cls, string): + try: + return etree.fromstring(string) + except etree.XMLSyntaxError as e: + raise ValidationError(string, "%%r: %r" % e) + + def any_html_from_bytes(self, cls, string): + try: + return html.fromstring(string) + except etree.ParserError as e: + if e.args[0] == "Document is empty": + pass + else: + raise + + def uuid_from_unicode(self, cls, string, suggested_encoding=None): + attr = self.get_cls_attrs(cls) + ser_as = attr.serialize_as + encoding = attr.encoding + + if encoding is None: + encoding = suggested_encoding + + retval = string + + if ser_as in ('bytes', 'bytes_le'): + retval, = binary_decoding_handlers[encoding](string) + + try: + retval = _uuid_deserialize[ser_as](retval) + except ValueError as e: + raise ValidationError(e) + + return retval + + def uuid_from_bytes(self, cls, string, suggested_encoding=None, **_): + attr = self.get_cls_attrs(cls) + ser_as = attr.serialize_as + encoding = attr.encoding + + if encoding is None: + encoding = suggested_encoding + + 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') + + try: + retval = _uuid_deserialize[ser_as](retval) + except ValueError as e: + raise ValidationError(e) + + return retval + + def unicode_from_bytes(self, cls, value): + retval = value + + if isinstance(value, six.binary_type): + 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) + + elif self.string_encoding is not None: + retval = six.text_type(value, self.string_encoding, + errors=cls_attrs.unicode_errors) + + else: + retval = six.text_type(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 cls_attrs.encoding is None: + raise Exception("You need to define a source encoding for " + "decoding incoming unicode values.") + else: + retval = value.encode(cls_attrs.encoding) + + return retval + + 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) + + try: + return D(string) + except InvalidOperation as e: + 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)) + + def double_from_bytes(self, cls, string): + try: + return float(string) + except (TypeError, ValueError) as e: + raise ValidationError(string, "%%r: %r" % e) + + 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) + + try: + return int(string) + except ValueError: + raise ValidationError(string, "Could not cast %r to integer") + + def time_from_unicode(self, cls, string): + """Expects ISO formatted times.""" + + match = _time_re.match(string) + if match is None: + raise ValidationError(string, "%%r does not match regex %r " % + _time_re.pattern) + + fields = match.groupdict(0) + 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) + + def time_from_bytes(self, cls, string): + if isinstance(string, six.binary_type): + string = string.decode(self.default_string_encoding) + + return self.time_from_unicode(cls, string) + + def date_from_unicode_iso(self, cls, string): + """This is used by protocols like SOAP who need ISO8601-formatted dates + no matter what. + """ + + try: + return date(*(strptime(string, u'%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')) + + return date(year, month, day) + + raise ValidationError(string) + + def enum_base_from_bytes(self, cls, value): + if self.validator is self.SOFT_VALIDATION and not ( + cls.validate_string(cls, value)): + raise ValidationError(value) + return getattr(cls, value) + + def model_base_from_bytes(self, cls, value): + return cls.from_bytes(value) + + def datetime_from_unicode_iso(self, cls, string): + astz = self.get_cls_attrs(cls).as_timezone + + match = cls._utc_re.match(string) + if match: + tz = pytz.utc + retval = _parse_datetime_iso_match(match, tz=tz) + if astz is not None: + retval = retval.astimezone(astz) + return retval + + 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 = FixedOffset(tz_hr * 60 + tz_min, {}) + retval = _parse_datetime_iso_match(match, tz=tz) + if astz is not None: + retval = retval.astimezone(astz) + return retval + + if match is None: + match = cls._local_re.match(string) + if match: + retval = _parse_datetime_iso_match(match) + if astz: + retval = retval.replace(tzinfo=astz) + return retval + + raise ValidationError(string) + + def datetime_from_unicode(self, cls, string): + serialize_as = self.get_cls_attrs(cls).serialize_as + return self._datetime_dsmap[serialize_as](cls, string) + + def datetime_from_bytes(self, cls, string): + if isinstance(string, six.binary_type): + 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): + string = string.decode(self.default_string_encoding) + + date_format = self._get_date_format(self.get_cls_attrs(cls)) + try: + if date_format is not None: + dt = datetime.strptime(string, date_format) + return date(dt.year, dt.month, dt.day) + + return self.date_from_unicode_iso(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'))) + else: + 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)) + try: + if date_format is not None: + dt = datetime.strptime(string, date_format) + return date(dt.year, dt.month, dt.day) + + return self.date_from_unicode_iso(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'))) + else: + # the message from ValueError is quite nice already + raise ValidationError(e.message, "%s") + + 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']) + f, i = modf(seconds) + seconds = i + microseconds = int(1e6 * f) + + delta = timedelta(days=days, hours=hours, minutes=minutes, + seconds=seconds, microseconds=microseconds) + + if duration['sign'] == "-": + delta *= -1 + + return delta + + def duration_from_bytes(self, cls, string): + if isinstance(string, six.binary_type): + 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') + + def byte_array_from_bytes(self, cls, value, suggested_encoding=None): + encoding = self.get_cls_attrs(cls).encoding + if encoding is BINARY_ENCODING_USE_DEFAULT: + encoding = suggested_encoding + return binary_decoding_handlers[encoding](value) + + def file_from_bytes(self, cls, value, suggested_encoding=None): + encoding = self.get_cls_attrs(cls).encoding + if encoding is BINARY_ENCODING_USE_DEFAULT: + encoding = suggested_encoding + + return File.Value(data=binary_decoding_handlers[encoding](value)) + + 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': + raise TypeError("Only primitives can be deserialized from string.") + + # sd-list being space-delimited list. + retval = [] + inner_type, = cls._type_info.values() + for s in string.split(): + retval.append(self.from_bytes(inner_type, s)) + + return retval + + def xmlattribute_from_bytes(self, cls, value): + return self.from_bytes(cls.type, value) + + def _datetime_from_unicode(self, cls, string): + cls_attrs = self.get_cls_attrs(cls) + + # get parser + parser = cls_attrs.parser + + # get date_format + dt_format = cls_attrs.dt_format + if dt_format is None: + dt_format = cls_attrs.date_format + if dt_format is None: + dt_format = cls_attrs.out_format + if dt_format is None: + dt_format = cls_attrs.format + + # parse the string + if parser is not None: + 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 + if astz: + retval = retval.astimezone(cls_attrs.as_time_zone) + + else: + retval = self.datetime_from_unicode_iso(cls, string) + + return retval + + +_uuid_deserialize = { + None: lambda s: uuid.UUID(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[('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')) + usecond = fields.get("sec_frac") + if usecond is None: + usecond = 0 + else: + # we only get the most significant 6 digits because that's what + # datetime can handle. + usecond = min(999999, int(round(float(usecond) * 1e6))) + + 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_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 + +_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, +} + + +def _file_to_iter(f): + try: + data = f.read(65536) + while len(data) > 0: + yield data + data = f.read(65536) + + finally: + f.close() diff --git a/pym/calculate/contrib/spyne/protocol/_inbase.pyc b/pym/calculate/contrib/spyne/protocol/_inbase.pyc new file mode 100644 index 0000000000000000000000000000000000000000..47c214e1111585296064958038d2ecc9312d84ec GIT binary patch literal 27201 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 F{}=PD81w)D literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/_outbase.py b/pym/calculate/contrib/spyne/protocol/_outbase.py new file mode 100644 index 0000000..f3ab858 --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/_outbase.py @@ -0,0 +1,904 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from __future__ import print_function, unicode_literals + +import logging +logger = logging.getLogger(__name__) + +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 time import mktime, strftime + +try: + from lxml import etree + from lxml import 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.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.util.cdict import cdict + + +class OutProtocolBase(ProtocolMixin): + """This is the abstract base class for all out protocol implementations. + Child classes can implement only the required subset of the public methods. + + An output protocol must implement :func:`serialize` and + :func:`create_out_string`. + + The OutProtocolBase class supports the following events: + + * ``before_serialize``: + Called before after the serialization operation is attempted. + + * ``after_serialize``: + Called after the serialization operation is finished. + + The arguments the constructor takes are as follows: + + :param app: The application this protocol belongs to. + :param mime_type: The mime_type this protocol should set for transports + that support this. This is a quick way to override the mime_type by + default instead of subclassing the releavant protocol implementation. + :param ignore_uncap: Silently ignore cases when the protocol is not capable + 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, + ignore_wrappers=ignore_wrappers, + binary_encoding=binary_encoding, string_encoding=string_encoding) + + self.ignore_uncap = ignore_uncap + self.message = None + + 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, + }) + + + def serialize(self, ctx, message): + """Serializes ``ctx.out_object``. + + If ctx.out_stream is not None, ``ctx.out_document`` and + ``ctx.out_string`` are skipped and the response is written directly to + ``ctx.out_stream``. + + :param ctx: :class:`MethodContext` instance. + :param message: One of ``(ProtocolBase.REQUEST, ProtocolBase.RESPONSE)``. + """ + + def create_out_string(self, ctx, out_string_encoding=None): + """Uses ctx.out_document to set ctx.out_string""" + + def fault_to_http_response_code(self, fault): + """Special function to convert native Python exceptions to Http response + codes. + """ + + if isinstance(fault, RequestTooLongError): + return HTTP_413 + + if isinstance(fault, ResourceNotFoundError): + return HTTP_404 + + if isinstance(fault, RequestNotAllowed): + return HTTP_405 + + if isinstance(fault, InvalidCredentialsError): + return HTTP_401 + + if isinstance(fault, Fault) and (fault.faultcode.startswith('Client.') + or fault.faultcode == 'Client'): + return HTTP_400 + + return HTTP_500 + + def set_validator(self, validator): + """You must override this function if you want your protocol to support + validation.""" + + assert validator is None + + self.validator = None + + def to_bytes(self, cls, value, *args, **kwargs): + if value is None: + return None + + 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): + if value is None: + return None + + handler = self._to_unicode_handlers[cls] + retval = handler(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), \ + # "AssertionError: %r %r handler: %r" % \ + # (type(retval), retval, handler) + + return retval + + def to_bytes_iterable(self, cls, value): + if value is None: + return [] + + if isinstance(value, PushBase): + return value + + handler = self._to_bytes_iterable_handlers[cls] + return handler(cls, value) + + def null_to_bytes(self, cls, value, **_): + return b"" + + def null_to_unicode(self, cls, value, **_): + return u"" + + 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') + + def any_dict_to_unicode(self, cls, value, **_): + return repr(value) + + 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') + + 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, **_) + + if ser_as in ('bytes', 'bytes_le', 'fields', 'int', six.binary_type): + return retval + + return retval.encode('ascii') + + def uuid_to_unicode(self, cls, value, suggested_encoding=None, **_): + attr = self.get_cls_attrs(cls) + ser_as = attr.serialize_as + encoding = attr.encoding + + if encoding is None: + encoding = suggested_encoding + + retval = _uuid_serialize[ser_as](value) + if ser_as in ('bytes', 'bytes_le'): + retval = binary_encoding_handlers[encoding]((retval,)) + return retval + + def unicode_to_bytes(self, cls, value, **_): + retval = value + + cls_attrs = self.get_cls_attrs(cls) + + if isinstance(value, six.text_type): + 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) + + if cls_attrs.str_format is not None: + return cls_attrs.str_format.format(value) + elif cls_attrs.format is not None: + return cls_attrs.format % retval + + return retval + + def any_uri_to_unicode(self, cls, value, **_): + return self.unicode_to_unicode(cls, value, **_) + + def unicode_to_unicode(self, cls, value, **_): # :))) + cls_attrs = self.get_cls_attrs(cls) + + retval = value + #retval = str(value) + #DEBUG + #print("SPYNE DEBUG2") + + #print(retval) + #print(type(retval)) + #print(cls) + if isinstance(value, six.binary_type): + 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) + + if cls_attrs.str_format is not None: + return cls_attrs.str_format.format(value) + elif cls_attrs.format is not None: + return cls_attrs.format % retval + + return retval + + def decimal_to_bytes(self, cls, value, **_): + return self.decimal_to_unicode(cls, value, **_).encode('utf8') + + def decimal_to_unicode(self, cls, value, **_): + D(value) # sanity check + cls_attrs = self.get_cls_attrs(cls) + + if cls_attrs.str_format is not None: + return cls_attrs.str_format.format(value) + elif cls_attrs.format is not None: + return cls_attrs.format % value + + return str(value) + + def double_to_bytes(self, cls, value, **_): + return self.double_to_unicode(cls, value, **_).encode('utf8') + + def double_to_unicode(self, cls, value, **_): + float(value) # sanity check + cls_attrs = self.get_cls_attrs(cls) + + if cls_attrs.str_format is not None: + return cls_attrs.str_format.format(value) + elif cls_attrs.format is not None: + return cls_attrs.format % value + + return repr(value) + + def integer_to_bytes(self, cls, value, **_): + return self.integer_to_unicode(cls, value, **_).encode('utf8') + + def integer_to_unicode(self, cls, value, **_): + int(value) # sanity check + cls_attrs = self.get_cls_attrs(cls) + + if cls_attrs.str_format is not None: + return cls_attrs.str_format.format(value) + elif cls_attrs.format is not None: + return cls_attrs.format % value + + return str(value) + + def time_to_bytes(self, cls, value, **kwargs): + return self.time_to_unicode(cls, value, **kwargs) + + def time_to_unicode(self, cls, value, **_): + """Returns ISO formatted times.""" + if isinstance(value, datetime): + value = value.time() + return value.isoformat() + + def date_to_bytes(self, cls, val, **_): + return self.date_to_unicode(cls, val, **_).encode("utf8") + + def date_to_unicode(self, cls, val, **_): + if isinstance(val, datetime): + val = val.date() + + sa = self.get_cls_attrs(cls).serialize_as + + if sa is None or sa in (str, 'str'): + return self._date_to_bytes(cls, val) + + return _datetime_smap[sa](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') + 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'): + return self._datetime_to_unicode(cls, val) + + return _datetime_smap[sa](cls, val) + + def duration_to_bytes(self, cls, value, **_): + return self.duration_to_unicode(cls, value, **_).encode("utf8") + + def duration_to_unicode(self, cls, value, **_): + if value.days < 0: + value = -value + negative = True + else: + negative = False + + tot_sec = int(value.total_seconds()) + seconds = value.seconds % 60 + minutes = value.seconds // 60 + hours = minutes // 60 + minutes %= 60 + seconds = float(seconds) + useconds = value.microseconds + + retval = deque() + if negative: + retval.append("-P") + else: + retval.append("P") + if value.days != 0: + retval.append("%iD" % value.days) + + if tot_sec != 0 and tot_sec % 86400 == 0 and useconds == 0: + return ''.join(retval) + + retval.append('T') + + if hours > 0: + retval.append("%iH" % hours) + + if minutes > 0: + retval.append("%iM" % minutes) + + if seconds > 0 or useconds > 0: + retval.append("%i" % seconds) + if useconds > 0: + retval.append(".%i" % useconds) + retval.append("S") + + if len(retval) == 2: + retval.append('0S') + + return ''.join(retval) + + def boolean_to_bytes(self, cls, value, **_): + return str(bool(value)).lower().encode('ascii') + + def boolean_to_unicode(self, cls, value, **_): + return str(bool(value)).lower() + + def byte_array_to_bytes(self, cls, value, suggested_encoding=None, **_): + cls_attrs = self.get_cls_attrs(cls) + + encoding = cls_attrs.encoding + if encoding is BINARY_ENCODING_USE_DEFAULT: + if suggested_encoding is None: + encoding = self.binary_encoding + else: + encoding = suggested_encoding + + 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) + retval = encoder(value) + if encoding is not None and isinstance(retval, six.text_type): + retval = retval.encode('ascii') + + return retval + + def byte_array_to_unicode(self, cls, value, suggested_encoding=None, **_): + encoding = self.get_cls_attrs(cls).encoding + if encoding is BINARY_ENCODING_USE_DEFAULT: + if suggested_encoding is None: + encoding = self.binary_encoding + else: + encoding = suggested_encoding + + if encoding is None: + 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') + + return retval + + def byte_array_to_bytes_iterable(self, cls, value, **_): + return value + + def file_to_bytes(self, cls, value, suggested_encoding=None): + """ + :param cls: A :class:`spyne.model.File` subclass + :param value: Either a sequence of byte chunks or a + :class:`spyne.model.File.Value` instance. + """ + + encoding = self.get_cls_attrs(cls).encoding + if encoding is BINARY_ENCODING_USE_DEFAULT: + if suggested_encoding is None: + encoding = self.binary_encoding + else: + encoding = suggested_encoding + + if isinstance(value, File.Value): + if value.data is not None: + return binary_encoding_handlers[encoding](value.data) + + if value.handle is not None: + # maybe we should have used the sweeping except: here. + if hasattr(value.handle, 'fileno'): + if six.PY2: + 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(),) + else: + data = (value.handle.read(),) + + return binary_encoding_handlers[encoding](data) + + if value.path is not None: + handle = open(value.path, 'rb') + fileno = handle.fileno() + data = mmap(fileno, 0, access=ACCESS_READ) + + return binary_encoding_handlers[encoding](data) + + assert False, "Unhandled file type" + + if isinstance(value, FileData): + 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) + 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) + raise + + def file_to_unicode(self, cls, value, suggested_encoding=None): + """ + :param cls: A :class:`spyne.model.File` subclass + :param value: Either a sequence of byte chunks or a + :class:`spyne.model.File.Value` instance. + """ + + cls_attrs = self.get_cls_attrs(cls) + encoding = cls_attrs.encoding + if encoding is BINARY_ENCODING_USE_DEFAULT: + 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.") + + retval = self.file_to_bytes(cls, value, suggested_encoding) + if not isinstance(retval, six.text_type): + 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): + return _file_to_iter(value.data[0]) + return iter(value.data) + + if value.handle is not None: + f = value.handle + 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." + + 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')) + + except IOError as e: + if e.errno == errno.ENOENT: + raise ResourceNotFoundError(value.path) + else: + raise InternalError("Error accessing requested file") + + def simple_model_to_bytes_iterable(self, cls, value, **kwargs): + retval = self.to_bytes(cls, value, **kwargs) + if retval is None: + return (b'',) + return (retval,) + + def complex_model_to_bytes_iterable(self, cls, value, **_): + if self.ignore_uncap: + return tuple() + raise TypeError("This protocol can only serialize primitives.") + + def complex_model_base_to_bytes(self, cls, value, **_): + raise TypeError("Only primitives can be serialized to string.") + + def complex_model_base_to_unicode(self, cls, value, **_): + raise TypeError("Only primitives can be serialized to string.") + + def xmlattribute_to_bytes(self, cls, string, **kwargs): + return self.to_bytes(cls.type, string, **kwargs) + + def xmlattribute_to_unicode(self, cls, string, **kwargs): + return self.to_unicode(cls.type, string, **kwargs) + + def model_base_to_bytes_iterable(self, cls, value, **kwargs): + return cls.to_bytes_iterable(value, **kwargs) + + def model_base_to_bytes(self, cls, value, **kwargs): + return cls.to_bytes(value, **kwargs) + + def model_base_to_unicode(self, cls, value, **kwargs): + return cls.to_unicode(value, **kwargs) + + def _datetime_to_unicode(self, cls, value, **_): + """Returns ISO formatted datetimes.""" + + cls_attrs = self.get_cls_attrs(cls) + + if cls_attrs.as_timezone is not None and value.tzinfo is not None: + value = value.astimezone(cls_attrs.as_timezone) + + if not cls_attrs.timezone: + value = value.replace(tzinfo=None) + + dt_format = self._get_datetime_format(cls_attrs) + + 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) + + # FIXME: must deprecate string_format, this should have been str_format + str_format = cls_attrs.string_format + if str_format is None: + str_format = cls_attrs.str_format + if str_format is not None: + return str_format.format(value) + + # FIXME: must deprecate interp_format, this should have been just format + interp_format = cls_attrs.interp_format + if interp_format is not None: + return interp_format.format(value) + + return retval + + def _date_to_bytes(self, cls, value, **_): + cls_attrs = self.get_cls_attrs(cls) + + date_format = cls_attrs.date_format + 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) + + str_format = cls_attrs.str_format + if str_format is not None: + return str_format.format(value) + + format = cls_attrs.format + if format is not None: + return format.format(value) + + return retval + + # Format a datetime through its full proleptic Gregorian date range. + # http://code.activestate.com/recipes/ + # 306860-proleptic-gregorian-dates-and-strftime-before-1900/ + # http://stackoverflow.com/a/32206673 + # + # >>> strftime(datetime.date(1850, 8, 2), "%Y/%M/%d was a %A") + # '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 + # remove the s because the result of + # %sY + # should be %Y if %s isn't supported, not the + # 4 digit year. + _illegal_s = re.compile(r"((^|[^%])(%%)*%s)") + + @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 + + # Every 28 years the calendar repeats, except through century leap + # years where it's 6 years. But only if you're using the Gregorian + # calendar. ;) + + @classmethod + def strftime(cls, dt, fmt): + if cls._illegal_s.search(fmt): + raise TypeError("This strftime implementation does not handle %s") + if dt.year > 1900: + return dt.strftime(fmt) + + year = dt.year + # 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) + year += off + + # Move to around the year 2000 + year += ((2000 - year) // 28) * 28 + timetuple = dt.timetuple() + 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)) + + sites = [] + for site in sites1: + if site in sites2: + sites.append(site) + + s = s1 + syear = "%4d" % (dt.year,) + for site in sites: + 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, + + 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), + + 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, 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')) + usecond = fields.get("sec_frac") + if usecond is None: + usecond = 0 + else: + # we only get the most significant 6 digits because that's what + # datetime can handle. + usecond = int(round(float(usecond) * 1e6)) + + 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_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 + +_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, +} + + +def _file_to_iter(f): + try: + data = f.read(8192) + while len(data) > 0: + yield data + data = f.read(8192) + + finally: + f.close() + + +META_ATTR = ['nullable', 'default_factory'] diff --git a/pym/calculate/contrib/spyne/protocol/_outbase.pyc b/pym/calculate/contrib/spyne/protocol/_outbase.pyc new file mode 100644 index 0000000000000000000000000000000000000000..109829d2e335617887ac37d6d5cc933ab0ebbe7e GIT binary patch literal 33578 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/cloth/_base.py b/pym/calculate/contrib/spyne/protocol/cloth/_base.py new file mode 100644 index 0000000..4ea7fe6 --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/cloth/_base.py @@ -0,0 +1,326 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from __future__ import print_function + +import logging +logger = logging.getLogger(__name__) + +from inspect import isgenerator + +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.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.util.tlist import tlist + + +class XmlClothProtocolContext(ProtocolContext): + def __init__(self, parent, transport, type=None): + super(XmlClothProtocolContext, self).__init__(parent, transport, type) + + self.inst_stack = tlist([], tuple) + self.prot_stack = tlist([], ProtocolMixin) + self.doctype_written = False + + +class XmlCloth(ToParentMixin, ToClothMixin): + 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) + + self._init_cloth(cloth, cloth_parser, strip_comments) + self.developer_mode = False + self.encoding = encoding + self.default_method = 'xml' + self.doctype = doctype + self.use_ns = use_ns + self.skip_root_tag = skip_root_tag + + def get_context(self, parent, transport): + return XmlClothProtocolContext(parent, transport) + + def serialize(self, ctx, message): + """Uses ``ctx.out_object``, ``ctx.out_header`` or ``ctx.out_error`` to + set ``ctx.out_body_doc``, ``ctx.out_header_doc`` and + ``ctx.out_document`` as an ``lxml.etree._Element instance``. + + Not meant to be overridden. + """ + + assert message in (self.REQUEST, self.RESPONSE) + + self.event_manager.fire_event('before_serialize', ctx) + + if ctx.out_stream is None: + ctx.out_stream = BytesIO() + logger.debug("%r %d", ctx.out_stream, id(ctx.out_stream)) + + if ctx.out_error is not None: + # All errors at this point must be Fault subclasses. + inst = ctx.out_error + cls = inst.__class__ + name = cls.get_type_name() + + if self.developer_mode: + # FIXME: the eff is this? + ctx.out_object = (inst,) + + retval = self._incgen(ctx, cls, inst, name) + else: + with self.docfile(ctx.out_stream, encoding=self.encoding) as xf: + retval = self.to_parent(ctx, cls, inst, xf, name) + + else: + assert message is self.RESPONSE + result_class = ctx.descriptor.out_message + + name = result_class.get_type_name() + 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() + + else: + result_inst = result_class() + + 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 + + retval = self._incgen(ctx, result_class, result_inst, name) + + self.event_manager.fire_event('after_serialize', ctx) + + return retval + + def create_out_string(self, ctx, charset=None): + """Sets an iterable of string fragments to ctx.out_string if the output + is a StringIO object, which means we're run by a sync framework. Async + frameworks have the out_stream write directly to the output stream so + out_string should not be used. + """ + + if isinstance(ctx.out_stream, BytesIO): + ctx.out_string = [ctx.out_stream.getvalue()] + + @coroutine + def _incgen(self, ctx, cls, inst, name): + """Entry point to the (stack of) XmlCloth-based protocols. + + Not supposed to be overridden. + """ + + if name is None: + name = cls.get_type_name() + + try: + with self.docfile(ctx.out_stream, encoding=self.encoding) as xf: + ctx.outprot_ctx.doctype_written = False + ctx.protocol.prot_stack = tlist([], ProtocolMixin) + ret = self.subserialize(ctx, cls, inst, xf, name) + + if isgenerator(ret): # Poor man's yield from + try: + while True: + sv2 = (yield) + ret.send(sv2) + + except Break as b: + try: + ret.throw(b) + except StopIteration: + pass + + except LxmlSyntaxError as e: + if e.msg == 'no content written': + pass + else: + raise + + def docfile(self, *args, **kwargs): + logger.debug("Starting file with %r %r", args, kwargs) + return etree.xmlfile(*args, **kwargs) + + def _get_doctype(self, cloth): + if self.doctype is not None: + return self.doctype + + if cloth is not None: + return cloth.getroottree().docinfo.doctype + + if self._root_cloth is not None: + return self._root_cloth.getroottree().docinfo.doctype + + if self._cloth is not None: + return self._cloth.getroottree().docinfo.doctype + + def write_doctype(self, ctx, parent, cloth=None): + dt = self._get_doctype(cloth) + if dt is None: + return + + parent.write_doctype(dt) + ctx.outprot_ctx.doctype_written = True + logger.debug("Doctype written as: '%s'", dt) + + @staticmethod + def get_class_cloth(cls): + return cls.Attributes._xml_cloth + + @staticmethod + def get_class_root_cloth(cls): + return cls.Attributes._xml_root_cloth + + def check_class_cloths(self, ctx, cls, inst, parent, name, **kwargs): + c = self.get_class_root_cloth(cls) + 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) + 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 False, None + + @coroutine + def subserialize(self, ctx, cls, inst, parent, name='', **kwargs): + """Bridge between multiple XmlCloth-based protocols. + + Not supposed to be overridden. + """ + + pstack = ctx.protocol.prot_stack + pstack.append(self) + logger.debug("%s push prot %r. newlen: %d", R("%"), self, len(pstack)) + + have_cloth = False + + cls_cloth = self.get_class_cloth(cls) + if cls_cloth is not None: + logger.debug("to object cloth for %s", cls.get_type_name()) + ret = self.to_parent_cloth(ctx, cls, inst, cls_cloth, parent, name) + + 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) + 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) + have_cloth = True + + else: + logger.debug("to parent for %s", cls.get_type_name()) + ret = self.start_to_parent(ctx, cls, inst, parent, name, **kwargs) + + if isgenerator(ret): # Poor man's yield from + try: + while True: + sv2 = (yield) + ret.send(sv2) + + except Break as b: + try: + ret.throw(b) + except StopIteration: + pass + finally: + self._finalize_protocol(ctx, parent, have_cloth) + else: + self._finalize_protocol(ctx, parent, have_cloth) + + pstack.pop() + logger.debug("%s pop prot %r. newlen: %d", B("%"), self, len(pstack)) + + def _finalize_protocol(self, ctx, parent, have_cloth): + if have_cloth: + self._close_cloth(ctx, parent) + return + + if len(ctx.protocol.prot_stack) == 1 and len(ctx.protocol.eltstack) > 0: + self._close_cloth(ctx, parent) + return + + @staticmethod + def _gen_tagname(ns, name): + if ns is not None: + name = "{%s}%s" % (ns, name) + return name + + def _gen_attrib_dict(self, inst, fti): + attrs = {} + + for field_name, field_type in fti.attrs.items(): + ns = field_type._ns + if ns is None: + ns = field_type.Attributes.sub_ns + + sub_name = field_type.Attributes.sub_name + if sub_name is None: + sub_name = field_name + + val = getattr(inst, field_name, None) + 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) + else: + valstr = self.to_unicode(field_type.type, val) + + if valstr is not None: + attrs[sub_name] = valstr + + return attrs + + def decompose_incoming_envelope(self, ctx, message): + raise NotImplementedError("This is an output-only protocol.") diff --git a/pym/calculate/contrib/spyne/protocol/cloth/_base.pyc b/pym/calculate/contrib/spyne/protocol/cloth/_base.pyc new file mode 100644 index 0000000000000000000000000000000000000000..167be8b812db890382c63c9f72b7b05ffe16bbac GIT binary patch literal 11268 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/cloth/to_cloth.py b/pym/calculate/contrib/spyne/protocol/cloth/to_cloth.py new file mode 100644 index 0000000..6dd59cd --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/cloth/to_cloth.py @@ -0,0 +1,865 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +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 spyne.protocol import OutProtocolBase +from spyne.util.cdict import cdict + +_revancestors = lambda elt: list(reversed(tuple(elt.iterancestors()))) + +_NODATA = type("_NODATA", (object,), {}) + + +def _prevsibls(elt, strip_comments, since=None): + return reversed(list(_prevsibls_since(elt, strip_comments, since))) + + +def _prevsibls_since(elt, strip_comments, since): + if since is elt: + return + + for prevsibl in elt.itersiblings(preceding=True): + if prevsibl is since: + break + + if strip_comments and isinstance(elt, etree.CommentBase): + if elt.text.startswith('[if ') and elt.text.endswith('[endif]'): + pass + else: + continue + + 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'): + 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) + # FIXME: get rid of this. We don't want logic creep inside cloths + obj.WRITE_CONTENTS_WHEN_NOT_NONE = '{}write-contents'.format(prefix) + + obj.SPYNE_ATTRS = { + obj.ID_ATTR_NAME, + obj.DATA_ATTR_NAME, + obj.ATTR_ATTR_NAME, + obj.ROOT_ATTR_NAME, + obj.TAGBAG_ATTR_NAME, + obj.WRITE_CONTENTS_WHEN_NOT_NONE, + } + + +class ClothParserMixin(object): + 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' + + def set_identifier_prefix(self, what): + _set_identifier_prefix(self, what) + return self + + @classmethod + def from_xml_cloth(cls, cloth, strip_comments=True): + retval = cls() + 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) + return retval + + @staticmethod + 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]'): + pass + else: + elt.getparent().remove(elt) + + def _parse_file(self, file_name, cloth_parser): + cloth = etree.parse(file_name, parser=cloth_parser) + return cloth.getroot() + + def _init_cloth(self, cloth, cloth_parser, strip_comments): + """Called from XmlCloth.__init__ in order to not break the dunder init + signature consistency""" + + self._cloth = None + self._root_cloth = None + self.strip_comments = strip_comments + + self._mrpc_cloth = self._root_cloth = None + + if cloth is None: + return + + if isinstance(cloth, string_types): + cloth = self._parse_file(cloth, cloth_parser) + + if strip_comments: + self._strip_comments(cloth) + + q = "//*[@%s]" % self.ROOT_ATTR_NAME + elts = cloth.xpath(q) + if len(elts) > 0: + logger_c.debug("Using %r as root cloth.", cloth) + self._root_cloth = elts[0] + else: + logger_c.debug("Using %r as plain cloth.", cloth) + self._cloth = cloth + + self._mrpc_cloth = self._pop_elt(cloth, 'mrpc_entry') + + def _pop_elt(self, elt, what): + query = '//*[@%s="%s"]' % (self.ID_ATTR_NAME, what) + retval = elt.xpath(query) + if len(retval) > 1: + raise ValueError("more than one element found for query %r" % query) + + elif len(retval) == 1: + retval = retval[0] + next(retval.iterancestors()).remove(retval) + return retval + + +_set_identifier_prefix(ClothParserMixin, ClothParserMixin.ID_PREFIX) + + +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) + + 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, + }) + + 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)) + + def _get_outmost_elts(self, tmpl, tag_id=None): + ids = set() + + # we assume xpath() returns elements in top to bottom (or outside to + # inside) order. + for elt in self._get_elts(tmpl, tag_id): + if elt is tmpl: # FIXME: kill this + logger_c.debug("Don't send myself") + continue # don't send myself + + if len(set((id(e) for e in elt.iterancestors())) & ids) > 0: + logger_c.debug("Don't send grandchildren") + continue # don't send grandchildren + + if id(elt) in ids: # FIXME: this check should be safe to remove + logger_c.debug("Don't send what's already been sent") + continue # don't send what's already been sent + + if self.ID_ATTR_NAME in elt.attrib: + # Prevent primitive attrs like spyne-attr from interfering + # with elt descent + ids.add(id(elt)) + + yield elt + + def _get_clean_elt(self, elt, what): + query = '//*[@%s="%s"]' % (self.ID_ATTR_NAME, what) + retval = elt.xpath(query) + if len(retval) > 1: + raise ValueError("more than one element found for query %r" % query) + + elif len(retval) == 1: + retval = retval[0] + del retval.attrib[self.ID_ATTR_NAME] + return retval + + def _get_elts_by_id(self, elt, what): + retval = elt.xpath('//*[@id="%s"]' % what) + logger_c.debug("id=%r got %r", what, retval) + return retval + + def _is_tagbag(self, elt): + return self.TAGBAG_ATTR_NAME in elt.attrib + + @staticmethod + def _methods(ctx, cls, inst): + while cls.Attributes._wrapper and len(cls._type_info) > 0: + cls, = cls._type_info.values() + + if cls.Attributes.methods is not None: + for k, v in cls.Attributes.methods.items(): + is_shown = True + if v.when is not None: + is_shown = v.when(inst, ctx) + + if is_shown: + yield k, v + + def _actions_to_cloth(self, ctx, cls, inst, template): + if self._mrpc_cloth is None: + logger_c.warning("missing 'mrpc_template'") + return + + for elt in self._get_elts(template, self.MRPC_ID): + for k, v in self._methods(ctx, cls, inst): + href = v.in_message.get_type_name() + 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 + + 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): + """Enters the given tag in the document by using the shortest path from + current tag. + + 1. Moves up the tree by writing all tags so that the set of ancestors + of the current tag are a subset of the ancestors of the parent tag + 2. Writes all tags until hitting a direct ancestor, enters it, and + keeps writing previous siblings of ancestor tags and entering + ancestor tags until hitting the target tag. + 3. Enters the target tag and returns + + There is no _exit_cloth because exiting from tags is done + automatically with subsequent calls to _enter_cloth and finally to + _close_cloth. + + :param ctx: A MethodContext instance + :param cloth: The target cloth -- an ``lxml.etree._Element`` instance. + :param parent: The target stream -- typically an + ``lxml.etree._IncrementalFileWriter`` instance. + :param attrib: A dict of additional attributes for the target cloth. + :param skip: When True, the target tag is actually not entered. + Typically used for XmlData and friends. + :param method: One of ``(None, 'html', 'xml')``. When not ``None``, + overrides the output method of lxml. + :param skip_dupe: When ``False`` (the default) if this function is + called repeatedly for the same tag, the tag is exited and reentered. + This typically happens for types with ``max_occurs`` > 1 + (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) + + if not ctx.outprot_ctx.doctype_written: + self.write_doctype(ctx, parent, cloth) + + tags = ctx.protocol.tags + rootstack = ctx.protocol.rootstack + assert isinstance(rootstack, oset) + + eltstack = ctx.protocol.eltstack + ctxstack = ctx.protocol.ctxstack + + cureltstack = eltstack[rootstack.back] + curctxstack = ctxstack[rootstack.back] + + if skip_dupe and len(cureltstack) > 0 and cureltstack[-1] is cloth: + return + + cloth_root = cloth.getroottree().getroot() + if not cloth_root in rootstack: + rootstack.add(cloth_root) + cureltstack = eltstack[rootstack.back] + curctxstack = ctxstack[rootstack.back] + + assert rootstack.back == cloth_root + + while rootstack.back != cloth_root: + self._close_cloth(ctx, parent) + + last_elt = None + if len(cureltstack) > 0: + last_elt = cureltstack[-1] + + ancestors = _revancestors(cloth) + + # move up in tag stack until the ancestors of both + # source and target tags match + while ancestors[:len(cureltstack)] != cureltstack: + elt = cureltstack.pop() + elt_ctx = curctxstack.pop() + + last_elt = elt + if elt_ctx is not None: + self.event_manager.fire_event(("before_exit", elt), ctx, parent) + elt_ctx.__exit__(None, None, None) + logger_c.debug("\texit norm %s %s", elt.tag, elt.attrib) + if elt.tail is not None: + parent.write(elt.tail) + + # unless we're at the same level as the relevant ancestor of the + # target node + 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)) + parent.write(sibl) + + # write remaining ancestors of the target node. + 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) + continue + + 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 + + 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) + if anc.text is not None: + parent.write(anc.text) + + rootstack.add(anc.getroottree().getroot()) + cureltstack = eltstack[rootstack.back] + curctxstack = ctxstack[rootstack.back] + cureltstack.append(anc) + curctxstack.append(anc_ctx) + + # now that at the same level as the target node, + # write its previous siblings + prevsibls = _prevsibls(cloth, self.strip_comments, since=last_elt) + for elt in prevsibls: + if elt is last_elt: + continue + + if id(elt) in tags: + 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) + parent.write(elt) + + skip = skip or (cloth.tag == self.DATA_TAG_NAME) + + if skip: + tags.add(id(cloth)) + if method is not None: + curtag = parent.method(method) + curtag.__enter__() + else: + curtag = None + + 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.update(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 + if method is not None: + kwargs['method'] = method + curtag = parent.element(cloth.tag, cloth_attrib, **kwargs) + curtag.__enter__() + if cloth.text is not None: + parent.write(cloth.text) + + rootstack.add(cloth.getroottree().getroot()) + cureltstack = eltstack[rootstack.back] + curctxstack = ctxstack[rootstack.back] + + cureltstack.append(cloth) + curctxstack.append(curtag) + + logger_c.debug("") + + def _close_cloth(self, ctx, parent): + rootstack = ctx.protocol.rootstack + close_until = rootstack.back + cureltstack = ctx.protocol.eltstack[close_until] + curctxstack = ctx.protocol.ctxstack[close_until] + + for elt, elt_ctx in reversed(tuple(zip(cureltstack, curctxstack))): + if elt_ctx is not None: + self.event_manager.fire_event(("before_exit", elt), ctx, parent) + elt_ctx.__exit__(None, None, None) + logger_c.debug("exit %s close", elt.tag) + if elt.tail is not None: + parent.write(elt.tail) + + for sibl in elt.itersiblings(preceding=False): + logger_c.debug("write %s nextsibl", sibl.tag) + parent.write(sibl) + if sibl.tail is not None: + parent.write(sibl.tail) + + if elt is close_until: + logger_c.debug("closed until %r, breaking out", close_until) + break + + del ctx.protocol.eltstack[close_until] + del ctx.protocol.ctxstack[close_until] + + if len(rootstack) > 0: + rootstack.pop() + + @coroutine + 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, '') + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as e: + try: + ret.throw(e) + except (Break, StopIteration, GeneratorExit): + pass + + @coroutine + def to_root_cloth(self, ctx, cls, inst, cloth, parent, name): + if len(ctx.protocol.eltstack) > 0: + ctx.protocol[self].rootstack.add(cloth) + + cls_attrs = self.get_cls_attrs(cls) + self._enter_cloth(ctx, cloth, parent, method=cls_attrs.method) + + ret = self.start_to_parent(ctx, cls, inst, parent, name) + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as e: + try: + ret.throw(e) + except (Break, StopIteration, GeneratorExit): + pass + + # 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): + + prot_name = self.__class__.__name__ + + if issubclass(cls, XmlAttribute): + cls = cls.type + as_attr = True + + elif issubclass(cls, XmlData): + cls = cls.type + as_data = True + + pushed = False + if cloth is None: + logger_c.debug("No cloth fround, switching to to_parent...") + ret = self.to_parent(ctx, cls, inst, parent, name, **kwargs) + + else: + cls, _ = self.get_polymorphic_target(cls, inst) + cls_attrs = self.get_cls_attrs(cls) + + inst = self._sanitize(cls_attrs, inst) + + # if instance is None, use the default factory to generate one + _df = cls_attrs.default_factory + if inst is None and callable(_df): + inst = _df() + + # if instance is still None, use the default value + if inst is None: + inst = cls_attrs.default + + # if there's a subprotocol, switch to it + subprot = cls_attrs.prot + if subprot is not None and not (subprot is self): + # 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 " \ + "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) + + # if there is no subprotocol, try rendering the value + else: + ret = None + + # try rendering the null value + if inst is None: + if cls_attrs.min_occurs > 0: + attrs = {} + if as_attr: + # FIXME: test needed + attrs[name] = '' + + 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()) + 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) + + elif as_data: + # we only support XmlData of a primitive.,. is this a + # problem? + ret = self.to_unicode(cls, inst) + if ret is not None: + parent.write(ret) + + elif as_attr: + sub_name = cls_attrs.sub_name + if sub_name is None: + sub_name = name + attrs = {sub_name: self.to_unicode(cls, inst)} + + self._enter_cloth(ctx, cloth, parent, attrib=attrs, + method=cls_attrs.method) + + else: + # push the instance at hand to instance stack. this makes it + # easier for protocols to make decisions based on parents of + # instances at hand. + pushed = True + logger_c.debug("%s %r pushed %r %r", R("#"), self, cls, inst) + ctx.outprot_ctx.inst_stack.append((cls, inst, from_arr)) + + # 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) + else: + # try rendering anything else + handler = self.rendering_handlers[cls] + + # disabled for performance reasons + # identifier = "%s.%s" % (prot_name, handler.__name__) + # from spyne.util.web import log_repr + # logger_s.debug("Writing %s using %s for %s. Inst: %r", + # 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) + + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as e: + try: + ret.throw(e) + except (Break, StopIteration, GeneratorExit): + pass + finally: + if pushed: + logger_c.debug("%s %r popped %r %r", B("#"), + self, cls, inst) + ctx.outprot_ctx.inst_stack.pop() + + else: + if pushed: + 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): + cls_attrs = self.get_cls_attrs(cls) + self._enter_cloth(ctx, cloth, parent, method=cls_attrs.method) + + # FIXME: Does it make sense to do this in other types? + if self.WRITE_CONTENTS_WHEN_NOT_NONE in cloth.attrib: + logger_c.debug("Writing contents for %r", cloth) + for c in cloth: + parent.write(c) + + else: + parent.write(self.to_unicode(cls, inst)) + + 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): + inst = etree.fromstring(inst) + parent.write(inst) + + def any_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) + parent.write(inst) + + 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): + inst = html.fromstring(inst) + parent.write(inst) + + def any_uri_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) + 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): + fti = cls.get_flat_type_info(cls) + cls_attrs = self.get_cls_attrs(cls) + + # It's actually an odict but that's irrelevant here. + fti_check = dict(fti.items()) + elt_check = set() + + attrib = self._gen_attrib_dict(inst, fti) + 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) + + if self._is_tagbag(cloth): + logger_c.debug("%r(%r) IS a tagbag", cloth, cloth.attrib) + elts = self._get_elts(cloth) + else: + logger_c.debug("%r(%r) is NOT a tagbag", cloth, cloth.attrib) + elts = self._get_outmost_elts(cloth) + + # 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) + + 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)): + field_name = elt.attrib.get(k_attr, None) + if field_name is None: + continue + + 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) + + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as e: + try: + ret.throw(e) + except StopIteration: + pass + finally: + # cf below + if not (as_attr or as_data): + break + else: + # this is here so that attribute on complex model doesn't get + # mixed with in-line attr inside complex model. if an element + # has spyne-id, all other attrs are ignored and are processed + # by the object's serializer not its parent. + if not (as_attr or as_data): + break + + if len(fti_check) > 0: + 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): + field_type = fti.get(field_name, None) + fti_check.pop(field_name, None) + + if field_type is None: + logger_c.warning("elt id %r not in %r", field_name, cls) + elt_check.add(field_name) + self._enter_cloth(ctx, elt, parent, skip=True) + return + + 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) + return + + sub_name = cls_attrs.sub_name + if sub_name is None: + sub_name = field_name + + if issubclass(cls, Array): + # if cls is an array, inst should already be a sequence type + # (eg list), so there's no point in doing a getattr -- we will + # unwrap it and serialize it in the next round of to_cloth call. + val = inst + else: + 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) + + @coroutine + 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) + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as e: + try: + ret.throw(e) + except StopIteration: + pass + + else: + sv = _NODATA + + for sv in inst: + was_empty = False + + ret = self.to_cloth(ctx, cls, sv, cloth, parent, + from_arr=True, name=name, **kwargs) + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as e: + try: + ret.throw(e) + except StopIteration: + pass + + if sv is _NODATA: + # FIXME: what if min_occurs >= 1? + # fake entering the cloth to prevent it from being flushed as + # parent or sibling of another node later. + self._enter_cloth(ctx, cloth, parent, skip=True) diff --git a/pym/calculate/contrib/spyne/protocol/cloth/to_cloth.pyc b/pym/calculate/contrib/spyne/protocol/cloth/to_cloth.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d57a0d69f371634f23bdeb2e77508a596c5d3593 GIT binary patch literal 25561 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/cloth/to_parent.py b/pym/calculate/contrib/spyne/protocol/cloth/to_parent.py new file mode 100644 index 0000000..e8b974c --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/cloth/to_parent.py @@ -0,0 +1,522 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from __future__ import print_function + +import logging +logger = logging.getLogger(__name__) + +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.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.cdict import cdict +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) + + 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, + }) + + 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 ctx.outprot_ctx.doctype_written: + self.write_doctype(ctx, parent) + + return self.to_parent(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): + return subprot + return None + + def to_subprot(self, ctx, cls, inst, parent, name, subprot, **kwargs): + return subprot.subserialize(ctx, cls, inst, parent, name, **kwargs) + + @coroutine + def to_parent(self, ctx, cls, inst, parent, name, nosubprot=False, **kwargs): + pushed = False + has_cloth = False + + prot_name = self.__class__.__name__ + + cls, switched = self.get_polymorphic_target(cls, inst) + cls_attrs = self.get_cls_attrs(cls) + if cls_attrs.out_type: + logger.debug("out_type from %r to %r", cls, cls_attrs.out_type) + cls = cls_attrs.out_type + cls_attrs = self.get_cls_attrs(cls) + + inst = self._sanitize(cls_attrs, inst) + + # if there is a subprotocol, switch to it + 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) + else: + # if there is a class cloth, switch to it + has_cloth, cor_handle = self.check_class_cloths(ctx, cls, inst, + parent, name, **kwargs) + if has_cloth: + ret = cor_handle + + else: + # if instance is None, use the default factory to generate one + _df = cls_attrs.default_factory + if inst is None and callable(_df): + inst = _df() + + # if instance is still None, use the default value + if inst is None: + inst = cls_attrs.default + + # 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()) + self.null_to_parent(ctx, cls, inst, parent, name, **kwargs) + + return + + # if requested, ignore wrappers + if self.ignore_wrappers and issubclass(cls, ComplexModelBase): + cls, inst = self.strip_wrappers(cls, inst) + + # if cls is an iterable of values and it's not being iterated + # on, do it + 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) + else: + # fetch the serializer for the class at hand + try: + handler = self.serialization_handlers[cls] + + except KeyError: + # if this protocol uncapable of serializing this class + if self.ignore_uncap: + logger.debug("Ignore uncap %r", name) + return # ignore it if requested + + # raise the error otherwise + 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) ) + pushed = True + logger.debug("%s %r pushed %r using %r", + R("$"), self, cls, handler) + + # disabled for performance reasons + # from spyne.util.web import log_repr + # identifier = "%s.%s" % (prot_name, handler.__name__) + # log_str = log_repr(inst, cls, + # from_array=kwargs.get('from_arr', None)) + # logger.debug("Writing %s using %s for %s. Inst: %r", name, + # identifier, cls.get_type_name(), log_str) + + # finally, serialize the value. ret is the coroutine handle + ret = handler(ctx, cls, inst, parent, name, **kwargs) + + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + + except Break as e: + try: + ret.throw(e) + + except (Break, StopIteration, GeneratorExit): + pass + + finally: + if has_cloth: + self._close_cloth(ctx, parent) + + if pushed: + logger.debug("%s %r popped %r %r", B("$"), self, cls, + inst) + ctx.outprot_ctx.inst_stack.pop() + + else: + if has_cloth: + self._close_cloth(ctx, parent) + + if pushed: + logger.debug("%s %r popped %r %r", B("$"), self, cls, inst) + ctx.outprot_ctx.inst_stack.pop() + + @coroutine + def array_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + if inst is None: + inst = () + + ser_subprot = self.get_subprot(ctx, self.get_cls_attrs(cls)) + + # FIXME: it's sad that this function has the same code twice. + + if isinstance(inst, PushBase): + # this will be popped by pusher_try_close + ctx.pusher_stack.append(inst) + + i = 0 + + try: + while True: + 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 + + if ser_subprot is not None: + ser_subprot.column_table_before_row(ctx, cls, inst, + parent, name, **kwargs) + + ret = self.to_parent(ctx, cls, sv, parent, name, **kwargs) + + i += 1 + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + + except Break as e: + try: + ret.throw(e) + except StopIteration: + pass + + finally: + # disabled because to_parent is supposed to take care of this + #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) + else: + # disabled because to_parent is supposed to take care of this + #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) + + except Break: + # pusher is done with pushing + pass + + else: + 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 + + if ser_subprot is not None: + 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) + ret.send(sv2) + + except Break as e: + try: + ret.throw(e) + except StopIteration: + pass + + finally: + # disabled because to_parent is supposed to take care of this + #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) + + else: + # disabled because to_parent is supposed to take care of this + #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) + + def not_supported(self, ctx, cls, *args, **kwargs): + if not self.ignore_uncap: + raise NotImplementedError("Serializing %r not supported!" % cls) + + def any_uri_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + self.model_base_to_parent(ctx, cls, inst, parent, name, **kwargs) + + def imageuri_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + self.model_base_to_parent(ctx, cls, inst, parent, name, **kwargs) + + def byte_array_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + parent.write(E(name, self.to_unicode(cls, inst, self.binary_encoding))) + + 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'})) + + 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): + inst = etree.fromstring(inst) + + parent.write(E(name, inst)) + + def any_html_to_unicode(self, cls, inst, **_): + if isinstance(inst, (str, six.text_type)): + inst = html.fromstring(inst) + + return inst + + 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)): + inst = html.tostring(inst) + + else: + if isinstance(inst, str) or isinstance(inst, six.text_type): + inst = html.fromstring(inst) + + parent.write(E(name, inst)) + + def any_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + parent.write(E(name, inst)) + + def any_dict_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + elt = E(name) + dict_to_etree(inst, elt) + parent.write(E(name, elt)) + + def _gen_sub_name(self, cls, cls_attrs, k, use_ns=None): + if self.use_ns is not None and use_ns is None: + use_ns = self.use_ns + + sub_ns = cls_attrs.sub_ns + if sub_ns is None: + sub_ns = cls.get_namespace() + + sub_name = cls_attrs.sub_name + if sub_name is None: + sub_name = k + + if use_ns: + name = "{%s}%s" % (sub_ns, sub_name) + else: + name = sub_name + + return name + + @coroutine + def _write_members(self, ctx, cls, inst, parent, use_ns=None, **kwargs): + if self.use_ns is not None and use_ns is None: + use_ns = self.use_ns + + for k, v in self.sort_fields(cls): + attr = self.get_cls_attrs(v) + if attr.exc: + prot_name = self.__class__.__name__ + logger.debug("%s: excluded for %s.", k, prot_name) + continue + + if issubclass(v, XmlAttribute): + continue + + try: # e.g. SqlAlchemy could throw NoSuchColumnError + subvalue = getattr(inst, k, None) + except: + subvalue = None + + # This is a tight loop, so enable this only when necessary. + # logger.debug("get %r(%r) from %r: %r" % (k, v, inst, subvalue)) + + sub_name = self._gen_sub_name(cls, attr, k, use_ns) + + if issubclass(v, XmlData): + subvalstr = self.to_unicode(v.type, subvalue) + if subvalstr is not None: + parent.write(subvalstr) + 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) + if ret is not None: + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as b: + try: + ret.throw(b) + except StopIteration: + pass + + @coroutine + def _complex_to_parent_do(self, ctx, cls, inst, parent, **kwargs): + # parent.write(u"\u200c") # zero-width non-joiner + parent.write(" ") # FIXME: to force empty tags to be sent as + # instead of + ret = self._write_members(ctx, cls, inst, parent, **kwargs) + if ret is not None: + try: + while True: + sv2 = (yield) # may throw Break + ret.send(sv2) + + except Break: + try: + ret.throw(Break()) + except StopIteration: + pass + + 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) + + 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) + + with parent.element(name, attrib=attrib): + 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] + tag_name = SOAP11_ENV("Fault") + + with parent.element(tag_name): + parent.write( + E("faultcode", '%s:%s' % (PREF_SOAP_ENV, inst.faultcode)), + E("faultstring", inst.faultstring), + E("faultactor", inst.faultactor), + ) + + if isinstance(inst.detail, etree._Element): + parent.write(E.detail(inst.detail)) + + # add other nonstandard fault subelements with get_members_etree + self._write_members(ctx, cls, inst, parent) + # no need to track the returned generator because we expect no + # PushBase instance here. + + def schema_validation_error_to_parent(self, ctx, cls, inst, parent, **_): + PREF_SOAP_ENV = ctx.app.interface.prefmap[NS_SOAP11_ENV] + tag_name = SOAP11_ENV("Fault") + + with parent.element(tag_name): + parent.write( + 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), + ) + + if isinstance(inst.detail, etree._Element): + parent.write(E.detail(inst.detail)) + + # add other nonstandard fault subelements with get_members_etree + self._write_members(ctx, cls, inst, parent) + # no need to track the returned generator because we expect no + # PushBase instance here. diff --git a/pym/calculate/contrib/spyne/protocol/cloth/to_parent.pyc b/pym/calculate/contrib/spyne/protocol/cloth/to_parent.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b342c776e958e83d237594088d62f045c9fd1400 GIT binary patch literal 15038 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 a`2YZlVi?xPFs?}pDdhPUOVe?CIQ4(Y*CBiW literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/csv.py b/pym/calculate/contrib/spyne/protocol/csv.py new file mode 100644 index 0000000..915ca88 --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/csv.py @@ -0,0 +1,136 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.protocol.csv`` package contains the Csv output protocol. + +This protocol is here merely for illustration purposes. While it is in a +somewhat working state, it is not that easy to use. Expect a revamp in the +coming versions. +""" + +from __future__ import absolute_import + +import logging +logger = logging.getLogger(__name__) + +import csv + +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() + + queue = StringIO() + + serializer, = cls._type_info.values() + + if issubclass(serializer, ComplexModelBase): + type_info = serializer.get_flat_type_info(serializer) + keys = [k for k, _ in prot.sort_fields(serializer)] + + else: + type_info = {serializer.get_type_name(): serializer} + keys = list(type_info.keys()) + + if ctx.out_error is not None: + writer = csv.writer(queue, dialect=csv.excel) + 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]) + + yield queue.getvalue() + queue.truncate(0) + + else: + writer = csv.DictWriter(queue, dialect=csv.excel, fieldnames=keys) + if prot.header: + titles = {} + for k in keys: + v = type_info[k] + titles[k] = prot.trc(v, ctx.locale, k) + + writer.writerow(titles) + + yield queue.getvalue() + queue.truncate(0) + + 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 + queue.truncate(0) + + +class Csv(HierDictDocument): + 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) + + self.header = header + + def create_in_document(self, ctx): + raise NotImplementedError() + + def serialize(self, ctx, message): + 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: " \ + "%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) + + def any_uri_to_unicode(self, cls, value, **_): + if isinstance(value, cls.Value): + value = value.text + return super(Csv, self).any_uri_to_unicode(cls, value, **_) diff --git a/pym/calculate/contrib/spyne/protocol/csv.pyc b/pym/calculate/contrib/spyne/protocol/csv.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0a044d2c35a18bd6d818cd06266e9641e3711cd GIT binary patch literal 4603 zcmcgwO>-N^5$#=&AOR90OvQ}-D)03Il5tb9*8bCK z{`(()-%MouQ^VhT_eAX9z;s16Kt1XDl6lhiWy2SbBbq!7Nox*8w=v) z?a5SoGS!`x7trku={Cf)WE&baIrCiPtBpmfx89k<1MI&*9`Bl9bJGrvbF(}s3s)pX zww&05&COsCCwuXZ36dgrahlt}LH2$JSIUbiPfGUW$F1nsPNw+-i{w`zCkQ$}Ggz zU5Tqd`!ew{;9Yfml6%523}ed*QcmajcI@x@J%KdH$G^RF&ViJO)YXkDKB zQjW;?W=IiOC)2WnGjZVTcxLt4qI~VkNnK7LRF~iQvLDOItmIcD^(e&s4PJH&yIoU8 z)6$#cnCIabs5Z~|-fKwtp6AX;Z$U;i1{(P`#JrP+j2hBIkomIXaijOGZEt%=KN}y^ zTO2bGT77m-PH>@a9W^Ig_x~$TbG!lxvqU|fcx2BqR(W#%OI6~{Zz<8mJ7%%$Qx!b_ zoRr^q@bSr<9Npy7>a(jf0v-n=TsWCmskdYV1`j;X+2=6!9GN@&srPiO6)eF!|Gzri zeu27O7~5#%AN^Git!7uB{YA#ty{+b+7xx1-Z%s~G;x0<>hf;p-AKjHv3u@k=n(h(@ z)YQGBZf^VIaW9arVn{W24tv>;X8GDt;mh5VH$X++8matGbNHu#2h6i zb4=!HvN&{aVBm^q>)06^Q83=hjEX=*eTWWRIm{D)mcEDh@U%LW&)qd~7Z>nOS0;LA zRwVF&3RAmcs|SZ5%|s$x*2Vs)I-8rUaUn59Pk8jz^|8$W&MwXqqdpzxX#(WZ!%a@M zLkQ9r6SAupyQAuFX7#!ILo=+Du%<*%q`!rlwAf2`(I0z`Gzw{o@J%jrT+?_f@p*hk=2hPGVE(yd!JR|dy!x5%$AzrSK((QD(9V^_2wUAw;g?v3Sl zZ(SQ4Lt@$N>{RnBlghIK$1URszApma6SZkIOkc&6{S-vJ^M1o$^cTDZ@29mTkKB2$ zjnPH#Eq~5y*DiStukN+HrWg2a%(VO^?<`~*m|OBL`z>$YoA%UPsD260Q;I%a19$+Re0T@Be5i~_j0MyE?2Z+S}2%-cM2FRKkCLRnlT;S}q8#DR2)=&FJ zv)0XHlFl%Fc&5A#dH-)21RzWhptp3x5{)IQ*N4HCQu9tDE_}HD=*zYB zhYH#EE#Q+Us2{?2a92ntX^vzj4;iB&QzN9~JJjo?qcq~j#qxDKjXIn{{g4BuD8X{U zoA)nyHSaVQsib=CAsECWyaqc1LqH>#ed03ovhZVhf8q!@tdP2iy2oz$*UH70d4;w=He>0AE9}dTlke`1X*}${qGF;SG?} z`iU-tcp7Vy-JkA?d{z~)TVbZcy5N{E+ zN>hi{;^$ZQutu<=6RKcWKa^-4718k}f>~12M5$mNSPuU{xF&!00olxfHSGYyAM+$) z=o2r$$@&cGnFrV`HeP_&K<$o^`ub;?h2! z#2FeddVuYiVt06-dp;rgf`nSVe7SP3rPWctY~nI|4y2C0rH+Jc`3-a{i;YID(QMQ^ zia1P-h-iFjjO`&HjK;uCxP?ggrP9;A+rZ{Az*=lwQ% O!Zz%< + app + f1 + + +With ``ignore_wrappers=True`` (which is the default) This gets serialized to +dict as follows: :: + + { + "application": "app", + "feature": "f1" + } + +When ``ignore_wrappers=False``, the same value/type combination would result in +the following dict: :: + + {"Permission": { + { + "application": "app", + "feature": "f1" + } + }, + +This could come in handy in case you don't know what type to expect. +""" + +from spyne.protocol.dictdoc._base import DictDocument +from spyne.protocol.dictdoc.hier import HierDictDocument +from spyne.protocol.dictdoc.simple import SimpleDictDocument diff --git a/pym/calculate/contrib/spyne/protocol/dictdoc/__init__.pyc b/pym/calculate/contrib/spyne/protocol/dictdoc/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..85905a980012b6c1ce029c9743e857d824d99dc5 GIT binary patch literal 3403 zcma)9+iu%N5T%_<3$_JqO%NMMVAqgVqaT)GX zvTFFT=vVbm`U!pO2efB)DU(X?j6$#cY~%NPe03j} z$n%bH-SVPsFWK_u+uqT(x5dvlyyS*Azv&&_bk8@vB-^YONx}#lqy5I$TF3i&23KQYIh-$LXtKrmpY&W_KD`=6t87$# zQjwmEB%zrIPZ`%UX&RamrA`Sx7({ELl0+>5l+^ea8CEz}ed_mppYRD2p*1~CQ<*m( zs(F^kv*#+3Nvm(C?GhSbfss?0Uyel>dywa1)huUPb#pHYbG%&;6; z6(&|`6_WFYX!Hr2HOBZor$&gM9$j4c{u7x?1bN9cT1q6EH;P~+k3|yyDlK3!RtvdC z1_le}QWCh}FeWfg3qI?m|$?#Vj#L3G^ZhaLx>Ck)+$1@ zQKQG}BJH-?rM7Uvp1@J4xaK@Svnou~GiSt;IU7hS4Zaht4X*%R17g zcmfHT#CQQvp0bFeKOqzfW>AG3mZ@}#J{mcwc-dJ&IU0008n2uUE?<%QoBKE>mBmaJ z5v5`dfHix~P$0HY0UeuoAzQ%mfb&p^abg<`oI@*ohpRUBWeh4-{P@Emb!_cj1Qjkah%$8l##~a0_ahpK08w#MHqDz@$;Q3K7dgnukQE|_F+HliYt8K@eAh_ z=wQPbmPaL^2O(#uG4AbTtAC}6lD(%XIAf1F);UO!Jj-x|4E*>Xe41N0m77m-c?4%3 zm8WAjdIzIVpxf`ye2$rem``@~xu2RJu`#|3`Jg=i-FRnR<{eHr9P12+aT=T9Fo3;}vBRGG&$9m;?lu3(17{ DZLS^S literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/dictdoc/_base.py b/pym/calculate/contrib/spyne/protocol/dictdoc/_base.py new file mode 100644 index 0000000..a10b121 --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/dictdoc/_base.py @@ -0,0 +1,147 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +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.protocol import ProtocolBase + + +class DictDocument(ProtocolBase): + """An abstract protocol that can use hierarchical or flat dicts as input + and output documents. + + Implement ``serialize()``, ``deserialize()``, ``create_in_document()`` and + ``create_out_string()`` to use this. + """ + + # flags to be used in tests + _decimal_as_string = False + _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) + + self.key_encoding = key_encoding + self.polymorphic = polymorphic + self.complex_as = complex_as + self.ordered = ordered + if ordered: + raise NotImplementedError('ordered=True') + + self.stringified_types = (DateTime, Date, Time, Uuid, Duration, + AnyXml, AnyHtml) + + def set_validator(self, validator): + """Sets the validator for the protocol. + + :param validator: one of ('soft', None) + """ + + if validator == 'soft' or validator is self.SOFT_VALIDATION: + self.validator = self.SOFT_VALIDATION + elif validator is None: + self.validator = None + else: + raise ValueError(validator) + + def decompose_incoming_envelope(self, ctx, message): + """Sets ``ctx.in_body_doc``, ``ctx.in_header_doc`` and + ``ctx.method_request_string`` using ``ctx.in_document``. + """ + + 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. + + doc = ctx.in_document + + ctx.in_header_doc = None + 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) + + if not isinstance(doc, dict) or len(doc) != 1: + raise ValidationError(doc, + "Need a dictionary with exactly one key as method name.") + + if len(doc) == 0: + raise Fault("Client", "Empty request") + + ctx.method_request_string = self.gen_method_request_string(ctx) + + def gen_method_request_string(self, ctx): + """Uses information in context object to return a method_request_string. + + 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) + + def deserialize(self, ctx, message): + raise NotImplementedError() + + def serialize(self, ctx, message): + raise NotImplementedError() + + def create_in_document(self, ctx, in_string_encoding=None): + raise NotImplementedError() + + def create_out_string(self, ctx, out_string_encoding='utf8'): + raise NotImplementedError() + + def _check_freq_dict(self, cls, d, fti=None): + if fti is None: + fti = cls.get_flat_type_info(cls) + + for k, v in fti.items(): + val = d[k] + + attrs = self.get_cls_attrs(v) + 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() + 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) + + elif val > max_o: + raise ValidationError("%r.%s" % (cls, k), + '%%s member must occur at most %d times.' % max_o) diff --git a/pym/calculate/contrib/spyne/protocol/dictdoc/_base.pyc b/pym/calculate/contrib/spyne/protocol/dictdoc/_base.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2589be61e72cca0263acf35e440681343ba28935 GIT binary patch literal 5508 zcmdT|&2t=A5$~D((5}4F%CckPa>_Nh5MIajiiF^R3nbg8z5$=-;9V@n=y?)F)Czdlo61URu(`z>>sVlzHkyz8I0}6eW$8wqXL+Z|12r`F{USC(t>w8tHg)jU((%VhZ01Vx0|UAW z`f(A3hId={joOM5C0yq#C4}%*P+|E&9C4GKX#;DTqC+2+?AVFlT|n znh=Wwu`;JEFG8|V^Ad#(3Y$Wo75==?%j9l$`0V=6Xx384-_a)b1LKS)w{y(UH%{QE zPN9`Ej8yLD!7vK^*vWEd5MwaJy|v?OCrU?!nRoExr=gP-23;qdNJMw%W#~aNiWQ5< z+1}PFkD$Y!sm`_S?Hgc(>NQr7D=5Q@Qg6BvPv#wDx$W)A1Z?Nw>`}Ta<0g{>n_+~F z`A7k4f*-bkdwBE_8iPNJ4q<#Y?b&n)8f}FRt8`eSmo>5un>_4+)er&$bs=hWI41IbB16aW`WEi4a!%b8-kVFI6-OPSstofg+JKJ3)NZT zgRvd!Vx)5S40qWEJxC!ko+s9}ug0EAgDk|2u>;X4i^oZpkDwfEN)%))=>yN#V)T<8 z%sCA8GBZ2T$2( z;25nII$w>Wom=m%j>cw~rSEp%U)7OOH%ET3@9!$Tsz>8g-F&zE&bPbo+`2g$V@6l) z?w0)3sg19)1;e^ly&d>+cQkevczHbfJQ}LLY0cYBtNg87ZM$s+th(tV*5rZ#^MM8I z+oUgvDFJDT_8XMH&4vP+EeXc)4Vh`n&|UWF2_IGhJDb`N_?sP;r~WCLO$8@2L*>k* z>I~q4%$eR};$dvTF=H-f((gTocdW`K1Ce((8z-S>~G$ z?{9e@t$p}leQoQ(!=8HqJekL@iirV$3sqt-%fe-8$+T0`6ub)ZQO27|%74j701k&(dx{gYITbdY{5K30Ky~2xYz|w` z;>0p=EU(P~gVStw*kc9B#6EzA=Aa9#+{wZ*17-=U6XsC)K$(&~15nm}`5I#1Fbln0 zeOf3z1yew6p#d?IIVWIvd%FZyULfL_tZ$*|DHS@t#011;KOZ}vMP}%z0|b?LELI5Q z;%HHB=cIn3x)I(a3DfuD2(dx4S~rrB89S5X^aK@M0UJT7jUPYW*xV9abT>91J?w36 z0ACTrG(yNMCve~5g(We_{Zx;DMPf3z$FVd7K2O|i+MfzhY(0V$wDHrRObi$@1ngp! zvg?y8X~{)UyDIg*QkLcojDF>aIGwnUtO|(NOJjrDZo69PM`XidBcVEnCaBz$1Ix%;RpL!ww}L_YxVMMMpNf z1)DZvZ-w@%oB_h2;E5N?*rE_7sv81p8c>B1ir* zF{@Xs_yjV#G7&Mt>})#$#0@B z$OzNcE^Ap#F2W)60TvQvLXVzFwIF(llq?g`ZIbI#)2;h9c4dFljEGcUwget4pxJ`& z;SuixD!wE^Le5lps3)zv4DyvrxHp-H=TxGzxaWyXF~`1|;}8A+U4@Zpmhu+=$%`1) z6F{xB@>!~QdRpTBUr*i-j_)WQQ<%Yb|9u0LtoFD9_#fPsGu78Bkr&684cOZ_dNE*# zlU;&OaVk(|h?fN&0f&=7$bZN5UPG#UNmM7CChZ|-DNz~A|I0;jIIe;k zv`>`(h0`2PVsZMapm!+M(uFd8`SiNXZPI>~^6Rh9#d(`_JQve{0-0G}sJyOGw#P7wQAyNp!w#v0y@ zb_#=Jiw)z%UL0SL&>{_UL6MYLC$fWBqh>{bme?^ck@WVZeJ(t_E9Wgw$I_G22`}M; zogNBs8RrE<73_Nhq;ekTO+N=uJ7@^$`LcZx)m7U%XMf#VM#6r5={}nta zUl7vk^-3M7SY2w?<#uzS`Bt;ptTZbv{C1>_W3k2A?k;~k;1~pZ{t#V!ZRnvVnK%z4 zlV)>8a>XxjJ{ZMHz}DUHKG@oN 1: + 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') + + 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()) + + if not self.issubclass(subcls, cls): + 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) + + # get all class attributes, including the ones coming from + # parent classes. + flat_type_info = cls.get_flat_type_info(cls) + if flat_type_info is None: + logger.critical("No flat_type_info found for type %r", cls) + raise TypeError(cls) + + # this is for validating cls.Attributes.{min,max}_occurs + frequencies = defaultdict(int) + + try: + items = doc.items() + except AttributeError: + # Input is not a dict, so we assume it's a sequence that we can pair + # 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) + except TypeError as e: + logger.error("Invalid document %r for %r", doc, cls) + raise ValidationError(doc) + + # parse input to set incoming data to related attributes. + for k, v in items: + if self.key_encoding is not None and isinstance(k, bytes): + try: + k = k.decode(self.key_encoding) + except UnicodeDecodeError: + raise ValidationError(k) + + member = flat_type_info.get(k, None) + if member is None: + member, k = flat_type_info.alt.get(k, (None, k)) + if member is None: + continue + + member_attrs = self.get_cls_attrs(member) + + if member_attrs.exc: + continue + + mo = member_attrs.max_occurs + if mo > 1: + subinst = getattr(inst, k, None) + if subinst is None: + subinst = [] + + for a in v: + subinst.append( + self._from_dict_value(ctx, k, member, a, validator)) + + else: + subinst = self._from_dict_value(ctx, k, member, v, validator) + + inst._safe_set(k, subinst, member, member_attrs) + + frequencies[k] += 1 + + attrs = self.get_cls_attrs(cls) + if validator is self.SOFT_VALIDATION and attrs.validate_freq: + self._check_freq_dict(cls, frequencies, flat_type_info) + + return inst + + def _object_to_doc(self, cls, inst, tags=None): + if inst is None: + return None + + if tags is None: + tags = set() + + retval = None + + if isinstance(inst, Fault): + retval = None + inst_id = id(inst) + if not (inst_id in tags): + retval = self._fault_to_doc(inst, cls) + tags.add(inst_id) + return retval + + cls_attrs = self.get_cls_attrs(cls) + if cls_attrs.exc: + return + + cls_orig = None + if cls_attrs.out_type is not None: + cls_orig = cls + cls = cls_attrs.out_type + # remember to do this if cls_attrs are needed below + # (currently cls_attrs is not used so we don't do this) + # cls_attrs = self.get_cls_attrs(cls) + + elif cls_attrs.type is not None: + cls_orig = cls + cls = cls_attrs.type + # remember to do this if cls_attrs are needed below + # (currently cls_attrs is not used so we don't do this) + # cls_attrs = self.get_cls_attrs(cls) + + if self.ignore_wrappers: + 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() + if not issubclass(cls, Array): + inst = getattr(inst, key, None) + cls, = ti.values() + ti = getattr(cls, '_type_info', {}) + + # transform the results into a dict: + if cls.Attributes.max_occurs > 1: + if inst is not None: + retval = [] + + for subinst in inst: + 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)) + + # this is DANGEROUS + #logger.debug("Said array: %r", inst) + + return None + + 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) + + 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) + + for k, v in self.sort_fields(cls): + subattr = self.get_cls_attrs(v) + + if subattr.exc: + continue + + try: + subinst = getattr(inst, k, None) + + # to guard against e.g. sqlalchemy throwing NoSuchColumnError + except Exception as e: + logger.error("Error getting %r: %r" % (k, e)) + subinst = None + + if subinst is None: + subinst = subattr.default + else: + if id(subinst) in tags: + continue + + logger.debug("%s%r%r", " " * len(tags), k, v) + val = self._object_to_doc(v, subinst, tags) + min_o = subattr.min_occurs + + complex_as = self.get_complex_as(subattr) + if val is not None or min_o > 0 or complex_as is list: + sub_name = subattr.sub_name + if sub_name is None: + sub_name = k + + yield (sub_name, val) + + def _to_dict_value(self, cls, inst, tags, cls_orig=None): + if cls_orig is None: + cls_orig = cls + cls, switched = self.get_polymorphic_target(cls, inst) + cls_attrs = self.get_cls_attrs(cls) + + inst = self._sanitize(cls_attrs, inst) + + if issubclass(cls_orig, File): + cls_orig_attrs = self.get_cls_attrs(cls_orig) + if not isinstance(inst, cls_orig_attrs.type): + return self.to_serstr(cls_orig, inst, self.binary_encoding) + + retval = self._complex_to_doc(cls_orig_attrs.type, inst, tags) + complex_as = self.get_complex_as(cls_orig_attrs) + + if complex_as is dict and not self.ignore_wrappers: + retval = next(iter(retval.values())) + + return retval + + if issubclass(cls, (Any, AnyDict)): + return inst + + if issubclass(cls, Array): + st, = cls._type_info.values() + return self._object_to_doc(st, inst, tags) + + if issubclass(cls, ComplexModelBase): + return self._complex_to_doc(cls, inst, tags) + + if issubclass(cls, (ByteArray, Uuid)): + return self.to_serstr(cls, inst, self.binary_encoding) + + return self.to_serstr(cls, inst) + + def _complex_to_doc(self, cls, inst, tags): + cls_attrs = self.get_cls_attrs(cls) + sf = cls_attrs.simple_field + if sf is not None: + # we want this to throw when sf does not exist + subcls = cls.get_flat_type_info(cls)[sf] + + 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) + + 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: + return list(self._complex_to_list(cls, inst, tags)) + return self._complex_to_dict(cls, inst, tags) + + def _complex_to_dict(self, cls, inst, tags): + inst = cls.get_serialization_instance(inst) + cls_attr = self.get_cls_attrs(cls) + complex_as = self.get_complex_as(cls_attr) + + 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): + return d + + else: + if isinstance(cls_attr.wrapper, + (six.text_type, six.binary_type)): + 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): + return d + + else: + if isinstance(cls_attr.wrapper, six.text_type): + return {cls_attr.wrapper.encode(self.key_encoding): d} + elif isinstance(cls_attr.wrapper, six.binary_type): + return {cls_attr.wrapper: d} + else: + return {cls.get_type_name().encode(self.key_encoding): d} + + def _complex_to_list(self, cls, inst, tags): + inst = cls.get_serialization_instance(inst) + + for k, v in self._get_member_pairs(cls, inst, tags): + yield v diff --git a/pym/calculate/contrib/spyne/protocol/dictdoc/hier.pyc b/pym/calculate/contrib/spyne/protocol/dictdoc/hier.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92629f23e992b0122b4e634f0244f327b5874e76 GIT binary patch literal 14176 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 GEB-GnKytJI literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/dictdoc/simple.py b/pym/calculate/contrib/spyne/protocol/dictdoc/simple.py new file mode 100644 index 0000000..6b608bd --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/dictdoc/simple.py @@ -0,0 +1,404 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import logging +logger = logging.getLogger(__name__) + +import re +RE_HTTP_ARRAY_INDEX = re.compile("\\[([0-9]+)\\]") + +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.protocol.dictdoc import DictDocument + + +def _s2cmi(m, nidx): + """ + Sparse to contiguous mapping inserter. + + >>> m1={3:0, 4:1, 7:2} + >>> _s2cmi(m1, 5); m1 + 1 + {3: 0, 4: 1, 5: 2, 7: 3} + >>> _s2cmi(m1, 0); m1 + 0 + {0: 0, 3: 1, 4: 2, 5: 3, 7: 4} + >>> _s2cmi(m1, 8); m1 + 4 + {0: 0, 3: 1, 4: 2, 5: 3, 7: 4, 8: 5} + """ + nv = -1 + for i, v in m.items(): + if i >= nidx: + m[i] += 1 + elif v > nv: + nv = v + m[nidx] = nv + 1 + return nv + 1 + + +def _fill(inst_class, frequencies): + """This function initializes the frequencies dict with null values. If this + is not done, it won't be possible to catch missing elements when validating + the incoming document. + """ + + ctype_info = inst_class.get_flat_type_info(inst_class) + cfreq_key = inst_class, 0 + + for k, v in ctype_info.items(): + if v.Attributes.min_occurs > 0: + frequencies[cfreq_key][k] = 0 + + +class SimpleDictDocument(DictDocument): + """This protocol contains logic for protocols that serialize and deserialize + 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) + + self.hier_delim = hier_delim + self.strict_arrays = strict_arrays + + def _to_native_values(self, cls, member, orig_k, k, v, req_enc, validator): + value = [] + + 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): + try: + v2 = v2.decode(req_enc) + except UnicodeDecodeError as e: + raise ValidationError(v2, "%r while decoding %%r" % e) + + # validate raw data (before deserialization) + try: + if (validator is self.SOFT_VALIDATION and not + member.type.validate_string(member.type, v2)): + raise ValidationError([orig_k, v2]) + + except TypeError: + raise ValidationError([orig_k, v2]) + + cls_attrs = self.get_cls_attrs(member.type) + v2 = self._parse(cls_attrs, v2) + + # deserialize to native type + if issubclass(member.type, File): + if isinstance(v2, File.Value): + native_v2 = v2 + else: + 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) + 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)) + + # validate native data (after deserialization) + native_v2 = self._sanitize(cls_attrs, native_v2) + if validator is self.SOFT_VALIDATION: + if not member.type.validate_native(member.type, native_v2): + raise ValidationError([orig_k, v2]) + + value.append(native_v2) + + return value + + def simple_dict_to_object(self, ctx, doc, cls, validator=None, req_enc=None): + """Converts a flat dict to a native python object. + + See :func:`spyne.model.complex.ComplexModelBase.get_flat_type_info`. + """ + + if issubclass(cls, (Any, AnyDict)): + 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.") + + # this is for validating cls.Attributes.{min,max}_occurs + frequencies = defaultdict(lambda: defaultdict(int)) + if validator is self.SOFT_VALIDATION: + _fill(cls, frequencies) + + if issubclass(cls, Array): + # we need the wrapper object instance here as it's a root object + retval = cls.get_serialization_instance([]) + else: + retval = cls.get_deserialization_instance(ctx) + + 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()) + + idxmap = defaultdict(dict) + for orig_k, v in sorted(doc.items(), key=lambda _k: _k[0]): + k = RE_HTTP_ARRAY_INDEX.sub("", orig_k) + + member = simple_type_info.get(k, None) + if member is None: + logger.debug("\tdiscarding field %r" % k) + continue + + if member.can_be_empty: + if v != ['empty']: # maybe raise a ValidationError instead? + # 'empty' is the only valid value at this point after all + continue + + assert issubclass(member.type, ComplexModelBase) + + if issubclass(member.type, Array): + value = [] + + elif self.get_cls_attrs(member.type).max_occurs > 1: + value = [] + + else: + value = [member.type.get_deserialization_instance(ctx)] + # do we have to ignore later assignments? they're illegal + # but not harmful. + 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) + + + # assign the native value to the relevant class in the nested object + # structure. + cinst = retval + ctype_info = cls.get_flat_type_info(cls) + ccls_attr = self.get_cls_attrs(cls) + value = self._cast(ccls_attr, value) + + idx, nidx = 0, 0 + pkey = member.path[0] + cfreq_key = cls, idx + + indexes = deque(RE_HTTP_ARRAY_INDEX.findall(orig_k)) + for pkey in member.path[:-1]: + nidx = 0 + 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_attrs = self.get_cls_attrs(ncls) + mo = ncls_attrs.max_occurs + if mo > 1: + if len(indexes) == 0: + nidx = 0 + else: + nidx = int(indexes.popleft()) + + if ninst is None: + ninst = [] + cinst._safe_set(pkey, ninst, ncls, nattrs) + + if self.strict_arrays: + if len(ninst) == 0: + newval = ncls.get_deserialization_instance(ctx) + ninst.append(newval) + frequencies[cfreq_key][pkey] += 1 + + if nidx > len(ninst): + 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 + + cinst = ninst[nidx] + + else: + _m = idxmap[id(ninst)] + cidx = _m.get(nidx, None) + if cidx is None: + cidx = _s2cmi(_m, nidx) + newval = ncls.get_deserialization_instance(ctx) + ninst.insert(cidx, newval) + frequencies[cfreq_key][pkey] += 1 + cinst = ninst[cidx] + + assert cinst is not None, ninst + + else: + if ninst is None: + ninst = ncls.get_deserialization_instance(ctx) + cinst._safe_set(pkey, ninst, ncls, nattrs) + frequencies[cfreq_key][pkey] += 1 + + cinst = ninst + + cfreq_key = cfreq_key + (ncls, nidx) + idx = nidx + ctype_info = ncls.get_flat_type_info(ncls) + + frequencies[cfreq_key][member.path[-1]] += len(value) + + member_attrs = self.get_cls_attrs(member.type) + if member_attrs.max_occurs > 1: + _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) + 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)) + + else: + 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])) + + if validator is self.SOFT_VALIDATION: + logger.debug("\tvalidate_freq: \n%r", frequencies) + for k, d in frequencies.items(): + 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]) + break + else: + path_cls = k[-2] + logger.debug("\t\tdo validate_freq: %r", k) + self._check_freq_dict(path_cls, d) + + if issubclass(cls, Array): + # unwrap the request object + 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): + """Converts a native python object to a flat dict. + + See :func:`spyne.model.complex.ComplexModelBase.get_flat_type_info`. + """ + + if retval is None: + retval = {} + + if prefix is None: + prefix = [] + + if inst is None and self.get_cls_attrs(cls).min_occurs == 0: + return retval + + if tags is None: + tags = set([id(inst)]) + else: + if id(inst) in tags: + return retval + + if issubclass(cls, ComplexModelBase): + fti = cls.get_flat_type_info(cls) + + for k, v in fti.items(): + new_prefix = list(prefix) + cls_attrs = self.get_cls_attrs(v) + sub_name = cls_attrs.sub_name + if sub_name is None: + sub_name = k + 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): + subtype, = v._type_info.values() + else: + subtype = v + + # for simple types, the same key is repeated with multiple + # values + if issubclass(subtype, SimpleModel): + key = self.hier_delim.join(new_prefix) + l = [] + for ssv in subinst: + l.append(subinst_eater(self, ssv, subtype)) + retval[key] = l + + else: + # for complex types, brackets are used for each value. + 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) + + if i == -1: + key = self.hier_delim.join(new_prefix) + retval[key] = 'empty' + + else: + 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])) + + retval[key] = subinst_eater(self, inst, cls) + + return retval diff --git a/pym/calculate/contrib/spyne/protocol/dictdoc/simple.pyc b/pym/calculate/contrib/spyne/protocol/dictdoc/simple.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7f848605ff62e07a6b6801a39a7fbd1698075606 GIT binary patch literal 10435 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/html/__init__.py b/pym/calculate/contrib/spyne/protocol/html/__init__.py new file mode 100644 index 0000000..43b6c5c --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/html/__init__.py @@ -0,0 +1,41 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +""" +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.microformat import HtmlMicroFormat +from spyne.protocol.html.addtl import PrettyFormat +from spyne.protocol.html.addtl import BooleanListProtocol + + +# FIXME: REMOVE ME +def translate(cls, locale, default): + retval = None + if cls.Attributes.translations is not None: + retval = cls.Attributes.translations.get(locale, None) + if retval is None: + return default + return retval diff --git a/pym/calculate/contrib/spyne/protocol/html/__init__.pyc b/pym/calculate/contrib/spyne/protocol/html/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d85df7789c09d1f896cd4ae15204016802598f85 GIT binary patch literal 1122 zcmcgr&2H2%5S}F4{p*%iMM5ABMB=iSCTfd{kPw1a0uE4BX-~NXZ{po`>%>t!0j;#0 z;0<^l-h@Zs#sk1iva1#eIO53T`96=wR+t+s~tcFYLbDH)Gi3}hn=|JX! zb|7~lcEMrnHQ0mLYjLN+9f&(E-T=J;c^Beti@Oc(LELL`4|E^$0mOqA_dyRK--LLx z#e)WqARZAO!eGZR zvPQqG44Twv8w}M?8e@lCV4uWmvN{%4w#;C~oM?mdmbyz+DJm-yc9={nG0SCv$yDjp zq3!h{qwBo55R>%=2h08=^Wg@&Hh-(q%DgmHF0j3c&Ce={xVXvQCid7EEk*H0Sv*_4 zB=v~z(B$=mrhP?%O7_u%CBUTvmoCGr0aS&V6U(bez-iEwv>jq}yE*U3bU%?d$vk35^R( literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/html/_base.py b/pym/calculate/contrib/spyne/protocol/html/_base.py new file mode 100644 index 0000000..142118e --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/html/_base.py @@ -0,0 +1,251 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import logging +logger = logging.getLogger(__name__) + +from collections import defaultdict + +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.util.etreeconv import dict_to_etree + +from spyne.protocol.cloth import XmlCloth +from spyne.protocol.cloth._base import XmlClothProtocolContext + + +def parse_html_fragment_file(T_FILES): + elt = html.fromstring(open(T_FILES).read()) + elt.getparent().remove(elt) + return elt + + +class HtmlClothProtocolContext(XmlClothProtocolContext): + def __init__(self, parent, transport, type=None): + super(HtmlClothProtocolContext, self).__init__(parent, transport, type) + + self.assets = [] + self.eltstack = defaultdict(list) + self.ctxstack = defaultdict(list) + self.rootstack = oset() + self.tags = set() + self.objcache = dict() + + # these are supposed to be for neurons.base.screen.ScreenBase subclasses + self.screen = None + self.prev_view = None + self.next_view = 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) + + self.hier_delim = hier_delim + self.doctype = doctype + self.default_method = 'html' + + def _parse_file(self, file_name, cloth_parser): + if cloth_parser is None: + cloth_parser = html.HTMLParser() + + cloth = html.parse(file_name, parser=cloth_parser) + return cloth.getroot() + + def docfile(self, *args, **kwargs): + logger.debug("Starting file with %r %r", args, kwargs) + return etree.htmlfile(*args, **kwargs) + + def get_context(self, parent, transport): + return HtmlClothProtocolContext(parent, transport) + + @staticmethod + def get_class_cloth(cls): + return cls.Attributes._html_cloth + + @staticmethod + def get_class_root_cloth(cls): + return cls.Attributes._html_root_cloth + + def dict_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + parent.write(repr(inst)) + + @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)) + else: + attr_dict[attr_name] = class_name + + @staticmethod + def add_style(attr_dict, data): + style = attr_dict.get('style', None) + + if style is not None: + attr_dict['style'] = ';'.join(style, data) + + else: + attr_dict['style'] = data + + @staticmethod + def selsafe(s): + return s.replace('[', '').replace(']', '').replace('.', '__') + + @coroutine + 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) + if ret is not None: + try: + while True: + sv2 = (yield) # may throw Break + ret.send(sv2) + + except Break: + try: + ret.throw(Break()) + except StopIteration: + pass + + 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 = inst + + content = None + text = cls_attrs.text + + else: + content = getattr(inst, 'content', None) + text = getattr(inst, 'text', None) + if text is None: + text = cls_attrs.text + + if anchor_class is None: + anchor_class = cls_attrs.anchor_class + + if text is None: + text = name + + retval = E.a(text) + + if href is not None: + retval.attrib['href'] = href + + if anchor_class is not None: + retval.attrib['class'] = anchor_class + + if content is not None: + retval.append(content) + + return retval + + def any_uri_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + retval = self.gen_anchor(cls, inst, name) + parent.write(retval) + + 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 = inst + text = getattr(cls.Attributes, 'text', None) + + else: + text = getattr(inst, 'text', None) + if text is None: + text = getattr(cls.Attributes, 'text', None) + + retval = E.img(src=href) + if text is not None: + retval.attrib['alt'] = text + + parent.write(retval) + + def byte_array_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + ret = self.to_unicode(cls, inst, self.binary_encoding) + + if ret is not None: + parent.write(ret) + + def model_base_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + ret = self.to_unicode(cls, inst) + + if ret is not None: + parent.write(ret) + + 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)): + inst = etree.fromstring(inst) + + parent.write(inst) + + 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)): + inst = html.tostring(inst) + + else: + if isinstance(inst, str) or isinstance(inst, six.text_type): + inst = html.fromstring(inst) + + parent.write(inst) + + 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') + dict_to_etree(inst, elt) + + parent.write(elt[0]) + + def fault_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + self.complex_to_parent(ctx, cls, inst, parent, name, **kwargs) + + +# FIXME: Deprecated +HtmlBase = HtmlCloth diff --git a/pym/calculate/contrib/spyne/protocol/html/_base.pyc b/pym/calculate/contrib/spyne/protocol/html/_base.pyc new file mode 100644 index 0000000000000000000000000000000000000000..179ab7900f656b7befdff38d8a8df9f072cef44f GIT binary patch literal 10012 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 AIsgCw literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/html/addtl.py b/pym/calculate/contrib/spyne/protocol/html/addtl.py new file mode 100644 index 0000000..c89af8a --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/html/addtl.py @@ -0,0 +1,52 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from lxml.builder import E +from pprint import pformat + +from spyne import Boolean +from spyne.protocol.html import HtmlBase + + +class PrettyFormat(HtmlBase): + def to_parent(self, ctx, cls, inst, parent, name, **kwargs): + parent.write(E.pre(pformat(inst))) + + +class BooleanListProtocol(HtmlBase): + def __init__(self, nothing=None): + super(BooleanListProtocol, self).__init__() + + self.nothing = nothing + + def to_parent(self, ctx, cls, inst, parent, name, nosubprot=False, **kwargs): + if inst is None: + return + + wrote_nothing = True + for k, v in cls.get_flat_type_info(cls).items(): + if not issubclass(v, Boolean): + continue + + if getattr(inst, k, False): + parent.write(E.p(self.trc(cls, ctx.locale, k))) + wrote_nothing = False + + if wrote_nothing and self.nothing is not None: + parent.write(E.p(self.nothing)) diff --git a/pym/calculate/contrib/spyne/protocol/html/addtl.pyc b/pym/calculate/contrib/spyne/protocol/html/addtl.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9b814c8d52e6461f598646bed9d8229de4ba3ed0 GIT binary patch literal 2037 zcmcgtOK%)S5U!rtr{g6iA-RNu;eh54?OB5j|M3De1>L5j|K*M;ZcRlN#2h+XS zE7m9HZ*j~a|AC*tjUNDC)vWDEoSoHFO;=Ap>hXQG;Xk9TzyJF4*OWHD5btjwu7=9+ zD6&L_qNyUqc0e|uBBW{9+9BBv6=W6qC zUfQh(5%2L`sFNo5Mq|LM;d^5=-yQM6o>w_zXYwiar|sK1`H+{+d-kDD8dG|iE0e;= z-0?}$%w2@9B+9+UXtH$8#O8;OzM9l4e^iwZ$6rqz?%%7E^f;LtH*xiM=<#{$AtC(pked5KvH<~i zi!Dy-;s&3Kgf6yu8P>F%Q`mrOaSEQ-Yk2ckmXE}_p_riS`zMVqw&LFR3d1-Rf*n+) zk-?A6()e4Lo*N&}Y~o|Ts!g1ivr2dkRuxX*o;$ZZOl{(v=8{Pbu_^Jsk(JLA>x|}J z(6#}le=SV+O)6xzRhn4SmYGxCR-JjJnR=Q@rR4+nGofQy;Zmln9`O{b6IdqRphtS< zvFP7F5Og?)UqIYlC{o+16ZF*Q>Za-iw^XD?!5wuFaX-^HS?#d8!-_GdnYAChT`&Q6 zA%gav+U_36UyuB4*wey}50|;kz*MYZn4)lXlb2pvxD;3VXkapBg015AQ{{y#%tU>?) literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/html/microformat.py b/pym/calculate/contrib/spyne/protocol/html/microformat.py new file mode 100644 index 0000000..b78e1e1 --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/html/microformat.py @@ -0,0 +1,197 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from inspect import isgenerator + +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.protocol.html import HtmlBase + + +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): + """Protocol that returns the response object according to the "html + microformat" specification. See + https://en.wikipedia.org/wiki/Microformats for more info. + + The simple flavour is like the XmlDocument protocol, but returns data in +
or tags. + + :param app: A spyne.application.Application instance. + :param root_tag: The type of the root tag that encapsulates the return + data. + :param child_tag: The type of the tag that encapsulates the fields of + the returned object. + :param field_name_attr: The name of the attribute that will contain the + 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) + + if six.PY2: + text_type = basestring + else: + text_type = str + + assert isinstance(root_tag, text_type) + assert isinstance(child_tag, text_type) + assert isinstance(field_name_attr, text_type) + assert field_name_tag is None or isinstance(field_name_tag, text_type) + + self.root_tag = root_tag + self.child_tag = child_tag + self.field_name_attr = field_name_attr + self.field_name_tag = field_name_tag + if field_name_tag is not None: + 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, + }) + + def anyuri_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + retval = self.gen_anchor(cls, inst, parent) + retval.attrib[self.field_name_attr] = name + parent.write(retval) + + def model_base_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + retval = E(self.child_tag, **{self.field_name_attr: name}) + 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_tag.tail = data_str + retval.append(field_name_tag) + + else: + retval.text = data_str + + parent.write(retval) + + 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 len(ctx.protocol.prot_stack) == 1: + if self.doctype is not None: + parent.write_doctype(self.doctype) + + # set this to true as no doctype can be written after this + # stage anyway. + ctx.outprot_ctx.doctype_written = True + + 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): + 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) + 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) + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as e: + try: + ret.throw(e) + except StopIteration: + pass + + @coroutine + 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() + + 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) + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as e: + try: + ret.throw(e) + except StopIteration: + pass + + else: + for sv in inst: + ret = self.to_parent(ctx, cls, sv, parent, name, + from_arr=True, **kwargs) + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as e: + try: + ret.throw(e) + except StopIteration: + pass + + def null_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + return [ E(self.child_tag, **{self.field_name_attr: name}) ] + +# FIXME: yuck. +from spyne.protocol.cloth import XmlCloth +XmlCloth.HtmlMicroFormat = HtmlMicroFormat diff --git a/pym/calculate/contrib/spyne/protocol/html/microformat.pyc b/pym/calculate/contrib/spyne/protocol/html/microformat.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4fe6d13ef64dad14c7c7fc138f7fc45929464f13 GIT binary patch literal 6555 zcmd5=-EU(@6+dIgPV9Wx`;}eVZR@RCY6NxYwggy~rMuf!l+w`NY&Tica=E#l#MikW z&YkflL5Wn@RyG~!po}#2i-I}XcD6Ug7P2FiqW~e(u$t-neDVd}093>6vHYjOQw@Jwf z>YkwFBy~@^nN^BUQF5BPr%|6IeVW!4^`_`8qB}&lx@TmsHHzmcIZNHMr1TlmXURuL zotE3vI8F3leA)^nD^;_hQ=JDk%UvV)Jl|#kSSBXgu{HdMS)Pq-lxkZ+?OLvbO*fva zVJ`}8dkQ7#y_)C2uAM~nYP$Pfo5Z$>^7Skk#(L-Ftf%8^fziVD+OE}ZI4^S8$Glz{ znZ69<%8N;`p_8LX^`lU&%qN< z;JJ>+{1hs)_$k^04oWn@)=`!-?4ewyJse|#_Heuk?co?z+QS*J`#Pg%ZxZO4Qg(s{ z70O>DhF5E(V|~ zte82GkBMN20tTRr!VF<97iPJDy>8Yh{}0(Yu0qDHD<#^)NDOPx-fS_ft25uQ1e}q-c^y4^ELiO^aMQLw4Sk&XPUnN?#!RfGa&n_Pi@SMD}47}zLFJFR7{561Pa9hyrE3p(v=N1M@5_oASaXP8akQyrU#m&{To#TJo!ZuLe7vu; z)<%cN>jgFd(*uT=0pTkxtajN9gY-(v1{>zcdY6Vl9we<`IK0%linHyex`RqwobT#k z8C;DG(olB}n2%@YS!R7OzSQFF+ub1qyY2*y9$pd^s6eM-Ff^k$u)5F#>*RnPi<|fV zi3P%b1f%=Z74FYmEY)Bqcky@X=Vf(oto~0dcWC2&U~TS>#U@`Ii(4Z|ot1)fZAWq3 z3bWJ(QOd`@Ye8Yw;@P|xkxJ+saDhHKT@KJ3%oE=OHCT2|(MAfO_#+mcWq&hn*v>IR z=Vt7nGTWEoVT_UwwHlpEU>RodE}%B-BQ&rF>qk2G;rgRQB110=S!0&H*qR0|wZ9&L ztIt|pYCno*S;363n8)kG55dU&D2=S|!&wn6WvTXHaV}E5a_gcjw1(JXAgFZ11u&aS zb7Tr2!GR!z7~Uvs>G?d*a^YRz$;G=u_j2}oR3jXYv;hsCL{vTv&QbVk-#PGEwCdY1 z9zO|Egt1&C7W8_492v{u*W)NED+L@oeVef;F~j3&FFaDJB5PBi+N|5@H~&Xd*_%uz~nI|k2CoqlP5qV zkGNO7-h=;VwpW^u~s3UnqRu0!w+}h+pmucfE(O0>jl@0-^bHYDS$@v!$A< zm8zvPioX}QCSUHWVZ@B8m#V6MCt^D54dh*-tOwvkq8N#DGuc?#!!q1|!+ zu@PHi4u0D3@Ig+;$F`3uG% zkztPDP~%KYI3lINxVq#ym?KFJt1HDMbWBRR13eo^%{OeKuW05Wo#UkxPX{SLl|FTmmt!ZS22%wrGa`3qg#_7u$G@0K*=qaBl(| z8HQE=Y3h*@nG>gRyVaY90bhEwGT5XC;Xuua3k zkS5NkbE=`{CmN-YH_wgyY~nFh$o9}d5G}$N@Ldafm5UZc$w;{=+7+0%+t*z>o}_oG zq+nrgnm;LUIKYfJ0l1lWe?f9_fwwpU5@3!|2p$s(P6k?qhXEGzk7@UD+Ig67Z26z~ z?s{`yu2BPAi0Tf8zoC_tt&eE}0e`bj`M*f*Pm|g`!7K*FO-ik7{To9XGUT76ltO(K z(^di674Us^6=Yf73M{#J%f5Al3?VgbzTCSQ{XH%%G5J1|FM$ZAklATpG9d3&?vRMh zg4VI-ONGRGNvZ_U+D~+{hNQv65a*u^oRY_w6A0UWo^4ACvuv~BifK=uI}XD$u3^OAy6^J#t$c5@u_4xAc*jQEFF4Dg_UA|P8)z$7A&17zMW zAPW|Magdc*$bnC8^=j*VhU}D@03aB$6H4vRILOv%fJ^?2AbVx2f+0;A!iZI@A1Z;d*fF{X#V`$oL6JZ!Ui&T(tEe*DQxq@gKfTlziobSu+87gHb1}? zKg2Vy@LM@zT@viYA+P6I;^QXJ=E(2zG>+(zK{Svng}WATo8-H=6s>0xzL9&4aQk6o zAO^TjPSd=b%!$$Eajxo3GZ9;48xuS8R=G66LY-Asjj^ZQt$3LURuqH_@2?hj~zPy0MeP2>e=kWzm zEFSM!CY*1_5c6? literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/html/table/__init__.py b/pym/calculate/contrib/spyne/protocol/html/table/__init__.py new file mode 100644 index 0000000..0c52d57 --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/html/table/__init__.py @@ -0,0 +1,4 @@ + +from spyne.protocol.html.table._base import HtmlTableBase +from spyne.protocol.html.table.row import HtmlRowTable +from spyne.protocol.html.table.column import HtmlColumnTable diff --git a/pym/calculate/contrib/spyne/protocol/html/table/__init__.pyc b/pym/calculate/contrib/spyne/protocol/html/table/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..97e2cba3934f4ab230e5f087554e3760ade3c867 GIT binary patch literal 432 zcmaJ-y-ve05I*MzAw)%A0Ku3gwpyyPAcSCHVhEkGxJhcI5q2EKj;cHyZ^9$6@c?j6 zg4C&&@3Zf_^LKale`XioU!U6orsd)Jgl1LA|rb>u`gP7svZJw(V3IEK`>2U z3)-~W>OxDpM^$Q_Eaf>0Czt~E`eb6O56RHh?a4Hh$NGu;j0o)r%obhNnU={aU$0ox z+r6%r^q!f@inz&&kE|4i4ZX%oy11i@b=>rrK}A`PJo}%4xf$3n1LM4^E6X`W$#X37 Rp!BYj;?Xr>0)#o4lRt|naCra# literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/html/table/_base.py b/pym/calculate/contrib/spyne/protocol/html/table/_base.py new file mode 100644 index 0000000..3471419 --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/html/table/_base.py @@ -0,0 +1,69 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +from spyne.protocol.html import HtmlBase + + +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): + + 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 + self.table_name = table_name + self.field_name_attr = field_name_attr + self.field_type_name_attr = field_type_name_attr + self.border = border + self.row_class = row_class + self.cell_class = cell_class + self.header_cell_class = header_cell_class + self.link_gen = link_gen + self.table_class = table_class + self.table_width = table_width + self.mrpc_delim_text = mrpc_delim_text + + def null_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + pass + + def add_field_attrs(self, attr_dict, name, cls): + if self.field_name_attr: + self.add_html_attr(self.field_name_attr, attr_dict, name) + + if self.field_type_name_attr: + types = set() + c = cls + while c is not None: + if c.Attributes._explicit_type_name or c.__extends__ is None: + types.add(c.get_type_name()) + + c = c.__extends__ + + self.add_html_attr(self.field_type_name_attr, attr_dict, + ' '.join(types)) diff --git a/pym/calculate/contrib/spyne/protocol/html/table/_base.pyc b/pym/calculate/contrib/spyne/protocol/html/table/_base.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0409841b4c5643ab8ea89dba5477c257cfff63a1 GIT binary patch literal 2319 zcmcguQEwYX5T3Ig$4-+bO`FnEgrGcNA;nhOs(k?jMM4N9KU^vyBBAAcw{gxn-(7Fl zN{p^gsrWBE@DJdh@Dq6B2f+8unIsQ9$Ii}uyE`{KGduG+?Z3A+{`&KepJG{k+IW6} z;XZ*#@E1rXG7sb^kRWM^4dghGq%ChnE<}DfYDvADUX^OZ+mabh3#5i4EvbRq zQsdZ;)Npf6Y8=~@dWVkGcO>aay^AdMf*PwL2HMyFzzf&|z&o1?ps=L?3L6Tba7#g7 z>e~vizO4Z3cNO4W?7|M--BSR~dkVIhsKY@Y0gOFwH7ZNLiDx>^i^`fs9!I6$zFIh| zpkXVw%1_}>R6WjsOc_$%OYFOi>f?HW50p) zKA?C+@h-#wqY>^$pwYrrqb!{~e>N(Y{-nsC3}1{~>g|3R#i!BKx{)iFx!r#Cpn^%DC}e^Yb3&TCcG`Z=RXcWTv_ES~RFdT#T-2*+gB#}4FH`wLpeTH02b7vdTIy5bVW%8I8wseUFC%|IR4?bE^qXq$F1U#FqhpUL+; zw>cdo1}Y0=25RY0cjboO3?msUF@7-6qGL%anMX-tSQXl-TBLeYpnAQPagkeXwJ*`g z>15%p^Q>fJ&&w>0(fybGs{LiK;ccEcu!1sGlISs0dtH+mofT<5&|cCqVH=SwOad+n zKg2A2A3|w|M>zF9zR|K^S2I5iG0{8s0!xlvENG91+9cgzJ9re_Z*8@bes6D ro_qcFc);t_yH~Cm{>LdpR!@jM(I18zcU=EJ`Ls#z=cHS0+nx5m#<~83 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/html/table/column.py b/pym/calculate/contrib/spyne/protocol/html/table/column.py new file mode 100644 index 0000000..36b5f50 --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/html/table/column.py @@ -0,0 +1,336 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +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.protocol.html.table import HtmlTableBase + + +class HtmlColumnTableRowProtocol(object): + def column_table_gen_header(self, ctx, cls, parent, name, **kwargs): + return False + + def column_table_before_row(self, ctx, cls, inst, parent, name, **kwargs): + pass + + 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. + + Returns one record per table row in a table that has as many columns as + field names, just like a regular spreadsheet. + + This is not quite unlike the HtmlMicroFormatprotocol, but returns data + as a html table using the tag. + + Generally used to serialize Array()'s of ComplexModel objects. If an + array has prot=HtmlColumnTable, its serializer (what's inside the Array( )) + must implement HtmlColumnTableRowProtocol interface. + + :param app: A spyne.application.Application instance. + :param header: Boolean value to determine whether to show field + names in the beginning of the table or not. Defaults to True. Set to + False to skip headers. + :param table_name_attr: The name of the attribute that will contain the + response name of the complex object in the table tag. Set to None to + disable. + :param table_name: When not none, overrides what goes in `table_name_attr`. + :param table_class: When not none, specifies what goes in `class` attribute + in the `
` tag. Table name gets appended when + `table_name_attr == 'class'` + :param field_name_attr: The name of the attribute that will contain the + field names of the complex object children for every table cell. Set + to None to disable. + :param row_class: value that goes inside the + :param cell_class: value that goes inside the tags are generated before exiting the
+ :param header_cell_class: value that goes inside the + :param mrpc_delim_text: The text that goes between mrpc calls. + """ + + def __init__(self, *args, **kwargs): + 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, + }) + + 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 = '' + if inst is not None: + inst_str = self.to_unicode(cls, inst) + + if from_arr: + td_attrs = {} + + self.add_field_attrs(td_attrs, name, cls) + + parent.write(E.tr(E.td(inst_str, **td_attrs))) + + else: + parent.write(inst_str) + + @coroutine + 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. + if inst is None: + return + + logger.debug("Generate row for %r", cls) + + 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 = ' ' + + 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) + continue + + try: + sub_value = getattr(inst, k, None) + except: # e.g. SQLAlchemy could throw NoSuchColumnError + sub_value = None + + sub_name = cls_attr.sub_name + if sub_name is None: + sub_name = k + + if self.hier_delim is not None: + 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) + + 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) + + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + + except Break as b: + try: + ret.throw(b) + except StopIteration: + pass + + m = cls.Attributes.methods + if m is not None and len(m) > 0: + td_attrs = {'class': 'mrpc-cell'} + + with parent.element('td', td_attrs): + first = True + + for mn, md in self._methods(ctx, cls, inst): + if first: + first = False + elif mrpc_delim_elt is not None: + parent.write(" ") + parent.write(mrpc_delim_elt) + + pd = {} + for k, v in self.sort_fields(cls): + if getattr(v.Attributes, 'primary_key', None): + r = self.to_unicode(v, getattr(inst, k, None)) + if r is not None: + pd[k] = r + + params = urlencode(pd) + + 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'} + )) + + logger.debug("Generate row for %r done.", cls) + 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'): + if issubclass(cls, ComplexModelBase): + fti = self.sort_fields(cls) + for k, v in fti: + cls_attr = self.get_cls_attrs(v) + if cls_attr.exc: + continue + + th_attrs = {} + self.add_field_attrs(th_attrs, k, cls) + + if cls_attr.hidden: + 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'} + parent.write(E.th(**th_attrs)) + + else: + th_attrs = {} + self.add_field_attrs(th_attrs, name, cls) + + header_name = self.trc(cls, ctx.locale, name) + + parent.write(E.th(header_name, **th_attrs)) + + self.extend_header_row(ctx, cls, parent, name) + + @coroutine + def _gen_table(self, ctx, cls, inst, parent, name, gen_rows, **kwargs): + logger.debug("Generate table for %r", cls) + cls_attrs = self.get_cls_attrs(cls) + + attrib = {} + table_class = oset() + if self.table_class is not None: + 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()) + + if self.table_name_attr == 'class': + table_class.add(tn) + else: + attrib[self.table_name_attr] = tn + + attrib['class'] = ' '.join(table_class) + if self.table_width is not None: + attrib['width'] = self.table_width + + self.event_manager.fire_event('before_table', ctx, cls, inst, parent, + name, prot=self, **kwargs) + + with parent.element('table', attrib): + write_header = self.header + if cls_attrs.header is False: + write_header = cls_attrs.header + + if write_header: + ret = False + + subprot = self.get_subprot(ctx, cls_attrs) + if subprot is not None: + ret = subprot.column_table_gen_header(ctx, cls, parent, + name) + if not ret: + self._gen_thead(ctx, cls, parent, name) + + with parent.element('tbody'): + ret = gen_rows(ctx, cls, inst, parent, name, **kwargs) + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as b: + try: + ret.throw(b) + except StopIteration: + pass + + self.extend_table(ctx, cls, parent, name, **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) + + 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) + + def wrap_table(self, ctx, cls, inst, parent, name, gen_rows, **kwargs): + return self._gen_table(ctx, cls, inst, parent, name, gen_rows, **kwargs) + + def extend_table(self, ctx, cls, parent, name, **kwargs): + """This is called as the last operation during the table body generation + after all the
tag + which in turn is inside a tag.""" + + def extend_data_row(self, ctx, cls, inst, parent, name, **kwargs): + """This is called as the last operation during the row generation + after all the tag which + in turn is inside a tag.""" + + def extend_header_row(self, ctx, cls, parent, name, **kwargs): + """This is called once as the last operation during the table header + generation after all the + tag which in turn is inside a tag.""" diff --git a/pym/calculate/contrib/spyne/protocol/html/table/column.pyc b/pym/calculate/contrib/spyne/protocol/html/table/column.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e63719073401d38c4f9ad57c207dc6a79a040be5 GIT binary patch literal 11598 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 Cf_16@ literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/html/table/row.py b/pym/calculate/contrib/spyne/protocol/html/table/row.py new file mode 100644 index 0000000..5a33e1a --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/html/table/row.py @@ -0,0 +1,216 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +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.protocol.html.table import HtmlTableBase + + +class HtmlRowTable(HtmlTableBase): + """Protocol that returns the response object as a html table. + + The simple flavour is like the HtmlMicroFormatprotocol, but returns data + as a html table using the
tags are generated before exiting the
tags are generated before exiting the
tag. + + Returns one record per table in a table with two columns. + + :param app: A spyne.application.Application instance. + :param header: Boolean value to determine whether to show field + names in the beginning of the table or not. Defaults to True. Set to + False to skip headers. + :param table_name_attr: The name of the attribute that will contain the + response name of the complex object in the table tag. Set to None to + disable. + :param table_name: When not none, overrides what goes in `table_name_attr`. + :param table_class: When not none, specifies what goes in `class` attribute + in the `
` tag. Table name gets appended when + `table_name_attr == 'class'` + :param field_name_attr: The name of the attribute that will contain the + field names of the complex object children for every table cell. Set + to None to disable. + :param row_class: value that goes inside the + :param cell_class: value that goes inside the ;_c~hCv0C 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 OQ=Z>HQl6ix4E;B|rp3_! literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/server/twisted/websocket.py b/pym/calculate/contrib/spyne/server/twisted/websocket.py new file mode 100644 index 0000000..2e74cab --- /dev/null +++ b/pym/calculate/contrib/spyne/server/twisted/websocket.py @@ -0,0 +1,255 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.server.twisted`` module contains a server transport compatible +with the Twisted event loop. It uses the TwistedWebResource object as transport. + +Also see the twisted examples in the examples directory of the source +distribution. + +If you want to have a hard-coded URL in the wsdl document, this is how to do +it: :: + + resource = TwistedWebResource(...) + resource.http_transport.doc.wsdl11.build_interface_document("http://example.com") + +This is not strictly necessary -- if you don't do this, Spyne will get the +URL from the first request, build the wsdl on-the-fly and cache it as a +string in memory for later requests. However, if you want to make sure +you only have this url on the WSDL, this is how to do it. Note that if +your client takes the information in wsdl seriously, all requests will go +to the designated url above which can make testing a bit difficult. Use +in moderation. + +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.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 + + +class WebSocketTransportContext(TransportContext): + def __init__(self, parent, transport, type, client_handle): + TransportContext.__init__(self, parent, transport, type) + + self.client_handle = client_handle + """TwistedWebSocketProtocol instance.""" + + self.parent = parent + """Parent Context""" + + def get_peer(self): + if self.client_handle is not None: + peer = self.client_handle.transport.getPeer() + return Address.from_twisted_address(peer) + + +class WebSocketMethodContext(MethodContext): + def __init__(self, transport, client_handle): + MethodContext.__init__(self, transport, MethodContext.SERVER) + + self.transport = WebSocketTransportContext(self, transport, 'ws', + client_handle) + + +class TwistedWebSocketProtocol(WebSocketsProtocol): + """A protocol that parses and generates messages in a WebSocket stream.""" + + def __init__(self, transport, bookkeep=False, _clients=None): + self._spyne_transport = transport + self._clients = _clients + self.__app_id = id(self) + if bookkeep: + self.connectionMade = self._connectionMade + self.connectionLost = self._connectionLost + + @property + def app_id(self): + return self.__app_id + + @app_id.setter + def app_id(self, what): + entry = self._clients.get(self.__app_id, None) + + if entry: + del self._clients[self.__app_id] + self._clients[what] = entry + + self.__app_id = what + + def _connectionMade(self): + WebSocketsProtocol.connectionMade(self) + + self._clients[self.app_id] = self + + def _connectionLost(self, reason): + del self._clients[id(self)] + + + def frameReceived(self, opcode, data, fin): + tpt = self._spyne_transport + + initial_ctx = WebSocketMethodContext(tpt, client_handle=self) + initial_ctx.in_string = [data] + + contexts = tpt.generate_contexts(initial_ctx) + p_ctx, others = contexts[0], contexts[1:] + + if p_ctx.in_error: + p_ctx.out_object = p_ctx.in_error + + else: + tpt.get_in_object(p_ctx) + + if p_ctx.in_error: + p_ctx.out_object = p_ctx.in_error + + else: + tpt.get_out_object(p_ctx) + if p_ctx.out_error: + p_ctx.out_object = p_ctx.out_error + + def _cb_deferred(retval, cb=True): + if cb and len(p_ctx.descriptor.out_message._type_info) <= 1: + p_ctx.out_object = [retval] + else: + p_ctx.out_object = retval + + tpt.get_out_string(p_ctx) + self.sendFrame(opcode, ''.join(p_ctx.out_string), fin) + p_ctx.close() + process_contexts(tpt, others, p_ctx) + + def _eb_deferred(err): + p_ctx.out_error = err.value + if not issubclass(err.type, Fault): + logger.error(err.getTraceback()) + + tpt.get_out_string(p_ctx) + self.sendFrame(opcode, ''.join(p_ctx.out_string), fin) + p_ctx.close() + + ret = p_ctx.out_object + if isinstance(ret, (list, tuple)): + ret = ret[0] + + if isinstance(ret, Deferred): + ret.addCallback(_cb_deferred) + ret.addErrback(_eb_deferred) + + elif isinstance(ret, PushBase): + raise NotImplementedError() + + else: + _cb_deferred(p_ctx.out_object, cb=False) + + +class TwistedWebSocketFactory(Factory): + def __init__(self, app, bookkeep=False, _clients=None): + self.app = app + self.transport = ServerBase(app) + self.bookkeep = bookkeep + self._clients = _clients + if _clients is None: + self._clients = {} + + def buildProtocol(self, addr): + return TwistedWebSocketProtocol(self.transport, self.bookkeep, + self._clients) + +class _Fake(object): + pass + + +def _FakeWrap(cls): + class _Ret(ComplexModel): + _type_info = {"ugh ": cls} + + return _Ret + + +class _FakeCtx(object): + def __init__(self, obj, cls): + self.out_object = obj + self.out_error = None + self.descriptor = _Fake() + self.descriptor.out_message = cls + + +class InvalidRequestError(Exception): + pass + + +class TwistedWebSocketResource(WebSocketsResource): + def __init__(self, app, bookkeep=False, clients=None): + self.app = app + self.clients = clients + if clients is None: + self.clients = {} + + if bookkeep: + self.propagate = self.do_propagate + + WebSocketsResource.__init__(self, TwistedWebSocketFactory(app, + bookkeep, self.clients)) + + def propagate(self): + raise InvalidRequestError("You must enable bookkeeping to have " + "message propagation work.") + + def get_doc(self, obj, cls=None): + if cls is None: + cls = obj.__class__ + + op = self.app.out_protocol + ctx = _FakeCtx(obj, cls) + op.serialize(ctx, op.RESPONSE) + op.create_out_string(ctx) + + 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) + c.sendFrame(CONTROLS.TEXT, doc, True) diff --git a/pym/calculate/contrib/spyne/server/twisted/websocket.pyc b/pym/calculate/contrib/spyne/server/twisted/websocket.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8ecff5affbf135ed751b6ffd4b8572ee297d289 GIT binary patch literal 11090 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 V{jV=AEKM){a%pa<(VRlA@!z)O*@*xE literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/server/wsgi.py b/pym/calculate/contrib/spyne/server/wsgi.py new file mode 100644 index 0000000..9928c98 --- /dev/null +++ b/pym/calculate/contrib/spyne/server/wsgi.py @@ -0,0 +1,624 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +""" +A server that uses http as transport via wsgi. It doesn't contain any server +logic. +""" + +import logging +logger = logging.getLogger(__name__) + +import cgi +import threading + +from inspect import isgenerator +from itertools import chain + +from spyne import Address +from spyne.util.six.moves.http_cookies import SimpleCookie +from spyne.util.six.moves.urllib.parse import unquote, quote + +from spyne import File, Fault +from spyne.application import get_fault_string_from_exception +from spyne.auxproc import process_contexts +from spyne.error import RequestTooLongError +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.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 + + +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 + +try: + 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): + """Rebuilds the calling url from values found in the + environment. + + This algorithm was found via PEP 333, the wsgi spec and + contributed by Ian Bicking. + """ + + url = '' + if protocol: + url = environ['wsgi.url_scheme'] + '://' + + if server_name: + if environ.get('HTTP_HOST'): + url += environ['HTTP_HOST'] + + else: + url += environ['SERVER_NAME'] + + 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 path: + 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:] + + else: + url += quote(environ.get('SCRIPT_NAME', '')) + + url += quote(environ.get('PATH_INFO', '')) + + if 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(';')) + retval = odict() + + for name_value in pairs: + if name_value is None or len(name_value) == 0: + continue + 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('+', ' ')) + + value = None + if nv[1] is not None: + value = unquote(nv[1].replace('+', ' ')) + + l = retval.get(name, None) + if l is None: + l = retval[name] = [] + l.append(value) + + return retval + + +def _get_http_headers(req_env): + retval = {} + + for k, v in req_env.items(): + if k.startswith("HTTP_"): + key = k[5:].lower() + val = [v] + retval[key]= val + logger.debug("Add http header %r = %r", key, val) + + return retval + + +def _gen_http_headers(headers): + retval = [] + + for k,v in headers.items(): + if isinstance(v, (list, tuple)): + for v2 in v: + retval.append((k, v2)) + else: + retval.append((k, v)) + + return retval + + +class WsgiTransportContext(HttpTransportContext): + """The class that is used in the transport attribute of the + :class:`WsgiMethodContext` class.""" + + def __init__(self, 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) + """HTTP Request verb, as a convenience to users.""" + + self.headers = _get_http_headers(self.req_env) + + def get_path(self): + 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) + if qs is not None: + retval += '?' + qs + return retval + + def get_cookie(self, key): + cookie_string = self.req_env.get('HTTP_COOKIE', None) + if cookie_string is None: + return + + cookie = SimpleCookie() + cookie.load(cookie_string) + + return cookie.get(key, None).value + + def get_request_method(self): + 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) + + if address_parser.is_valid_ipv4(addr): + return Address(type=Address.TCP4, host=addr, port=port) + + if address_parser.is_valid_ipv6(addr): + return Address(type=Address.TCP6, host=addr, port=port) + + +class WsgiMethodContext(HttpMethodContext): + """The WSGI-Specific method context. WSGI-Specific information is stored in + the transport attribute using the :class:`WsgiTransportContext` class. + """ + + TransportContext = None + HttpTransportContext = WsgiTransportContext + + +class WsgiApplication(HttpBase): + """A `PEP-3333 `_ + compliant callable class. + + If you want to have a hard-coded URL in the wsdl document, this is how to do + it: :: + + wsgi_app = WsgiApplication(...) + wsgi_app.doc.wsdl11.build_interface_document("http://example.com") + + This is not strictly necessary -- if you don't do this, Spyne will get the + URL from the first request, build the wsdl on-the-fly and cache it as a + string in memory for later requests. However, if you want to make sure + you only have this url on the WSDL, this is how to do it. Note that if + your client takes the information in the Wsdl document seriously (not all + do), all requests will go to the designated url above even when you get the + Wsdl from another location, which can make testing a bit difficult. Use in + moderation. + + Supported events: + * ``wsdl`` + Called right before the wsdl data is returned to the client. + + * ``wsdl_exception`` + Called right after an exception is thrown during wsdl generation. + The exception object is stored in ctx.transport.wsdl_error + attribute. + + * ``wsgi_call`` + Called first when the incoming http request is identified as a rpc + request. + + * ``wsgi_return`` + Called right before the output stream is returned to the WSGI + handler. + + * ``wsgi_exception`` + Called right before returning the exception to the client. + + * ``wsgi_close`` + Called after the whole data has been returned to the client. It's + 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) + + self._mtx_build_interface_document = threading.Lock() + + self._wsdl = None + if self.doc.wsdl11 is not None: + self._wsdl = self.doc.wsdl11.get_interface_document() + + def __call__(self, req_env, start_response, wsgi_url=None): + """This method conforms to the WSGI spec for callable wsgi applications + (PEP 333). It looks in environ['wsgi.input'] for a fully formed rpc + message envelope, will deserialize the request parameters and call the + method on the object returned by the get_handler() method. + """ + + url = wsgi_url + if url is None: + 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] + return self.handle_wsdl_request(req_env, start_response, url) + + else: + return self.handle_rpc(req_env, start_response) + + def is_wsdl_request(self, req_env): + # Get the wsdl for the service. Assume path_info matches pattern: + # /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') + ) + ) + + def handle_wsdl_request(self, req_env, start_response, url): + 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)) + return [HTTP_404] + + if self._wsdl is None: + self._wsdl = self.doc.wsdl11.get_interface_document() + + ctx.transport.wsdl = self._wsdl + + if ctx.transport.wsdl is None: + try: + self._mtx_build_interface_document.acquire() + + ctx.transport.wsdl = self._wsdl + + if ctx.transport.wsdl is None: + self.doc.wsdl11.build_interface_document(url) + 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) + + 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) + + 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 + return [retval] + + def handle_error(self, p_ctx, others, error, start_response): + """Serialize errors to an iterable of strings and return them. + + :param p_ctx: Primary (non-aux) context. + :param others: List if auxiliary contexts (can be empty). + :param error: One of ctx.{in,out}_error. + :param start_response: See the WSGI spec for more info. + """ + + if p_ctx.transport.resp_code is None: + 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) + + start_response(p_ctx.transport.resp_code, + _gen_http_headers(p_ctx.transport.resp_headers)) + + try: + process_contexts(self, others, p_ctx, error=error) + except Exception as e: + # Report but ignore any exceptions from auxiliary methods. + logger.exception(e) + + 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) + + 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:] + + # TODO: rate limiting + p_ctx.active = True + + if p_ctx.in_error: + 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) + + self.get_out_object(p_ctx) + if p_ctx.out_error: + 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)) + is_generator = len(p_ctx.out_object) == 1 and isgenerator(g) + + # if the out_object is a generator function, this hack makes the user + # code run until first yield, which lets it set response headers and + # whatnot before calling start_response. It's important to run this + # here before serialization as the user function can also set output + # protocol. Is there a better way? + if is_generator: + first_obj = next(g) + p_ctx.out_object = ( chain((first_obj,), g), ) + + if p_ctx.transport.resp_code is None: + p_ctx.transport.resp_code = HTTP_200 + + try: + self.get_out_string(p_ctx) + + 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) + + + 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: + # when there is more than one return type, the result is + # encapsulated inside a list. when there's just one, the result + # is returned in a non-encapsulated form. the apply_mtom always + # expects the objects to be inside an iterable, hence the + # following test. + out_type_info = p_ctx.descriptor.out_message._type_info + if len(out_type_info) == 1: + 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, + ) + + 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'] + else: + 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])) + except TypeError: + pass + + 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)) + + try: + process_contexts(self, others, p_ctx, error=None) + except Exception as e: + # Report but ignore any exceptions from auxiliary methods. + logger.exception(e) + + return retval + + def __finalize(self, p_ctx): + p_ctx.close() + self.event_manager.fire_event('wsgi_close', p_ctx) + + return () + + def __reconstruct_wsgi_request(self, http_env): + """Reconstruct http payload using information in the http header.""" + + content_type = http_env.get("CONTENT_TYPE") + charset = None + if content_type is not None: + # fyi, here's what the parse_header function returns: + # >>> import cgi; cgi.parse_header("text/xml; charset=utf-8") + # ('text/xml', {'charset': 'utf-8'}) + content_type = cgi.parse_header(content_type) + 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') + + length = str(http_env.get('CONTENT_LENGTH', self.max_content_length)) + if len(length) == 0: + length = 0 + else: + length = int(length) + + if length > self.max_content_length: + raise RequestTooLongError() + bytes_read = 0 + + while bytes_read < length: + bytes_to_read = min(self.block_length, length - bytes_read) + + if bytes_to_read + bytes_read > self.max_content_length: + raise RequestTooLongError() + + data = istream.read(bytes_to_read) + if data is None or len(data) == 0: + break + + bytes_read += len(data) + + yield data + + def decompose_incoming_envelope(self, prot, ctx, message): + """This function is only called by the HttpRpc protocol to have the wsgi + environment parsed into ``ctx.in_body_doc`` and ``ctx.in_header_doc``. + """ + + params = {} + wsgi_env = ctx.in_document + + if self.has_patterns: + # http://legacy.python.org/dev/peps/pep-0333/#url-reconstruction + domain = wsgi_env.get('HTTP_HOST', None) + if domain is None: + domain = wsgi_env['SERVER_NAME'] + else: + domain = domain.partition(':')[0] # strip port info + + 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]) + + 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']) + + 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) + + 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, []) + val.extend(v) + ctx.in_body_doc[k] = val + + for k, v in files.items(): + val = ctx.in_body_doc.get(k, []) + + mime_type = v.headers.get('Content-Type', + 'application/octet-stream') + + path = getattr(v.stream, 'name', None) + if path is None: + 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)) + + ctx.in_body_doc[k] = val + + for k, v in ctx.in_body_doc.items(): + if v == ['']: + ctx.in_body_doc[k] = [None] diff --git a/pym/calculate/contrib/spyne/server/wsgi.pyc b/pym/calculate/contrib/spyne/server/wsgi.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8c7a652c716369a071030035062ffcb7eb1a6a53 GIT binary patch literal 19303 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 ZAqQVa>#Zwq^^WI{=KJz}2cJ2Z|6f7|`au8y literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/server/zeromq.py b/pym/calculate/contrib/spyne/server/zeromq.py new file mode 100644 index 0000000..f897d55 --- /dev/null +++ b/pym/calculate/contrib/spyne/server/zeromq.py @@ -0,0 +1,164 @@ +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.server.zeromq`` module contains a server implementation that +uses ZeroMQ (zmq.REP) as transport. +""" +import threading + +import zmq + +from spyne.auxproc import process_contexts +from spyne.context import MethodContext +from spyne.server import ServerBase + + +class ZmqMethodContext(MethodContext): + def __init__(self, app): + super(ZmqMethodContext, self).__init__(app, MethodContext.SERVER) + self.transport.type = 'zmq' + + +class ZeroMQServer(ServerBase): + """The ZeroMQ server transport.""" + 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: + raise ValueError("ctx should be the same as socket.context") + super(ZeroMQServer, self).__init__(app) + + self.app_url = app_url + self.wsdl_url = wsdl_url + + if ctx: + self.ctx = ctx + elif socket: + self.ctx = socket.context + else: + self.ctx = zmq.Context() + + if socket: + self.zmq_socket = socket + else: + self.zmq_socket = self.ctx.socket(zmq.REP) + self.zmq_socket.bind(app_url) + + 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 serve_forever(self): + """Runs the ZeroMQ server.""" + + while True: + error = None + + initial_ctx = ZmqMethodContext(self) + initial_ctx.in_string = [self.zmq_socket.recv()] + + contexts = self.generate_contexts(initial_ctx) + p_ctx, others = contexts[0], contexts[1:] + + # TODO: Rate limiting + p_ctx.active = True + + if p_ctx.in_error: + p_ctx.out_object = p_ctx.in_error + error = p_ctx.in_error + + else: + self.get_in_object(p_ctx) + + if p_ctx.in_error: + p_ctx.out_object = p_ctx.in_error + error = p_ctx.in_error + else: + self.get_out_object(p_ctx) + if p_ctx.out_error: + p_ctx.out_object = p_ctx.out_error + error = p_ctx.out_error + + self.get_out_string(p_ctx) + + process_contexts(self, others, error) + + self.zmq_socket.send(b''.join(p_ctx.out_string)) + + p_ctx.close() + + +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""" + + 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: + raise ValueError("ctx should be the same as socket.context") + + self.app = app + + if ctx: + self.ctx = ctx + elif socket: + self.ctx = socket.context + else: + self.ctx = zmq.Context() + + if socket: + self.frontend = socket + else: + 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) + self.pool = [] + self.background_jobs = [] + for i in range(pool_size): + worker, job = self.create_worker(i, be_url) + self.pool.append(worker) + self.background_jobs.append(job) + + self.backend = self.ctx.socket(zmq.DEALER) + self.backend.bind(be_url) + + def create_worker(self, i, be_url): + socket = self.ctx.socket(zmq.REP) + socket.connect(be_url) + worker = ZeroMQServer(self.app, be_url, socket=socket) + job = threading.Thread(target=worker.serve_forever) + job.daemon = True + return worker, job + + def serve_forever(self): + """Runs the ZeroMQ server.""" + + for job in self.background_jobs: + job.start() + + zmq.device(zmq.QUEUE, self.frontend, self.backend) + + # We never get here... + self.frontend.close() + self.backend.close() diff --git a/pym/calculate/contrib/spyne/server/zeromq.pyc b/pym/calculate/contrib/spyne/server/zeromq.pyc new file mode 100644 index 0000000000000000000000000000000000000000..01186b68e2eb20b0ff408236b478965811e56054 GIT binary patch literal 5503 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/service.py b/pym/calculate/contrib/spyne/service.py new file mode 100644 index 0000000..5b02c3a --- /dev/null +++ b/pym/calculate/contrib/spyne/service.py @@ -0,0 +1,251 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +""" +This module contains the :class:`Service` class and its helper objects. +""" + +import logging +logger = logging.getLogger(__name__) + +from spyne.util.six.moves.collections_abc import Sequence + +from spyne.evmgr import EventManager +from spyne.util import six +from spyne.util.oset import oset + + +class ServiceBaseMeta(type): + """Adds event managers.""" + + 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)) + + def __get_base_event_handlers(self, cls_bases): + handlers = {} + + for base in cls_bases: + evmgr = getattr(base, 'event_manager', None) + if evmgr is None: + continue + + for k, v in evmgr.handlers.items(): + handler = handlers.get(k, oset()) + for h in v: + handler.add(h) + handlers[k] = handler + + return handlers + +class ServiceMeta(ServiceBaseMeta): + """Creates the :class:`spyne.MethodDescriptor` objects by iterating over + tagged methods. + """ + + def __init__(self, cls_name, cls_bases, cls_dict): + super(ServiceMeta, self).__init__(cls_name, cls_bases, cls_dict) + + self.__has_aux_methods = self.__aux__ is not None + has_nonaux_methods = None + + for k, v in cls_dict.items(): + if not hasattr(v, '_is_rpc'): + continue + + descriptor = v(_default_function_name=k, _service_class=self) + + # these two lines are needed for staticmethod wrapping to work + setattr(self, k, staticmethod(descriptor.function)) + descriptor.reset_function(getattr(self, k)) + + try: + getattr(self, k).descriptor = descriptor + except AttributeError: + pass + # FIXME: this fails with builtins. Temporary hack while we + # investigate whether we really need this or not + + self.public_methods[k] = descriptor + if descriptor.aux is None and self.__aux__ is None: + has_nonaux_methods = True + else: + 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.") + + 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): + __in_header__ = None + """The incoming header object that the methods under this service definition + accept.""" + + __out_header__ = None + """The outgoing header object that the methods under this service definition + accept.""" + + __service_name__ = None + """The name of this service definition as exposed in the interface document. + Defaults to the class name.""" + + __service_module__ = None + """This is used for internal idenfitication of the service class, + to override the ``__module__`` attribute.""" + + __port_types__ = () + """WSDL-Specific portType mappings""" + + __aux__ = None + """The auxiliary method type. When set, the ``aux`` property of every method + defined under this service is set to this value. The _aux flag in the @srpc + decorator overrides this.""" + + @classmethod + def get_service_class_name(cls): + return cls.__name__ + + @classmethod + def get_service_name(cls): + if cls.__service_name__ is None: + return cls.__name__ + else: + return cls.__service_name__ + + @classmethod + def get_service_module(cls): + if cls.__service_module__ is None: + return cls.__module__ + else: + return cls.__service_module__ + + @classmethod + def get_internal_key(cls): + return "%s.%s" % (cls.get_service_module(), cls.get_service_name()) + + @classmethod + def get_port_types(cls): + return cls.__port_types__ + + @classmethod + def _has_callbacks(cls): + """Determines if this service definition has callback methods or not.""" + + for method in cls.public_methods.values(): + if method.is_callback: + return True + + return False + + @classmethod + def get_context(cls): + """Returns a user defined context. Override this in your ServiceBase + subclass to customize context generation.""" + return None + + @classmethod + def call_wrapper(cls, ctx, args=None): + """Called in place of the original method call. You can override this to + do your own exception handling. + + :param ctx: The method context. + + The overriding function must call this function by convention. + """ + + if ctx.function is not None: + if args is None: + args = ctx.in_object + + assert not isinstance(args, six.string_types) + + # python3 wants a proper sequence as *args + if not isinstance(args, Sequence): + args = tuple(args) + + if not ctx.descriptor.no_ctx: + args = (ctx,) + tuple(args) + + return ctx.function(*args) + + @classmethod + def initialize(cls, app): + pass + + +@six.add_metaclass(ServiceMeta) +class Service(ServiceBaseBase): + """The ``Service`` class is the base class for all service definitions. + + The convention is to have public methods defined under a subclass of this + class along with common properties of public methods like header classes or + auxiliary processors. The :func:`spyne.decorator.srpc` decorator or its + wrappers should be used to flag public methods. + + This class is designed to be subclassed just once. You're supposed to + combine Service subclasses in order to get the public method mix you + want. + + It is a natural abstract base class, because it's of no use without any + method definitions, hence the 'Base' suffix in the name. + + This class supports the following events: + * ``method_call`` + Called right before the service method is executed + + * ``method_return_object`` + Called right after the service method is executed + + * ``method_exception_object`` + Called when an exception occurred in a service method, before the + exception is serialized. + + * ``method_accept_document`` + Called by the transport right after the incoming stream is parsed to + the incoming protocol's document type. + + * ``method_return_document`` + Called by the transport right after the outgoing object is + serialized to the outgoing protocol's document type. + + * ``method_exception_document`` + Called by the transport right before the outgoing exception object + is serialized to the outgoing protocol's document type. + + * ``method_return_string`` + Called by the transport right before passing the return string to + the client. + + * ``method_exception_string`` + Called by the transport right before passing the exception string to + the client. + """ + + +# FIXME: To be deleted in Spyne 3 +ServiceBase = Service diff --git a/pym/calculate/contrib/spyne/service.pyc b/pym/calculate/contrib/spyne/service.pyc new file mode 100644 index 0000000000000000000000000000000000000000..68c46cb6d1787f0843bfd5db838fe3d997bda857 GIT binary patch literal 8425 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 SO&_7<^=t0)_Py;|-}? double because sqla doesn't + # 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.Binary: ByteArray, + 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, +} + + +# this needs to be called whenever a new column is instantiated. +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 + else: + col.nullable = False + + if subcls.Attributes.db_default is not None: + if col is None: + col_kwargs['default'] = subcls.Attributes.db_default + else: + col.default = subcls.Attributes.db_default + + +def _get_sqlalchemy_type(cls): + db_type = cls.Attributes.db_type + if db_type is not None: + return db_type + + # must be above Unicode, because Ltree is Unicode's subclass + if issubclass(cls, Ltree): + return PGLTree + + # must be above Unicode, because Ip*Address is Unicode's subclass + if issubclass(cls, (IpAddress, Ipv4Address, Ipv6Address)): + return PGInet + + # must be above Unicode, because Uuid is Unicode's subclass + if issubclass(cls, Uuid): + return PGUuid(as_uuid=True) + + # must be above Unicode, because Point is Unicode's subclass + if issubclass(cls, Point): + return PGGeometry("POINT", dimension=cls.Attributes.dim) + + # must be above Unicode, because Line is Unicode's subclass + if issubclass(cls, Line): + return PGGeometry("LINESTRING", dimension=cls.Attributes.dim) + + # must be above Unicode, because Polygon is Unicode's subclass + if issubclass(cls, Polygon): + return PGGeometry("POLYGON", dimension=cls.Attributes.dim) + + # must be above Unicode, because MultiPoint is Unicode's subclass + if issubclass(cls, MultiPoint): + return PGGeometry("MULTIPOINT", dimension=cls.Attributes.dim) + + # must be above Unicode, because MultiLine is Unicode's subclass + if issubclass(cls, MultiLine): + return PGGeometry("MULTILINESTRING", dimension=cls.Attributes.dim) + + # must be above Unicode, because MultiPolygon is Unicode's subclass + if issubclass(cls, MultiPolygon): + return PGGeometry("MULTIPOLYGON", dimension=cls.Attributes.dim) + + # 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 + 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 + return sqlalchemy.UnicodeText + else: + return sqlalchemy.Unicode(cls.Attributes.max_len) + + if issubclass(cls, EnumBase): + return sqlalchemy.Enum(*cls.__values__, name=cls.__type_name__) + + if issubclass(cls, AnyXml): + return PGXml + + if issubclass(cls, AnyHtml): + return PGHtml + + if issubclass(cls, (Any, AnyDict)): + sa = cls.Attributes.store_as + if sa is None: + return None + if isinstance(sa, c_json): + return PGJson + if isinstance(sa, c_jsonb): + return PGJsonB + raise NotImplementedError(dict(cls=cls, store_as=sa)) + + if issubclass(cls, ByteArray): + return sqlalchemy.LargeBinary + + if issubclass(cls, (Integer64, UnsignedInteger64)): + return sqlalchemy.BigInteger + + if issubclass(cls, (Integer32, UnsignedInteger32)): + return sqlalchemy.Integer + + if issubclass(cls, (Integer16, UnsignedInteger16)): + return sqlalchemy.SmallInteger + + if issubclass(cls, (Integer8, UnsignedInteger8)): + return sqlalchemy.SmallInteger + + if issubclass(cls, Float): + return FLOAT + + if issubclass(cls, Double): + return DOUBLE_PRECISION + + if issubclass(cls, (Integer, UnsignedInteger)): + return sqlalchemy.DECIMAL + + if issubclass(cls, Decimal): + return sqlalchemy.DECIMAL + + if issubclass(cls, Boolean): + if cls.Attributes.store_as is bool: + return sqlalchemy.Boolean + if cls.Attributes.store_as is int: + return sqlalchemy.SmallInteger + + raise ValueError("Boolean.store_as has invalid value %r" % + cls.Attributes.store_as) + + if issubclass(cls, Date): + return sqlalchemy.Date + + if issubclass(cls, DateTime): + if cls.Attributes.timezone is None: + if cls.Attributes.as_timezone is None: + return sqlalchemy.DateTime(timezone=True) + else: + return sqlalchemy.DateTime(timezone=False) + else: + return sqlalchemy.DateTime(timezone=cls.Attributes.timezone) + + if issubclass(cls, Time): + return sqlalchemy.Time + + if issubclass(cls, Duration): + return sqlalchemy.dialects.postgresql.base.INTERVAL + + if issubclass(cls, XmlModifier): + retval = _get_sqlalchemy_type(cls.type) + return retval + + +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 + + 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_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') + 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 " \ + "column name for the object itself." + + fk = ForeignKey( + '%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, + ) + + 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): + """Gets the parent class and returns a column that points to the primary key + of the parent. + """ + + assert cls.Attributes.table_name is not None, "%r has no table name." % cls + 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_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]) + + # 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) + 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): + """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) + left_col.primary_key = right_col.primary_key = True + return left_col, right_col + + +class _FakeTable(object): + def __init__(self, name): + self.name = name + self.c = {} + self.columns = [] + self.indexes = [] + + def append_column(self, col): + self.columns.append(col) + self.c[col.name] = col + + +def _gen_index_info(table, col, k, v): + """ + :param table: sqla table + :param col: sqla col + :param k: field name (not necessarily == k) + :param v: spyne type + """ + + unique = v.Attributes.unique + index = v.Attributes.index + if unique and not index: + index = True + + try: + index_name, index_method = index + + except (TypeError, ValueError): + index_name = "%s_%s%s" % (table.name, k, '_unique' if unique else '') + index_method = index + + if index in (False, None): + return + + 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) + + if isinstance(table, _FakeTable): + table.indexes.append(index_args) + + else: + indexes = dict([(idx.name, idx) for idx in col.table.indexes]) + existing_idx = indexes.get(index_name, None) + if existing_idx is None: + Index(*index_args[0], **index_args[1]) + + else: + 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') + + assert existing_val == index_method, \ + "Indexing methods differ between existing and current index " \ + "directives. Existing: {!r}, New: {!r}".format( + 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) + + if base_class is None: + for b in cls_bases: + if getattr(b, '_type_info', None) is not None and b.__mixin__: + base_class = b + + if base_class is not None: + base_table_name = base_class.Attributes.table_name + if base_table_name is not None: + if base_table_name == table_name: + inheritance = _SINGLE + else: + inheritance = _JOINED + raise NotImplementedError("Joined table inheritance is not yet " + "implemented.") + + # check whether the base classes are already mapped + base_mapper = None + if base_class is not None: + base_mapper = base_class.Attributes.sqla_mapper + + if base_mapper is None: + for b in cls_bases: + bm = _mapper_registry.get(b, None) + if bm is not None: + assert base_mapper is None, "There can be only one base mapper." + base_mapper = bm + inheritance = _SINGLE + + return inheritance, base_class, base_mapper, inc + + +def _check_table(cls): + table_name = cls.Attributes.table_name + metadata = cls.Attributes.sqla_metadata + + # check whether the object already has a table + table = None + if table_name in metadata.tables: + table = metadata.tables[table_name] + else: + # We need FakeTable because table_args can contain all sorts of stuff + # that can require a fully-constructed table, and we don't have that + # information here yet. + table = _FakeTable(table_name) + + return table + + +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) + + if 'name' in col_kwargs: + colname = col_kwargs.pop('name') + else: + colname = subname + + if not subcls.Attributes.exc_db: + if colname in table.c: + col = table.c[colname] + + else: + col = Column(colname, sqla_type, *col_args, **col_kwargs) + table.append_column(col) + _gen_index_info(table, col, subname, subcls) + + if not subcls.Attributes.exc_mapper: + props[subname] = col + + elif mp is not None: + props[subname] = mp + + +def _gen_array_m2m(cls, props, subname, arrser, storage): + """Generates a relational many-to-many array. + + :param cls: The class that owns the field + :param props: SQLAlchemy Mapper properties + :param subname: Field name + :param arrser: Array serializer, ie the __orig__ of the class inside the + Array object + :param storage: The storage configuration object passed to the store_as + attribute. + """ + + 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) + + storage.left = col_own.key + storage.right = col_child.key + + # 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]) + else: + rel_table_name = storage.multi + + if rel_table_name in metadata.tables: + rel_t = metadata.tables[rel_table_name] + + col_own_existing = rel_t.c.get(col_own.key, None) + assert col_own_existing is not None + if col_own_existing is not None: + assert col_own.type.__class__ == col_own_existing.type.__class__ + + col_child_existing = rel_t.c.get(col_child.key, None) + if col_child_existing is None: + rel_t.append_column(col_child) + + else: + assert col_child.type.__class__ == col_child_existing.type.__class__ + + else: + rel_t = Table(rel_table_name, metadata, *(col_own, col_child)) + + own_t = cls.Attributes.sqla_table + + rel_kwargs = dict( + lazy=storage.lazy, + backref=storage.backref, + cascade=storage.cascade, + order_by=storage.order_by, + back_populates=storage.back_populates, + ) + + if storage.explicit_join: + # Specify primaryjoin and secondaryjoin when requested. + # There are special cases when sqlalchemy can't figure it out by itself. + # this is where we help it when we can. + # e.g.: http://sqlalchemy.readthedocs.org/en/rel_1_0/orm/join_conditions.html#self-referential-many-to-many-relationship + + 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 = 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]), + )) + + if storage.single_parent is not None: + rel_kwargs['single_parent'] = storage.single_parent + + props[subname] = relationship(arrser, **rel_kwargs) + + else: + rel_kwargs.update(dict( + secondary=rel_t, + )) + + if storage.single_parent is not None: + rel_kwargs['single_parent'] = storage.single_parent + + props[subname] = relationship(arrser, **rel_kwargs) + + +def _gen_array_simple(cls, props, subname, arrser_cust, storage): + """Generate an array of simple objects. + + :param cls: The class that owns this field + :param props: SQLAlchemy Mapper properties + :param subname: Field name + :param arrser_cust: Array serializer, ie the class itself inside the Array + object + :param storage: The storage configuration object passed to the store_as + """ + + table_name = cls.Attributes.table_name + 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, + deferrable=storage.fk_left_deferrable, + initially=storage.fk_left_initially) + + 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 + + # get right(data) column info + child_right_col_type = _get_sqlalchemy_type(arrser_cust) + child_right_col_name = storage.right # this is the data column + if child_right_col_name is None: + child_right_col_name = subname + + # get table name + child_table_name = arrser_cust.Attributes.table_name + if child_table_name is None: + 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__) + + 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__) + else: + # Table exists but our own foreign key doesn't. + child_left_col = next(_gen_col) + _sp_attrs_to_sqla_constraints(cls, arrser_cust, col=child_left_col) + child_t.append_column(child_left_col) + + else: + # table does not exist, generate table + child_right_col = Column(child_right_col_name, child_right_col_type) + _sp_attrs_to_sqla_constraints(cls, arrser_cust, col=child_right_col) + + 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_left_col, + child_right_col, + ) + _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. + + def _i(self, *args): + setattr(self, child_right_col_name, args[0]) + + cls_ = type("_" + cls_name, (object,), {'__init__': _i}) + mapper(cls_, child_t) + props["_" + subname] = relationship(cls_) + + # generate association proxy + 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, + deferrable=storage.fk_right_deferrable, + 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. + + 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) + + # if the column is already there, the decision about whether + # it should be in child's mapper or not should also have been + # made. + # + # so, not adding the child column to to child mapper + # here. + col = child_t.c[storage.right] + + else: + col = next(_gen_col) + + _sp_attrs_to_sqla_constraints(cls, arrser_cust, col=col) + + 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, + foreign_keys=[col], + back_populates=storage.back_populates, + ) + + if storage.single_parent is not None: + rel_kwargs['single_parent'] = storage.single_parent + + props[subname] = relationship(arrser, **rel_kwargs) + + +def _is_array(v): + return v.Attributes.max_occurs > 1 or issubclass(v, Array) + + +def _add_array_to_complex(cls, props, subname, subcls, storage): + arrser_cust = subcls + if issubclass(subcls, Array): + arrser_cust, = subcls._type_info.values() + + arrser = arrser_cust + if arrser_cust.__orig__ is not None: + arrser = arrser_cust.__orig__ + + if storage.multi != False: # many to many + _gen_array_m2m(cls, props, subname, arrser, storage) + + elif issubclass(arrser, SimpleModel): # one to many simple type + _gen_array_simple(cls, props, subname, arrser_cust, storage) + + else: # one to many complex type + _gen_array_o2m(cls, props, subname, arrser, arrser_cust, storage) + + +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 + real_v = subcls + 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 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, + deferrable=storage.fk_left_deferrable, + 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: + col.nullable = False + else: + table.append_column(col) + + rel_kwargs = dict( + lazy=storage.lazy, + backref=storage.backref, + order_by=storage.order_by, + back_populates=storage.back_populates, + ) + + if storage.single_parent is not None: + 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]] + + rel = relationship(real_v, uselist=False, foreign_keys=[col], + **rel_kwargs) + + _gen_index_info(table, col, subname, subcls) + + props[subname] = rel + props[col.name] = col + + +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) + + +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) + col = Column(colname, t, **col_kwargs) + + props[subname] = col + if not subname in table.c: + 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') + else: + colname = subname + + if colname in table.c: + col = table.c[colname] + + else: + t = PGObjectJson(subcls, ignore_wrappers=storage.ignore_wrappers, + complex_as=storage.complex_as, dbt=dbt) + col = Column(colname, t, **col_kwargs) + + props[subname] = col + if not subname in table.c: + table.append_column(col) + + +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) + 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) + if isinstance(storage, c_xml): + 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') + if isinstance(storage, c_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) + + if storage is None: + return + + raise ValueError(storage) + + +def _convert_fake_table(cls, table): + metadata = cls.Attributes.sqla_metadata + table_name = cls.Attributes.table_name + + _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) + + for index_args, index_kwargs in _table.indexes: + Index(*index_args, **index_kwargs) + + return table + + +def _gen_mapper(cls, props, table, cls_bases): + """Generate SQLAlchemy mapper from Spyne definition data. + + :param cls: La Class. + :param props: Dict of properties for SQLAlchemt'y Mapper call. + :param table: A Table instance. Not a `_FakeTable` or anything. + :param cls_bases: Sequence of class 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) + if _props is None: + mapper_kwargs['properties'] = props + else: + props.update(_props) + mapper_kwargs['properties'] = props + + po = mapper_kwargs.get('polymorphic_on', None) + if po is not None: + if not isinstance(po, Column): + 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'] + + if base_mapper is not None: + mapper_kwargs['inherits'] = base_mapper + + if inheritance is not _SINGLE: + mapper_args = (table,) + mapper_args + + cls_mapper = mapper(cls, *mapper_args, **mapper_kwargs) + + def on_load(target, context): + d = target.__dict__ + + for k, v in cls.get_flat_type_info(cls).items(): + if not k in d: + if isclass(v) and issubclass(v, ComplexModelBase): + pass + else: + d[k] = None + + 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) + col_args, col_kwargs = sanitize_args(subcls.Attributes.sqla_column_args) + _sp_attrs_to_sqla_constraints(cls, subcls, col_kwargs) + + if isinstance(storage, HybridFileStore): + if subname in table.c: + col = table.c[subname] + + else: + assert isabs(storage.store) + #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') + + else: + raise NotImplementedError(storage.db_format) + + col = Column(subname, t, **col_kwargs) + + props[subname] = col + if not subname in table.c: + table.append_column(col) + + else: + raise NotImplementedError(storage) + + +def add_column(cls, subname, subcls): + """Add field to the given Spyne object also mapped as a SQLAlchemy object + to a SQLAlchemy table + + :param cls: The class to add the column to. + :param subname: The column name + :param subcls: The column type, a ModelBase subclass. + """ + + table = cls.__table__ + mapper_props = {} + + # Add to table + sqla_type = _get_sqlalchemy_type(subcls) + if sqla_type is None: # complex model + _add_complex_type(cls, mapper_props, table, subname, subcls) + else: + _add_simple_type(cls, mapper_props, table, subname, subcls, sqla_type) + + # Add to mapper + sqla_mapper = cls.Attributes.sqla_mapper + for subname, subcls in mapper_props.items(): + if not sqla_mapper.has_property(subname): + sqla_mapper.add_property(subname, subcls) + + +def _parent_mapper_has_property(cls, cls_bases, k): + if len(cls_bases) == 0 and cls.__orig__ is cls_bases[0]: + return False + + for b in cls_bases: + if not hasattr(b, 'Attributes'): + continue + + mapper = b.Attributes.sqla_mapper + if mapper is not None and mapper.has_property(k): + # print(" Skipping mapping field", "%s.%s" % (cls.__name__, k), + # "because parent mapper from", b.__name__, "already has it") + return True + + # print("NOT skipping mapping field", "%s.%s" % (cls.__name__, k)) + return False + + +def gen_sqla_info(cls, cls_bases=()): + """Return SQLAlchemy table object corresponding to the passed Spyne object. + Also maps given class to the returned table. + """ + + table = _check_table(cls) + mapper_props = {} + + ancestors = cls.ancestors() + if len(ancestors) > 0: + anc_mapper = ancestors[0].Attributes.sqla_mapper + if anc_mapper is None: + # no mapper in parent, use all fields + fields = cls.get_flat_type_info(cls).items() + + elif anc_mapper.concrete: + # there is mapper in parent and it's concrete, so use all fields + fields = cls.get_flat_type_info(cls).items() + + else: + # there is a mapper in parent and it's not concrete, so parent + # columns are already mapped, so use only own fields. + fields = cls._type_info.items() + + else: + # when no parents, use all fields anyway. + assert set(cls._type_info.items()) == \ + set(cls.get_flat_type_info(cls).items()) + + fields = cls.get_flat_type_info(cls).items() + + for k, v in fields: + if _parent_mapper_has_property(cls, cls_bases, k): + continue + + t = _get_sqlalchemy_type(v) + + if t is None: # complex model + 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)) + else: + _add_complex_type(cls, mapper_props, table, k, v) + else: + _add_simple_type(cls, mapper_props, table, k, v, t) + + if isinstance(table, _FakeTable): + table = _convert_fake_table(cls, table) + + cls_mapper = _gen_mapper(cls, mapper_props, table, cls_bases) + + cls.__tablename__ = cls.Attributes.table_name + cls.Attributes.sqla_mapper = cls.__mapper__ = cls_mapper + cls.Attributes.sqla_table = cls.__table__ = table + + return table + + +def _get_spyne_type(v): + """Map sqlalchemy types to spyne types.""" + + cust = {} + if v.primary_key: + cust['primary_key'] = True + + if not v.nullable: + 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 + 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)): + return Unicode(v.type.length, **cust) + + if isinstance(v.type, sqlalchemy.Numeric): + return Decimal(v.type.precision, v.type.scale, **cust) + + if isinstance(v.type, PGXml): + if len(cust) > 0: + return AnyXml(**cust) + else: + return AnyXml + + if isinstance(v.type, PGHtml): + if len(cust) > 0: + return AnyHtml(**cust) + else: + return AnyHtml + + if type(v.type) in _sq2sp_type_map: + retval = _sq2sp_type_map[type(v.type)] + if len(cust) > 0: + return retval.customize(**cust) + else: + return retval + + if isinstance(v.type, (PGObjectJson, PGObjectXml)): + retval = v.type.cls + if len(cust) > 0: + return retval.customize(**cust) + else: + return retval + + if isinstance(v.type, PGFileJson): + retval = v.FileData + if len(cust) > 0: + return v.FileData.customize(**cust) + else: + return retval + + raise Exception("Spyne type was not found. Probably _sq2sp_type_map " + "needs a new entry. %r" % v) + + +def gen_spyne_info(cls): + table = cls.Attributes.sqla_table + _type_info = cls._type_info + mapper_args, mapper_kwargs = sanitize_args(cls.Attributes.sqla_mapper_args) + + if len(_type_info) == 0: + for c in table.c: + _type_info[c.name] = _get_spyne_type(c) + else: + mapper_kwargs['include_properties'] = _type_info.keys() + + # Map the table to the object + cls_mapper = mapper(cls, table, *mapper_args, **mapper_kwargs) + + cls.Attributes.table_name = cls.__tablename__ = table.name + cls.Attributes.sqla_mapper = cls.__mapper__ = cls_mapper + + +def get_pk_columns(cls): + """Return primary key fields of a Spyne object.""" + + 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): + retval.append((k, v)) + + return tuple(retval) if len(retval) > 0 else None diff --git a/pym/calculate/contrib/spyne/store/relational/_base.pyc b/pym/calculate/contrib/spyne/store/relational/_base.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cb0922272e67bde147028db2602ab10bad76115d GIT binary patch literal 30824 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/store/relational/document.py b/pym/calculate/contrib/spyne/store/relational/document.py new file mode 100644 index 0000000..0383f7a --- /dev/null +++ b/pym/calculate/contrib/spyne/store/relational/document.py @@ -0,0 +1,353 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import logging +logger = logging.getLogger(__name__) + +import os +import json +import shutil + +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 spyne.util.xml import get_object_as_xml, get_xml_as_object + +except ImportError as _import_error: + etree = None + 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 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'): + super(PGXml, self).__init__() + self.xml_declaration = xml_declaration + self.pretty_print = pretty_print + self.encoding = encoding + + def get_col_spec(self, **_): + return "xml" + + def bind_processor(self, dialect): + def process(value): + if value is None or \ + isinstance(value, (six.text_type, six.binary_type)): + 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 process + + def result_processor(self, dialect, col_type): + def process(value): + if value is not None: + return etree.fromstring(value) + else: + return value + return process + +sqlalchemy.dialects.postgresql.base.ischema_names['xml'] = PGXml + + +class PGHtml(UserDefinedType): + def __init__(self, pretty_print=False, encoding='UTF-8'): + super(PGHtml, self).__init__() + + self.pretty_print = pretty_print + self.encoding = encoding + + def get_col_spec(self, **_): + return "text" + + def bind_processor(self, dialect): + def process(value): + if isinstance(value, (six.text_type, six.binary_type)) \ + or value is None: + return value + else: + return html.tostring(value, pretty_print=self.pretty_print, + encoding=self.encoding) + return process + + def result_processor(self, dialect, col_type): + def process(value): + if value is not None and len(value) > 0: + return html.fromstring(value) + else: + return None + return process + + +class PGJson(UserDefinedType): + def __init__(self, encoding='UTF-8'): + self.encoding = encoding + + def get_col_spec(self, **_): + return "json" + + def bind_processor(self, dialect): + def process(value): + if isinstance(value, (text_type, binary_type)) or value is None: + return value + else: + if six.PY2: + return json.dumps(value, encoding=self.encoding) + else: + return json.dumps(value) + return process + + def result_processor(self, dialect, col_type): + def process(value): + if isinstance(value, (text_type, binary_type)): + return json.loads(value) + else: + return value + return process + +sqlalchemy.dialects.postgresql.base.ischema_names['json'] = PGJson + + +class PGJsonB(PGJson): + def get_col_spec(self, **_): + return "jsonb" + + +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): + self.cls = cls + self.root_tag_name = root_tag_name + self.no_namespace = no_namespace + self.pretty_print = pretty_print + + def get_col_spec(self, **_): + return "xml" + + 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 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'): + 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 + self.get_object_as_json = get_object_as_json + self.get_dict_as_object = get_dict_as_object + + def get_col_spec(self, **_): + return self.dbt + + def bind_processor(self, dialect): + def process(value): + if value is not None: + try: + return self.get_object_as_json(value, self.cls, + ignore_wrappers=self.ignore_wrappers, + complex_as=self.complex_as, + ).decode(self.encoding) + + except Exception as e: + logger.debug("Failed to serialize %r to json: %r", value, e) + raise + + return process + + def result_processor(self, dialect, col_type): + from spyne.util.dictdoc import JsonDocument + + def process(value): + if value is None: + return None + + if isinstance(value, six.binary_type): + 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, + 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'): + if type is None: + type = FileData + + super(PGFileJson, self).__init__(type, ignore_wrappers=True, + complex_as=list, dbt=dbt) + self.store = store + + def bind_processor(self, dialect): + def process(value): + if value is not None: + if value.data is not None: + 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. '..')") + + with open(fp, 'wb') as file: + for d in value.data: + file.write(d) + + elif value.handle is not None: + 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. '..')") + + if isinstance(value.handle, (StringIO, BytesIO)): + 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: + out_file.write(data) + + elif value.path is not None: + in_file_path = value.path + + if not isfile(in_file_path): + logger.error("File path in %r not found" % value) + + if dirname(abspath(in_file_path)) != self.store: + dest = join(self.store, uuid1().get_hex()) + + if value.move: + shutil.move(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) + + value.path = basename(dest) + value.abspath = dest + + else: + 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, + ignore_wrappers=self.ignore_wrappers, + complex_as=self.complex_as, + ) + + return process + + def result_processor(self, dialect, col_type): + def process(value): + if value is None: + return None + + if isinstance(value, six.text_type): + value = json.loads(value) + + elif isinstance(value, six.binary_type): + 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.store = self.store + retval.abspath = path = join(self.store, retval.path) + retval.handle = None + retval.data = [b''] + + if not os.access(path, os.R_OK): + logger.error("File %r is not readable", path) + return retval + + 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,) + # FIXME: Where do we close this mmap? + + return retval + + return process diff --git a/pym/calculate/contrib/spyne/store/relational/document.pyc b/pym/calculate/contrib/spyne/store/relational/document.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9eb0f94515d33b799feccd72c33530e0b9742daa GIT binary patch literal 15162 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 xf35^C^*r`|C6`BR6bGDq zHE=TU324V00fIRRbp=Ny%u1M5a7@CyggFJrB`ipoS8zhYqJ#wnOA@9fEGjrDp$^Un zoTk7TReVbFoZ@4OPfMOvd|dGv$@7X&C_XEBLGhB}bCMSopHzHa^0eYpiZ6gO4ZGzT zOpE&iUu8@Uh&&oQ@I%+*aff7(yr^#Mm9unQN3*l}%J&4hJDXc^(CY3!7f5pneJV!f z{&xL<+d_^jO7INNO|G3nmsSQ%{1QJgO@&Kiw@gQ>f{vZ|UKzijOpcsgv_oF&k24Z9 z{P06(91V`&ps5_iQN?rXYb%woEt)}V*?3rqUBMSa%RaOkJg&rHyTuomjim?1(%NF! z#t{Z@G&;Nziy-2ah$dm+76OXuQBR4i zw)<|x>u%(ntG?B}pgtJ&jqY#i+QC9yQ!>_j^3GDk=5g#`sG03kL)AKwvoZ8?=;}%2 zYz?KHxxVbkI-Tg*9(p~pR401&hF*`X)`_0i=hqWci*{^9cGHT=E30=0uP{*cPL#b( zlx3>rE9eNSX7PK^^6Vz}+Xi-`Mz=sl3=e_0`Rf43wLI+LV(NhDX2L?vZ2aK9UHcqBQW|GVlnQ1aq')(sql.cast(other, PGArray(PGLTree))) + else: + return self.op('@>')(other) + + def descendant_of(self, other): + if isinstance(other, list): + return self.op('<@')(sql.cast(other, PGArray(PGLTree))) + else: + return self.op('<@')(other) + + def lquery(self, other): + if isinstance(other, list): + return self.op('?')(sql.cast(other, PGArray(PGLQuery))) + else: + return self.op('~')(other) + + def ltxtquery(self, other): + return self.op('@')(other) + + comparator_factory = Comparator + + __visit_name__ = 'LTREE' + + +class PGLQuery(UserDefinedType): + """Postresql `lquery` type.""" + + __visit_name__ = 'LQUERY' + + +class PGLTxtQuery(UserDefinedType): + """Postresql `ltxtquery` type.""" + + __visit_name__ = 'LTXTQUERY' + + +ischema_names['ltree'] = PGLTree +ischema_names['lquery'] = PGLQuery +ischema_names['ltxtquery'] = PGLTxtQuery + + +def visit_LTREE(self, type_, **kw): + return 'LTREE' + + +def visit_LQUERY(self, type_, **kw): + return 'LQUERY' + + +def visit_LTXTQUERY(self, type_, **kw): + return 'LTXTQUERY' + + +PGTypeCompiler.visit_LTREE = visit_LTREE +PGTypeCompiler.visit_LQUERY = visit_LQUERY +PGTypeCompiler.visit_LTXTQUERY = visit_LTXTQUERY diff --git a/pym/calculate/contrib/spyne/store/relational/simple.pyc b/pym/calculate/contrib/spyne/store/relational/simple.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b995782f98d48243e8d5e909fd3172dd397c335a GIT binary patch literal 4039 zcmd5dnpQwbDFt(htzJ}w6qQ^WMTjV*lLQg-u-WX6lWlixcV_~z zRPoaOE&d5Vfj52tobRkJp^5~3NYZuYWajL6&YbUDo&Rfc?9V@bKMbh%UwT zCaE!*tzC+zC@E8;OpeZz9;a}GUganprPoBSSm-o`CDN0m%hY84nDB`X8Z#7*3)i7= zV!)lHFx$)AsR4J6^bF}Dg=JdSvof3J8MB!;L(AbTwl?M|oRi4{h4V70ke(;)lE-vG zCQO;hoC<{tv|Ft(RMFr3R2eR^K+n90v&AScf_Bo0Vr{B9yq;tdnczexzSr^-ZR`|t zb~g9A9lf6IOtYOu=C3NXdSDAY+u#50Np|K0uh!eGz_+^PAH_Q3ma)g^^oedpEgj-G z>oSk85?LKUHg1M1eh)UzWW(-?tZfmow)MkWmDyCqP7C>#kMZm|EmDh9+LJ{o1_;wR?}2I$hpT)5pgd zziwyfLc$DuW@ccorm5dm@ZHQ?3p_JAZi?Hq?TJpW&_%{sIBpIv^4iVMa2Gf~ zIc4W=?kW*oUJ*pqGz(WVAhRGmNWqcSJjehxwSXlu$Q7c66clO`=vL^rEaSDrjLXDJ z-0{2zA~v_#nTfs?`rH2iO|lRN`O{OKcE#te1w6P_`~r7CUbzT0#ID3G?2QFZgG+8)2PH3iS3ycrM}@smQ|f9R29@csZ^dPdBXFOc6b_V&r|R5289f% zJ^;DJWa!2+yX@kiQ1(9MVMdv_PRYeba?sYE+Stha>LY%q7MV!y^1QGe@a>_VeBUBO zQDL$??lt{@^GH_;v*-Q7iP81|xN7Z?C+_g*Y3Jr{R@|I=AJ^p}&!E^Ku?&h$R_3_O za2B0>2U7IZ05A11zfqqsxoXX!<0=p7Q(VW*S>$-s_%kaR z;B5iGfhgpC0QwH!#{f~VwfEEBy9EPWdy~fy26P3|gbZU&>RX=q@P!MSJ9V4+nE|mY zOPlCj6k5rlWiLBe#e`WnNpPYn_HxaCs&IF3)9Y0Mi1kzuPxv1vu}o; z!#9R%Y*&%iCDn7s>&N)1(v=3r;>D0x(`UBUYs^yx-?MlAy&;VJSO?bBI)e_ncH|qa zkdhP(X;CxI9eKew6gtbSZG!L1kD8s$ef}Zv=6(2_8V~g5MzZ@w8{`*_--#63ScO(d zx-m(r3gM;*L4| L$(IW9aZ1iVP+(^X literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/store/relational/spatial.py b/pym/calculate/contrib/spyne/store/relational/spatial.py new file mode 100644 index 0000000..152362b --- /dev/null +++ b/pym/calculate/contrib/spyne/store/relational/spatial.py @@ -0,0 +1,84 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from sqlalchemy import sql +from sqlalchemy.ext.compiler import compiles +from sqlalchemy.sql.type_api import UserDefinedType + + +class PGGeometry(UserDefinedType): + """Geometry type for Postgis 2""" + + class PlainWkt: + pass + + class PlainWkb: + pass + + def __init__(self, geometry_type='GEOMETRY', srid=4326, dimension=2, + format='wkt'): + self.geometry_type = geometry_type.upper() + self.name = 'geometry' + self.srid = int(srid) + self.dimension = dimension + self.format = format + + if self.format == 'wkt': + self.format = PGGeometry.PlainWkt + elif self.format == 'wkb': + self.format = PGGeometry.PlainWkb + + def get_col_spec(self): + return '%s(%s,%d)' % (self.name, self.geometry_type, self.srid) + + def column_expression(self, col): + if self.format is PGGeometry.PlainWkb: + return sql.func.ST_AsBinary(col, type_=self) + if self.format is PGGeometry.PlainWkt: + return sql.func.ST_AsText(col, type_=self) + + 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) + + return process + + def bind_expression(self, bindvalue): + if self.format is PGGeometry.PlainWkt: + return sql.func.ST_GeomFromText(bindvalue, self.srid) + + +Geometry = PGGeometry + + +@compiles(PGGeometry) +def compile_geometry(type_, compiler, **kw): + return '%s(%s,%d)' % (type_.name, type_.geometry_type, type_.srid) + + +@compiles(PGGeometry, "sqlite") +def compile_geometry_sqlite(type_, compiler, **kw): + return "BLOB" diff --git a/pym/calculate/contrib/spyne/store/relational/spatial.pyc b/pym/calculate/contrib/spyne/store/relational/spatial.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2971cd4445d6f5873982b456d256159e0ee54fc7 GIT binary patch literal 3890 zcmcgvTW=dx5T5ngPTVFhK?re4Y5M?mqjgZ#2x)P=C+RxtU9;zy z)>8VE3iwm}6P|hEjUNEtH|tybfOsIbea3SxK4)gWZ)T7EzgExu`TK7_bY=YV@%<&5 zeF_ob<4GdY_hio#kNuJ)CF%RJ=NElnlCtzGvR6UBET$p{on+I9GxszFU z7~9P)N9T5uPMkhCa#N!j12vknh0)j#y3|V$`lB#RJAD&|>UbFTvuK#0TddNh6!v?F z=FsNNB;LRIQFAbIkFs>D@p03}&RidKx<{QuW1Ds`O3n4H#*GgfH*Q`ZjIg3%4iAg* zrgd3vnz>0jF3!?Uf?;T#q%jx;WgKvcC(*L1H}BB?e|0DzN`-TGlUdEzcAdd*X~+-9#1Cp1()@XRw6AI9 zXzy?^Fu7ZWHdz>wjE)4BOP`kr`Rd$z8s>vksVmY!c12`V^GX(`u8 ztgya}zT#gHhFl5I3a%Us)2=&_cqYFZ%% zF(2ev7m@oEs-;Qdt<2Jo;bOMfcOhmDT^Vz;rv;OtEc4PZ?;`yPE>WOK@CwDN6s$c( z8ooKzrU`lK1t_?TL%%?q`l=;*E)N)kqHwB4(@^$VYCDPPI@Lis=8$ey;6+?D4^G_! z#{h!s!^DMS?6Uk5j9Ff=NcxrXy0>1QRu*D-i}TkYfZ@MX7S7^Y_&kzY7+9v~9xUh; zm^$9{P!4#5x|3&p7KH+0=0Z^!Se5tVG+H>lX&Voos}8p@G=_fNo28mQhi8`@1vw0( ztQ&^2CuzW}4lYvg(ipr=@eah?KIkprN=Hav<4J_2>Qze@{0n}~TUn|3wQ6luq30Sh z_#3YKpPruFGuVL8=lJ-_pF2W*^mrD9#pJ;F_;7Mxx<^N8ij?#=guf@aK~H1B4AodL zD5&+52O_)M-`?LY%%6G~u;K;pK`hcQmdO|W3JXVAN5}59ifbeD9dn(e`^fZ1T4xBGE?Lq9A2IDO9K Sv%E>2_we>NZdCn?m45)62|gPD literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/store/relational/util.py b/pym/calculate/contrib/spyne/store/relational/util.py new file mode 100644 index 0000000..e30633f --- /dev/null +++ b/pym/calculate/contrib/spyne/store/relational/util.py @@ -0,0 +1,279 @@ +# +# retrieved from https://github.com/kvesteri/sqlalchemy-utils +# commit 99e1ea0eb288bc50ddb4a4aed5c50772d915ca73 +# +# Copyright (c) 2012, Konsta Vesterinen +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * The names of the contributors may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +import os +import cProfile + +from copy import copy + +from sqlalchemy.engine import Dialect, create_engine +from sqlalchemy.engine.url import make_url +from sqlalchemy.exc import OperationalError, ProgrammingError +from sqlalchemy.orm import object_session +from sqlalchemy.orm.exc import UnmappedInstanceError + + +def get_bind(obj): + """ + Return the bind for given SQLAlchemy Engine / Connection / declarative + model object. + :param obj: SQLAlchemy Engine / Connection / declarative model object + :: + from sqlalchemy_utils import get_bind + get_bind(session) # Connection object + get_bind(user) + """ + if hasattr(obj, 'bind'): + conn = obj.bind + else: + try: + conn = object_session(obj).bind + except UnmappedInstanceError: + conn = obj + + if not hasattr(conn, 'execute'): + raise TypeError( + 'This method accepts only Session, Engine, Connection and ' + 'declarative model objects.' + ) + return conn + + +def quote(mixed, ident): + """ + Conditionally quote an identifier. + :: + from sqlalchemy_utils import quote + engine = create_engine('sqlite:///:memory:') + quote(engine, 'order') + # '"order"' + quote(engine, 'some_other_identifier') + # 'some_other_identifier' + :param mixed: SQLAlchemy Session / Connection / Engine / Dialect object. + :param ident: identifier to conditionally quote + """ + if isinstance(mixed, Dialect): + dialect = mixed + else: + dialect = get_bind(mixed).dialect + return dialect.preparer(dialect).quote(ident) + + +def database_exists(url): + """Check if a database exists. + + :param url: A SQLAlchemy engine URL. + + Performs backend-specific testing to quickly determine if a database + exists on the server. :: + + database_exists('postgresql://postgres@localhost/name') #=> False + create_database('postgresql://postgres@localhost/name') + database_exists('postgresql://postgres@localhost/name') #=> True + + Supports checking against a constructed URL as well. :: + + engine = create_engine('postgresql://postgres@localhost/name') + database_exists(engine.url) #=> False + create_database(engine.url) + database_exists(engine.url) #=> True + + """ + + url = copy(make_url(url)) + database = url.database + 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': + 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) + return bool(engine.execute(text).scalar()) + + elif engine.dialect.name == 'sqlite': + return database == ':memory:' or os.path.exists(database) + + else: + text = 'SELECT 1' + try: + url.database = database + engine = create_engine(url) + engine.execute(text) + return True + + except (ProgrammingError, OperationalError): + return False + + +def create_database(url, encoding='utf8', psql_template='template1'): + """Issue the appropriate CREATE DATABASE statement. + + :param url: A SQLAlchemy engine URL. + :param encoding: The encoding to create the database as. + :param psql_template: + The name of the template from which to create the new database, + only supported by PostgreSQL driver. As per Postgresql docs, defaults to + "template1". + + To create a database, you can pass a simple URL that would have + been passed to ``create_engine``. :: + + create_database('postgresql://postgres@localhost/name') + + You may also pass the url from an existing engine. :: + + create_database(engine.url) + + Has full support for mysql, postgres, and sqlite. In theory, + other database engines should be supported. + """ + + url = copy(make_url(url)) + + database = url.database + + 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': + from psycopg2.extensions import 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) + ) + engine.execute(text) + + elif engine.dialect.name == 'mysql': + text = "CREATE DATABASE {0} CHARACTER SET = '{1}'".format( + quote(engine, database), + encoding + ) + engine.execute(text) + + elif engine.dialect.name == 'sqlite' and database != ':memory:': + open(database, 'w').close() + + else: + text = 'CREATE DATABASE {0}'.format(quote(engine, database)) + engine.execute(text) + + +def drop_database(url): + """Issue the appropriate DROP DATABASE statement. + + :param url: A SQLAlchemy engine URL. + + Works similar to the :ref:`create_database` method in that both url text + and a constructed url are accepted. :: + + drop_database('postgresql://postgres@localhost/name') + drop_database(engine.url) + + """ + + url = copy(make_url(url)) + + database = url.database + + 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:': + os.remove(url.database) + + 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' + ) + 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} + engine.execute(text) + + # Drop the database. + text = 'DROP DATABASE {0}'.format(quote(engine, database)) + engine.execute(text) + + else: + text = 'DROP DATABASE {0}'.format(quote(engine, database)) + engine.execute(text) + + +# https://zapier.com/engineering/profiling-python-boss/ +def do_cprofile(func): + def profiled_func(*args, **kwargs): + profile = cProfile.Profile() + try: + profile.enable() + result = func(*args, **kwargs) + profile.disable() + return result + finally: + profile.print_stats(sort='time') + + return profiled_func diff --git a/pym/calculate/contrib/spyne/store/relational/util.pyc b/pym/calculate/contrib/spyne/store/relational/util.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ada8c58880b26080b09322580a06ed3d7c0ebc8 GIT binary patch literal 7783 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/__init__.py b/pym/calculate/contrib/spyne/test/__init__.py new file mode 100644 index 0000000..51fda37 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/__init__.py @@ -0,0 +1,31 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +class FakeApp(object): + transport = 'transport' + tns = 'tns' + name = 'name' + services = [] + classes = () + +import logging +logging.basicConfig(level=logging.DEBUG) +logging.getLogger('spyne.util.appreg').setLevel(logging.INFO) + +from spyne.context import FakeContext diff --git a/pym/calculate/contrib/spyne/test/__init__.pyc b/pym/calculate/contrib/spyne/test/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05b99ac4ba5cc218a01d06fac96346b659434132 GIT binary patch literal 752 zcmcgp!EV$r5FIDG*>0f+RD{$YK)Gz97E~?>(E>$CRS~H;kW0uWQ{$~SvEtc^J(u6& zPx=Ym_yCx3fKR}dpJ&G7dC%kc=ics*yYHVH_%mYOU-I%xh86$;t`xKiz5(0Xt0WxE#8z@I0lNe1Ih1quW4KIbOhW=^^);S2 z_fLr8*eNgnn1NLYF(cPdP%NTdk z!^pbBR#i!`s%SSj>%QGsb_-!IB7smqQauhgra>RnHn#R2{aB3;Az1zcTlvNhxi!n< zr@7nGm%cm7p5@*UE?nJQ*BX89-L}KUQFizwJ3L;vEoWq?^%&2IIr6G9ouR7A+_sSV z4|#bJnW(?h{NiyzQx00ZLF*q#j+D+eWNcPDH=s`CDRhrPI{d2d2)|M)l_+88mn&>2 zP=trsUTf3oaA8?{)9{TeqXWz9H>V%phW=`#b56v8#?H{W2nbDncX9Tf_PFw>q!|ed a`IZ0Dt)S@n_>nI{*F@r@*?qOI4x-=baHfj@ literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interface/__init__.py b/pym/calculate/contrib/spyne/test/interface/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pym/calculate/contrib/spyne/test/interface/__init__.pyc b/pym/calculate/contrib/spyne/test/interface/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b1c7d0d3b8b86a4fabb2d0ea6ef2c94dd0bd562 GIT binary patch literal 178 zcmZSn%**xW&fbJ%1}I6aE4>E~o7nVIMp zRF-7q=Najl>lbI1r0NzVCTAz6rxxoM7gXk@>Kf@88tWOF=@wK1Rp_Orr$fZ`OHzwV r^fU8HQj5|OlT-EM<1_OzOXB18fTnQ(&9}+TPbtkwwF9}L1c(^`IzcNz literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interface/test_interface.py b/pym/calculate/contrib/spyne/test/interface/test_interface.py new file mode 100644 index 0000000..a47c7c5 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interface/test_interface.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +import unittest + +from spyne import Application, Service, rpc +from spyne.model import Array, ComplexModel, AnyXml, UnsignedLong, \ + UnsignedInteger16, Integer, DateTime, Unicode +from spyne.protocol.http import HttpRpc +from spyne.protocol.soap import Soap11 + + +class TestInterface(unittest.TestCase): + def test_imports(self): + import logging + logging.basicConfig(level=logging.DEBUG) + + class KeyValuePair(ComplexModel): + __namespace__ = "1" + key = Unicode + value = Unicode + + class Something(ComplexModel): + __namespace__ = "2" + d = DateTime + i = Integer + + class SomethingElse(ComplexModel): + __namespace__ = "3" + a = AnyXml + b = UnsignedLong + s = Something + + class BetterSomething(Something): + __namespace__ = "4" + k = UnsignedInteger16 + + class Service1(Service): + @rpc(SomethingElse, _returns=Array(KeyValuePair)) + def some_call(ctx, sth): + pass + + class Service2(Service): + @rpc(BetterSomething, _returns=Array(KeyValuePair)) + def some_other_call(ctx, sth): + pass + + application = Application([Service1, Service2], + in_protocol=HttpRpc(), + out_protocol=Soap11(), + name='Service', tns='target_namespace' + ) + + imports = application.interface.imports + tns = application.interface.get_tns() + 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 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 + + def test_custom_primitive_in_array(self): + RequestStatus = Unicode(values=['new', 'processed'], zonta='bonta') + + class DataRequest(ComplexModel): + status = Array(RequestStatus) + + class HelloWorldService(Service): + @rpc(DataRequest) + def some_call(ctx, dgrntcl): + pass + + 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__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/interface/test_interface.pyc b/pym/calculate/contrib/spyne/test/interface/test_interface.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2b25debe6020a3b25d54e317d51e2a52779f5a74 GIT binary patch literal 5354 zcmc&&OLH7o6+Yeb(CFon{E$&BP#|#_sCb0rltU;(5kD$U5nNP{9m1rFq21jYwcL-P z?;T?Wsi;D!*xB$`*s#ckU%@u}Y}oMwlJ7e`4@EMSuo-65SNEQC`rh+C_e|wK%M1Vh z{GWdaWb~=v|1a^F&oG4eb0iVzmUCAUM^ab1uA~*|RwS)Tw<-?lDw5PBtxLBq>6~=u zByC8yA?dty=OtZ`?t-L?(p{8vNxDmtE=za0e6uRaIZ2z+ZIykwZuJv2=CfLYWoERWGb3ZlpUZ(Pxr8tzCIa5H*I39xZR_E(kW^$`smrPJDg=iJxG(ojjF zCx{G&%CDk>_x)rT{l<@r0Bilc*g@f)5wb^B#~K|}U7o{si;l0s((7e@8ufaX4%_Rc zc{ohCWH^*KGe9u(dL9WhiXTS@%GDDx(gIYbgYmK48k%A&i67l~V{33=_wsC~{pOa5 zZFCJ=J@)&N*)oHJEV{PS-oD=6zHx1E0E%|h@0ai`i#Xhh$APHJ-elPx9C%Hf@(Lb9 zIqD9-mdU7-BkcF$tpBZbQ)4DQshgb^vzEtHdS{LhiX=Dwzd>zb!eYk_H7MfW{*AS&dM0!*n3 z0=zMUG9!gBEnmZ98W>7vfIHAdZbcT!e4?1MPH_=LXO(i&9o}eB=+lazi>Ta>OS!Qu zgJ4D?Z{ob`cuW<8dOu|!mD=rzoMc^%|07IFIU`q|Yc)b{c#g`!gzA)440B|QQ6Vdn zLlN0wk(q#-@S%M>c=TM&RD|3wl|TYb5P^NF|Bc<7s%JKu(JWw)1$u#>BtIpqWJ}!B zW+c?BaCi;FQ~*sa9$iXdv*FtN0nU39k1`AAZD2mK=FT@+6FCXSg*CM{zSx@HE7bGq)eZR_&MDy{J$t{+yt1vLYERnN`a&K-829n~@cNh(m9VnS~X39gef! zpvY|=9{uScMFg~Q7nE@Lpv`hUJ^jwb#d z10aS4YXY9CvBhepSKuV?_faF2zem1_gWGww8~3%S-?@A1;X57~Q>Hvj#G@b{uOAv- zlS-_c#pxg~tkF4HrUX36l=uD~3vwRzQh!k91f=A1K)-E3z$W2tQQ&=wGJYdSd}A~O zc86I&8jVp;P23PH&_-a$?A;I7`k2cdfQo+o-QqH*1@C?g*;t=Oz&TENQgi)1ae?DXnJjVK=mhYU~LQPkf? zXLP2x**JiA3v7LeXPoWH@VzKW^55n~5{~lzS<$}>vS|@l(V^~-Pw0SYH8k?u6SaBNL_(_B|tmpHGn-9ngnHJ}YyHVLds%ko?4aj2Xy^CS$ zS+leqiwY$f-IC|u8g;y>4=H*r_9+S(W-J({am%u&4oCfKVJWSS202Q~i=%pL z4QOqKJf>i64z*b<+hvyG^1bmTpuNZ6pP1(C3y|tWT4)=fcmSSm`zG=zh_)c=O=SQ7 gqEJ=V&GILLUtFSStmI4XhVwIb#aXGWzqjOk1%^U=F8}}l literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interface/test_wsgi.py b/pym/calculate/contrib/spyne/test/interface/test_wsgi.py new file mode 100644 index 0000000..e27f3c8 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interface/test_wsgi.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import unittest + +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.service import Service + + +def start_response(code, headers): + print(code, headers) + + +class Test(unittest.TestCase): + def setUp(self): + class SomeService(Service): + @rpc(Unicode) + def some_call(ctx, some_str): + print(some_str) + + + app = Application([SomeService], "some_tns", in_protocol=Soap11(), + out_protocol=Soap11()) + self.wsgi_app = WsgiApplication(app) + + def test_document_built(self): + self.h = 0 + + 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) + 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' + + self.wsgi_app.doc.wsdl11.event_manager.add_listener( + "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' + + 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)) + + from lxml import etree + + assert etree.fromstring(retval).tag == WSDL11('definitions') + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/interface/test_wsgi.pyc b/pym/calculate/contrib/spyne/test/interface/test_wsgi.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8dc2328d23485115674cec3c08c5dbaae623f90f GIT binary patch literal 4150 zcmcgvTW=f36+XM9C{dy=c48;#EzJcjThyfGrZP|jNnJ;=jmC5`lpBO7uw}R-X_>tc zJ44k5;yy%0+CSCb(TDaY^sPUj{k}7lXrs=fL~@67&fL!BJ7>-|{oQso^s3|=Qgme03G|xen^J7aXe-cd$+xB0k>VN2r*EkTBs?)H$4gIqJ;xp(*=z1#dvL}I9 z12Ob^ix)LjN$3`m!AeG?7O^4#gz zj#FE^FbrDUAJFvYuI}gAmwWH^XHWfcRo?2|?z_y}8?*7`tMQR_eK&hr+8eieyT9!1 z?%kL@#f+XkItu*0x6b#o(%brQJh4h9e}X}J*lvrb_;Kx%+PYa)I{P*`luaU)?f|PN zB>AEJe~ZWc0u6jQf+Iz}8xw!<=%^uSteqxNN6w0vVOJI9a@v#1s)-(=gLPgM61wgb zkaz}GM8h3ne{9$k9}^Pk%A#``$IoIS;cM_QQzXH0G%&qC@O164D(snWK8Rz-W zNT?&@?h5)URg#or$d&kYaFV2`(s>Tj&}@dY%nq8R%-Xwf7@Ez+p(<}HS{l%oPMw*R z$*it?HK}sn!Q^W0&l#$nq0J3ZW~j5FD|8zoJsHntUFC3sv-zQ(sF{RAUIP>4JgddU<= z+#h>C`*pvsAvCY^e$a0XBj$T-c!K#p8qav)F1x#)*tI7-s~DF^$F%}hId4la zUdI#)k|yVA_*_Cw!FQa)G~7)4bzRkJT(z9}0amK{)U?XGc#P6Syfn^b3|71awqx)~ z)Q-0sSEKdldaQ_HRMG2q@wji$gu4JRMP>$ao<}NfhXqVu7*qTbrY~??%=*amfG~1@ zC{dm@FbSYc$kB@>6=>OmnbS@s&3V{!KQUI{w)%9|;vPKFa$Sh-hZLN71y)K=$1h4rK z$v4^jn9W;gJfVGL{mTGK@8(a6+%RS7#c^0y1+F#}UFIj?nYYpC4Zj2}?r#`cmt3N; zJj3)w=prby**w>}?*oiFmOMakz;ARd-U%2cerYzvFp@1%0_YMbkz}i^YLH>~0uuLt zxO5fNnxt*~0fHO&>#(fdThuCB=%KLC0tJzfZcDl&c~goNB056lGHq!n;G9+7Rp}Mx zX#)9FeES^8S0T#)6%rJqP5T%U`Si}g{p7*m<40PfF%xOl`Rwt&`63w}ma@aZFSpkTkZf1r8E>|@8_LGp0_;QphJbPaQ) zmbO|#B1ChSWzf1D`#`B1$zh>g$*mR)E;JK#x&=;oUQv!tE>#zq;`h$3`-Y< zj`=xziZRA>02)1|K+`N-TYoYR*t|@j(FqDPs{A_;ju9l$cC`B3cRlI=Us{x!D;PF( zrg?+SJ8W1+oA=QyMc3Yi=Xk@EK)Y%Q(u&#}?M{1hQ6d&&lv_!cx0Z6|a2j>h*w=TB z9vqw-j7xZf;QNR2dU!E2bfiXNn0r>Z^&H;HwAtO&BF)nzVGgdp6I=Ia%uu>5hftuM zy|-z7=dYcwLiuX*-mK0Fpz6eG0qgnN6*f)nq^ifhs{I?}xJegIB33Gaf(|?eJNC8|~&B?{%X80Vh?B AN&o-= literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interface/test_xml_schema.py b/pym/calculate/contrib/spyne/test/interface/test_xml_schema.py new file mode 100644 index 0000000..4163539 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interface/test_xml_schema.py @@ -0,0 +1,551 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import logging +import unittest + +from pprint import pprint +from lxml import etree + +from spyne import Application +from spyne import 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.model import Mandatory as M +from spyne.model import Unicode +from spyne.model import Uuid +from spyne.model import Boolean +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 + + +class TestXmlSchema(unittest.TestCase): + def test_choice_tag(self): + class SomeObject(ComplexModel): + __namespace__ = "badass_ns" + + one = Integer(xml_choice_group="numbers") + two = Integer(xml_choice_group="numbers") + punk = Unicode + + class KickassService(Service): + @rpc(_returns=SomeObject) + def wooo(ctx): + return SomeObject() + + Application([KickassService], + tns='kickass.ns', + in_protocol=Soap11(validator='lxml'), + out_protocol=Soap11() + ) + + docs = get_schema_documents([SomeObject]) + 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"]' + '/xs:sequence/xs:choice/xs:element[@name="one"]', + 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'))] + + class SummaryStats(SummaryStatsOfDouble): + ''' this is an empty base class ''' + + class Payload(ComplexModel): + _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() + ) + + # 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#")), + ] + + 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'))), + ] + + class RdfService(Service): + @rpc(Unicode, Unicode, _returns=Project) + def some_call(ctx, a, b): + pass + + 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' + + id = XmlAttribute(Uuid) + edition = Unicode + + class SomeService(Service): + @rpc(Product, _returns=Product) + def echo_product(ctx, product): + logging.info('edition_id: %r', product.edition_id) + return product + + 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' + + 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) + return product + + app = Application([SomeService], + tns='some_ns', + in_protocol=Soap11(validator='lxml'), + out_protocol=Soap11() + ) + + _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] + + 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/' + + @rpc(M(Uuid), _returns=Unicode) + def say_my_uuid(ctx, uuid): + return 'Your UUID: %s' % uuid + + Application([ExampleService], + tns='kickass.ns', + in_protocol=Soap11(validator='lxml'), + out_protocol=Soap11() + ) + + # if no exceptions while building the schema, no problem. + # see: http://stackoverflow.com/questions/16042132/cannot-use-mandatory-uuid-or-other-pattern-related-must-be-type-as-rpc-argumen + + def test_any_tag(self): + logging.basicConfig(level=logging.DEBUG) + + class SomeType(ComplexModel): + __namespace__ = "zo" + + 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}) + + assert len(_any) == 1 + assert _any[0].attrib['namespace'] == '##other' + assert _any[0].attrib['processContents'] == 'lax' + + def _build_xml_data_test_schema(self, custom_root): + tns = 'kickass.ns' + + class ProductEdition(ComplexModel): + __namespace__ = tns + id = XmlAttribute(Uuid) + if custom_root: + name = XmlData(Uuid) + else: + name = XmlData(Unicode) + + class Product(ComplexModel): + __namespace__ = tns + id = XmlAttribute(Uuid) + edition = ProductEdition + + class ExampleService(Service): + @rpc(Product, _returns=Product) + def say_my_uuid(ctx, product): + pass + + 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'] + 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 + + def _test_xml_data_validation(self): + schema = self._build_xml_data_test_schema(custom_root=False) + + assert schema.validation_schema.validate(etree.fromstring(""" + + punk + + """)), schema.validation_schema.error_log.last_error + + def _test_xml_data_validation_custom_root(self): + schema = self._build_xml_data_test_schema(custom_root=True) + + assert schema.validation_schema.validate(etree.fromstring(""" + + + 00000000-0000-0000-0000-000000000002 + + + """)), 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 = { + "s0": "aa", + "s2": "cc", + "s3": "dd", + } + + class C(ComplexModel): + __namespace__ = "aa" + a = Integer + b = Integer(sub_name="bb") + c = Integer(sub_ns="cc") + d = Integer(sub_ns="dd", sub_name="dd") + + elt = get_schema_documents([C], "aa")['tns'] + print(etree.tostring(elt, pretty_print=True)) + + seq, = xpath(elt, "xs:complexType/xs:sequence") + + assert len(seq) == 4 + assert len(xpath(seq, 'xs:element[@name="a"]')) == 1 + assert len(xpath(seq, 'xs:element[@name="bb"]')) == 1 + + # 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 + + def test_mandatory(self): + xpath = lambda o, x: o.xpath(x, namespaces={"xs": NS_XSD}) + + class C(ComplexModel): + __namespace__ = "aa" + foo = XmlAttribute(M(Unicode)) + + elt = get_schema_documents([C])['tns'] + print(etree.tostring(elt, pretty_print=True)) + foo, = xpath(elt, 'xs:complexType/xs:attribute[@name="foo"]') + attrs = foo.attrib + assert 'use' in attrs and attrs['use'] == 'required' + + def test_annotation(self): + tns = 'some_ns' + doc = "Some Doc" + + class SomeClass(ComplexModel): + __namespace__ = tns + some_attr = Unicode(doc=doc) + + 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] + + +class TestParseOwnXmlSchema(unittest.TestCase): + def test_simple(self): + tns = 'some_ns' + class SomeGuy(ComplexModel): + __namespace__ = 'some_ns' + + id = Integer + + 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[tns].types["SomeGuy"] + assert NewGuy.get_type_name() == SomeGuy.get_type_name() + assert NewGuy.get_namespace() == SomeGuy.get_namespace() + assert dict(NewGuy._type_info) == dict(SomeGuy._type_info) + + def test_customized_unicode(self): + 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'] + 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" + + def test_boolean_default(self): + tns = 'some_ns' + class SomeGuy(ComplexModel): + __namespace__ = tns + bald = Boolean(default=True) + + 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 + + def test_boolean_attribute_default(self): + tns = 'some_ns' + class SomeGuy(ComplexModel): + __namespace__ = tns + + bald = XmlAttribute(Boolean(default=True)) + + 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 + + def test_attribute(self): + tns = 'some_ns' + class SomeGuy(ComplexModel): + __namespace__ = tns + + name = XmlAttribute(Unicode) + + 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 + + def test_attribute_with_customized_type(self): + tns = 'some_ns' + class SomeGuy(ComplexModel): + __namespace__ = tns + + name = XmlAttribute(Unicode(default="aa")) + + 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" + + def test_inherited_attribute(self): + class DeviceEntity(ComplexModel): + token = XmlAttribute(Unicode, use='required') + + class DigitalInput(DeviceEntity): + IdleState = XmlAttribute(Unicode) + + class SomeService(Service): + @rpc(_returns=DigitalInput, _body_style='bare') + def GetDigitalInput(ctx): + return DigitalInput() + + Application([SomeService], 'some_tns', + in_protocol=Soap11(validator='lxml'), + out_protocol=Soap11()) + + def test_simple_type_explicit_customization(self): + class Header(ComplexModel): + test = Boolean(min_occurs=0, nillable=False) + pw = Unicode.customize(min_occurs=0, nillable=False, min_len=6) + + class Params(ComplexModel): + sendHeader = Header.customize(nillable=False, min_occurs=1) + + 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() + ) + # if instantiation doesn't fail, test is green. + + +class TestParseForeignXmlSchema(unittest.TestCase): + def test_simple_content(self): + tns = 'some_ns' + + schema = """ + + + + + + + +""" + + objects = parse_schema_string(schema) + pprint(objects[tns].types) + + NewGuy = objects[tns].types['SomeGuy'] + ti = NewGuy._type_info + pprint(dict(ti)) + assert issubclass(ti['_data'], XmlData) + assert ti['_data'].type is Unicode + + assert issubclass(ti['attr'], XmlAttribute) + assert ti['attr'].type is Unicode + + +class TestCodeGeneration(unittest.TestCase): + def _get_schema(self, *args): + schema_doc = get_schema_documents(args)['tns'] + return parse_schema_element(schema_doc) + + def test_simple(self): + ns = 'some_ns' + + class SomeObject(ComplexModel): + __namespace__ = ns + _type_info = [ + ('i', Integer), + ('s', Unicode), + ] + + s = self._get_schema(SomeObject)[ns] + code = CodeGenerator().genpy(ns, s) + + # FIXME: Properly parse it + assert """class SomeObject(_ComplexBase): + _type_info = [ + ('i', Integer), + ('s', Unicode), + ]""" in code + + +if __name__ == '__main__': + unittest.main() + diff --git a/pym/calculate/contrib/spyne/test/interface/test_xml_schema.pyc b/pym/calculate/contrib/spyne/test/interface/test_xml_schema.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6448a535c9d620f4063bd5144cbe6f2167012155 GIT binary patch literal 28440 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interface/wsdl/__init__.py b/pym/calculate/contrib/spyne/test/interface/wsdl/__init__.py new file mode 100644 index 0000000..d23660d --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interface/wsdl/__init__.py @@ -0,0 +1,68 @@ + +# +# spyne - Copyright (C) spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from spyne.application import Application +from spyne.interface.wsdl import Wsdl11 +from spyne.protocol.soap import Soap11 +import spyne.const.xml as ns + +def build_app(service_list, tns, name): + app = Application(service_list, tns, name=name, + in_protocol=Soap11(), out_protocol=Soap11()) + app.transport = 'http://schemas.xmlsoap.org/soap/http' + return app + +class AppTestWrapper(): + def __init__(self, application): + + self.url = 'http:/localhost:7789/wsdl' + self.service_string = ns.WSDL11('service') + self.port_string = ns.WSDL11('port') + self.soap_binding_string = ns.WSDL11_SOAP('binding') + self.operation_string = ns.WSDL11('operation') + self.port_type_string = ns.WSDL11('portType') + self.binding_string = ns.WSDL11('binding') + + self.app = application + self.interface_doc = Wsdl11(self.app.interface) + self.interface_doc.build_interface_document(self.url) + self.wsdl = self.interface_doc.get_interface_document() + + def get_service_list(self): + return self.interface_doc.root_elt.findall(self.service_string) + + def get_port_list(self, service): + from lxml import etree + print((etree.tostring(service, pretty_print=True))) + return service.findall(self.port_string) + + def get_soap_bindings(self, binding): + return binding.findall(self.soap_binding_string) + + def get_port_types(self): + return self.interface_doc.root_elt.findall(self.port_type_string) + + def get_port_operations(self, port_type): + return port_type.findall(self.operation_string) + + def get_bindings(self): + return self.interface_doc.root_elt.findall(self.binding_string) + + def get_binding_operations(self, binding): + return [o for o in binding.iterfind(self.operation_string)] diff --git a/pym/calculate/contrib/spyne/test/interface/wsdl/__init__.pyc b/pym/calculate/contrib/spyne/test/interface/wsdl/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0713baa95b90d9bf8bec3d47d04ef529f2655e01 GIT binary patch literal 3704 zcmc&%-EQMl5I&BRwCT3n(r)<^5)~}S5;P{=)fOs1yX;DEfx0WFQbi?BV8 zyvR%zWQkctM>aLJLf?hr+?f2pb#-taO@_Mr^CZ#OS2rt0E*Y2o4!7u`DX#%yxKmRM zQ=Mmpariu0TSvu@aS-`Qtc~FmlWI@?Nrrju;7ZtuZvet{9)XoRg%@0v&(H%?7doDGA>{Rs|seLqfP z8xn59b7t~AS)rdeq^L>V8tLhOPWuc+~A)w?E|H8s91 z43Li`;vlHj2}sV|pmX}p5)3%h^m7TSBnyVgd8W<5{{F|GNO%m#%y1$=C4xkG8mD2L zjwEIoLLtdx=qV04y2vBv6$pZ>X^|MZF4aa7tN-NdUQfbVK~S55i!m2D-Jg?>WwhUa z`skV2LO)UN&z@e5+kn2_#Jo}#GuTX}B!*s|>=AXIlmc=!Jk8p?cUgu=NXFZDg z=_E>xc@>?b$Niz^Q2P8^o~$P`f|RX8sqV=hqS0UU?vApl8G*uD2DF-!(YDG9>O92L{Zy9>tK z1}SU(4n>|9GH21QWTw!Sl5OHuG(@!Oca8g>RM+DfR}pb?~!~!@*&AC36BKtBa(X{*VYNAPoVq1uf-m3 zMQ@{NR?W86S?}1L7Mgs^9WnNX#Y!&P-ML$ZyapH^wPja*J?ZjBQr>%*AZ2g$?$PBf zt9*G_uRDVb7dXCg7@lAv$@Pv$)h09^eJZ=X2{%c2KP?0Lx!B9?Y~TReur?c=_FrZb BQoR5G literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interface/wsdl/defult_services.py b/pym/calculate/contrib/spyne/test/interface/wsdl/defult_services.py new file mode 100644 index 0000000..5d54a7f --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interface/wsdl/defult_services.py @@ -0,0 +1,49 @@ + +# +# spyne - Copyright (C) spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +from spyne.model.primitive import String +from spyne.service import Service +from spyne.decorator import rpc + + +def TDefaultPortService(): + class DefaultPortService(Service): + @rpc(String, _returns=String) + def echo_default_port_service(self, string): + return string + + return DefaultPortService + + +def TDefaultPortServiceMultipleMethods(): + class DefaultPortServiceMultipleMethods(Service): + @rpc(String, _returns=String) + def echo_one(self, string): + return string + + @rpc(String, _returns=String) + def echo_two(self, string): + return string + + @rpc(String, _returns=String) + def echo_three(self, string): + return string + + return DefaultPortServiceMultipleMethods diff --git a/pym/calculate/contrib/spyne/test/interface/wsdl/defult_services.pyc b/pym/calculate/contrib/spyne/test/interface/wsdl/defult_services.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05c143ef0ef1666c564571985e86f2b8622d5569 GIT binary patch literal 2309 zcmdT_&2G~`5T1>b^alzE1QL`B6eM$qtrk=+2%&J_KX0GrcRws@`cP_g3KKN6tYAkC7R%{Q=hRJQx{ZKq&mjOw`cG{FC6^@YT)(07pd7_|! zaP~p~`Ojp*a4~W=8*j5)6)4-Ky?U5_7>?P*ramsY zw-s$ZjyAV@^)YrtJRW;~Y}wd2FD*BtVaoB5$%;7R5v)&)cdCgX`8Lkt^q@+xCay_p z_~vZKUC~A?qE^@edUKOC*tKcNbq{^lRrdsxC5NQdVH&&)@v`Cw@#Csj&RPQS1 zeJvsIBUzrSw@A(G4IKUUViHRJx?~}BtK%~A@6-DpWL%WIi;(7Z!Mltc%8ZkZjU)-U z12X%7-)8&yLhu!aLg-wmk>IRGx>6%@j28Iw+R&0{T6)1hiqSHTb`?>T{1D?=0sM~^ z*rV#ve`$fV78e71&@lJrHn=-OONjJ}z`W^Pmg$b&tA4mV91)XaY8=}7yE;`cMUMLQ?H-#s6PK2J%MN~KWB)9n?yRL7= y_kMYHzqpobul{6boL0@yR*jFE#8}Jf+z|_pmAlZM`77+XvrjC&rtk(UD?b2Y(;MCZ literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interface/wsdl/port_service_services.py b/pym/calculate/contrib/spyne/test/interface/wsdl/port_service_services.py new file mode 100644 index 0000000..365bb62 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interface/wsdl/port_service_services.py @@ -0,0 +1,127 @@ + +# +# spyne - Copyright (C) spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from spyne.model.primitive import String +from spyne.service import Service +from spyne.decorator import rpc + +def TS1(): + class S1(Service): + name = 'S1Fools' + __namespace__ = 'Hippity' + + @rpc(String, _returns=String) + def echo_string_s1(self, string): + return string + return S1 + +def TS2(): + class S2(Service): + name = 'S2Fools' + __namespace__ = 'Hoppity' + + @rpc(String, _returns=String) + def bobs(self, string): + return string + + return S2 + +def TS3(): + class S3(Service): + name = 'S3Fools' + __namespace__ = 'Hoppity' + __service_name__ = 'BlahService' + __port_types__ = ['bobhope', 'larry'] + + @rpc(String, _returns=String) + def echo(self, string): + return string + + @rpc(String, _port_type='bobhope', _returns=String) + def echo_bob_hope(self, string): + return 'Bob Hope' + + return S3 + +def TMissingRPCPortService(): + class MissingRPCPortService(Service): + name = 'MissingRPCPortService' + __namespace__ = 'MissingRPCPortService' + __service_name__ = 'MissingRPCPortService' + __port_types__ = ['existing'] + + @rpc(String, _returns=String) + def raise_exception(self, string): + return string + return MissingRPCPortService + +def TBadRPCPortService(): + class BadRPCPortService(Service): + name = 'MissingRPCPortService' + __namespace__ = 'MissingRPCPortService' + __service_name__ = 'MissingRPCPortService' + __port_types__ = ['existing'] + + @rpc(String, _port_type='existingss', _returns=String) + def raise_exception(self, string): + return string + + return BadRPCPortService + +def TMissingServicePortService(): + class MissingServicePortService(Service): + name = 'MissingRPCPortService' + __namespace__ = 'MissingRPCPortService' + __service_name__ = 'MissingRPCPortService' + __port_types__ = ['existing'] + + @rpc(String, _port_type='existingss', _returns=String) + def raise_exception(self, string): + return string + + return MissingServicePortService + +def TSinglePortService(): + class SinglePortService(Service): + name = 'SinglePort' + __service_name__ = 'SinglePortService_ServiceInterface' + __namespace__ = 'SinglePortNS' + __port_types__ = ['FirstPortType'] + + @rpc(String, _port_type='FirstPortType', _returns=String) + def echo_default_port_service(self, string): + return string + + return SinglePortService + +def TDoublePortService(): + class DoublePortService(Service): + name = 'DoublePort' + __namespace__ = 'DoublePort' + __port_types__ = ['FirstPort', 'SecondPort'] + + @rpc(String, _port_type='FirstPort', _returns=String) + def echo_first_port(self, string): + return string + + @rpc(String, _port_type='SecondPort', _returns=String) + def echo_second_port(self, string): + return string + + return DoublePortService diff --git a/pym/calculate/contrib/spyne/test/interface/wsdl/port_service_services.pyc b/pym/calculate/contrib/spyne/test/interface/wsdl/port_service_services.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4dc30595ae90ab77a9d4815ea27ae9e99fcd1536 GIT binary patch literal 7354 zcmdT}+j1L45S^7}S@I<$Tv9-|$M#lMTCp=u z;vzhm-{MdB1m5@nIHzZ&wPVEzHYG=vr*~#&cGWY}r%z97>hFcwzyAE==Z?z%O1OTB zVxK@n_zzT~R5wr?feP3zsidU3Q)*+%x2IH6R^4f}F^zUv{jStTMMcw6nNd+iDpeKD zNTsHts#IoGRFle_ie{xUucA4rEU0K+wdxB{ApQq`^#CeX=0^*H}3aix96(p3^U_)v!3nn zTUn@Y3&rx$CjqqLowYiIs&jy2hc(HTtb_IIAiWf}3(?%QSu=?@Z(MKo_uNj}TW);X zw6Qab{dVU;d)wHi?eF!>;&NkYrLlBlvA>5A4YR%N?>C*Xt{L~7$+p@Z(|ly3q}fk1 z7h1o}gR5=e{pawFrn8fVUYF1=y-P)?t18twc|X&z*Y27ybhEeRMS4*Lb0^KN`OyEc1LrIe2qg2MaQqBqXO%#r8jXA z6H>v&8L{OP0%2Jm#@iG(YL%}&9T1ie03j71XfEfA13=THbQR)E7n;klnQq#TaXo14 zn)a>dDCQ|>)(0&4RWu8|r8a&m(XT*@YbeK9GKUn3j$g;zl9#ViO)fSpxq2E)UKv_4 z?M*Cs6P2Sb9nO5Ctl-I`vf4&{TA7M6U@%l>#K{Yl?Ze4e2VLmJ_&7dfDOr>VK`hD zdx-W(Hu@4o0Ys^dAC3BTXwg8ibZWwV;J^9OrSj7Z$bp5rYFUoi9|2o}8`83v2hL9nRb z$9p7RGLK{H_{9^+j%1Il9a|Hc#~ssmaoYO|w+2K>k2sPj-(d&i#{-mk1)sufI> z{CUxHE2xui6in#LtnmOROfo=+wG)XCO`HA>Wr6{54eHg6pn`ihn*=D=spMB zaMWVI=L}8>3Gzb=QA=X}8x#;8AzB(7ybeW6{wOv)S{*ohfgdEj#8of8)LlK)%;y>A z*RKazEyqB%cxtUB38*`9W*t>u$00@NW+Fl5=$hn&5}B>`ZsPn2!}|2y19TpTHVMKc zZ}C(l#+bS=V5yBi!qNO*1Q*Xk8;2Fjj$cnF#8X&UZh#Rr{~u6xJKf!U4$6+CH~g7I zQr}E$Na`B74aQ%%iDm`qjRPUr471w#03^JJ1D=7wLM2BhKE#qlY%SACdl8{E!LZ`7 zMqsr?KOvxc#QpTtH9Dy=DvAG+?!ajwef>a zH=#wwDHK#ZU%GN6OTl4F}tc#nc)sXwG(B3m=Xqd$Qt7Uzt1 gQj#E_`=5z!GO1)K&IkCEYO}Su+J)MDZGoSE0m3GLZ2$lO literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interface/wsdl/test_bindings.py b/pym/calculate/contrib/spyne/test/interface/wsdl/test_bindings.py new file mode 100644 index 0000000..e82bcf9 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interface/wsdl/test_bindings.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python +#encoding: utf8 +# +# spyne - Copyright (C) spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import logging +logging.basicConfig(level=logging.DEBUG) + +import unittest + +import spyne.const.xml as ns + + +from spyne.interface.wsdl.wsdl11 import Wsdl11 +from . import build_app +from .port_service_services import TS1 +from .port_service_services import TSinglePortService +from .port_service_services import TDoublePortService + +class TestWSDLBindingBehavior(unittest.TestCase): + def setUp(self): + self.transport = 'http://schemas.xmlsoap.org/soap/http' + self.url = 'http:/localhost:7789/wsdl' + self.port_type_string = ns.WSDL11('portType') + self.service_string = ns.WSDL11('service') + self.binding_string = ns.WSDL11('binding') + self.operation_string = ns.WSDL11('operation') + self.port_string = ns.WSDL11('port') + + def test_binding_simple(self): + sa = build_app([TS1()], 'S1Port', 'TestServiceName') + + interface_doc = Wsdl11(sa.interface) + interface_doc.build_interface_document(self.url) + + + services = interface_doc.root_elt.xpath( + '/wsdl:definitions/wsdl:service', + namespaces = { + 'wsdl':'http://schemas.xmlsoap.org/wsdl/' }) + self.assertEqual(len(services), 1) + + portTypes = interface_doc.root_elt.xpath( + '/wsdl:definitions/wsdl:portType', + namespaces = { + 'wsdl':'http://schemas.xmlsoap.org/wsdl/' }) + self.assertEqual(len(portTypes), 1) + + ports = interface_doc.root_elt.xpath( + '/wsdl:definitions/wsdl:service[@name="%s"]/wsdl:port' % + "S1", + namespaces = { + 'wsdl':'http://schemas.xmlsoap.org/wsdl/' }) + self.assertEqual(len(ports), 1) + + + def test_binding_multiple(self): + SinglePortService, DoublePortService = TSinglePortService(), TDoublePortService() + + sa = build_app( + [SinglePortService, DoublePortService], + 'MultiServiceTns', + 'AppName' + ) + interface_doc = Wsdl11(sa.interface) + interface_doc.build_interface_document(self.url) + + + # 2 Service, + # First has 1 port + # Second has 2 + + # => 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/' }) + self.assertEqual(len(services), 2) + + 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/' }) + + 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/' }) + 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/' }) + self.assertEqual(len(ports), 2) + + # checking name and type + #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) diff --git a/pym/calculate/contrib/spyne/test/interface/wsdl/test_bindings.pyc b/pym/calculate/contrib/spyne/test/interface/wsdl/test_bindings.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0974f23732362bcc7c403fc3a825f7ce3680d6f5 GIT binary patch literal 3681 zcmc&$>uwuG6h6D__?By15n9Tnv=l6)*m9{_hyax|6$n9u)~OXu3{_y~CzO%c=ZPF^@2erN9nX_{_bLRWLGtOU&^*?|A^@kqiABX?% z@uPp?BH*7z5mA>&5e+N~Y^m6ELY9@kcBtzVT}w2Wqd}Rv6|p!JRcTnGZjG#v zXLrND`Lku_xEiSg6*VlbnKBnUI*8is5bexZ` zR=PH}feMGxmP(1-P6JN$Fba>&&wYM$$_00y5P4j&rDBn>X~3f$I>}y@3QMW5%oUco z!cs0Q<-$@aES17ig^!&^l^5O8?{K+qOuF7`>E6B?`nq{IjCA6s&1BSXq0+*8eP!A) zN_u{@pJ=mw_wI)uwSMHYFqkamz-}L<%2c?avj|IlH;bOZAtk9A`6f(aQ_6=lV3v1g zCmXP)bBm^`%1TTdK9a*Tg~#B=%)=B%qp>xzYW%&Je+51u z0Um+RA6zl~v%sJ}Lr{2q;?S{xXkr0J45DL37GtUed@-%rVxe880kfNtRw8B;b2=!~ zofFGCcBEq!hcl500>+R%JBXq5?4WG+Y>)u;)Sw#ZzItll+{|j?Ts|-WSaD2Sf`d*Q z1UAcT06TLgZ}~%|-(;Hvbv;mfVH^TxIx`e-taFzbefh+c*4McC0`vpgEdeTOA~*W2 z=PyzaK;M3TpWKn}?!k*suHV$xA7vg2?tyofEO_an?t%y|v_c3ng^sz*rcCdqHZMqe zhr={dYuL!UT#$9yUba@8npL(OYtdS@XKRjC5v%YD z;X&ktSHE%KnO97zj9NDHi8;g(VoEV{`XchI*Pxn1980DN(+gB%8c6O0)kKRev@0}V z%A7&94E!}Rb(+kA|KCApP^~PC$p*<9oKl6K)0OI{`B|A6Bq`z4pm}U>FnromH-odz0uRvayDSm{_mh z)D5I97irW*I?J>SGUmRH;tdoK7#EW5A}H=P6mN4ODc`MPY=^G{{6N%dvr?AJTOo8dgwC<*Q_(A=ZnbpDT9G+2>1*JSBphB5Z=@j4 z8z#Xx;_$nx+;rbVaf^$8LnF2S?{eeJ@0G675-7061(MBGEQu>zbD9#HxDrUw zZf6;q`(#KrI7NYK0pcQUX8C-|3-JfHnESp~vbUEOS#jm#?7TmP{~BRkV6ZLN7o8P` Ii+t^W0Q4S900000 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interface/wsdl/test_default_wsdl.py b/pym/calculate/contrib/spyne/test/interface/wsdl/test_default_wsdl.py new file mode 100644 index 0000000..c81046e --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interface/wsdl/test_default_wsdl.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +import logging +logging.basicConfig(level=logging.DEBUG) + +import unittest + +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.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 + +ns = { + 'wsdl': 'http://schemas.xmlsoap.org/wsdl/', + 'xs': 'http://www.w3.org/2001/XMLSchema', +} + + +class TestDefaultWSDLBehavior(unittest.TestCase): + def _default_service(self, app_wrapper, service_name): + self.assertEqual(1, len(app_wrapper.get_service_list())) + + services = app_wrapper.get_service_list() + service = services[0] + + # the default behavior requires that there be only a single service + self.assertEqual(1, len(services)) + 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 + ports = app_wrapper.get_port_list(service) + self.assertEqual(len(ports), 1) + + def _default_port_type(self, app_wrapper, portType_name, op_count): + # Verify the portType Count + portTypes = app_wrapper.get_port_types() + + # there should be only one portType + self.assertEqual(1, len(portTypes)) + + # Verify the portType name + portType = portTypes[0] + # Check the name of the port + self.assertEqual(portType_name, portType.get('name')) + + # verify that the portType definition has the correct + # number of operations + ops = app_wrapper.get_port_operations(portType) + self.assertEqual(op_count, len(ops)) + + def _default_binding(self, wrapper, binding_name, opp_count): + # the default behavior is only single binding + bindings = wrapper.get_bindings() + self.assertEqual(1, len(bindings)) + + # check for the correct binding name + binding = bindings[0] + name = binding.get('name') + self.assertEqual(binding_name, name) + + # Test that the default service contains the soap binding + sb = wrapper.get_soap_bindings(binding) + self.assertEqual(1, len(sb)) + + # verify the correct number of operations + ops = wrapper.get_binding_operations(binding) + self.assertEqual(opp_count, len(ops)) + + def _default_binding_methods(self, wrapper, op_count, op_names): + binding = wrapper.get_bindings()[0] + operations = wrapper.get_binding_operations(binding) + + # Check the number of operations bound to the port + self.assertEqual(op_count, len(operations)) + + # Check the operation names are correct + for op in operations: + 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' + ) + + wrapper = AppTestWrapper(app) + self._default_port_type(wrapper, 'DefaultPortName', 1) + + def test_default_port_type_multiple(self): + app = build_app( + [TDefaultPortServiceMultipleMethods()], + 'DefaultServiceTns', + 'MultipleDefaultPortServiceApp' + ) + + wrapper = AppTestWrapper(app) + + self._default_port_type(wrapper, "MultipleDefaultPortServiceApp", 3) + + def test_default_binding(self): + app = build_app( + [TDefaultPortService()], + 'DefaultPortTest', + 'DefaultBindingName' + ) + + wrapper = AppTestWrapper(app) + + self._default_binding(wrapper, "DefaultBindingName", 1) + + def test_default_binding_multiple(self): + app = build_app( + [TDefaultPortServiceMultipleMethods()], + 'DefaultPortTest', + 'MultipleDefaultBindingNameApp' + ) + + wrapper = AppTestWrapper(app) + + self._default_binding(wrapper, 'MultipleDefaultBindingNameApp', 3) + + def test_default_binding_methods(self): + app = build_app( + [TDefaultPortService()], + 'DefaultPortTest', + 'DefaultPortMethods' + ) + + wrapper = AppTestWrapper(app) + + 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') + def whatever(ss): + return ss + + app = Application([SomeService], tns='tns') + app.transport = 'None' + + wsdl = Wsdl11(app.interface) + wsdl.build_interface_document('url') + wsdl = etree.fromstring(wsdl.get_interface_document()) + + schema = wsdl.xpath( + '/wsdl:definitions/wsdl:types/xs:schema[@targetNamespace="tns"]', + namespaces=ns, + ) + assert len(schema) == 1 + + print(etree.tostring(wsdl, pretty_print=True)) + + elts = schema[0].xpath( + 'xs:element[@name="whatever%s"]' % REQUEST_SUFFIX, namespaces=ns) + assert len(elts) > 0 + assert elts[0].attrib['type'] == 'xs:string' + + elts = schema[0].xpath( + 'xs:element[@name="whatever%s"]' % RESPONSE_SUFFIX, namespaces=ns) + assert len(elts) > 0 + assert elts[0].attrib['type'] == 'xs:string' + + def test_bare_with_conflicting_types(self): + class SomeService(Service): + @srpc(Array(String), _returns=Array(String)) + def whatever(sa): + return sa + + @srpc(Array(String), _returns=Array(String), _body_style='bare') + def whatever_bare(sa): + return sa + + app = Application([SomeService], tns='tns') + app.transport = 'None' + + wsdl = Wsdl11(app.interface) + wsdl.build_interface_document('url') + wsdl = etree.fromstring(wsdl.get_interface_document()) + 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 + + elts = schema.xpath( + 'xs:element[@name="whatever_bare%s"]' % REQUEST_SUFFIX, + namespaces=ns) + + assert len(elts) > 0 + assert elts[0].attrib['type'] == 'tns:string%s' % ARRAY_SUFFIX + + elts = schema.xpath( + 'xs:element[@name="whatever_bare%s"]' % RESPONSE_SUFFIX, + namespaces=ns) + + assert len(elts) > 0 + assert elts[0].attrib['type'] == 'tns:string%s' % ARRAY_SUFFIX + + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/interface/wsdl/test_default_wsdl.pyc b/pym/calculate/contrib/spyne/test/interface/wsdl/test_default_wsdl.pyc new file mode 100644 index 0000000000000000000000000000000000000000..147eeb237ef2f8a83ddd9c792f50daadfb8d0059 GIT binary patch literal 8612 zcmd5>%Xb@B8UIF-Wy_Ic=jFuom4=g6?ICj0mH?$KdAX&fag!^Dv}(&#){Jc>qetgn z$MHD{3(^fNIc!+*9{_&pHlCpFsr8()x6Ov3xw<67oAD4AJEzM~^o|NQ(bgR;=`tg*GXQVmf#}!EqN_SS8 zvwl3S<2h;0`SAfAACl%FKdwr0Sh`1~dBl%rBsnVGW70h4#|I^um+oyp zj6}!fRzcEh0Vz&$A?PVL8?_T)Z|A@GTXqxZCh_e!se#*~!`P*9?1u+1cVRF{I_;M0 z^m~5tpr2fct-F!727@^D^A*gmZg!F=#H61(f~l3u@mgy$aaa4PYsBg8PCMKD)ZU9% zK-(E4@s-$Z^dmcZrdhgneW|e$Hm<+*);k~g`C05?mKs;zUv4bzSg2y*f-x69+%a3i ztW5`PfAb_pJ5E%_#0?uIXU}>9GUq~?wzmC{%MF)ydh7Nix*N_7URzwW?TxtGvh_RN z#P(Z*dOuxX+`=Y{j!$E6oO)|(tG@M$621J=OJ^59xbj{@H*f_|-?8pEzR22)Yd0E~ z-@6!Zv~G9$X>KAE)kR$P78;mE6Vew-zX=@)v;%u6Xs0AmQ9Bb7m9$fqXhJ)a5|y@U#Vg>kBOxj^m)a+CHc_XD|K zkRTu5E6QCx*uuTi&O3@Zt?qNTAa_f06SSiRY>JyoB)m6~-OYzha0YM9CxHu%8qc-d zA&)w^M8(i+b>kYv>G%pQYva@{eYV+39N#91du|Tj>#+;5LKO{@j&-_-NjH-%4xq!j zQX>O&XB#JLe$&Aq-17F|sC~nY_-HpZny`*~m#wP7aaUWzq-bM#?8Qx+E+(DTbFVHA zwqXdpm+RkIv>g|p8MNBBTI;c0w1e$leCFl)*;ndk&z%`;gQ6a}91203|HQLMArI42u(cidThsudLz)T~WACd8izFiPs#)5xi)5V2V(ssQ*zRxkoFmW;m#vC+I8ue_ z5B5)(WJWH`oDY{VYpIh`s21mo(}i4^e3e|7zs7*J`lW?ACc}};yudQEhsAo4PG%y7 zp;DxiLy_`%ux3v*wNvg>L!vL1yP6^2j8a|g^df@uZmA#2)(Ou!k)uM4-4%|h1G%E= zpr$%*)Y&7vQjn|8|5ImRbYV2%s9lY%o`x zMQ<-_UjtdLAdsZOI0Ohw9mi$Jw;(VDFI57-ofkQ{{K+ZF^aOfQrr-e!KyTRjEj9As zv)AQ@N}I5}+~K*rfm6`tc{VSw$?e)rW9adGCEbkG%*V|6MG`a6P&0)E)0(ZRbB1@0 zgsu|m5B5zsM4#MphiV4T!5C;AYnI2AU@n-21dt@SKnhJS=2`NC6+X*W$R_bPTA*0yah>yXTg{LUpg|X$=ox=vobrW1d4((;nYQ z0TJP#p&<5+w~GDazAs0{6vy(&SS$vW09Ud4weglXl<~IVql}fFbx&b-81s&CKBGYN z-61!}c&(4If)#EZW7D|3(cfuZS;#&H5F;>V9RFCU@{?rNI6&<3 zbicv64@bt(p^SdfqcX8C_jt?jfs7|b%O9HV-beX^{thukpiVGLApbR&H@NN$zH{yp0W5tH6DCs9=vq8WY4 ze};=Yc0Ba(9nS>*XnXGXZnmgl7gMNZO=lbZZk+j`HYW9t+}FATW3X834l&Ac;4y}1 z5p*z~D3L(MSMFf$Ch{b)0Z!_Y8{ zGi0-Q2hAuX(%z#@{mo^Z;CHz6@Z~^*H3#vK>C63ItP`7QVu^8DLU=8T*E+opi-Fcp zXr8@z$G+z4U>}`#trTe$U93f^B7Wl(c0BcovO$AyPFfFWOxy<03AY^%P*!stjKw~U z2K&WH+(ljHqw~D$jZ;HrpXO$&QB3eFp4Mtru0~I9s9T28&^+Cxt)68RV)!tf%8Me7 z5vs3P=5t}xZ*TIsMzxI6T1)#~|A0Jae2`oVId=vvx1pNZvs!h4{iA}Y)h2LkDNS(@ zDu?T58}daoZ(#)j$bnqO;aye@skF%C%Mz57k3<-tE1~DNvLa6QxqhUOP6G~Yr;FO{ zZ*fTb92yDcCyoV`!fY@T94nNAGWsV9M+?)zk>Et|RQ9cA&zGm?x`fLDO7;udKZa8P zx&y@(;DPP{PepOmg#hFPaYgnKh{KO$*!>5hJDfm92e6;p1T{3v z6XKo0gJfBz3CExnXt1kUren}RWeHFDs<_`8;pQWTOoH}bsi7Y4&0FZ3x4+UWm`_2z zUoW7w%^{YCG}*u5G(+!26f*C!`4JoSRV;>%9F}QeI6A!c9?$`qi3Z-N-6yWyVMTc8kvxRcA9=s^O;7m+eoJ{xVsnk#syFJv zYpUluZEIT5%6*qHAX1lQ7zUXYHuOk_1v~R&HaFOOzy?2#ius7mQ8sjn=0i3rPnz+= z{fYU6BtJnjlI)`usym5?kG#lM$8Dgj+FQdfj}9f>P@{}LgT~g;z^hbpuL7S^4ywhY zg-S3ToPdv+rjH4p&3iS~;E`4{zR)t2VNPn8Bbo29d7TZF$DC(FM`S`at7t}?*$F8BlmZdB>(b>wO%Hhg^N);FXXDiS62s`YyI=wKgJqtRmLMQ$8b#PEa?$wsxhg5^t^t5=z(=!m8Ya8_NzZ}KwK7PmPrwUh!Z+;<5 zj5Q#1Gz>qz>!fOkG(NwII6Y44nY9~gjytw%5us`q5%BHUqarO(dAI^TTx!|akZX#f y%1sJnUzJA>_qtC&-qe@*77kbqjufheIsT)ljQ^sx!%;9-C + + + Echo, test + Echo, test + + + ''' + + 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 + args""" + function_name = self.default_function_name + + if _operation_name is None: + operation_name = function_name + else: + operation_name = _operation_name + + if _in_message_name is None: + request_name = operation_name + suffix + else: + request_name = _in_message_name + + return function_name, operation_name, request_name + + 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)} + if _in_message_name: + srpc_kparams['_in_message_name'] = _in_message_name + if _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 + + application = Application([EchoService], + tns='spyne.examples.echo', + in_protocol=in_protocol, + out_protocol=Soap11() + ) + app = WsgiApplication(application) + + testapp = _TestApp(app) + + # so that it doesn't interfere with other tests. + spyne.const.REQUEST_SUFFIX = '' + + return testapp + + def assert_response_ok(self, resp): + """check the default response""" + 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)) + + ### 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 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') + + ### soap tests ### + 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) + + function_name, operation_name, request_name = self.get_function_names( + suffix, _operation_name, _in_message_name) + + soap_input_body = """ + + + + + test + 2 + + + """.format(request_name) + + # check 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)) + + 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)) + if request_name != operation_name: + wrong_string = 'nlFJdEt%BzDDAqBt!(k0D_)p1vcE)zdxh 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 RH|OwoUZ|vV^SR>4e*jhjBAWmJ literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interface/wsdl/test_wsdl_ports_services.py b/pym/calculate/contrib/spyne/test/interface/wsdl/test_wsdl_ports_services.py new file mode 100644 index 0000000..ab84e64 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interface/wsdl/test_wsdl_ports_services.py @@ -0,0 +1,215 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from spyne.interface.wsdl.wsdl11 import Wsdl11 +import logging +logging.basicConfig(level=logging.DEBUG) + +import unittest + +import spyne.const.xml as ns + +from spyne.test.interface.wsdl import AppTestWrapper +from spyne.test.interface.wsdl import build_app +from spyne.test.interface.wsdl.port_service_services import TBadRPCPortService +from spyne.test.interface.wsdl.port_service_services import TDoublePortService +from spyne.test.interface.wsdl.port_service_services import TMissingRPCPortService +from spyne.test.interface.wsdl.port_service_services import TMissingServicePortService +from spyne.test.interface.wsdl.port_service_services import TSinglePortService + +class TestWSDLPortServiceBehavior(unittest.TestCase): + def setUp(self): + self.transport = 'http://schemas.xmlsoap.org/soap/http' + self.url = 'http:/localhost:7789/wsdl' + self.port_type_string = ns.WSDL11('portType') + self.service_string = ns.WSDL11('service') + self.binding_string = ns.WSDL11('binding') + self.operation_string = ns.WSDL11('operation') + self.port_string = ns.WSDL11('port') + + def test_tns(self): + sa = build_app([TSinglePortService()], 'SinglePort', 'TestServiceName') + + wsdl = Wsdl11(sa.interface) + wsdl.build_interface_document(self.url) + sa_el = wsdl.root_elt + tns = sa_el.get('targetNamespace') + self.assertEqual('SinglePort', tns) + + sa = build_app( + [TSinglePortService(), TDoublePortService()], + 'MultiServiceTns', + 'AppName' + ) + + wsdl = Wsdl11(sa.interface) + wsdl.build_interface_document(self.url) + tns = wsdl.root_elt.get('targetNamespace') + + self.assertEqual(tns, 'MultiServiceTns') + + def test_raise_missing_port(self): + # Test that an exception is raised when a port is declared in the service class + # but the rpc method does not declare a port. + + app = build_app( + [TMissingRPCPortService()], + 'MisingPortTns', + 'MissingPortApp' + ) + + interface_doc = Wsdl11(app.interface) + self.assertRaises(ValueError, interface_doc.build_interface_document, + self.url) + + app = build_app( + [TSinglePortService(), TMissingRPCPortService()], + 'MissingPort2Tns', + 'MissingPort2App' + ) + + interface_doc = Wsdl11(app.interface) + self.assertRaises(ValueError, interface_doc.build_interface_document, + self.url) + + + def test_raise_invalid_port(self): + + app = build_app( + [TBadRPCPortService()], + 'MisingPortTns', + 'MissingPortApp' + ) + + interface_doc = Wsdl11(app.interface) + self.assertRaises(ValueError, interface_doc.build_interface_document, + self.url) + + app = build_app( + [TBadRPCPortService(), TSinglePortService()], + 'MissingPort2Tns', + 'MissingPortApp' + ) + + interface_doc = Wsdl11(app.interface) + self.assertRaises(ValueError, interface_doc.build_interface_document, + self.url) + + + + def test_raise_no_service_port(self): + + app = build_app( + [TMissingServicePortService()], + 'MisingPortTns', + 'MissingPortApp' + ) + + interface_doc = Wsdl11(app.interface) + self.assertRaises(ValueError, interface_doc.build_interface_document, + self.url) + + app = build_app( + [TSinglePortService(), TMissingServicePortService()], + 'MissingServicePort2Tns', + 'MissingServicePort2App' + ) + + interface_doc = Wsdl11(app.interface) + self.assertRaises(ValueError, interface_doc.build_interface_document, + self.url) + + + def test_service_name(self): + sa = build_app([TSinglePortService()], 'SinglePort', 'TestServiceName') + wsdl = Wsdl11(sa.interface) + wsdl.build_interface_document(self.url) + sa_el = wsdl.root_elt + + sl = [s for s in sa_el.iterfind(self.service_string)] + name = sl[0].get('name') + print((len(sl))) + + self.assertEqual('SinglePortService_ServiceInterface', name) + + + def test_service_contains_ports(self): + # Check that the element for the service has the correct number of ports + # Check that the element for the service has the correct port names + + app = build_app( + [TSinglePortService()], + 'SinglePortTns', + 'SinglePortApp' + ) + + wrapper = AppTestWrapper(app) + service = wrapper.get_service_list()[0] + + # verify that there is only one port + ports = wrapper.get_port_list(service) + self.assertEqual(1, len(ports)) + + # verify that the ports name matched the port specified in + # the service class + port = ports[0] + + self.assertEqual('FirstPortType', port.get('name')) + + def test_port_name(self): + sa = build_app([TSinglePortService()], 'tns', name='SinglePortApp') + wsdl = Wsdl11(sa.interface) + wsdl.build_interface_document(self.url) + sa_wsdl_el = wsdl.root_elt + + pl = sa_wsdl_el.findall(self.port_type_string) + print(('\n', pl, pl[0].attrib)) + self.assertEqual('FirstPortType', pl[0].get('name')) + + da = build_app([TDoublePortService()], 'tns', name='DoublePortApp') + + wsdl = Wsdl11(da.interface) + wsdl.build_interface_document(self.url) + da_wsdl_el = wsdl.root_elt + + pl2 = da_wsdl_el.findall(self.port_type_string) + self.assertEqual('FirstPort', pl2[0].get('name')) + self.assertEqual('SecondPort', pl2[1].get('name')) + + + def test_port_count(self): + sa = build_app([TSinglePortService()], 'tns', name='SinglePortApp') + wsdl = Wsdl11(sa.interface) + wsdl.build_interface_document(self.url) + sa_wsdl_el = wsdl.root_elt + + self.assertEqual(1, len(sa_wsdl_el.findall(self.port_type_string))) + pl = sa_wsdl_el.findall(self.port_type_string) + self.assertEqual(1, len(pl)) + + da = build_app([TDoublePortService()], 'tns', name='DoublePortApp') + wsdl = Wsdl11(da.interface) + wsdl.build_interface_document(self.url) + + from lxml import etree + print(etree.tostring(wsdl.root_elt, pretty_print=True)) + self.assertEqual(2, len(wsdl.root_elt.findall(self.port_type_string))) + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/interface/wsdl/test_wsdl_ports_services.pyc b/pym/calculate/contrib/spyne/test/interface/wsdl/test_wsdl_ports_services.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46c95310e28dc3de0aea9414d463cd11ea46ebba GIT binary patch literal 6579 zcmdUz-Etg9700`0Kcro)ELo1fVp2e`VS(~45@3^5Du5-E0Euvo##8W*_MV>mWs6jC`w!vTYi5$-i?fXHxI|-D0lJ(0agm|sh##B9=dIAB0aEn{A#yr`UlY{G@W0L5|f4F zPL>b5%ye0Au9ppytRE%^nX#|lz5AV4x*q}?%fZG_`R>s;vI{5}r+dlo#pwWwv3&Uq z{Dd~nQd=#$$eKu<&BN4i6k9>vBu}scN~Olp2?egN+ts31VDY5D*qj3s(c*#gqT;zz z5xbU;p9+_zrKd^~khQICbEV@+!YdLDb~70t; zwuyAMqwNZc+{%Ro*bYaL$ZVJoBg>+J9-Qp$Nn+!o;VuXwk}zUy)aI~03G+#p{I;^t*&C)Uc*Lr8@l|MSS%780j@Ka35Qk(|8~CX?uXo@crL1r!Ay!LBU; z3Kz`b2$gA`;_bY7xQdAh4>?~b7`X#l?9?Wz93EBRP$03Qn{$Ay=>HxbV&1R`0SWDo zoXr0Q9>jLr|0+`dYfQe5WKO}Xo+;SB%_8^3Ggaw#S^EtnpE1?N>7y`-2co*4VtP(> zP}cumb)V+Wo~h2#g)FveVfMMPWfwoA>hxyj0r7vTYkJ3X+ceFlK7^%x*J|r$EpaKT>gS&NU`IWM^@kH(QP&UQCyQVE7%ps+QZ#?# zP4--(cX14d_LO(v^R<1t_c6Xoj@6Vd!OJMkyoLgXp!oga)cI=DTtDFjh#jBX++XCl zJQU&L<@<1A{TJAY50E1}iBkVdD6|D0+H(IUlUq!_j0CHP#dimP;@?5xyzRn8&WcAo zycEV}0hjEzoF&~Fob^2Ab;G-*FX<(BzVnzXvG^4V{~Qabt#B^kKq8ufZs}7xXA`2* zr zRsfq_j{shYNlIj0Fcd*e0}?Dyw+Z|ly(p3mQOdgFuMS@gBE8HYw_cI8kaxkl`Naed^~t_4j0K5FJ}7rB~| z&7(+yq;ZZ|`6w9U>c+-|sm-(JIXIp(xo@%uQ5I_D@K11W%d!IMCj5%lI_OnT9{|u3#yQB0J-Is9#bj6dBx2msdu`%-EfgI^U zAR99XM%iGJL_y&5{?6yi`RhzJn0%YbYfQG7{DjFvB(pV;+__wS`3+3uCcb73NnJM@ zjmwSejcbjojb(f<7cV=)p%nye2~~Nh$wgbI45K?VT9T}s_-V06K z-^|kecqnJ|*8O`A-;lv4X>6$pxdw3K!u%S`3sPw+CGiA_p14+AW!IEFpO}YF*oAY; zK=GOFI%2e@9$N8he3C4<`*QO@GbL9EGTB``ZZkBIESvuh>SR-Jc|Hr;lsUfUV0@j9 Yg_z=1-O`u5mbV6m=l;Fxe{AW003#iR;s5{u literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/__init__.py b/pym/calculate/contrib/spyne/test/interop/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pym/calculate/contrib/spyne/test/interop/__init__.pyc b/pym/calculate/contrib/spyne/test/interop/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..426d0822a296d6952e0eb2cce6dac9bd99e117fb GIT binary patch literal 176 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 Y5Y^7Pb$8yKFI7slsoJAw{#1AV2f&))r~m)} literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/server/__init__.py b/pym/calculate/contrib/spyne/test/interop/server/__init__.py new file mode 100644 index 0000000..9379343 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interop/server/__init__.py @@ -0,0 +1,29 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +import socket + + +def get_open_port(): + s = socket.socket() + s.bind(('', 0)) # Bind to a free port provided by the host. + retval = s.getsockname()[1] + s.close() + return retval diff --git a/pym/calculate/contrib/spyne/test/interop/server/__init__.pyc b/pym/calculate/contrib/spyne/test/interop/server/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e81f63713c7505f9b710f529cba8bd0ad882a582 GIT binary patch literal 555 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/server/httprpc_csv_basic.py b/pym/calculate/contrib/spyne/test/interop/server/httprpc_csv_basic.py new file mode 100644 index 0000000..8d59b90 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interop/server/httprpc_csv_basic.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import logging +logging.basicConfig(level=logging.DEBUG) +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.interface.wsdl import Wsdl11 +from spyne.protocol.csv import OutCsv +from spyne.protocol.http import HttpRpc +from spyne.server.wsgi import WsgiApplication +from spyne.test.interop.server._service import services + +httprpc_csv_application = Application(services, + 'spyne.test.interop.server.httprpc.csv', in_protocol=HttpRpc(), out_protocol=OutCsv()) + + +host = '127.0.0.1' +port = [0] + + +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_csv_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') + server.serve_forever() + + except ImportError: + print("Error: example server code requires Python >= 2.5") diff --git a/pym/calculate/contrib/spyne/test/interop/server/httprpc_csv_basic.pyc b/pym/calculate/contrib/spyne/test/interop/server/httprpc_csv_basic.pyc new file mode 100644 index 0000000000000000000000000000000000000000..89af038400c56de60b01dd4b53165c8ee24a0aa6 GIT binary patch literal 1601 zcmZ`&%Wm676um>ql4VPlWZ6ztIV~H&fHx*9w{-v`O&>{+6foL?M&W=PmLW$p?cpOc zBPCw@KZ-80=uh-d`U&0j1KN9swCtiOX~}cXea<~cjlX(pfBy0N&k@v58~=ZeAN3mp zi1Cks0Pq1gzy*WYG6xH;fiZ#_5I5kOf!_q)go~9MHv>l5O%N@}+Tgby_OG(S@uBey_4uL2N+Q2ftt09S{S^hTsn?dkw@UWFzoLz<3Av2;y~! zyTJQ6A;dl4Jvv-lmcIq@2Kd_$_aVV~cYxo6cmS6c$an1O7jxMmhz}qegFmjyZ-V#` zvI+PTEWbmkWBgFc0po3|T%nJ0JPm z3LXVtaG^Gd#_}rXPALmrM1^qPW?~M81gzKOvc^;I7)D^sr@Hb^C(kRqvkyl^~ z!7~+$>GanAVXmL3MP-v@UT9r5f>L4&ZeCT|N?=(dNG_?wXEX2H^nu@Aq;Uy2M z4i!k5i%_I-s0*n+LF-h9Qm1)h*8|yAxE*SHPaW?mN6~$$6TW80XQxk3>{MaIvF(2K z1~;Xq81hWYLLS@vZJ3pU-;{}pnA?)So~M#4`^PJNUgY-UFYQC;i+yUZsk$hV1V=Cz ze-)}UdQ#-GG%?&hefI57&o#}B{GDJRmzo%&96VMl)+eL@Jx2V0SL_)f43{C{E$^O% zsNPz-%qnJK#2vbw*C6kE)P-DmP4bPFnKzsnK0VT=zU^33{YE9JM_14fmU-`!gdq;4 zDkXMmO?adcJ-FkpwZT2o z+|u)}W;A(q6VoouXNCEB87!C;5~+}e%I`9o#pq%mli>DCk!anylCDT!9ewVWMi+<9 zLszAmACzHq875r0hRlOQXZo2lJvu0_Fv8(UQsFKw&8=nYRwKE0S7fB*U~Lk~qpXPM rf= 2.5") + + +if __name__ == '__main__': + main() diff --git a/pym/calculate/contrib/spyne/test/interop/server/httprpc_pod_basic.pyc b/pym/calculate/contrib/spyne/test/interop/server/httprpc_pod_basic.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d196eec29f44ec3a8a00e604e6ddb4aa0dda5193 GIT binary patch literal 1782 zcmc&!Pj4GV6o0cDJGNsxZjwesa9EHcSxDK%0a__4=ORelz}`gWey%{_@=nn$If! ze}O;qI}RLRiX#K=LC#>xKrlG>fctLZ!!0mIrWN2TaEl%-5G^=wFSi*mif%!^3PlH| zoqFAdybDDSroDQ-3i%ooeVF#^bqDeR6hoK}>vb3MbtpzK9RU+P5Pjf1;Az?gbdHK349%Xz&5r(+y_2_3lH>fAhsxwl^E>7@%SD!{06O+k1v1XUTTzM;u4P|MC zR#ixugbvRzTvxLYyRlSN;xU?2+CHw;rF~;CT{KMgABG>{cOr2CP75nIp>_}PXMVhd^Yg~4ky`5_Y z*B))$Vj>@G7tWF27H|xxbIv{3#(maoxh(A3hx0W@=E7;pb5A;u{Nyaz#=YOV*MV3(ID$9g+Hd)S<)3j?mnJbMqKs#Z5T~Gnn*qF+>Bh}TH=lVwp%G^MX zGZ@og2$Ff!7Ly(*nuq?s_0ll$I&IQcl7JlLxi=n;x6tL+h8 zgQ#IBs!K%6PVpKfr>T*6Ar`Kq0c=GhCm(NhG?kPBOXvTDtU0NgT5j`Vz2QB}4 zj~#K=y-n__-ytjZDAfo56&*U6;JXt0?0_7>&(y{)s6CKlc;`U*=enf{_!CeQSUdtn0kn9`UC>YDl-Gf?=@w)0m_(uF z!CWPId{Crek{{?)9>@^GQbfEHos9^=gKWgjXKh)`#wvj1SjAoiCAHv z3zY|jF43Ad$oxf7q)8NFqH}BPavoJ)CXuSFg}M0-vG9t>8hEQWS4o9RzEyKiReD)c z^dY}#DnM1Co8+iUUAUY~mF@*)D2vFYhLAT-sFJ!+9FVS;cxR}3WH>%~=6+1y|J3ghS`jtdIBLJCzo0|0oqz+^axN$6tO-P%Nwcw@!V%6X&p}`=mZ<@er2Ubm3 zbV0TOdt?^^iR2FK)5EMSfyyPit@Q;FMCB5qoS_9P0V|uW4J!v0!#Zw%)rMOt07tMG zgX{ustv%-sOqgm8-{#C`Q*QT_VblWLB>gNwb&r3k!U%O~4GnUqI!1;AEe}*W(}rg# z2}pxjwZmb|QqJR}^XCVL)$>C+Wjiv5^}Ftsn%69O%s!4E_za7=LXS7V;R8=`jTbui z`fS=G@!IGwbsW=n-_I@W$TM7FSYqvXo8ZNrllxRzf@X}r2~%o-O+29<^X)O&CPh6x zL8ZeY2=8as^lh7bbNbpKLdb9hCR381YqPk}6(ZwSF7v6ujW-I*_|mj&y0fh?0(xD& zL&{ZYGE~e5sbEC)6Rl>;s+^_C{OPAN3&x52Y{qd%MHsycV^z(}c{n<8k3VsbpB@$0 z6yd5kw)PpHlUaREW)`s7x>GtQ!91*zC|J`(dvMViT?1T$xgJ1_&37aw4y~Ml7&yD) ziG$om5O8b|O!rAK*aU&pQ4n~K*ubaI>~N~{^CUJTeD(F0KYVLIrTc;@Qzf=3jzOg* zXC;ze@{NO>^*_(M;g5!X9rA!Pk5R=B?_B?OTLkqLtJhnWfjGZfWzWuR5>6ZD=?h~fBN{7-B%+AlIKm#O;9bomh( b+QjjW7!lW&d1k#W+G3An&*|;Z1c<)@Ey=z4 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/server/msgpackrpc_http_basic.py b/pym/calculate/contrib/spyne/test/interop/server/msgpackrpc_http_basic.py new file mode 100644 index 0000000..d19e869 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interop/server/msgpackrpc_http_basic.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +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') + +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 + +msgpackrpc_application = Application(services, 'spyne.test.interop.server', + in_protocol=MessagePackRpc(validator='soft'), + out_protocol=MessagePackRpc()) + +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') + server.serve_forever() + + except ImportError: + print("Error: example server code requires Python >= 2.5") + +if __name__ == '__main__': + main() diff --git a/pym/calculate/contrib/spyne/test/interop/server/msgpackrpc_http_basic.pyc b/pym/calculate/contrib/spyne/test/interop/server/msgpackrpc_http_basic.pyc new file mode 100644 index 0000000000000000000000000000000000000000..352d090e5c6c7c72589b6113b2c835cdec88ffb1 GIT binary patch literal 1810 zcmc&!&2HpG5U#c-Gnv24Bv~RNI2fcwbBWD_{gI+&`N^&pq_A2!LP2veUc1NX#D8>m zvP4Qw!*lQ$To7-PZC7L6?@#%T~%FORo_?b{yFTu{r$J^6KI|e{(p|2 z`U8g)e++Vf82|@3VURjz;=lqJBasWK3kwD(t)+s&QqdyCY{j@)fxHbx2WA~$VSL;e3R^1X%ao0Y+};lFMM9=6`bb$ zoabtb%28jG+^=P&tE9^PLS=QFoT}hjrMc3+C^eT=?JF+Nxm;SwI*E?8uA|qn63K+& z9zDb%<2tHpUPg5#wH1$0e55k*MP272iM6Oot5~Ij(5pzevXVYZ{$;j?!f&`zamHU^ zd|{oaZQ5y~zavCVUIa$aB&NH#K96&e#u|fa(cWsV^#CW;nZCADWH;S??0<~!RNw*( zgJ=U4ZXZAOD-IVw6N8X7NTPzl71o;8F60grE?gm5@RYO#+xQVA`+${4NUZb;0;AiY zJH(_b2QG2B+UT|~8C)U}87$C|3mE$eQex$n#oU1{)U!s_CS!K#!b#ttepGHj3v)Z| zf&2ye%+e0L_^M>^9WwNALN$MB*l<(vB0lAjh1Uo}>KBv0`T%E#I+j|Lnb$DEv!-6G zz58nKzVg)uS{)reJMe@;>7EyS_C}?-nxgo*l$G4`_>XZ>=X|*}sZ#Dq{==D&TzRi9 z^l?>sPe1i`{f84`k$wk>u=e`oOwFxlnk$QYf-5|?N)COImUPz1#9Wo}WH{2%H z#y2!H*2k672nRMsm1W%WLzMH%(AlIK%`1sbBMq^>F37z}YeLL00ok*cQT^ix^4!!G zXE32b6*vTEN(Q-j{pdkZn*!|mj{_w%-=QubeO*uZJCuG3u~u)hI{gSmD9 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap11/__init__.py b/pym/calculate/contrib/spyne/test/interop/server/soap11/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap11/__init__.pyc b/pym/calculate/contrib/spyne/test/interop/server/soap11/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a850feacd3b9d1bde6c426df1f3dcd9fe7fb1eaf GIT binary patch literal 190 zcmZSn%**xW&fbJ%1}I6aE4>E~o7nVIMp zRF-7q=Najl>lbI1r0NzVCTAz6rxxoM7gXk@>Kf@88tWOF=@wK1Rp_Orr$fZ`OHzwV z^fU8HQj78n^ovuA%2JE;i}Mo;3=Q?;<1_OzOXB18fF^SQ?Xt= 2.5") diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap11/httprpc_soap_basic.pyc b/pym/calculate/contrib/spyne/test/interop/server/soap11/httprpc_soap_basic.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e175e9f66a8570856a0aa2540de45e2661dee00a GIT binary patch literal 1548 zcmZ`%&2HO95T2!E%d#X(@^2I;EgK+(FD5HDO#mZJ{}LnxjG&NFIN*h4#1Tz<`QzQS z6QBJ8J><|+-=uHSN9e5&(9UpaIYCoWT7;@~lC;0tw+;2i$S=Z62X0+-Z52C<OAP(w~uZXd-3OJaKD8 zu61`KKwlgGa6fAdDiQjf{ynNo$?ckykMl@hPhOp6#@ zg=gofLhb%^X^xBBee$)t=Y6&FDMcC1E{h}~2vy^+Bb`ovDDqjFRAfGV_WjS#4dbSH z9*`p{!!&RVT`g(mfGIaa(%TtFH{?z##_!Ed9~*x)BjSDHkegYX`(9H}@iS@skC926 zG}(9qpyu@rEysj+(v0RwKLTLF9hqBn)Qb>u&hWi14Cg;Cw5cwj5%s|ciWSLVB-ZR(yLxC`7(X|@PS`e-0yjhe4QHHEu-mal%V!2!glw(@t5BC;cj_J9v&u%)%!dw zzg|t>Lh^Ywi;j7n literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap11/soap_http_basic.py b/pym/calculate/contrib/spyne/test/interop/server/soap11/soap_http_basic.py new file mode 100644 index 0000000..65a8605 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interop/server/soap11/soap_http_basic.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +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') + + +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 + + +soap11_application = Application(services, 'spyne.test.interop.server', + in_protocol=Soap11(validator='lxml', cleanup_namespaces=True), + out_protocol=Soap11()) + + +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(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') + server.serve_forever() + + except ImportError: + print("Error: example server code requires Python >= 2.5") + + +if __name__ == '__main__': + main() diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap11/soap_http_basic.pyc b/pym/calculate/contrib/spyne/test/interop/server/soap11/soap_http_basic.pyc new file mode 100644 index 0000000000000000000000000000000000000000..95048ef6fe36c42cb387db1f13b0f0812caa4e54 GIT binary patch literal 1837 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap12/__init__.py b/pym/calculate/contrib/spyne/test/interop/server/soap12/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap12/__init__.pyc b/pym/calculate/contrib/spyne/test/interop/server/soap12/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7ca14cb69382939a763a100cfa272364454765d2 GIT binary patch literal 190 zcmZSn%**xW&fbJ%1}I6aE4>E~o7nVIMp zRF-7q=Najl>lbI1r0NzVCTAz6rxxoM7gXk@>Kf@88tWOF=@wK1Rp_Orr$fZ`OHzwV z^fU8HQj78n^ovuA%2JE;i}Mo;42|^T<1_OzOXB18fF^SQ?Xt= 2.5") diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap12/httprpc_soap_basic.pyc b/pym/calculate/contrib/spyne/test/interop/server/soap12/httprpc_soap_basic.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5d2964017fe0c03c0d8fb2151a12c5089536da45 GIT binary patch literal 1441 zcmZ`%+iu%N5S^uD$=1b^W6PJO1=s>9^kTA7a{-Jry(LHr7;Pb;aKRUrA;&W9<;A;e zCw}&KK@l0CESi5d@w?1U<xuoGN2aQxsc9nup8!OpjcP zD{}|v4FV?9XWmz|Cg}l%He6*GW)b;?RT11w7F}RirKmvmypCj=M5a*sbCTvJQYOt8 zZe5XEnY)p3AL*k<+SA-FXQE}NcQSu@?53J5j$HrScRG=JLME@2D%6pS@1v}gxC|2) z3Azd|uTq8D{q@G26}kK38+YnG89U^)8r^m>{)|w=Ic2d}P+@i)ZzG+?KNk6Ey0Bcn zeD%X`uMKyzKyyrns0_2fK6I=&Gsn!h*&@7}e00z4%o6^^o$9|xv6Ca(XI!Y+zO!8t zV_BOu{zu7F&YG;eFQ8`o9o>x?UrDo1Tg`pQ4&h3PhMms}ZS0{el&M+HqYT5)j7ZIq z6rOrI<)PP9&v-6oxT3Bp$604p^HDOMUR9n=m*%I1=`XSHv`{olWx4n%<611;V={pI zO<$7eUuosb^zGBferf5Rde3~F8aync_##@M_AMKSQ*ZLMH+gzk-jIcdi$#U|OodF%Uy%DC*_3#6$X8PERx#qyN6M LCHi91>5G2>a|U0{ literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_basic.py b/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_basic.py new file mode 100644 index 0000000..27fe6f0 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_basic.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +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') + +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 + + +soap12_application = Application(services, 'spyne.test.interop.server', + in_protocol=Soap12(validator='lxml', cleanup_namespaces=True), + out_protocol=Soap12()) + +host = '127.0.0.1' +port = 9754 + +def main(): + try: + from wsgiref.simple_server import make_server + from wsgiref.validate import validator + + 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') + server.serve_forever() + + except ImportError: + print("Error: example server code requires Python >= 2.5") + +if __name__ == '__main__': + main() diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_basic.pyc b/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_basic.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d62b14a9a9628ce17813386b9c4565fbcffacdc9 GIT binary patch literal 1725 zcmc&!OK;pZ5FSeFeXnlY@Ui`>+Jm$Y=>YgThT){^q+9|l9VZ$> zI)rEh=?J0?NH^eD41N>%7NnbS?11_M_$C>%!sa#`Z(*L|AH1HJHT;$QgiF0i6{t=N z?pLZb<-C;s%UtSDFV%)?Vzv_mq`^L8dJs36D{UrhSp|?Vqa(CyQ-36 zo)}RU^+cO|;X*Ozy4Lhi^B=P&Dre|;GS$~iqv9w5qa|h0_Buy|aIAd^zEMl-kBNt2?ju77lp}dV+ zwo#$mU-4CY^Z*&^G%7^5{mE-!|$Ix zvQ3t8vsag}ZfUbeM@UEznGF1N-ejYmUB9J%7=3Y?)!Q*?a2 zb5c<;Ldx4F|5Pn_NSKD}BSDD10LU@`Tzg` literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_basic_twisted.py b/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_basic_twisted.py new file mode 100644 index 0000000..d115e2f --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_basic_twisted.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import logging +logging.basicConfig(level=logging.DEBUG) +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 + +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 + + 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)) + + return reactor.run() + +if __name__ == '__main__': + import sys + sys.exit(main(sys.argv)) diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_basic_twisted.pyc b/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_basic_twisted.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0821bacd968b5f9ad0dc33005ecdf2ef2c867ffd GIT binary patch literal 1458 zcmc&z&2G~`5T12@+O%n#QYat}Z~^5~yD6xZDufW_=TZT3K}fk6C*Hc7+Fr{$X^51b z%5!kyz)SEZJOVc!0A_Ym${XOH_0H_rwdh7Ha&}+WXKuVE1BvvlqoavKYgUo}x2Iro$NscD2K z6K~M)*4l?UP3gEd1D6nQ(Tc&i!ui4ng(rU(Ij77O+MakBXGVq|xkB3sOvb@~ckmWD zwA2+^zQmgku})PSYdbm729fbs^9wfJ4hl>q~%q;H0t{4698h*uk99 zEEtQQ-LQ_t zf!YzkW<1cvu}ZDD&tE)y|H}49Ds3rbg-wcMC27i;sBsSYx5RBW>~G27T?goL-XXpN zZ$JNlcO_$_Zl`1F&nda8azBRLTj6aQ=IDz!mr-QvW~Rmxm!A}d+)-Dx`0oW_fga~N c8E5i|Ww}X?w%8DBR1_{uQ#8F+he{*<0HOs}Pyhe` literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_static.py b/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_static.py new file mode 100644 index 0000000..6cc742f --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_static.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import logging +logging.basicConfig(level=logging.DEBUG) +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 + +host = '127.0.0.1' +port = 9756 +url = 'app' + +def main(argv): + 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') + log.startLoggingWithObserver(observer.emit, setStdout=False) + + static_dir = os.path.abspath('.') + logging.info("registering static folder %r on /" % static_dir) + root = File(static_dir) + + wr = TwistedWebResource(soap12_application) + logging.info("registering %r on /%s" % (wr, url)) + root.putChild(url, wr) + + site = Site(root) + + reactor.listenTCP(port, site) + logging.info("listening on: %s:%d" % (host,port)) + + return reactor.run() + + +if __name__ == '__main__': + import sys + sys.exit(main(sys.argv)) diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_static.pyc b/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_http_static.pyc new file mode 100644 index 0000000000000000000000000000000000000000..980bc1b8830657605a422e516265bf506bd217c4 GIT binary patch literal 1806 zcmc&!-EQMV6h7npr)iu1Y`ZKg6c9zZsl6#^S6U&2C@eRtW#ukfDL281r_N+;kL8)P zR7$SOGjV~$oA3zS@c?kn8K+&r0}#jKIlptx_Z_?T*LL^MKYssd2Gy^I&#&<|zu^+& zUqA{l29N*?0kOv$4{kvSQq>@?!L5LC9b_FAjg47=sG^%NZgQqNq%FwWFm5|r1JVv; zT^M&!Mz1Z1TQKfHj4s;{ciHIo{?FHHabNhA?IV)&va7HAp?k zYOwa4jNsHEYrwkZWCW)PSqs*6C%+%R60m3kLWT{m8$eGsdLe8N7Td7c zAvnpe33eA2eZqCsgd@UgRiiB#F=~&XpnZGe*o77D58%?P+*`0XBn7H(vFw!xs}_e~ zO62|l*dthV*jAmj1@@Ssc`4H$Y|1P-+zb)pgklz{{1bc{T0rzSm$xg9ynV4JdR|W)i@w+M`r_DQ^d=LEnoNc?Uf~fg z_|5`MBco>LI=@s2GxqIw-~9MJBb-R)SC*Crg*d`30fvmeq%T`Ynd}qN@aK&h@vBCv z`SV>P{BVu%d5+t|yGYlyU(K(h|1ny_4{4!s3qQrB>LZUbIhioa=EjYc{8`!XBXqeZ l=l^4fF#0mn@iLWPagUEs(Gv$^w_>F4H3eQ?=TT4e#6LY2n*RU* literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_zeromq.py b/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_zeromq.py new file mode 100644 index 0000000..62c2b73 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_zeromq.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import logging + +from spyne.test.interop.server.soap12.soap_http_basic import soap12_application + +from spyne.server.zeromq import ZeroMQServer + +host = '127.0.0.1' +port = 55555 + +def main(): + url = "tcp://%s:%d" % (host,port) + + logging.basicConfig(level=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("listening on %r" % url) + logging.info("************************") + + server.serve_forever() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_zeromq.pyc b/pym/calculate/contrib/spyne/test/interop/server/soap12/soap_zeromq.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d8bf4a9740e4ef1e48277a0d651ab9a1a6d5be9b GIT binary patch literal 1262 zcmc&y&2AGh5FT%STUuHus^EZR4pk$nc$rC*ElKYx7t)Q8#U(f)*{`9RBneg+9Z zuaG@R7^EKbJYZH=f}{j#8G22&x}MbP&AUCRPoy?;bkS;Wi%lA>xbz*s zC18Uu(d^JPUumJ}k!&*D~h`W7Yq)omkI_9Yk+k)1Gw5;9%}aC>J@15?u>lQI~s_-f`eUijRM7fzT^9AW@l}H6*?#K zL?*^@l20=!a;;GHRU%H)#M~yp{eOIBgOvM5@($``<0D7K2aA8Hxy48vnSRGOzsOM(uSFiSSg*r3efEaGHgO*b4BWm1fkL9{}y zG*Tr9s-lR1XdwroiTfRu4dckM_3Zi6{TFDPB9i!;fKpTGs0Zj|iR{`A>(T^g)B49n zr>AZTC@uo&hV34-?K9R1Rxj1MK@zyd9FpXZjrNoHVC$iuJ8s%y+cz=FW*+vB!blq5 z*pfBdqV+(uwwn2r5JE;#aqlA$=EoTlL%DBUKl?@FyDgYeN5*abX&7gBX*aiM0k-U| zushxoTeQQwLDMA~1Qr(r4a-5-HV|&o;sO!Yp_n-og+oy|bX#D{7C1@^idO!Px# literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/test_django.py b/pym/calculate/contrib/spyne/test/interop/test_django.py new file mode 100644 index 0000000..b5df8b5 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interop/test_django.py @@ -0,0 +1,305 @@ +# coding: utf-8 +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +from __future__ import absolute_import + +import datetime +import re +from django.core.exceptions import ImproperlyConfigured +from django.test import TestCase, TransactionTestCase, Client + +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 + + +class SpyneTestCase(TransactionTestCase): + def setUp(self): + self.client = DjangoTestClient('/hello_world/', hello_world_service.app) + + def _test_say_hello(self): + 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) + + +class DjangoViewTestCase(TestCase): + def test_say_hello(self): + 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) + + 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')) + + def test_error(self): + client = Client() + 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/"') + + def test_not_cached_wsdl(self): + """Test if wsdl is not cached.""" + client = Client() + 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') + + self.assertContains( + 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) + + 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) + + 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'] + 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') + self.assertIsNotNone(email_field.Attributes.pattern) + self.assertEqual(email_field.Attributes.min_occurs, 1) + self.assertFalse(email_field.Attributes.nullable) + + 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') + self.assertEqual(blank_field.Attributes.min_occurs, 0) + self.assertFalse(blank_field.Attributes.nullable) + + 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) + + 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') + 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) + self.assertEqual(length_validators_field.Attributes.max_len, 10) + + 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') + 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)) + 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.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', + date_field=datetime.date.today(), + datetime_field=datetime.datetime.now(), + time_field=datetime.time() + ) + 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) + + 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) + + def test_abstract_custom_djangomodel(self): + """Test if can create custom DjangoComplexModel.""" + @add_metaclass(DjangoComplexModelMeta) + class OrderedDjangoComplexModel(ComplexModelBase): + __abstract__ = True + + class Attributes(ComplexModelBase.Attributes): + declare_order = 'declared' + + class OrderedFieldContainer(OrderedDjangoComplexModel): + class Attributes(OrderedDjangoComplexModel.Attributes): + django_model = FieldContainer + + field_container = OrderedFieldContainer() + type_info_fields = field_container._type_info.keys() + django_field_names = [field.get_attname() for field in + FieldContainer._meta.fields] + # file field is not mapped + 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' + ): + @add_metaclass(DjangoComplexModelMeta) + class CustomNotAbstractDjangoComplexModel(ComplexModelBase): + class Attributes(ComplexModelBase.Attributes): + declare_order = 'declared' + + +# in XmlSchema ^ and $ are set implicitly +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, '')) + + def test_valid(self): + """Test valid email.""" + 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')) + + def test_invalid(self): + """Test invalid email.""" + 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-')) + + +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.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.service.raise_validation_error() + + +class FromUnicodeAssertionTestCase(TestCase): + + def test_from_unicode_does_not_assert(self): + client = Client() + 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) diff --git a/pym/calculate/contrib/spyne/test/interop/test_django.pyc b/pym/calculate/contrib/spyne/test/interop/test_django.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff2289a2a8eb695c6262425b523cf18c6a97cd82 GIT binary patch literal 18325 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 E2ZxcL^8f$< literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/test_httprpc.py b/pym/calculate/contrib/spyne/test/interop/test_httprpc.py new file mode 100644 index 0000000..4d72bc4 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interop/test_httprpc.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import unittest + +import time + +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 + + +_server_started = False + + +class TestHttpRpc(unittest.TestCase): + def setUp(self): + global _server_started + from spyne.test.interop.server.httprpc_pod_basic import main, port + + if not _server_started: + def run_server(): + main() + + thread.start_new_thread(run_server, ()) + + # FIXME: Does anybody have a better idea? + time.sleep(2) + + _server_started = True + + self.base_url = 'http://localhost:%d' % port[0] + + def test_404(self): + url = '%s/404' % self.base_url + try: + data = urlopen(url).read() + except HTTPError as e: + assert e.code == 404 + + def test_413(self): + url = self.base_url + try: + 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 + 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 + 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 + data = urlopen(url).read() + + assert data == b'punk' + + def test_echo_integer(self): + url = '%s/echo_integer?i=444' % self.base_url + data = urlopen(url).read() + + assert data == b'444' + + def test_echo_datetime(self): + dt = datetime.now(pytz.utc).isoformat().encode('ascii') + params = urlencode({ + 'dt': dt, + }) + + print(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, + }) + + print(params) + url = '%s/echo_datetime?%s' % (self.base_url, str(params)) + data = urlopen(url).read() + + assert dt == data + + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/interop/test_httprpc.pyc b/pym/calculate/contrib/spyne/test/interop/test_httprpc.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eac24b6c1cfcc8cc94500fa9a18be5fca4915d88 GIT binary patch literal 4609 zcmdT{U2hvj6urCaIB}Ygw3I-o097<#K4Ld*TBNF_Km}At7`h26wS<Q+-lBpvEPoJaY@${BTrz&n*5H*BkSVanRa!IGs_ekxry7Z zf@VMOn6%Yv8#i9`dYMVJ9hxut#yXvKeRcKYck{fLyJMKOis9?dWntFZgOOUigU8;2 zz=;aba2z7$@m#>F?Q5e%z&J7{?UFXi#DOE@0}uciPS25wv?sJNDd9?$Dz~^7%{F}O z8amhn%fobCPrirrW!DqW1!8Z=x1#U{@{P!@FRmn;W3mIq#^t_`NoCo@#wEGWUrb0G z2yw;~waNV4jz|POL<-;=ihR|_u2>3t#Yw7-3;;cZ$dh<$3E6jQS8`=V&C{r2Pzu50 zgfyUb?PqA!`!=t4lG_)T>)E#3=%wdsZ`5t#%wiU|w&HbT>o(g?&EmP*()rrb#l>tJ zGiqjiy%?`Mn5Yh|Oy0}16K%j?dDg07y-Dnl_tU7L$1CVro<+QbUzSR9_N98g(`&_@ zjh=Ov7TO7?6dH2@_ZoyMQR8N{!Dh8$(b{0UDC@PO+p$erdcu(Qb2AWw&4=6!70g*K zNwP+%xf=~wN`y&kNBY{1F_~h$n)i*;9;=%OG_H~k`pTNln(h=*(Z7Lw1o*0=#(k2V zp~iGX@#p-qHxtYT(|*NQ0`pj$cnyyYAwXd8Y*S;$q2ck&r1Y(s$2SDvJve5y<%A`MHAU$FJ%v&+d3;98aa@HmA+OTlmu za$ND#a6q-+wy>s4da3$;l{3Q=oW+F!xz0w|iJ>dJzCao+IRcO;unmb9;anHEC2cL< zv=?}D-i)^&;}yIv04Bbt2Kd6u5sXgqK`7V*8Gr)h#t38tuabiN5ixoYWWv@^MAmw} zgvcZUq>>+ji3U#$7ylZ73*>2e1w4F;tvQGhyy4Rvdxm13FYp{$Y#711bpA5-9l%-v ztfvly^-!tHPz350F)%V;w&47rWAev-9)~9}_wk1G!r8OeMvy+5sfP+F9UqX|UYz}3 z0oC+F*9V}{xep!zDLs){MImQ|cqqW`kFKl-ia5H&00$RuGh1_+hNYJRHPhPYA!X%B zx_;GO$@=M*hCnt7_uUJt1s&C|xq^nxkzXIFOEar#qq{R2*ix+J;!fT-X%>w{q5NA$QhTY?@kiR`~zHA1XxKUAJ1Q|y2IMNO( z%|z2Wn067V9r*^dd;dDp4^z`P3waFS&6uUU9i-79jtYia6AEK*nAjh$W_ zii<)>o@f@+sqhA^BOV~UCO6gz;R1JHg3RJP?%Myz0jSEzphFl~XBWkpciJm^)4`ZG zKXir1&a&YdXsdAkyGg^BIQL}=#+i@>e)uZIp5;Oo@BeJJ@O4hvt3-}8Vlmq8H(2EE z@eXo;&8oa&>17~_(zt7)NbfjN)a|wV9dtt$65+EH&rv*2@dCwZiWeysDQXa-qiXB$ zYuS)jZ|Y#l)UsDOUKt;J%9V0uYH%`MGoz@gY@WcxewsL<6tYw=?2U#v+WUZuS)_<+ z-fwjhT=ID@Ga)N?MXUHp-z6Qrj1^>ISP9ji^>)D4dvOOpV*pXTR-wT)F2qBGbqXqX f-|_={{HRjhYaRF55F&Qs4pmT{5wzr zBvyB!bf9t}alxTA4@wUz9}?freJEQ{wIOLk)q$jAtt}{*pz1=>#d#aJ4;SYwKwU&ov!E0@8chEMH zvzlAuF<1H^RXlL%zy^v+jb)mhH!@?Xlx2~nx)8PYaY>41e#>o~H9}~X7nx>SFs>WU zHC;|O8V6UN7tE29103oV3PhMV#2>;#wzvmpK5==8M%Q3=AZh(+_kP>k5RU?iDI=sb zXmW@{?V-@fo&z5ZFPE4JjXb)bJ<7-C27*B&uCf;7zERo~$S7#x*(2RYIj4aU4-@22 z-9;lQ`%zSiEG;KO>HUX!RG=NyCJCZ7)QCSUYRwxVL&cj5-UJ<7jZI3(f#Uj|j8TEu zBVnj-qn4RGVXOePvgsmJikGJWe!&QZwFc2tHBnid>^_U+Oix6;6YfQ-(0oX_OUGPA zCYs?+xcxNT-W|#r?g;sKZ0!+68O@_K6Lu}{HVy+jl(U$k-@>7mP=M2S*PNcC9-;n* zD}~P9qR&`ngIsVmsD&P=siayNOn92}W|1Odz@&&!8NSJKWU-MNQ^npOR8zo24ddBF zu%c!b!2=9SQCh(LkHApH8Ze62ITKSoNAvg!jj2pcd1b6lE6$jCG#INyJ}q%-l5aLl z>q66Q<|R<)g^XA5SlmN#l`*6J`wFG5x{pIq7qy*k=bk?YRi&6j7ObH?zJ)@s(>Bwn zw#q~5Y154Q$zq9cE_#?*4n->2yfIGj!L;oh{r!k-`|w&zkr#&Nip;dTX?#ryvaw8c zQHJIX%|v|>Q-2r$#~8>Vc_W1JDw%1GP~9}?CcfvkPF@%!L~_sVJAG#ZABnB?p7RU% C@W~wj literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/test_pyramid.py b/pym/calculate/contrib/spyne/test/interop/test_pyramid.py new file mode 100644 index 0000000..2dd3b04 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interop/test_pyramid.py @@ -0,0 +1,76 @@ +# coding: utf-8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# +import unittest +from wsgiref.util import setup_testing_defaults +from wsgiref.validate import validator + +from lxml import etree +from pyramid import testing +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.server.pyramid import PyramidApplication + + +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 + + def setUp(self): + request = testing.DummyRequest() + self.config = testing.setUp(request=request) + + def tearDown(self): + testing.tearDown() + + 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())) + + 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', + } + setup_testing_defaults(env) + + request = Request(env) + resp = request.get_response(wsgi_app) + self.assert_(resp.status.startswith("200 ")) + node = etree.XML(resp.body) # will throw exception if non well formed + diff --git a/pym/calculate/contrib/spyne/test/interop/test_pyramid.pyc b/pym/calculate/contrib/spyne/test/interop/test_pyramid.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e25d28e2ade87658bbe76761b71f028368538da9 GIT binary patch literal 3404 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 tag below is wrong. + # + # + # + # + # + # + # abc + # def + # + # + # + # + # + # The right request looks like this: + # + # + # abc + # def + # + # + def _test_echo_complex_bare(self): + 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__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/interop/test_suds.pyc b/pym/calculate/contrib/spyne/test/interop/test_suds.pyc new file mode 100644 index 0000000000000000000000000000000000000000..45f7c314310e928ad3691a5c18a15e1865e41f3c GIT binary patch literal 17174 zcmd5@+ix6MT0hm@zO?VLW5=Fk5>F8|eSs!rm~gq1K74}b*Xz7m4v1tFw)LLh`d{0aNa&AG-Y+J@Hm|e@P z7mQah+eK+CvBipq4w>~KnN~E-VbdBm>%-btGR+aw8a3;qrd2lUWo;cY%`wv&H|yhi zKWv&4rZs8SC-r{BG^b2!+N@9O{itcqnAQoienRidra5a`b7p-`@5fB@q-o8Y^?B1; zFzX9w9XH;z*#zVh=2wl`HRjvvr;Iykym{jdne9chSupNY+P7r9=ZrgT9u!P>%HoLA zoMZ)pio2B=;Ku(6eyUN4XzICP1(-6?CIL<->m_%t$2*-e zi~%3ix}n$2?r%1IFNpMh68*QmFswDa51PG(A7oFu?`^zO>owznBwFY{*2m7_=5A*v z@N}trUKrh|giR*W!ZmDSH5x+EA!el3^*YTR=~bM2&CO^8BkJuS@*YPK=Y_S$75p<&gy2`R+6%j@ zO&=6k?d(Kb?cnmtYpbCjc^5mi`UBuJTn&k)i4l$Nh-s}9g@n3afhWcYTOa2 zl#M$ol`-R%r7~{ZF{w-#NGBJZjHPpZijv8e=~yP$XDEzpIbqxxsmvPpgjD8?J1dow z#+{SOym3!TWx=@fQh}&1NM+Hur=+rE+(oHC%$KBc+PKe2<&1GpOXYdvo{`E~<32By zbH+U@m1X0elgbOmU6#su%EAjkVx2e?9OJ*p!q1@sS%3(D?SaMJg0Uh|oV&(+WSOUy z0Y?L?5RV1m)WxWhfk>dcf#Ftx;sTrwaRCQ7rQA?rRQqg2Q72r&Eh}%Xt~T5CT63!% zMsL34u73Sd=r%=u>b3foClb>UH4@4kVg3~|`AW>>E2vkAi}XG4 zc0!x-DRlUGOkuh(XU$qd zq9R%dqLAn{RFp)(Ip_gALs7xBZI?(Dm^P|0v=?X+!YjnduZSL01y~hw*d)E^p`iW9 zKEoR-DB{zvdl416SKn$oiGdJh{8otm$ZrR0-EO<9+E36$03X(xvR>CaI;@F3AVWBP zz`o8mA=4Ra!kRC9p*Xb9;W2_hdl|Kea@7Zn^T?0396tbleAn4*cU!f{K95lu{_GcV zYhPd+uA{LCU&4d-Vs1ZRzlM>AV)JLYlqd~wq!`VFFNG<$p$qo%%8Kr^tNA>GH(h&lOa23_F2a!EKDxh!IFlyq&d=d$p#08TZF)uNl#1=#AmrKx0VYjWuk|!)atG z?hYBKfJ^Xt3l+MFVxwW8>DY@e57Yv|^cS_aWN54%&i zm%jPe_nhUD)S_S;8asIHbHs@6hUg1HWElf02T}WaN&i_ zALq*weIdj%VL_4lltDGpbR^IOKAj=6b1E4*Y_>;YBwP1`Ia5NO;K7*b-Zd6D+6pGk zhu|;-sX%_>Xp+6E;c1jlwtB&Xl@P^KgoIVU*{p3ek%5BL`{dJ*e9-EJ(eh@^Z&nzU zsls@ZwVy@-ZI8^F&Bde|DxoNjK|64QcuAXLA*{akxbAfrK4qFj0+{@0r%niDJ@4pv zUV=FCyaXvV!uVZ49WwXB7^=+QLeV;9O2tsO*dUOn5{Y zIk24xzCj48Cu1cf5MkPd?M-cgq{=`I8B{RuzQ@UBPNPlMoDjq;YsHdig}OtlP?4mm zO7iYj@Saz5kvkv-YeGFSv0=N`*^-`cKMAw>e)bI%I@*hzwg^xxYN<~214ow;X|$Ol z$;lWcIU8|-ow$xB%$~!8@`R1y{0%h6(lsx##az!^VW_Z>nQscE5cm~f?eh^>m8k4< zfS^pq6^sKwMD~#8M1m8kO(Zp0BD;yarerj+t-v~RnG>M<2xmbsm1!_*hSWzRHXw4W zGfK7~>wqnCLlf31#;h}*unyF~gjoU;kx@89d%!+%kFrqQ1D3+uqo<5H;KpnYdH`J9 zgA8QCcJ!30_8pWq<00iXCbVt^_qw&Zr>tnBK{J9oFsJ?xp)SP#ZXrd#C7MRES@2cF z8Q*I6y1q=I(rfuaFZO3bY>x!4@Mp`fciVbzGm%=M0vj+I8B1#hj=lv_pv||L=pan0 zpcYVz6_itN)8Bu*m%~dOPA;+Up@>)mn@4=dWbn~4yO_c>8wXhWLH|Ag3>hZCnG%!2 z@~pL3Sc;kdIg7t_Dv2U4YH$$%PK;Tr-#q|{1`G>$eb*G}D!|l;djOvyo;#r9MroD7 z&DijuF2tWWz6nc;E~B;^WJj!rRy-$RIMT2x7XD5zin;4P+Jvd>4_V_Y+22Odc>Uj2 z@BP;cA+Koh2ZYnpBvLTF@)9ytvWo4H}BNWDoa_fhFfQ_;M`CGC^wA1kh zRUzG&Y>^}OtWOdsvd6%?e9G6OE+=1{g`+WBIAg_%kUYTG7e4qQ%<}&OA1Duv#!mUZ zJVd<+WeEj|5(*L}^dfmHR*Iiv)?_jZ?5O&2Kx2;4yit)&nI$+qdzf)D=>#kGGi272 zXG%ULU2{m+6xPl$xXwf;b*N}kvNLC9J%ATIBdN|s=aku&jjpBb8MBQIu4y8Xl^MY% z;6n(BTMaN(@?cp`nC;mZ^zAv?itUpu^<}o_vldzwm>4*OSY%cfUtn(rTy%>o zs`{$Efztj=r6Ex_luX`^t#jrtu=t3@FQV|Vuu*G8-Lw`w^qTFC#^0)+M7!Lx>zu*C zV!vdAxD(M7i9W$jPOlsAw!-Aopd}NXmabs8Ii$m483o9c(^>s?z~1Dj28%5gbk}6} zDRJ%=*(zZq!Eboc%`Ly_ic;Hd`++38Mc?{iJKj)X22$3*=zDPWZO)W2+;DfO3pGlh zGO>x9hzBF63-=gIG2UWM>7VA6?mVWXZTWc>bR3OCc?J*aSEBvM{ab>_4X{|5LZvR! z$XaKiR+q)VN?EKRmSg*Z^_8^7`+8!2i&*0(S6fA~H^ZT7DvlQ$niGuo2;MUn#|meTl_;s+a#U=$@# zg{^S-CD+^{E(v)X@WO}9HTI53@2K9Cgn-d^Q#g|CabB)i4x-L9i0R+dEhwEGtT2y(-Ck$iXRch)aAx1 z%I{QRvQV_faGfZQWKu=J5UJ{*LVJrp*aVPYZKiMzB#Ak%Jz;yACZX8D_{ad1OeWr= z{zION?TMej_Ga8J#)gtu4Zno)$$_USp5B!W22F*DUZp0eg>Hp9bjdZ)joqS zm2KUnkaX5Fkd!24gj9Qg`w#TQIdrCY%Z2$uP6?*u`eO_`oLqZ*Nk)jjQmG^)O`M)A z86#0irc4K@`h@57QmV!Thj*hi|D(7!N83w)^AOq!Rqx|O!d;w6v%O8Pi_?CdPcr+L zQRq<`8W}rHrD+C+m@FNXXzwnr3F83lM(D zc{DbTnFjJJS+-PH8D|q$(Ue@7E02B(S;K|e*I#;5Q8=({IBtz5Tn;Z9m{4Tn~BJooLJJ%6l{({llL;xB9QYbX_8ogVjBBj^-+AzWoiJ#ptELtmt#lm^(JkIsWFU-trtY;SBiNB&g0$)4b7kdRaDhn({@S*u3L2woj4nb%k z8gnU&7BRdktj6F9Gyd~>g=-0_1|0CMUc+;+!?}U1Jm+E0K{m)Gp?Gx8RO(9R;JHZT zQD97l5;`t7afKI99E1|!<77WF#Q*&2rOQ{YzIyGo*WajZ)Ln1WH`ih4xZ-|@X|{s~ z&YR2mZW80T5R!xAt3(LlWlUEmP{}1IVO}lPn8G5v=y$UN52S96_%vi{5nG*T=NM>i z{{RqNT;tDWV*A#_jzMM|6C=F;h}byFAlT@fam<<^jiX{U zv~(?OkelutHl-KT5Z01mOW zeUQ065`!%6fc@J5>VIL9Kl9|mKOtW(#~0M$c!I}B+Ke8HkG^=noQCUg%WnS;hj44z z{yi4I&w^S<&pX#y`vVrV)%G8v5QE*3vMJ@qYP_kPButPEc;f$=vER&UX2HP#e6LYM zF$PLa_yOj75vEza+Kv& z9A$yyA6Vu?QRrN&I&d;Y4Ez~%D7tA-_3I(WOU|3vYwRZZvm*}nyS&A9G-*r9qM&*Z zw(k(lv`NgH%;0zWSkT67vt)LkC8W(INb83T*~J4YK>d>5v;^Ogc^79UYd(h=mi zSjB1+Ho4$X_BA1r$`rAV!uAG2(~?=@c36_`rQ2T>)h6oZ9{hBl%11XL*n4~J_Kh_= zmtI&#qwHrS`D@*75SJ|8ehBfs;7xvt$gEP=PcP5xfuH(#KyXCa>GuBXZSjWXd>6ZBbR1oDfBFN6;{ok-+{|(-L z5F<1v`IIRfDerhul3J2Mut4GgoRIlboP2~Ea0FBw_F7_9m;}{Sa++h3^s9Q4Xps$Z z4AKLN5^eL8lPE&6)`xp?>k>;N%#{C#H6;t8(WE4C_RXQoIU%M`)P$!w^h9lBNEdM? zmukA>Hfu+#)3~pzn;x3`jSnXg#6Qaf7N6b0l+PC`FA_p(9hqf;Ptf9*XER3Ws)w9|`Z>p0R(EBY%s< z_gOHVZ~rNaAF%jy7JtFwFIoH*i@#>U?Ns~kSo|Z3%ydZYi~c5*tWG-+-as*ImCNPf zzTa|rv^-LtEDx2Z$|uX?<@4yB$N$OlxpJ{w!u2xxM`YAcd0C92HHKOAHA>0XYyVBY(9C)ihhWzpXsKJ`th&LC3!SXU0CrAbn~hg`AyyE ze;K{|Y-lN?iua@sa0r@wDJxaO6HFC~P_7Ug8u=0|`)zK1NQ2I0a_5IfKoz`Zm}A literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/interop/test_wsi.py b/pym/calculate/contrib/spyne/test/interop/test_wsi.py new file mode 100644 index 0000000..cb0aefe --- /dev/null +++ b/pym/calculate/contrib/spyne/test/interop/test_wsi.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python +# +# WS-I interoperability test http://www.ws-i.org/deliverables/workinggroup.aspx?wg=testingtools +# latest download: http://www.ws-i.org/Testing/Tools/2005/06/WSI_Test_Java_Final_1.1.zip +# +# Before launching this test, you should download the zip file and unpack it in this +# directory this should create the wsi-test-tools directory. +# +# Adapted from http://thestewscope.wordpress.com/2008/08/19/ruby-wrapper-for-ws-i-analyzer-tools/ +# from Luca Dariz +# + +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' + +WSI_ANALYZER_CONFIG_TEMPLATE=string.Template(""" + + + false + + + + + + ${ASSERTIONS_FILE} + + + + ${PORT_NAME} + + + ${PORT_NAME} + + + ${PORT_NAME} + + + ${PORT_NAME} + + + ${PORT_NAME} + + + ${PORT_NAME} + + + ${PORT_NAME} + + ${WSDL_URI} + + +""") + +#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_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_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" +] +WSI_CLASSPATH_TAG = "WSI_CP" +WSI_CLASSPATH_VAL = ':'.join(WSIClasspath) + + +def configure_env(): + os.environ[WSI_HOME_TAG] = WSI_HOME_VAL + os.environ[WSI_JAVA_HOME_TAG] = WSI_JAVA_HOME_VAL + 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)) + # extract target elements + 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} + config = WSI_ANALYZER_CONFIG_TEMPLATE.substitute(vars) + 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 + os.system(WSI_EXECUTION_COMMAND + config_file) + + # parse result + e = etree.parse(SPYNE_REPORT_FILE).getroot() + 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) + + # filter for the object describing the wsdl test + desc = [o for o in outs if o.get('type') == 'description'][0] + + # loop over every group test + for entry in desc.iterchildren(): + # loop over every single test + 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 fail_msg: + print(('\nFAILURE in test %s\n' %test.get('id'))) + print((fail_msg[0].text)) + if fail_det: + 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') + configure_env() + create_config('http://localhost:9754/?wsdl', CONFIG_FILE) + analyze_wsdl(CONFIG_FILE) diff --git a/pym/calculate/contrib/spyne/test/interop/test_wsi.pyc b/pym/calculate/contrib/spyne/test/interop/test_wsi.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a9d0e1026f02382604cea4b73fe88a377d383d66 GIT binary patch literal 6033 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/model/test_binary.py b/pym/calculate/contrib/spyne/test/model/test_binary.py new file mode 100644 index 0000000..06a4841 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/model/test_binary.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +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 + +ns_xsd = spyne.const.xml.NS_XSD +ns_test = 'test_namespace' + + +class TestBinary(unittest.TestCase): + def setUp(self): + self.data = bytes(bytearray(range(0xff))) + + def test_data(self): + element = etree.Element('test') + Soap11().to_parent(None, ByteArray, [self.data], element, ns_test) + print(etree.tostring(element, pretty_print=True)) + element = element[0] + + a2 = Soap11().from_element(None, ByteArray, element) + self.assertEqual(self.data, _bytes_join(a2)) + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/model/test_binary.pyc b/pym/calculate/contrib/spyne/test/model/test_binary.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a928baa2ecdf73649f83fe55f1e78128ec79f19 GIT binary patch literal 1643 zcmcgs%~BIV5boK{KY;*p05ATOhg{fH(87ylDM;xlhYeQgUdACi#0~rB&ZLS|!703l z2cN??@e#cF0NCAw@C35i>Fw_6>FKY3;{RFg{QmXx%LHy7AHQ#KnIA}Edfo` z1!NvX9thg=A@w1vK~!^c4bnPf4Tu^}uCv^PsOe<%)qXkJVBk2vm(ju8pkmRabOi<#7 zE;X1@+9wD*#3b1Ux6yV+qjK?QW?&K)B zM$0~(V{{yb)ARp6;rl#5qOu5MQ?p`o_9t`()%LQ5ldOCIb0p(|q6|qj4l_#8-0G(0(jkX`l zC&UnP5RBbNj;g`fuaH6PGfWtxzT_kzdl@g>}ci2o$bPf$60nAJm##9IB5h4_W{aETf2~Dg}soV4E?GShK8ac+P-yBW-7_0>_0#)Yvy@k zxm;wIo@c2mJ?-;Q1Z7p&Vp61m!9Nz)2Aj8=JQRVO2iFEvIorE6m=w9O0lIagLSx1p z>n$169!<(5ypNAt?n_VpHqV2E_Z Ry0 " + "and " + " " + "have conflicting names.") + + +class TestAdditional(unittest.TestCase): + def test_time_segment(self): + data = TimeSegment.from_string("[11:12:13.123456,14:15:16.789012]") + + assert data.start_inclusive + assert data.start == datetime.time(11, 12, 13, 123456) + assert data.end == datetime.time(14, 15, 16, 789012) + assert data.end_inclusive + + def test_date_segment(self): + data = DateSegment.from_string("[2016-03-03,2016-05-07[") + + assert data.start_inclusive == True + assert data.start == datetime.date(2016, 3, 3) + assert data.end == datetime.date(2016, 5, 7) + 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]") + + 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_inclusive == True + + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/model/test_complex.pyc b/pym/calculate/contrib/spyne/test/model/test_complex.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6993a4ea5e78c355ad19236ac1d0b6d890a08f7a GIT binary patch literal 60965 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 GW&R(!{m&Z! literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/model/test_enum.py b/pym/calculate/contrib/spyne/test/model/test_enum.py new file mode 100644 index 0000000..7d8fd4f --- /dev/null +++ b/pym/calculate/contrib/spyne/test/model/test_enum.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import unittest + +from pprint import pprint + +from spyne.application import Application +from spyne.const.xml import XSD +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.protocol.soap.soap11 import Soap11 + +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', +] + +DaysOfWeekEnum = Enum( + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + 'Sunday', + type_name = 'DaysOfWeekEnum', +) + +class SomeService(Service): + @rpc(DaysOfWeekEnum, _returns=DaysOfWeekEnum) + def get_the_day(self, day): + return DaysOfWeekEnum.Sunday + + +class SomeClass(ComplexModel): + days = DaysOfWeekEnum(max_occurs=7) + + +class TestEnum(unittest.TestCase): + def setUp(self): + 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') + + 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] + + print((etree.tostring(elt, pretty_print=True))) + print(simple_type) + + 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) + + def test_serialize(self): + mo = DaysOfWeekEnum.Monday + print((repr(mo))) + + elt = etree.Element('test') + XmlDocument().to_parent(None, DaysOfWeekEnum, mo, elt, 'test_namespace') + elt = elt[0] + ret = XmlDocument().from_element(None, DaysOfWeekEnum, elt) + + self.assertEqual(mo, ret) + + def test_serialize_complex_array(self): + days = [ + 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'), + ] + + DaysOfWeekEnumArray = Array(DaysOfWeekEnum) + DaysOfWeekEnumArray.__namespace__ = 'tns' + + elt = etree.Element('test') + XmlDocument().to_parent(None, DaysOfWeekEnumArray, days, + elt, 'test_namespace') + + elt = elt[0] + ret = XmlDocument().from_element(None, Array(DaysOfWeekEnum), elt) + assert days == ret + + 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)] + + def test_serialize_simple_array(self): + t = SomeClass(days=[ + DaysOfWeekEnum.Monday, + DaysOfWeekEnum.Tuesday, + DaysOfWeekEnum.Wednesday, + DaysOfWeekEnum.Thursday, + DaysOfWeekEnum.Friday, + DaysOfWeekEnum.Saturday, + DaysOfWeekEnum.Sunday, + ]) + + SomeClass.resolve_namespace(SomeClass, 'tns') + + elt = etree.Element('test') + XmlDocument().to_parent(None, SomeClass, t, elt, 'test_namespace') + elt = elt[0] + + print((etree.tostring(elt, pretty_print=True))) + + ret = XmlDocument().from_element(None, SomeClass, elt) + self.assertEqual(t.days, ret.days) + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/model/test_enum.pyc b/pym/calculate/contrib/spyne/test/model/test_enum.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0de8ce51325ea4a497ef2863371b8b37fd881c54 GIT binary patch literal 5581 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 0: + secs *= -1 + answer = '-' + answer + gg = SomeBlob() + gg.howlong = timedelta(seconds=secs) + + 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 + 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' + gg = SomeBlob() + gg.howlong = timedelta(seconds=35) + + 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 + 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' + gg = SomeBlob() + gg.howlong = timedelta(minutes=5, seconds=35) + + 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 + 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' + gg = SomeBlob() + gg.howlong = timedelta(milliseconds=666) + + 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 + 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) + + 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))) + + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/model/test_primitive.pyc b/pym/calculate/contrib/spyne/test/model/test_primitive.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a53313611814a77b3351617a60767a0d378918f0 GIT binary patch literal 41096 zcmeHw3v^t^dEV>-1hEt-lHe00MJ^u@A&~?D5`2l4C5ogZIwVA2kb118Y?inS@KXDL z_U?*=EZK7C#*S;pP957#{7Tv$r#)`cxIKv*_oQ_apT7@vopaKt zZDRK{>i2zfU%T7|;YeJ_Jtm03+?ly^XXbzZ^WV8WudH10t*`yc4^5lkUl0C1Xi~=i zM#>l$|5K)9OgUw8DU;%L+LY2JmsTC}Jto%^=6g-9H_R_Hxn*I#&*b{T{Bo099_IT^ zu3z~cQ|dM4jLBu}GkQ&Fg(=@*a(CG4Wu`P>$}3IoPJ7*FN~=tHwaKlv*UL?5jVTYB z+**6xZ%X~9yw2p-neuv*TW`u6Om2fIZ#21$ro74IHktB}$qkwEW|P}&%3Dlsiz#n4 zxvi#rm&x5_%G*qCn<;NMx$UN$HMy)Q?=ZO?ro7YScAD}oliOv=yG?GlDG!_6uqoed za(A2Z9+TT+$|EK>V#kp&rF%^IUX#1mUav5vy{5d+|=F5fp^p*TIuYM)(&lM`RjyUCe*W-)p<&qvEfouudVf%>3SBg61x`m@ zK3u96>S}+sQZLRHYxT8gKiMc>F4oR@Wv}i(QK(hC%BX8ee*G{A=neo@0XkFi~xpDSu@!wdF z?8BDcfzl_-rPI~vM!8t2tFL;|ujea;auMr1ZJ%`!MW+gWeHzX6k3fBh#LP7)8q%;c zHNvWqG!hLkuTJv$`U;ff^X01BC>8U0+e%HD_|G6Y(C}*qO5Wuo69?wz>sP9kgQG_e z_+GuZA47PyFkAEw_;d4>;{Jo9a7GuxMmJAu5KZm0z?nchWJ@V!z?0I-fFboL18&r-3|P@J zWx$8}lmQc3u1vv- zpm9Z|U`(J;maH?b$P-Knbjgwp#$B(>M&oW!W|MI@Dl=r@aRtnVrVnq0BDh?o?*Cad#;*Y~0<-+-=-pW%d~N zZe>P{yGNOOj60&ty~e#qnZ3rnSDAgr-Kz|E+CF7Qjk{kNFtbr*z`PD91AaB8%t7Oh zD+4ZdP?-ti9#ZD8aVL~HV%)>Z95wC{WsVv5s4~ZmdrX=8jC)*}6GZU)fH~8|eKHU- zpHrlP_W)Vy##~LAmr|ylRwixgJ?2HQ-junKHvS$1e)7YpwS{RG4*2&sm-g7wspisN zb#SG*aG7oTjzlRiR80r`p9o9Al`*Cs1Lnj`uK}-lvBz9pZf-#4axB2+KK1|Q@E%); z78v!{n+y9@_!rHEw&n6vJU{fAQOm8(g)3Az-duPG3kUp1no9?4=`+oxE7d`*x$sUE zzNfixl?p%6T)0|=pKC5$!@>doH=0WaZRyvWOV`@cSDH)L+0sn9X$98X((TQq8*J&} zL@C(FMqBy=&83@cX`#7v$d+CUOP3k{Mv!+QMn*ORDJL7NkQV0VO5U`D(}9_4wXwRT zEXzVlg=E79#U&~ZTrSia-iZFcT#>|9K%6OCPqYL;#6 zUR=9u>vLlW1gii@-H+k5JoiMWb_-8Ki`J&Q2<-Nu=skGs!qbS_ooMV?aK3TFEZ~|z zz!Qx%xG@{zYPE9Us$Z>~Xu|5SaD?|coA@BA9w+NiiY_;xA~-_QUX<0!*L*2ECw(7k z8WgxQwOY022v5n}rL0O#n}bSMtW`!>3KEAJQ7p|!!zx1q%cHhdCvEAwLbAvB+XGSJl5|Q?J8R z4t0Mj6PN}NC!C5%+#y>O`z%zZ!HlXk-;%MgiDWEbI$Q>a9mK=F{dg4HztP|>V+cOg zBx5;UdRuCXC2k@}4}L}5{{$FkZ2<5#Xx1dkO(A;|(St5q=^pgU*2~oT;h;4O`@+Jv zwd*t|(oCemiICv_=F@PF;r1n*!rNbmDV*RG=!94rD7@=+n1Z0N zbW?cG_x=<eU?%$2Xq&B68dSL^lhk81t8+vXw0X~genSfYmeljh_p}GdyqbFUKM=v>_-Jk&mTfO9vkhJD^nLmOv+|xHy54 z03z3_o1hb}d=w82goPAMIsndl*S*Tk67Y>jF85>bKbe>SH!CKK*J3Be_rfIJj6r`Q zp2YXUkh$(Z^Sw1>uJS*KhaA(Hb(+LHmg3eDC3)-!6~dUaI-I$~zTytLz+P zDp!g%uTIM=;I|(^8=pJ}E~B2cJ>a!zrjd`S2Q{+39!3V%7g#GDO!9%iu)-zHupP9= zxcAc10G@a2Jb5T+;6`pJk4CD;b+SuI&zV?@_KWM)dZCney;*GN%66^O-#$|-Xk$C5 zSR%I+EmbY6YqydA5w2wcnADEgC&eviEnEQ^EE9cDY4Z{!ing)fkGf$uj_9tVs}4&8 zD+jU(4yGF>1%ZOCBkU&KScVH!FEc~fXL=EBmurU!8=u-&VqnLVME<1r;5V^X#x>pj z_OX{_RB)hj(ZVB|pQ+Zc$M2!u_|y@0j~_fVarlU=G>6K7e1m67MQ&6(TUkH@u3pX0 z6>8kOX4jL|O3{&@lU-E&ydFW3R*<9j%ySKFt+OTf3t~!;!)V4i%?jRGw2$d3MaaoX z_iO;VU`2io!wHChR@^GMA6BGRSVt=-62bB%4qlD{ZbQnb2WSaMX$k}+P+n~SYydKZ zA1I{<@I#q}ALs}06CrVvkT*gv(TxOu54RK}PzUW$J*DNGbWU*`w2+@Klo~|=bcFQe ztYadz?hJDTp+m}b9%1q*le0|Tf<%NiQ>&KqAt*RkaV^2hch2#85=mEqL{t)e(TQJ~ z{X8xM;A8-rtpLp0)TTCs_CelIwhe2 zQ0WLzcgWd0AomS+MgjOV_H^y-h#;`HC&7gqM7C@vaP?qJ7F-rcoJgIH_G(b{S0hS5XiE zbbZRshW^<5yK@`Jt9~;C~~Hdh;P=4*dCrP zE(SkD<^8x3lr%$ZlPI<5!Iice$`kCFgAK4pRR1KdyNV{{Tuo>aEWuY$?z7T>EB66k zwxyPX1?&dKWGoYC!kIs3H@6pOz$&iZVQL?j6b_jK7{^tx1n>s2nX8B^Ql5zP%Lcob zK%~mH)?3gx*&x6)L?B@jN#wm5)4mn-DNLg{opf?YgGrtykJ%}3PkI5k5P4Ln8jweUv$W+=U_;_* zfyx*2s9rO4)p93v*}|Qk>%g6&&Y&{l{#Fk450e~dMHc)SgGC%`a}RI8&)9!Ra<<3w2~BoW)JBC z%D-XK3?&050G;4(!dA5G0$KzJ+zLckpA})?JS(N5DCUe@NI}{ZlGxrx2dl((R+|?Q zqlRFtK#j4TBgoNqZdnY1*ZRy=1UzB`J7fGmFmTj?bFnblFPhnY@c^*7P}`xXnN&!! zn8TT=i!nYGU?@NWy#VV$3Q%|<vTNn&o% za%J)$nl^Z%Wo&2JPH6ZzbJUWYGLzj%tkZN4FZFOrMXNLQAU9p|g`(3=*9GGSJU&89 zPAFQ(@1Vxtgv6u<(p!L{o1`6Y1A1;kEXklnQVzctzo!^SIfIO4QGq%vs}vZTZ!us1 zVF)s)Hz)@>2~}yS08xRWz^%a0X>Lb8W?wa!8X;j!3Jpscr;Mn+~{bR@Wj~(AT zcJRKjF`rYbKAUC4d9_i`!kF>ER}d*QD!VhduGYkHpxxGO*ikH?1WbWnz?6|Ajx&s& z?Or$`s!<^Dy!*f-^N4^K0d57DN3h|&3R=u2Sex5ogN9sHz#`U1zykjO6sYI+1~IVY z4d4gj93a8KxKu<7S&qyU87veo^ct`!@@Q&}OEhh^RwNHRayA79c|;xSq9J9A9t8?w zp|gdfV>#Rdm*+7_XMl}FWTdayybMHZY>_xpIoW%yxCB7SaCBt#oW~$xu>vLBa6mv7 ze#P5~WD##)hem(|mrsm`8<|a4N^__fQCBXV*%UlHpL-#dK8t+ z5CNK>rl8^P{x$_5FX}dkh+uzT#65oSKK&mZ)4y?#*wChC{IGDVx#l?k9XsYd@X)H3 zdsK6LyiN1t$HZcUht516mcT!0wAWCkS0${ObA^}qwMiG;uar^|n&lg?|F#g<)^QB| z>r>mYxwR8pTj8&;j*L2D))b8`^iPf~3?wSPzQoVRPI`X?okpPZXt!H_tJS3BuryC% z0nGd~0Y*C)xmX~DmVaZ+Q)3X9UM&PK)xN>8_w zks|h_ua0g#5qgTO!Fp=7<48^%7eS{JU8g|6U42~SD;6Fe92+~jf9&x7@xvF#58XF0 zcHhKAPAZ%C`@{pv1CK5%X&G%AgV+z{w4Ir-0NM#3Fi$&dMBp(gib8E>Y@U2Z=}2IE);{ne--jBk_}_+c><61PH~WMEUzT zb&FFXUuzIhpaWSX)~&;mG6a%Dg){=Jgb{~_gaI1H&BA+uSk$?QTW#A#-Pv|7F~I6( z6mhe4?;8X)rp3Ntywq(_Fq??BrHV1~wp#XHC|aeQ%s`$k>+*kCfmuY9KxHf9y)?cW z7PDW0RNPRnkad+2Z{uhq)2?`Zy43J7xcud6qv957UeUiqs8V1VC}Nuc*_{mL;+k+t zz6YRKY=vU61&YplFp&iC$iyx16n6HbxQv125M7rLL>l!WOOoxLk|4~st(%_|v=(_%a!opa z3uz2iE0j?b*sMRoT4JY_(PFSMjGsn@IIQ03l$w6-u~R3{3|(&n_+14z%y#hFh&um&1pWK5I-NoP0oE=Edgnug@sBh4F(z+3XtyKr z=h{HKrv=)ORhH1-flL#jgQh`+keo>2JJbGOAWI?nZY4`eehUdwD@CJ5u@tprO4;Gz z*Epg}>CTd%tVr-)+9Yob0*r)WN8)=&%yGBC>)i*kO9;g`9w0eDb0K74FP**+U@*?JfO9lZ>gGShMWg0MMSUp5TuzRK(iL*Zv{^8CIJI$O zQ@B?;FCLnT=YZ{42Tssb3u(P+c!u#dGGPR+JRCOQNsBA?5G}4Fmj%bz{T1bAmjrU# z)%++|lMKzI_9oY|7bRND4#;O!teCO3ARnr=eb9n@B!fyBKgm|GKC(@HN1v0}&=$4oCz6N7n-i zu}s0P595fe|2B#P6N)y)5y4x5yXY-~O^DvmG;$LrkW=V)3PY0YlKnS+&_)t5L?L0+ zZ{_8~OdetKD3h~H-ok|5cZ=0~csY(lu?pZ5Jfmfa0*N>~p>!~ePZKmW>d6u^LFh>o zOVoq%41NWsFQaKvySQOeAN*wKsgb5Zl!XNmP(JqB07zNrsDRqRZT+(Z8v{seGdkp( zn=Mzfxv-h6351Xj!HLAZKXmc_pbk;%u%Lkps>X>92ps4${%3>gCjis8KDoF7!}Wyw zTSj6B{GD(l7%-Y)r?I7(9qoSiL+#IL<=U2Ck8hlxB@6|QcX8}zTFMNb%K0STZ}bCB-C7G3#Ds? zdEa?I>OAxEtFMXzyjS0e9AIw`R?-HQkCTE*#agz0rBKO2@>vPvNWFOVow^%n#jUK_ zS`i!}Y>79lC5wC_RT=)1>`cKcNk7zHx{R`G_OK%RqC8HL;Q32Ik>1$QCW`Oz@T3{9 zgw7p4NWvGdZ)@XHo)ypc8<(d`u;|q-dMeIVYx9owpNQG;q=_PN~(Qg7eL8dJe;- z+kD-VT9aCt>P-)%!`w9I^2X)GXYcv#OTYK4AYto&(Z9C)hLA&TejkDF>2M zdRl7)F7O^a6}$z!HWl2ia0}j!-XK2{qLxj=PzR1^a`sEdcIQ6!!B-xLVbbcc_#6md>1ya=v9&IoZ*3Me@y7m5P;+i|?6E|CJ2AnO_ zfijT}WaXk1Ov)Q{L*W*I)b@k(zd}VSR*3+53}%HHf@Z`&5ooD%PGSVcyl}Ztc@}el zt5oS_XO8n@f$QKY#=__na#nowAU8sr(;?GWG**_A$wdf$i>4*q;VB~$X>h(bunjMip$cuUmk4hPJp1pz5pS&jZXmT(pBf2Vba14 zVlA4mc7BOTiz@wjmi==k1grDQNV+PC$*{x+1kZf2JXfFpb~98%ju1hW3@zf;d}YFN z>lZ=M$jjg%E43T}%#9oy>l%i}-9S5V2Rv8$C8-o^9|Y&~Eg1Ab^-r%**j7na4N8yV zFVIP_+122nCN32x6we}nNgvYOD!$0qz6Wy_4IROwBiz=pi2%i3ZFs>2<^-cjtI&n2)HyX@dtgJL!zY(Ds0FA z;PHbum0PBRU`)J&{9ekrSQA}*eX5i~12r!Y*3OL-x1 ze8b4Xu0qbwnmj_Xe$KLL1AFA-6_>b-!=I(Yl3jS0)iu;!v7L&q%O|JKO6JP#7;~E? zlDX9Ht?q!+hlUAQYaUV9u1&8$ed_n>-%}yvl1YHQ5K#ssH ziP%44@gEGFb5>};egX&qAcpDV2rD_{f+|?NQPuO!ReD7rxa-G*DqKz}h`@&KODxx^ zwC4eV{9F|ldMFdL>+DmNgY$b#2npwRnREn!+I1ZSj6oAw#*;oy zIFJb$SfD|0cN0!Sq$pj*-5@9b9VBP?1&b79~N8?03bpNu}l94 zXug=GSG%QK`gpb{mu%^2XvfGOkEnV5i)bYZNCJT@Y&<3a%i;E|$ll`Lh`=R+A^G4c zCLhb@ED-;2kw8?tt^;u$MiAg(@m*o1`z|5#R*gvHlz?_vl_?Ya&N$_~L|uBv%Y-WmpZ-11t5$pZR? zBx1d+%KDc zKP_VBv~=;ABfM`LZe?5l>{`382IDcj-UNO1=6vL3Cpkq{#6Dbr3@q=5(<*QQgd1=- z1Y4Myfl`OZO(s0O1V)_zq6ryw;$%@0LqYCF`({a=n^;{12nQ$TRViN6(|?!{;j$R4y6m(j zhJ{EE^TMU3ctNfwqk!Z!hldx74m7rxc^h|yw+w8pZAuOh70DJ)Jpq`J&ebfq3*kTE zU8o|=oWgck3vb*3{uuvl^Zd_HzmC?0%?c0XwJ3+-)CkuV=)WTRdXQE{uTR>5Q^tAi|Iu3Uy#>juTWoIR_ z-Vcr-5wx`X7&yWP}u^{L3jrHe0PVI;9gP7ezpAh4lQ}mNZ98JwZyR^ZJ(~V z#Ng@r?xCMfwQq^9M@4+6qS+5L^D{@$8*&A#v9-fep~4;n@M-?|qylh(#*Ds$=5+0*tdeD3u-{Y+YjZW3i( zl@Q$A6wz^%d3=A!g6$KeHf{jpK%ev=cE)*X%FVx#^ygeoai{ziR0#S5#Q<|}Nrm8; zamxj%5cC(fY@tHEyy$|*iV7Jv6+OL$3Zs^yLc}@6Ef=IheBUr`xgZtdlZbK4o2k(G zA6UahQD9b zrFSEp2qa6SmXTe@{3;yh7rD+HJwF=8lY+FOlsD0erlB5Ssc3p&UA44eL*Pg2v3iV@ zYO4x_>H5e9za@2ac?fWwwT7zjdw^rZ3+o82pBEr5o zioXt83N5(xHhK1oUwGe}zIwUW%yP+Ie)s4}u@ebCoW7zUcl^yOq*bD;j7v2(4}S1L zQ65VY4R~scMIr}X%AzH0@*OFtoaMQM+`AJETK6Hxc@xc!=SPrqU*!x>t%xNc6qkQZ ztlGr!AP!~&K0h}M%u4>=jAeKKjj&93xEVCwf|{FwnuOqj;xEKv2sW$SzPAHrSggad zfN!nOT5i@uIEK&r%?>?;3MzV7Pf=!{_g5WSLxhH^XV7wIQuS2ya0g6u7=GuZn2>HG z%=7*fH0|`TycbD~aLzK8#ZsaZjyZk2t(zz|golY?MJSe#4__sQZB1a<2D}Rg90RUx zNbL%8!ZK>W5ih&WK0~7ti%g~lKL|i8Ym(6r3Qj@n10#RI48ZRcI>C3{aJH89xgZ4) z(Kz-^hA#s&HNu^?kvNF9HFP?vPrr6}ASO=dy>IyZeZy1UQ;^;AP5M+W$B!Kw-#^Cx z*|9O4WrzP3YyuIPMFMPcO;R~dyd!soO$av31N_17{_!@Ec#l8`8`{G$?|(}0aUMMO zlJ5KU@y1OtS1mLK#b}y_1x3u2@jq0n(Ozf z6WEd|bNZRBK@YeEH*RFGKd}R0;ct5GQ|1XQJ}?M1_CN6p9z0u!N8t*+W8(+(KijC(y%HZVc3|un z%Iu4H6z$$`VWj%r%SYrT( z&QclC_~zX}=h=$oI0!Y*Jf}lW%0_y2SNZt5;OT)^Di6(ACxyR49&iwqI2I8MdjR(G ziXNy7se7O_tW9kOPv8loC+zxOqjV(@)EyY)0PMEtY%e)TK`(8WY$&GI{*S0QM$K>`D8lsCfpr=`_0+M z%L7b~GEwaV%ss^9Jd?LFd5Q_cH5_s>2cpY3&oOzP$=jI#KaBGZChunQx0!s9$=_k} zVJ1Jp5Jc$>g(4evZj6F!=(Lf5GHenEXp7zrp0oO#Tg%-)8bvCcn?* zKQj3vCSParCrrM{&o?F=&;${adfj z4h)Av$Ojj|$1O7>nVw80b8lu{rZ=+!KX+vA%&g6<%&gAzqkJoV*CW@T89*8T^<|c! z=|YX~a^w8Hn^)q^xF=c(AUzfXqJkOd zX!?#HRs|A*CD4)dh20z!MtvtYw;UhIkPbf0RilzhF)IPI7A5G(dP%Ujbc}?$D!QT2 zL4REL9%zU5ENpUR$PnBGCQV03@IETA$ZC*C5zc{f1*k}ir!_~9$*96 zS00=ZUor9HHy*Vw0==eQpU)$Jpi=iKr`|s7zZBvi`Kv>`ul@zY_VMSwRKO z`L|3?FnJ4;-AF_UGaeMRvn+ayMI-|IwXk4l)(qRjV&Xud;$JJ)WMs|G+IM4nQ4DRX zphABQ0J7Swjmy2C*GP}i5HfJ(p#Zr z1@H3pqXidRC|qQ5!j9TabmA?;4tW5W88g62ha*Zi=YE!fbnhU0HXvQKzmx=L%1Mq8@C3`m*eejAqRskG%3&mBqOzqK3h z2D(jBSuuK{_QJ)nDe;NmYJ5tkTs4-V!G(*5k5742fWpf2-YRH)4Wcb8&$E6tOGuDp zK;ApwnlgH4@xsM}haL@@yv#z7gt;(&+BQ8hcG~0lUiLW?V`HbCZR9Ga(8$@2Tq_T< z-=si=*)L7Ac?PzKwc$u?s7=dUY_p~b*`k|fWs94pW{cX*&(6y)sS&dk^c+Td@ zRcYItxp?;WGd`~ii*>SG$cVi6L1_SkK^vIDTaEMRI%qn}Ok{1YG@28;ff1jI%&IBSWHI0tQ8n2vK>gSrVv?EKU zY8u&CpWy=_Dq$w!KVF)L@nZL@kYX!H+cP>{aTzQv?CH>USg9Q-+=Xo?c)#gnV1z78 zDKKAHFEn5%e{ZgqanrFn=n1l4yPLKrwsvXRGXiSTp$rgz^BDBz;f-^gLBulr8gW0% z_~C$gL3`k^W_4Lwakwk=Hw|P^ZA(u_R)&)DB>!31MS<)@me?Ga21>qEop4VCZYSRE&-0}chmd!6@jgD=wrpT0&>`(5!oFc|;CVDH?JGUf z+S}I|3C-oBob*=S_$U%B)I}`PDNd6VC||Vog%Kv&HxQx|0$s-ojqgqN ueV#XS3AEw28m~(PKg^|9r&nY9pTF)I0R5;m^Q^WkVkrNc}&$U`HYV literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/multipython/__init__.py b/pym/calculate/contrib/spyne/test/multipython/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pym/calculate/contrib/spyne/test/multipython/__init__.pyc b/pym/calculate/contrib/spyne/test/multipython/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e94b730c2e3384c14b02e19c7b3677d91942dd3 GIT binary patch literal 180 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/protocol/__init__.py b/pym/calculate/contrib/spyne/test/protocol/__init__.py new file mode 100644 index 0000000..7250806 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/protocol/__init__.py @@ -0,0 +1,24 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""This is Spyne's test package. + +You are not supposed to import test package from production code because tests +fiddle with global state of Spyne classes. +""" diff --git a/pym/calculate/contrib/spyne/test/protocol/__init__.pyc b/pym/calculate/contrib/spyne/test/protocol/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6e2bae812f59292ba0483ae4863a06527e27755f GIT binary patch literal 353 zcmY+9K~4iP3`J8|fJS1^(mT3oq83y(2yp^7Wdoa#ChjyM9Y;f4xCuvK#|7|E zBt#T{Th^EL-|^R3^ZD`q9L?{WXus3qMkN{Zq&hLH>Cw1*Q+e2C2K}qL@9=^_kOgXp zFQG--G>ec0mKrRk!^E79ka`ciuZ}4_fs9spRlqRH*oJtUN5g)-OHA`g}rv1 z1!unu?06)bE$sZ#&X=>gSBJ&6J?!1c>ol}bq~g5KT^8@H9y`_ZH#?;%czdq1Xqj&o C!Dn#* literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/protocol/_test_dictdoc.py b/pym/calculate/contrib/spyne/test/protocol/_test_dictdoc.py new file mode 100644 index 0000000..9dd8352 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/protocol/_test_dictdoc.py @@ -0,0 +1,1381 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from __future__ import unicode_literals + +import logging +logger = logging.getLogger(__name__) + +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 + +from datetime import datetime +from datetime import date +from datetime import time +from datetime import timedelta + +import lxml.etree +import lxml.html + +from lxml.builder import E + +from spyne import MethodContext +from spyne.service import Service +from spyne.server import ServerBase +from spyne.application import Application +from spyne.decorator import srpc, rpc +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.fault import Fault +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 + + +def _unbyte(d): + if d is None: + return + + for k, v in list(d.items()): + if isinstance(k, bytes): + del d[k] + d[k.decode('utf8')] = v + + if isinstance(v, dict): + _unbyte(v) + + for k, v in d.items(): + if isinstance(v, (list, tuple)): + l = [] + for sub in v: + if isinstance(sub, dict): + l.append(_unbyte(sub)) + + elif isinstance(sub, bytes): + l.append(sub.decode("utf8")) + + else: + l.append(sub) + + d[k] = tuple(l) + + elif isinstance(v, bytes): + try: + d[k] = v.decode('utf8') + except UnicodeDecodeError: + d[k] = v + + return d + + +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), + ) + + 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') + initial_ctx.in_string = [in_string] + + ctx, = server.generate_contexts(initial_ctx, in_string_charset='utf8') + if not just_ctx: + server.get_in_object(ctx) + if not just_in_object: + server.get_out_object(ctx) + server.get_out_string(ctx) + + return ctx + return _dry_me + +def TDictDocumentTest(serializer, _DictDocumentChild, dumps_kwargs=None, + loads_kwargs=None, convert_dict=None): + if not dumps_kwargs: + dumps_kwargs = {} + if not loads_kwargs: + loads_kwargs = {} + _dry_me = TDry(serializer, _DictDocumentChild, dumps_kwargs) + + if convert_dict is None: + convert_dict = lambda v: v + + class Test(unittest.TestCase): + def dumps(self, o): + print("using", dumps_kwargs, "to dump", o) + return serializer.dumps(o, **dumps_kwargs) + + def loads(self, o): + return _unbyte(serializer.loads(o, **loads_kwargs)) + + def test_complex_with_only_primitive_fields(self): + class SomeComplexModel(ComplexModel): + i = Integer + s = Unicode + + class SomeService(Service): + @srpc(SomeComplexModel, _returns=SomeComplexModel) + def some_call(scm): + return SomeComplexModel(i=5, s='5x') + + ctx = _dry_me([SomeService], {"some_call":[]}) + + s = self.loads(b''.join(ctx.out_string)) + + s = s["some_callResponse"]["some_callResult"]["SomeComplexModel"] + assert s["i"] == 5 + assert s["s"] in ("5x", b"5x") + + def test_complex(self): + class CM(ComplexModel): + i = Integer + s = Unicode + + class CCM(ComplexModel): + c = CM + i = Integer + s = Unicode + + class SomeService(Service): + @srpc(CCM, _returns=CCM) + 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", + }}} + }) + + 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') + + def test_multiple_list(self): + class SomeService(Service): + @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"]]}) + + data = b''.join(ctx.out_string) + print(data) + + 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'))) + def some_call(s): + return s + + ctx = _dry_me([SomeService], {"some_call":{"s":["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): + @srpc(Iterable(Unicode), _returns=Iterable(Unicode)) + def some_call(s): + return s + + ctx = _dry_me([SomeService], {"some_call":{"s":["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): + i = Integer + s = Unicode + + class CCM(ComplexModel): + c = CM + i = Integer + s = Unicode + + class ECM(CCM): + d = DateTime + + class SomeService(Service): + @srpc(Iterable(ECM), _returns=Iterable(ECM)) + 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" + }}] + }}) + + print(ctx.in_object) + + 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" + + def test_invalid_request(self): + class SomeService(Service): + @srpc(Integer, String, DateTime) + def yay(i,s,d): + print(i,s,d) + + ctx = _dry_me([SomeService], {"some_call": {"yay": []}}, + just_in_object=True) + + print(ctx.in_error) + assert ctx.in_error.faultcode == 'Client.ResourceNotFound' + + def test_invalid_string(self): + class SomeService(Service): + @srpc(Integer, String, DateTime) + def yay(i,s,d): + print(i, s, d) + + ctx = _dry_me([SomeService], {"yay": {"s": 1}}, validator='soft', + just_in_object=True) + + 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) + + ctx = _dry_me([SomeService], {"yay": ["s", "B"]}, validator='soft', + just_in_object=True) + + assert ctx.in_error.faultcode == 'Client.ValidationError' + + def test_missing_value(self): + class SomeService(Service): + @srpc(Integer, Unicode, Mandatory.DateTime) + def yay(i, s, d): + print(i, s, d) + + 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.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) + + ctx = _dry_me([SomeService],{"yay": {"d":"a2011"}},validator='soft', + just_in_object=True) + + assert ctx.in_error.faultcode == 'Client.ValidationError' + + def test_fault_to_dict(self): + class SomeService(Service): + @srpc(_returns=String) + def some_call(): + raise Fault() + + _dry_me([SomeService], {"some_call":[]}) + + def test_prune_none_and_optional(self): + class SomeObject(ComplexModel): + i = Integer + s = String(min_occurs=1) + + class SomeService(Service): + @srpc(_returns=SomeObject) + def some_call(): + return SomeObject() + + ctx = _dry_me([SomeService], {"some_call":[]}) + + ret = self.loads(b''.join(ctx.out_string)) + + 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') + + class SomeService(Service): + @srpc(AnyXml, _returns=AnyXml) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == lxml.etree._Element + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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') + + class SomeService(Service): + @srpc(AnyHtml, _returns=AnyHtml) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == lxml.html.HtmlElement + return p + + ctx = _dry_me([SomeService], {"some_call": [d]}) + + s = self.loads(b''.join(ctx.out_string)) + d = {"some_callResponse": {"some_callResult": d}} + + print(s) + print(d) + assert s == d + + def test_any_dict(self): + d = {'helo': 213, 'data': {'nested': [12, 0.3]}} + + class SomeService(Service): + @srpc(AnyDict, _returns=AnyDict) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == dict + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + s = b''.join(ctx.out_string) + d = self.dumps({"some_callResponse": {"some_callResult": d}}) + + print(s) + print(d) + assert self.loads(s) == self.loads(d) + + def test_unicode(self): + d = u'some string' + + class SomeService(Service): + @srpc(Unicode, _returns=Unicode) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == six.text_type + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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' + + class SomeService(Service): + @srpc(AnyUri, _returns=AnyUri) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, six.string_types) + return p + + ctx = _dry_me([SomeService], {"some_call": [d]}) + + 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' + + class SomeService(Service): + @srpc(ImageUri, _returns=ImageUri) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, six.string_types) + return p + + ctx = _dry_me([SomeService], {"some_call": [d]}) + + 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') + if _DictDocumentChild._decimal_as_string: + d = str(d) + + class SomeService(Service): + @srpc(Decimal, _returns=Decimal) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == decimal.Decimal + return p + + ctx = _dry_me([SomeService], {"some_call": [d]}) + + s = self.loads(b''.join(ctx.out_string)) + d = {"some_callResponse": {"some_callResult": d}} + print(s) + print(d) + assert s == d + + def test_double(self): + d = 12.3467 + + class SomeService(Service): + @srpc(Double, _returns=Double) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == float + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + s = self.loads(b''.join(ctx.out_string)) + d = {"some_callResponse": {"some_callResult": d}} + print(s) + print(d) + assert s == d + + def test_integer(self): + d = 5 + + class SomeService(Service): + @srpc(Integer, _returns=Integer) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == int + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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 + if _DictDocumentChild._huge_numbers_as_string: + d = str(d) + + class SomeService(Service): + @srpc(Integer, _returns=Integer) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == long + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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_big(self): + d = 1<<1000 + if _DictDocumentChild._huge_numbers_as_string: + d = str(d) + + class SomeService(Service): + @srpc(Integer, _returns=Integer) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == long + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + s = self.loads(b''.join(ctx.out_string)) + d = {"some_callResponse": {"some_callResult": d}} + print(s) + print(d) + assert s == d + + def test_time(self): + d = time(10, 20, 30).isoformat() + + class SomeService(Service): + @srpc(Time, _returns=Time) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == time + assert p.isoformat() == d + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + s = self.loads(b''.join(ctx.out_string)) + d = {"some_callResponse": {"some_callResult": d}} + print(s) + print(d) + assert s == d + + def test_date(self): + vdt = datetime(2010, 9, 8) + d = vdt.date().isoformat() + + class SomeService(Service): + @srpc(Date, _returns=Date) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == date + assert p.isoformat() == d + return p + + @srpc(_returns=Date) + def some_call_dt(): + return vdt + + ctx = _dry_me([SomeService], {"some_call": [d]}) + 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)) + rd = {"some_call_dtResponse": {"some_call_dtResult": d}} + print(s) + print(rd) + assert s == rd + + def test_datetime(self): + d = datetime(2010, 9, 8, 7, 6, 5).isoformat() + + class SomeService(Service): + @srpc(DateTime, _returns=DateTime(timezone=False)) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == datetime + assert p.replace(tzinfo=None).isoformat() == d + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}, validator='soft') + + s = self.loads(b''.join(ctx.out_string)) + d = {"some_callResponse": {"some_callResult": d}} + print(s) + print(d) + assert s == d + + 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))) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == datetime + assert p.isoformat() == d + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}, validator='soft') + + s = self.loads(b''.join(ctx.out_string)) + d = {"some_callResponse": {"some_callResult": d}} + print(s) + print(d) + assert s == d + + def test_duration(self): + d = ProtocolBase().to_unicode(Duration, timedelta(0, 45)) + + class SomeService(Service): + @srpc(Duration, _returns=Duration) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == timedelta + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + s = self.loads(b''.join(ctx.out_string)) + d = {"some_callResponse": {"some_callResult": d}} + print(s) + print(d) + assert s == d + + def test_boolean(self): + d = True + + class SomeService(Service): + @srpc(Boolean, _returns=Boolean) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == bool + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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' + + class SomeService(Service): + @srpc(Uuid, _returns=Uuid) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == uuid.UUID + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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)' + + class SomeService(Service): + @srpc(Point, _returns=Point) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, six.string_types) + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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)' + + class SomeService(Service): + @srpc(Point, _returns=Point) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, six.string_types) + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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)' + + class SomeService(Service): + @srpc(Line, _returns=Line) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, six.string_types) + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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)' + + class SomeService(Service): + @srpc(Line, _returns=Line) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, six.string_types) + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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))' + + class SomeService(Service): + @srpc(Polygon(2), _returns=Polygon(2)) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, six.string_types) + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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))' + + class SomeService(Service): + @srpc(Polygon(3), _returns=Polygon(3)) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, six.string_types) + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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))' + + class SomeService(Service): + @srpc(MultiPoint(2), _returns=MultiPoint(2)) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, six.string_types) + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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,)' + + class SomeService(Service): + @srpc(MultiPoint(3), _returns=MultiPoint(3)) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, six.string_types) + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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))' + + class SomeService(Service): + @srpc(MultiLine(2), _returns=MultiLine(2)) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, six.string_types) + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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))' + + class SomeService(Service): + @srpc(MultiLine(3), _returns=MultiLine(3)) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, six.string_types) + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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)))' + + class SomeService(Service): + @srpc(MultiPolygon(2), _returns=MultiPolygon(2)) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, six.string_types) + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + 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)))' + + class SomeService(Service): + @srpc(MultiPolygon(3), _returns=MultiPolygon(3)) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, six.string_types) + return p + + ctx = _dry_me([SomeService], {"some_call":[d]}) + + s = self.loads(b''.join(ctx.out_string)) + d = {"some_callResponse": {"some_callResult": d}} + print(s) + print(d) + assert s == d + + def test_generator(self): + class SomeService(Service): + @srpc(_returns=Iterable(Integer)) + def some_call(): + return iter(range(1000)) + + ctx = _dry_me([SomeService], {"some_call":[]}) + + s = self.loads(b''.join(ctx.out_string)) + d = {"some_callResponse": {"some_callResult": tuple(range(1000))}} + print(s) + print(d) + assert s == d + + def test_bytearray(self): + dbe = _DictDocumentChild.default_binary_encoding + beh = binary_encoding_handlers[dbe] + + data = bytes(bytearray(range(0xff))) + encoded_data = beh([data]) + if _DictDocumentChild.text_based: + encoded_data = encoded_data.decode('latin1') + + class SomeService(Service): + @srpc(ByteArray, _returns=ByteArray) + def some_call(ba): + print(ba) + print(type(ba)) + assert isinstance(ba, tuple) + assert ba == (data,) + return ba + + ctx = _dry_me([SomeService], {"some_call": [encoded_data]}) + + s = self.loads(b''.join(ctx.out_string)) + d = {"some_callResponse": {"some_callResult": encoded_data}} + + print(repr(s)) + print(repr(d)) + print(repr(encoded_data)) + assert s == d + + def test_file_data(self): + # the only difference with the bytearray test is/are the types + # inside @srpc + dbe = _DictDocumentChild.default_binary_encoding + beh = binary_encoding_handlers[dbe] + + data = bytes(bytearray(range(0xff))) + encoded_data = beh([data]) + if _DictDocumentChild.text_based: + encoded_data = encoded_data.decode('latin1') + + class SomeService(Service): + @srpc(File, _returns=File) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, File.Value) + assert p.data == (data,) + return p.data + + # 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)) + d = {"some_callResponse": {"some_callResult": encoded_data}} + + print(s) + print(d) + print(repr(encoded_data)) + assert s == d + + def test_file_value(self): + dbe = _DictDocumentChild.default_binary_encoding + beh = binary_encoding_handlers[dbe] + + # Prepare data + v = File.Value( + name='some_file.bin', + type='application/octet-stream', + ) + file_data = bytes(bytearray(range(0xff))) + v.data = (file_data,) + beh([file_data]) + if _DictDocumentChild.text_based: + test_data = beh(v.data).decode('latin1') + else: + test_data = beh(v.data) + + print(repr(v.data)) + + class SomeService(Service): + @srpc(File, _returns=File) + def some_call(p): + print(p) + print(type(p)) + assert isinstance(p, File.Value) + assert p.data == (file_data,) + assert p.type == v.type + 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, + }}}) + + print(self.loads(s)) + print(self.loads(d)) + print(v) + assert self.loads(s) == self.loads(d) + + def test_validation_frequency(self): + class SomeService(Service): + @srpc(ByteArray(min_occurs=1), _returns=ByteArray) + def some_call(p): + pass + + try: + _dry_me([SomeService], {"some_call": []}, validator='soft') + except ValidationError: + pass + else: + raise Exception("must raise ValidationError") + + def test_validation_nullable(self): + class SomeService(Service): + @srpc(ByteArray(nullable=False), _returns=ByteArray) + def some_call(p): + pass + + try: + _dry_me([SomeService], {"some_call": [None]}, + validator='soft') + except ValidationError: + pass + + else: + raise Exception("must raise ValidationError") + + def test_validation_string_pattern(self): + class SomeService(Service): + @srpc(Uuid) + def some_call(p): + pass + + try: + _dry_me([SomeService], {"some_call": ["duduk"]}, + validator='soft') + except ValidationError as e: + print(e) + pass + + else: + raise Exception("must raise ValidationError") + + def test_validation_integer_range(self): + class SomeService(Service): + @srpc(Integer(ge=0, le=5)) + def some_call(p): + pass + + try: + _dry_me([SomeService], {"some_call": [10]}, + validator='soft') + except ValidationError: + pass + + else: + raise Exception("must raise ValidationError") + + def test_validation_integer_type(self): + class SomeService(Service): + @srpc(Integer8) + def some_call(p): + pass + + try: + _dry_me([SomeService], {"some_call": [-129]}, + validator='soft') + except ValidationError: + pass + + else: + raise Exception("must raise ValidationError") + + def test_validation_integer_type_2(self): + class SomeService(Service): + @srpc(Integer8) + def some_call(p): + pass + + try: + _dry_me([SomeService], {"some_call": [1.2]}, validator='soft') + + except ValidationError: + pass + + else: + raise Exception("must raise ValidationError") + + def test_not_wrapped(self): + class SomeInnerClass(ComplexModel): + d = date + dt = datetime + + class SomeClass(ComplexModel): + a = int + b = Unicode + c = SomeInnerClass.customize(not_wrapped=True) + + class SomeService(Service): + @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.c.d == date(2018, 11, 22) + return p + + inner = {"a": 1, "b": "s", "c": {"d": '2018-11-22'}} + doc = {"some_call": [inner]} + 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) + + def test_validation_freq_parent(self): + class C(ComplexModel): + i = Integer(min_occurs=1) + s = Unicode + + class SomeService(Service): + @srpc(C) + def some_call(p): + pass + + try: + # must raise validation error for missing i + _dry_me([SomeService], {"some_call": {'p': {'C': {'s': 'a'}}}}, + validator='soft') + except ValidationError as e: + logger.exception(e) + pass + except BaseException as e: + logger.exception(e) + pass + else: + 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') + + def test_inheritance(self): + class P(ComplexModel): + identifier = Uuid + signature = Unicode + + class C(P): + foo = Unicode + bar = Uuid + + class SomeService(Service): + @rpc(_returns=C) + def some_call(ctx): + result = C() + result.identifier = uuid.UUID(int=0) + 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' + }}}} + + assert s == d + + def test_exclude(self): + class C(ComplexModel): + s1 = Unicode(exc=True) + s2 = Unicode + + class SomeService(Service): + @srpc(C, _returns=C) + def some_call(sc): + assert sc.s1 is None, "sc={}".format(sc) + assert sc.s2 == "s2" + return 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'}}}}) + ) + + def test_polymorphic_deserialization(self): + class P(ComplexModel): + sig = Unicode + + class C(P): + foo = Unicode + + class D(P): + bar = Integer + + class SomeService(Service): + @rpc(P, _returns=Unicode) + def typeof(ctx, p): + return type(p).__name__ + + ctx = _dry_me([SomeService], + {"typeof": [{'C':{'sig':'a', 'foo': 'f'}}]}, + polymorphic=True) + + 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) + + s = self.loads(b''.join(ctx.out_string)) + d = {"typeofResponse": {"typeofResult": 'D'}} + + print(s) + print(d) + assert s == d + + def test_default(self): + class SomeComplexModel(ComplexModel): + _type_info = [ + ('a', Unicode), + ('b', Unicode(default='default')), + ] + + class SomeService(Service): + @srpc(SomeComplexModel) + def some_method(s): + pass + + 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) + + 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)), + ] + + class SomeService(Service): + @srpc(SomeComplexModel) + def some_method(s): + pass + + 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) + + assert ctx.in_object.s.b == 'default' + assert ctx.in_error is None + + return Test diff --git a/pym/calculate/contrib/spyne/test/protocol/_test_dictdoc.pyc b/pym/calculate/contrib/spyne/test/protocol/_test_dictdoc.pyc new file mode 100644 index 0000000000000000000000000000000000000000..324867b2c143be5b6c85dd5aedf7069017f15a4c GIT binary patch literal 71973 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 Q?`!") + + assert SomeObject.Attributes._html_cloth is None + assert SomeObject.Attributes._html_root_cloth is not None + + def test_html(self): + class SomeObject(ComplexModel): + class Attributes(ComplexModel.Attributes): + html_cloth = html.fromstring('') + + assert SomeObject.Attributes._html_cloth is not None + assert SomeObject.Attributes._html_root_cloth is None + + def test_root_xml(self): + class SomeObject(ComplexModel): + class Attributes(ComplexModel.Attributes): + xml_cloth = etree.fromstring('') + + assert SomeObject.Attributes._xml_cloth is None + assert SomeObject.Attributes._xml_root_cloth is not None + + def test_xml(self): + class SomeObject(ComplexModel): + class Attributes(ComplexModel.Attributes): + xml_cloth = html.fromstring('') + + assert SomeObject.Attributes._xml_cloth is not None + assert SomeObject.Attributes._xml_root_cloth is None + + +class TestXmlClothToParent(unittest.TestCase): + def setUp(self): + self.ctx = FakeContext() + self.stream = BytesIO() + logging.basicConfig(level=logging.DEBUG) + + def _run(self, inst, cls=None): + if cls is None: + cls = inst.__class__ + + with etree.xmlfile(self.stream) as parent: + XmlCloth().subserialize(self.ctx, cls, inst, parent, + name=cls.__name__) + + elt = etree.fromstring(self.stream.getvalue()) + + print(etree.tostring(elt, pretty_print=True)) + return elt + + def test_simple(self): + v = 'punk.' + elt = self._run(v, Unicode) + + assert elt.text == v + + def test_complex_primitive(self): + class SomeObject(ComplexModel): + s = Unicode + + v = 'punk.' + elt = self._run(SomeObject(s=v)) + + assert elt[0].text == v + + def test_complex_inheritance(self): + class A(ComplexModel): + i = Integer + + class B(A): + s = Unicode + + i = 42 + s = 'punk.' + elt = self._run(B(i=i, s=s)) + + # order is important + assert len(elt) == 2 + assert elt[0].text == str(i) + assert elt[1].text == s + + +### !!! WARNING !!! ### !!! WARNING !!! ### !!! WARNING !!! ### !!! WARNING !!! +# +# This test uses spyne_id and spyne_tagbag instead of spyne-id and spyne-tagbag +# for ease of testing. The attributes used here are different from what you are +# going to see in the real-world uses of this functionality. +# You have been warned !!! +# +### !!! WARNING !!! ### !!! WARNING !!! ### !!! WARNING !!! ### !!! WARNING !!! +class TestXmlCloth(unittest.TestCase): + def setUp(self): + self.ctx = FakeContext() + self.stream = BytesIO() + logging.basicConfig(level=logging.DEBUG) + + def _run(self, inst, spid=None, cloth=None): + cls = inst.__class__ + if cloth is None: + assert spid is not None + cloth = etree.fromstring("""""" % spid) + else: + assert spid is None + + with etree.xmlfile(self.stream) as parent: + XmlCloth(cloth=cloth).set_identifier_prefix('spyne_') \ + .subserialize(self.ctx, cls, inst, parent) + + elt = etree.fromstring(self.stream.getvalue()) + + print(etree.tostring(elt, pretty_print=True)) + return elt + + def test_simple_value(self): + class SomeObject(ComplexModel): + s = Unicode + + v = 'punk.' + elt = self._run(SomeObject(s=v), spid='s') + + assert elt[0].text == v + + def test_simple_empty(self): + class SomeObject(ComplexModel): + s = Unicode + + elt = self._run(SomeObject(), spid='s') + + assert len(elt) == 0 + + # FIXME: just fix it + def _test_simple_empty_nonoptional(self): + class SomeObject(ComplexModel): + s = Unicode(min_occurs=1) + + elt = self._run(SomeObject(), spid='s') + + assert elt[0].text is None + + # FIXME: just fix it + def _test_simple_empty_nonoptional_clear(self): + class SomeObject(ComplexModel): + s = Unicode(min_occurs=1) + + cloth = etree.fromstring("""oi punk!""") + + elt = self._run(SomeObject(), cloth=cloth) + + assert elt[0].text is None + + def test_xml_data_tag(self): + class SomeObject(ComplexModel): + d = XmlData(Unicode) + + cloth = etree.fromstring('') + + elt = self._run(SomeObject(d='data'), cloth=cloth) + + assert elt.text == 'data' + + def test_xml_data_attr(self): + class SomeObject(ComplexModel): + d = XmlData(Unicode) + + cloth = etree.fromstring('') + + elt = self._run(SomeObject(d='data'), cloth=cloth) + + assert elt.text == 'data' + + def test_xml_data_attr_undesignated(self): + class SomeObject(ComplexModel): + d = Unicode + + cloth = etree.fromstring('') + + elt = self._run(SomeObject(d='data'), cloth=cloth) + + assert elt.text == 'data' + + def test_simple_value_xmlattribute(self): + v = 'punk.' + + class SomeObject(ComplexModel): + s = XmlAttribute(Unicode(min_occurs=1)) + + cloth = etree.fromstring("""""") + elt = self._run(SomeObject(s=v), cloth=cloth) + + assert elt.attrib['s'] == v + + def test_simple_value_xmlattribute_subname(self): + v = 'punk.' + + class SomeObject(ComplexModel): + 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 + + def test_simple_value_xmlattribute_non_immediate(self): + v = 'punk.' + + class SomeObject(ComplexModel): + 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 + + def test_simple_value_xmlattribute_non_immediate_non_designated(self): + v = 'punk.' + + class SomeObject(ComplexModel): + 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 + + def test_non_tagbag(self): + cloth = E.a( + E.b( + E.c( + E.d( + spyne_id="i", + ), + spyne_id="c", + ), + spyne_id="i", + ), + spyne_tagbag='', + ) + + class C2(ComplexModel): + i = Integer + + class C1(ComplexModel): + i = Integer + c = C2 + + elt = self._run(C1(i=1, c=C2(i=2)), cloth=cloth) + assert elt.xpath('//b/text()') == ['1'] + # no order guarantee is given + assert set(elt.xpath('//d/text()')) == set(['1', '2']) + + def test_array(self): + v = range(3) + + class SomeObject(ComplexModel): + s = Array(Integer) + + cloth = E.a( + E.b( + E.c(spyne_id="integer"), + spyne_id="s", + ) + ) + + elt = self._run(SomeObject(s=v), cloth=cloth) + + assert elt.xpath('//c/text()') == [str(i) for i in v] + + def test_array_empty(self): + class SomeObject(ComplexModel): + s = Array(Integer) + + elt_str = '' + cloth = etree.fromstring(elt_str) + + elt = self._run(SomeObject(), cloth=cloth) + + assert elt.xpath('//c') == [] + + # FIXME: just fix it + def _test_array_empty_nonoptional(self): + class SomeObject(ComplexModel): + s = Array(Integer(min_occurs=1)) + + elt_str = '' + cloth = etree.fromstring(elt_str) + + elt = self._run(SomeObject(), cloth=cloth) + + 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) + + cloth = E.a( + E.b1(), + E.b2( + E.c1(spyne_id="s"), + E.c2(), + ), + E.e( + E.g1(), + E.g2(spyne_id="i"), + E.g3(), + ), + ) + + 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' + + def test_sibling_order(self): + class SomeObject(ComplexModel): + s = Unicode + + v = SomeObject(s='s') + + cloth = E.a( + E.b1(), + E.b2( + E.c0(), + E.c1(), + E.c2(spyne_id="s"), + E.c3(), + E.c4(), + ), + ) + + 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' + + def test_parent_text(self): + class SomeObject(ComplexModel): + s = Unicode + + v = SomeObject(s='s') + + cloth = E.a( + "text 0", + E.b1(spyne_id="s"), + ) + + print(etree.tostring(cloth, pretty_print=True)) + elt = self._run(v, cloth=cloth) + print(etree.tostring(elt, pretty_print=True)) + + assert elt.tag == 'a' + assert elt.text == 'text 0' + + assert elt[0].tag == 'b1' + assert elt[0].text == 's' + + def test_anc_text(self): + class SomeObject(ComplexModel): + s = Unicode + + v = SomeObject(s='s') + + cloth = E.a( + E.b1( + "text 1", + E.c1(spyne_id="s"), + ) + ) + + print(etree.tostring(cloth, pretty_print=True)) + 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' + + def test_prevsibl_tail(self): + class SomeObject(ComplexModel): + s = Unicode + + v = SomeObject(s='s') + + cloth = E.a( + E.b1( + E.c1(), + "text 2", + E.c2(spyne_id="s"), + ) + ) + + print(etree.tostring(cloth, pretty_print=True)) + 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' + + def test_sibling_tail_close(self): + class SomeObject(ComplexModel): + s = Unicode + + v = SomeObject(s='s') + + cloth = E.a( + E.b0(spyne_id="s"), + "text 3", + ) + + print(etree.tostring(cloth, pretty_print=True)) + 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' + + def test_sibling_tail_close_sibling(self): + class SomeObject(ComplexModel): + s = Unicode + i = Integer + + v = SomeObject(s='s', i=5) + + cloth = E.a( + E.b0(spyne_id="s"), + "text 3", + E.b1(spyne_id="i"), + ) + + print(etree.tostring(cloth, pretty_print=True)) + 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' + + def test_sibling_tail_close_anc(self): + class SomeObject(ComplexModel): + s = Unicode + i = Integer + + v = SomeObject(s='s', i=5) + + cloth = E.a( + E.b0(), + "text 0", + E.b1( + E.c0(spyne_id="s"), + "text 1", + E.c1(), + "text 2", + ), + "text 3", + 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' + + def test_nested_conflicts(self): + class SomeObject(ComplexModel): + s = Unicode + i = Integer + c = SelfReference + + v = SomeObject(s='x', i=1, c=SomeObject(s='y', i=2)) + + cloth = E.a( + E.b0(), + "text 0", + E.b1( + E.c0(spyne_id="s"), + "text 1", + E.c1( + E.d0(spyne_id="s"), + E.d1(spyne_id="i"), + spyne_id="c", + ), + "text 2", + ), + "text 3", + 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) + + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/protocol/test_cloth.pyc b/pym/calculate/contrib/spyne/test/protocol/test_cloth.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1687a13ac6d6ef7c30a84c1cab71f68fa088450f GIT binary patch literal 26692 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 qWB;|tIU+;' \ + 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)) + 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) + 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
' + + + def test_complex(self): + class CM(ComplexModel): + i = Integer + s = String + + class CCM(ComplexModel): + c = CM + i = Integer + s = String + + 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)) + 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) + server.get_in_object(ctx) + server.get_out_object(ctx) + server.get_out_string(ctx) + + # + # Here's what this is supposed to return: + # + #
+ #
+ #
456
+ #
+ #
123
+ #
abc
+ #
+ #
def
+ #
+ #
+ # + + elt = html.fromstring(b''.join(ctx.out_string)) + print(html.tostring(elt, pretty_print=True)) + + resp = elt.find_class('some_callResponse') + assert len(resp) == 1 + 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' + + 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' + + c_s = c[0].findall('div[@class="s"]') + assert len(c_s) == 1 + assert c_s[0].text == 'abc' + + s = res[0].findall('div[@class="s"]') + assert len(s) == 1 + assert s[0].text == 'def' + + def test_multiple(self): + class SomeService(Service): + @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)) + 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) + 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
') + + 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
' + + def test_before_first_root(self): + class CM(ComplexModel): + i = Integer + s = String + + class CCM(ComplexModel): + c = CM + i = Integer + s = String + + class SomeService(Service): + @srpc(CCM, _returns=Array(CCM)) + def some_call(ccm): + 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)) + server = WsgiApplication(app) + + call_wsgi_app_kwargs(server, + ccm_c_s='abc', ccm_c_i=123, ccm_i=456, ccm_s='def') + + assert cb_called[0] + + def test_complex_array(self): + class CM(ComplexModel): + i = Integer + s = String + + class CCM(ComplexModel): + c = CM + i = Integer + s = String + + 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)) + server = WsgiApplication(app) + + 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: + # + #
+ #
+ #
456
+ #
+ #
123
+ #
abc
+ #
+ #
def
+ #
+ #
+ #
456
+ #
+ #
123
+ #
abc
+ #
+ #
def
+ #
+ #
+ # + + print(out_string) + elt = html.fromstring(out_string) + show(elt, "TestHtmlMicroFormat.test_complex_array") + + resp = elt.find_class('some_callResponse') + assert len(resp) == 1 + res = resp[0].find_class('some_callResult') + assert len(res) == 1 + + assert len(res[0].find_class("CCM")) == 2 + + # We don't need to test the rest as the test_complex test takes care of + # that + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/protocol/test_html_microformat.pyc b/pym/calculate/contrib/spyne/test/protocol/test_html_microformat.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f18ee0bda5c35a031483aa965ce8e4c54bf6b353 GIT binary patch literal 11692 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/protocol/test_html_table.py b/pym/calculate/contrib/spyne/test/protocol/test_html_table.py new file mode 100644 index 0000000..d979356 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/protocol/test_html_table.py @@ -0,0 +1,508 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import logging +logging.basicConfig(level=logging.DEBUG) + +import unittest + +from lxml import etree, html + +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.protocol.html.table import HtmlColumnTable, HtmlRowTable +from spyne.service import Service +from spyne.server.wsgi import WsgiApplication +from spyne.util.test import show, call_wsgi_app_kwargs, call_wsgi_app + + +class CM(ComplexModel): + _type_info = [ + ('i', Integer), + ('s', String), + ] + + +class CCM(ComplexModel): + _type_info = [ + ('c', CM), + ('i', Integer), + ('s', String), + ] + + +class TestHtmlColumnTable(unittest.TestCase): + def test_complex_array(self): + class SomeService(Service): + @srpc(CCM, _returns=Array(CCM)) + def some_call(ccm): + return [ccm] * 5 + + 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', + ) + + elt = etree.fromstring(out_string) + show(elt, 'TestHtmlColumnTable.test_complex_array') + + elt = html.fromstring(out_string) + + row, = elt[0] # thead + cell = row.findall('th[@class="i"]') + assert len(cell) == 1 + assert cell[0].text == 'i' + + cell = row.findall('th[@class="s"]') + assert len(cell) == 1 + assert cell[0].text == 's' + + for row in elt[1]: # tbody + cell = row.xpath('td[@class="i"]') + assert len(cell) == 1 + assert cell[0].text == '456' + + cell = row.xpath('td[@class="c"]//td[@class="i"]') + assert len(cell) == 1 + assert cell[0].text == '123' + + cell = row.xpath('td[@class="c"]//td[@class="s"]') + assert len(cell) == 1 + assert cell[0].text == 'abc' + + cell = row.xpath('td[@class="s"]') + assert len(cell) == 1 + assert cell[0].text == 'def' + + def test_string_array(self): + class SomeService(Service): + @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)) + server = WsgiApplication(app) + + 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') == \ + '
+ :param header_cell_class: value that goes inside the + """ + + 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): + if from_arr: + td_attrib = {} + if False and self.field_name_attr: + td_attrib[self.field_name_attr] = name + + parent.write(E.tr(E.td(self.to_unicode(cls, inst), **td_attrib))) + else: + parent.write(self.to_unicode(cls, inst)) + + @coroutine + 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 + + 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) + continue + try: + sub_value = getattr(inst, k, None) + except: # e.g. SQLAlchemy could throw NoSuchColumnError + sub_value = None + + sub_name = v.Attributes.sub_name + if sub_name is None: + sub_name = k + + tr_attrs = {} + if self.row_class is not None: + self.add_html_attr('class', tr_attrs, self.row_class) + + 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_field_attrs(th_attrs, sub_name, v) + + if sub_attrs.hidden: + self.add_style(th_attrs, 'display:None') + + if self.header: + 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_field_attrs(td_attrs, sub_name, v) + + if sub_attrs.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, **kwargs) + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as b: + try: + ret.throw(b) + except StopIteration: + pass + + @coroutine + def array_to_parent(self, ctx, cls, inst, parent, name, **kwargs): + with parent.element('div'): + if issubclass(cls, ComplexModelBase): + ret = super(HtmlRowTable, self).array_to_parent( + ctx, cls, inst, parent, name, **kwargs) + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as b: + try: + ret.throw(b) + except StopIteration: + pass + else: + table_attrib = {} + 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 + + 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): + if self.header: + 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_field_attrs(td_attrs, name, cls) + + cls_attrs = self.get_cls_attrs(cls) + + if cls_attrs.hidden: + 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) + if isgenerator(ret): + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as b: + try: + ret.throw(b) + except StopIteration: + pass diff --git a/pym/calculate/contrib/spyne/protocol/html/table/row.pyc b/pym/calculate/contrib/spyne/protocol/html/table/row.pyc new file mode 100644 index 0000000000000000000000000000000000000000..60630fe10cd848d085f2e881aa43f897c404faf8 GIT binary patch literal 6410 zcmcgw-ESOM6+biU*j|4-&S#UBp){&Ro3)an6hac3kOoR=+D<}kmZHsg=h{2=?9687 zZk$DSU((kS2_asJprWsUpb`>N)khw9;Q^#dApQcx8xj&v@cW&+Yj53viUhGe$M^Hx z^L5Yf%vAn1J@MB+e{icQ{htc{KPR4)zeOX)pC_qE+mpH{9{awezSMm&zHC&)jL1FA z9nhr}Nk^qUCiOA5bVSl|X;-CQb^Qa9PDp!F>XXu*lKPair=>nE?HQ@hNPAZ5v(lcE z`kY%mD(Sqm4@&)@v=^kl;6}$JJtXbJQa|kaZp&hLobQXPdlv6V= z@~%xXW4Y-{VWLfUKD*60Xo!*RAQ=@WB^+&>dO9wyV%`5cgRje>VC&GvD z9^48G)zyJ8(3|Q*GfIEP6?W;>F~LYYqP9eLT*4cRl%*U8eWl24-ptd$wjvu8#&(OW zM8}|AcJiz=LB6_Snl^~aAPQO#IIxtsHZc+4=O$K`39S{ZrO}(G@}eEtPXDy0gVpZdX>nvDWw!5#pj#%{y7IZ8XI{e5>-~enzNmRdQDO8r=$OLE z79<&D)h)qRVq1aT$^$6bZD(bF`}s~(MC~Bzbj}BtgR;}hObwkhX-15r+U31AxRo}_ znoyY<_jk5T6r19Fa3#-E6J^1jDD6V$Jcx}oMH~JPwps>;giLu*w(_lDEiq}VJjf@D z+NPwWH1?`lPqK{K=4(3OgwKm0%WW;VYSyA|YT=kXxLI^fEx2JUI=jrSMJYVRgEo^+ z;ADfUL-H!a1`lmS)!YTnuk+x(hRimA+O^ z3Hq!rZ*ZON8j?FsN*7EIl=OVC+%g$WfG0Cg2l*XS6iE!bZBfSc+*$C}KILvbK=WoA zmF346mL1bf;FtXjb@i=a*CxB#_cgoK56D{@k-<$W;jFoC;3h?)0u|AniRQ9sc7akbA;%~q1e1#G;AP&2S@uYYZtCQa3AyV4`L`rZp3 zW~zY0ShD&e#KJuU)Wb@B1XFAeL=^FGo3_`&;K$TvPQo7O%yO`<~u&j_BE znQL2USp0di4G;oM`m&9-FW(jMY(Z5anF~}x@d)6qsolag@6NfZ}JqpqfnT9)a?>Gty zO>i7>bLcRI*dv%IO_4-t@*Pd7jaHP!sVT}um6PmCldf4dqGG+Y+_t&J<|106r2H0I zOWm?qN|V)dpIhqmY%9;s)}CD|6KhU)qUI*_DVH>XpFUeV^Gxl`xzn84lX4OL$7czIey|QEy`Rw@I_HR-kAvGAMdzY>!Iux+Eey@Uuwq zl*WOljRUeh-tS(>uyllBgJ5BpfMQw$1yQtJVNhZ9TZ+;M2QNF`->`2H=Z2z0eM#eM z(pL}c%NQC%Tc}V>sAY+g!s@@+PGBp%*v*nAqG*x&h4eE7gtP5k_dhMwGsHgijEgZH zW8&AiTr2W+1Ktmhb2}N?SkWa}eTXik=U&89vVIacaMYXi=KM3hx{tTz7@keK@9!{y za~w^qmGNd(9jEvE9z5pUC!+4dq6#l47ky2ASK$hjT?6l;&{8kLm-oN#dvv(gUhvud zH+=8z9iJz`?>=j>tKT;M>%Qz%WoKd#3KN{znUw8G*%*`J177)!Dhsyls%&E!c8-X5 zdq)sZy(0quA$Bkax$aeDXG)f{Y4JRU2s)W3E7-LGZd0-|E!)$oz_=769yVbFY-ocS z6~N6xy|W$#osk%_4yM4~>qjw^LcW_}%-;W@=aIpzGMF9MryOE1m>Mtu=Q-KNDCB{@ zU`uW1rTB?%I>@c~2(iSVYI1+TeRo0Vh48m;jGV@#>P*n7nmBcIL&N zknMT8w)oKRoszqci9IRB4}5s(wH+{@myJhd`yf|%w|oBb^6d}(5&M{IPDt^4-`l~9 zQg2?DeM+_$blLLlKVV6qOMd6WE6}m@pJbV;;^yZ-`=%i8aJd1?z zF^n#L8bs5Rvf3+XG>LGTq7DkC2D$4z&=Pxia$`%yWU@1obvVx3FHJj5YdD~V$WPo`v3+Foi@KF1qIVL3DQUS;DF z?Jnx;oA3x$@Wnt)TcY+1HOnhRx1fxwal_`F7w~eTaJ)duO|{x5uwRVWGx zK!GpCuL;%gG!hWH1Q(qpDqs-ZQO!YPf;dAyVh(zLkb{6QU1rDEP`qGn19aTwpcN#I z+rN?#IF&i*m*N4YGzVcBGF-KvgWkiENnP?YqR#F2WChz+Zoltm6`wg6YmphJr1+C0 z5DfBY_Z%i*UUqgt=O6tpKmjm1z*Hy>Re%$~nx8wY0X$;gF4mmUGIVs*y7(qflNK_%4L$oDqwsDvZU<+^`r~o@L8AC>DfrO5wM+ZpqQ)P$GP_Xb| zY6wYCxnUHi!$U+jYy~tZ<~t1DI3dMfbo?Zj0!#;B=R7^eQ7R0(_nog2-G5tOHvT(r zzdPjZrbC?l-o8e}c^7cvy!~S!&I7&u4wg7?zpaS#4iM+vk0H)7B5Hs>u8n~ki@fmH z^-{;lo$yKYLe_=hXG#78aBwPI0@2Kult?NLY?#kNUKV{f3JEFSEy?T|9e;MKn$MBRnM>ha!3o`DxZW_JDjfgRF-v zhuJx1KK@6q>YYGl+{=TrnhBXbnHe9H_p~5Ud}z4JprOug@HMjw_-`m)HyUx?#EUOq z)51qcSnY?jQm6n%x%bSZt^fNwBj1&uz@uf)=U$6)uz@eq_>>AY z=y`q^5Me=rFMR4^)FEHj`XpSzO!&-T4PLkKMapVWYoU?eZKpNX9<|jjKGoo>0Ap6` zFMa3LmwtU$5A|{oO+ua)j&mJlaUVDFNji0Q \n + # \" --> " + # + i = 0 + n = len(str) + res = [] + 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 + res.append(str[i:]) + break + # else: + j = k = -1 + if o_match: + 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 + res.append(str[i:k]) + res.append(str[k+1]) + i = k + 2 + else: # OctalPatt matched + res.append(str[i:j]) + res.append(chr(int(str[j+1:j+4], 8))) + i = j + 4 + return _nulljoin(res) + + +def _parse_cookie(cookie): + """Parse a ``Cookie`` HTTP header into a dict of name/value pairs. + This function attempts to mimic browser cookie parsing behavior; + it specifically does not follow any of the cookie-related RFCs + (because browsers don't either). + The algorithm used is identical to that used by Django version 1.9.10. + """ + cookiedict = {} + for chunk in cookie.split(str(';')): + if str('=') in chunk: + key, val = chunk.split(str('='), 1) + else: + # Assume an empty name per + # https://bugzilla.mozilla.org/show_bug.cgi?id=169091 + key, val = str(''), chunk + key, val = key.strip(), val.strip() + if key or val: + # unquote using Python's algorithm. + cookiedict[key] = _unquote_cookie(val) + return cookiedict + + +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: + if delete == False: + # You need python >= 2.6 for this. + retval = tempfile.NamedTemporaryFile('wb+', dir=dir, + delete=delete) + else: + retval = tempfile.NamedTemporaryFile('wb+', dir=dir) + else: + retval = BytesIO() + + return retval + + 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"] + +def _header_to_bytes(prot, val, cls): + if issubclass(cls, DateTime): + if val.tzinfo is not None: + val = val.astimezone(pytz.utc) + else: + 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) + else: + # because wsgi_ref wants header values in unicode. + return prot.to_unicode(cls, val) + + +class HttpRpc(SimpleDictDocument): + """The so-called HttpRpc protocol implementation. It only works with Http + (wsgi and twisted) transports. + + :param app: An :class:'spyne.application.Application` instance. + :param validator: Validation method to use. One of (None, 'soft') + :param mime_type: Default mime type to set. Default is + 'application/octet-stream' + :param tmp_dir: Temporary directory to store partial file uploads. Default + is to use the OS default. + :param tmp_delete_on_close: The ``delete`` argument to the + :class:`tempfile.NamedTemporaryFile`. + See: http://docs.python.org/2/library/tempfile.html#tempfile.NamedTemporaryFile. + :param ignore_uncap: As HttpRpc can't serialize complex models, it throws a + server exception when the return type of the user function is Complex. + Passing ``True`` to this argument prevents that by ignoring the return + value. + """ + + mime_type = 'text/plain' + default_binary_encoding = BINARY_ENCODING_URLSAFE_BASE64 + 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) + + self.tmp_dir = tmp_dir + self.tmp_delete_on_close = tmp_delete_on_close + self.parse_cookie = parse_cookie + + def get_tmp_delete_on_close(self): + return self.__tmp_delete_on_close + + 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) + + 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: + self.validator = self.SOFT_VALIDATION + elif validator is None: + self.validator = None + else: + 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)) + + ctx.in_document = ctx.transport.req + ctx.transport.request_encoding = in_string_encoding + + def decompose_incoming_envelope(self, ctx, message): + assert message == SimpleDictDocument.REQUEST + + ctx.transport.itself.decompose_incoming_envelope(self, ctx, message) + + if self.parse_cookie: + cookies = ctx.in_header_doc.get('cookie', None) + if cookies is None: + cookies = ctx.in_header_doc.get('Cookie', None) + + if cookies is not None: + for cookie_string in cookies: + logger.debug("Loading cookie string %r", cookie_string) + cookie = _parse_cookie(cookie_string) + for k, v in cookie.items(): + l = ctx.in_header_doc.get(k, []) + 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)) + + def deserialize(self, ctx, message): + assert message in (self.REQUEST,) + + 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) + 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) + + 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) + + self.event_manager.fire_event('after_deserialize', ctx) + + def serialize(self, ctx, message): + retval = None + + assert message in (self.RESPONSE,) + + if ctx.out_document is not None: + return + + if ctx.out_error is not None: + 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) + + return retval + + @coroutine + def _handle_rpc_nonempty(self, ctx): + result_class = ctx.descriptor.out_message + + out_class = None + out_object = None + + if ctx.descriptor.body_style is BODY_STYLE_WRAPPED: + 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.") + + if len(fti) == 1: + out_class, = fti.values() + out_object, = ctx.out_object + + else: + out_class = result_class + 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: + ctx.transport.set_mime_type(str(out_object.type)) + + ret = self.to_bytes_iterable(out_class, out_object) + + if not isinstance(ret, PushBase): + ctx.out_document = ret + + else: + ctx.transport.itself.set_out_document_push(ctx) + while True: + sv = yield + ctx.out_document.send(sv) + + def _handle_rpc(self, ctx): + retval = None + + # assign raw result to its wrapper, result_message + if ctx.out_object is None or len(ctx.out_object) < 1: + ctx.out_document = [''] + + else: + retval = self._handle_rpc_nonempty(ctx) + + header_class = ctx.descriptor.out_header + if header_class is not None: + # HttpRpc supports only one header class + header_class = header_class[0] + + # header + if ctx.out_header is not None: + out_header = ctx.out_header + 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) + + return retval + + 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') + + def integer_from_bytes(self, cls, 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_]+)}') + + +class HttpPattern(object): + """Experimental. Stay away. + + :param address: Address pattern + :param verb: HTTP Verb pattern + :param host: HTTP "Host:" header pattern + """ + + @staticmethod + def _compile_url_pattern(pattern): + """where <> placeholders don't contain slashes.""" + + if pattern is None: + return None + pattern = _fragment_pattern_re.sub(r'(?P<\1>[^/]*)', pattern) + pattern = _full_pattern_re.sub(r'(?P<\1>[^/]*)', pattern) + return re.compile(pattern) + + @staticmethod + def _compile_host_pattern(pattern): + """where <> placeholders don't contain dots.""" + + if pattern is None: + return None + pattern = _fragment_pattern_re.sub(r'(?P<\1>[^\.]*)', pattern) + pattern = _full_pattern_re.sub(r'(?P<\1>.*)', pattern) + return re.compile(pattern) + + @staticmethod + def _compile_verb_pattern(pattern): + """where <> placeholders are same as {} ones.""" + + if pattern is None: + return None + pattern = _fragment_pattern_re.sub(r'(?P<\1>.*)', pattern) + pattern = _full_pattern_re.sub(r'(?P<\1>.*)', pattern) + return re.compile(pattern) + + def __init__(self, address=None, verb=None, host=None, endpoint=None): + self.address = address + self.host = host + self.verb = verb + + self.endpoint = endpoint + if self.endpoint is not None: + assert isinstance(self.endpoint, MethodDescriptor) + + def hello(self, descriptor): + if self.address is None: + self.address = descriptor.name + + @property + def address(self): + return self.__address + + @address.setter + def address(self, what): + if what is not None and not what.startswith('/'): + what = '/' + what + + self.__address = what + self.address_re = self._compile_url_pattern(what) + + @property + def host(self): + return self.__host + + @host.setter + def host(self, what): + self.__host = what + self.host_re = self._compile_host_pattern(what) + + @property + def verb(self): + return self.__verb + + @verb.setter + def verb(self, what): + self.__verb = what + self.verb_re = self._compile_verb_pattern(what) + + def as_werkzeug_rule(self): + from werkzeug.routing import Rule + from spyne.util.invregexp import invregexp + + methods = None + if self.verb is not None: + methods = invregexp(self.verb) + + host = self.host + if host is None: + 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) + + 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) diff --git a/pym/calculate/contrib/spyne/protocol/http.pyc b/pym/calculate/contrib/spyne/protocol/http.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd0d592e478023db6f041e2ef4071ca2150f75aa GIT binary patch literal 17096 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 I z0r?OFj|t`%e#hFjUxV=-nUFXZ$ooV@=6oegNMlxQ_4LG}u&QxX`%|1FM?vJ?lW^Px znHxp1nOnBCd?a?AMEe&~QSYW3{l-Q4Wf4Ea(Q`AD@zFi7FBds>W3R*VIxd?cJ~wE= zaokg9T8f{!V2e^#kWDkt8?`WV95fNSX3G^ZQDzKf%Jxw{$Y&Q4K6U;cx6WT85qO&} z3DjVJcZL2paLi__cUYF^m$^Kn7>|PQgJAJ{-rz~R^WX-Pd*8s_C8z(||FpZ0qe5SP zf&FAR(@m3*Qbw^9dCosE`8pC2OQM1X_r>`~JlgU-;iP_(lM;sezwHNw=o`2n6u-ao zecX?4p*`mtNMt`md%f}d!AX7oHTyv|Nv072_)%maD1fw^O10p`gTtEl_y#zqS_oR2 z$X^<6k;7>8^SqOmI|Zls`BT3hZpD!Y-3pmP$fy~dgln%SfDj>tNyG~9nWMfO-o@ct zDCm1uzAB#CihN8adoSX|feCHyOgQaU1V6y-PRt(0O6sj;%Til%YVYgEt9-y#{%;B3mg z@vm9st!6ecIlLH0%FVRg2+Q_!3i0lpu%j8rDPHgzdg3UBA}97-X{ko+Z+0V3QS zH|CWrslXmtW?5XS9<#!jj`4VH`D&6OT&S{60s$K)$aI9cPiLj(b*G5hoWcRv0PB>jm>Zfoon=TFen z24{H)nc-phTE_TqZ?RaIC`^vx8sb&l8BkP|PIGiJYvLsyCP9cvq9h0qU6!*YW_dou ziei8*Fn0=xKr!Jk2`f3Wr9>NoA^NQ6h#I5fa44X}ciw+m##i7bIK&Z%C&xTAL0Rse zI0;RmoIWlakD7SeO!$db+F*qa{2@US+|u%02f}&ToHfqO7Z`zy&mb9Qh>7t6L<|n$ mYrK7sIlOiv{Dgl6e(C|6;&gG}#N 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) + + +_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) + + return _json_rpc_flavors[flavour](*args, **kwargs) diff --git a/pym/calculate/contrib/spyne/protocol/json.pyc b/pym/calculate/contrib/spyne/protocol/json.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0a90d4ef1075ebf066da7bea1db9822dce15043 GIT binary patch literal 14463 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/msgpack.py b/pym/calculate/contrib/spyne/protocol/msgpack.py new file mode 100644 index 0000000..71563fa --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/msgpack.py @@ -0,0 +1,361 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.protocol.msgpack`` module contains implementations for protocols +that use MessagePack as serializer. + +Initially released in 2.8.0-rc. + +""" + +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.protocol.dictdoc import HierDictDocument + + +class MessagePackDecodeError(Fault): + CODE = "Client.MessagePackDecodeError" + + def __init__(self, data=None): + super(MessagePackDecodeError, self) \ + .__init__(self.CODE, data) + + +NON_NUMBER_TYPES = tuple({list, dict, six.text_type, six.binary_type}) + + +class MessagePackDocument(HierDictDocument): + """An integration class for the msgpack protocol.""" + + mime_type = 'application/x-msgpack' + text_based = False + + type = set(HierDictDocument.type) + type.add('msgpack') + + default_string_encoding = 'UTF-8' + from_serstr = HierDictDocument.from_bytes + to_serstr = HierDictDocument.to_bytes + + # flags to be used in tests + _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.Unpacker, + 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 + if not raw: + self.from_serstr = self.from_unicode + + if use_bin_type: + self.from_serstr = self.from_unicode + + self.kwargs = kwargs + if raw != False: + kwargs['raw'] = raw + + if use_list != True: + kwargs['use_list'] = use_list + + if use_bin_type != True: + kwargs['use_bin_type'] = use_bin_type + + self._from_bytes_handlers[Double] = self._ret_number + self._from_bytes_handlers[Boolean] = self._ret_bool + self._from_bytes_handlers[Integer] = self.integer_from_bytes + + self._from_unicode_handlers[Double] = self._ret_number + self._from_unicode_handlers[Boolean] = self._ret_bool + self._from_unicode_handlers[Integer] = self.integer_from_bytes + + self._to_bytes_handlers[Double] = self._ret_number + self._to_bytes_handlers[Boolean] = self._ret_bool + self._to_bytes_handlers[Integer] = self.integer_to_bytes + + self._to_unicode_handlers[Double] = self._ret_number + self._to_unicode_handlers[Boolean] = self._ret_bool + self._to_unicode_handlers[Integer] = self.integer_to_bytes + + def _ret(self, _, value): + return value + + def _ret_number(self, _, value): + if isinstance(value, NON_NUMBER_TYPES): + raise ValidationError(value) + if value in (True, False): + return int(value) + return value + + def _ret_bool(self, _, value): + if value is None or value in (True, False): + return value + raise ValidationError(value) + + def get_class_name(self, cls): + class_name = cls.get_type_name() + if not six.PY2: + if not isinstance(class_name, bytes): + class_name = class_name.encode(self.default_string_encoding) + + return class_name + + def create_in_document(self, ctx, in_string_encoding=None): + """Sets ``ctx.in_document``, using ``ctx.in_string``. + + :param ctx: The MethodContext object + :param in_string_encoding: MessagePack is a binary protocol. So this + argument is ignored. + """ + + # 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): + unpacker = self.mw_unpacker(**self.kwargs) + 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)) + except ValueError as e: + raise MessagePackDecodeError(' '.join(e.args)) + + def gen_method_request_string(self, ctx): + """Uses information in context object to return a method_request_string. + + 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 = mrs.decode(self.key_encoding) + + return '{%s}%s' % (self.app.interface.get_tns(), mrs) + + 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) + 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: + return value + else: + return super(MessagePackDocument, self).integer_to_bytes(cls, value) + + +class MessagePackRpc(MessagePackDocument): + """An integration class for the msgpack-rpc protocol.""" + + 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'): + ctx.out_string = (msgpack.packb(o) for o in ctx.out_document) + + def create_in_document(self, ctx, in_string_encoding=None): + """Sets ``ctx.in_document``, using ``ctx.in_string``. + + :param ctx: The MethodContext object + :param in_string_encoding: MessagePack is a binary protocol. So this + argument is ignored. + """ + + # TODO: Use feed api + try: + ctx.in_document = msgpack.unpackb(b''.join(ctx.in_string), + **self.kwargs) + + except ValueError as e: + raise MessagePackDecodeError(''.join(e.args)) + + try: + len(ctx.in_document) + except TypeError: + 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") + + def decompose_incoming_envelope(self, ctx, message): + # FIXME: For example: {0: 0, 1: 0, 2: "some_call", 3: [1,2,3]} will also + # work. Is this a problem? + + # FIXME: Msgid is ignored. Is this a problem? + msgparams = [] + if len(ctx.in_document) == 3: + msgtype, msgid, msgname_or_error = ctx.in_document + + 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 msgtype == MessagePackRpc.MSGPACK_REQUEST: + assert message == MessagePackRpc.REQUEST + + elif msgtype == MessagePackRpc.MSGPACK_RESPONSE: + assert message == MessagePackRpc.RESPONSE + + elif msgtype == MessagePackRpc.MSGPACK_NOTIFY: + raise NotImplementedError() + + else: + raise MessagePackDecodeError("Unknown message type %r" % msgtype) + + 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 + + if isinstance(msgname_or_error, dict) and msgname_or_error: + # we got an error + ctx.in_error = msgname_or_error + else: + ctx.in_body_doc = msgparams + + # 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.RESPONSE) + + self.event_manager.fire_event('before_deserialize', ctx) + + if ctx.descriptor is None: + raise Fault("Client", "Method %r not found." % + ctx.method_request_string) + + # instantiate the result message + if message is self.REQUEST: + body_class = ctx.descriptor.in_message + elif message is self.RESPONSE: + body_class = ctx.descriptor.out_message + else: + raise Exception("what?") + + if ctx.in_error: + 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) + + else: + ctx.in_object = [] + + 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) + + if ctx.out_error is not None: + ctx.out_document = [ + [MessagePackRpc.MSGPACK_ERROR, 0, + Fault.to_dict(ctx.out_error.__class__, ctx.out_error)] + ] + return + + # get the result message + if message is self.REQUEST: + out_type = ctx.descriptor.in_message + msgtype = MessagePackRpc.MSGPACK_REQUEST + method_name_or_error = ctx.descriptor.operation_name + + elif message is self.RESPONSE: + out_type = ctx.descriptor.out_message + msgtype = MessagePackRpc.MSGPACK_RESPONSE + method_name_or_error = None + + else: + raise Exception("what?") + + if out_type is None: + return + + out_type_info = out_type._type_info + + # instantiate the result message + out_instance = out_type() + + # assign raw result to its wrapper, result_message + for i, (k, v) in enumerate(out_type_info.items()): + attrs = self.get_cls_attrs(v) + out_instance._safe_set(k, ctx.out_object[i], v, attrs) + + # 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) + 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) diff --git a/pym/calculate/contrib/spyne/protocol/msgpack.pyc b/pym/calculate/contrib/spyne/protocol/msgpack.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4f7be98583468d89cb2ae7ea99deb0f1166a9a26 GIT binary patch literal 11972 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/soap/__init__.py b/pym/calculate/contrib/spyne/protocol/soap/__init__.py new file mode 100644 index 0000000..754461f --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/soap/__init__.py @@ -0,0 +1,30 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.protocol.soap`` package contains an implementation of a subset +of the Soap 1.1 standard and awaits for volunteers for implementing the +brand new Soap 1.2 standard. + +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 diff --git a/pym/calculate/contrib/spyne/protocol/soap/__init__.pyc b/pym/calculate/contrib/spyne/protocol/soap/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ae0609dc56ee953553afa206d1cd27ac82ac720c GIT binary patch literal 636 zcmaJ;%}(Pm5O$IhP$VQcE+-#*siOo07lih_2ZUNqxj1ezZ7m!-vfb_W;r6;u!6R_v z0brZ}S|Nn3nanqt`8+?#^Ktg{__uDz+lle}6UF^P)e=&njz}956_G9`RZOCQlL05B zN=7^x@Pt&85g!nBK)RGvDdLnYriX#^AFBHe(7Ja0UIXi`@uo3~IV1YIroCt$#2RR0 zv=>r4Dm0Z{ub=~Tcxf~>D=MhlE*8YyfMqKzE=T(*eum3!Z6&{rD7BD4{4uoFV2b zYdRjf8hxk1*9+@_|LGKW-s0Pz(#zXnNIp!8^VT$+`!lq^7}YSZqL|}fG7m+}!`i-& zF6RlxOi}(*4%bWat+Tn3%gc+r-}{ZxCA-R<^e}tdhs%c=W+f}mS#de*_ZY!oy&nDf j`x^7maL&2Z(sRy`>1xFg6MB%;yLE@}O literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/soap/mime.py b/pym/calculate/contrib/spyne/protocol/soap/mime.py new file mode 100644 index 0000000..d4aaa1d --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/soap/mime.py @@ -0,0 +1,315 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.protocol.soap.mime`` module contains additional logic for using +optimized encodings for binary when encapsulating Soap 1.1 messages in Http. + +The functionality in this code seems to work at first glance but is not well +tested. + +Testcases and preferably improvements are most welcome. +""" + +from __future__ import print_function, unicode_literals + +import logging +logger = logging.getLogger(__name__) + +import re + +from base64 import b64encode +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 + + +XPATH_NSDICT = dict(xop=NS_XOP) + + +def _join_attachment(ns_soap_env, href_id, envelope, payload, prefix=True): + """Places the data from an attachment back into a SOAP message, replacing + its xop:Include element or href. + + Returns a tuple of length 2 with the new message and the number of + replacements made + + :param id: content-id or content-location of attachment + :param prefix: Set this to true if id is content-id or false if it is + content-location. It prefixes a "cid:" to the href value. + :param envelope: soap envelope string to be operated on + :param payload: attachment data + """ + + # grab the XML element of the message in the SOAP body + soaptree = etree.fromstring(envelope) + soapbody = soaptree.find("{%s}Body" % ns_soap_env) + + if soapbody is None: + raise ValidationError(None, "SOAP Body tag not found") + + message = None + for child in list(soapbody): + if child.tag != "{%s}Fault" % ns_soap_env: + message = child + break + + idprefix = '' + + if prefix: + idprefix = "cid:" + href_id = "%s%s" % (idprefix, href_id,) + + num = 0 + xpath = ".//xop:Include[@href=\"{}\"]".format(href_id) + + for num, node in enumerate(message.xpath(xpath, namespaces=XPATH_NSDICT)): + parent = node.getparent() + parent.remove(node) + parent.text = payload + + return etree.tostring(soaptree), num + + +def collapse_swa(ctx, content_type, ns_soap_env): + """ + Translates an SwA multipart/related message into an application/soap+xml + message. + + Returns the 'appication/soap+xml' version of the given HTTP body. + + References: + SwA http://www.w3.org/TR/SOAP-attachments + XOP http://www.w3.org/TR/xop10/ + MTOM http://www.w3.org/TR/soap12-mtom/ + http://www.w3.org/Submission/soap11mtom10/ + + :param content_type: value of the Content-Type header field, parsed by + cgi.parse_header() function + :param ctx: request context + """ + + 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) + + if u'multipart/related' not in mime_type: + return envelope + + charset = content_data.get('charset', None) + if charset is None: + charset = 'ascii' + + boundary = content_data.get('boundary', None) + if boundary is None: + raise ValidationError(None, u"Missing 'boundary' value from " + u"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()) + msg_string = chain( + (msg_string.encode(charset), generator.NL.encode('ascii')), + (e for e in envelope), + ) + + msg_string = b''.join(msg_string) + msg = message_from_bytes(msg_string) # our message + + soapmsg = None + 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': + 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]): + soapmsg = part.get_payload() + continue + + # binary packages + cte = part.get("Content-Transfer-Encoding") + + if cte != 'base64': + payload = b64encode(part.get_payload(decode=True)) + else: + payload = part.get_payload() + + cid = part.get("Content-ID").strip("<>") + cloc = part.get("Content-Location") + numreplaces = None + + # Check for Content-ID and make replacement + if cid: + 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) + + if soapmsg is None: + raise ValidationError(None, "Invalid MtoM request") + + return (soapmsg,) + + +def apply_mtom(headers, envelope, params, paramvals): + """Apply MTOM to a SOAP envelope, separating attachments into a + MIME multipart message. + + Returns a tuple of length 2 with dictionary of headers and string of body + that can be sent with HTTPConnection + + References: + XOP http://www.w3.org/TR/xop10/ + MTOM http://www.w3.org/TR/soap12-mtom/ + http://www.w3.org/Submission/soap11mtom10/ + + :param headers Headers dictionary of the SOAP message that would + originally be sent. + :param envelope Iterable containing SOAP envelope string that would have + originally been sent. + :param params params attribute from the Message object used for the SOAP + :param paramvals values of the params, passed to Message.to_parent + """ + + # grab the XML element of the message in the SOAP body + envelope = ''.join(envelope) + + soaptree = etree.fromstring(envelope) + soapbody = soaptree.find("{%s}Body" % _ns_soap_env) + + message = None + for child in list(soapbody): + if child.tag == ("{%s}Fault" % _ns_soap_env): + return headers, envelope + else: + message = child + break + + # Get additional parameters from original Content-Type + ctarray = [] + for n, v in headers.items(): + if n.lower() == 'content-type': + ctarray = v.split(';') + break + + roottype = ctarray[0].strip() + rootparams = {} + for ctparam in ctarray[1:]: + 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) + + # 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')) + + # Set up root SOAP part headers. + del rootpkg['mime-version'] + + rootpkg.add_header('Content-ID', '') + + for n, v in rootparams.items(): + rootpkg.set_param(n, v) + + rootpkg.set_param('type', roottype) + + mtompkg.attach(rootpkg) + + # Extract attachments from SOAP envelope. + for i in range(len(params)): + name, typ = params[i] + + if issubclass(typ, (ByteArray, File)): + id = "SpyneAttachment_%s" % (len(mtompkg.get_payload()), ) + + param = message[i] + param.text = "" + + incl = etree.SubElement(param, "{%s}Include" % _ns_xop) + incl.attrib["href"] = "cid:%s" % id + + if paramvals[i].fileName and not paramvals[i].data: + paramvals[i].load_from_file() + + if issubclass(type, File): + data = paramvals[i].data + else: + data = ''.join(paramvals[i]) + + attachment = MIMEApplication(data, _encoder=encode_7or8bit) + + del attachment['mime-version'] + + 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(), ) + marray = mtompkg.as_string().split(bound) + mtombody = bound + mtombody += bound.join(marray[1:]) + + # set Content-Length + mtompkg.add_header("Content-Length", str(len(mtombody))) + + # extract dictionary of headers from MIMEMultipart message + mtomheaders = {} + for name, value in mtompkg.items(): + mtomheaders[name] = value + + if len(mtompkg.get_payload()) <= 1: + return headers, envelope + + return mtomheaders, [mtombody] diff --git a/pym/calculate/contrib/spyne/protocol/soap/mime.pyc b/pym/calculate/contrib/spyne/protocol/soap/mime.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3689b4b38b9ec36b7b699d66093538ff2a341b07 GIT binary patch literal 8537 zcmd5>OLH7Ya?YN?n|MD75)@kyxx~uEK%f+oOha5z0u|z#gct*axE>2J985O`4fJEs zT}=SHz`>^0r;YHzf53-5?ZFZL0gl*+4c~pY5B>r6$qpa(Vt-#&Hy-kC*cUkrf{m`K ztgNi8tjsU7tN%7K^e_MPcdyz~{8aJxQ>jY!wIkw*H1Kr9t4QcbRFOtSqN+5i;;^?W zVUIL=#P5;)Uh(_njU$bIoq(YMX$81pEsbg09+GfIqFHIo+V(XG=Onr=jqA2OEaALF zH>7dHwnrqqDba#779_eQja#;NRKm9;x-E^{;`ldY-<5PmcR8lwye*AIapG~^(YSUk zYM1|xcoX8^mN()w?udU^yh-^Miui$eQ}QiTcu%}(eOaQ)HkW3g<9rGF-P-frSFf_} zN$l6UX=0Lg64tV$)vZNA(+c9uZFyc`f+TK*ZkTj}w!538Zk`2k zXDI2KAPRo!d#)e16AxXPj_w3;D?M?K_WYP5t!|cwErVfq6AQVkwN*Frv#izeGdGCc zFOBKehK4BFZXUPoVu3l~nAr<5$m02K=KE3Rn#4Uy(gU|;+}$9}jN1uYaocxya^r$B zPK!+=q5X>WN|Fs|avB6mCW8+|l$?YWaYeT_* z;%BJ>wV6>ox@i!bW+|Q-r#j<+f;GdyfMu9%P`zRX@!0wB1J#IcyL!>p-h(zTn!ZW> zVw4j)eheNaNiD?)x}HCM{^WTcnxNZCjqM&Qx*vDDVbF#~lY%29v^pK=;XOX2fle)af8 zdAIJnso%wP-c%Pq0qh*d@bGEe4s%>6KUCv)ah>;YEpS&zRrgJv^4hy5@4^oxyKd;m z9kb^?aE}7~p(wF`RIZ}eO8fF?$4^18Z0yp-?TT8SZ@E8&F}EVf;yvVI_@SS{E|vq2 zf|RW=vF6R?FSe?jOBTG!!7%!SP z&~2BO9_}-VuT1W?PQs)`66?q+A7CEiIshlZXyTdrw!)CcY+dFBqV$6H@EH#XOwe!iuI9pAu$U@yuc^&@z2LT!q2(EP#pEg%&!hT0C84%r zgbT}E_ppR6(MR?*-d6G~T?qrkj+O3-*-PRFwU1UZ1eaxK{eZ!8MZ@;;gWBr*wbc)o zyCbLsfG>3F793F|DC5)0M}@oTbw6I&IvwxAI=TV%u%NYhuSN~p$E_YP;l6Au59+u zU9+dRblUKAJ#x@5=~IC(+@#lsuZH8FC28UGXVvL<>BG?j=Uk8>23Rtjw%KlgpQJ};9 z2{s`KxWPjs>U;}%s?S#l>w(2o`HqEW88zVB_ou}hR)S$Ue&(=ehO4e` zKXQr~ft?`=jmSYo(mm(!#}4<6*a6u`IWzr*bGeBS1Ip}g9J~~o_%#X0dQMr5$vk;! zukC^?SNM*rMA-5uQ6)p=e>mp4t~y6xY39L*!R>5JV#F{=qpZ=qEXw{3f=`l-m;KY) zoKOWoH{%Gx6?2o(9`A^pr(^P_M@{FNoK5NxPe}S>2cyIMGpT=y856|}vmkGJFD79t z_(A_+G>_#QvT1kBlc;{ix z23Q2%3+$!$><^BkP?;6Z;5%WIG2$NP6mac)%02hBpJo7XjBq6C1h0XXzuek-;nKgH zvjJQMvh%Ztx(H?D&mJK2!(6i`J15Gkl;P^%b|=f~oYAV4wSz!o@(zP85}$k(-Os56WIXrEUYs~#f<WQSjl4SXg@@fIFD2Ays>gslEa#yFibjHRr1r!YHb%HUShb5YduXXIG z6&@I_$nLhiRLuxUDDRvCBTKJPv#!=bjIsp)t$>CibnExYoXdVe@VrC_pt82ju_CmR zF`3qHW3>J@NqFi6AXX)WawQ?N7zIzo9jY&ro|mdnziKziI)x5&H8hokeu(cBG))qt zFW9mLmTlwL7s-uk1IX3UHh{c^fq7IUB^LR7@4(CMIt)?%@SE9DYY$Ro-{2vWgMeIv z&P_afDwBX%gZiAT4p%3gn@-hv%bBWTNl$X}fTq7}^^La}}LiwZ%i=G?vF-6G^V{+QNh zGt>3$cbPmh=>_Hjo&qg#MTedTteCc95VKw!uFJ~~aN&R)|41?70D;K*_NoT$K_Vgs1Fy}tcHnO$q9 zy|2kSKnRm?yA+U+=IH1INW#i%hyRGI8+Zw{7$G2Y&PK%mH6h_2A^IZ>1iAqr8kJA* zhu9BoEKx!BZrdo!O=ues2|76Flk_ii3w&zCbSf#2(T!RFN_G4>I=F$3qkAm*+r_C~>- zqR@J?Ub=W7z9AiZ3zy!) z)zAMO9-Vc<6IYSlMRll5dGDj5%4nf=*-NOgC?zQbVh!>F6PH-{9Gm_Rl_D>&wOo{f z0dg%ILj?t8SR3BhORTF)nLU(r+o)`zE|RgVrNt)VVFd2jS56i~)>*>6go*!OBHVJf zuKT4z*v!4E4MP6Q#X95w*#A+Ihn}kADyT&(NrMi`>LCua(9o5FQ+cYaR-uxzb5X(9 zvOCLy=Ol&pFIIH-TCe^8#j;3Hcr;fQR=|-_+~N(Ulm;lr7f6>IeQt~WZnCqFgT%)J zfOvjID3zc~7pZ}A0VvBXT+Yh0z;b5}0Bq&4fL3s=nS`hZaw!{y$X82b1S1z^uuEWM znW!Zv82%$%NRfcA+Wth5S{&$I}DsgF8^tUu;MF+O=B zVSQpN;R-Ri1sq?=8m6pT+Qk=<4OBoCQ!0j~a#*FcpFudTW9R7FN^a3LJ+i`OLhjO5 z>JQmVX>lQK&cVGGp2Om3ZqQo3YUBKJ)bC)RewPnDkb8Jj@!LqI_!Wni9P9J7%CBgd zz@J-Yqu|OF+qR+enXPvZEZSBwypva;n_~@FCB`l_4*|&L87ecS2=H;C?x9N;x(F*u zraM>7MpjB5Ggs7#Di4T_LIFBMQ)Wf#`uINUq-tLbm`w`t_YfxgDIPL2R$-0Q)<=i% zw->N`-kAgdAE=C@VmblHJ_q1FS?zbm@o(5!sPo=Qq zN>}IMC=ou+B0zM?Oz;_+xM9?Av&nPAd|DI9{Ivctr?G8wW}E-fQSxJ^Ns=(L$tN#) z2v=sS{XA)vQD&Fg)NjYN^Yq 0: + header = header_envelope[0].getchildren() + + body = None + if len(body_envelope) > 0 and len(body_envelope[0]) > 0: + body = body_envelope[0][0] + + return header, body + + +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 )) + else: + string = ''.join(chain( (chunk,), xml_string )) + + if charset: + string = string.decode(charset) + + try: + try: + 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.') + 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)) + + return root, xmlids + + +# see http://www.w3.org/TR/2000/NOTE-SOAP-20000508/ +# 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 + + elif e.get('href'): + resolved_element = xmlids[e.get('href').replace('#', '')] + if resolved_element is None: + continue + resolve_hrefs(resolved_element, xmlids) + + # copies the attributes + [e.set(k, v) for k, v in resolved_element.items()] + + # copies the children + [e.append(child) for child in resolved_element.getchildren()] + + # copies the text + e.text = resolved_element.text + + else: + resolve_hrefs(e, xmlids) + + return element + + +class Soap11(XmlDocument): + """The base implementation of a subset of the Soap 1.1 standard. The + document is available here: http://www.w3.org/TR/soap11/ + + :param app: The owner application instance. + :param validator: One of (None, 'soft', 'lxml', 'schema', + ProtocolBase.SOFT_VALIDATION, XmlDocument.SCHEMA_VALIDATION). + Both ``'lxml'`` and ``'schema'`` values are equivalent to + ``XmlDocument.SCHEMA_VALIDATION``. + :param xml_declaration: Whether to add xml_declaration to the responses + Default is 'True'. + :param cleanup_namespaces: Whether to add clean up namespace declarations + in the response document. Default is 'True'. + :param encoding: The suggested string encoding for the returned xml + documents. The transport can override this. + :param pretty_print: When ``True``, returns the document in a pretty-printed + format. + """ + + mime_type = 'text/xml; charset=utf-8' + + type = set(XmlDocument.type) + type.update(('soap', 'soap11')) + + ns_soap_env = ns.NS_SOAP11_ENV + ns_soap_enc = ns.NS_SOAP11_ENC + + def __init__(self, *args, **kwargs): + super(Soap11, self).__init__(*args, **kwargs) + + # SOAP requires DateTime strings to be in iso format. The following + # lines make sure custom datetime formatting via + # DateTime(dt_format="...") (or similar) is bypassed. + self._to_unicode_handlers[Time] = lambda cls, value: value.isoformat() + self._to_unicode_handlers[DateTime] = lambda cls, value: value.isoformat() + + self._from_unicode_handlers[Date] = self.date_from_unicode_iso + self._from_unicode_handlers[DateTime] = self.datetime_from_unicode_iso + + def create_in_document(self, ctx, charset=None): + if isinstance(ctx.transport, HttpTransportContext): + # according to the soap-via-http standard, soap requests must only + # work with proper POST requests. + content_type = ctx.transport.get_request_content_type() + http_verb = ctx.transport.get_request_method() + 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.") + + content_type = cgi.parse_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) + + 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) + + ctx.in_document = envelope_xml + + if body_document.tag == '{%s}Fault' % self.ns_soap_env: + ctx.in_body_doc = body_document + + else: + ctx.in_header_doc = header_document + ctx.in_body_doc = body_document + ctx.method_request_string = ctx.in_body_doc.tag + self.validate_body(ctx, message) + + def deserialize(self, ctx, message): + """Takes a MethodContext instance and a string containing ONE soap + message. + Returns the corresponding native python object + + Not meant to be overridden. + """ + + assert message in (self.REQUEST, self.RESPONSE) + + self.event_manager.fire_event('before_deserialize', ctx) + + if ctx.in_body_doc.tag == "{%s}Fault" % self.ns_soap_env: + ctx.in_object = None + ctx.in_error = self.from_element(ctx, Fault, ctx.in_body_doc) + + else: + if message is self.REQUEST: + header_class = ctx.descriptor.in_header + body_class = ctx.descriptor.in_message + + elif message is self.RESPONSE: + header_class = ctx.descriptor.out_header + body_class = ctx.descriptor.out_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): + headers = [None] * len(header_class) + 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__) + header_doc = in_header_dict.get(nsval, None) + if header_doc is not None: + headers[i] = self.from_element(ctx, head_class, + header_doc) + + if len(headers) == 1: + ctx.in_header = headers[0] + else: + ctx.in_header = headers + + # decode method arguments + 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) + + 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 + ctx.out_body_doc, ctx.out_header_doc and ctx.out_document as an + lxml.etree._Element instance. + + Not meant to be overridden. + """ + + assert message in (self.REQUEST, self.RESPONSE) + + 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) + 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()) + + else: + if message is self.REQUEST: + header_message_class = ctx.descriptor.in_header + body_message_class = ctx.descriptor.in_message + + elif message is self.RESPONSE: + header_message_class = ctx.descriptor.out_header + body_message_class = ctx.descriptor.out_message + + # body + ctx.out_body_doc = out_body_doc = etree.Element( + '{%s}Body' % self.ns_soap_env) + + # assign raw result to its wrapper, result_message + if ctx.descriptor.body_style is BODY_STYLE_WRAPPED: + out_type_info = body_message_class._type_info + out_object = body_message_class() + bm_attrs = self.get_cls_attrs(body_message_class) + + keys = iter(out_type_info) + values = iter(ctx.out_object) + while True: + try: + k = next(keys) + except StopIteration: + break + try: + v = next(values) + except StopIteration: + v = None + + 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()) + + else: + out_object = ctx.out_object[0] + + sub_ns = body_message_class.Attributes.sub_ns + if sub_ns is None: + sub_ns = body_message_class.get_namespace() + if sub_ns is DEFAULT_NS: + sub_ns = self.app.interface.get_tns() + + sub_name = body_message_class.Attributes.sub_name + 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) + + # 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) + + 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, + soap_header_elt, + header_class.get_namespace(), + header_class.get_type_name(), + ) + + ctx.out_document.append(ctx.out_body_doc) + + if self.cleanup_namespaces: + etree.cleanup_namespaces(ctx.out_document) + + self.event_manager.fire_event('after_serialize', ctx) + + def fault_to_http_response_code(self, fault): + return HTTP_500 diff --git a/pym/calculate/contrib/spyne/protocol/soap/soap11.pyc b/pym/calculate/contrib/spyne/protocol/soap/soap11.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eeecbc7d8ac727f54934252d0d5d876c00a2db67 GIT binary patch literal 11887 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/soap/soap12.py b/pym/calculate/contrib/spyne/protocol/soap/soap12.py new file mode 100644 index 0000000..69858a1 --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/soap/soap12.py @@ -0,0 +1,152 @@ +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +""" +The ``spyne.protoco.soap.soap12`` module contains the implementation of a +subset of the Soap 1.2 standard. + +This modules is EXPERIMENTAL. +More info can be found at: https://www.w3.org/TR/soap12-part1/ +""" + +import logging + +from lxml.builder import E + +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") + + +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' + + soap_env = PREFMAP[NS_SOAP12_ENV] + ns_soap_env = NS_SOAP12_ENV + + type = set(Soap11.type) + 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: + subcode_node.append(subcode) + return subcode_node + + def gen_fault_codes(self, faultstring): + 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 + else: + 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) + while subcode is not None: + faultcode.append(subcode.find('soap:Value', namespaces=nsmap).text) + subcode = subcode.find('soap:Subcode', namespaces=nsmap) + + 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})) + + subelts = [ + reason, + E("{%s}Role" % self.ns_soap_env, inst.faultactor), + ] + + return self._fault_to_parent_impl(ctx, cls, inst, parent, ns, subelts) + + 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): + 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 + for value in faultcodes[::-1]: + if child_subcode: + child_subcode = self.generate_subcode(value, child_subcode) + else: + child_subcode = self.generate_subcode(value) + if child_subcode != 0: + code.append(child_subcode) + + _append(subelts, code) + + if isinstance(inst.detail, dict): + _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)) + + 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 = [ + E("{%s}Reason" % self.soap_env, inst.faultstring), + E("{%s}Role" % self.soap_env, inst.faultactor), + ] + + return self._fault_to_parent_impl(ctx, cls, inst, parent, ns, subelts) + + def fault_from_element(self, ctx, cls, element): + nsmap = element.nsmap + + code = self.generate_faultcode(element) + reason = element.find("soap:Reason/soap:Text", namespaces=nsmap).text.strip() + role = element.find("soap:Role", namespaces=nsmap) + node = element.find("soap:Node", namespaces=nsmap) + detail = element.find("soap:Detail", namespaces=nsmap) + 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) diff --git a/pym/calculate/contrib/spyne/protocol/soap/soap12.pyc b/pym/calculate/contrib/spyne/protocol/soap/soap12.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c1db0a0f79cc2f654c3a9c8e31a6b5cc4479bb7c GIT binary patch literal 5493 zcmcgw-)|gO6+W|TuXopW?EJ7vO4=+xg0^Y1+jUV|xfEy;L-upC1oo`cuaL@8c@|gd!5@qx2*yN#aQ#75tSYDaoiT{jzv$&qy*OqgmlYY&$=On4iXkPmBu3eR6K}L(xUzE`q>7S9&lJu9vGoI`$ zi#aO?xb-ewa1Seqb!;vrZLD;8^&qTu$U2##)%mjSZti7jcltC){DtzVJzz$ z(Zd>zPHU}E*f5R4JZjZ(ueg{lS2R%Fcyw>W|H0jj?){JMwCZ=W91EvgSz{2UjZM?o z$|h;l2<>`f+uCul-flm8_N?{n-By+l+xPu8x7k^{J`Qu+Y1iZb;HTU4@KBb;hO1Uk zd02KM>b6wZ1M!}2V%K@<;cV6(v3+?Xcuw~Hvcy`cBw zkM4EWf{pG2%bURR=J9vmCYxdLg~&Jl7xJ8~t3=sgLe>!c z@M#z);U<{1ZF1u<{t}4WI=T1;HUs36c%ZCP{NLIgB_A{f+hGpweK@gO*WcHZR&I3c z3?BmMAKTUj#E^DgH`)I~6jmL1Ph`iFRUGJkS@z1ZQ__x-Ogr{GIdJE_SCahpbO`E% zAQiTI%8_m{k41lewb<`XHV0W`irTdOAWSBXM?NfKIW8>%ZZa_GQ{Cv4p4^~&0+Vdn zS+u~UiBXE-$hoXl_PTnI!qCJh(V}>ST6BDMxzGk6jX zP0?1@zrNP$yxZ#BxITW45iK(uI(vI635g!|)Z%?JCV8Ai%=y~&?akwR(x+AhXcZlc{9Pm2TlSf~YRdl2s9x#~Az6WIX z3wd4qcxlNfyPlI3DeI94cm%NMRvUj;WAbUxAKB-b*8{0>UL-iIYdzA?r z;X|~AgF@W@seOP&vI4&yWqW`99;H)O9) z5#isA{HiRMZvE^XF1fcL`5$!}D5Fi>A2UAr<*|{sQOiS&X80*f{-zKYVfz z5ow-x*0y^lY*|hDWzUV^MqT8>vqRwdjGEG6o=&|sHBs}blDE9{qF5wy;QP{v(F|{R z-sO`l$8%JeF#c6`kn8^IEO0q5!olzkNnw17 zj8Cd7#ohhX9e6LFj^=-z#U&Q6aokjvf{__*B1}&`tV!CbbNSa;dyB=}EUvR?vFNa9 zqtNZ!a2QbfHPGtLmEs!wbO)^I8^B;YPNKuq=ahWTe-r!M#O0jaTP&UPE|!pNl`7tA z(A^c(8IPA?f3vjYmCF}PE1qgF^_PyQ4%kKIga%I??d5bA)KrJ0q(V$VHuxl1_oAed zW=B~sRqqQVRfUuAIqJ z4Y&!YRVa>WasxKar8EWdzr`U97KBN~gGuvPl|gs(vg3b~gPA`0AFz0b(}-4%{b+?R zP(E*?ygV(IQMz0l-O963FwOIR3u{4X6R!qOeghd5e=G3sRlUx6O)8{Mm-7{XCX)%LThsZoj18Emn9%4zLg~}d@SqeNogp0 zX$;nJ;fw<3`X)BU+;~?bp}la@t{E|dtpVI_HdHEg3#P2e0>+4sgw18l>jMqs1UM??r=ga>ENfoU| literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/xml.py b/pym/calculate/contrib/spyne/protocol/xml.py new file mode 100644 index 0000000..f993032 --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/xml.py @@ -0,0 +1,1160 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +"""The ``spyne.protocol.xml`` module contains an xml-based protocol that +serializes python objects to xml using Xml Schema conventions. + +Logs valid documents to ``'spyne.protocol.xml'`` and invalid documents to +``spyne.protocol.xml.invalid``. Use the usual ``logging.getLogger()`` and +friends to configure how these get logged. + +Warning! You can get a lot of crap in the 'invalid' logger. You're not advised +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 +from collections import defaultdict + +from lxml import etree +from lxml import 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 spyne.model.binary import BINARY_ENCODING_BASE64 +from spyne.model.enum import EnumBase + +from spyne.protocol import ProtocolBase + +from spyne.util import six + +if six.PY2: + STR_TYPES = (str, unicode) +else: + STR_TYPES = (str, bytes) + + +NIL_ATTR = {XSI('nil'): 'true'} +XSI_TYPE = XSI('type') + + +def _append(parent, child_elt): + if hasattr(parent, 'append'): + parent.append(child_elt) + else: + parent.write(child_elt) + + +def _gen_tagname(ns, name): + if ns is not None: + name = "{%s}%s" % (ns, name) + return name + + +class SchemaValidationError(Fault): + """Raised when the input stream could not be validated by the Xml Schema.""" + + CODE = 'Client.SchemaValidationError' + + def __init__(self, faultstring): + super(SchemaValidationError, self).__init__(self.CODE, faultstring) + + +class SubXmlBase(ProtocolBase): + def subserialize(self, ctx, cls, inst, parent, ns=None, name=None): + return self.to_parent(ctx, cls, inst, parent, name) + + def to_parent(self, ctx, cls, inst, parent, ns, *args, **kwargs): + """Serializes inst to an Element instance and appends it to the 'parent'. + + :param self: The protocol that will be used to serialize the given + value. + :param cls: The type of the value that's going to determine how to + pack the given value. + :param inst: The value to be set for the 'text' element of the newly + created SubElement + :param parent: The parent Element to which the new child will be + appended. + :param ns: The target namespace of the new SubElement, used with + 'name' to set the tag. + :param name: The tag name of the new SubElement, 'retval' by default. + """ + raise NotImplementedError() + + +class XmlDocument(SubXmlBase): + """The Xml input and output protocol, using the information from the Xml + Schema generated by Spyne types. + + See the following material for more (much much more!) information. + + * http://www.w3.org/TR/xmlschema-0/ + * http://www.w3.org/TR/xmlschema-1/ + * http://www.w3.org/TR/xmlschema-2/ + + Receiving Xml from untrusted sources is a dodgy security dance as the Xml + attack surface is /huge/. + + Spyne's ```lxml.etree.XMLParser``` instance has ```resolve_pis```, + ```load_dtd```, ```resolve_entities```, ```dtd_validation```, + ```huge_tree``` Defaults to ``False`` + + Having ```resolve_entities``` disabled will prevent the 'lxml' validation + for documents with custom xml entities defined in the DTD. See the example + in examples/xml/validation_error to play with the settings that work best + for you. Please note that enabling ```resolve_entities``` is a security + hazard that can lead to disclosure of sensitive information. + + See https://pypi.python.org/pypi/defusedxml for a pragmatic overview of + Xml security in Python world. + + :param app: The owner application instance. + + :param validator: One of (None, 'soft', 'lxml', 'schema', + ProtocolBase.SOFT_VALIDATION, XmlDocument.SCHEMA_VALIDATION). + Both ``'lxml'`` and ``'schema'`` values are equivalent to + ``XmlDocument.SCHEMA_VALIDATION``. + + Defaults to ``None``. + + :param replace_null_with_default: If ``False``, does not replace incoming + explicit null values with denoted default values. This is against Xml + Schema standard but consistent with other Spyne protocol + implementations. Set this to False if you want cross-protocol + compatibility. + + Defaults to ``True``. + + Relevant quote from xml schema primer + (http://www.w3.org/TR/xmlschema-0/): + + .. + When a value is present and is null The schema processor treats + defaulted elements slightly differently. When an element is declared + with a default value, the value of the element is whatever value + appears as the element's content in the instance document; if the + element appears without any content, the schema processor provides + the element with a value equal to that of the default attribute. + However, if the element does not appear in the instance document, + the schema processor does not provide the element at all. In + summary, the differences between element and attribute defaults can + be stated as: Default attribute values apply when attributes are + missing, and default element values apply when elements are empty. + + :param xml_declaration: Whether to add xml_declaration to the responses + + Defaults to ``True``. + + :param cleanup_namespaces: Whether to add clean up namespace declarations + in the response document. + + Defaults to ``True``. + + :param encoding: The suggested string encoding for the returned xml + documents. The transport can override this. + + Defaults to ``None``. + + :param pretty_print: When ``True``, returns the document in a pretty-printed + format. + + Defaults to ``False``. + + :param parse_xsi_type: Set to ``False`` to disable parsing of ``xsi:type`` + attribute, effectively disabling polymorphism. + + Defaults to ``True``. + + The following are passed straight to the ``XMLParser()`` instance from + lxml. Docs are also plagiarized from the lxml documentation. Please note + that some of the defaults are different to make parsing safer by default. + + :param attribute_defaults: read the DTD (if referenced by the document) and + add the default attributes from it. + + Defaults to ``False`` + + :param dtd_validation: validate while parsing (if a DTD was referenced). + + Defaults to ``False`` + + :param load_dtd: load and parse the DTD while parsing (no validation is + performed). + + Defaults to ``False``. + + :param no_network: prevent network access when looking up external + documents. + + Defaults to ``True``. + + :param ns_clean: try to clean up redundant namespace declarations. + Please note that this is for incoming documents. + See ``cleanup_namespaces`` parameter for output documents. + + Defaults to ``False``. + + :param recover: try hard to parse through broken Xml. + + Defaults to ``False``. + + :param remove_blank_text: discard blank text nodes between tags, also known + as ignorable whitespace. This is best used together with a DTD or schema + (which tells data and noise apart), otherwise a heuristic will be + applied. + + Defaults to ``False``. + + :param remove_pis: When ``True`` xml parser discards processing + instructions. + + Defaults to ``True``. + + :param strip_cdata: replace CDATA sections by normal text content. + + Defaults to ``True`` + + :param resolve_entities: replace entities by their text value. + + Defaults to ``False``. + + :param huge_tree: disable security restrictions and support very deep trees + and very long text content. (only affects libxml2 2.7+) + + Defaults to ``False``. + + :param compact: use compact storage for short text content. + + Defaults to ``True``. + + """ + + SCHEMA_VALIDATION = type("Schema", (object,), {}) + + mime_type = 'text/xml' + default_binary_encoding = BINARY_ENCODING_BASE64 + + type = set(ProtocolBase.type) + 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) + + self.validation_schema = None + self.xml_declaration = xml_declaration + self.cleanup_namespaces = cleanup_namespaces + self.replace_null_with_default = replace_null_with_default + + if encoding is None: + self.encoding = 'UTF-8' + else: + self.encoding = encoding + + self.polymorphic = polymorphic + 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.parser_kwargs = dict( + attribute_defaults=attribute_defaults, + dtd_validation=dtd_validation, + load_dtd=load_dtd, + no_network=no_network, + ns_clean=ns_clean, + recover=recover, + remove_blank_text=remove_blank_text, + remove_comments=True, + remove_pis=remove_pis, + strip_cdata=strip_cdata, + resolve_entities=resolve_entities, + huge_tree=huge_tree, + compact=compact, + encoding=encoding, + ) + + def set_validator(self, validator): + 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: + self.validator = self.SOFT_VALIDATION + + elif validator is None: + pass + + else: + raise ValueError(validator) + + self.validation_schema = None + + def validate_body(self, ctx, message): + """Sets ctx.method_request_string and calls :func:`generate_contexts` + for validation.""" + + assert message in (self.REQUEST, self.RESPONSE), message + + line_header = LIGHT_RED + "Error:" + END_COLOR + try: + self.validate_document(ctx.in_body_doc) + if message is self.REQUEST: + line_header = LIGHT_GREEN + "Method request string:" + END_COLOR + else: + line_header = LIGHT_RED + "Response:" + END_COLOR + finally: + if logger.level == logging.DEBUG: + logger.debug("%s %s" % (line_header, ctx.method_request_string)) + logger.debug(etree.tostring(ctx.in_document, pretty_print=True)) + + def set_app(self, value): + ProtocolBase.set_app(self, value) + + self.validation_schema = None + + if self.validator is self.SCHEMA_VALIDATION and value is not None: + from spyne.interface.xml_schema import XmlSchema + + xml_schema = XmlSchema(value.interface) + xml_schema.build_validation_schema() + + self.validation_schema = xml_schema.validation_schema + + def __validate_lxml(self, payload): + ret = self.validation_schema.validate(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')) + + 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) + try: + try: + 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) + except XMLSyntaxError as e: + logger_invalid.error("%r in string %r", e, string) + 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_body_doc = ctx.in_document + ctx.method_request_string = ctx.in_body_doc.tag + self.validate_body(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: + raise ValidationError(None) + + if self.replace_null_with_default: + return cls_attrs.default + + return None + + # if present, use the xsi:type="ns0:ObjectName" + # attribute to instantiate subclass objects + if self.parse_xsi_type: + xsi_type = element.get(XSI_TYPE, None) + if xsi_type is not None: + if ":" in xsi_type: + prefix, objtype = xsi_type.split(':', 1) + else: + prefix, objtype = None, xsi_type + + ns = element.nsmap.get(prefix) + if ns is not None: + classkey = "{%s}%s" % (ns, objtype) + + else: + 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) + raise ValidationError(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) + + def to_parent(self, ctx, cls, inst, parent, ns, *args, **kwargs): + cls, add_type = self.get_polymorphic_target(cls, inst) + cls_attrs = self.get_cls_attrs(cls) + + subprot = cls_attrs.prot + if subprot is not None and isinstance(subprot, SubXmlBase): + return subprot.subserialize(ctx, cls, inst, parent, ns, + *args, **kwargs) + + handler = self.serialization_handlers[cls] + + if inst is None: + inst = cls_attrs.default + + if inst is None: + return self.null_to_parent(ctx, cls, inst, parent, ns, + *args, **kwargs) + + if cls_attrs.exc: + return + kwargs['add_type'] = add_type + return handler(ctx, cls, inst, parent, ns, *args, **kwargs) + + def deserialize(self, ctx, message): + """Takes a MethodContext instance and a string containing ONE root xml + tag. + + Returns the corresponding native python object. + + Not meant to be overridden. + """ + + assert message in (self.REQUEST, self.RESPONSE) + + 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) + else: + raise ctx.in_error + + if message is self.REQUEST: + body_class = ctx.descriptor.in_message + elif message is self.RESPONSE: + body_class = ctx.descriptor.out_message + + # decode method arguments + 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) + + if logger.level == logging.DEBUG and message is self.REQUEST: + 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) + + logger.debug("%s %s" % (line_header, outdoc_str)) + + 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 ``ctx.out_body_doc``, ``ctx.out_header_doc`` and + ``ctx.out_document`` as an ``lxml.etree._Element instance``. + + Not meant to be overridden. + """ + + assert message in (self.REQUEST, self.RESPONSE) + + 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()) + ctx.out_document = tmp_elt[0] + + else: + if message is self.REQUEST: + result_message_class = ctx.descriptor.in_message + elif message is self.RESPONSE: + result_message_class = ctx.descriptor.out_message + + # assign raw result to its wrapper, result_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()): + attrs = self.get_cls_attrs(v) + result_inst._safe_set(k, ctx.out_object[i], v, attrs) + + else: + 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()) + ctx.out_document = tmp_elt[0] + + else: + 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) + + return retval + + def create_out_string(self, ctx, charset=None): + """Sets an iterable of string fragments to ctx.out_string""" + + 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)] + + 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'))) + + @coroutine + def incgen(self, ctx, cls, inst, ns, name=None): + if name is None: + name = cls.get_type_name() + with etree.xmlfile(ctx.out_stream) as xf: + ret = self.to_parent(ctx, cls, inst, xf, ns, name) + if isgenerator(ret): + try: + while True: + y = (yield) # may throw Break + ret.send(y) + + except Break: + try: + ret.throw(Break()) + except StopIteration: + pass + + if hasattr(ctx.out_stream, 'finish'): + ctx.out_stream.finish() + + def _gen_tag(self, cls, ns, name, add_type=False, **_): + if ns is not None: + name = "{%s}%s" % (ns, name) + + retval = E(name) + if add_type: + retval.attrib[XSI_TYPE] = cls.get_type_name_ns(self.app.interface) + + return retval + + 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): + 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): + if issubclass(cls, XmlAttribute): + return + + elif issubclass(cls, XmlData): + parent.attrib.update(NIL_ATTR) + + else: + elt = self._gen_tag(cls, ns, name, **kwargs) + elt.attrib.update(NIL_ATTR) + _append(parent, elt) + + def null_from_element(self, ctx, cls, element): + return None + + def xmldata_to_parent(self, ctx, cls, inst, parent, ns, name, + add_type=False, **_): + cls_attrs = self.get_cls_attrs(cls) + + ns = cls._ns + if ns is None: + ns = cls_attrs.sub_ns + + name = _gen_tagname(ns, name) + + if add_type: + parent.attrib[XSI_TYPE] = cls.get_type_name_ns(self.app.interface) + + cls.marshall(self, name, inst, parent) + + def xmlattribute_to_parent(self, ctx, cls, inst, parent, ns, name, **_): + ns = cls._ns + cls_attrs = self.get_cls_attrs(cls) + if ns is None: + ns = cls_attrs.sub_ns + + name = _gen_tagname(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)) + 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): + attrib = {} + if add_type: + tnn = cls.get_type_name_ns(self.app.interface) + if tnn != None: + attrib[XSI_TYPE] = tnn + else: + # this only happens on incomplete interface states for eg. + # get_object_as_xml where the full init is not performed for + # perf reasons + attrib[XSI_TYPE] = cls.get_type_name() + + if isinstance(parent, etree._Element): + elt = etree.SubElement(parent, tag_name, attrib=attrib) + elt.extend(subelts) + ret = self._get_members_etree(ctx, cls, inst, elt) + + if isgenerator(ret): + try: + while True: + y = (yield) # may throw Break + ret.send(y) + + except Break: + try: + ret.throw(Break()) + except StopIteration: + pass + + else: + with parent.element(tag_name, attrib=attrib): + for e in subelts: + parent.write(e) + ret = self._get_members_etree(ctx, cls, inst, parent) + if isgenerator(ret): + try: + while True: + y = (yield) + ret.send(y) + + except Break: + try: + ret.throw(Break()) + except StopIteration: + pass + + @coroutine + def _get_members_etree(self, ctx, cls, inst, parent): + try: + 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 + ret.send(sv2) + + except Break: + try: + ret.throw(Break()) + except StopIteration: + pass + + for k, v in cls._type_info.items(): + sub_cls_attrs = self.get_cls_attrs(v) + if sub_cls_attrs.exc: + continue + try: + subvalue = getattr(inst, k, None) + except: # e.g. SqlAlchemy could throw NoSuchColumnError + subvalue = None + + # This is a tight loop, so enable this only when necessary. + # logger.debug("get %r(%r) from %r: %r" % (k, v, inst, subvalue)) + + sub_ns = v.Attributes.sub_ns + if sub_ns is None: + sub_ns = cls.get_namespace() + + sub_name = v.Attributes.sub_name + if sub_name is None: + sub_name = k + + mo = v.Attributes.max_occurs + 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) + if ret is not None: + try: + while True: + sv2 = (yield) # may throw Break + ret.send(sv2) + + except Break: + try: + ret.throw(Break()) + except StopIteration: + pass + + else: + for sv in subvalue: + 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 + ret.send(sv2) + + except Break: + try: + ret.throw(Break()) + except StopIteration: + pass + + # 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) + if ret is not None: + try: + while True: + sv2 = (yield) + ret.send(sv2) + except Break as b: + try: + ret.throw(b) + except StopIteration: + pass + + except Break: + pass + + 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 + if sub_name is not None: + name = sub_name + if name is None: + name = cls.get_type_name() + + sub_ns = cls_attrs.sub_ns + if not sub_ns in (None, DEFAULT_NS): + ns = sub_ns + + tag_name = _gen_tagname(ns, name) + + inst = cls.get_serialization_instance(inst) + + 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)) + + elif isinstance(inst.detail, dict): + if len(inst.detail) > 0: + _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)) + + # add other nonstandard fault subelements with get_members_etree + 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("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,**_): + subelts = [ + 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)) + + # 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): + self.modelbase_to_parent(ctx, cls, str(inst), parent, ns, name, **kwargs) + + def any_xml_to_parent(self, ctx, cls, inst, parent, ns, name, **_): + if isinstance(inst, STR_TYPES): + inst = etree.fromstring(inst) + + _append(parent, E(_gen_tagname(ns, name), inst)) + + 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: + inst = html.fromstring(inst) + + _append(parent, E(_gen_tagname(ns, name), inst)) + + def any_dict_to_parent(self, ctx, cls, inst, parent, ns, name, **_): + elt = E(_gen_tagname(ns, name)) + dict_to_etree(inst, elt) + + _append(parent, elt) + + def complex_from_element(self, ctx, cls, elt): + inst = cls.get_deserialization_instance(ctx) + + flat_type_info = cls.get_flat_type_info(cls) + + # this is for validating cls.Attributes.{min,max}_occurs + frequencies = defaultdict(int) + cls_attrs = self.get_cls_attrs(cls) + + if cls_attrs._xml_tag_body_as is not None: + 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) + else: + value = self.from_unicode(xtba_type.type, elt.text) + + inst._safe_set(xtba_key, value, xtba_type.type, xtba_attrs) + + # parse input to set incoming data to related attributes. + for c in elt: + if isinstance(c, etree._Comment): + continue + + key = c.tag.split('}', 1)[-1] + frequencies[key] += 1 + + member = flat_type_info.get(key, None) + if member is None: + member, key = cls._type_info_alt.get(key, (None, key)) + if member is None: + member, key = cls._type_info_alt.get(c.tag, (None, key)) + if member is None: + continue + + member_attrs = self.get_cls_attrs(member) + mo = member_attrs.max_occurs + if mo > 1: + value = getattr(inst, key, None) + if value is None: + value = [] + + value.append(self.from_element(ctx, member, c)) + + else: + value = self.from_element(ctx, member, c) + + inst._safe_set(key, value, member, member_attrs) + + for key, value_str in c.attrib.items(): + submember = flat_type_info.get(key, None) + + if submember is None: + submember, key = cls._type_info_alt.get(key, (None, key)) + if submember is None: + continue + + submember_attrs = self.get_cls_attrs(submember) + mo = submember_attrs.max_occurs + if mo > 1: + value = getattr(inst, key, None) + if value is None: + value = [] + + value.append(self.from_unicode(submember.type, value_str)) + + else: + value = self.from_unicode(submember.type, value_str) + + inst._safe_set(key, value, submember.type, submember_attrs) + + for key, value_str in elt.attrib.items(): + member = flat_type_info.get(key, None) + if member is None: + member, key = cls._type_info_alt.get(key, (None, key)) + if member is None: + continue + + if not issubclass(member, XmlAttribute): + continue + + if issubclass(member.type, (ByteArray, File)): + value = self.from_unicode(member.type, value_str, + self.binary_encoding) + else: + value = self.from_unicode(member.type, value_str) + + member_attrs = self.get_cls_attrs(member.type) + inst._safe_set(key, value, member.type, member_attrs) + + if self.validator is self.SOFT_VALIDATION: + for key, c in flat_type_info.items(): + 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) + + return inst + + def array_from_element(self, ctx, cls, element): + retval = [ ] + (serializer,) = cls._type_info.values() + + for child in element.getchildren(): + retval.append(self.from_element(ctx, serializer, child)) + + return retval + + def iterable_from_element(self, ctx, cls, element): + (serializer,) = cls._type_info.values() + + for child in element.getchildren(): + yield self.from_element(ctx, serializer, child) + + def enum_from_element(self, ctx, cls, element): + if self.validator is self.SOFT_VALIDATION and not ( + 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') + if factor is not None: + factor = factor.text + detail = element.find('detail') + + return cls(faultcode=code, faultstring=string, faultactor=factor, + detail=detail) + + def xml_from_element(self, ctx, cls, element): + children = element.getchildren() + retval = None + + if children: + retval = element.getchildren()[0] + + return retval + + def html_from_element(self, ctx, cls, element): + children = element.getchildren() + retval = None + + if len(children) == 1: + retval = children[0] + # this is actually a workaround to a case that should never exist -- + # anyXml types should only have one child tag. + elif len(children) > 1: + retval = E.html(*children) + + return retval + + def dict_from_element(self, ctx, cls, element): + children = element.getchildren() + if children: + return etree_to_dict(element) + + return None + + def unicode_from_element(self, ctx, cls, element): + if self.validator is self.SOFT_VALIDATION and not ( + cls.validate_string(cls, element.text)): + raise ValidationError(element.text) + + s = element.text + if s is None: + s = '' + + retval = self.from_unicode(cls, s) + + if self.validator is self.SOFT_VALIDATION and not ( + 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)): + 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)): + 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)): + 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)): + raise ValidationError(retval) + + return retval diff --git a/pym/calculate/contrib/spyne/protocol/xml.pyc b/pym/calculate/contrib/spyne/protocol/xml.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2b4eea8774bc25d8621aa6d6f1874337ef7e20af GIT binary patch literal 36304 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/protocol/yaml.py b/pym/calculate/contrib/spyne/protocol/yaml.py new file mode 100644 index 0000000..1a9a46a --- /dev/null +++ b/pym/calculate/contrib/spyne/protocol/yaml.py @@ -0,0 +1,187 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.protocol.yaml`` package contains the Yaml-related protocols. +Currently, only :class:`spyne.protocol.yaml.YamlDocument` is supported. + +Initially released in 2.10.0-rc. +""" + +from __future__ import absolute_import + +import logging +logger = logging.getLogger(__name__) + +from spyne import ValidationError +from spyne.util import six +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.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 CSafeDumper as SafeDumper + +except ImportError: + from yaml import Loader + from yaml import Dumper + from yaml import SafeLoader + from yaml import SafeDumper + + +NON_NUMBER_TYPES = tuple({list, dict, six.text_type, six.binary_type}) + + +class YamlDocument(HierDictDocument): + """An implementation of the Yaml protocol that uses the PyYaml package. + See ProtocolBase ctor docstring for its arguments. Yaml-specific arguments + follow: + + :param safe: Use ``safe_dump`` instead of ``dump`` and ``safe_load`` instead + of ``load``. This is not a security feature, search for 'safe_dump' in + http://www.pyyaml.org/wiki/PyYAMLDocumentation + :param kwargs: See the yaml documentation in ``load, ``safe_load``, ``dump`` + or ``safe_dump`` depending on whether you use yaml as an input or output + protocol. + + For the output case, Spyne sets ``default_flow_style=False`` and + ``indent=4`` by default. + """ + + mime_type = 'text/yaml' + + type = set(HierDictDocument.type) + type.add('yaml') + + text_based = True + + default_binary_encoding = BINARY_ENCODING_BASE64 + + # 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) + + self._from_unicode_handlers[Double] = self._ret_number + self._from_unicode_handlers[Boolean] = self._ret_bool + self._from_unicode_handlers[Integer] = self._ret_number + + self._to_unicode_handlers[Double] = self._ret + self._to_unicode_handlers[Boolean] = self._ret + self._to_unicode_handlers[Integer] = self._ret + + loader = Loader + dumper = Dumper + if safe: + loader = SafeLoader + dumper = SafeDumper + + self.in_kwargs = dict(kwargs) + self.out_kwargs = dict(kwargs) + + self.in_kwargs['Loader'] = loader + self.out_kwargs['Dumper'] = dumper + + loader.add_constructor('tag:yaml.org,2002:python/unicode', + _unicode_loader) + + 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 'default_flow_style' in self.out_kwargs: + self.out_kwargs['default_flow_style'] = False + + def _ret(self, _, value): + return value + + def _ret_number(self, _, value): + if isinstance(value, NON_NUMBER_TYPES): + raise ValidationError(value) + if value in (True, False): + return int(value) + return value + + def _ret_bool(self, _, value): + if value is None or value in (True, False): + return value + raise ValidationError(value) + + 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' + + try: + try: + s = b''.join(ctx.in_string).decode(in_string_encoding) + except TypeError: + s = ''.join(ctx.in_string) + + ctx.in_document = yaml.load(s, **self.in_kwargs) + + except ParserError as e: + raise Fault('Client.YamlDecodeError', repr(e)) + + 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) + + +def _unicode_loader(loader, node): + return node.value + + +def _decimal_to_bytes(): + pass + + +def _decimal_from_bytes(): + pass diff --git a/pym/calculate/contrib/spyne/protocol/yaml.pyc b/pym/calculate/contrib/spyne/protocol/yaml.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f233a35e853d1634b78066b35872b6dbf41fb12 GIT binary patch literal 6650 zcmd5=-ESMm5uYO|N~At*%U}7hFR_!bsYN+<>ISM4$d>KIh(jw!JFeLl#}jW!opiio z@0O7X$S-x!6b1Uwm%g?yMS-H|Lkko|f&M4`6Z+PFpud^r9qHJwN-K%0ot@p;`JP!8 z|Fc;A_rLzx?$G#W2LCrViPFDYL_SdqqeXs!LW}wZY8A+0xJY4sZ_W7I!Rt>Xrsr|<;zSE;pXV6b+QS|^2<1qx45|1`BulQp^}ON)%|pP|-Svwcb6 zSE%)>ftLk-jasi8ctzlI)H+Yrqv&%gDVz4Il=v2YSQW=)!`YnRae-gW37!!6^_<|U zz~_ZvWYG`R8>HSOb%9is_Abi!7VVZqqi>UclGG}7anC9Gis%{9sn{ok;7|tznX=NQa|Kb{vHxd!rM2X}a+;(sibBEA9;YIMB9()J}(k zL7aeMy;{8+1v>CTkiadmm9++(}NmVk%9N)Kf zFZTS5ye!-r_6OMlAKPkrT{XQcU!2~_oK0^MPNyhUf&V6@J`{ zr?!{$#K+UR37d4FIzcz+Ob|k@8;4-K|PL>vC1SlgbRs?IP8^vLciPY)Ay2`gUG*%bla z$*+9}w+g9Utp^+H>jwu1^}%QawbbLJw|)@p2kTJNjnD37E-u=g7H9tex=1%fbDTx^ zFe^;dV{CySZ?~DxOV10#pb^xFlVs?z^u8LX$Y-_3k$teMKt8cY@sLeu?(tv=m_8Z| zwGGR}Lyegb%kme}4%_t(u*{v=VRvBKOLmiUBNPLBf)Ul_;C8z(n49WRs6M>og{gwh zVFe-5ZU>PM5Bu{bYcf)GUka-$A8v_-cpAi*xZh6o3sne(`uNzr%IPIhLLBQLTh* z5VtGNn$gMnP~r76>( zz>@TXzH;?wprrZ)y(mr;sCK-8TrgfZNN^e&5WYGwXZ0tpmujw;ae|wbFM1rr;iw-c zgI!3(n&F)0us$3y1M6=rAWz3k^OTbdYA$9ZL;5*p>%%lz4}+a+@2?xzxKjWAdKzf8 zHg1*Db?Kzm(5+mpzjtkIFv5h;X}dX{e_`jJDOv!MD2pY#d_T0CQ&D6Clc9gk(p z{8kFf)^cIdS}atoS^2+=Jy^~fLYhPF0AhlNCLXiAgOF#Pid=PeA#A?yik6exYD zj$FLganslMq^Q1NGG~`L5_Uhr1j!8?gEvHda*i}Io3si)vpAhF3OS)f-2&~GDcRuQ zF&mormkBD7z)l*ZTq3=wqcl5p<9@?!JpAnDZO47^c>8wKVHJogJV=JhxyTT66GXa} z>&anjI9D+oxrVqA|0O;t^G+7bY#q0%FVPgU1bKZp>>Q=%L@yRAYpjd2j0gM&r@-3YfR z?e-XDI>mOoJ}Lc(15n{?zZC{(Aj~sKap{pKLPI)P=L2jITkgehT27g`$&k~Mx#WZ( z9w3d%QRhTSd~K2Dq82QMe9`IHKa+AXsEj%q-J~eZ0i`UWlG?9FC$$Qx(tSuyke)_b(2YXom}ybDM|z z7>sf;Inw5kp9Vj`Cw&(~d8u3|Ly3zR%f&Jp!J=e2WIFl3@OGtGnXSw$9P6-u@P|{# z)+WxgR!w5d8UjX{28TB~mobQTBNUs7a7W`W&IR1|7ksj=5L5Zd`DHu%lkSC)6Q*Q# zG@OYi=dOVl)6Ph%^l!NS|BqG9T{)}rIuvIAF=4j$UCbQ^!#K*iL;jKnk%c9aPz&Q; zj~}yK`+G{?1BfT-Hlw+fVD$JAC+`~5JaeaNzAzr@AT-&CUDd21lvP+aF=t|tUs}_+ zK@#-w74Mg7@>VquSNe|7h#ZUhx3A{O0tb4B0e?FFAO{1 zV|uI%adM}{vmasjcHDOkH(fWm^rJJFr`#)+3oC^MydLFU$!|;ZTUfwKaSW~EO=;Fw Ni|2}`4l1Qe>Az2L@R$Gq literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/server/__init__.py b/pym/calculate/contrib/spyne/server/__init__.py new file mode 100644 index 0000000..5ab6584 --- /dev/null +++ b/pym/calculate/contrib/spyne/server/__init__.py @@ -0,0 +1,23 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.server`` package contains the server transports.""" + +from spyne.server._base import ServerBase +from spyne.server.null import NullServer diff --git a/pym/calculate/contrib/spyne/server/__init__.pyc b/pym/calculate/contrib/spyne/server/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ee149657ae903ab7631b8027b7fdc09c40bf175c GIT binary patch literal 389 zcmZ8c%}T>S5T5*4r68#E0dfpNc4?J*DIz{V4~?f>Hfge?i580+^&}8|0R>~l+jm?z7z|z#z4Q!hkZ0gn`Q@<3ULn?Mo z5RdDx8Ok%a?X;fw?dWMQX;6rw&V{gdl>c>RVo%FEV!_`2?-^3s4PN2UKLf^8@(x?B z)qefRo8BI3vtmyim6g%y6y&2(v|`H#wp>R|PZLa*<;3&pI4*=T$_l|q<%)DSRb6yi NJ})RopJ3+RI7ipGWr6?z literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/server/_base.py b/pym/calculate/contrib/spyne/server/_base.py new file mode 100644 index 0000000..5f27140 --- /dev/null +++ b/pym/calculate/contrib/spyne/server/_base.py @@ -0,0 +1,260 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import logging +logger = logging.getLogger(__name__) + +from inspect import isgenerator + +from spyne import EventManager +from spyne.auxproc import process_contexts +from spyne.interface import AllYourInterfaceDocuments +from spyne.model import Fault, PushBase +from spyne.protocol import ProtocolBase +from spyne.util import Break, coroutine + + +class ServerBase(object): + """This class is the abstract base class for all server transport + implementations. Unlike the client transports, this class does not define + a pure-virtual method that needs to be implemented by all base classes. + + If there needs to be a call to start the main loop, it's called + ``serve_forever()`` by convention. + """ + + transport = None + """The transport type, which is a URI string to its definition by + convention.""" + + def __init__(self, app): + self.app = app + self.app.transport = self.transport # FIXME: this is weird + self.appinit() + + self.event_manager = EventManager(self) + self.doc = AllYourInterfaceDocuments(app.interface) + + def appinit(self): + self.app.reinitialize(self) + + def generate_contexts(self, ctx, in_string_charset=None): + """Calls create_in_document and decompose_incoming_envelope to get + method_request string in order to generate contexts. + """ + try: + # sets ctx.in_document + self.app.in_protocol.create_in_document(ctx, in_string_charset) + + # sets ctx.in_body_doc, ctx.in_header_doc and + # ctx.method_request_string + 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. + retval = self.app.in_protocol.generate_method_contexts(ctx) + + except Fault as e: + ctx.in_object = None + ctx.in_error = e + ctx.out_error = e + + retval = (ctx,) + + ctx.fire_event('method_exception_object') + + return retval + + def get_in_object(self, ctx): + """Uses the ``ctx.in_string`` to set ``ctx.in_body_doc``, which in turn + is used to set ``ctx.in_object``.""" + + try: + # sets ctx.in_object and ctx.in_header + self.app.in_protocol.deserialize(ctx, + message=self.app.in_protocol.REQUEST) + + except Fault as e: + logger.exception(e) + logger.debug("Failed document is: %s", ctx.in_document) + + ctx.in_object = None + ctx.in_error = e + ctx.out_error = e + + ctx.fire_event('method_exception_object') + + def get_out_object(self, ctx): + """Calls the matched user function by passing it the ``ctx.in_object`` + to set ``ctx.out_object``.""" + + if ctx.in_error is None: + # event firing is done in the spyne.application.Application + self.app.process_request(ctx) + else: + raise ctx.in_error + + def convert_pull_to_push(self, ctx, gen): + oobj, = ctx.out_object + if oobj is None: + gen.throw(Break()) + + elif isinstance(oobj, PushBase): + pass + + elif len(ctx.pusher_stack) > 0: + oobj = ctx.pusher_stack[-1] + assert isinstance(oobj, PushBase) + + else: + raise ValueError("%r is not a PushBase instance" % oobj) + + retval = self.init_interim_push(oobj, ctx, gen) + return self.pusher_try_close(ctx, oobj, retval) + + def get_out_string_pull(self, ctx): + """Uses the ``ctx.out_object`` to set ``ctx.out_document`` and later + ``ctx.out_string``.""" + + # This means the user wanted to override the way Spyne generates the + # outgoing byte stream. So we leave it alone. + if ctx.out_string is not None: + return + + 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 len(ctx.pusher_stack) > 0: + # we suspend request processing here because there now + # seems to be a PushBase waiting for input. + return self.convert_pull_to_push(ctx, ret) + + self.finalize_context(ctx) + + def finalize_context(self, ctx): + if ctx.out_error is None: + ctx.fire_event('method_return_document') + else: + 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') + else: + ctx.fire_event('method_exception_string') + + if ctx.out_string is None: + ctx.out_string = (b'',) + + # for backwards compatibility + get_out_string = get_out_string_pull + + @coroutine + def get_out_string_push(self, ctx): + """Uses the ``ctx.out_object`` to directly set ``ctx.out_string``.""" + + ret = ctx.out_protocol.serialize(ctx, message=ProtocolBase.RESPONSE) + if isgenerator(ret): + try: + while True: + y = (yield) + ret.send(y) + + except Break: + try: + ret.throw(Break()) + except StopIteration: + pass + + self.finalize_context(ctx) + + def serve_forever(self): + """Implement your event loop here, if needed.""" + + raise NotImplementedError() + + def init_interim_push(self, ret, p_ctx, gen): + assert isinstance(ret, PushBase) + assert p_ctx.out_stream is not None + + # we don't add interim pushers to the stack because we don't know + # where to find them in the out_object's hierarchy. whatever finds + # one in the serialization pipeline has to push it to pusher_stack so + # the machinery in ServerBase can initialize them using this function. + + # fire events + p_ctx.fire_event('method_return_push') + + def _cb_push_finish(): + process_contexts(self, (), p_ctx) + + return self.pusher_init(p_ctx, gen, _cb_push_finish, ret, interim=True) + + def pusher_init(self, p_ctx, gen, _cb_push_finish, pusher, interim): + return pusher.init(p_ctx, gen, _cb_push_finish, None, interim) + + def pusher_try_close(self, ctx, pusher, _): + logger.debug("Closing pusher with ret=%r", pusher) + + pusher.close() + + popped = ctx.pusher_stack.pop() + assert popped is pusher + + 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.') + return + + p_ctx.pusher_stack.append(ret) + + # fire events + 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." + + def _cb_push_finish(): + process_contexts(self, others, p_ctx) + + retval = self.pusher_init(p_ctx, gen, _cb_push_finish, ret, + interim=False) + + self.pusher_try_close(p_ctx, ret, retval) + + return retval + + @staticmethod + def set_out_document_push(ctx): + ctx.out_document = _write() + ctx.out_document.send(None) + + +def _write(): + v = yield + yield v diff --git a/pym/calculate/contrib/spyne/server/_base.pyc b/pym/calculate/contrib/spyne/server/_base.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5fddb851c1eb9cf986256e6524d06972807c9dc5 GIT binary patch literal 8706 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/server/django.py b/pym/calculate/contrib/spyne/server/django.py new file mode 100644 index 0000000..a611057 --- /dev/null +++ b/pym/calculate/contrib/spyne/server/django.py @@ -0,0 +1,390 @@ +# encoding: utf-8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.server.django`` module contains a Django-compatible Http +transport. It's a thin wrapper around +:class:`spyne.server.wsgi.WsgiApplication`. +""" + +from __future__ import absolute_import + +import logging +logger = logging.getLogger(__name__) + +from functools import update_wrapper + +from spyne import Address +from spyne.application import get_fault_string_from_exception, Application +from spyne.auxproc import process_contexts +from spyne.interface import AllYourInterfaceDocuments +from spyne.model.fault import Fault +from spyne.protocol.soap import Soap11 +from spyne.protocol.http import HttpRpc +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 + + +class DjangoApplication(WsgiApplication): + """You should use this for regular RPC.""" + + HttpResponseObject = HttpResponse + + # noinspection PyMethodOverriding + # because this is VERY similar to a Wsgi app + # but not that much. + def __call__(self, request): + retval = self.HttpResponseObject() + + def start_response(status, headers): + # Status is one of spyne.const.http + status, reason = status.split(' ', 1) + + retval.status_code = int(status) + for header, value in headers: + retval[header] = value + + environ = request.META.copy() + + # FIXME: No idea what these two did. + # They were commented out to fix compatibility issues with + # Django-1.2.x + # See http://github.com/arskom/spyne/issues/222. + + # If you don't override wsgi.input django and spyne will read + # the same buffer twice. If django read whole buffer spyne + # would hang waiting for extra request data. Use DjangoServer instead + # of monkeypatching wsgi.inpu. + + #environ['wsgi.input'] = request + #environ['wsgi.multithread'] = False + + response = WsgiApplication.__call__(self, environ, start_response) + self.set_response(retval, response) + + return retval + + def set_response(self, retval, response): + retval.content = _bytes_join(response, b"") + + +class StreamingDjangoApplication(DjangoApplication): + """You should use this when you're generating HUGE data as response. + + New in Django 1.5. + """ + + HttpResponseObject = StreamingHttpResponse + + def set_response(self, retval, response): + retval.streaming_content = response + + +class DjangoHttpTransportContext(HttpTransportContext): + def get_path(self): + return self.req.path + + def get_request_method(self): + return self.req.method + + def get_request_content_type(self): + return self.req.META['CONTENT_TYPE'] + + def get_path_and_qs(self): + return self.req.get_full_path() + + 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) + + if address_parser.is_valid_ipv4(addr, port): + return Address(type=Address.TCP4, host=addr, port=port) + + if address_parser.is_valid_ipv6(addr, port): + return Address(type=Address.TCP6, host=addr, port=port) + + +class DjangoHttpMethodContext(HttpMethodContext): + HttpTransportContext = DjangoHttpTransportContext + + +class DjangoServer(HttpBase): + """Server talking in Django request/response objects.""" + + def __init__(self, app, chunked=False, cache_wsdl=True): + super(DjangoServer, self).__init__(app, chunked=chunked) + self._wsdl = None + self._cache_wsdl = cache_wsdl + + def handle_rpc(self, request, *args, **kwargs): + """Handle rpc request. + + :params request: Django HttpRequest instance. + :returns: HttpResponse instance. + + """ + contexts = self.get_contexts(request) + p_ctx, others = contexts[0], contexts[1:] + + # TODO: Rate limiting + p_ctx.active = True + + if p_ctx.in_error: + return self.handle_error(p_ctx, others, p_ctx.in_error) + + 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) + + self.get_out_object(p_ctx) + if p_ctx.out_error: + return self.handle_error(p_ctx, others, p_ctx.out_error) + + try: + self.get_out_string(p_ctx) + + 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) + + 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) + + if p_ctx.descriptor and p_ctx.descriptor.mtom: + raise NotImplementedError + + if self.chunked: + response = StreamingHttpResponse(p_ctx.out_string) + else: + 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') + + if self.doc.wsdl11 is None: + raise Http404('WSDL is not available') + + if self._wsdl is None: + # Interface document building is not thread safe so we don't use + # server interface document shared between threads. Instead we + # create and build interface documents in current thread. This + # section can be safely repeated in another concurrent thread. + doc = AllYourInterfaceDocuments(self.app.interface) + doc.wsdl11.build_interface_document(request.build_absolute_uri()) + wsdl = doc.wsdl11.get_interface_document() + + if self._cache_wsdl: + self._wsdl = wsdl + else: + wsdl = self._wsdl + + ctx.transport.wsdl = wsdl + + response = HttpResponse(ctx.transport.wsdl) + return self.response(response, ctx, ()) + + def handle_error(self, p_ctx, others, error): + """Serialize errors to an iterable of strings and return them. + + :param p_ctx: Primary (non-aux) context. + :param others: List if auxiliary contexts (can be empty). + :param error: One of ctx.{in,out}_error. + """ + + if p_ctx.transport.resp_code is None: + 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)) + return self.response(resp, p_ctx, others, error) + + def get_contexts(self, request): + """Generate contexts for rpc request. + + :param request: Django HttpRequest instance. + :returns: generated contexts + """ + + initial_ctx = DjangoHttpMethodContext(self, request, + self.app.out_protocol.mime_type) + + initial_ctx.in_string = [request.body] + return self.generate_contexts(initial_ctx) + + def response(self, response, p_ctx, others, error=None): + """Populate response with transport headers and finalize it. + + :param response: Django HttpResponse. + :param p_ctx: Primary (non-aux) context. + :param others: List if auxiliary contexts (can be empty). + :param error: One of ctx.{in,out}_error. + :returns: Django HttpResponse + + """ + for h, v in p_ctx.transport.resp_headers.items(): + if v is not None: + response[h] = v + + if p_ctx.transport.resp_code: + response.status_code = int(p_ctx.transport.resp_code[:3]) + + try: + process_contexts(self, others, p_ctx, error=error) + except Exception as e: + # Report but ignore any exceptions from auxiliary methods. + logger.exception(e) + + p_ctx.close() + + return response + + +class DjangoView(object): + """Represent spyne service as Django class based view.""" + + application = None + server = None + services = () + 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'] + + def __init__(self, server, **kwargs): + self.server = server + + for key, value in kwargs.items(): + setattr(self, key, value) + + @classmethod + def as_view(cls, **initkwargs): + """Register application, server and create new view. + + :returns: callable view function + """ + + # 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__)) + 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)) + + def get(key): + value = initkwargs.get(key) + 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'), + ) + server = get('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'): + self.head = self.get + self.request = request + self.args = args + self.kwargs = kwargs + return self.dispatch(request, *args, **kwargs) + + # take name and docstring from class + update_wrapper(view, cls, updated=()) + + # and possible attributes set by decorators + # like csrf_exempt from dispatch + update_wrapper(view, cls.dispatch, assigned=()) + return view + + @csrf_exempt + def dispatch(self, request, *args, **kwargs): + # Try to dispatch to the right method; if a method doesn't exist, + # 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) + else: + handler = self.http_method_not_allowed + return handler(request, *args, **kwargs) + + def get(self, request, *args, **kwargs): + return self.server.handle_wsdl(request, *args, **kwargs) + + 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}) + 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' + return response + + def _allowed_methods(self): + return [m.upper() for m in self.http_method_names if hasattr(self, m)] diff --git a/pym/calculate/contrib/spyne/server/django.pyc b/pym/calculate/contrib/spyne/server/django.pyc new file mode 100644 index 0000000000000000000000000000000000000000..98193e2d604cd54936fc6a9a0a87917b873c6f3d GIT binary patch literal 14731 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/server/http.py b/pym/calculate/contrib/spyne/server/http.py new file mode 100644 index 0000000..6c621b2 --- /dev/null +++ b/pym/calculate/contrib/spyne/server/http.py @@ -0,0 +1,326 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from collections import defaultdict + +from email import utils +from email.utils import encode_rfc2231 +from email.message import tspecials + +from spyne import TransportContext, MethodDescriptor, MethodContext, Redirect +from spyne.server import ServerBase +from spyne.protocol.http import HttpPattern +from spyne.const.http import gen_body_redirect, HTTP_301, HTTP_302, HTTP_303, \ + HTTP_307 + + +class HttpRedirect(Redirect): + def __init__(self, ctx, location, orig_exc=None, code=HTTP_302): + super(HttpRedirect, self) \ + .__init__(ctx, location, orig_exc=orig_exc) + + self.ctx = ctx + self.location = location + self.orig_exc = orig_exc + self.code = code + + def do_redirect(self): + if not isinstance(self.ctx.transport, HttpTransportContext): + if self.orig_exc is not None: + raise self.orig_exc + raise TypeError(self.ctx.transport) + + self.ctx.transport.respond(self.code, location=self.location) + +# +# Plagiarized HttpTransport.add_header() and _formatparam() function from +# Python 2.7 stdlib. +# +# Copyright (C) 2001-2007 Python Software Foundation +# Author: Barry Warsaw +# Contact: email-sig@python.org +# +def _formatparam(param, value=None, quote=True): + """Convenience function to format and return a key=value pair. + + This will quote the value if needed or if quote is true. If value is a + three tuple (charset, language, value), it will be encoded according + to RFC2231 rules. If it contains non-ascii characters it will likewise + be encoded according to RFC2231 rules, using the utf-8 charset and + a null language. + """ + if value is None or len(value) == 0: + return param + + # A tuple is used for RFC 2231 encoded parameter values where items + # are (charset, language, value). charset is a string, not a Charset + # instance. RFC 2231 encoded values are never quoted, per RFC. + if isinstance(value, tuple): + # Encode as per RFC 2231 + param += '*' + value = encode_rfc2231(value[2], value[0], value[1]) + return '%s=%s' % (param, value) + + try: + value.encode('ascii') + + except UnicodeEncodeError: + 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) + + +class HttpTransportContext(TransportContext): + """The abstract base class that is used in the transport attribute of the + :class:`HttpMethodContext` class and its subclasses.""" + + def __init__(self, parent, transport, request, content_type): + super(HttpTransportContext, self).__init__(parent, transport, 'http') + + self.req = request + """HTTP Request. This is transport-specific""" + + self.resp_headers = {} + """HTTP Response headers.""" + + self.mime_type = content_type + + self.resp_code = None + """HTTP Response code.""" + + self.wsdl = None + """The WSDL document that is being returned. Only relevant when handling + WSDL requests.""" + + self.wsdl_error = None + """The error when handling WSDL requests.""" + + def get_mime_type(self): + return self.resp_headers.get('Content-Type', None) + + def set_mime_type(self, 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 + self.parent.out_string = [gen_body_redirect(resp_code, l)] + self.mime_type = 'text/html' + + else: + # So that deserialization is skipped. + self.parent.out_string = [] + + def get_path(self): + raise NotImplementedError() + + def get_request_method(self): + raise NotImplementedError() + + def get_request_content_type(self): + raise NotImplementedError() + + def get_path_and_qs(self): + raise NotImplementedError() + + def get_cookie(self, key): + raise NotImplementedError() + + def get_peer(self): + raise NotImplementedError() + + @staticmethod + def gen_header(_value, **kwargs): + parts = [] + + for k, v in kwargs.items(): + if v is None: + parts.append(k.replace('_', '-')) + + else: + parts.append(_formatparam(k.replace('_', '-'), v)) + + if _value is not None: + parts.insert(0, _value) + + return '; '.join(parts) + + def add_header(self, _name, _value, **kwargs): + """Extended header setting. + + name is the header field to add. keyword arguments can be used to set + additional parameters for the header field, with underscores converted + to dashes. Normally the parameter will be added as key="value" unless + value is None, in which case only the key will be added. If a + parameter value contains non-ASCII characters it can be specified as a + three-tuple of (charset, language, value), in which case it will be + encoded according to RFC2231 rules. Otherwise it will be encoded using + the utf-8 charset and a language of ''. + + Examples: + + msg.add_header('content-disposition', 'attachment', filename='bud.gif') + msg.add_header('content-disposition', 'attachment', + filename=('utf-8', '', Fußballer.ppt')) + msg.add_header('content-disposition', 'attachment', + filename='Fußballer.ppt')) + """ + + self.resp_headers[_name] = self.gen_header(_value, **kwargs) + + mime_type = property( + lambda self: self.get_mime_type(), + lambda self, what: self.set_mime_type(what), + ) + """Provides an easy way to set outgoing mime type. Synonym for + `content_type`""" + + content_type = mime_type + """Provides an easy way to set outgoing mime type. Synonym for + `mime_type`""" + + +class HttpMethodContext(MethodContext): + """The Http-Specific method context. Http-Specific information is stored in + the transport attribute using the :class:`HttpTransportContext` class. + """ + + # because ctor signatures differ between TransportContext and + # HttpTransportContext, we needed a new variable + TransportContext = None + HttpTransportContext = HttpTransportContext + + 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) + """Holds the HTTP-specific information""" + + def set_out_protocol(self, what): + self._out_protocol = what + if self._out_protocol.app is None: + self._out_protocol.set_app(self.app) + if isinstance(self.transport, HttpTransportContext): + self.transport.set_mime_type(what.mime_type) + + out_protocol = property(MethodContext.get_out_protocol, set_out_protocol) + """Assigning an out protocol overrides the mime type of the transport.""" + + +class HttpBase(ServerBase): + transport = 'http://schemas.xmlsoap.org/soap/http' + + def __init__(self, app, chunked=False, + max_content_length=2 * 1024 * 1024, + block_length=8 * 1024): + super(HttpBase, self).__init__(app) + + self.chunked = chunked + self.max_content_length = max_content_length + self.block_length = block_length + + self._http_patterns = set() + + for k, v in self.app.interface.service_method_map.items(): + # p_ stands for primary + p_method_descriptor = v[0] + for patt in p_method_descriptor.patterns: + if isinstance(patt, HttpPattern): + self._http_patterns.add(patt) + + # 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) ))) + + 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. + + :param ctx: A MethodContext instance + :param method: The verb in the HTTP Request (GET, POST, etc.) + :param host: The contents of the ``Host:`` header + :param path: Path but not the arguments. (i.e. stuff before '?', if it's + there) + """ + + if not path.startswith('/'): + path = '/{}'.format(path) + + params = defaultdict(list) + for patt in self._http_patterns: + assert isinstance(patt, HttpPattern) + + if patt.verb is not None: + match = patt.verb_re.match(method) + if match is None: + continue + if not (match.span() == (0, len(method))): + continue + + for k,v in match.groupdict().items(): + params[k].append(v) + + if patt.host is not None: + match = patt.host_re.match(host) + if match is None: + continue + if not (match.span() == (0, len(host))): + continue + + for k, v in match.groupdict().items(): + params[k].append(v) + + if patt.address is None: + if path.split('/')[-1] != patt.endpoint.name: + continue + + else: + match = patt.address_re.match(path) + if match is None: + continue + + if not (match.span() == (0, len(path))): + continue + + for k,v in match.groupdict().items(): + params[k].append(v) + + d = patt.endpoint + assert isinstance(d, MethodDescriptor) + ctx.method_request_string = d.name + + break + + return params + + @property + def has_patterns(self): + return len(self._http_patterns) > 0 diff --git a/pym/calculate/contrib/spyne/server/http.pyc b/pym/calculate/contrib/spyne/server/http.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dcfda64dbd0c62e65bb00d26963eb86410c3e74d GIT binary patch literal 12030 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/server/msgpack.py b/pym/calculate/contrib/spyne/server/msgpack.py new file mode 100644 index 0000000..1c0fd4d --- /dev/null +++ b/pym/calculate/contrib/spyne/server/msgpack.py @@ -0,0 +1,217 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from __future__ import absolute_import + +import logging +logger = logging.getLogger(__name__) + +import msgpack + +from mmap import mmap +from collections import OrderedDict + +from spyne import MethodContext, TransportContext, Address +from spyne.auxproc import process_contexts +from spyne.error import ValidationError, InternalError +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 + + +MSGPACK_SHELL_OVERHEAD = 10 + + +def _process_v1_msg(prot, msg): + header = None + body = msg[1] + if not isinstance(body, (binary_type, mmap, memoryview)): + raise ValidationError(body, "Body must be a bytestream.") + + if len(msg) > 2: + header = msg[2] + if not isinstance(header, dict): + raise ValidationError(header, "Header must be a dict.") + for k, v in header.items(): + header[k] = msgpack.unpackb(v) + + ctx = MessagePackMethodContext(prot, MessagePackMethodContext.SERVER) + ctx.in_string = [body] + ctx.transport.in_header = header + + return ctx + + +class MessagePackTransportContext(TransportContext): + def __init__(self, parent, transport): + super(MessagePackTransportContext, self).__init__(parent, transport) + + self.in_header = None + self.protocol = None + self.inreq_queue = OrderedDict() + self.request_len = None + + def get_peer(self): + if self.protocol is not None: + peer = self.protocol.transport.getPeer() + return Address.from_twisted_address(peer) + + +class MessagePackOobMethodContext(object): + __slots__ = 'd' + + def __init__(self): + if Deferred is not None: + self.d = Deferred() + else: + self.d = None + + def close(self): + if self.d is not None and not self.d.called: + self.d.cancel() + + +class MessagePackMethodContext(MethodContext): + TransportContext = MessagePackTransportContext + + def __init__(self, transport, way): + self.oob_ctx = None + + super(MessagePackMethodContext, self).__init__(transport, way) + + def close(self): + super(MessagePackMethodContext, self).close() + if self.transport is not None: + self.transport.protocol = None + self.transport = None + + if self.oob_ctx is not None: + self.oob_ctx.close() + + +class MessagePackTransportBase(ServerBase): + # These are all placeholders that need to be overridden in subclasses + OUT_RESPONSE_NO_ERROR = None + OUT_RESPONSE_CLIENT_ERROR = None + OUT_RESPONSE_SERVER_ERROR = None + + IN_REQUEST = None + + def __init__(self, app): + super(MessagePackTransportBase, self).__init__(app) + + self._version_map = { + self.IN_REQUEST: _process_v1_msg + } + + def produce_contexts(self, msg): + """Produce contexts based on incoming message. + + :param msg: Parsed request in this format: `[IN_REQUEST, body, header]` + """ + + if not isinstance(msg, (list, tuple)): + logger.debug("Incoming request: %r", msg) + raise ValidationError(msg, "Request must be a list") + + 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") + + 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") + + processor = self._version_map.get(msg[0], None) + if processor is None: + logger.debug("Invalid incoming request: %r", msg) + raise ValidationError(msg[0], "Unknown request type %r") + + msglen = len(msg[1]) + # shellen = len(msgpack.packb(msg)) + # logger.debug("Shell size: %d, message size: %d, diff: %d", + # shellen, msglen, shellen - msglen) + # some approx. msgpack overhead based on observations of what's above. + msglen += MSGPACK_SHELL_OVERHEAD + + initial_ctx = processor(self, msg) + contexts = self.generate_contexts(initial_ctx) + + p_ctx, others = contexts[0], contexts[1:] + p_ctx.transport.request_len = msglen + + return p_ctx, others + + def process_contexts(self, contexts): + p_ctx, others = contexts[0], contexts[1:] + + if p_ctx.in_error: + return self.handle_error(p_ctx, others, p_ctx.in_error) + + 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) + + self.get_out_object(p_ctx) + if p_ctx.out_error: + return self.handle_error(p_ctx, others, p_ctx.out_error) + + try: + self.get_out_string(p_ctx) + + except Exception as e: + logger.exception(e) + contexts.out_error = InternalError("Serialization Error.") + return self.handle_error(contexts, others, contexts.out_error) + + def handle_error(self, p_ctx, others, error): + self.get_out_string(p_ctx) + + try: + process_contexts(self, others, p_ctx, error=error) + except Exception as e: + # Report but ignore any exceptions from auxiliary methods. + logger.exception(e) + + 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)]), + + +class MessagePackServerBase(MessagePackTransportBase): + """Contains the transport protocol logic but not the transport itself. + + Subclasses should implement logic to move bitstreams in and out of this + class.""" + + OUT_RESPONSE_NO_ERROR = 0 + OUT_RESPONSE_CLIENT_ERROR = 1 + OUT_RESPONSE_SERVER_ERROR = 2 + + IN_REQUEST = 1 diff --git a/pym/calculate/contrib/spyne/server/msgpack.pyc b/pym/calculate/contrib/spyne/server/msgpack.pyc new file mode 100644 index 0000000000000000000000000000000000000000..954032828f4855ae2109b90a7551dcd550370842 GIT binary patch literal 8057 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 0: + ctx.close() + + return retval diff --git a/pym/calculate/contrib/spyne/server/null.pyc b/pym/calculate/contrib/spyne/server/null.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4f2c41b5910136be3887e4d48d5d263875d01903 GIT binary patch literal 7647 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/server/pyramid.py b/pym/calculate/contrib/spyne/server/pyramid.py new file mode 100644 index 0000000..7319da2 --- /dev/null +++ b/pym/calculate/contrib/spyne/server/pyramid.py @@ -0,0 +1,58 @@ +# encoding: utf-8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.server.pyramid`` module contains a Pyramid-compatible Http +transport. It's a thin wrapper around +:class:`spyne.server.wsgi.WsgiApplication`. +""" + +from __future__ import absolute_import + +from pyramid.response import Response +from spyne.server.wsgi import WsgiApplication + + +class PyramidApplication(WsgiApplication): + """Pyramid View Wrapper. Use this for regular RPC""" + + def __call__(self, request): + retval = Response() + + def start_response(status, headers): + 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) + retval.body = b"".join(response) + + return retval + + def set_response(self, retval, response): + retval.body = b"".join(response) + + +class StreamingPyramidApplication(WsgiApplication): + """You should use this when you're generating HUGE data as response.""" + + def set_response(self, retval, response): + retval.app_iter = response diff --git a/pym/calculate/contrib/spyne/server/pyramid.pyc b/pym/calculate/contrib/spyne/server/pyramid.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d8a9f329086239559a68370b40096e9acdc7be6 GIT binary patch literal 2308 zcmc&#-EQMV6h5}ow24?+wrGFgf&mF_Zt7?YDq^)lS(cyWrmS3+Y9o*{wI_*-V|!=D zEs@%*B7Po$hv7|l1nzhN&Np@_3tVv1C6Z6h%sD>4-#HF`zt;cl*IyMCSp;hb*@BG7FK435mG#E zWIIW@sHDw~So+A?s&BO{OjT+diqGsFXxe#Jh*K@AN@*c=Sr=*lUXn{=?mh4B)XcK* zkjaCp%Cm&6mc=COXB-?2JSKLNi99l8URxDs3%F?n8!U(v`z?&RRQ;PRd!4n~xc}lJ z;am5Eiw{R!4#AA#@^clL`e*{zavY!)U^)~X3<6d%A(Pgk_%c(c;;_jx6iaa`x?xss{UW&mZ| z#T!l@p^5ISl{Abrh#FmI_eAD(+gwPrvV1dOj!eX4SQ|aev!lItht<-~%VIZtZ)h^B zb}E^CBWKDC9k_RP!@KWFw%*1K;w0~u zzv*pz+&Io1@kFRXgzj1>#Bn0?JdRz)syN9sXM`FZms|%hM`gNfs)mzM`PAuZ^{iIL zMsV&dt$e#w9k`=wc;RZ2j<(qLTd@BU6Y_fg=K7}B^RD{|T8albJ{+;e4Q6;Y7*_zM z2js+VW)23>*^e-Da2je&`lQ?$OiEgs|GG@nJRX0$rH~2AtSl8?Ny)FAXvj>)kWRVrK|FX{z zull!r#%l~kFb|kKEo))sWu2#@UhS^axhll6tnX+gW~xw{cXBZkkDh$`u}GzrLK@y} z&DstBi4QcGkpWn^@7aMv@BZb==5IpG6RQ6gP`Ea}kMvt0U<{*MAh$tY19^e1MqBsz zF^B`L-XHW30^(>PIjwE28KD?`vY6D>wpw+;Z6W&#OP>3Zs(>H`cmWua!yt8_U@&!H=m0aZ3xx|) z4~8Da9`yYdO(bT1eeVp6navA@@(HET^IU06MHuE~uEUTM+n#+ijLI}DP={G{L>c7~06S#)C!OXq z`hYS6%W#iz4^=gj3EJApuUfxKCaBjP-A28hVbrGt&8pn4#8)fvk=Aw32&K>dYMEoK cEU^*lN234HX_MZ(o>u9sz?*M{wp#n_3;O$-LjV8( literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/server/twisted/_base.py b/pym/calculate/contrib/spyne/server/twisted/_base.py new file mode 100644 index 0000000..98a386c --- /dev/null +++ b/pym/calculate/contrib/spyne/server/twisted/_base.py @@ -0,0 +1,79 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from twisted.internet.defer import Deferred +from twisted.internet.interfaces import IPullProducer +from twisted.web.iweb import UNKNOWN_LENGTH + +from zope.interface import implementer + + +@implementer(IPullProducer) +class Producer(object): + deferred = None + + def __init__(self, body, consumer): + """:param body: an iterable of strings""" + + # check to see if we can determine the length + try: + len(body) # iterator? + self.length = sum([len(fragment) for fragment in body]) + self.body = iter(body) + + except TypeError: + self.length = UNKNOWN_LENGTH + self.body = body + + self.deferred = Deferred() + + self.consumer = consumer + + def resumeProducing(self): + try: + chunk = next(self.body) + + except StopIteration as e: + self.consumer.unregisterProducer() + if self.deferred is not None: + self.deferred.callback(self.consumer) + self.deferred = None + return + + self.consumer.write(chunk) + + def pauseProducing(self): + pass + + def stopProducing(self): + if self.deferred is not None: + 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} + +def _address_from_twisted_address(peer): + 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/pym/calculate/contrib/spyne/server/twisted/_base.pyc b/pym/calculate/contrib/spyne/server/twisted/_base.pyc new file mode 100644 index 0000000000000000000000000000000000000000..88a49df7f1777e84daf90d95793dfc54d0a2574a GIT binary patch literal 2751 zcmcgu>uwuW5T3K^OPs`w)1U?f2%~bbK(%QoL8<_?q!CmFH`=6XYYDb%@3CWNZ|pgy zHEMsA$AUNE5%|Xgz&CT8v=aT>Sl-#0@wv@>-^{W9PjmI}zy5qQqUEQ8_YFMe4~Q6F zMF~-=XrM^3?NQ=U>eIk?wogfg(kczA&aO~WqqI(gIw@Tz?bCBbah3E6jiJ=&ccSM+ z58)j&WQRH>tCX(MV2#wYLVAs6>lClhE^AGS8&11G@v74{C|;x8L5t#bUTv^R`XcE~ z-Uw5|EsC3T*tviJrvKv8QPAuP#4SD6WvOH5X~J{+V4frgWggE*x^!-ycdvh^fA@Yr z{9(WU-O=~XzXty_EfSsT%<57WJe_%#KHlnEJZ1+%<7^1I!ns1~_^1_5C@WRYBr7$F zeNpNZ9CoUhHu51Vc-Yv(V=#^u`(%lpDvnZFMH4Y@{dAF@`SOb-`e%=R+2$cni9(O8 zznsBlh3;pUsbZ^ivP$KQlv1{~9Ef$@kWA47TW5sWUZJO+C_qXfryif?GQ{;FDx7>E-PCCC`R%{;}9Vo&U`5Oq1O&F{W93;X#fYzIvvX@MU zyVrWf!XD?@PWQ{6!9lJR(dZrB%UfsP?EHI+0CllxI8D0LW%btBa zHCD&Ha2Ofg#ZpYMFq~#n8;0*eHy0tO;;U8FQCnV9HB{4E_eM+-PRAL(3mA(nL6K-C z5I<8u>n_mp1g)6VGmjK7nfWxUFg{{{MnoqKDjzXSvntK%q6itdUKzzIWm3zB50>)* ztK$&{916Sp9ZsDjGSg42B+_z$9NN6N&EVQ;p1IU=RP(IV6Ar&TErEdRLl)@gnRXyW zNisxA!8oGFB{JOMumfIKe52!eb^d4Qy6w=8ii!nEDx94l3mXrVZ6p8){3f ztEz*F&&SUmk7K^Qlr>l+36!ADD+q2;MKm`rV)z;!!}UT+=ygglIrA5AGxBnBCQD~& z&ZI-2ve7W`RgNZ1nPrf?VqXe=Z&`5d$eif7JvVKeqtf%DT}byt9;FtA2Ei8Qp^E_5 zvJ?g|yY`=qbip(_|AaB)_^@Y~-(UyVD*@|vQtz`*kQL4kxa{mg$6qiE+Q-X5g zF^PgVS-i#K9f%jui}qR@O~5348;{`=*1Ve6*laW#zPqP5?Kk5XBsbD@kM<6vEb-nI z$Guz5f%oniS$LL^r3(cY4M>5)1VLQO0Og;1d}XnTrh|J0N)3I;KNQ^ivWG?Q7UeiM zR+J(yZHE^RxFbq~504%m?1w+zJdo2&v<*Js-5&yaNJEu-%VnBV2gt7l@AF``fcLfF zGL+zB7N4-6?@D9Q+()U#RTx{2=v9HgK;ZTBTdMFYS9jm=feecls`{B?Ed)0Wy+ I+g_vcAF{1h)c^nh literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/server/twisted/http.py b/pym/calculate/contrib/spyne/server/twisted/http.py new file mode 100644 index 0000000..0c76176 --- /dev/null +++ b/pym/calculate/contrib/spyne/server/twisted/http.py @@ -0,0 +1,790 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The ``spyne.server.twisted`` module contains a server transport compatible +with the Twisted event loop. It uses the TwistedWebResource object as transport. + +Also see the twisted examples in the examples directory of the source +distribution. + +If you want to have a hard-coded URL in the wsdl document, this is how to do +it: :: + + resource = TwistedWebResource(...) + resource.http_transport.doc.wsdl11.build_interface_document("http://example.com") + +This is not strictly necessary. If you don't do this, Spyne will get the URL +from the first request, build the wsdl on-the-fly and cache it as a string in +memory for later requests. However, if you want to make sure you only have this +url on the WSDL, this is how to do it. Note that if your client takes the +information in wsdl seriously, all requests will go to the designated url above +which can make testing a bit difficult. Use in moderation. +""" + +from __future__ import absolute_import + +import logging +logger = logging.getLogger(__name__) + +import re +import cgi +import gzip +import shutil +import threading + +from os import fstat +from mmap import mmap +from inspect import isclass +from collections import namedtuple +from tempfile import TemporaryFile + +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.threads import deferToThread + +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 +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.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.twisted import log_and_let_go + +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): + """ + Begin sending the contents of this L{File} (or a subset of the + contents, based on the 'range' header) to the given request. + """ + file.restat(False) + + if file.type is None: + file.type, file.encoding = getTypeAndEncoding(file.basename(), + file.contentTypes, + file.contentEncodings, + file.defaultType) + + if not file.exists(): + return file.childNotFound.render(request) + + if file.isdir(): + return file.redirect(request) + + request.setHeader('accept-ranges', 'bytes') + + try: + fileForReading = file.openForReading() + except IOError as e: + import errno + + if e[0] == errno.EACCES: + return ForbiddenResource().render(request) + else: + raise + + #if request.setLastModified(file.getmtime()) is CACHED: + # return '' + + producer = file.makeProducer(request, fileForReading) + + if request.method == 'HEAD': + return '' + + producer.start() + # and make sure the connection doesn't get closed + return NOT_DONE_YET + + +def _set_response_headers(request, headers): + retval = [] + + for k, v in headers.items(): + if isinstance(v, (list, tuple)): + request.responseHeaders.setRawHeaders(k, v) + else: + request.responseHeaders.setRawHeaders(k, [v]) + + return retval + + +def _reconstruct_url(request): + # HTTP "Hosts" header only supports ascii + + server_name = request.getHeader(b"x-forwarded-host") + server_port = request.getHeader(b"x-forwarded-port") + if server_port is not None: + try: + server_port = int(server_port) + except Exception as e: + logger.debug("Ignoring exception: %r for value %r", e, server_port) + server_port = None + + is_secure = request.getHeader(b"x-forwarded-proto") + if is_secure is not None: + is_secure = is_secure == 'https' + + if server_name is None: + 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) + + if is_secure: + url_scheme = 'https' + else: + url_scheme = 'http' + + uri = _decode_path(request.uri) + return ''.join([url_scheme, "://", server_name, uri]) + + +class _Transformer(object): + def __init__(self, req): + self.req = req + + def get(self, key, default): + key = key.lower() + if key.startswith((b'http_', b'http-')): + key = key[5:] + + retval = self.req.getHeader(key) + if retval is None: + retval = default + return retval + + +class TwistedHttpTransportContext(HttpTransportContext): + def set_mime_type(self, what): + if isinstance(what, text_type): + what = what.encode('ascii', errors='replace') + super(TwistedHttpTransportContext, self).set_mime_type(what) + self.req.setHeader('Content-Type', what) + + def get_cookie(self, key): + return self.req.getCookie(key) + + def get_path(self): + return self.req.URLPath().path + + def get_path_and_qs(self): + return self.req.uri + + def get_request_method(self): + return self.req.method + + def get_request_content_type(self): + return self.req.getHeader("Content-Type") + + def get_peer(self): + peer = Address.from_twisted_address(self.req.transport.getPeer()) + addr = address_parser.get_ip(_Transformer(self.req)) + + if addr is None: + return peer + + if address_parser.is_valid_ipv4(addr): + return Address(type=Address.TCP4, host=addr, port=0) + + if address_parser.is_valid_ipv6(addr): + return Address(type=Address.TCP6, host=addr, port=0) + + +class TwistedHttpMethodContext(HttpMethodContext): + HttpTransportContext = TwistedHttpTransportContext + + +def _decode_path(fragment): + if six.PY2: + return unquote(fragment).decode('utf8') + + return unquote_to_bytes(fragment).decode('utf8') + + +class TwistedHttpTransport(HttpBase): + 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() + + deferLater(reactor, 0, _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 super(TwistedHttpTransport, self).pusher_init( + 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 + ctx.out_stream.write(data) + + ctx.out_document = _ISwearImAGenerator() + + def pusher_try_close(self, ctx, pusher, retval): + # the whole point of this function is to call ctx.out_stream.finish() + # 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) + + if not pusher.interim: + ctx.out_stream.finish() + + return subretval + + def _cb_push_close(r): + def _eb_inner(f): + if not pusher.interim: + ctx.out_stream.finish() + + return f + + if not isinstance(r, Deferred): + 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) \ + .addErrback(log_and_let_go, logger) + + 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) + + if not pusher.interim: + retval = ctx.out_stream.finish() + + return retval + + def decompose_incoming_envelope(self, prot, ctx, message): + """This function is only called by the HttpRpc protocol to have the + twisted web's Request object is parsed into ``ctx.in_body_doc`` and + ``ctx.in_header_doc``. + """ + + request = ctx.in_document + assert isinstance(request, Request) + + ctx.in_header_doc = dict(request.requestHeaders.getAllRawHeaders()) + ctx.in_body_doc = request.args + + for fi in ctx.transport.file_info: + assert isinstance(fi, _FileInfo) + if fi.file_name is None: + continue + + l = ctx.in_body_doc.get(fi.field_name, None) + 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) + ) + + # this is a huge hack because twisted seems to take the slashes in urls + # too seriously. + 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')) + + if ctx.method_request_string is None: # no pattern match + ctx.method_request_string = u'{%s}%s' % ( + self.app.interface.get_tns(), + _decode_path(request.path.rsplit(b'/', 1)[-1])) + + logger.debug(u"%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, []) + val.extend(v) + ctx.in_body_doc[k] = val + + r = {} + for k, v in ctx.in_body_doc.items(): + l = [] + for v2 in v: + if isinstance(v2, string_types): + l.append(unquote(v2)) + else: + l.append(v2) + r[k] = l + ctx.in_body_doc = r + + # This is consistent with what server.wsgi does. + if request.method in ('POST', 'PUT', 'PATCH'): + for k, v in ctx.in_body_doc.items(): + if v == ['']: + ctx.in_body_doc[k] = [None] + + +FIELD_NAME_RE = re.compile(r'name="([^"]+)"') +FILE_NAME_RE = re.compile(r'filename="([^"]+)"') +_FileInfo = namedtuple("_FileInfo", "field_name file_name file_type data") + + +def _get_file_info(ctx): + """We need this hack because twisted doesn't offer a way to get file name + from Content-Disposition header. + """ + + retval = [] + + request = ctx.transport.req + headers = request.getAllHeaders() + 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': + request.content.seek(0) + content = TemporaryFile() + with gzip.GzipFile(fileobj=request.content) as ifstr: + shutil.copyfileobj(ifstr, content) + content.seek(0) + + img = cgi.FieldStorage( + fp=content, + headers=ctx.in_header_doc, + environ={ + 'REQUEST_METHOD': request.method, + 'CONTENT_TYPE': content_type, + } + ) + + try: + keys = img.keys() + except TypeError: + return retval + + for k in keys: + fields = img[k] + + if isinstance(fields, cgi.FieldStorage): + fields = (fields,) + + for field in fields: + file_type = field.type + 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)])) + + return retval + + +def _has_fd(istr): + if not hasattr(istr, 'fileno'): + return False + try: + istr.fileno() + except IOError: + return False + else: + return True + + +def get_twisted_child_with_default(res, path, request): + # this hack is necessary because twisted takes the slash character in + # 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) + else: + if not res.prepath.startswith('/'): + request.realprepath = b'/' + res.prepath + else: + request.realprepath = res.prepath + + if path in res.children: + retval = res.children[path] + else: + retval = res.getChild(path, request) + + if isinstance(retval, NoResource): + retval = res + else: + request.realpostpath = request.path[ + len(path) + (0 if path.startswith(b'/') else 1):] + + return retval + + +class TwistedWebResource(Resource): + """A server transport that exposes the application as a twisted web + Resource. + """ + + 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._wsdl = None + self.prepath = prepath + + 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')): + return self.__handle_wsdl_request(request) + return self.handle_rpc(request) + + def handle_rpc_error(self, p_ctx, others, error, request): + logger.error(error) + resp_code = p_ctx.transport.resp_code + # If user code set its own response code, don't touch it. + if resp_code is None: + resp_code = p_ctx.out_protocol.fault_to_http_response_code(error) + + request.setResponseCode(int(resp_code[:3])) + _set_response_headers(request, p_ctx.transport.resp_headers) + + # In case user code set its own out_* attributes before failing. + p_ctx.out_document = None + p_ctx.out_string = None + + p_ctx.out_object = error + self.http_transport.get_out_string(p_ctx) + + retval = b''.join(p_ctx.out_string) + + p_ctx.close() + + process_contexts(self.http_transport, others, p_ctx, error=error) + + return retval + + def handle_rpc(self, request): + 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 = [''] + else: + initial_ctx.in_string = [mmap(f.fileno(), 0)] + else: + request.content.seek(0) + initial_ctx.in_string = [request.content.read()] + + initial_ctx.transport.file_info = _get_file_info(initial_ctx) + + contexts = self.http_transport.generate_contexts(initial_ctx) + p_ctx, others = contexts[0], contexts[1:] + + p_ctx.active = True + p_ctx.out_stream = request + # TODO: Rate limiting + p_ctx.active = True + + if p_ctx.in_error: + return self.handle_rpc_error(p_ctx, others, p_ctx.in_error, request) + + else: + 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) + + 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) + + ret = p_ctx.out_object[0] + retval = NOT_DONE_YET + if isinstance(ret, Deferred): + ret.addCallback(_cb_deferred, request, p_ctx, others, resource=self) + ret.addErrback(_eb_deferred, request, p_ctx, others, resource=self) + ret.addErrback(log_and_let_go, logger) + + elif isinstance(ret, PushBase): + self.http_transport.init_root_push(ret, p_ctx, others) + + else: + try: + 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) + except Exception as e: + logger_server.exception(e) + + return retval + + def __handle_wsdl_request(self, request): + # disabled for performance reasons. + # logger.debug("WSDL request headers: %r", + # list(request.requestHeaders.getAllRawHeaders())) + + ctx = TwistedHttpMethodContext(self.http_transport, request, + "text/xml; charset=utf-8") + url = _reconstruct_url(request) + + if self.http_transport.doc.wsdl11 is None: + return HTTP_404 + + if self._wsdl is None: + self._wsdl = self.http_transport.doc.wsdl11.get_interface_document() + + ctx.transport.wsdl = self._wsdl + _set_response_headers(request, ctx.transport.resp_headers) + + 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() + + assert ctx.transport.wsdl is not None + + 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) + raise + + finally: + ctx.close() + + +def _cb_request_finished(retval, request, p_ctx): + request.finish() + p_ctx.close() + + +def _eb_request_finished(retval, request, p_ctx): + err(request) + p_ctx.close() + request.finish() + + +def _cb_deferred(ret, request, p_ctx, others, resource, cb=True): + ### set response headers + resp_code = p_ctx.transport.resp_code + + # If user code set its own response code, don't touch it. + if resp_code is None: + resp_code = HTTP_200 + request.setResponseCode(int(resp_code[:3])) + + _set_response_headers(request, p_ctx.transport.resp_headers) + + ### normalize response data + om = p_ctx.descriptor.out_message + single_class = None + if cb: + if p_ctx.descriptor.is_out_bare(): + p_ctx.out_object = [ret] + + 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() + else: + p_ctx.out_object = ret + else: + p_ctx.out_object = ret + + ### start response + retval = NOT_DONE_YET + + 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') + 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) + + 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) + + try: + request.registerProducer(producer, False) + except Exception as e: + logger_server.exception(e) + try: + _eb_deferred(Failure(), request, p_ctx, others, resource) + except Exception as e: + logger_server.exception(e) + raise + + else: + def _cb(ret): + if isinstance(ret, Deferred): + 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) + + process_contexts(resource.http_transport, others, p_ctx) + + return retval + + +def _eb_deferred(ret, request, p_ctx, others, resource): + # DRY this with what's in Application.process_request + if ret.check(Redirect): + try: + ret.value.do_redirect() + + # Now that the processing is switched to the outgoing message, + # point ctx.protocol to ctx.out_protocol + p_ctx.protocol = p_ctx.outprot_ctx + + _cb_deferred(None, request, p_ctx, others, resource, cb=False) + + 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.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') + + request.write(ret) + + else: + p_ctx.out_error = InternalError(ret.value) + logger.error(ret.getTraceback()) + + ret = resource.handle_rpc_error(p_ctx, others, p_ctx.out_error, request) + + p_ctx.fire_event('method_exception_object') + + request.write(ret) + + request.finish() diff --git a/pym/calculate/contrib/spyne/server/twisted/http.pyc b/pym/calculate/contrib/spyne/server/twisted/http.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b4d0ef3e976ca77d2d96e52ec1d44f19fa4fe3a GIT binary patch literal 25580 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 E24Q5>g8%>k literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/server/twisted/msgpack.py b/pym/calculate/contrib/spyne/server/twisted/msgpack.py new file mode 100644 index 0000000..8d548d7 --- /dev/null +++ b/pym/calculate/contrib/spyne/server/twisted/msgpack.py @@ -0,0 +1,477 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from __future__ import absolute_import + +import logging +logger = logging.getLogger(__name__) + +import io + +import msgpack + +from time import time +from hashlib import md5 +from collections import deque, OrderedDict +from itertools import chain + +from twisted.internet import reactor +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.auxproc import process_contexts +from spyne.error import InternalError +from spyne.server.twisted import log_and_let_go + + +class TwistedMessagePackProtocolFactory(Factory): + IDLE_TIMEOUT_SEC = None + + def __init__(self, tpt): + assert isinstance(tpt, ServerBase) + + self.tpt = tpt + self.event_manager = EventManager(self) + + def buildProtocol(self, address): + retval = TwistedMessagePackProtocol(self.tpt, factory=self) + + if self.IDLE_TIMEOUT_SEC is not None: + retval.IDLE_TIMEOUT_SEC = self.IDLE_TIMEOUT_SEC + + 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 + + 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) + + +def _cha(*args): + return 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): + """Twisted protocol implementation for Spyne's MessagePack transport. + + :param tpt: Spyne transport. It's an app-wide instance. + :param max_buffer_size: Max. encoded message size. + :param out_chunk_size: Split + :param factory: Twisted protocol factory + + Supported events: + * ``outresp_flushed(ctx, ctxid, data)`` + Called right after response data is flushed to the socket. + * ctx: Always None + * ctxid: Integer equal to ``id(ctx)`` + * data: Flushed bytes object + + """ + + from spyne.server.msgpack import MessagePackTransportBase + 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.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._delaying = None + self.sent_bytes = 0 + self.recv_bytes = 0 + self.idle_timer = None + self.out_chunks = deque() + self.inreq_queue = OrderedDict() + self.inactive_queue = list() + self.disconnecting = False # FIXME: should we use this to raise an + # invalid connection state exception ? + + @staticmethod + def gen_chunks(l, n): + """Yield successive n-sized chunks from l.""" + if isinstance(l, io.BufferedIOBase): + while True: + data = l.read(n) + if not data: + break + yield data + l.close() + + else: + for i in range(0, len(l), 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 + ) + + return md5(repr(retval).encode('utf8')).hexdigest() + + def connectionMade(self): + logger.debug("%08x connection made", id(self)) + self.sessid = '' + self._delaying = None + self.sent_bytes = 0 + self.recv_bytes = 0 + self.idle_timer = None + self.out_chunks = deque() + self.inreq_queue = OrderedDict() + self.inactive_queue = list() + self.active_queue = dict() + self.disconnecting = False # FIXME: should we use this to raise an + # invalid connection state exception ? + + self._reset_idle_timer() + if self.factory is not None: + self.factory.event_manager.fire_event("connection_made", self) + + def connectionLost(self, reason=connectionDone): + if reason is connectionDone: + logger.debug("%08x connection done", id(self)) + else: + logger.debug("%08x connection lost: %s", id(self), reason) + self.disconnecting = False + if self.factory is not None: + self.factory.event_manager.fire_event("connection_lost", self) + self._cancel_idle_timer() + + def _cancel_idle_timer(self): + if self.idle_timer is not None: + if not self.idle_timer.called: + # FIXME: Workaround for a bug in Twisted 18.9.0 when + # DelayedCall.debug == True + try: + self.idle_timer.cancel() + except AttributeError: + del self.idle_timer.func + del self.idle_timer.args + del self.idle_timer.kw + + self.idle_timer = None + + def dataReceived(self, data): + self._buffer.feed(data) + self.recv_bytes += len(data) + + self._reset_idle_timer() + + for msg in self._buffer: + self.process_incoming_message(msg) + + if self.disconnecting: + return + + def _reset_idle_timer(self): + if self.idle_timer is not None: + t = self.idle_timer + self.idle_timer = None + if not t.called: + 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) \ + .addErrback(self._err_idle_cancelled_unknown_error) + + def _err_idle_cancelled(self, err): + err.trap(CancelledError) + + # do nothing. + + def _err_idle_cancelled_unknown_error(self, err): + logger.error("Sessid %s error cancelling idle timer: %s", + self.sessid, err.getTraceback()) + self.idle_timer = None + + def loseConnection(self, reason=None): + self.disconnecting = True + self.idle_timer = None + logger.debug("Aborting connection because %s", reason) + self.transport.abortConnection() + + 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()) + p_ctx.transport.protocol = self + p_ctx.transport.sessid = self.sessid + + self.inactive_queue.append((p_ctx, others)) + self.process_inactive() + + @property + def num_active_contexts(self): + return len(self.inreq_queue) + + @property + def num_inactive_contexts(self): + return len(self.inactive_queue) + + def process_inactive(self): + peer = self.transport.getPeer() + addr_str = Address.from_twisted_address(peer) + + if self.max_in_queue_size == 0: + while self.num_inactive_contexts > 0: + p_ctx, others = self.inactive_queue.pop() + self.active_queue[id(p_ctx)] = p_ctx + + self.inreq_queue[id(p_ctx)] = None + self.process_contexts(p_ctx, others) + + else: + while self.num_active_contexts < self.max_in_queue_size and \ + self.num_inactive_contexts > 0: + p_ctx, others = self.inactive_queue.pop() + self.active_queue[id(p_ctx)] = p_ctx + + self.inreq_queue[id(p_ctx)] = None + 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) + self.loseConnection("Too many 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 + self.inreq_queue[ctxid] = data + + for k, v in list(self.inreq_queue.items()): + if v is None: + break + + self.out_write(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] + + self.process_inactive() + + def out_write(self, reqdata): + if self.out_chunk_size == 0: + if isinstance(reqdata, io.BufferedIOBase): + nbytes = reqdata.tell() + reqdata.seek(0) + self.transport.write(reqdata.read()) + else: + nbytes = len(reqdata) + self.transport.write(reqdata) + + self.sent_bytes += nbytes + + else: + if isinstance(reqdata, io.BufferedIOBase): + reqdata.seek(0) + + chunks = self.gen_chunks(reqdata, self.out_chunk_size) + self.out_chunks.append(chunks) + 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) + + def _write_single_chunk(self): + try: + chunk = next(chain.from_iterable(self.out_chunks)) + except StopIteration: + chunk = None + self.out_chunks.clear() + + if chunk is None: + self._delaying = None + + logger.debug("%s no more chunks...", self.sessid) + + else: + self.transport.write(chunk) + self.sent_bytes += len(chunk) + + 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)) + + else: + logger.debug("%s Disconnection detected, discarding " + "remaining chunks", self.sessid) + self.out_chunks.clear() + + def handle_error(self, p_ctx, others, exc): + self.spyne_tpt.get_out_string(p_ctx) + + if isinstance(exc, InternalError): + error = self.spyne_tpt.OUT_RESPONSE_SERVER_ERROR + else: + error = self.spyne_tpt.OUT_RESPONSE_CLIENT_ERROR + + data = p_ctx.out_document[0] + if isinstance(data, dict): + data = list(data.values()) + + out_object = (error, msgpack.packb(data),) + if p_ctx.oob_ctx is not None: + p_ctx.oob_ctx.d.callback(out_object) + return + + out_string = msgpack.packb(out_object) + p_ctx.transport.resp_length = len(out_string) + self.enqueue_outresp_data(id(p_ctx), out_string) + + try: + process_contexts(self, others, p_ctx, error=error) + + except Exception as e: + # Report but ignore any exceptions from auxiliary methods. + logger.error("Exception ignored from auxiliary method: %r", e) + 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) \ + .addErrback(log_and_let_go, logger) + + def process_contexts(self, p_ctx, others): + if p_ctx.in_error: + self.handle_error(p_ctx, others, p_ctx.in_error) + return + + self.spyne_tpt.get_in_object(p_ctx) + if p_ctx.in_error: + logger.error(p_ctx.in_error) + self.handle_error(p_ctx, others, p_ctx.in_error) + return + + self.spyne_tpt.get_out_object(p_ctx) + if p_ctx.out_error: + self.handle_error(p_ctx, others, p_ctx.out_error) + return + + ret = p_ctx.out_object + if isinstance(ret, Deferred): + self._register_callbacks(ret, p_ctx, others) + + else: + ret = p_ctx.out_object[0] + if isinstance(ret, Deferred): + self._register_callbacks(ret, p_ctx, others) + + else: + self._cb_deferred(p_ctx.out_object, p_ctx, others, nowrap=True) + + def _eb_deferred(self, fail, p_ctx, others): + assert isinstance(fail, Failure) + + if isinstance(fail.value, Fault): + p_ctx.out_error = fail.value + + else: + p_ctx.out_error = InternalError(fail.value) + if not getattr(fail, 'logged', False): + logger.error(fail.getTraceback()) + + try: + self.handle_error(p_ctx, others, p_ctx.out_error) + + except Exception as e: + logger.exception(e) + raise + + def _cb_deferred(self, ret, p_ctx, others, nowrap=False): + # this means callback is not invoked directly instead of as part of a + # deferred chain + if not nowrap: + # if there is one return value or the output is bare (which means + # there can't be anything other than 1 return value case) use the + # enclosing list. otherwise, the return value is a tuple anyway, so + # leave it be. + if p_ctx.descriptor.is_out_bare(): + p_ctx.out_object = [ret] + + else: + if len(p_ctx.descriptor.out_message._type_info) > 1: + p_ctx.out_object = ret + else: + p_ctx.out_object = [ret] + + if p_ctx.oob_ctx is not None: + assert isinstance(p_ctx.oob_ctx.d, Deferred) + + p_ctx.oob_ctx.d.callback(p_ctx.out_object) + return + + try: + self.spyne_tpt.get_out_string(p_ctx) + self.spyne_tpt.pack(p_ctx) + + 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) + + except Exception as e: + logger.exception(e) + logger.error("%r", p_ctx) + self.handle_error(p_ctx, others, InternalError(e)) + + finally: + p_ctx.close() + + process_contexts(self.spyne_tpt, others, p_ctx) diff --git a/pym/calculate/contrib/spyne/server/twisted/msgpack.pyc b/pym/calculate/contrib/spyne/server/twisted/msgpack.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f068061f2bc36c03c458e5fbb2a20740d90012e5 GIT binary patch literal 16603 zcmc&*+m9SqT0hl2w;s>UW6#(V+i}^6lXeofbK4|4B+J<2apd5Pvo%iaG@F!by3UMi zrnV~B$szywGq?;c#^-;-}O+03rW2Qc)LkyX?Vw&ToKCaKh zCf;Y76Q(|4nvW`V`5mP^+E%urCsA(QE^<(-xVdBS4^SG%W zH%-^nUDG^a>L*O|q^Y0O7Lz7^!Ze>W^(Xat%EYHk^C?q*N}s1q{IqFSO}&ce8DkgB zhGWA0<`ZM?8}oksw6Uj6{TUO^8hb?Q4)p4tHQ_-%)SolqoUw0uzs@4p#I%-;dB5|AH*QzC!4kHQet&Yw2A$KJWZEC{{ zQ6ty3tZv*4qC_7@@tE46k+)JU7?5QUDJVdJe;NwWqC#vdP+m(cYEWO8HfIwp6_{gTP%OkOe{J1n_t zj9)hS5Hk=?K8k#<$+A|fBkapfiLxlka+1i~&oZv;T$W+`u>Z2+oG;AVxknBYYFO^F z-_&hZs*|djjW@gnWUBaSlGTwr+sV?iakT!*%V*oW`OQ}HV(rzlS(Mu|ZR`*>Dm$CC zcN2T&#o7xm)n0hzOnVnCYIbu|%g#?y^@raxbxc;lfG0u-YprwWD>NeuyNy8g`+l< zQFt#(?_TxSR+d2+j0f%((t1bmB!dS9yK)(+&2IeZ3RKVV7rLLqWzJ=7vr?)1`uKbkmcdX?{I!8JR+M#hw;im~neg zrEZkDNh@~)x3AaSt}IunQ$1P;k!tTSa}-T66U|`9U+-){NBddyZ7YK9k(K-0D2+Yt zTc3PiHs#1M+^URv$vCslB*eH7WbQ7vS@x3+9}?s(?5FJ9eW#@Qa#d#Uk$SqU$B`RY z7Dp7p^G>h{etV*_L?kZbWf@g~aVDI|jENz4jp!8bNfdjhm~fq6g$O-`_b%fnQyg(7 z#u|7qPVswlsi*;acFhUv)nIZ}LAsgk*@lWL^?_2pi8p7Ys&PEhS|-g$^3C}rRGz{T z3Q2}#6$ymJ1$+hT6bSaXfK`REt_erXC&NUrcFcsM0>B{r6%&q$@Q<6YBAI>0PMC09 zRKuhR_etTD2`3~oZNf>(%$RUWGW$(9Ety#p;w>}M@qpxk5b=tG#?BEMej*wGIF^qJ z5K()miw_SIAEFH)Z7BEXX!H6bZqW8BtXf#?~c*Y;|%$15vWk*LM*aqd|oOJ~qSnEiYlS{}CCeIBab!zQesy z<3Q^Xn~VxtdBb2VsL?Helu=Q4KrsSj9#DxRw2WKWf2c(4JhUQ+WlCT^f85+Hi?-Zn z?h4ZJC(K<@oBpJ^J0ew}f@VO4Q7OUZD7RR>KzM|jS`=S_a7n?G#wg>L>a zlOK@=*w|4B02iIT1->f`j0+$sxYh*-k8KlBDIk_|H(IH?Mx66><_;i4H&25kBV4bI zkGsX6#deSeO&6$ZQTq(Eaxdi=AxPYy-9B?C3T;p8*B>8SZL!zv{_vk?_`XH=Tzn_k&0ONMFK!lvi!MC_cp5G|s37JGZrq4u z;-5EHzU )uMY**XXYA<~DO%>s#=5`g=9t)zNSdFw500uh5Ih2z6F=+USct_@xu+ zJr{n6WJF5S;Evcpm`Z@nDlK7t5Q%{8nu6+D0j9lYQK5i=ugs}4!LZFB7yX*=wk@Qu z=<9&~K3fTqmIm!46wDNr<{XCk{QkEw0k9(bf8^Qp*EuZ*FjNpA|7$C-;G z93`o}rEizz#Bl3m2~h&{AKkV^9hKe1AcjLp@Ek^2*L6)cMK376AnsBy@(OcwLp)+@ z!6vftduA*JQqU*MXyeW73{ch)psZ=&5MnL-70jji36xH#BgL)ZY8y-F`w=pVzu
' \ + '' \ + '' \ + '' \ + '' \ + '' \ + '' \ + '' \ + '
some_callResponse
1
2
' + + def test_anyuri_string(self): + _link = "http://arskom.com.tr/" + + class C(ComplexModel): + c = AnyUri + + class SomeService(Service): + @srpc(_returns=Array(C)) + def some_call(): + return [C(c=_link)] + + 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 + + def test_anyuri_uri_value(self): + _link = "http://arskom.com.tr/" + _text = "Arskom" + + class C(ComplexModel): + c = AnyUri + + class SomeService(Service): + @srpc(_returns=Array(C)) + 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)) + 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].text == _text + assert elt.xpath('//td[@class="c"]')[0][0].attrib['href'] == _link + + def test_row_subprot(self): + 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 + + class SearchProtocol(HtmlBase): + def to_parent(self, ctx, cls, inst, parent, name, **kwargs): + 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))) + + def column_table_gen_header(self, ctx, cls, parent, name): + 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', []) + + tr_ctx = parent.element('tr') + tr_ctx.__enter__() + ctxstack.append(tr_ctx) + + 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): + ctxstack = ctx.protocol[self].array_subprot_ctxstack + + for elt_ctx in reversed(ctxstack): + elt_ctx.__exit__(None, None, None) + + del ctxstack[:] + + class Search(ComplexModel): + query = Unicode + uri = Unicode + + SearchTable = Array( + Search.customize(prot=SearchProtocol()), + prot=HtmlColumnTable(field_type_name_attr=None), + ) + + 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'), + ] + + app = Application([SomeService], 'tns', in_protocol=HttpRpc(), + out_protocol=HtmlMicroFormat()) + 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="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', + ] + + assert elt.xpath('//th[@class="search-link"]/text()') == ["Search"] + + +class TestHtmlRowTable(unittest.TestCase): + def test_anyuri_string(self): + _link = "http://arskom.com.tr/" + + class C(ComplexModel): + c = AnyUri + + class SomeService(Service): + @srpc(_returns=C) + def some_call(): + return C(c=_link) + + 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 + + def test_anyuri_uri_value(self): + _link = "http://arskom.com.tr/" + _text = "Arskom" + + class C(ComplexModel): + c = AnyUri + + class SomeService(Service): + @srpc(_returns=C) + 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)) + 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].text == _text + assert elt.xpath('//td[@class="c"]')[0][0].attrib['href'] == _link + + def test_complex(self): + class SomeService(Service): + @srpc(CCM, _returns=CCM) + def some_call(ccm): + return ccm + + 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') + + elt = html.fromstring(out_string) + show(elt, "TestHtmlRowTable.test_complex") + + # Here's what this is supposed to return + """ + + + + + + + + + + + + + + + +
i456
c + + + + + + + + + + + +
i123
sabc
+
sdef
+ """ + + print(html.tostring(elt, pretty_print=True)) + 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/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/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)) + 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)) + 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
' \ + '
' \ + '
' + + def test_string_array_no_header(self): + class SomeService(Service): + @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)) + + 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
' \ + '
' \ + '
' + + + 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'), + ] + 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)) + 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__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/protocol/test_html_table.pyc b/pym/calculate/contrib/spyne/test/protocol/test_html_table.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd579188204460e00e8f05a17f1f685c4cfbcddc GIT binary patch literal 20634 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/protocol/test_http.py b/pym/calculate/contrib/spyne/test/protocol/test_http.py new file mode 100644 index 0000000..3f34572 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/protocol/test_http.py @@ -0,0 +1,867 @@ +#!/usr/bin/env python +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +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 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.server.http import HttpTransportContext +from spyne.util.test import call_wsgi_app_kwargs + + +class TestString(unittest.TestCase): + def setUp(self): + class SomeService(Service): + @srpc(String, _returns=String) + def echo_string(s): + return s + + 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' + + 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' + + 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' + + +class TestHttpTransportContext(unittest.TestCase): + def test_gen_header(self): + val = HttpTransportContext.gen_header("text/plain", charset="utf8") + assert val == 'text/plain; charset="utf8"' + + +class TestSimpleDictDocument(unittest.TestCase): + def test_own_parse_qs_01(self): + assert dict(_parse_qs('')) == {} + def test_own_parse_qs_02(self): + assert dict(_parse_qs('p')) == {'p': [None]} + def test_own_parse_qs_03(self): + assert dict(_parse_qs('p=')) == {'p': ['']} + def test_own_parse_qs_04(self): + assert dict(_parse_qs('p=1')) == {'p': ['1']} + def test_own_parse_qs_05(self): + 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]} + def test_own_parse_qs_07(self): + 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']} + def test_own_parse_qs_09(self): + 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']} + def test_own_parse_qs_11(self): + 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()) + server = WsgiApplication(app) + + 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) + + server.get_in_object(ctx) + if ctx.in_error is not None: + raise ctx.in_error + + server.get_out_object(ctx) + if ctx.out_error is not None: + raise ctx.out_error + + server.get_out_string(ctx) + + return ctx + +class TestValidation(unittest.TestCase): + def test_validation_frequency(self): + class SomeService(Service): + @srpc(ByteArray(min_occurs=1), _returns=ByteArray) + def some_call(p): + pass + + try: + _test([SomeService], '', validator='soft') + except ValidationError: + pass + else: + raise Exception("must raise ValidationError") + + def _test_validation_frequency_simple_bare(self): + class SomeService(Service): + @srpc(ByteArray(min_occurs=1), _body_style='bare', _returns=ByteArray) + def some_call(p): + pass + + try: + _test([SomeService], '', validator='soft') + except ValidationError: + pass + else: + raise Exception("must raise ValidationError") + + def test_validation_frequency_complex_bare_parent(self): + class C(ComplexModel): + i=Integer(min_occurs=1) + s=String + + class SomeService(Service): + @srpc(C, _body_style='bare') + def some_call(p): + pass + + # must not complain about missing s + _test([SomeService], 'i=5', validator='soft') + + # must raise validation error for missing i + try: + _test([SomeService], 's=a', validator='soft') + except ValidationError: + pass + else: + raise Exception("must raise ValidationError") + + # must raise validation error for missing i + try: + _test([SomeService], '', validator='soft') + except ValidationError: + pass + else: + raise Exception("must raise ValidationError") + + def test_validation_frequency_parent(self): + class C(ComplexModel): + i=Integer(min_occurs=1) + s=String + + class SomeService(Service): + @srpc(C) + def some_call(p): + pass + + # must not complain about missing s + _test([SomeService], 'p.i=5', validator='soft') + try: + # must raise validation error for missing i + _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') + + def test_validation_array(self): + class C(ComplexModel): + i=Integer(min_occurs=1) + s=String + + class SomeService(Service): + @srpc(Array(C)) + def some_call(p): + pass + + # must not complain about missing s + _test([SomeService], 'p[0].i=5', validator='soft') + try: + # must raise validation error for missing i + _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') + + def test_validation_array_index_jump_error(self): + class C(ComplexModel): + i=Integer + + class SomeService(Service): + @srpc(Array(C), _returns=String) + def some_call(p): + return repr(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) + except ValidationError: + pass + else: + raise Exception("must raise ValidationError") + + def test_validation_array_index_jump_tolerate(self): + class C(ComplexModel): + i=Integer + + class SomeService(Service): + @srpc(Array(C), _returns=String) + def some_call(p): + return repr(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)]' + + # 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)]' + + def test_validation_nested_array(self): + class CC(ComplexModel): + d = DateTime + + class C(ComplexModel): + i = Integer(min_occurs=1) + cc = Array(CC) + + class SomeService(Service): + @srpc(Array(C)) + def some_call(p): + print(p) + + # must not complain about missing s + _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') + 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') + + def test_validation_nullable(self): + class SomeService(Service): + @srpc(ByteArray(nullable=False), _returns=ByteArray) + def some_call(p): + pass + + try: + _test([SomeService], 'p', validator='soft') + except ValidationError: + pass + else: + raise Exception("must raise ValidationError") + + def test_validation_string_pattern(self): + class SomeService(Service): + @srpc(Uuid) + def some_call(p): + pass + + try: + _test([SomeService], "p=duduk", validator='soft') + except ValidationError: + pass + else: + raise Exception("must raise ValidationError") + + def test_validation_integer_range(self): + class SomeService(Service): + @srpc(Integer(ge=0, le=5)) + def some_call(p): + pass + + try: + _test([SomeService], 'p=10', validator='soft') + except ValidationError: + pass + else: + raise Exception("must raise ValidationError") + + def test_validation_integer_type(self): + class SomeService(Service): + @srpc(Integer8) + def some_call(p): + pass + + try: + _test([SomeService], "p=-129", validator='soft') + except ValidationError: + pass + else: + raise Exception("must raise ValidationError") + + def test_validation_integer_type_2(self): + class SomeService(Service): + @srpc(Integer8) + def some_call(p): + pass + + try: + _test([SomeService], "p=1.2", validator='soft') + except ValidationError: + pass + else: + raise Exception("must raise ValidationError") + + +class Test(unittest.TestCase): + def test_multiple_return(self): + class SomeService(Service): + @srpc(_returns=[Integer, String]) + def some_call(): + return 1, 's' + + try: + _test([SomeService], '') + except TypeError: + pass + else: + raise Exception("Must fail with: HttpRpc does not support complex " + "return types.") + + def test_primitive_only(self): + class SomeComplexModel(ComplexModel): + i = Integer + s = String + + class SomeService(Service): + @srpc(SomeComplexModel, _returns=SomeComplexModel) + def some_call(scm): + return SomeComplexModel(i=5, s='5x') + + try: + _test([SomeService], '') + except TypeError: + pass + else: + raise Exception("Must fail with: HttpRpc does not support complex " + "return types.") + + def test_complex(self): + class CM(ComplexModel): + _type_info = [ + ("i", Integer), + ("s", String), + ] + + class CCM(ComplexModel): + _type_info = [ + ("i", Integer), + ("c", CM), + ("s", String), + ] + + class SomeService(Service): + @srpc(CCM, _returns=String) + 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') + + 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) + def some_call(s): + return '\n'.join(s) + + ctx = _test([SomeService], '&s=1&s=2') + assert b''.join(ctx.out_string) == b'1\n2' + + def test_complex_array(self): + class CM(ComplexModel): + _type_info = [ + ("i", Integer), + ("s", String), + ] + + class SomeService(Service): + @srpc(Array(CM), _returns=String) + def some_call(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') + + 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): + _type_info = [ + ("i", Integer), + ("s", String), + ] + + class SomeService(Service): + @srpc(Array(CM), _returns=String) + def some_call(cs): + return repr(cs) + + ctx = _test([SomeService], 'cs=empty') + + assert b''.join(ctx.out_string) == b'[]' + + def test_complex_object_empty(self): + class CM(ComplexModel): + _type_info = [ + ("i", Integer), + ("s", String), + ] + + class SomeService(Service): + @srpc(CM, _returns=String) + def some_call(c): + return repr(c) + + ctx = _test([SomeService], 'c=empty') + + assert b''.join(ctx.out_string) == b'CM()' + + def test_nested_flatten(self): + class CM(ComplexModel): + _type_info = [ + ("i", Integer), + ("s", String), + ] + + class CCM(ComplexModel): + _type_info = [ + ("i", Integer), + ("c", CM), + ("s", String), + ] + + class SomeService(Service): + @srpc(CCM, _returns=String) + def some_call(ccm): + return repr(ccm) + + 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')" + + def test_nested_flatten_with_multiple_values_1(self): + class CM(ComplexModel): + _type_info = [ + ("i", Integer), + ("s", String), + ] + + class CCM(ComplexModel): + _type_info = [ + ("i", Integer), + ("c", CM), + ("s", String), + ] + + class SomeService(Service): + @srpc(CCM.customize(max_occurs=2), _returns=String) + 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') + + 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'))]" + + def test_nested_flatten_with_multiple_values_2(self): + class CM(ComplexModel): + _type_info = [ + ("i", Integer), + ("s", String), + ] + + class CCM(ComplexModel): + _type_info = [ + ("i", Integer), + ("c", CM.customize(max_occurs=2)), + ("s", String), + ] + + class SomeService(Service): + @srpc(CCM, _returns=String) + 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') + + 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): + class CM(ComplexModel): + _type_info = [ + ("i", Integer), + ("s", String), + ] + + class CCM(ComplexModel): + _type_info = [ + ("i", Integer), + ("c", Array(CM)), + ("s", String), + ] + + class SomeService(Service): + @srpc(CCM, _returns=String) + 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') + + 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): + class CCM(ComplexModel): + _type_info = [ + ("i", Integer), + ("c", Array(String)), + ("s", String), + ] + + class SomeService(Service): + @srpc(Array(CCM), _returns=String) + 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)) + 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')), + ] + + class SomeService(Service): + @srpc(CM, _returns=String) + def some_call(cm): + return repr(cm) + + # s is missing + 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) + assert s == b"CM(i=1)" + + # s is empty + 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): + class CCM(ComplexModel): + _type_info = [ + ("i", Integer), + ("c", Array(String)), + ("s", String), + ] + + class SomeService(Service): + @srpc(CCM, _returns=String) + 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)) + 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)) + 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)) + 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'] + + class ResponseHeader(ComplexModel): + _type_info = { + 'Set-Cookie': String(max_occurs='unbounded'), + 'Expires': DateTime + } + + class SomeService(Service): + __out_header__ = ResponseHeader + + @rpc(String) + def some_call(ctx, s): + assert s is not None + 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' + + 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, + } + + ret = wsgi_app(req_dict, start_response) + print(list(ret)) + + wsgi_app = wsgiref_validator(wsgi_app) + + ret = wsgi_app(req_dict, start_response) + + assert list(ret) == [b''] + + +class TestHttpPatterns(unittest.TestCase): + def test_rules(self): + _int = 5 + _fragment = 'some_fragment' + + class SomeService(Service): + @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()) + 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', + } + + initial_ctx = WsgiMethodContext(server, environ, 'some-content-type') + + ctx, = server.generate_contexts(initial_ctx) + + foo = [] + for i in server._http_patterns: + foo.append(i) + + assert len(foo) == 1 + print(foo) + assert ctx.descriptor is not None + + server.get_in_object(ctx) + assert ctx.in_error is None + + server.get_out_object(ctx) + assert ctx.out_error is None + + +class ParseCookieTest(unittest.TestCase): + def test_cookie_parse(self): + string = 'some_string' + class RequestHeader(ComplexModel): + some_field = String + + class SomeService(Service): + __in_header__ = RequestHeader + + @rpc(String) + def some_call(ctx, s): + assert ctx.in_header.some_field == string + + def start_response(code, headers): + assert code == HTTP_200 + + c = 'some_field=%s'% (string,) + + 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, + } + + ret = wsgi_app(req_dict, start_response) + print(ret) + + wsgi_app = wsgiref_validator(wsgi_app) + + ret = wsgi_app(req_dict, start_response) + print(ret) + + # These tests copied from Django: + # https://github.com/django/django/pull/6277/commits/da810901ada1cae9fc1f018f879f11a7fb467b28 + 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'}) + # 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', '': '"'} + ) + # Illegal cookies that have an '=' char in an unquoted value. + 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'}) + # Cookies with '[' and ']'. + 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'}) + # _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'}) + + def test_invalid_cookies(self): + """ + Cookie strings that go against RFC6265 but browsers will send if set + via document.cookie. + """ + # 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()) + # Even a double quote may be an unamed value. + 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'}) + # More characters the spec forbids. + 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'}) + # 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': ''}) + + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/protocol/test_http.pyc b/pym/calculate/contrib/spyne/test/protocol/test_http.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7c26f04ce72304c000de6be64ad6084e1240784c GIT binary patch literal 46785 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/protocol/test_json.py b/pym/calculate/contrib/spyne/test/protocol/test_json.py new file mode 100644 index 0000000..ac162fb --- /dev/null +++ b/pym/calculate/contrib/spyne/test/protocol/test_json.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +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.server import ServerBase +from spyne.server.null import NullServer + +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))): + def dumps(self, o): + return super(TestDictDocument, self).dumps(o).encode('utf8') + + def loads(self, o): + return super(TestDictDocument, self).loads(o.decode('utf8')) + +_dry_sjrpc1 = TDry(json, _SpyneJsonRpc1) + +class TestSpyneJsonRpc1(unittest.TestCase): + def test_call(self): + class SomeService(Service): + @srpc(Integer, _returns=Integer) + def yay(i): + print(i) + return i + + ctx = _dry_sjrpc1([SomeService], + {"ver": 1, "body": {"yay": {"i":5}}}, True) + + print(ctx) + print(list(ctx.out_string)) + assert ctx.out_document == {"ver": 1, "body": 5} + + def test_call_with_header(self): + class SomeHeader(ComplexModel): + i = Integer + + 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) + + print(ctx) + print(list(ctx.out_string)) + assert ctx.out_document == {"ver": 1, "body": 5} + + def test_error(self): + class SomeHeader(ComplexModel): + i = Integer + + 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) + + print(ctx) + print(list(ctx.out_string)) + assert ctx.out_document == {"ver": 1, "fault": { + 'faultcode': 'Server', 'faultstring': 'Internal Error'}} + + +class TestJsonDocument(unittest.TestCase): + def test_out_kwargs(self): + class SomeService(Service): + @srpc() + def yay(): + pass + + 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) + + 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) + + def test_invalid_input(self): + class SomeService(Service): + pass + + 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' + + +class TestJsonP(unittest.TestCase): + def test_callback_name(self): + callback_name = 'some_callback' + + class SomeComplexModel(ComplexModel): + i = Integer + s = Unicode + + v1 = 42 + v2 = SomeComplexModel(i=42, s='foo') + + class SomeService(Service): + @srpc(_returns=Integer) + def yay(): + return v1 + + @srpc(_returns=SomeComplexModel) + def complex(): + return v2 + + 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');')) + + 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');')) + + + def test_wrapped_array_in_wrapped_response(self): + from spyne.model.complex import ComplexModel, Array + from spyne.model.primitive import Unicode + + class Permission(ComplexModel): + _type_info = [ + ('application', Unicode), + ('feature', Unicode), + ] + + class SomeService(Service): + @srpc(_returns=Array(Permission)) + def yay(): + return [ + Permission(application='app', feature='f1'), + Permission(application='app', feature='f2') + ] + + 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') + print(retstr) + assert retstr == '{"yayResponse": {"yayResult": [' \ + '{"Permission": {"application": "app", "feature": "f1"}}, ' \ + '{"Permission": {"application": "app", "feature": "f2"}}]}}' + + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/protocol/test_json.pyc b/pym/calculate/contrib/spyne/test/protocol/test_json.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e23b4674982118195cc43bd83d74cae7f5554dc GIT binary patch literal 10904 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 tFVPjVmyk_(8E?j$^kymPsp zT}X$&Av}MDTmQu&if}oU5VdXHrNp7GOKq1NMYLU@s6bpP(g8Wn;qVf*OM|IpYL}&6 zq-2P?!_*!o8CRlYgu0{D9<}WJivP;!mB*QtFS?OFO3I=n&ZDycH5 zd5X@Hx=GO-saveMXr9y!I&j_gZHg91m1z58dgD;E$P*8UUbm~H?of1r-no?j+2IkN zaEFtMiJH}muvz>c{2Emlj!c1V81I@Ao{8E~i6xJt`COT|S+tU+M(r9)9s~Jtub0GO zVB#!2ULx;>wo&Buj#}&`O_lG&p|ah)&Eq@|_H47v{U(poj%`=aUdg(>MD0G$q5(6! z%8N7(L9xSTKzOdS4mxTx2;Z${VZW==Lmtna?(_zn@hVUDjMC3G>?)%mFmoz@66nK~ zCqR3pJMsSrIfahaY8;xuW-X;pY^Y6;8$VaNm!(>TtXkFti@Snb=O_%(K1zqSUD%NF zE8OJRaOl8+8f-U0#3lWJ`~th(5?VVIM?dGlG7RbW``SjQsS%_W|A>w1 zYQr`PvlMDGK6h1lc}N8ZlQNg`os>IOkVy*tThx~NI$uiSt>sUbdVBD$^g->>lE%7s zd$1$Ssh4zbFI9IR)b2m5-Cw@j+rx;O>U1o93Fb3Py*x8nm?hHkySl@ZYrQ>h0bAV1 zttU~CGwqDK6Hd`ByNk{xR~S#SAkzN3_d(v#W*CF|TKP$=jm$OEps-<2I2ZgUjZ}0Be$!EaL!3FH71)>dOU`M4Y4~+5w0gMT@q%7Y_QhBR7At9N;vn%uvnxaJJhsIdm_fjR@y3tSogj%L zJbQif6ar|*33BF26V8ZJaVze$QvupY$g@*1#Ik1f-(ithumSPDY@>Vm2Lv8s+rmJ3 z00TcDQid1_01n>~eTNDr4$~j(!Oke*4p3r*(cl0RM!6D=u|_#Ps8BRc(K)^joFan; zV*dy<$^=-5CghrA00Pu>T*i%#UNczZ5;`|gU3Y5-b zusuBhrGQT^i+pZ?PE|pk>!^7*xL{ur|9_|UM>X5lC z;O4a-;?{Rj?B3?!TK)Pm=T_hmEF*Hj^7m3%JRtX_^UV;wlH-i0H)L7wGgPa%smer; z(+}?#TyUl>37BY3wvPf6$k;QmmuRh{40Hj1(LT75EIsa|S+4x|IgSnmuV5M2+V)(# z$s=%EVGJKcD;tegz0vZ&tT)zL>-s!Mm^yfsS=zmOm`F+h4+ghhZ`LL1!X(p5HePSF zHhuIr>MN~h8x1pqg$A?}8^~#SiY{yM5xpcXy!p7b?mufh-M~oznK-Tf&5OGC+HbbJ zXN@%(lVo9#yv?++`I#Kbe&g};x`_Me-o1M#J2p4GmUL`xG+QFGSI3ggmjAroTHjce zzPHBoG%N5uUUO>wJn?n-Rv}6lXoM!m9HJA-LQ2l(;XKkz0`X`JyAZl{Ry_EY6N z!Q)qo6FCNpCyIO;BwBgQfMI7FD4kJ{)A%iqUp)ozkafs2QK`pE3j5nxoJu8Eyb3(lQl$&nn` zI|hLVSkz-Uw{r3xQab|?y(`$Pj$06_?2JrVSogaDz}&C?3|(UDB;U2T^y%>ydoqnqxd_@u4aNi0(!H64(M@lfW@z35D og`>~yd*BzGsp(HqRNP5-28lkN&j0zllZBDVinCBy{IcTw7wk-zDgXcg literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/protocol/test_soap11.py b/pym/calculate/contrib/spyne/test/protocol/test_soap11.py new file mode 100644 index 0000000..01d8346 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/protocol/test_soap11.py @@ -0,0 +1,500 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +# +# Most of the service tests are performed through the interop tests. +# + +import datetime +import unittest + +from lxml import etree +import pytz + +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.fault import Fault +from spyne.protocol.soap import Soap11 +from spyne.service import Service +from spyne.server import ServerBase + +from spyne.protocol.soap import _from_soap +from spyne.protocol.soap import _parse_xml_string + +Application.transport = 'test' + + +def start_response(code, headers): + print(code, headers) + + +class Address(ComplexModel): + __namespace__ = "TestService" + + street = String + city = String + zip = Integer + since = DateTime + laditude = Float + longitude = Float + +class Person(ComplexModel): + __namespace__ = "TestService" + + name = String + birthdate = DateTime + age = Integer + 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): + return s + + @rpc(String, Integer, _returns=DateTime) + def a(ctx, s, i): + return datetime.datetime.now() + + @rpc(Person, String, Address, _returns=Address) + def b(ctx, p, s, a): + return Address() + + @rpc(Person) + def d(ctx, Person): + pass + + @rpc(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") + def f(ctx, _from, _self, _import): + return '1234' + + +class MultipleReturnService(Service): + @rpc(String, _returns=(String, String, String)) + def multi(ctx, s): + 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.srv = TestService() + + wsdl = Wsdl11(self.app.interface) + 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())) + + def test_override_param_names(self): + for n in [b'self', b'import', b'return', b'from']: + assert n in self.wsdl_str, '"%s" not in self.wsdl_str' + +class TestMultiple(unittest.TestCase): + def setUp(self): + 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') + + def test_multiple_return(self): + 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 = sent_xml[0] + + print((etree.tostring(sent_xml, pretty_print=True))) + 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') + + +class TestSoap11(unittest.TestCase): + def test_simple_message(self): + m = ComplexModel.produce( + namespace=None, + type_name='myMessage', + members={'s': String, 'i': Integer} + ) + m.resolve_namespace(m, 'test') + + m_inst = m(s="a", i=43) + + e = etree.Element('test') + Soap11().to_parent(None, m, m_inst, e, m.get_namespace()) + e=e[0] + + 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') + + values = Soap11().from_element(None, m, e) + + 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''' + + + + + + + + + + somemachine + someuser + + + machine2 + user2 + + +'''] + + root, xmlids = _parse_xml_string(envelope_string, + etree.XMLParser(), 'utf8') + header, payload = _from_soap(root, xmlids) + + # quick and dirty test href reconstruction + self.assertEqual(len(payload[0]), 2) + + def test_namespaces(self): + m = ComplexModel.produce( + namespace="some_namespace", + type_name='myMessage', + members={'s': String, 'i': Integer}, + ) + + mi = m() + mi.s = 'a' + + e = etree.Element('test') + Soap11().to_parent(None, m, mi, e, m.get_namespace()) + e=e[0] + + self.assertEqual(e.tag, '{some_namespace}myMessage') + + def test_class_to_parent(self): + m = ComplexModel.produce( + 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.age = 2 + m_inst.p.addresses = [] + + element=etree.Element('test') + Soap11().to_parent(None, m, m_inst, element, m.get_namespace()) + 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( + len(element[0].find('{%s}addresses' % Person.get_namespace())), 0) + + p1 = Soap11().from_element(None, m, element)[0] + + self.assertEqual(p1.name, m_inst.p.name) + self.assertEqual(p1.age, m_inst.p.age) + self.assertEqual(p1.addresses, []) + + def test_datetime_fixed_format(self): + # Soap should ignore formats + 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') + 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'): + d = Soap11().from_unicode(Date, iso_d) + assert isinstance(d, datetime.date) == True + assert d.year == 2013 + assert d.month == 4 + assert d.day == 5 + + def test_to_parent_nested(self): + m = ComplexModel.produce( + namespace=None, + type_name='myMessage', + members={'p':Person} + ) + + m.resolve_namespace(m, "m") + + p = Person() + p.name = 'steve-o' + p.age = 2 + p.addresses = [] + + for i in range(0, 100): + a = Address() + a.street = '123 happy way' + a.zip = i + a.laditude = '45.22' + a.longitude = '444.234' + p.addresses.append(a) + + m_inst = m(p=p) + + element=etree.Element('test') + Soap11().to_parent(None, m, m_inst, element, m.get_namespace()) + element=element[0] + + self.assertEqual('{%s}myMessage' % m.get_namespace(), element.tag) + + 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) + + def test_fault_deserialization_missing_fault_actor(self): + element = etree.fromstring(b""" + + + + soap:Client + Some String + + + Some_Policy + + + + + """) + + ret = Soap11().from_element(None, Fault, element[0][0]) + assert ret.faultcode == "soap:Client" + + +# TestSoapHeader supporting classes. +# SOAP Header Elements defined by WS-Addressing. + +NAMESPACE_ADDRESSING = 'http://www.w3.org/2005/08/addressing' + +class Action (Unicode): + __type_name__ = "Action" + __namespace__ = NAMESPACE_ADDRESSING + +class MessageID (Unicode): + __type_name__ = "MessageID" + __namespace__ = NAMESPACE_ADDRESSING + +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 + ) + def someRequest(ctx, response): + print (response) + return 'OK' + +class TestSoapHeader(unittest.TestCase): + + def setUp(self): + 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''' + + /SomeAction + SomeMessageID + SomeRelatesToID + + + + OK + + + ''' + ] + + 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') + + def test_soap_input_header_order(self): + """ + Tests supports for input headers whose elements are provided in + different order than that defined in rpc declaration _in_header parameter. + """ + server = ServerBase(self.app) + initial_ctx = MethodContext(server, MethodContext.SERVER) + initial_ctx.in_string = [ + b''' + + SomeMessageID + SomeRelatesToID + /SomeAction + + + + OK + + + ''' + ] + + 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') + + + def test_soap_input_header_order_and_missing(self): + """ + Test that header ordering logic also works when an input header + element is missing. Confirm that it returns None for the missing + parameter. + """ + server = ServerBase(self.app) + initial_ctx = MethodContext(server, MethodContext.SERVER) + initial_ctx.in_string = [ + b''' + + SomeMessageID + /SomeAction + + + + OK + + + ''' + ] + + 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], None) + + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/protocol/test_soap11.pyc b/pym/calculate/contrib/spyne/test/protocol/test_soap11.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ea83f1749cb5e6be992c56b79063b19cb29b05a GIT binary patch literal 21870 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 + + + + + EA055406-5881-4F02-A3DC-9A5A7510D018.dat + + + + 26981FCD51C95FA47780400B7A45132F + + + + +--uuid:2e53e161-b47f-444a-b594-eb6b72e76997 +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary +Content-ID: <04dfbca1-54b8-4631-a556-4addea6716ed-223384@cxf.apache.org> + +sample data +--uuid:2e53e161-b47f-444a-b594-eb6b72e76997-- +""" + + +# Service Classes +class DownloadPartFileResult(ComplexModel): + ErrorCode = Integer + ErrorMessage = String + Data = String + + +class TestSingleSoap12(TestSingle): + def setUp(self): + 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') + self.wsdl_str = wsdl.get_interface_document() + self.wsdl_doc = etree.fromstring(self.wsdl_str) + + +class TestMultipleSoap12(TestMultiple): + def setUp(self): + 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') + + +class TestSoap12(unittest.TestCase): + + def test_soap12(self): + element = etree.fromstring(b""" + + + + + env:Sender + + st:SomeDomainProblem + + + + + Some_Policy + + + + + """) + + so = Soap12() + ret = so.from_element(None, Fault, element[0][0]) + assert ret.faultcode == "env:Sender.st:SomeDomainProblem" + + def test_fault_generation(self): + 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()) + + req = b""" + + + + + + """ + + server = WsgiApplication(app) + response = etree.fromstring(b''.join(server({ + 'QUERY_STRING': '', + 'PATH_INFO': '/call', + 'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'text/xml; charset=utf8', + 'wsgi.input': BytesIO(req) + }, start_response, "http://null"))) + + response_str = etree.tostring(response, pretty_print=True) + print(response_str) + + expected = b""" + + + + + A plausible fault + + http://faultactor.example.com + + soap12env:Sender + + Plausible + + issue + + + + + extra info + + + + """ + if not LXMLOutputChecker().check_output(expected, response_str, PARSE_XML): + raise Exception("Got: %s but expected: %s" % (response_str, expected)) + + def test_gen_fault_codes(self): + fault_string = "Server.Plausible.error" + value, faultstrings = Soap12().gen_fault_codes(faultstring=fault_string) + self.assertEqual(value, "%s:Receiver" %(Soap12.soap_env)) + self.assertEqual(faultstrings[0], "Plausible") + self.assertEqual(faultstrings[1], "error") + + fault_string = "UnknownFaultCode.Plausible.error" + with self.assertRaises(TypeError): + value, faultstrings = Soap12().gen_fault_codes(faultstring=fault_string) + + def test_mtom(self): + FILE_NAME = 'EA055406-5881-4F02-A3DC-9A5A7510D018.dat' + TNS = 'http://gib.gov.tr/vedop3/eFatura' + class SomeService(Service): + @rpc(Unicode(sub_name="fileName"), ByteArray(sub_name='binaryData'), + ByteArray(sub_name="hash"), _returns=Unicode) + def documentRequest(ctx, file_name, file_data, data_hash): + assert file_name == FILE_NAME + assert file_data == (b'sample data',) + + return file_name + + app = Application([SomeService], tns=TNS, + in_protocol=Soap12(), out_protocol=Soap12()) + + server = WsgiApplication(app) + response = etree.fromstring(b''.join(server({ + 'QUERY_STRING': '', + 'PATH_INFO': '/call', + 'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'Content-Type: multipart/related; ' + 'type="application/xop+xml"; ' + 'boundary="uuid:2e53e161-b47f-444a-b594-eb6b72e76997"; ' + 'start=""; ' + 'start-info="application/soap+xml"; action="sendDocument"', + 'wsgi.input': BytesIO(MTOM_REQUEST.replace(b"\n", b"\r\n")) + }, start_response, "http://null"))) + + response_str = etree.tostring(response, pretty_print=True) + print(response_str) + + nsdict = dict(tns=TNS) + + assert etree.fromstring(response_str) \ + .xpath(".//tns:documentRequestResult/text()", namespaces=nsdict) \ + == [FILE_NAME] + + def test_mtom_join_envelope_chunks(self): + FILE_NAME = 'EA055406-5881-4F02-A3DC-9A5A7510D018.dat' + TNS = 'http://gib.gov.tr/vedop3/eFatura' + + # large enough payload to be chunked + PAYLOAD = b"sample data " * 1024 + class SomeService(Service): + @rpc(Unicode(sub_name="fileName"), ByteArray(sub_name='binaryData'), + ByteArray(sub_name="hash"), _returns=Unicode) + def documentRequest(ctx, file_name, file_data, data_hash): + assert file_name == FILE_NAME + assert file_data == (PAYLOAD,) + + return file_name + + app = Application([SomeService], tns=TNS, + in_protocol=Soap12(), out_protocol=Soap12()) + + server = WsgiApplication(app, block_length=1024) + response = etree.fromstring(b''.join(server({ + 'QUERY_STRING': '', + 'PATH_INFO': '/call', + 'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'Content-Type: multipart/related; ' + 'type="application/xop+xml"; ' + 'boundary="uuid:2e53e161-b47f-444a-b594-eb6b72e76997"; ' + 'start=""; ' + 'start-info="application/soap+xml"; action="sendDocument"', + 'wsgi.input': BytesIO(MTOM_REQUEST + .replace(b"\n", b"\r\n") + .replace(b"sample data", PAYLOAD)), + }, start_response, "http://null"))) + + response_str = etree.tostring(response, pretty_print=True) + print(response_str) + + nsdict = dict(tns=TNS) + + assert etree.fromstring(response_str) \ + .xpath(".//tns:documentRequestResult/text()", namespaces=nsdict) \ + == [FILE_NAME] + + def test_bytes_join_attachment(self): + href_id = "http://tempuri.org/1/634133419330914808" + payload = "ANJNSLJNDYBC SFDJNIREMX:CMKSAJN" + envelope = ''' + + + + + 0 + + + + + + + + + ''' % href_id + + (joinedmsg, numreplaces) = _join_attachment(NS_SOAP11_ENV, + href_id, envelope, payload) + + soaptree = etree.fromstring(joinedmsg) + + body = soaptree.find(ns.SOAP11_ENV("Body")) + response = body.getchildren()[0] + result = response.getchildren()[0] + r = XmlDocument().from_element(None, DownloadPartFileResult, result) + + self.assertEqual(payload, r.Data) + + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/protocol/test_soap12.pyc b/pym/calculate/contrib/spyne/test/protocol/test_soap12.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6030638232590010050b48e54efc7ac003e48a7e GIT binary patch literal 14391 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 DDu+)z literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/protocol/test_xml.py b/pym/calculate/contrib/spyne/test/protocol/test_xml.py new file mode 100644 index 0000000..2ae3218 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/protocol/test_xml.py @@ -0,0 +1,628 @@ +#!/usr/bin/env python +# encoding: utf-8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from __future__ import print_function + +import logging +logging.basicConfig(level=logging.DEBUG) + +import sys +import unittest +import decimal +import datetime + +from pprint import pprint +from base64 import b64encode + +from lxml import etree +from lxml.builder import E + +from spyne import MethodContext, rpc, ByteArray, File, AnyXml +from spyne.context import FakeContext +from spyne.const import RESULT_SUFFIX +from spyne.service import Service +from spyne.server import ServerBase +from spyne.application import Application +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.server.wsgi import WsgiApplication +from spyne.const.xml import NS_XSI + + +class TestXml(unittest.TestCase): + def test_empty_string(self): + class a(ComplexModel): + b = Unicode + + elt = etree.fromstring('') + o = get_xml_as_object(elt, a) + + assert o.b == '' + + def test_xml_data(self): + class C(ComplexModel): + a = XmlData(Unicode) + b = XmlAttribute(Unicode) + + class SomeService(Service): + @srpc(C, _returns=C) + def some_call(c): + assert c.a == 'a' + assert c.b == 'b' + return c + + 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'' + ] + + ctx, = server.generate_contexts(initial_ctx) + server.get_in_object(ctx) + server.get_out_object(ctx) + server.get_out_string(ctx) + + 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] + + print(etree.tostring(ret, pretty_print=True)) + + assert ret.text == "a" + 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') + print(etree.tostring(parent, pretty_print=True)) + 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']) + + 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'}) + assert xpath == val.s + + def test_decimal(self): + d = decimal.Decimal('1e100') + + class SomeService(Service): + @srpc(Decimal(120,4), _returns=Decimal) + def some_call(p): + print(p) + print(type(p)) + assert type(p) == decimal.Decimal + assert d == p + return p + + 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'

' + ] + + 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)) + + print(etree.tostring(elt, pretty_print=True)) + 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 + + m = { + "s0": "aa", + "s2": "cc", + "s3": "dd", + } + + class C(ComplexModel): + __namespace__ = "aa" + a = Integer + b = Integer(sub_name="bb") + c = Integer(sub_ns="cc") + d = Integer(sub_ns="dd", sub_name="dd") + + 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:bb/text()", namespaces=m) == ["2"] + 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) + print(c) + assert c.a == 1 + assert c.b == 2 + assert c.c == 3 + assert c.d == 4 + + 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 + + m = { + "s0": "aa", + "s2": "cc", + "s3": "dd", + } + + class C(ComplexModel): + __namespace__ = "aa" + a = XmlAttribute(Integer) + b = XmlAttribute(Integer(sub_name="bb")) + c = XmlAttribute(Integer(sub_ns="cc")) + d = XmlAttribute(Integer(sub_ns="dd", sub_name="dd")) + + 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("//*/@bb") == ["2"] + assert elt.xpath("//*/@s2:c", namespaces=m) == ["3"] + assert elt.xpath("//*/@s3:dd", namespaces=m) == ["4"] + + c = get_xml_as_object(elt, C) + print(c) + assert c.a == 1 + assert c.b == 2 + assert c.c == 3 + assert c.d == 4 + + 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'), + ] + + for xml_date in xml_dates: + c = get_xml_as_object(xml_date, d) + assert isinstance(c, datetime.date) == True + assert c.year == 2013 + assert c.month == 4 + assert c.day == 5 + + def test_datetime_usec(self): + fs = etree.fromstring + 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) + assert d.microsecond == 123457 + + # rounds down + 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) + # FIXME: this is very interesting. why? + if not six.PY2: + assert d.microsecond == 123456 + else: + assert d.microsecond == 123457 + + 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) + server.get_in_object(ctx) + return ctx + + def test_mandatory_elements(self): + class SomeService(Service): + @srpc(M(Unicode), _returns=Unicode) + def some_call(s): + assert s == 'hello' + return s + + 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'' + ]) + 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' + + # Invalid call + ctx = self._get_ctx(server, [ + b'' + # no mandatory elements here... + 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) + 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()) + server = WsgiApplication(app) + + req = ( + u'' + u'Ğ' + u'' + ).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)) + print("AAA") + + assert u'Ğ'.encode('utf8') in b''.join(resp) + + def test_mandatory_subelements(self): + class C(ComplexModel): + foo = M(Unicode) + + class SomeService(Service): + @srpc(C.customize(min_occurs=1), _returns=Unicode) + def some_call(c): + assert c is not None + assert c.foo == 'hello' + return c.foo + + app = Application( + [SomeService], "tns", name="test_mandatory_subelements", + in_protocol=XmlDocument(validator='lxml'), + out_protocol=XmlDocument()) + server = ServerBase(app) + + ctx = self._get_ctx(server, [ + b'' + # no mandatory elements at all... + b'' + ]) + self.assertRaises(SchemaValidationError, server.get_out_object, ctx) + + 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): + class C(ComplexModel): + bar = XmlAttribute(M(Unicode)) + + 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' + return c.foo + + app = Application( + [SomeService], "tns", name="test_mandatory_element_attributes", + in_protocol=XmlDocument(validator='lxml'), + out_protocol=XmlDocument()) + server = ServerBase(app) + + ctx = self._get_ctx(server, [ + b'' + # no mandatory elements at all... + b'' + ]) + self.assertRaises(SchemaValidationError, server.get_out_object, ctx) + + 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): + 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' + + def test_null_mandatory_attribute(self): + class Action (ComplexModel): + data = XmlAttribute(M(Unicode)) + + elt = get_object_as_xml(Action(), Action) + eltstr = etree.tostring(elt) + print(eltstr) + assert eltstr == b'' + + def test_bytearray(self): + v = b'aaaa' + elt = get_object_as_xml([v], ByteArray, 'B') + eltstr = etree.tostring(elt) + print(eltstr) + 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) + eltstr = etree.tostring(elt) + print(eltstr) + assert etree.tostring(elt[0], encoding="unicode") == v + + def test_any_xml_bytes(self): + v = b"" + + 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') + eltstr = etree.tostring(elt) + print(eltstr) + assert etree.tostring(elt[0]) == etree.tostring(v) + + def test_file(self): + v = b'aaaa' + f = BytesIO(v) + elt = get_object_as_xml(File.Value(handle=f), File, 'B') + eltstr = etree.tostring(elt) + print(eltstr) + 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 + + 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 + + def test_default(self): + class SomeComplexModel(ComplexModel): + _type_info = [ + ('a', Unicode), + ('b', Unicode(default='default')), + ] + + obj = XmlDocument().from_element( + None, SomeComplexModel, + etree.fromstring(""" + + string + + """) + ) + + # xml schema says it should be None + assert obj.b == 'default' + + obj = XmlDocument().from_element( + None, SomeComplexModel, + etree.fromstring(""" + + string + + + """ % NS_XSI) + ) + + # xml schema says it should be 'default' + assert obj.b == 'default' + + obj = XmlDocument(replace_null_with_default=False).from_element( + None, SomeComplexModel, + etree.fromstring(""" + + string + + + """ % NS_XSI) + ) + + # xml schema says it should be 'default' + assert obj.b is None + + def test_polymorphic_roundtrip(self): + + class B(ComplexModel): + __namespace__ = 'some_ns' + _type_info = { + '_b': Unicode, + } + + def __init__(self): + super(B, self).__init__() + self._b = "b" + + class C(B): + __namespace__ = 'some_ns' + _type_info = { + '_c': Unicode, + } + + def __init__(self): + super(C, self).__init__() + self._c = "c" + + class A(ComplexModel): + __namespace__ = 'some_ns' + _type_info = { + '_a': Unicode, + '_b': B, + } + + def __init__(self, b=None): + super(A, self).__init__() + 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) + + element_tree = etree.fromstring(xml_string) + new_a = get_xml_as_object_polymorphic(elt, A) + + assert new_a._a == a._a, (a._a, new_a._a) + assert new_a._b._b == a._b._b, (a._b._b, new_a._b._b) + assert new_a._b._c == a._b._c, (a._b._c, new_a._b._c) + + +class TestIncremental(unittest.TestCase): + def test_one(self): + class SomeComplexModel(ComplexModel): + s = Unicode + i = Integer + + v = SomeComplexModel(s='a', i=1), + + class SomeService(Service): + @rpc(_returns=SomeComplexModel) + def get(ctx): + return v + + 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) + + 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'] + + def test_many(self): + class SomeComplexModel(ComplexModel): + s = Unicode + 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), + ] + + class SomeService(Service): + @rpc(_returns=Array(SomeComplexModel)) + def get(ctx): + return v + + 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) + + 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'] + + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/protocol/test_xml.pyc b/pym/calculate/contrib/spyne/test/protocol/test_xml.pyc new file mode 100644 index 0000000000000000000000000000000000000000..20be48bf6bb9fb18e0d81e0d25bd8b7eca8a86d4 GIT binary patch literal 28139 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/sort_wsdl.py b/pym/calculate/contrib/spyne/test/sort_wsdl.py new file mode 100644 index 0000000..96a4581 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/sort_wsdl.py @@ -0,0 +1,104 @@ +#!/usr/bin/python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""Quick hack to sort the wsdl. it's helpful when comparing the wsdl output +from two spyne versions. +""" + +ns_wsdl = "http://schemas.xmlsoap.org/wsdl/" +ns_schema = "http://www.w3.org/2001/XMLSchema" + +import sys + +from lxml import etree + + +def cache_order(l, ns): + return dict([ ("{%s}%s" % (ns, a), l.index(a)) for a in l]) + + +wsdl_order = ('types', 'message', 'service', 'portType', 'binding') +wsdl_order = cache_order(wsdl_order, ns_wsdl) + +schema_order = ('import', 'element', 'simpleType', 'complexType', 'attribute') +schema_order = cache_order(schema_order, ns_schema) + +parser = etree.XMLParser(remove_blank_text=True) + + +def main(): + tree = etree.parse(sys.stdin, parser=parser) + sort_wsdl(tree) + tree.write(sys.stdout, encoding="UTF-8", xml_declaration=True) + return 0 + + +def sort_wsdl(tree): + l0 = [] + type_node = None + + for e in tree.getroot(): + if e.tag == "{%s}types" % ns_wsdl: + assert type_node is None + type_node = e + + else: + l0.append(e) + e.getparent().remove(e) + + 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): + nodes = [] + for p in e.getchildren(): + nodes.append(p) + + nodes.sort(key=lambda e: e.attrib.get('name', '0')) + + for p in nodes: + e.append(p) + + schemas = [] + + for e in type_node: + schemas.append(e) + e.getparent().remove(e) + + schemas.sort(key=lambda e: e.attrib["targetNamespace"]) + + for s in schemas: + type_node.append(s) + + for s in schemas: + nodes = [] + for e in s: + nodes.append(e) + e.getparent().remove(e) + + nodes.sort(key=lambda e: (schema_order[e.tag], e.attrib.get('name', '\0'))) + + for e in nodes: + s.append(e) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/pym/calculate/contrib/spyne/test/sort_wsdl.pyc b/pym/calculate/contrib/spyne/test/sort_wsdl.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5813a7acd820cca1d409e771fd9e3b63b9e01204 GIT binary patch literal 3412 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 rB2pu2ZKg({* + 123456 + + """ + + _ = 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 + + +class TestMultipleMethods(unittest.TestCase): + def test_single_method(self): + try: + Application([MultipleMethods1, MultipleMethods2], 'tns', + in_protocol=Soap11(), out_protocol=Soap11()) + + except ValueError: + pass + + else: + raise Exception('must fail.') + + def test_simple_aux_nullserver(self): + data = [] + + class SomeService(Service): + @srpc(String) + def call(s): + data.append(s) + + class AuxService(Service): + __aux__ = SyncAuxProc() + + @srpc(String) + def call(s): + data.append(s) + + app = Application([SomeService, AuxService], 'tns', 'name', Soap11(), + Soap11()) + server = NullServer(app) + server.service.call("hey") + + assert data == ['hey', 'hey'] + + def test_namespace_in_message_name(self): + class S(Service): + @srpc(String, _in_message_name='{tns}inMessageName') + def call(s): + pass + + app = Application([S], 'tns', 'name', Soap11(), Soap11()) + + def test_simple_aux_wsgi(self): + data = [] + + class SomeService(Service): + @srpc(String, _returns=String) + def call(s): + data.append(s) + + class AuxService(Service): + __aux__ = SyncAuxProc() + + @srpc(String, _returns=String) + def call(s): + data.append(s) + + 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'] + + def test_thread_aux_wsgi(self): + import logging + logging.basicConfig(level=logging.DEBUG) + + data = set() + + class SomeService(Service): + @srpc(String, _returns=String) + def call(s): + data.add(s) + + class AuxService(Service): + __aux__ = ThreadAuxProc() + + @srpc(String, _returns=String) + def call(s): + data.add(s + "aux") + + 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") + + import time + time.sleep(1) + + 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): + pass + + @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.'") + + def __run_service(self, service): + 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")) + + elt = etree.fromstring(return_string) + print(etree.tostring(elt, pretty_print=True)) + + return elt, app.interface.nsmap + + def test_settings_headers_from_user_code(self): + class RespHeader(ComplexModel): + __namespace__ = 'tns' + Elem1 = String + + # test header in service definition + class SomeService(Service): + __out_header__ = RespHeader + + @rpc() + def some_call(ctx): + ctx.out_header = RespHeader() + 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' + + # test header in decorator + class SomeService(Service): + @rpc(_out_header=RespHeader) + def some_call(ctx): + ctx.out_header = RespHeader() + 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' + + # test no header + class SomeService(Service): + @rpc() + def some_call(ctx): + ctx.out_header = RespHeader() + ctx.out_header.Elem1 = 'Test1' + + elt, nsmap = self.__run_service(SomeService) + 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() + + 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() + 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') + def some_call(ctx, s): + assert s == 'abc' + + app = Application([SomeService], 'tns', in_protocol=Soap11(), + out_protocol=Soap11(cleanup_namespaces=True)) + + req = b""" + + + abc + + + """ + + server = WsgiApplication(app) + resp = etree.fromstring(b''.join(server({ + 'QUERY_STRING': '', + 'PATH_INFO': '/call', + 'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'text/xml; charset=utf8', + 'SERVER_NAME': 'localhost', + 'wsgi.input': BytesIO(req), + }, start_response, "http://null"))) + + print(etree.tostring(resp, pretty_print=True)) + + assert resp[0].tag == '{http://schemas.xmlsoap.org/soap/envelope/}Body' + assert len(resp[0]) == 1 + assert resp[0][0].tag == '{tns}some_call' + RESPONSE_SUFFIX + assert len(resp[0][0]) == 0 + + def test_soap_bare_empty_input(self): + class SomeService(Service): + + @rpc(_body_style='bare', _returns=String) + def some_call(ctx): + return 'abc' + + app = Application([SomeService], 'tns', in_protocol=Soap11(), + out_protocol=Soap11(cleanup_namespaces=True)) + + req = b""" + + + + + + """ + + server = WsgiApplication(app) + resp = etree.fromstring(b''.join(server({ + 'QUERY_STRING': '', + 'PATH_INFO': '/call', + 'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'text/xml; charset=utf8', + 'SERVER_NAME': 'localhost', + 'wsgi.input': BytesIO(req) + }, start_response, "http://null"))) + + print(etree.tostring(resp, pretty_print=True)) + + assert resp[0].tag == '{http://schemas.xmlsoap.org/soap/envelope/}Body' + assert resp[0][0].tag == '{tns}some_call' + RESPONSE_SUFFIX + assert resp[0][0].text == 'abc' + + def test_soap_bare_empty_model_input_method_name(self): + class EmptyRequest(ComplexModel): + pass + + try: + class SomeService(Service): + @rpc(EmptyRequest, _body_style='bare', _returns=String) + def some_call(ctx, request): + return 'abc' + except Exception: + pass + else: + raise Exception("Must fail with exception: body_style='bare' does " + "not allow empty model as param") + + def test_implicit_class_conflict(self): + class someCallResponse(ComplexModel): + __namespace__ = 'tns' + s = String + + class SomeService(Service): + @rpc(someCallResponse, _returns=String) + def someCall(ctx, x): + return ['abc', 'def'] + + try: + Application([SomeService], 'tns', in_protocol=Soap11(), + out_protocol=Soap11(cleanup_namespaces=True)) + except ValueError as e: + print(e) + else: + raise Exception("must fail.") + + def test_soap_bare_wrapped_array_output(self): + class SomeService(Service): + @rpc(_body_style='bare', _returns=Array(String)) + def some_call(ctx): + return ['abc', 'def'] + + app = Application([SomeService], 'tns', in_protocol=Soap11(), + out_protocol=Soap11(cleanup_namespaces=True)) + + req = b""" + + + + + + """ + + server = WsgiApplication(app) + resp = etree.fromstring(b''.join(server({ + 'QUERY_STRING': '', + 'PATH_INFO': '/call', + 'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'text/xml; charset=utf8', + 'wsgi.input': BytesIO(req) + }, start_response, "http://null"))) + + print(etree.tostring(resp, pretty_print=True)) + + assert resp[0].tag == '{http://schemas.xmlsoap.org/soap/envelope/}Body' + assert resp[0][0].tag == '{tns}some_call' + RESPONSE_SUFFIX + assert resp[0][0][0].text == 'abc' + assert resp[0][0][1].text == 'def' + + def test_array_iterable(self): + class SomeService(Service): + @rpc(Array(Unicode), Iterable(Unicode)) + def some_call(ctx, a, b): + pass + + app = Application([SomeService], 'tns', in_protocol=Soap11(), + out_protocol=Soap11(cleanup_namespaces=True)) + + server = WsgiApplication(app) + + def test_invalid_self_reference(self): + try: + class SomeService(Service): + @rpc(_returns=SelfReference) + def method(ctx): + pass + except LogicError: + pass + else: + raise Exception("Must fail with: " + "'SelfReference can't be used inside @rpc and its ilk'") + + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/test_service.pyc b/pym/calculate/contrib/spyne/test/test_service.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0381ad652484c49f7eb888fbfd0400281df9d831 GIT binary patch literal 25350 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/test_soft_validation.py b/pym/calculate/contrib/spyne/test/test_soft_validation.py new file mode 100644 index 0000000..2177bd7 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/test_soft_validation.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +# +# Most of the service tests are performed through the interop tests. +# + +import unittest + +from spyne.application import Application +from spyne.decorator import srpc +from spyne.error import ValidationError +from spyne.service import Service +from spyne.protocol.http import HttpRpc +from spyne.protocol.soap import Soap11 +from spyne.model.primitive import Integer +from spyne.model.primitive import String +from spyne.server import ServerBase +from spyne.server.wsgi import WsgiApplication + +from spyne import MethodContext +from spyne.server.wsgi import WsgiMethodContext + +Application.transport = 'test' + + +class TestValidationString(unittest.TestCase): + def test_min_len(self): + StrictType = String(min_len=3) + + self.assertEqual(StrictType.validate_string(StrictType, 'aaa'), True) + self.assertEqual(StrictType.validate_string(StrictType, 'a'), False) + + def test_max_len(self): + StrictType = String(max_len=3) + + self.assertEqual(StrictType.validate_string(StrictType, 'a'), True) + self.assertEqual(StrictType.validate_string(StrictType, 'aaa'), True) + self.assertEqual(StrictType.validate_string(StrictType, 'aaaa'), False) + + def test_pattern(self): + # Pattern match needs to be checked after the string is decoded, that's + # why we need to use validate_native here. + StrictType = String(pattern='[a-z]') + + self.assertEqual(StrictType.validate_native(StrictType, 'a'), True) + self.assertEqual(StrictType.validate_native(StrictType, 'a1'), False) + self.assertEqual(StrictType.validate_native(StrictType, '1'), False) + + +class TestValidationInteger(unittest.TestCase): + def test_lt(self): + StrictType = Integer(lt=3) + + self.assertEqual(StrictType.validate_native(StrictType, 2), True) + self.assertEqual(StrictType.validate_native(StrictType, 3), False) + + def test_le(self): + StrictType = Integer(le=3) + + self.assertEqual(StrictType.validate_native(StrictType, 2), True) + self.assertEqual(StrictType.validate_native(StrictType, 3), True) + self.assertEqual(StrictType.validate_native(StrictType, 4), False) + + def test_gt(self): + StrictType = Integer(gt=3) + + self.assertEqual(StrictType.validate_native(StrictType, 4), True) + self.assertEqual(StrictType.validate_native(StrictType, 3), False) + + def test_ge(self): + StrictType = Integer(ge=3) + + self.assertEqual(StrictType.validate_native(StrictType, 3), True) + self.assertEqual(StrictType.validate_native(StrictType, 2), False) + +class TestHttpRpcSoftValidation(unittest.TestCase): + def setUp(self): + class SomeService(Service): + @srpc(String(pattern='a')) + def some_method(s): + pass + @srpc(String(pattern='a', max_occurs=2)) + def some_other_method(s): + pass + + self.application = Application([SomeService], + in_protocol=HttpRpc(validator='soft'), + out_protocol=Soap11(), + name='Service', tns='tns', + ) + + + def __get_ctx(self, mn, qs): + server = WsgiApplication(self.application) + ctx = WsgiMethodContext(server, { + 'QUERY_STRING': qs, + 'PATH_INFO': '/%s' % mn, + 'REQUEST_METHOD': "GET", + 'SERVER_NAME': 'localhost', + }, 'some-content-type') + + ctx, = server.generate_contexts(ctx) + server.get_in_object(ctx) + + return ctx + + def test_http_rpc(self): + ctx = self.__get_ctx('some_method', 's=1') + self.assertEqual(ctx.in_error.faultcode, 'Client.ValidationError') + + ctx = self.__get_ctx('some_method', 's=a') + self.assertEqual(ctx.in_error, None) + + ctx = self.__get_ctx('some_other_method', 's=1') + self.assertEqual(ctx.in_error.faultcode, 'Client.ValidationError') + ctx = self.__get_ctx('some_other_method', 's=1&s=2') + self.assertEqual(ctx.in_error.faultcode, 'Client.ValidationError') + ctx = self.__get_ctx('some_other_method', 's=1&s=2&s=3') + self.assertEqual(ctx.in_error.faultcode, 'Client.ValidationError') + ctx = self.__get_ctx('some_other_method', 's=a&s=a&s=a') + self.assertEqual(ctx.in_error.faultcode, 'Client.ValidationError') + + ctx = self.__get_ctx('some_other_method', 's=a&s=a') + self.assertEqual(ctx.in_error, None) + ctx = self.__get_ctx('some_other_method', 's=a') + self.assertEqual(ctx.in_error, None) + ctx = self.__get_ctx('some_other_method', '') + self.assertEqual(ctx.in_error, None) + +class TestSoap11SoftValidation(unittest.TestCase): + def test_basic(self): + class SomeService(Service): + @srpc(String(pattern='a')) + def some_method(s): + pass + + application = Application([SomeService], + in_protocol=Soap11(validator='soft'), + out_protocol=Soap11(), + name='Service', tns='tns', + ) + server = ServerBase(application) + + ctx = MethodContext(server, MethodContext.SERVER) + ctx.in_string = [u""" + + + + OK + + + + """] + + ctx, = server.generate_contexts(ctx) + server.get_in_object(ctx) + + self.assertEqual(isinstance(ctx.in_error, ValidationError), True) + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/test_soft_validation.pyc b/pym/calculate/contrib/spyne/test/test_soft_validation.pyc new file mode 100644 index 0000000000000000000000000000000000000000..837fbae3043da440012d57d1d33384b23f2d4e8d GIT binary patch literal 8120 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/test_sqlalchemy.py b/pym/calculate/contrib/spyne/test/test_sqlalchemy.py new file mode 100644 index 0000000..9d7af0d --- /dev/null +++ b/pym/calculate/contrib/spyne/test/test_sqlalchemy.py @@ -0,0 +1,1302 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +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 +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 spyne.model.binary import HybridFileStore +from spyne.model.complex import xml +from spyne.model.complex import table + +from spyne.store.relational import get_pk_columns +from spyne.store.relational.document import PGJsonB, PGJson, PGFileJson, \ + PGObjectJson + +TableModel = TTableModel() + + +class TestSqlAlchemyTypeMappings(unittest.TestCase): + def test_init(self): + fn = inspect.stack()[0][3] + from sqlalchemy.inspection import inspect as sqla_inspect + + class SomeClass1(TableModel): + __tablename__ = "%s_%d" % (fn, 1) + i = Integer32(pk=True) + 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() + + def test_bool(self): + fn = inspect.stack()[0][3] + + class SomeClass1(TableModel): + __tablename__ = "%s_%d" % (fn, 1) + i = Integer32(pk=True) + b = 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) + + def test_jsonb(self): + fn = inspect.stack()[0][3] + + class SomeClass1(TableModel): + __tablename__ = "%s_%d" % (fn, 1) + i = Integer32(pk=True) + 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') + + 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')) + + assert isinstance(SomeClass3.Attributes.sqla_table.c.a.type, PGFileJson) + assert SomeClass3.Attributes.sqla_table.c.a.type.dbt == 'jsonb' + + def test_obj_json(self): + fn = inspect.stack()[0][3] + + class SomeClass(ComplexModel): + s = Unicode + d = Double + + class SomeClass1(TableModel): + __tablename__ = "%s_%d" % (fn, 1) + _type_info = [ + ('i', Integer32(pk=True)), + ('a', Array(SomeClass, store_as='json')), + ] + + 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') + + assert isinstance(SomeClass2.Attributes.sqla_table.c.a.type, + PGObjectJson) + + +class TestSqlAlchemySchema(unittest.TestCase): + def setUp(self): + logging.getLogger('sqlalchemy').setLevel(logging.DEBUG) + + self.engine = create_engine('sqlite:///:memory:') + self.session = sessionmaker(bind=self.engine)() + self.metadata = TableModel.Attributes.sqla_metadata = MetaData() + self.metadata.bind = self.engine + logging.info('Testing against sqlalchemy-%s', sqlalchemy.__version__) + + def test_obj_json_dirty(self): + fn = inspect.stack()[0][3] + + class SomeClass(ComplexModel): + s = Unicode + d = Double + + class SomeClass1(TableModel): + __tablename__ = "%s_%d" % (fn, 1) + _type_info = [ + ('i', Integer32(pk=True)), + ('a', SomeClass.store_as('jsonb')), + ] + + self.metadata.create_all() + + sc1 = SomeClass1(i=5, a=SomeClass(s="s", d=42.0)) + self.session.add(sc1) + self.session.commit() + + from sqlalchemy.orm.attributes import flag_modified + + # TODO: maybe do the flag_modified() on setitem? + sc1.a.s = "ss" + flag_modified(sc1, 'a') + + assert sc1 in self.session.dirty + + self.session.commit() + 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 + + def test_schema(self): + class SomeClass(TableModel): + __tablename__ = 'some_class' + __table_args__ = {"sqlite_autoincrement": True} + + id = Integer32(primary_key=True, autoincrement=False) + s = Unicode(64, unique=True) + i = Integer32(64, index=True) + + t = SomeClass.__table__ + self.metadata.create_all() # 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 idx.unique + + def test_colname_simple(self): + class SomeClass(TableModel): + __tablename__ = 'some_class' + __table_args__ = {"sqlite_autoincrement": True} + + id = Integer32(primary_key=True, autoincrement=False) + s = Unicode(64, sqla_column_args=dict(name='ss')) + + t = SomeClass.__table__ + self.metadata.create_all() # not needed, just nice to see. + + assert 'ss' in t.c + + def test_colname_complex_table(self): + class SomeOtherClass(TableModel): + __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}, + ) + + id = Integer32(primary_key=True) + 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. + + assert 'oo_id' in t.c + + def test_colname_complex_json(self): + class SomeOtherClass(TableModel): + __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}, + ) + + id = Integer32(primary_key=True) + 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. + + assert 'oo' in t.c + + def test_nested_sql(self): + class SomeOtherClass(TableModel): + __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}, + ) + + id = Integer32(primary_key=True) + o = SomeOtherClass.customize(store_as='table') + + self.metadata.create_all() + + 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) + print(sc_db) + 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) + 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' + __table_args__ = {"sqlite_autoincrement": True} + + id = Integer32(primary_key=True) + s = Unicode(64) + + class SomeClass(TableModel): + __tablename__ = 'some_class' + __table_args__ = {"sqlite_autoincrement": True} + + id = Integer32(primary_key=True) + others = Array(SomeOtherClass, store_as='table') + + self.metadata.create_all() + + 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) + + 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' + __table_args__ = {"sqlite_autoincrement": True} + + id = Integer32(primary_key=True) + s = Unicode(64) + + class SomeClass(TableModel): + __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() + + 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) + + 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' + __table_args__ = {"sqlite_autoincrement": True} + + id = Integer32(primary_key=True) + s = Unicode(64) + + class SomeClass(TableModel): + __tablename__ = 'some_class' + __table_args__ = {"sqlite_autoincrement": True} + + id = Integer32(primary_key=True) + others = Array(SomeOtherClass, + store_as=table(multi=True, backref='some_classes')) + + self.metadata.create_all() + + soc1 = SomeOtherClass(s='ehe1') + soc2 = SomeOtherClass(s='ehe2') + sc = SomeClass(others=[soc1, soc2]) + + self.session.add(sc) + self.session.commit() + self.session.close() + + soc_db = self.session.query(SomeOtherClass).all() + + assert soc_db[0].some_classes[0].id == 1 + assert soc_db[1].some_classes[0].id == 1 + + self.session.close() + + def test_nested_sql_array_as_xml(self): + class SomeOtherClass(ComplexModel): + id = Integer32 + s = Unicode(64) + + class SomeClass(TableModel): + __tablename__ = 'some_class' + __table_args__ = {"sqlite_autoincrement": True} + + id = Integer32(primary_key=True) + others = Array(SomeOtherClass, store_as='xml') + + self.metadata.create_all() + + 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) + + assert sc_db.others[0].s == 'ehe1' + assert sc_db.others[1].s == 'ehe2' + + self.session.close() + + def test_nested_sql_array_as_xml_no_ns(self): + class SomeOtherClass(ComplexModel): + id = Integer32 + s = Unicode(64) + + class SomeClass(TableModel): + __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() + + 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] + + from lxml import etree + assert etree.fromstring(sc_xml).tag == 'SomeOtherClassArray' + + self.session.close() + + def test_inheritance(self): + class SomeOtherClass(TableModel): + __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')) + + self.metadata.create_all() + + 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) + assert sc_db.numbers == [1, 2, 3, 4] + self.session.close() + + sc_db = self.session.query(SomeOtherClass).get(5) + assert sc_db.id == 5 + try: + sc_db.numbers + except AttributeError: + pass + else: + raise Exception("must fail") + + self.session.close() + + def test_inheritance_with_complex_fields(self): + class Foo(TableModel): + __tablename__ = 'foo' + __table_args__ = {"sqlite_autoincrement": True} + + id = Integer32(primary_key=True) + s = Unicode(64) + + class Bar(TableModel): + __tablename__ = 'bar' + __table_args__ = {"sqlite_autoincrement": True} + __mapper_args__ = { + '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') + + class SubBar(Bar): + __mapper_args__ = { + 'polymorphic_identity': 'subbar', + } + i = Integer32 + + sqlalchemy.orm.configure_mappers() + + mapper_subbar = SubBar.Attributes.sqla_mapper + mapper_bar = Bar.Attributes.sqla_mapper + 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") + + def test_mixins_with_complex_fields(self): + class Foo(TableModel): + __tablename__ = 'foo' + __table_args__ = {"sqlite_autoincrement": True} + + id = Integer32(primary_key=True) + s = Unicode(64) + + class Bar(TableModel): + __tablename__ = 'bar' + __table_args__ = {"sqlite_autoincrement": True} + __mixin__ = True + __mapper_args__ = { + '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') + + class SubBar(Bar): + __mapper_args__ = { + 'polymorphic_identity': 'subbar', + } + i = Integer32 + + sqlalchemy.orm.configure_mappers() + + mapper_subbar = SubBar.Attributes.sqla_mapper + mapper_bar = Bar.Attributes.sqla_mapper + 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") + + def test_sqlalchemy_inheritance(self): + # no spyne code is involved here. + # this is just to test test the sqlalchemy behavior that we rely on. + + class Employee(object): + def __init__(self, name): + self.name = name + + def __repr__(self): + return self.__class__.__name__ + " " + self.name + + class Manager(Employee): + def __init__(self, name, manager_data): + self.name = name + self.manager_data = manager_data + + def __repr__(self): + return ( + self.__class__.__name__ + " " + + self.name + " " + self.manager_data + ) + + class Engineer(Employee): + def __init__(self, name, engineer_info): + self.name = name + self.engineer_info = engineer_info + + def __repr__(self): + return ( + 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), + ) + + employee_mapper = mapper(Employee, employees_table, + polymorphic_on=employees_table.c.type, + polymorphic_identity='employee') + + manager_mapper = mapper(Manager, inherits=employee_mapper, + polymorphic_identity='manager') + + engineer_mapper = mapper(Engineer, inherits=employee_mapper, + polymorphic_identity='engineer') + + self.metadata.create_all() + + 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' + + def test_inheritance_polymorphic_with_non_nullables_in_subclasses(self): + class SomeOtherClass(TableModel): + __tablename__ = 'some_other_class' + __table_args__ = {"sqlite_autoincrement": True} + __mapper_args__ = {'polymorphic_on': 't', 'polymorphic_identity': 1} + + id = Integer32(primary_key=True) + t = Integer32(nillable=False) + s = Unicode(64, nillable=False) + + class SomeClass(SomeOtherClass): + __mapper_args__ = ( + (), + {'polymorphic_identity': 2}, + ) + + i = Integer(nillable=False) + + self.metadata.create_all() + + assert SomeOtherClass.__table__.c.s.nullable == False + + # this should be nullable to let other classes be added. + # spyne still checks this constraint when doing input validation. + # spyne should generate a constraint to check this at database level as + # well. + assert SomeOtherClass.__table__.c.i.nullable == True + + soc = SomeOtherClass(s='s') + self.session.add(soc) + self.session.commit() + soc_id = soc.id + + try: + sc = SomeClass(i=5) + self.session.add(sc) + self.session.commit() + except IntegrityError: + self.session.rollback() + else: + raise Exception("Must fail with IntegrityError.") + + 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 + + self.session.close() + + def test_inheritance_polymorphic(self): + class SomeOtherClass(TableModel): + __tablename__ = 'some_class' + __table_args__ = {"sqlite_autoincrement": True} + __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')) + + self.metadata.create_all() + + 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 + self.session.close() + + def test_nested_sql_array_as_json(self): + class SomeOtherClass(ComplexModel): + id = Integer32 + s = Unicode(64) + + class SomeClass(TableModel): + __tablename__ = 'some_class' + __table_args__ = {"sqlite_autoincrement": True} + + id = Integer32(primary_key=True) + others = Array(SomeOtherClass, store_as='json') + + self.metadata.create_all() + + 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) + + 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' + __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.session.commit() + self.session.expunge_all() + + ret = self.session.query(SomeClass).get(1) + assert ret.i == 1 # redundant + assert ret.s == 's' + + def test_default_ctor(self): + class SomeOtherClass(ComplexModel): + id = Integer32 + s = Unicode(64) + + class SomeClass(TableModel): + __tablename__ = 'some_class' + __table_args__ = {"sqlite_autoincrement": True} + + id = Integer32(primary_key=True) + others = Array(SomeOtherClass, store_as='json') + f = Unicode(32, default='uuu') + + self.metadata.create_all() + self.session.add(SomeClass()) + self.session.commit() + self.session.expunge_all() + + assert self.session.query(SomeClass).get(1).f == 'uuu' + + def test_default_value(self): + class SomeClass(TableModel): + __tablename__ = 'some_class' + __table_args__ = {"sqlite_autoincrement": True} + + id = Integer32(primary_key=True) + f = Unicode(32, db_default=u'uuu') + + self.metadata.create_all() + val = SomeClass() + assert val.f is None + + self.session.add(val) + self.session.commit() + + self.session.expunge_all() + + assert self.session.query(SomeClass).get(1).f == u'uuu' + + def test_default_ctor_with_sql_relationship(self): + class SomeOtherClass(TableModel): + __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} + + id = Integer32(primary_key=True) + o = SomeOtherClass.customize(store_as='table') + + self.metadata.create_all() + self.session.add(SomeClass()) + self.session.commit() + + def test_store_as_index(self): + class SomeOtherClass(TableModel): + __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} + + id = Integer32(primary_key=True) + o = SomeOtherClass.customize(store_as='table', index='btree') + + self.metadata.create_all() + idx, = SomeClass.__table__.indexes + assert 'o_id' in idx.columns + + def test_scalar_collection(self): + class SomeClass(TableModel): + __tablename__ = 'some_class' + + id = Integer32(primary_key=True) + values = Array(Unicode).store_as('table') + + self.metadata.create_all() + + 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'] + del sc + + sc = self.session.query(SomeClass).get(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.query(SomeClass).get(1) + sc.values = sc.values[1:] + self.session.commit() + del sc + sc = self.session.query(SomeClass).get(1) + assert sc.values == ['b', 'c', 'd'] + + def test_multiple_fk(self): + class SomeChildClass(TableModel): + __tablename__ = 'some_child_class' + + id = Integer32(primary_key=True) + s = Unicode(64) + i = Integer32 + + class SomeClass(TableModel): + __tablename__ = 'some_class' + + id = Integer32(primary_key=True) + children = Array(SomeChildClass).store_as('table') + mirror = SomeChildClass.store_as('table') + + self.metadata.create_all() + + children = [ + SomeChildClass(s='p', i=600), + SomeChildClass(s='|', i=10), + SomeChildClass(s='q', i=9), + ] + + sc = SomeClass(children=children) + self.session.add(sc) + self.session.flush() + sc.mirror = children[1] + self.session.commit() + del sc + + sc = self.session.query(SomeClass).get(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' + + id = Integer32(primary_key=True) + s = Unicode(64) + i = Integer32 + + class SomeClass(TableModel): + __tablename__ = 'some_class' + + id = Integer32(primary_key=True) + child_id = Integer32(fk='some_child_class.id') + + foreign_keys = SomeClass.__table__.c['child_id'].foreign_keys + assert len(foreign_keys) == 1 + fk, = foreign_keys + assert fk._colspec == 'some_child_class.id' + + def test_multirel_single_table(self): + class SomeChildClass(TableModel): + __tablename__ = 'some_child_class' + + id = Integer32(primary_key=True) + s = Unicode(64) + + class SomeOtherChildClass(TableModel): + __tablename__ = 'some_other_child_class' + + id = Integer32(primary_key=True) + i = Integer32 + + class SomeClass(TableModel): + __tablename__ = 'some_class' + + id = Integer32(primary_key=True) + + children = Array(SomeChildClass, + store_as=table( + multi='children', lazy='joined', + left='parent_id', right='child_id', + fk_left_ondelete='cascade', + fk_right_ondelete='cascade', + ), + ) + + 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', + ), + ) + + t = SomeClass.Attributes.sqla_metadata.tables['children'] + + 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' + + 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' + + id = Integer32(primary_key=True) + s = Unicode(32) + + TableModel.Attributes.sqla_metadata.create_all() + + # 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() + + # convert sqla info to spyne info + class Reflected(TM2): + __table__ = TM2.Attributes.sqla_metadata.tables['some_class'] + + pprint(dict(Reflected._type_info).items()) + assert issubclass(Reflected._type_info['id'], Integer) + + # this looks at spyne attrs + 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 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' + id = Integer32(pk=True) + i = Integer32 + s = Unicode(32) + + class SomeTableSubset(TableModel): + __table__ = SomeTable.__table__ + + id = Integer32(pk=True) # sqla session doesn't work without pk + i = Integer32 + + class SomeTableOtherSubset(TableModel): + __table__ = SomeTable.__table__ + _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.commit() + + st = self.session.query(SomeTable).get(1) + sts = self.session.query(SomeTableSubset).get(1) + stos = self.session.query(SomeTableOtherSubset).get(1) + + sts.i = 3 + sts.s = 'ss' # will not be flushed to db + self.session.commit() + + assert st.s == 's' + assert stos.i == 3 + + def test_file_storage(self): + class C(TableModel): + __tablename__ = "c" + + id = Integer32(pk=True) + 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.session.add(c) + self.session.flush() + self.session.commit() + + c = self.session.query(C).get(1) + print(c) + assert c.f.name == "name" + assert c.f.type == "type" + assert c.f.data[0][:] == b"data" + + def test_append_field_complex_existing_column(self): + class C(TableModel): + __tablename__ = "c" + u = Unicode(pk=True) + + class D(TableModel): + __tablename__ = "d" + d = Integer32(pk=True) + c = C.store_as('table') + + 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): + __tablename__ = "c" + u = Unicode(pk=True) + + class D(C): + i = Integer32 + + C.append_field('d', DateTime) + + assert D.Attributes.sqla_mapper.has_property('d') + + def _test_append_field_complex_explicit_existing_column(self): + # FIXME: Test something! + + class C(TableModel): + __tablename__ = "c" + id = Integer32(pk=True) + + # c already also produces c_id. this is undefined behaviour, one of them + # gets ignored, whichever comes first. + class D(TableModel): + __tablename__ = "d" + id = Integer32(pk=True) + c = C.store_as('table') + c_id = Integer32(15) + + def test_append_field_complex_circular_array(self): + class C(TableModel): + __tablename__ = "cc" + id = Integer32(pk=True) + + class D(TableModel): + __tablename__ = "dd" + id = Integer32(pk=True) + 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() + + c1, c2 = C(id=1), C(id=2) + d = D(id=1, c=[c1, c2]) + self.session.add(d) + self.session.commit() + assert c1.d.id == 1 + + def test_append_field_complex_new_column(self): + class C(TableModel): + __tablename__ = "c" + u = Unicode(pk=True) + + 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) + + def test_append_field_array(self): + class C(TableModel): + __tablename__ = "c" + id = Integer32(pk=True) + + 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 + print(repr(D.Attributes.sqla_table)) + assert isinstance(D.Attributes.sqla_table.c['c_id'].type, + sqlalchemy.Integer) + + def test_append_field_array_many(self): + class C(TableModel): + __tablename__ = "c" + id = Integer32(pk=True) + + 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 + + def test_append_field_complex_cust(self): + class C(TableModel): + __tablename__ = "c" + id = Integer32(pk=True) + + 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 + + def _test_append_field_cust(self): + class C(TableModel): + __tablename__ = "c" + id = Integer32(pk=True) + + C2 = C.customize() + + C.append_field("s", Unicode) + + C() + + self.metadata.create_all() + + assert "s" in C2._type_info + assert "s" in C2.Attributes.sqla_mapper.columns + + self.session.add(C2(s='foo')) + self.session.commit() + 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, + } + + id = Integer32(pk=True) + t = M(Integer32) + + class D(C): + __mapper_args__ = { + 'polymorphic_identity': 2, + } + d = Unicode + + D2 = D.customize() + + assert C().t == 1 + assert D().t == 2 + + # That's the way SQLAlchemy works. Don't use customized classes in + # anywhere other than interface definitions + assert D2().t == None + + def test_base_append_simple(self): + class B(TableModel): + __tablename__ = 'b' + __mapper_args__ = { + 'polymorphic_on': 't', + 'polymorphic_identity': 1, + } + + id = Integer32(pk=True) + t = M(Integer32) + + class C(B): + __mapper_args__ = { + 'polymorphic_identity': 1, + } + s = Unicode + + B.append_field('i', Integer32) + + self.metadata.create_all() + + self.session.add(C(s="foo", i=42)) + self.session.commit() + + c = self.session.query(C).first() + + assert c.s == 'foo' + assert c.i == 42 + assert c.t == 1 + + def test_base_append_complex(self): + class B(TableModel): + __tablename__ = 'b' + __mapper_args__ = { + 'polymorphic_on': 't', + 'polymorphic_identity': 1, + } + + id = Integer32(pk=True) + t = M(Integer32) + + class C(B): + __mapper_args__ = { + 'polymorphic_identity': 1, + } + s = Unicode + + class D(TableModel): + __tablename__ = 'd' + id = Integer32(pk=True) + i = M(Integer32) + + B.append_field('d', D.store_as('table')) + + self.metadata.create_all() + + self.session.add(C(d=D(i=42))) + self.session.commit() + + c = self.session.query(C).first() + + assert c.d.i == 42 + + +class TestSqlAlchemySchemaWithPostgresql(unittest.TestCase): + def setUp(self): + self.metadata = TableModel.Attributes.sqla_metadata = MetaData() + + def test_enum(self): + table_name = "test_enum" + + enums = ('SUBSCRIBED', 'UNSUBSCRIBED', 'UNCONFIRMED') + + class SomeClass(TableModel): + __tablename__ = table_name + + id = Integer32(primary_key=True) + e = Enum(*enums, type_name='status_choices') + + t = self.metadata.tables[table_name] + assert 'e' in t.c + assert tuple(t.c.e.type.enums) == enums + + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/test_sqlalchemy.pyc b/pym/calculate/contrib/spyne/test/test_sqlalchemy.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0cc8819ee94077dcfcf309c3ebe45fad55a9015 GIT binary patch literal 57549 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/transport/__init__.py b/pym/calculate/contrib/spyne/test/transport/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pym/calculate/contrib/spyne/test/transport/__init__.pyc b/pym/calculate/contrib/spyne/test/transport/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a753cd365712f51b60d57816a4e706a976106d7 GIT binary patch literal 178 zcmZSn%**xW&fbJ%1}I6aE4>E~o7nVIMp zRF-7q=Najl>lbI1r0NzVCTAz6rxxoM7gXk@>Kf@88tWOF=@wK1Rp_Orr$fZ`OHzwV r^h=5o^NI`di%Rt4<1_OzOXB18fTnQ(&9}+TPbtkwwF9}L1c(^`Lh&no literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/transport/test_msgpack.py b/pym/calculate/contrib/spyne/test/transport/test_msgpack.py new file mode 100644 index 0000000..c94174a --- /dev/null +++ b/pym/calculate/contrib/spyne/test/transport/test_msgpack.py @@ -0,0 +1,94 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +import msgpack + +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 + from spyne.server.msgpack import MessagePackServerBase + + prot = TwistedMessagePackProtocol(MessagePackServerBase(app)) + transport = StringTransportWithDisconnection() + prot.makeConnection(transport) + transport.protocol = prot + + return prot + + 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()) + + prot = self.gen_prot(app) + request = msgpack.packb({'yay': [v]}) + prot.dataReceived(msgpack.packb([1, request])) + val = prot.transport.value() + print(repr(val)) + val = msgpack.unpackb(val) + print(repr(val)) + + self.assertEqual(val, [0, msgpack.packb(v)]) + + 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()) + + prot = self.gen_prot(app) + request = msgpack.packb({'yay': [v]}) + def _ccb(_): + val = prot.transport.value() + print(repr(val)) + val = msgpack.unpackb(val) + print(repr(val)) + + self.assertEqual(val, [0, msgpack.packb(v)]) + + prot.dataReceived(msgpack.packb([1, request])) + + return p_ctx[0].out_object[0].addCallback(_ccb) + diff --git a/pym/calculate/contrib/spyne/test/transport/test_msgpack.pyc b/pym/calculate/contrib/spyne/test/transport/test_msgpack.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7463f8da560f090b0818574a82aac939b81fe78b GIT binary patch literal 4220 zcmc&%%W@k<6umQg*ph7=0to~R9b0yM0GxAMvK1F=G4`~&`*!!eef!*VdrE&V)&KhAx9<}fKPCKr zj<*=0Nbw&?Ph`v2L+J(54`nNqeo3}U(l5(aSptqLNv|UPs%%w#yDYsq>Cem7yl+>e zSCf8Sw(4kC#nz>}AUlDibMj2&smOO*i`3R?%tLeMA3PfkTH_W_d@&sMI!Ww0gUrpL z-Lm;^C$WwL@?p{lIFN#GvraNdt?zgV9pBiZh}-r-oIJieNJf2|IWMG|QPy$J7S3Hj zV-uCB(Ntmc1Ok1i;SS#78VU=Sz;vPMa0bj~r6g&nm9m(Y+Ma|MOtWa`I^F^^IUEDw z)_x!dA>4sB+^0@GDET(rSC)Q74&dJXQ1;8RAIMYvKd8uli5@$s%6>(vgto-CP^)xkrQSM)Q-kqT}o;_XC6#Yr5gp8_nw6Th(BL>8ioMezDO4(FolK6;>yykNCy)Goj51A zC;+%1z)TgV^F&!2%PA%U%I2gyKgK0o=|TC`eU7h>TR`lTgnAb!No(U(J;u2z!va`r z)Um&fqKa}aj^n*6$_A}L-;Nm|fkYo3;+gogp;*Ku!j)TNm^}m21f(p)Cqq-c9_7}J z@~qHcWiOrF!dq}nnAB3pZ+JlHv=Rh~`w`9shs+o#)V&w)t>UMkF%oL1`>jM-+_zEW z=(Z^857JQ&O~Y}96V0nAP7T)DEZ}Vz#vkETldFM-qRR?B&W=YtX~->N%wXg+4A`Lt z1B*xrc%?zPVbic_ctVCWujD@tCr9dIRBr2XY3yQS6WiIfsX5QFl<&s9kp(u9KkP8q z>7&d~V#0|F5SP36WE6W6G0U7t#k;x}!|*gOvXilx+b1LD5&9S_pL%!}&Q%s9y+rw7 zl%?SB;RmpzAiYXZ4K7xe!5@p^a&ReF36_HezMf0y3EEG)i$76J=ceOvE}G<~W2^=m zIY!)z9D`E8CuK6up~xZ1lI$Sds`8W1=inrG`h-Nl7!G*~DiG~jA^U`Kq|5=5LS!C; zu;!&(Bl{dd4Rq8!`;_D`l*6(dR#eFXm4K^`LXwN0lP;3OPATaKvzO!&C`NxEEmKFU z!K5*r8T|pqi5uiTxiNZDyJPdOV~0d^%07DZ38eZEJdCVj4TaS!!5PXKJ0?_{19i+a z{TOCZr5*a8%Mr>2;{-E#Inp_F67~r$Qu+$8u_L`}&}k)Xh_g3N%pyp29WHo85@pYr zzEBfwn^#z4b0!d_iBYnBpZb)wg7z;z^ZE6*_c@)6+-$Q{w_`4%tu~quQS*I7wGZwH z>}%eqK)HZ>nZ-7gjlQHZnk(UQxD+V+noDRJ2HbygEq8Bdy&-LT!%>-y&7|IYR7Ss7 z1M@n53@>Qr4HnD@3B5=$`9QJr5EWntpz9*RBi0bixQ1%7M@}zEcXA_rUUC%h@_=!G zE=N@fT}0h8HlqB0NDy&oO38_wHswMP0W{JrSx08WPGVApC^^4=Ir0L?~vB!zRnoFOiIPVy` z!(2w8Ii9I8U0K;^=IMS6FNvhlYS5`Ww? m3}L+tZsJC;jxRE`=YQ~n8u6*WgMLO5(pXsxSM-zST6aE4>E~o7nVIMp zRF-7q=Najl>lbI1r0NzVCTAz6rxxoM7gXk@>Kf@88tWOF=@wK1Rp_Orr$fZ`OHzwV m^h--JbM)imGxIV_;^Xyz25|t5w#m&;Da}c>1391sh#3G&k|{|5 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/util/test_address.py b/pym/calculate/contrib/spyne/test/util/test_address.py new file mode 100644 index 0000000..04f8918 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/util/test_address.py @@ -0,0 +1,639 @@ +#!/usr/bin/env python +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +# The MIT License +# +# Copyright (c) Val Neekman @ Neekware Inc. http://neekware.com +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +from unittest import TestCase + + +from spyne.util.address import set_address_parser_settings + +set_address_parser_settings(trusted_proxies=['177.139.233.100']) + +from spyne.util.address import address_parser + + +class IPv4TestCase(TestCase): + """IP address Test""" + + def test_meta_none(self): + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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': '', + } + 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', + } + ip = address_parser.get_real_ip(request) + self.assertEqual(ip, None) + + def test_missing_x_forwarded(self): + request = { + '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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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': '', + } + 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', + } + ip = address_parser.get_real_ip(request) + self.assertEqual(ip, "177.139.233.139") + + +class IPv4TrustedProxiesTestCase(TestCase): + """Trusted Proxies - IP address Test""" + + def test_meta_none(self): + 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', + } + + ip = address_parser.get_trusted_ip(request) + self.assertEqual(ip, "198.84.193.157") + + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + ip = address_parser.get_trusted_ip(request, trusted_proxies=['177.139.233.139']) + self.assertEqual(ip, "198.84.193.156") + + +class IPv6TestCase(TestCase): + """IP address Test""" + + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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': '', + } + 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': '', + } + 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', + } + 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', + } + 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', + } + 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', + } + ip = address_parser.get_real_ip(request) + self.assertEqual(ip, "74dc::02ba") + + def test_private_remote_address(self): + request = { + '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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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', + } + 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': '', + } + 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', + } + ip = address_parser.get_real_ip(request) + self.assertEqual(ip, "74dc::02ba") + + +class IPv6TrustedProxiesTestCase(TestCase): + """Trusted Proxies - IP address Test""" + + def test_http_x_forwarded_for_no_proxy(self): + request = { + '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', + } + 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/pym/calculate/contrib/spyne/test/util/test_address.pyc b/pym/calculate/contrib/spyne/test/util/test_address.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c868f2edd731f76ab2e6b576c8dfe46531b25d7 GIT binary patch literal 27989 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/test/util/test_util.py b/pym/calculate/contrib/spyne/test/util/test_util.py new file mode 100644 index 0000000..3b8b5e7 --- /dev/null +++ b/pym/calculate/contrib/spyne/test/util/test_util.py @@ -0,0 +1,601 @@ +#!/usr/bin/env python + +from __future__ import print_function + +import json +import decimal +import unittest + +import pytz +import sqlalchemy + +from pprint import pprint +from decimal import Decimal as D +from datetime import datetime + +from lxml import etree + +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.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.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 + + +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__ + + +class TestTypeInfo(unittest.TestCase): + def test_insert(self): + d = TypeInfo() + + d['a'] = 1 + assert d[0] == d['a'] == 1 + + d.insert(0, ('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 + + 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 + + +class TestXml(unittest.TestCase): + def test_serialize(self): + + class C(ComplexModel): + __namespace__ = "tns" + i = Integer + s = Unicode + + c = C(i=5, s="x") + + ret = get_object_as_xml(c, C) + print(etree.tostring(ret)) + assert ret.tag == "{tns}C" + + ret = get_object_as_xml(c, C, "X") + print(etree.tostring(ret)) + assert ret.tag == "{tns}X" + + ret = get_object_as_xml(c, C, "X", no_namespace=True) + print(etree.tostring(ret)) + assert ret.tag == "X" + + ret = get_object_as_xml(c, C, no_namespace=True) + print(etree.tostring(ret)) + assert ret.tag == "C" + + def test_deserialize(self): + class Punk(ComplexModel): + __namespace__ = 'some_namespace' + + a = Unicode + b = Integer + c = Decimal + d = DateTime + + class Foo(ComplexModel): + __namespace__ = 'some_other_namespace' + + a = Unicode + b = Integer + c = Decimal + d = DateTime + e = XmlAttribute(Integer) + + 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 + ) + + 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' + 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() + + 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) + doc = get_object_as_xml(foo, Foo) + print(etree.tostring(doc, pretty_print=True)) + foo_back = get_xml_as_object(doc, Foo) + + assert foo_back == foo + + # as long as it doesn't fail, it's ok. + get_validation_schema([Punk, Foo]) + + +class TestCDict(unittest.TestCase): + def test_cdict(self): + from spyne.util.cdict import cdict + + class A(object): + pass + + class B(A): + pass + + class E(B): + pass + + class F(E): + pass + + class C(object): + pass + + d = cdict({A: "fun", F: 'zan'}) + + assert d[A] == 'fun' + assert d[B] == 'fun' + assert d[F] == 'zan' + try: + d[C] + except KeyError: + pass + else: + raise Exception("Must fail.") + + +class TestTDict(unittest.TestCase): + def test_tdict_notype(self): + d = tdict() + d[0] = 1 + assert d[0] == 1 + + d = tdict() + d.update({0:1}) + assert d[0] == 1 + + d = tdict.fromkeys([0], 1) + assert d[0] == 1 + + def test_tdict_k(self): + d = tdict(str) + try: + d[0] = 1 + except TypeError: + pass + else: + raise Exception("must fail") + + d = tdict(str) + d['s'] = 1 + assert d['s'] == 1 + + def test_tdict_v(self): + d = tdict(vt=str) + try: + d[0] = 1 + except TypeError: + pass + else: + raise Exception("must fail") + + d = tdict(vt=str) + d[0] = 's' + assert d[0] == 's' + + +class TestLogRepr(unittest.TestCase): + def test_log_repr_simple(self): + from spyne.model.complex import ComplexModel + from spyne.model.primitive import String + from spyne.util.web import log_repr + + class Z(ComplexModel): + z=String + + l = MAX_STRING_FIELD_LENGTH + 100 + print(log_repr(Z(z="a" * l))) + 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', (...)]" + + def test_log_repr_complex(self): + from spyne.model import ByteArray + from spyne.model import 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)), + ] + l = MAX_STRING_FIELD_LENGTH + 100 + 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', (...)])" + + def test_log_repr_dict_vanilla(self): + from spyne.model import AnyDict + from spyne.util.web import log_repr + + t = AnyDict + + assert log_repr({1: 1}, t) == "{1: 1}" + assert log_repr({1: 1, 2: 2}, t) == "{1: 1, 2: 2}" + assert log_repr({1: 1, 2: 2, 3: 3}, t) == "{1: 1, 2: 2, (...)}" + + assert log_repr([1], t) == "[1]" + assert log_repr([1, 2], t) == "[1, 2]" + assert log_repr([1, 2, 3], t) == "[1, 2, (...)]" + + def test_log_repr_dict_keys(self): + from spyne.model import AnyDict + from spyne.util.web import log_repr + + t = AnyDict(logged='keys') + + assert log_repr({1: 1}, t) == "{1: (...)}" + + assert log_repr([1], t) == "[1]" + + def test_log_repr_dict_values(self): + from spyne.model import AnyDict + from spyne.util.web import log_repr + + t = AnyDict(logged='values') + + assert log_repr({1: 1}, t) == "{(...): 1}" + + assert log_repr([1], t) == "[1]" + + def test_log_repr_dict_full(self): + from spyne.model import AnyDict + from spyne.util.web import log_repr + + 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]" + + 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') + + assert log_repr({1: 1, 2: 2, 3: 3}, t) == "{1: (...), 2: (...), 3: (...)}" + assert log_repr([1, 2, 3], t) == "[1, 2, 3]" + + 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') + + assert log_repr({1: 1, 2: 2, 3: 3}, t) == "{(...): 1, (...): 2, (...): 3}" + assert log_repr([1, 2, 3], t) == "[1, 2, 3]" + + +class TestDeserialize(unittest.TestCase): + def test_deserialize(self): + from spyne.protocol.soap import Soap11 + + class SomeService(Service): + @srpc(Integer, _returns=Iterable(Integer)) + def some_call(yo): + return range(yo) + + app = Application([SomeService], 'tns', in_protocol=Soap11(), + out_protocol=Soap11()) + + meat = 30 + + string = """ + + + + %s + + + + """ % meat + + obj = deserialize_request_string(string, app) + + assert obj.yo == meat + + +class TestEtreeDict(unittest.TestCase): + + longMessage = True + + 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") + + 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): + def test_the(self): + class C(ComplexModel): + __namespace__ = "tns" + i = Integer + s = Unicode + a = Array(DateTime) + + def __eq__(self, other): + print("Yaaay!") + 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)]) + + for iw, ca in ((False,dict), (True,dict), (False,list), (True, list)): + print() + 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) + print(o) + print(c) + assert o == c + + +class TestAttrDict(unittest.TestCase): + def test_attr_dict(self): + 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' + + +class TestYaml(unittest.TestCase): + def test_deser(self): + class C(ComplexModel): + a = Unicode + b = Decimal + + ret = get_object_as_yaml(C(a='burak', b=D(30)), C) + assert ret == b"""C: + a: burak + b: '30' +""" + + +class TestJson(unittest.TestCase): + def test_deser(self): + class C(ComplexModel): + _type_info = [ + ('a', Unicode), + ('b', Decimal), + ] + + 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"}') + + +class TestFifo(unittest.TestCase): + def test_msgpack_fifo(self): + import msgpack + + v1 = [1, 2, 3, 4] + v2 = [5, 6, 7, 8] + v3 = {b"a": 9, b"b": 10, b"c": 11} + + s1 = msgpack.packb(v1) + s2 = msgpack.packb(v2) + s3 = msgpack.packb(v3) + + unpacker = msgpack.Unpacker() + unpacker.feed(s1) + unpacker.feed(s2) + unpacker.feed(s3[:4]) + + assert next(iter(unpacker)) == v1 + assert next(iter(unpacker)) == v2 + try: + next(iter(unpacker)) + except StopIteration: + pass + else: + raise Exception("must fail") + + unpacker.feed(s3[4:]) + assert next(iter(unpacker)) == v3 + + +class TestTlist(unittest.TestCase): + def test_tlist(self): + tlist([], int) + + a = tlist([1, 2], int) + a.append(3) + a += [4] + a = [5] + [a] + a = a + [6] + a[0] = 1 + a[5:] = [5] + + try: + tlist([1, 2, 'a'], int) + a.append('a') + a += ['a'] + _ = ['a'] + a + _ = a + ['a'] + a[0] = 'a' + a[0:] = 'a' + + except TypeError: + pass + else: + raise Exception("Must fail") + + +class TestMemoization(unittest.TestCase): + def test_memoize(self): + counter = [0] + @memoize + def f(arg): + counter[0] += 1 + print(arg, counter) + + f(1) + f(1) + assert counter[0] == 1 + + f(2) + assert counter[0] == 2 + + def test_memoize_ignore_none(self): + counter = [0] + @memoize_ignore_none + def f(arg): + counter[0] += 1 + print(arg, counter) + return arg + + f(None) + f(None) + assert counter[0] == 2 + + f(1) + assert counter[0] == 3 + f(1) + assert counter[0] == 3 + + def test_memoize_ignore_values(self): + counter = [0] + @memoize_ignore((1,)) + def f(arg): + counter[0] += 1 + print(arg, counter) + return arg + + f(1) + f(1) + assert counter[0] == 2 + + f(2) + assert counter[0] == 3 + f(2) + assert counter[0] == 3 + + def test_memoize_id(self): + counter = [0] + @memoize_id + def f(arg): + counter[0] += 1 + print(arg, counter) + return arg + + d = {} + f(d) + f(d) + assert counter[0] == 1 + + f({}) + assert counter[0] == 2 + f({}) + assert counter[0] == 3 + + +if __name__ == '__main__': + unittest.main() diff --git a/pym/calculate/contrib/spyne/test/util/test_util.pyc b/pym/calculate/contrib/spyne/test/util/test_util.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e7dc73631c38e5334728a2fb117768722def5d86 GIT binary patch literal 27058 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/_base.py b/pym/calculate/contrib/spyne/util/_base.py new file mode 100644 index 0000000..d23dea5 --- /dev/null +++ b/pym/calculate/contrib/spyne/util/_base.py @@ -0,0 +1,44 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from time import mktime +from datetime import datetime + +from spyne.util import memoize, six + + +def utctime(): + return mktime(datetime.utcnow().timetuple()) + + +@memoize +def get_version(package): + if isinstance(package, (six.text_type, six.binary_type)): + package = __import__(package) + + verstr = getattr(package, '__version__') + retval = [] + + for f in verstr.split("."): + try: + retval.append(int(f)) + except ValueError: + retval.append(f) + + return tuple(retval) diff --git a/pym/calculate/contrib/spyne/util/_base.pyc b/pym/calculate/contrib/spyne/util/_base.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1df1b01ee12561b4d56a1f65500e5245eec71304 GIT binary patch literal 1104 zcmcIj&2G~`5T0E-=?|*f1GExIoGql-YC+|KDkR{VN~uIqBxIaq8#b{W*E=Z1g- z8}KZ=36H>y2Y_$ZErkcDWlwfy=kNPw68zfQ{Q2Yihap`*8ow{`xgNv_ucDl&P}EnX zMAwvSDm3+VqX(1+RD{$Isc2EZ1#3uOi27|ZA&pvczC!pKjoNe)ts$-bjVDq#aT}tT zvMo%buS?a8jkicIECGcnX7;n;0B2_}|7-S@*mlJeucC>jE22pt5@k<(+HMrWK@d^z zZ`nBy%h@O1kWkd;d6k<;TyBNyLQUqbPI5aqe3n!T{x~ZS;^&F8Y&umooMvO=5?3us z(>aLupT_%#ooWG(*o?=GJ(;u3lXQ?d6C;7(L1`)Z5Jx8v(gN~y-DaZtE?hwqd(B^LfCQGousd=D~BFHG(1tV~lhNfbw7 zg)1iQZ0R^Fho&d~4cX?BQ(jcY2M=tS)r&@#h%~iDHLDr9gsHLNjJXCpP*vrY{l;Wf zWy+CX2V1hQ^ft@q=1pBARD7Fh3ZXvD^`v~TG>eQvbZz(|%YD;lcRO`q1XymEdJNUw zhamk(ZR>5-*1IZDdumHP(A`M>1sE^{w&b6+6@vV(#j;a9Ssl-7Pr&r{AZ}6k(_JjE XH20#Ijpn&I5(rKVJ8DPo1{>iYR@dxX literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/_twisted_ws.py b/pym/calculate/contrib/spyne/util/_twisted_ws.py new file mode 100644 index 0000000..df7468c --- /dev/null +++ b/pym/calculate/contrib/spyne/util/_twisted_ws.py @@ -0,0 +1,610 @@ +# -*- test-case-name: twisted.web.test.test_websockets -*- +# Copyright (c) Twisted Matrix Laboratories. +# 2011-2012 Oregon State University Open Source Lab +# 2011-2012 Corbin Simpson +# +# See LICENSE for details. + +""" +The WebSockets protocol (RFC 6455), provided as a resource which wraps a +factory. +""" + +__all__ = ["WebSocketsResource", "IWebSocketsProtocol", "IWebSocketsResource", + "WebSocketsProtocol", "WebSocketsProtocolWrapper"] + + +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.web.resource import IResource +from twisted.web.server import NOT_DONE_YET + + + +class _WSException(Exception): + """ + Internal exception for control flow inside the WebSockets frame parser. + """ + + + +class CONTROLS(Flags): + """ + Control frame specifiers. + """ + + CONTINUE = FlagConstant(0) + TEXT = FlagConstant(1) + BINARY = FlagConstant(2) + CLOSE = FlagConstant(8) + PING = FlagConstant(9) + PONG = FlagConstant(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. + + @type key: C{str} + @param key: The key to respond to. + + @rtype: C{str} + @return: An encoded response. + """ + 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. + + @type buf: C{str} + @param buf: A buffer of bytes. + + @type key: C{str} + @param key: The masking key. Must be exactly four bytes. + + @rtype: C{str} + @return: A masked buffer of bytes. + """ + key = [ord(i) for i in key] + buf = list(buf) + for i, char in enumerate(buf): + buf[i] = chr(ord(char) ^ key[i % 4]) + return "".join(buf) + + + +def _makeFrame(buf, opcode, fin, mask=None): + """ + Make a frame. + + This function always creates unmasked frames, and attempts to use the + smallest possible lengths. + + @type buf: C{str} + @param buf: A buffer of bytes. + + @type opcode: C{CONTROLS} + @param opcode: Which type of frame to create. + + @rtype: C{str} + @return: A packed frame. + """ + bufferLength = len(buf) + if mask is not None: + lengthMask = 0x80 + 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)) + else: + length = chr(lengthMask | bufferLength) + + if fin: + header = 0x80 + else: + header = 0x01 + + header = chr(header | opcode.value) + if mask is not None: + buf = "%s%s" % (mask, _mask(buf, mask)) + frame = "%s%s%s" % (header, length, buf) + return frame + + + +def _parseFrames(frameBuffer, needMask=True): + """ + Parse frames in a highly compliant manner. + + @param frameBuffer: A buffer of bytes. + @type frameBuffer: C{list} + + @param needMask: If C{True}, refuse any frame which is not masked. + @type needMask: C{bool} + """ + start = 0 + payload = "".join(frameBuffer) + + while True: + # If there's not at least two bytes in the buffer, bail. + if len(payload) - start < 2: + break + + # Grab the header. This single byte holds some flags and an opcode + header = ord(payload[start]) + if header & 0x70: + # At least one of the reserved flags is set. Pork chop sandwiches! + raise _WSException("Reserved flag in frame (%d)" % header) + + fin = header & 0x80 + + # Get the opcode, and translate it to a local enum which we actually + # care about. + opcode = header & 0xf + try: + opcode = CONTROLS.lookupByValue(opcode) + except ValueError: + raise _WSException("Unknown opcode %d in frame" % opcode) + + # Get the payload length and determine whether we need to look for an + # extra length. + length = ord(payload[start + 1]) + masked = length & 0x80 + + if not masked and needMask: + # The client must mask the data sent + raise _WSException("Received data not masked") + + 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 len(payload) - start < 4: + break + + length = payload[start + 2:start + 4] + length = unpack(">H", length)[0] + offset += 2 + 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 = unpack(">Q", length)[0] + offset += 8 + + if masked: + if len(payload) - (start + offset) < 4: + # This is not strictly necessary, but it's more explicit so + # that we don't create an invalid key. + break + + key = payload[start + offset:start + offset + 4] + offset += 4 + + if len(payload) - (start + offset) < length: + break + + data = payload[start + offset:start + offset + length] + + if masked: + data = _mask(data, key) + + if opcode == CONTROLS.CLOSE: + if len(data) >= 2: + # Gotta unpack the opcode and return usable data here. + data = unpack(">H", data[:2])[0], data[2:] + else: + # No reason given; use generic data. + data = 1000, "No reason given" + + yield opcode, data, bool(fin) + start += offset + length + + if len(payload) > start: + frameBuffer[:] = [payload[start:]] + else: + frameBuffer[:] = [] + + + + +class IWebSocketsProtocol(IProtocol): + """ + A protocol which understands the WebSockets interface. + + @since: 13.1 + """ + + 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. + """ + 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. + """ + for frame in _parseFrames(self._buffer): + opcode, data, fin = frame + if opcode in (CONTROLS.CONTINUE, CONTROLS.TEXT, CONTROLS.BINARY): + # Business as usual. Decode the frame, if we have a decoder. + # Pass the frame to the underlying protocol. + self.frameReceived(opcode, data, fin) + elif opcode == CONTROLS.CLOSE: + # The other side wants us to close. + reason, text = data + log.msg("Closing connection: %r (%d)" % (text, reason)) + + # Close the connection. + self.transport.loseConnection() + return + elif opcode == CONTROLS.PING: + # 5.5.2 PINGs must be responded to with PONGs. + # 5.5.3 PONGs must contain the data that was sent with the + # 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. + """ + packet = _makeFrame(data, opcode, fin) + self.transport.write(packet) + + + def dataReceived(self, data): + """ + Append the data to the buffer list and parse the whole. + """ + self._buffer.append(data) + try: + self._parseFrames() + except _WSException: + # Couldn't parse all the frames, something went wrong, let's bail. + log.err() + self.transport.loseConnection() + + + def loseConnection(self): + """ + Close the connection. + + This includes telling the other side we're closing the connection. + + If the other side didn't signal that the connection is being closed, + then we might not see their last message, but since their last message + should, according to the spec, be a simple acknowledgement, it + shouldn't be a problem. + """ + # Send a closing frame. It's only polite. (And might keep the browser + # from hanging.) + if not self._disconnecting: + frame = _makeFrame("", CONTROLS.CLOSE, True) + self.transport.write(frame) + self._disconnecting = True + self.transport.loseConnection() + + + +class WebSocketsProtocolWrapper(WebSocketsProtocol): + """ + A protocol wrapper which provides L{IWebSocketsProtocol} by making messages + as data frames. + + @since: 13.1 + """ + + 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 + as the transport to C{self.wrappedProtocol}. + """ + directlyProvides(self, providedBy(transport)) + WebSocketsProtocol.makeConnection(self, transport) + self.wrappedProtocol.makeConnection(self) + + + def connectionMade(self): + """ + Initialize the list of messages. + """ + 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}. + """ + 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 + forwarding the messages if C{fin} is set. + """ + self._messages.append(data) + if fin: + content = "".join(self._messages) + self._messages[:] = [] + self.wrappedProtocol.dataReceived(content) + + + def connectionLost(self, reason): + """ + Forward C{connectionLost} to C{self.wrappedProtocol}. + """ + self.wrappedProtocol.connectionLost(reason) + + + +class IWebSocketsResource(Interface): + """ + A WebSockets resource. + + @since: 13.1 + """ + + def lookupProtocol(protocolNames, request): + """ + Build a protocol instance for the given protocol options and request. + The returned protocol is plugged to the HTTP transport, and the + returned protocol name, if specified, is used as + I{Sec-WebSocket-Protocol} value. If the protocol provides + L{IWebSocketsProtocol}, it will be connected directly, otherwise it + will be wrapped by L{WebSocketsProtocolWrapper}. + + @param protocolNames: The asked protocols from the client. + @type protocolNames: C{list} of C{str} + + @param request: The connecting client request. + @type request: L{IRequest} + + @return: A tuple of (protocol, matched protocol name or C{None}). + @rtype: C{tuple} + """ + + + +@implementer(IResource, IWebSocketsResource) +class WebSocketsResource(object): + """ + A resource for serving a protocol through WebSockets. + + This class wraps a factory and connects it to WebSockets clients. Each + connecting client will be connected to a new protocol of the factory. + + Due to unresolved questions of logistics, this resource cannot have + children. + + @param factory: The factory producing either L{IWebSocketsProtocol} or + L{IProtocol} providers, which will be used by the default + C{lookupProtocol} implementation. + @type factory: L{twisted.internet.protocol.Factory} + + @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") + + + def putChild(self, path, child): + """ + Reject attempts to add a child resource to this resource. The + 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") + + + def lookupProtocol(self, protocolNames, request): + """ + Build a protocol instance for the given protocol names and request. + This default implementation ignores the protocol names and just return + a protocol instance built by C{self._factory}. + + @param protocolNames: The asked protocols from the client. + @type protocolNames: C{list} of C{str} + + @param request: The connecting client request. + @type request: L{Request} + + @return: A tuple of (protocol, C{None}). + @rtype: C{tuple} + """ + protocol = self._factory.buildProtocol(request.transport.getPeer()) + return protocol, None + + + def render(self, request): + """ + Render a request. + + We're not actually rendering a request. We are secretly going to handle + a WebSockets connection instead. + + @param request: The connecting client request. + @type request: L{Request} + + @return: a string if the request fails, otherwise C{NOT_DONE_YET}. + """ + request.defaultContentType = None + # If we fail at all, we'll fail with 400 and no response. + failed = False + + if request.method != "GET": + # 4.2.1.1 GET is required. + failed = True + print('request.method', request.method) + + upgrade = request.getHeader("Upgrade") + if upgrade is None or "websocket" not in upgrade.lower(): + # 4.2.1.3 Upgrade: WebSocket is required. + failed = True + print('request.getHeader("Upgrade")', request.getHeader("Upgrade")) + + connection = request.getHeader("Connection") + if connection is None or "upgrade" not in connection.lower(): + # 4.2.1.4 Connection: Upgrade is required. + failed = True + print('request.getHeader("Connection")', request.getHeader("Connection")) + + key = request.getHeader("Sec-WebSocket-Key") + 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")) + + version = request.getHeader("Sec-WebSocket-Version") + if version != "13": + # 4.2.1.6 Only version 13 works. + 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")) + + if failed: + request.setResponseCode(400) + return "" + + askedProtocols = request.requestHeaders.getRawHeaders( + "Sec-WebSocket-Protocol") + protocol, protocolName = self.lookupProtocol(askedProtocols, request) + + # If a protocol is not created, we deliver an error status. + if not protocol: + request.setResponseCode(502) + return "" + + # We are going to finish this handshake. We will return a valid status + # code. + # 4.2.2.5.1 101 Switching Protocols + request.setResponseCode(101) + # 4.2.2.5.2 Upgrade: websocket + request.setHeader("Upgrade", "WebSocket") + # 4.2.2.5.3 Connection: Upgrade + request.setHeader("Connection", "Upgrade") + # 4.2.2.5.4 Response to the key challenge + request.setHeader("Sec-WebSocket-Accept", _makeAccept(key)) + # 4.2.2.5.5 Optional codec declaration + if protocolName: + request.setHeader("Sec-WebSocket-Protocol", protocolName) + + # Provoke request into flushing headers and finishing the handshake. + request.write("") + + # And now take matters into our own hands. We shall manage the + # transport's lifecycle. + transport, request.transport = request.transport, None + + if not IWebSocketsProtocol.providedBy(protocol): + protocol = WebSocketsProtocolWrapper(protocol) + + # Connect the transport to our factory, and make things go. We need to + # do some stupid stuff here; see #3204, which could fix it. + if request.isSecure(): + # Secure connections wrap in TLSMemoryBIOProtocol too. + transport.protocol.wrappedProtocol = protocol + else: + transport.protocol = protocol + protocol.makeConnection(transport) + + return NOT_DONE_YET diff --git a/pym/calculate/contrib/spyne/util/_twisted_ws.pyc b/pym/calculate/contrib/spyne/util/_twisted_ws.pyc new file mode 100644 index 0000000000000000000000000000000000000000..248dabca7e79e3c64f413ee37d0833b1f4fc8bd4 GIT binary patch literal 18890 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 SHm1+u_|oe1!t`?!rT+nV>#4>7 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/address.py b/pym/calculate/contrib/spyne/util/address.py new file mode 100644 index 0000000..55a0da0 --- /dev/null +++ b/pym/calculate/contrib/spyne/util/address.py @@ -0,0 +1,276 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +# The MIT License +# +# Copyright (c) Val Neekman @ Neekware Inc. http://neekware.com +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +from __future__ import print_function + +# Direct plagiarization of https://github.com/un33k/django-ipware/ +# at 57897c03026913892e61a164bc8b022778802ab9 + +import socket + +# List of known proxy server(s) +TRUSTED_PROXIES = [] + +# Search for the real IP address in the following order +# Configurable via settings.py +PRECEDENCE = ( + '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', +) + +# Private IP addresses +# http://en.wikipedia.org/wiki/List_of_assigned_/8_IPv4_address_blocks +# http://www.ietf.org/rfc/rfc3330.txt (IPv4) +# http://www.ietf.org/rfc/rfc5156.txt (IPv6) +# 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.', + # class B private blocks + '192.0.2.', + # reserved for documentation and example code + '192.168.', # class C private block + '255.255.255.', # IPv4 broadcast address +) + ( + '2001:db8:', + # reserved for documentation and example code + 'fc00:', # IPv6 private block + 'fe80:', # link-local unicast + 'ff00:', # IPv6 multicast +) + +LOOPBACK_PREFIX = ( + '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): + """Changes global parameters for Spyne's residend ip address parser. + + :param trusted_proxies: Tuple of reverse proxies that are under YOUR control. + :param field_precedence: A tuple of field names that may contain address + information, in decreasing level of preference. + :param private_ip_prefixes: You might want to add your list of + public-but-otherwise-private ip prefixes or addresses here. + """ + + global address_parser + + 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): + 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]) + + if len(trusted_proxies) > 0: + self.trusted_proxies = trusted_proxies + + else: + 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) + + def get_ip(self, wsgi_env, real_ip_only=False, right_most_proxy=False): + """ + Returns client's best-matched ip-address, or None + """ + best_matched_ip = None + + for key in self.field_precedence: + value = wsgi_env.get(key, None) + if value is None: + value = wsgi_env.get(key.replace('_', '-'), None) + + if value is None or value == '': + continue + + 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): + continue + + if not ip_str.startswith(self.private_ip_prefixes): + return ip_str + + if not real_ip_only: + loopback = LOOPBACK_PREFIX + + if best_matched_ip is None: + best_matched_ip = ip_str + + elif best_matched_ip.startswith(loopback) \ + and not ip_str.startswith(loopback): + best_matched_ip = ip_str + + return best_matched_ip + + 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) + + 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 + """ + + if trusted_proxies is None: + trusted_proxies = self.trusted_proxies + + if trusted_proxies is None or len(trusted_proxies) == 0: + trusted_proxies = TRUSTED_PROXIES + + if trusted_proxies is None or len(trusted_proxies) == 0: + return + + 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) + + if value is None or value == '': + continue + + ips = [ip.strip().lower() for ip in value.split(',')] + + if len(ips) > 1: + if right_most_proxy: + ips.reverse() + + for proxy in trusted_proxies: + if proxy in ips[-1]: + return ips[0] + + @staticmethod + def is_valid_ipv4(ip_str): + """ + Check the validity of an IPv4 address + """ + + if ip_str is None: + return False + + try: + socket.inet_pton(socket.AF_INET, ip_str) + + except AttributeError: # pragma: no cover + try: # Fall-back on legacy API or False + socket.inet_aton(ip_str) + except (AttributeError, socket.error): + return False + return ip_str.count('.') == 3 + + except socket.error: + return False + + return True + + @staticmethod + def is_valid_ipv6(ip_str): + """ + Check the validity of an IPv6 address + """ + + if ip_str is None: + return False + + try: + socket.inet_pton(socket.AF_INET6, ip_str) + + except socket.error: + return False + + return True + + @staticmethod + 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) + + +address_parser = AddressParser() diff --git a/pym/calculate/contrib/spyne/util/address.pyc b/pym/calculate/contrib/spyne/util/address.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e89a2c525e326b4e2ad57dbeb35ecbae8532c3b0 GIT binary patch literal 6410 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/attrdict.py b/pym/calculate/contrib/spyne/util/attrdict.py new file mode 100644 index 0000000..de996aa --- /dev/null +++ b/pym/calculate/contrib/spyne/util/attrdict.py @@ -0,0 +1,87 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + + +def TAttrDict(default=None): + class AttrDict(object): + def __init__(self, *args, **kwargs): + self.__data = dict(*args, **kwargs) + + def __call__(self, **kwargs): + retval = AttrDict(self.__data.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': + raise ValueError("'items' is part of dict interface") + self.__data[key] = value + + def __setitem__(self, key, value): + self.__data[key] = value + + def __iter__(self): + return iter(self.__data) + + def items(self): + return self.__data.items() + + def get(self, key, *args): + return self.__data.get(key, *args) + + 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])]) + + 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 self.__data: + return self.__data[key] + else: + return default() + + 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/pym/calculate/contrib/spyne/util/attrdict.pyc b/pym/calculate/contrib/spyne/util/attrdict.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52e5260a81c40ab717ca41f2e50a510e349911d8 GIT binary patch literal 4824 zcmd5=?Q&B^7=AZN)25^r<--9HB3K*HHUds@5EzhF$5AtSqB1h#dYW@u)1*l_XM=R6 z_`@<%XB;oVJMm7u1pj#hKF_=P0*0UI7-qNc*|TT&d7t-dm+ZfDv;X}4*AI2+|FZad z6D_@gF3L$H^4Q2-Be9V^k-HfRk&(wDdl=73gpr(VU@)tLBH!Mf;+M7Z6qcwPbZj{^ zE}ou4hXtJQqbDLyjBI4M%&%AyU;ieuFZi01t8NDUE$5QeM%~pR>o0?zE&UT+3{==1 zI29gNBpAcxJUos=5ryZWaU?I%lzuWTQC@`^iKbO3NHn9utn6c{Icd&F^0Pz*9V|*T ztHPYLPb+%NIi%ao4IYd7Sd^evehCnj1nR?P(bD7Sz`(AN-HiMJ0pqGftxU42Wvb_L z=prcY<{{Vt4c11X3zZ+8k;bhJ6~bgQb$Lu}{zS11NwiD9gjDIJNu||TUwN<6-Elv5 z+LxBERMLivm%3rS8E(dDCGGCC7cVbgTv_VwV8(L1x#`C%J=bVeLfC?kmaztH zV{N0|aMr#GIVET@sx58L_8MCH5xRXW|8~qf*Uy$B}z*-iy@T4FoR8y4Y0Gd7a%{2o=Ar13EiWolk$~Mc_UBt z(RmQaH87UO5R*o3%yx(4N6-xs`#}8tY1S3DI{s$tMxo&ShcP&5`h#QGxi}PEFHJ;^Js5z(}qylFXU`bNqq8wl;~oND?aqMTkt;&-*L!cz=cUKsL#( z`m8`}jQmqAHF4y=1R}b5z_9iMKp1%HAk2nN@_&WyOUv~aKtICq1$2xS&CkueBqzs> zu&+n-S~N=9w2Cj9)ZV)jGmRQb&ty@&5%yY64K$(he+C=gL`&)Cg2I0&GxR5hglcvR z0yM*6pK6^Nove@__HeZ9YmJi?UazRuI8D*@#V^G5ENfLM(>#v~=&rgSy#H!w2`se(1xDAYY^s{!m6ZKkz zOsxZ^P(6bMuTVP5jzo<#4_?QkUQ()^b{ufOfL2qbd?@2dCax$qp|#Re=<=qJozEAh z3)$hnT+tLV#q9i)Pc$@@mr9h-`gwnXG!Vn)h~VvPGY{zoCB7j%Dd&+)EIm9*rt zG|_=RMoTZE^B2X{duMrT^haMD<56o-{!xn|?}^ci;bWVPhXrr3LzCcbb_^Hg_duZeGmy_jH#A1bO7UvJ%xC`t{` restarts the process (via :func:`os.execv`) + if any of the files it monitors change (or is deleted). By default, the + autoreloader monitors all imported modules; you can add to the + set by adding to ``autoreload.files``:: + + spyne.util.autorel.AutoReloader.FILES.add(myFile) + + + spyne.util.autorel.AutoReloader.match = r'^(?!cherrypy).+' + + The autoreload plugin takes a ``frequency`` argument. The default is + 1 second; that is, the autoreloader will examine files once each second. + """ + + FILES = set() + """The set of files to poll for modifications.""" + + def __init__(self, frequency=1, match='.*'): + self.max_cloexec_files = MAX_FILES + + self.mtimes = {} + self.files = set(AutoReloader.FILES) + + self.match = match + """A regular expression by which to match filenames. + + If there are imported files you do *not* wish to monitor, you can + adjust the ``match`` attribute, a regular expression. For example, + to stop monitoring cherrypy itself, try ``match=r'^(?!cherrypy).+'``\\. + """ + + self.frequency = frequency + """The interval in seconds at which to poll for modified files.""" + + def start(self): + from twisted.internet.task import LoopingCall + + retval = LoopingCall(self.run) + retval.start(self.frequency) + 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') + ): + f = m.__loader__.archive + else: + try: + 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)) + files.add(f) + return files + + 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'): + filename = filename[:-1] + + oldtime = self.mtimes.get(filename, 0) + if oldtime is None: + # Module with no .py file. Skip it. + continue + + try: + mtime = os.stat(filename).st_mtime + except OSError: + # Either a module with no .py file, or it's been deleted. + mtime = None + + if filename not in self.mtimes: + # If a module has no .py file, this will be None. + self.mtimes[filename] = mtime + else: + if mtime is None or mtime > oldtime: + # The file has been deleted or modified. + logger.info("Restarting because '%s' has changed." % + filename) + + from twisted.internet import reactor + reactor.stop() + self._do_execv() + return + + @staticmethod + def _extend_pythonpath(env): + """ + If sys.path[0] is an empty string, the interpreter was likely + invoked with -m and the effective path is about to change on + re-exec. Add the current directory to $PYTHONPATH to ensure + that the new process sees the same path. + + This issue cannot be addressed in the general case because + Python cannot reliably reconstruct the + original command line (http://bugs.python.org/issue14208). + + (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) + ) + + if needs_patch: + env["PYTHONPATH"] = path_prefix + existing_path + + def _set_cloexec(self): + """Set the CLOEXEC flag on all open files (except stdin/out/err). + + If self.max_cloexec_files is an integer (the default), then on + platforms which support it, it represents the max open files setting + for the operating system. This function will be called just before + the process is restarted via os.execv() to prevent open files + from persisting into the new process. + + Set self.max_cloexec_files to 0 to disable this behavior. + """ + for fd in range(3, self.max_cloexec_files): # skip stdin/out/err + try: + flags = fcntl.fcntl(fd, fcntl.F_GETFD) + except IOError: + continue + fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC) + + def _do_execv(self): + """Re-execute the current process. + + This must be called from the main thread, because certain platforms + (OS X) don't allow execv to be called in a child thread very well. + """ + args = sys.argv[:] + + self._extend_pythonpath(os.environ) + + 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': + from _systemrestart import SystemRestart + raise SystemRestart + + args.insert(0, sys.executable) + if sys.platform == 'win32': + args = ['"%s"' % arg for arg in args] + + os.chdir(_module__file__base) + logger.debug("Change working directory to: %s", _module__file__base) + + if self.max_cloexec_files: + self._set_cloexec() + + os.execv(sys.executable, args) diff --git a/pym/calculate/contrib/spyne/util/autorel.pyc b/pym/calculate/contrib/spyne/util/autorel.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42ee445b0c87f3a74834c6f854cce9b348af4921 GIT binary patch literal 6600 zcmcgxO>-Pq6@5LDMjBa)WXo~l0CC5}34^xOp{L9yL9twvVa%`73H#FQ~nFRer8K&r7D% z_M*xg>cL<|vExfBnU=X1hmDt{@h_w?rbc5=JxHobFRP}fl3De+;#?26k8=}S^*L-P z{U?4l>mF|H6pDv8Zm0O8>@gHu8{wV1H#Wmhu0BZBG%6QRd9`ngKxaji=yGf%cD;tn z?4p2SwlN>diqccEJ(vVF6@^WFUJ&rTG>2$9%AZv5bvM`}{!l{WS8|oBcdq-ziLklkM-U%2;XB zkMeSVRyUmM_|8TB*!Hhaog5o}xzZ9Ewv$}&Ig z_KFf6QJeI!pZEPi(f8vh_oF27Z809gXzT9|Sexc8zS!BBjM|Xp?d+_tJ3G)8rZ>oS zqi@r!F>Kg4`l%Z?Z{5DJ)xdc5?%*a&xjO&9_w7a&U*~&%dH&P-hi}AfU6zC1V72kq z`O$aK{$zE&`v|^`_VB?Xth`z3$99GT(<5VRKqZA8^_S@p!#%#j&e!nnApwu}671)DEe#!NrPWoSp`EmxMjWoI((hU?hCW&VKzaD1j{ ztiwMm>nSTHqJ2>Bsq2q^ui!FayQcu@jOqZJFrOgwSw)p+lm$o;$UMcz-te&lz{2QK zgSU7@$a*@ha-#;Pl%1C@=!I#fSTBJKk%EEiXA+C1r8#2J6NG_jwO3Q+m&z_Of_0V@ zDzUhQN!9Y`-En14$ZPk_F(p{$sm{uVF)8A6_s&2-Pc3xl2&23SwG3)X>nmu1_(Ja4vcgf z&LYSGU%Cb#fG81`NsD%5B5TXw1P5B-K%A_lEo)`a%>rm7%x;OJzfqQO_Z+4$^1c_@ zwwu62yGGWR7iCwfN$pMnNOR=SttJ%z5r(@FT*egY>A(pbhh<_4NKtA}%C3~n7Yu1x zH9m`YtIsgGc^!p!dcu=C zTaFH7U{Uv=ui>SVm4C&4gGicmz`gaa}U?Lo&N^AuUaNGmjx*<~Q^ z;su7uUJ%yzDJhs*Vnoc@Sf{@+ycjS6TMv@h>KK`N?R<4fcM7 z0)R&-02^K*6L1GC;dcab_yNEkSUZiXy^1P6lxR9bCIEU1Kr&!jKIAh9@d`#j_bVU+ z5V=*S`OV)kv4|u}$6Lpi=uzG6*@16t3CuVZCc(Ccs7Vn9++^vV&IaRA z(tN+z12zc`|3VjIK+r1I>M7T(zB1Ty+=(YJKrPR#p7J|1M40W^I7D)lhB$NjQ| zT=bK)#4trUV8=J_KD_twoz1&f?|sZiotu8?q&N2?+L3*8eK5`;j2mK&Zsf+Kh9XNj$q5e*eb3o7d(3)*Tl^$<3SLmef=K-n@^8N)b-_V+b{_kqr`2?xweZWE>#9prQZ=Zpj>Klm=UNMxTgIAYUp zjNV*Gzlq9JXu_fs?MFvW3>a*-#F2~?FDl$I%R!pIb6NE9*>mQsVI13#!$kj}DEBz| zQHimR35OXY!=A`m99``PAK_^d9})18pEfw3j1(vW>iw;{BR+gMY;9m`{)Aq>Pt1h+>> from spyne.util.cdict import cdict +>>> class A(object): +... pass +... +>>> class B(A): +... pass +... +>>> class C(object): +... pass +... +>>> class D: +... pass +... +>>> d=cdict({A: "fun", object: "base"}) +>>> print d[A] +fun +>>> print d +{: 'fun', : 'base'} +>>> print d[B] +fun +>>> print d +{: 'fun', : 'fun', : 'base'} +>>> print d[C] +base +>>> print d +{: 'fun', : 'fun', : 'base', : 'base'} +>>> print d[D] +*** KeyError: +>>> +""" + +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__'): + cls = cls.__class__ + + for b in reversed(cls.__bases__): + try: + retval = self[b] + # this is why a cdict instance must never be modified after + # the first lookup + self[cls] = retval + return retval + except KeyError: + pass + raise e + + def get(self, k, d=None): + try: + return self[k] + + except KeyError: + return d diff --git a/pym/calculate/contrib/spyne/util/cdict.pyc b/pym/calculate/contrib/spyne/util/cdict.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc978a96616159b355d2e68583bd648837129bcb GIT binary patch literal 2165 zcmcgsUvC>l5T8A}p*<1>L4{NV(kc?N8#U)PpcF!C;W!8(DyujTDXF64a<{fGKJS^^ zb?MQV2U76~c;T}kz6l?JH$DLTX3uS-O7zb|IeErAyK}$!&CK4^{$BC_`ty(PVp=>k z{C^HHpFt%=htPr&k1|1rf|Q^Wk5rA$VAd(Ak-9(wIMnG8(HYUVhfD0e-@L#ezXL8# z(%8yoH;atf!}6+3jf~`ArgbUDsZL}*kj}@BA}ei?DkE(!3uR}8mUg7%{V1DZbC4H4 zo5zt+GG;t%;^jz=RVjZMsmfbvTa@hV-sK|%)VamhOecZ-%0AwR{GrmSh_duYl{gM* zt|Pqcn8cBmqev&2k`buda;i8Q18!`{)PiBgTyyQ4X{l8($rF{yXqqzpEYHV|#Db`c z8)YV!;60n*y{a%;-B*Q-5on0LXkb;91cBsdipXr7^V)58p6}3oDVV+g2$I}#9Gee2+j0#ZU%MtN zRxr7XYxAp)%(O_gmC3!%kq@u)TmHkHDxXFePNGzYVbE!`w`Bu#jeyz$ciXtzz<)W@n z%DN}<^<97PN%HAte7()g{q!F^Jtl?Cdpzh}i1`3YVM<^E5Kn+ZkH3CQj7M%h z^!J;X02H%7qbxzX5c3;Ud6_KHiJ()WQ$c5#8VC9(s#}l7J{7-`n0q8_jSqo{bJOAV zNuB0`G|_`E3EX&RiRaPY(H6~XRKD*3YjkB^r&IhK`VLn62j7451pXHiLcqQYIXLy` zXFv+Ni!}C|Ot)t*L5Cr?(S%|14Oq4g#iPo;>CT4ArdCbD&|ZZ7xU`mCN0EuFEfyfI zeG9jOKX{{(zJQw>lMdFXY=B%*tjt(GQcfRRt{G+_W?&O5a?13uYRyd1%F^Slk6Y8y zj&i*j+-w;T+L%W1IKnt-xnZ%f8Ql0NxUsb{E#VQU;jr3o@epab#s<@}&#`Yo%zIEI zYT~lDDptj^_b%3c%@-HN3M6Jf7Vc*kVm^c_mlt)uf*!t&B9rT(SoC%Wvdh+fqR-U>q`(!y^gLR3hh7)7i>vfdZ)UGe8s{r$z#yub(Rl@sUEuPhV*X3R7L+SoVfeL e$FTWc_aXlSarZ^+RJCj0L`cK;c*$E9tKPr(8!06K literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/cherry.py b/pym/calculate/contrib/spyne/util/cherry.py new file mode 100644 index 0000000..b604fc7 --- /dev/null +++ b/pym/calculate/contrib/spyne/util/cherry.py @@ -0,0 +1,41 @@ +# Use Cherrypy as wsgi server. +# Source: https://www.digitalocean.com/community/tutorials/how-to-deploy-python-wsgi-applications-using-a-cherrypy-web-server-behind-nginx + +import logging +import calculate.contrib.cherrypy as cherrypy + + +def cherry_graft_and_start(wsgi_application, host="0.0.0.0", port=8000, + 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) + + # Mount the application + cherrypy.tree.graft(wsgi_application, "/") + + # Unsubscribe the default server + cherrypy.server.unsubscribe() + + # Instantiate a new server object + server = cherrypy._cpserver.Server() + + # Configure the server object + server.socket_host = host + server.socket_port = port + server.thread_pool = num_threads + + # 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_certificate_chain = cacert # eg. 'ssl/bundle.crt' + + # Subscribe this server + server.subscribe() + + # Start the server engine (Option 1 *and* 2) + cherrypy.engine.start() + + return cherrypy.engine.block() diff --git a/pym/calculate/contrib/spyne/util/cherry.pyc b/pym/calculate/contrib/spyne/util/cherry.pyc new file mode 100644 index 0000000000000000000000000000000000000000..241d87eb0d83e572632aae87e49bdb7e09c915e3 GIT binary patch literal 1191 zcmcIjO>Wab6n^$JX%Z6pN6XKGpItV!X+dR!P(?v(P?1ux>BcydsWZ;hW6g{Uk<6-` zfLm|~j=&)}0|$Wj#!-UA8r$>oeQ(~p-wFFQ=zab9{R4-^)4|_kT$aQHzW@}#`4R_^ zhmbQkXD|t2f^v;)R$mLgtiySWG-ty$I+4HeIkoEuA4mR`#}80_9~GR!b#XCVC%Ehn z6b>NwE(wHi4M9N2N4&-a*1QF71Q56uRd2kbIECgWI1@nzCnQcPd@?Z<aF(+$M51 zT*Hb^F--s^u7tANRAxCZL{u8>G}kKnbg5i`>UekurK46Uon^Af+zrIz)JlG$iwl`~ zKd)ZDeE-H#+cM$aqMLQptENEfQcQ-rJyw|Qkh`G)!;WZD-i&f}3>hUx0eMQQ5tTN?)d>3zQCwLQD>*)T z8e{LLx;TuU#a248U#5JPX2QmP`1^;^!IS9VXuq7JMI^GU(Z`jODsF}sp@%*6*|5aV zE=h|?;*0bXe~8<_c7nTXhYi>U>jwC;K1qE0tj7kS{}+xzG<5e+@Ko_iVVfh4UBID7 o%d0{cZ=oC!9&M3$gkn{tNB^Z%D(HE0OJ2}SEOojcY_oRo2Q)AjQvd(} literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/color.py b/pym/calculate/contrib/spyne/util/color.py new file mode 100644 index 0000000..f12490a --- /dev/null +++ b/pym/calculate/contrib/spyne/util/color.py @@ -0,0 +1,74 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +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)) + + 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)) + +except ImportError: + R = lambda s: s + G = lambda s: s + B = lambda s: s + DARK_R = lambda s: s + DARK_G = lambda s: s + DARK_B = lambda s: s + YEL = lambda s: s + MAG = lambda s: s + CYA = lambda s: s + DARK_YEL = lambda s: s + DARK_MAG = lambda s: s + DARK_CYA = lambda s: s + + +if __name__ == '__main__': + print(R("RED")) + print(G("GREEN")) + print(B("BLUE")) + print(DARK_R("DARK_RED")) + print(DARK_G("DARK_GREEN")) + print(DARK_B("DARK_BLUE")) + print(YEL("YELLOW")) + print(MAG("MAGENTA")) + print(CYA("CYAN")) diff --git a/pym/calculate/contrib/spyne/util/color.pyc b/pym/calculate/contrib/spyne/util/color.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9ea7489d00e2965c1aa93d58d6c465d045298b97 GIT binary patch literal 5556 zcmd5=+fvg|6y0fBpf|w#1yQ_CXB^t`23{Eo)}q!rlj116#J~wyNH3G551m0D)Zg+? z`~=_p0oUHCR2h7dHfh?Om2;A;wa-31m#zQIrha_?_I{Ikp9Ic}i$vaMjY#3Ekwetb zXk8<%yC+34a$>X|Bc;<^PY3|{NdX`~B>?27 z1%UjF0Fa**0P=GJKz?4pI5jnTXHSxvqTLv|pEMh+7wC&d)00i#-VLOFano znH~iHm2l*2))`r(|I=*ez8|{|sS2wwa ze;m8zMa1qV00Osz2Vi5gqYH@BPJ;G=Lf{eFiZfX)7sLHkABJ+HFn%0nr&VwIV*r~i zr{!7=OG=-$T-(=CYLuS(%vbZfj_r>CEg8?tE31A|Dr==xvskGFqFI}lgCQ|q6{yhh z+=5fzn7dnOcl{5o=I#7^!K?fBY}?x0wYF`q;I+F=d-itz)}8#Vx!HCXcjWEu?V!BS z@#{`OwB_*v7W&w+8XL-5I0x*pOHgPXwM)-za( zIBsxT4AgHU1%@g7hUG6iy;ONq3enx^L)>Lq((|tX9O(J|4xgYc{f`bGL{;MUcT^4T z*nx+`j^zw9b8p-4xkv0;IyBcV58Aa%Xs&Uu`#Wm?Hx&PSyy4!uR;pB9zYXypcnu&7E+oAnX&t$g-M_5fWR=6Kf!r~EnjbLDt&ZPuZM+*-L81gHC?K(Au}hLJ3W)l! z+=ok&VZt^?&RG4+d3mkaSICvTHk<~L=`oQrESNIuc literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/coopmt.py b/pym/calculate/contrib/spyne/util/coopmt.py new file mode 100644 index 0000000..62fb142 --- /dev/null +++ b/pym/calculate/contrib/spyne/util/coopmt.py @@ -0,0 +1,102 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""The cooperative multitasking module. It includes the coroutine stuff. + +This could have been named just coroutine.py if it wasn't for the coroutine +decorator. +""" + + +import logging +logger = logging.getLogger(__name__) + +from itertools import chain +from inspect import isgeneratorfunction + + +class Break(Exception): + """Raised for breaking out of infinite loops inside coroutines.""" + pass + + +def coroutine(func): + assert isgeneratorfunction(func) + + 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) + raise + + try: + next(ret) + + except StopIteration: + return None + + except Exception as e: + if not hasattr(e, 'logged'): + logger.error("Exception in coroutine") + logger.exception(e) + try: + e.logged = True + except: + pass + + raise + + return ret + + return start + + +def keepfirst(func): + assert isgeneratorfunction(func) + + 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) + raise + + try: + first = next(ret) + + except StopIteration: + return None + + except Exception as e: + if not hasattr(e, 'logged'): + logger.error("Exception in coroutine") + logger.exception(e) + try: + e.logged = True + except: + pass + + raise + + return chain((first,), ret) + + return start diff --git a/pym/calculate/contrib/spyne/util/coopmt.pyc b/pym/calculate/contrib/spyne/util/coopmt.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2a4f01fe74084aef30232e02c5c78a483ba6a721 GIT binary patch literal 2619 zcmc&$TW=dx5T3K^TbwHigiD3kB1N^3Vygue2`U7Yil{&VZ6c-k#cXzu?Ty#F=A5&% zmXenS0Z;q{{t1s&9uN{g0PzcW;|IVuV-o|axJZq#vy(IDGBao9`)2L`vfBLl$8SH0 zY5wu?|7|>W43Q9ZAr&PaWs16rw4!5=v`=SHE3)KMR;6)`x;0X~wL)2)#trH=pjSyR zQ6IB4`kd&D=;Lmak~%BhWl9<{SYiA7ttEE*4aC7v2XRqMw255$nGVKf=292gQJN2e zagmgnZU=W=kmhk#CfWv04w#~JX|4n7%6`AyY#t0#3p-_&1j7hsjhwG7ZvxkhK4@04s_0u z7p7n4u}h0ww%s;58eOEBPv6F4*B~^KffPY{6z+>Ddkgbnlv)JK(H!wlAin!NnVMq&MKZM#Tt?6Xx z(aqO7lc^gP`HlAL9SfJclPDfV18qBYGR^hwjrR3d+t+XIPNvw=)`P)pzJp?99WLY8 zA;F;sn=j+B6^NRushD%Xv;1(hb_c={eFdN>vYX@-Jyi5134j!RL3FC?FaUaDg@k7}+td zhFw`P80f@qV|eF5tS5{>0AvA<);g9Pv+ZCy(RcXl;-C?*ib2`J7#0A99LF3`agi{f z7`t)N>!-%L49v?5$D4Bfz~NpzlukHzULk?E*_l~vNaEYW2v&HAI7(NdncI8ST&t1w*7zY=9;~IP6 zbd%cj)~`GnigJ@=n?li_FnID5-B?icv;x8}NLv1tq~AY=r04&dq~}7?^FNZ*tk1gmMwikR7;U#^KNa4R*2CDU`73JO+fW<+c6I6MZ{936_5c6? literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/dictdoc.py b/pym/calculate/contrib/spyne/util/dictdoc.py new file mode 100644 index 0000000..77571cd --- /dev/null +++ b/pym/calculate/contrib/spyne/util/dictdoc.py @@ -0,0 +1,214 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from spyne.context import FakeContext + +from spyne.protocol.dictdoc import HierDictDocument +from spyne.protocol.dictdoc import 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 + + +try: + from spyne.protocol.yaml import YamlDocument +except ImportError as _import_error: + _local_import_error = _import_error + def YamlDocument(*args, **kwargs): + raise _local_import_error + + +try: + 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 + + +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) + + self._from_unicode_handlers[Double] = lambda cls, val: val + self._from_unicode_handlers[Boolean] = lambda cls, val: val + self._from_unicode_handlers[Decimal] = lambda cls, val: val + self._from_unicode_handlers[Integer] = lambda cls, val: val + + self._to_unicode_handlers[Double] = lambda cls, val: val + self._to_unicode_handlers[Boolean] = lambda cls, val: val + self._to_unicode_handlers[Decimal] = lambda cls, val: val + 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): + if protocol_inst is None: + protocol_inst = protocol(ignore_wrappers=ignore_wrappers, + complex_as=complex_as) + + return protocol_inst._doc_to_object(None, cls, d) + + +get_dict_as_object = get_doc_as_object +"""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): + if cls is None: + cls = o.__class__ + + if protocol_inst is None: + protocol_inst = protocol(ignore_wrappers=ignore_wrappers, + complex_as=complex_as) + + retval = protocol_inst._object_to_doc(cls, o) + + if not ignore_wrappers: + return {cls.get_type_name(): retval} + + return retval + + +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): + 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): + if cls is None: + cls = o.__class__ + + 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): + if cls is None: + cls = o.__class__ + + 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): + 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.create_out_string(ctx, encoding) + return b''.join(ctx.out_string) + + +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) + return prot._object_to_doc(cls, o) + + +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.create_out_string(ctx) + return b''.join(ctx.out_string) + + +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) + + return prot._object_to_doc(cls, o) + + +def json_loads(s, cls, protocol=JsonDocument, **kwargs): + if s is None: + return None + 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) + + +get_json_as_object = json_loads + + +def yaml_loads(s, cls, protocol=YamlDocument, ignore_wrappers=False, **kwargs): + if s is None: + return None + 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) + return retval + + +get_yaml_as_object = yaml_loads diff --git a/pym/calculate/contrib/spyne/util/dictdoc.pyc b/pym/calculate/contrib/spyne/util/dictdoc.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0c23106412a2bfe46aff38bb1a65e9437829038 GIT binary patch literal 8216 zcmdT}TXP&o6+XQ;?doD(e80pvj^iv;B;f>{0LBDccI-feYXk+^mtj5ImPeZ1S!PC# zMM*D_Ui|}jqP?(cl(^y!}BKW8St z`TB3a4J7}W!2eH>(i;Vl7XFMxB5flLBZlRILy|R5%v(h-n8n&MAwa&|aSsE9_UXaE` z?Z2S%r0fISOTGT5rG-&=8vahpK0v)ZXv*u)=%c=+^?1wq-jK6ee`Qe5{^xX7Z;w`< z*UGD-l^3+~9kCT@U6g%L;F{QL(s)=&eQUF>yfyvMO?^~<16_%Hm_4RYBO z#Qo-`y&HEj`#f`%bEtd}+GHgRvXwa4YTHiUvVfMgu-%R9!M16%eU`?Z-UwwZI4XS6 zFObqnh)m=w=md|^cdfcNo8h1We`e-=~GrQPr2Aj=wn=Yr_?T%giVClw(OE+#VcDK=E z$*!-v`sJ-GjFwwiZYvI!y4zk64}A+MeoW(&L^&Ko-ni)*N4T<14*(lsR6Va^BAI)uDEdr$yE<;njegXQJJ%A*CedoiOwL>n`Ex2*rP*=a>KNj>^ikI|3Ec*|oTk)49@v-m*gI=!66JgJSIsB3L@yBQw=7aO*k z8Nwr$+F{%J*>=}vd|tTTi4%*b1Lkn#0F%+T$*-%K;^mT}UuiEWMB z8#3nj7%AnFW#XclDa;xD&Ht~~Ih!2KP7}-Wb-KRaj$2z1i`;@%F2M|hb=v=vh`#X`{(O~87Q~{$m)D6 z;tZUb+%DH2rl@xF7)PU?UIDyKvjJRVK`P@0xNb9@Z8Obh`#CDpDufiK4Sov>968Vj zE<^!X?#6&?dh?>#=2>Pl?(24be30`gfy2bgsO zuTOcFQw8KoSSVD?d_hUH6c7QXzCx7AM<^r%pOw{nVt}jTaL(|8$>CLteu`72-?CBI zRtUO@eG)#e_u=-wjaPaM=(5ug1Ef*SC#{qdw=gagncKbcVQQYoB>EJ`uPxpbdf*urJNNE@0JkB0CI#gu? z_0C@uWZi(zX1AvGXho*PGlywaWCMe1vVnsJgLuwo$gk)XKsS!I+i}u;3V_MYu+zes zUpJO`ORZNg0W_Y~4N9%Usf&KfLlW;h5Nh#3Vw;)uIW*0Zu(PgcY{X$lSum)t6BKWt z%u%;xJJ?1s+WS6x-K0=IN50UDx${T%eB7F+rHpER1NR)yP@9s1&WIMwg1L-sO??@i zTVLNlN8uIpjV+>gHl)5MctY%36*Rh5r%?`RZ~)KCmZYkoR-Dcb!Fe!Nq4jRDGm;bI z*%KHj9fXs9=_|D8p4x}hZ4HEzw7tvr-$A?roMqTW5&oZ6qjq$N)c|8y39JU0+-k~d zH9$VM8WQgS=5&gO+5{&%unCXRkM{$LA3_|hj32R!lAU_+e$38D<5b2$Zg1m?>jhpq z!tI*lHkn5x`pTe2UO^cE7s>$8fVa0%D5YuAFT?vXn-x@LGpBHv*BD?oZrBcTn6Qz< zf56;EI9xLUVdL!kuyMP14cKxH1H6NtA3h%SfVM(6Z?Hqq?Ss~@MPORo(F9ga9O+Ho z7d9z zFLKsBq&KnpO%Lp=!g}$;N=?IcmN-+ z?2p&LH+3=Pb#xl+hi}9W6K_Tp_zKc&rGG`q1?UJTOL*{D!6MNsS125 z8K~v`o?2XV3D934W-P060C!(G&X+)4&X+iE4UJMc@F=|q#VN-{D7~nJDsqR`73TWz z4%Fk_V*{1p-S2l%M2-{&6KC_2iTj|w@ zca`Hx5K)+BPP2+bFPPveamkb)mArS*(_7-0UWdUMN-u6cWQVsYZd3e(;uDIWQrw|n zpy54$=s!cPW$==R!)>a*ejDdDcGeKfTkgK spyne type mapping +* Service for common exception handling + +""" + +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) +try: + from django.core.validators import comma_separated_int_list_re +except ImportError: + comma_separated_int_list_re = re.compile(r'^[\d,]+$') + +from spyne.error import (ResourceNotFoundError, ValidationError as + BaseValidationError, Fault) +from spyne.model import primitive +from spyne.model.complex import ComplexModelMeta, ComplexModelBase +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!#-'\*\+\-/=\?\^_`\{-~]+)*@" + # domain part is either a single symbol + r"(([a-zA-Z0-9]|" + # or have at least two symbols + # hyphen can't be at the beginning or end of domain part + # 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) + + +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) + + +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) + + +class BaseDjangoFieldMapper(object): + + """Abstrace base class for field mappers.""" + + _VALIDATOR_HANDLERS = cdict({ + MinLengthValidator: _handle_minlength, + MaxLengthValidator: _handle_maxlength, + }) + + @staticmethod + def is_field_nullable(field, **kwargs): + """Return True if django field is nullable.""" + return field.null + + @staticmethod + def is_field_blank(field, **kwargs): + """Return True if django field is blank.""" + return field.blank + + def map(self, field, **kwargs): + """Map field to spyne model. + + :param field: Django Field instance + :param kwargs: Extra params to configure spyne model + :returns: tuple (field attribute name, mapped spyne model) + + """ + params = kwargs.copy() + + self._process_validators(field.validators, params) + + nullable = self.is_field_nullable(field, **kwargs) + blank = self.is_field_blank(field, **kwargs) + required = not (field.has_default() or blank or field.primary_key) + + if field.has_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) + + return (field.attname, customized_model) + + def get_spyne_model(self, field, **kwargs): + """Return spyne model for given Django field.""" + raise NotImplementedError + + def _process_validators(self, validators, params): + for v in validators: + handler = self._VALIDATOR_HANDLERS.get(type(v)) + if handler: + handler(v, params) + + +class DjangoFieldMapper(BaseDjangoFieldMapper): + + """Basic mapper for django fields.""" + + def __init__(self, spyne_model): + """Django field mapper constructor.""" + self.spyne_model = spyne_model + + def get_spyne_model(self, field, **kwargs): + """Return configured spyne model.""" + return self.spyne_model + + +class DecimalMapper(DjangoFieldMapper): + + """Mapper for DecimalField.""" + + def map(self, field, **kwargs): + """Map DecimalField to spyne model. + + :returns: tuple (field attribute name, mapped spyne model) + + """ + params = kwargs.copy() + 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): + """Constructor for relation field mapper.""" + self.django_model_mapper = django_model_mapper + + @staticmethod + def is_field_blank(field, **kwargs): + """Return True if `optional_relations` is set. + + Otherwise use basic behaviour. + + """ + 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() + field_type = related_field.__class__.__name__ + field_mapper = self.django_model_mapper.get_field_mapper(field_type) + + _, related_spyne_model = field_mapper.map(related_field, **kwargs) + return related_spyne_model + + +class DjangoModelMapper(object): + + r"""Mapper from django models to spyne complex models. + + You can extend it registering new field types: :: + + class NullBooleanMapper(DjangoFieldMapper): + + def map(self, field, **kwargs): + params = kwargs.copy() + # your mapping logic goes here + return super(NullBooleanMapper, self).map(field, **params) + + default_model_mapper.register_field_mapper('NullBooleanField', \ + NullBooleanMapper(primitive.Boolean)) + + + You may subclass it if you want different mapping logic for different + Django models. + + """ + + field_mapper_class = DjangoFieldMapper + + class UnknownFieldMapperException(Exception): + + """Raises when there is no field mapper for given django_type.""" + + def __init__(self, django_spyne_models=()): + """Register field mappers in internal registry.""" + self._registry = {} + + for django_type, spyne_model in django_spyne_models: + self.register(django_type, spyne_model) + + def get_field_mapper(self, django_type): + """Get mapper registered for given django_type. + + :param django_type: Django internal field type + :returns: registered mapper + :raises: :exc:`UnknownFieldMapperException` + + """ + try: + return self._registry[django_type] + except KeyError: + raise self.UnknownFieldMapperException( + '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. + + :param django_type: Django internal field type + :param spyne_model: Spyne model, usually primitive + + """ + field_mapper = self.field_mapper_class(spyne_model) + self.register_field_mapper(django_type, field_mapper) + + def register_field_mapper(self, django_type, field_mapper): + """Register field mapper for django_type. + + :param django_type: Django internal field type + :param field_mapper: :class:`DjangoFieldMapper` instance + + """ + self._registry[django_type] = field_mapper + + @staticmethod + def get_all_field_names(meta): + 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) + ))) + + @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)) + + if unknown_fields_names: + raise ImproperlyConfigured( + 'Unknown field names: {0}' + .format(', '.join(unknown_fields_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. + + :param django_model: Django model class. + :param exclude: list of fields excluded from mapping. + :param kwargs: extra kwargs are passed to all field mappers + + :returns: dict mapping attribute names to spyne models + :raises: :exc:`UnknownFieldMapperException` + + """ + field_map = odict() + + for field in self._get_fields(django_model, exclude): + field_type = field.__class__.__name__ + + try: + field_mapper = self._registry[field_type] + except KeyError: + # mapper for this field is not registered + if not (field.has_default() or field.null): + # field is required + raise self.UnknownFieldMapperException( + 'No mapper for field type {0}'.format(field_type)) + else: + # skip this field + logger.info('Field {0} is skipped from mapping.') + continue + + attr_name, spyne_model = field_mapper.map(field, **kwargs) + field_map[attr_name] = spyne_model + + return field_map + + +def strip_regex_metachars(pattern): + """Strip ^ and $ from pattern begining and end. + + According to http://www.w3.org/TR/xmlschema-0/#regexAppendix XMLSchema + expression language does not contain the metacharacters ^ and $. + + :returns: stripped pattern string + + """ + start = 0 + till = len(pattern) + + if pattern.startswith('^'): + start = 1 + + if pattern.endswith('$'): + till -= 1 + + return pattern[start:till] + + +# 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_-]+' + + +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), + + # simple fixed defaults for relation fields + ('ForeignKey', primitive.Integer32), + ('OneToOneField', primitive.Integer32), +) + + +def model_mapper_factory(mapper_class, field_map): + """Factory for model mappers. + + The factory is useful to create custom field mappers based on default one. + + """ + 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( + 'OneToOneField', RelationMapper(model_mapper)) + + model_mapper.register_field_mapper('DecimalField', + DecimalMapper(primitive.Decimal)) + return model_mapper + + +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)) + + if abstract: + # skip processing of abstract models + return super_new(mcs, name, bases, attrs) + + attributes = attrs.get('Attributes') + + if attributes is None: + 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') + + 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) + spyne_attrs.update(attrs) + return super_new(mcs, name, bases, spyne_attrs) + + +@add_metaclass(DjangoComplexModelMeta) +class DjangoComplexModel(ComplexModelBase): + + """Base class with Django model mapping support. + + Sample usage: :: + + class PersonType(DjangoComplexModel): + class Attributes(DjangoComplexModel.Attributes): + django_model = Person + + + Attribute :attr:`django_model` is required for Django model mapping + machinery. You can customize your types defining custom type fields: :: + + class PersonType(DjangoComplexModel): + gender = primitive.Unicode(pattern='^[FM]$') + + class Attributes(DjangoComplexModel.Attributes): + django_model = Person + + + There is an option to specify custom mapper: :: + + class PersonType(DjangoComplexModel): + class Attributes(DjangoComplexModel.Attributes): + django_model = Person + django_mapper = my_custom_mapper + + You can also exclude some fields from mapping: :: + + class PersonType(DjangoComplexModel): + class Attributes(DjangoComplexModel.Attributes): + django_model = Person + django_exclude = ['phone'] + + You may set `django_optional_relations`` attribute flag to indicate + that relation fields (ForeignKey, OneToOneField) of your model are + optional. This is useful when you want to create base and related + instances in remote procedure. In this case primary key of base model is + not yet available. + + """ + + __abstract__ = True + + +class ObjectNotFoundError(ResourceNotFoundError): + + """Fault constructed from `model.DoesNotExist` exception.""" + + def __init__(self, does_not_exist_exc): + """Construct fault with code Client.NotFound.""" + message = str(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) + + +class ValidationError(BaseValidationError): + + """Fault constructed from `ValidationError` exception.""" + + def __init__(self, validation_error_exc): + """Construct fault with code Client..""" + 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) + + +class DjangoService(Service): + + """Service with common Django exception handling.""" + + @classmethod + def call_wrapper(cls, ctx): + """Handle common Django exceptions.""" + try: + out_object = super(DjangoService, cls).call_wrapper(ctx) + except ObjectDoesNotExist as e: + raise ObjectNotFoundError(e) + except DjValidationError as e: + raise ValidationError(e) + return out_object + + +# FIXME: To be removed in Spyne 3 +DjangoServiceBase = DjangoService diff --git a/pym/calculate/contrib/spyne/util/django.pyc b/pym/calculate/contrib/spyne/util/django.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f7fb8c0e67dbb9087952c8781641559d336f4f19 GIT binary patch literal 19878 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/dyninit.py b/pym/calculate/contrib/spyne/util/dyninit.py new file mode 100644 index 0000000..21eb775 --- /dev/null +++ b/pym/calculate/contrib/spyne/util/dyninit.py @@ -0,0 +1,147 @@ +# encoding: utf-8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from datetime import date, datetime + +from spyne import D, Integer, ModelBase, Date, DateTime, IpAddress, Decimal, \ + Boolean +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 = (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 = (u'f', u'0', u'off', u'no', u'false') + +BOOL_VALUES_NONE = (None, '') + + +if six.PY2: + bytes = str +else: + unicode = str + + +_prot = ProtocolBase() + +def _bool_from_int(i): + if i in (0, 1): + return i == 1 + raise ValueError(i) + + +def _bool_from_bytes(s): + if s in BOOL_VALUES_NONE: + return None + + s = s.strip() + if s in BOOL_VALUES_NONE: + return None + s = s.lower() + if s in BOOL_VALUES_BYTES_TRUE: + return True + if s in BOOL_VALUES_BYTES_FALSE: + return False + raise ValueError(s) + + +def _bool_from_str(s): + if s in BOOL_VALUES_NONE: + return None + + s = s.strip() + if s in BOOL_VALUES_NONE: + return None + if s in BOOL_VALUES_STR_TRUE: + return True + if s in BOOL_VALUES_STR_FALSE: + return False + 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(), + }) +}) + + +def dynamic_init(cls, **kwargs): + fti = cls.get_flat_type_info(cls) + retval = cls() + + for k, v in fti.items(): + if k in kwargs: + subval = kwargs[k] + t = MAP[v] + setattr(retval, k, t[type(subval)](subval)) + + return retval diff --git a/pym/calculate/contrib/spyne/util/dyninit.pyc b/pym/calculate/contrib/spyne/util/dyninit.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48a318b0a177e522d9bcff40a07652799a3fcf79 GIT binary patch literal 7929 zcmd5>{dN<_6~C)5TZ%CzAtvS{7zja0uxu0Rw3KqnS59+61ZQN@vW26_+L2kat5vk4 z1hx2|IREr*`T~8EK0^QN1GK+;M_Ng?+_Vi6mZj^vGxyHkuemdGC;iW3g@640Z{O6Z z_sQY^Z}E$trHDLy9SVp-hg^q3BA3YF))WOP3e)7KDa??Yp)gBsmckslISOaUouP1+ z+*u0q z`wn?G$vsKlZ^&IFJx@EQsQp*c?~%Ji&72^oNzc(9Bt1jk8Tt{(S@O;ba*n)ng1k?9 zf&3YPY4YCZMtz<(yz_!B0b3UAG;QoTq_eca3>oq+NOKwl7X@1eb}3={V3;YNFkS95 z>9eH4q0f=VJ2b@Ty`YfLe%Pn=t_a32CeI!_qDPx(k`>HfE`9oCa+WSoY;H5njkG-SMHWcX!` zS`gcT8ZywDi~u4Tuo-m{A_How^DFts@41U#{2{{0P`;CvL9>{?^9z)mGO$ zkDAv?pRLBe(JQT5{Y7nC$E$Ix+te%9O6#AN);CsKT~L(t_O@+b?HE5;^}0>J>6;RU zn8%>iEx4=NXh&hyZ<-QXV$M|L%sB-oQJpOdOe))C`U~# zUX4xLZwVGe-y@J0_i@~LvI)LT_1N-la-f_VOY`~d2bKFW(&rp0>OD{myb@2^E3E2} zSGKxF$JfyovqtQfOlpoHeimlN_~|J~*}ngSpDQzWmAdS)iU?KJEm6*t}dcyU~6>=kCQg_z6pR3k|1XdMh(rz9x^ir zrcmZQJf z6BZLY+I_B0#Oy7gHX^YR#?pyplow2_(@Cge8Lh~IS(b8f`U`SG}1$a_lyR`(J^7`fNV*=y^5~Hgvrsew!?ajGqx&dmvQaEZVk1UpT?juL=k^65_KZ&_%b!;6D6 z&Cj%uOzh4W3ytj3OGC9m3oVaXOIgDbA$<#Wy)by=`V%-7j z9G!*o2R6z`ogmrSEu$-02}cf(N$be5kr@Yz-gHB7?{%nQx2A7WjUPwUn8g!c8GMOf z44e170SsrvT{*x*@7*-Ld`7QQwBvBy>E5%4^fX1g8QRU#E9_-(>PNNlG9!3g+RYK4 z{j>f{`E@~I^hDhv3#k}4M^*|1EC>zwL1 z13uL&-t9^6e{-8+hhfty&T8r;gLfHlJ$f+APu-;qS8^^f`(S6ng38T>k|1XvDBkJF zrb|+z;&@XWcuKAVSRvsk@%EK3mlW^t3toPA(f}|9&HjiCqTgw aRB$Xdd literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/email.py b/pym/calculate/contrib/spyne/util/email.py new file mode 100644 index 0000000..456f7f5 --- /dev/null +++ b/pym/calculate/contrib/spyne/util/email.py @@ -0,0 +1,129 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from __future__ import absolute_import + +import logging +logger = logging.getLogger(__name__) + +import getpass +import inspect +import traceback +import smtplib + +from socket import gethostname +from subprocess import Popen, PIPE + +from email.utils import COMMASPACE, formatdate +from email.mime.text import MIMEText +from email.mime.multipart import MIMEMultipart +from email.mime.application import MIMEApplication + +from spyne.util import six + + +def email_exception(exception_address, message="", bcc=None): + # http://stackoverflow.com/questions/1095601/find-module-name-of-the-originating-exception-in-python + frm = inspect.trace()[-1] + mod = inspect.getmodule(frm[0]) + module_name = mod.__name__ if mod else frm[1] + + 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) + + try: + smtp_object = smtplib.SMTP('localhost') + smtp_object.sendmail(sender, recipients, msg.as_string()) + logger.error("Error email sent") + + except Exception as e: + logger.error("Error: unable to send email") + logger.exception(e) + + +def email_text_smtp(addresses, sender=None, subject='', message="", + host='localhost', port=25): + if sender is None: + 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 + + 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()) + logger.info("Text email sent to: %r.", addresses) + + +def email_text(addresses, sender=None, subject='', message="", bcc=None, + att=None): + if att is None: + att = {} + + if sender is None: + sender = 'Spyne ' + + exc = traceback.format_exc() + if exc is not None and exc != 'None\n': + message = (u"%s\n\n%s" % (message, exc)) + msg = MIMEText(message.encode('utf8'), 'plain', 'utf8') + if len(att) > 0: + newmsg = MIMEMultipart() + newmsg.attach(msg) + for k, v in att.items(): + part = MIMEApplication(v) + part.add_header('Content-Disposition', 'attachment', filename=k) + newmsg.attach(part) + + msg = newmsg + + msg['To'] = COMMASPACE.join(addresses) + msg['From'] = sender + msg['Date'] = formatdate() + msg['Subject'] = subject + + 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()) + + logger.info("Text email sent to: %r.", addresses) diff --git a/pym/calculate/contrib/spyne/util/email.pyc b/pym/calculate/contrib/spyne/util/email.pyc new file mode 100644 index 0000000000000000000000000000000000000000..61685fe92d2711be0331c8f7154b443acdf5186e GIT binary patch literal 3896 zcmcgvT~iy$6}>Y8Aqfct7;LS*38@N+HYr4z-FOo(wS~)Ot6T|$8eFxBl9V!%20UUu zl<8IiRpQC}8}dK$1NJq)B0nK-`;@2ToZAw3E4$9q22iW}_Sfyc=bYP=zG~F|`HwIE zIFQ*-8Q+J8BIZ3$WQadc5|PxCt|uPbz9hbMeTjS-l_Xk_H|Sf`q39}0w>+;eNq1>p zuSmBtuUDm8)p|*inxxCpU3N<^NK%)yA>D?gE7DzY)EjtF|Z&mH@vwqfY;+|sOSsV8xb`?d~H+eF#Q7=x%d0|gn&oX*0BKtZwHVf0J z?Q{4diqm`?Wp;tJm#0V0UPJ5ouaA$Pot-{=eq`A^&x0EM{i9#DUMo<0Kx0HqJ9QzJv}FUs-&~fQ>pn^yv8^IzGdB&^7YpjYhw9 zQ_{9C(-M!~LcDJlWV#^5K1+ZgThhLgv~B=|1-U896op$aG0Yi?m<~ zFT?6+cw);kTHNMGgb}Y(yNw(PEkb~=Ah+UD z?C068EZBQ;S(Dx>PvU>$N0AZ}DP{#lk@s_Z zXvWuB)QNLL&h405ZO14aCieX2ijZ*<#+fBxUgc&BUuT@Leem_^pX#K~iagcI3n0Z1 zIPD#CxMM!p#;Qx4JL!+2fwfiClY9^+M5G~%kBTBMwxcwRlWhY?nul}a)9pzX_LFGa z=Ij}|L2bICYsQ%wb4`NB7U3Y$)q(ajA5M}8kre6m2>V`7ojb|12=NvHc(I-i*NOdb zaQPP8d(qV(;5aup8|1?%&|P>GY%mUuI~M8_6BU87kew#Azocfa%a!_MO;yW?w&=tLJ6&b~LX zak8gq=wJb=h&C7!cMBiDWOPHn>1}u|zwA}Ly4Uo#yoX*5zYTBOFL|q8%UknT(F%BD zaSO$OF(m>id(RKC&R3{F1gH@eDK?pJZajfFSWiY!3Q;xDoI(*fqy#~TKvNZWK#-uOaE zf=Db&@pl!bI{l>*LCsWRs1{l4zxtpsGbLH2#89!&_B9=ywHfb|caVB=Ckg>!6A*d< zr9Pm71dK~S_L}=Bm<--xF!=g(d#C8A0tKXN@PGwFptK6!V~s&jo{aK1Q+fsO)BZgc zjFJNH^tb!L_i5Rtg_H(?`qxmI;0LsDl{h=k+d6~Aj1m~|Qw~s8I`s*DG@n8B(Wy+8 zx)1ObbkH5_q4lGBbx1q|*q0?KLW1|(5w7noz!)IEML2N^*q7xJN%>#YOwz`s zQDils94YMTCEXlV*!SWOpUCfl>?$)Lv<68KLy*;w!A5uoDGywVedBu`(=pa@+3in% zlh0uQw{S+6Y>8_}D&*rCy^xG&2^fpjZ|Q{`jMR&)I&8`X7z#4gWwfHyfRi8{FA_wL zyjh1Hn6Cv$5lq81vCO&NO@m52T9@Ll-n7A7O+wyN((!qL_N{euZnax7x-Y}^uTgOW zp?nt=4HFMDSM3`~iGTw-T;w_O1=M@@MQp}7B$xSvJP)l62d`6fDSgi4Bw|kdMmDcw zyh^y~$JyRIZcdH-_t4oVi zkl&$Y=;vHKC?F41KqwpyWWu_)g=|>$=Yqn#$ehXkEq}vrQ+xEXd%g3CofLR71zb_( zlaCZWSg5XeU;IknEWsvP?mGEm3kV&j^Hg!YEt3x}BkLYVblFV$<02p6nQ|924VBCH zO#Q}%SRY%r$-k4vY1H9S-K*>#)^by{Bc1=};lM=5z117u{R46bDfjs0h7L3e)5n+? ze8S?FDDEPtweR9}Lxdl=7ulyglldWvCW5!B830)TPn<10Y?}P_o2Au9Rd02(?)?Ya Cx(Ijx literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/etreeconv.py b/pym/calculate/contrib/spyne/util/etreeconv.py new file mode 100644 index 0000000..cbd440c --- /dev/null +++ b/pym/calculate/contrib/spyne/util/etreeconv.py @@ -0,0 +1,131 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""This module contains the utility methods that convert an ElementTree +hierarchy to python dicts and vice versa. +""" + +import collections + +from spyne.util import six + +from lxml import etree + +from spyne.util.odict import odict + + +def root_dict_to_etree(d): + """Converts a dictionary to an xml hiearchy. Just like a valid xml document, + the dictionary must have a single element. The format of the child + dictionaries is the same as :func:`dict_to_etree`. + """ + + assert len(d) == 1, "Incoming dict len must be exactly 1. Data: %r" % d + + key, = d.keys() + retval = etree.Element(key) + for val in d.values(): + break + + if val is None: + return retval + + if isinstance(val, dict) or isinstance(val, odict): + dict_to_etree(val, retval) + elif not isinstance(val, collections.Sized) or isinstance(val, six.string_types): + retval.text=str(val) + else: + for a in val: + dict_to_etree(a, retval) + + return retval + + +def dict_to_etree(d, parent): + """Takes a the dict whose value is either None or an instance of dict, odict + or an iterable. The iterables can contain either other dicts/odicts or + str/unicode instances. + """ + + for k, v in d.items(): + if v is None: + etree.SubElement(parent, k) + + elif isinstance(v, six.string_types): + etree.SubElement(parent, k).text = v + + elif isinstance(v, dict) or isinstance(v, odict): + child = etree.SubElement(parent, k) + dict_to_etree(v, child) + + elif not isinstance(v, collections.Sized): + etree.SubElement(parent, k).text = str(v) + + elif len(v) == 0: + etree.SubElement(parent, k) + + else: + for e in v: + child=etree.SubElement(parent, k) + if isinstance(e, dict) or isinstance(e, odict): + dict_to_etree(e, child) + else: + child.text=str(e) + + +def root_etree_to_dict(element, iterable=(list, list.append)): + """Takes an xml root element and returns the corresponding dict. The second + argument is a pair of iterable type and the function used to add elements to + the iterable. The xml attributes are ignored. + """ + + return {element.tag: iterable[0]([etree_to_dict(element, iterable)])} + + +def etree_to_dict(element, iterable=(list, list.append)): + """Takes an xml root element and returns the corresponding dict. The second + argument is a pair of iterable type and the function used to add elements to + the iterable. The xml attributes are ignored. + """ + + if (element.text is None) or element.text.isspace(): + retval = odict() + for elt in element: + if not (elt.tag in retval): + retval[elt.tag] = iterable[0]() + iterable[1](retval[elt.tag], etree_to_dict(elt, iterable)) + + else: + retval = element.text + + return retval + + +def etree_strip_namespaces(element): + """Removes any namespace information form the given element recursively.""" + + retval = etree.Element(element.tag.rpartition('}')[-1]) + retval.text = element.text + for a in element.attrib: + retval.attrib[a.rpartition('}')[-1]] = element.attrib[a] + + for e in element: + retval.append(etree_strip_namespaces(e)) + + return retval diff --git a/pym/calculate/contrib/spyne/util/etreeconv.pyc b/pym/calculate/contrib/spyne/util/etreeconv.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c54b43ec1413724f5362ffc866a6c4836eaa5575 GIT binary patch literal 3933 zcmds4&2Ah;5U!d1vDdK^CzcbefYXVHSfqGY2_c{;LZCPYBE>?JL`GJu&3LA>JNE3% zdb-!_qF6#ngpfFJ;{kXEZiqJk2_cR=0ul!f+<>pDXYDw5Us&(-_D^+nP1pBTl`DVE z&HVBEkB=iNKR$jx#ACij6BBKq^(gi!^=Jbfd@Gdt)UVJ+g*+ZtDXmh!MjJIZu2EX2 z{uFIYVO*ydP%=&Nlyn-TXZX8)f}Z#kPtyyiojp3)kjXiUXJpGsKK*|41RIs3dC*IY z>gVw=)hfy}8zz}iwx`w5CTU{Fs;_M?k9jV%EU~8xtHMm(Np)Xm_CcZbOfS(zSVX1cSLvz8d-i=AEs8*m1y(nw zXum?A?B1jGrxkX{&NLN0dWw6pQ-moyP0w-2msAcLJS@H?JHxAx!_dnfPL@y5_AF1$ znja=pbF_U@HvLTY6mNnV*w>k-Y?(&qd1iHUf%dDS6NWmSyT8FCb{D_A`H649IRF4kf| z#Uxo5kkHP{E%gARPx7J<5adr}W7JF1SkxS-NVHLa6RS00A8L%c`DB|E^X-ae-YIXvtNF8D)nE4Jz02Mi zf6hDYM|?qiq5ML(@t6*b9)0RD^*~N$)?M$B&wK;F0C5nMsr5ctpSCe09ANJ3&Jpeh z61dInx)5bchDYT(Q*1|mYQGL%Z`$-*j1i)vRp-U zMyx6Re)SACf3(R$tD6sLzxL`n+km&jytDbbR}P)cs~*RZ+JS}th&>2RxSlGp4gb(O zj#!t#EpYlCxBVd80o%d@4y(_4xj~#|bTbKc0vZ;IA+GX*BlZO1Okj5R6(tc?xL8V9 z#PO|EJGui{GBPT{?lL({^yZ?S)tI)ZF*rq30sZY^mPC0BJ4#lWlJT&c)|#i#3U6>i z-vrYbI;t`i?+>?1wgwGez(WC(JecQ(MTD9G6ER@A1x(U_l?Hq}O~zy(F@k%8ut1a$ zKJ7@mCr3;4lCeH^mWipiU<>jTKJ_JU)?4t;c&~v^XS{jzmhmi9<}d=o9J82R2h4gC z1B6R31|VE=*^iT%PhClAOgWEk+;8$O^9!019xf{|!zZC!QZj-3_^{|o)?i$PY7iy`V`zd8#eq)La^UB9&!JcijgGk<2;+EiHc~?_7-7N5 zc6S;luh1fJZVfHtx`048%L^U91RZ%jiOCYgIH52CC1~2P>y|m*muU-x!@ZR-K6W=B z2Gb+fJz|%zU#Ko2ld}^8^EMvy4H_3OUEN`p%b_b?if5eYo|DupAup|N-YcUi*E0yH zQ&enBfB`{FArN8hR)&ETMN0>BOMpIB9dab_wrD+Tlt&^?L$WM3{>Ic3upvzIEa3;0FfRZ(9(AfTx+cRKQ1uo=jMsn=$YR~~ zkf#qd+}eGY)<+jvZgq1>a0t12S>-}MzTR#ZMXLuKRbY&{gC@}Ze2+<;ja7!aP_7xd z!PS!-E4U|_tefni`YY+H3LOm#gQ;}fl32Yj|35U@Ws)%hiS_I&DdP$Rdz*0dkz^rt zl?y7aI~eFJwr3&k7|Mm(pmSi7dCAx8=3tSVH_#lvqu<6UBRqyv9aSzMMWEC|p>@u8 z`H~UZ>7ah^bR_G^3ro4z;}BaOVYGMH(!BdB`HhO#MppeG2r|p qm-B7xV)*%y3a!_h +# +# 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. +# + +import os + +from spyne.util.six.moves.collections_abc import Iterator + +__all__ = 'FileProxy', 'ReusableFileProxy', 'SeekableFileProxy' + + +class FileProxy(Iterator): + """The complete proxy for ``wrapped`` file-like object. + + :param wrapped: the file object to wrap + :type wrapped: :class:`file`, file-like object + """ + + def __init__(self, wrapped): + self.wrapped = wrapped + self.mmap = None + + def __iter__(self): + f = self.wrapped + it = getattr(f, '__iter__', None) + if callable(it): + return it() + return self + + def __next__(self): + """Implementation of :class:`collections.Iterator` protocol.""" + line = self.readline() + if not line: + raise StopIteration('hit eof') + return line + + next = __next__ + + def read(self, size=-1): + """Reads at the most ``size`` bytes from the file. + It maybe less if the read hits EOF before obtaining ``size`` bytes. + + :param size: bytes to read. if it is negative or omitted, + read all data until EOF is reached. default is -1 + :returns: read bytes. an empty string when EOF is encountered + immediately + :rtype: :class:`str` + """ + return self.wrapped.read(size) + + def readline(self, size=None): + r"""Reads an entire line from the file. A trailing newline + character is kept in the string (but maybe absent when a file + ends with an incomplete line). + + :param size: if it's present and non-negative, it is maximum + byte count (including trailing newline) and + an incomplete line maybe returned + :type size: :class:`numbers.Integral` + :returns: read bytes + :rtype: :class:`str` + + .. note:: + + Unlike ``stdio``'s :c:func:`fgets()`, the returned string + contains null characters (``'\0'``) if they occurred in + the input. + + """ + return self.wrapped.readline(size) + + def readlines(self, sizehint=None): + """Reads until EOF using :meth:`readline()`. + + :param sizehint: if it's present, instead of reading up to EOF, + whole lines totalling approximately ``sizehint`` + bytes (or more to accommodate a final whole line) + :type sizehint: :class:`numbers.Integral` + :returns: a list containing the lines read + :rtype: :class:`list` + """ + wrapped = self.wrapped + try: + readlines = wrapped.readlines + except AttributeError: + lines = [] + while 1: + line = wrapped.readline() + if line: + lines.append(line) + else: + break + return lines + return readlines() if sizehint is None else readlines(sizehint) + + def xreadlines(self): + """The same to ``iter(file)``. Use that. + + .. deprecated:: long time ago + + Use :func:`iter()` instead. + """ + return iter(self) + + def close(self): + """Closes the file. It's a context manager as well, + so prefer :keyword:`with` statement than direct call of + this:: + + with FileProxy(file_) as f: + print f.read() + """ + try: + close = self.wrapped.close + except AttributeError: + pass + else: + close() + + def __enter__(self): + return self.wrapped + + def __exit__(self, exc_type, value, traceback): + self.close() + + def __del__(self): + if self.mmap is not None: + self.mmap.close() + self.wrapped.close() + + def fileno(self): + return self.wrapped.fileno() + + +class SeekableFileProxy(FileProxy): + """The almost same to :class:`FileProxy` except it has + :meth:`seek()` and :meth:`tell()` methods in addition. + """ + + def seek(self, offset, whence=os.SEEK_SET): + """Sets the file's current position. + + :param offset: the offset to set + :type offset: :class:`numbers.Integral` + :param whence: see the docs of :meth:`file.seek()`. + default is :const:`os.SEEK_SET` + """ + self.wrapped.seek(offset, whence) + + def tell(self): + """Gets the file's current position. + + :returns: the file's current position + :rtype: :class:`numbers.Integral` + """ + return self.wrapped.tell() + + +class ReusableFileProxy(SeekableFileProxy): + """It memorizes the current position (:meth:`tell()`) when the context + enters and then rewinds (:meth:`seek()`) back to the memorized + :attr:`initial_offset` when the context exits. + """ + + def __enter__(self): + self.initial_offset = self.tell() + self.seek(0) + return super(ReusableFileProxy, self).__enter__() + + def __exit__(self, exc_type, value, traceback): + self.seek(self.initial_offset) diff --git a/pym/calculate/contrib/spyne/util/fileproxy.pyc b/pym/calculate/contrib/spyne/util/fileproxy.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f103cccf91cecaec8de096b7d1ea758fb9938ab GIT binary patch literal 7704 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 0: + ostr.write(INDENT * indent) + ostr.write("public:\n") + for e in self.public_entries: + e.to_decl_stream(ostr, indent + 1) + ostr.write("\n") + + if len(self.protected_entries) > 0: + ostr.write(INDENT * indent) + ostr.write("protected:\n") + for e in self.protected_entries: + e.to_decl_stream(ostr, indent + 1) + ostr.write("\n") + + if len(self.private_entries) > 0: + ostr.write(INDENT * indent) + ostr.write("private:\n") + for e in self.private_entries: + e.to_decl_stream(ostr, indent + 1) + ostr.write("\n") + + ostr.write(INDENT * indent) + ostr.write("};\n") + + if self.namespace is not None: + ostr.write("}\n") + + def to_defn_stream(self, ostr, indent=0): + if self.namespace is not None: + ostr.write("namespace ") + ostr.write(self.namespace) + ostr.write(" {\n") + + if len(self.public_entries) > 0: + for e in self.public_entries: + e.to_defn_stream(ostr, indent) + + if len(self.protected_entries) > 0: + for e in self.protected_entries: + e.to_defn_stream(ostr, indent) + + if len(self.private_entries) > 0: + for e in self.private_entries: + e.to_defn_stream(ostr, indent) + + 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() + + ocls = Class() + ocls.name = cls.get_type_name() + ocls.namespace = namespace + + keys = Class() + keys.name = "Key" + keys.parent = ocls + keys.type = "struct" + ocls.public_entries.append(keys) + + 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) + ) + + member.comment_before = v.Annotations.doc + member.parent = keys + + keys.public_entries.append(member) + + ocls.to_decl_stream(sys.stdout) + sys.stdout.write("\n\n\n\n") + ocls.to_defn_stream(sys.stdout) diff --git a/pym/calculate/contrib/spyne/util/gencpp.pyc b/pym/calculate/contrib/spyne/util/gencpp.pyc new file mode 100644 index 0000000000000000000000000000000000000000..90d0fef4498acf03e2a9d1f6acbbaee98db6a95f GIT binary patch literal 8296 zcmd5>O>Z1Y8LsXbk3C~McH(4`T|(&12TUB|(FRzS?6OK?FVX@#i#iC4>_)?Qy6yCM z+%xVf2b;Ay;M_QJK;p7{LjnO8uKWW82gHpV7Y=(s;)ammdEV-ei4#X!Ruh~X?_}OPp@ONbx0?4>R8Ui4Mc$pxdnZ*eqrwU4oy~ivRB$5eoy&Wx zJQDxr)gxEkn`ZlN<0KD$AJuK|TZ3iKJm?rN+8Xx5tuQv)>qncRcjJmTSjSN4^#*Hf zb_empFfmcQ;oTkX#i2J?>xEssZU!}NI&siR0&n@+HLu(6XdUXM=->FXbQ$}2_?QYB z@5r2-iVnK&py*4eLQoN;Qan6~=SZW(BeSQh{JRa3y~|lFF3K{B{tPP2+gGYB3$TF& zY!4PtxHBiT8fDamRcjE3a-v};!KKX!^mPYYBtUyDTpuK%nH}lsteY^AHDtC9`|Ax1 zE2;E5Xf=0q((FfTuY9pN+%pdb@r|V~H+5vf>%&fWv$GNErY700-&lJ23rjD*a(%dm zHm;+XJsjqCXx4|I3Ny4(tZ?&W9IG)*rxqB-r8o+#$m$F z)=L=FLKQd}LyZbfnCV0WBz>8?W40GrjT_gp7eQjjL?Vnk^ zVD4m&7d!|SEnX-vDPAJNM3Xq4*KB%6;p0zoI71I{=97qm9>0bb2m};_vClRADk_UH zuINv*nn5L)B386dRWWA7oWmA5VniJkfVqJ&eG!!f%qjO20J2cZU}HgJVIvnwl}p^& z3fpbN8@JnAgJ7qRM_=ecb?DPf6t|MrI8>dFZPcewM8#E{>O}RV(Du#PBzs+s@E*jQc029_+Owe4AtzAxJAyb!8w1>*z&mqVUUFyg~kPe{3bNfkq zLAL9iVVL-*(Gmg)1wpcCJ%U}}>Y`HoI$8zE#zHOf=Nl-3YUM0gO~A`h`^g0fM_dq> z`jObf%=(FXBx_p(^Hyf>!$7R6J%0}F@m@mAE%aRwcKfN)qYV}Hu0H04{Ii((zr4bF zoL+%IPOs1s^W~pHkH5f*q_?6)LH4Qt3lfh{v7>d zJP|I+d@5X-BL+F*@F$id{|r{~Ut~oLi-S;aQF{8;Q1tm5H{ zGmMWnq{Mf45UP)gBmU-Hlfc3LZ@5DRkd!Nj|#7s<~*C*qw!QdgDuQH*5&YdTQHJT<(IrDIx=ABvh zD1$Fx@Od!!Job4HC1Ws8wbC)2x5KTqFzMn+KBTJ1-p4g;v`Z|cxUl?7XdE$YV6yPm zO>G-oF&a5>yVyYBSwu%fzLio&R8~r9Le1VV6wjC*gQ1OJToQHq(GOt#c!a|G`5qr% zVs#N!LFcgv^8;+72}0%6i};8{$qDm&JP_`!8w0h7Qq1}xO2<@CMnu3Fu_W`mqdoM?CD_*AY~v5AGv_D{0N zm#0WyKns}~3y*)L^HX;7t*YwPMsAhD14~v$*G~f@ygxnivcQEPX!(~=3uYqHTC~#5 zn;B^Q%j~0}uQeFmSfmsRo=VorHuaT_w28tf*2oGS0g|-@g<{CvN^w4H%0>HJsDWau zvFHc-SwBS4i`+-T>3R30ORIoDL%=pGRswzQTne{Y_y5IxqZ$S(bN8)Mofo%hnJKm| zufz}Ocn3vaMHN1gMPopeg-C!e+mcHwZln#^4M-V! zDm)+?lUZXbYY3z>uYq8Y%wU6N&{~<#u_Z=_M-U7d;*4fSBW)H6;3QZW?yU8rZW}3@ zBnq{mn>tJe1_{V8$b09cH+tAHVb&+EtEjXwBaPSi5JgjD5SF>j)Y-3yTb{HdA(r{# zN4PYl8#>HN{_C0K7yg-;ZM>2BXSuG*b->e7c3c%|2sN_AuBvl3>;yYRNkA2CmR0iS zbiXH;NHaHA(kUzVUlh#<4LFsm7O0-H)PmbT&(v9(n8Cr)t*ShAy49^?(~njI?%J)Y z$P*pE)hQ>-8Cq3WY*icC>X*lEB?ofSt!mHQ>fp((j4Lj><89fqnF=sHn8* z#zSp8pLWkkE_B{Ghv(zkNP9t*=kiv@8X|8CpHSW?CL&mbbx9;>SM6R-J6G=4GZ{f5 zH1|NZ-&L!`shunKI-UF5Y;FZeeEQsxdJ;uoTPJLx_hBRO!_GNIFo$4=OSjob=90g|fX~R@ z_OZiY8_4{9;wQ96Il)(r`R2MlUR4<{=4cu zR~^7Jt|&7@0f1`X#}2bYY^kld64+%d-JHB%U!h zw0eB|5HYb58*jBHeMLirpJ2EZ`m1Ju{w2%-D_tHQp+36bbbTxeh{Aj6- zr%eDyS5hmI^{L_0kUSjKnMAfhglXi5q+vEf(`L}yrlPjKt>B)5U^OT8rR>-l4#PMw zgb`=0_dDs-C|)0kvxZdLmi8s0KF?V-RJRRIv$kX4%8=Q5XHB+}*!p%H4;at!=)7An z=-OYmcw*_%dpf;sFxW9Rx)aQDEqSBc*FH}ytIJKcIz#(|7lx#<8DbUQe^cs*vf`Gc zCdMnHDTU)Ue(7wBOZZouLd&Mkj57nzY0jzU{?ojB(J46<=R%3Sr{TNLJ7P*DmT0#@ z9{g(Y6)YjY)W|jLPt!j7l+D>o){)e=d=STzclYTx7uS{6I06yj!|V1pmN%FO)dWn% UopCE}y;+~BSL)OCSL-YP0VJOM+5i9m literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/http.py b/pym/calculate/contrib/spyne/util/http.py new file mode 100644 index 0000000..3e21a8a --- /dev/null +++ b/pym/calculate/contrib/spyne/util/http.py @@ -0,0 +1,66 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +import sys +import time + +from time import strftime +from time import gmtime +from collections import deque + +# 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): + """Generate a HTTP response cookie. No sanity check whatsoever is done, + don't send anything other than ASCII. + + :param k: Cookie key. + :param v: Cookie value. + :param max_age: Seconds. + :param domain: Domain. + :param path: Path. + :param comment: Whatever. + :param secure: If true, appends 'Secure' to the cookie string. + """ + + retval = deque(['%s=%s' % (k, v)]) + + if max_age is not None: + retval.append("Max-Age=%d" % max_age) + assert time.time() < sys.maxint + + 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))) + if domain is not None: + retval.append("Domain=%s" % domain) + if path is not None: + retval.append("Path=%s" % path) + if comment is not None: + retval.append("Comment=%s" % comment) + if secure: + retval.append("Secure") + + return '; '.join(retval) diff --git a/pym/calculate/contrib/spyne/util/http.pyc b/pym/calculate/contrib/spyne/util/http.pyc new file mode 100644 index 0000000000000000000000000000000000000000..27e46fec341cfdd7aec596298e005a2f15d87485 GIT binary patch literal 1555 zcmcIjQEwYX5S~5zY{zxdB1%g^LJQI6??cYDX} zI>eGIA;N#)r|`t@;Dw*S8xK6fw|l-M{sEl5do%OR&FnWbTl;&v{nwwre;?BNY2f`8 zmX5GtMT`=n@s-SI%$(h$gi-3z*du2BYEG}wxK`?QO6rvQH1?t6lj<*<6#4WEfR;6m zx;A6{FP@VwgJ@bdyD830oXXN-Jtpb3?n95{4+|MKA#GtJ`z7(V0j0 zCX6l_y=~IUqiCDvTU7i?t0v8$de(RkFf%op)#wtR*J3x{i;Trb%QIpJ;gOPY0UEwsfD*JDhJHD%x*)3kL@INXXQR>&YU*Z2$ zc$-%KHQu0No2?IW%Ti{D8g*y}x2Dxc-P^WCXdpe8N*2OMF8GVn)0e!EI?t4rJj}9r zEPMPU<65ZLEO|JU;hg_C6-H(*nZ|0uGc$#onF_@Z zMu$g7y|!~5`19jaZHK&MXMOG1TS`@u!;%eD3@lN3NNw|d&QFf;`U#7=x3CSZ6(de` zf*v~elAN>IJBDe;>6T?Els#6)?7(!OwJc1Wsb@uz70xS-)er~`-Nm&*XIZSe_OQm9 z=59a7eIZ&m&}A(9?2N&M!?r~MrB zm#Ig+&-ywxaz7X093!LqI$tWe|ETxyaqr=i{d@_Jo}5fddw*f#q(3z#@8NrUK_=_F z@w&VVAH$?S!A3g|ybgPZedyg`@3PzMF6-P_4R*(K%!iik(Dva*ZEWeoEJ|V9(Q^16q-%2j7sD2^e353+B9UL-hpao;I;;ay`1xDxKiJP+IsgCw literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/invregexp.py b/pym/calculate/contrib/spyne/util/invregexp.py new file mode 100644 index 0000000..1e7f1e5 --- /dev/null +++ b/pym/calculate/contrib/spyne/util/invregexp.py @@ -0,0 +1,322 @@ + +# +# invRegex.py +# +# Copyright 2008, Paul McGuire +# +# The pyparsing license follows: +# +######### +# +# 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. +# +######### +# +# pyparsing script to expand a regular expression into all possible matching +# strings +# +# Supports: +# - {n} and {m,n} repetition, but not unbounded + or * repetition +# - ? optional elements +# - [] character ranges +# - () grouping +# - | alternation +# + +__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 + + +class CharacterRangeEmitter(object): + def __init__(self, chars): + # remove duplicate chars in character range, but preserve original order + seen = set() + self.charset = "".join(seen.add(c) or c for c in chars if c not in seen) + + def __str__(self): + return '[' + self.charset + ']' + + def __repr__(self): + return '[' + self.charset + ']' + + def make_generator(self): + def gen_chars(): + for s in self.charset: + yield s + return gen_chars + + +class OptionalEmitter(object): + def __init__(self, expr): + self.expr = expr + + def make_generator(self): + def optional_gen(): + yield "" + for s in self.expr.make_generator()(): + yield s + return optional_gen + + +class DotEmitter(object): + def make_generator(self): + def dot_gen(): + for c in printables: + yield c + return dot_gen + + +class GroupEmitter(object): + def __init__(self, exprs): + self.exprs = ParseResults(exprs) + + def make_generator(self): + def group_gen(): + def recurse_list(elist): + if len(elist) == 1: + for s in elist[0].make_generator()(): + yield s + else: + 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 + + return group_gen + + +class AlternativeEmitter(object): + def __init__(self, exprs): + self.exprs = exprs + + def make_generator(self): + def alt_gen(): + for e in self.exprs: + for s in e.make_generator()(): + yield s + + return alt_gen + + +class LiteralEmitter(object): + def __init__(self, lit): + self.lit = lit + + def __str__(self): + return "Lit:" + self.lit + + def __repr__(self): + return "Lit:" + self.lit + + def make_generator(self): + def lit_gen(): + yield self.lit + + return lit_gen + + +def handle_range(toks): + return CharacterRangeEmitter(srange(toks[0])) + + +def handle_repetition(toks): + toks = toks[0] + if toks[1] in "*+": + raise ParseFatalException("", 0, "unbounded repetition operators not supported") + if toks[1] == "?": + return OptionalEmitter(toks[0]) + if "count" in toks: + return GroupEmitter([toks[0]] * int(toks.count)) + if "minCount" in toks: + mincount = int(toks.minCount) + maxcount = int(toks.maxCount) + optcount = maxcount - mincount + if optcount: + opt = OptionalEmitter(toks[0]) + for i in range(1, optcount): + opt = OptionalEmitter(GroupEmitter([toks[0], opt])) + return GroupEmitter([toks[0]] * mincount + [opt]) + else: + return [toks[0]] * mincount + + +def handle_literal(toks): + lit = "" + for t in toks: + if t[0] == "\\": + if t[1] == "t": + lit += '\t' + else: + lit += t[1] + else: + lit += t + return LiteralEmitter(lit) + + +def handle_macro(toks): + macroChar = toks[0][1] + if macroChar == "d": + return CharacterRangeEmitter("0123456789") + elif macroChar == "w": + return CharacterRangeEmitter(srange("[A-Za-z0-9_]")) + elif macroChar == "s": + return LiteralEmitter(" ") + else: + raise ParseFatalException("", 0, "unsupported macro character (" + macroChar + ")") + + +def handle_sequence(toks): + return GroupEmitter(toks[0]) + + +def handle_dot(): + return CharacterRangeEmitter(printables) + + +def handle_alternative(toks): + return AlternativeEmitter(toks[0]) + + +_parser = None +def parser(): + global _parser + if _parser is None: + ParserElement.setDefaultWhitespaceChars("") + 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" + + reRange = Combine(lbrack + SkipTo(rbrack, ignore=escapedChar) + rbrack) + 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("*+?")) + ) + + reRange.setParseAction(handle_range) + reLiteral.setParseAction(handle_literal) + reMacro.setParseAction(handle_macro) + reDot.setParseAction(handle_dot) + + 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), + ]) + + _parser = reExpr + + return _parser + + +def count(gen): + """Simple function to count the number of elements returned by a generator.""" + i = 0 + for s in gen: + i += 1 + return i + + +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 + """ + invReGenerator = GroupEmitter(parser().parseString(regex)).make_generator() + return invReGenerator() + + +def main(): + tests = r""" + [A-EA] + [A-D]* + [A-D]{3} + X[A-C]{3}Y + X[A-C]{3}\( + X\d + foobar\d\d + foobar{2} + foobar{2,9} + fooba[rz]{2} + (foobar){2} + ([01]\d)|(2[0-5]) + ([01]\d\d)|(2[0-4]\d)|(25[0-5]) + [A-C]{1,2} + [A-C]{0,3} + [A-C]\s[A-C]\s[A-C] + [A-C]\s?[A-C][A-C] + [A-C]\s([A-C][A-C]) + [A-C]\s([A-C][A-C])? + [A-C]{2}\d{2} + @|TH[12] + @(@|TH[12])? + @(@|TH[12]|AL[12]|SP[123]|TB(1[0-9]?|20?|[3-9]))? + @(@|TH[12]|AL[12]|SP[123]|TB(1[0-9]?|20?|[3-9])|OH(1[0-9]?|2[0-9]?|30?|[4-9]))? + (([ECMP]|HA|AK)[SD]|HS)T + [A-CV]{2} + 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') + + for t in tests: + t = t.strip() + if not t: + continue + + print('-' * 50) + print(t) + try: + print(count(invregexp(t))) + for s in invregexp(t): + print(s) + + except ParseFatalException as pfe: + print(pfe.msg) + print() + continue + + print() + + +if __name__ == "__main__": + main() diff --git a/pym/calculate/contrib/spyne/util/invregexp.pyc b/pym/calculate/contrib/spyne/util/invregexp.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bb3e2ca1148137f551f06d7a700fa9baff7a79e0 GIT binary patch literal 13040 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/meta.py b/pym/calculate/contrib/spyne/util/meta.py new file mode 100644 index 0000000..81f8da0 --- /dev/null +++ b/pym/calculate/contrib/spyne/util/meta.py @@ -0,0 +1,139 @@ +# encoding: utf-8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""Metaclass utilities for +:attr:`spyne.model.complex.ComplexModelBase.Attributes.declare_order` +""" + +import sys +import inspect + +from functools import wraps +from itertools import chain +from warnings import warn + +from spyne.util.odict import odict + + +class ClassNotFoundException(Exception): + """Raise when class declaration is not found in frame stack.""" + + +class AttributeNotFoundException(Exception): + """Raise when attribute is not found in class declaration.""" + + +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. + + Based on https://gist.github.com/DasIch/5562625 + """ + + def __new__(cls, name, bases, attributes): + try: + constructor = attributes["__new__"] + except KeyError: + return type.__new__(cls, name, bases, attributes) + + 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')): + break + else: + return constructor(cls, name, bases, attributes) + + try: + cls.__prepare__ + except AttributeError: + return constructor(cls, name, bases, attributes) + + if isinstance(attributes, odict): + # we create class dynamically with passed odict + return constructor(cls, name, bases, attributes) + + current_frame = sys._getframe() + class_declaration = None + + while class_declaration is None: + literals = list(reversed(current_frame.f_code.co_consts)) + + for literal in literals: + if inspect.iscode(literal) and literal.co_name == name: + class_declaration = literal + break + + else: + if current_frame.f_back: + current_frame = current_frame.f_back + else: + raise ClassNotFoundException( + "Can't find class declaration in any frame") + + def get_index(attribute_name, + _names=class_declaration.co_names): + try: + return _names.index(attribute_name) + except ValueError: + 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.") + raise AttributeNotFoundException(msg) + + by_appearance = sorted( + attributes.items(), key=lambda item: get_index(item[0]) + ) + + namespace = cls.__prepare__(name, bases) + for key, value in by_appearance: + namespace[key] = value + + 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__)) + + return new_cls + + try: + attributes["__new__"] = wraps(constructor)(preparing_constructor) + except: + warn("Wrapping class initializer failed. This is normal " + "when running under Nuitka") + + return type.__new__(cls, name, bases, attributes) diff --git a/pym/calculate/contrib/spyne/util/meta.pyc b/pym/calculate/contrib/spyne/util/meta.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c5069abb7126db6e7fb0f24adbb87c1b73e52c9a GIT binary patch literal 4377 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 [key, prev, next] + if iterable is not None: + self |= iterable + + def __len__(self): + return len(self.map) + + def __contains__(self, key): + return key in self.map + + def add(self, key): + if key not in self.map: + end = self.end + curr = end[PREV] + curr[NEXT] = end[PREV] = self.map[key] = [key, curr, end] + + def extend(self, keys): + for key in keys: + if key not in self.map: + end = self.end + curr = end[PREV] + curr[NEXT] = end[PREV] = self.map[key] = [key, curr, end] + + def discard(self, key): + if key in self.map: + key, prev, next = self.map.pop(key) + prev[NEXT] = next + next[PREV] = prev + + def __iter__(self): + end = self.end + curr = end[NEXT] + while curr is not end: + yield curr[KEY] + curr = curr[NEXT] + + def __reversed__(self): + end = self.end + curr = end[PREV] + while curr is not end: + yield curr[KEY] + curr = curr[PREV] + + def pop(self, last=True): + if not self: + 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)) + + def __eq__(self, other): + if isinstance(other, oset): + return len(self) == len(other) and list(self) == list(other) + return set(self) == set(other) + + @property + def back(self): + return self.end[1][0] + +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(o) + print(o.end) + + o = oset() + print(o.back) + + o = oset([3]) + print(o.back) diff --git a/pym/calculate/contrib/spyne/util/oset.pyc b/pym/calculate/contrib/spyne/util/oset.pyc new file mode 100644 index 0000000000000000000000000000000000000000..305f6738235a8b72dc34d991b038c2d95ef82ad9 GIT binary patch literal 4183 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 Q4Z4kXx83Zv+pTu%FC?-EG5`Po literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/simple.py b/pym/calculate/contrib/spyne/util/simple.py new file mode 100644 index 0000000..164be68 --- /dev/null +++ b/pym/calculate/contrib/spyne/util/simple.py @@ -0,0 +1,57 @@ + +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +"""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): + """Wraps `services` argument inside a WsgiApplication that uses Soap 1.1 for + both input and output protocols. + """ + + 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()) + + 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): + """Wraps `services` argument inside a PyramidApplication that uses Soap 1.1 + for both input and output protocols. + """ + + 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()) + + return PyramidApplication(application) diff --git a/pym/calculate/contrib/spyne/util/simple.pyc b/pym/calculate/contrib/spyne/util/simple.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c09ea7c72c8c7d5a22be3ee1f7b69491a36f6317 GIT binary patch literal 1603 zcmc&!&2G~`5FY=;Euj^mfRN~AkGaH=3n~|cK;>MJD^w{LcWZCc751*>T^B`4PvNzA z6CQyZ4*)akvF&(z{CxXOf^XaXuU|f&Rq>}F7Iv|f@6w4L?Di1D0Y!O=yp!A^%;Iapv4Pg#2M=fr!{T|Fi zLSXL00=+lrxByuA!6hou8o|PYqv0kcFer{2UK@5|L~|i?VNMutrmgE40g;7ZoE@8~ zTr0oBrZvK_BdnVxal+1Y(`WddYJ1M4s$1)j(XFNJ6T+i&eR(tXD zv5{7cYMy`KQ(?xg&e2|+JdKn6Q9VPCSWKs#e%xAF;sv5)j1eAVOe!}c?j%XJmU$OV zrjG)mfj97Xyj}l4km~~T{{^|;%^F_G;?MkYv_X#jE5F?9bj;epa(>O#y&*BIds5<~ zBTh<_*sD@JI&!HUC< z;nZrD6*|u{yBdi#Lb)d093E;VQkpdT2*ox3*4dZR46i!9y$RUFJTEF;w551S)flQP O3I;*sZEZ(k;Qas~O^|;8 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/six.py b/pym/calculate/contrib/spyne/util/six.py new file mode 100644 index 0000000..d13ddbe --- /dev/null +++ b/pym/calculate/contrib/spyne/util/six.py @@ -0,0 +1,985 @@ +# 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.14.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 + + +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 __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 + +_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"), + 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, text_type): + return s.encode(encoding, errors) + elif isinstance(s, binary_type): + return s + else: + raise TypeError("not expecting type '%s'" % type(s)) + + +def ensure_str(s, encoding='utf-8', errors='strict'): + """Coerce *s* to `str`. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + if not isinstance(s, (text_type, binary_type)): + raise TypeError("not expecting type '%s'" % type(s)) + if PY2 and isinstance(s, text_type): + s = s.encode(encoding, errors) + elif PY3 and isinstance(s, binary_type): + s = s.decode(encoding, errors) + return s + + +def ensure_text(s, encoding='utf-8', errors='strict'): + """Coerce *s* to six.text_type. + + For Python 2: + - `unicode` -> `unicode` + - `str` -> `unicode` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + if isinstance(s, binary_type): + return s.decode(encoding, errors) + elif isinstance(s, text_type): + return s + else: + raise TypeError("not expecting type '%s'" % type(s)) + + +def python_2_unicode_compatible(klass): + """ + A 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) \ No newline at end of file diff --git a/pym/calculate/contrib/spyne/util/six.pyc b/pym/calculate/contrib/spyne/util/six.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af02b04aad46eb0c427f54506d2ec51dba8b6608 GIT binary patch literal 36324 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 0: + kt, = set((type(s) for s in S)) + + if v is not None: + vt = type(v) + + retval = tdict(kt, vt) + + for s in S: + retval[s] = v + + return retval + + def repr(self): + return "tdict(kt=%s, vt=%s, data=%s)" % \ + (self._kt, self._vt, super(tdict, self).__repr__()) diff --git a/pym/calculate/contrib/spyne/util/tdict.pyc b/pym/calculate/contrib/spyne/util/tdict.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7782a659d1053db0d2112cdda03d208028be6e10 GIT binary patch literal 3947 zcmcgv-EJF26h5=-IC1JUX+lc{rFDf$T|u0-K%r78^cNwJFE$Z@sMX@GC&||K+T9sP z4N5MceFrXh7T$zM;Eo4??>lQZRw)%X#`esfnKL_ce!e;9IQ(;A{*T{(`yr9hC&cp$ zG-933tI5uJqyIB9Rg|7pdS2`?9nNw14BV=;EBeZUMCAOa;Ygp5WybCO@@ytj-Of$H3uhktEb1mo6os4@nn)M0}_942s z_q1QLpIJ|f#>uWtI&s#=u>}e+^m9j?y~#nxbH~v;ojp&04F~O(w{`BSTRYp`_EZ~3 z@-aFQi&}LIMLX97wKjD5S~q=k?W489zTfRR=x$8g^%=m|q+Ew7aHgZD0cxI!?3H$MM_P-ksucrHZKpr_G|N7A>d-Rg)0) z6pqg?(HzBZ3+@bOnuVZT5Yb4Ulkrrgk7)b`n&YWr5_)ai?r{Enbbbu>$G9PZxQhZ4 z!?D0SK!@MYMu@y4Mbs_xcr|rt=6owlY{V1PksAQgy*%&d>bTqv@;Z+!bSBlY`_U4f z(^Z|0yMm@p5VQOm<@JKUtbFh~<)ahWIa0NjNv)te(o(fk;Oh;VuAZ|v`eU@$=ox|i zADzr)g*i%!h2|Iw|7s3GtT2Zn`-M5wIukZ|gX@?!rfUv{lIv)W{-@hdzS8xpU@|xt z(1&u!dAN`OK4vjsKu5$c7%w3|Vt`Wjy5Yd)5$|yk_F`u}B26!j|9{2bgcP5njc~AJ z68eLp(nDX9vx9E`+z1N9yE?ldpz~oUn^{dtFhXZu@>^nz8No*F0DflVyQgQFj_y7@ zB@ggUNe+?VG{+s3jLq2x1kvh9y-=@=tjWi<%GfcZ($Sz!0Fw zLoB^ubW}&{nx!-{VHdEFaR5!=kZ7Kfr>D8^-G@tZ2=l@@fN2>RO=T10x*DgMLKJzC zx@l4tR*tzI9(i~|4iOeWYbN~GJW+3sGrC@VYQ^eF%Q8i6^m<0{uJB84YHC4N4 zVUggdQB)62v(ETADoe9g&&ILmosZ+<|5qFr0b-HzDG(@jq)~!^iI^uMz7g@JYTin^ zsPB6g#d15kM2?m-Ag1ed1>##cMQiG^Szf7xl@h+?N~v0@mP50+)KqtPiXX@AegbW& m1u{wQ`~9wBrTB-yzn2BH!Jn?+YW*99y>GIvQSX$)rSNYyRS)O@ literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/spyne/util/test.py b/pym/calculate/contrib/spyne/util/test.py new file mode 100644 index 0000000..850f20d --- /dev/null +++ b/pym/calculate/contrib/spyne/util/test.py @@ -0,0 +1,97 @@ +# encoding: utf8 +# +# spyne - Copyright (C) Spyne contributors. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# + +from pprint import pformat + +from spyne.util import urlencode + + +def _start_response(code, headers): + print(code, pformat(headers)) + +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): + if headers is None: + headers = {} + if body_pairs is None: + body_pairs = [] + + body_pairs = [(k,str(v)) for k,v in body_pairs] + + request = { + u'QUERY_STRING': urlencode(body_pairs), + u'PATH_INFO': '/%s' % mn, + u'REQUEST_METHOD': u'GET', + u'SERVER_NAME': u'spyne.test', + u'SERVER_PORT': u'0', + u'wsgi.url_scheme': u'http', + } + + print(headers) + request.update(headers) + + out_string = [] + t = None + for s in app(request, _start_response): + t = type(s) + out_string.append(s) + + if t == bytes: + out_string = b''.join(out_string) + else: + out_string = ''.join(out_string) + + return out_string + +from os import mkdir, getcwd +from os.path import join, basename + + +def show(elt, tn=None, stdout=True): + if tn is None: + import inspect + + for frame in inspect.stack(): + if frame[3].startswith("test_"): + 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 + out_string = etree.tostring(elt, pretty_print=True) + if stdout: + print(out_string) + + fn = '%s.html' % tn + if basename(getcwd()) != 'test_html': + try: + mkdir('test_html') + except OSError: + pass + + f = open(join("test_html", fn), 'wb') + else: + f = open(fn, 'wb') + + f.write(html.tostring(elt, pretty_print=True, doctype="")) diff --git a/pym/calculate/contrib/spyne/util/test.pyc b/pym/calculate/contrib/spyne/util/test.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b5eb6667a2d472907c789b588139e14ade557ea GIT binary patch literal 2735 zcmcIm+j1L45bfEOWl5HN$;DK-1P986DpaI6Q066-A{7feP?60_5TXJWSv!_w@69{2 z*rMbrisXe);vs*+C-BA-FTm-RbNc|>+TNYsp6;HWb9&bOyH@$@&*wi4==`sM`{%gK z?+^igibA4DQBRTLu|uIlkxM-nW0#&0^$HZ=SD|2zo;lPjz8FGNq-QXl7fBNqb_)g=qrWsp(EA0=C`a^A+CY{9k)}6-2CykBGTj>NA z4Luyr^v&Fk!=}~7HZXq)9(`l`ne{Vm(j+$e8b{)6NLgN;Nh0kJ`e8WWRdI%MxW3{y zY|2ZM)lD6mx^#$T5kWITSI}Sw+*ib9DUZ(D4RakBelbqCgF}unGJFLaRXjCWC$s zH{g99w-Q5klWDL(n`cE%XM1N_q(he_aHIx7?QV_Ifg zSWM^X5ME@cj-S)xX^DY<C%X{K?y57U~ zw&C4vuA7`;wRgX}<3DVFv757YyVcDXarau7(CPY*THT%9t(;3OXl^iIb0%Y_<$c@o z{Pz7vt(+-&`*rQ!uGh_Zk4Dy}IfI)4*8o9%GZ^Ve1Fhg1#}}@(lUNJpjLkeDIAbkO zgTB?C08_*y)dE5wRL6l}cYnee@!P{>9M?Hfk3ow)L)VHuUX*3+eiBUlv_H-awizf9 z`Lhr_)5kfSh*^?b@Gu+4Lou)-FBI<{FZF#~rU5~!s>*yhA3Lt9sRcDJ{}p#m)tsU# zs#UyQajNQ)v*gUW6_X%33dWffXQ=JqB#<{AQ%N|y-#0q$M_PIZZyz^MAdz9XaWXY1E#?MU@u!2RRJnt!?nXXMlA>hT7XUG_UN~( zXNvZY*9pJJC_5;F>AxwaBge!sAcq5pgTn!kR*e4zCJAU|tFTr~3ZVZF0u#1(cw$A! z$i%6UU6hswUkh~Pq6w(UBB8Tlh)C*jyg~)LOh*;U{voAQtmr$tLiQ3{FwM|D5C#pQ z!hFIjC|_!(6*|03Oy}2f3ThM}s&Y60%GRkf*4uJWjRktVH;hmp4GB*SRHMTK!}@j8 zSU2Vdo`NL)$gb_{wXpxoWUU_uYiZw@HJ-S}+tzq>ERAdw3i7qhv_@TU5N6t1fE%c_ zhBp?D#Z36c!DYmZIN2A(2g$&KOop?)dt+<&LHEgCYmKe$)fqD$_W-dR$0pSSD-m%% z4UU8*a#ER-u^kDz4*W1d$2M|K`Tih8^1eSiJbca{1J0#&I?$;dC$ZEaJdHx{1CI6~ zM-$d2=iK8ub+cT1ObqWji}%=wSGU_~Wm%Gmj|7cihH@_GNrt0LJ{6>y=+H_Vu(1%s z*Z}PI_#Btz9AwB$3lKhPla+K<}z^SzT6d zsVl1FE;*~}DrjGFD!9995lx}syaV#L>&q~grKPg>@&Pm3AO7-a@E3-3Q)!{Hryk=) zI*u$cF;Z43u+%m&jkIq^Qqo!NH+aHbh*xE}s9KZ|CmIy}Q8akAXVc0>gYC!-ZJKZA zHjAp!(6-%29o--$0tA3<4bA<5?#PH+luEHG8hku9QW**-MobmRQ6N=AP68?KQZ8oM z1LEUAUaV4Hf6|fThHxqRCYQQ(Vhtx$SdEvBTu1xW$n$l6xA4}HNHQlc-s4H@Pp-;w zlS6y+a)cdl^7G$i3u^6!9Husb70wRP;g}kz5 z#o^rLg{yi+YCQ=KhkdInh*1?{#rF^%mgS(-;nEIEC=VsMz*QG&F-doAx?j!nImwH> zN|LtHisw4p-_|Lf+k1v1bV_&NJcbVdE`&BZ(avo^>K?kX+s~h^-t7)Y)$X9U)4A7m zSiUmsrTe`d>$+|@D(uRg&h5`Sw^vt&BdqAyogF{kJ*@J6SLxCjj$>6V1JaPRzAN zD|p{5m_@T3g!sK|QYuk5CBqyB=m0{@i4E;z+UX@CFkP(~26xdMT`VT$58H&W-{QgR z=nz2A)DzVYk#=8`g`}M_88m_~$FoMZgPMhfW{R3htJrm`93YbD>gbmHB&v2nERrZn zdxZv?kFuIW8fUkhI$j})8C)^>6067g=&Dl58WTBaB=U2wKV1aL<9j^%B04dlX$DtJ z1D^?&RAY@RNDssp(ecra_yTx)KyDImkZLlJy=ucjZy58Km?WvgpqFI`1NzDvOAH3p zt}Ul)?o}M~0L>A2F-!QUp;VSl4SfJ%M-5$na**m)p3mthlh4`FWx2szhV=>r zumP`X5Y#|yCq68AgxVW3%;HPz2>euyt{A9EqKH3)=%|I5PhVlV#RM&X*+y@ z#{uHDXs#QrjptYsV{%;QJRK&We5{o&&?1EuU<=X-6AmH?*+xsHLEhg(=~M8r=%g_& zUOuzZg$k6G2iMP28!NZ2aN;z&wCE(xR;(KcunFNb68G&$-$zzC^d*c{N1vw3!1x_# z`5oFM%Pg7}at(s7hLB9q;A1-X!Ni(Q-T);f6nJD{1|h3aB6iJlKq;eMg$%1pi#$Ydkgh(isLYvGs;S zTV$u%HNK3&>3aABobVWJoLm-OQ9nAErf0|Z#EED9P3^2_>FMmWlDyWZwAH?-&f7Zm zd>ThM_9@y~7t#xC7JQ6zu)=x%zD43Cx8C<_93Ft&%^o@k9h(S<1Z*B zY75#IBziMWB`KBE_GsTDv6t0I2$2bT8+-JbXum>ng?9WZ;*;O_`2sszgD8%3-45+g zF$RTJaT%$I9oWt)24Y@9V~Ng)27(c^Bb6-*e}2vJ=!qK@Ul9Q6F9v_C?UKr1z3KUCzs? zyI;solD;osjwLsIfoJH_uR842|FD0jR~b6GLT6QqJ>~~-10i z|5lCkx!XfirMVHHb57qU>U^a=Aeb^Qgq@-owWk>ojI($?fj+S2Gqc+X1Vv1?H+l?K zvjTyLgQW{HnS1H*lj9yN3ECAMKo`g+5#f?;4__sxOI7CcYS~zS0CwPGRU5AXL!=5H z3prt4V;7W02WfJ&{wOGV_G6x{)gK220V_oqwZf({fhl^KT3M^FKCG{qb*$s$1yI00+ZJ#>fF^sh(?`n`iY7+b1FZP1%lXWz-OZ z*Q(IN_Bg0}+4$`^s%)fT`zQ`K*M`V|aT&X<#i$phNwf$WRTir(>Mg2nVysyV+j-VB zc5>PHSK-;<-mJTMpx(Gk7bhkPb==@C92Z7e=Tc@#o>`uZ(=aWSajy(S8K*0YIJC;? z;v}+e^G27-8JTkxTQ0d}jM5gFo@<@!1~laJT^>e;Hnd#0<>aZoiM{Gt9Uk&*n8PGH zL{p~0ggdmkjupNN4esI6Dd&;-J3?zqIG6iq)-{Yvj1NVbMK;e<" % l + + if callable(cls_attrs.logged): + try: + return cls_attrs.logged(obj) + except Exception as e: + logger.error("Exception %r in log_repr transformer ignored", e) + logger.exception(e) + pass + + if issubclass(cls, AnyDict): + retval = [] + + if isinstance(obj, dict): + if logged == 'full': + for i, (k, v) in enumerate(obj.items()): + retval.append('%r: %r' % (k, v)) + + elif logged == 'keys': + for i, k in enumerate(obj.keys()): + if i >= MAX_DICT_ELEMENT_NUM: + retval.append("(...)") + break + + retval.append('%r: (...)' % (k,)) + + 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),)) + + elif logged == 'keys-full': + for k in obj.keys(): + retval.append('%r: (...)' % (k,)) + + elif logged == 'values-full': + for v in obj.values(): + retval.append('(...): %r' % (v,)) + + elif logged is True: # default behaviour + for i, (k, v) in enumerate(obj.items()): + if i >= MAX_DICT_ELEMENT_NUM: + retval.append("(...)") + break + + retval.append('%r: %s' % (k, + log_repr(v, parent=k, tags=tags))) + else: + raise ValueError("Invalid value logged=%r", logged) + + return "{%s}" % ', '.join(retval) + + else: + if logged in ('full', 'keys-full', 'values-full'): + retval = [repr(s) for s in obj] + + else: + for i, v in enumerate(obj): + if i >= MAX_DICT_ELEMENT_NUM: + retval.append("(...)") + break + + retval.append(log_repr(v, tags=tags)) + + return "[%s]" % ', '.join(retval) + + if (issubclass(cls, Array) or (cls_attrs.max_occurs > 1)) and not from_array: + if id(obj) in tags: + return "%s(...)" % obj.__class__.__name__ + + tags.add(id(obj)) + + retval = [] + + subcls = cls + if issubclass(cls, Array): + subcls, = cls._type_info.values() + + if isinstance(obj, PushBase): + return '[]' + + if logged is None: + logged = cls_attrs.logged + + for i, o in enumerate(obj): + 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)) + + if issubclass(cls, ComplexModelBase): + if id(obj) in tags: + return "%s(...)" % obj.__class__.__name__ + + tags.add(id(obj)) + + retval = [] + i = 0 + + for k, t in cls.get_flat_type_info(cls).items(): + if i >= MAX_FIELD_NUM: + retval.append("(...)") + break + + if not t.Attributes.logged: + continue + + if logged == '...': + retval.append("%s=(...)" % k) + continue + + try: + v = getattr(obj, k, None) + except (AttributeError, KeyError, DetachedInstanceError): + v = None + + # HACK!: sometimes non-db attributes restored from database don't + # get properly reinitialized. + if isclass(v) and issubclass(v, ModelBase): + continue + + polymap = t.Attributes.polymap + if polymap is not None: + t = polymap.get(v.__class__, t) + + if v is not None: + retval.append("%s=%s" % (k, log_repr(v, t, parent=k, tags=tags))) + i += 1 + + return "%s(%s)" % (cls.get_type_name(), ', '.join(retval)) + + if issubclass(cls, Unicode) and isinstance(obj, six.string_types): + if len(obj) > MAX_STRING_FIELD_LENGTH: + return '%r(...)' % obj[:MAX_STRING_FIELD_LENGTH] + + return repr(obj) + + if issubclass(cls, File) and isinstance(obj, FileData): + return log_repr(obj, FileData, tags=tags) + + retval = repr(obj) + + if len(retval) > MAX_STRING_FIELD_LENGTH: + retval = retval[:MAX_STRING_FIELD_LENGTH] + "(...)" + + return retval + + +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}) + 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) + 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') + + if put_not_found == 'raise': + def put_not_found(obj): + raise ResourceNotFoundError('%s.id=%d' % (T_name, obj.id)) + + 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}) + 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 + + else: + if ctx.udc.session.query(T).get(obj.id) is None: + # this is to prevent the client from setting the primary key + # of a new object instead of the database's own primary-key + # generator. + # Instead of raising an exception, you can also choose to + # ignore the primary key set by the client by silently doing + # obj.id = None in order to have the database assign the + # primary key the traditional way. + put_not_found(obj.id) + + else: + ctx.udc.session.merge(obj) + + return obj.id + + @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: + raise ResourceNotFoundError(obj_id) + + ctx.udc.session.query(T).filter_by(id=obj_id).delete() + + return WriterService diff --git a/pym/calculate/contrib/spyne/util/web.pyc b/pym/calculate/contrib/spyne/util/web.pyc new file mode 100644 index 0000000000000000000000000000000000000000..25817eb33e31a30494c9bff4cd29f329b65930c3 GIT binary patch literal 9357 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 0] + + script = '' + if len(fragments) > 0: + script = fragments[0] + + app = self.mounts.get(script, self.default) + if app is self.default: + return app(environ, start_response) + + 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:]))) + + if pi == '/': + environ['PATH_INFO'] = '' + else: + environ['PATH_INFO'] = pi + + return app(environ, start_response) + + +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. + + :param apps: List of tuples containing (application, url) pairs + :param port: Port to listen to. + :param static_dir: The directory that contains static files. Pass `None` if + you don't want to server static content. Url fragments in the `apps` + argument take precedence. + :param interface: The network interface to which the server binds, if not + specified, it will accept connections on any interface by default. + """ + + import twisted.web.server + import twisted.web.static + + 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) + logging.info("registering static folder %r on /" % static_dir) + root = twisted.web.static.File(static_dir) + else: + root = Resource() + + for app, url in apps: + resource = WSGIResource(reactor, reactor, app) + logging.info("registering %r on /%s" % (app, url)) + root.putChild(url, resource) + + site = twisted.web.server.Site(root) + reactor.listenTCP(port, site, interface=interface) + logging.info("listening on: %s:%d" % (interface, port)) + + return reactor.run() diff --git a/pym/calculate/contrib/spyne/util/wsgi_wrapper.pyc b/pym/calculate/contrib/spyne/util/wsgi_wrapper.pyc new file mode 100644 index 0000000000000000000000000000000000000000..efc9cd3e606519109e53bee25e976132d93611a3 GIT binary patch literal 4402 zcmcgv%WfOV6}{aQDNzs0mR}RZh-;Jx;tXuk;}Ir+U>I@yNDPb>p{0Q^LY!u+yGSSS1zBVHdVgP~R^^4`tM_0NrAK3Tsx}^MsBzTSI2C3_yNStl(w0@s4(3k{ zpQr4sYZ%VpWsmxBu1_BR?X;L=%PwJLep`5@2Tvv~Y>*r}jyEl%EqD3IeuJSiv8I!y z2VZS;#;0yj6_XT75rstG{h75J-{hU4M{kLqy*{Gf`}78X zHF7?kVMJ#8WL}V);Uz-+%?#zM%D}n%3^NWpJH4yQ}0C_%4t$2H-fkAa7<#@j#xTqU>&gftvNp7rKFXG zc+k}8k#$@=QacUE04oZlBJh=Ivbif*Jh4_AE)LI)DNMjDL@uZftLm&5$SZvLP^379 zb%-F@kK$&2JPgx3bz#WG(5_%0uj$|Qmc3>Fj@R%Py+uD}nOJF-U%dVp62sFlIoyQW z1c$=E2xhnpj!(p`&tCtGUCUmdVK=kyX2`7a@((^8t}o zn&aJ`=)lQZr$^^!I0g|5*Py%5sfWi9z)d=9^3_8G_PPgZzUR@Se4Y=g1xtG_UW;RF z%QZ1>KiU0l_;TyT?=FH5`BOERou|Re?cH$e$*bonhe?YgQi7zfoy4R?33jrR>0IJT z;!HwpSfsi1x`3;Tq_xhEQ&Z#;o~X~pg+|+Pk)yD&FyqJ#5D~pX!ZDJ)^JXCFU}KYx zU2v5d-oQ|pw4dft7M2HL9*s174p!-p7{r`*VfYx&+EonXt#})L1LKna34(daU-2>b z?s%&R=_P;O-zpQlOaYcT3?;F{umk~EvWvnnDPqhQnX^NqkD=Y5NG@!=RpdJ0!X79L z7b?r_qnxRph^HkRL3V|U3Jub;U9oESFg%B&lc^WQA27;SUu-b5mQw3yP$vtHL z@Cpr=X?S%?HAguz1j!Fs=IFauoYBu-KbNl2q&G+)TrX3-NpB(5!jvsGaT9oN%6yK7 z*LdS>L3-=a_q10%xI)A0oY$PIi_C6#Lvj&l5Xp{A_dTx?7A#Q$B(qDAL41>?t3c!5 zVfWpW)H;neQo%#UiwvVmP=u0y3?RWhwfzAU1OTh9#!)U9VFIXv0K#>nqeKbV)JH&D zKq!SWlN^Y{9H&50_mnMETqL@BHo+Z$l9T9EC50~W2P2eRgV;tU%}xPoj=>sykm3vp z-BfT~0`y8y9{S8C?|%T&(18HazJ{7i=O%!c7LVsHLbt%376_)u?;gXi&wztcQ%X?* zy>VgOrrO5HB4li`9J3M|RWxNvg-L2Q)h;ZE3FIscVA>#Z(-*BO=~OQj6uS)ws=Azb zU6uC4jtpE+iwRW9*MV%KTplf5F}=<51JeQ@UWSW6mUv97F6&$(S7sKO{)7>*a)8Wg z46$^=-x1yuKV>}Mi(*|$pKEtgm_u-^wpsC$K^hO_g-V)(G*95ow8wz*TzGa++DmnU z6DW{onTq0AkHrY^DWeFBPyzTnz4X8Vyk8>KQn1TkP`EGz+7=TN>+;(PSFydF-@JT( zm#YP$kL_+hm3g0?W!TYE!xveC??FIPkf394en3_2uUY9A=jz+*per5Eyo!8Nt=Y}B zq;(7Xj=@G1knIzF&@RpM!)>X$(rPYKBcw&KV4c}WH!6c$cyaOtT!G&^5y9Z3;4_>A zYkbUAw6M}Fx%ElSj}GklJS+O>Zhaw;w#Zlr(w42T6pbtF3q+=4gO4Zf=^)LLl0Zs< zT;2h86zi1s*nPS!JsTO`lHSZrI08#ikTlYbF7hMz90Vd>Wd%`ObQE>uo+*l|GqadT zOA%>mDk0(T25gwJQ+>StB;R_WU08|xEuOT$;D@g;ro8Im7p-{3yXJl3H~s6F-S%$y zH@#clZC^|h{2au=ml(uuz&l^V8QKIKqhelm4%QEN&FxL` element and returns a _Schema object. + + :param elt: The `` element, an lxml.etree._Element instance. + :param files: A dict that maps namespaces to path to schema files that + contain the schema document for those namespaces. + :param repr_: A callable that functions as `repr`. + :param skip_errors: Skip parsing errors and return a partial schema. + See debug log for details. + + :return: :class:`spyne.interface.xml_schema.parser._Schema` instance. + """ + + 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): + """Parses a schema file and returns a _Schema object. Schema files typically + have the `*.xsd` extension. + + :param file_name: The path to the file that contains the schema document + to be parsed. + :param files: A dict that maps namespaces to path to schema files that + contain the schema document for those namespaces. + :param repr_: A callable that functions as `repr`. + :param skip_errors: Skip parsing errors and return a partial schema. + See debug log for details. + + :return: :class:`spyne.interface.xml_schema.parser._Schema` instance. + """ + + if files is None: + files = dict() + + 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) diff --git a/pym/calculate/contrib/spyne/util/xml.pyc b/pym/calculate/contrib/spyne/util/xml.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c03696d7863feeb22fd01d2507d489d618687811 GIT binary patch literal 11575 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 (3, 0): + # For Python 3, __str__() and __unicode__() should be identical. + __str__ = lambda x: x.__unicode__() + else: + __str__ = lambda x: unicode(x).encode("utf-8") + +# Used instead of byte literals as they are not supported on Python versions +# prior to 2.6. +def byte_str(s="", encoding="utf-8", input_encoding="utf-8", errors="strict"): + """ + Returns a byte string version of 's', encoded as specified in 'encoding'. + + Accepts str & unicode objects, interpreting non-unicode strings as byte + strings encoded using the given input encoding. + + """ + assert isinstance(s, basestring) + if isinstance(s, unicode): + return s.encode(encoding, errors) + if s and encoding != input_encoding: + return s.decode(input_encoding, errors).encode(encoding, errors) + return s + +# Class used to represent a byte string. Useful for asserting that correct +# string types are being passed around where needed. +if sys.version_info >= (3, 0): + byte_str_class = bytes +else: + byte_str_class = str diff --git a/pym/calculate/contrib/suds/__init__.pyc b/pym/calculate/contrib/suds/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..abc072ba578b16baf84949fac75cef49dd0c4774 GIT binary patch literal 6327 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/argparser.py b/pym/calculate/contrib/suds/argparser.py new file mode 100644 index 0000000..4c06b97 --- /dev/null +++ b/pym/calculate/contrib/suds/argparser.py @@ -0,0 +1,419 @@ +# -*- coding: utf-8 -*- + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jurko Gospodnetić ( jurko.gospodnetic@pke.hr ) + +""" +Suds web service operation invocation function argument parser. + +See the parse_args() function description for more detailed information. + +""" + +__all__ = ["parse_args"] + + +def parse_args(method_name, param_defs, args, kwargs, external_param_processor, + extra_parameter_errors): + """ + Parse arguments for suds web service operation invocation functions. + + Suds prepares Python function objects for invoking web service operations. + This function implements generic binding agnostic part of processing the + arguments passed when calling those function objects. + + Argument parsing rules: + * Each input parameter element should be represented by single regular + Python function argument. + * At most one input parameter belonging to a single choice parameter + structure may have its value specified as something other than None. + * Positional arguments are mapped to choice group input parameters the + same as is done for a simple all/sequence group - each in turn. + + Expects to be passed the web service operation's parameter definitions + (parameter name, type & optional ancestry information) in order and, based + on that, extracts the values for those parameter from the arguments + provided in the web service operation invocation call. + + Ancestry information describes parameters constructed based on suds + library's automatic input parameter structure unwrapping. It is expected to + include the parameter's XSD schema 'ancestry' context, i.e. a list of all + the parent XSD schema tags containing the parameter's tag. Such + ancestry context provides detailed information about how the parameter's + value is expected to be used, especially in relation to other input + parameters, e.g. at most one parameter value may be specified for + parameters directly belonging to the same choice input group. + + Rules on acceptable ancestry items: + * Ancestry item's choice() method must return whether the item + represents a XSD schema tag. + * Passed ancestry items are used 'by address' internally and the same XSD + schema tag is expected to be identified by the exact same ancestry item + object during the whole argument processing. + + During processing, each parameter's definition and value, together with any + additional pertinent information collected from the encountered parameter + definition structure, is passed on to the provided external parameter + processor function. There that information is expected to be used to + construct the actual binding specific web service operation invocation + request. + + Raises a TypeError exception in case any argument related errors are + detected. The exceptions raised have been constructed to make them as + similar as possible to their respective exceptions raised during regular + Python function argument checking. + + Does not support multiple same-named input parameters. + + """ + arg_parser = _ArgParser(method_name, param_defs, external_param_processor) + return arg_parser(args, kwargs, extra_parameter_errors) + + +class _ArgParser: + """Internal argument parser implementation function object.""" + + def __init__(self, method_name, param_defs, external_param_processor): + self.__method_name = method_name + self.__param_defs = param_defs + self.__external_param_processor = external_param_processor + self.__stack = [] + + def __call__(self, args, kwargs, extra_parameter_errors): + """ + Runs the main argument parsing operation. + + Passed args & kwargs objects are not modified during parsing. + + Returns an informative 2-tuple containing the number of required & + allowed arguments. + + """ + assert not self.active(), "recursive argument parsing not allowed" + self.__init_run(args, kwargs, extra_parameter_errors) + try: + self.__process_parameters() + return self.__all_parameters_processed() + finally: + self.__cleanup_run() + assert not self.active() + + def active(self): + """ + Return whether this object is currently running argument processing. + + Used to avoid recursively entering argument processing from within an + external parameter processor. + + """ + return bool(self.__stack) + + def __all_parameters_processed(self): + """ + Finish the argument processing. + + Should be called after all the web service operation's parameters have + been successfully processed and, afterwards, no further parameter + processing is allowed. + + Returns a 2-tuple containing the number of required & allowed + arguments. + + See the _ArgParser class description for more detailed information. + + """ + assert self.active() + sentinel_frame = self.__stack[0] + self.__pop_frames_above(sentinel_frame) + assert len(self.__stack) == 1 + self.__pop_top_frame() + assert not self.active() + args_required = sentinel_frame.args_required() + args_allowed = sentinel_frame.args_allowed() + self.__check_for_extra_arguments(args_required, args_allowed) + return args_required, args_allowed + + def __check_for_extra_arguments(self, args_required, args_allowed): + """ + Report an error in case any extra arguments are detected. + + Does nothing if reporting extra arguments as exceptions has not been + enabled. + + May only be called after the argument processing has been completed. + + """ + assert not self.active() + if not self.__extra_parameter_errors: + return + + if self.__kwargs: + param_name = self.__kwargs.keys()[0] + if param_name in self.__params_with_arguments: + msg = "got multiple values for parameter '%s'" + else: + msg = "got an unexpected keyword argument '%s'" + self.__error(msg % (param_name,)) + + if self.__args: + def plural_suffix(count): + if count == 1: + return "" + return "s" + def plural_was_were(count): + if count == 1: + return "was" + return "were" + expected = args_required + if args_required != args_allowed: + expected = "%d to %d" % (args_required, args_allowed) + given = self.__args_count + msg_parts = ["takes %s positional argument" % (expected,), + plural_suffix(expected), " but %d " % (given,), + plural_was_were(given), " given"] + self.__error("".join(msg_parts)) + + def __cleanup_run(self): + """Cleans up after a completed argument parsing run.""" + self.__stack = [] + assert not self.active() + + def __error(self, message): + """Report an argument processing error.""" + raise TypeError("%s() %s" % (self.__method_name, message)) + + def __frame_factory(self, ancestry_item): + """Construct a new frame representing the given ancestry item.""" + frame_class = Frame + if ancestry_item is not None and ancestry_item.choice(): + frame_class = ChoiceFrame + return frame_class(ancestry_item, self.__error, + self.__extra_parameter_errors) + + def __get_param_value(self, name): + """ + Extract a parameter value from the remaining given arguments. + + Returns a 2-tuple consisting of the following: + * Boolean indicating whether an argument has been specified for the + requested input parameter. + * Parameter value. + + """ + if self.__args: + return True, self.__args.pop(0) + try: + value = self.__kwargs.pop(name) + except KeyError: + return False, None + return True, value + + def __in_choice_context(self): + """ + Whether we are currently processing a choice parameter group. + + This includes processing a parameter defined directly or indirectly + within such a group. + + May only be called during parameter processing or the result will be + calculated based on the context left behind by the previous parameter + processing if any. + + """ + for x in self.__stack: + if x.__class__ is ChoiceFrame: + return True + return False + + def __init_run(self, args, kwargs, extra_parameter_errors): + """Initializes data for a new argument parsing run.""" + assert not self.active() + self.__args = list(args) + self.__kwargs = dict(kwargs) + self.__extra_parameter_errors = extra_parameter_errors + self.__args_count = len(args) + len(kwargs) + self.__params_with_arguments = set() + self.__stack = [] + self.__push_frame(None) + + def __match_ancestry(self, ancestry): + """ + Find frames matching the given ancestry. + + Returns a tuple containing the following: + * Topmost frame matching the given ancestry or the bottom-most sentry + frame if no frame matches. + * Unmatched ancestry part. + + """ + stack = self.__stack + if len(stack) == 1: + return stack[0], ancestry + previous = stack[0] + for frame, n in zip(stack[1:], xrange(len(ancestry))): + if frame.id() is not ancestry[n]: + return previous, ancestry[n:] + previous = frame + return frame, ancestry[n + 1:] + + def __pop_frames_above(self, frame): + """Pops all the frames above, but not including the given frame.""" + while self.__stack[-1] is not frame: + self.__pop_top_frame() + assert self.__stack + + def __pop_top_frame(self): + """Pops the top frame off the frame stack.""" + popped = self.__stack.pop() + if self.__stack: + self.__stack[-1].process_subframe(popped) + + def __process_parameter(self, param_name, param_type, ancestry=None): + """Collect values for a given web service operation input parameter.""" + assert self.active() + param_optional = param_type.optional() + has_argument, value = self.__get_param_value(param_name) + if has_argument: + self.__params_with_arguments.add(param_name) + self.__update_context(ancestry) + self.__stack[-1].process_parameter(param_optional, value is not None) + self.__external_param_processor(param_name, param_type, + self.__in_choice_context(), value) + + def __process_parameters(self): + """Collect values for given web service operation input parameters.""" + for pdef in self.__param_defs: + self.__process_parameter(*pdef) + + def __push_frame(self, ancestry_item): + """Push a new frame on top of the frame stack.""" + frame = self.__frame_factory(ancestry_item) + self.__stack.append(frame) + + def __push_frames(self, ancestry): + """ + Push new frames representing given ancestry items. + + May only be given ancestry items other than None. Ancestry item None + represents the internal sentinel item and should never appear in a + given parameter's ancestry information. + + """ + for x in ancestry: + assert x is not None + self.__push_frame(x) + + def __update_context(self, ancestry): + if not ancestry: + return + match_result = self.__match_ancestry(ancestry) + last_matching_frame, unmatched_ancestry = match_result + self.__pop_frames_above(last_matching_frame) + self.__push_frames(unmatched_ancestry) + + +class Frame: + """ + Base _ArgParser context frame. + + When used directly, as opposed to using a derived class, may represent any + input parameter context/ancestry item except a choice order indicator. + + """ + + def __init__(self, id, error, extra_parameter_errors): + """ + Construct a new Frame instance. + + Passed error function is used to report any argument checking errors. + + """ + assert self.__class__ != Frame or not id or not id.choice() + self.__id = id + self._error = error + self._extra_parameter_errors = extra_parameter_errors + self._args_allowed = 0 + self._args_required = 0 + self._has_value = False + + def args_allowed(self): + return self._args_allowed + + def args_required(self): + return self._args_required + + def has_value(self): + return self._has_value + + def id(self): + return self.__id + + def process_parameter(self, optional, has_value): + args_required = 1 + if optional: + args_required = 0 + self._process_item(has_value, 1, args_required) + + def process_subframe(self, subframe): + self._process_item( + subframe.has_value(), + subframe.args_allowed(), + subframe.args_required()) + + def _process_item(self, has_value, args_allowed, args_required): + self._args_allowed += args_allowed + self._args_required += args_required + if has_value: + self._has_value = True + + +class ChoiceFrame(Frame): + """ + _ArgParser context frame representing a choice order indicator. + + A choice requires as many input arguments as are needed to satisfy the + least requiring of its items. For example, if we use I(n) to identify an + item requiring n parameter, then a choice containing I(2), I(3) & I(7) + requires 2 arguments while a choice containing I(5) & I(4) requires 4. + + Accepts an argument for each of its contained elements but allows at most + one of its directly contained items to have a defined value. + + """ + + def __init__(self, id, error, extra_parameter_errors): + assert id.choice() + Frame.__init__(self, id, error, extra_parameter_errors) + self.__has_item = False + + def _process_item(self, has_value, args_allowed, args_required): + self._args_allowed += args_allowed + self.__update_args_required_for_item(args_required) + self.__update_has_value_for_item(has_value) + + def __update_args_required_for_item(self, item_args_required): + if not self.__has_item: + self.__has_item = True + self._args_required = item_args_required + return + self._args_required = min(self.args_required(), item_args_required) + + def __update_has_value_for_item(self, item_has_value): + if item_has_value: + if self.has_value() and self._extra_parameter_errors: + self._error("got multiple values for a single choice " + "parameter") + self._has_value = True diff --git a/pym/calculate/contrib/suds/argparser.pyc b/pym/calculate/contrib/suds/argparser.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5d658de292aafd457ae2ec163168c9842629b70 GIT binary patch literal 17516 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 SY=i2AK}~eOGyh-n@BTlqV`)bK literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/bindings/__init__.py b/pym/calculate/contrib/suds/bindings/__init__.py new file mode 100644 index 0000000..1704fa9 --- /dev/null +++ b/pym/calculate/contrib/suds/bindings/__init__.py @@ -0,0 +1,18 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the (LGPL) GNU Lesser General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License +# for more details at ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Provides modules containing classes to support Web Services (SOAP) bindings. +""" diff --git a/pym/calculate/contrib/suds/bindings/__init__.pyc b/pym/calculate/contrib/suds/bindings/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e557408d4a18a2d8f8b7ba30f30eb517701ca61d GIT binary patch literal 242 zcmYL@y$ZrG5XVy;l!A*-kinr2Hj5Mo5q*JL=peY9ZBk00CZ(6u`Zm6!FW`xa2lu 1: + return self.replycomposite(rtypes, nodes) + if len(rtypes) == 0: + return + if rtypes[0].multi_occurrence(): + return self.replylist(rtypes[0], nodes) + if len(nodes): + resolved = rtypes[0].resolve(nobuiltin=True) + return self.unmarshaller().process(nodes[0], resolved) + + def replylist(self, rt, nodes): + """ + Construct a I{list} reply. + + Called for replies with possible multiple occurrences. + + @param rt: The return I{type}. + @type rt: L{suds.xsd.sxbase.SchemaObject} + @param nodes: A collection of XML nodes. + @type nodes: [L{Element},...] + @return: A list of I{unmarshalled} objects. + @rtype: [L{Object},...] + + """ + resolved = rt.resolve(nobuiltin=True) + unmarshaller = self.unmarshaller() + return [unmarshaller.process(node, resolved) for node in nodes] + + def replycomposite(self, rtypes, nodes): + """ + Construct a I{composite} reply. + + Called for replies with multiple output nodes. + + @param rtypes: A list of known return I{types}. + @type rtypes: [L{suds.xsd.sxbase.SchemaObject},...] + @param nodes: A collection of XML nodes. + @type nodes: [L{Element},...] + @return: The I{unmarshalled} composite object. + @rtype: L{Object},... + + """ + dictionary = {} + for rt in rtypes: + dictionary[rt.name] = rt + unmarshaller = self.unmarshaller() + composite = Factory.object("reply") + for node in nodes: + tag = node.name + rt = dictionary.get(tag) + if rt is None: + if node.get("id") is None and not self.options().allowUnknownMessageParts: + message = "<%s/> not mapped to message part" % (tag,) + raise Exception(message) + continue + resolved = rt.resolve(nobuiltin=True) + sobject = unmarshaller.process(node, resolved) + value = getattr(composite, tag, None) + if value is None: + if rt.multi_occurrence(): + value = [] + setattr(composite, tag, value) + value.append(sobject) + else: + setattr(composite, tag, sobject) + else: + if not isinstance(value, list): + value = [value,] + setattr(composite, tag, value) + value.append(sobject) + return composite + + def mkparam(self, method, pdef, object): + """ + Builds a parameter for the specified I{method} using the parameter + definition (pdef) and the specified value (object). + + @param method: A method name. + @type method: str + @param pdef: A parameter definition. + @type pdef: tuple: (I{name}, L{xsd.sxbase.SchemaObject}) + @param object: The parameter value. + @type object: any + @return: The parameter fragment. + @rtype: L{Element} + + """ + marshaller = self.marshaller() + content = Content(tag=pdef[0], value=object, type=pdef[1], + real=pdef[1].resolve()) + return marshaller.process(content) + + def mkheader(self, method, hdef, object): + """ + Builds a soapheader for the specified I{method} using the header + definition (hdef) and the specified value (object). + + @param method: A method name. + @type method: str + @param hdef: A header definition. + @type hdef: tuple: (I{name}, L{xsd.sxbase.SchemaObject}) + @param object: The header value. + @type object: any + @return: The parameter fragment. + @rtype: L{Element} + + """ + marshaller = self.marshaller() + if isinstance(object, (list, tuple)): + return [self.mkheader(method, hdef, item) for item in object] + content = Content(tag=hdef[0], value=object, type=hdef[1]) + return marshaller.process(content) + + def envelope(self, header, body): + """ + Build the B{} for a SOAP outbound message. + + @param header: The SOAP message B{header}. + @type header: L{Element} + @param body: The SOAP message B{body}. + @type body: L{Element} + @return: The SOAP envelope containing the body and header. + @rtype: L{Element} + + """ + env = Element("Envelope", ns=envns) + env.addPrefix(Namespace.xsins[0], Namespace.xsins[1]) + env.append(header) + env.append(body) + return env + + def header(self, content): + """ + Build the B{} for a SOAP outbound message. + + @param content: The header content. + @type content: L{Element} + @return: The SOAP body fragment. + @rtype: L{Element} + + """ + header = Element("Header", ns=envns) + header.append(content) + return header + + def bodycontent(self, method, args, kwargs): + """ + Get the content for the SOAP I{body} node. + + @param method: A service method. + @type method: I{service.Method} + @param args: method parameter values. + @type args: list + @param kwargs: Named (keyword) args for the method invoked. + @type kwargs: dict + @return: The XML content for the . + @rtype: [L{Element},...] + + """ + raise Exception("not implemented") + + def headercontent(self, method): + """ + Get the content for the SOAP I{Header} node. + + @param method: A service method. + @type method: I{service.Method} + @return: The XML content for the . + @rtype: [L{Element},...] + + """ + content = [] + wsse = self.options().wsse + if wsse is not None: + content.append(wsse.xml()) + headers = self.options().soapheaders + if not isinstance(headers, (tuple, list, dict)): + headers = (headers,) + elif not headers: + return content + pts = self.headpart_types(method) + if isinstance(headers, (tuple, list)): + n = 0 + for header in headers: + if isinstance(header, Element): + content.append(deepcopy(header)) + continue + if len(pts) == n: + break + h = self.mkheader(method, pts[n], header) + ns = pts[n][1].namespace("ns0") + h.setPrefix(ns[0], ns[1]) + content.append(h) + n += 1 + else: + for pt in pts: + header = headers.get(pt[0]) + if header is None: + continue + h = self.mkheader(method, pt, header) + ns = pt[1].namespace("ns0") + h.setPrefix(ns[0], ns[1]) + content.append(h) + return content + + def replycontent(self, method, body): + """ + Get the reply body content. + + @param method: A service method. + @type method: I{service.Method} + @param body: The SOAP body. + @type body: L{Element} + @return: The body content. + @rtype: [L{Element},...] + + """ + raise Exception("not implemented") + + def body(self, content): + """ + Build the B{} for a SOAP outbound message. + + @param content: The body content. + @type content: L{Element} + @return: The SOAP body fragment. + @rtype: L{Element} + + """ + body = Element("Body", ns=envns) + body.append(content) + return body + + def bodypart_types(self, method, input=True): + """ + Get a list of I{parameter definitions} (pdefs) defined for the + specified method. + + An input I{pdef} is a (I{name}, L{xsd.sxbase.SchemaObject}) tuple, + while an output I{pdef} is a L{xsd.sxbase.SchemaObject}. + + @param method: A service method. + @type method: I{service.Method} + @param input: Defines input/output message. + @type input: boolean + @return: A list of parameter definitions + @rtype: [I{pdef},...] + + """ + if input: + parts = method.soap.input.body.parts + else: + parts = method.soap.output.body.parts + return [self.__part_type(p, input) for p in parts] + + def headpart_types(self, method, input=True): + """ + Get a list of header I{parameter definitions} (pdefs) defined for the + specified method. + + An input I{pdef} is a (I{name}, L{xsd.sxbase.SchemaObject}) tuple, + while an output I{pdef} is a L{xsd.sxbase.SchemaObject}. + + @param method: A service method. + @type method: I{service.Method} + @param input: Defines input/output message. + @type input: boolean + @return: A list of parameter definitions + @rtype: [I{pdef},...] + + """ + if input: + headers = method.soap.input.headers + else: + headers = method.soap.output.headers + return [self.__part_type(h.part, input) for h in headers] + + def returned_types(self, method): + """ + Get the I{method} return value type(s). + + @param method: A service method. + @type method: I{service.Method} + @return: Method return value type. + @rtype: [L{xsd.sxbase.SchemaObject},...] + + """ + return self.bodypart_types(method, input=False) + + def __part_type(self, part, input): + """ + Get a I{parameter definition} (pdef) defined for a given body or header + message part. + + An input I{pdef} is a (I{name}, L{xsd.sxbase.SchemaObject}) tuple, + while an output I{pdef} is a L{xsd.sxbase.SchemaObject}. + + @param part: A service method input or output part. + @type part: I{suds.wsdl.Part} + @param input: Defines input/output message. + @type input: boolean + @return: A list of parameter definitions + @rtype: [I{pdef},...] + + """ + if part.element is None: + query = TypeQuery(part.type) + else: + query = ElementQuery(part.element) + part_type = query.execute(self.schema()) + if part_type is None: + raise TypeNotFound(query.ref) + if part.type is not None: + part_type = PartElement(part.name, part_type) + if not input: + return part_type + if part_type.name is None: + return part.name, part_type + return part_type.name, part_type + + +class PartElement(SchemaElement): + """ + Message part referencing an XSD type and thus acting like an XSD element. + + @ivar resolved: The part type. + @type resolved: L{suds.xsd.sxbase.SchemaObject} + + """ + + def __init__(self, name, resolved): + """ + @param name: The part name. + @type name: str + @param resolved: The part type. + @type resolved: L{suds.xsd.sxbase.SchemaObject} + + """ + root = Element("element", ns=Namespace.xsdns) + SchemaElement.__init__(self, resolved.schema, root) + self.__resolved = resolved + self.name = name + self.form_qualified = False + + def implany(self): + pass + + def optional(self): + return True + + def namespace(self, prefix=None): + return Namespace.default + + def resolve(self, nobuiltin=False): + if nobuiltin and self.__resolved.builtin(): + return self + return self.__resolved diff --git a/pym/calculate/contrib/suds/bindings/binding.pyc b/pym/calculate/contrib/suds/bindings/binding.pyc new file mode 100644 index 0000000000000000000000000000000000000000..002fac83d3a790841e944c876ea362f79a2852fd GIT binary patch literal 17731 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 aD+tQ?0t@#ccl}Ols&4{YJpE(yNB;|FzN}6F literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/bindings/document.py b/pym/calculate/contrib/suds/bindings/document.py new file mode 100644 index 0000000..825a677 --- /dev/null +++ b/pym/calculate/contrib/suds/bindings/document.py @@ -0,0 +1,143 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the (LGPL) GNU Lesser General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License +# for more details at ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Classes for the (WS) SOAP I{document/literal} binding. + +""" + +from suds import * +from suds.argparser import parse_args +from suds.bindings.binding import Binding +from suds.sax.element import Element + + +class Document(Binding): + """ + The document/literal style. Literal is the only (@use) supported since + document/encoded is pretty much dead. + + Although the SOAP specification supports multiple documents within the SOAP + , it is very uncommon. As such, suds library supports presenting an + I{RPC} view of service methods defined with only a single document + parameter. To support the complete specification, service methods defined + with multiple documents (multiple message parts), are still presented using + a full I{document} view. + + More detailed description: + + An interface is considered I{wrapped} if: + - There is exactly one message part in that interface. + - The message part resolves to an element of a non-builtin type. + Otherwise it is considered I{bare}. + + I{Bare} interface is interpreted directly as specified in the WSDL schema, + with each message part represented by a single parameter in the suds + library web service operation proxy interface (input or output). + + I{Wrapped} interface is interpreted without the external wrapping document + structure, with each of its contained elements passed through suds + library's web service operation proxy interface (input or output) + individually instead of as a single I{document} object. + + """ + def bodycontent(self, method, args, kwargs): + wrapped = method.soap.input.body.wrapped + if wrapped: + pts = self.bodypart_types(method) + root = self.document(pts[0]) + else: + root = [] + + def add_param(param_name, param_type, in_choice_context, value): + """ + Construct request data for the given input parameter. + + Called by our argument parser for every input parameter, in order. + + A parameter's type is identified by its corresponding XSD schema + element. + + """ + # Do not construct request data for undefined input parameters + # defined inside a choice order indicator. An empty choice + # parameter can still be included in the constructed request by + # explicitly providing an empty string value for it. + #TODO: This functionality might be better placed inside the + # mkparam() function but to do that we would first need to better + # understand how different Binding subclasses in suds work and how + # they would be affected by this change. + if in_choice_context and value is None: + return + + # Construct request data for the current input parameter. + pdef = (param_name, param_type) + p = self.mkparam(method, pdef, value) + if p is None: + return + if not wrapped: + ns = param_type.namespace("ns0") + p.setPrefix(ns[0], ns[1]) + root.append(p) + + parse_args(method.name, self.param_defs(method), args, kwargs, + add_param, self.options().extraArgumentErrors) + + return root + + def replycontent(self, method, body): + if method.soap.output.body.wrapped: + return body[0].children + return body.children + + def document(self, wrapper): + """ + Get the document root. For I{document/literal}, this is the name of the + wrapper element qualified by the schema's target namespace. + + @param wrapper: The method name. + @type wrapper: L{xsd.sxbase.SchemaObject} + @return: A root element. + @rtype: L{Element} + + """ + tag = wrapper[1].name + ns = wrapper[1].namespace("ns0") + return Element(tag, ns=ns) + + def mkparam(self, method, pdef, object): + """ + Expand list parameters into individual parameters each with the type + information. This is because in document arrays are simply + multi-occurrence elements. + + """ + if isinstance(object, (list, tuple)): + return [self.mkparam(method, pdef, item) for item in object] + return super(Document, self).mkparam(method, pdef, object) + + def param_defs(self, method): + """Get parameter definitions for document literal.""" + pts = self.bodypart_types(method) + if not method.soap.input.body.wrapped: + return pts + pt = pts[0][1].resolve() + return [(c.name, c, a) for c, a in pt if not c.isattr()] + + def returned_types(self, method): + rts = super(Document, self).returned_types(method) + if not method.soap.output.body.wrapped: + return rts + return [child for child, ancestry in rts[0].resolve(nobuiltin=True)] diff --git a/pym/calculate/contrib/suds/bindings/document.pyc b/pym/calculate/contrib/suds/bindings/document.pyc new file mode 100644 index 0000000000000000000000000000000000000000..df7717b5ac93b8658c5318db3c47c6e09298d8e1 GIT binary patch literal 5307 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/bindings/rpc.py b/pym/calculate/contrib/suds/bindings/rpc.py new file mode 100644 index 0000000..f0d5bd9 --- /dev/null +++ b/pym/calculate/contrib/suds/bindings/rpc.py @@ -0,0 +1,91 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the (LGPL) GNU Lesser General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License +# for more details at ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Classes for the (WS) SOAP I{rpc/literal} and I{rpc/encoded} bindings. + +""" + +from suds import * +from suds.mx.encoded import Encoded as MxEncoded +from suds.umx.encoded import Encoded as UmxEncoded +from suds.bindings.binding import Binding, envns +from suds.sax.element import Element + + +encns = ("SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/") + + +class RPC(Binding): + """RPC/Literal binding style.""" + + def param_defs(self, method): + return self.bodypart_types(method) + + def envelope(self, header, body): + env = super(RPC, self).envelope(header, body) + env.addPrefix(encns[0], encns[1]) + env.set("%s:encodingStyle" % (envns[0],), encns[1]) + return env + + def bodycontent(self, method, args, kwargs): + n = 0 + root = self.method(method) + for pd in self.param_defs(method): + if n < len(args): + value = args[n] + else: + value = kwargs.get(pd[0]) + p = self.mkparam(method, pd, value) + if p is not None: + root.append(p) + n += 1 + return root + + def replycontent(self, method, body): + return body[0].children + + def method(self, method): + """ + Get the document root. For I{rpc/(literal|encoded)}, this is the name + of the method qualified by the schema tns. + + @param method: A service method. + @type method: I{service.Method} + @return: A root element. + @rtype: L{Element} + + """ + ns = method.soap.input.body.namespace + if ns[0] is None: + ns = ('ns0', ns[1]) + return Element(method.name, ns=ns) + + +class Encoded(RPC): + """RPC/Encoded (section 5) binding style.""" + + def marshaller(self): + return MxEncoded(self.schema()) + + def unmarshaller(self): + """ + Get the appropriate schema based XML decoder. + + @return: Typed unmarshaller. + @rtype: L{UmxTyped} + + """ + return UmxEncoded(self.schema()) diff --git a/pym/calculate/contrib/suds/bindings/rpc.pyc b/pym/calculate/contrib/suds/bindings/rpc.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3158ef74d3694b3fd191b93c912f0f77dfa3fc58 GIT binary patch literal 3419 zcmb_eZEqVz5T5f}Y$s`>MvVwa^i)xBN^65e3xo=_4TTmpAvzZdmXNvJt>a7Xt+(se zQSC3J9}&Ny|B)X6&&-|Uv_c3qwX&0aotu5;nVBvBwcLF6!OPz~Dt=}Bzm2B6(cB7Mt(CS1NoJd&vRjY48+P}H zJG=IS=UM7?!oaA^4X3sn`^A)sy~J1k)ZPnXKZy5ryV(r>#;;{TqhWD1?=GNwFW=oN z@fuIu%}<#s`YL`J>r;C}6{*-ToH^ach)W75q|M|(pRxw<`$LY=s2JIVGt z-06r(Fr{M{b7yz!#0PB6T{Qg_gn|zM5@d-z0jPQaq$HgRyMt${FLD!`e?rHIA7S}%i4IC^{G`PFX_+QvIw+F? zTo$eKzY?uu#o~EDhb7>KC9rYr)#YxBzp)cQP{26o6^JW(bLPD+qu64O2s!j9Rhh#y zF-!<>MTJSKOalYg_jfZj2*w4CyjY9twK5LhNIvC=Dn@arTwi4{Cr4biLf=_obrzxU z3YsvMtoN*UtV@>1pJ5}}bb<6GI>2OFd4&wqDve*r4B!=deDkZOX^kcoG5{TjTXaa2 zeb0SNu1^;zUM)N@$zjG8%reKI9C~nifsV^Gt<$8=R6lG`_9soMbbzHgtF&U!Q5^R< zEP8T<9%HrJV%SbONBrP0@DATaAPW(kylr0@3FYWeI3>95B(W04x@oFnzr}~d0ir{; zxY@pzEr-vf%N&ShB})>6D}$rHIP|F-j+A7Q^sGKI>>~~{FNqE8{}@BP20>QMI&ZC6 z7p&#ds&&y?vR15fc|7nP*&1;kp9lWTX~c0?Vl>Ao4`YVN8zLYx6$^;-TRTkfGhbi{ zN-~v(vm1Pg@hp1TO173MC)VCa2RwkK2at$fP(irF_9LGi)+xKeLCaSvBTNz0B?2RW zJD&rqKqRJ~Rph*NxT$FuzweZhGT|rQh*P!Ao@?9RqI%@@qE!@(Nl_&>rq^&F&^G?K zzQk^%PP8QhnagvW{bb~Z!5~n+y>}$@dAhev%oS#4!EK?OouApX@7P*pPXkXCGwu0C zPN^sR9y~AhwYMdsPUrhFWky-ds`xUt%8Sq`MHy?_v>!gdmoH7{)&zh%kBwM=B1uhX z9P6DtkFj64LJ6ybI2{?`gyb-WLZ_~$oQv4y@Ky;1o`0Q4m$7(OB1s_LVuP5nw0Hr8 zU$t61kObTB^OyU5DHi>Hl=!2Nhnz+GeR#azmsB8G&v_rSj?ID<%x#n2n^h^v^_QSc zGv#Ymt<)$tYK?P^vcsvuLz5p5?xJZM;=gM;3O9#`{t$u-ckvprTUvQ0NMifO#_L6# zwR0<>Nl0-JqabpQMV3ZQoY!&QBfi`o7n&u%<;0crAjx2k&YJ-v9*Nvc58W_S*)G01 zO921hTKzkYov?lu$jH`Nl4gNxlwHKzo~sdqKW{&@eZ?=m>~!?ag5?oH!na59+^T;I zm>;9DY&;b)`5TAdBUmgzb2ur#MYxzgr%mf(oC8*GaZz?YV!>WMS&7 zpKPOPetP6I-jQpc;bALJcCl7+1V8f3dHx1E?P%OC(yauFa}^7QX)CLvQ_I(Rh0~3! z%wCD@qT?{1<^422tz9V3^PZ$Ahu^dksc!`=$vn66T=VrR8^(6mN=+oE6;$Vya;?19 F{s-UQ+kpT8 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/builder.py b/pym/calculate/contrib/suds/builder.py new file mode 100644 index 0000000..a844f0d --- /dev/null +++ b/pym/calculate/contrib/suds/builder.py @@ -0,0 +1,122 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +The I{builder} module provides an wsdl/xsd defined types factory +""" + +from suds import * +from suds.sudsobject import Factory + + +class Builder: + """ Builder used to construct an object for types defined in the schema """ + + def __init__(self, resolver): + """ + @param resolver: A schema object name resolver. + @type resolver: L{resolver.Resolver} + """ + self.resolver = resolver + + def build(self, name): + """ build a an object for the specified typename as defined in the schema """ + if isinstance(name, basestring): + type = self.resolver.find(name) + if type is None: + raise TypeNotFound(name) + else: + type = name + cls = type.name + if type.mixed(): + data = Factory.property(cls) + else: + data = Factory.object(cls) + resolved = type.resolve() + md = data.__metadata__ + md.sxtype = resolved + md.ordering = self.ordering(resolved) + history = [] + self.add_attributes(data, resolved) + for child, ancestry in type.children(): + if self.skip_child(child, ancestry): + continue + + self.process(data, child, history[:]) + return data + + def process(self, data, type, history): + """ process the specified type then process its children """ + if type in history: + return + if type.enum(): + return + history.append(type) + resolved = type.resolve() + value = None + + + + if type.multi_occurrence(): + value = [] + else: + if len(resolved) > 0: + if resolved.mixed(): + value = Factory.property(resolved.name) + md = value.__metadata__ + md.sxtype = resolved + else: + value = Factory.object(resolved.name) + md = value.__metadata__ + md.sxtype = resolved + md.ordering = self.ordering(resolved) + + setattr(data, type.name, value if not type.optional() or type.multi_occurrence() else None) + if value is not None: + data = value + if not isinstance(data, list): + self.add_attributes(data, resolved) + for child, ancestry in resolved.children(): + if self.skip_child(child, ancestry): + continue + self.process(data, child, history[:]) + + def add_attributes(self, data, type): + """ add required attributes """ + for attr, ancestry in type.attributes(): + name = '_%s' % attr.name + value = attr.get_default() + setattr(data, name, value) + + def skip_child(self, child, ancestry): + """ get whether or not to skip the specified child """ + if child.any(): return True + for x in ancestry: + if x.choice(): + return True + return False + + def ordering(self, type): + """ get the ordering """ + result = [] + for child, ancestry in type.resolve(): + name = child.name + if child.name is None: + continue + if child.isattr(): + name = '_%s' % child.name + result.append(name) + return result diff --git a/pym/calculate/contrib/suds/builder.pyc b/pym/calculate/contrib/suds/builder.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd2b4cbe33b3d02abcef5429c563164da148afa7 GIT binary patch literal 3552 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 element. + + @param replyroot: A SOAP reply message root XML element or None. + @type replyroot: L{Element}|I{None} + @return: A fault object. + @rtype: L{Object} + + """ + envns = suds.bindings.binding.envns + soapenv = replyroot and replyroot.getChild("Envelope", envns) + soapbody = soapenv and soapenv.getChild("Body", envns) + fault = soapbody and soapbody.getChild("Fault", envns) + return fault is not None and UmxBasic().process(fault) + + def __headers(self): + """ + Get HTTP headers for a HTTP/HTTPS SOAP request. + + @return: A dictionary of header/values. + @rtype: dict + + """ + action = self.method.soap.action + if isinstance(action, unicode): + action = action.encode("utf-8") + result = { + "Content-Type": "text/xml; charset=utf-8", + "SOAPAction": action} + result.update(**self.options.headers) + log.debug("headers = %s", result) + return result + + def __location(self): + """Returns the SOAP request's target location URL.""" + return Unskin(self.options).get("location", self.method.location) + + +class _SimClient(_SoapClient): + """ + Loopback _SoapClient used for SOAP request/reply simulation. + + Used when a web service operation is invoked with injected SOAP request or + reply data. + + """ + + __injkey = "__inject" + + @classmethod + def simulation(cls, kwargs): + """Get whether injected data has been specified in I{kwargs}.""" + return kwargs.has_key(_SimClient.__injkey) + + def invoke(self, args, kwargs): + """ + Invoke a specified web service method. + + Uses an injected SOAP request/response instead of a regularly + constructed/received one. + + Depending on how the ``nosend`` & ``retxml`` options are set, may do + one of the following: + * Return a constructed web service operation request without sending + it to the web service. + * Invoke the web service operation and return its SOAP reply XML. + * Invoke the web service operation, process its results and return + the Python object representing the returned value. + + @param args: Positional arguments for the method invoked. + @type args: list|tuple + @param kwargs: Keyword arguments for the method invoked. + @type kwargs: dict + @return: SOAP request, SOAP reply or a web service return value. + @rtype: L{RequestContext}|I{builtin}|I{subclass of} L{Object}|I{bytes}| + I{None} + + """ + simulation = kwargs.pop(self.__injkey) + msg = simulation.get("msg") + if msg is not None: + assert msg.__class__ is suds.byte_str_class + return self.send(_parse(msg)) + msg = self.method.binding.input.get_message(self.method, args, kwargs) + log.debug("inject (simulated) send message:\n%s", msg) + reply = simulation.get("reply") + if reply is not None: + assert reply.__class__ is suds.byte_str_class + status = simulation.get("status") + description = simulation.get("description") + if description is None: + description = "injected reply" + return self.process_reply(reply, status, description) + raise Exception("reply or msg injection parameter expected") + + +def _parse(string): + """ + Parses given XML document content. + + Returns the resulting root XML element node or None if the given XML + content is empty. + + @param string: XML document content to parse. + @type string: I{bytes} + @return: Resulting root XML element node or None. + @rtype: L{Element}|I{None} + + """ + if string: + return suds.sax.parser.Parser().parse(string=string) diff --git a/pym/calculate/contrib/suds/client.pyc b/pym/calculate/contrib/suds/client.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cfcbddb7738a22ecc9a815b3f5ce795aaeaffae1 GIT binary patch literal 33062 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/metrics.py b/pym/calculate/contrib/suds/metrics.py new file mode 100644 index 0000000..9b15f18 --- /dev/null +++ b/pym/calculate/contrib/suds/metrics.py @@ -0,0 +1,63 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +The I{metrics} module defines classes and other resources +designed for collecting and reporting performance metrics. +""" + +import time +from suds import * +from math import modf + +from logging import getLogger +log = getLogger(__name__) + + +class Timer: + + def __init__(self): + self.started = 0 + self.stopped = 0 + + def start(self): + self.started = time.time() + self.stopped = 0 + return self + + def stop(self): + if self.started > 0: + self.stopped = time.time() + return self + + def duration(self): + return ( self.stopped - self.started ) + + def __str__(self): + if self.started == 0: + return 'not-running' + if self.started > 0 and self.stopped == 0: + return 'started: %d (running)' % self.started + duration = self.duration() + jmod = ( lambda m : (m[1], m[0]*1000) ) + if duration < 1: + ms = (duration*1000) + return '%d (ms)' % ms + if duration < 60: + m = modf(duration) + return '%d.%.3d (seconds)' % jmod(m) + m = modf(duration/60) + return '%d.%.3d (minutes)' % jmod(m) diff --git a/pym/calculate/contrib/suds/metrics.pyc b/pym/calculate/contrib/suds/metrics.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f4066420fda73404a7bd67a80abab11ef8555c07 GIT binary patch literal 2073 zcmb_d%Z?jG6us4Mdu+#qAxuU@ilRo!NH!uKAs|7>iV&=jqFJ) z2+DXBet|vzz)!K~1K^x$XH1lA@~~aEPrYuRI(6@L>z@z$zuy1z=Tx?z7M|as*#t(5 z%wU!1KyoEB0Q_2#2XaajO5TzplvyZ>{kG(7DLOLih%y~9d-5E+x}rOxVfW;Bk>?^m z&3g1W9rpO5Uts#D=O+5`Sz%nArFIh)m0ss2(q@sB#ztvAw-(QNsiVrBn>wnEt=4sF zY+oCjElZ=LMO8;>mFFgPS-JFUYqP3q-&>g)^ToVOO|*T>xS#!t&&g1MfTQ`WfgvCW zESerUE{%IqEtjTtZS+pF!qnG-apU)B_G=ge!JvciptFE#5wv((f{@}7w5c6IN8;&_ zPE-0}3($T*vxhKna3zAP*aGi+I^>#@3`RV3dqCFBYiINpSF4rLyW?1sFNS_Sjr|36O^_%NrLy}}==8`0$hY&_oPrXX} zE+(AFg}-T%2j}J#0nhRhc?O%KD+ftqf|y!(-f@Qrtub%TnV!5T_X+4t)Q7L7e1s`b z17$G145j{*@o=FSt2{vN4>orQ>yrxa^NBIIffSs6u)F1m?-wi?EiC^IZ;}R<-Op9j0 z;grvS%5O05lVpRy0dC8sNL_i{k%JAgYEQ0Of-RWs`q@9k!4ob{$p*>RlPl~E**%;# zGgx?gJKO*N?C=J7H#ubq%gQ~d*JX)PVsE3rO|NgGBOML56Qk?s=jo?h#iYdv5Jz|T z2;>fqcCcWv`l-g!fld|sUC`Qu0Qh$hYZ_$tdHLGpzi zWfNfgkslZzjlaaGHEC69J9>GvKw)skjy(BYg2q%RCT(B4e5(2}pUf91o{r&B*m%G- zXm6XuB%LJI)k*RNpuJ09NaIl5Q#aHA={!(<)rB3Xn`&PTxnWzb%6Vau#PuUb}T)5<9ZV_2JWF*`t1b0u-C@7)%fL@FU?7!s}wZ49Pp`*QtLr6 wcjsPHzb?oB4Pq~*j`1xnrhkn3_q;1vuh68?`W^IPnwTI?;-uw; zoj_}dOzP==ua{=V>js(L4LTiOhWPdRTCH4;zvHP2m@{nn<#tC)g1ja+IMI4RHH-JrJ)jSDm`k}2|zQGrH9I&?{VSfEYh zwOMu8@@Ihc*;4HVS1^@ctNavn{W+0aBqOyZprAJ2s8znurB5 z2^ntWRg}diTl;xt8~QpQo8K01H_%>^dK{d1yKj^?uk#?~A&%mZL(G#^HC)LuTudgT z2DocFP7`gT*+>)Rb77h(z|#|Bc7N4InQy4wngm^CWB!l9H5Xw~%2u9ODeq&dF9Arn zVp>#00ay|<=o?jgdd`T?2O}mSW&R_=ls8BjrJRb!B1y8GBOnsu%eWgBHolwEJ3Z79x zJ+C^W0@OaMf-`y5qzWdLo>c1?ek!k>Qo-4*b~>*;tAd%V_FP^&t%CDe?QC8oTtqf;BktS{18rQt z+tuwr$8Iz7jX}kFCw8yzw*1&^`cV|NH})4M!vEkmkL_0pvzO*8ERG`k=GvBSCdoL8 z7_zJ5*$P^A&;_Zz8s7D}DD#$k&92Su$XwIr?J3m|?A?_0o8@c_%~Qn77?y?wZlj zy2s6)N3xlD1*NrK7zK-KL1>Z%2&%X9^3EGq8dqLl)EgU%rWcsS*3M!k--Yfyky4`( zw!@^+cpd{7u2R+V1@p@A;f^#K`c9+q5=w@b%9(a1ocS6`>0;Y{OE(%a zlSZS}33?GPIf+Ii=rkJ*kI?ldkrnfi(okFM@zGBq$#h0*qm}wtGL7q{PCJ1rWLRyY zN`6BC|1Y@lAn${1+7U_Mrv!0J-FcGL|;I7@XidY`Jba!^|K_w)H1e3o-ArU>i zZ&lGzKqB}7mw+7biNbn?l}T+-<)~DS9qc(SmGy&_6HP+~r*=`a)}Gq1lP`!V)qo97`zY zxoPK+-H5|hn1pwACPLAHRJ4Lxug<6rv&e2c#-ZG>m6r!ZqmO_(%uP;gqmrL1wE7Fk5oloj{j*iHXWOE$^nHD=?MWIZHE^JxWit!Z|!%+JSIgvNsk3 zuFMk-9=F;fb3%EQy6Z6Wz$V z92X+bV$|zMh6&_fZ&!{tQjgLoqTe72yei-<_c@aOa-W8@B|3V96ZbzNVv53h z8d>25*-KO%!=)2seT*RvyK?!m2^LFDTc8&)lGbB0?_y3lwJgON>LGLz>!cS$j&1k5 zA1n(!K!kqchQ__q^P_M*)Iok<5ANNDh#2M@F7^Hb9P-F?E<@zEwQG7Y28|*&*6SL4 z)Px&Am&|nirp^cHqBY#%VFbMc4R<`&L5V}4?sTmOQ4UWl+nZr?)9uEcrZzI2P2adY z)Rf1tu6H)X@~*X21r1%b%O>pFdiyXd;#kwwq^~|cwDP26#ek7bOCo*_^@Yw4r|w_G z7#m1d#1mqDXnB|f*^i@87IB{u`7=7?n|)I!A}^s>`f1e9>${xzK9#c_Mp571vz1$e zeqpqKcz0xPZI=N%^dO6IV&YpV$$=Ka=mayhhZ1`G9(U0@32}Uhqcc&()Of!*W>MWQ zj#TN!%S!h!QTVxEF2ef%lS-~sr87pcijv6azd>ZFKYAKsqZaP-DI&IdzkN8GD1VOI za`pK-)MtBBLuq2s9MjcJp~Q@z$djFJ5_Z~tza9w~PI;<}SZwfbUe= z!EsD7d+Z4l&?OB0<9zEz`?u}_8q0{sL9FD$eumb3`&K$hxPGq`VA3&Ihvvn4X4aZu z3)5x0{Bk%KXj=j&ZHoevX zt2y*8_Yd_bdrStmBb@LSe;EV+qO`@C9sT^a^k?N=wjTE(9$4N@u`A}(T335uK_r#O zIQ|}F6u|^m8A{zBVfQ>aXmCYxVDem+PQvnW+)t5Ge9oWYz=KXYVryw9J+iJx{_qHH zkK1pjhr+QPqZcv8M@Vu^x3RYRWPPH3rasO;k8zJClKfzIZG@TL(!jG24l`6d^Ext- z)3wrJhK>p%sGFTOxT~85Qy^jZg=tu=KP>P=jKo7fBB_X;itinNBdtL^`&mQ)7)(Wv zDnmvH6d+0v@6k=)LKzW(5eWy}*;DP;gkcd!K!gBYQK+e{(F6CBc6lp8ToM3t0);RF zfv_SG*G9-qn5U&kSey785*S5zHcrfTm~6_~JL#At_MXXl!7PjOB!_BTFlJ+ANG&}C zG4X-@B)h+c9?eZesfmN*9CHZ0Um+PJ_>3H$$Sf$HL@uL01p8caUx+OiysJ` z5&Nssil(g9Y2*G3SYn}x4kBVj0_N637KN>&(i8oaUF0+l$=Uk~>lj)&?)LHtpCK8# zfQ;XtcP5?LQi-_c~G@>rvSCxG*#F&r? z9*7|j1FtIQ&im??a04Z~;=PPKL{g&k1xd)Ig~h9A70%cI8&G7z6k(!UMtEV#9<03= z(KOFx9>R<8PghVQ6u~>CKvQ`V5c)lyX&7)*P8}ec1wqU@PoFZ32%6vV!8wfPaMeVT z-{&_uF8XKGkcTE7iXy=0XcR%yfg;!sLgpPpCIbuJr5+8I5xMOESS~*lEJ6@87#1wV zhj)e9k#L~tu+_EI?)9pR?_ zQ|FNf_Vl#&HpURnf;&@8QC=#9I7}X&cizDR{?3VV-_-*m|Lj-*TS~))0>6rZ{)%L% zKlDZFBOd+PAt;Bgct$z)w1I$z{q`e^arQa4#1_{o__~IIwPA&G`<%Rz6-)LbN5SF1 z{l%tda@jz8EsRr$V>n50@P8p0qLmKmH2zN45v8F2!ADXI z;)s$Gh7i4r+ft{6?^_oWzFHk*Z3JcLEb@*~$bA;rb1TKTEqT7l9AG)gV8IdpmD7uqM71N`wkJz5 zH-ZV;9C1TmDmHn{klXxYKaZ$LrjX?=2}1{* zf&Jiw+aNBYL~7(%?a4IgO<5u*=Xpf8#}yo!^H9t!Z_2-BzXW@S=Ro5k8?8*>!?8JM b#+j+kUYNZ!dt>h0+|=Ck+*#z4bJPC?H}m%v literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/mx/basic.py b/pym/calculate/contrib/suds/mx/basic.py new file mode 100644 index 0000000..b2de161 --- /dev/null +++ b/pym/calculate/contrib/suds/mx/basic.py @@ -0,0 +1,45 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Provides basic I{marshaller} classes. +""" + +from suds import * +from suds.mx import * +from suds.mx.core import Core + + +class Basic(Core): + """ + A I{basic} (untyped) marshaller. + """ + + def process(self, value, tag=None): + """ + Process (marshal) the tag with the specified value using the + optional type information. + @param value: The value (content) of the XML node. + @type value: (L{Object}|any) + @param tag: The (optional) tag name for the value. The default is + value.__class__.__name__ + @type tag: str + @return: An xml node. + @rtype: L{Element} + """ + content = Content(tag=tag, value=value) + result = Core.process(self, content) + return result diff --git a/pym/calculate/contrib/suds/mx/basic.pyc b/pym/calculate/contrib/suds/mx/basic.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f450c243b7f6f3eb8b5928eb6a09da38fde63b3 GIT binary patch literal 1239 zcmbtT&2H2%5T5*WK~a$qhzl2dKq6bz>;+Y5RiT!`0cj~H?E!iT+1R^H2VB`ke09*rnJ=p-+gQNH!p}jy8eQxUWQYtIPxh)Iv;i}3T zdzx#lnx!aoZmqIORQ|#ddw9T++3MU7-GjPOZUddSbbc+_ryZR3DH?^6Q3YC`RHNb> zj})dyF{Ng=&_n{qKJv4UrHEVOE@w*i#hsvpg9WeAH9vuD!pmFcing(SgN9ZJaW$FX{=iefc;N zrk3iDqm0VoLlKXzK8?>*;g*ZsT=v%zR`@8qLyvDYVM3UU$txvL7E>@(B3Ok~lf2bV zly(h8a=VZ$<37l;B+CdP%ho}AEQ;x@YwotOC)&mg#l8{qO8=cnL#KvfboE}V3bS6W z4?4OUgyW84cD^h}{d&-qDCI7sjaheTG4+9?UbIS2QgTv;p_o-&T@U?6Sk?g>cD_A-y_4;{8mQ@XU|VSi)qKD`nanOzf_aA1k^`Ghyhq+)$A2H! zx8-pWFREI$8mq+EaCQoo_`pVv~&|qR})Nu1yC+Y lHFxx9hCQ$6sb zNTo-zm!wMeB42BzJFV~^eA*7i8*1LP;zfv?No-VXu8qek4peF%H1OcVq&FGiiS22k zr?1Rb((kL()Ocd53M5GB2e|Y%XcUlui)br^2Q2Sa2^A7*BB-*kKp0RD99&>wk({NT zM&@r9jyJdmI5b&+_bnEdMXbAIIG(*XiF+nYVm}JaU776h(~=Gzv=QF%Q|V{ut;=he&wv(v z9Xrn49jl^mU2YxD0Dr{8dITh06hO|2gqhM_}2({@%VLUl_=it37-j#RPRKLHbCxKoY9jp-~ zo$+1P>Um)t8qXu{X);1od-OwVfi5=MhXA98Z0kKo99M(`+lLk6u!D{v6XJG5q*n#q zE{I`W3>QiEsv>3&F!ZQGE)SdH9)wIyMGRY{W~W`nTl8;e3J9-Css<8 zR)(L!IbM$2NvwDfyJd(Op2zFo^RmFj{z!SAOVKiQG?pMdJ53V9c)Ik!ETYM*<+(wg z3()_6$wN9b58r~w9*f0Qr{!F9E;~(U)#;J1bP-oKY0MUyGLJxm<7!SNx^YDMF;k=} zhBcxHb!KE+DBXimNI)57{({y5d7JoVsIhgJd4D7kPRa^54-s;th@(QP^F|8ZI%1 ziKLC68kczIu2LUG1~sBY6Pjcdx=%tpLu%nStV4$;8${z0NO8$2vLWR(CIm5Kn*LtL zT@gr^mITLYHb>j!h_QlGAyfP;wo>iAfy<`98mB*6RE3o^0JQzKoT`6EUt#NJs(gcT z5C<|^}61-RujvzeusQcjY{PV987_Gf3$CY@}0iEH-ds9Ld9mWZX7 zr!=3E)qNb@wk3s1({^HR=H*ib*V8mfZ5d)hoskusnrJb7f;U;T8~3A4oB-N8Y?S`9 zjI&+bHo;T5&+r@gS~9y;Q1W*M>~c;gkoN~+Z;+>UQaNAC=|R7hqWmCBkX5L>`R)L! z3!ZFbG1yI#NcnNmKP~B`M{hu{qaf!?XeljwMk60RC)qu$AU`lK%-VEX$O#V1&u2(FWBzoX zhLW#w<+<|&#Q(t1BFF4x)zog2v*XXrLrTZID~iJ?D#2*8Cq1P@5XObk(cFS$hdd(C zNRw3Ep|teMM+f!Ua{!gM&M*eH9G)K9DoB26Xnh%|J%17zdqyd_{8&(?{qBPdI1%%W zd{063Gt)A4AWOqjnx9KV_|Fh!vbTL-M5Q@D9Zxq4Kb8r90|eV2D0pvoRMV4UzHh)5 zB0n5XU3yr4uzLoo@dMSnU7B+ujJCql=KCW*(&t#>`8=0<@k0Ssy-j}xxzref)AL42 zFo|$plx*DKA1=Edepv)*js+rXE8mokbiW03nY8s0?GKN(rc4s>U9V90#xgxs;G zBbC~}PM*l0X#b#-AAIehnY_nYypICnGKCql271}JvwFy(dEerGl{VLWMy^*{I3uq* KtCdw}x%w|puIRr2 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/mx/encoded.py b/pym/calculate/contrib/suds/mx/encoded.py new file mode 100644 index 0000000..ec09536 --- /dev/null +++ b/pym/calculate/contrib/suds/mx/encoded.py @@ -0,0 +1,131 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Provides encoded I{marshaller} classes. +""" + +from suds import * +from suds.mx import * +from suds.mx.literal import Literal +from suds.mx.typer import Typer +from suds.sudsobject import Factory, Object +from suds.xsd.query import TypeQuery + + +# +# Add encoded extensions +# aty = The soap (section 5) encoded array type. +# +Content.extensions.append('aty') + + +class Encoded(Literal): + """ + A SOAP section (5) encoding marshaller. + This marshaller supports rpc/encoded soap styles. + """ + + def start(self, content): + # + # For soap encoded arrays, the 'aty' (array type) information + # is extracted and added to the 'content'. Then, the content.value + # is replaced with an object containing an 'item=[]' attribute + # containing values that are 'typed' suds objects. + # + start = Literal.start(self, content) + if start and isinstance(content.value, (list,tuple)): + resolved = content.type.resolve() + for c in resolved: + if hasattr(c[0], 'aty'): + content.aty = (content.tag, c[0].aty) + self.cast(content) + break + return start + + def end(self, parent, content): + # + # For soap encoded arrays, the soapenc:arrayType attribute is + # added with proper type and size information. + # Eg: soapenc:arrayType="xs:int[3]" + # + Literal.end(self, parent, content) + if content.aty is None: + return + tag, aty = content.aty + ns0 = ('at0', aty[1]) + ns1 = ('at1', 'http://schemas.xmlsoap.org/soap/encoding/') + array = content.value.item + child = parent.getChild(tag) + child.addPrefix(ns0[0], ns0[1]) + child.addPrefix(ns1[0], ns1[1]) + name = '%s:arrayType' % ns1[0] + value = '%s:%s[%d]' % (ns0[0], aty[0], len(array)) + child.set(name, value) + + def encode(self, node, content): + if content.type.any(): + Typer.auto(node, content.value) + return + if content.real.any(): + Typer.auto(node, content.value) + return + ns = None + name = content.real.name + if self.xstq: + ns = content.real.namespace() + Typer.manual(node, name, ns) + + def cast(self, content): + """ + Cast the I{untyped} list items found in content I{value}. + Each items contained in the list is checked for XSD type information. + Items (values) that are I{untyped}, are replaced with suds objects and + type I{metadata} is added. + @param content: The content holding the collection. + @type content: L{Content} + @return: self + @rtype: L{Encoded} + """ + aty = content.aty[1] + resolved = content.type.resolve() + array = Factory.object(resolved.name) + array.item = [] + query = TypeQuery(aty) + ref = query.execute(self.schema) + if ref is None: + raise TypeNotFound(qref) + for x in content.value: + if isinstance(x, (list, tuple)): + array.item.append(x) + continue + if isinstance(x, Object): + md = x.__metadata__ + md.sxtype = ref + array.item.append(x) + continue + if isinstance(x, dict): + x = Factory.object(ref.name, x) + md = x.__metadata__ + md.sxtype = ref + array.item.append(x) + continue + x = Factory.property(ref.name, x) + md = x.__metadata__ + md.sxtype = ref + array.item.append(x) + content.value = array + return self diff --git a/pym/calculate/contrib/suds/mx/encoded.pyc b/pym/calculate/contrib/suds/mx/encoded.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a57c2e4d501e8fda1318df25c7b291328d08fff GIT binary patch literal 3691 zcmb_f&u<&Y6@JTKA}Pt1C0mVpD7Hl$&_P2bX&V%35ja(1Ab=seD+6iO1k8AMC6Zb0 zQaeM3Y{W~|Q%^bc)Kl;Mi+b&~#{#{!-}h!IsfPwh9GN@&=Ixs|^M1_tp6mbG?0)|0 zUq6kd`m5vp5Rd&6hD789V<1UQvOu0yRLxU$$?7s`$Vo#2erZV7lu1iYT7KS?Y)vL@ zIcdwJBPSitZAsRZ$-11ZOOS5JcvHr=Bw3To0N>k^Hsln#I`T)6OOfB6+?J#($Gvr) z=>dlB)3SImN>Ur9d0ZrE5`Or_#FTbuvMeo^VVoIjQ`_&3{)4|>fF+K@>z-T#`FP~g z(qx{|1moFanwGs9Mfv@aiCs}HTnqG*=i@YXUbIt*{(6?;D?Mf0LRWm?k8E77F?$Z1J*+~c9_8HR3%zxTr9C+|HCEeElOv@avJZiJZ1|s4Xs;b^b>c8X*)M<;5o!&|BS(j zj03q4xd`O4Cd-;!)TI1U9Ed>1b#V=GO*yUcEBIu#WQ9>TVyXhJv7!hS8AM{In&)# zL2Rtk23Cj2af1q_dz|Mjk09_d4j|Avr#^qzcK&$ zJA-$Ax}Tn%?b}&m_b2mJy!z9HYJDB+>^AkRZ3jOHZU>vePOyh@J&5TR-VxfW0sK3N zn*oILF6$EDHAWhWeAbroH4?|3^)UimXQU7#Mye)z2*?t7*_LICz8^Pa+?3^76=%d2 z@mV6SZN~fpl1GD)H1w&-v!!`*okK@Oo<{txIRreKXv&QI-0AU8FGtiZ0ZyYBPN1E)YO#ByB*A5(H_{*tCXg|+`4lOBOPp~1~|mHOiVsQ>7fUF z1Sy-Nj%oaG9L%h0dAWG#W*+aKK&RcsAc(_`Muj8e(h0VMn0qqcuAt)utcObw5#lvr z9~1n5AnIFq16TleAsU2$hM-gdGX^czPk5fpCa*QzPUpkn;P`7_Q{j#xlP>+)Xe}H|kG_y4kaUlTc#_@iv^D>=gNctrFeB_2`LlPSn z+DqBci!5OqL|ftl9iX;I zH`c2DO8Ovt{KcWK(#xv@JSe6oCE$9WFp?ri1j_9pzdL& zQeARJfr?W*Mgx7z~mk9t^a9iddtfH#qPN*Jdd7t=ckfLCCkv2f*Cv)H$)_5B2pZ<5mcM43V)dz;J^d;v?p5LnMVz&A4Gx>DU+$MdE z+jYWK39r6M=jc!^uCtAP!o@uOci;sL!Y{qs-(?$OX??5K4Z4WmRr+3qPL# AjsO4v literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/mx/literal.py b/pym/calculate/contrib/suds/mx/literal.py new file mode 100644 index 0000000..a7e5e38 --- /dev/null +++ b/pym/calculate/contrib/suds/mx/literal.py @@ -0,0 +1,311 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the (LGPL) GNU Lesser General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License +# for more details at ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Provides literal I{marshaller} classes. + +""" + +from suds import * +from suds.mx import * +from suds.mx.core import Core +from suds.mx.typer import Typer +from suds.resolver import Frame, GraphResolver +from suds.sax.element import Element +from suds.sudsobject import Factory + +from logging import getLogger +log = getLogger(__name__) + + +# add typed extensions +Content.extensions.append("type") # The expected xsd type +Content.extensions.append("real") # The 'true' XSD type +Content.extensions.append("ancestry") # The 'type' ancestry + + +class Typed(Core): + """ + A I{typed} marshaller. + + This marshaller is semi-typed as needed to support both I{document/literal} + and I{rpc/literal} SOAP message styles. + + @ivar schema: An XSD schema. + @type schema: L{xsd.schema.Schema} + @ivar resolver: A schema type resolver. + @type resolver: L{GraphResolver} + + """ + + def __init__(self, schema, xstq=True): + """ + @param schema: A schema object + @type schema: L{xsd.schema.Schema} + @param xstq: The B{x}ml B{s}chema B{t}ype B{q}ualified flag indicates + that the I{xsi:type} attribute values should be qualified by + namespace. + @type xstq: bool + + """ + Core.__init__(self) + self.schema = schema + self.xstq = xstq + self.resolver = GraphResolver(self.schema) + + def reset(self): + self.resolver.reset() + + def start(self, content): + """ + Start marshalling the 'content' by ensuring that both the 'content' + _and_ the resolver are primed with the XSD type information. The + 'content' value is both translated and sorted based on the XSD type. + Only values that are objects have their attributes sorted. + + """ + log.debug("starting content:\n%s", content) + if content.type is None: + name = content.tag + if name.startswith("_"): + name = "@" + name[1:] + content.type = self.resolver.find(name, content.value) + if content.type is None: + raise TypeNotFound(content.tag) + else: + known = None + if isinstance(content.value, Object): + known = self.resolver.known(content.value) + if known is None: + log.debug("object %s has no type information", + content.value) + known = content.type + frame = Frame(content.type, resolved=known) + self.resolver.push(frame) + frame = self.resolver.top() + content.real = frame.resolved + content.ancestry = frame.ancestry + self.translate(content) + self.sort(content) + if self.skip(content): + log.debug("skipping (optional) content:\n%s", content) + self.resolver.pop() + return False + return True + + def suspend(self, content): + """ + Suspend to process list content. + + Primarily, this involves popping the 'list' content off the resolver's + stack so its list items can be marshalled. + + """ + self.resolver.pop() + + def resume(self, content): + """ + Resume processing list content. + + To do this, we really need to simply push the 'list' content back onto + the resolver stack. + + """ + self.resolver.push(Frame(content.type)) + + def end(self, parent, content): + """ + End processing the content. + + Make sure the content ending matches the top of the resolver stack + since for list processing we play games with the resolver stack. + + """ + log.debug("ending content:\n%s", content) + current = self.resolver.top().type + if current != content.type: + raise Exception("content (end) mismatch: top=(%s) cont=(%s)" % ( + current, content)) + self.resolver.pop() + + def node(self, content): + """ + Create an XML node. + + The XML node is namespace qualified as defined by the corresponding + schema element. + + """ + ns = content.type.namespace() + if content.type.form_qualified: + node = Element(content.tag, ns=ns) + if ns[0]: + node.addPrefix(ns[0], ns[1]) + else: + node = Element(content.tag) + self.encode(node, content) + log.debug("created - node:\n%s", node) + return node + + def setnil(self, node, content): + """ + Set the 'node' nil only if the XSD type specifies that it is permitted. + + """ + if content.type.nillable: + node.setnil() + + def setdefault(self, node, content): + """Set the node to the default value specified by the XSD type.""" + default = content.type.default + if default is not None: + node.setText(default) + return default + + def optional(self, content): + if content.type.optional(): + return True + for a in content.ancestry: + if a.optional(): + return True + return False + + def encode(self, node, content): + """ + Add (SOAP) encoding information if needed. + + The encoding information is added only if the resolved type is derived + by extension. Furthermore, the xsi:type value is qualified by namespace + only if the content (tag) and referenced type are in different + namespaces. + + """ + if content.type.any(): + return + if not content.real.extension(): + return + if content.type.resolve() == content.real: + return + ns = None + name = content.real.name + if self.xstq: + ns = content.real.namespace("ns1") + Typer.manual(node, name, ns) + + def skip(self, content): + """ + Get whether to skip this I{content}. + + Should be skipped when the content is optional and value is either None + or an empty list. + + @param content: Content to skip. + @type content: L{Object} + @return: True if content is to be skipped. + @rtype: bool + + """ + if self.optional(content): + v = content.value + if v is None: + return True + if isinstance(v, (list, tuple)) and not v: + return True + return False + + def optional(self, content): + if content.type.optional(): + return True + for a in content.ancestry: + if a.optional(): + return True + return False + + def translate(self, content): + """ + Translate using the XSD type information. + + Python I{dict} is translated to a suds object. Most importantly, + primitive values are translated from python to XML types using the XSD + type. + + @param content: Content to translate. + @type content: L{Object} + @return: self + @rtype: L{Typed} + + """ + v = content.value + if v is None: + return + if isinstance(v, dict): + cls = content.real.name + content.value = Factory.object(cls, v) + md = content.value.__metadata__ + md.sxtype = content.type + return + v = content.real.translate(v, False) + content.value = v + return self + + def sort(self, content): + """ + Sort suds object attributes. + + The attributes are sorted based on the ordering defined in the XSD type + information. + + @param content: Content to sort. + @type content: L{Object} + @return: self + @rtype: L{Typed} + + """ + v = content.value + if isinstance(v, Object): + md = v.__metadata__ + md.ordering = self.ordering(content.real) + return self + + def ordering(self, type): + """ + Attribute ordering defined in the specified XSD type information. + + @param type: XSD type object. + @type type: L{SchemaObject} + @return: An ordered list of attribute names. + @rtype: list + + """ + result = [] + for child, ancestry in type.resolve(): + name = child.name + if child.name is None: + continue + if child.isattr(): + name = "_%s" % (child.name,) + result.append(name) + return result + + +class Literal(Typed): + """ + A I{literal} marshaller. + + This marshaller is semi-typed as needed to support both I{document/literal} + and I{rpc/literal} soap message styles. + + """ + pass diff --git a/pym/calculate/contrib/suds/mx/literal.pyc b/pym/calculate/contrib/suds/mx/literal.pyc new file mode 100644 index 0000000000000000000000000000000000000000..44d2d3c80c0580d475d613f6bcaaecdeeaa714d8 GIT binary patch literal 9850 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/mx/typer.py b/pym/calculate/contrib/suds/mx/typer.py new file mode 100644 index 0000000..3533ddc --- /dev/null +++ b/pym/calculate/contrib/suds/mx/typer.py @@ -0,0 +1,126 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the (LGPL) GNU Lesser General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License +# for more details at ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Provides XSD typing classes. + +""" + +from suds.sax import Namespace +from suds.sax.text import Text +from suds.sudsobject import Object + + +class Typer: + """ + Provides XML node typing as either automatic or manual. + + @cvar types: Class to XSD type mapping. + @type types: dict + + """ + + types = { + bool: ("boolean", Namespace.xsdns), + float: ("float", Namespace.xsdns), + int: ("int", Namespace.xsdns), + long: ("long", Namespace.xsdns), + str: ("string", Namespace.xsdns), + Text: ("string", Namespace.xsdns), + unicode: ("string", Namespace.xsdns)} + + @classmethod + def auto(cls, node, value=None): + """ + Automatically set the node's xsi:type attribute based on either + I{value}'s or the node text's class. When I{value} is an unmapped + class, the default type (xs:any) is set. + + @param node: XML node. + @type node: L{sax.element.Element} + @param value: Object that is or would be the node's text. + @type value: I{any} + @return: Specified node. + @rtype: L{sax.element.Element} + + """ + if value is None: + value = node.getText() + if isinstance(value, Object): + known = cls.known(value) + if known.name is None: + return node + tm = known.name, known.namespace() + else: + tm = cls.types.get(value.__class__, cls.types.get(str)) + cls.manual(node, *tm) + return node + + @classmethod + def manual(cls, node, tval, ns=None): + """ + Set the node's xsi:type attribute based on either I{value}'s or the + node text's class. Then adds the referenced prefix(s) to the node's + prefix mapping. + + @param node: XML node. + @type node: L{sax.element.Element} + @param tval: XSD schema type name. + @type tval: str + @param ns: I{tval} XML namespace. + @type ns: (prefix, URI) + @return: Specified node. + @rtype: L{sax.element.Element} + + """ + xta = ":".join((Namespace.xsins[0], "type")) + node.addPrefix(Namespace.xsins[0], Namespace.xsins[1]) + if ns is None: + node.set(xta, tval) + else: + ns = cls.genprefix(node, ns) + qname = ":".join((ns[0], tval)) + node.set(xta, qname) + node.addPrefix(ns[0], ns[1]) + return node + + @classmethod + def genprefix(cls, node, ns): + """ + Generate a prefix. + + @param node: XML node on which the prefix will be used. + @type node: L{sax.element.Element} + @param ns: Namespace needing a unique prefix. + @type ns: (prefix, URI) + @return: I{ns} with a new prefix. + @rtype: (prefix, URI) + + """ + for i in range(1, 1024): + prefix = "ns%d" % (i,) + uri = node.resolvePrefix(prefix, default=None) + if uri in (None, ns[1]): + return prefix, ns[1] + raise Exception("auto prefix, exhausted") + + @classmethod + def known(cls, object): + try: + md = object.__metadata__ + known = md.sxtype + return known + except Exception: + pass diff --git a/pym/calculate/contrib/suds/mx/typer.pyc b/pym/calculate/contrib/suds/mx/typer.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d6e5549512f4a5df6a51cf6d928a2e9f647c199 GIT binary patch literal 3819 zcmb_f-EJF26h31+PU1F7nnKkdR2HeIuGBgLp$bI^722wb)CROJY8wfe$?hcCbUo|t zj2lNuZYbRG2wd<8JOP(H1h2sZz<1899XAz%(mL|gGjrz5`T4$cru9D;T6VhQ6t6kI^}ihH)x{~<_*ecsNbZGCgwAg&QaQ=ABbKM zJ=vJ0be6j9c~<*AhSt|*@jOe7iyn9HM1Fse+3hIFwR6UGTCMCaeA)_vo{y~SzHtMc zn6T8q(nB-yVb;X#tIb`Lct67%`vX(H>b-!aU@CAlrtWgGw6q!2hHfXCxW`=IU z!{d1q^ZL|$7W2l`d=B%OsrmegdF#ad6y4l7O=f}8mc&KT3q>1?EmAX%rgo9Z{EjIjJ@iFi`z(oyGU{tP)H!0z zhi@g%b;$>eTa9jW_#_PzJ$7j_c&F&cbk`g#&B5Uggl+2@)8{?+C?~sj%s9qfg0~Z<%=4XDIF3g z4J(M?QJoHvL%=PZz0YU6VTs2kYe9aG8f34?$ywT+8UC<6O)_#h$95(1D zMT+&cYi#9jz@tQhBlpEPraI5}BWHYsP)q!;x@hFGRf!e?QD&P%Z=y}@Od1uo%E?5} z+QD<356uxyAvt3mkq5l7B#h`pk9LfW#*$IyB5k9g0u6&IAiUR zTh(^|8lQumRpur816}IA7`+-juHX}rE!%ROA+;LaKX7`~F}dj*>pOSDzekh1Zv{=_ z%4!tY2url*OX1gEG0f9w6Yx0>61#ZvvP!|)0SunfUK&3v?P}B=m?YcE5JTt=X z{-c!>GuPXvkx0ShdSQ(~ciVWbC4c|`>oV)Swuy;3;{xZWw%D_B#G(pGIpQBujzoa3 zc7k`PlKoy!a?$I_DnKvb55#LT@MS&8T~G^GM3Fcji-mG~zYS56!QH^G&0&_OE1PNN zd?(NBaCBqz>CN8FPgczK_KF*(Zlyn3VQb3HU|&=-@vq~gdxteGo>q(1UqhX*T~SLa zVG1%cCsh0u6L4u4Mq&gfYjgpH5ENpzfgV_`PwiDw4Y~mOC{PYnkxBeSBxjgK%v9{z zu5ha<+!8K>yx}T7hI=4b-Gg(uC!C&<)8XE+Amqn4GCifX{4q_>?&}hALazxCC#VTU z^(8_+WJ2mRMY#l^OS5H41JtC^0KcNAewn~*a;3vKuCb;}s&%zNsxI<3yumemE2^1PA`$p*0>(jf=< zG5VJL_$dZL-TC%Dw?B{*tk_a?u41QjF3ONbdNAMBk1wNlv%U)s-~*n zyo~t?=mnP<*Hp(avhKrFT20lK-8n3BX|D8MkIZOC51lvZdRuVEX)m=!KUv^k#ufQ< zGYw(J@!e5k20kmSl)q!>#vfo)=#oj_2|*VC56kS0V9PJ}1YgHZiWbhP1@*2vruJLoN`^cW52AK7Emx=7 zYcx}-@*_@Sd=+~VDsfwOitt|mHl&|Q7kwjF`Sv}0gR8Z=n#bQ99A0lTdHo!QUXKd_ zEaSHWOfAx3&Qs=1ua_1{uQy$eQj`&n5kHn=4pb~Phoxh#12H=vfgLh(ZnxQ*h>F{GO_{TnlWk`pl$zw}y4_YDdzn?v9(PtqOpL2X1FEnf7 GNBwWhjc(`w literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/options.py b/pym/calculate/contrib/suds/options.py new file mode 100644 index 0000000..a296ad5 --- /dev/null +++ b/pym/calculate/contrib/suds/options.py @@ -0,0 +1,162 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Suds basic options classes. +""" + +from suds.cache import Cache, NoCache +from suds.properties import * +from suds.store import DocumentStore, defaultDocumentStore +from suds.transport import Transport +from suds.wsse import Security +from suds.xsd.doctor import Doctor + + +class TpLinker(AutoLinker): + """ + Transport (auto) linker used to manage linkage between + transport objects Properties and those Properties that contain them. + """ + + def updated(self, properties, prev, next): + if isinstance(prev, Transport): + tp = Unskin(prev.options) + properties.unlink(tp) + if isinstance(next, Transport): + tp = Unskin(next.options) + properties.link(tp) + + +class Options(Skin): + """ + Options: + - B{cache} - The XML document cache. May be set to None for no caching. + - type: L{Cache} + - default: L{NoCache()} + - B{documentStore} - The XML document store used to access locally + stored documents without having to download them from an external + location. May be set to None for no internal suds library document + store. + - type: L{DocumentStore} + - default: L{defaultDocumentStore} + - B{extraArgumentErrors} - Raise exceptions when unknown message parts + are detected when receiving a web service reply, compared to the + operation's WSDL schema definition. + - type: I{bool} + - default: True + - B{allowUnknownMessageParts} - Raise exceptions when extra arguments are + detected when invoking a web service operation, compared to the + operation's WSDL schema definition. + - type: I{bool} + - default: False + - B{faults} - Raise faults raised by server, else return tuple from + service method invocation as (httpcode, object). + - type: I{bool} + - default: True + - B{service} - The default service name. + - type: I{str} + - default: None + - B{port} - The default service port name, not tcp port. + - type: I{str} + - default: None + - B{location} - This overrides the service port address I{URL} defined + in the WSDL. + - type: I{str} + - default: None + - B{transport} - The message transport. + - type: L{Transport} + - default: None + - B{soapheaders} - The soap headers to be included in the soap message. + - type: I{any} + - default: None + - B{wsse} - The web services I{security} provider object. + - type: L{Security} + - default: None + - B{doctor} - A schema I{doctor} object. + - type: L{Doctor} + - default: None + - B{xstq} - The B{x}ml B{s}chema B{t}ype B{q}ualified flag indicates + that the I{xsi:type} attribute values should be qualified by + namespace. + - type: I{bool} + - default: True + - B{prefixes} - Elements of the soap message should be qualified (when + needed) using XML prefixes as opposed to xmlns="" syntax. + - type: I{bool} + - default: True + - B{retxml} - Flag that causes the I{raw} soap envelope to be returned + instead of the python object graph. + - type: I{bool} + - default: False + - B{prettyxml} - Flag that causes I{pretty} xml to be rendered when + generating the outbound soap envelope. + - type: I{bool} + - default: False + - B{autoblend} - Flag that ensures that the schema(s) defined within + the WSDL import each other. + - type: I{bool} + - default: False + - B{cachingpolicy} - The caching policy. + - type: I{int} + - 0 = Cache XML documents. + - 1 = Cache WSDL (pickled) object. + - default: 0 + - B{plugins} - A plugin container. + - type: I{list} + - default: I{list()} + - B{nosend} - Create the soap envelope but do not send. + When specified, method invocation returns a I{RequestContext} + instead of sending it. + - type: I{bool} + - default: False + - B{unwrap} - Enable automatic parameter unwrapping when possible. + Enabled by default. If disabled, no input or output parameters are + ever automatically unwrapped. + - type: I{bool} + - default: True + - B{sortNamespaces} - Namespaces are sorted alphabetically. If disabled, + namespaces are left in the order they are received from the source. + Enabled by default for historical purposes. + - type: I{bool} + - default: True + """ + def __init__(self, **kwargs): + domain = __name__ + definitions = [ + Definition('cache', Cache, NoCache()), + Definition('documentStore', DocumentStore, defaultDocumentStore), + Definition('extraArgumentErrors', bool, True), + Definition('allowUnknownMessageParts', bool, False), + Definition('faults', bool, True), + Definition('transport', Transport, None, TpLinker()), + Definition('service', (int, basestring), None), + Definition('port', (int, basestring), None), + Definition('location', basestring, None), + Definition('soapheaders', (), ()), + Definition('wsse', Security, None), + Definition('doctor', Doctor, None), + Definition('xstq', bool, True), + Definition('prefixes', bool, True), + Definition('retxml', bool, False), + Definition('prettyxml', bool, False), + Definition('autoblend', bool, False), + Definition('cachingpolicy', int, 0), + Definition('plugins', (list, tuple), []), + Definition('nosend', bool, False), + Definition('unwrap', bool, True), + Definition('sortNamespaces', bool, True)] + Skin.__init__(self, domain, definitions, kwargs) diff --git a/pym/calculate/contrib/suds/options.pyc b/pym/calculate/contrib/suds/options.pyc new file mode 100644 index 0000000000000000000000000000000000000000..40214ad024d82aff6a05680a3a0908acc93569b6 GIT binary patch literal 6864 zcmc&(ZEqXL5nhtAEXkH%Vqt1WU*CxOI*H3{c zKOOx26MpueXhI*Gxp|6P{c&&=R3Gr5l9}cdIa82kN zJbI-by(z-0Vz0YSQvMRn+FlV_IZ!qVWR|-qORWrIWv#YbYteu4>9#@UE}?m%g0Xg& z@wA)qbGJoP)O_iwi0#uXC=#8zJ(n5nKEX(+hpLEOW5U0>irIamQk!SS`JojI?dhN} zk(>IFWzQ7s98K=$J5l;dn_BC%{$u>?r)V^^4mF@{lkTAm=)1Sa;@Q80U`^svuPM8# zaM@iMGfP=m9ZHwUM5St^d6fPRw3}$1@~f^AS7w8kI&fBgXR=%y7ilY1ir2@P)yD_j zSUDMFsZ&vkS)FV#qhJZrkXp%Vp5SMHLgR#Z(L$_HJV1P>P} zX~~h;^w4E`>RBBRnOR$bqOIJ$TA z^;i9`es^DwM)xgD^L{D8Rz78ciabxthXQrPYqCcsEP69A-wQ852b5$eSMVt3LOn zo96nV+?laU&+7#j1f~BHP38D^7jz_8B?tTbsRCL;gWA7T5NK;n9NvGZcjx(7=0Az60j#@oysD8 zl|nHxfo2J`a%G%tNUv}Lp>_Z*pd7zrbf6?KDA3aAJf3a>v=VUfkO*Bj zm=Wf&YJX$p_j^xwq=juJ3JVOQG-91M=t%{Yt!>W+Sr#w$dWw4XO|e*ybOA%jCNKOR zpZhI-M>{-QA*?;AO7#Jp&4MGX*i=Q79%ewjk!)(B-sb;R8{ewfE`%p_@Qr$G^S&<) znMNoFQ$9*yD{cZZ0ii)IY3QS_Um=p0 zA+j<%)W$?1q6fHGy>Avpg`pvw+@8JY?aaMv>9F1o8L8gU2dgAQm zc4qrkkaV%Lv6;%pT7}x<9Nls>B+D_ve%x+R8pK5iD=+uXB&B#~3$;B{>GWdaOb`WE z+dqbmbRM>hQ0Edc&mm6Fl-_Z+06ViPti6~NxLa{|k{pjJjNPUSmj`_edfuYAk%+Qk zG-NpU$ebuFf5>q{Jx@MzWZmm(qX)Ph)ioTa73%aMWCevtSluQ%w-x#?M3*q-_MxdcTmcM30rYEPWVNT(dC zQ1A#dL@YVT3M6Wb8`bVVviy`)4q}~#%_GpMEr96$JQ(iTr@HoT1@0W~Mop6p0^?b>617^Nb^8`BRRWhBrPZ~ki#@T z_vCMDV%~E%kAhb*dDPihS0mYjnj>HJaWO)6OB;D4bM91m`1z`fk&d3+$uY#-o)Jm+ zoh&GYYx@&_Vl;4Y0U?!@NkASl3yv;`wyA;dDU7$d4j5B60X*-`l59RfN)S-$0jx$=g`|Xt zauR?O4xpcnK-}E8XTV`=d6Zjndni#AAjTm@W4K&$=nly&{Fk2UHBJWh8WGh(8p<#$ zIrKXkC)@jwq{JdR+^w!9Hnc^L@(o~&p=3+N`B!GW{ zoXk*^0k5AjXP>&!)l2y=V@Xz+cQ412n&pDP7}lE^l1Ao*p)2VWXM7*U1XPTpTFB@4 z{TV;|4~(FwHRqxhDsrd;Ih36}6a(9}qY;d>M(x;2=XhY1Q!&~CzZSjU{iElbo zHhjB;Dlygnet|>T<#H|oyM_i(ply_FsW5g*<-vW1@w2jUE)e=06i0#+sS*ILhm|>= zFABmVxJFkcLO48_$s+P+Dhj=srw?>_jG|J0vkIt~z(+c~XdN_gufBqLi;b%-!ir>M zLik(3GA9q;{ODl|=TDLyckyEdL#k}|sNo{x)4J@@!;t8aAM`rZETLif31j(zY8!k4 z4645FN>r4qazzmig34^_m@{hgfO!K5?NM>IM`AM@x`LPur}aFvM|E4ON%s3xgz5LW zB-*2W@V;J6P!93C4T04lCglTj%aV;EdG1e+8)2>`SyiF1L2Ow}?5dzzU|a-xfQ=;^^S( zc!MU6)wHQz&SP8#Ja)QlCq!JEy+2g)1b%_cnNM%Q_sE7@-njjV67xs6L3j8+5o`v% n-(##t@_(oj*e3qq%iw<`|F)N&ohjqCpdAy4~X literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/plugin.py b/pym/calculate/contrib/suds/plugin.py new file mode 100644 index 0000000..b957897 --- /dev/null +++ b/pym/calculate/contrib/suds/plugin.py @@ -0,0 +1,276 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the (LGPL) GNU Lesser General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License +# for more details at ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +The plugin module provides suds plugin implementation classes. + +""" + +from suds import * + +from logging import getLogger +log = getLogger(__name__) + + +class Context(object): + """Plugin context.""" + pass + + +class InitContext(Context): + """ + Init Context. + + @ivar wsdl: The WSDL. + @type wsdl: L{wsdl.Definitions} + + """ + pass + + +class DocumentContext(Context): + """ + The XML document load context. + + @ivar url: The URL. + @type url: str + @ivar document: Either the XML text or the B{parsed} document root. + @type document: (str|L{sax.element.Element}) + + """ + pass + + +class MessageContext(Context): + """ + The context for sending the SOAP envelope. + + @ivar envelope: The SOAP envelope to be sent. + @type envelope: (str|L{sax.element.Element}) + @ivar reply: The reply. + @type reply: (str|L{sax.element.Element}|object) + + """ + pass + + +class Plugin: + """Plugin base.""" + pass + + +class InitPlugin(Plugin): + """Base class for all suds I{init} plugins.""" + + def initialized(self, context): + """ + Suds client initialization. + + Called after WSDL the has been loaded. Provides the plugin with the + opportunity to inspect/modify the WSDL. + + @param context: The init context. + @type context: L{InitContext} + + """ + pass + + +class DocumentPlugin(Plugin): + """Base class for suds I{document} plugins.""" + + def loaded(self, context): + """ + Suds has loaded a WSDL/XSD document. + + Provides the plugin with an opportunity to inspect/modify the unparsed + document. Called after each WSDL/XSD document is loaded. + + @param context: The document context. + @type context: L{DocumentContext} + + """ + pass + + def parsed(self, context): + """ + Suds has parsed a WSDL/XSD document. + + Provides the plugin with an opportunity to inspect/modify the parsed + document. Called after each WSDL/XSD document is parsed. + + @param context: The document context. + @type context: L{DocumentContext} + + """ + pass + + +class MessagePlugin(Plugin): + """Base class for suds I{SOAP message} plugins.""" + + def marshalled(self, context): + """ + Suds is about to send the specified SOAP envelope. + + Provides the plugin with the opportunity to inspect/modify the envelope + Document before it is sent. + + @param context: The send context. + The I{envelope} is the envelope document. + @type context: L{MessageContext} + + """ + pass + + def sending(self, context): + """ + Suds is about to send the specified SOAP envelope. + + Provides the plugin with the opportunity to inspect/modify the message + text before it is sent. + + @param context: The send context. + The I{envelope} is the envelope text. + @type context: L{MessageContext} + + """ + pass + + def received(self, context): + """ + Suds has received the specified reply. + + Provides the plugin with the opportunity to inspect/modify the received + XML text before it is SAX parsed. + + @param context: The reply context. + The I{reply} is the raw text. + @type context: L{MessageContext} + + """ + pass + + def parsed(self, context): + """ + Suds has SAX parsed the received reply. + + Provides the plugin with the opportunity to inspect/modify the SAX + parsed DOM tree for the reply before it is unmarshalled. + + @param context: The reply context. + The I{reply} is DOM tree. + @type context: L{MessageContext} + + """ + pass + + def unmarshalled(self, context): + """ + Suds has unmarshalled the received reply. + + Provides the plugin with the opportunity to inspect/modify the + unmarshalled reply object before it is returned. + + @param context: The reply context. + The I{reply} is unmarshalled suds object. + @type context: L{MessageContext} + + """ + pass + + +class PluginContainer: + """ + Plugin container provides easy method invocation. + + @ivar plugins: A list of plugin objects. + @type plugins: [L{Plugin},] + @cvar ctxclass: A dict of plugin method / context classes. + @type ctxclass: dict + + """ + + domains = { + 'init': (InitContext, InitPlugin), + 'document': (DocumentContext, DocumentPlugin), + 'message': (MessageContext, MessagePlugin)} + + def __init__(self, plugins): + """ + @param plugins: A list of plugin objects. + @type plugins: [L{Plugin},] + + """ + self.plugins = plugins + + def __getattr__(self, name): + domain = self.domains.get(name) + if not domain: + raise Exception, 'plugin domain (%s), invalid' % (name,) + ctx, pclass = domain + plugins = [p for p in self.plugins if isinstance(p, pclass)] + return PluginDomain(ctx, plugins) + + +class PluginDomain: + """ + The plugin domain. + + @ivar ctx: A context. + @type ctx: L{Context} + @ivar plugins: A list of plugins (targets). + @type plugins: list + + """ + + def __init__(self, ctx, plugins): + self.ctx = ctx + self.plugins = plugins + + def __getattr__(self, name): + return Method(name, self) + + +class Method: + """ + Plugin method. + + @ivar name: The method name. + @type name: str + @ivar domain: The plugin domain. + @type domain: L{PluginDomain} + + """ + + def __init__(self, name, domain): + """ + @param name: The method name. + @type name: str + @param domain: A plugin domain. + @type domain: L{PluginDomain} + + """ + self.name = name + self.domain = domain + + def __call__(self, **kwargs): + ctx = self.domain.ctx() + ctx.__dict__.update(kwargs) + for plugin in self.domain.plugins: + method = getattr(plugin, self.name, None) + if method and callable(method): + method(ctx) + return ctx diff --git a/pym/calculate/contrib/suds/plugin.pyc b/pym/calculate/contrib/suds/plugin.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c3789c40d4729df3ab76a2c0624965c5795e1852 GIT binary patch literal 9198 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/properties.py b/pym/calculate/contrib/suds/properties.py new file mode 100644 index 0000000..5907d94 --- /dev/null +++ b/pym/calculate/contrib/suds/properties.py @@ -0,0 +1,539 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Properties classes. +""" + + +class AutoLinker(object): + """ + Base class, provides interface for I{automatic} link + management between a L{Properties} object and the L{Properties} + contained within I{values}. + """ + def updated(self, properties, prev, next): + """ + Notification that a values was updated and the linkage + between the I{properties} contained with I{prev} need to + be relinked to the L{Properties} contained within the + I{next} value. + """ + pass + + +class Link(object): + """ + Property link object. + @ivar endpoints: A tuple of the (2) endpoints of the link. + @type endpoints: tuple(2) + """ + def __init__(self, a, b): + """ + @param a: Property (A) to link. + @type a: L{Property} + @param b: Property (B) to link. + @type b: L{Property} + """ + pA = Endpoint(self, a) + pB = Endpoint(self, b) + self.endpoints = (pA, pB) + self.validate(a, b) + a.links.append(pB) + b.links.append(pA) + + def validate(self, pA, pB): + """ + Validate that the two properties may be linked. + @param pA: Endpoint (A) to link. + @type pA: L{Endpoint} + @param pB: Endpoint (B) to link. + @type pB: L{Endpoint} + @return: self + @rtype: L{Link} + """ + if pA in pB.links or \ + pB in pA.links: + raise Exception, 'Already linked' + dA = pA.domains() + dB = pB.domains() + for d in dA: + if d in dB: + raise Exception, 'Duplicate domain "%s" found' % d + for d in dB: + if d in dA: + raise Exception, 'Duplicate domain "%s" found' % d + kA = pA.keys() + kB = pB.keys() + for k in kA: + if k in kB: + raise Exception, 'Duplicate key %s found' % k + for k in kB: + if k in kA: + raise Exception, 'Duplicate key %s found' % k + return self + + def teardown(self): + """ + Teardown the link. + Removes endpoints from properties I{links} collection. + @return: self + @rtype: L{Link} + """ + pA, pB = self.endpoints + if pA in pB.links: + pB.links.remove(pA) + if pB in pA.links: + pA.links.remove(pB) + return self + + +class Endpoint(object): + """ + Link endpoint (wrapper). + @ivar link: The associated link. + @type link: L{Link} + @ivar target: The properties object. + @type target: L{Property} + """ + def __init__(self, link, target): + self.link = link + self.target = target + + def teardown(self): + return self.link.teardown() + + def __eq__(self, rhs): + return ( self.target == rhs ) + + def __hash__(self): + return hash(self.target) + + def __getattr__(self, name): + return getattr(self.target, name) + + +class Definition: + """ + Property definition. + @ivar name: The property name. + @type name: str + @ivar classes: The (class) list of permitted values + @type classes: tuple + @ivar default: The default value. + @ivar type: any + """ + def __init__(self, name, classes, default, linker=AutoLinker()): + """ + @param name: The property name. + @type name: str + @param classes: The (class) list of permitted values + @type classes: tuple + @param default: The default value. + @type default: any + """ + if not isinstance(classes, (list, tuple)): + classes = (classes,) + self.name = name + self.classes = classes + self.default = default + self.linker = linker + + def nvl(self, value=None): + """ + Convert the I{value} into the default when I{None}. + @param value: The proposed value. + @type value: any + @return: The I{default} when I{value} is I{None}, else I{value}. + @rtype: any + """ + if value is None: + return self.default + else: + return value + + def validate(self, value): + """ + Validate the I{value} is of the correct class. + @param value: The value to validate. + @type value: any + @raise AttributeError: When I{value} is invalid. + """ + if value is None: + return + if len(self.classes) and \ + not isinstance(value, self.classes): + msg = '"%s" must be: %s' % (self.name, self.classes) + raise AttributeError,msg + + + def __repr__(self): + return '%s: %s' % (self.name, str(self)) + + def __str__(self): + s = [] + if len(self.classes): + s.append('classes=%s' % str(self.classes)) + else: + s.append('classes=*') + s.append("default=%s" % str(self.default)) + return ', '.join(s) + + +class Properties: + """ + Represents basic application properties. + Provides basic type validation, default values and + link/synchronization behavior. + @ivar domain: The domain name. + @type domain: str + @ivar definitions: A table of property definitions. + @type definitions: {name: L{Definition}} + @ivar links: A list of linked property objects used to create + a network of properties. + @type links: [L{Property},..] + @ivar defined: A dict of property values. + @type defined: dict + """ + def __init__(self, domain, definitions, kwargs): + """ + @param domain: The property domain name. + @type domain: str + @param definitions: A table of property definitions. + @type definitions: {name: L{Definition}} + @param kwargs: A list of property name/values to set. + @type kwargs: dict + """ + self.definitions = {} + for d in definitions: + self.definitions[d.name] = d + self.domain = domain + self.links = [] + self.defined = {} + self.modified = set() + self.prime() + self.update(kwargs) + + def definition(self, name): + """ + Get the definition for the property I{name}. + @param name: The property I{name} to find the definition for. + @type name: str + @return: The property definition + @rtype: L{Definition} + @raise AttributeError: On not found. + """ + d = self.definitions.get(name) + if d is None: + raise AttributeError(name) + return d + + def update(self, other): + """ + Update the property values as specified by keyword/value. + @param other: An object to update from. + @type other: (dict|L{Properties}) + @return: self + @rtype: L{Properties} + """ + if isinstance(other, Properties): + other = other.defined + for n,v in other.items(): + self.set(n, v) + return self + + def notset(self, name): + """ + Get whether a property has never been set by I{name}. + @param name: A property name. + @type name: str + @return: True if never been set. + @rtype: bool + """ + self.provider(name).__notset(name) + + def set(self, name, value): + """ + Set the I{value} of a property by I{name}. + The value is validated against the definition and set + to the default when I{value} is None. + @param name: The property name. + @type name: str + @param value: The new property value. + @type value: any + @return: self + @rtype: L{Properties} + """ + self.provider(name).__set(name, value) + return self + + def unset(self, name): + """ + Unset a property by I{name}. + @param name: A property name. + @type name: str + @return: self + @rtype: L{Properties} + """ + self.provider(name).__set(name, None) + return self + + def get(self, name, *df): + """ + Get the value of a property by I{name}. + @param name: The property name. + @type name: str + @param df: An optional value to be returned when the value + is not set + @type df: [1]. + @return: The stored value, or I{df[0]} if not set. + @rtype: any + """ + return self.provider(name).__get(name, *df) + + def link(self, other): + """ + Link (associate) this object with anI{other} properties object + to create a network of properties. Links are bidirectional. + @param other: The object to link. + @type other: L{Properties} + @return: self + @rtype: L{Properties} + """ + Link(self, other) + return self + + def unlink(self, *others): + """ + Unlink (disassociate) the specified properties object. + @param others: The list object to unlink. Unspecified means unlink all. + @type others: [L{Properties},..] + @return: self + @rtype: L{Properties} + """ + if not len(others): + others = self.links[:] + for p in self.links[:]: + if p in others: + p.teardown() + return self + + def provider(self, name, history=None): + """ + Find the provider of the property by I{name}. + @param name: The property name. + @type name: str + @param history: A history of nodes checked to prevent + circular hunting. + @type history: [L{Properties},..] + @return: The provider when found. Otherwise, None (when nested) + and I{self} when not nested. + @rtype: L{Properties} + """ + if history is None: + history = [] + history.append(self) + if name in self.definitions: + return self + for x in self.links: + if x in history: + continue + provider = x.provider(name, history) + if provider is not None: + return provider + history.remove(self) + if len(history): + return None + return self + + def keys(self, history=None): + """ + Get the set of I{all} property names. + @param history: A history of nodes checked to prevent + circular hunting. + @type history: [L{Properties},..] + @return: A set of property names. + @rtype: list + """ + if history is None: + history = [] + history.append(self) + keys = set() + keys.update(self.definitions.keys()) + for x in self.links: + if x in history: + continue + keys.update(x.keys(history)) + history.remove(self) + return keys + + def domains(self, history=None): + """ + Get the set of I{all} domain names. + @param history: A history of nodes checked to prevent + circular hunting. + @type history: [L{Properties},..] + @return: A set of domain names. + @rtype: list + """ + if history is None: + history = [] + history.append(self) + domains = set() + domains.add(self.domain) + for x in self.links: + if x in history: + continue + domains.update(x.domains(history)) + history.remove(self) + return domains + + def prime(self): + """ + Prime the stored values based on default values + found in property definitions. + @return: self + @rtype: L{Properties} + """ + for d in self.definitions.values(): + self.defined[d.name] = d.default + return self + + def __notset(self, name): + return not (name in self.modified) + + def __set(self, name, value): + d = self.definition(name) + d.validate(value) + value = d.nvl(value) + prev = self.defined[name] + self.defined[name] = value + self.modified.add(name) + d.linker.updated(self, prev, value) + + def __get(self, name, *df): + d = self.definition(name) + value = self.defined.get(name) + if value == d.default and len(df): + value = df[0] + return value + + def str(self, history): + s = [] + s.append('Definitions:') + for d in self.definitions.values(): + s.append('\t%s' % repr(d)) + s.append('Content:') + for d in self.defined.items(): + s.append('\t%s' % str(d)) + if self not in history: + history.append(self) + s.append('Linked:') + for x in self.links: + s.append(x.str(history)) + history.remove(self) + return '\n'.join(s) + + def __repr__(self): + return str(self) + + def __str__(self): + return self.str([]) + + +class Skin(object): + """ + The meta-programming I{skin} around the L{Properties} object. + @ivar __pts__: The wrapped object. + @type __pts__: L{Properties}. + """ + def __init__(self, domain, definitions, kwargs): + self.__pts__ = Properties(domain, definitions, kwargs) + + def __setattr__(self, name, value): + builtin = name.startswith('__') and name.endswith('__') + if builtin: + self.__dict__[name] = value + return + self.__pts__.set(name, value) + + def __getattr__(self, name): + return self.__pts__.get(name) + + def __repr__(self): + return str(self) + + def __str__(self): + return str(self.__pts__) + + +class Unskin(object): + def __new__(self, *args, **kwargs): + return args[0].__pts__ + + +class Inspector: + """ + Wrapper inspector. + """ + def __init__(self, options): + self.properties = options.__pts__ + + def get(self, name, *df): + """ + Get the value of a property by I{name}. + @param name: The property name. + @type name: str + @param df: An optional value to be returned when the value + is not set + @type df: [1]. + @return: The stored value, or I{df[0]} if not set. + @rtype: any + """ + return self.properties.get(name, *df) + + def update(self, **kwargs): + """ + Update the property values as specified by keyword/value. + @param kwargs: A list of property name/values to set. + @type kwargs: dict + @return: self + @rtype: L{Properties} + """ + return self.properties.update(**kwargs) + + def link(self, other): + """ + Link (associate) this object with anI{other} properties object + to create a network of properties. Links are bidirectional. + @param other: The object to link. + @type other: L{Properties} + @return: self + @rtype: L{Properties} + """ + p = other.__pts__ + return self.properties.link(p) + + def unlink(self, other): + """ + Unlink (disassociate) the specified properties object. + @param other: The object to unlink. + @type other: L{Properties} + @return: self + @rtype: L{Properties} + """ + p = other.__pts__ + return self.properties.unlink(p) diff --git a/pym/calculate/contrib/suds/properties.pyc b/pym/calculate/contrib/suds/properties.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bfaaf1d4a5643ea2dba5ac723435018fb6f36c86 GIT binary patch literal 19774 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 T_^Z`}^TFx*`TE7n7eDwCM;@$M literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/resolver.py b/pym/calculate/contrib/suds/resolver.py new file mode 100644 index 0000000..82014f6 --- /dev/null +++ b/pym/calculate/contrib/suds/resolver.py @@ -0,0 +1,493 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +The I{resolver} module provides a collection of classes that +provide wsdl/xsd named type resolution. +""" + +from suds import * +from suds.sax import splitPrefix, Namespace +from suds.sudsobject import Object +from suds.xsd.query import BlindQuery, TypeQuery, qualify + +import re + +from logging import getLogger +log = getLogger(__name__) + + +class Resolver: + """ + An I{abstract} schema-type resolver. + @ivar schema: A schema object. + @type schema: L{xsd.schema.Schema} + """ + + def __init__(self, schema): + """ + @param schema: A schema object. + @type schema: L{xsd.schema.Schema} + """ + self.schema = schema + + def find(self, name, resolved=True): + """ + Get the definition object for the schema object by name. + @param name: The name of a schema object. + @type name: basestring + @param resolved: A flag indicating that the fully resolved type + should be returned. + @type resolved: boolean + @return: The found schema I{type} + @rtype: L{xsd.sxbase.SchemaObject} + """ + log.debug('searching schema for (%s)', name) + qref = qualify(name, self.schema.root, self.schema.tns) + query = BlindQuery(qref) + result = query.execute(self.schema) + if result is None: + log.error('(%s) not-found', name) + return None + log.debug('found (%s) as (%s)', name, Repr(result)) + if resolved: + result = result.resolve() + return result + + +class PathResolver(Resolver): + """ + Resolves the definition object for the schema type located at a given path. + The path may contain (.) dot notation to specify nested types. + @ivar wsdl: A wsdl object. + @type wsdl: L{wsdl.Definitions} + """ + + def __init__(self, wsdl, ps='.'): + """ + @param wsdl: A schema object. + @type wsdl: L{wsdl.Definitions} + @param ps: The path separator character + @type ps: char + """ + Resolver.__init__(self, wsdl.schema) + self.wsdl = wsdl + self.altp = re.compile('({)(.+)(})(.+)') + self.splitp = re.compile('({.+})*[^\\%s]+' % ps[0]) + + def find(self, path, resolved=True): + """ + Get the definition object for the schema type located at the specified path. + The path may contain (.) dot notation to specify nested types. + Actually, the path separator is usually a (.) but can be redefined + during contruction. + @param path: A (.) separated path to a schema type. + @type path: basestring + @param resolved: A flag indicating that the fully resolved type + should be returned. + @type resolved: boolean + @return: The found schema I{type} + @rtype: L{xsd.sxbase.SchemaObject} + """ + result = None + parts = self.split(path) + try: + result = self.root(parts) + if len(parts) > 1: + result = result.resolve(nobuiltin=True) + result = self.branch(result, parts) + result = self.leaf(result, parts) + if resolved: + result = result.resolve(nobuiltin=True) + except PathResolver.BadPath: + log.error('path: "%s", not-found' % path) + return result + + def root(self, parts): + """ + Find the path root. + @param parts: A list of path parts. + @type parts: [str,..] + @return: The root. + @rtype: L{xsd.sxbase.SchemaObject} + """ + result = None + name = parts[0] + log.debug('searching schema for (%s)', name) + qref = self.qualify(parts[0]) + query = BlindQuery(qref) + result = query.execute(self.schema) + if result is None: + log.error('(%s) not-found', name) + raise PathResolver.BadPath(name) + log.debug('found (%s) as (%s)', name, Repr(result)) + return result + + def branch(self, root, parts): + """ + Traverse the path until a leaf is reached. + @param parts: A list of path parts. + @type parts: [str,..] + @param root: The root. + @type root: L{xsd.sxbase.SchemaObject} + @return: The end of the branch. + @rtype: L{xsd.sxbase.SchemaObject} + """ + result = root + for part in parts[1:-1]: + name = splitPrefix(part)[1] + log.debug('searching parent (%s) for (%s)', Repr(result), name) + result, ancestry = result.get_child(name) + if result is None: + log.error('(%s) not-found', name) + raise PathResolver.BadPath(name) + result = result.resolve(nobuiltin=True) + log.debug('found (%s) as (%s)', name, Repr(result)) + return result + + def leaf(self, parent, parts): + """ + Find the leaf. + @param parts: A list of path parts. + @type parts: [str,..] + @param parent: The leaf's parent. + @type parent: L{xsd.sxbase.SchemaObject} + @return: The leaf. + @rtype: L{xsd.sxbase.SchemaObject} + """ + name = splitPrefix(parts[-1])[1] + if name.startswith('@'): + result, path = parent.get_attribute(name[1:]) + else: + result, ancestry = parent.get_child(name) + if result is None: + raise PathResolver.BadPath(name) + return result + + def qualify(self, name): + """ + Qualify the name as either: + - plain name + - ns prefixed name (eg: ns0:Person) + - fully ns qualified name (eg: {http://myns-uri}Person) + @param name: The name of an object in the schema. + @type name: str + @return: A qualified name. + @rtype: qname + """ + m = self.altp.match(name) + if m is None: + return qualify(name, self.wsdl.root, self.wsdl.tns) + else: + return (m.group(4), m.group(2)) + + def split(self, s): + """ + Split the string on (.) while preserving any (.) inside the + '{}' alternalte syntax for full ns qualification. + @param s: A plain or qualified name. + @type s: str + @return: A list of the name's parts. + @rtype: [str,..] + """ + parts = [] + b = 0 + while 1: + m = self.splitp.match(s, b) + if m is None: + break + b,e = m.span() + parts.append(s[b:e]) + b = e+1 + return parts + + class BadPath(Exception): pass + + +class TreeResolver(Resolver): + """ + The tree resolver is a I{stateful} tree resolver + used to resolve each node in a tree. As such, it mirrors + the tree structure to ensure that nodes are resolved in + context. + @ivar stack: The context stack. + @type stack: list + """ + + def __init__(self, schema): + """ + @param schema: A schema object. + @type schema: L{xsd.schema.Schema} + """ + Resolver.__init__(self, schema) + self.stack = Stack() + + def reset(self): + """ + Reset the resolver's state. + """ + self.stack = Stack() + + def push(self, x): + """ + Push an I{object} onto the stack. + @param x: An object to push. + @type x: L{Frame} + @return: The pushed frame. + @rtype: L{Frame} + """ + if isinstance(x, Frame): + frame = x + else: + frame = Frame(x) + self.stack.append(frame) + log.debug('push: (%s)\n%s', Repr(frame), Repr(self.stack)) + return frame + + def top(self): + """ + Get the I{frame} at the top of the stack. + @return: The top I{frame}, else None. + @rtype: L{Frame} + """ + if len(self.stack): + return self.stack[-1] + else: + return Frame.Empty() + + def pop(self): + """ + Pop the frame at the top of the stack. + @return: The popped frame, else None. + @rtype: L{Frame} + """ + if len(self.stack): + popped = self.stack.pop() + log.debug('pop: (%s)\n%s', Repr(popped), Repr(self.stack)) + return popped + log.debug('stack empty, not-popped') + return None + + def depth(self): + """ + Get the current stack depth. + @return: The current stack depth. + @rtype: int + """ + return len(self.stack) + + def getchild(self, name, parent): + """Get a child by name.""" + log.debug('searching parent (%s) for (%s)', Repr(parent), name) + if name.startswith('@'): + return parent.get_attribute(name[1:]) + return parent.get_child(name) + + +class NodeResolver(TreeResolver): + """ + The node resolver is a I{stateful} XML document resolver + used to resolve each node in a tree. As such, it mirrors + the tree structure to ensure that nodes are resolved in + context. + """ + + def __init__(self, schema): + """ + @param schema: A schema object. + @type schema: L{xsd.schema.Schema} + """ + TreeResolver.__init__(self, schema) + + def find(self, node, resolved=False, push=True): + """ + @param node: An xml node to be resolved. + @type node: L{sax.element.Element} + @param resolved: A flag indicating that the fully resolved type should be + returned. + @type resolved: boolean + @param push: Indicates that the resolved type should be + pushed onto the stack. + @type push: boolean + @return: The found schema I{type} + @rtype: L{xsd.sxbase.SchemaObject} + """ + name = node.name + parent = self.top().resolved + if parent is None: + result, ancestry = self.query(name, node) + else: + result, ancestry = self.getchild(name, parent) + known = self.known(node) + if result is None: + return result + if push: + frame = Frame(result, resolved=known, ancestry=ancestry) + pushed = self.push(frame) + if resolved: + result = result.resolve() + return result + + def findattr(self, name, resolved=True): + """ + Find an attribute type definition. + @param name: An attribute name. + @type name: basestring + @param resolved: A flag indicating that the fully resolved type should be + returned. + @type resolved: boolean + @return: The found schema I{type} + @rtype: L{xsd.sxbase.SchemaObject} + """ + name = '@%s'%name + parent = self.top().resolved + if parent is None: + result, ancestry = self.query(name, node) + else: + result, ancestry = self.getchild(name, parent) + if result is None: + return result + if resolved: + result = result.resolve() + return result + + def query(self, name, node): + """Blindly query the schema by name.""" + log.debug('searching schema for (%s)', name) + qref = qualify(name, node, node.namespace()) + query = BlindQuery(qref) + result = query.execute(self.schema) + return (result, []) + + def known(self, node): + """Resolve type referenced by @xsi:type.""" + ref = node.get('type', Namespace.xsins) + if ref is None: + return None + qref = qualify(ref, node, node.namespace()) + query = BlindQuery(qref) + return query.execute(self.schema) + + +class GraphResolver(TreeResolver): + """ + The graph resolver is a I{stateful} L{Object} graph resolver + used to resolve each node in a tree. As such, it mirrors + the tree structure to ensure that nodes are resolved in + context. + """ + + def __init__(self, schema): + """ + @param schema: A schema object. + @type schema: L{xsd.schema.Schema} + """ + TreeResolver.__init__(self, schema) + + def find(self, name, object, resolved=False, push=True): + """ + @param name: The name of the object to be resolved. + @type name: basestring + @param object: The name's value. + @type object: (any|L{Object}) + @param resolved: A flag indicating that the fully resolved type + should be returned. + @type resolved: boolean + @param push: Indicates that the resolved type should be + pushed onto the stack. + @type push: boolean + @return: The found schema I{type} + @rtype: L{xsd.sxbase.SchemaObject} + """ + known = None + parent = self.top().resolved + if parent is None: + result, ancestry = self.query(name) + else: + result, ancestry = self.getchild(name, parent) + if result is None: + return None + if isinstance(object, Object): + known = self.known(object) + if push: + frame = Frame(result, resolved=known, ancestry=ancestry) + pushed = self.push(frame) + if resolved: + if known is None: + result = result.resolve() + else: + result = known + return result + + def query(self, name): + """Blindly query the schema by name.""" + log.debug('searching schema for (%s)', name) + schema = self.schema + wsdl = self.wsdl() + if wsdl is None: + qref = qualify(name, schema.root, schema.tns) + else: + qref = qualify(name, wsdl.root, wsdl.tns) + query = BlindQuery(qref) + result = query.execute(schema) + return (result, []) + + def wsdl(self): + """Get the wsdl.""" + container = self.schema.container + if container is None: + return None + else: + return container.wsdl + + def known(self, object): + """Get the type specified in the object's metadata.""" + try: + md = object.__metadata__ + known = md.sxtype + return known + except Exception: + pass + + +class Frame: + def __init__(self, type, resolved=None, ancestry=()): + self.type = type + if resolved is None: + resolved = type.resolve() + self.resolved = resolved.resolve() + self.ancestry = ancestry + + def __str__(self): + return '%s\n%s\n%s' % \ + (Repr(self.type), + Repr(self.resolved), + [Repr(t) for t in self.ancestry]) + + class Empty: + def __getattr__(self, name): + if name == 'ancestry': + return () + else: + return None + + +class Stack(list): + def __repr__(self): + result = [] + for item in self: + result.append(repr(item)) + return '\n'.join(result) diff --git a/pym/calculate/contrib/suds/resolver.pyc b/pym/calculate/contrib/suds/resolver.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1485599444225407dcee15759fbd373e09101b6d GIT binary patch literal 17810 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 HIXd&dC)qZE literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/sax/__init__.py b/pym/calculate/contrib/suds/sax/__init__.py new file mode 100644 index 0000000..c75b320 --- /dev/null +++ b/pym/calculate/contrib/suds/sax/__init__.py @@ -0,0 +1,104 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the (LGPL) GNU Lesser General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License +# for more details at ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +The sax module contains a collection of classes that provide a (D)ocument +(O)bject (M)odel representation of an XML document. The goal is to provide an +easy, intuitive interface for managing XML documents. Although the term DOM is +used here, this model is B{far} better. + +XML namespaces in suds are represented using a (2) element tuple containing the +prefix and the URI, e.g. I{('tns', 'http://myns')} + +@var encoder: A I{pluggable} XML special character processor used to encode/ + decode strings. +@type encoder: L{Encoder} + +""" + +from suds.sax.enc import Encoder + +# pluggable XML special character encoder. +encoder = Encoder() + + +def splitPrefix(name): + """ + Split the name into a tuple (I{prefix}, I{name}). The first element in the + tuple is I{None} when the name does not have a prefix. + + @param name: A node name containing an optional prefix. + @type name: basestring + @return: A tuple containing the (2) parts of I{name}. + @rtype: (I{prefix}, I{name}) + + """ + if isinstance(name, basestring) and ":" in name: + return tuple(name.split(":", 1)) + return None, name + + +class Namespace: + """XML namespace.""" + + default = (None, None) + xmlns = ("xml", "http://www.w3.org/XML/1998/namespace") + xsdns = ("xs", "http://www.w3.org/2001/XMLSchema") + xsins = ("xsi", "http://www.w3.org/2001/XMLSchema-instance") + all = (xsdns, xsins) + + @classmethod + def create(cls, p=None, u=None): + return p, u + + @classmethod + def none(cls, ns): + return ns == cls.default + + @classmethod + def xsd(cls, ns): + try: + return cls.w3(ns) and ns[1].endswith("XMLSchema") + except Exception: + pass + return False + + @classmethod + def xsi(cls, ns): + try: + return cls.w3(ns) and ns[1].endswith("XMLSchema-instance") + except Exception: + pass + return False + + @classmethod + def xs(cls, ns): + return cls.xsd(ns) or cls.xsi(ns) + + @classmethod + def w3(cls, ns): + try: + return ns[1].startswith("http://www.w3.org") + except Exception: + pass + return False + + @classmethod + def isns(cls, ns): + try: + return isinstance(ns, tuple) and len(ns) == len(cls.default) + except Exception: + pass + return False diff --git a/pym/calculate/contrib/suds/sax/__init__.pyc b/pym/calculate/contrib/suds/sax/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e2eb920bec904bb6769021cc9af2cb84ed77261a GIT binary patch literal 3656 zcmcInZEq7t5Z<#BC%Ggfp@J6Cs;ep$=gQawS_&zG@G2pJsV;q?{&GFvt?h&Joprm$ zwn9F^4{3j6e?a@ptY1U{i59TEd%JtPvop^;GrKPTwdsy_|M)!;(@z=C0~CD&RV+jc zwIkw^NFC8HiB?HCsw7_EMOnmU@e++C5#zTa;$`aM)o-n35m&^aw@QL`NZOy(UKrJ>eJOVbOD92EJpBvzQ@-Kpl$u&*-XdXK8@ zCs-i8ht)h*sVvl>P#UkonUFA(j~_me@pMUD((c_nOl1Pe`9f~ys!&gAGRe#^G08JU zEmd^FNXbrK$bOiG-6ZS2B2L%k&D8YrVYdf0mBfO+yz}TGgu6qnV%bxLs^JwjgSpTU zjax^ZusD`&WiY+&x};wg_LUxBFO6-b9>##9Pz!q?YN%;<*nhDqRjLR8X@-LZg7g|n zxPYLOjAfX`tkci_{hCzuZe89#^3It|pR37pJ!1y@jYfZhZuQu851xgER9OTai+y<$ zQwQm=+YQ^PI%bRYKt%~qi+W)ZMo^rPgSr~fu%*D#u5Y*!pIDJBsZ9a3blp8LlYv_7 z@ZjjK-3)stf8*mh;D=d3HGL7$0F@<_+bH@6R7QyBs2%a5B#J$vBf3v3)HWq*KLHh) zqnPl*5r^O0Elt=P@&{pMT~9qS!^2Z>rT5Tk50f-* zwBtmZdYWXz@%izU%faPu8>-uFP@FW7N*Y0sWQhra`e0(#v5GhNkum<7x)oGn{j77^ zF>7cwu@6UEMC0_K-EX1jKT#i1?&vtq4^SYK3^!S`}(d z#3%T-B3?4>S}qT+auRezYn{7mv+f3W-C1{&yX&*=3GQypx?9}coOQQ_f9QQes-8gg zO75teGKR+eRPW+B4e`-vR3BZc=S8=H$&J0MSFbb(XSN?Pg9Td4H_pF!;lds*I*fX% zA6nr$(badDe11lRh*Y9NJKaXnM3m=<+mek+OCgL2kEZc1QL33>1FnbfO$l;;RH)FX z>u70GMU*0X%nEC^i2>3KSp-RiQifHIYEDhD>V(78c(lr=*^FPN-&;W@KSJRaWd2({ z3LRGO8XA+`sd~^8=`H_?6h^{3^TZ}SWV~Oq9kB$(p1Pv=UO0}EIpQ&3J!E{F9J3q+ zbI)>SWK%|$%qn(KS*%Bi>G8C?<4AGl;n2Mordllk@K0j;dz(*=AM5xY9!w8WDm%N* zrnBVCo%AtK(4_nvg*jyz4*wM1`KPJ+l&a5AePFZw4ajVwyv=5!8GHV7G%PEv+XrX4 z3#u{;W;|tDp21v}{Gqj_y!s2uTlsk&FDIwwgv4dh9>JE74inOw6OzJ<{B8-UchGz- zW7&*A2?M7J4l3g0$8!gH99P_hJ5IfYf_E@!QscXbGrf!C-|+o|-GN9VXO$^HDT`S9 zm)QOrbNiR)>4mbB&%UEHzzHx_nNNs(G-LVjO?0N)*k#VY8XMeX<}~fYXY}9oJh7bP z6Iepc;I@&$tbd-N5q_OZW>ai30He;!*tnP^i4#pWUba_j$HTztBje21b* zWW}kJQ24unba=A7wY0U0FY2bp*n8iJ_hZHWv}Fgzls6g;De~j X&|kA)U;hH4HOa4(w##efwe5cZ0DeSl literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/sax/attribute.py b/pym/calculate/contrib/suds/sax/attribute.py new file mode 100644 index 0000000..e8c4247 --- /dev/null +++ b/pym/calculate/contrib/suds/sax/attribute.py @@ -0,0 +1,173 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the (LGPL) GNU Lesser General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License +# for more details at ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Provides XML I{attribute} classes. + +""" + +from suds import UnicodeMixin +from suds.sax import splitPrefix, Namespace +from suds.sax.text import Text + + +class Attribute(UnicodeMixin): + """ + An XML attribute object. + + @ivar parent: The node containing this attribute. + @type parent: L{element.Element} + @ivar prefix: The I{optional} namespace prefix. + @type prefix: basestring + @ivar name: The I{unqualified} attribute name. + @type name: basestring + @ivar value: The attribute's value. + @type value: basestring + + """ + + def __init__(self, name, value=None): + """ + @param name: The attribute's name with I{optional} namespace prefix. + @type name: basestring + @param value: The attribute's value. + @type value: basestring + + """ + self.parent = None + self.prefix, self.name = splitPrefix(name) + self.setValue(value) + + def clone(self, parent=None): + """ + Clone this object. + + @param parent: The parent for the clone. + @type parent: L{element.Element} + @return: A copy of this object assigned to the new parent. + @rtype: L{Attribute} + + """ + a = Attribute(self.qname(), self.value) + a.parent = parent + return a + + def qname(self): + """ + Get this attribute's B{fully} qualified name. + + @return: The fully qualified name. + @rtype: basestring + + """ + if self.prefix is None: + return self.name + return ":".join((self.prefix, self.name)) + + def setValue(self, value): + """ + Set the attribute's value. + + @param value: The new value (may be None). + @type value: basestring + @return: self + @rtype: L{Attribute} + + """ + if isinstance(value, Text): + self.value = value + else: + self.value = Text(value) + return self + + def getValue(self, default=Text("")): + """ + Get the attributes value with optional default. + + @param default: An optional value to return when the attribute's value + has not been set. + @type default: basestring + @return: The attribute's value, or I{default}. + @rtype: L{Text} + + """ + return self.value or default + + def hasText(self): + """ + Get whether the attribute has a non-empty I{text} string value. + + @return: True when has I{text}. + @rtype: boolean + + """ + return bool(self.value) + + def namespace(self): + """ + Get the attribute's namespace. This may either be the namespace defined + by an optional prefix, or the default namespace. + + @return: The attribute's namespace. + @rtype: (I{prefix}, I{name}) + + """ + if self.prefix is None: + return Namespace.default + return self.resolvePrefix(self.prefix) + + def resolvePrefix(self, prefix): + """ + Resolve the specified prefix to a known namespace. + + @param prefix: A declared prefix. + @type prefix: basestring + @return: The namespace mapped to I{prefix}. + @rtype: (I{prefix}, I{name}) + + """ + if self.parent is None: + return Namespace.default + return self.parent.resolvePrefix(prefix) + + def match(self, name=None, ns=None): + """ + Match by (optional) name and/or (optional) namespace. + + @param name: The optional attribute tag name. + @type name: str + @param ns: An optional namespace. + @type ns: (I{prefix}, I{name}) + @return: True if matched. + @rtype: boolean + + """ + byname = name is None or (self.name == name) + byns = ns is None or (self.namespace()[1] == ns[1]) + return byname and byns + + def __eq__(self, rhs): + """Equals operator.""" + return (isinstance(rhs, Attribute) and self.prefix == rhs.name and + self.name == rhs.name) + + def __repr__(self): + """Programmer friendly string representation.""" + return "attr (prefix=%s, name=%s, value=(%s))" % (self.prefix, + self.name, self.value) + + def __unicode__(self): + """XML string representation.""" + return u'%s="%s"' % (self.qname(), self.value and self.value.escape()) diff --git a/pym/calculate/contrib/suds/sax/attribute.pyc b/pym/calculate/contrib/suds/sax/attribute.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8ff5655b0298ef1e7f9ad44db6ff4d5a29afec8d GIT binary patch literal 5750 zcmb_g-EJI78Lesm&SV^$1wz6K(TQ*vqwE+EtWZQ&&PFQ~HZiMqSb>Gq^i0>-o%D21 zrg|KYoViLQE)n7d;D#G+c>`XA8*aGe0pOgkx@+38H(9MclFQZg^HtS3-(S_jf7eW{*rB7ROzxB zuBiPLd@m{OsR70=tJg}sQtG$+t14bmd!1Fv-$c>+Y@8n@u{Qp19zXIQodv}tfXzY)ovCfLS{*y!PXTZwu=UEXYS&|+2#bIK6H@j}j*`KU?yMp@NnLDHmBjT~aSScF{WaL@&)hF;~P2Gaw}z%317j>-*!0{1-`a z2pf18rXoxTI~RxATJHv9F6#>b;eg%FG7eJEgm&{x7yPms7Kl;Gx3xTu;jRj?a9w;( zIywYYrW>6O0(KQkC}hbFDoP50x;IJEc)J%Trs$?gHaY&__-7x6AO2)p9~^9(No=-F zbiD1L>yD^AEY?FwVzWqS3|sRc((2j@-gPX1UcKP;2ia8{1=#<3>@oXGS2S$_hH4Oshmhev!*EnSN0ka&4_K)#a}L=;VIo`DWH#aDfg<3s?v%&&gjvml_aAAuniE zp9NuwE>0Tx7es!Fie;>Iz0qv+DW892?E(9?QP93%hMs!1s>avk6BNPFo{9yck0TIl z!~*wZ&*l%9=(ziZE-Y+Lb>I~~J{e5XbUO2$*C}0%o3>MdPfsd?&x|F6{Oyz=zv)ug zC#c=swMegEUjff=ErGy4%@N9YY61Gf=mu*LCE!_8SZ}OYQ>e^A`nniIQ-E88DR^r9 zKI?RAp32tQXnmb+L0Q_wKQPY$v?sXgxwD=-TQ_D0S`N=w^F~xs`Sd%(XzKU0Psg%V z(^&Cu<%}Al1d~6<3q8twp||TfRjQySCnm{E5oLWHuuYU*Jhs(y>i)$!U=s2x{Fzl0 zs_i9dWrN+3~-0D8eBuVjA}M)R6)a!^&pz0RXQM8 zS@_Ei_>s(aqb&(=9ahi%7l%3%H&Qnf8RYgsk%y5%UQvKJ3^y99v6a6aA_#{vrb1ys8!Kg8m`MpR2W2b^A=q#ob;Y?VemWXy zQD9QCgp$TTqu&8U8i6t*f(;7}0Rc4vtl0;8I4Y(j1%Nc;K_J`+=0ZA zmU7lv;CgwU>L{!EeePSrGP|r1T%HdS3a}xvm0}?a+Ui-*ZllxcKK!}$??|)Y*!S3K zb1U2)XcXMA`8Ns&!WpB0`(gZ&%)g8L7r8Dyj7Dk&z~N}{e?EfNk|20GdA+G0)y%`D zvZ9lmS8CLJewlQO;@2aEBlXmF+$vS5=sY~JE6nbIH|~43HRoryBSB&wE_nRl8z>6; zi?KF&dZg`@=Msa5+>jiGM_9>*=jN#>;&lG)^jQW=V-WiO1Az{Rz@9-!F(ciV%)h)q zFrkV3XIcItJ0EcC)+~U`j$(}~;~1HcZK_#-_@rv!yIhhxIuvI#vWb=BsV21aM_-CV zhG84>9f!enwAF$RX}++l5}~gksm!Q^vITrollcDu`#wd1AY;?1(e=__q2(FUV99>V zu8*V(Ih9<2ZXhj&iQeESnB{`Xf2m$B!YnD++^WZ_$5GKg^kGb$D$;BThcK>q8xH=B zW^1i;%`X!MGGVVum6UnB@Qdg`MAjG)n(ZX`Os8a(G;=!iIiAl*z`%1^l>o;W=S-cR zHyJ=ta9kbN1Xa1c3-`;FV@g1S~logZKf-l`6e$PN)m2IE9$aXPJn^H{^Z7(AIod=Kf$+ZKa>-?47z-ln-D z>M9jUsP1((&DNGx1&70>M`3~+hTL8l{tfjKhVw33x9c##2gC61Sk5LL-frh> z_$VI=XiH%z_kb`Q=J6!uCwCi$ao!I@>!|tC81UsyE>i)sd3#y-CTrhfL9-Q)8+?bg z@3Qb&+(I$8QmK8##|<$P0&Q3HLtF3G?$u7yB*o!CI;Du z7QB=M_^^lOyGa-CCh}Yp(6dMeQ8jm&XWGNjCN5{^g7(iXz8`%ZV&xvR>}@ozH8vLh E4=g`Yc>n+a literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/sax/date.py b/pym/calculate/contrib/suds/sax/date.py new file mode 100644 index 0000000..6418796 --- /dev/null +++ b/pym/calculate/contrib/suds/sax/date.py @@ -0,0 +1,460 @@ +# -*- coding: utf-8 -*- + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jurko Gospodnetić ( jurko.gospodnetic@pke.hr ) +# based on code by: Glen Walker +# based on code by: Nathan Van Gheem ( vangheem@gmail.com ) + +"""Classes for conversion between XML dates and Python objects.""" + +from suds import UnicodeMixin + +import datetime +import re +import time + + +_SNIPPET_DATE = \ + r"(?P\d{1,})-(?P\d{1,2})-(?P\d{1,2})" +_SNIPPET_TIME = \ + r"(?P\d{1,2}):(?P[0-5]?[0-9]):(?P[0-5]?[0-9])" \ + r"(?:\.(?P\d+))?" +_SNIPPET_ZONE = \ + r"(?:(?P[-+])(?P\d{1,2})" \ + r"(?::(?P[0-5]?[0-9]))?)" \ + r"|(?P[Zz])" + +_PATTERN_DATE = r"^%s(?:%s)?$" % (_SNIPPET_DATE, _SNIPPET_ZONE) +_PATTERN_TIME = r"^%s(?:%s)?$" % (_SNIPPET_TIME, _SNIPPET_ZONE) +_PATTERN_DATETIME = r"^%s[T ]%s(?:%s)?$" % (_SNIPPET_DATE, _SNIPPET_TIME, + _SNIPPET_ZONE) + +_RE_DATE = re.compile(_PATTERN_DATE) +_RE_TIME = re.compile(_PATTERN_TIME) +_RE_DATETIME = re.compile(_PATTERN_DATETIME) + + +class Date(UnicodeMixin): + """ + An XML date object supporting the xsd:date datatype. + + @ivar value: The object value. + @type value: B{datetime}.I{date} + + """ + + def __init__(self, value): + """ + @param value: The date value of the object. + @type value: (datetime.date|str) + @raise ValueError: When I{value} is invalid. + + """ + if isinstance(value, datetime.datetime): + self.value = value.date() + elif isinstance(value, datetime.date): + self.value = value + elif isinstance(value, basestring): + self.value = self.__parse(value) + else: + raise ValueError("invalid type for Date(): %s" % type(value)) + + @staticmethod + def __parse(value): + """ + Parse the string date. + + Supports the subset of ISO8601 used by xsd:date, but is lenient with + what is accepted, handling most reasonable syntax. + + Any timezone is parsed but ignored because a) it is meaningless without + a time and b) B{datetime}.I{date} does not support timezone + information. + + @param value: A date string. + @type value: str + @return: A date object. + @rtype: B{datetime}.I{date} + + """ + match_result = _RE_DATE.match(value) + if match_result is None: + raise ValueError("date data has invalid format '%s'" % (value,)) + return _date_from_match(match_result) + + def __unicode__(self): + return self.value.isoformat() + + +class DateTime(UnicodeMixin): + """ + An XML datetime object supporting the xsd:dateTime datatype. + + @ivar value: The object value. + @type value: B{datetime}.I{datetime} + + """ + + def __init__(self, value): + """ + @param value: The datetime value of the object. + @type value: (datetime.datetime|str) + @raise ValueError: When I{value} is invalid. + + """ + if isinstance(value, datetime.datetime): + self.value = value + elif isinstance(value, basestring): + self.value = self.__parse(value) + else: + raise ValueError("invalid type for DateTime(): %s" % type(value)) + + @staticmethod + def __parse(value): + """ + Parse the string datetime. + + Supports the subset of ISO8601 used by xsd:dateTime, but is lenient + with what is accepted, handling most reasonable syntax. + + Subsecond information is rounded to microseconds due to a restriction + in the python datetime.datetime/time implementation. + + @param value: A datetime string. + @type value: str + @return: A datetime object. + @rtype: B{datetime}.I{datetime} + + """ + match_result = _RE_DATETIME.match(value) + if match_result is None: + raise ValueError("date data has invalid format '%s'" % (value,)) + + date = _date_from_match(match_result) + time, round_up = _time_from_match(match_result) + tzinfo = _tzinfo_from_match(match_result) + + value = datetime.datetime.combine(date, time) + value = value.replace(tzinfo=tzinfo) + if round_up: + value += datetime.timedelta(microseconds=1) + return value + + def __unicode__(self): + return self.value.isoformat() + + +class Time(UnicodeMixin): + """ + An XML time object supporting the xsd:time datatype. + + @ivar value: The object value. + @type value: B{datetime}.I{time} + + """ + + def __init__(self, value): + """ + @param value: The time value of the object. + @type value: (datetime.time|str) + @raise ValueError: When I{value} is invalid. + + """ + if isinstance(value, datetime.time): + self.value = value + elif isinstance(value, basestring): + self.value = self.__parse(value) + else: + raise ValueError("invalid type for Time(): %s" % type(value)) + + @staticmethod + def __parse(value): + """ + Parse the string date. + + Supports the subset of ISO8601 used by xsd:time, but is lenient with + what is accepted, handling most reasonable syntax. + + Subsecond information is rounded to microseconds due to a restriction + in the python datetime.time implementation. + + @param value: A time string. + @type value: str + @return: A time object. + @rtype: B{datetime}.I{time} + + """ + match_result = _RE_TIME.match(value) + if match_result is None: + raise ValueError("date data has invalid format '%s'" % (value,)) + + time, round_up = _time_from_match(match_result) + tzinfo = _tzinfo_from_match(match_result) + if round_up: + time = _bump_up_time_by_microsecond(time) + return time.replace(tzinfo=tzinfo) + + def __unicode__(self): + return self.value.isoformat() + + +class FixedOffsetTimezone(datetime.tzinfo, UnicodeMixin): + """ + A timezone with a fixed offset and no daylight savings adjustment. + + http://docs.python.org/library/datetime.html#datetime.tzinfo + + """ + + def __init__(self, offset): + """ + @param offset: The fixed offset of the timezone. + @type offset: I{int} or B{datetime}.I{timedelta} + + """ + if type(offset) == int: + offset = datetime.timedelta(hours=offset) + elif type(offset) != datetime.timedelta: + raise TypeError("timezone offset must be an int or " + "datetime.timedelta") + if offset.microseconds or (offset.seconds % 60 != 0): + raise ValueError("timezone offset must have minute precision") + self.__offset = offset + + def dst(self, dt): + """ + http://docs.python.org/library/datetime.html#datetime.tzinfo.dst + + """ + return datetime.timedelta(0) + + def utcoffset(self, dt): + """ + http://docs.python.org/library/datetime.html#datetime.tzinfo.utcoffset + + """ + return self.__offset + + def tzname(self, dt): + """ + http://docs.python.org/library/datetime.html#datetime.tzinfo.tzname + + """ + # total_seconds was introduced in Python 2.7 + if hasattr(self.__offset, "total_seconds"): + total_seconds = self.__offset.total_seconds() + else: + total_seconds = (self.__offset.days * 24 * 60 * 60) + \ + (self.__offset.seconds) + + hours = total_seconds // (60 * 60) + total_seconds -= hours * 60 * 60 + + minutes = total_seconds // 60 + total_seconds -= minutes * 60 + + seconds = total_seconds // 1 + total_seconds -= seconds + + if seconds: + return "%+03d:%02d:%02d" % (hours, minutes, seconds) + return "%+03d:%02d" % (hours, minutes) + + def __unicode__(self): + return "FixedOffsetTimezone %s" % (self.tzname(None),) + + +class UtcTimezone(FixedOffsetTimezone): + """ + The UTC timezone. + + http://docs.python.org/library/datetime.html#datetime.tzinfo + + """ + + def __init__(self): + FixedOffsetTimezone.__init__(self, datetime.timedelta(0)) + + def tzname(self, dt): + """ + http://docs.python.org/library/datetime.html#datetime.tzinfo.tzname + + """ + return "UTC" + + def __unicode__(self): + return "UtcTimezone" + + +class LocalTimezone(datetime.tzinfo): + """ + The local timezone of the operating system. + + http://docs.python.org/library/datetime.html#datetime.tzinfo + + """ + + def __init__(self): + self.__offset = datetime.timedelta(seconds=-time.timezone) + self.__dst_offset = None + if time.daylight: + self.__dst_offset = datetime.timedelta(seconds=-time.altzone) + + def dst(self, dt): + """ + http://docs.python.org/library/datetime.html#datetime.tzinfo.dst + + """ + if self.__is_daylight_time(dt): + return self.__dst_offset - self.__offset + return datetime.timedelta(0) + + def tzname(self, dt): + """ + http://docs.python.org/library/datetime.html#datetime.tzinfo.tzname + + """ + if self.__is_daylight_time(dt): + return time.tzname[1] + return time.tzname[0] + + def utcoffset(self, dt): + """ + http://docs.python.org/library/datetime.html#datetime.tzinfo.utcoffset + + """ + if self.__is_daylight_time(dt): + return self.__dst_offset + return self.__offset + + def __is_daylight_time(self, dt): + if not time.daylight: + return False + time_tuple = dt.replace(tzinfo=None).timetuple() + time_tuple = time.localtime(time.mktime(time_tuple)) + return time_tuple.tm_isdst > 0 + + def __unicode__(self): + dt = datetime.datetime.now() + return "LocalTimezone %s offset: %s dst: %s" % (self.tzname(dt), + self.utcoffset(dt), self.dst(dt)) + + +def _bump_up_time_by_microsecond(time): + """ + Helper function bumping up the given datetime.time by a microsecond, + cycling around silently to 00:00:00.0 in case of an overflow. + + @param time: Time object. + @type time: B{datetime}.I{time} + @return: Time object. + @rtype: B{datetime}.I{time} + + """ + dt = datetime.datetime(2000, 1, 1, time.hour, time.minute, + time.second, time.microsecond) + dt += datetime.timedelta(microseconds=1) + return dt.time() + + +def _date_from_match(match_object): + """ + Create a date object from a regular expression match. + + The regular expression match is expected to be from _RE_DATE or + _RE_DATETIME. + + @param match_object: The regular expression match. + @type match_object: B{re}.I{MatchObject} + @return: A date object. + @rtype: B{datetime}.I{date} + + """ + year = int(match_object.group("year")) + month = int(match_object.group("month")) + day = int(match_object.group("day")) + return datetime.date(year, month, day) + + +def _time_from_match(match_object): + """ + Create a time object from a regular expression match. + + Returns the time object and information whether the resulting time should + be bumped up by one microsecond due to microsecond rounding. + + Subsecond information is rounded to microseconds due to a restriction in + the python datetime.datetime/time implementation. + + The regular expression match is expected to be from _RE_DATETIME or + _RE_TIME. + + @param match_object: The regular expression match. + @type match_object: B{re}.I{MatchObject} + @return: Time object + rounding flag. + @rtype: tuple of B{datetime}.I{time} and bool + + """ + hour = int(match_object.group('hour')) + minute = int(match_object.group('minute')) + second = int(match_object.group('second')) + subsecond = match_object.group('subsecond') + + round_up = False + microsecond = 0 + if subsecond: + round_up = len(subsecond) > 6 and int(subsecond[6]) >= 5 + subsecond = subsecond[:6] + microsecond = int(subsecond + "0" * (6 - len(subsecond))) + return datetime.time(hour, minute, second, microsecond), round_up + + +def _tzinfo_from_match(match_object): + """ + Create a timezone information object from a regular expression match. + + The regular expression match is expected to be from _RE_DATE, _RE_DATETIME + or _RE_TIME. + + @param match_object: The regular expression match. + @type match_object: B{re}.I{MatchObject} + @return: A timezone information object. + @rtype: B{datetime}.I{tzinfo} + + """ + tz_utc = match_object.group("tz_utc") + if tz_utc: + return UtcTimezone() + + tz_sign = match_object.group("tz_sign") + if not tz_sign: + return + + h = int(match_object.group("tz_hour") or 0) + m = int(match_object.group("tz_minute") or 0) + if h == 0 and m == 0: + return UtcTimezone() + + # Python limitation - timezone offsets larger than one day (in absolute) + # will cause operations depending on tzinfo.utcoffset() to fail, e.g. + # comparing two timezone aware datetime.datetime/time objects. + if h >= 24: + raise ValueError("timezone indicator too large") + + tz_delta = datetime.timedelta(hours=h, minutes=m) + if tz_sign == "-": + tz_delta *= -1 + return FixedOffsetTimezone(tz_delta) diff --git a/pym/calculate/contrib/suds/sax/date.pyc b/pym/calculate/contrib/suds/sax/date.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0362118724393fbff5da9a4e6de8ffbd3c6789f3 GIT binary patch literal 15213 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/sax/document.py b/pym/calculate/contrib/suds/sax/document.py new file mode 100644 index 0000000..1a70a61 --- /dev/null +++ b/pym/calculate/contrib/suds/sax/document.py @@ -0,0 +1,176 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Provides XML I{document} classes. +""" + +from suds import * +from suds.sax import * +from suds.sax.element import Element + + +class Document(UnicodeMixin): + """ An XML Document """ + + DECL = '' + + def __init__(self, root=None): + """ + @param root: A root L{Element} or name used to build + the document root element. + @type root: (L{Element}|str|None) + """ + self.__root = None + self.append(root) + + def root(self): + """ + Get the document root element (can be None) + @return: The document root. + @rtype: L{Element} + """ + return self.__root + + def append(self, node): + """ + Append (set) the document root. + @param node: A root L{Element} or name used to build + the document root element. + @type node: (L{Element}|str|None) + """ + if isinstance(node, basestring): + self.__root = Element(node) + return + if isinstance(node, Element): + self.__root = node + return + + def getChild(self, name, ns=None, default=None): + """ + Get a child by (optional) name and/or (optional) namespace. + @param name: The name of a child element (may contain prefix). + @type name: basestring + @param ns: An optional namespace used to match the child. + @type ns: (I{prefix}, I{name}) + @param default: Returned when child not-found. + @type default: L{Element} + @return: The requested child, or I{default} when not-found. + @rtype: L{Element} + """ + if self.__root is None: + return default + if ns is None: + prefix, name = splitPrefix(name) + if prefix is None: + ns = None + else: + ns = self.__root.resolvePrefix(prefix) + if self.__root.match(name, ns): + return self.__root + else: + return default + + def childAtPath(self, path): + """ + Get a child at I{path} where I{path} is a (/) separated + list of element names that are expected to be children. + @param path: A (/) separated list of element names. + @type path: basestring + @return: The leaf node at the end of I{path} + @rtype: L{Element} + """ + if self.__root is None: + return None + if path[0] == '/': + path = path[1:] + path = path.split('/',1) + if self.getChild(path[0]) is None: + return None + if len(path) > 1: + return self.__root.childAtPath(path[1]) + else: + return self.__root + + def childrenAtPath(self, path): + """ + Get a list of children at I{path} where I{path} is a (/) separated + list of element names that are expected to be children. + @param path: A (/) separated list of element names. + @type path: basestring + @return: The collection leaf nodes at the end of I{path} + @rtype: [L{Element},...] + """ + if self.__root is None: + return [] + if path[0] == '/': + path = path[1:] + path = path.split('/',1) + if self.getChild(path[0]) is None: + return [] + if len(path) > 1: + return self.__root.childrenAtPath(path[1]) + else: + return [self.__root,] + + def getChildren(self, name=None, ns=None): + """ + Get a list of children by (optional) name and/or (optional) namespace. + @param name: The name of a child element (may contain prefix). + @type name: basestring + @param ns: An optional namespace used to match the child. + @type ns: (I{prefix}, I{name}) + @return: The list of matching children. + @rtype: [L{Element},...] + """ + if name is None: + matched = self.__root + else: + matched = self.getChild(name, ns) + if matched is None: + return [] + else: + return [matched,] + + def str(self): + """ + Get a string representation of this XML document. + @return: A I{pretty} string. + @rtype: basestring + """ + s = [] + s.append(self.DECL) + root = self.root() + if root is not None: + s.append('\n') + s.append(root.str()) + return ''.join(s) + + def plain(self): + """ + Get a string representation of this XML document. + @return: A I{plain} string. + @rtype: basestring + """ + s = [] + s.append(self.DECL) + root = self.root() + if root is not None: + s.append(root.plain()) + return ''.join(s) + + def __unicode__(self): + return self.str() diff --git a/pym/calculate/contrib/suds/sax/document.pyc b/pym/calculate/contrib/suds/sax/document.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0932b1de97efe1c7d5e3be90ff9e25f9d753f144 GIT binary patch literal 5689 zcmeHL?QY!06&>!bR@${>xptIB{mNARz^brU4iE%^kT_CgrwHH(HszqL+?J)5BZ)G_ z-Eg?J1Zz>WPX8BZf&MM}0)2$OMBk(j(4KRLIJg|NN_-Dt>kRui>(H(L_pZqxDo&Q;DY@6}_74)m2hghYhveP+rtfW=id1=9KzU zsTWH9Y`dwVrrPREQ`+~?v>#;sr*UMg{^@7;^{3CHes6ea(tM{5l>c z=WKrDx|DD)F`S#vpntb`@g=1{#(*86F;E(Mpsi8$?YfF)xq&aypHfks`cb!rbf#q# z6QFlZZO>3=PH3rUS~~4=!i-F~qN0{O$182=%&F*#bgn9Yt20M6zJ^Axr?SsdS#5ua zryqQDbeQO;CbMxr{c!1>?(HRQ(q2D`)4dOuK7aJdt@oEcy3?y+YI$u?;y2J>Gbc&~ z(jL^*iKkw8u)GHwbFTdpnzk-}YlAQg4|Ue>=c{^M{`LLmg%wA-pXoF_G~CUH7Ex^?vad%=6}u9&^O z6+4XViVcre$}MyU$AX<8h|@R^g0~^TQXkc9c|C%yyu{vw9E^RSU|bGZ+>DL;W0PNO zAKmGNsopXAWfQDrCLd<$s(y6ZuoDK&XwlUPM^zRSEqp5MdbHMM4dQc`6k>@V)vRDg zXNeg;Mkj|QJjUaTn#z_`ULucJL~H?m#f+NFxWn1wu`xXV23gg1*2U4fV@co8)1Hyroe=z$XNY2-aB+^JRed^2Aj}0W?Xf9H zyN%1vqEXZH-n`eq1qf3!j#j?=HEtY);e#hLD!ZXh>T2smSdsUS$G-e|O^q6A1jjY# zQI3AX&Zwrocw9(1sB;vQgNJD;`k*21cCLR`h78vkJO1ymNac8jPN;kPpc}n&tULWd z4kiqfWyeQh8m)kvPCd4RuxHMK0tDv5NvN#9TL~_hN_P&!W8Legc^Id9keS{1Xn8`6 z&==ob)norvnidS2S^zKArJkau=u>g$VVL*!1;nzgGYddK=hNqI`O!@zJ}x;LlVh<^ zWOl=00=D*rD8S3l_Dx!tD(&aDcKgFLIxW3=Ys|mn9ZXVAX1*8#q7W-u-ed|u4t9%< z+*;?Yaxo=sc8E8Dx=+;QSJ2o&66X)Z)H!ouW^6xsYKkX(LCob|9mfVN0%B1LF-1}; z)RLUw40qYc5%S+N`38}92TRyD(5P9)&#ZSHSF5(*EqK$lvn=>~Oe`X)QAASIKqR5c z@YEtoizi^l+YAI$7jGkq7#^NNj>Z@sfjAjjNGAv(_Y%SgA{b`@J6m7~jPPk)J!z=y zcV*B`6=D}Lw&j%A;tOIx`|d@d73Og6Ak6p0vze*xVv8v0tSoD5NUgv_1(yVwR3nPY z=pjrka1B`@B$%Ut=@CCH7mPzuX3_~jI#`L|Em@6^)db2|)PC%JJ6)5{RIFs;BP<|5O5|zWxG6 z1iAj3=;c?@l*T@dT>mW$UK+KF5R%}!7_|%`)+qen;LLky97IWjZwZ1?T+~&1UHVdI zqFNz)f;Xkq5W>C>`utBxDeR= z5*+}D2^lHc5vMyzlR^PEi~)L*xSzCC_OO_TRF4$w6))8kDql?HBV>DU?15xzW@*{D z#o+0x*BuaaW>C^tWRp->0hue`M_T4bk?OQsMSA6{by6hKV17K(PS8a5EF5%B=Cm|G z8z;0X$uYIbf#mMJjr(#0bk$oO&mmZb4*GE_M|PLoD8p8##mk(*{qI23A1RKUq?%16 zH+TyP?oD?Jrxum39^&TJe1#eezPelb^t5~6>9KocqrZjd%E<0ea(VY8IA?q%@A%(> z8b$Fzzxdx~GtGut=6p7wRG;4~#vbuCZeNc>z6(iz!R11ya!BD0dY;z?XYkzX>WmlV zcacr^HG*D!ecvS{vV&ll#`rL1g5a-QoS;zNW`|r-e92*f8U%9w4uZpeG)#C)>jeQK zDF~c7X-R*EjTlz!OoEb9%V*~DzsZK1@M#Wz3C)e") + return "".join(result) + result.append(">") + if self.hasText(): + result.append(self.text.escape()) + for c in self.children: + result.append("\n") + result.append(c.str(indent + 1)) + if len(self.children): + result.append("\n%s" % (tab,)) + result.append("" % (self.qname(),)) + return "".join(result) + + def plain(self): + """ + Get a string representation of this XML fragment. + + @return: A I{plain} string. + @rtype: basestring + + """ + result = ["<%s" % (self.qname(),), self.nsdeclarations()] + for a in self.attributes: + result.append(" %s" % (unicode(a),)) + if self.isempty(): + result.append("/>") + return "".join(result) + result.append(">") + if self.hasText(): + result.append(self.text.escape()) + for c in self.children: + result.append(c.plain()) + result.append("" % (self.qname(),)) + return "".join(result) + + def nsdeclarations(self): + """ + Get a string representation for all namespace declarations as xmlns="" + and xmlns:p="". + + @return: A separated list of declarations. + @rtype: basestring + + """ + s = [] + myns = None, self.expns + if self.parent is None: + pns = Namespace.default + else: + pns = None, self.parent.expns + if myns[1] != pns[1]: + if self.expns is not None: + s.append(' xmlns="%s"' % (self.expns,)) + for item in self.nsprefixes.items(): + p, u = item + if self.parent is not None: + ns = self.parent.resolvePrefix(p) + if ns[1] == u: + continue + s.append(' xmlns:%s="%s"' % (p, u)) + return "".join(s) + + def match(self, name=None, ns=None): + """ + Match by (optional) name and/or (optional) namespace. + + @param name: The optional element tag name. + @type name: str + @param ns: An optional namespace. + @type ns: (I{prefix}, I{name}) + @return: True if matched. + @rtype: boolean + + """ + byname = name is None or (self.name == name) + byns = ns is None or (self.namespace()[1] == ns[1]) + return byname and byns + + def branch(self): + """ + Get a flattened representation of the branch. + + @return: A flat list of nodes. + @rtype: [L{Element},...] + + """ + branch = [self] + for c in self.children: + branch += c.branch() + return branch + + def ancestors(self): + """ + Get a list of ancestors. + + @return: A list of ancestors. + @rtype: [L{Element},...] + + """ + ancestors = [] + p = self.parent + while p is not None: + ancestors.append(p) + p = p.parent + return ancestors + + def walk(self, visitor): + """ + Walk the branch and call the visitor function on each node. + + @param visitor: A function. + @type visitor: single argument function + @return: self + @rtype: L{Element} + + """ + visitor(self) + for c in self.children: + c.walk(visitor) + return self + + def prune(self): + """Prune the branch of empty nodes.""" + pruned = [] + for c in self.children: + c.prune() + if c.isempty(False): + pruned.append(c) + for p in pruned: + self.children.remove(p) + + def __childrenAtPath(self, parts): + result = [] + node = self + ancestors = parts[:-1] + leaf = parts[-1] + for name in ancestors: + ns = None + prefix, name = splitPrefix(name) + if prefix is not None: + ns = node.resolvePrefix(prefix) + child = node.getChild(name, ns) + if child is None: + break + node = child + if child is not None: + ns = None + prefix, leaf = splitPrefix(leaf) + if prefix is not None: + ns = node.resolvePrefix(prefix) + result = child.getChildren(leaf) + return result + + def __len__(self): + return len(self.children) + + def __getitem__(self, index): + if isinstance(index, basestring): + return self.get(index) + if index < len(self.children): + return self.children[index] + + def __setitem__(self, index, value): + if isinstance(index, basestring): + self.set(index, value) + else: + if index < len(self.children) and isinstance(value, Element): + self.children.insert(index, value) + + def __eq__(self, rhs): + return (isinstance(rhs, Element) and + self.match(rhs.name, rhs.namespace())) + + def __repr__(self): + return "Element (prefix=%s, name=%s)" % (self.prefix, self.name) + + def __unicode__(self): + return self.str() + + def __iter__(self): + return NodeIterator(self) + + +class NodeIterator: + """ + The L{Element} child node iterator. + + @ivar pos: The current position + @type pos: int + @ivar children: A list of a child nodes. + @type children: [L{Element},...] + + """ + + def __init__(self, parent): + """ + @param parent: An element to iterate. + @type parent: L{Element} + + """ + self.pos = 0 + self.children = parent.children + + def next(self): + """ + Get the next child. + + @return: The next child. + @rtype: L{Element} + @raise StopIterator: At the end. + + """ + try: + child = self.children[self.pos] + self.pos += 1 + return child + except Exception: + raise StopIteration() + + +class PrefixNormalizer: + """ + The prefix normalizer provides namespace prefix normalization. + + @ivar node: A node to normalize. + @type node: L{Element} + @ivar branch: The nodes flattened branch. + @type branch: [L{Element},...] + @ivar namespaces: A unique list of namespaces (URI). + @type namespaces: [str,...] + @ivar prefixes: A reverse dict of prefixes. + @type prefixes: {u: p} + + """ + + @classmethod + def apply(cls, node): + """ + Normalize the specified node. + + @param node: A node to normalize. + @type node: L{Element} + @return: The normalized node. + @rtype: L{Element} + + """ + return PrefixNormalizer(node).refit() + + def __init__(self, node): + """ + @param node: A node to normalize. + @type node: L{Element} + + """ + self.node = node + self.branch = node.branch() + self.namespaces = self.getNamespaces() + self.prefixes = self.genPrefixes() + + def getNamespaces(self): + """ + Get the I{unique} set of namespaces referenced in the branch. + + @return: A set of namespaces. + @rtype: set + + """ + s = set() + for n in self.branch + self.node.ancestors(): + if self.permit(n.expns): + s.add(n.expns) + s = s.union(self.pset(n)) + return s + + def pset(self, n): + """ + Convert the nodes nsprefixes into a set. + + @param n: A node. + @type n: L{Element} + @return: A set of namespaces. + @rtype: set + + """ + s = set() + for ns in n.nsprefixes.items(): + if self.permit(ns): + s.add(ns[1]) + return s + + def genPrefixes(self): + """ + Generate a I{reverse} mapping of unique prefixes for all namespaces. + + @return: A reverse dict of prefixes. + @rtype: {u: p} + + """ + prefixes = {} + n = 0 + for u in self.namespaces: + prefixes[u] = "ns%d" % (n,) + n += 1 + return prefixes + + def refit(self): + """Refit (normalize) the prefixes in the node.""" + self.refitNodes() + self.refitMappings() + + def refitNodes(self): + """Refit (normalize) all of the nodes in the branch.""" + for n in self.branch: + if n.prefix is not None: + ns = n.namespace() + if self.permit(ns): + n.prefix = self.prefixes[ns[1]] + self.refitAttrs(n) + + def refitAttrs(self, n): + """ + Refit (normalize) all of the attributes in the node. + + @param n: A node. + @type n: L{Element} + + """ + for a in n.attributes: + self.refitAddr(a) + + def refitAddr(self, a): + """ + Refit (normalize) the attribute. + + @param a: An attribute. + @type a: L{Attribute} + + """ + if a.prefix is not None: + ns = a.namespace() + if self.permit(ns): + a.prefix = self.prefixes[ns[1]] + self.refitValue(a) + + def refitValue(self, a): + """ + Refit (normalize) the attribute's value. + + @param a: An attribute. + @type a: L{Attribute} + + """ + p, name = splitPrefix(a.getValue()) + if p is None: + return + ns = a.resolvePrefix(p) + if self.permit(ns): + p = self.prefixes[ns[1]] + a.setValue(":".join((p, name))) + + def refitMappings(self): + """Refit (normalize) all of the nsprefix mappings.""" + for n in self.branch: + n.nsprefixes = {} + n = self.node + for u, p in self.prefixes.items(): + n.addPrefix(p, u) + + def permit(self, ns): + """ + Get whether the I{ns} is to be normalized. + + @param ns: A namespace. + @type ns: (p, u) + @return: True if to be included. + @rtype: boolean + + """ + return not self.skip(ns) + + def skip(self, ns): + """ + Get whether the I{ns} is to B{not} be normalized. + + @param ns: A namespace. + @type ns: (p, u) + @return: True if to be skipped. + @rtype: boolean + + """ + return ns is None or ns in ( + Namespace.default, + Namespace.xsdns, + Namespace.xsins, + Namespace.xmlns) diff --git a/pym/calculate/contrib/suds/sax/element.pyc b/pym/calculate/contrib/suds/sax/element.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e9ec7a6f21488c0780487ad71106ee4c79cc954 GIT binary patch literal 38445 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/sax/enc.py b/pym/calculate/contrib/suds/sax/enc.py new file mode 100644 index 0000000..f750556 --- /dev/null +++ b/pym/calculate/contrib/suds/sax/enc.py @@ -0,0 +1,94 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the (LGPL) GNU Lesser General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License +# for more details at ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Provides XML I{special character} encoder classes. + +""" + +import re + + +class Encoder: + """ + An XML special character encoder/decoder. + + @cvar encodings: A mapping of special characters encoding. + @type encodings: [(str, str),...] + @cvar decodings: A mapping of special characters decoding. + @type decodings: [(str, str),...] + @cvar special: A list of special characters. + @type special: [char,...] + + """ + + encodings = ( + ("&(?!(amp|lt|gt|quot|apos);)", "&"), + ("<", "<"), + (">", ">"), + ('"', """), + ("'", "'")) + decodings = ( + ("<", "<"), + (">", ">"), + (""", '"'), + ("'", "'"), + ("&", "&")) + special = ("&", "<", ">", '"', "'") + + def encode(self, s): + """ + Encode special characters found in string I{s}. + + @param s: A string to encode. + @type s: str + @return: The encoded string. + @rtype: str + + """ + if isinstance(s, basestring) and self.__needs_encoding(s): + for x in self.encodings: + s = re.sub(x[0], x[1], s) + return s + + def decode(self, s): + """ + Decode special characters encodings found in string I{s}. + + @param s: A string to decode. + @type s: str + @return: The decoded string. + @rtype: str + + """ + if isinstance(s, basestring) and "&" in s: + for x in self.decodings: + s = s.replace(x[0], x[1]) + return s + + def __needs_encoding(self, s): + """ + Get whether string I{s} contains special characters. + + @param s: A string to check. + @type s: str + @return: True if needs encoding. + @rtype: boolean + + """ + if isinstance(s, basestring): + for c in self.special: + if c in s: + return True diff --git a/pym/calculate/contrib/suds/sax/enc.pyc b/pym/calculate/contrib/suds/sax/enc.pyc new file mode 100644 index 0000000000000000000000000000000000000000..897ef97ba6e1e5a07f22d8e608aef24db39eee36 GIT binary patch literal 2699 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/sax/text.py b/pym/calculate/contrib/suds/sax/text.py new file mode 100644 index 0000000..985386e --- /dev/null +++ b/pym/calculate/contrib/suds/sax/text.py @@ -0,0 +1,116 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Contains XML text classes. +""" + +from suds import * +from suds.sax import * + + +class Text(unicode): + """ + An XML text object used to represent text content. + @ivar lang: The (optional) language flag. + @type lang: bool + @ivar escaped: The (optional) XML special character escaped flag. + @type escaped: bool + """ + __slots__ = ('lang', 'escaped') + + @classmethod + def __valid(cls, *args): + return len(args) and args[0] is not None + + def __new__(cls, *args, **kwargs): + if cls.__valid(*args): + lang = kwargs.pop('lang', None) + escaped = kwargs.pop('escaped', False) + result = super(Text, cls).__new__(cls, *args, **kwargs) + result.lang = lang + result.escaped = escaped + else: + result = None + return result + + def escape(self): + """ + Encode (escape) special XML characters. + @return: The text with XML special characters escaped. + @rtype: L{Text} + """ + if not self.escaped: + post = sax.encoder.encode(self) + escaped = ( post != self ) + return Text(post, lang=self.lang, escaped=escaped) + return self + + def unescape(self): + """ + Decode (unescape) special XML characters. + @return: The text with escaped XML special characters decoded. + @rtype: L{Text} + """ + if self.escaped: + post = sax.encoder.decode(self) + return Text(post, lang=self.lang) + return self + + def trim(self): + post = self.strip() + return Text(post, lang=self.lang, escaped=self.escaped) + + def __add__(self, other): + joined = u''.join((self, other)) + result = Text(joined, lang=self.lang, escaped=self.escaped) + if isinstance(other, Text): + result.escaped = self.escaped or other.escaped + return result + + def __repr__(self): + s = [self] + if self.lang is not None: + s.append(' [%s]' % self.lang) + if self.escaped: + s.append(' ') + return ''.join(s) + + def __getstate__(self): + state = {} + for k in self.__slots__: + state[k] = getattr(self, k) + return state + + def __setstate__(self, state): + for k in self.__slots__: + setattr(self, k, state[k]) + + +class Raw(Text): + """ + Raw text which is not XML escaped. + This may include I{string} XML. + """ + def escape(self): + return self + + def unescape(self): + return self + + def __add__(self, other): + joined = u''.join((self, other)) + return Raw(joined, lang=self.lang) diff --git a/pym/calculate/contrib/suds/sax/text.pyc b/pym/calculate/contrib/suds/sax/text.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f6cac3300fce691f43daac2ec4073b9de630cbb9 GIT binary patch literal 4249 zcmcgvZEqA+6uz^&-FCOdRuQlS$wWXGlr|be3?ZZfzF?s0v<6+paXNFmopw62%)LuX zXg`&Y#`xJ!{xN@rKR}=7+!fKbK`$|_l|G%uJz+AGDe$)X8IR?Ef2da$t7C@UB#B6dKFCEz%W}N8tOp<(27cC zR2w=$hpHUysWwg)<=S;B1})o@DiOunQ&fsG4V6p@(^N@Am}!+Xg_%*wv@pk1u+lol zL;nD2`uKgEkF+n=Hg#S%vGi#q+?_EA^&cdr#iHYP%wIO^);kQBPqbak9YnICUNWfWUo`u*L9 zL=UA5rHjLOLDo(xiB9+B8;AlBTsoPsD}EpsY^ z6Kb3$zNiaF36rzo1*;BN|ozsuc9_Zf2e;@QTx@w zOhrL+&eRl?v=e+0kDGNeFc~lY;;DVi=vaJS) zodF4%+kLggOWmRyOmLOt(KhPege9B!6~>PS+NZ-pK{@G2{Kc1|?ELYlyUAp9hciv%EYX?k&(_yoZ)`B7E4m%pV_ z+g_PF&`9CgN$rLJ`4DEz05s#T6OUK@JC7N){h`>Ai(3)_nlHgbemWS5o}~mp3ooIR z_arw20!C-+!gLE`U7kRYl32X}AgGFS%m?61ld|d!glfi{cVS{a5*HFCZlc?Ph=qR$ z(=(wt@H`h3$}qoy483tnyP)*)BZj44eEuywiJX%>XLv@D37EFQs~{2&CuS@jg3{yM z^E${;kYcAGVBm)9;0-5S5RQ*RFhmN^av?ZC>F^kZ5ggFq00#sJ6$ywqR8km7S1N3o zc1QNOM0$xv$w6hheH#ZFJ}6{VJjkV?F+XAfErE3wf1X+=k_F^aH~YrGDyap|DpX#V zXRsV~wruwe?tV=PtQu7nR#gsxRTKmszTBe*V+fSu$(79_&7X0DB?wZ3tA~y9Sc`yw zp%%v#c0)Ui@>QJ#vsgJ&{9UPzk|Yf8LYBjzcLK$7)_Y@=0IU~+!EeC8TOC&z1&oPw z)N)ZA0B=dPgi}w#nI0V>8Bu;dSQjsI0e;<-a*B<8R~h=o|NerxFPiw*`Uty@P7X`C z>KrLPWF(_*SLcbOP{5WiecO4Az36Bin_vh--j>2}mD1P{75d1mcM5cF)JqsnanSo< zaIF9~cF&9HO5M6YKgcS01LgxIl3~{#%&B`|SL8am?5-SaykTgv!kRFY+T77LvbGdF zjdB4AVzpdBw~mwn(&Iy%Ap*nj2b}M!fLDiwryOvY07Kxshlkw@L+egIWt}r^{-CP7 z2TgSk*)eWja1QT^Rk$`hZB=jqOTpV9FToy2@7uEmf&C&d=eg{VQbUVcuYgDm#C0Xw z)^IrS7lzwK(#!bh@R1ZTt}>$fG}h%?U|ZXbA_*8Sxo-p~$ekjYCpk;<771@6!9|df zUBdnMjw!{0(#=Vb`efa!S7vLC>BbC3tufh{YSg8z2hmQ99r7a#ZeSRypvON)Jo$8} zvTQ%W{NTF;A0_yhU`Cs-K%{L#p!-(X*+}CJKQ(?{Sm}Fxgt{iTx`CDL=#ii1an{4d z=k{ZRVxM>Rx!3K9snB5D+77P&)6vX?V(e%p z9dnMxiq$midD;&zGOm}78i}g~tarfz35Ad9LvV(3Z*mU9kr!|tGq}X)qvwR@ZYY;9 z6}(HrIxv>@+&?-{xEDB;_H;0$2GwhIuTgDOm)+4kQ0|}nwi4WuSr}YmdwI%>oolI- Yb7XDgjBBnMTxT10T2-1}vwCv*Z@9KWSpWb4 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/servicedefinition.py b/pym/calculate/contrib/suds/servicedefinition.py new file mode 100644 index 0000000..44bc52e --- /dev/null +++ b/pym/calculate/contrib/suds/servicedefinition.py @@ -0,0 +1,246 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +The I{service definition} provides a textual representation of a service. +""" + +from suds import * +import suds.metrics as metrics +from suds.sax import Namespace + +from logging import getLogger +log = getLogger(__name__) + + +class ServiceDefinition(UnicodeMixin): + """ + A service definition provides an object used to generate a textual description + of a service. + @ivar wsdl: A wsdl. + @type wsdl: L{wsdl.Definitions} + @ivar sort_namespaces: Whether to sort namespaces on storing them. + @ivar service: The service object. + @type service: L{suds.wsdl.Service} + @ivar ports: A list of port-tuple: (port, [(method-name, pdef)]) + @type ports: [port-tuple,..] + @ivar prefixes: A list of remapped prefixes. + @type prefixes: [(prefix,uri),..] + @ivar types: A list of type definitions + @type types: [I{Type},..] + """ + + def __init__(self, wsdl, service): + """ + @param wsdl: A WSDL object + @type wsdl: L{Definitions} + @param service: A service B{name}. + @type service: str + @param service: A service B{name}. + @param sort_namespaces: Whether to sort namespaces on storing them. + """ + self.wsdl = wsdl + self.service = service + self.ports = [] + self.params = [] + self.types = [] + self.prefixes = [] + self.addports() + self.paramtypes() + self.publictypes() + self.getprefixes() + self.pushprefixes() + + def pushprefixes(self): + """ + Add our prefixes to the WSDL so that when users invoke methods + and reference the prefixes, they will resolve properly. + """ + for ns in self.prefixes: + self.wsdl.root.addPrefix(ns[0], ns[1]) + + def addports(self): + """ + Look through the list of service ports and construct a list of tuples + where each tuple is used to describe a port and its list of methods as: + (port, [method]). Each method is a tuple: (name, [pdef,..]) where each + pdef is a tuple: (param-name, type). + """ + timer = metrics.Timer() + timer.start() + for port in self.service.ports: + p = self.findport(port) + for op in port.binding.operations.values(): + m = p[0].method(op.name) + binding = m.binding.input + method = (m.name, binding.param_defs(m)) + p[1].append(method) + metrics.log.debug("method '%s' created: %s", m.name, timer) + p[1].sort() + timer.stop() + + def findport(self, port): + """ + Find and return a port tuple for the specified port. + Created and added when not found. + @param port: A port. + @type port: I{service.Port} + @return: A port tuple. + @rtype: (port, [method]) + """ + for p in self.ports: + if p[0] == p: return p + p = (port, []) + self.ports.append(p) + return p + + def getprefixes(self): + """Add prefixes for each namespace referenced by parameter types.""" + namespaces = [] + for l in (self.params, self.types): + for t,r in l: + ns = r.namespace() + if ns[1] is None: continue + if ns[1] in namespaces: continue + if Namespace.xs(ns) or Namespace.xsd(ns): + continue + namespaces.append(ns[1]) + if t == r: continue + ns = t.namespace() + if ns[1] is None: continue + if ns[1] in namespaces: continue + namespaces.append(ns[1]) + i = 0 + + if self.wsdl.options.sortNamespaces: + namespaces.sort() + + for u in namespaces: + p = self.nextprefix() + ns = (p, u) + self.prefixes.append(ns) + + def paramtypes(self): + """Get all parameter types.""" + for m in [p[1] for p in self.ports]: + for p in [p[1] for p in m]: + for pd in p: + if pd[1] in self.params: continue + item = (pd[1], pd[1].resolve()) + self.params.append(item) + + def publictypes(self): + """Get all public types.""" + for t in self.wsdl.schema.types.values(): + if t in self.params: continue + if t in self.types: continue + item = (t, t) + self.types.append(item) + self.types.sort(key=lambda x: x[0].name) + + def nextprefix(self): + """ + Get the next available prefix. This means a prefix starting with 'ns' with + a number appended as (ns0, ns1, ..) that is not already defined in the + WSDL document. + """ + used = [ns[0] for ns in self.prefixes] + used += [ns[0] for ns in self.wsdl.root.nsprefixes.items()] + for n in range(0,1024): + p = 'ns%d'%n + if p not in used: + return p + raise Exception('prefixes exhausted') + + def getprefix(self, u): + """ + Get the prefix for the specified namespace (URI) + @param u: A namespace URI. + @type u: str + @return: The namspace. + @rtype: (prefix, uri). + """ + for ns in Namespace.all: + if u == ns[1]: return ns[0] + for ns in self.prefixes: + if u == ns[1]: return ns[0] + raise Exception('ns (%s) not mapped' % u) + + def xlate(self, type): + """ + Get a (namespace) translated I{qualified} name for specified type. + @param type: A schema type. + @type type: I{suds.xsd.sxbasic.SchemaObject} + @return: A translated I{qualified} name. + @rtype: str + """ + resolved = type.resolve() + name = resolved.name + if type.multi_occurrence(): + name += '[]' + ns = resolved.namespace() + if ns[1] == self.wsdl.tns[1]: + return name + prefix = self.getprefix(ns[1]) + return ':'.join((prefix, name)) + + def description(self): + """ + Get a textual description of the service for which this object represents. + @return: A textual description. + @rtype: str + """ + s = [] + indent = (lambda n : '\n%*s'%(n*3,' ')) + s.append('Service ( %s ) tns="%s"' % (self.service.name, self.wsdl.tns[1])) + s.append(indent(1)) + s.append('Prefixes (%d)' % len(self.prefixes)) + for p in self.prefixes: + s.append(indent(2)) + s.append('%s = "%s"' % p) + s.append(indent(1)) + s.append('Ports (%d):' % len(self.ports)) + for p in self.ports: + s.append(indent(2)) + s.append('(%s)' % p[0].name) + s.append(indent(3)) + s.append('Methods (%d):' % len(p[1])) + for m in p[1]: + sig = [] + s.append(indent(4)) + sig.append(m[0]) + sig.append('(') + sig.append(', '.join("%s %s" % (self.xlate(p[1]), p[0]) for p + in m[1])) + sig.append(')') + try: + s.append(''.join(sig)) + except Exception: + pass + s.append(indent(3)) + s.append('Types (%d):' % len(self.types)) + for t in self.types: + s.append(indent(4)) + s.append(self.xlate(t[0])) + s.append('\n\n') + return ''.join(s) + + def __unicode__(self): + try: + return self.description() + except Exception as e: + log.exception(e) + return tostr(e) diff --git a/pym/calculate/contrib/suds/servicedefinition.pyc b/pym/calculate/contrib/suds/servicedefinition.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29d38eee0e86e105e0b6da067975dd78c8769eea GIT binary patch literal 9322 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 AxBvhE literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/serviceproxy.py b/pym/calculate/contrib/suds/serviceproxy.py new file mode 100644 index 0000000..278c189 --- /dev/null +++ b/pym/calculate/contrib/suds/serviceproxy.py @@ -0,0 +1,80 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +The service proxy provides access to web services. + +Replaced by: L{client.Client} +""" + +from suds import * +from suds.client import Client + + +class ServiceProxy(UnicodeMixin): + + """ + A lightweight soap based web service proxy. + @ivar __client__: A client. + Everything is delegated to the 2nd generation API. + @type __client__: L{Client} + @note: Deprecated, replaced by L{Client}. + """ + + def __init__(self, url, **kwargs): + """ + @param url: The URL for the WSDL. + @type url: str + @param kwargs: keyword arguments. + @keyword faults: Raise faults raised by server (default:True), + else return tuple from service method invocation as (http code, object). + @type faults: boolean + @keyword proxy: An http proxy to be specified on requests (default:{}). + The proxy is defined as {protocol:proxy,} + @type proxy: dict + """ + client = Client(url, **kwargs) + self.__client__ = client + + def get_instance(self, name): + """ + Get an instance of a WSDL type by name + @param name: The name of a type defined in the WSDL. + @type name: str + @return: An instance on success, else None + @rtype: L{sudsobject.Object} + """ + return self.__client__.factory.create(name) + + def get_enum(self, name): + """ + Get an instance of an enumeration defined in the WSDL by name. + @param name: The name of a enumeration defined in the WSDL. + @type name: str + @return: An instance on success, else None + @rtype: L{sudsobject.Object} + """ + return self.__client__.factory.create(name) + + def __unicode__(self): + return unicode(self.__client__) + + def __getattr__(self, name): + builtin = name.startswith('__') and name.endswith('__') + if builtin: + return self.__dict__[name] + else: + return getattr(self.__client__.service, name) diff --git a/pym/calculate/contrib/suds/serviceproxy.pyc b/pym/calculate/contrib/suds/serviceproxy.pyc new file mode 100644 index 0000000000000000000000000000000000000000..467681206ae0185286c60eb644adb2c3688b4776 GIT binary patch literal 2896 zcmcguU2hvj6rHslH*s4P2_XbUXdXavQE&vRDr8WVlJX@&sMe_vc^THbV|&u|u9=yQ z6D4^nulxu88RCIozz=|P@2o$HA|XhHlewPRoxOAKJ?EZv^N-t|`8&V-kc#@##P=?S z>%(M19Kl8+Ylu7&hcs)7ydkDdanux1))KlUM!32meiGuj5Z@ndh^#FJ-5ca%0Mj{~ zXz8>)F{zd_Tb`bgJu#VfGD%bIob;uf>)~RP>vcM@p5;lZGdVo#%l-2-H@fh>J^s4v zm_PC9MsV)QyceczOv4U;3)4Y3@(G=|%#OByis3$n(Z~*=!!{^KB!HZdDNS0GC{2(~ zizn?m$)g)09(3t2_bW_C;`2!6W<2q8O;)-xnaN?|5dKD?WLjo=Tb9FPo%(xg@o|ES z;D%+H>!es7yNsUu1gt0|I}2?CH`PD5 zV^)n!0Z)kf92b3=mU*A=ZeOl~;*j}jUuGut%R2{*b+Sg@-$Gsi;IGd`v9|HW%6uim>K7LxhbmC_fJ21pdQ@c(c|%st1`D!iwQ^6o1OVh zJf)N=j92Pi%pIL8ZrzEPyhKMDdl>Fj7*O>X|B*Ou5R0D^XDJ2uJIpe-FSM6Q0cf31 z3Mf}Ol8Gd;N-hT|R3uZq++I_ht_6f0S{N&fJZ>!D%OW*U!Z+p9`j%oNFiOt zy15aacNzG?Pjd=-2y}S-3*9OL)X&JjwJZNqq^eA#_r!p$P%kC59B)wNWBX z9%~PrLPhUm?FbmL`7d#5t!v9wI2BSC5QbVBuP8k!04257mqDTe2Gk=o3;6wmuQeZx zba3(i!WeI%j4`#~3c2_uEita$TZ9@F;URo25Tk~nvFxndSkP;MJ8RifK_QrBRbfaI znReW7G4bo#0aBJq)y|dr63Y-{=zbzOjXk>lISe`;-H#U)Vl40SlHXfcUP2EV!tQVq ztPO7rAYGJFOB`>oSTw{S!*2^N^MR-AmEs=*o~jRKTkqz^Pgs<6k*yX=k#;J@#Xw0D z@9nAwYfTHCNrhqfcrOW}H^ob;RDH5i{4(FfNg{eXYDYI4U0T#)N+d?8l#^1^GOKc0 zl2{;(GF2+3%`x?KOvuM~$h;1-3X^C5P10j3>|G2;C$u-)jjcOd9sD&9xY+TVxEx+D vP&rQ=Ai3*>7fN^`(UVUD=e{wgreL2hB|5IrC!s12U!${0Iopj+^h)zD>#5O8 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/soaparray.py b/pym/calculate/contrib/suds/soaparray.py new file mode 100644 index 0000000..ea04fa7 --- /dev/null +++ b/pym/calculate/contrib/suds/soaparray.py @@ -0,0 +1,71 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +The I{soaparray} module provides XSD extensions for handling +soap (section 5) encoded arrays. +""" + +from suds import * +from logging import getLogger +from suds.xsd.sxbasic import Factory as SXFactory +from suds.xsd.sxbasic import Attribute as SXAttribute + + +class Attribute(SXAttribute): + """ + Represents an XSD that handles special + attributes that are extensions for WSDLs. + @ivar aty: Array type information. + @type aty: The value of wsdl:arrayType. + """ + + def __init__(self, schema, root, aty): + """ + @param aty: Array type information. + @type aty: The value of wsdl:arrayType. + """ + SXAttribute.__init__(self, schema, root) + if aty.endswith('[]'): + self.aty = aty[:-2] + else: + self.aty = aty + + def autoqualified(self): + aqs = SXAttribute.autoqualified(self) + aqs.append('aty') + return aqs + + def description(self): + d = SXAttribute.description(self) + d = d+('aty',) + return d + +# +# Builder function, only builds Attribute when arrayType +# attribute is defined on root. +# +def __fn(x, y): + ns = (None, "http://schemas.xmlsoap.org/wsdl/") + aty = y.get('arrayType', ns=ns) + if aty is None: + return SXAttribute(x, y) + return Attribute(x, y, aty) + +# +# Remap tags to __fn() builder. +# +SXFactory.maptag('attribute', __fn) diff --git a/pym/calculate/contrib/suds/soaparray.pyc b/pym/calculate/contrib/suds/soaparray.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5644beb0dbd65e851471beb7564a2e2d29a84ca6 GIT binary patch literal 2085 zcmbtVTW{k;6h3w?O}rE;u0jH7koF;qL@c513RTOp3l$R5stVPo|cQY+Jd$5{p_bOD&qVJ};Cu;v_v3dS!KG zin=mlTDM{@D^(WNEaG8eWOQ!vPCR@dbd}diE8*rc)AMb5_#D`I zm8ZqIY=yMz1M!UM6?WZdQB+`YA(^yIn(KCHT#s{EF14tq;=-u%z;StuaXvR^95?MN z#`Fb@B{~b}lIRjPq-*HrvO{N%lk0%mPYEGt5lG28R1G=yJ~-Nt11>!|ZtD<)T>SIi zUG9I_Kj)heD}Db%@jKLU^&=DRWWSxn(VYDnHB>RhLuS zN3Y4}8nkj>Th}&WQH{{NF=KeA%c4~AsVa;eL&D3|C#%mMWsmk_J)6a5sZ6{*3gc#- z^f2T;n&ItG@2%jCU@y#BfQ*2ftAK#BtpMo0LJ@*n_5%dzh_jFUo)|*H+qAnda%tV$TG+>Rp(je z3Yzd16Q1gJGtT=z3Sl-rKywP|_xs`S-msT59b8{-P9cYIRF|$oCk$LzIGH$rIH^H! z1qX+d=*58AeX_`L=NPwjipu){893DGh!uHc1nk_}<{*x}=*@VwC|SDWx}C**Z^V|b z+3n?lS&1s+Rrs&Q-yX1|y3$U9xU^l7-F@ueb5U3Ba$hHJ!@v8XbLTh9rq$<|&TuU$ z=m+lvuR*UK)6G47a`;_qJ>>doi8Lx~Qo7Jf_MV>GlZnE@b r^VxBjJi7P!CCh3d8!KmbSBaD7V=u@j%#vaC^}{IG<6r09kA~5o + + + + + + 'root' can be used to distinguish serialization roots from other + elements that are present in a serialization but are not roots of + a serialized value graph + + + + + + + + + + + + + Attributes common to all elements that function as accessors or + represent independent (multi-ref) values. The href attribute is + intended to be used in a manner like CONREF. That is, the element + content should be empty iff the href attribute appears + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 'Array' is a complex type for accessors identified by position + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +""") + + +class DocumentStore(object): + """ + Local XML document content repository. + + Each XML document is identified by its location, i.e. URL without any + protocol identifier. Contained XML documents can be looked up using any URL + referencing that same location. + + """ + + def __init__(self, *args, **kwargs): + self.__store = { + 'schemas.xmlsoap.org/soap/encoding/': soap5_encoding_schema} + self.update = self.__store.update + self.update(*args, **kwargs) + + def __len__(self): + return len(self.__store) + + def open(self, url): + """ + Open a document at the specified URL. + + The document URL's needs not contain a protocol identifier, and if it + does, that protocol identifier is ignored when looking up the store + content. + + Missing documents referenced using the internal 'suds' protocol are + reported by raising an exception. For other protocols, None is returned + instead. + + @param url: A document URL. + @type url: str + @return: Document content or None if not found. + @rtype: bytes + + """ + protocol, location = self.__split(url) + content = self.__find(location) + if protocol == 'suds' and content is None: + raise Exception, 'location "%s" not in document store' % location + return content + + def __find(self, location): + """ + Find the specified location in the store. + + @param location: The I{location} part of a URL. + @type location: str + @return: Document content or None if not found. + @rtype: bytes + + """ + return self.__store.get(location) + + def __split(self, url): + """ + Split the given URL into its I{protocol} & I{location} components. + + @param url: A URL. + @param url: str + @return: (I{protocol}, I{location}) + @rtype: (str, str) + + """ + parts = url.split('://', 1) + if len(parts) == 2: + return parts + return None, url + + +defaultDocumentStore = DocumentStore() diff --git a/pym/calculate/contrib/suds/store.pyc b/pym/calculate/contrib/suds/store.pyc new file mode 100644 index 0000000000000000000000000000000000000000..28fd9b236be3f4d8f6db7c06eaa0c06bdf3165f4 GIT binary patch literal 18861 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 not accepted by type() + name = str(name) + key = ".".join((name, str(bases))) + subclass = cls.cache.get(key) + if subclass is None: + subclass = type(name, bases, dict) + cls.cache[key] = subclass + return subclass + + @classmethod + def object(cls, classname=None, dict={}): + if classname is not None: + subclass = cls.subclass(classname, Object) + inst = subclass() + else: + inst = Object() + for a in dict.items(): + setattr(inst, a[0], a[1]) + return inst + + @classmethod + def metadata(cls): + return Metadata() + + @classmethod + def property(cls, name, value=None): + subclass = cls.subclass(name, Property) + return subclass(value) + + +class Object(UnicodeMixin): + + def __init__(self): + self.__keylist__ = [] + self.__printer__ = Printer() + self.__metadata__ = Metadata() + + def __setattr__(self, name, value): + builtin = name.startswith("__") and name.endswith("__") + if not builtin and name not in self.__keylist__: + self.__keylist__.append(name) + self.__dict__[name] = value + + def __delattr__(self, name): + try: + del self.__dict__[name] + builtin = name.startswith("__") and name.endswith("__") + if not builtin: + self.__keylist__.remove(name) + except Exception: + cls = self.__class__.__name__ + raise AttributeError, "%s has no attribute '%s'" % (cls, name) + + def __getitem__(self, name): + if isinstance(name, int): + name = self.__keylist__[int(name)] + return getattr(self, name) + + def __setitem__(self, name, value): + setattr(self, name, value) + + def __iter__(self): + return Iter(self) + + def __len__(self): + return len(self.__keylist__) + + def __contains__(self, name): + return name in self.__keylist__ + + def __repr__(self): + return str(self) + + def __unicode__(self): + return self.__printer__.tostr(self) + + +class Iter: + + def __init__(self, sobject): + self.sobject = sobject + self.keylist = self.__keylist(sobject) + self.index = 0 + + def next(self): + keylist = self.keylist + nkeys = len(self.keylist) + while self.index < nkeys: + k = keylist[self.index] + self.index += 1 + if hasattr(self.sobject, k): + v = getattr(self.sobject, k) + return (k, v) + raise StopIteration() + + def __keylist(self, sobject): + keylist = sobject.__keylist__ + try: + keyset = set(keylist) + ordering = sobject.__metadata__.ordering + ordered = set(ordering) + if not ordered.issuperset(keyset): + log.debug("%s must be superset of %s, ordering ignored", + keylist, ordering) + raise KeyError() + return ordering + except Exception: + return keylist + + def __iter__(self): + return self + + +class Metadata(Object): + def __init__(self): + self.__keylist__ = [] + self.__printer__ = Printer() + + +class Facade(Object): + def __init__(self, name): + Object.__init__(self) + md = self.__metadata__ + md.facade = name + + +class Property(Object): + + def __init__(self, value): + Object.__init__(self) + self.value = value + + def items(self): + for item in self: + if item[0] != "value": + yield item + + def get(self): + return self.value + + def set(self, value): + self.value = value + return self + + +class Printer: + """Pretty printing of a Object object.""" + + @classmethod + def indent(cls, n): + return "%*s" % (n * 3, " ") + + def tostr(self, object, indent=-2): + """Get s string representation of object.""" + history = [] + return self.process(object, history, indent) + + def process(self, object, h, n=0, nl=False): + """Print object using the specified indent (n) and newline (nl).""" + if object is None: + return "None" + if isinstance(object, Object): + if len(object) == 0: + return "" + return self.print_object(object, h, n + 2, nl) + if isinstance(object, dict): + if len(object) == 0: + return "" + return self.print_dictionary(object, h, n + 2, nl) + if isinstance(object, (list, tuple)): + if len(object) == 0: + return "" + return self.print_collection(object, h, n + 2) + if isinstance(object, basestring): + return '"%s"' % (tostr(object),) + return "%s" % (tostr(object),) + + def print_object(self, d, h, n, nl=False): + """Print complex using the specified indent (n) and newline (nl).""" + s = [] + cls = d.__class__ + if d in h: + s.append("(") + s.append(cls.__name__) + s.append(")") + s.append("...") + return "".join(s) + h.append(d) + if nl: + s.append("\n") + s.append(self.indent(n)) + if cls != Object: + s.append("(") + if isinstance(d, Facade): + s.append(d.__metadata__.facade) + else: + s.append(cls.__name__) + s.append(")") + s.append("{") + for item in d: + if self.exclude(d, item): + continue + item = self.unwrap(d, item) + s.append("\n") + s.append(self.indent(n+1)) + if isinstance(item[1], (list,tuple)): + s.append(item[0]) + s.append("[]") + else: + s.append(item[0]) + s.append(" = ") + s.append(self.process(item[1], h, n, True)) + s.append("\n") + s.append(self.indent(n)) + s.append("}") + h.pop() + return "".join(s) + + def print_dictionary(self, d, h, n, nl=False): + """Print complex using the specified indent (n) and newline (nl).""" + if d in h: + return "{}..." + h.append(d) + s = [] + if nl: + s.append("\n") + s.append(self.indent(n)) + s.append("{") + for item in d.items(): + s.append("\n") + s.append(self.indent(n+1)) + if isinstance(item[1], (list,tuple)): + s.append(tostr(item[0])) + s.append("[]") + else: + s.append(tostr(item[0])) + s.append(" = ") + s.append(self.process(item[1], h, n, True)) + s.append("\n") + s.append(self.indent(n)) + s.append("}") + h.pop() + return "".join(s) + + def print_collection(self, c, h, n): + """Print collection using the specified indent (n) and newline (nl).""" + if c in h: + return "[]..." + h.append(c) + s = [] + for item in c: + s.append("\n") + s.append(self.indent(n)) + s.append(self.process(item, h, n - 2)) + s.append(",") + h.pop() + return "".join(s) + + def unwrap(self, d, item): + """Translate (unwrap) using an optional wrapper function.""" + try: + md = d.__metadata__ + pmd = getattr(md, "__print__", None) + if pmd is None: + return item + wrappers = getattr(pmd, "wrappers", {}) + fn = wrappers.get(item[0], lambda x: x) + return (item[0], fn(item[1])) + except Exception: + pass + return item + + def exclude(self, d, item): + """Check metadata for excluded items.""" + try: + md = d.__metadata__ + pmd = getattr(md, "__print__", None) + if pmd is None: + return False + excludes = getattr(pmd, "excludes", []) + return item[0] in excludes + except Exception: + pass + return False diff --git a/pym/calculate/contrib/suds/sudsobject.pyc b/pym/calculate/contrib/suds/sudsobject.pyc new file mode 100644 index 0000000000000000000000000000000000000000..72326aa6d7c0436e3f745694ab326f7c65cd7f8a GIT binary patch literal 13696 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/transport/__init__.py b/pym/calculate/contrib/suds/transport/__init__.py new file mode 100644 index 0000000..e45b66a --- /dev/null +++ b/pym/calculate/contrib/suds/transport/__init__.py @@ -0,0 +1,166 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the (LGPL) GNU Lesser General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License +# for more details at ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Contains transport interface (classes). + +""" + +from suds import UnicodeMixin + +import sys + + +class TransportError(Exception): + def __init__(self, reason, httpcode, fp=None): + Exception.__init__(self, reason) + self.httpcode = httpcode + self.fp = fp + + +class Request(UnicodeMixin): + """ + A transport request. + + Request URL input data may be given as either a byte or a unicode string, + but it may not under any circumstances contain non-ASCII characters. The + URL value is stored as a str value internally. With Python versions prior + to 3.0, str is the byte string type, while with later Python versions it is + the unicode string type. + + @ivar url: The URL for the request. + @type url: str + @ivar message: The optional message to be sent in the request body. + @type message: bytes|None + @type timeout: int|None + @ivar headers: The HTTP headers to be used for the request. + @type headers: dict + + """ + + def __init__(self, url, message=None, timeout=None): + """ + Raised exception in case of detected non-ASCII URL characters may be + either UnicodeEncodeError or UnicodeDecodeError, depending on the used + Python version's str type and the exact value passed as URL input data. + + @param url: The URL for the request. + @type url: bytes|str|unicode + @param message: The optional message to be sent in the request body. + @type message: bytes|None + + """ + self.__set_URL(url) + self.headers = {} + self.message = message + self.timeout = timeout + + def __unicode__(self): + result = [u"URL: %s\nHEADERS: %s" % (self.url, self.headers)] + if self.message is not None: + result.append(u"MESSAGE:") + result.append(self.message.decode("raw_unicode_escape")) + return u"\n".join(result) + + def __set_URL(self, url): + """ + URL is stored as a str internally and must not contain ASCII chars. + + Raised exception in case of detected non-ASCII URL characters may be + either UnicodeEncodeError or UnicodeDecodeError, depending on the used + Python version's str type and the exact value passed as URL input data. + + """ + if isinstance(url, str): + url.encode("ascii") # Check for non-ASCII characters. + self.url = url + elif sys.version_info < (3, 0): + self.url = url.encode("ascii") + else: + self.url = url.decode("ascii") + + +class Reply(UnicodeMixin): + """ + A transport reply. + + @ivar code: The HTTP code returned. + @type code: int + @ivar headers: The HTTP headers included in the received reply. + @type headers: dict + @ivar message: The message received as a reply. + @type message: bytes + + """ + + def __init__(self, code, headers, message): + """ + @param code: The HTTP code returned. + @type code: int + @param headers: The HTTP headers included in the received reply. + @type headers: dict + @param message: The (optional) message received as a reply. + @type message: bytes + + """ + self.code = code + self.headers = headers + self.message = message + + def __unicode__(self): + return u"""\ +CODE: %s +HEADERS: %s +MESSAGE: +%s""" % (self.code, self.headers, self.message.decode("raw_unicode_escape")) + + +class Transport(object): + """The transport I{interface}.""" + + def __init__(self): + from suds.transport.options import Options + self.options = Options() + + def open(self, request): + """ + Open the URL in the specified request. + + @param request: A transport request. + @type request: L{Request} + @return: An input stream. + @rtype: stream + @raise TransportError: On all transport errors. + + """ + raise Exception('not-implemented') + + def send(self, request): + """ + Send SOAP message. Implementations are expected to handle: + - proxies + - I{HTTP} headers + - cookies + - sending message + - brokering exceptions into L{TransportError} + + @param request: A transport request. + @type request: L{Request} + @return: The reply + @rtype: L{Reply} + @raise TransportError: On all transport errors. + + """ + raise Exception('not-implemented') diff --git a/pym/calculate/contrib/suds/transport/__init__.pyc b/pym/calculate/contrib/suds/transport/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..820f7260c7febd3f7e311bad4fabaade551ad406 GIT binary patch literal 6195 zcmd^D&vV>J6>iPglXwzuvVnCKKMHzTvOA&TF;zgIT-27miD6TfI6=-9MGgpAYTI%& z(xBEPHc2>a!htHzoVoK4@PBdR0^j#q)6yic3+wEODXZPxQonxv`g`Ad-Tl9>4xfDY zFTY7t^XudP79RV16sb}VQ3fjQsXS1Vo_g3*0o#3*_tnF`N|%&bQU~Z+Rxg!$q13M) zE~|8)Oiy~x`QCv_&(C{TeD67x4wX4C-(K*&E1Y0&bdh>|55@3iS=4b>SY20fVW(wP z>#V3vbr2^;kCHsL*4S&~;V}Crexm?mYL5P-$dWQOce9hM*sb3}&x5&uovJD;zw91f zeT2t;6@|gFu_F8_^)lcx!@Uu|NS09Wp_OjpvG1d(l{ya8Go_vd>ILlctj9)#vM&`_ zNntfqYInrZ^$Loelf+Ex3=2DtRupALR!5OEj_P_!wQJ6KFm+=%(3pJuim=UFj3SwH#7jp)V?H_YMThMlE$!`pFVKJ$2b8gg0R zz+*Xw3N8mLL8GzLv4|%IIu7wNiY8?`%h{wByJcZyc&mxj&ZG`4_H{g#b{GWpIs6OF zZ)e8Ve&eXJY}^Ja&BkH-dPFAw0`(H8MWsh{5u1If47jH>o&6J}4>f+<9duQ08X$^q zno0F1;T_;^I;(XW*Rh_&r+VM$!|bssbZoWB>LXL>Snr?KMwhJ3900YgtE@P@F4Fcf zKC5MPQP%h*<)GqJCs~!uCbo`?#8{m;%0`Um6hUzfp< zhvm4nIQ4aXIyKkzlcOv*`UxfFF+{&64~xsJlLrBdCJ-5oS+}ysaiwQfzRBf?bq`=Q z&g$(?^KWrp_Z<`w!EWfpSQ{T2H@p;YigVrcYAgo3V@*M_=t|Z5WqLYxazwP3!;Q1g z2=-6cK_=}8r1Lt}1fUv@w10#9$SMTEaYjwdoOEcBB(^~5fd>rO$g5;`U3o8DW-_g=>gQ&XgH01eo2dubLgZV`?j5XJxjw>&OV`P`fU z_6?e+J3&UWQ1h#x{m@b7BcvSmr%3}eI|0I+#lhw3=Qhy zDq_V-kdU&8KE4&~{u&jKa06e7lm|Vvb{MGVt`|(L)T0$u{etoHSeW_+Fzy;0*Hgzr z+vw$s0s@!R@j${Y(M}fMoqYu*th1@F+Tq7L+qZVYJ=SMb@9xgt-uBOTHtQ>BRPmFj z+26?6B%YcXwH}Tnyj(^#TxB5!W2lpe8&3&gsip#L346z7R*1JbTf5L~XLJjX6XW_f%n=8_ZojD8ipx~MJ?>B> zbkt-j@60VITDegB`Q~buwrH}B5WnUxWVdz#FUQ-iGl@3_CmGGNf@_~|%T~S@(Xl7r z?h3*r(r}G!Tx#QcNT7CJp!J3hf;l9)gW%AIcDe_-N<#a4sJs%|n{X{&f>?dfS8L8o zc4wNy?%mpXH9!yN!FhPqhD>@>(3}+$*GR^Ps$oWz&OCk|^dJ4bA z>FDA@N$s3xXCrz>#EBV12NwptmAB+hz+X-z=$9XtEPQkgmCxp*=3u)_V&ak9@+418 z`m?^i{nX!@JRc{N%^1T+HdLd64drEzQWMG0n1;P@rwvKen%(SNvoLGACr2;q&`PWF zj$!QQ9XqG6;dk&#SikA$L?XUwO?;+p<(B<{O3(_t#qc?jU#SF1Su9ZcsVuo+^M7E7 zPs8sa=aU17J8DSPPEC>>WJ0lW712prnqxw9c-_>C5uy2-j?JGt)%tJmJZ%#F=YIMv z7at&}0KfCv0kPi16BjN-M#Xc|X4Bsp$m~gbILYB`Q{TfaMV@!?V0Z`C&AKcP2uRM> zv&l3!6C9mQx+^zVA#K<0m+WGr`GUF~Y*u&pC{D?vL`TVT^ z%9x}qAH6;X_YiUdZn*xHG5b~d$nc7&J)&FQHpL4 z^DnKejwJbIxN#bSJVP{8NCp?j3(3_Xlh}~4L-PG{{}|vEiLG){I}3Zt1@uqd-R_4x VEl3(a=w0qz?5~|$`*7{Oe*wd7{U87U literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/transport/http.py b/pym/calculate/contrib/suds/transport/http.py new file mode 100644 index 0000000..f1dc8ce --- /dev/null +++ b/pym/calculate/contrib/suds/transport/http.py @@ -0,0 +1,249 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the (LGPL) GNU Lesser General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License +# for more details at ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Basic HTTP transport implementation classes. + +""" + +from suds.properties import Unskin +from suds.transport import * + +import base64 +from cookielib import CookieJar +import httplib +import socket +import sys +import urllib2 +import gzip +import zlib + +from logging import getLogger +log = getLogger(__name__) + + +class HttpTransport(Transport): + """ + Basic HTTP transport implemented using using urllib2, that provides for + cookies & proxies but no authentication. + + """ + + def __init__(self, **kwargs): + """ + @param kwargs: Keyword arguments. + - B{proxy} - An HTTP proxy to be specified on requests. + The proxy is defined as {protocol:proxy,} + - type: I{dict} + - default: {} + - B{timeout} - Set the URL open timeout (seconds). + - type: I{float} + - default: 90 + + """ + Transport.__init__(self) + Unskin(self.options).update(kwargs) + self.cookiejar = CookieJar() + self.proxy = {} + self.urlopener = None + + def open(self, request): + try: + url = self.__get_request_url_for_urllib(request) + headers = request.headers + log.debug('opening (%s)', url) + u2request = urllib2.Request(url, headers=headers) + self.proxy = self.options.proxy + return self.u2open(u2request) + except urllib2.HTTPError as e: + raise TransportError(str(e), e.code, e.fp) + + def send(self, request): + url = self.__get_request_url_for_urllib(request) + msg = request.message + headers = request.headers + if 'Content-Encoding' in headers: + encoding = headers['Content-Encoding'] + if encoding == 'gzip': + msg = gzip.compress(msg) + elif encoding == 'deflate': + msg = zlib.compress(msg) + try: + u2request = urllib2.Request(url, msg, headers) + self.addcookies(u2request) + self.proxy = self.options.proxy + request.headers.update(u2request.headers) + log.debug('sending:\n%s', request) + fp = self.u2open(u2request, timeout=request.timeout) + self.getcookies(fp, u2request) + headers = fp.headers + if sys.version_info < (3, 0): + headers = headers.dict + message = fp.read() + if 'Content-Encoding' in headers: + encoding = headers['Content-Encoding'] + if encoding == 'gzip': + message = gzip.decompress(message) + elif encoding == 'deflate': + message = zlib.decompress(message) + reply = Reply(httplib.OK, headers, message) + log.debug('received:\n%s', reply) + return reply + except urllib2.HTTPError as e: + if e.code not in (httplib.ACCEPTED, httplib.NO_CONTENT): + raise TransportError(e.msg, e.code, e.fp) + + def addcookies(self, u2request): + """ + Add cookies in the cookiejar to the request. + + @param u2request: A urllib2 request. + @rtype: u2request: urllib2.Request. + + """ + self.cookiejar.add_cookie_header(u2request) + + def getcookies(self, fp, u2request): + """ + Add cookies in the request to the cookiejar. + + @param u2request: A urllib2 request. + @rtype: u2request: urllib2.Request. + + """ + self.cookiejar.extract_cookies(fp, u2request) + + def u2open(self, u2request, timeout=None): + """ + Open a connection. + + @param u2request: A urllib2 request. + @type u2request: urllib2.Request. + @return: The opened file-like urllib2 object. + @rtype: fp + + """ + tm = timeout or self.options.timeout + url = self.u2opener() + if (sys.version_info < (3, 0)) and (self.u2ver() < 2.6): + socket.setdefaulttimeout(tm) + return url.open(u2request) + return url.open(u2request, timeout=tm) + + def u2opener(self): + """ + Create a urllib opener. + + @return: An opener. + @rtype: I{OpenerDirector} + + """ + if self.urlopener is None: + return urllib2.build_opener(*self.u2handlers()) + return self.urlopener + + def u2handlers(self): + """ + Get a collection of urllib handlers. + + @return: A list of handlers to be installed in the opener. + @rtype: [Handler,...] + + """ + return [urllib2.ProxyHandler(self.proxy)] + + def u2ver(self): + """ + Get the major/minor version of the urllib2 lib. + + @return: The urllib2 version. + @rtype: float + + """ + try: + part = urllib2.__version__.split('.', 1) + return float('.'.join(part)) + except Exception as e: + log.exception(e) + return 0 + + def __deepcopy__(self, memo={}): + clone = self.__class__() + p = Unskin(self.options) + cp = Unskin(clone.options) + cp.update(p) + return clone + + @staticmethod + def __get_request_url_for_urllib(request): + """ + Returns the given request's URL, properly encoded for use with urllib. + + We expect that the given request object already verified that the URL + contains ASCII characters only and stored it as a native str value. + + urllib accepts URL information as a native str value and may break + unexpectedly if given URL information in another format. + + Python 3.x httplib.client implementation must be given a unicode string + and not a bytes object and the given string is internally converted to + a bytes object using an explicitly specified ASCII encoding. + + Python 2.7 httplib implementation expects the URL passed to it to not + be a unicode string. If it is, then passing it to the underlying + httplib Request object will cause that object to forcefully convert all + of its data to unicode, assuming that data contains ASCII data only and + raising a UnicodeDecodeError exception if it does not (caused by simple + unicode + string concatenation). + + Python 2.4 httplib implementation does not really care about this as it + does not use the internal optimization present in the Python 2.7 + implementation causing all the requested data to be converted to + unicode. + + """ + assert isinstance(request.url, str) + return request.url + + +class HttpAuthenticated(HttpTransport): + """ + Provides basic HTTP authentication for servers that do not follow the + specified challenge/response model. Appends the I{Authorization} HTTP + header with base64 encoded credentials on every HTTP request. + + """ + + def open(self, request): + self.addcredentials(request) + return HttpTransport.open(self, request) + + def send(self, request): + self.addcredentials(request) + return HttpTransport.send(self, request) + + def addcredentials(self, request): + credentials = self.credentials() + if None not in credentials: + credentials = ':'.join(credentials) + if sys.version_info < (3, 0): + encodedString = base64.b64encode(credentials) + else: + encodedBytes = base64.urlsafe_b64encode(credentials.encode()) + encodedString = encodedBytes.decode() + request.headers['Authorization'] = 'Basic %s' % encodedString + + def credentials(self): + return self.options.username, self.options.password diff --git a/pym/calculate/contrib/suds/transport/http.pyc b/pym/calculate/contrib/suds/transport/http.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed26bb89be8fa2fbba6f9e5e1283a470bf17d795 GIT binary patch literal 9227 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

qJF>BH)` z?Q+t+575#!gmSrF=0~y#-@R#teHkb4P)p(s5-2P(affY&DWpxwH-z*Mf^&^ruaxTz zA@h|2G!%J&n2NfRCdf6HBMVf{H!pmaz{<}-AA}!%2C=Lov5j26Vw*S5eQX*qP0_8qD)dD#~Apk6o1$M!UU3<2+pGg&R z9idJVXq$vMMT^SZ=ORFvkyj!D8?P`|aR8?N43_!4Z0>K+Z|I%WnN!YkL()d{N3B-k zcXg{JacQg7O~Zc7S7vkJI?@0hOmeYw3*OgQ@FeZ=pwuBzIq)SftV&#j!r1J{I9{rJR4?O1KP_EN20tIr&*&EW6hnMpa@FyXye z-B#%^zzq4(?OnoSm?hGagB`isl9g;S z#kyFKr7vD6-ERPI2VIH$m`>2uAZlPQ#r7tGBvN9OG>T`5J7(^HfdERIbVAsIzz9uz zuVNui5ZE)xSbfc-=W*?m{@%Ay^*k0UEGmy6 zYQiZM=cM+;dVCXW{Rxj8RwgE3-N*26y1|sUd^~54lb50u0^Pz)+~_F1KP9*^KI*Z e-ytpL42p@7BTju}2G;=gYCuY~&5WM>^}hi%qgK=a literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/transport/https.py b/pym/calculate/contrib/suds/transport/https.py new file mode 100644 index 0000000..cdff55a --- /dev/null +++ b/pym/calculate/contrib/suds/transport/https.py @@ -0,0 +1,99 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the (LGPL) GNU Lesser General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License +# for more details at ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Contains classes for authenticated HTTP transport implementations. + +""" + +from suds.transport import * +from suds.transport.http import HttpTransport + +import urllib2 + + +class HttpAuthenticated(HttpTransport): + """ + Provides basic HTTP authentication that follows the RFC-2617 specification. + + As defined by specifications, credentials are provided to the server upon + request (HTTP/1.0 401 Authorization Required) by the server only. + + @ivar pm: The password manager. + @ivar handler: The authentication handler. + + """ + + def __init__(self, **kwargs): + """ + @param kwargs: Keyword arguments. + - B{proxy} - An HTTP proxy to be specified on requests. + The proxy is defined as {protocol:proxy,} + - type: I{dict} + - default: {} + - B{timeout} - Set the URL open timeout (seconds). + - type: I{float} + - default: 90 + - B{username} - The username used for HTTP authentication. + - type: I{str} + - default: None + - B{password} - The password used for HTTP authentication. + - type: I{str} + - default: None + + """ + HttpTransport.__init__(self, **kwargs) + self.pm = urllib2.HTTPPasswordMgrWithDefaultRealm() + + def open(self, request): + self.addcredentials(request) + return HttpTransport.open(self, request) + + def send(self, request): + self.addcredentials(request) + return HttpTransport.send(self, request) + + def addcredentials(self, request): + credentials = self.credentials() + if None not in credentials: + u = credentials[0] + p = credentials[1] + self.pm.add_password(None, request.url, u, p) + + def credentials(self): + return self.options.username, self.options.password + + def u2handlers(self): + handlers = HttpTransport.u2handlers(self) + handlers.append(urllib2.HTTPBasicAuthHandler(self.pm)) + return handlers + + +class WindowsHttpAuthenticated(HttpAuthenticated): + """ + Provides Windows (NTLM) based HTTP authentication. + + @author: Christopher Bess + + """ + + def u2handlers(self): + try: + from ntlm import HTTPNtlmAuthHandler + except ImportError: + raise Exception("Cannot import python-ntlm module") + handlers = HttpTransport.u2handlers(self) + handlers.append(HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(self.pm)) + return handlers diff --git a/pym/calculate/contrib/suds/transport/https.pyc b/pym/calculate/contrib/suds/transport/https.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c4d4349ea35066419beb0de98e5fe50f799cec2 GIT binary patch literal 3749 zcmcgvZEqA+6uz^&-L@+zDx#?9O*C;av;`z64bjqqDFN1Ix(01Xmg&yj?v&Y?aqeB( z75c^c)nDKj|D!)ZpXbcJbOA#GjkCG8_ifIc^PK0Lb6fuVWNq*BzaF;L@G0Z(3YvX@ zE>vm@y{E#GiapijsI20W>Xp@2S$UjSR9sP86&21XQ&t_URMqcF9V+$n){F{gm6?&% zx$$b1FKyQ6`ITGfYHMlYf+(@N9S7DLt2=3~gTCvU#6|7EnNY7cn;Y8YL1MEscRK22 zvFTwua8a7r#ab=;2T$FDILGeGVt5k6b?36?=*@;>J)@TD+*QT)dW3S#Mc4v7f=Idubl(UXTPkCSR0K6=%9Z62>Mk4n70KaBnEH zP1lsr$k00k^)qx%sa;P!RqCmy{_vFNN@}-E@?oh3A9)}eU$TFqm+um^l`P1Eo_@3! zJvVMs4?BXF!IaAG>A!Wcmb+a8b{seMd7k zjT7Jf=-<_8X27~)PuHz!r%7nfPh;@B5}h~=UarNpi&M5xi$3_01U*AFh{$NpK`5aw z!9GofmuX{NK5g$r;V~kOG%?R^{Yq*lY{~>fTO%KXTohh0A>t#69p|sjMfQcNL7Si94=}K|%I9MoKz+1*7eL z6o*UOVPxH693}nzh5c`?wys`TGCMmKNI5d^D!Joxyg2 zRZ&R5SunNp3`ePKn#pBD;&YU=WHPc(NG(J?4hx8i)Hz0$Dm0%8vI|%q*FOZ=0Scjn z8E~cxVaSZaI^z!;qnM*>3X&3<{^enrwUQ-*3;`GV3_W)m9n;M!uPVF)tQW;voI4@5 zKrj+=9EQ^)4KzzlmG_o+)|1QPFfp=rATd(;R;!nW{g_iasMQM7cB>@`%ICgM1{P6C zG<`~*XegssPlNQuM`)J$t6Hm;=HHvI;5R#8b{}Brew2i`!twe^@Wyx9HumHp4Oh|Z z`{-VH*TnUaUy-}Gl!}ef^>HX%*Bi~d_iz&nSUX=>H|4z*R?`&MthH{AT%TrL-1=6H zwZ$b;qJqIW&L9sl8Jr$n{gvtoy}bL$IaNW8c~n#RSIYA|P!0EBFzh!^C7${T833dM z^{|A*gJiQ?6;{e6ZFhFeN5&Uf);Mx;e;0Gw&~S0@2;Z#6`dW}Asa*Vd|IY?6Cs{~v zP!|-a&*6~dA1?ZzaK`L(yT^YRZsj?8=7d}OZ6k3kAs~$KiGM+AVjux50{pX>PWbZb zR3Yykpb1r!SN2Y$)|@JsO%VJK*^x~C$Lx-kr>ww^j?28G s6Q-9IS@{dNL|IbOr_>2FuNO)Z*w+g`ek~|@2ZREmEkaWT6+$pTVge1+mIw9{(%iKROLHN2Q9HGL z8b5^p$PWPfnxsstCL|!$xp%hD{%oJ^{J7>$?|lCpLh(8H{~VXvL&5=$kXpcPh%Fct zI~#Wn2nR+eslhjZGk{M=HQ;sVdkwmM7m52a4wMp#O(Yj_l#H3qf<&b<(@ds1l8I`$ zZuApB&q94oSAS!f>)Fy1`{>Xt|-?K@fg8{esqH|dVm2P%&7`XDuc;oQ4fssqMHq748*ma{+}6YQb{+aJXa!1f{7^Mm1l+<&PFm@ zWg^J27>SO;fFAKhq)k@VoIISg=s=?sUL(WH8rP5%USS9Zyg?|Wp(h?Iy& znug%XG|0xvY`L5Sc;PBJt9&aDk6?)E;BJ^lF>eofq;w0%Wj<@p9(VlCUR#XEZIyG? zuI6XEoS*4wZwIeF!lkYw0jpu}Si9B^{&p<`sz;eJ!T3H-;yk7-5YP9y41M1iSVQ@1 zJoJoi<5HB7#?6L(=usJayGS%)q)=K_D4Osa78W`cnT~|&ky?)o{X1NyT2EIAcy@z) LQjHppYq`!Z9+9*( literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/umx/__init__.py b/pym/calculate/contrib/suds/umx/__init__.py new file mode 100644 index 0000000..ca65cad --- /dev/null +++ b/pym/calculate/contrib/suds/umx/__init__.py @@ -0,0 +1,56 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Provides modules containing classes to support +unmarshalling (XML). +""" + +from suds.sudsobject import Object + + + +class Content(Object): + """ + @ivar node: The content source node. + @type node: L{sax.element.Element} + @ivar data: The (optional) content data. + @type data: L{Object} + @ivar text: The (optional) content (xml) text. + @type text: basestring + """ + + extensions = [] + + def __init__(self, node, **kwargs): + Object.__init__(self) + self.node = node + self.data = None + self.text = None + for k,v in kwargs.items(): + setattr(self, k, v) + + def __getattr__(self, name): + if name not in self.__dict__: + if name in self.extensions: + v = None + setattr(self, name, v) + else: + raise AttributeError, \ + 'Content has no attribute %s' % name + else: + v = self.__dict__[name] + return v diff --git a/pym/calculate/contrib/suds/umx/__init__.pyc b/pym/calculate/contrib/suds/umx/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a9f958cd18de992e658900349ce884667a5a95bb GIT binary patch literal 1450 zcmb_cT~E|N6umRMEU>zY(U_n<^g&HEaaR*XLySR@_#mPwBr4I2-R-axy6xJT!V;Dj z@rU^PeDw$Dxif&g_@YiTr*~%V+>di_Tl>*!?q2`)sYgenhW7%dxeG{$)`5Z&NtvL5 zq;*Lmsgahnf!#WNB|0Q}zh0wcf>y%@-&_JT-;~8pnrIUYiloZ$?iIO>(>%@lK`)Dq z!ImuoQw@hjX`59(h)c5>XBjJm?_Mq6YB$rL7@>eU%Z6Wfw{*|iNr;OurgM7|HS0XX zG&cbnQ6o5@q&^U_2@Z6<&UvsfLD6c+nVRo_W`MDf?!;w~7m1z^);6^Z7ajsrRAo=Q zgSJ<+dqcmT50>{$JZkGq51`s!^6!IF_LA7f-d?}I0YXOCRvu0LK9e} zY#j^c+X*X0?gb{n?QjB?V@<6d7*}2%Tcugj=_aYMZS+|+x-)t-r{?Z=bidy*Rbo2TVAMGdusz(1m@jTAa~43NC8pgo zD;$&TnX_2LH17bOye;^jr1Hh_QqXpT%7;wkfg}r>yr%SIt#K~sP+Y$JMN;14bJ)Oo z7W$xkHRL!}%vJW~J3rWr4Vp4wKGJSwb#TLYUOdN1+GCEJxB(t@ZqR!s;$S0Iu;&0z zkMAy(Wl_5CA)4kxSDARABhLC?IkabBM5(^7olS)<^Ld9@|UkvQuLIHI009l=mMnQK|1L#tIeHr1=BD^jj4ug$myw-(6M$2TlPF3 gqEFfkh5H@3#*X;re~H26|JY~zgnb(J-jFl(Usc;j_y7O^ literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/umx/attrlist.py b/pym/calculate/contrib/suds/umx/attrlist.py new file mode 100644 index 0000000..df8da0b --- /dev/null +++ b/pym/calculate/contrib/suds/umx/attrlist.py @@ -0,0 +1,88 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Provides filtered attribute list classes. +""" + +from suds import * +from suds.umx import * +from suds.sax import Namespace + + +class AttrList: + """ + A filtered attribute list. + Items are included during iteration if they are in either the (xs) or + (xml) namespaces. + @ivar raw: The I{raw} attribute list. + @type raw: list + """ + def __init__(self, attributes): + """ + @param attributes: A list of attributes + @type attributes: list + """ + self.raw = attributes + + def real(self): + """ + Get list of I{real} attributes which exclude xs and xml attributes. + @return: A list of I{real} attributes. + @rtype: I{generator} + """ + for a in self.raw: + if self.skip(a): continue + yield a + + def rlen(self): + """ + Get the number of I{real} attributes which exclude xs and xml attributes. + @return: A count of I{real} attributes. + @rtype: L{int} + """ + n = 0 + for a in self.real(): + n += 1 + return n + + def lang(self): + """ + Get list of I{filtered} attributes which exclude xs. + @return: A list of I{filtered} attributes. + @rtype: I{generator} + """ + for a in self.raw: + if a.qname() == 'xml:lang': + return a.value + return None + + def skip(self, attr): + """ + Get whether to skip (filter-out) the specified attribute. + @param attr: An attribute. + @type attr: I{Attribute} + @return: True if should be skipped. + @rtype: bool + """ + ns = attr.namespace() + skip = ( + Namespace.xmlns[1], + 'http://schemas.xmlsoap.org/soap/encoding/', + 'http://schemas.xmlsoap.org/soap/envelope/', + 'http://www.w3.org/2003/05/soap-envelope', + ) + return ( Namespace.xs(ns) or ns[1] in skip ) diff --git a/pym/calculate/contrib/suds/umx/attrlist.pyc b/pym/calculate/contrib/suds/umx/attrlist.pyc new file mode 100644 index 0000000000000000000000000000000000000000..88409719bc02052f46ccc4aff9addc2915c4b66f GIT binary patch literal 2806 zcmb_e;cgp65Z<#LJ9b(cksk4wR7t9a@#BKzi0Dx}RDlLv5_|L(dpxS`Ga-K1~OQEQwDtwGOr8jg%RCzOrO@ z7w4bjWbQldeu`zjf>7`sjzg9x0{C@MrZ`A}vt?G`WrdaM%=d$u==PdbGV%vRL*ldh zUoN-!^`2EDBfUgP9r034JA-Q?oAPge^6v zqi|hD^B@5QUB9DGy+kJ7WLxgzz}`93%YT74+iB0nD%(kj@@c<>Fy`wS#dROz!Vwoj zxSZQwlU|#b5PX8~9D9j3T3lkbfdXeK9u&S^?B|>FgkpQ{0GaD#DI{*edA`q9=u#C9 zYy-;TWD`$^}aitqu>{CJjtG9ZlPGoGxsQ&zKpm zt0Qe)_XAik6rEV|i5#So6T}$v2x9t>a5xg;n;)gPWKfPE9dYG|=s7fW}|rI z6|Clfgc5FOizQv#JLao_-lJs@N%;apIKstTozI3R@&xjjHG#<3@ktM!L=*N`gh zDf|%r6F-F?05j{*<_wPJd3G}U_RaHpzxIdUp8oif!uIj#J*LnX1R21L(1FYa=|Jhi z%ms(n9!L)^wpp*sdLa8y`Y`jUrw{1Ef;xTp4zL0EJR3kZfb(FF*`E;%KdSm`k)amz zL>H-Ot1?k~nMjFBq%zSObvP`3(-SzwRl z-$Ixrid8Aa+jUiEc++WMigA;uq!e5|7N?c?^lmDQLfq*vR}F3(rfZ$7LX=n%dHAM# z-`wgMlZCCSh)C!*(_2wHREoKd#dQ6_I&`-)U>nSUU{Y6x$Rqa07MgCzu7kgnM!7JY zuxQ(oc6$PX6+x%vqGCt7FD}?v3hkBAH5u5o{w1Hs4Z6`dx65{D&lW1C^S>U z-UBD##PFSq<0>gJj?K_6$~tQ$FIjIKXLTCKcKe-xe^$XhJf^TJe9w2^+gl&qrobject I{unmarshalling}. +""" + +from suds import * +from suds.umx import * +from suds.umx.attrlist import AttrList +from suds.sax.text import Text +from suds.sudsobject import Factory, merge + + +reserved = {'class':'cls', 'def':'dfn'} + + +class Core: + """ + The abstract XML I{node} unmarshaller. This class provides the + I{core} unmarshalling functionality. + """ + + def process(self, content): + """ + Process an object graph representation of the xml I{node}. + @param content: The current content being unmarshalled. + @type content: L{Content} + @return: A suds object. + @rtype: L{Object} + """ + self.reset() + return self.append(content) + + def append(self, content): + """ + Process the specified node and convert the XML document into + a I{suds} L{object}. + @param content: The current content being unmarshalled. + @type content: L{Content} + @return: A I{append-result} tuple as: (L{Object}, I{value}) + @rtype: I{append-result} + @note: This is not the proper entry point. + @see: L{process()} + """ + self.start(content) + self.append_attributes(content) + self.append_children(content) + self.append_text(content) + self.end(content) + return self.postprocess(content) + + def postprocess(self, content): + """ + Perform final processing of the resulting data structure as follows: + - Mixed values (children and text) will have a result of the I{content.node}. + - Simi-simple values (attributes, no-children and text) will have a result of a + property object. + - Simple values (no-attributes, no-children with text nodes) will have a string + result equal to the value of the content.node.getText(). + @param content: The current content being unmarshalled. + @type content: L{Content} + @return: The post-processed result. + @rtype: I{any} + """ + node = content.node + if len(node.children) and node.hasText(): + return node + attributes = AttrList(node.attributes) + if attributes.rlen() and \ + not len(node.children) and \ + node.hasText(): + p = Factory.property(node.name, node.getText()) + return merge(content.data, p) + if len(content.data): + return content.data + lang = attributes.lang() + if content.node.isnil(): + return None + if not len(node.children) and content.text is None: + if self.nillable(content): + return None + else: + return Text('', lang=lang) + if isinstance(content.text, basestring): + return Text(content.text, lang=lang) + else: + return content.text + + def append_attributes(self, content): + """ + Append attribute nodes into L{Content.data}. + Attributes in the I{schema} or I{xml} namespaces are skipped. + @param content: The current content being unmarshalled. + @type content: L{Content} + """ + attributes = AttrList(content.node.attributes) + for attr in attributes.real(): + name = attr.name + value = attr.value + self.append_attribute(name, value, content) + + def append_attribute(self, name, value, content): + """ + Append an attribute name/value into L{Content.data}. + @param name: The attribute name + @type name: basestring + @param value: The attribute's value + @type value: basestring + @param content: The current content being unmarshalled. + @type content: L{Content} + """ + key = name + key = '_%s' % reserved.get(key, key) + setattr(content.data, key, value) + + def append_children(self, content): + """ + Append child nodes into L{Content.data} + @param content: The current content being unmarshalled. + @type content: L{Content} + """ + for child in content.node: + cont = Content(child) + cval = self.append(cont) + key = reserved.get(child.name, child.name) + if key in content.data: + v = getattr(content.data, key) + if isinstance(v, list): + v.append(cval) + else: + setattr(content.data, key, [v, cval]) + continue + if self.multi_occurrence(cont): + if cval is None: + setattr(content.data, key, []) + else: + setattr(content.data, key, [cval,]) + else: + setattr(content.data, key, cval) + + def append_text(self, content): + """ + Append text nodes into L{Content.data} + @param content: The current content being unmarshalled. + @type content: L{Content} + """ + if content.node.hasText(): + content.text = content.node.getText() + + def reset(self): + pass + + def start(self, content): + """ + Processing on I{node} has started. Build and return + the proper object. + @param content: The current content being unmarshalled. + @type content: L{Content} + @return: A subclass of Object. + @rtype: L{Object} + """ + content.data = Factory.object(content.node.name) + + def end(self, content): + """ + Processing on I{node} has ended. + @param content: The current content being unmarshalled. + @type content: L{Content} + """ + pass + + def single_occurrence(self, content): + """ + Get whether the content has at most a single occurrence (not a list). + @param content: The current content being unmarshalled. + @type content: L{Content} + @return: True if content has at most a single occurrence, else False. + @rtype: boolean + '""" + return not self.multi_occurrence(content) + + def multi_occurrence(self, content): + """ + Get whether the content has more than one occurrence (a list). + @param content: The current content being unmarshalled. + @type content: L{Content} + @return: True if content has more than one occurrence, else False. + @rtype: boolean + '""" + return False + + def nillable(self, content): + """ + Get whether the object is nillable. + @param content: The current content being unmarshalled. + @type content: L{Content} + @return: True if nillable, else False + @rtype: boolean + '""" + return False diff --git a/pym/calculate/contrib/suds/umx/core.pyc b/pym/calculate/contrib/suds/umx/core.pyc new file mode 100644 index 0000000000000000000000000000000000000000..72598282e303e26f609153fd8cf4be5f4689b0db GIT binary patch literal 7750 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 Z^83Q0Kip(x*nMuPjuN}>tgo(@{{>s#V;TSe literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/umx/typed.py b/pym/calculate/contrib/suds/umx/typed.py new file mode 100644 index 0000000..f28cb92 --- /dev/null +++ b/pym/calculate/contrib/suds/umx/typed.py @@ -0,0 +1,140 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +Provides typed unmarshaller classes. +""" + +from suds import * +from suds.umx import * +from suds.umx.core import Core +from suds.resolver import NodeResolver, Frame +from suds.sudsobject import Factory + +from logging import getLogger +log = getLogger(__name__) + + +# +# Add typed extensions +# type = The expected xsd type +# real = The 'true' XSD type +# +Content.extensions.append('type') +Content.extensions.append('real') + + +class Typed(Core): + """ + A I{typed} XML unmarshaller + @ivar resolver: A schema type resolver. + @type resolver: L{NodeResolver} + """ + + def __init__(self, schema): + """ + @param schema: A schema object. + @type schema: L{xsd.schema.Schema} + """ + self.resolver = NodeResolver(schema) + + def process(self, node, type): + """ + Process an object graph representation of the xml L{node}. + @param node: An XML tree. + @type node: L{sax.element.Element} + @param type: The I{optional} schema type. + @type type: L{xsd.sxbase.SchemaObject} + @return: A suds object. + @rtype: L{Object} + """ + content = Content(node) + content.type = type + return Core.process(self, content) + + def reset(self): + log.debug('reset') + self.resolver.reset() + + def start(self, content): + # + # Resolve to the schema type; build an object and setup metadata. + # + if content.type is None: + found = self.resolver.find(content.node) + if found is None: + log.error(self.resolver.schema) + raise TypeNotFound(content.node.qname()) + content.type = found + else: + known = self.resolver.known(content.node) + frame = Frame(content.type, resolved=known) + self.resolver.push(frame) + real = self.resolver.top().resolved + content.real = real + cls_name = real.name + if cls_name is None: + cls_name = content.node.name + content.data = Factory.object(cls_name) + md = content.data.__metadata__ + md.sxtype = real + + def end(self, content): + self.resolver.pop() + + def multi_occurrence(self, content): + return content.type.multi_occurrence() + + def nillable(self, content): + resolved = content.type.resolve() + return ( content.type.nillable or \ + (resolved.builtin() and resolved.nillable ) ) + + def append_attribute(self, name, value, content): + """ + Append an attribute name/value into L{Content.data}. + @param name: The attribute name + @type name: basestring + @param value: The attribute's value + @type value: basestring + @param content: The current content being unmarshalled. + @type content: L{Content} + """ + type = self.resolver.findattr(name) + if type is None: + log.warning('attribute (%s) type, not-found', name) + else: + value = self.translated(value, type) + Core.append_attribute(self, name, value, content) + + def append_text(self, content): + """ + Append text nodes into L{Content.data} + Here is where the I{true} type is used to translate the value + into the proper python type. + @param content: The current content being unmarshalled. + @type content: L{Content} + """ + Core.append_text(self, content) + known = self.resolver.top().resolved + content.text = self.translated(content.text, known) + + def translated(self, value, type): + """ translate using the schema type """ + if value is not None: + resolved = type.resolve() + return resolved.translate(value) + return value diff --git a/pym/calculate/contrib/suds/umx/typed.pyc b/pym/calculate/contrib/suds/umx/typed.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0558cd246db9769c1c972c6c11787a294603744b GIT binary patch literal 4758 zcmb_gU2_{r6}_Vm+mhwji8l*H0X1xqMY|B0rItV$YAZ`%Yqu(Bwq;0M2O1h(!J;KJJj--29 z=?V~I&whp2s3*~r{yukHqUeVB`853EN}*bXzx(au*YMKuhtuat8I~0Yr;xYf3o}m? z-@1R`Ww}t@cN#vv+6Hi?GGl_f{vJ`4V-!y0I^ZQ=i^M=7z@1Xa{t<=FqplAZ3GlBJ z*ixl9o0+lmI;foL;q{~zmo^>v*5HXM?^U7bP`8P=m)k?JKB(tFiz=Ax-0iTUQ~Rii z7IuKz*>aktCuix@xQjhF>Q{U@vnk%50x5}Ra34Ta@`~}t|2otfmc&rH2@PyWIsk(!vqr;8*9TP4?QyB zq)ZkUxR?cwXL6UgX@Rlx&|R4Da-IRA986zrA?T52FL2J48m=^EOF}XB0*|k3ayc-W znPc(6Z~Wg4#?`fP!fE&vTYhm>ET}?~t+v_p=Hh-rb$yp-i8a;reW~}owLxjzvdonc zfV?{O)^g=~sW)f#3A&>xKPqwu?IYfFL`=1J;h|KqsLNhX;HgzmWyXHyjffH5!my74TK&NG?*zLUO_UI%4mk_YIxPopO37{iivio=4?5M z=&PdJD3m^WvYYA8wSJAy5+4Z;0=4r!)Y+lh@8c{m@|gyeXM0jkNMo-*`&+dC6?hK+ zCqjWg2vnZ!ti^m(fDL)+S%)D2bN(7gj-@d(kQldfx}MOjB)M)=-2QrdxEUBv5Ug5j z$(~&6_G?5Bxb*CntlDyoU#xq`3S!d=>cIJW1^-oT;QOJ3yDhUj6u_38b*uu%GJ8i> zySmh_#CJK}`?uk?(@Fd90xM4}qBbmYqc^3bJD=uhbVz|aDD*B(Sr%nPf3DH$DGY2_ zxX+4Zp6d8tazrbwJqymW1Q`^!b)-Ril^e3SPb)?E0dg` z%@gO!>DkhmkY;o8Jjs?OoaU}T0I%ZLfOh$oKn{5ydtYCp-sB-oSeHEw8EGwc$|sv) zpAYDcZ>;kJ8*2APR+p+o|Myx|*z~J;uDY=549^U9-%du;t!S?6*VF5xZ}I`lK)E?+ z|DOFo)72k^dExG>QyO}ArRKZ`X?j=Ai0-1{JuGSXA}Mod;%MZqOmdqg&ZIs+psgi( zH*vjJpG@(z{0^tEsYs}YP}hDlmi`zE!v4ilBk9tM9XIZ5?2zrww0Ru)<^$Z;f(k zR{rsTk)_2O4g9UKRjJqcq+4(@lCcF|aY&;tkiL=yTcq#=ty#e|^Z!e#VV{KXSI>}J zT|Kez>D0G5tihC-y~a!qzUiqL4R6MQpJ0V6d_Gs)V^pgj5R7Je|8&&2OI+l$j+FP* z@oGrpV*)-(ZyN6F352S**7q=F>n4_#Hb~(8%g0~Z(4R-mqwYC>z%*d)r)M;P?k zG%>l^i3#Z6@mZRxG~hsZ`~6i82sbeXZq3yb5l7{_tM%tfx}Ek;qqEz&)oFFU(P`peyK}qK8}^ya zML$EKjNy|}&&0|AZ%4;dt{a0f{(Hhxu!$Bz~Z*$t_-IR+BqV^ZF=TuzU?f^kl#E_wxzg{g&L=X>@}wlCyV%qsCFt J1EG(a{{>BA27>?q literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/version.py b/pym/calculate/contrib/suds/version.py new file mode 100644 index 0000000..9fdfb67 --- /dev/null +++ b/pym/calculate/contrib/suds/version.py @@ -0,0 +1,26 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" +Module containing the library's version information. + + This version information has been extracted into a separate file so it can be +read from the setup.py script without having to import the suds package itself. +See the setup.py script for more detailed information. + +""" + +__version__ = "0.8.5" +__build__ = "" diff --git a/pym/calculate/contrib/suds/version.pyc b/pym/calculate/contrib/suds/version.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1029c483328335519f007d03f412adb1d9957ee4 GIT binary patch literal 486 zcmZuuy-ve05O!K95QNxZy#a|1kT5{i0U=%hmNIn-PJBr$5__wqsaZu6@rUy&4*n%(nA^e}j8N(COks zS15{vO_{_C#Jx%~1GGLM7?g3Fp|}5Y(V;BnE}16}EJVFd$AWw$kY&afS;nUW-)%+g zlflk=+n6kyilP31Zp0j1X>KfW(pcATZa4E;HoH%;s#22X)18. + + @ivar id: The object id. + @type id: str + @ivar options: An options dictionary. + @type options: L{options.Options} + @ivar url: The URL used to load the object. + @type url: str + @ivar tns: The target namespace for the WSDL. + @type tns: str + @ivar schema: The collective WSDL schema object. + @type schema: L{SchemaCollection} + @ivar children: The raw list of child objects. + @type children: [L{WObject},...] + @ivar imports: The list of L{Import} children. + @type imports: [L{Import},...] + @ivar messages: The dictionary of L{Message} children keyed by I{qname}. + @type messages: [L{Message},...] + @ivar port_types: The dictionary of L{PortType} children keyed by I{qname}. + @type port_types: [L{PortType},...] + @ivar bindings: The dictionary of L{Binding} children keyed by I{qname}. + @type bindings: [L{Binding},...] + @ivar service: The service object. + @type service: L{Service} + + """ + + Tag = "definitions" + + def __init__(self, url, options, imported_definitions=None): + """ + @param url: A URL to the WSDL. + @type url: str + @param options: An options dictionary. + @type options: L{options.Options} + + """ + log.debug("reading WSDL at: %s ...", url) + reader = DocumentReader(options) + d = reader.open(url) + root = d.root() + WObject.__init__(self, root) + self.id = objid(self) + self.options = options + self.url = url + self.tns = self.mktns(root) + self.types = [] + self.schema = None + self.children = [] + self.imports = [] + self.messages = {} + self.port_types = {} + self.bindings = {} + self.services = [] + self.add_children(self.root) + self.children.sort() + pmd = self.__metadata__.__print__ + pmd.excludes.append("children") + pmd.excludes.append("wsdl") + pmd.wrappers["schema"] = repr + if imported_definitions is None: + imported_definitions = {} + imported_definitions[url] = self + self.open_imports(imported_definitions) + self.resolve() + self.build_schema() + self.set_wrapped() + for s in self.services: + self.add_methods(s) + log.debug("WSDL at '%s' loaded:\n%s", url, self) + + def mktns(self, root): + """Get/create the target namespace.""" + tns = root.get("targetNamespace") + prefix = root.findPrefix(tns) + if prefix is None: + log.debug("warning: tns (%s), not mapped to prefix", tns) + prefix = "tns" + return (prefix, tns) + + def add_children(self, root): + """Add child objects using the factory.""" + for c in root.getChildren(ns=wsdlns): + child = Factory.create(c, self) + if child is None: continue + self.children.append(child) + if isinstance(child, Import): + self.imports.append(child) + continue + if isinstance(child, Types): + self.types.append(child) + continue + if isinstance(child, Message): + self.messages[child.qname] = child + continue + if isinstance(child, PortType): + self.port_types[child.qname] = child + continue + if isinstance(child, Binding): + self.bindings[child.qname] = child + continue + if isinstance(child, Service): + self.services.append(child) + continue + + def open_imports(self, imported_definitions): + """Import the I{imported} WSDLs.""" + for imp in self.imports: + imp.load(self, imported_definitions) + + def resolve(self): + """Tell all children to resolve themselves.""" + for c in self.children: + c.resolve(self) + + def build_schema(self): + """Process L{Types} objects and create the schema collection.""" + loaded_schemata = {} + container = SchemaCollection(self) + for t in (t for t in self.types if t.local()): + for root in t.contents(): + schema = Schema(root, self.url, self.options, loaded_schemata, container) + container.add(schema) + if not container: + root = Element.buildPath(self.root, "types/schema") + schema = Schema(root, self.url, self.options, loaded_schemata, container) + container.add(schema) + self.schema = container.load(self.options, loaded_schemata) + #TODO: Recheck this XSD schema merging. XSD schema imports are not + # supposed to be transitive. They only allow the importing schema to + # reference entities from the imported schema, but do not include them + # as their own content. + for s in (t.schema() for t in self.types if t.imported()): + self.schema.merge(s) + return self.schema + + def add_methods(self, service): + """Build method view for service.""" + bindings = { + "document/literal": Document(self), + "rpc/literal": RPC(self), + "rpc/encoded": Encoded(self)} + for p in service.ports: + binding = p.binding + ptype = p.binding.type + operations = p.binding.type.operations.values() + for name in (op.name for op in operations): + m = Facade("Method") + m.name = name + m.location = p.location + m.binding = Facade("binding") + op = binding.operation(name) + m.soap = op.soap + key = "/".join((op.soap.style, op.soap.input.body.use)) + m.binding.input = bindings.get(key) + key = "/".join((op.soap.style, op.soap.output.body.use)) + m.binding.output = bindings.get(key) + p.methods[name] = m + + def set_wrapped(self): + """Set (wrapped|bare) flag on messages.""" + for b in self.bindings.values(): + for op in b.operations.values(): + for body in (op.soap.input.body, op.soap.output.body): + body.wrapped = False + if not self.options.unwrap: + continue + if len(body.parts) != 1: + continue + for p in body.parts: + if p.element is None: + continue + query = ElementQuery(p.element) + pt = query.execute(self.schema) + if pt is None: + raise TypeNotFound(query.ref) + resolved = pt.resolve() + if resolved.builtin(): + continue + body.wrapped = True + + def __getstate__(self): + nopickle = ("options",) + state = self.__dict__.copy() + for k in nopickle: + if k in state: + del state[k] + return state + + def __repr__(self): + return "Definitions (id=%s)" % (self.id,) + + +class Import(WObject): + """ + Represents the . + + @ivar location: The value of the I{location} attribute. + @type location: str + @ivar ns: The value of the I{namespace} attribute. + @type ns: str + @ivar imported: The imported object. + @type imported: L{Definitions} + + """ + + def __init__(self, root, definitions): + """ + @param root: An XML root element. + @type root: L{Element} + @param definitions: A definitions object. + @type definitions: L{Definitions} + + """ + WObject.__init__(self, root) + self.location = root.get("location") + self.ns = root.get("namespace") + self.imported = None + pmd = self.__metadata__.__print__ + pmd.wrappers["imported"] = repr + + def load(self, definitions, imported_definitions): + """Load the object by opening the URL.""" + url = self.location + log.debug("importing (%s)", url) + if "://" not in url: + url = urljoin(definitions.url, url) + d = imported_definitions.get(url) + if not d: + d = Definitions(url, definitions.options, imported_definitions) + if d.root.match(Definitions.Tag, wsdlns): + self.import_definitions(definitions, d) + return + if d.root.match(Schema.Tag, Namespace.xsdns): + self.import_schema(definitions, d) + return + raise Exception("document at '%s' is unknown" % url) + + def import_definitions(self, definitions, d): + """Import/merge WSDL definitions.""" + definitions.types += d.types + definitions.messages.update(d.messages) + definitions.port_types.update(d.port_types) + definitions.bindings.update(d.bindings) + self.imported = d + log.debug("imported (WSDL):\n%s", d) + + def import_schema(self, definitions, d): + """Import schema as content.""" + if not definitions.types: + root = Element("types", ns=wsdlns) + definitions.root.insert(root) + types = Types(root, definitions) + definitions.types.append(types) + else: + types = definitions.types[-1] + types.root.append(d.root) + log.debug("imported (XSD):\n%s", d.root) + + def __gt__(self, other): + return False + + +class Types(WObject): + """Represents .""" + + def __init__(self, root, definitions): + """ + @param root: An XML root element. + @type root: L{Element} + @param definitions: A definitions object. + @type definitions: L{Definitions} + + """ + WObject.__init__(self, root) + self.definitions = definitions + + def contents(self): + return self.root.getChildren("schema", Namespace.xsdns) + + def schema(self): + return self.definitions.schema + + def local(self): + return self.definitions.schema is None + + def imported(self): + return not self.local() + + def __gt__(self, other): + return isinstance(other, Import) + + +class Part(NamedObject): + """ + Represents . + + @ivar element: The value of the {element} attribute. Stored as a I{qref} as + converted by L{suds.xsd.qualify}. + @type element: str + @ivar type: The value of the {type} attribute. Stored as a I{qref} as + converted by L{suds.xsd.qualify}. + @type type: str + + """ + + def __init__(self, root, definitions): + """ + @param root: An XML root element. + @type root: L{Element} + @param definitions: A definitions object. + @type definitions: L{Definitions} + + """ + NamedObject.__init__(self, root, definitions) + pmd = Metadata() + pmd.wrappers = dict(element=repr, type=repr) + self.__metadata__.__print__ = pmd + tns = definitions.tns + self.element = self.__getref("element", tns) + self.type = self.__getref("type", tns) + + def __getref(self, a, tns): + """Get the qualified value of attribute named 'a'.""" + s = self.root.get(a) + if s is not None: + return qualify(s, self.root, tns) + + +class Message(NamedObject): + """ + Represents . + + @ivar parts: A list of message parts. + @type parts: [I{Part},...] + + """ + + def __init__(self, root, definitions): + """ + @param root: An XML root element. + @type root: L{Element} + @param definitions: A definitions object. + @type definitions: L{Definitions} + + """ + NamedObject.__init__(self, root, definitions) + self.parts = [] + for p in root.getChildren("part"): + part = Part(p, definitions) + self.parts.append(part) + + def __gt__(self, other): + return isinstance(other, (Import, Types)) + + +class PortType(NamedObject): + """ + Represents . + + @ivar operations: A list of contained operations. + @type operations: list + + """ + + def __init__(self, root, definitions): + """ + @param root: An XML root element. + @type root: L{Element} + @param definitions: A definitions object. + @type definitions: L{Definitions} + + """ + NamedObject.__init__(self, root, definitions) + self.operations = {} + for c in root.getChildren("operation"): + op = Facade("Operation") + op.name = c.get("name") + op.tns = definitions.tns + input = c.getChild("input") + if input is None: + op.input = None + else: + op.input = input.get("message") + output = c.getChild("output") + if output is None: + op.output = None + else: + op.output = output.get("message") + faults = [] + for fault in c.getChildren("fault"): + f = Facade("Fault") + f.name = fault.get("name") + f.message = fault.get("message") + faults.append(f) + op.faults = faults + self.operations[op.name] = op + + def do_resolve(self, definitions): + """ + Resolve named references to other WSDL objects. + + @param definitions: A definitions object. + @type definitions: L{Definitions} + + """ + for op in self.operations.values(): + if op.input is None: + op.input = Message(Element("no-input"), definitions) + else: + qref = qualify(op.input, self.root, definitions.tns) + msg = definitions.messages.get(qref) + if msg is None: + raise Exception("msg '%s', not-found" % (op.input,)) + op.input = msg + if op.output is None: + op.output = Message(Element("no-output"), definitions) + else: + qref = qualify(op.output, self.root, definitions.tns) + msg = definitions.messages.get(qref) + if msg is None: + raise Exception("msg '%s', not-found" % (op.output,)) + op.output = msg + for f in op.faults: + qref = qualify(f.message, self.root, definitions.tns) + msg = definitions.messages.get(qref) + if msg is None: + raise Exception("msg '%s', not-found" % (f.message,)) + f.message = msg + + def operation(self, name): + """ + Shortcut used to get a contained operation by name. + + @param name: An operation name. + @type name: str + @return: The named operation. + @rtype: Operation + @raise L{MethodNotFound}: When not found. + + """ + try: + return self.operations[name] + except Exception as e: + raise MethodNotFound(name) + + def __gt__(self, other): + return isinstance(other, (Import, Types, Message)) + + +class Binding(NamedObject): + """ + Represents . + + @ivar operations: A list of contained operations. + @type operations: list + + """ + + def __init__(self, root, definitions): + """ + @param root: An XML root element. + @type root: L{Element} + @param definitions: A definitions object. + @type definitions: L{Definitions} + + """ + NamedObject.__init__(self, root, definitions) + self.operations = {} + self.type = root.get("type") + sr = self.soaproot() + if sr is None: + self.soap = None + log.debug("binding: '%s' not a SOAP binding", self.name) + return + soap = Facade("soap") + self.soap = soap + self.soap.style = sr.get("style", default="document") + self.add_operations(self.root, definitions) + + def soaproot(self): + """Get the soap:binding.""" + for ns in (soapns, soap12ns): + sr = self.root.getChild("binding", ns=ns) + if sr is not None: + return sr + + def add_operations(self, root, definitions): + """Add children.""" + dsop = Element("operation", ns=soapns) + for c in root.getChildren("operation"): + op = Facade("Operation") + op.name = c.get("name") + sop = c.getChild("operation", default=dsop) + soap = Facade("soap") + soap.action = '"%s"' % (sop.get("soapAction", default=""),) + soap.style = sop.get("style", default=self.soap.style) + soap.input = Facade("Input") + soap.input.body = Facade("Body") + soap.input.headers = [] + soap.output = Facade("Output") + soap.output.body = Facade("Body") + soap.output.headers = [] + op.soap = soap + input = c.getChild("input") + if input is None: + input = Element("input", ns=wsdlns) + body = input.getChild("body") + self.body(definitions, soap.input.body, body) + for header in input.getChildren("header"): + self.header(definitions, soap.input, header) + output = c.getChild("output") + if output is None: + output = Element("output", ns=wsdlns) + body = output.getChild("body") + self.body(definitions, soap.output.body, body) + for header in output.getChildren("header"): + self.header(definitions, soap.output, header) + faults = [] + for fault in c.getChildren("fault"): + sf = fault.getChild("fault") + if sf is None: + continue + fn = fault.get("name") + f = Facade("Fault") + f.name = sf.get("name", default=fn) + f.use = sf.get("use", default="literal") + faults.append(f) + soap.faults = faults + self.operations[op.name] = op + + def body(self, definitions, body, root): + """Add the input/output body properties.""" + if root is None: + body.use = "literal" + body.namespace = definitions.tns + body.parts = () + return + parts = root.get("parts") + if parts is None: + body.parts = () + else: + body.parts = re.split("[\\s,]", parts) + body.use = root.get("use", default="literal") + ns = root.get("namespace") + if ns is None: + body.namespace = definitions.tns + else: + prefix = root.findPrefix(ns, "b0") + body.namespace = (prefix, ns) + + def header(self, definitions, parent, root): + """Add the input/output header properties.""" + if root is None: + return + header = Facade("Header") + parent.headers.append(header) + header.use = root.get("use", default="literal") + ns = root.get("namespace") + if ns is None: + header.namespace = definitions.tns + else: + prefix = root.findPrefix(ns, "h0") + header.namespace = (prefix, ns) + msg = root.get("message") + if msg is not None: + header.message = msg + part = root.get("part") + if part is not None: + header.part = part + + def do_resolve(self, definitions): + """ + Resolve named references to other WSDL objects. This includes + cross-linking information (from) the portType (to) the I{SOAP} protocol + information on the binding for each operation. + + @param definitions: A definitions object. + @type definitions: L{Definitions} + + """ + self.__resolveport(definitions) + for op in self.operations.values(): + self.__resolvesoapbody(definitions, op) + self.__resolveheaders(definitions, op) + self.__resolvefaults(definitions, op) + + def __resolveport(self, definitions): + """ + Resolve port_type reference. + + @param definitions: A definitions object. + @type definitions: L{Definitions} + + """ + ref = qualify(self.type, self.root, definitions.tns) + port_type = definitions.port_types.get(ref) + if port_type is None: + raise Exception("portType '%s', not-found" % (self.type,)) + # Later on we will require access to the message data referenced by + # this port_type instance, and in order for those data references to be + # available, port_type first needs to dereference its message + # identification string. The only scenario where the port_type might + # possibly not have already resolved its references, and where this + # explicit resolve() call is required, is if we are dealing with a + # recursive WSDL import chain. + port_type.resolve(definitions) + self.type = port_type + + def __resolvesoapbody(self, definitions, op): + """ + Resolve SOAP body I{message} parts by cross-referencing with operation + defined in port type. + + @param definitions: A definitions object. + @type definitions: L{Definitions} + @param op: An I{operation} object. + @type op: I{operation} + + """ + ptop = self.type.operation(op.name) + if ptop is None: + raise Exception("operation '%s' not defined in portType" % ( + op.name,)) + soap = op.soap + parts = soap.input.body.parts + if parts: + pts = [] + for p in ptop.input.parts: + if p.name in parts: + pts.append(p) + soap.input.body.parts = pts + else: + soap.input.body.parts = ptop.input.parts + parts = soap.output.body.parts + if parts: + pts = [] + for p in ptop.output.parts: + if p.name in parts: + pts.append(p) + soap.output.body.parts = pts + else: + soap.output.body.parts = ptop.output.parts + + def __resolveheaders(self, definitions, op): + """ + Resolve SOAP header I{message} references. + + @param definitions: A definitions object. + @type definitions: L{Definitions} + @param op: An I{operation} object. + @type op: I{operation} + + """ + soap = op.soap + headers = soap.input.headers + soap.output.headers + for header in headers: + mn = header.message + ref = qualify(mn, self.root, definitions.tns) + message = definitions.messages.get(ref) + if message is None: + raise Exception("message '%s', not-found" % (mn,)) + pn = header.part + for p in message.parts: + if p.name == pn: + header.part = p + break + if pn == header.part: + raise Exception("message '%s' has not part named '%s'" % ( + ref, pn)) + + def __resolvefaults(self, definitions, op): + """ + Resolve SOAP fault I{message} references by cross-referencing with + operations defined in the port type. + + @param definitions: A definitions object. + @type definitions: L{Definitions} + @param op: An I{operation} object. + @type op: I{operation} + + """ + ptop = self.type.operation(op.name) + if ptop is None: + raise Exception("operation '%s' not defined in portType" % ( + op.name,)) + soap = op.soap + for fault in soap.faults: + for f in ptop.faults: + if f.name == fault.name: + fault.parts = f.message.parts + continue + if hasattr(fault, "parts"): + continue + raise Exception("fault '%s' not defined in portType '%s'" % ( + fault.name, self.type.name)) + + def operation(self, name): + """ + Shortcut used to get a contained operation by name. + + @param name: An operation name. + @type name: str + @return: The named operation. + @rtype: Operation + @raise L{MethodNotFound}: When not found. + + """ + try: + return self.operations[name] + except Exception: + raise MethodNotFound(name) + + def __gt__(self, other): + return not isinstance(other, Service) + + +class Port(NamedObject): + """ + Represents a service port. + + @ivar service: A service. + @type service: L{Service} + @ivar binding: A binding name. + @type binding: str + @ivar location: The service location (URL). + @type location: str + + """ + + def __init__(self, root, definitions, service): + """ + @param root: An XML root element. + @type root: L{Element} + @param definitions: A definitions object. + @type definitions: L{Definitions} + @param service: A service object. + @type service: L{Service} + + """ + NamedObject.__init__(self, root, definitions) + self.__service = service + self.binding = root.get("binding") + address = root.getChild("address") + self.location = address is not None and address.get("location") + self.methods = {} + + def method(self, name): + """ + Get a method defined in this portType by name. + + @param name: A method name. + @type name: str + @return: The requested method object. + @rtype: I{Method} + + """ + return self.methods.get(name) + + +class Service(NamedObject): + """ + Represents . + + @ivar port: The contained ports. + @type port: [Port,..] + @ivar methods: The contained methods for all ports. + @type methods: [Method,..] + + """ + + def __init__(self, root, definitions): + """ + @param root: An XML root element. + @type root: L{Element} + @param definitions: A definitions object. + @type definitions: L{Definitions} + + """ + NamedObject.__init__(self, root, definitions) + self.ports = [] + for p in root.getChildren("port"): + port = Port(p, definitions, self) + self.ports.append(port) + + def port(self, name): + """ + Locate a port by name. + + @param name: A port name. + @type name: str + @return: The port object. + @rtype: L{Port} + + """ + for p in self.ports: + if p.name == name: + return p + + def setlocation(self, url, names=None): + """ + Override the invocation location (URL) for service method. + + @param url: A URL location. + @type url: A URL. + @param names: A list of method names. None=ALL + @type names: [str,..] + + """ + for p in self.ports: + for m in p.methods.values(): + if names is None or m.name in names: + m.location = url + + def do_resolve(self, definitions): + """ + Resolve named references to other WSDL objects. Ports without SOAP + bindings are discarded. + + @param definitions: A definitions object. + @type definitions: L{Definitions} + + """ + filtered = [] + for p in self.ports: + ref = qualify(p.binding, self.root, definitions.tns) + binding = definitions.bindings.get(ref) + if binding is None: + raise Exception("binding '%s', not-found" % (p.binding,)) + if binding.soap is None: + log.debug("binding '%s' - not a SOAP binding, discarded", + binding.name) + continue + # After we have been resolved, our caller will expect that the + # binding we are referencing has been fully constructed, i.e. + # resolved, as well. The only scenario where the operations binding + # might possibly not have already resolved its references, and + # where this explicit resolve() call is required, is if we are + # dealing with a recursive WSDL import chain. + binding.resolve(definitions) + p.binding = binding + filtered.append(p) + self.ports = filtered + + def __gt__(self, other): + return True + + +class Factory: + """ + Simple WSDL object factory. + + @cvar tags: Dictionary of tag-->constructor mappings. + @type tags: dict + + """ + + tags = { + "import": Import, + "types": Types, + "message": Message, + "portType": PortType, + "binding": Binding, + "service": Service} + + @classmethod + def create(cls, root, definitions): + """ + Create an object based on the root tag name. + + @param root: An XML root element. + @type root: L{Element} + @param definitions: A definitions object. + @type definitions: L{Definitions} + @return: The created object. + @rtype: L{WObject} + + """ + fn = cls.tags.get(root.name) + if fn is not None: + return fn(root, definitions) diff --git a/pym/calculate/contrib/suds/wsdl.pyc b/pym/calculate/contrib/suds/wsdl.pyc new file mode 100644 index 0000000000000000000000000000000000000000..81772d07b746944f7d68925d3f8525687c6146d6 GIT binary patch literal 33180 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 R!Qr17{&P1l{DI+D{x_eKqgem| literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/wsse.py b/pym/calculate/contrib/suds/wsse.py new file mode 100644 index 0000000..96d9eb6 --- /dev/null +++ b/pym/calculate/contrib/suds/wsse.py @@ -0,0 +1,236 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +The I{wsse} module provides WS-Security. +""" + +from logging import getLogger +from suds import * +from suds.sudsobject import Object +from suds.sax.element import Element +from suds.sax.date import DateTime, UtcTimezone +from datetime import datetime, timedelta + +try: + from hashlib import md5 +except ImportError: + # Python 2.4 compatibility + from md5 import md5 + + +dsns = \ + ('ds', + 'http://www.w3.org/2000/09/xmldsig#') +wssens = \ + ('wsse', + 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd') +wsuns = \ + ('wsu', + 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd') +wsencns = \ + ('wsenc', + 'http://www.w3.org/2001/04/xmlenc#') + +nonce_encoding_type = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" +username_token_profile = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0" +wsdigest = "%s#PasswordDigest" % username_token_profile +wstext = "%s#PasswordText" % username_token_profile + + +class Security(Object): + """ + WS-Security object. + @ivar tokens: A list of security tokens + @type tokens: [L{Token},...] + @ivar signatures: A list of signatures. + @type signatures: TBD + @ivar references: A list of references. + @type references: TBD + @ivar keys: A list of encryption keys. + @type keys: TBD + """ + + def __init__(self): + """ """ + Object.__init__(self) + self.mustUnderstand = True + self.tokens = [] + self.signatures = [] + self.references = [] + self.keys = [] + + def xml(self): + """ + Get xml representation of the object. + @return: The root node. + @rtype: L{Element} + """ + root = Element('Security', ns=wssens) + root.set('mustUnderstand', str(self.mustUnderstand).lower()) + for t in self.tokens: + root.append(t.xml()) + return root + + +class Token(Object): + """ I{Abstract} security token. """ + + @classmethod + def now(cls): + return datetime.now() + + @classmethod + def utc(cls): + return datetime.utcnow().replace(tzinfo=UtcTimezone()) + + @classmethod + def sysdate(cls): + utc = DateTime(cls.utc()) + return str(utc) + + def __init__(self): + Object.__init__(self) + + +class UsernameToken(Token): + """ + Represents a basic I{UsernameToken} WS-Secuirty token. + @ivar username: A username. + @type username: str + @ivar password: A password. + @type password: str + @type password_digest: A password digest + @ivar nonce: A set of bytes to prevent replay attacks. + @type nonce: str + @ivar created: The token created. + @type created: L{datetime} + """ + + def __init__(self, username=None, password=None): + """ + @param username: A username. + @type username: str + @param password: A password. + @type password: str + """ + Token.__init__(self) + self.username = username + self.password = password + self.nonce = None + self.created = None + self.password_digest = None + self.nonce_has_encoding = False + + def setnonceencoding(self, value=False): + self.nonce_has_encoding = value + + def setpassworddigest(self, passwd_digest): + """ + Set password digest which is a text returned by + auth WS. + """ + self.password_digest = passwd_digest + + def setnonce(self, text=None): + """ + Set I{nonce} which is an arbitrary set of bytes to prevent replay + attacks. + @param text: The nonce text value. + Generated when I{None}. + @type text: str + """ + if text is None: + s = [] + s.append(self.username) + s.append(self.password) + s.append(Token.sysdate()) + m = md5() + m.update(':'.join(s).encode('utf-8')) + self.nonce = m.hexdigest() + else: + self.nonce = text + + def setcreated(self, dt=None): + """ + Set I{created}. + @param dt: The created date & time. + Set as datetime.utc() when I{None}. + @type dt: L{datetime} + """ + if dt is None: + self.created = Token.utc() + else: + self.created = dt + + def xml(self): + """ + Get xml representation of the object. + @return: The root node. + @rtype: L{Element} + """ + root = Element('UsernameToken', ns=wssens) + u = Element('Username', ns=wssens) + u.setText(self.username) + root.append(u) + p = Element('Password', ns=wssens) + p.setText(self.password) + if self.password_digest: + p.set("Type", wsdigest) + p.setText(self.password_digest) + else: + p.set("Type", wstext) + root.append(p) + if self.nonce is not None: + n = Element('Nonce', ns=wssens) + if self.nonce_has_encoding: + n.set("EncodingType", nonce_encoding_type) + n.setText(self.nonce) + root.append(n) + if self.created is not None: + n = Element('Created', ns=wsuns) + n.setText(str(DateTime(self.created))) + root.append(n) + return root + + +class Timestamp(Token): + """ + Represents the I{Timestamp} WS-Secuirty token. + @ivar created: The token created. + @type created: L{datetime} + @ivar expires: The token expires. + @type expires: L{datetime} + """ + + def __init__(self, validity=90): + """ + @param validity: The time in seconds. + @type validity: int + """ + Token.__init__(self) + self.created = Token.utc() + self.expires = self.created + timedelta(seconds=validity) + + def xml(self): + root = Element("Timestamp", ns=wsuns) + created = Element('Created', ns=wsuns) + created.setText(str(DateTime(self.created))) + expires = Element('Expires', ns=wsuns) + expires.setText(str(DateTime(self.expires))) + root.append(created) + root.append(expires) + return root diff --git a/pym/calculate/contrib/suds/wsse.pyc b/pym/calculate/contrib/suds/wsse.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5eaa922a79af06025129c91d2154c7c99642bddd GIT binary patch literal 8342 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 Yu6BAt;hwMh;NA~ZGxhm}`P1|IKMI2%-~a#s literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/xsd/__init__.py b/pym/calculate/contrib/suds/xsd/__init__.py new file mode 100644 index 0000000..c5d8015 --- /dev/null +++ b/pym/calculate/contrib/suds/xsd/__init__.py @@ -0,0 +1,75 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + + +from suds import * +from suds.sax import Namespace, splitPrefix + + +def qualify(ref, resolvers, defns=Namespace.default): + """ + Get a reference that is I{qualified} by namespace. + @param ref: A referenced schema type name. + @type ref: str + @param resolvers: A list of objects to be used to resolve types. + @type resolvers: [L{sax.element.Element},] + @param defns: An optional target namespace used to qualify references + when no prefix is specified. + @type defns: A default namespace I{tuple: (prefix,uri)} used when ref not prefixed. + @return: A qualified reference. + @rtype: (name, namespace-uri) + """ + ns = None + p, n = splitPrefix(ref) + if p is not None: + if not isinstance(resolvers, (list, tuple)): + resolvers = (resolvers,) + for r in resolvers: + resolved = r.resolvePrefix(p) + if resolved[1] is not None: + ns = resolved + break + if ns is None: + raise Exception('prefix (%s) not resolved' % p) + else: + ns = defns + return (n, ns[1]) + +def isqref(object): + """ + Get whether the object is a I{qualified reference}. + @param object: An object to be tested. + @type object: I{any} + @rtype: boolean + @see: L{qualify} + """ + return (\ + isinstance(object, tuple) and \ + len(object) == 2 and \ + isinstance(object[0], basestring) and \ + isinstance(object[1], basestring)) + + +class Filter: + def __init__(self, inclusive=False, *items): + self.inclusive = inclusive + self.items = items + def __contains__(self, x): + if self.inclusive: + result = ( x in self.items ) + else: + result = ( x not in self.items ) + return result diff --git a/pym/calculate/contrib/suds/xsd/__init__.pyc b/pym/calculate/contrib/suds/xsd/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..093e4cc477e000fcf04970d611b57891fe926256 GIT binary patch literal 2412 zcmb_d-EJF26h5QECf;3aSt)v`G~y3e^UwB2X>s-ElI>de_+* zw~peyp?MIvs>D4{#sie^oL$GxEn(#upP4yx{=YMgf7VuBefr05G1XrK|Bo>2kC+nt z6s1HzG38OJXyDP2M}r0(HArcXPMef8=t|Mi0wqnlB06eO0(yy(7B62D{d}}Y$s!%L zmm$-<#n)D#98aIOJtq0&AR1^pjAHHH!O9L({cc+6*iV}jbU!9pfb zqUcwT$|jWyG!cu=mZ|uYoJSKy4s1>8d-U2PyTdzuMWv#QX#6!VpSA3Ds7!}cg z?>+RtpIuLU8=vSw}$1Bo5uH6P@{4?hmCzIB0gLV+q;3byICVh-j3~E7`krqhYEa`t3@__NXxT z%1XCLhh%7QwF;foatrN7MaB`kPSVW4DG!GnlG&y0nPc}^g}7k2`0a<7Y6se%*?Xd` z4s>$RUc@O17s$vn9SBZVurk(U)x~*3LNA674qQ2!LRw zz8uxeg%u$ZFTjQfI@rdc%$dxEMz{`i{*;e)Tb z`uMnOM~Ur@ZPE=xlNlF=o#BOJ|LP2Hg0!DtqP3RVP^;<=#+q7J@2Zws0=?;h zA;Co!&0}+x_Oi}<1|mFin3kwqDMj%xZ6l;r}U z<#puneTBA2v};nQi^(7AoQ|w{sim-u(*xUPQGyz)(|+&)Rsm!1)=^-$r=|TE zwByJoXPA;u!TvWIhJ4p zn&@%2_GT4Q!!XV>7opXJ;V#xyX5rC>x31dKZz`v`#f71iSr`uTWR&uf8Fr)8>fj?# z0cU$=mQeq#X#|{qDIkt;ORY8zD!FV-m07eJ=~LWuI(Ux)4qw$ix#QFiLGT{$-r`gc3q=RZ}Pw|5yhKZo_7^bF~_KwX>a> zjV+LWxlfQM=sWfS+H+?m+cBh+tk}_fo_p@coNfPow|} zNT`-5BJqNIZBewuqAiZwBBHjSj<}4(aaX90_!HZELUluDOQ@bW8f-Dv2u=ThDk>F~ z*>dbnWeSt)EG?un)=Ryp3R+Oi6|Ocm@&9d2Svx-EDMp^1qloC!6s?7cZOm z5wH6RO)kVmB)kxp=(NQ76R{HFB;w)0%U$t%OI)}6RLZO6rSz5vzA(ZMx96pH zIHGjM4ySf07im@LGM8y7&GdvaFTKHz%oGI%*aZ77VBN6L>~w1*F}b=xFd4bBrXpJ` zLwrfeLOU?Ly+4I)@%a&O|a-c^v;&q0C&5|?*_S$x7Y@qrs0+X*dr%NK`I4_xjr76t}2u;?}hffXF zN#NPg{8s#`o89so|)7Qi%wUy?qd^^#Mc8zmJMS=Q2 zoN(cDV1Ffbj);?5li0W9Yg;~(FF1p^XxI~O+9<&8TfeO6SwL*A(x8oN?zwT~Jxc<% z+i=9Q6eJ9i*a1s}zlY|^m1V*u=zExJ429FUDH%CODqx<{(s!CeZh(Ig8utXfX{`%2 zo+`v>ROqrke|-Mk)8y&5W6JZftCbs{J2i$i1|L<++s1kNGvK&B<38v`+tH`dgDBf* z*p-gG!7?jTBu;z6-e&Y4)v^@m>(3BJwP&1&;DV)}MSc<8# zF()Xb5t@l_O8CgcoYt6Q7&C6ng%O7u;5lR^;neaH_c==;v!Qvf^ad8sf#*I#BU(FA zC%TK@y=W);IO-v@hmD7!C=+F}Bnd8Xsf0@98v%ih!)K0}B}oYhOOp5l3}P;mVC0(U e`?C$6KVKMC7xevyKn_*dYxP_Aqn-Bl7ykmPd?cO# literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/xsd/doctor.py b/pym/calculate/contrib/suds/xsd/doctor.py new file mode 100644 index 0000000..5a52e76 --- /dev/null +++ b/pym/calculate/contrib/suds/xsd/doctor.py @@ -0,0 +1,223 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +The I{doctor} module provides classes for fixing broken (sick) +schema(s). +""" + +from suds.sax import Namespace +from suds.sax.element import Element +from suds.plugin import DocumentPlugin, DocumentContext + +from logging import getLogger +log = getLogger(__name__) + + +class Doctor: + """ + Schema Doctor. + """ + def examine(self, root): + """ + Examine and repair the schema (if necessary). + @param root: A schema root element. + @type root: L{Element} + """ + pass + + +class Practice(Doctor): + """ + A collection of doctors. + @ivar doctors: A list of doctors. + @type doctors: list + """ + + def __init__(self): + self.doctors = [] + + def add(self, doctor): + """ + Add a doctor to the practice + @param doctor: A doctor to add. + @type doctor: L{Doctor} + """ + self.doctors.append(doctor) + + def examine(self, root): + for d in self.doctors: + d.examine(root) + return root + + +class TnsFilter: + """ + Target Namespace filter. + @ivar tns: A list of target namespaces. + @type tns: [str,...] + """ + + def __init__(self, *tns): + """ + @param tns: A list of target namespaces. + @type tns: [str,...] + """ + self.tns = [] + self.add(*tns) + + def add(self, *tns): + """ + Add I{targetNamespaces} to be added. + @param tns: A list of target namespaces. + @type tns: [str,...] + """ + self.tns += tns + + def match(self, root, ns): + """ + Match by I{targetNamespace} excluding those that + are equal to the specified namespace to prevent + adding an import to itself. + @param root: A schema root. + @type root: L{Element} + """ + tns = root.get('targetNamespace') + if len(self.tns): + matched = ( tns in self.tns ) + else: + matched = 1 + itself = ( ns == tns ) + return ( matched and not itself ) + + +class Import: + """ + An to be applied. + @cvar xsdns: The XSD namespace. + @type xsdns: (p,u) + @ivar ns: An import namespace. + @type ns: str + @ivar location: An optional I{schemaLocation}. + @type location: str + @ivar filter: A filter used to restrict application to + a particular schema. + @type filter: L{TnsFilter} + """ + + xsdns = Namespace.xsdns + + def __init__(self, ns, location=None): + """ + @param ns: An import namespace. + @type ns: str + @param location: An optional I{schemaLocation}. + @type location: str + """ + self.ns = ns + self.location = location + self.filter = TnsFilter() + + def setfilter(self, filter): + """ + Set the filter. + @param filter: A filter to set. + @type filter: L{TnsFilter} + """ + self.filter = filter + + def apply(self, root): + """ + Apply the import (rule) to the specified schema. + If the schema does not already contain an import for the + I{namespace} specified here, it is added. + @param root: A schema root. + @type root: L{Element} + """ + if not self.filter.match(root, self.ns): + return + if self.exists(root): + return + node = Element('import', ns=self.xsdns) + node.set('namespace', self.ns) + if self.location is not None: + node.set('schemaLocation', self.location) + log.debug('inserting: %s', node) + root.insert(node) + + def add(self, root): + """ + Add an to the specified schema root. + @param root: A schema root. + @type root: L{Element} + """ + node = Element('import', ns=self.xsdns) + node.set('namespace', self.ns) + if self.location is not None: + node.set('schemaLocation', self.location) + log.debug('%s inserted', node) + root.insert(node) + + def exists(self, root): + """ + Check to see if the already exists + in the specified schema root by matching I{namespace}. + @param root: A schema root. + @type root: L{Element} + """ + for node in root.children: + if node.name != 'import': + continue + ns = node.get('namespace') + if self.ns == ns: + return 1 + return 0 + + +class ImportDoctor(Doctor, DocumentPlugin): + """ + Doctor used to fix missing imports. + @ivar imports: A list of imports to apply. + @type imports: [L{Import},...] + """ + + def __init__(self, *imports): + self.imports = [] + self.add(*imports) + + def add(self, *imports): + """ + Add a namespace to be checked. + @param imports: A list of L{Import} objects. + @type imports: [L{Import},..] + """ + self.imports += imports + + def examine(self, node): + for imp in self.imports: + imp.apply(node) + + def parsed(self, context): + node = context.document + # xsd root + if node.name == 'schema' and Namespace.xsd(node.namespace()): + self.examine(node) + return + # look deeper + context = DocumentContext() + for child in node: + context.document = child + self.parsed(context) diff --git a/pym/calculate/contrib/suds/xsd/doctor.pyc b/pym/calculate/contrib/suds/xsd/doctor.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2bf48575785a494c6c091f5ac456858d9f0fec5b GIT binary patch literal 7780 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/xsd/query.py b/pym/calculate/contrib/suds/xsd/query.py new file mode 100644 index 0000000..8f2266b --- /dev/null +++ b/pym/calculate/contrib/suds/xsd/query.py @@ -0,0 +1,208 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +The I{query} module defines a class for performing schema queries. +""" + +from suds import * +from suds.sudsobject import * +from suds.xsd import qualify, isqref +from suds.xsd.sxbuiltin import Factory + +from logging import getLogger +log = getLogger(__name__) + + +class Query(Object): + """ + Schema query base class. + + """ + def __init__(self, ref=None): + """ + @param ref: The schema reference being queried. + @type ref: qref + """ + Object.__init__(self) + self.id = objid(self) + self.ref = ref + self.history = [] + self.resolved = False + if not isqref(self.ref): + raise Exception('%s, must be qref' % tostr(self.ref)) + + def execute(self, schema): + """ + Execute this query using the specified schema. + @param schema: The schema associated with the query. The schema is used + by the query to search for items. + @type schema: L{schema.Schema} + @return: The item matching the search criteria. + @rtype: L{sxbase.SchemaObject} + """ + raise Exception, 'not-implemented by subclass' + + def filter(self, result): + """ + Filter the specified result based on query criteria. + @param result: A potential result. + @type result: L{sxbase.SchemaObject} + @return: True if result should be excluded. + @rtype: boolean + """ + if result is None: + return True + reject = ( result in self.history ) + if reject: + log.debug('result %s, rejected by\n%s', Repr(result), self) + return reject + + def result(self, result): + """ + Query result post processing. + @param result: A query result. + @type result: L{sxbase.SchemaObject} + """ + if result is None: + log.debug('%s, not-found', self.ref) + return + if self.resolved: + result = result.resolve() + log.debug('%s, found as: %s', self.ref, Repr(result)) + self.history.append(result) + return result + + +class BlindQuery(Query): + """ + Schema query class that I{blindly} searches for a reference in the + specified schema. It may be used to find Elements and Types but will match + on an Element first. This query will also find builtins. + + """ + def execute(self, schema): + if schema.builtin(self.ref): + name = self.ref[0] + b = Factory.create(schema, name) + log.debug('%s, found builtin (%s)', self.id, name) + return b + result = None + for d in (schema.elements, schema.types): + result = d.get(self.ref) + if self.filter(result): + result = None + else: + break + if result is None: + eq = ElementQuery(self.ref) + eq.history = self.history + result = eq.execute(schema) + return self.result(result) + + +class TypeQuery(Query): + """ + Schema query class that searches for Type references in the specified + schema. Matches on root types only. + + """ + def execute(self, schema): + if schema.builtin(self.ref): + name = self.ref[0] + b = Factory.create(schema, name) + log.debug('%s, found builtin (%s)', self.id, name) + return b + result = schema.types.get(self.ref) + if self.filter(result): + result = None + return self.result(result) + + +class GroupQuery(Query): + """ + Schema query class that searches for Group references in the specified + schema. + + """ + def execute(self, schema): + result = schema.groups.get(self.ref) + if self.filter(result): + result = None + return self.result(result) + + +class AttrQuery(Query): + """ + Schema query class that searches for Attribute references in the specified + schema. Matches on root Attribute by qname first, then searches deeper into + the document. + + """ + def execute(self, schema): + result = schema.attributes.get(self.ref) + if self.filter(result): + result = self.__deepsearch(schema) + return self.result(result) + + def __deepsearch(self, schema): + from suds.xsd.sxbasic import Attribute + result = None + for e in schema.all: + result = e.find(self.ref, (Attribute,)) + if self.filter(result): + result = None + else: + break + return result + + +class AttrGroupQuery(Query): + """ + Schema query class that searches for attributeGroup references in the + specified schema. + + """ + def execute(self, schema): + result = schema.agrps.get(self.ref) + if self.filter(result): + result = None + return self.result(result) + + +class ElementQuery(Query): + """ + Schema query class that searches for Element references in the specified + schema. Matches on root Elements by qname first, then searches deeper into + the document. + + """ + def execute(self, schema): + result = schema.elements.get(self.ref) + if self.filter(result): + result = self.__deepsearch(schema) + return self.result(result) + + def __deepsearch(self, schema): + from suds.xsd.sxbasic import Element + result = None + for e in schema.all: + result = e.find(self.ref, (Element,)) + if self.filter(result): + result = None + else: + break + return result diff --git a/pym/calculate/contrib/suds/xsd/query.pyc b/pym/calculate/contrib/suds/xsd/query.pyc new file mode 100644 index 0000000000000000000000000000000000000000..58704cf488a5ea29864c66d08219fdcd6b59d9b3 GIT binary patch literal 7584 zcmdT}&vP6{8SUBCuC!~(lI29iBtU~>SioK<5FBt)lRw)}xLQ@kRW)2t+Y4$~Q`uR{Dwin%fO~p%U*ihRI<(Y;uP4&=I+h-Gvnp&(t!E1BstT8<)|JA#royvR>uO;=r^2A|5MCgCJDIyC)gWULN!FAl8L{Up_6lj6@X8V$7V?U-Sp`A%eP zyBYl(zm|vIG8SKJRajj_u{R0gsDF^vQIG6iYWl7jpWO|5S&|+&Lj#6^$=*l?1CwSo z-2H?zD*VPCZ{f1vLSf)HY%I!(3Tt%WBkcJC-H5G*r^2dK>U0+^i^|_>aSrw(il)YI zt6al@?grMlrM8>$w8!yyE#P_$m+hm-l-l*w19;O@URKF#xbIZe19{L{Py3xI zRu)yZ#LDghU$b46H8|s}SsFL+;9XCRfW-=YQ{{MXqL8U@vNy&-8VohI@4BYHatGkv zq-NAJx@+hc=a8^nzLy=0jeCuIU)b#$dcR~Z>*2&^cvs$Zh&jch~eX%p3FX zM58F{bi^k~cQ*>La5yu}I8D4Je%^^JeJPFZ2C+5rZfa~2|H6bm-@vk!y0hOi<19)> z(lSeImO8L-pRI}eeiM}zE?3w#YTZc`hgZ8H#%RaUXtIB0|J&C(*Iv4627{}1656Z# zHoPhbZjTRqVvBCJXHlryinr=D|qqdAT@0>4#}zRT7HaMZWLZmCq_s8yfyfI*Gxi(_6v%`T%*OUvE@q@wOUSIPwAkjTW_sFVn~NQ3|y00M=* zsvcI548Z?R=F?Z$cDKf$e<-q^H%F9^=8O!29zutvMYW3Gc)i4tgu|(y z#t=?DPLrOo6rvdv90!cZO8(kRvrhsROO2#w$>V-98HJlg{E%B6*z5X|ZBgL;^DLNM z_!}%J=e~$6Wf^W{K=409YY}aN@z{*QlK=iQc>F{TmL9&3USy)GzU-Zca~p8)bKaV_ z*;>M*Ji3j7p+R)xJUbni{@|9A?R3JV*Xg(w(crJM_$-T~GnBc`6RL=>&*QQjzP?cR zmRA~Q8mls!TL^Wbc)f>*@?&y!3zy~o9Z7jL*}tI>hC02U3XCLk*-nrl zR>7mTKD@nVX|j?h1u&SUn;3#Ozcfd&4Nyn<%3c=e2wSPzY6k_f+RKKEb zzxARzg!0$auFKwJBs66YXVe49@Y45~nZmdisvqO}8O$&+viwzL%jFCYB|qF zBjxVdTmcXaEL{c20%C-)||Is#T<5b^A#25H9( zKMT$Z9Zc>$mz~jjlI0;W7uaL=Na0)?L8frn(Lxv@Ea4RVa~zTWA;08Q&=t~1)uoVT z@5wk$HU_w?MxnfQZw1!|cwYA|poXlkQuCJacNur0sQ%~B&?n*iFR)+_IPLkmo6 zfGM}=c6bDf$1`7}zeMP~Pc#{W6C66$dQ5PVC>z zvh+iouJPDF(25T%)7%1)@)7I{OftAH_Kzq|?tKm!As3ims>&X4g4|G*A@ zjc+?``Nk0S{1;)Ad|c9!AdV%)VB+bdp6qQMQ*U{PvM#BIDdYVd@+}F_tgC*EZOnogfGX>3?0@e~)oz2zI&={bdaHJ_np?yZ>d}^>E3rI4)}3o=npJfR-nB zetr}CSgUWZeG- z_l!B4`;78U)?Q*!WLwAeS{hTYeg0QZsg(1GOP}=mj^1#kX)}cy(W(4Yn3%` Txw`S{# + node. + + @ivar wsdl: A WSDL object. + @type wsdl: L{suds.wsdl.Definitions} + @ivar children: A list contained schemas. + @type children: [L{Schema},...] + @ivar namespaces: A dictionary of contained schemas by namespace. + @type namespaces: {str: L{Schema}} + + """ + + def __init__(self, wsdl): + """ + @param wsdl: A WSDL object. + @type wsdl: L{suds.wsdl.Definitions} + + """ + self.wsdl = wsdl + self.children = [] + self.namespaces = {} + + def add(self, schema): + """ + Add a schema node to the collection. Schema(s) within the same target + namespace are consolidated. + + @param schema: A schema object. + @type schema: (L{Schema}) + + """ + key = schema.tns[1] + existing = self.namespaces.get(key) + if existing is None: + self.children.append(schema) + self.namespaces[key] = schema + else: + existing.root.children += schema.root.children + existing.root.nsprefixes.update(schema.root.nsprefixes) + + def load(self, options, loaded_schemata): + """ + Load schema objects for the root nodes. + - de-reference schemas + - merge schemas + + @param options: An options dictionary. + @type options: L{options.Options} + @param loaded_schemata: Already loaded schemata cache (URL --> Schema). + @type loaded_schemata: dict + @return: The merged schema. + @rtype: L{Schema} + + """ + if options.autoblend: + self.autoblend() + for child in self.children: + child.build() + for child in self.children: + child.open_imports(options, loaded_schemata) + for child in self.children: + child.dereference() + log.debug("loaded:\n%s", self) + merged = self.merge() + log.debug("MERGED:\n%s", merged) + return merged + + def autoblend(self): + """ + Ensure that all schemas within the collection import each other which + has a blending effect. + + @return: self + @rtype: L{SchemaCollection} + + """ + namespaces = self.namespaces.keys() + for s in self.children: + for ns in namespaces: + tns = s.root.get("targetNamespace") + if tns == ns: + continue + for imp in s.root.getChildren("import"): + if imp.get("namespace") == ns: + continue + imp = Element("import", ns=Namespace.xsdns) + imp.set("namespace", ns) + s.root.append(imp) + return self + + def locate(self, ns): + """ + Find a schema by namespace. Only the URI portion of the namespace is + compared to each schema's I{targetNamespace}. + + @param ns: A namespace. + @type ns: (prefix, URI) + @return: The schema matching the namespace, else None. + @rtype: L{Schema} + + """ + return self.namespaces.get(ns[1]) + + def merge(self): + """ + Merge contained schemas into one. + + @return: The merged schema. + @rtype: L{Schema} + + """ + if self.children: + schema = self.children[0] + for s in self.children[1:]: + schema.merge(s) + return schema + + def __len__(self): + return len(self.children) + + def __unicode__(self): + result = ["\nschema collection"] + for s in self.children: + result.append(s.str(1)) + return "\n".join(result) + + +class Schema(UnicodeMixin): + """ + The schema is an objectification of a (XSD) definition. It + provides inspection, lookup and type resolution. + + @ivar root: The root node. + @type root: L{sax.element.Element} + @ivar baseurl: The I{base} URL for this schema. + @type baseurl: str + @ivar container: A schema collection containing this schema. + @type container: L{SchemaCollection} + @ivar children: A list of direct top level children. + @type children: [L{SchemaObject},...] + @ivar all: A list of all (includes imported) top level children. + @type all: [L{SchemaObject},...] + @ivar types: A schema types cache. + @type types: {name:L{SchemaObject}} + @ivar imports: A list of import objects. + @type imports: [L{SchemaObject},...] + @ivar elements: A list of objects. + @type elements: [L{SchemaObject},...] + @ivar attributes: A list of objects. + @type attributes: [L{SchemaObject},...] + @ivar groups: A list of group objects. + @type groups: [L{SchemaObject},...] + @ivar agrps: A list of attribute group objects. + @type agrps: [L{SchemaObject},...] + @ivar form_qualified: The flag indicating: (@elementFormDefault). + @type form_qualified: bool + + """ + + Tag = "schema" + + def __init__(self, root, baseurl, options, loaded_schemata=None, + container=None): + """ + @param root: The XML root. + @type root: L{sax.element.Element} + @param baseurl: The base URL used for importing. + @type baseurl: basestring + @param options: An options dictionary. + @type options: L{options.Options} + @param loaded_schemata: An optional already loaded schemata cache (URL + --> Schema). + @type loaded_schemata: dict + @param container: An optional container. + @type container: L{SchemaCollection} + + """ + self.root = root + self.id = objid(self) + self.tns = self.mktns() + self.baseurl = baseurl + self.container = container + self.children = [] + self.all = [] + self.types = {} + self.imports = [] + self.elements = {} + self.attributes = {} + self.groups = {} + self.agrps = {} + if options.doctor is not None: + options.doctor.examine(root) + form = self.root.get("elementFormDefault") + self.form_qualified = form == "qualified" + + # If we have a container, that container is going to take care of + # finishing our build for us in parallel with building all the other + # schemata in that container. That allows the different schema within + # the same container to freely reference each other. + #TODO: check whether this container content build parallelization is + # really necessary or if we can simply build our top-level WSDL + # contained schemata one by one as they are loaded + if container is None: + if loaded_schemata is None: + loaded_schemata = {} + loaded_schemata[baseurl] = self + #TODO: It seems like this build() step can be done for each schema + # on its own instead of letting the container do it. Building our + # XSD schema objects should not require any external schema + # information and even references between XSD schema objects within + # the same schema can not be established until all the XSD schema + # objects have been built. The only reason I can see right now why + # this step has been placed under container control is so our + # container (a SchemaCollection instance) can add some additional + # XML elements to our schema before our XSD schema object entities + # get built, but there is bound to be a cleaner way to do this, + # similar to how we support such XML modifications in suds plugins. + self.build() + self.open_imports(options, loaded_schemata) + log.debug("built:\n%s", self) + self.dereference() + log.debug("dereferenced:\n%s", self) + + def mktns(self): + """ + Make the schema's target namespace. + + @return: namespace representation of the schema's targetNamespace + value. + @rtype: (prefix, URI) + + """ + tns = self.root.get("targetNamespace") + tns_prefix = None + if tns is not None: + tns_prefix = self.root.findPrefix(tns) + return tns_prefix, tns + + def build(self): + """ + Build the schema (object graph) using the root node using the factory. + - Build the graph. + - Collate the children. + + """ + self.children = BasicFactory.build(self.root, self) + collated = BasicFactory.collate(self.children) + self.children = collated[0] + self.attributes = collated[2] + self.imports = collated[1] + self.elements = collated[3] + self.types = collated[4] + self.groups = collated[5] + self.agrps = collated[6] + + def merge(self, schema): + """ + Merge the schema contents. + + Only objects not already contained in this schema's collections are + merged. This provides support for bidirectional imports producing + cyclic includes. + + @returns: self + @rtype: L{Schema} + + """ + for item in schema.attributes.items(): + if item[0] in self.attributes: + continue + self.all.append(item[1]) + self.attributes[item[0]] = item[1] + for item in schema.elements.items(): + if item[0] in self.elements: + continue + self.all.append(item[1]) + self.elements[item[0]] = item[1] + for item in schema.types.items(): + if item[0] in self.types: + continue + self.all.append(item[1]) + self.types[item[0]] = item[1] + for item in schema.groups.items(): + if item[0] in self.groups: + continue + self.all.append(item[1]) + self.groups[item[0]] = item[1] + for item in schema.agrps.items(): + if item[0] in self.agrps: + continue + self.all.append(item[1]) + self.agrps[item[0]] = item[1] + schema.merged = True + return self + + def open_imports(self, options, loaded_schemata): + """ + Instruct all contained L{sxbasic.Import} children to import all of + their referenced schemas. The imported schema contents are I{merged} + in. + + @param options: An options dictionary. + @type options: L{options.Options} + @param loaded_schemata: Already loaded schemata cache (URL --> Schema). + @type loaded_schemata: dict + + """ + for imp in self.imports: + imported = imp.open(options, loaded_schemata) + if imported is None: + continue + imported.open_imports(options, loaded_schemata) + log.debug("imported:\n%s", imported) + self.merge(imported) + + def dereference(self): + """Instruct all children to perform dereferencing.""" + all = [] + indexes = {} + for child in self.children: + child.content(all) + dependencies = {} + for x in all: + x.qualify() + midx, deps = x.dependencies() + dependencies[x] = deps + indexes[x] = midx + for x, deps in dependency_sort(dependencies): + midx = indexes.get(x) + if midx is None: + continue + d = deps[midx] + log.debug("(%s) merging %s <== %s", self.tns[1], Repr(x), Repr(d)) + x.merge(d) + + def locate(self, ns): + """ + Find a schema by namespace. Only the URI portion of the namespace is + compared to each schema's I{targetNamespace}. The request is passed on + to the container. + + @param ns: A namespace. + @type ns: (prefix, URI) + @return: The schema matching the namespace, else None. + @rtype: L{Schema} + + """ + if self.container is not None: + return self.container.locate(ns) + + def custom(self, ref, context=None): + """ + Get whether the specified reference is B{not} an (xs) builtin. + + @param ref: A str or qref. + @type ref: (str|qref) + @return: True if B{not} a builtin, else False. + @rtype: bool + + """ + return ref is None or not self.builtin(ref, context) + + def builtin(self, ref, context=None): + """ + Get whether the specified reference is an (xs) builtin. + + @param ref: A str or qref. + @type ref: (str|qref) + @return: True if builtin, else False. + @rtype: bool + + """ + w3 = "http://www.w3.org" + try: + if isqref(ref): + ns = ref[1] + return ref[0] in Factory.tags and ns.startswith(w3) + if context is None: + context = self.root + prefix = splitPrefix(ref)[0] + prefixes = context.findPrefixes(w3, "startswith") + return prefix in prefixes and ref[0] in Factory.tags + except Exception: + return False + + def instance(self, root, baseurl, loaded_schemata, options): + """ + Create and return an new schema object using the specified I{root} and + I{URL}. + + @param root: A schema root node. + @type root: L{sax.element.Element} + @param baseurl: A base URL. + @type baseurl: str + @param loaded_schemata: Already loaded schemata cache (URL --> Schema). + @type loaded_schemata: dict + @param options: An options dictionary. + @type options: L{options.Options} + @return: The newly created schema object. + @rtype: L{Schema} + @note: This is only used by Import children. + + """ + return Schema(root, baseurl, options, loaded_schemata) + + def str(self, indent=0): + tab = "%*s" % (indent * 3, "") + result = [] + result.append("%s%s" % (tab, self.id)) + result.append("%s(raw)" % (tab,)) + result.append(self.root.str(indent + 1)) + result.append("%s(model)" % (tab,)) + for c in self.children: + result.append(c.str(indent + 1)) + result.append("") + return "\n".join(result) + + def __repr__(self): + return '<%s tns="%s"/>' % (self.id, self.tns[1]) + + def __unicode__(self): + return self.str() diff --git a/pym/calculate/contrib/suds/xsd/schema.pyc b/pym/calculate/contrib/suds/xsd/schema.pyc new file mode 100644 index 0000000000000000000000000000000000000000..56a350306701f2edd912e93eeb6fe9cf437efe17 GIT binary patch literal 15024 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 1 + return max == "unbounded" + + def optional(self): + """ + Get whether this type is optional. + + @return: True if optional, else False. + @rtype: boolean + + """ + return self.min == "0" + + def required(self): + """ + Get whether this type is required. + + @return: True if required, else False. + @rtype: boolean + + """ + return not self.optional() + + def resolve(self, nobuiltin=False): + """ + Resolve the node's type reference and return the referenced type node. + + Only XSD schema objects that actually support 'having a type' custom + implement this interface while others simply resolve as themselves. + + @param nobuiltin: Flag indicating whether resolving to an external XSD + built-in type should not be allowed. + @return: The resolved (true) type. + @rtype: L{SchemaObject} + """ + return self + + def sequence(self): + """ + Get whether this is an . + + @return: True if , else False. + @rtype: boolean + + """ + return False + + def xslist(self): + """ + Get whether this is an . + + @return: True if , else False. + @rtype: boolean + + """ + return False + + def all(self): + """ + Get whether this is an . + + @return: True if , else False. + @rtype: boolean + + """ + return False + + def choice(self): + """ + Get whether this is an . + + @return: True if , else False. + @rtype: boolean + + """ + return False + + def any(self): + """ + Get whether this is an . + + @return: True if , else False. + @rtype: boolean + + """ + return False + + def builtin(self): + """ + Get whether this is a built-in schema-instance XSD type. + + @return: True if a built-in type, else False. + @rtype: boolean + + """ + return False + + def enum(self): + """ + Get whether this is a simple-type containing an enumeration. + + @return: True if enumeration, else False. + @rtype: boolean + + """ + return False + + def isattr(self): + """ + Get whether the object is a schema I{attribute} definition. + + @return: True if an attribute, else False. + @rtype: boolean + + """ + return False + + def extension(self): + """ + Get whether the object is an extension of another type. + + @return: True if an extension, else False. + @rtype: boolean + + """ + return False + + def restriction(self): + """ + Get whether the object is an restriction of another type. + + @return: True if a restriction, else False. + @rtype: boolean + + """ + return False + + def mixed(self): + """Get whether the object has I{mixed} content.""" + return False + + def find(self, qref, classes=[], ignore=None): + """ + Find a referenced type in self or children. Return None if not found. + + Qualified references for all schema objects checked in this search will + be added to the set of ignored qualified references to avoid the find + operation going into an infinite loop in case of recursively defined + structures. + + @param qref: A qualified reference. + @type qref: qref + @param classes: A collection of classes used to qualify the match. + @type classes: Collection(I{class},...), e.g. [I(class),...] + @param ignore: A set of qualified references to ignore in this search. + @type ignore: {qref,...} + @return: The referenced type. + @rtype: L{SchemaObject} + @see: L{qualify()} + + """ + if not len(classes): + classes = (self.__class__,) + if ignore is None: + ignore = set() + if self.qname in ignore: + return + ignore.add(self.qname) + if self.qname == qref and self.__class__ in classes: + return self + for c in self.rawchildren: + p = c.find(qref, classes, ignore=ignore) + if p is not None: + return p + + def translate(self, value, topython=True): + """ + Translate between an XSD type values and Python objects. + + When converting a Python object to an XSD type value the operation may + return any Python object whose string representation matches the + desired XSD type value. + + @param value: A value to translate. + @type value: str if topython is True; any Python object otherwise + @param topython: Flag indicating the translation direction. + @type topython: bool + @return: The converted I{language} type. + + """ + return value + + def childtags(self): + """ + Get a list of valid child tag names. + + @return: A list of child tag names. + @rtype: [str,...] + + """ + return () + + def dependencies(self): + """ + Get a list of dependencies for dereferencing. + + @return: A merge dependency index and a list of dependencies. + @rtype: (int, [L{SchemaObject},...]) + + """ + return None, [] + + def autoqualified(self): + """ + The list of I{auto} qualified attribute values. + + Qualification means to convert values into I{qref}. + + @return: A list of attribute names. + @rtype: list + + """ + return ["type", "ref"] + + def qualify(self): + """ + Convert reference attribute values into a I{qref}. + + Constructed I{qref} uses the default document namespace. Since many + WSDL schemas are written improperly: when the document does not define + its default namespace, the schema target namespace is used to qualify + references. + + """ + defns = self.root.defaultNamespace() + if Namespace.none(defns): + defns = self.schema.tns + for a in self.autoqualified(): + ref = getattr(self, a) + if ref is None: + continue + if isqref(ref): + continue + qref = qualify(ref, self.root, defns) + log.debug("%s, convert %s='%s' to %s", self.id, a, ref, qref) + setattr(self, a, qref) + + def merge(self, other): + """Merge another object as needed.""" + other.qualify() + for n in ("default", "max", "min", "name", "nillable", "qname", + "type"): + if getattr(self, n) is not None: + continue + v = getattr(other, n) + if v is None: + continue + setattr(self, n, v) + + def content(self, collection=None, filter=Filter(), history=None): + """ + Get a I{flattened} list of this node's contents. + + @param collection: A list to fill. + @type collection: list + @param filter: A filter used to constrain the result. + @type filter: L{Filter} + @param history: The history list used to prevent cyclic dependency. + @type history: list + @return: The filled list. + @rtype: list + + """ + if collection is None: + collection = [] + if history is None: + history = [] + if self in history: + return collection + history.append(self) + if self in filter: + collection.append(self) + for c in self.rawchildren: + c.content(collection, filter, history) + history.pop() + return collection + + def str(self, indent=0, history=None): + """ + Get a string representation of this object. + + @param indent: The indent. + @type indent: int + @return: A string. + @rtype: str + + """ + if history is None: + history = [] + if self in history: + return "%s ..." % Repr(self) + history.append(self) + tab = "%*s" % (indent * 3, "") + result = ["%s<%s" % (tab, self.id)] + for n in self.description(): + if not hasattr(self, n): + continue + v = getattr(self, n) + if v is None: + continue + result.append(' %s="%s"' % (n, v)) + if len(self): + result.append(">") + for c in self.rawchildren: + result.append("\n") + result.append(c.str(indent+1, history[:])) + if c.isattr(): + result.append("@") + result.append("\n%s" % (tab,)) + result.append("" % (self.__class__.__name__,)) + else: + result.append(" />") + return "".join(result) + + def description(self): + """ + Get the names used for repr() and str() description. + + @return: A dictionary of relevant attributes. + @rtype: [str,...] + + """ + return () + + def __unicode__(self): + return unicode(self.str()) + + def __repr__(self): + s = [] + s.append("<%s" % (self.id,)) + for n in self.description(): + if not hasattr(self, n): + continue + v = getattr(self, n) + if v is None: + continue + s.append(' %s="%s"' % (n, v)) + s.append(" />") + return "".join(s) + + def __len__(self): + n = 0 + for x in self: + n += 1 + return n + + def __iter__(self): + return Iter(self) + + def __getitem__(self, index): + """ + Returns a contained schema object referenced by its 0-based index. + + Returns None if such an object does not exist. + + """ + i = 0 + for c in self: + if i == index: + return c + i += 1 + + +class Iter: + """ + The content iterator - used to iterate the L{Content} children. + + The iterator provides a I{view} of the children that is free of container + elements such as , or . + + @ivar stack: A stack used to control nesting. + @type stack: list + + """ + + class Frame: + """A content iterator frame.""" + + def __init__(self, sx): + """ + @param sx: A schema object. + @type sx: L{SchemaObject} + + """ + self.sx = sx + self.items = sx.rawchildren + self.index = 0 + + def next(self): + """ + Get the I{next} item in the frame's collection. + + @return: The next item or None + @rtype: L{SchemaObject} + + """ + if self.index < len(self.items): + result = self.items[self.index] + self.index += 1 + return result + + def __init__(self, sx): + """ + @param sx: A schema object. + @type sx: L{SchemaObject} + + """ + self.stack = [] + self.push(sx) + + def push(self, sx): + """ + Create a frame and push the specified object. + + @param sx: A schema object to push. + @type sx: L{SchemaObject} + + """ + self.stack.append(Iter.Frame(sx)) + + def pop(self): + """ + Pop the I{top} frame. + + @return: The popped frame. + @rtype: L{Frame} + @raise StopIteration: when stack is empty. + + """ + if self.stack: + return self.stack.pop() + raise StopIteration() + + def top(self): + """ + Get the I{top} frame. + + @return: The top frame. + @rtype: L{Frame} + @raise StopIteration: when stack is empty. + + """ + if self.stack: + return self.stack[-1] + raise StopIteration() + + def next(self): + """ + Get the next item. + + @return: A tuple: the next (child, ancestry). + @rtype: (L{SchemaObject}, [L{SchemaObject},..]) + @raise StopIteration: A the end. + + """ + frame = self.top() + while True: + result = frame.next() + if result is None: + self.pop() + return self.next() + if isinstance(result, Content): + ancestry = [f.sx for f in self.stack] + return result, ancestry + self.push(result) + return self.next() + + def __iter__(self): + return self + + +class XBuiltin(SchemaObject): + """Represents a built-in XSD schema node.""" + + def __init__(self, schema, name): + """ + @param schema: The containing schema. + @type schema: L{schema.Schema} + + """ + root = Element(name) + SchemaObject.__init__(self, schema, root) + self.name = name + self.nillable = True + + def namespace(self, prefix=None): + return Namespace.xsdns + + def builtin(self): + return True + + +class Content(SchemaObject): + """XSD schema objects representing real XML document content.""" + pass + + +class NodeFinder: + """ + Find nodes based on flexable criteria. + + I{matcher} may be any object implementing a match(n) method. + + @ivar matcher: An object used as criteria for match. + @type matcher: I{any}.match(n) + @ivar limit: Limit the number of matches. 0=unlimited. + @type limit: int + + """ + def __init__(self, matcher, limit=0): + """ + @param matcher: An object used as criteria for match. + @type matcher: I{any}.match(n) + @param limit: Limit the number of matches. 0=unlimited. + @type limit: int + + """ + self.matcher = matcher + self.limit = limit + + def find(self, node, list): + """ + Traverse the tree looking for matches. + + @param node: A node to match on. + @type node: L{SchemaObject} + @param list: A list to fill. + @type list: list + + """ + if self.matcher.match(node): + list.append(node) + self.limit -= 1 + if self.limit == 0: + return + for c in node.rawchildren: + self.find(c, list) + return self diff --git a/pym/calculate/contrib/suds/xsd/sxbase.pyc b/pym/calculate/contrib/suds/xsd/sxbase.pyc new file mode 100644 index 0000000000000000000000000000000000000000..30dd78095efb350d46608ca4cefe4612581e5c29 GIT binary patch literal 24709 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 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/xsd/sxbasic.py b/pym/calculate/contrib/suds/xsd/sxbasic.py new file mode 100644 index 0000000..0f659ba --- /dev/null +++ b/pym/calculate/contrib/suds/xsd/sxbasic.py @@ -0,0 +1,862 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the (LGPL) GNU Lesser General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License +# for more details at ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +"""Classes representing I{basic} XSD schema objects.""" + +from suds import * +from suds.reader import DocumentReader +from suds.sax import Namespace +from suds.transport import TransportError +from suds.xsd import * +from suds.xsd.query import * +from suds.xsd.sxbase import * + +from urlparse import urljoin + +from logging import getLogger +log = getLogger(__name__) + + +class RestrictionMatcher: + """For use with L{NodeFinder} to match restriction.""" + def match(self, n): + return isinstance(n, Restriction) + + +class TypedContent(Content): + """Represents any I{typed} content.""" + + def __init__(self, *args, **kwargs): + Content.__init__(self, *args, **kwargs) + self.resolved_cache = {} + + def resolve(self, nobuiltin=False): + """ + Resolve the node's type reference and return the referenced type node. + + Returns self if the type is defined locally, e.g. as a + subnode. Otherwise returns the referenced external node. + + @param nobuiltin: Flag indicating whether resolving to XSD built-in + types should not be allowed. + @return: The resolved (true) type. + @rtype: L{SchemaObject} + + """ + cached = self.resolved_cache.get(nobuiltin) + if cached is not None: + return cached + resolved = self.__resolve_type(nobuiltin) + self.resolved_cache[nobuiltin] = resolved + return resolved + + def __resolve_type(self, nobuiltin=False): + """ + Private resolve() worker without any result caching. + + @param nobuiltin: Flag indicating whether resolving to XSD built-in + types should not be allowed. + @return: The resolved (true) type. + @rtype: L{SchemaObject} + + """ + # There is no need for a recursive implementation here since a node can + # reference an external type node but XSD specification explicitly + # states that that external node must not be a reference to yet another + # node. + qref = self.qref() + if qref is None: + return self + query = TypeQuery(qref) + query.history = [self] + log.debug("%s, resolving: %s\n using:%s", self.id, qref, query) + resolved = query.execute(self.schema) + if resolved is None: + log.debug(self.schema) + raise TypeNotFound(qref) + if resolved.builtin() and nobuiltin: + return self + return resolved + + def qref(self): + """ + Get the I{type} qualified reference to the referenced XSD type. + + This method takes into account simple types defined through restriction + which are detected by determining that self is simple (len == 0) and by + finding a restriction child. + + @return: The I{type} qualified reference. + @rtype: qref + + """ + qref = self.type + if qref is None and len(self) == 0: + ls = [] + m = RestrictionMatcher() + finder = NodeFinder(m, 1) + finder.find(self, ls) + if ls: + return ls[0].ref + return qref + + +class Complex(SchemaObject): + """ + Represents an XSD schema node. + + @cvar childtags: A list of valid child node names. + @type childtags: (I{str},...) + + """ + + def childtags(self): + return ("all", "any", "attribute", "attributeGroup", "choice", + "complexContent", "group", "sequence", "simpleContent") + + def description(self): + return ("name",) + + def extension(self): + for c in self.rawchildren: + if c.extension(): + return True + return False + + def mixed(self): + for c in self.rawchildren: + if isinstance(c, SimpleContent) and c.mixed(): + return True + return False + + +class Group(SchemaObject): + """ + Represents an XSD schema node. + + @cvar childtags: A list of valid child node names. + @type childtags: (I{str},...) + + """ + + def childtags(self): + return "all", "choice", "sequence" + + def dependencies(self): + deps = [] + midx = None + if self.ref is not None: + query = GroupQuery(self.ref) + g = query.execute(self.schema) + if g is None: + log.debug(self.schema) + raise TypeNotFound(self.ref) + deps.append(g) + midx = 0 + return midx, deps + + def merge(self, other): + SchemaObject.merge(self, other) + self.rawchildren = other.rawchildren + + def description(self): + return "name", "ref" + + +class AttributeGroup(SchemaObject): + """ + Represents an XSD schema node. + + @cvar childtags: A list of valid child node names. + @type childtags: (I{str},...) + + """ + + def childtags(self): + return "attribute", "attributeGroup" + + def dependencies(self): + deps = [] + midx = None + if self.ref is not None: + query = AttrGroupQuery(self.ref) + ag = query.execute(self.schema) + if ag is None: + log.debug(self.schema) + raise TypeNotFound(self.ref) + deps.append(ag) + midx = 0 + return midx, deps + + def merge(self, other): + SchemaObject.merge(self, other) + self.rawchildren = other.rawchildren + + def description(self): + return "name", "ref" + + +class Simple(SchemaObject): + """Represents an XSD schema node.""" + + def childtags(self): + return "any", "list", "restriction" + + def enum(self): + for child, ancestry in self.children(): + if isinstance(child, Enumeration): + return True + return False + + def mixed(self): + return len(self) + + def description(self): + return ("name",) + + def extension(self): + for c in self.rawchildren: + if c.extension(): + return True + return False + + def restriction(self): + for c in self.rawchildren: + if c.restriction(): + return True + return False + + +class List(SchemaObject): + """Represents an XSD schema node.""" + + def childtags(self): + return () + + def description(self): + return ("name",) + + def xslist(self): + return True + + +class Restriction(SchemaObject): + """Represents an XSD schema node.""" + + def __init__(self, schema, root): + SchemaObject.__init__(self, schema, root) + self.ref = root.get("base") + + def childtags(self): + return "attribute", "attributeGroup", "enumeration" + + def dependencies(self): + deps = [] + midx = None + if self.ref is not None: + query = TypeQuery(self.ref) + super = query.execute(self.schema) + if super is None: + log.debug(self.schema) + raise TypeNotFound(self.ref) + if not super.builtin(): + deps.append(super) + midx = 0 + return midx, deps + + def restriction(self): + return True + + def merge(self, other): + SchemaObject.merge(self, other) + filter = Filter(False, self.rawchildren) + self.prepend(self.rawchildren, other.rawchildren, filter) + + def description(self): + return ("ref",) + + +class Collection(SchemaObject): + """Represents an XSD schema collection (a.k.a. order indicator) node.""" + + def childtags(self): + return "all", "any", "choice", "element", "group", "sequence" + + +class All(Collection): + """Represents an XSD schema node.""" + def all(self): + return True + + +class Choice(Collection): + """Represents an XSD schema node.""" + def choice(self): + return True + + +class Sequence(Collection): + """Represents an XSD schema node.""" + def sequence(self): + return True + + +class ComplexContent(SchemaObject): + """Represents an XSD schema node.""" + + def childtags(self): + return "attribute", "attributeGroup", "extension", "restriction" + + def extension(self): + for c in self.rawchildren: + if c.extension(): + return True + return False + + def restriction(self): + for c in self.rawchildren: + if c.restriction(): + return True + return False + + +class SimpleContent(SchemaObject): + """Represents an XSD schema node.""" + + def childtags(self): + return "extension", "restriction" + + def extension(self): + for c in self.rawchildren: + if c.extension(): + return True + return False + + def restriction(self): + for c in self.rawchildren: + if c.restriction(): + return True + return False + + def mixed(self): + return len(self) + + +class Enumeration(Content): + """Represents an XSD schema node.""" + + def __init__(self, schema, root): + Content.__init__(self, schema, root) + self.name = root.get("value") + + def description(self): + return ("name",) + + def enum(self): + return True + + +class Element(TypedContent): + """Represents an XSD schema node.""" + + def __init__(self, schema, root): + TypedContent.__init__(self, schema, root) + is_reference = self.ref is not None + is_top_level = root.parent is schema.root + if is_reference or is_top_level: + self.form_qualified = True + else: + form = root.get("form") + if form is not None: + self.form_qualified = (form == "qualified") + nillable = self.root.get("nillable") + if nillable is not None: + self.nillable = (nillable in ("1", "true")) + self.implany() + + def implany(self): + """ + Set the type to when implicit. + + An element has an implicit type when it has no body and no + explicitly defined type. + + @return: self + @rtype: L{Element} + + """ + if self.type is None and self.ref is None and self.root.isempty(): + self.type = self.anytype() + + def childtags(self): + return "any", "attribute", "complexType", "simpleType" + + def extension(self): + for c in self.rawchildren: + if c.extension(): + return True + return False + + def restriction(self): + for c in self.rawchildren: + if c.restriction(): + return True + return False + + def dependencies(self): + deps = [] + midx = None + e = self.__deref() + if e is not None: + deps.append(e) + midx = 0 + return midx, deps + + def merge(self, other): + SchemaObject.merge(self, other) + self.rawchildren = other.rawchildren + + def description(self): + return "name", "ref", "type" + + def anytype(self): + """Create an xsd:anyType reference.""" + p, u = Namespace.xsdns + mp = self.root.findPrefix(u) + if mp is None: + mp = p + self.root.addPrefix(p, u) + return ":".join((mp, "anyType")) + + def namespace(self, prefix=None): + """ + Get this schema element's target namespace. + + In case of reference elements, the target namespace is defined by the + referenced and not the referencing element node. + + @param prefix: The default prefix. + @type prefix: str + @return: The schema element's target namespace + @rtype: (I{prefix},I{URI}) + + """ + e = self.__deref() + if e is not None: + return e.namespace(prefix) + return super(Element, self).namespace() + + def __deref(self): + if self.ref is None: + return + query = ElementQuery(self.ref) + e = query.execute(self.schema) + if e is None: + log.debug(self.schema) + raise TypeNotFound(self.ref) + return e + + +class Extension(SchemaObject): + """Represents an XSD schema node.""" + + def __init__(self, schema, root): + SchemaObject.__init__(self, schema, root) + self.ref = root.get("base") + + def childtags(self): + return ("all", "attribute", "attributeGroup", "choice", "group", + "sequence") + + def dependencies(self): + deps = [] + midx = None + if self.ref is not None: + query = TypeQuery(self.ref) + super = query.execute(self.schema) + if super is None: + log.debug(self.schema) + raise TypeNotFound(self.ref) + if not super.builtin(): + deps.append(super) + midx = 0 + return midx, deps + + def merge(self, other): + SchemaObject.merge(self, other) + filter = Filter(False, self.rawchildren) + self.prepend(self.rawchildren, other.rawchildren, filter) + + def extension(self): + return self.ref is not None + + def description(self): + return ("ref",) + + +class Import(SchemaObject): + """ + Represents an XSD schema node. + + @cvar locations: A dictionary of namespace locations. + @type locations: dict + @ivar ns: The imported namespace. + @type ns: str + @ivar location: The (optional) location. + @type location: namespace-uri + @ivar opened: Opened and I{imported} flag. + @type opened: boolean + + """ + + locations = {} + + @classmethod + def bind(cls, ns, location=None): + """ + Bind a namespace to a schema location (URI). + + This is used for imports that do not specify a schemaLocation. + + @param ns: A namespace-uri. + @type ns: str + @param location: The (optional) schema location for the namespace. + (default=ns) + @type location: str + + """ + if location is None: + location = ns + cls.locations[ns] = location + + def __init__(self, schema, root): + SchemaObject.__init__(self, schema, root) + self.ns = (None, root.get("namespace")) + self.location = root.get("schemaLocation") + if self.location is None: + self.location = self.locations.get(self.ns[1]) + self.opened = False + + def open(self, options, loaded_schemata): + """ + Open and import the referenced schema. + + @param options: An options dictionary. + @type options: L{options.Options} + @param loaded_schemata: Already loaded schemata cache (URL --> Schema). + @type loaded_schemata: dict + @return: The referenced schema. + @rtype: L{Schema} + + """ + if self.opened: + return + self.opened = True + log.debug("%s, importing ns='%s', location='%s'", self.id, self.ns[1], + self.location) + result = self.__locate() + if result is None: + if self.location is None: + log.debug("imported schema (%s) not-found", self.ns[1]) + else: + url = self.location + if "://" not in url: + url = urljoin(self.schema.baseurl, url) + result = (loaded_schemata.get(url) or + self.__download(url, loaded_schemata, options)) + log.debug("imported:\n%s", result) + return result + + def __locate(self): + """Find the schema locally.""" + if self.ns[1] != self.schema.tns[1]: + return self.schema.locate(self.ns) + + def __download(self, url, loaded_schemata, options): + """Download the schema.""" + try: + reader = DocumentReader(options) + d = reader.open(url) + root = d.root() + root.set("url", url) + return self.schema.instance(root, url, loaded_schemata, options) + except TransportError: + msg = "import schema (%s) at (%s), failed" % (self.ns[1], url) + log.error("%s, %s", self.id, msg, exc_info=True) + raise Exception(msg) + + def description(self): + return "ns", "location" + + +class Include(SchemaObject): + """ + Represents an XSD schema node. + + @ivar location: The (optional) location. + @type location: namespace-uri + @ivar opened: Opened and I{imported} flag. + @type opened: boolean + + """ + + locations = {} + + def __init__(self, schema, root): + SchemaObject.__init__(self, schema, root) + self.location = root.get("schemaLocation") + if self.location is None: + self.location = self.locations.get(self.ns[1]) + self.opened = False + + def open(self, options, loaded_schemata): + """ + Open and include the referenced schema. + + @param options: An options dictionary. + @type options: L{options.Options} + @param loaded_schemata: Already loaded schemata cache (URL --> Schema). + @type loaded_schemata: dict + @return: The referenced schema. + @rtype: L{Schema} + + """ + if self.opened: + return + self.opened = True + log.debug("%s, including location='%s'", self.id, self.location) + url = self.location + if "://" not in url: + url = urljoin(self.schema.baseurl, url) + result = (loaded_schemata.get(url) or + self.__download(url, loaded_schemata, options)) + log.debug("included:\n%s", result) + return result + + def __download(self, url, loaded_schemata, options): + """Download the schema.""" + try: + reader = DocumentReader(options) + d = reader.open(url) + root = d.root() + root.set("url", url) + self.__applytns(root) + return self.schema.instance(root, url, loaded_schemata, options) + except TransportError: + msg = "include schema at (%s), failed" % url + log.error("%s, %s", self.id, msg, exc_info=True) + raise Exception(msg) + + def __applytns(self, root): + """Make sure included schema has the same target namespace.""" + TNS = "targetNamespace" + tns = root.get(TNS) + if tns is None: + tns = self.schema.tns[1] + root.set(TNS, tns) + else: + if self.schema.tns[1] != tns: + raise Exception, "%s mismatch" % TNS + + def description(self): + return "location" + + +class Attribute(TypedContent): + """Represents an XSD schema node.""" + + def __init__(self, schema, root): + TypedContent.__init__(self, schema, root) + self.use = root.get("use", default="") + + def childtags(self): + return ("restriction",) + + def isattr(self): + return True + + def get_default(self): + """ + Gets the attribute value. + + @return: The default value for the attribute + @rtype: str + + """ + return self.root.get("default", default="") + + def optional(self): + return self.use != "required" + + def dependencies(self): + deps = [] + midx = None + if self.ref is not None: + query = AttrQuery(self.ref) + a = query.execute(self.schema) + if a is None: + log.debug(self.schema) + raise TypeNotFound(self.ref) + deps.append(a) + midx = 0 + return midx, deps + + def description(self): + return "name", "ref", "type" + + +class Any(Content): + """Represents an XSD schema node.""" + + def get_child(self, name): + root = self.root.clone() + root.set("note", "synthesized (any) child") + child = Any(self.schema, root) + return child, [] + + def get_attribute(self, name): + root = self.root.clone() + root.set("note", "synthesized (any) attribute") + attribute = Any(self.schema, root) + return attribute, [] + + def any(self): + return True + + +class Factory: + """ + @cvar tags: A factory to create object objects based on tag. + @type tags: {tag:fn,} + + """ + + tags = { + "all": All, + "any": Any, + "attribute": Attribute, + "attributeGroup": AttributeGroup, + "choice": Choice, + "complexContent": ComplexContent, + "complexType": Complex, + "element": Element, + "enumeration": Enumeration, + "extension": Extension, + "group": Group, + "import": Import, + "include": Include, + "list": List, + "restriction": Restriction, + "simpleContent": SimpleContent, + "simpleType": Simple, + "sequence": Sequence, + } + + @classmethod + def maptag(cls, tag, fn): + """ + Map (override) tag => I{class} mapping. + + @param tag: An XSD tag name. + @type tag: str + @param fn: A function or class. + @type fn: fn|class. + + """ + cls.tags[tag] = fn + + @classmethod + def create(cls, root, schema): + """ + Create an object based on the root tag name. + + @param root: An XML root element. + @type root: L{Element} + @param schema: A schema object. + @type schema: L{schema.Schema} + @return: The created object. + @rtype: L{SchemaObject} + + """ + fn = cls.tags.get(root.name) + if fn is not None: + return fn(schema, root) + + @classmethod + def build(cls, root, schema, filter=("*",)): + """ + Build an xsobject representation. + + @param root: An schema XML root. + @type root: L{sax.element.Element} + @param filter: A tag filter. + @type filter: [str,...] + @return: A schema object graph. + @rtype: L{sxbase.SchemaObject} + + """ + children = [] + for node in root.getChildren(ns=Namespace.xsdns): + if "*" in filter or node.name in filter: + child = cls.create(node, schema) + if child is None: + continue + children.append(child) + c = cls.build(node, schema, child.childtags()) + child.rawchildren = c + return children + + @classmethod + def collate(cls, children): + imports = [] + elements = {} + attributes = {} + types = {} + groups = {} + agrps = {} + for c in children: + if isinstance(c, (Import, Include)): + imports.append(c) + continue + if isinstance(c, Attribute): + attributes[c.qname] = c + continue + if isinstance(c, Element): + elements[c.qname] = c + continue + if isinstance(c, Group): + groups[c.qname] = c + continue + if isinstance(c, AttributeGroup): + agrps[c.qname] = c + continue + types[c.qname] = c + for i in imports: + children.remove(i) + return children, imports, attributes, elements, types, groups, agrps + + +####################################################### +# Static Import Bindings :-( +####################################################### +Import.bind( + "http://schemas.xmlsoap.org/soap/encoding/", + "suds://schemas.xmlsoap.org/soap/encoding/") +Import.bind( + "http://www.w3.org/XML/1998/namespace", + "http://www.w3.org/2001/xml.xsd") +Import.bind( + "http://www.w3.org/2001/XMLSchema", + "http://www.w3.org/2001/XMLSchema.xsd") diff --git a/pym/calculate/contrib/suds/xsd/sxbasic.pyc b/pym/calculate/contrib/suds/xsd/sxbasic.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3bf658ad740599aad5d835dc7dcc1a0188fd88c GIT binary patch literal 33301 zcmeHwdvF}dd0#I8;zfWwl1JR}c#k>qcn6+H@LrXd zTuGksZs9E!#?|Dsd7eQBwZLRZg6wT$QrRRaV)q{FT3w zR8n!JQp)f5`(}CuFOr8{$WjuJ(>v4C)6@O+_wKKIy8qko;O%F=`q_$0|GM#e8b|Ww zF6ScWE+Z|usLRz#?h?`tSKI04huq~ME8XX6!)|_;yS&Sl;$1G@?e3P`<%e9<@1h@e(SUo;xx3DN z`tlwZ4Z3)*n?)0L`rLgk8glW&${qH(`(1>pEO)oh9dXe^S?(U6`-qG7X1V)(?xQYx zILqDda}T&^B+Gro=RW45N3+}mKKG!D9&_Gv%aOSqa{mIu|6B zYw>(JXv|!XE3IU#`d$2umhfnc$@6x)3#aEAmBo3~5XR*wZd(2T@+Zslak5aZ#Cg$6 z&2l|iXf#`IHk*yKXdj9$Hfz@#)q4KyT->_Yn4626t-ZJ%#!0JLt+c9*`dj4|+ST-= z$F`iskvxJV2I&E{k#>;)f%YJ{aB37(>5>{u44?Qr`53O>G?*qSmPx@K0O^ZD$~;;8=1Fa z>rDxJQBi;+;p=-#y`|O=PA)Ak#L+~f-U5R7L1R15vgoTwHXO9LhwSq`u(2JE=iNH* zCFkU*_Hk6%_as0PW;mP#<@z$PxW$*Q1QmPjScOQ!5oF8W#-XP$iq}i-U5(|tUGAq# zu2jVZAOqxaeqi~W0G4(l1#GomZ2^+Re;`bwb}NpiD`lYOC?5!k|1G|*+?-2V1kH`x zJk24!rST5;pr)fZ1Y}p*R}zNuMSSf9?+~!)#dYf*khJ7hx*U24inuZ0numBk#S+~_ zW8TII{_7d!oWey)GrtPR4F>5SP?`MK<~46uLFCpFG!pGCG$meY#m#!Traly!b9$lNEYBmCLYYNagpc>7w+%262sL52yYK~||Jj#ulxHG~+ug3euQEY>2_+6ra>pjxeQJC4SD z!PC~r@!*mgX^0ezwwjCaQPof^${NSPwx-0H-xgzD$>BLE!Vk$XTf_$NP@&*tqaL>o zB4e5$%ZPD$I>p;*R%?$6YngZ;2z7YuRn4!Gh?t@c$ej}XC;dgj z`FOK>tK1?IYJ5kJ2Dcl{8$cwAp~hlMTnjfBYpsB=24?-=gqI0%??`eirH3-E9&WYN!#+*c76wfTqVdNopBNd95 z;>uzx7TTHuL14M>La4Y0{-9S@c(6%0@-NUCJ; zDFe+ULF-zxu{gI%J@Z`j_O&V$w{kOv+-N~tMT=&Zb>5tZpeCcfRz|%NG~mfr|7b0) z2d}>#yl_;4Yi8Nk2iX(xsWMSE(>wzZW(};{mpWbK-S>dWdKOMJ&+DlI(5}i6pB$xT zCQ2a0j1q_fXsProDRQ~is*-H1hys-s@L8x#%BUq$HRnYWEDRkT*==Z@B9p7ABB88t zLj$EJq3#U;cOSyfe5K?DXWqE^iwl&>oH)?wp zM?y6m3TW3r&(Om|kEhC;bcPD<=#S8r2Ko|C;*HD(s-MU=-4iE}A*OrwdfoF&cvjf3 zN&zhzPp6=+j~Dcn6K@o?j?h zM)9%H3wMB}E62vh#*P|ViGQ$~!4G6YGbP0)uQLM5Omm-HiXU=>59 zeuFxD#n!23#DS$3e9w-sXJB9uN$3*<7CMJ>*e+>Dp>nCCJA6lJZG~?z5jQ0gPKo0e zv30(>6i4A{mRjA}@C@?W?JIloc^tm42hmqC_qA;ChuH#pWdxs)59Tk|*_IGJq>l#{ zZpsY%$P5R%2YSVUMbQ=9)E@`;ERLidR`^9!@Bpk(JmP!K1iR5V0@j!yb#(HpN#jFe zJY+X!xQjRCdB}H0@Z?rt+nh|NUtLZXxTYP1wmY)ea- zYZJuM_E9%p2nke;ldquWgza`vO?siCP{F36y%$#IfZ3VsrpJ*07e&{QbYuWZgRy~Y zh-yyJAQy$r$IZD|JgC4$InoU}5Zdfxco7x-8je(UJ(SBXk4R*vFcD0PpOm!Hz*%!n z;jUfcq=WcPKK7e9QvBYW;e8Z^)D5w|93DE`8f~3Jl|RFG4U+)tH$x1sfEi-sm*`ao5rd5HTR49386TBjqSFH~zwkU^NUApv z!-skH5hh}H9FlUo{4OLV{YxC%$>YM0vC-r@Ygk(N7V>iH-5TMt-rvRXeaX%K9UI1x z!n6vt$qm)FZQy2;c-J>^tmS6ZZB3c2;7osBeoRJGQg$dQj|1je(vg1?h5>7QjS)cA;WaCPu(1bjm7@4iIXCB`N=Z_%S;ej zc5l`(N!r9jLZe>T2R3eR6;&a~$d%eG=IJolWH%Ty9&eZo>DFKL6+a8UwDi zieH_^1092hOxUG_qw>GS8&mvfmdz)?uHhL@j49sd=Fh&;v1?yw&@>#^}1 zavu;Iy(@cj`A-MZy%DuAH{$WN8&B~du20|)iC}!-vw&cMUjg2Qy9k2A4=if<93X3O z1M{>I2T@2ZfvXa}VkY_cJ+$#54tZWaMy7420vFDg~ocTJtYzG8j4Zsv|Y}6g9Fxlg8;pgtXMe4$mV%CT_}cE=5OEY=|S2pO4Kj zEr-^j%Fn8NyZFx6KgK?j_i_SZ?ppi(~_Xox8Pye}EDOZkkU zVVH)S!l7M+ zmt{HvU+A3fg;ntFN6u6l1h54NkKyrqLpX~t_=|+`YiQ-G_kl6XbOgq;sOaP>7}HRl zut?Z+UVA;Hw_u-2V=cy0Zx+syzI5FPkbQYB0`p=@e0#DG>LIU)EO#+fy-_hB`3=<3 zISWo+zYpajC22&3iHDlXA^QGx@|ACOXpr4#l=Qc|NkX1DjjVYfyll7X55Z zro#Afr?Qu4UY+nPa@W%e#SJ*w`t>6Z5C|rHO7K@_HKb7-)HMTm%S zaMfY@2!C+tv?#=#y4Xu-j_>@9tp&BE~Y-Mhj6KgSo3L} z!sQyDR(OSZINITVG(N8pqHMcX3lXWZV*=;8Q?QrS5*FBo07v=lu_AVr!)je)0NL$x z=4uk5kvCyOK_ru1Zd^_|b} z3mf}A2(XIK=6B5VmF+w2FChfOj9Um_c-2uZxuYYhOZ(MP8@qO z`7K;*L?)mdEwDpK8yB9z5p2Gv9gJJ!0)=juoTl%vd6C{Du)OI$SI3+zN@78?1;4>* zg@9~?x*;xZS?5>_WFcB8EJle{4lIvAQB2;V9xNWT^1rI{UU$PPAIQpUJx>XRYzEvS zerFrac}2G#VGRm=t0q{~l`h81GFpv==~{d% zu7%fGmUZPQy*0Ip1agbmY+liQX-wTv*KT-2_u?N@Y1yQ1VzgKd6O1OBfk9-9;)ir; z3lse%R%O9Ei6CaXyMyP%0W3<>gXzk|KSpJKCB{^`Fhzm!SV&?nj`}i?6KnSB0pV7y zR9l6`8)xc4iowA(E-TCn6`xjxRz*wY>WyHg5iM)MNWI}35HHyaYFu?5yefL6q|+I(N$umeOI-+^yabl*5jI( z0BaW`zh9VgH~S?HORhVeQWe&^V}^5C9Hd(}#eH{ri-u@80ue0TZ4Xr58ya~^o-1B+QQ^>c;Izr8K*EM;_@1TuJee4@- zBGD(MXSUWiP>fMp`IRhQ>s_fD43WpARu(Z2g@Cf>0?~?yW@VsH*xWRx$xO~Lc3#US z5ebin)9{S|ubgPcT+IuS!PQ;hy_djy^CggD!lrQv?DVFs>kHX*g@@z0dSYUmwhkBN zeH{2%T{6_AWG_c)mUIhkj^PnkFIZ5zh&es%0I|?6?k=L1ZxXyiIB^i<6ym+55etwf zkUgL|Aw#GsK5o^{0!O5yfmEfVO<@89jYm<;HA3aPn@#X1*nTFL-L|L{>p|1~MpCKF z%>}Sw0tCBOzHu9of;7EQ$3kf=@yALzukd8@91D%P0(I@vL19+`EDl8xFNJ*-Q7YGM znQNBKm7tlfux1N`bk6`xePZxz5kKUAnG3lsudw!$5<1Nt4-nhuU+-0eOKA3ep-_0t zbO)^dvv;i=yKv`|;f0lS4IuX*u!zKP2}72nmIr9~Bh0TN$&F9bOx2%onRjqlvNc^1 zqwc;%#Oh~7!^RNBUWia$7SO+KNEO-o6>Lfbd;xZ+s0LyMfokCwa}-&SBA-1lv)O_d zxlGapFPs=gV=$}D<`@H$v>@82!s6a5T5?D!in|jq5~oN-)W0RD=pArSs<{C|Q)xGlwK^QzAJY!iRidb+)z9CGI3_GA#kwwYxR*+>7A3 z0j)S27}_iI>CJ4BVFe}i$8k7|BRPlU{d!*4Te?}?@(I*-AImjs$|~EH=tvGbfg?GJ zWFy=49#Ko-XYh<^xA%`&>X>)uj|hA=dzE*GhJ*USJ8P%esiYUy+>)JZxou&7ebXW+ z+d-Mm`StJQ9Z01*U1gpx{J$E)B-Wgh=+>z7qk!a}Wz@N8^b%pc3i;{UEh2xXLWe@w z@V464qN6{H%K|%Pv`|=P9*%ZI&P6=_U)XJu0kzqUoDuYLCc)2R1jxMy$I86WCgW2j93dES@@30xvjO}_Bqe2Cf*9zThS{(!BZy_7md zdmuh`z%|ODyD-n4;wm`PA93_7j)b;rQC>g@VVgJZ64po05h|c#_Yl6{oRtP%~g3zJ>8jt z!aV4$Tw!Tqw!{6b`?dQ$sN;dbiz<8-)Jg3rQq3d%V=xc^K!Q=+pT1*1@l zj~2`a?LPy109ye@0X(iLV7XNowuy-vh+4yLF$-~}Ity1{THVETU<>tRTZU<@S3%9- zKo#6}>nM(ma&5D*tcB|aC^ZAJ`)VYu8vl~~1*~o~wK`s}Cr3SO?9Evfh8zB-?O2!_ z1zE8~99gkv73>^CZiVd(Ng7#+oc6aQm1NJ(VAyt{Ze!8d1_>*%yYUVlUJ0YsQj|lq z;<Fl(o(ri)*!60vP-^#O`~w>zxb;aD@YS-ipHJhZ@dv za0wc!Y{g`FmrWphvhlc>qJTE*F|L{GdbA_VU;kHm_ScyF6(%nr5koVAD2TknynO{p zn=sYvLO^&9p)#t1k3#6}EHyi6~rtLI54JoZuGh4uW++3 zRy^pg?^MjV_Nl^%V8E{rrBUPyzoRn4yhJ`-4Bc!62hQ3pe+^#)w@tc+@j{VRkZXx& z8OM^7AT#m725f}a6Spxx+K)Zkdc+=AUm8`LUmOSqUk>|${I_#45LcK-uABjNKeqw_V@c^RTI#l5OF=(Q?h zU4BBsUQ?WpNS*=ea341VAl)MM|&V)nSnPBut!jRzB@mcP~ zmUN@Y_=yw3+N|jK;E`mMBo}^x$!R7}F$tJF&BW7JOHSSklEu^0Vo3HvnMUnVv ze_8M6DM=|}3?Vh5*m-kIgPCqEDZrCyspl;S2I^@B_l{|&5;oaro+n5+n6B%IQiUfJ zMSQE6+1GKhe2G%RrU%mf?W8h*x37T7U=~=uN1FmRu|e)ZMgf3ncSy_)Ba3VWlMHZj zf2#g**Mq*@7}Obq)r^X*ao=J}-EtqwGi$X$z#Vn0UAAShi|w@8GWx;%l| zmPbmD=kpgRRPco48=`m?Vl(#nB`fS0Dl6jU9X6EhaHYvn%ICF92&g33tSR^8wrvs3 zS@%;cEgzqT@r%6tStcE`!9IuD{x^n7JNfkv_jdIHn!EQ5^bb42FZFu3_RyOSX&VBW`9YCU`}E8=G6YuZUe-bg}|3$hX9=K8q7DtNVwJk=sBQGuQT%n2#74^JUp)s;g;0 zt5jE#^JMtbNW~@A>Z$v2!?aUrtWr^h|I||@bhk@Gt&$Q3@fK>RYxGkOA~F;9@&WZz zS_CYQVD$%IVHESqE~@)YmP8gDtj`G5`0|? zVS!|-&WQ#l`jyKnAWDum3 zk}8>Nv>LesOrZ(?4j{6jA`^ZYch(FfwwS9eLm#!_{t611QX|9R@AC3#Ca0PFJtUiI zFyU8OH zMQo>BO-U|OMHwn58v*;EuA5;WleuK`?vvcEmXr3TsFGTbV9V!fqK{Rii;5+QB!mv* ze)u<;aByviM7~loITBJ|FHKIVRGTA`YLXe!e2HU2i_>*+gFxz$`??VM09L<2taRpw zoRkc;mat?;qSmO_{Q{dqe884d>b`VF&R5t*$`aVQQuxcf@heO^rWAe+wOz@8f~j06 zg# kHR&-Q-*-wPOpN3`Xd0&;z&4&Q&b64Wl(OV_e?7^XFRmRY&+#t8HDka?Lp+iQ8Xi zb8w(J8&e9Plm%O;9j8&WW0sXH&1%At|HcLlA(#Xeau*CK7$|gZAS3_NLtIL~(?Dy= z>vIT2GWKTi!`Y^h4C!S^&+CT{0l_@7agXlBVo=hmIG!vFNQJ!n-aqW$nK|4zapN=V}w{A(g ziz1Sm&%%(Y+q`Wqp>hUzb?+FX`|NH)_?Fv*tpbF;O_)k4-FR6ncCI%@kG zoAMA&vK2kpb7K(4u#}ZE_2mlg>5mXNi$j4$4=5iY`^d(UBS`Kc`?ShIVTtRNNP@u# zm&gwS0Ua9#`ld@tldJA4LBl$ZOkQo}cgOqcsdZ2n;+CNQPZ2uWBt{7bxn!;-B{D6&ejGVPxD`y7*g z)(BNjp&!Utty*^kD&apywaGyy>mcH}d=8cHw@~sy0P+gTwF?mPYXZc#;}6#XB_nPA zPT-LGu&okXAAI-@8^QsBZcD%4TH^gD%=@QIUPh9`L1$aSj*$5G@3a1kP@&OEn>$~w z@Pk4X6wn{B{VWbSBa1{@#m6n7!Is=f`z+nbSU$~@u{@e5W4ZlL#+W(oMG;I0^x+4w zCH?rpI=cb5PW)gAaA?!Vf;qxf?%w`Gw7s_~2x;2R{$< z%bF)I?{_i2ylJ1-L~P3=x_p>^Rv3ks@#Re1#pgChvf!5k%CXODqQGMeZ#lrOm61rz zuwa$!vm>(x3Pw*2+ojL+7OrL%?i`M}35w81v+ zxyrK-F`?OMI-Mr-G(M^E8HOxCEmj`{(PAM5EP5@U11BUV?*|_vL&FKaWQQ?Jqei}k zTVB6u=z@ffYL7SMVLkg$1~x*3SjAo16#MCynqBqcPUb z!>UXchNG!h3-y@A2j$KLvx{{_1Yx73KyO?7IE&5J-%aoN7EemQ(o7*Z^ zB%T1z@%_rzQlto%BO0b6xu>5-#{li0N@vh{+s5Oqi&i!b(_afzD_B@$=Y5klHs+1u z_@sU*Ys}hevSJtS*xA^Wrs4}T`^8yyBP0-wzSCEzYt0n<+napH?_U7M7EdB^Nj=R( zD2Ls=Q-^u>ZQj7qjtJ$jTYHBv#uk+`ydSO*(w_6)Nh;kUw6EZV3U`lN`eN#!!T@8= zPjjuMb61x+_X-t*9;aTHysmjzs2aMoFZR(>h51=iJLH^%1x_8j>~21;HMy9ZRX$Kl zPE5>l=mGdKZKpvv|1k@TX;$P+5AZSk|CGG-Qk_E)mH7KxYo?J>`=hodUE&p zm14y^DVi0=Qj0n=^h(N0V;KgfiwO$2k+K18g-28ajRm$b-rD*scRctE*a$!BbTvo( z48hi5YB1L&r2olrpVpNT?1I{L~p%Cu_-42uip80K$LG zGh(7l6sdYzCTGhJ-oOp>tgb;(N}cc$5-~6;t5W-A3%w3 zs{{yPgF5hHl=u^s02LHV@Wr4OpY^GwgKX}(tNYvv=D$FyNC(KaOE>=zjCT-pzuqK|mvbPw|Pl*|*thev51tW|L%=E*1`1WWkwC>xtZ;#!6Syh5%pLp@L*IqqAMG4 literal 0 HcmV?d00001 diff --git a/pym/calculate/contrib/suds/xsd/sxbuiltin.py b/pym/calculate/contrib/suds/xsd/sxbuiltin.py new file mode 100644 index 0000000..3537022 --- /dev/null +++ b/pym/calculate/contrib/suds/xsd/sxbuiltin.py @@ -0,0 +1,347 @@ +# -*- coding: utf-8 -*- + +# This program is free software; you can redistribute it and/or modify it under +# the terms of the (LGPL) GNU Lesser General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License +# for more details at ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +"""Classes representing I{built-in} XSD schema objects.""" + +from suds import * +from suds.xsd import * +from suds.sax.date import * +from suds.xsd.sxbase import XBuiltin + +import datetime +import decimal +import sys + + +class XAny(XBuiltin): + """Represents an XSD node.""" + + def __init__(self, schema, name): + XBuiltin.__init__(self, schema, name) + self.nillable = False + + def get_child(self, name): + child = XAny(self.schema, name) + return child, [] + + def any(self): + return True + + +class XBoolean(XBuiltin): + """Represents an XSD boolean built-in type.""" + + _xml_to_python = {"1": True, "true": True, "0": False, "false": False} + _python_to_xml = {True: "true", 1: "true", False: "false", 0: "false"} + + @staticmethod + def translate(value, topython=True): + if topython: + if isinstance(value, basestring): + return XBoolean._xml_to_python.get(value) + else: + if isinstance(value, (bool, int)): + return XBoolean._python_to_xml.get(value) + return value + + +class XDate(XBuiltin): + """Represents an XSD built-in type.""" + + @staticmethod + def translate(value, topython=True): + if topython: + if isinstance(value, basestring) and value: + return Date(value).value + else: + if isinstance(value, datetime.date): + return Date(value) + return value + + +class XDateTime(XBuiltin): + """Represents an XSD built-in type.""" + + @staticmethod + def translate(value, topython=True): + if topython: + if isinstance(value, basestring) and value: + return DateTime(value).value + else: + if isinstance(value, datetime.datetime): + return DateTime(value) + return value + + +class XDecimal(XBuiltin): + """ + Represents an XSD built-in type. + + Excerpt from the XSD datatype specification + (http://www.w3.org/TR/2004/REC-xmlschema-2-20041028): + + > 3.2.3 decimal + > + > [Definition:] decimal represents a subset of the real numbers, which can + > be represented by decimal numerals. The ·value space· of decimal is the + > set of numbers that can be obtained by multiplying an integer by a + > non-positive power of ten, i.e., expressible as i × 10^-n where i and n + > are integers and n >= 0. Precision is not reflected in this value space; + > the number 2.0 is not distinct from the number 2.00. The ·order-relation· + > on decimal is the order relation on real numbers, restricted to this + > subset. + > + > 3.2.3.1 Lexical representation + > + > decimal has a lexical representation consisting of a finite-length + > sequence of decimal digits (#x30-#x39) separated by a period as a decimal + > indicator. An optional leading sign is allowed. If the sign is omitted, + > "+" is assumed. Leading and trailing zeroes are optional. If the + > fractional part is zero, the period and following zero(es) can be + > omitted. For example: -1.23, 12678967.543233, +100000.00, 210. + + """ + + # Python versions before 2.7 do not support the decimal.Decimal.canonical() + # method but they maintain their decimal.Decimal encoded in canonical + # format internally so we can easily emulate that function by simply + # returning the same decimal instance. + if sys.version_info < (2, 7): + _decimal_canonical = staticmethod(lambda decimal: decimal) + else: + _decimal_canonical = decimal.Decimal.canonical + + @staticmethod + def _decimal_to_xsd_format(value): + """ + Converts a decimal.Decimal value to its XSD decimal type value. + + Result is a string containing the XSD decimal type's lexical value + representation. The conversion is done without any precision loss. + + Note that Python's native decimal.Decimal string representation will + not do here as the lexical representation desired here does not allow + representing decimal values using float-like `E' + format, e.g. 12E+30 or 0.10006E-12. + + """ + value = XDecimal._decimal_canonical(value) + negative, digits, exponent = value.as_tuple() + + # The following implementation assumes the following tuple decimal + # encoding (part of the canonical decimal value encoding): + # - digits must contain at least one element + # - no leading integral 0 digits except a single one in 0 (if a non-0 + # decimal value has leading integral 0 digits they must be encoded + # in its 'exponent' value and not included explicitly in its + # 'digits' tuple) + assert digits + assert digits[0] != 0 or len(digits) == 1 + + result = [] + if negative: + result.append("-") + + # No fractional digits. + if exponent >= 0: + result.extend(str(x) for x in digits) + result.extend("0" * exponent) + return "".join(result) + + digit_count = len(digits) + + # Decimal point offset from the given digit start. + point_offset = digit_count + exponent + + # Trim trailing fractional 0 digits. + fractional_digit_count = min(digit_count, -exponent) + while fractional_digit_count and digits[digit_count - 1] == 0: + digit_count -= 1 + fractional_digit_count -= 1 + + # No trailing fractional 0 digits and a decimal point coming not after + # the given digits, meaning there is no need to add additional trailing + # integral 0 digits. + if point_offset <= 0: + # No integral digits. + result.append("0") + if digit_count > 0: + result.append(".") + result.append("0" * -point_offset) + result.extend(str(x) for x in digits[:digit_count]) + else: + # Have integral and possibly some fractional digits. + result.extend(str(x) for x in digits[:point_offset]) + if point_offset < digit_count: + result.append(".") + result.extend(str(x) for x in digits[point_offset:digit_count]) + return "".join(result) + + @classmethod + def translate(cls, value, topython=True): + if topython: + if isinstance(value, basestring) and value: + return decimal.Decimal(value) + else: + if isinstance(value, decimal.Decimal): + return cls._decimal_to_xsd_format(value) + return value + + +class XFloat(XBuiltin): + """Represents an XSD built-in type.""" + + @staticmethod + def translate(value, topython=True): + if topython: + if isinstance(value, basestring) and value: + return float(value) + else: + return value + + +class XInteger(XBuiltin): + """Represents an XSD built-in type.""" + + @staticmethod + def translate(value, topython=True): + if topython: + if isinstance(value, basestring) and value: + return int(value) + else: + return value + + +class XLong(XBuiltin): + """Represents an XSD built-in type.""" + + @staticmethod + def translate(value, topython=True): + if topython: + if isinstance(value, basestring) and value: + return long(value) + else: + return value + + +class XString(XBuiltin): + """Represents an XSD node.""" + pass + + +class XTime(XBuiltin): + """Represents an XSD built-in type.""" + + @staticmethod + def translate(value, topython=True): + if topython: + if isinstance(value, basestring) and value: + return Time(value).value + else: + if isinstance(value, datetime.time): + return Time(value) + return value + + +class Factory: + + tags = { + # any + "anyType": XAny, + # strings + "string": XString, + "normalizedString": XString, + "ID": XString, + "Name": XString, + "QName": XString, + "NCName": XString, + "anySimpleType": XString, + "anyURI": XString, + "NOTATION": XString, + "token": XString, + "language": XString, + "IDREFS": XString, + "ENTITIES": XString, + "IDREF": XString, + "ENTITY": XString, + "NMTOKEN": XString, + "NMTOKENS": XString, + # binary + "hexBinary": XString, + "base64Binary": XString, + # integers + "int": XInteger, + "integer": XInteger, + "unsignedInt": XInteger, + "positiveInteger": XInteger, + "negativeInteger": XInteger, + "nonPositiveInteger": XInteger, + "nonNegativeInteger": XInteger, + # longs + "long": XLong, + "unsignedLong": XLong, + # shorts + "short": XInteger, + "unsignedShort": XInteger, + "byte": XInteger, + "unsignedByte": XInteger, + # floats + "float": XFloat, + "double": XFloat, + "decimal": XDecimal, + # dates & times + "date": XDate, + "time": XTime, + "dateTime": XDateTime, + "duration": XString, + "gYearMonth": XString, + "gYear": XString, + "gMonthDay": XString, + "gDay": XString, + "gMonth": XString, + # boolean + "boolean": XBoolean, + } + + @classmethod + def maptag(cls, tag, fn): + """ + Map (override) tag => I{class} mapping. + + @param tag: An XSD tag name. + @type tag: str + @param fn: A function or class. + @type fn: fn|class. + + """ + cls.tags[tag] = fn + + @classmethod + def create(cls, schema, name): + """ + Create an object based on the root tag name. + + @param schema: A schema object. + @type schema: L{schema.Schema} + @param name: The name. + @type name: str + @return: The created object. + @rtype: L{XBuiltin} + + """ + fn = cls.tags.get(name, XBuiltin) + return fn(schema, name) diff --git a/pym/calculate/contrib/suds/xsd/sxbuiltin.pyc b/pym/calculate/contrib/suds/xsd/sxbuiltin.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f136dfc7f2b904260057c6bcb22f66e82d69f29b GIT binary patch literal 11531 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 nnu&zV50yrd`x?bJI%CLqjg`+&o