Skip to content
This repository

rpclib-2.8.0 commits #129

Merged
merged 30 commits into from almost 2 years ago

1 participant

Burak Arslan
Burak Arslan
Owner
plq commented March 20, 2012

No description provided.

added some commits May 08, 2012
Burak Arslan clarify license in pypi d92fc47
Burak Arslan Merge branch 'master' of github.com:plq/rpclib ef1ae10
Burak Arslan fix service tests that were failing due to null transport in Application d441600
Burak Arslan now using the new AuxMethodContext class to pass various to the aux m…
…ethods.
4a2e734
Burak Arslan fix json protocol deserialization 21101a2
Burak Arslan rpclib.protocol.json: log the error on getattr if there's any a46b202
Burak Arslan add docstring to wsgimounter 679a178
Burak Arslan rpclib.aux: initialize_context function initializes ctx.aux. 610e329
Burak Arslan negligible 77c4328
Burak Arslan nullserver got prettier. a17d807
Burak Arslan rpclib.util.xml.get_object_as_xml: pass no_namespace=True to strip na…
…mespaces out of the xml output.
19683f0
Burak Arslan rpclib.aux: remove debug statements 3983a10
Burak Arslan changelog update 58fe120
Burak Arslan rpclib.aux.thread: Initialize threadpool as late as possible to let t…
…he process fork before spawning threads.
5c17662
Burak Arslan replace tabs with 4 spaces / remove trailing space aaa8c06
Burak Arslan make httprpc test standalone. 1e88498
Burak Arslan reorganize and fix tests, make interop tests mostly standalone.
still issues with running them with a single py.test command though.
e3cf052
Burak Arslan remove dead code. 1a90a9a
Burak Arslan fix zeromq server caccff1
Burak Arslan make optional dependencies really optional 9e155e4
Burak Arslan negligible 6e584e4
Burak Arslan fix typo. whoops. d771dff
Burak Arslan make SelfReference work again. c47195a
Burak Arslan ignore packages whose names start with _ in automatic namespace assig…
…nment
5bb1052
Burak Arslan get_object_as_xml and get_xml_as_object argument change.
now get_object_as_xml can also get class suggestion.
ab91a3e
Burak Arslan examples/helloworld_soap_twisted: fiddled with default namespace pref…
…ix. xmlns:tns="..." is now xmlns="..."
584d4f4
Burak Arslan add docstring to InterfaceDocumentBase 5e31435
Burak Arslan make _body_style='bare' work. At least in Soap11 05c9dee
Burak Arslan pep8 tweak 1d4795c
Burak Arslan don't put alias in interface.classes set a08a3de
Burak Arslan
Owner
plq commented May 21, 2012

okay, this goes in. further fixes will be made in following pull requests.

Burak Arslan plq merged commit a08a3de into from May 21, 2012
Burak Arslan plq closed this May 21, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 30 unique commits by 1 author.

May 08, 2012
Burak Arslan clarify license in pypi d92fc47
Burak Arslan Merge branch 'master' of github.com:plq/rpclib ef1ae10
May 09, 2012
Burak Arslan fix service tests that were failing due to null transport in Application d441600
Burak Arslan now using the new AuxMethodContext class to pass various to the aux m…
…ethods.
4a2e734
Burak Arslan fix json protocol deserialization 21101a2
Burak Arslan rpclib.protocol.json: log the error on getattr if there's any a46b202
Burak Arslan add docstring to wsgimounter 679a178
May 10, 2012
Burak Arslan rpclib.aux: initialize_context function initializes ctx.aux. 610e329
Burak Arslan negligible 77c4328
Burak Arslan nullserver got prettier. a17d807
Burak Arslan rpclib.util.xml.get_object_as_xml: pass no_namespace=True to strip na…
…mespaces out of the xml output.
19683f0
Burak Arslan rpclib.aux: remove debug statements 3983a10
May 11, 2012
Burak Arslan changelog update 58fe120
Burak Arslan rpclib.aux.thread: Initialize threadpool as late as possible to let t…
…he process fork before spawning threads.
5c17662
May 12, 2012
Burak Arslan replace tabs with 4 spaces / remove trailing space aaa8c06
Burak Arslan make httprpc test standalone. 1e88498
May 13, 2012
Burak Arslan reorganize and fix tests, make interop tests mostly standalone.
still issues with running them with a single py.test command though.
e3cf052
Burak Arslan remove dead code. 1a90a9a
Burak Arslan fix zeromq server caccff1
Burak Arslan make optional dependencies really optional 9e155e4
Burak Arslan negligible 6e584e4
Burak Arslan fix typo. whoops. d771dff
May 15, 2012
Burak Arslan make SelfReference work again. c47195a
May 16, 2012
Burak Arslan ignore packages whose names start with _ in automatic namespace assig…
…nment
5bb1052
May 17, 2012
Burak Arslan get_object_as_xml and get_xml_as_object argument change.
now get_object_as_xml can also get class suggestion.
ab91a3e
May 19, 2012
Burak Arslan examples/helloworld_soap_twisted: fiddled with default namespace pref…
…ix. xmlns:tns="..." is now xmlns="..."
584d4f4
Burak Arslan add docstring to InterfaceDocumentBase 5e31435
Burak Arslan make _body_style='bare' work. At least in Soap11 05c9dee
Burak Arslan pep8 tweak 1d4795c
Burak Arslan don't put alias in interface.classes set a08a3de
This page is out of date. Refresh to see the latest.

