2.1.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.

2.1.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.OpenCollection() 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 the PropertyRef definitions in the metadata model. You can obtain an entity’s key from the Entity.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 CheckFilter())

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.

GetLocation()

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.

GetTitle()

Returns a user recognisable title for the collection.

By default this is the fully qualified name of the entity set in the metadata model.

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 is 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.

SelectKeys()

Sets the select rule to select the key property/properties only.

Any expand rule is removed.

expand_entities(entityIterable)

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 and select 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 CheckFilter().

filter_entities(entityIterable)

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 CheckFilter() on each one.

CheckFilter(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.CheckFilter() 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 is a list of tuples, each consisting of:

( an order object as used by :py:meth:`CalculateOrderKey` , 1 | -1 )
CalculateOrderKey(entity, orderObject)

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.CalculateOrderKey() for more. The implementation in the case class simply raises NotImplementedError.

order_entities(entityIterable)

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 CalculateOrderKey() so is not suitable for use with long lists of entities. However, if no ordering is required then no list is created.

SetInlineCount(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 properties of the entity are set to their defaults, or to null if no default is defined (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.

CopyEntity(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:

  1. entity is updated with any auto-generated values such as

    an autoincrement correct key.

  2. 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)

Updates entity which must already be in the entity set.

Data providers must override this method if the collection is writable.

update_bindings(entity)

Iterates through the Entity.NavigationItems() and generates appropriate calls to create/update any pending bindings.

Unlike the Update() 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.

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 in set_page(), next_skiptoken() will return a suitable value for identifying the next page in the collection immediately after a complete iteration of iterpage().

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 by set_orderby().

Entities are also expanded and selected according to the rules defined by Expand.

Data providers must override this implementation which, by default, returns no entities (simulating an empty collection).

class pyslet.odata2.csdl.Entity(entity_set)

Bases: 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() or EntityCollection.CopyEntity 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 of SimpleValue, 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.SetFromPyVaue() 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'].OpenCollection() 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'].GetEntity()     # 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.

If an entity does not exist, OpenCollection will fail if called on one of its navigation properties with NonExistentEntity.

You can use IsEntityCollection() to determine if a property will return an EntityCollection 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.

DataKeys()

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.

NavigationKeys()

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.

NavigationItems()

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.

CheckNavigationConstraints(ignoreEnd=None)

For entities that do not yet exist, checks that each of the required navigation properties has been bound (with DeferredValue.BindEntity()).

If a required navigation property has not been bound then NavigationConstraintError is raised.

If the entity already exists, EntityExists is raised.

For data providers, ignoreEnd may be set to an association set end bound to this entity’s entity set. Any violation of the related association is ignored.

IsNavigationProperty(name)

Returns true if name is the name of a navigation property, False otherwise.

IsEntityCollection(name)

Returns True if name is the name of a navigation property that points to an entity collection, False otherwise.

Update()

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.
KeyDict()

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 using Selected().

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).

ETagValues()

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.

SetConcurrencyTokens()

A utility method for data providers.

Sets all ETagValues() using the following algorithm:

  1. Binary values are set directly from the output of

    generate_ctoken()

  2. String values are set from the hexdigest of the output

    generate_ctoken()

  3. Integer values are incremented.

  4. DateTime and DateTimeOffset values are set to the current

    time in UTC (and nudged by 1s if necessary)

  5. Guid values are set to a new random (type 4) UUID.

Any other type will generate a ValueError.

ETagIsStrong()

Returns True if this entity’s etag is a strong entity tag as 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.

class pyslet.odata2.csdl.SimpleValue(pDef=None)

Bases: 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.

typeCode = None

the SimpleType code

mtype = None

an optional pyslet.rfc2616.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 typeCode as follows:

  • Edm.Boolean: one of the Python constants True or False
  • Edm.Byte, Edm.SByte, Edm.Int16, Edm.Int32: int
  • Edm.Int64: 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: raw string
  • Edm.String: unicode string
  • 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.

SimpleCast(typeCode)

Returns a new SimpleValue instance created from typeCode

The value of the new instance is set using Cast()

Cast(targetValue)

Updates and returns targetValue a SimpleValue instance.

The value of targetValue 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.

SetFromSimpleValue(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.

SetFromLiteral(value)

Decodes a value from the value’s literal form.

You can get the literal form of a value using the unicode function.

SetNull()

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 typeCode.

SetRandomValue(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

class pyslet.odata2.csdl.NumericValue(pDef=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 using SetFromNumericLiteral()

All numeric types may have their value set directly from int, long, float or Decimal.

Integer representations are rounded towards zero using the python int or long functions when necessary.

SetToZero()

Set this value to the default representation of zero

SetFromNumericLiteral(numericValue)

Decodes a value from a numeric tuple as returned by Parser.ParseNumericLiteral().

class pyslet.odata2.csdl.FloatValue(pDef=None)

Bases: pyslet.odata2.csdl.NumericValue

Abstract class that represents one of Edm.Double or Edm.Single.

Values can be set from int, 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 and DoubleValue only differ in the Max value used when range checking.

Values are formatted using Python’s default unicode conversion.

2.1.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(pDef=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(pDef=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, long, float or Decimal where the non-zero test is used to set the value.

class pyslet.odata2.csdl.ByteValue(pDef=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, long, float or Decimal

class pyslet.odata2.csdl.DateTimeValue(pDef=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, long, float or Decimal.

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 FromUnixTime() 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 unicode string. For example, if the property has precision 3 then the output of the unicode conversion will appear in the following form:

1969-07-20T20:17:40.000
class pyslet.odata2.csdl.DateTimeOffsetValue(pDef=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, 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 FromUnixTime() 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 unicode string. For example, if the property has precision 3 then the output of the unicode 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(pDef=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, long, float or Decimal values.

class pyslet.odata2.csdl.DoubleValue(pDef=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(pDef=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 can be string or unicode strings and must be of length 32 characters.

class pyslet.odata2.csdl.Int16Value(pDef=None)

Bases: pyslet.odata2.csdl.NumericValue

Represents a simple value of type Edm.Int16

class pyslet.odata2.csdl.Int32Value(pDef=None)

Bases: pyslet.odata2.csdl.NumericValue

Represents a simple value of type Edm.Int32

class pyslet.odata2.csdl.Int64Value(pDef=None)

Bases: pyslet.odata2.csdl.NumericValue

Represents a simple value of type Edm.Int64

class pyslet.odata2.csdl.SByteValue(pDef=None)

Bases: pyslet.odata2.csdl.NumericValue

Represents a simple value of type Edm.SByte

class pyslet.odata2.csdl.SingleValue(pDef=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

SetFromNumericLiteral(numericValue)

Decodes a Single value from a Numeric literal.

class pyslet.odata2.csdl.StringValue(pDef=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 the native unicode function.

class pyslet.odata2.csdl.TimeValue(pDef=None)

Bases: pyslet.odata2.csdl.SimpleValue

Represents a simple value of type Edm.Time

Time literals allow content in the form:

hh:mm:ss.sss

Time values can be set from an instance of pyslet.iso8601.Time, int, long, float or Decimal.

When set from a numeric value the value must be in the range 0..86399.9̅ and is treated as an elapsed time in seconds since midnight.

If a property definition was set on construction then the defined precision is used when representing the value as a unicode string. For example, if the property has precision 3 then the output of the unicode conversion will appear in the following form:

20:17:40.000

2.1.3.1.1.2. Complex Types

class pyslet.odata2.csdl.Complex(pDef=None)

Bases: pyslet.odata2.csdl.EDMValue, pyslet.odata2.csdl.TypeInstance

Represents a single instance of a ComplexType.

IsNull()

Complex values are never NULL

SetNull()

Sets all simple property values to NULL 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.

2.1.3.1.1.4. Supporting Classes

class pyslet.odata2.csdl.EDMValue(pDef=None)

Bases: 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.

pDef = None

An optional Property instance from the metadata model defining this value’s type

__nonzero__()

EDMValue instances are treated as being non-zero if IsNull() returns False.

IsNull()

Returns True if this object is Null.

classmethod NewValue(pDef)

Constructs an instance of the correct child class of EDMValue to represent a value defined by Property instance pDef.

We support a special case for creating a type-less NULL. If you pass None for pDef then a type-less SipmleValue is instantiated.

classmethod NewSimpleValue(typeCode)

Constructs an instance of the correct child class of EDMValue to represent an (undeclared) simple value of SimpleType typeCode.

classmethod NewSimpleValueFromValue(value)

Constructs an instance of the correct child class of EDMValue to hold value.

value may be any of the types listed in SimpleValue.

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 or EntityType.

Behaves like a read-only dictionary mapping property names onto EDMValue instances. (You can change the value of a property using the methods of EDMValue 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

2.1.3.1.2. Metadata Model

class pyslet.odata2.csdl.CSDLElement(parent, name=None)

Bases: pyslet.xmlnames20091208.XMLNSElement, pyslet.pep8.PEP8Compatibility

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. The EntitySet instances and AssociationSet instances it contains are declared within the scope.

name = None

the declared name of the container

Documentation = None

the optional Documentation

EntitySet = None

a list of EntitySet instances

AssociationSet = None

a list of AssociationSet instances

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

navigation = None

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. Attempting to create an Order in the base collection of Orders will always fail:

with Orders.OpenCollection() 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.OpenCollection() as collectionCustomers:
    # get the existing customer
    customer=collectionCustomers['ALFKI']
    with customer['Orders'].OpenCollection() 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.OpenCollection() as collectionCustomers,
        Orders.OpenCollection() as collectionOrders:
    customer=collectionCustomers.new_entity()
    # set customer details here
    order=collectionOrders.new_entity()
    # set order details here
    customer['Orders'].BindEntity(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

GetFQName()

Returns the fully qualified name of this entity set.

GetLocation()

Returns a pyslet.rfc2396.URI instance representing the location for this entity set.

SetLocation()

Sets the location of this entity set by resolving 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.

GetKey(keylike)

Extracts a key 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 to SimpleValue 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 GetKey, 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.

GetKeyDict(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(entityCollectionBinding, **extraArgs)

Binds this entity set to a specific class or callable used by OpenCollection()

entityCollectionBinding 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.

extraArgs is a python dict of named arguments to pass to the binding callable

OpenCollection()

Returns an EntityCollection instance suitable for accessing the entities themselves.

BindNavigation(name, entityCollectionBinding, **extraArgs)

Binds the navigation property name to a class or callable used by OpenNavigation()

entityCollectionBinding 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.

extraArgs is a python dict of named arguments to pass to the binding callable

OpenNavigation(name, sourceEntity)

Returns a NavigationCollection instance suitable for accessing the entities obtained by navigating from sourceEntity, an Entity instance, via the navigation property with name.

NavigationTarget(name)

Returns the target entity set of navigation property name

NavigationMultiplicity(name)

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.NavigationMultiplicity['Orders']==(Multiplicity.ZeroToOne,Multiplicity.Many)
IsEntityCollection(name)

Returns True if more than one entity is possible when navigating the named property.

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.odata2.csdl.CSDLElement

Represents the links between two actual sets of entities in the metadata model.

The GetQualifiedName() 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

entity_set = None

EntitySet 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

GetQualifiedName()

A utility function to return a qualified name.

The qualified name comprises the name of the parent AssociationSet and the role 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

Property = None

a list of Property

GetFQName()

Returns the full name of this type, including the schema namespace prefix.

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

Key = None

the Key

ValidateExpansion(expand, select)

A utility method for data providers.

Checks the expand and select options, as described in EntityCollection.Expand() for validity raising ValueError if they violate the OData specification.

Specifically the following are checked:

  1. That “*” only ever appears as the last item in a select

    path

  2. That nothing appears after a simple property in a select

    path

  3. That all names are valid property names

  4. That all expanded names are those of navigation properties

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

property = None

the Property instance of this (key) property

UpdateTypeRefs(scope, stopOnErrors=False)

Sets property

class pyslet.odata2.csdl.Property(parent)

Bases: pyslet.odata2.csdl.CSDLElement

Models a property of an EntityType or ComplexType.

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

fixedLength = None

a boolean indicating that the property must be of length maxLength

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

class pyslet.odata2.csdl.NavigationProperty(parent)

Bases: pyslet.odata2.csdl.CSDLElement

Models a navigation property of an EntityType.

name = None

the declared name of the navigation property

fromRole = None

the name of this link’s source role

toRole = None

the name of this link’s target role

from_end = None

the AssociationEnd instance representing this link’s source

toEnd = None

the AssociationEnd instance representing this link’s target

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 contained AssociationEnd 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

class pyslet.odata2.csdl.AssociationEnd(parent)

Bases: pyslet.odata2.csdl.CSDLElement

Models one end of an Association.

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

class pyslet.odata2.csdl.Documentation(parent)

Bases: pyslet.odata2.csdl.CSDLElement

Used to document elements in the metadata model

2.1.3.1.3. Misc Definitions

pyslet.odata2.csdl.ValidateSimpleIdentifier(identifier)

Validates a simple identifier, returning the identifier unchanged or raising ValueError.

class pyslet.odata2.csdl.SimpleType

Bases: pyslet.xsdatatypes20041028.Enumeration

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.DecodeValue(u"Edm.Int32")==SimpleType.Int32
SimpleType.DecodeValue(u"Int32")==SimpleType.Int32
SimpleType.EncodeValue(SimpleType.Int32)==u"Edm.Int32"  
PythonType = {<type 'str'>: 14, <type 'unicode'>: 14, <type 'long'>: 7, <type 'float'>: 8, <type 'bool'>: 2, <type 'int'>: 13}

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[types.IntType]==SimpleType.Int64
class pyslet.odata2.csdl.ConcurrencyMode

Bases: pyslet.xsdatatypes20041028.Enumeration

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.DecodeMaxLength(value)

Decodes a maxLength value from a unicode 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.EncodeMaxLength(value)

Encodes a maxLength value as a unicode 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.DecodeMultiplicity(src)

Decodes a Multiplicity value from a unicode string.

The valid strings are “0..1”, “1” and “*”

pyslet.odata2.csdl.EncodeMultiplicity(value)

Encodes a Multiplicity value as a unicode 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.

ParseBinaryLiteral()

Parses a binary literal, returning a binary string

ParseBooleanLiteral()

Parses a boolean literal returning True, False or None if no boolean literal was found.

ParseByteLiteral()

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.

ParseDateTimeLiteral()

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.

ParseGuidLiteral()

Parses a Guid literal, returning a UUID instance from the uuid module.

Returns None if no Guid can be parsed.

ParseNumericLiteral()

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.

ParseTimeLiteral()

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.

2.1.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.

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__() and clear() 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 change

You 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)

2.1.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.

class pyslet.odata2.csdl.NavigationError

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.EDMError

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.EDMError

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.EDMError

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 by NameTableMixin 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.EDMError

Bases: exceptions.Exception

General exception for all CSDL model errors.

2.1.3.1.5.1. Constants

pyslet.odata2.csdl.EDM_NAMESPACE = 'http://schemas.microsoft.com/ado/2009/11/edm'

Namespace to use for CSDL elements