4.3.1. Entity Data Model (EDM)¶
This module defines functions and classes for working with data based on Microsoft’s Entity Data Model (EDM) as documented by the Conceptual Schema Definition Language and associated file format: http://msdn.microsoft.com/en-us/library/dd541474.aspx
The classes in this model fall in to two categories. The data classes represent the actual data objects, like simple and complex values, entities and collections. The metadata classes represent the elements of the metadata model like entity types, property definitions, associations, entity sets and so on. The metadata elements have direct XML representations, the data classes do not.
4.3.1.1. Data Model¶
-
class
pyslet.odata2.csdl.
EntityCollection
(entity_set, **kwargs)¶ Bases:
pyslet.odata2.csdl.DictionaryLike
,pyslet.pep8.PEP8Compatibility
Represents a collection of entities from an
EntitySet
.To use a database analogy, EntitySet’s are like tables whereas EntityCollections are more like the database cursors that you use to execute data access commands. An entity collection may consume physical resources (like a database connection) and so should be closed with the
close()
method when you’re done.Entity collections support the context manager protocol in python so you can use them in with statements to make clean-up easier:
with entity_set.open() as collection: if 42 in collection: print "Found it!"
The close method is called automatically when the with statement exits.
Entity collections also behave like a python dictionary of
Entity
instances keyed on a value representing the Entity’s key property or properties. The keys are either single values (as in the above code example) or tuples in the case of compound keys. The order of the values in the tuple is taken from the order of thePropertyRef
definitions in the metadata model. You can obtain an entity’s key from theEntity.key()
method.When an EntityCollection represents an entire entity set you cannot use dictionary assignment to modify the collection. You must use
insert_entity()
instead where the reasons for this restriction are expanded on.For consistency with python dictionaries the following statement is permitted, though it is effectively a no-operation:
etColl[key]=entity
The above statement raises KeyError if entity is not a member of the entity set. If key does not match the entity’s key then ValueError is raised.
Although you can’t add an entity with assignment you can delete an entity with the delete operator:
del etColl[key]
Deletes the entity with key from the entity set.
These two operations have a different meaning when a collection represents the subset of entities obtained through navigation. See
NavigationCollection
for details.Notes for data providers
Derived classes MUST call super in their __init__ method to ensure the proper construction of the parent collection class. The proper way to do this is:
class MyCollection(EntityCollection): def __init__(self,paramA,paramsB,**kwargs): # paramA and paramB are examples of how to # consume private keyword arguments in this # method so that they aren't passed on to the # next __init__ super(MyCollection,self).__init__(**kwargs)
All collections require a named entity_set argument, an
EntitySet
instance from which all entities in the collection are drawn.Derived classes MUST also override
itervalues()
. The implementation of itervalues must return an iterable object that honours the value of the expand query option, the current filter and the orderby rules.Derived classes SHOULD also override
__getitem__()
and__len__()
as the default implementations are very inefficient, particularly for non-trivial entity sets.Writeable data sources must override py:meth:__delitem__.
If a particular operation is not supported for some data-service specific reason then NotImplementedError must be raised.
Writeable entity collections SHOULD override
clear()
as the default implementation is very inefficient.-
entity_set
= None¶ the entity set from which the entities are drawn
-
expand
= None¶ the expand query option in effect
-
select
= None¶ the select query option in effect
-
filter
= None¶ a filter or None for no filter (see
check_filter()
)
-
orderby
= None¶ a list of orderby rules or None for no ordering
-
skip
= None¶ the skip query option in effect
-
top
= None¶ the top query option in effect
-
topmax
= None¶ the provider-enforced maximum page size in effect
-
inlinecount
= None¶ True if inlinecount option is in effect
The inlinecount option is used to alter the representation of the collection and, if set, indicates that the __len__ method will be called before iterating through the collection itself.
-
get_location
()¶ Returns the location of this collection as a
URI
instance.By default, the location is given as the location of the
entity_set
from which the entities are drawn.
-
get_title
()¶ Returns a user recognisable title for the collection.
By default this is the fully qualified name of the entity set in the metadata model.
-
set_expand
(expand, select=None)¶ Sets the expand and select query options for this collection.
The expand query option causes the named navigation properties to be expanded and the associated entities to be loaded in to the entity instances before they are returned by this collection.
- expand
A dictionary of expand rules. Expansions can be chained, represented by the dictionary entry also being a dictionary:
# expand the Customer navigation property... {'Customer': None } # expand the Customer and Invoice navigation properties {'Customer': None, 'Invoice': None} # expand the Customer property and then the Orders # property within Customer {'Customer': {'Orders': None}}
The select query option restricts the properties that are set in returned entities. The select option is a similar dictionary structure, the main difference being that it can contain the single key ‘*’ indicating that all data properties are selected.
-
select_keys
()¶ Sets the select rule to select the key property/properties only.
Any expand rule is removed.
-
expand_entities
(entity_iterable)¶ Utility method for data providers.
Given an object that iterates over all entities in the collection, returns a generator function that returns expanded entities with select rules applied according to
expand
andselect
rules.Data providers should use a better method of expanded entities if possible as this implementation simply iterates through the entities and calls
Entity.expand()
on each one.
-
set_filter
(filter)¶ Sets the filter object for this collection
See
check_filter()
for more information.
-
filter_entities
(entity_iterable)¶ Utility method for data providers.
Given an object that iterates over all entities in the collection, returns a generator function that returns only those entities that pass through the current
filter
object.Data providers should use a better method of filtering entities if possible as this implementation simply iterates through the entities and calls
check_filter()
on each one.
-
check_filter
(entity)¶ Checks entity against the current filter object and returns True if it passes.
This method is really a placeholder. Filtering is not covered in the CSDL model itself but is a feature of the OData
pyslet.odata2.core
module.See
pyslet.odata2.core.EntityCollectionMixin.check_filter()
for more. The implementation in the case class simply raises NotImplementedError if a filter has been set.
-
set_orderby
(orderby)¶ Sets the orderby rules for this collection.
- orderby
A list of tuples, each consisting of:
(an order object as used by :py:meth:`calculate_order_key` , 1 | -1 )
-
calculate_order_key
(entity, order_object)¶ Given an entity and an order object returns the key used to sort the entity.
This method is really a placeholder. Ordering is not covered in the CSDL model itself but is a feature of the OData
pyslet.odata2.core
module.See
pyslet.odata2.core.EntityCollectionMixin.calculate_order_key()
for more. The implementation in the case class simply raises NotImplementedError.
-
order_entities
(entity_iterable)¶ Utility method for data providers.
Given an object that iterates over the entities in random order, returns a generator function that returns the same entities in sorted order (according to the
orderby
object).This implementation simply creates a list and then sorts it based on the output of
calculate_order_key()
so is not suitable for use with long lists of entities. However, if no ordering is required then no list is created.
-
set_inlinecount
(inlinecount)¶ Sets the inline count flag for this collection.
-
new_entity
()¶ Returns a new py:class:Entity instance suitable for adding to this collection.
The data properties of the entity are set to null, not to their default values, even if the property is marked as not nullable.
The entity is not considered to exist until it is actually added to the collection. At this point we deviate from dictionary-like behaviour, Instead of using assignment you must call
insert_entity()
.:e=collection.new_entity() e["ID"]=1000 e["Name"]="Fred" assert 1000 not in collection collection[1000]=e # raises KeyError
The correct way to add the entity is:
collection.insert_entity(e)
The first block of code is prone to problems as the key 1000 may violate the collection’s key allocation policy so we raise KeyError when assignment is used to insert a new entity to the collection. This is consistent with the concept behind OData and Atom where new entities are POSTed to collections and the ID and resulting entity are returned to the caller on success because the service may have modified them to satisfy service-specific constraints.
-
copy_entity
(entity)¶ Creates a new entity copying the value from entity
The key is not copied and is initially set to NULL.
-
insert_entity
(entity)¶ Inserts entity into this entity set.
After a successful call to insert_entity:
- entity is updated with any auto-generated values such as
- an autoincrement correct key.
exists
is set to True for entity
Data providers must override this method if the collection is writable.
If the call is unsuccessful then entity should be discarded as its associated bindings may be in a misleading state (when compared to the state of the data source itself).
A general
ConstraintError
will be raised when the insertion violates model constraints (including an attempt to create two entities with duplicate keys).
-
update_entity
(entity, merge=True)¶ Updates entity which must already be in the entity set.
The optional merge parameter can be used to force replace semantics instead of the default merge. When merging, any unselected data properties are left unchanced. With merge=False unselected data properties are replaced with their default values as defined by the underlying container. You will have to read back the entity (without a select filter) to obtain those defaults as the values in the entity objects.
Data providers must override this method if the collection is writable.
-
update_bindings
(entity)¶ Iterates through the
Entity.navigation_items()
and generates appropriate calls to create/update any pending bindings.Unlike the
commit()
method, which updates all data and navigation values simultaneously, this method can be used to selectively update just the navigation properties.
-
set_page
(top, skip=0, skiptoken=None)¶ Sets the page parameters that determine the next page returned by
iterpage()
.The skip and top query options are integers which determine the number of entities returned (top) and the number of entities skipped (skip).
skiptoken is an opaque token previously obtained from a call to
next_skiptoken()
on a similar collection which provides an index into collection prior to any additional skip being applied.
-
set_topmax
(topmax)¶ Sets the maximum page size for this collection.
Data consumers should use
set_page()
to control paging, however data providers can use this method to force the collection to limit the size of a page to at most topmax entities. When topmax is in force and is less than the top value set inset_page()
,next_skiptoken()
will return a suitable value for identifying the next page in the collection immediately after a complete iteration ofiterpage()
.Provider enforced paging is optional, if it is not supported NotImplementedError must be raised.
-
iterpage
(set_next=False)¶ Returns an iterable subset of the values returned by
itervalues()
The subset is defined by the top, skip and skiptoken values set with
set_page()
If set_next is True then the page is automatically advanced so that the next call to iterpage iterates over the next page.
Data providers should override this implementation for a more efficient implementation. The default implementation simply wraps
itervalues()
.
-
next_skiptoken
()¶ Following a complete iteration of the generator returned by
iterpage()
, this method returns the skiptoken which will generate the next page or None if all requested entities were returned.
-
itervalues
()¶ Iterates over the collection.
The collection is filtered as defined by
set_filter()
and sorted according to any rules defined byset_orderby()
.Entities are also expanded and selected according to the rules defined by
set_expand
.Data providers must override this implementation which, by default, returns no entities (simulating an empty collection).
-
CopyEntity
(*args, **kwargs)¶ Deprecated equivalent to
copy_entity()
-
Expand
(*args, **kwargs)¶ Deprecated equivalent to
set_expand()
-
Filter
(*args, **kwargs)¶ Deprecated equivalent to
set_filter()
-
OrderBy
(*args, **kwargs)¶ Deprecated equivalent to
set_orderby()
-
SelectKeys
(*args, **kwargs)¶ Deprecated equivalent to
select_keys()
-
SetInlineCount
(*args, **kwargs)¶ Deprecated equivalent to
set_inlinecount()
-
TopMax
(*args, **kwargs)¶ Deprecated equivalent to
set_topmax()
-
-
class
pyslet.odata2.csdl.
Entity
(entity_set)¶ Bases:
pyslet.py2.SortableMixin
,pyslet.odata2.csdl.TypeInstance
Represents a single instance of an
EntityType
.Entity instance must only be created by data providers, a child class may be used with data provider-specific functionality. Data consumers should use the
EntityCollection.new_entity()
orEntityCollection.copy_entity
methods to create instances.- entity_set is the entity set this entity belongs to
Entity instances extend
TypeInstance
’s dictionary-like behaviour to include all properties. As a result the dictionary values are one ofSimpleValue
,Complex
or py:class:DeferredValue instances.Property values are created on construction and cannot be assigned directly. To update a simple value use the value’s
SimpleValue.set_from_value()
method:e['Name'].set_from_value("Steve") # update simple property Name e['Address']['City'].set_from_value("Cambridge") # update City in complex property Address
A simple valued property that is NULL is still a
SimpleValue
instance, though it will behave as 0 in tests:e['Name'].set_from_value(None) # set to NULL if e['Name']: print "Will not print!"
Navigation properties are represented as
DeferredValue
instances. A deferred value can be opened in a similar way to an entity set:# open the collection obtained from navigation property Friends with e['Friends'].open() as friends: # iterate through all the friends of entity e for friend in friends: print friend['Name']
A convenience method is provided when the navigation property points to a single entity (or None) by definition:
mum=e['Mother'].get_entity() # may return None
In the EDM one or more properties are marked as forming the entity’s key. The entity key is unique within the entity set. On construction, an Entity instance is marked as being ‘non-existent’,
exists
is set to False. This is consistent with the fact that the data properties of an entity are initialised to their default values, or NULL if there is no default specified in the model. Entity instances returned as values in collection objects have exists set to True.Entities from the same entity set can be compared (unlike
Complex
instances), comparison is done bykey()
. Therefore, two instances that represent that same entity will compare equal.If an entity does not exist, open will fail if called on one of its navigation properties with
NonExistentEntity
.You can use
is_entity_collection()
to determine if a property will return anEntityCollection
without the cost of accessing the data source itself.-
exists
= None¶ whether or not the instance exists in the entity set
-
selected
= None¶ the set of selected property names or None if all properties are selected
-
__iter__
()¶ Iterates over the property names, including the navigation properties.
Unlike native Python dictionaries, the order in which the properties are iterated over is defined. The regular property names are yielded first, followed by the navigation properties. Within these groups properties are yielded in the order they were declared in the metadata model.
-
data_keys
()¶ Iterates through the names of this entity’s data properties only
The order of the names is always the order they are defined in the metadata model.
-
data_items
()¶ Iterator that yields tuples of (key,value) for this entity’s data properties only.
The order of the items is always the order they are defined in the metadata model.
-
merge
(fromvalue)¶ Sets this entity’s value from fromvalue which must be a
TypeInstance
instance. In other words, it may be either an Entity or a Complex value.There is no requirement that fromvalue be of the same type, but it must be broadly compatible, which is defined as:
Any named property present in both the current value and fromvalue must be of compatible types.Any named property in the current value which is not present in fromvalue is left unchanged by this method.
Null values in fromvalue are not copied.
Iterates through the names of this entity’s navigation properties only.
The order of the names is always the order they are defined in the metadata model.
Iterator that yields tuples of (key,deferred value) for this entity’s navigation properties only.
The order of the items is always the order they are defined in the metadata model.
For entities that do not yet exist, checks that each of the required navigation properties has been bound (with
DeferredValue.bind_entity()
).If a required navigation property has not been bound then
NavigationConstraintError
is raised.If the entity already exists,
EntityExists
is raised.For data providers, ignore_end may be set to an association set end bound to this entity’s entity set. Any violation of the related association is ignored.
Returns true if name is the name of a navigation property, False otherwise.
-
is_entity_collection
(name)¶ Returns True if name is the name of a navigation property that points to an entity collection, False otherwise.
-
commit
()¶ Updates this entity following modification.
You can use select rules to provide a hint about which fields have been updated. By the same logic, you cannot update a property that is not selected!
The default implementation opens a collection object from the parent entity set and calls
EntityCollection.update_entity()
.
-
delete
()¶ Deletes this entity from the parent entity set.
The default implementation opens a collection object from the parent entity set and uses the del operator.
Data providers must ensure that the entity’s
exists
flag is set to False after deletion.
-
key
()¶ Returns the entity key as a single python value or a tuple of python values for compound keys.
The order of the values is always the order of the PropertyRef definitions in the associated EntityType’s
key
.
-
set_key
(key)¶ Sets this entity’s key from a single python value or tuple.
The entity must be non-existent or
EntityExists
is raised.
-
auto_key
(base=None)¶ Sets the key to a random value
- base
- An optional key suggestion which can be used to influence the choice of automatically generated key.
-
key_dict
()¶ Returns the entity key as a dictionary mapping key property names onto
SimpleValue
instances.
-
expand
(expand, select=None)¶ Expands and selects properties of the entity according to the given expand and select rules (if any).
Data consumers will usually apply expand rules to a collection which will then automatically ensure that all entities returned by the collection have been expanded.
If, as a result of select, a non-key property is unselected then its value is set to NULL. (Properties that comprise the key are never NULL.)
If a property that is being expanded is also subject to one or more selection rules these are passed along with any chained expand method call.
The selection rules in effect are saved in the
select
member and can be tested usingis_selected()
.
-
is_selected
(name)¶ Returns true if the property name is selected in this entity.
You should not rely on the value of a unselected property, in most cases it will be set to NULL.
-
etag
()¶ Returns a list of EDMValue instance values to use for optimistic concurrency control or None if the entity does not support it (or if all concurrency tokens are NULL or unselected).
-
etag_values
()¶ Returns a list of EDMValue instance values that may be used for optimistic concurrency control. The difference between this method and
etag()
is that this method returns all values even if they are NULL or unselected. If there are no concurrency tokens then an empty list is returned.
-
generate_ctoken
()¶ Returns a hash object representing this entity’s value.
The hash is a SHA256 obtained by concatenating the literal representations of all data properties (strings are UTF-8 encoded) except the keys and properties which have Fixed concurrency mode.
-
set_concurrency_tokens
()¶ A utility method for data providers.
Sets all
etag_values()
using the following algorithm:- Binary values are set directly from the output of
generate_ctoken()
- String values are set from the hexdigest of the output
generate_ctoken()
- Integer values are incremented.
- DateTime and DateTimeOffset values are set to the current
- time in UTC (and nudged by 1s if necessary)
- Guid values are set to a new random (type 4) UUID.
Any other type will generate a ValueError.
-
etag_is_strong
()¶ Tests the strength of this entity’s etag
Defined by RFC2616:
A "strong entity tag" MAY be shared by two entities of a resource only if they are equivalent by octet equality.
The default implementation returns False which is consistent with the implementation of
generate_ctoken()
as that does not include the key fields.
Deprecated equivalent to
check_navigation_constraints()
-
DataKeys
(*args, **kwargs)¶ Deprecated equivalent to
data_keys()
-
ETagIsStrong
(*args, **kwargs)¶ Deprecated equivalent to
etag_is_strong()
-
ETagValues
(*args, **kwargs)¶ Deprecated equivalent to
etag_values()
-
IsEntityCollection
(*args, **kwargs)¶ Deprecated equivalent to
is_entity_collection()
Deprecated equivalent to
is_navigation_property()
-
KeyDict
(*args, **kwargs)¶ Deprecated equivalent to
key_dict()
Deprecated equivalent to
navigation_items()
Deprecated equivalent to
navigation_keys()
-
Selected
(*args, **kwargs)¶ Deprecated equivalent to
is_selected()
-
SetConcurrencyTokens
(*args, **kwargs)¶ Deprecated equivalent to
set_concurrency_tokens()
-
class
pyslet.odata2.csdl.
SimpleValue
(p_def=None)¶ Bases:
pyslet.py2.UnicodeMixin
,pyslet.odata2.csdl.EDMValue
An abstract class that represents a value of a simple type in the EDMModel.
This class is not designed to be instantiated directly, use one of the factory methods in
EDMValue
to construct one of the specific child classes.-
type_code
= None¶ the
SimpleType
code
-
mtype
= None¶ an optional
pyslet.http.params.MediaType
representing this value
-
value
= None¶ The actual value or None if this instance represents a NULL value
The python type used for value depends on type_code as follows:
- Edm.Boolean:
- one of the Python constants True or False
- Edm.Byte, Edm.SByte, Edm.Int16, Edm.Int32:
- int
- Edm.Int64:
- int (Python 2: long)
- Edm.Double, Edm.Single:
- python float
- Edm.Decimal:
- python Decimal instance (from decimal module)
- Edm.DateTime, Edm.DateTimeOffset:
- py:class:pyslet.iso8601.TimePoint instance
- Edm.Time:
- py:class:pyslet.iso8601.Time instance (not a Duration, note corrected v2 specification of OData)
- Edm.Binary:
- binary string
- Edm.String:
- character string (unicode in Python 2)
- Edm.Guid:
- python UUID instance (from uuid module)
For future compatibility, this attribute should only be updated using
set_from_value()
or one of the other related methods.
-
simple_cast
(type_code)¶ Returns a new
SimpleValue
instance created from type_codeThe value of the new instance is set using
cast()
-
cast
(target_value)¶ Updates and returns target_value a
SimpleValue
instance.The value of target_value is replaced with a value cast from this instance’s value.
If the types are incompatible a TypeError is raised, if the values are incompatible then ValueError is raised.
NULL values can be cast to any value type.
-
set_from_simple_value
(new_value)¶ The reverse of the
cast()
method, sets this value to the value of new_value casting as appropriate.
-
__eq__
(other)¶ Instances compare equal only if they are of the same type and have values that compare equal.
-
__unicode__
()¶ Formats this value into its literal form.
NULL values cannot be represented in literal form and will raise ValueError.
-
set_from_literal
(value)¶ Decodes a value from the value’s literal form.
You can get the literal form of a value using the unicode function.
-
set_null
()¶ Sets the value to NULL
-
set_from_value
(new_value)¶ Sets the value from a python variable coercing new_value if necessary to ensure it is of the correct type for the value’s
type_code
.
-
set_random_value
(base=None)¶ Sets a random value based
- base
- a
SimpleValue
instance of the same type that may be used as a base or stem or the random value generated or may be ignored, depending on the value type.
-
classmethod
copy
(value)¶ Constructs a new SimpleValue instance by copying value
-
IsNull
(*args, **kwargs)¶ Deprecated equivalent to
is_null()
-
SetFromSimpleValue
(*args, **kwargs)¶ Deprecated equivalent to
set_from_simple_value()
-
-
class
pyslet.odata2.csdl.
NumericValue
(p_def=None)¶ Bases:
pyslet.odata2.csdl.SimpleValue
An abstract class that represents all numeric simple values.
The literal forms of numeric values are parsed in a two-stage process. Firstly the utility class
Parser
is used to obtain a numeric tuple and then the value is set usingset_from_numeric_literal()
All numeric types may have their value set directly from int, (Python 2 long,) float or Decimal.
Integer representations are rounded towards zero using the python int (or Python 2 long) functions when necessary.
-
set_to_zero
()¶ Set this value to the default representation of zero
-
set_from_numeric_literal
(num)¶ Decodes a value from a numeric tuple as returned by
Parser.parse_numeric_literal()
.
-
SetFromLiteral
(*args, **kwargs)¶ Deprecated equivalent to
set_from_literal()
-
SetFromNumericLiteral
(*args, **kwargs)¶ Deprecated equivalent to
set_from_numeric_literal()
-
SetToZero
(*args, **kwargs)¶ Deprecated equivalent to
set_to_zero()
-
-
class
pyslet.odata2.csdl.
FloatValue
(p_def=None)¶ Bases:
pyslet.odata2.csdl.NumericValue
Abstract class that represents one of Edm.Double or Edm.Single.
Values can be set from int, (Python 2: long,) float or Decimal.
There is no hard-and-fast rule about the representation of float in Python and we may refuse to accept values that fall within the accepted ranges defined by the CSDL if float cannot hold them. That said, you won’t have this problem in practice.
The derived classes
SingleValue
andDoubleValue
only differ in the Max value used when range checking.Values are formatted using Python’s default string conversion.
4.3.1.1.1. Primitive SimpleTypes¶
Simple values can be created directly using one of the type-specific classes below.
-
class
pyslet.odata2.csdl.
BinaryValue
(p_def=None)¶ Bases:
pyslet.odata2.csdl.SimpleValue
Represents a
SimpleValue
of type Edm.Binary.Binary literals allow content in the following form:
[A-Fa-f0-9][A-Fa-f0-9]*
Binary values can be set from any Python type, though anything other than a binary string is set to its pickled representation. There is no reverse facility for reading an object from the pickled value.
-
class
pyslet.odata2.csdl.
BooleanValue
(p_def=None)¶ Bases:
pyslet.odata2.csdl.SimpleValue
Represents a simple value of type Edm.Boolean
Boolean literals are one of:
true | false
Boolean values can be set from their Python equivalents and from any int, (Python 2 long,) float or Decimal where the non-zero test is used to set the value.
-
class
pyslet.odata2.csdl.
ByteValue
(p_def=None)¶ Bases:
pyslet.odata2.csdl.NumericValue
Represents a simple value of type Edm.Byte
Byte literals must not have a sign, decimal point or exponent.
Byte values can be set from an int, (Python 2: long,) float or Decimal
-
class
pyslet.odata2.csdl.
DateTimeValue
(p_def=None)¶ Bases:
pyslet.odata2.csdl.SimpleValue
Represents a simple value of type Edm.DateTime
DateTime literals allow content in the following form:
yyyy-mm-ddThh:mm[:ss[.fffffff]]
DateTime values can be set from an instance of
iso8601.TimePoint
or type int, (Python 2: long,) float, Decimal or the standard Python date.datetime and date.date instances. In the case of date.date, the new value represents midnight at the beginning of the specified day.Any zone specifier is ignored. There is no conversion to UTC, the value simply becomes a local time in an unspecified zone. This is a weakness of the EDM, it is good practice to limit use of the DateTime type to UTC times.
When set from a numeric value, the value must be non-negative. Unix time is assumed. See the
from_unix_time()
factory method of TimePoint for information.If a property definition was set on construction then the defined precision is used when representing the value as a character string. For example, if the property has precision 3 then the output of the string conversion will appear in the following form:
1969-07-20T20:17:40.000
-
class
pyslet.odata2.csdl.
DateTimeOffsetValue
(p_def=None)¶ Bases:
pyslet.odata2.csdl.SimpleValue
Represents a simple value of type Edm.DateTimeOffset
DateTimeOffset literals are defined in terms of the XMLSchema lexical representation.
DateTimeOffset values can be set from an instance of
iso8601.TimePoint
or type int, (Python 2: long,) float or Decimal.TimePoint instances must have a zone specifier. There is no automatic assumption of UTC.
When set from a numeric value, the value must be non-negative. Unix time in UTC assumed. See the
from_unix_time()
factory method of TimePoint for information.If a property definition was set on construction then the defined precision is used when representing the value as a character string. For example, if the property has precision 3 then the output of the string conversion will appear in the following form:
1969-07-20T15:17:40.000-05:00
It isn’t completely clear if the canonical representation of UTC using ‘Z’ instead of an offset is intended or widely supported so we always use an offset:
1969-07-20T20:17:40.000+00:00
-
class
pyslet.odata2.csdl.
DecimalValue
(p_def=None)¶ Bases:
pyslet.odata2.csdl.NumericValue
Represents a simple value of type Edm.Decimal
Decimal literals must not use exponent notation and there must be no more than 29 digits to the left and right of the decimal point.
Decimal values can be set from int, (Python 2: long,) float or Decimal values.
-
class
pyslet.odata2.csdl.
DoubleValue
(p_def=None)¶ Bases:
pyslet.odata2.csdl.FloatValue
Represents a simple value of type Edm.Double
-
Max
= 1.7976931348623157e+308¶ the largest positive double value
This value is set dynamically on module load, theoretically it may be set lower than the maximum allowed by the specification if Python’s native float is of insufficient precision but this is unlikely to be an issue.
-
MaxD
= Decimal('1.79769313486E+308')¶ the largest positive double value converted to decimal form
-
-
class
pyslet.odata2.csdl.
GuidValue
(p_def=None)¶ Bases:
pyslet.odata2.csdl.SimpleValue
Represents a simple value of type Edm.Guid
Guid literals allow content in the following form: dddddddd-dddd-dddd-dddd-dddddddddddd where each d represents [A-Fa-f0-9].
Guid values can also be set directly from either binary or hex strings. Binary strings must be of length 16 and are passed as raw bytes to the UUID constructor, hexadecimal strings must be of length 32 characters. (In Python 2 both str and unicode types are accepted as hexadecimal strings, the length being used to determine if the source is a binary or hexadecimal representation.)
-
class
pyslet.odata2.csdl.
Int16Value
(p_def=None)¶ Bases:
pyslet.odata2.csdl.NumericValue
Represents a simple value of type Edm.Int16
-
class
pyslet.odata2.csdl.
Int32Value
(p_def=None)¶ Bases:
pyslet.odata2.csdl.NumericValue
Represents a simple value of type Edm.Int32
-
class
pyslet.odata2.csdl.
Int64Value
(p_def=None)¶ Bases:
pyslet.odata2.csdl.NumericValue
Represents a simple value of type Edm.Int64
-
class
pyslet.odata2.csdl.
SByteValue
(p_def=None)¶ Bases:
pyslet.odata2.csdl.NumericValue
Represents a simple value of type Edm.SByte
-
class
pyslet.odata2.csdl.
SingleValue
(p_def=None)¶ Bases:
pyslet.odata2.csdl.FloatValue
Represents a simple value of type Edm.Single
-
Max
= 3.4028234663852886e+38¶ the largest positive single value
This value is set dynamically on module load, theoretically it may be set lower than the maximum allowed by the specification if Python’s native float is of insufficient precision but this is very unlikely to be an issue unless you’ve compiled Python on in a very unusual environment.
-
MaxD
= Decimal('3.40282346639E+38')¶ the largest positive single value converted to Decimal
-
set_from_numeric_literal
(num)¶ Decodes a Single value from a
Numeric
literal.
-
-
class
pyslet.odata2.csdl.
StringValue
(p_def=None)¶ Bases:
pyslet.odata2.csdl.SimpleValue
Represents a simple value of type Edm.String”
The literal form of a string is the string itself.
Values may be set from any string or object which supports conversion to character string.
-
class
pyslet.odata2.csdl.
TimeValue
(p_def=None)¶
4.3.1.1.2. Complex Types¶
-
class
pyslet.odata2.csdl.
Complex
(p_def=None)¶ Bases:
pyslet.odata2.csdl.EDMValue
,pyslet.odata2.csdl.TypeInstance
Represents a single instance of a
ComplexType
.-
is_null
()¶ Complex values are never NULL
-
set_null
()¶ Sets all simple property values to NULL recursively
-
set_default_value
()¶ Sets all simple property values to defaults recursively
-
merge
(new_value)¶ Sets this value from new_value which must be a
Complex
instance.There is no requirement that new_value is of the same type, but it must be broadly compatible, which is defined as:
Any named property present in both the current value and new_value must be of compatible types.Any named property in the current value which is not present in new_value is left unchanged by this method.
Null values are not merged.
-
4.3.1.1.4. Supporting Classes¶
-
class
pyslet.odata2.csdl.
EDMValue
(p_def=None)¶ Bases:
pyslet.py2.BoolMixin
,pyslet.pep8.PEP8Compatibility
Abstract class to represent a value in the EDMModel.
This class is used to wrap or ‘box’ instances of a value. In particular, it can be used in a context where that value can have either a simple or complex type.
EDMValue instances are treated as being non-zero if
is_null()
returns False.-
is_null
()¶ Returns True if this object is Null.
-
classmethod
from_property
(p_def)¶ Constructs an instance of the correct child class of
EDMValue
to represent a value defined byProperty
instance p_def.We support a special case for creating a type-less NULL. If you pass None for p_def then a type-less
SipmleValue
is instantiated.
-
classmethod
from_type
(type_code)¶ Constructs an instance of the correct child class of
EDMValue
to represent an (undeclared) simple value ofSimpleType
type_code.
-
classmethod
from_value
(value)¶ Constructs an instance of the correct child class of
EDMValue
to hold value.value may be any of the types listed in
SimpleValue
.
-
classmethod
NewSimpleValue
(*args, **kwargs)¶ Deprecated equivalent to
from_type()
-
classmethod
NewSimpleValueFromValue
(*args, **kwargs)¶ Deprecated equivalent to
from_value()
-
classmethod
NewValue
(*args, **kwargs)¶ Deprecated equivalent to
from_property()
-
-
class
pyslet.odata2.csdl.
TypeInstance
(type_def=None)¶ Bases:
pyslet.odata2.csdl.DictionaryLike
,pyslet.pep8.PEP8Compatibility
Abstract class to represents a single instance of a
ComplexType
orEntityType
.Behaves like a read-only dictionary mapping property names onto
EDMValue
instances. (You can change the value of a property using the methods ofEDMValue
and its descendants.)Unlike regular Python dictionaries, iteration over the of keys in the dictionary (the names of the properties) is always done in the order in which they are declared in the type definition.
-
type_def
= None¶ the definition of this type
-
AddProperty
(*args, **kwargs)¶ Deprecated equivalent to
add_property()
-
4.3.1.2. Metadata Model¶
-
class
pyslet.odata2.csdl.
CSDLElement
(parent, name=None)¶ Bases:
pyslet.xml.namespace.NSElement
All elements in the metadata model inherit from this class.
-
class
pyslet.odata2.csdl.
Schema
(parent)¶ Bases:
pyslet.odata2.csdl.NameTableMixin
,pyslet.odata2.csdl.CSDLElement
Represents the Edm root element.
Schema instances are based on
NameTableMixin
allowing you to look up the names of declared Associations, ComplexTypes, EntityTypes, EntityContainers and Functions using dictionary-like methods.-
name
= None¶ the declared name of this schema
-
Association
= None¶ a list of
Association
instances
-
ComplexType
= None¶ a list of
ComplexType
instances
-
EntityType
= None¶ a list of
EntityType
instances
-
-
class
pyslet.odata2.csdl.
EntityContainer
(parent)¶ Bases:
pyslet.odata2.csdl.NameTableMixin
,pyslet.odata2.csdl.CSDLElement
Models an entity container in the metadata model.
An EntityContainer inherits from
NameTableMixin
to enable it to behave like a scope. TheEntitySet
instances andAssociationSet
instances it contains are declared within the scope.-
name
= None¶ the declared name of the container
-
Documentation
= None¶ the optional
Documentation
-
AssociationSet
= None¶ a list of
AssociationSet
instances
-
find_entitysets
(entity_type)¶ Returns a list of all entity sets with a given type
- entity_type
- An
EntityType
instance.
Returns an empty list if no declared EntitySets have this type.
-
-
class
pyslet.odata2.csdl.
EntitySet
(parent)¶ Bases:
pyslet.odata2.csdl.CSDLElement
Represents an EntitySet in the metadata model.
-
name
= None¶ the declared name of the entity set
-
entityTypeName
= None¶ the name of the entity type of this set’s elements
-
entityType
= None¶ the
EntityType
of this set’s elements
-
keys
= None¶ a list of the names of this entity set’s keys in their declared order
a mapping from navigation property names to
AssociationSetEnd
instances
-
linkEnds
= None¶ A mapping from
AssociationSetEnd
instances that reference this entity set to navigation property names (or None if this end of the association is not bound to a named navigation property)
-
unboundPrincipal
= None¶ An
AssociationSetEnd
that represents our end of an association with an unbound principal or None if all principals are bound.What does that mean? It means that there is an association set bound to us where the other role has a multiplicity of 1 (required) but our entity type does not have a navigation property bound to the association. As a result, our entities can only be created by a deep insert from the principal (the entity set at the other end of the association).
Clear as mud? An example may help. Suppose that each Order entity must have an associated Customer but (perhaps perversely) there is no navigation link from Order to Customer, only from Customer to Order. For the Order entity, the Customer is the principal as Orders can only be exist when they are associated with a Customer.
Attempting to create an Order in the base collection of Orders will always fail:
with Orders.open() as collection: order=collection.new_entity() # set order fields here collection.insert_entity(order) # raises ConstraintError as order is not bound to a customer
Instead, you have to create new orders from a Customer entity:
with Customers.open() as collectionCustomers: # get the existing customer customer=collectionCustomers['ALFKI'] with customer['Orders'].open() as collectionOrders: # create a new order order=collectionOrders.new_entity() # ... set order details here collectionOrders.insert_entity(order)
You can also use a deep insert:
with Customers.open() as collectionCustomers, Orders.open() as collectionOrders: customer=collectionCustomers.new_entity() # set customer details here order=collectionOrders.new_entity() # set order details here customer['Orders'].bind_entity(order) collectionCustomers.insert_entity(customer)
For the avoidance of doubt, an entity set can’t have two unbound principals because if it did you would never be able to create entities in it!
-
Documentation
= None¶ the optional
Documentation
-
get_fqname
()¶ Returns the fully qualified name of this entity set.
-
get_location
()¶ Returns a
pyslet.rfc2396.URI
instance representing the location for this entity set.
-
set_location
()¶ Sets the location of this entity set
Resolves a relative path consisting of:
[ EntityContainer.name '.' ] name
The resolution of URIs is done in accordance with the XML specification, so is affected by any xml:base attributes set on parent elements or by the original base URI used to load the metadata model. If no base URI can be found then the location remains expressed in relative terms.
-
get_key
(keylike)¶ Extracts a key from a keylike argument
- keylike
- A value suitable for using as a key in an
EntityCollection
based on this entity set.
Keys are represented as python values (as described in
SimpleValue
) or as tuples of python values in the case of compound keys. The order of the values in a compound key is the order in which the Key properties are defined in the corresponding EntityType definition.If keylike is already in the correct format for this entity type then it is returned unchanged.
If the key is single-valued and keylike is a tuple containing a single value then the single value is returned without the tuple wrapper.
If keylike is a dictionary, or an
Entity
instance, which maps property names to values (or toSimpleValue
instances) the key is calculated from it by extracting the key properties. As a special case, a value mapped with a dictionary key of the empty string is assumed to be the value of the key property for an entity type with a single-valued key, but only if the key property’s name is not itself in the dictionary.If keylike cannot be turned in to a valid key the KeyError is raised.
-
extract_key
(keyvalue)¶ Extracts a key value from keylike.
Unlike get_key, this method attempts to convert the data in keyvalue into the correct format for the key. For compound keys keyvalue must be a suitable list or tuple or compatible iterable supporting the len method. Dictionaries are not supported.
If keyvalue cannot be converted into a suitable representation of the key then None is returned.
-
key_dict
(key)¶ Given a key from this entity set, returns a key dictionary.
The result is a mapping from named properties to
SimpleValue
instances. The property name is always used as the key in the mapping, even if the key refers to a single property. This contrasts withget_key_dict()
.
-
get_key_dict
(key)¶ Given a key from this entity set, returns a key dictionary.
The result is a mapping from named properties to
SimpleValue
instances. As a special case, if a single property defines the entity key it is represented using the empty string, not the property name.
-
bind
(binding, **kws)¶ Binds this entity set to a collection class
- binding
- Must be a class (or other callable) that returns an
EntityCollection
instance, by default we are bound to the default EntityCollection class which behaves like an empty collection. - kws
- A python dict of named arguments to pass to the binding callable
-
open
()¶ Opens this entity set
Returns an
EntityCollection
instance suitable for accessing the entities themselves.
Binds the navigation property name.
- binding
- Must be a class (or other callable) that returns a
NavigationCollection
instance. By default we are bound to the default NavigationCollection class which behaves like an empty collection. - kws
- A python dict of named arguments to pass to the binding callable
Opens a navigation collection
Returns a
NavigationCollection
instance suitable for accessing the entities obtained by navigating from source_entity, anEntity
instance, via the navigation property with name.
-
get_target
(name)¶ Returns the target entity set of navigation property name
-
get_multiplicity
(name)¶ Gets the multiplicities of a named navigation properly
Returns the
Multiplicity
of both the source and the target of the named navigation property, as a tuple, for example, if customers is an entity set from the sample OData service:customers.get_multiplicity['Orders'] == (Multiplicity.ZeroToOne, Multiplicity.Many)
-
is_entity_collection
(name)¶ Tests the multiplicity of a named navigation property
Returns True if more than one entity is possible when navigating the named property.
Deprecated equivalent to
bind_navigation()
-
GetFQName
(*args, **kwargs)¶ Deprecated equivalent to
get_fqname()
-
GetKeyDict
(*args, **kwargs)¶ Deprecated equivalent to
get_key_dict()
-
GetLocation
(*args, **kwargs)¶ Deprecated equivalent to
get_location()
-
IsEntityCollection
(*args, **kwargs)¶ Deprecated equivalent to
is_entity_collection()
-
KeyKeys
(*args, **kwargs)¶ Deprecated equivalent to
key_keys()
Deprecated equivalent to
get_multiplicity()
Deprecated equivalent to
get_target()
Deprecated equivalent to
open_navigation()
-
SetLocation
(*args, **kwargs)¶ Deprecated equivalent to
set_location()
-
-
class
pyslet.odata2.csdl.
AssociationSet
(parent)¶ Bases:
pyslet.odata2.csdl.CSDLElement
Represents an association set in the metadata model.
The purpose of the association set is to bind the ends of an association to entity sets in the container.
Contrast this with the association element which merely describes the association between entity types.
At first sight this part of the entity data model can be confusing but imagine an entity container that contains two entity sets that have the same entity type. Any navigation properties that reference this type will need to be explicitly bound to one or other of the entity sets in the container.
As an aside, it isn’t really clear if the model was intended to be used this way. It may have been intended that the entity type in the definition of an entity set should be unique within the scope of the entity container.-
name
= None¶ the declared name of this association set
-
associationName
= None¶ the name of the association definition
-
association
= None¶ the
Association
definition
-
Documentation
= None¶ the optional
Documentation
-
-
class
pyslet.odata2.csdl.
AssociationSetEnd
(parent)¶ Bases:
pyslet.py2.SortableMixin
,pyslet.odata2.csdl.CSDLElement
Represents the links between two entity sets
The
get_qualified_name()
method defines the identity of this element. The built-in Python hash function returns a hash based on this value and the associated comparison functions are also implemented enabling these elements to be added to ordinary Python dictionaries.Oddly, role names are sometimes treated as optional but it can make it a challenge to work out which end of the association is which when we are actually using the model if one or both are missing. The algorithm we use is to use role names if either are given, otherwise we match the entity types. If these are also identical then the choice is arbitrary. To prevent confusion missing role names are filled in when the metadata model is loaded.
-
name
= None¶ the role-name given to this end of the link
-
entitySetName
= None¶ name of the entity set this end links to
-
associationEnd
= None¶ AssociationEnd
that defines this end of the link
-
otherEnd
= None¶ the other
AssociationSetEnd
of this link
-
Documentation
= None¶ the optional
Documentation
-
get_qualified_name
()¶ A utility function to return a qualified name.
The qualified name comprises the name of the parent
AssociationSet
and the role name.
-
GetQualifiedName
(*args, **kwargs)¶ Deprecated equivalent to
get_qualified_name()
-
-
class
pyslet.odata2.csdl.
Type
(parent)¶ Bases:
pyslet.odata2.csdl.NameTableMixin
,pyslet.odata2.csdl.CSDLElement
An abstract class for both Entity and Complex types.
Types inherit from
NameTableMixin
to allow them to behave as scopes in their own right. The named properties are declared in the type’s scope enabling you so use them as dictionaries to look up property definitions.Because of the way nested scopes work, this means that you can concatenate names to do a deep look up, for example, if Person is a defined type:
Person['Address']['City'] is Person['Address.City']
-
name
= None¶ the declared name of this type
-
baseType
= None¶ the name of the base-type for this type
-
get_fqname
()¶ Returns the full name of this type
Includes the schema namespace prefix.
-
GetFQName
(*args, **kwargs)¶ Deprecated equivalent to
get_fqname()
-
-
class
pyslet.odata2.csdl.
EntityType
(parent)¶ Bases:
pyslet.odata2.csdl.Type
Models the key and the collection of properties that define a set of
Entity
-
validate_expansion
(expand, select)¶ A utility method for data providers.
Checks the expand and select options, as described in
EntityCollection.set_expand()
for validity raising ValueError if they violate the OData specification.Specifically the following are checked:
- That “*” only ever appears as the last item in a select path
- That nothing appears after a simple property in a select path
- That all names are valid property names
- That all expanded names are those of navigation properties
-
ValidateExpansion
(*args, **kwargs)¶ Deprecated equivalent to
validate_expansion()
-
-
class
pyslet.odata2.csdl.
Key
(parent)¶ Bases:
pyslet.odata2.csdl.CSDLElement
Models the key fields of an
EntityType
-
PropertyRef
= None¶ a list of
PropertyRef
-
-
class
pyslet.odata2.csdl.
PropertyRef
(parent)¶ Bases:
pyslet.odata2.csdl.CSDLElement
Models a reference to a single property within a
Key
.-
name
= None¶ the name of this (key) property
-
-
class
pyslet.odata2.csdl.
Property
(parent)¶ Bases:
pyslet.odata2.csdl.CSDLElement
Models a property of an
EntityType
orComplexType
.Instances of this class are callable, taking an optional string literal. They return a new
EDMValue
instance with a value set from the optional literal or NULL if no literal was supplied. Complex values can’t be created from a literal.-
name
= None¶ the declared name of the property
-
type
= None¶ the name of the property’s type
-
simpleTypeCode
= None¶ one of the
SimpleType
constants if the property has a simple type
-
complexType
= None¶ the associated
ComplexType
if the property has a complex type
-
nullable
= None¶ if the property may have a null value
-
defaultValue
= None¶ a string containing the default value for the property or None if no default is defined
-
maxLength
= None¶ the maximum length permitted for property values
-
precision
= None¶ a positive integer indicating the maximum number of decimal digits (decimal values)
-
scale
= None¶ a non-negative integer indicating the maximum number of decimal digits to the right of the point
-
unicode
= None¶ a boolean indicating that a string property contains unicode data
-
Documentation
= None¶ the optional
Documentation
-
-
class
pyslet.odata2.csdl.
ComplexType
(parent)¶ Bases:
pyslet.odata2.csdl.Type
Models the collection of properties that define a
Complex
value.This class is a trivial sub-class of
Type
Bases:
pyslet.odata2.csdl.CSDLElement
Models a navigation property of an
EntityType
.the declared name of the navigation property
the name of this link’s source role
the name of this link’s target role
the
AssociationEnd
instance representing this link’s source
the
AssociationEnd
instance representing this link’s target
flag set if
Association
is ambiguous within the parent EntityType,backLink
will never be set!
the
NavigationProperty
that provides the back link (or None, if this link is one-way)
-
class
pyslet.odata2.csdl.
Association
(parent)¶ Bases:
pyslet.odata2.csdl.NameTableMixin
,pyslet.odata2.csdl.CSDLElement
Models an association.
This class inherits from
NameTableMixin
to enable it to behave like a scope in its own right. The containedAssociationEnd
instances are declared in the association scope by role name.-
name
= None¶ the name declared for this association
-
Documentation
= None¶ the optional
Documentation
-
AssociationEnd
= None¶ a list of
AssociationEnd
instances
-
get_fqname
()¶ Returns the full name of this association
The result includes the schema namespace prefix.
-
GetFQName
(*args, **kwargs)¶ Deprecated equivalent to
get_fqname()
-
-
class
pyslet.odata2.csdl.
AssociationEnd
(parent)¶ Bases:
pyslet.odata2.csdl.CSDLElement
Models one end of an
Association
.We define a hash method to allow AssociationEnds to be used as keys in a dictionary.
-
name
= None¶ the role-name given to this end of the link
-
type
= None¶ name of the entity type this end links to
-
entityType
= None¶ EntityType
this end links to
-
multiplicity
= None¶ a
Multiplicity
constant
-
otherEnd
= None¶ the other
AssociationEnd
of this link
-
get_qualified_name
()¶ A utility function to return a qualified name.
The qualified name comprises the name of the parent
Association
and the role name.
-
-
class
pyslet.odata2.csdl.
Documentation
(parent)¶ Bases:
pyslet.odata2.csdl.CSDLElement
Used to document elements in the metadata model
4.3.1.3. Misc Definitions¶
-
pyslet.odata2.csdl.
validate_simple_identifier
(identifier)¶ Validates a simple identifier, returning the identifier unchanged or raising ValueError.
-
class
pyslet.odata2.csdl.
SimpleType
¶ Bases:
pyslet.xml.xsdatatypes.EnumerationNoCase
SimpleType defines constants for the core data types defined by CSDL
SimpleType.Boolean SimpleType.DEFAULT == None
For more methods see
Enumeration
The canonical names for these constants uses the Edm prefix, for example, “Edm.String”. As a result, the class has attributes of the form “SimpleType.Edm.Binary” which are inaccessible to python unless getattr is used. To workaround this problem (and because the Edm. prefix seems to be optional) we also define aliases without the Edm. prefix. As a result you can use, e.g., SimpleType.Int32 as the symbolic representation in code but the following are all True:
SimpleType.from_str("Edm.Int32") == SimpleType.Int32 SimpleType.from_str("Int32") == SimpleType.Int32 SimpleType.to_str(SimpleType.Int32) == "Edm.Int32"
-
PythonType
= {<type 'float'>: 8, <type 'unicode'>: 14, <type 'long'>: 7, <type 'int'>: 13, <type 'bool'>: 2, <type 'str'>: 14}¶ A python dictionary that maps a type code (defined by the types module) to a constant from this class indicating a safe representation in the EDM. For example:
SimpleType.PythonType[int]==SimpleType.Int64
-
-
class
pyslet.odata2.csdl.
ConcurrencyMode
¶ Bases:
pyslet.xml.xsdatatypes.EnumerationNoCase
ConcurrencyMode defines constants for the concurrency modes defined by CSDL
ConcurrencyMode.Fixed ConcurrencyMode.DEFAULT == ConcurrencyMode.none
Note that although ‘Fixed’ and ‘None’ are the correct values lower-case aliases are also defined to allow the value ‘none’ to be accessible through normal attribute access. In most cases you won’t need to worry as a test such as the following is sufficient:
- if property.concurrencyMode==ConcurrencyMode.Fixed:
- # do something with concurrency tokens
For more methods see
Enumeration
-
pyslet.odata2.csdl.
maxlength_from_str
(value)¶ Decodes a maxLength value from a character string.
“The maxLength facet accepts a value of the literal string “max” or a positive integer with value ranging from 1 to 2^31”
The value ‘max’ is returned as the value
MAX
-
pyslet.odata2.csdl.
maxlength_to_str
(value)¶ Encodes a maxLength value as a character string.
-
pyslet.odata2.csdl.
MAX
= -1¶ we define the constant MAX to represent the special ‘max’ value of maxLength
-
class
pyslet.odata2.csdl.
Multiplicity
¶ Defines constants for representing association end multiplicities.
-
pyslet.odata2.csdl.
multiplictiy_from_str
(src)¶ Decodes a
Multiplicity
value from a character string.The valid strings are “0..1”, “1” and “*”
-
pyslet.odata2.csdl.
multiplicity_to_str
(value)¶ Encodes a
Multiplicity
value as a character string.
-
class
pyslet.odata2.csdl.
Parser
(source)¶ Bases:
pyslet.unicode5.BasicParser
A CSDL-specific parser, mainly for decoding literal values of simple types.
The individual parsing methods may raise ValueError in cases where parsed value has a value that is out of range.
-
parse_binary_literal
()¶ Parses a binary literal, returning a binary string
-
parse_boolean_literal
()¶ Parses a boolean literal returning True, False or None if no boolean literal was found.
-
parse_byte_literal
()¶ Parses a byteLiteral, returning a python integer.
We are generous in what we accept, ignoring leading zeros. Values outside the range for byte return None.
-
parse_datetime_literal
()¶ Parses a DateTime literal, returning a
pyslet.iso8601.TimePoint
instance.Returns None if no DateTime literal can be parsed. This is a generous way of parsing iso8601-like values, it accepts omitted zeros in the date, such as 4-7-2001.
-
parse_guid_literal
()¶ Parses a Guid literal, returning a UUID instance from the uuid module.
Returns None if no Guid can be parsed.
-
parse_numeric_literal
()¶ Parses a numeric literal returning a named tuple of strings:
( sign, ldigits, rdigits, expSign, edigits )
An empty string indicates a component that was not present except that rdigits will be None if no decimal point was present. Likewise, edigits may be None indicating that no exponent was found.
Although both ldigits and rdigits can be empty they will never both be empty strings. If there are no digits present then the method returns None, rather than a tuple. Therefore, forms like “E+3” are not treated as being numeric literals whereas, perhaps oddly, 1E+ is parsed as a numeric literal (even though it will raise ValueError later when setting any of the numeric value types).
Representations of infinity and not-a-number result in ldigits being set to ‘inf’ and ‘nan’ respectively. They always result in rdigits and edigits being None.
-
parse_time_literal
()¶ Parses a Time literal, returning a
pyslet.iso8601.Time
instance.Returns None if no Time literal can be parsed. This is a generous way of parsing iso8601-like values, it accepts omitted zeros in the leading field, such as 7:45:00.
-
4.3.1.4. Utility Classes¶
These classes are not specific to the EDM but are used to support the implementation. They are documented to allow them to be reused in other modules.
-
class
pyslet.odata2.csdl.
NameTableMixin
¶ Bases:
pyslet.odata2.csdl.DictionaryLike
A mix-in class to help other objects become named scopes.
Using this mix-in the class behaves like a read-only named dictionary with string keys and object values. If the dictionary contains a value that is itself a NameTableMixin then keys can be compounded to look-up items in sub-scopes.
For example, if the name table contains a value with key “X” that is itself a name table containing a value with key “Y” then both “X” and “X.Y” are valid keys, the latter performing a ‘deep lookup’ in the nested scope.
-
name
= None¶ the name of this name table (in the context of its parent)
-
nameTable
= None¶ a dictionary mapping names to child objects
-
__getitem__
(key)¶ Looks up key in
nameTable
and, if not found, in each child scope with a name that is a valid scope prefix of key. For example, if key is “My.Scope.Name” then a child scope with name “My.Scope” would be searched for “Name” or a child scope with name “My” would be searched for “Scope.Name”.
-
__iter__
()¶ Yields all keys defined in this scope and all compounded keys from nested scopes. For example, a child scope with name “My.Scope” which itself has a child “Name” would generate two keys: “My.Scope” and “My.Scope.Name”.
-
__len__
()¶ Returns the number of keys in this scope including all compounded keys from nested scopes.
-
declare
(value)¶ Declares a value in this named scope.
value must have a name attribute which is used to declare it in the scope; duplicate keys are not allowed and will raise
DuplicateKey
.Values are always declared in the top-level scope, even if they contain the compounding character ‘.’, however, you cannot declare “X” if you have already declared “X.Y” and vice versa.
-
undeclare
(value)¶ Removes a value from the named scope.
Values can only be removed from the top-level scope.
-
-
class
pyslet.odata2.csdl.
DictionaryLike
¶ Bases:
object
An abstract class for behaving like a dictionary.
Python 3 note: the dictionary interface has changed in Python 3 with the introduction of the dictionary view object and the corresponding change in behaviour of the keys, values and items methods. This class has not changed so is currently Python 2 dictionary like only. It is envisaged that when Pyslet is extended to include support for OData 4 a more Python3-friendly class will be used.
Derived classes must override
__iter__()
and__getitem__()
and if the dictionary is writable__setitem__()
and probably__delitem__()
too. These methods all raise :NotImplementedError by default.Dervied classes should also override
__len__()
andclear()
as the default implementations are inefficient.A note on thread safety. Unlike native Python dictionaries, DictionaryLike objects can not be treated as thread safe for updates. The implementations of the read-only methods (including the iterators) are designed to be thread safe so, once populated, they can be safely shared. Derived classes should honour this contract when implementing
__iter__()
,__getitem__()
and__len__()
or clearly document that the object is not thread-safe at all.Finally, one other difference worth noting is touched on in a comment from the following question on Stack Overflow: http://stackoverflow.com/questions/3358770/python-dictionary-is-thread-safe
This question is about whether a dictionary can be modified during iteration. Although not typically a thread-safety issue the commenter says:
I think they are related. What if one thread iterates and the other modifies the dict?To recap, native Python dictionaries limit the modifications you can make during iteration, quoting from the docs:
The dictionary p should not be mutated during iteration. It is safe (since Python 2.1) to modify the values of the keys as you iterate over the dictionary, but only so long as the set of keys does not changeYou should treat DictionaryLike objects with the same respect but the behaviour is not defined at this abstract class level and will vary depending on the implementation. Derived classes are only dictionary-like, they are not actually Python dictionaries!
-
__getitem__
(key)¶ Implements self[key]
This method must be overridden to make a concrete implementation
-
__setitem__
(key, value)¶ Implements assignment to self[key]
This method must be overridden if you want your dictionary-like object to be writable.
-
__delitem__
(key)¶ Implements del self[key]
This method should be overridden if you want your dictionary-like object to be writable.
-
__iter__
()¶ Returns an object that implements the iterable protocol on the keys
This method must be overridden to make a concrete implementation
-
__len__
()¶ Implements len(self)
The default implementation simply counts the keys returned by __iter__ and should be overridden with a more efficient implementation if available.
-
__contains__
(key)¶ Implements: key in self
The default implementation uses __getitem__ and returns False if it raises a KeyError.
-
iterkeys
()¶ Returns an iterable of the keys, simple calls __iter__
-
itervalues
()¶ Returns an iterable of the values.
The default implementation is a generator function that iterates over the keys and uses __getitem__ to yield each value.
-
keys
()¶ Returns a list of keys.
This is a copy of the keys in no specific order. Modifications to this list do not affect the object. The default implementation uses
iterkeys()
-
values
()¶ Returns a list of values.
This is a copy of the values in no specific order. Modifications to this list do not affect the object. The default implementation uses
itervalues()
.
-
iteritems
()¶ Returns an iterable of the key,value pairs.
The default implementation is a generator function that uses
__iter__()
and __getitem__ to yield the pairs.
-
items
()¶ Returns a list of key,value pair tuples.
This is a copy of the items in no specific order. Modifications to this list do not affect the object. The default implementation uses
iteritems
.
-
has_key
(key)¶ Equivalent to: key in self
-
get
(key, default=None)¶ Equivalent to: self[key] if key in self else default.
Implemented using __getitem__
-
setdefault
(key, value=None)¶ Equivalent to: self[key] if key in self else value; ensuring self[key]=value
Implemented using __getitem__ and __setitem__.
-
pop
(key, value=None)¶ Equivalent to: self[key] if key in self else value; ensuring key not in self.
Implemented using __getitem__ and __delitem__.
-
clear
()¶ Removes all items from the object.
The default implementation uses
keys()
and deletes the items one-by-one with __delitem__. It does this to avoid deleting objects while iterating as the results are generally undefined. A more efficient implementation is recommended.
-
popitem
()¶ Equivalent to: self[key] for some random key; removing key.
This is a rather odd implementation but to avoid iterating over the whole object we create an iterator with __iter__, use __getitem__ once and then discard it. If an object is found we use __delitem__ to delete it, otherwise KeyError is raised.
-
bigclear
()¶ Removes all the items from the object (alternative for large dictionary-like objects).
This is an alternative implementation more suited to objects with very large numbers of keys. It uses
popitem()
repeatedly until KeyError is raised. The downside is that popitem creates (and discards) one iterator object for each item it removes. The upside is that we never load the list of keys into memory.
-
copy
()¶ Makes a shallow copy of this object.
This method must be overridden if you want your dictionary-like object to support the copy operation.
-
update
(items)¶ Iterates through items using __setitem__ to add them to the set.
-
__weakref__
¶ list of weak references to the object (if defined)
-
4.3.1.5. Exceptions¶
-
class
pyslet.odata2.csdl.
NonExistentEntity
¶ Bases:
pyslet.odata2.csdl.EDMError
Raised when attempting to perform a restricted operation on an entity that doesn’t exist yet. For example, getting the value of a navigation property.
-
class
pyslet.odata2.csdl.
EntityExists
¶ Bases:
pyslet.odata2.csdl.EDMError
Raised when attempting to perform a restricted operation on an entity that already exists. For example, inserting it into the base collection.
-
class
pyslet.odata2.csdl.
ConstraintError
¶ Bases:
pyslet.odata2.csdl.EDMError
General error raised when a constraint has been violated.
Bases:
pyslet.odata2.csdl.ConstraintError
Raised when attempting to perform an operation on an entity and a violation of a navigation property’s relationship is encountered. For example, adding multiple links when only one is allowed or failing to add a link when one is required.
-
class
pyslet.odata2.csdl.
ConcurrencyError
¶ Bases:
pyslet.odata2.csdl.ConstraintError
Raised when attempting to perform an update on an entity and a violation of a concurrency control constraint is encountered.
-
class
pyslet.odata2.csdl.
ModelIncomplete
¶ Bases:
pyslet.odata2.csdl.ModelError
Raised when a model element has a missing reference.
For example, an
EntitySet
that is bound to an undeclared :EntityType
.
-
class
pyslet.odata2.csdl.
ModelConstraintError
¶ Bases:
pyslet.odata2.csdl.ModelError
Raised when an issue in the model other than completeness prevents an action being performed.
For example, an entity type that is dependent on two unbound principals (so can never be inserted).
-
class
pyslet.odata2.csdl.
DuplicateName
¶ Bases:
pyslet.odata2.csdl.ModelError
Raised by
NameTableMixin
when attempting to declare a name in a context where the name is already declared.This might be raised if your metadata document incorrectly defines two objects with the same name in the same scope, for example
-
class
pyslet.odata2.csdl.
IncompatibleNames
¶ Bases:
pyslet.odata2.csdl.DuplicateName
A special type of
DuplicateName
exception raised byNameTableMixin
when attempting to declare a name which might hide, or be hidden by, another name already declared.CSDL’s definition of SimpleIdentifier allows ‘.’ to be used in names but also uses it for qualifying names. As a result, it is possible to define a scope with a name like “My.Scope” which precludes the later definition of a scope called simply “My” (and vice versa).
-
class
pyslet.odata2.csdl.
InvalidMetadataDocument
¶ Bases:
pyslet.odata2.csdl.ModelError
Raised by general CSDL model violations.
-
class
pyslet.odata2.csdl.
EDMError
¶ Bases:
exceptions.Exception
General exception for all CSDL model errors.