Showing 49 changed files with 466 additions and 341 deletions. Show diff stats Hide diff stats

  1. 4  CHANGELOG.rst
  2. 2  doc/source/manual/highlevel.rst
  3. 2  doc/source/manual/t_and_p.rst
  4. 256  doc/source/manual/validation.rst
  5. 2  examples/authentication/http_cookie/server_soap.py
  6. 5  examples/helloworld_soap_twisted.py
  7. 2  examples/validation.py
  8. 4  setup.py
  9. 1  src/rpclib/__init__.py
  10. 14  src/rpclib/_base.py
  11. 5  src/rpclib/application.py
  12. 2  src/rpclib/aux/__init__.py
  13. 22  src/rpclib/aux/_base.py
  14. 4  src/rpclib/aux/sync.py
  15. 10  src/rpclib/aux/thread.py
  16. 3  src/rpclib/client/_base.py
  17. 18  src/rpclib/const/ansi_color.py
  18. 9  src/rpclib/interface/_base.py
  19. 10  src/rpclib/interface/wsdl/wsdl11.py
  20. 7  src/rpclib/interface/xml_schema/_base.py
  21. 6  src/rpclib/interface/xml_schema/model/complex.py
  22. 11  src/rpclib/model/_base.py
  23. 32  src/rpclib/model/complex.py
  24. 8  src/rpclib/model/primitive.py
  25. 5  src/rpclib/protocol/_base.py
  26. 2  src/rpclib/protocol/html.py
  27. 2  src/rpclib/protocol/http.py
  28. 6  src/rpclib/protocol/json/__init__.py
  29. 21  src/rpclib/protocol/xml/_base.py
  30. 6  src/rpclib/protocol/xml/model/complex.py
  31. 45  src/rpclib/server/null.py
  32. 2  src/rpclib/server/twisted/__init__.py
  33. 5  src/rpclib/server/wsgi.py
  34. 4  src/rpclib/server/zeromq.py
  35. 42  src/rpclib/test/interop/{_test_client_base.py → _test_soap_client_base.py}
  36. 5  src/rpclib/test/interop/server/httprpc_pod_basic.py
  37. 4  src/rpclib/test/interop/server/soap_http_basic.py
  38. 10  src/rpclib/test/interop/server/soap_zeromq.py
  39. 19  src/rpclib/test/interop/test_httprpc.py
  40. 4  src/rpclib/test/interop/{test_client_http.py → test_soap_client_http.py}
  41. 3  src/rpclib/test/interop/{test_client_http_twisted.py → test_soap_client_http_twisted.py}
  42. 5  src/rpclib/test/interop/{test_client_zeromq.py → test_soap_client_zeromq.py}
  43. 28  src/rpclib/test/interop/test_suds.py
  44. 6  src/rpclib/test/test_service.py
  45. 2  src/rpclib/test/wsdl/__init__.py
  46. 56  src/rpclib/test/wsdl/test_bindings.py
  47. 58  src/rpclib/util/__init__.py
  48. 5  src/rpclib/util/wsgi_wrapper.py
  49. 23  src/rpclib/util/xml.py
4  CHANGELOG.rst
Source Rendered
@@ -18,6 +18,8 @@ rpclib-2.8.0-beta
18 18
    now ignored.
19 19
  * Add support for async methods, which execute after the primary user code
20 20
    returns. Currently, the only async execution method is via threads.
  21
+ * Xml & friends: Start tags are now in the same namespace as the definitions
  22
+   themselves. Intermediate tags are in the parent's namespace, just as before.
21 23
  * Full change log:
22 24
     * https://github.com/arskom/rpclib/pull/128
23 25
     * https://github.com/arskom/rpclib/pull/129
@@ -77,7 +79,7 @@ rpclib-2.5.1-beta
77 79
 
78 80
 rpclib-2.5.0-beta
79 81
 -----------------
80  
- * Implemented fanout support for transports and protocols that can handle 
  82
+ * Implemented fanout support for transports and protocols that can handle
81 83
    that.
82 84
  * Implemented a helper module that generates a Soap/Wsdl 1.1 application in
83 85
    ``rpclib.util.simple``
2  doc/source/manual/highlevel.rst
Source Rendered
@@ -73,7 +73,7 @@ procedure calls to the outside world. The following is used to wrap that
73 73
 code:
74 74
 
75 75
 * **User Methods**:
76  
-    User methods are the code that you wrote and decided to use rpclib to 
  76
+    User methods are the code that you wrote and decided to use rpclib to
77 77
     expose to the outside world.
78 78
 
79 79
 * **Decorators**:
2  doc/source/manual/t_and_p.rst
Source Rendered
@@ -100,7 +100,7 @@ is stored. Workers are identified by an integer. ::
100 100
                                                                  nullable=False)
101 101
 
102 102
 The consumer is a :class:`rpclib.server._base.ServerBase` child that receives
103  
-requests by polling the database. 
  103
+requests by polling the database.
104 104
 
105 105
 The transport is for displaying it in the Wsdl. While it's irrelevant here, it's
106 106
 nice to put it in: ::
256  doc/source/manual/validation.rst
Source Rendered
@@ -2,7 +2,7 @@
2 2
 
3 3
 Input Validation
4 4
 ================
5  
-This is necessary in the cases in which you have to ensure that the received 
  5
+This is necessary in the cases in which you have to ensure that the received
6 6
 data comply with a given format, such as:
7 7
 
8 8
 - a number must be within a certain range
@@ -13,21 +13,22 @@ data comply with a given format, such as:
13 13
 Data validation can be handled by two subsystems:
14 14
 
15 15
 XML schema
16  
-	such rules are enforced by *lxml*, the underlying XML parsing library 
  16
+    such rules are enforced by *lxml*, the underlying XML parsing library
  17
+
17 18
 "Soft" level
18  
-	*rpclib* itself can apply additional checks after the data were validated by
19  
-	the layer underneath
  19
+    *rpclib* itself can apply additional checks after the data were validated by
  20
+    the layer underneath
20 21
 
21 22
 The differences between them are:
22 23
 
23  
-- Soft validation ignores unknown fields, while *lxml* validation rejects 
  24
+- Soft validation ignores unknown fields, while *lxml* validation rejects
24 25
   them.
25  
-- Soft validation doesn't care about namespaces, while *lxml* validation 
  26
+- Soft validation doesn't care about namespaces, while *lxml* validation
26 27
   rejects unexpected namespaces.
27 28
 - Soft validation works with any transport protocol supported by *rpclib*,
28 29
   while *lxml* validation only works for XML data (i.e. just SOAP/XML).
29 30
 
30  
-============================== ======== =========                            
  31
+============================== ======== =========
31 32
 Criteria                       lxml     soft
32 33
 ============================== ======== =========
33 34
 Unknown fields                 reject   ignore
@@ -35,32 +36,29 @@ Unknown namespaces             reject   ignore
35 36
 Supported transport protocols  SOAP/XML any
