diff --git a/doc/api.rst b/doc/api.rst index 1071699..ac3e496 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -28,15 +28,15 @@ Internals .. automodule:: wsme.types :members: register_type -:mod:`wsme.controller` -- Controller -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:mod:`wsme.api` -- API related api +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. automodule:: wsme.controller +.. automodule:: wsme.api :members: scan_api, FunctionArgument, FunctionDefinition -:mod:`wsme.rest` -- REST protocol commons -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:mod:`wsme.protocols.rest` -- REST protocol commons +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. automodule:: wsme.rest +.. automodule:: wsme.protocols.rest :members: diff --git a/doc/changes.rst b/doc/changes.rst index d25e3c3..42596a1 100644 --- a/doc/changes.rst +++ b/doc/changes.rst @@ -13,6 +13,12 @@ Changes * Fix: If a complex type was only used as an input type, it was not registered. +* Add support for user types. + +* Add an Enum type (which is a user type). + +* The 'binary' type is now a user type. + * Complex types: - Fix inspection of complex types with inheritance. diff --git a/doc/index.rst b/doc/index.rst index 7be1e3c..147c801 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -9,6 +9,7 @@ Contents gettingstarted api + types protocols integrate diff --git a/doc/types.rst b/doc/types.rst new file mode 100644 index 0000000..343a012 --- /dev/null +++ b/doc/types.rst @@ -0,0 +1,184 @@ +Types +===== + +3 kinds of data types can be used as input or output by WSME. + +Native types +------------ + +The native types are a fixed set of standard python types that +the different protocols will map to theirs own basic types. + +The native types are : + + - :class:`str` + - :class:`unicode` + - :class:`int` + - :class:`float` + - :class:`bool` + - :class:`decimal.Decimal` + - :class:`datetime.date` + - :class:`datetime.datetime` + - :class:`datetime.time` + + - Arrays -- This is a special case. When stating a list + datatype, always state its content type as the unique element + of a list. Example:: + + class SomeWebService(object): + @expose([str]) + def getlist(self): + return ['a', 'b', 'c'] + +There are other types that are supported out of the boxe, see +the :ref:`pre-defined-user-types`. + +User types +---------- + +User types allow to define new almost-native types. + +The idea is that you may have python data that should be transported as native +types by the different protocols, but needs conversion to/from this basetypes, +or needs to validate data integrity. + +To define a user type, you just have to inherit from +:class:`wsme.types.UserType` and instanciate your new class. This instance +will be your new type and can be used as @:class:`wsme.expose` or +@:class:`wsme.validate` parameters. + +Note that protocols can choose to specifically handle a user type or +a base class of user types. This is case with the two pre-defined +user types, :class:`wsme.types.Enum` and :data:`wsme.types.binary`. + +.. _pre-defined-user-types: + +Pre-defined user types +~~~~~~~~~~~~~~~~~~~~~~ + +WSME provides some pre-defined user types: + +- :class:`binary ` -- for transporting binary data as + base64 strings. +- :class:`Enum ` -- enforce that the values belongs to a + pre-defined list of values. + +These types are good examples of how to define user types. Have +a look at their source code ! + +Here is a little example that combines :class:`binary ` +and :class:`Enum `:: + + ImageKind = Enum(str, 'jpeg', 'gif') + + class Image(object): + name = unicode + kind = ImageKind + data = binary + +.. data:: wsme.types.binary + + The :class:`wsme.types.BinaryType` instance to use when you need to + transfert base64 encoded data. + +.. autoclass:: wsme.types.BinaryType + +.. autoclass:: wsme.types.Enum + + +Complex types +------------- + +Complex types are structured types. They are defined as simple python classes +and will be mapped to adequate structured types in the various protocols. + +The attributes that are set at the class level will be used by WSME to discover +the structure. These attributes can be: + + - A datatype -- Any native, user or complex type. + - A :class:`wsattr ` -- Allow to add more information about + the attribute, for example if it is mandatory. + - A :class:`wsproperty ` -- Special typed property. Works + like standard properties with additional properties like + :class:`wsattr `. + +Attributes having a leading '_' in there name will be ignored, as well as the +ones that are none of the above list. It means the type can have functions, +they will not get in the way. + +Example +~~~~~~~ + +:: + + Gender = Enum(str, 'male', 'female') + Title = Enum(str, 'M', 'Mrs') + + class Person(object): + lastname = wsattr(unicode, mandatory=True) + firstname = wsattr(unicode, mandatory=True) + + age = int + gender = Gender + title = Title + + hobbies = [unicode] + +Rules +~~~~~ + +A few things you should know about complex types: + + - The class must have a default constructor -- + Since instances of the type will be created by the protocols when + used as input types, they must be instanciable without any argument. + + - Complex types are registered automatically + (and thus inspected) as soon a they are used in expose or validate, + even if they are nested in another complex type. + + If for some reasons you need to control when type is inspected, you + can use :func:`wsme.types.register_type`. + + - The datatype attributes will be replaced + + When using the 'short' way of defining attributes, ie setting a + simple data type, they will be replaced by a wsattr instance. + + So, when you write:: + + class Person(object): + name = unicode + + After type registration the class will actually be equivalent to:: + + class Person(object): + name = wsattr(unicode) + + You can still access the datatype by accessing the attribute on the + class, along with the other wsattr properties:: + + class Person(object): + name = unicode + + register_type(Person) + + assert Person.name.datatype is unicode + assert Person.name.key == "name" + assert Person.name.mandatory is False + + - The default value of instances attributes is :data:`Unset `. + + :: + + class Person(object): + name = wsattr(unicode) + + p = Person() + assert p.name is Unset + + This allow the protocol to make a clear distinction between null values + that will be transmitted, and unset values that will not be transmitted. + + For input values, it allows the code to know if the values were, or not, + sent by the caller.