********** Data Types ********** .. module:: yangson.datatype :synopsis: Classes representing YANG data types .. testsetup:: import os from yangson import DataModel from yangson.schemadata import SchemaContext os.chdir("examples/ex5") .. testcleanup:: os.chdir("../..") The *datatype* module defines the following classes: * :class:`BitsType`: YANG **bits** type. * :class:`BinaryType`: YANG **binary** type. * :class:`BooleanType`: YANG **boolean** type. * :class:`DataType`: Abstract class for data types. * :class:`Decimal64Type`: YANG **decimal64** type. * :class:`EmptyType`: YANG **empty** type. * :class:`EnumerationType`: YANG **enumeration** type. * :class:`LeafrefType`: YANG **leafref** type. * :class:`LinkType`: Abstract class for data types representing links. * :class:`InstanceIdentifierType`: YANG **instance-identifier** type. * :class:`IdentityrefType`: YANG **identityref** type. * :class:`IntegralType`: Abstract class for integral types. * :class:`Int8Type`: YANG **int8** type. * :class:`Int16Type`: YANG **int16** type. * :class:`Int32Type`: YANG **int32** type. * :class:`Int64Type`: YANG **int64** type. * :class:`NumericType`: Abstract class for numeric types. * :class:`StringType`: YANG **string** type. * :class:`Uint8Type`: YANG **uint8** type. * :class:`Uint16Type`: YANG **uint16** type. * :class:`Uint32Type`: YANG **uint32** type. * :class:`Uint64Type`: YANG **uint64** type. * :class:`UnionType`: YANG **union** type. Doctest__ snippets for this module use the data model from :ref:`sec-ex5`. __ http://www.sphinx-doc.org/en/stable/ext/doctest.html .. doctest:: >>> dm = DataModel.from_file('yang-library-ex5.json', ... mod_path=[".", "../../../yang-modules/ietf"]) >>> binary_t = dm.get_data_node('/example-5-a:binary-leaf').type >>> bits_t = dm.get_data_node('/example-5-a:bits-leaf').type >>> boolean_t = dm.get_data_node('/example-5-a:boolean-leaf').type >>> decimal64_t = dm.get_data_node('/example-5-a:decimal64-leaf').type >>> empty_t = dm.get_data_node('/example-5-a:empty-leaf').type >>> enumeration_t = dm.get_data_node('/example-5-a:enumeration-leaf').type >>> identityref_t = dm.get_data_node('/example-5-a:identityref-leaf').type >>> ii_t = dm.get_data_node('/example-5-a:instance-identifier-leaf').type >>> leafref_t = dm.get_data_node('/example-5-a:leafref-leaf').type >>> string_t = dm.get_data_node('/example-5-a:string-leaf').type >>> union_t = dm.get_data_node('/example-5-a:union-leaf').type YANG provides a selection of built-in data types, and also supports defining new types that are derived from existing types (built-in or derived) by specifying the base type and zero or more restrictions. See sec. `7.3`_ of [RFC7950]_ for details. *Yangson* library resolves all derived types so that the base type corresponds to a Python class and restrictions are represented as values of appropriate instance attributes. Instances of subclasses of :class:`DataType` typically appear as values of :attr:`~.TerminalNode.type` attribute that is common to all :class:`~.schemanode.TerminalNode` instances. .. class:: DataType(sctx: SchemaContext, name: YangIdentifier) This is the abstract superclass for all classes representing YANG data types. The methods described in this class comprise common API for all type, some subclasses then introduce type-specific methods. The constructor arguments *sctx* and *name* initialize values of the instance attributes :attr:`sctx` and :attr:`name`, respectively. .. rubric:: Instance Attributes .. attribute:: sctx :class:`~.schemadata.SchemaContext` in which the type definition and restrictions are to be interpreted. .. doctest:: >>> string_t.sctx.text_mid ('example-5-a', '2018-10-25') .. attribute:: default Default value of the type that may be defined by using the **default** statement inside a **typedef**. .. doctest:: >>> string_t.default 'xxy' .. attribute:: units Units of the type's values may be specified using the **units** statement inside a **typedef**. .. doctest:: >>> string_t.units is None True .. attribute:: name Name of the type if it is derived, otherwise ``None``. .. doctest:: >>> string_t.name 'my-string' >>> boolean_t.name is None True .. attribute:: error_tag This attribute records the error tag of the most recent type validation that failed. .. attribute:: error_message This attribute records the error message specified for the most recent type validation that failed. .. doctest:: >>> 'abc' in string_t False >>> string_t.error_tag 'invalid-type' >>> string_t.error_message 'xes and y: abc' .. rubric:: Public Methods .. method:: __contains__(val: ScalarValue) -> bool Return ``True`` if the argument *val* contains a valid value of the receiver type, otherwise return ``False``. This method enables the Python operators ``in`` and ``not in`` for use with types. .. doctest:: >>> "Dopey" in enumeration_t True >>> "SnowWhite" not in enumeration_t True .. automethod:: __str__ .. method:: from_raw(raw: RawScalar) -> Optional[ScalarValue] Return :term:`cooked value` converted from a :term:`raw value` *raw* according to the rules of the receiver data type, or ``None`` if the value in *raw* cannot be converted. The argument *raw* should follow the rules for JSON representation of scalar values as defined in [RFC7951]_. Conformance to the receiving type isn't guaranteed, as long as *raw* can be correctly converted. .. doctest:: >>> bits_t.from_raw('dos tres') ('dos', 'tres') >>> bits_t.from_raw(0) is None True .. method:: to_raw(val: ScalarValue) -> Optional[RawScalar] Return a :term:`raw value` converted from a :term:`cooked value` *val* according to the rules of the receiver data type, or ``None`` if the conversion fails. This method is essentially inverse to :meth:`from_raw`. The returned value can be encoded into JSON text by using the standard library functions :func:`json.dump` and :func:`json.dumps`. .. doctest:: >>> bits_t.to_raw(('dos', 'tres')) 'dos tres' >>> bits_t.to_raw((2,3)) is None True .. method:: parse_value(text: str) -> Optional[ScalarValue] Return a value of receiver's type parsed from *text*, or ``None`` if parsing fails. The argument *text* should follow the rules for lexical representation of scalar values as defined in [RFC7950]_. Conformance of the result to the receiving type isn't guaranteed, as long as *text* can be correctly parsed. .. doctest:: >>> boolean_t.parse_value('true') True >>> boolean_t.parse_value('foo') is None True .. method:: canonical_string(val: ScalarValue) -> Optional[str] Return canonical string representation of *val* as defined for the receiver type, or ``None`` if *val* is not a valid value of the receiver type. See sec. `9.1`_ in [RFC7950]_ for more information about canonical forms. This method is a partial inverse of :meth:`parse_value`, the latter method is however able to parse non-canonical string forms, as shown in the next example. .. doctest:: >>> e = decimal64_t.parse_value("002.718281") >>> e Decimal('2.7183') >>> decimal64_t.canonical_string(e) '2.7183' .. method:: from_yang(text: str) -> ScalarValue Return a value of receiver's type parsed from *text* that is expected to follow the rules for encoding the argument of the **default** statement in YANG. Conformance to the receiving type isn't guaranteed, as long as *text* can be correctly converted. This method raises :exc:`~.InvalidArgument` if the receiver type cannot properly parse *text*. .. doctest:: >>> sctx = SchemaContext(dm.schema_data, 'example-5-a', ('example-5-a', '')) >>> identityref_t.from_yang('ex5b:derived-identity') ('derived-identity', 'example-5-b') .. method:: yang_type() -> YangIdentifier Return YANG name of the receiver. .. doctest:: >>> ii_t.yang_type() 'instance-identifier' .. class:: EmptyType This class is a subclass of :class:`DataType`, and represents YANG **empty** type. It is implemented as a singleton class because the **empty** type cannot be restricted. .. class:: BitsType This class is a subclass of :class:`DataType`, and represents YANG **bits** type. A :term:`cooked value` of this type is a tuple of strings – names of the bits that are set. See documentation of :meth:`~DataType.from_raw` for an example. .. rubric:: Instance Attributes .. attribute:: bit A dictionary that maps bit labels as defined by **bit** statements to bit positions. The position are either defined explicitly via the **position** statement, or assigned automatically – see sec. `9.7.4.2`_ in [RFC7950]_ for details. .. doctest:: >>> bits_t.bit['un'] 1 .. class:: BooleanType This class is a subclass of :class:`DataType`, and represents YANG **boolean** type. Both :term:`raw value` and :term:`cooked value` of this type is a Python :class:`bool` value. See documentation of :meth:`~DataType.parse_value` for an example. .. class:: StringType This class is a subclass of :class:`DataType`, and represents YANG **string** type. .. rubric:: Instance Attributes .. attribute:: length Specification of restrictions on the string length. It is a list of two-element lists specifying the lower and upper bounds for the string length. This attribute is compiled from the **length** type restriction. .. doctest:: >>> string_t.length.intervals [[2, 4]] >>> 'xxxxy' in string_t # too long False .. attribute:: patterns List of regular expression patterns with which the type is restricted (those that do not have the **invert-match** modifier). Each entry is a compiled Python regular expression pattern. .. doctest:: >>> string_t.patterns[0].regex re.compile('^(?:x*y)$(?!\\n\\Z)') >>> 'xxxy' in string_t # match True >>> 'xxyy' not in string_t # no match True >>> 'xxy\n' not in string_t # no match True .. attribute:: invert_patterns List of regular expression patterns that have the **invert-match** modifier, with which the type is restricted. Each entry is a compiled Python regular expression pattern. .. class:: BinaryType This class is a subclass of :class:`StringType`, and represents YANG **binary** type. Raw values are strings obtained as output of the *Base 64* encoding [RFC4648]_. The :term:`cooked value` is a Python :class:`bytes` object. .. doctest:: >>> binary_t.to_raw(b'\xFF\xFE') '//4=' Characters outside the encoding alphabet of Base 64 are not permitted in a raw value: .. doctest:: >>> binary_t.from_raw('u#Q==') is None True .. class:: EnumerationType This class is a subclass of :class:`DataType`, and represents YANG **enumeration** type. Both :term:`raw value` and :term:`cooked value` of this type is a string, and it must must be one of the names specified in the type's definition via the **enum** statement. See documentation of :meth:`~DataType.contains` for an example. .. rubric:: Instance Attributes .. attribute:: enum A dictionary that maps assigned enum names to their values as defined via the **value** statement or assigned automatically. .. doctest:: >>> enumeration_t.enum['Happy'] 4 .. class:: LinkType This is an abstract superclass for types that refer to other instance nodes (**leafref** and **instance-identifier**). It is a subclass of :class:`DataType`. .. rubric:: Instance Attributes .. attribute:: require_instance Boolean flag that indicates whether an instance node being referred to is required to exist. This property is set by the **require-instance** statement in type's definition, see sec. `9.9.3`_ in [RFC7950]_. .. doctest:: >>> leafref_t.require_instance True .. class:: LeafrefType This class is a subclass of :class:`LinkType`, and represents YANG **leafref** type. The type of a :term:`cooked value` of this type is dictated by the type of the leaf node that is being referred to via the **path** statement. .. rubric:: Instance Attributes .. attribute:: path An :class:`~.xpathast.Expr` object (XPath abstract syntax tree) parsed from the argument of the **path** statement. .. doctest:: >>> print(leafref_t.path.syntax_tree(), end='') LocationPath Root Step (child ('string-leaf', 'example-5-a')) .. attribute:: ref_type Type of the leaf being referred to. .. doctest:: >>> type(leafref_t.ref_type) >>> 'abc' in leafref_t False .. class:: InstanceIdentifierType This class is a subclass of :class:`LinkType`, and represents YANG **instance-identifier** type. A :term:`cooked value` of this type is an :class:`~.instance.InstanceRoute` object parsed from a :term:`raw value` as defined in sec. `9.13`_ of [RFC7950]_. .. doctest:: >>> type(ii_t.from_raw('/example-5-a:boolean-leaf')) >>> str(ii_t.from_raw('/example-5-a:boolean-leaf')) '/example-5-a:boolean-leaf' .. class:: IdentityrefType This class is a subclass of :class:`DataType`, and represents YANG **identityref** type. A :term:`cooked value` of this type is a :term:`qualified name` of an identity defined by the data model. See documentation of :meth:`~DataType.from_yang` for an example. .. rubric:: Instance Attributes .. attribute:: bases List of :term:`qualified name`\ s of identities that are defined as bases for this type via the **base** statement. .. doctest:: >>> identityref_t.bases [('base-identity', 'example-5-b')] .. class:: NumericType This class is an abstract superclass for all classes representing numeric types. It is subclass of :class:`DataType`. .. class:: Decimal64Type This class is a subclass of :class:`NumericType`, and represents YANG **decimal64** type. A :term:`cooked value` of this type is a :class:`decimal.Decimal` number. See documentation of :meth:`~DataType.canonical_string` for an example. .. class:: IntegralType This class is an abstract superclass for all classes representing integral numbers. It is subclass of :class:`NumericType`, and represents YANG **integral** type. Python unlimited precision integers (:class:`int`) are use for :term:`cooked value`\ s of all integral types, and restrictions on ranges are enforced explicitly for specific types such as **uint32**. .. class:: Int8Type This class is a subclass of :class:`IntegralType`, and represents YANG **int8** type. .. class:: Int16Type This class is a subclass of :class:`IntegralType`, and represents YANG **int16** type. .. class:: Int32Type This class is a subclass of :class:`IntegralType`, and represents YANG **int32** type. .. class:: Int64Type This class is a subclass of :class:`IntegralType`, and represents YANG **int64** type. .. class:: Uint8Type This class is a subclass of :class:`IntegralType`, and represents YANG **uint8** type. .. class:: Uint16Type This class is a subclass of :class:`IntegralType`, and represents YANG **uint16** type. .. class:: Uint32Type This class is a subclass of :class:`IntegralType`, and represents YANG **uint32** type. .. class:: Uint64Type This class is a subclass of :class:`IntegralType`, and represents YANG **uint64** type. .. class:: UnionType This class is a subclass of :class:`DataType`, and represents YANG **union** type. A :term:`cooked value` of this type must be a valid cooked value of a union's member type. Methods in this class are implemented so that they iterate through the member types in the order in which they are specified in the union type definition, and try the same method from their classes. If the method fails, next member class is tried in turn. The result of the first method implementation that succeeds is used as the result of the implementation in the :class:`UnionType`. If the method does not succeed for any of the member classes, then the :class:`UnionType` method fails, too. .. doctest:: >>> union_t.parse_value('true') # result is bool, not string True .. rubric:: Instance Attributes .. attribute:: types List of member types. .. doctest:: >>> len(union_t.types) 2 >>> type(union_t.types[0]) .. _7.3: https://rfc-editor.org/rfc/rfc7950.html#section-7.3 .. _9.1: https://rfc-editor.org/rfc/rfc7950.html#section-9.1 .. _9.7.4.2: https://rfc-editor.org/rfc/rfc7950.html#section-9.7.4.2 .. _9.9.3: https://rfc-editor.org/rfc/rfc7950.html#section-9.9.3 .. _9.13: https://rfc-editor.org/rfc/rfc7950.html#section-9.13