36 37
 ============================== ======== =========
37 38
 
  39
+.. NOTE::
  40
+    The two validation sybsystems operate independently, you can use either one,
  41
+    but not both at the same time. The validator is indicated when instantiating
  42
+    the protocol: ``validator='soft'`` or ``validator='lxml'``.
  43
+
  44
+    ::
  45
+
  46
+        #using 'soft' validation with HttpRpc
  47
+        application = Application([NameOfMonthService],
  48
+            tns='rpclib.examples.multiprot',
  49
+            in_protocol=HttpRpc(validator='soft'),
  50
+            out_protocol=HttpRpc()
  51
+            )
  52
+
  53
+        #using lxml validation with Soap
  54
+        application = Application([UserService],
  55
+            tns='rpclib.examples.authentication',
  56
+            interface=Wsdl11(),
  57
+            in_protocol=Soap11(validator='lxml'),
  58
+            out_protocol=Soap11()
  59
+            )
38 60
 
39  
-	
40 61
 
41  
-.. NOTE::
42  
-	The two validation sybsystems operate independently, you can use either one,
43  
-	but not both at the same time. The validator is indicated when instantiating
44  
-	the protocol: ``validator='soft'`` or ``validator='lxml'``.
45  
-	
46  
-	::
47  
-
48  
-		#using 'soft' validation with HttpRpc
49  
-		application = Application([NameOfMonthService],
50  
-			tns='rpclib.examples.multiprot',
51  
-			in_protocol=HttpRpc(validator='soft'),
52  
-			out_protocol=HttpRpc()
53  
-			)
54  
-
55  
-		#using lxml validation with Soap
56  
-		application = Application([UserService],
57  
-			tns='rpclib.examples.authentication',
58  
-			interface=Wsdl11(),
59  
-			in_protocol=Soap11(validator='lxml'),
60  
-			out_protocol=Soap11()
61  
-			)
62  
-
63  
-	
64 62
 
65 63
 
66 64
 Simple validation at the XML schema level
@@ -69,11 +67,11 @@ This applies to all the primitive data types, and is suitable for simple logical
69 67
 conditions.
70 68
 
71 69
 .. NOTE::
72  
-	Constraints applied at this level are reflected in the XML schema itself,
73  
-	thus a client that retrieves the WSDL of the service will be able to see
74  
-	what the constraints are.
75  
-	As it was mentioned in the introduction, such validation is only effective
76  
-	in the context of SOAP/XML.
  70
+    Constraints applied at this level are reflected in the XML schema itself,
  71
+    thus a client that retrieves the WSDL of the service will be able to see
  72
+    what the constraints are.
  73
+    As it was mentioned in the introduction, such validation is only effective
  74
+    in the context of SOAP/XML.
77 75
 
78 76
 
79 77
 Any primitive type
@@ -83,60 +81,60 @@ along with their default values
83 81
 
84 82
 - ``default = None`` - default value if the input is ``None``
85 83
 - ``nillable = True`` - if True, the item is optional
86  
-- ``min_occurs = 0`` - set this to 1 to make the type mandatory. Can be set to 
  84
+- ``min_occurs = 0`` - set this to 1 to make the type mandatory. Can be set to
87 85
   any positive integer
88  
-- ``max_occurs = 1`` - can be set to any strictly positive integer. Values 
  86
+- ``max_occurs = 1`` - can be set to any strictly positive integer. Values
89 87
   greater than 1 will imply an iterable of objects as native Python type. Can be
90 88
   set to ``unbounded`` for arbitrary number of arguments
91  
-  
  89
+
92 90
   .. NOTE::
93  
-	As of rpclib-2.8.0, use ``float('inf')`` instead of ``unbounded``.
94  
-  
  91
+    As of rpclib-2.8.0, use ``float('inf')`` instead of ``unbounded``.
  92
+
95 93
 These rules can be combined, the example below illustrates how to create a
96 94
 mandatory string:
97 95
 
98  
-	String(min_occurs=1, min_len=1, nillable=False)
99  
-	
  96
+    String(min_occurs=1, min_len=1, nillable=False)
  97
+
100 98
 
101 99
 Numbers
102 100
 ~~~~~~~
103  
-Integers and other countable numerical data types (i.e. except Float or 
104  
-Double) can be compared with specific values, using the following keywords: 
  101
+Integers and other countable numerical data types (i.e. except Float or
  102
+Double) can be compared with specific values, using the following keywords:
105 103
 ``ge``, ``gt``, ``le``, ``lt`` (they correspond to >=, >, <=, <) ::
106 104
 
107  
-	Integer(ge=1, le=12) #an integer between 1 and 12, i.e. 1 <= x <= 12
108  
-	Integer(gt=1, le=42) #1 < x <= 42
109  
-	
  105
+    Integer(ge=1, le=12) #an integer between 1 and 12, i.e. 1 <= x <= 12
  106
+    Integer(gt=1, le=42) #1 < x <= 42
  107
+
110 108
 
111 109
 Strings
112 110
 ~~~~~~~
113 111
 These can be validated against a regular expression: ::
114 112
 
115  
-	String(pattern = "[0-9]+") #must contain at least one digit, digits only 
116  
-	
117  
-	
  113
+    String(pattern = "[0-9]+") #must contain at least one digit, digits only
  114
+
  115
+
118 116
 Length checks can be enforced as well: ::
119 117
 
120  
-	String(min_len = 5, max_len = 10)
121  
-	String(max_len = 10) #implicit value for min_len = 0
  118
+    String(min_len = 5, max_len = 10)
  119
+    String(max_len = 10) #implicit value for min_len = 0
122 120
 
123 121
 
124 122
 Other string-related constraints are related to encoding issues. You can specify
125 123
 
126 124
 - which encoding the strings must be in
