More docs. That's the lot for python now except path and schema.

This commit is contained in:
Tony Garnock-Jones 2023-03-17 00:07:27 +01:00
parent c7687772b0
commit a4403cf6f3
18 changed files with 2333 additions and 617 deletions

View File

@ -0,0 +1,8 @@
Python's strings, byte strings, integers, booleans, and double-precision floats stand directly
for their Preserves counterparts. Wrapper objects for [Float][preserves.values.Float] and
[Symbol][preserves.values.Symbol] complete the suite of atomic types.
Python's lists and tuples correspond to Preserves `Sequence`s, and dicts and sets to
`Dictionary` and `Set` values, respectively. Preserves `Record`s are represented by
[Record][preserves.values.Record] objects. Finally, embedded values are represented by
[Embedded][preserves.values.Embedded] objects.

View File

@ -12,7 +12,7 @@ of JSON) and [machine-oriented binary format](https://preserves.dev/preserves-bi
also implements [Preserves Schema](https://preserves.dev/preserves-schema.html) and [Preserves
Path](https://preserves.dev/preserves-path.html).
- Main package API: [preserves](/api)
- Main package API: [preserves](api)
## What is Preserves?
@ -24,12 +24,6 @@ Preserves `Value`s are categorized in the following way:
{% include "value-grammar.md" %}
Python's strings, byte strings, integers, booleans, and double-precision floats stand directly
for their Preserves counterparts. Small wrapper classes for `Float` and `Symbol` complete the
suite of atomic types.
Python's lists and tuples correspond to Preserves `Sequence`s, and dicts and sets to
`Dictionary` and `Set` values, respectively. Preserves `Record`s are represented by a `Record`
class. Finally, embedded values are represented by a small `Embedded` wrapper class.
{% include "python-representation.md" %}
[semantics]: https://preserves.dev/preserves.html#semantics

View File

@ -1,3 +1,5 @@
# Representations of Values
{% include "python-representation.md" %}
::: preserves.values

View File

@ -1,6 +1,6 @@
"""Preserves specifies a [total ordering](https://preserves.dev/preserves.html#total-order) and
an [equivalence](https://preserves.dev/preserves.html#equivalence) between terms. This module
implements the ordering and equivalence relations.
an [equivalence](https://preserves.dev/preserves.html#equivalence) between terms. The
[preserves.compare][] module implements the ordering and equivalence relations.
```python
>>> cmp("bzz", "c")

View File

@ -1,13 +1,16 @@
"""TODO"""
"""The [preserves.error][] module exports various `Error` subclasses."""
class DecodeError(ValueError):
"""TODO"""
"""Raised whenever [preserves.binary.Decoder][] or [preserves.text.Parser][] detect invalid
input."""
pass
class EncodeError(ValueError):
"""TODO"""
"""Raised whenever [preserves.binary.Encoder][] or [preserves.text.Formatter][] are unable to proceed."""
pass
class ShortPacket(DecodeError):
"""TODO"""
"""Raised whenever [preserves.binary.Decoder][] or [preserves.text.Parser][] discover that
they want to read beyond the end of the currently-available input buffer in order to
completely read an encoded value."""
pass

View File

@ -1,9 +1,18 @@
"""TODO"""
"""The [preserves.fold][] module exports various utilities for traversing compound `Value`s."""
from .values import ImmutableDict, dict_kvs, Embedded, Record
def map_embeddeds(f, v):
"""TODO"""
"""Returns an [equivalent][preserves.compare.eq] copy of `v`, except where each contained
[Embedded][preserves.values.Embedded] value is replaced by `f` applied to the Embedded's
`embeddedValue` attribute.
```python
>>> map_embeddeds(lambda w: Embedded(f'w={w}'), ['a', Embedded(123), {'z': 6.0}])
('a', #!'w=123', {'z': 6.0})
```
"""
def walk(v):
if isinstance(v, Embedded):
return f(v.embeddedValue)

View File

@ -1,4 +1,4 @@
"""TODO"""
"""The [preserves.merge][] module exports various utilities for merging `Value`s."""
from .values import ImmutableDict, dict_kvs, Embedded, Record
@ -6,7 +6,8 @@ def merge_embedded_id(a, b):
return a if a is b else None
def merge(v0, *vs, merge_embedded=None):
"""TODO"""
"""Repeatedly merges `v0` with each element in `vs` using [merge2][preserves.merge.merge2],
returning the final result. The `merge_embedded` parameter is passed on to merge2."""
v = v0
for vN in vs:
v = merge2(v, vN, merge_embedded=merge_embedded)
@ -20,7 +21,42 @@ def merge_seq(aa, bb, merge_embedded=None):
return [merge2(a, b, merge_embedded=merge_embedded) for (a, b) in zip(aa, bb)]
def merge2(a, b, merge_embedded=None):
"""TODO"""
"""Merges `a` and `b`, returning the result. Raises `ValueError` if, during the merge, a
pair of incompatible values is discovered.
If `a` and `b` are [Embedded][preserves.values.Embedded] objects, their `embeddedValue`s
are merged using `merge_embedded`, and the result is again wrapped in an
[Embedded][preserves.values.Embedded] object.
```python
>>> merge2(123, 234)
Traceback (most recent call last):
...
ValueError: Cannot merge items
>>> merge2(123, 123)
123
>>> merge2('hi', 0)
Traceback (most recent call last):
...
ValueError: Cannot merge items
>>> merge2([1, 2], [1, 2])
[1, 2]
>>> merge2([1, 2], [1, 3])
Traceback (most recent call last):
...
ValueError: Cannot merge items
>>> merge2({'a': 1, 'b': 2}, {'a': 1, 'c': 3})
{'a': 1, 'b': 2, 'c': 3}
>>> merge2({'a': 1, 'b': 2}, {'a': 10, 'c': 3})
Traceback (most recent call last):
...
ValueError: Cannot merge items
>>> merge2(Record('a', [1, {'x': 2}]), Record('a', [1, {'y': 3}]))
a(1, {'x': 2, 'y': 3})
```
"""
if a == b:
return a
if isinstance(a, (list, tuple)) and isinstance(b, (list, tuple)):

View File

@ -1,4 +1,19 @@
"""TODO"""
"""The [preserves.text][] module implements the [Preserves human-readable text
syntax](https://preserves.dev/preserves-text.html).
The main entry points are functions [stringify][preserves.text.stringify],
[parse][preserves.text.parse], and
[parse_with_annotations][preserves.text.parse_with_annotations].
```python
>>> stringify(Record(Symbol('hi'), [1, [2, 3]]))
'<hi 1 [2 3]>'
>>> parse('<hi 1 [2 3]>')
#hi(1, (2, 3))
```
"""
import numbers
import struct
@ -11,16 +26,110 @@ from .compat import basestring_, unichr_
from .binary import Decoder
class TextCodec(object):
"""TODO"""
pass
NUMBER_RE = re.compile(r'^([-+]?\d+)(((\.\d+([eE][-+]?\d+)?)|([eE][-+]?\d+))([fF]?))?$')
class Parser(TextCodec):
"""TODO"""
"""Parser for the human-readable Preserves text syntax.
Args:
input_buffer (str):
initial contents of the input buffer; may subsequently be extended by calling
[extend][preserves.text.Parser.extend].
include_annotations (bool):
if `True`, wrap each value and subvalue in an
[Annotated][preserves.values.Annotated] object.
parse_embedded:
function accepting a `Value` and returning a possibly-decoded form of that value
suitable for placing into an [Embedded][preserves.values.Embedded] object.
Normal usage is to supply input text, and keep calling [next][preserves.text.Parser.next]
until a [ShortPacket][preserves.error.ShortPacket] exception is raised:
```python
>>> d = Parser('123 "hello" @x []')
>>> d.next()
123
>>> d.next()
'hello'
>>> d.next()
()
>>> d.next()
Traceback (most recent call last):
...
preserves.error.ShortPacket: Short input buffer
```
Alternatively, keep calling [try_next][preserves.text.Parser.try_next] until it yields
`None`, which is not in the domain of Preserves `Value`s:
```python
>>> d = Parser('123 "hello" @x []')
>>> d.try_next()
123
>>> d.try_next()
'hello'
>>> d.try_next()
()
>>> d.try_next()
```
For convenience, [Parser][preserves.text.Parser] implements the iterator interface,
backing it with [try_next][preserves.text.Parser.try_next], so you can simply iterate
over all complete values in an input:
```python
>>> d = Parser('123 "hello" @x []')
>>> list(d)
[123, 'hello', ()]
```
```python
>>> for v in Parser('123 "hello" @x []'):
... print(repr(v))
123
'hello'
()
```
Supply `include_annotations=True` to read annotations alongside the annotated values:
```python
>>> d = Parser('123 "hello" @x []', include_annotations=True)
>>> list(d)
[123, 'hello', @#x ()]
```
If you are incrementally reading from, say, a socket, you can use
[extend][preserves.text.Parser.extend] to add new input as if comes available:
```python
>>> d = Parser('123 "he')
>>> d.try_next()
123
>>> d.try_next() # returns None because the input is incomplete
>>> d.extend('llo"')
>>> d.try_next()
'hello'
>>> d.try_next()
```
Attributes:
input_buffer (str): buffered input waiting to be processed
index (int): read position within `input_buffer`
"""
def __init__(self, input_buffer=u'', include_annotations=False, parse_embedded=lambda x: x):
"""TODO"""
super(Parser, self).__init__()
self.input_buffer = input_buffer
self.index = 0
@ -28,7 +137,8 @@ class Parser(TextCodec):
self.parse_embedded = parse_embedded
def extend(self, text):
"""TODO"""
"""Appends `text` to the remaining contents of `self.input_buffer`, trimming already-processed
text from the front of `self.input_buffer` and resetting `self.index` to zero."""
self.input_buffer = self.input_buffer[self.index:] + text
self.index = 0
@ -208,7 +318,11 @@ class Parser(TextCodec):
return Annotated(v) if self.include_annotations else v
def next(self):
"""TODO"""
"""Reads the next complete `Value` from the internal buffer, raising
[ShortPacket][preserves.error.ShortPacket] if too few bytes are available, or
[DecodeError][preserves.error.DecodeError] if the input is invalid somehow.
"""
self.skip_whitespace()
c = self.peek()
if c == '"':
@ -273,7 +387,8 @@ class Parser(TextCodec):
return self.wrap(self.read_raw_symbol_or_number([c]))
def try_next(self):
"""TODO"""
"""Like [next][preserves.text.Parser.next], but returns `None` instead of raising
[ShortPacket][preserves.error.ShortPacket]."""
start = self.index
try:
return self.next()
@ -282,7 +397,6 @@ class Parser(TextCodec):
return None
def __iter__(self):
"""TODO"""
return self
def __next__(self):
@ -291,26 +405,83 @@ class Parser(TextCodec):
raise StopIteration
return v
def parse(bs, **kwargs):
"""TODO"""
return Parser(input_buffer=bs, **kwargs).next()
def parse(text, **kwargs):
"""Yields the first complete encoded value from `text`, passing `kwargs` through to the
[Parser][preserves.text.Parser] constructor. Raises exceptions as per
[next][preserves.text.Parser.next].
Args:
text (str): encoded data to decode
"""
return Parser(input_buffer=text, **kwargs).next()
def parse_with_annotations(bs, **kwargs):
"""TODO"""
"""Like [parse][preserves.text.parse], but supplying `include_annotations=True` to the
[Parser][preserves.text.Parser] constructor."""
return Parser(input_buffer=bs, include_annotations=True, **kwargs).next()
class Formatter(TextCodec):
"""TODO"""
"""Printer (and indenting pretty-printer) for producing human-readable syntax from
Preserves `Value`s.
```python
>>> f = Formatter()
>>> f.append({'a': 1, 'b': 2})
>>> f.append(Record(Symbol('label'), ['field1', ['field2item1', 'field2item2']]))
>>> print(f.contents())
{"a": 1 "b": 2} <label "field1" ["field2item1" "field2item2"]>
>>> f = Formatter(indent=4)
>>> f.append({'a': 1, 'b': 2})
>>> f.append(Record(Symbol('label'), ['field1', ['field2item1', 'field2item2']]))
>>> print(f.contents())
{
"a": 1
"b": 2
}
<label "field1" [
"field2item1"
"field2item2"
]>
```
Args:
format_embedded:
function accepting an [Embedded][preserves.values.Embedded].embeddedValue and
returning a `Value` for serialization.
indent (int | None):
`None` disables indented pretty-printing; otherwise, an `int` specifies indentation
per nesting-level.
with_commas (bool):
`True` causes commas to separate sequence and set items and dictionary entries;
`False` omits commas.
trailing_comma (bool):
`True` causes a comma to be printed *after* the final item or entry in a sequence,
set or dictionary; `False` omits this trailing comma
include_annotations (bool):
`True` causes annotations to be included in the output; `False` causes them to be
omitted.
Attributes:
indent_delta (int): indentation per nesting-level
chunks (list[str]): fragments of output
"""
def __init__(self,
format_embedded=lambda x: x,
indent=None,
with_commas=False,
trailing_comma=False,
include_annotations=True):
"""TODO"""
super(Formatter, self).__init__()
self.indent_delta = 0 if indent is None else indent
self.indent_distance = 0
self.nesting = 0
self.with_commas = with_commas
self.trailing_comma = trailing_comma
self.chunks = []
@ -323,10 +494,12 @@ class Formatter(TextCodec):
return self._format_embedded(v)
def contents(self):
"""TODO"""
"""Returns a `str` constructed from the join of the chunks in `self.chunks`."""
return u''.join(self.chunks)
def is_indenting(self):
"""Returns `True` iff this [Formatter][preserves.text.Formatter] is in pretty-printing
indenting mode."""
return self.indent_delta > 0
def write_indent(self):
@ -370,7 +543,17 @@ class Formatter(TextCodec):
self.chunks.append(closer)
def append(self, v):
"""TODO"""
"""Extend `self.chunks` with at least one chunk, together making up the text
representation of `v`."""
if self.chunks and self.nesting == 0:
self.write_indent_space()
try:
self.nesting += 1
self._append(v)
finally:
self.nesting -= 1
def _append(self, v):
v = preserve(v)
if hasattr(v, '__preserve_write_text__'):
v.__preserve_write_text__(self)
@ -394,18 +577,18 @@ class Formatter(TextCodec):
else: self.write_stringlike_char(c)
self.chunks.append('"')
elif isinstance(v, list):
self.write_seq('[', ']', v, self.append)
self.write_seq('[', ']', v, self._append)
elif isinstance(v, tuple):
self.write_seq('[', ']', v, self.append)
self.write_seq('[', ']', v, self._append)
elif isinstance(v, set):
self.write_seq('#{', '}', v, self.append)
self.write_seq('#{', '}', v, self._append)
elif isinstance(v, frozenset):
self.write_seq('#{', '}', v, self.append)
self.write_seq('#{', '}', v, self._append)
elif isinstance(v, dict):
def append_kv(kv):
self.append(kv[0])
self._append(kv[0])
self.chunks.append(': ')
self.append(kv[1])
self._append(kv[1])
self.write_seq('{', '}', v.items(), append_kv)
else:
try:
@ -415,13 +598,14 @@ class Formatter(TextCodec):
if i is None:
self.cannot_format(v)
else:
self.write_seq('[', ']', i, self.append)
self.write_seq('[', ']', i, self._append)
def cannot_format(self, v):
raise TypeError('Cannot preserves-format: ' + repr(v))
def stringify(v, **kwargs):
"""TODO"""
"""Convert a single `Value` `v` to a string. Any supplied `kwargs` are passed on to the
underlying [Formatter][preserves.text.Formatter] constructor."""
e = Formatter(**kwargs)
e.append(v)
return e.contents()

View File

@ -1,4 +1,7 @@
"""TODO"""
"""The [preserves.values][] module implements the core representations of Preserves
[`Value`s](https://preserves.dev/preserves.html#semantics) as Python values.
"""
import re
import sys
@ -8,7 +11,16 @@ import math
from .error import DecodeError
def preserve(v):
"""TODO"""
"""Converts `v` to a representation of a Preserves `Value` by (repeatedly) setting
```python
v = v.__preserve__()
```
while `v` has a `__preserve__` method. Parsed [Schema][preserves.schema]
values are able to render themselves to their serialized representations this way.
"""
while hasattr(v, '__preserve__'):
v = v.__preserve__()
return v
@ -17,7 +29,10 @@ def float_to_int(v):
return struct.unpack('>Q', struct.pack('>d', v))[0]
def cmp_floats(a, b):
"""TODO"""
"""Implements the `totalOrder` predicate defined in section 5.10 of [IEEE Std
754-2008](https://dx.doi.org/10.1109/IEEESTD.2008.4610935).
"""
a = float_to_int(a)
b = float_to_int(b)
if a & 0x8000000000000000: a = a ^ 0x7fffffffffffffff
@ -25,9 +40,33 @@ def cmp_floats(a, b):
return a - b
class Float(object):
"""TODO"""
"""Wrapper for treating a Python double-precision floating-point value as a
single-precision (32-bit) float, from Preserves' perspective. (Python lacks native
single-precision floating point support.)
```python
>>> Float(3.45)
Float(3.45)
>>> import preserves
>>> preserves.stringify(Float(3.45))
'3.45f'
>>> preserves.stringify(3.45)
'3.45'
>>> preserves.parse('3.45f')
Float(3.45)
>>> preserves.parse('3.45')
3.45
>>> preserves.encode(Float(3.45))
b'\\x82@\\\\\\xcc\\xcd'
>>> preserves.encode(3.45)
b'\\x83@\\x0b\\x99\\x99\\x99\\x99\\x99\\x9a'
```
Attributes:
value (float): the double-precision representation of intended single-precision value
"""
def __init__(self, value):
"""TODO"""
self.value = value
def __eq__(self, other):
@ -49,7 +88,30 @@ class Float(object):
def __repr__(self):
return 'Float(' + repr(self.value) + ')'
def _to_bytes(self):
def to_bytes(self):
"""Converts this 32-bit single-precision floating point value to its binary32 format,
taking care to preserve the quiet/signalling bit-pattern of NaN values, unlike its
`struct.pack('>f', ...)` equivalent.
```python
>>> Float.from_bytes(b'\\x7f\\x80\\x00{')
Float(nan)
>>> Float.from_bytes(b'\\x7f\\x80\\x00{').to_bytes()
b'\\x7f\\x80\\x00{'
>>> struct.unpack('>f', b'\\x7f\\x80\\x00{')[0]
nan
>>> Float(struct.unpack('>f', b'\\x7f\\x80\\x00{')[0]).to_bytes()
b'\\x7f\\xc0\\x00{'
>>> struct.pack('>f', struct.unpack('>f', b'\\x7f\\x80\\x00{')[0])
b'\\x7f\\xc0\\x00{'
```
(Note well the difference between `7f80007b` and `7fc0007b`!)
"""
if math.isnan(self.value) or math.isinf(self.value):
dbs = struct.pack('>d', self.value)
vd = struct.unpack('>Q', dbs)[0]
@ -62,17 +124,39 @@ class Float(object):
def __preserve_write_binary__(self, encoder):
encoder.buffer.append(0x82)
encoder.buffer.extend(self._to_bytes())
encoder.buffer.extend(self.to_bytes())
def __preserve_write_text__(self, formatter):
if math.isnan(self.value) or math.isinf(self.value):
formatter.chunks.append('#xf"' + self._to_bytes().hex() + '"')
formatter.chunks.append('#xf"' + self.to_bytes().hex() + '"')
else:
formatter.chunks.append(repr(self.value) + 'f')
@staticmethod
def from_bytes(bs):
"""TODO"""
"""Converts a 4-byte-long byte string to a 32-bit single-precision floating point value
wrapped in a [Float][preserves.values.Float] instance. Takes care to preserve the
quiet/signalling bit-pattern of NaN values, unlike its `struct.unpack('>f', ...)`
equivalent.
```python
>>> Float.from_bytes(b'\\x7f\\x80\\x00{')
Float(nan)
>>> Float.from_bytes(b'\\x7f\\x80\\x00{').to_bytes()
b'\\x7f\\x80\\x00{'
>>> struct.unpack('>f', b'\\x7f\\x80\\x00{')[0]
nan
>>> Float(struct.unpack('>f', b'\\x7f\\x80\\x00{')[0]).to_bytes()
b'\\x7f\\xc0\\x00{'
>>> struct.pack('>f', struct.unpack('>f', b'\\x7f\\x80\\x00{')[0])
b'\\x7f\\xc0\\x00{'
```
(Note well the difference between `7f80007b` and `7fc0007b`!)
"""
vf = struct.unpack('>I', bs)[0]
if (vf & 0x7f800000) == 0x7f800000:
# NaN or inf. Preserve quiet/signalling bit by manually expanding to double-precision.
@ -86,10 +170,34 @@ class Float(object):
# FIXME: This regular expression is conservatively correct, but Anglo-chauvinistic.
RAW_SYMBOL_RE = re.compile(r'^[-a-zA-Z0-9~!$%^&*?_=+/.]+$')
def _eq(a, b):
from .compare import eq
return eq(a, b)
class Symbol(object):
"""TODO"""
"""Representation of Preserves `Symbol`s.
```python
>>> Symbol('xyz')
#xyz
>>> Symbol('xyz').name
'xyz'
>>> import preserves
>>> preserves.stringify(Symbol('xyz'))
'xyz'
>>> preserves.stringify(Symbol('hello world'))
'|hello world|'
>>> preserves.parse('xyz')
#xyz
>>> preserves.parse('|hello world|')
#hello world
```
Attributes:
name (str): the symbol's text label
"""
def __init__(self, name):
"""TODO"""
self.name = name.name if isinstance(name, Symbol) else name
def __eq__(self, other):
@ -134,16 +242,40 @@ class Symbol(object):
formatter.chunks.append('|')
class Record(object):
"""TODO"""
"""Representation of Preserves `Record`s, which are a pair of a *label* `Value` and a sequence of *field* `Value`s.
```python
>>> r = Record(Symbol('label'), ['field1', ['field2item1', 'field2item2']])
>>> r
#label('field1', ['field2item1', 'field2item2'])
>>> r.key
#label
>>> r.fields
('field1', ['field2item1', 'field2item2'])
>>> import preserves
>>> preserves.stringify(r)
'<label "field1" ["field2item1" "field2item2"]>'
>>> r == preserves.parse('<label "field1" ["field2item1" "field2item2"]>')
True
```
Args:
key (Value): the `Record`'s label
fields (iterable[Value]): the fields of the `Record`
Attributes:
key (Value): the `Record`'s label
fields (tuple[Value]): the fields of the `Record`
"""
def __init__(self, key, fields):
"""TODO"""
self.key = key
self.fields = tuple(fields)
self.__hash = None
def __eq__(self, other):
other = _unwrap(other)
return isinstance(other, Record) and (self.key, self.fields) == (other.key, other.fields)
return isinstance(other, Record) and _eq((self.key, self.fields), (other.key, other.fields))
def __ne__(self, other):
return not self.__eq__(other)
@ -176,12 +308,69 @@ class Record(object):
@staticmethod
def makeConstructor(labelSymbolText, fieldNames):
"""TODO"""
"""
Equivalent to `Record.makeBasicConstructor(Symbol(labelSymbolText), fieldNames)`.
Deprecated:
Use [preserves.schema][] definitions instead.
"""
return Record.makeBasicConstructor(Symbol(labelSymbolText), fieldNames)
@staticmethod
def makeBasicConstructor(label, fieldNames):
"""TODO"""
"""Constructs and returns a "constructor" for `Record`s having a certain `label` and
number of fields.
Deprecated:
Use [preserves.schema][] definitions instead.
The "constructor" is a callable function that accepts `len(fields)` arguments and
returns a [Record][preserves.values.Record] with `label` as its label and the arguments
to the constructor as field values.
In addition, the "constructor" has a `constructorInfo` attribute holding a
[RecordConstructorInfo][preserves.values.RecordConstructorInfo] object, an `isClassOf`
attribute holding a unary function that returns `True` iff its argument is a
[Record][preserves.values.Record] with label `label` and arity `len(fieldNames)`, and
an `ensureClassOf` attribute that raises an `Exception` if `isClassOf` returns false on
its argument and returns the argument otherwise.
Finally, for each field name `f` in `fieldNames`, the "constructor" object has an
attribute `_f` that is a unary function that retrieves the `f` field from the passed in
argument.
```python
>>> c = Record.makeBasicConstructor(Symbol('date'), 'year month day')
>>> c(1969, 7, 16)
#date(1969, 7, 16)
>>> c.constructorInfo
#date/3
>>> c.isClassOf(c(1969, 7, 16))
True
>>> c.isClassOf(Record(Symbol('date'), [1969, 7, 16]))
True
>>> c.isClassOf(Record(Symbol('date'), [1969]))
False
>>> c.ensureClassOf(c(1969, 7, 16))
#date(1969, 7, 16)
>>> c.ensureClassOf(Record(Symbol('date'), [1969]))
Traceback (most recent call last):
...
TypeError: Record: expected #date/3, got #date(1969)
>>> c._year(c(1969, 7, 16))
1969
>>> c._month(c(1969, 7, 16))
7
>>> c._day(c(1969, 7, 16))
16
```
Args:
label (Value): Label to use for constructed/matched `Record`s
fieldNames (tuple[str] | list[str] | str): Names of the `Record`'s fields
"""
if type(fieldNames) == str:
fieldNames = fieldNames.split()
arity = len(fieldNames)
@ -209,16 +398,27 @@ class Record(object):
return ctor
class RecordConstructorInfo(object):
"""TODO"""
"""Describes the shape of a `Record` constructor, namely its *label* and its *arity* (field
count).
```python
>>> RecordConstructorInfo(Symbol('label'), 3)
#label/3
```
Attributes:
key (Value): the label of matching `Record`s
arity (int): the number of fields in matching `Record`s
"""
def __init__(self, key, arity):
"""TODO"""
self.key = key
self.arity = arity
def __eq__(self, other):
other = _unwrap(other)
return isinstance(other, RecordConstructorInfo) and \
(self.key, self.arity) == (other.key, other.arity)
_eq((self.key, self.arity), (other.key, other.arity))
def __ne__(self, other):
return not self.__eq__(other)
@ -233,9 +433,30 @@ class RecordConstructorInfo(object):
# Blub blub blub
class ImmutableDict(dict):
"""TODO"""
"""A subclass of Python's built-in `dict` that overrides methods that could mutate the
dictionary, causing them to raise `TypeError('Immutable')` if called.
Implements the `__hash__` method, allowing [ImmutableDict][preserves.values.ImmutableDict]
instances to be used whereever immutable data are permitted; in particular, as keys in
other dictionaries.
```python
>>> d = ImmutableDict([('a', 1), ('b', 2)])
>>> d
{'a': 1, 'b': 2}
>>> d['c'] = 3
Traceback (most recent call last):
...
TypeError: Immutable
>>> del d['b']
Traceback (most recent call last):
...
TypeError: Immutable
```
"""
def __init__(self, *args, **kwargs):
"""TODO"""
if hasattr(self, '__hash'): raise TypeError('Immutable')
super(ImmutableDict, self).__init__(*args, **kwargs)
self.__hash = None
@ -258,7 +479,23 @@ class ImmutableDict(dict):
@staticmethod
def from_kvs(kvs):
"""TODO"""
"""Constructs an [ImmutableDict][preserves.values.ImmutableDict] from a sequence of
alternating keys and values; compare to the
[ImmutableDict][preserves.values.ImmutableDict] constructor, which takes a sequence of
key-value pairs.
```python
>>> ImmutableDict.from_kvs(['a', 1, 'b', 2])
{'a': 1, 'b': 2}
>>> ImmutableDict.from_kvs(['a', 1, 'b', 2])['c'] = 3
Traceback (most recent call last):
...
TypeError: Immutable
```
"""
i = iter(kvs)
result = ImmutableDict()
result_proxy = super(ImmutableDict, result)
@ -275,7 +512,15 @@ class ImmutableDict(dict):
return result
def dict_kvs(d):
"""TODO"""
"""Generator function yielding a sequence of alternating keys and values from `d`. In some
sense the inverse of [ImmutableDict.from_kvs][preserves.values.ImmutableDict.from_kvs].
```python
>>> list(dict_kvs({'a': 1, 'b': 2}))
['a', 1, 'b', 2]
```
"""
for k in d:
yield k
yield d[k]
@ -283,9 +528,49 @@ def dict_kvs(d):
inf = float('inf')
class Annotated(object):
"""TODO"""
"""A Preserves `Value` along with a sequence of `Value`s *annotating* it. Compares equal to
the underlying `Value`, ignoring the annotations. See the [specification document for more
about annotations](https://preserves.dev/preserves-text.html#annotations).
```python
>>> import preserves
>>> a = preserves.parse('''
... ; A comment
... [1 2 3]
... ''', include_annotations=True)
>>> a
@' A comment' (1, 2, 3)
>>> a.item
(1, 2, 3)
>>> a.annotations
[' A comment']
>>> a == (1, 2, 3)
True
>>> a == preserves.parse('@xyz [1 2 3]', include_annotations=True)
True
>>> a[0]
Traceback (most recent call last):
...
TypeError: 'Annotated' object is not subscriptable
>>> a.item[0]
1
>>> type(a.item[0])
<class 'preserves.values.Annotated'>
>>> a.item[0].annotations
[]
>>> print(preserves.stringify(a))
@" A comment" [1 2 3]
>>> print(preserves.stringify(a, include_annotations=False))
[1 2 3]
```
Attributes:
item (Value): the underlying annotated `Value`
annotations (list[Value]): the annotations attached to `self.item`
"""
def __init__(self, item):
"""TODO"""
self.annotations = []
self.item = item
@ -305,15 +590,15 @@ class Annotated(object):
formatter.append(self.item)
def strip(self, depth=inf):
"""TODO"""
"""Calls [strip_annotations][preserves.values.strip_annotations] on `self` and `depth`."""
return strip_annotations(self, depth)
def peel(self):
"""TODO"""
"""Calls [strip_annotations][preserves.values.strip_annotations] on `self` with `depth=1`."""
return strip_annotations(self, 1)
def __eq__(self, other):
return self.item == _unwrap(other)
return _eq(self.item, _unwrap(other))
def __ne__(self, other):
return not self.__eq__(other)
@ -325,11 +610,30 @@ class Annotated(object):
return ' '.join(list('@' + repr(a) for a in self.annotations) + [repr(self.item)])
def is_annotated(v):
"""TODO"""
"""`True` iff `v` is an instance of [Annotated][preserves.values.Annotated]."""
return isinstance(v, Annotated)
def strip_annotations(v, depth=inf):
"""TODO"""
"""Exposes `depth` layers of raw structure of
potentially-[Annotated][preserves.values.Annotated] `Value`s. If `depth==0` or `v` is not
[Annotated][preserves.values.Annotated], just returns `v`. Otherwise, descends recursively
into the structure of `v.item`.
```python
>>> import preserves
>>> a = preserves.parse('@"A comment" [@a 1 @b 2 @c 3]', include_annotations=True)
>>> is_annotated(a)
True
>>> print(preserves.stringify(a))
@"A comment" [@a 1 @b 2 @c 3]
>>> print(preserves.stringify(strip_annotations(a)))
[1 2 3]
>>> print(preserves.stringify(strip_annotations(a, depth=1)))
[@a 1 @b 2 @c 3]
```
"""
if depth == 0: return v
if not is_annotated(v): return v
@ -356,7 +660,18 @@ def strip_annotations(v, depth=inf):
return v
def annotate(v, *anns):
"""TODO"""
"""Wraps `v` in an [Annotated][preserves.values.Annotated] object, if it isn't already
wrapped, and appends each of the `anns` to the [Annotated][preserves.values.Annotated]'s
`annotations` sequence. NOTE: Does not recursively ensure that any parts of the argument
`v` are themselves wrapped in [Annotated][preserves.values.Annotated] objects!
```python
>>> import preserves
>>> print(preserves.stringify(annotate(123, "A comment", "Another comment")))
@"A comment" @"Another comment" 123
```
"""
if not is_annotated(v):
v = Annotated(v)
for a in anns:
@ -370,10 +685,38 @@ def _unwrap(x):
return x
class Embedded:
"""TODO"""
def __init__(self, value):
"""TODO"""
self.embeddedValue = value
"""Representation of a Preserves `Embedded` value. For more on the meaning and use of
embedded values, [see the specification](https://preserves.dev/preserves.html#embeddeds).
```python
>>> import io
>>> e = Embedded(io.StringIO('some text'))
>>> e # doctest: +ELLIPSIS
#!<_io.StringIO object at ...>
>>> e.embeddedValue # doctest: +ELLIPSIS
<_io.StringIO object at ...>
```
```python
>>> import preserves
>>> print(preserves.stringify(Embedded(None)))
Traceback (most recent call last):
...
TypeError: Cannot preserves-format: None
>>> print(preserves.stringify(Embedded(None), format_embedded=lambda x: 'abcdef'))
#!"abcdef"
```
Attributes:
embeddedValue:
any Python value; could be a platform object, could be a representation of a
Preserves `Value`, could be `None`, could be anything!
"""
def __init__(self, embeddedValue):
self.embeddedValue = embeddedValue
def __eq__(self, other):
other = _unwrap(other)

View File

@ -530,8 +530,8 @@
<div class="doc doc-contents first">
<p>Preserves specifies a <a href="https://preserves.dev/preserves.html#total-order">total ordering</a> and
an <a href="https://preserves.dev/preserves.html#equivalence">equivalence</a> between terms. This module
implements the ordering and equivalence relations.</p>
an <a href="https://preserves.dev/preserves.html#equivalence">equivalence</a> between terms. The
<a class="autorefs autorefs-internal" href="#preserves.compare">preserves.compare</a> module implements the ordering and equivalence relations.</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">cmp</span><span class="p">(</span><span class="s2">&quot;bzz&quot;</span><span class="p">,</span> <span class="s2">&quot;c&quot;</span><span class="p">)</span>
<span class="o">-</span><span class="mi">1</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">cmp</span><span class="p">(</span><span class="kc">True</span><span class="p">,</span> <span class="p">[])</span>

View File

@ -487,7 +487,7 @@
<a id="preserves.error"></a>
<div class="doc doc-contents first">
<p>TODO</p>
<p>The <a class="autorefs autorefs-internal" href="#preserves.error">preserves.error</a> module exports various <code>Error</code> subclasses.</p>
@ -516,7 +516,8 @@
Bases: <code>ValueError</code></p>
<p>TODO</p>
<p>Raised whenever <a class="autorefs autorefs-internal" href="../binary/#preserves.binary.Decoder">preserves.binary.Decoder</a> or <a class="autorefs autorefs-internal" href="../text/#preserves.text.Parser">preserves.text.Parser</a> detect invalid
input.</p>
@ -540,7 +541,7 @@
Bases: <code>ValueError</code></p>
<p>TODO</p>
<p>Raised whenever <a class="autorefs autorefs-internal" href="../binary/#preserves.binary.Encoder">preserves.binary.Encoder</a> or <a class="autorefs autorefs-internal" href="../text/#preserves.text.Formatter">preserves.text.Formatter</a> are unable to proceed.</p>
@ -564,7 +565,9 @@
Bases: <code><a class="autorefs autorefs-internal" title="preserves.error.DecodeError" href="#preserves.error.DecodeError">DecodeError</a></code></p>
<p>TODO</p>
<p>Raised whenever <a class="autorefs autorefs-internal" href="../binary/#preserves.binary.Decoder">preserves.binary.Decoder</a> or <a class="autorefs autorefs-internal" href="../text/#preserves.text.Parser">preserves.text.Parser</a> discover that
they want to read beyond the end of the currently-available input buffer in order to
completely read an encoded value.</p>

View File

@ -459,7 +459,7 @@
<a id="preserves.fold"></a>
<div class="doc doc-contents first">
<p>TODO</p>
<p>The <a class="autorefs autorefs-internal" href="#preserves.fold">preserves.fold</a> module exports various utilities for traversing compound <code>Value</code>s.</p>
@ -485,7 +485,12 @@
<div class="doc doc-contents ">
<p>TODO</p>
<p>Returns an <a class="autorefs autorefs-internal" href="../compare/#preserves.compare.eq">equivalent</a> copy of <code>v</code>, except where each contained
<a class="autorefs autorefs-internal" href="../values/#preserves.values.Embedded">Embedded</a> value is replaced by <code>f</code> applied to the Embedded's
<code>embeddedValue</code> attribute.</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">map_embeddeds</span><span class="p">(</span><span class="k">lambda</span> <span class="n">w</span><span class="p">:</span> <span class="n">Embedded</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;w=</span><span class="si">{</span><span class="n">w</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">),</span> <span class="p">[</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="n">Embedded</span><span class="p">(</span><span class="mi">123</span><span class="p">),</span> <span class="p">{</span><span class="s1">&#39;z&#39;</span><span class="p">:</span> <span class="mf">6.0</span><span class="p">}])</span>
<span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="c1">#!&#39;w=123&#39;, {&#39;z&#39;: 6.0})</span>
</code></pre></div>
<details class="quote">
<summary>Source code in <code>preserves/fold.py</code></summary>
@ -504,8 +509,26 @@
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">map_embeddeds</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;TODO&quot;&quot;&quot;</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">map_embeddeds</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Returns an [equivalent][preserves.compare.eq] copy of `v`, except where each contained</span>
<span class="sd"> [Embedded][preserves.values.Embedded] value is replaced by `f` applied to the Embedded&#39;s</span>
<span class="sd"> `embeddedValue` attribute.</span>
<span class="sd"> ```python</span>
<span class="sd"> &gt;&gt;&gt; map_embeddeds(lambda w: Embedded(f&#39;w={w}&#39;), [&#39;a&#39;, Embedded(123), {&#39;z&#39;: 6.0}])</span>
<span class="sd"> (&#39;a&#39;, #!&#39;w=123&#39;, {&#39;z&#39;: 6.0})</span>
<span class="sd"> ```</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span> <span class="nf">walk</span><span class="p">(</span><span class="n">v</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">Embedded</span><span class="p">):</span>
<span class="k">return</span> <span class="n">f</span><span class="p">(</span><span class="n">v</span><span class="o">.</span><span class="n">embeddedValue</span><span class="p">)</span>

View File

@ -459,7 +459,7 @@ of JSON) and <a href="https://preserves.dev/preserves-binary.html">machine-orien
also implements <a href="https://preserves.dev/preserves-schema.html">Preserves Schema</a> and <a href="https://preserves.dev/preserves-path.html">Preserves
Path</a>.</p>
<ul>
<li>Main package API: <a href="/api">preserves</a></li>
<li>Main package API: <a href="api">preserves</a></li>
</ul>
<h2 id="what-is-preserves">What is Preserves?</h2>
<p><em>Preserves</em> is a data model, with associated serialization formats.</p>
@ -492,11 +492,12 @@ language.</p>
| Dictionary
</code></pre></div>
<p>Python's strings, byte strings, integers, booleans, and double-precision floats stand directly
for their Preserves counterparts. Small wrapper classes for <code>Float</code> and <code>Symbol</code> complete the
suite of atomic types.</p>
for their Preserves counterparts. Wrapper objects for <a class="autorefs autorefs-internal" href="values/#preserves.values.Float">Float</a> and
<a class="autorefs autorefs-internal" href="values/#preserves.values.Symbol">Symbol</a> complete the suite of atomic types.</p>
<p>Python's lists and tuples correspond to Preserves <code>Sequence</code>s, and dicts and sets to
<code>Dictionary</code> and <code>Set</code> values, respectively. Preserves <code>Record</code>s are represented by a <code>Record</code>
class. Finally, embedded values are represented by a small <code>Embedded</code> wrapper class.</p>
<code>Dictionary</code> and <code>Set</code> values, respectively. Preserves <code>Record</code>s are represented by
<a class="autorefs autorefs-internal" href="values/#preserves.values.Record">Record</a> objects. Finally, embedded values are represented by
<a class="autorefs autorefs-internal" href="values/#preserves.values.Embedded">Embedded</a> objects.</p>

View File

@ -473,7 +473,7 @@
<a id="preserves.merge"></a>
<div class="doc doc-contents first">
<p>TODO</p>
<p>The <a class="autorefs autorefs-internal" href="#preserves.merge">preserves.merge</a> module exports various utilities for merging <code>Value</code>s.</p>
@ -499,7 +499,8 @@
<div class="doc doc-contents ">
<p>TODO</p>
<p>Repeatedly merges <code>v0</code> with each element in <code>vs</code> using <a class="autorefs autorefs-internal" href="#preserves.merge.merge2">merge2</a>,
returning the final result. The <code>merge_embedded</code> parameter is passed on to merge2.</p>
<details class="quote">
<summary>Source code in <code>preserves/merge.py</code></summary>
@ -508,8 +509,10 @@
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">merge</span><span class="p">(</span><span class="n">v0</span><span class="p">,</span> <span class="o">*</span><span class="n">vs</span><span class="p">,</span> <span class="n">merge_embedded</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;TODO&quot;&quot;&quot;</span>
<span class="normal">13</span>
<span class="normal">14</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">merge</span><span class="p">(</span><span class="n">v0</span><span class="p">,</span> <span class="o">*</span><span class="n">vs</span><span class="p">,</span> <span class="n">merge_embedded</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Repeatedly merges `v0` with each element in `vs` using [merge2][preserves.merge.merge2],</span>
<span class="sd"> returning the final result. The `merge_embedded` parameter is passed on to merge2.&quot;&quot;&quot;</span>
<span class="n">v</span> <span class="o">=</span> <span class="n">v0</span>
<span class="k">for</span> <span class="n">vN</span> <span class="ow">in</span> <span class="n">vs</span><span class="p">:</span>
<span class="n">v</span> <span class="o">=</span> <span class="n">merge2</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">vN</span><span class="p">,</span> <span class="n">merge_embedded</span><span class="o">=</span><span class="n">merge_embedded</span><span class="p">)</span>
@ -532,12 +535,40 @@
<div class="doc doc-contents ">
<p>TODO</p>
<p>Merges <code>a</code> and <code>b</code>, returning the result. Raises <code>ValueError</code> if, during the merge, a
pair of incompatible values is discovered.</p>
<p>If <code>a</code> and <code>b</code> are <a class="autorefs autorefs-internal" href="../values/#preserves.values.Embedded">Embedded</a> objects, their <code>embeddedValue</code>s
are merged using <code>merge_embedded</code>, and the result is again wrapped in an
<a class="autorefs autorefs-internal" href="../values/#preserves.values.Embedded">Embedded</a> object.</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">merge2</span><span class="p">(</span><span class="mi">123</span><span class="p">,</span> <span class="mi">234</span><span class="p">)</span>
<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
<span class="o">...</span>
<span class="ne">ValueError</span><span class="p">:</span> <span class="n">Cannot</span> <span class="n">merge</span> <span class="n">items</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">merge2</span><span class="p">(</span><span class="mi">123</span><span class="p">,</span> <span class="mi">123</span><span class="p">)</span>
<span class="mi">123</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">merge2</span><span class="p">(</span><span class="s1">&#39;hi&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
<span class="o">...</span>
<span class="ne">ValueError</span><span class="p">:</span> <span class="n">Cannot</span> <span class="n">merge</span> <span class="n">items</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">merge2</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">])</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">merge2</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span>
<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
<span class="o">...</span>
<span class="ne">ValueError</span><span class="p">:</span> <span class="n">Cannot</span> <span class="n">merge</span> <span class="n">items</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">merge2</span><span class="p">({</span><span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;b&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;c&#39;</span><span class="p">:</span> <span class="mi">3</span><span class="p">})</span>
<span class="p">{</span><span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;b&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s1">&#39;c&#39;</span><span class="p">:</span> <span class="mi">3</span><span class="p">}</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">merge2</span><span class="p">({</span><span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;b&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span> <span class="s1">&#39;c&#39;</span><span class="p">:</span> <span class="mi">3</span><span class="p">})</span>
<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
<span class="o">...</span>
<span class="ne">ValueError</span><span class="p">:</span> <span class="n">Cannot</span> <span class="n">merge</span> <span class="n">items</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">merge2</span><span class="p">(</span><span class="n">Record</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;x&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]),</span> <span class="n">Record</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;y&#39;</span><span class="p">:</span> <span class="mi">3</span><span class="p">}]))</span>
<span class="n">a</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;x&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s1">&#39;y&#39;</span><span class="p">:</span> <span class="mi">3</span><span class="p">})</span>
</code></pre></div>
<details class="quote">
<summary>Source code in <code>preserves/merge.py</code></summary>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">22</span>
<span class="normal">23</span>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
@ -560,8 +591,79 @@
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">merge2</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">merge_embedded</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;TODO&quot;&quot;&quot;</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span>
<span class="normal">74</span>
<span class="normal">75</span>
<span class="normal">76</span>
<span class="normal">77</span>
<span class="normal">78</span>
<span class="normal">79</span>
<span class="normal">80</span>
<span class="normal">81</span>
<span class="normal">82</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">merge2</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">merge_embedded</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Merges `a` and `b`, returning the result. Raises `ValueError` if, during the merge, a</span>
<span class="sd"> pair of incompatible values is discovered.</span>
<span class="sd"> If `a` and `b` are [Embedded][preserves.values.Embedded] objects, their `embeddedValue`s</span>
<span class="sd"> are merged using `merge_embedded`, and the result is again wrapped in an</span>
<span class="sd"> [Embedded][preserves.values.Embedded] object.</span>
<span class="sd"> ```python</span>
<span class="sd"> &gt;&gt;&gt; merge2(123, 234)</span>
<span class="sd"> Traceback (most recent call last):</span>
<span class="sd"> ...</span>
<span class="sd"> ValueError: Cannot merge items</span>
<span class="sd"> &gt;&gt;&gt; merge2(123, 123)</span>
<span class="sd"> 123</span>
<span class="sd"> &gt;&gt;&gt; merge2(&#39;hi&#39;, 0)</span>
<span class="sd"> Traceback (most recent call last):</span>
<span class="sd"> ...</span>
<span class="sd"> ValueError: Cannot merge items</span>
<span class="sd"> &gt;&gt;&gt; merge2([1, 2], [1, 2])</span>
<span class="sd"> [1, 2]</span>
<span class="sd"> &gt;&gt;&gt; merge2([1, 2], [1, 3])</span>
<span class="sd"> Traceback (most recent call last):</span>
<span class="sd"> ...</span>
<span class="sd"> ValueError: Cannot merge items</span>
<span class="sd"> &gt;&gt;&gt; merge2({&#39;a&#39;: 1, &#39;b&#39;: 2}, {&#39;a&#39;: 1, &#39;c&#39;: 3})</span>
<span class="sd"> {&#39;a&#39;: 1, &#39;b&#39;: 2, &#39;c&#39;: 3}</span>
<span class="sd"> &gt;&gt;&gt; merge2({&#39;a&#39;: 1, &#39;b&#39;: 2}, {&#39;a&#39;: 10, &#39;c&#39;: 3})</span>
<span class="sd"> Traceback (most recent call last):</span>
<span class="sd"> ...</span>
<span class="sd"> ValueError: Cannot merge items</span>
<span class="sd"> &gt;&gt;&gt; merge2(Record(&#39;a&#39;, [1, {&#39;x&#39;: 2}]), Record(&#39;a&#39;, [1, {&#39;y&#39;: 3}]))</span>
<span class="sd"> a(1, {&#39;x&#39;: 2, &#39;y&#39;: 3})</span>
<span class="sd"> ```</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span><span class="p">:</span>
<span class="k">return</span> <span class="n">a</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">))</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">)):</span>

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -385,6 +385,13 @@
contents()
</a>
</li>
<li class="md-nav__item">
<a href="#preserves.text.Formatter.is_indenting" class="md-nav__link">
is_indenting()
</a>
</li>
</ul>
@ -400,13 +407,6 @@
<nav class="md-nav" aria-label="Parser">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#preserves.text.Parser.__iter__" class="md-nav__link">
__iter__()
</a>
</li>
<li class="md-nav__item">
<a href="#preserves.text.Parser.extend" class="md-nav__link">
extend()
@ -431,13 +431,6 @@
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#preserves.text.TextCodec" class="md-nav__link">
TextCodec
</a>
</li>
<li class="md-nav__item">
@ -537,6 +530,13 @@
contents()
</a>
</li>
<li class="md-nav__item">
<a href="#preserves.text.Formatter.is_indenting" class="md-nav__link">
is_indenting()
</a>
</li>
</ul>
@ -552,13 +552,6 @@
<nav class="md-nav" aria-label="Parser">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#preserves.text.Parser.__iter__" class="md-nav__link">
__iter__()
</a>
</li>
<li class="md-nav__item">
<a href="#preserves.text.Parser.extend" class="md-nav__link">
extend()
@ -583,13 +576,6 @@
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#preserves.text.TextCodec" class="md-nav__link">
TextCodec
</a>
</li>
<li class="md-nav__item">
@ -637,7 +623,16 @@
<a id="preserves.text"></a>
<div class="doc doc-contents first">
<p>TODO</p>
<p>The <a class="autorefs autorefs-internal" href="#preserves.text">preserves.text</a> module implements the <a href="https://preserves.dev/preserves-text.html">Preserves human-readable text
syntax</a>.</p>
<p>The main entry points are functions <a class="autorefs autorefs-internal" href="#preserves.text.stringify">stringify</a>,
<a class="autorefs autorefs-internal" href="#preserves.text.parse">parse</a>, and
<a class="autorefs autorefs-internal" href="#preserves.text.parse_with_annotations">parse_with_annotations</a>.</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">stringify</span><span class="p">(</span><span class="n">Record</span><span class="p">(</span><span class="n">Symbol</span><span class="p">(</span><span class="s1">&#39;hi&#39;</span><span class="p">),</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]]))</span>
<span class="s1">&#39;&lt;hi 1 [2 3]&gt;&#39;</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">parse</span><span class="p">(</span><span class="s1">&#39;&lt;hi 1 [2 3]&gt;&#39;</span><span class="p">)</span>
<span class="c1">#hi(1, (2, 3))</span>
</code></pre></div>
@ -662,40 +657,153 @@
<div class="doc doc-contents ">
<p class="doc doc-class-bases">
Bases: <code><a class="autorefs autorefs-internal" title="preserves.text.TextCodec" href="#preserves.text.TextCodec">TextCodec</a></code></p>
Bases: <code><span title="preserves.text.TextCodec">TextCodec</span></code></p>
<p>TODO</p>
<p>Printer (and indenting pretty-printer) for producing human-readable syntax from
Preserves <code>Value</code>s.</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">f</span> <span class="o">=</span> <span class="n">Formatter</span><span class="p">()</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">f</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;b&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">})</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">f</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">Record</span><span class="p">(</span><span class="n">Symbol</span><span class="p">(</span><span class="s1">&#39;label&#39;</span><span class="p">),</span> <span class="p">[</span><span class="s1">&#39;field1&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;field2item1&#39;</span><span class="p">,</span> <span class="s1">&#39;field2item2&#39;</span><span class="p">]]))</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">print</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">contents</span><span class="p">())</span>
<span class="p">{</span><span class="s2">&quot;a&quot;</span><span class="p">:</span> <span class="mi">1</span> <span class="s2">&quot;b&quot;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}</span> <span class="o">&lt;</span><span class="n">label</span> <span class="s2">&quot;field1&quot;</span> <span class="p">[</span><span class="s2">&quot;field2item1&quot;</span> <span class="s2">&quot;field2item2&quot;</span><span class="p">]</span><span class="o">&gt;</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">f</span> <span class="o">=</span> <span class="n">Formatter</span><span class="p">(</span><span class="n">indent</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">f</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;b&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">})</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">f</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">Record</span><span class="p">(</span><span class="n">Symbol</span><span class="p">(</span><span class="s1">&#39;label&#39;</span><span class="p">),</span> <span class="p">[</span><span class="s1">&#39;field1&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;field2item1&#39;</span><span class="p">,</span> <span class="s1">&#39;field2item2&#39;</span><span class="p">]]))</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">print</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">contents</span><span class="p">())</span>
<span class="p">{</span>
<span class="s2">&quot;a&quot;</span><span class="p">:</span> <span class="mi">1</span>
<span class="s2">&quot;b&quot;</span><span class="p">:</span> <span class="mi">2</span>
<span class="p">}</span>
<span class="o">&lt;</span><span class="n">label</span> <span class="s2">&quot;field1&quot;</span> <span class="p">[</span>
<span class="s2">&quot;field2item1&quot;</span>
<span class="s2">&quot;field2item2&quot;</span>
<span class="p">]</span><span class="o">&gt;</span>
</code></pre></div>
<p><strong>Parameters:</strong></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>format_embedded</code></td>
<td>
</td>
<td><p>function accepting an <a class="autorefs autorefs-internal" href="../values/#preserves.values.Embedded">Embedded</a>.embeddedValue and
returning a <code>Value</code> for serialization.</p></td>
<td>
<code>lambda x: x</code>
</td>
</tr>
<tr>
<td><code>indent</code></td>
<td>
<code>int | None</code>
</td>
<td><p><code>None</code> disables indented pretty-printing; otherwise, an <code>int</code> specifies indentation
per nesting-level.</p></td>
<td>
<code>None</code>
</td>
</tr>
<tr>
<td><code>with_commas</code></td>
<td>
<code>bool</code>
</td>
<td><p><code>True</code> causes commas to separate sequence and set items and dictionary entries;
<code>False</code> omits commas.</p></td>
<td>
<code>False</code>
</td>
</tr>
<tr>
<td><code>trailing_comma</code></td>
<td>
<code>bool</code>
</td>
<td><p><code>True</code> causes a comma to be printed <em>after</em> the final item or entry in a sequence,
set or dictionary; <code>False</code> omits this trailing comma</p></td>
<td>
<code>False</code>
</td>
</tr>
<tr>
<td><code>include_annotations</code></td>
<td>
<code>bool</code>
</td>
<td><p><code>True</code> causes annotations to be included in the output; <code>False</code> causes them to be
omitted.</p></td>
<td>
<code>True</code>
</td>
</tr>
</tbody>
</table>
<p><strong>Attributes:</strong></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>indent_delta</code></td>
<td>
<code>int</code>
</td>
<td><p>indentation per nesting-level</p></td>
</tr>
<tr>
<td><code>chunks</code></td>
<td>
<code>list[str]</code>
</td>
<td><p>fragments of output</p></td>
</tr>
</tbody>
</table>
<p>TODO</p>
<details class="quote">
<summary>Source code in <code>preserves/text.py</code></summary>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">304</span>
<span class="normal">305</span>
<span class="normal">306</span>
<span class="normal">307</span>
<span class="normal">308</span>
<span class="normal">309</span>
<span class="normal">310</span>
<span class="normal">311</span>
<span class="normal">312</span>
<span class="normal">313</span>
<span class="normal">314</span>
<span class="normal">315</span>
<span class="normal">316</span>
<span class="normal">317</span>
<span class="normal">318</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">475</span>
<span class="normal">476</span>
<span class="normal">477</span>
<span class="normal">478</span>
<span class="normal">479</span>
<span class="normal">480</span>
<span class="normal">481</span>
<span class="normal">482</span>
<span class="normal">483</span>
<span class="normal">484</span>
<span class="normal">485</span>
<span class="normal">486</span>
<span class="normal">487</span>
<span class="normal">488</span>
<span class="normal">489</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
<span class="n">format_embedded</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">,</span>
<span class="n">indent</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">with_commas</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">trailing_comma</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">include_annotations</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;TODO&quot;&quot;&quot;</span>
<span class="nb">super</span><span class="p">(</span><span class="n">Formatter</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">indent_delta</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">if</span> <span class="n">indent</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">indent</span>
<span class="bp">self</span><span class="o">.</span><span class="n">indent_distance</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">nesting</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">with_commas</span> <span class="o">=</span> <span class="n">with_commas</span>
<span class="bp">self</span><span class="o">.</span><span class="n">trailing_comma</span> <span class="o">=</span> <span class="n">trailing_comma</span>
<span class="bp">self</span><span class="o">.</span><span class="n">chunks</span> <span class="o">=</span> <span class="p">[]</span>
@ -728,103 +836,30 @@
<div class="doc doc-contents ">
<p>TODO</p>
<p>Extend <code>self.chunks</code> with at least one chunk, together making up the text
representation of <code>v</code>.</p>
<details class="quote">
<summary>Source code in <code>preserves/text.py</code></summary>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">372</span>
<span class="normal">373</span>
<span class="normal">374</span>
<span class="normal">375</span>
<span class="normal">376</span>
<span class="normal">377</span>
<span class="normal">378</span>
<span class="normal">379</span>
<span class="normal">380</span>
<span class="normal">381</span>
<span class="normal">382</span>
<span class="normal">383</span>
<span class="normal">384</span>
<span class="normal">385</span>
<span class="normal">386</span>
<span class="normal">387</span>
<span class="normal">388</span>
<span class="normal">389</span>
<span class="normal">390</span>
<span class="normal">391</span>
<span class="normal">392</span>
<span class="normal">393</span>
<span class="normal">394</span>
<span class="normal">395</span>
<span class="normal">396</span>
<span class="normal">397</span>
<span class="normal">398</span>
<span class="normal">399</span>
<span class="normal">400</span>
<span class="normal">401</span>
<span class="normal">402</span>
<span class="normal">403</span>
<span class="normal">404</span>
<span class="normal">405</span>
<span class="normal">406</span>
<span class="normal">407</span>
<span class="normal">408</span>
<span class="normal">409</span>
<span class="normal">410</span>
<span class="normal">411</span>
<span class="normal">412</span>
<span class="normal">413</span>
<span class="normal">414</span>
<span class="normal">415</span>
<span class="normal">416</span>
<span class="normal">417</span>
<span class="normal">418</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">append</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;TODO&quot;&quot;&quot;</span>
<span class="n">v</span> <span class="o">=</span> <span class="n">preserve</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="s1">&#39;__preserve_write_text__&#39;</span><span class="p">):</span>
<span class="n">v</span><span class="o">.</span><span class="n">__preserve_write_text__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">v</span> <span class="ow">is</span> <span class="kc">False</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;#f&#39;</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">v</span> <span class="ow">is</span> <span class="kc">True</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;#t&#39;</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">float</span><span class="p">):</span>
<span class="k">if</span> <span class="n">math</span><span class="o">.</span><span class="n">isnan</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="ow">or</span> <span class="n">math</span><span class="o">.</span><span class="n">isinf</span><span class="p">(</span><span class="n">v</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;#xd&quot;&#39;</span> <span class="o">+</span> <span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s1">&#39;&gt;d&#39;</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span><span class="o">.</span><span class="n">hex</span><span class="p">()</span> <span class="o">+</span> <span class="s1">&#39;&quot;&#39;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">repr</span><span class="p">(</span><span class="n">v</span><span class="p">))</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">numbers</span><span class="o">.</span><span class="n">Number</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%d</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">v</span><span class="p">,))</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;#[</span><span class="si">%s</span><span class="s1">]&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">v</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;ascii&#39;</span><span class="p">),))</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">basestring_</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;&quot;&#39;</span><span class="p">)</span>
<span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">v</span><span class="p">:</span>
<span class="k">if</span> <span class="n">c</span> <span class="o">==</span> <span class="s1">&#39;&quot;&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;</span><span class="se">\\</span><span class="s1">&quot;&#39;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">write_stringlike_char</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;&quot;&#39;</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">write_seq</span><span class="p">(</span><span class="s1">&#39;[&#39;</span><span class="p">,</span> <span class="s1">&#39;]&#39;</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">append</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">write_seq</span><span class="p">(</span><span class="s1">&#39;[&#39;</span><span class="p">,</span> <span class="s1">&#39;]&#39;</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">append</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">set</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">write_seq</span><span class="p">(</span><span class="s1">&#39;#{&#39;</span><span class="p">,</span> <span class="s1">&#39;}&#39;</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">append</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">frozenset</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">write_seq</span><span class="p">(</span><span class="s1">&#39;#{&#39;</span><span class="p">,</span> <span class="s1">&#39;}&#39;</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">append</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">append_kv</span><span class="p">(</span><span class="n">kv</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">kv</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="bp">self</span><span class="o">.</span><span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;: &#39;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">kv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="bp">self</span><span class="o">.</span><span class="n">write_seq</span><span class="p">(</span><span class="s1">&#39;{&#39;</span><span class="p">,</span> <span class="s1">&#39;}&#39;</span><span class="p">,</span> <span class="n">v</span><span class="o">.</span><span class="n">items</span><span class="p">(),</span> <span class="n">append_kv</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">i</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">TypeError</span><span class="p">:</span>
<span class="n">i</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">i</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cannot_format</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">write_seq</span><span class="p">(</span><span class="s1">&#39;[&#39;</span><span class="p">,</span> <span class="s1">&#39;]&#39;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">append</span><span class="p">)</span>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">545</span>
<span class="normal">546</span>
<span class="normal">547</span>
<span class="normal">548</span>
<span class="normal">549</span>
<span class="normal">550</span>
<span class="normal">551</span>
<span class="normal">552</span>
<span class="normal">553</span>
<span class="normal">554</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">append</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Extend `self.chunks` with at least one chunk, together making up the text</span>
<span class="sd"> representation of `v`.&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">chunks</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">nesting</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">write_indent_space</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">nesting</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_append</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="k">finally</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">nesting</span> <span class="o">-=</span> <span class="mi">1</span>
</code></pre></div></td></tr></table></div>
</details>
</div>
@ -843,14 +878,14 @@
<div class="doc doc-contents ">
<p>TODO</p>
<p>Returns a <code>str</code> constructed from the join of the chunks in <code>self.chunks</code>.</p>
<details class="quote">
<summary>Source code in <code>preserves/text.py</code></summary>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">325</span>
<span class="normal">326</span>
<span class="normal">327</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">contents</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;TODO&quot;&quot;&quot;</span>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">496</span>
<span class="normal">497</span>
<span class="normal">498</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">contents</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Returns a `str` constructed from the join of the chunks in `self.chunks`.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="sa">u</span><span class="s1">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">chunks</span><span class="p">)</span>
</code></pre></div></td></tr></table></div>
</details>
@ -858,6 +893,36 @@
</div>
<div class="doc doc-object doc-function">
<h3 id="preserves.text.Formatter.is_indenting" class="doc doc-heading">
<code class="highlight language-python"><span class="n">is_indenting</span><span class="p">()</span></code>
</h3>
<div class="doc doc-contents ">
<p>Returns <code>True</code> iff this <a class="autorefs autorefs-internal" href="#preserves.text.Formatter">Formatter</a> is in pretty-printing
indenting mode.</p>
<details class="quote">
<summary>Source code in <code>preserves/text.py</code></summary>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">500</span>
<span class="normal">501</span>
<span class="normal">502</span>
<span class="normal">503</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">is_indenting</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Returns `True` iff this [Formatter][preserves.text.Formatter] is in pretty-printing</span>
<span class="sd"> indenting mode.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">indent_delta</span> <span class="o">&gt;</span> <span class="mi">0</span>
</code></pre></div></td></tr></table></div>
</details>
</div>
</div>
</div>
@ -878,24 +943,147 @@
<div class="doc doc-contents ">
<p class="doc doc-class-bases">
Bases: <code><a class="autorefs autorefs-internal" title="preserves.text.TextCodec" href="#preserves.text.TextCodec">TextCodec</a></code></p>
Bases: <code><span title="preserves.text.TextCodec">TextCodec</span></code></p>
<p>TODO</p>
<p>Parser for the human-readable Preserves text syntax.</p>
<p><strong>Parameters:</strong></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>input_buffer</code></td>
<td>
<code>str</code>
</td>
<td><p>initial contents of the input buffer; may subsequently be extended by calling
<a class="autorefs autorefs-internal" href="#preserves.text.Parser.extend">extend</a>.</p></td>
<td>
<code>&#39;&#39;</code>
</td>
</tr>
<tr>
<td><code>include_annotations</code></td>
<td>
<code>bool</code>
</td>
<td><p>if <code>True</code>, wrap each value and subvalue in an
<a class="autorefs autorefs-internal" href="../values/#preserves.values.Annotated">Annotated</a> object.</p></td>
<td>
<code>False</code>
</td>
</tr>
<tr>
<td><code>parse_embedded</code></td>
<td>
</td>
<td><p>function accepting a <code>Value</code> and returning a possibly-decoded form of that value
suitable for placing into an <a class="autorefs autorefs-internal" href="../values/#preserves.values.Embedded">Embedded</a> object.</p></td>
<td>
<code>lambda x: x</code>
</td>
</tr>
</tbody>
</table>
<p>Normal usage is to supply input text, and keep calling <a class="autorefs autorefs-internal" href="#preserves.text.Parser.next">next</a>
until a <a class="autorefs autorefs-internal" href="../error/#preserves.error.ShortPacket">ShortPacket</a> exception is raised:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">d</span> <span class="o">=</span> <span class="n">Parser</span><span class="p">(</span><span class="s1">&#39;123 &quot;hello&quot; @x []&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
<span class="mi">123</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
<span class="s1">&#39;hello&#39;</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
<span class="p">()</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
<span class="o">...</span>
<span class="n">preserves</span><span class="o">.</span><span class="n">error</span><span class="o">.</span><span class="n">ShortPacket</span><span class="p">:</span> <span class="n">Short</span> <span class="nb">input</span> <span class="n">buffer</span>
</code></pre></div>
<p>Alternatively, keep calling <a class="autorefs autorefs-internal" href="#preserves.text.Parser.try_next">try_next</a> until it yields
<code>None</code>, which is not in the domain of Preserves <code>Value</code>s:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">d</span> <span class="o">=</span> <span class="n">Parser</span><span class="p">(</span><span class="s1">&#39;123 &quot;hello&quot; @x []&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">try_next</span><span class="p">()</span>
<span class="mi">123</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">try_next</span><span class="p">()</span>
<span class="s1">&#39;hello&#39;</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">try_next</span><span class="p">()</span>
<span class="p">()</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">try_next</span><span class="p">()</span>
</code></pre></div>
<p>For convenience, <a class="autorefs autorefs-internal" href="#preserves.text.Parser">Parser</a> implements the iterator interface,
backing it with <a class="autorefs autorefs-internal" href="#preserves.text.Parser.try_next">try_next</a>, so you can simply iterate
over all complete values in an input:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">d</span> <span class="o">=</span> <span class="n">Parser</span><span class="p">(</span><span class="s1">&#39;123 &quot;hello&quot; @x []&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">list</span><span class="p">(</span><span class="n">d</span><span class="p">)</span>
<span class="p">[</span><span class="mi">123</span><span class="p">,</span> <span class="s1">&#39;hello&#39;</span><span class="p">,</span> <span class="p">()]</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">Parser</span><span class="p">(</span><span class="s1">&#39;123 &quot;hello&quot; @x []&#39;</span><span class="p">):</span>
<span class="o">...</span> <span class="nb">print</span><span class="p">(</span><span class="nb">repr</span><span class="p">(</span><span class="n">v</span><span class="p">))</span>
<span class="mi">123</span>
<span class="s1">&#39;hello&#39;</span>
<span class="p">()</span>
</code></pre></div>
<p>Supply <code>include_annotations=True</code> to read annotations alongside the annotated values:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">d</span> <span class="o">=</span> <span class="n">Parser</span><span class="p">(</span><span class="s1">&#39;123 &quot;hello&quot; @x []&#39;</span><span class="p">,</span> <span class="n">include_annotations</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">list</span><span class="p">(</span><span class="n">d</span><span class="p">)</span>
<span class="p">[</span><span class="mi">123</span><span class="p">,</span> <span class="s1">&#39;hello&#39;</span><span class="p">,</span> <span class="o">@</span><span class="c1">#x ()]</span>
</code></pre></div>
<p>If you are incrementally reading from, say, a socket, you can use
<a class="autorefs autorefs-internal" href="#preserves.text.Parser.extend">extend</a> to add new input as if comes available:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">d</span> <span class="o">=</span> <span class="n">Parser</span><span class="p">(</span><span class="s1">&#39;123 &quot;he&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">try_next</span><span class="p">()</span>
<span class="mi">123</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">try_next</span><span class="p">()</span> <span class="c1"># returns None because the input is incomplete</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="s1">&#39;llo&quot;&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">try_next</span><span class="p">()</span>
<span class="s1">&#39;hello&#39;</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">try_next</span><span class="p">()</span>
</code></pre></div>
<p><strong>Attributes:</strong></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>input_buffer</code></td>
<td>
<code>str</code>
</td>
<td><p>buffered input waiting to be processed</p></td>
</tr>
<tr>
<td><code>index</code></td>
<td>
<code>int</code>
</td>
<td><p>read position within <code>input_buffer</code></p></td>
</tr>
</tbody>
</table>
<p>TODO</p>
<details class="quote">
<summary>Source code in <code>preserves/text.py</code></summary>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">input_buffer</span><span class="o">=</span><span class="sa">u</span><span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="n">include_annotations</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">parse_embedded</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;TODO&quot;&quot;&quot;</span>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">132</span>
<span class="normal">133</span>
<span class="normal">134</span>
<span class="normal">135</span>
<span class="normal">136</span>
<span class="normal">137</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">input_buffer</span><span class="o">=</span><span class="sa">u</span><span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="n">include_annotations</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">parse_embedded</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">):</span>
<span class="nb">super</span><span class="p">(</span><span class="n">Parser</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">input_buffer</span> <span class="o">=</span> <span class="n">input_buffer</span>
<span class="bp">self</span><span class="o">.</span><span class="n">index</span> <span class="o">=</span> <span class="mi">0</span>
@ -916,33 +1104,6 @@
<div class="doc doc-object doc-function">
<h3 id="preserves.text.Parser.__iter__" class="doc doc-heading">
<code class="highlight language-python"><span class="fm">__iter__</span><span class="p">()</span></code>
</h3>
<div class="doc doc-contents ">
<p>TODO</p>
<details class="quote">
<summary>Source code in <code>preserves/text.py</code></summary>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">284</span>
<span class="normal">285</span>
<span class="normal">286</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="fm">__iter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;TODO&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span>
</code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
@ -955,15 +1116,18 @@
<div class="doc doc-contents ">
<p>TODO</p>
<p>Appends <code>text</code> to the remaining contents of <code>self.input_buffer</code>, trimming already-processed
text from the front of <code>self.input_buffer</code> and resetting <code>self.index</code> to zero.</p>
<details class="quote">
<summary>Source code in <code>preserves/text.py</code></summary>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">extend</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">text</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;TODO&quot;&quot;&quot;</span>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">139</span>
<span class="normal">140</span>
<span class="normal">141</span>
<span class="normal">142</span>
<span class="normal">143</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">extend</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">text</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Appends `text` to the remaining contents of `self.input_buffer`, trimming already-processed</span>
<span class="sd"> text from the front of `self.input_buffer` and resetting `self.index` to zero.&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">input_buffer</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">input_buffer</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">index</span><span class="p">:]</span> <span class="o">+</span> <span class="n">text</span>
<span class="bp">self</span><span class="o">.</span><span class="n">index</span> <span class="o">=</span> <span class="mi">0</span>
</code></pre></div></td></tr></table></div>
@ -984,75 +1148,85 @@
<div class="doc doc-contents ">
<p>TODO</p>
<p>Reads the next complete <code>Value</code> from the internal buffer, raising
<a class="autorefs autorefs-internal" href="../error/#preserves.error.ShortPacket">ShortPacket</a> if too few bytes are available, or
<a class="autorefs autorefs-internal" href="../error/#preserves.error.DecodeError">DecodeError</a> if the input is invalid somehow.</p>
<details class="quote">
<summary>Source code in <code>preserves/text.py</code></summary>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">210</span>
<span class="normal">211</span>
<span class="normal">212</span>
<span class="normal">213</span>
<span class="normal">214</span>
<span class="normal">215</span>
<span class="normal">216</span>
<span class="normal">217</span>
<span class="normal">218</span>
<span class="normal">219</span>
<span class="normal">220</span>
<span class="normal">221</span>
<span class="normal">222</span>
<span class="normal">223</span>
<span class="normal">224</span>
<span class="normal">225</span>
<span class="normal">226</span>
<span class="normal">227</span>
<span class="normal">228</span>
<span class="normal">229</span>
<span class="normal">230</span>
<span class="normal">231</span>
<span class="normal">232</span>
<span class="normal">233</span>
<span class="normal">234</span>
<span class="normal">235</span>
<span class="normal">236</span>
<span class="normal">237</span>
<span class="normal">238</span>
<span class="normal">239</span>
<span class="normal">240</span>
<span class="normal">241</span>
<span class="normal">242</span>
<span class="normal">243</span>
<span class="normal">244</span>
<span class="normal">245</span>
<span class="normal">246</span>
<span class="normal">247</span>
<span class="normal">248</span>
<span class="normal">249</span>
<span class="normal">250</span>
<span class="normal">251</span>
<span class="normal">252</span>
<span class="normal">253</span>
<span class="normal">254</span>
<span class="normal">255</span>
<span class="normal">256</span>
<span class="normal">257</span>
<span class="normal">258</span>
<span class="normal">259</span>
<span class="normal">260</span>
<span class="normal">261</span>
<span class="normal">262</span>
<span class="normal">263</span>
<span class="normal">264</span>
<span class="normal">265</span>
<span class="normal">266</span>
<span class="normal">267</span>
<span class="normal">268</span>
<span class="normal">269</span>
<span class="normal">270</span>
<span class="normal">271</span>
<span class="normal">272</span>
<span class="normal">273</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">next</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;TODO&quot;&quot;&quot;</span>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">320</span>
<span class="normal">321</span>
<span class="normal">322</span>
<span class="normal">323</span>
<span class="normal">324</span>
<span class="normal">325</span>
<span class="normal">326</span>
<span class="normal">327</span>
<span class="normal">328</span>
<span class="normal">329</span>
<span class="normal">330</span>
<span class="normal">331</span>
<span class="normal">332</span>
<span class="normal">333</span>
<span class="normal">334</span>
<span class="normal">335</span>
<span class="normal">336</span>
<span class="normal">337</span>
<span class="normal">338</span>
<span class="normal">339</span>
<span class="normal">340</span>
<span class="normal">341</span>
<span class="normal">342</span>
<span class="normal">343</span>
<span class="normal">344</span>
<span class="normal">345</span>
<span class="normal">346</span>
<span class="normal">347</span>
<span class="normal">348</span>
<span class="normal">349</span>
<span class="normal">350</span>
<span class="normal">351</span>
<span class="normal">352</span>
<span class="normal">353</span>
<span class="normal">354</span>
<span class="normal">355</span>
<span class="normal">356</span>
<span class="normal">357</span>
<span class="normal">358</span>
<span class="normal">359</span>
<span class="normal">360</span>
<span class="normal">361</span>
<span class="normal">362</span>
<span class="normal">363</span>
<span class="normal">364</span>
<span class="normal">365</span>
<span class="normal">366</span>
<span class="normal">367</span>
<span class="normal">368</span>
<span class="normal">369</span>
<span class="normal">370</span>
<span class="normal">371</span>
<span class="normal">372</span>
<span class="normal">373</span>
<span class="normal">374</span>
<span class="normal">375</span>
<span class="normal">376</span>
<span class="normal">377</span>
<span class="normal">378</span>
<span class="normal">379</span>
<span class="normal">380</span>
<span class="normal">381</span>
<span class="normal">382</span>
<span class="normal">383</span>
<span class="normal">384</span>
<span class="normal">385</span>
<span class="normal">386</span>
<span class="normal">387</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">next</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Reads the next complete `Value` from the internal buffer, raising</span>
<span class="sd"> [ShortPacket][preserves.error.ShortPacket] if too few bytes are available, or</span>
<span class="sd"> [DecodeError][preserves.error.DecodeError] if the input is invalid somehow.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">skip_whitespace</span><span class="p">()</span>
<span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">peek</span><span class="p">()</span>
<span class="k">if</span> <span class="n">c</span> <span class="o">==</span> <span class="s1">&#39;&quot;&#39;</span><span class="p">:</span>
@ -1133,19 +1307,22 @@
<div class="doc doc-contents ">
<p>TODO</p>
<p>Like <a class="autorefs autorefs-internal" href="#preserves.text.Parser.next">next</a>, but returns <code>None</code> instead of raising
<a class="autorefs autorefs-internal" href="../error/#preserves.error.ShortPacket">ShortPacket</a>.</p>
<details class="quote">
<summary>Source code in <code>preserves/text.py</code></summary>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">275</span>
<span class="normal">276</span>
<span class="normal">277</span>
<span class="normal">278</span>
<span class="normal">279</span>
<span class="normal">280</span>
<span class="normal">281</span>
<span class="normal">282</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">try_next</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;TODO&quot;&quot;&quot;</span>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">389</span>
<span class="normal">390</span>
<span class="normal">391</span>
<span class="normal">392</span>
<span class="normal">393</span>
<span class="normal">394</span>
<span class="normal">395</span>
<span class="normal">396</span>
<span class="normal">397</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">try_next</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Like [next][preserves.text.Parser.next], but returns `None` instead of raising</span>
<span class="sd"> [ShortPacket][preserves.error.ShortPacket].&quot;&quot;&quot;</span>
<span class="n">start</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">index</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
@ -1166,52 +1343,68 @@
</div>
<div class="doc doc-object doc-class">
<h2 id="preserves.text.TextCodec" class="doc doc-heading">
<code>TextCodec</code>
</h2>
<div class="doc doc-contents ">
<p class="doc doc-class-bases">
Bases: <code>object</code></p>
<p>TODO</p>
</div>
</div>
<div class="doc doc-object doc-function">
<h2 id="preserves.text.parse" class="doc doc-heading">
<code class="highlight language-python"><span class="n">parse</span><span class="p">(</span><span class="n">bs</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></code>
<code class="highlight language-python"><span class="n">parse</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></code>
</h2>
<div class="doc doc-contents ">
<p>TODO</p>
<p>Yields the first complete encoded value from <code>text</code>, passing <code>kwargs</code> through to the
<a class="autorefs autorefs-internal" href="#preserves.text.Parser">Parser</a> constructor. Raises exceptions as per
<a class="autorefs autorefs-internal" href="#preserves.text.Parser.next">next</a>.</p>
<p><strong>Parameters:</strong></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>text</code></td>
<td>
<code>str</code>
</td>
<td><p>encoded data to decode</p></td>
<td>
<em>required</em>
</td>
</tr>
</tbody>
</table>
<details class="quote">
<summary>Source code in <code>preserves/text.py</code></summary>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">294</span>
<span class="normal">295</span>
<span class="normal">296</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="n">bs</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;TODO&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">Parser</span><span class="p">(</span><span class="n">input_buffer</span><span class="o">=</span><span class="n">bs</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">408</span>
<span class="normal">409</span>
<span class="normal">410</span>
<span class="normal">411</span>
<span class="normal">412</span>
<span class="normal">413</span>
<span class="normal">414</span>
<span class="normal">415</span>
<span class="normal">416</span>
<span class="normal">417</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Yields the first complete encoded value from `text`, passing `kwargs` through to the</span>
<span class="sd"> [Parser][preserves.text.Parser] constructor. Raises exceptions as per</span>
<span class="sd"> [next][preserves.text.Parser.next].</span>
<span class="sd"> Args:</span>
<span class="sd"> text (str): encoded data to decode</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">Parser</span><span class="p">(</span><span class="n">input_buffer</span><span class="o">=</span><span class="n">text</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
</code></pre></div></td></tr></table></div>
</details>
</div>
@ -1230,14 +1423,17 @@
<div class="doc doc-contents ">
<p>TODO</p>
<p>Like <a class="autorefs autorefs-internal" href="#preserves.text.parse">parse</a>, but supplying <code>include_annotations=True</code> to the
<a class="autorefs autorefs-internal" href="#preserves.text.Parser">Parser</a> constructor.</p>
<details class="quote">
<summary>Source code in <code>preserves/text.py</code></summary>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">298</span>
<span class="normal">299</span>
<span class="normal">300</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">parse_with_annotations</span><span class="p">(</span><span class="n">bs</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;TODO&quot;&quot;&quot;</span>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">419</span>
<span class="normal">420</span>
<span class="normal">421</span>
<span class="normal">422</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">parse_with_annotations</span><span class="p">(</span><span class="n">bs</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Like [parse][preserves.text.parse], but supplying `include_annotations=True` to the</span>
<span class="sd"> [Parser][preserves.text.Parser] constructor.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">Parser</span><span class="p">(</span><span class="n">input_buffer</span><span class="o">=</span><span class="n">bs</span><span class="p">,</span> <span class="n">include_annotations</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
</code></pre></div></td></tr></table></div>
</details>
@ -1257,16 +1453,19 @@
<div class="doc doc-contents ">
<p>TODO</p>
<p>Convert a single <code>Value</code> <code>v</code> to a string. Any supplied <code>kwargs</code> are passed on to the
underlying <a class="autorefs autorefs-internal" href="#preserves.text.Formatter">Formatter</a> constructor.</p>
<details class="quote">
<summary>Source code in <code>preserves/text.py</code></summary>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">423</span>
<span class="normal">424</span>
<span class="normal">425</span>
<span class="normal">426</span>
<span class="normal">427</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">stringify</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;TODO&quot;&quot;&quot;</span>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">606</span>
<span class="normal">607</span>
<span class="normal">608</span>
<span class="normal">609</span>
<span class="normal">610</span>
<span class="normal">611</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">def</span> <span class="nf">stringify</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Convert a single `Value` `v` to a string. Any supplied `kwargs` are passed on to the</span>
<span class="sd"> underlying [Formatter][preserves.text.Formatter] constructor.&quot;&quot;&quot;</span>
<span class="n">e</span> <span class="o">=</span> <span class="n">Formatter</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="n">e</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="k">return</span> <span class="n">e</span><span class="o">.</span><span class="n">contents</span><span class="p">()</span>

File diff suppressed because it is too large Load Diff