Built-in Types¶
See also
To learn how to create custom types, see the Extending Teleport section.
A Teleport type is created by providing two things:
A set of all JSON values that can be the type’s members
A way to interpret a JSON value according to the type
In implementing types, this roughly corresponds to a type-checking function and a deserialization function, although the latter is optional. This library implements all 10 built-in Teleport types, as well as a few extra ones.
Integer¶
Uses instances of int
and long
in both the JSON form and the
native form.
>>> t("Integer").check(1)
True
>>> t("Integer").check(1L)
True
Decimal¶
Uses instances of int
, long
, float
and
Decimal
in both the JSON form and the native form.
>>> t("Decimal").check(0)
True
>>> t("Decimal").check(922337203685477580700000L)
True
>>> t("Decimal").check(1.0e2)
True
>>> t("Decimal").check(Decimal('0.99'))
True
By default, the json
module maps non-integer JSON numbers to floats.
If precision is important for you, you’ll be happy to know that Python’s
built-in Decimal
class can be plugged into the json
module:
>>> import decimal
>>> json.loads('{"price": 0.99}', parse_float=decimal.Decimal)
{u'price': Decimal('0.99')}
See also
To read more the relevant design choices, see On Numeric Types.
String¶
Uses instances of unicode
and ASCII strings of type str
in
both the JSON form and the native form.
>>> t("String").check(u"hello world")
True
>>> t("String").check("hello world")
True
>>> t("String").check("hello" + chr(225))
False
Boolean¶
Uses instances of boolean
in both the JSON form and the native form.
>>> t("Boolean").check(True)
True
DateTime¶
The RFC 3339 (proposed) standard
is used to represent datetime objects in JSON form. In the native form,
instances of datetime
from the Python standard library are used.
>>> t("DateTime").check('2013-10-18T01:58:24.904349Z')
True
>>> a = t("DateTime").from_json('2013-10-18T01:58:24.904349Z')
>>> a
datetime.datetime(2013, 10, 18, 1, 58, 24, 904349, tzinfo=<UTC>)
>>> t("DateTime").to_json(a)
'2013-10-18T01:58:24.904349Z'
While RFC 3339 provides a convention for specifying time at an unknown location, Teleport does not support it, defaulting instead to UTC.
Creating Timestamps¶
It may be tempting for new Python programmers to use
datetime.now()
or
datetime.utcnow()
, but neither of these are
suitable for creating proper timestamps. The latter option comes close, but
fails to include a piece of data signifying that the time is in UTC.
Omitting timezones from the standard library was a wise decision, but not including a UTC object is a puzzling one. Sadly, there is no Python one-liner for creating a UTC timestamp. Similarly to pytz, Teleport provides a convenient import for this purpose:
>>> from teleport import utc
>>> datetime.utcnow().replace(tzinfo=utc)
datetime.datetime(2014, 12, 6, 9, 28, 55, 908619, tzinfo=<UTC>)
Note that another tempting option, datetime.now(utc)
, is also incorrect.
See also
On DateTime Standards discusses the choice of RFC 3309 over ISO 8601. On Timezones and Offsets discusses timezone issues.
JSON¶
A wildcard that consists of all JSON values, that is, all values accepted by
the json
module from the Python standard library.
>>> t("JSON").check([None, 1, "xyz"])
True
Schema¶
This is a very special type. Its value space is the set of all possible inputs
for t()
, all possible type definitions. The Schema type enables dynamic
typing, tagged unions and other high-level possibilities.
>>> t("Schema").check("Integer")
True
Array¶
Array is a generic type whose parameter is a type definition. This parameter
specifies the type of every element in the array. Uses instances of
list
in both the JSON form and the native form.
>>> t({"Array": "Integer"}).check([1, 2, 3])
True
>>> t({"Array": "Integer"}).check([1, 2, 3.0])
False
Map¶
Similar to the Array type, but using JSON objects in the JSON form and
instances of dict
in the native form.
>>> t({"Map": "Decimal"}).check({"x": 0.12, "y": 0.87})
True
>>> t({"Map": "Integer"}).check({"a": 1, "b": True})
False
Struct¶
The Struct type uses instances of dict
for both the JSON and native
form. It is a generic type and its parameter is a JSON object with two members:
required and optional. Both are of type t({"Map": "Schema"})
:
>>> TODO = t({"Struct": {
... "required": {"task": "String"},
... "optional": {"priority": "Integer",
... "deadline": "DateTime"}}})
With this type instance, you can validate JSON objects like these:
>>> TODO.check({"task": "Return videotapes"})
True
>>> TODO.check({"task": "Return videotapes",
... "deadline": "2015-04-05T14:30"})
True
Of course, you cannot omit a required field and each field’s schema must be respected:
>>> TODO.check({})
False
>>> TODO.check({"task": 1})
False
Like Array and Map, Struct performs recursive serialization:
>>> TODO.from_json({"task": "Return videotapes",
... "deadline": "2015-04-05T14:30"})
{u'deadline': datetime.datetime(2015, 4, 5, 14, 30),
u'task': u'Return videotapes'}