127 125
 - how to handle the situations in which a string cannot be decoded properly (to
128  
-  understand how this works, consult `Python's documentation 
  126
+  understand how this works, consult `Python's documentation
129 127
   <http://docs.python.org/howto/unicode.html>`_ ::
130 128
 
131 129
         String(encoding = 'win-1251')
132 130
         String(unicode_errors = 'strict') #could be 'replace' or 'ignore'
133 131
 
134  
-		
  132
+
135 133
 These restrictions can be combined: ::
136 134
 
137  
-	String(encoding = 'win-1251', max_len = 20)
138  
-	String(min_len = 5, max_len = 20, pattern = '[a-z]')
139  
-	
  135
+    String(encoding = 'win-1251', max_len = 20)
  136
+    String(min_len = 5, max_len = 20, pattern = '[a-z]')
  137
+
140 138
 
141 139
 Possible values
142 140
 ~~~~~~~~~~~~~~~
@@ -144,9 +142,9 @@ Sometimes you may want to allow only a certain set of values, which would be
144 142
 difficult to describe in terms of an interval. If this is the case, you can
145 143
 explicitly indicate the set: ::
146 144
 
147  
-	Integer(values = [1984, 13, 45, 42])
148  
-	Unicode(values = [u"alpha", u"bravo", u"charlie"]) #note the 'u' prefix
149  
-	
  145
+    Integer(values = [1984, 13, 45, 42])
  146
+    Unicode(values = [u"alpha", u"bravo", u"charlie"]) #note the 'u' prefix
  147
+
150 148
 
151 149
 
152 150
 Extending the rules of XML validation
@@ -159,7 +157,7 @@ from ``ModelBase``.
159 157
 
160 158
 
161 159
 After that, you must apply the relevant changes in the code that generates the
162  
-XML schema, otherwise these attributes will **not** be visible in the output. 
  160
+XML schema, otherwise these attributes will **not** be visible in the output.
163 161
 
164 162
 Examples of how to do that:
165 163
 https://github.com/arskom/rpclib/tree/master/src/rpclib/interface/xml_schema/model
@@ -170,7 +168,7 @@ https://github.com/arskom/rpclib/tree/master/src/rpclib/interface/xml_schema/mod
170 168
 
171 169
 Advanced validation
172 170
 -------------------
173  
-*rpclib* offers several primitives for this purpose, they are defined in 
  171
+*rpclib* offers several primitives for this purpose, they are defined in
174 172
 the **ModelBase** class, from which all the types are derived:
175 173
 https://github.com/arskom/rpclib/blob/master/src/rpclib/model/_base.py
176 174
 
@@ -181,36 +179,36 @@ These primitives are:
181 179
 - *validate_native* - invoked after the string is converted to a specific Python
182 180
   value.
183 181
 
184  
-Since XML is a text file, when you read it - you get a string; thus 
185  
-*validate_string* is the first filter that can be applied to such data. 
  182
+Since XML is a text file, when you read it - you get a string; thus
  183
+*validate_string* is the first filter that can be applied to such data.
186 184
 
187 185
 At a later stage, the data can be converted to something else, for example - a
188 186
 number. Once that conversion occurs, you can apply some additional checks - this
189 187
 is handled by *validate_native*.
190 188
 
191  
-	>>> stringNumber = '123'
192  
-	>>> stringNumber
193  
-	'123'		#note the quotes, it is a string
194  
-	>>> number = int(stringNumber)
195  
-	>>> number
196  
-	123 		#notice the absence of quotes, it is a number
197  
-	>>> stringNumber == 123
198  
-	False		#note quite what one would expect, right?
199  
-	>>> number == 123
200  
-	True
201  
-
202  
-In the example above, *number* is an actual number and can be validated with 
203  
-*validate_native*, whereas *stringNumber* is a string and can be validated by 
  189
+    >>> stringNumber = '123'
  190
+    >>> stringNumber
  191
+    '123'        #note the quotes, it is a string
  192
+    >>> number = int(stringNumber)
  193
+    >>> number
  194
+    123         #notice the absence of quotes, it is a number
  195
+    >>> stringNumber == 123
  196
+    False        #note quite what one would expect, right?
  197
+    >>> number == 123
  198
+    True
  199
+
  200
+In the example above, *number* is an actual number and can be validated with
  201
+*validate_native*, whereas *stringNumber* is a string and can be validated by
204 202
 *validate_string*.
205 203
 
206 204
 
207  
-Another case in which you need a native validation would be a sanity check on a 
208  
-date. Imagine that you have to verify if a received date complies with the 
209  
-*"YYYY-MM-DDThh:mm:ss"* pattern (which is *xs:datetime*). You can devise a 
  205
+Another case in which you need a native validation would be a sanity check on a
  206
+date. Imagine that you have to verify if a received date complies with the
  207
+*"YYYY-MM-DDThh:mm:ss"* pattern (which is *xs:datetime*). You can devise a
210 208
 regular expression that will look for 4 digits (YYYY), followed by a dash, then
211 209
 by 2 more digits for the month, etc. But such a regexp will happily absorb dates
212 210
 that have "13" as a month number, even though that doesn't make sense. You can
213  
-make a more complex regexp to deal with that, but it will be very hard to 
  211
+make a more complex regexp to deal with that, but it will be very hard to
214 212
 maintain and debug. The best approach is to convert the string into a datetime
215 213
 object and then perform all the checks you want.
216 214
 
@@ -224,16 +222,16 @@ We'll have to declare our own class, derived from *Unicode* (which, in turn, is
224 222
 derived from *SimpleModel*, which inherits from *ModelBase*).::
225 223
 
226 224
 
227  
-	class SpecialString(Unicode):
228  
-		"""Custom string type that prohibis the use of colons"""
229  
-		
230  
-		@staticmethod
231  
-		def validate_string(cls, value):
232  
-			"""Override the function to enforce our own verification logic"""
233  
-			if value:
234  
-				if ':' in value:
235  
-					return True
236  
-			return False
  225
+    class SpecialString(Unicode):
  226
+        """Custom string type that prohibis the use of colons"""
  227
+
  228
+        @staticmethod
  229
+        def validate_string(cls, value):
  230
+            """Override the function to enforce our own verification logic"""
  231
+            if value:
  232
+                if ':' in value:
  233
+                    return True
  234
+            return False
237 235
 
238 236
 
239 237
 
@@ -245,62 +243,56 @@ This time both flavours of validation are combined: *validate_string* to see if
245 243
 it is a number, and then *validate_native* to see if it is prime.
246 244
 
247 245
 .. NOTE::
