summaryrefslogtreecommitdiff
path: root/doc/constraints.html
diff options
context:
space:
mode:
authorelie <elie>2012-11-26 11:28:18 +0000
committerelie <elie>2012-11-26 11:28:18 +0000
commit7d61323e0193aaec202fab1e49142cc985264395 (patch)
treee34f8f6da5480de08f556d3f30022e3602bffdeb /doc/constraints.html
parent81e25eb1cd2a8f3b9aa757178bbf8db2cbd5e445 (diff)
downloadpyasn1-7d61323e0193aaec202fab1e49142cc985264395.tar.gz
documentation split up into chapters
Diffstat (limited to 'doc/constraints.html')
-rw-r--r--doc/constraints.html436
1 files changed, 436 insertions, 0 deletions
diff --git a/doc/constraints.html b/doc/constraints.html
new file mode 100644
index 0000000..53da1ad
--- /dev/null
+++ b/doc/constraints.html
@@ -0,0 +1,436 @@
+<html>
+<title>
+PyASN1 subtype constraints
+</title>
+<head>
+</head>
+<body>
+<center>
+<table width=60%>
+<tr>
+<td>
+
+<h4>
+1.4 PyASN1 subtype constraints
+</h4>
+
+<p>
+Most ASN.1 types can correspond to an infinite set of values. To adapt to
+particular application's data model and needs, ASN.1 provides a mechanism
+for limiting the infinite set to values, that make sense in particular case.
+</p>
+
+<p>
+Imposing value constraints on an ASN.1 type can also be seen as creating
+a subtype from its base type.
+</p>
+
+<p>
+In pyasn1, constraints take shape of immutable objects capable
+of evaluating given value against constraint-specific requirements.
+Constraint object is a property of pyasn1 type. Like TagSet property,
+associated with every pyasn1 type, constraints can never be modified
+in place. The only way to modify pyasn1 type constraint is to associate
+new constraint object to a new pyasn1 type object.
+</p>
+
+<p>
+A handful of different flavors of <i>constraints</i> are defined in ASN.1.
+We will discuss them one by one in the following chapters and also explain
+how to combine and apply them to types.
+</p>
+
+<a name="1.4.1"></a>
+<h4>
+1.4.1 Single value constraint
+</h4>
+
+<p>
+This kind of constraint allows for limiting type to a finite, specified set
+of values.
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+DialButton ::= OCTET STRING (
+ "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+)
+</pre>
+</td></tr></table>
+
+<p>
+Its pyasn1 implementation would look like:
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+>>> from pyasn1.type import constraint
+>>> c = constraint.SingleValueConstraint(
+ '0','1','2','3','4','5','6','7','8','9'
+)
+>>> c
+SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
+>>> c('0')
+>>> c('A')
+Traceback (most recent call last):
+...
+pyasn1.type.error.ValueConstraintError:
+ SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A
+>>>
+</pre>
+</td></tr></table>
+
+<p>
+As can be seen in the snippet above, if a value violates the constraint, an
+exception will be thrown. A constrainted pyasn1 type object holds a
+reference to a constraint object (or their combination, as will be explained
+later) and calls it for value verification.
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+>>> from pyasn1.type import univ, constraint
+>>> class DialButton(univ.OctetString):
+... subtypeSpec = constraint.SingleValueConstraint(
+... '0','1','2','3','4','5','6','7','8','9'
+... )
+>>> DialButton('0')
+DialButton(b'0')
+>>> DialButton('A')
+Traceback (most recent call last):
+...
+pyasn1.type.error.ValueConstraintError:
+ SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A
+>>>
+</pre>
+</td></tr></table>
+
+<p>
+Constrained pyasn1 value object can never hold a violating value.
+</p>
+
+<a name="1.4.2"></a>
+<h4>
+1.4.2 Value range constraint
+</h4>
+
+<p>
+A pair of values, compliant to a type to be constrained, denote low and upper
+bounds of allowed range of values of a type.
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+Teenagers ::= INTEGER (13..19)
+</pre>
+</td></tr></table>
+
+<p>
+And in pyasn1 terms:
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+>>> from pyasn1.type import univ, constraint
+>>> class Teenagers(univ.Integer):
+... subtypeSpec = constraint.ValueRangeConstraint(13, 19)
+>>> Teenagers(14)
+Teenagers(14)
+>>> Teenagers(20)
+Traceback (most recent call last):
+...
+pyasn1.type.error.ValueConstraintError:
+ ValueRangeConstraint(13, 19) failed at: 20
+>>>
+</pre>
+</td></tr></table>
+
+<p>
+Value range constraint usually applies numeric types.
+</p>
+
+<a name="1.4.3"></a>
+<h4>
+1.4.3 Size constraint
+</h4>
+
+<p>
+It is sometimes convenient to set or limit the allowed size of a data item
+to be sent from one application to another to manage bandwidth and memory
+consumption issues. Size constraint specifies the lower and upper bounds
+of the size of a valid value.
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+TwoBits ::= BIT STRING (SIZE (2))
+</pre>
+</td></tr></table>
+
+<p>
+Express the same grammar in pyasn1:
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+>>> from pyasn1.type import univ, constraint
+>>> class TwoBits(univ.BitString):
+... subtypeSpec = constraint.ValueSizeConstraint(2, 2)
+>>> TwoBits((1,1))
+TwoBits("'11'B")
+>>> TwoBits((1,1,0))
+Traceback (most recent call last):
+...
+pyasn1.type.error.ValueConstraintError:
+ ValueSizeConstraint(2, 2) failed at: (1, 1, 0)
+>>>
+</pre>
+</td></tr></table>
+
+<p>
+Size constraint can be applied to potentially massive values - bit or octet
+strings, SEQUENCE OF/SET OF values.
+</p>
+
+<a name="1.4.4"></a>
+<h4>
+1.4.4 Alphabet constraint
+</h4>
+
+<p>
+The permitted alphabet constraint is similar to Single value constraint
+but constraint applies to individual characters of a value.
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+MorseCode ::= PrintableString (FROM ("."|"-"|" "))
+</pre>
+</td></tr></table>
+
+<p>
+And in pyasn1:
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+>>> from pyasn1.type import char, constraint
+>>> class MorseCode(char.PrintableString):
+... subtypeSpec = constraint.PermittedAlphabetConstraint(".", "-", " ")
+>>> MorseCode("...---...")
+MorseCode('...---...')
+>>> MorseCode("?")
+Traceback (most recent call last):
+...
+pyasn1.type.error.ValueConstraintError:
+ PermittedAlphabetConstraint(".", "-", " ") failed at: "?"
+>>>
+</pre>
+</td></tr></table>
+
+<p>
+Current implementation does not handle ranges of characters in constraint
+(FROM "A".."Z" syntax), one has to list the whole set in a range.
+</p>
+
+<a name="1.4.5"></a>
+<h4>
+1.4.5 Constraint combinations
+</h4>
+
+<p>
+Up to this moment, we used a single constraint per ASN.1 type. The standard,
+however, allows for combining multiple individual constraints into
+intersections, unions and exclusions.
+</p>
+
+<p>
+In pyasn1 data model, all of these methods of constraint combinations are
+implemented as constraint-like objects holding individual constraint (or
+combination) objects. Like terminal constraint objects, combination objects
+are capable to perform value verification at its set of enclosed constraints
+according to the logic of particular combination.
+</p>
+
+<p>
+Constraints intersection verification succeeds only if a value is
+compliant to each constraint in a set. To begin with, the following
+specification will constitute a valid telephone number:
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+PhoneNumber ::= NumericString (FROM ("0".."9")) (SIZE 11)
+</pre>
+</td></tr></table>
+
+<p>
+Constraint intersection object serves the logic above:
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+>>> from pyasn1.type import char, constraint
+>>> class PhoneNumber(char.NumericString):
+... subtypeSpec = constraint.ConstraintsIntersection(
+... constraint.PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'),
+... constraint.ValueSizeConstraint(11, 11)
+... )
+>>> PhoneNumber('79039343212')
+PhoneNumber('79039343212')
+>>> PhoneNumber('?9039343212')
+Traceback (most recent call last):
+...
+pyasn1.type.error.ValueConstraintError:
+ ConstraintsIntersection(
+ PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'),
+ ValueSizeConstraint(11, 11)) failed at:
+ PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9') failed at: "?039343212"
+>>> PhoneNumber('9343212')
+Traceback (most recent call last):
+...
+pyasn1.type.error.ValueConstraintError:
+ ConstraintsIntersection(
+ PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'),
+ ValueSizeConstraint(11, 11)) failed at:
+ ValueSizeConstraint(10, 10) failed at: "9343212"
+>>>
+</pre>
+</td></tr></table>
+
+<p>
+Union of constraints works by making sure that a value is compliant
+to any of the constraint in a set. For instance:
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+CapitalOrSmall ::= IA5String (FROM ('A','B','C') | FROM ('a','b','c'))
+</pre>
+</td></tr></table>
+
+<p>
+It's important to note, that a value must fully comply to any single
+constraint in a set. In the specification above, a value of all small or
+all capital letters is compliant, but a mix of small&capitals is not.
+Here's its pyasn1 analogue:
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+>>> from pyasn1.type import char, constraint
+>>> class CapitalOrSmall(char.IA5String):
+... subtypeSpec = constraint.ConstraintsUnion(
+... constraint.PermittedAlphabetConstraint('A','B','C'),
+... constraint.PermittedAlphabetConstraint('a','b','c')
+... )
+>>> CapitalOrSmall('ABBA')
+CapitalOrSmall('ABBA')
+>>> CapitalOrSmall('abba')
+CapitalOrSmall('abba')
+>>> CapitalOrSmall('Abba')
+Traceback (most recent call last):
+...
+pyasn1.type.error.ValueConstraintError:
+ ConstraintsUnion(PermittedAlphabetConstraint('A', 'B', 'C'),
+ PermittedAlphabetConstraint('a', 'b', 'c')) failed at: failed for "Abba"
+>>>
+</pre>
+</td></tr></table>
+
+<p>
+Finally, the exclusion constraint simply negates the logic of value
+verification at a constraint. In the following example, any integer value
+is allowed in a type but not zero.
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+NoZero ::= INTEGER (ALL EXCEPT 0)
+</pre>
+</td></tr></table>
+
+<p>
+In pyasn1 the above definition would read:
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+>>> from pyasn1.type import univ, constraint
+>>> class NoZero(univ.Integer):
+... subtypeSpec = constraint.ConstraintsExclusion(
+... constraint.SingleValueConstraint(0)
+... )
+>>> NoZero(1)
+NoZero(1)
+>>> NoZero(0)
+Traceback (most recent call last):
+...
+pyasn1.type.error.ValueConstraintError:
+ ConstraintsExclusion(SingleValueConstraint(0)) failed at: 0
+>>>
+</pre>
+</td></tr></table>
+
+<p>
+The depth of such a constraints tree, built with constraint combination objects
+at its nodes, has not explicit limit. Value verification is performed in a
+recursive manner till a definite solution is found.
+</p>
+
+<a name="1.5"></a>
+<h4>
+1.5 Types relationships
+</h4>
+
+<p>
+In the course of data processing in an application, it is sometimes
+convenient to figure out the type relationships between pyasn1 type or
+value objects. Formally, two things influence pyasn1 types relationship:
+<i>tag set</i> and <i>subtype constraints</i>. One pyasn1 type is considered
+to be a derivative of another if their TagSet and Constraint objects are
+a derivation of one another.
+</p>
+
+<p>
+The following example illustrates the concept (we use the same tagset but
+different constraints for simplicity):
+</p>
+
+<table bgcolor="lightgray" border=0 width=100%><TR><TD>
+<pre>
+>>> from pyasn1.type import univ, constraint
+>>> i1 = univ.Integer(subtypeSpec=constraint.ValueRangeConstraint(3,8))
+>>> i2 = univ.Integer(subtypeSpec=constraint.ConstraintsIntersection(
+... constraint.ValueRangeConstraint(3,8),
+... constraint.ValueRangeConstraint(4,7)
+... ) )
+>>> i1.isSameTypeWith(i2)
+False
+>>> i1.isSuperTypeOf(i2)
+True
+>>> i1.isSuperTypeOf(i1)
+True
+>>> i2.isSuperTypeOf(i1)
+False
+>>>
+</pre>
+</td></tr></table>
+
+<p>
+As can be seen in the above code snippet, there are two methods of any pyasn1
+type/value object that test types for their relationship:
+<b>isSameTypeWith</b>() and <b>isSuperTypeOf</b>(). The former is
+self-descriptive while the latter yields true if the argument appears
+to be a pyasn1 object which has tagset and constraints derived from those
+of the object being called.
+</p>
+
+<hr>
+
+</td>
+</tr>
+</table>
+</center>
+</body>
+</html>