248  
-	*rpclib* has a primitive type called *Integer*, it is reasonable to use that
249  
-	one as a basis for this custom type. *Unicode* is used in this example
250  
-	simply because it is an opportunity to show both types of validation
251  
-	functions in action. This may be a good academic example, but it is 
252  
-	certainly not the approach one would use in production code.
253  
-
  246
+    *rpclib* has a primitive type called *Integer*, it is reasonable to use that
  247
+    one as a basis for this custom type. *Unicode* is used in this example
  248
+    simply because it is an opportunity to show both types of validation
  249
+    functions in action. This may be a good academic example, but it is
  250
+    certainly not the approach one would use in production code.
254 251
 
255 252
 ::
256 253
 
257  
-	class PrimeNumber(Unicode):
258  
-		"""Custom integer type that only works with prime numbers"""
259  
-		
260  
-		@staticmethod
261  
-		def validate_string(cls, value):
262  
-			"""See if it is a number"""
263  
-			import re
264  
-						
265  
-			if re.search("[0-9]+", value):
266  
-				return True
267  
-			else:
268  
-				return False
269  
-
270  
-		@staticmethod
271  
-		def validate_native(cls, value):
272  
-			"""See if it is prime"""
273  
-			
274  
-			#calling a hypothetical function that checks if it is prime
275  
-			return IsPrime(value)
  254
+    class PrimeNumber(Unicode):
  255
+        """Custom integer type that only works with prime numbers"""
276 256
 
  257
+        @staticmethod
  258
+        def validate_string(cls, value):
  259
+            """See if it is a number"""
  260
+            import re
  261
+
  262
+            if re.search("[0-9]+", value):
  263
+                return True
  264
+            else:
  265
+                return False
  266
+
  267
+        @staticmethod
  268
+        def validate_native(cls, value):
  269
+            """See if it is prime"""
  270
+
  271
+            #calling a hypothetical function that checks if it is prime
  272
+            return IsPrime(value)
277 273
 
278 274
 .. NOTE::
279  
-	Constraints applied at this level do **not modify** the XML schema itself,
280  
-	thus a client that retrieves the WSDL of the service will not be aware of
281  
-	these restrictions. Keep this in mind and make sure that validation rules
282  
-	that are not visible in the XML schema are documented elsewhere.
283  
-			
284  
-.. NOTE::
285  
-	When overriding ``validate_string`` or ``validate_native`` in a custom type
286  
-	class, the validation functions from the parent class are **not invoked**.
287  
-	If you wish to apply those validation functions as well, you must call them
288  
-	explicitly.
  275
+    Constraints applied at this level do **not modify** the XML schema itself,
  276
+    thus a client that retrieves the WSDL of the service will not be aware of
  277
+    these restrictions. Keep this in mind and make sure that validation rules
  278
+    that are not visible in the XML schema are documented elsewhere.
289 279
 
  280
+.. NOTE::
  281
+    When overriding ``validate_string`` or ``validate_native`` in a custom type
  282
+    class, the validation functions from the parent class are **not invoked**.
  283
+    If you wish to apply those validation functions as well, you must call them
  284
+    explicitly.
290 285
 
291  
-		
292 286
 Summary
293 287
 =======
294 288
 - simple checks can be applied at the XML schema level, you can control:
295  
-
296 289
   - the length of a string
297 290
   - the pattern with which a string must comply
298 291
   - a numeric interval, etc
299  
-  
300  
-- *rpclib* can apply arbitrary rules for the validation of input data
301 292
 
  293
+- *rpclib* can apply arbitrary rules for the validation of input data
302 294
   - *validate_string* is the first applied filter
303 295
   - *validate_native* is the applied at the second phase
304 296
   - Override these functions in your derived class to add new validation rules
305 297
   - The validation functions must return a *boolean* value
306  
-  - These rules are **not** shown in the XML schema
  298
+  - These rules are **not** shown in the XML schema
2  examples/authentication/http_cookie/server_soap.py
@@ -176,7 +176,7 @@ def _on_method_call(ctx):
5  examples/helloworld_soap_twisted.py
@@ -62,6 +62,11 @@ def say_hello(name, times):
62 62
 if __name__=='__main__':
63 63
     application = Application([HelloWorldService], 'rpclib.examples.hello.twisted',
64 64
                 interface=Wsdl11(), in_protocol=Soap11(), out_protocol=Soap11())
  65
+
  66
+    application.interface.nsmap[None] = application.interface.nsmap['tns']
  67
+    application.interface.prefmap[application.interface.nsmap['tns']] = None
  68
+    del application.interface.nsmap['tns']
  69
+
65 70
     wsgi_app = WsgiApplication(application)
66 71
 
67 72
     print('listening on 0.0.0.0:7789')
2  examples/validation.py
@@ -24,7 +24,7 @@ def get_name_of_month(month):
24 24
 from rpclib.server.wsgi import WsgiApplication
25 25
 from wsgiref.simple_server import make_server
26 26
 
27  
-host = '127.0.0.1' 
  27
+host = '127.0.0.1'
28 28
 port = 9912
29 29
 
30 30
 server = make_server(host, port, WsgiApplication(rest))
4  setup.py
@@ -17,7 +17,7 @@
17 17
 tools for creating and publishing web services in python.  This package
18 18
 features on-demand wsdl generation for the published services, a
19 19
 wsgi-compliant web application, support for complex class structures, binary
20  
-attachments, and a simple framework for creating additional serialization 
  20
+attachments, and a simple framework for creating additional serialization
21 21
 mechanisms.
22 22
 
23 23
 This project uses lxml as it's XML API, providing full namespace support.
@@ -61,7 +61,7 @@
61 61
     maintainer='Burak Arslan',
62 62
     maintainer_email='burak+rpclib@arskom.com.tr',
63 63
     url='http://github.com/arskom/rpclib',
64  
-    license='LGPL',
  64
+    license='LGPL-2.1',
65 65
     zip_safe=False,
66 66
     install_requires=[
67 67
       'pytz',
1  src/rpclib/__init__.py
@@ -19,6 +19,7 @@
19 19
 
20 20
 __version__ = '2.8.0-beta'
21 21
 
  22
+from rpclib._base import AuxMethodContext
22 23
 from rpclib._base import TransportContext
23 24
 from rpclib._base import EventContext
24 25
 from rpclib._base import MethodContext
14  src/rpclib/_base.py
@@ -27,6 +27,15 @@
27 27
 from rpclib.const.xml_ns import DEFAULT_NS
28 28
 from rpclib.util.oset import oset
29 29
 
  30
+class AuxMethodContext(object):
  31
+    """Generic object that holds information specific to auxiliary methods"""
  32
+    def __init__(self, p_ctx, error):
  33
+        self.p_ctx = p_ctx
  34
+        """Primary context that this method was bound to."""
  35
+
  36
+        self.error = error
  37
+        """Error from primary context (if any)."""
  38
+
30 39
 class TransportContext(object):
31 40
     """Generic object that holds transport-specific context information"""
32 41
     def __init__(self, transport, type=None):
@@ -88,6 +97,11 @@ def __init__(self, transport):
88 97
         events, as you'd probably want to separate the event data from the
89 98
         method data."""
90 99
 
  100
+        self.aux = None
  101
+        """Auxiliary-method specific context. You can use this to share data
  102
+        between auxiliary sessions. This is not set in primary methods.
  103
+        """
  104
+
91 105
         self.method_request_string = None
92 106
         """This is used as a basis on deciding which native method to call."""
93 107
 
5  src/rpclib/application.py
@@ -145,7 +145,8 @@ def process_request(self, ctx):
145 145
     def call_wrapper(self, ctx):
146 146
         """This method calls the call_wrapper method in the service definition.
147 147
         This can be overridden to make an application-wide custom exception
148  
-        management."""
  148
+        management.
  149
+        """
149 150
 
150 151
         return ctx.service_class.call_wrapper(ctx)
151 152
 
@@ -159,5 +160,5 @@ def reinitialize(self):
159 160
         aux_memo = set()
160 161
         for s,d in self.interface.method_id_map.values():
161 162
             if d.aux is not None and not id(d.aux) in aux_memo:
162  
-                d.aux.initialize(server, db=self.main)
  163
+                d.aux.initialize(server)
163 164
                 aux_memo.add(id(d.aux))
2  src/rpclib/aux/__init__.py
@@ -20,7 +20,7 @@
20 20
 """Module that contains backends that process the auxiliary contexts. These
21 21
 result from non-primary functions in service definitions.
22 22
 
23  
-Classes from this package will have the ``AuxProc`` suffix, short for 
  23
+Classes from this package will have the ``AuxProc`` suffix, short for
24 24
 "Auxiliary Processor". Sounds neat, huh? :)
25 25
 
26 26
 This package is EXPERIMENTAL. Stay away from it.
22  src/rpclib/aux/_base.py
@@ -20,11 +20,14 @@
20 20
 import logging
21 21
 logger = logging.getLogger(__name__)
22 22
 
  23
+from rpclib import AuxMethodContext
  24
+
23 25
 
24 26
 def process_contexts(server, contexts, p_ctx, error=None):
25 27
     for ctx in contexts:
  28
+        ctx.descriptor.aux.initialize_context(ctx, p_ctx, error)
26 29
         if error is None or ctx.descriptor.aux.process_exceptions:
27  
-            ctx.descriptor.aux.process_context(server, ctx, p_ctx, error)
  30
+            ctx.descriptor.aux.process_context(server, ctx)
28 31
 
29 32
 
30 33
 class AuxProcBase(object):
@@ -32,11 +35,7 @@ def __init__(self, process_exceptions=False):
32 35
         self.methods = []
33 36
         self.process_exceptions = process_exceptions
34 37
 
35  
-    def initialize(self):
36  
-        pass
37  
-
38  
-    def process(self, server, ctx, p_ctx, p_error, *args, **kwargs):
39  
-        logger.debug("Executing %r" % ctx.service_class.get_method_id(ctx.descriptor))
  38
+    def process(self, server, ctx, *args, **kwargs):
40 39
         server.get_in_object(ctx)
41 40
         if ctx.in_error is not None:
42 41
             logger.exception(ctx.in_error)
@@ -49,4 +48,13 @@ def process(self, server, ctx, p_ctx, p_error, *args, **kwargs):
49 48
 
50 49
         server.get_out_string(ctx)
51 50
         for s in ctx.out_string:
52  
-            logger.debug(s)
  51
+            pass
  52
+
  53
+    def process_context(self, server, ctx, p_ctx, p_error):
  54
+        raise NotImplementedError()
  55
+
  56
+    def initialize(self, server):
  57
+        pass
  58
+
  59
+    def initialize_context(self, ctx, p_ctx, error):
  60
+        ctx.aux = AuxMethodContext(p_ctx, error)
4  src/rpclib/aux/sync.py
@@ -24,5 +24,5 @@
24 24
 
25 25
 
26 26
 class SyncAuxProc(AuxProcBase):
27  
-    def process_context(self, server, ctx, p_ctx, p_error):
28  
-        self.process(server, ctx, p_ctx, p_error)
  27
+    def process_context(self, server, ctx):
  28
+        self.process(server, ctx)
10  src/rpclib/aux/thread.py
@@ -28,15 +28,19 @@
28 28
 class ThreadAuxProc(AuxProcBase):
29 29
     def __init__(self, pool_size=1):
30 30
         AuxProcBase.__init__(self)
  31
+
  32
+        self.pool = None
31 33
         self.__pool_size = pool_size
32  
-        self.pool = ThreadPool(pool_size)
33 34
 
34 35
     @property
35 36
     def pool_size(self):
36 37
         return self.__pool_size
37 38
 
38  
-    def process_context(self, server, ctx, p_ctx, p_error, *args, **kwargs):
39  
-        a = [server, ctx, p_ctx, p_error]
  39
+    def process_context(self, server, ctx, *args, **kwargs):
  40
+        a = [server, ctx]
40 41
         a.extend(args)
41 42
 
42 43
         self.pool.apply_async(self.process, a, kwargs)
  44
+
  45
+    def initialize(self, server):
  46
+        self.pool = ThreadPool(self.__pool_size)
3  src/rpclib/client/_base.py
@@ -149,7 +149,8 @@ def get_in_object(self, ctx):
149 149
 
150 150
         type_info = ctx.descriptor.out_message._type_info
151 151
 
152  
-        if len(ctx.descriptor.out_message._type_info) == 1: # TODO: Non-Wrapped Object Support
  152
+        # TODO: Non-Wrapped Object Support
  153
+        if len(ctx.descriptor.out_message._type_info) == 1:
153 154
             wrapper_attribute = type_info.keys()[0]
154 155
             ctx.in_object = getattr(ctx.in_object, wrapper_attribute, None)
155 156
 
18  src/rpclib/const/ansi_color.py
... ...
@@ -1,14 +1,22 @@
1 1
 
  2
+DARK_RED = ""
2 3
 LIGHT_GREEN = ""
3 4
 LIGHT_RED = ""
  5
+LIGHT_BLUE = ""
4 6
 END_COLOR = ""
5 7
 
6 8
 def enable_color():
7 9
     global LIGHT_GREEN
8  
-    LIGHT_GREEN = "\033[92m"
  10
+    LIGHT_GREEN = "\033[1;32m"
9 11
 
10 12
     global LIGHT_RED
11  
-    LIGHT_RED = "\033[91m"
  13
+    LIGHT_RED = "\033[1;31m"
  14
+
  15
+    global LIGHT_BLUE
  16
+    LIGHT_BLUE = "\033[1;34m"
  17
+
  18
+    global DARK_RED
  19
+    DARK_RED = "\033[0;31m"
12 20
 
13 21
     global END_COLOR
14 22
     END_COLOR = "\033[0m"
@@ -21,6 +29,12 @@ def disable_color():
21 29
     global LIGHT_RED
22 30
     LIGHT_RED = ""
23 31
 
  32
+    global LIGHT_BLUE
  33
+    LIGHT_BLUE = ""
  34
+
  35
+    global DARK_RED
  36
+    DARK_RED = ""
  37
+
24 38
     global END_COLOR
25 39
     END_COLOR = ""
26 40
 
9  src/rpclib/interface/_base.py
@@ -32,6 +32,7 @@
32 32
 from rpclib.const.suffix import RESPONSE_SUFFIX
33 33
 
34 34
 from rpclib.model import ModelBase
  35
+from rpclib.model.complex import Alias
35 36
 from rpclib.model.complex import ComplexModelBase
36 37
 
37 38
 
@@ -276,6 +277,11 @@ def get_namespace_prefix(self, ns):
276 277
         return pref
277 278
 
278 279
     def add_class(self, cls):
  280
+        if issubclass(cls, Alias):
  281
+            if issubclass(cls._target, ComplexModelBase):
  282
+                self.add_class(cls._target)
  283
+            return
  284
+
279 285
         if self.has_class(cls):
280 286
             return
281 287
 
@@ -323,6 +329,8 @@ def is_valid_import(self, ns):
323 329
 
324 330
 
325 331
 class InterfaceDocumentBase(object):
  332
+    """Base class for all interface document implementations"""
  333
+
326 334
     def __init__(self, interface):
327 335
         self.interface = interface
328 336
 
@@ -335,7 +343,6 @@ def build_interface_document(self, cls):
335 343
 
336 344
         raise NotImplementedError('Extend and override.')
337 345
 
338  
-
339 346
     def get_interface_document(self, cls):
340 347
         """This function is called by server transports that try to satisfy the
341 348
         request for the interface document. This should just return a previously
10  src/rpclib/interface/wsdl/wsdl11.py
@@ -405,7 +405,7 @@ def add_bindings_for_methods(self, service, root, service_name,
405 405
                                      cb_binding):
406 406
 
407 407
         pref_tns = self.interface.get_namespace_prefix(service.get_tns())
408  
-        
  408
+
409 409
         def inner(binding):
410 410
             for method in service.public_methods.values():
411 411
                 operation = etree.Element('{%s}operation' % _ns_wsdl)
@@ -508,11 +508,11 @@ def inner(binding):
508 508
                         mid_header.set('use', 'literal')
509 509
 
510 510
                     binding.append(operation)
511  
-        
  511
+
512 512
         port_type_list = service.get_port_types()
513 513
         if len(port_type_list) > 0:
514 514
             for port_type_name in port_type_list:
515  
-                
  515
+
516 516
                 # create binding nodes
517 517
                 binding = etree.SubElement(root, '{%s}binding' % _ns_wsdl)
518 518
                 binding.set('name', port_type_name)
@@ -520,7 +520,7 @@ def inner(binding):
520 520
 
521 521
                 transport = etree.SubElement(binding, '{%s}binding' % _ns_soap)
522 522
                 transport.set('style', 'document')
523  
-                
  523
+
524 524
                 inner(binding)
525 525
 
526 526
         else:
@@ -533,7 +533,7 @@ def inner(binding):
533 533
                 transport = etree.SubElement(cb_binding, '{%s}binding' % _ns_soap)
534 534
                 transport.set('style', 'document')
535 535
                 transport.set('transport', self.interface.app.transport)
536  
-            
  536
+
537 537
             inner(cb_binding)
538 538
 
539 539
         return cb_binding
7  src/rpclib/interface/xml_schema/_base.py
@@ -37,11 +37,13 @@
37 37
 from rpclib.model.primitive import Decimal
38 38
 from rpclib.model.primitive import String
39 39
 from rpclib.model.complex import ComplexModelBase
  40
+from rpclib.model.complex import Alias
40 41
 from rpclib.model.enum import EnumBase
41 42
 from rpclib.model.fault import Fault
42 43
 from rpclib.util.odict import odict
43 44
 
44 45
 from rpclib.interface.xml_schema.model import simple_add
  46
+from rpclib.interface.xml_schema.model.complex import alias_add
45 47
 from rpclib.interface.xml_schema.model.complex import complex_add
46 48
 from rpclib.interface.xml_schema.model.fault import fault_add
47 49
 from rpclib.interface.xml_schema.model.enum import enum_add
@@ -52,6 +54,7 @@
52 54
 
53 55
 _add_handlers = cdict({
54 56
     object: lambda interface, cls: None,
  57
+    Alias: alias_add,
55 58
     SimpleModel: simple_add,
56 59
     ComplexModelBase: complex_add,
57 60
     Fault: fault_add,
@@ -161,7 +164,7 @@ def build_validation_schema(self):
161 164
 
162 165
     def get_schema_node(self, pref):
163 166
         """Return schema node for the given namespace prefix."""
164  
-        # create schema node
  167
+
165 168
         if not (pref in self.schema_dict):
166 169
             schema = etree.Element("{%s}schema" % _ns_xsd, nsmap=self.interface.nsmap)
167 170
 
@@ -171,7 +174,7 @@ def get_schema_node(self, pref):
171 174
             self.schema_dict[pref] = schema
172 175
 
173 176
         else:
174  
-            schema = self.schema_nodes[pref]
  177
+            schema = self.schema_dict[pref]
175 178
 
176 179
         return schema
177 180
 
6  src/rpclib/interface/xml_schema/model/complex.py
@@ -122,13 +122,9 @@ def complex_add(document, cls):
122 122
 
123 123
     document.add_element(cls, element)
124 124
 
125  
-
126 125
 def alias_add(document, cls):
127  
-    if not document.has_class(cls._target):
128  
-        document.add(cls._target)
129  
-
130 126
     element = etree.Element('{%s}element' % namespace.xsd)
131 127
     element.set('name', cls.get_type_name())
132  
-    element.set('type', cls._target.get_type_name_ns(document.interface.app))
  128
+    element.set('type', cls._target.get_type_name_ns(document.interface))
133 129
 
134 130
     document.add_element(cls, element)
11  src/rpclib/model/_base.py
@@ -146,8 +146,15 @@ def resolve_namespace(cls, default_ns):
146 146
             cls.__namespace__ = default_ns
147 147
 
148 148
         if cls.__namespace__ is None:
149  
-            cls.__namespace__ = cls.__module__
150  
- 
  149
+            ret = []
  150
+            for f in cls.__module__.split('.'):
  151
+                if f.startswith('_'):
  152
+                    break
  153
+                else:
  154
+                    ret.append(f)
  155
+
  156
+            cls.__namespace__ = '.'.join(ret)
  157
+
151 158
     @classmethod
152 159
     def get_type_name(cls):
153 160
         """Returns the class name unless the __type_name__ attribute is defined.
32  src/rpclib/model/complex.py
@@ -87,7 +87,8 @@ def describe(self, name, element, app):
87 87
 
88 88
 
89 89
 class SelfReference(object):
90  
-    pass
  90
+    def __init__(self):
  91
+        raise NotImplementedError()
91 92
 
92 93
 
93 94
 class ComplexModelMeta(type(ModelBase)):
@@ -140,12 +141,17 @@ def __new__(cls, cls_name, cls_bases, cls_dict):
140 141
                                                                 % (cls_name, k))
141 142
         else:
142 143
             _type_info = cls_dict['_type_info']
  144
+
143 145
             if not isinstance(_type_info, TypeInfo):
144 146
                 cls_dict['_type_info'] = TypeInfo(_type_info)
145 147
 
146 148
                 for k, v in _type_info.items():
147  
-                    if not issubclass(v, ModelBase):
  149
+                    if issubclass(v, SelfReference):
  150
+                        pass
  151
+
  152
+                    elif not issubclass(v, ModelBase):
148 153
                         raise ValueError( (k,v) )
  154
+
149 155
                     elif issubclass(v, Array) and len(v._type_info) != 1:
150 156
                         raise Exception("Invalid Array definition in %s.%s."
151 157
                                                                 % (cls_name, k))
@@ -153,10 +159,10 @@ def __new__(cls, cls_name, cls_bases, cls_dict):
153 159
         return type(ModelBase).__new__(cls, cls_name, cls_bases, cls_dict)
154 160
 
155 161
     def __init__(self, cls_name, cls_bases, cls_dict):
156  
-        for k in cls_dict:
157  
-            if cls_dict[k] is SelfReference:
158  
-                cls_dict[k] = self
159  
-                self._type_info[k] = self
  162
+        type_info = cls_dict['_type_info']
  163
+        for k in type_info:
  164
+            if type_info[k] is SelfReference:
  165
+                type_info[k] = self
160 166
 
161 167
         type(ModelBase).__init__(self, cls_name, cls_bases, cls_dict)
162 168
 
@@ -169,8 +175,8 @@ class ComplexModelBase(ModelBase):
169 175
     def __init__(self, **kwargs):
170 176
         super(ComplexModelBase, self).__init__()
171 177
 
172  
-        # this ugliness is due to sqlalchemy's forcing relevant types for database
173  
-        # fields
  178
+        # this ugliness is due to sqlalchemy's forcing of relevant types for
  179
+        # database fields
174 180
         for k in self.get_flat_type_info(self.__class__).keys():
175 181
             try:
176 182
                 delattr(self, k)
@@ -257,7 +263,6 @@ def get_members_pairs(cls, inst):
257 263
             else:
258 264
                 yield (k, [v.to_string(subvalue)])
259 265
 
260  
-
261 266
     @classmethod
262 267
     @nillable_dict
263 268
     def to_dict(cls, value):
@@ -338,7 +343,7 @@ def from_string(cls, string):
338 343
     def resolve_namespace(cls, default_ns):
339 344
         if getattr(cls, '__extends__', None) != None:
340 345
             cls.__extends__.resolve_namespace(cls.__extends__, default_ns)
341  
-        
  346
+
342 347
         ModelBase.resolve_namespace(cls, default_ns)
343 348
 
344 349
         for k, v in cls._type_info.items():
@@ -378,10 +383,13 @@ def alias(type_name, namespace, target):
378 383
 
379 384
         cls_dict['__namespace__'] = namespace
380 385
         cls_dict['__type_name__'] = type_name
381  
-        cls_dict['_type_info'] = getattr(target, '_type_info', ())
382 386
         cls_dict['_target'] = target
383 387
 
384  
-        return ComplexModelMeta(type_name, (ClassAlias,), cls_dict)
  388
+        ti = getattr(target, '_type_info', None)
  389
+        if ti is not None:
  390
+            cls_dict['_type_info'] = ti
  391
+
  392
+        return ComplexModelMeta(type_name, (Alias,), cls_dict)
385 393
 
386 394
     @classmethod
387 395
     def customize(cls, **kwargs):
8 