The dom.element module¶
This module defines the Element class.
An Element describes an object and can have child objects. An Element can
display a head and optionally a tail. The head is text that is printed
before the children (if any). The tail is displayed after the children, and
will in most cases be used as a closing delimiter.
An Element can be constructed in two ways: either using the
from_origin() class method from tokens (this is done by the
LilyPondTransform class), or manually using the normal constructor.
You can specify all child elements in the constructor, so theoretically you can build a whole document in one expression.
To get the textual output of an element and all its child elements, use the
write() method. Indented output is created by the
write_indented() method.
Whitespace is handled in a smart way: Element subclasses can specify the preferred whitespace before, after and between elements, and elements that have head and tail texts can also specify the preperred whitespace after the head and before the tail. When outputting the text, the whitespace between elements is combined to fulfil all requirements but to prevent double spaces.
When an Element is constructed from tokens using the
with_origin() constructor, it is able to write ifself back in
the document if modified, using the edit() method.
Element inherits from Node, and thus from
list, to build a reliable and easy to navigate tree structure.
-
class
Point(pos, end, text, modified, space_before, space_after)¶ Bases:
tupleA Point describes a piece of text at a certain position. See
Element.points().-
end¶ The end position in the original text. None for newly added nodes.
-
modified¶ True if the text has been modified.
-
pos¶ The position in the original text. None for newly added nodes.
-
space_after¶ The desired whitespace after this text fragment.
-
space_before¶ The desired whitespace before this text fragment.
-
text¶ A callable returning the text (the
write_headorwrite_tailmethod of the respective element).
-
-
class
ElementType[source]¶ Bases:
typeMetaclass for Element.
This meta class automatically adds an empty
__slots__attribute if it is not defined in the class body, and replaces space defaults with dynamic properties that are settable on a per-instance basis.
-
class
Element(*children, **attrs)[source]¶ Bases:
quickly.node.NodeBase class for all element types.
The Element has no head or tail value.
Child elements can be specified directly as arguments to the constructor. Using keyword arguments you can give other spacing preferences than the default values for
space_before,space_after,space_between,space_after_headandspace_before_tail.-
space_before= ''¶ whitespace before this element
-
space_after_head= ''¶ whitespace before first child
-
space_between= ''¶ whitespace between children
-
space_before_tail= ''¶ whitespace before tail
-
space_after= ''¶ whitespace after this element
-
copy(with_children=True)[source]¶ Copy the node, without the origin.
If
with_childrenis True (the default), child nodes are also copied.
-
copy_with_origin(with_children=True)[source]¶ Copy the node, with origin if available.
If
with_childrenis True (the default), child nodes are also copied.
-
copy_origin_from(other, modified=None)[source]¶ Copy the origin from another element node to ourself.
If
modifiedis True, sets ourself as “modified”, i.e. we will write back changes when requested viaedits(). Ifmodifiedis False, our “modified” flag will be set to to unmodified state. Ifmodifiedis None (the default); the modified flag will be copied from the other.Note
The modified flag makes only sense for
TextElementtypes, that have a writable head value. Using this method on other node types can lead to changes going unnoticed.
-
py_dump(file=None, indent_width=4)[source]¶ Print out the node to the console in Python syntax.
This can be used to speed up developing code that creates DOM documents. If the head value of every
TextElementhas a properrepr()value, the code can be directly executed in Python.For example:
>>> from quickly.lang.latex import Latex >>> from parce.transform import transform_text >>> transform_text(Latex.root, r"\begin[opts]{lilypond}music = { c }\end{lilypond}").py_dump() tex.Document( tex.Environment( tex.Command('begin', tex.Option( tex.Text('opts')), tex.EnvironmentName('lilypond')), lily.Document( lily.Assignment( lily.Identifier( lily.Symbol('music')), lily.EqualSign(), lily.MusicList( lily.Note('c')))), tex.Command('end', tex.EnvironmentName('lilypond'))))
-
pos¶ Return the position of this element.
Only makes sense for elements that have an origin, or one of the descendants has an origin. Possibly an expensive call, when a node tree has been heavily modified already. Returns None if this node and no single descendant of it has an origin.
-
end¶ Return the end position of this element.
Only makes sense for elements that have an origin, or one of the descendants has an origin. Possibly an expensive call, when a node tree has been heavily modified already. Returns None if this node and no single descendant of it has an origin.
-
find_child(position)[source]¶ Return the child node touching the position.
If two child nodes touch the position, the one to the right is chosen. Only returns a node that has a
posattribute, i.e. at least one of its descendants has an origin.
-
find_descendant(position, end=None)[source]¶ Return the youngest descendant node that contains position.
If two descendant nodes touch the position, the one to the right is chosen. Only returns a node that has a
posattribute, i.e. at least one of its descendants has an origin. Ifendis specified, stops with the last node that contains the rangeposition…end. Returns None if there is no such node that contains this position.
-
find_descendants(position, end=None)[source]¶ Yield the child at position, then the grandchild, etc.
Stops with the last node that really contains the position. Only yields nodes that have a
posattribute, i.e. at least one of its descendants has an origin. Ifendis specified, stops with the last node that contains the rangeposition…end.
-
find_descendant_right(position)[source]¶ Return the first descendant that starts at or to the right of position.
Only returns a node that has a
posattribute, i.e. at least one of its descendants has an origin. Returns None if no node with aposvalue is found at or to the right of the position.
-
find_descendant_left(position)[source]¶ Return the last descendant that ends at or to the left of position.
Only returns a node that has a
posattribute, i.e. at least one of its descendants has an origin. Returns None if no node with aposvalue is found at or to the left of the position.
-
head¶ The head contents.
-
tail¶ The tail contents.
-
classmethod
read_head(head_origin)[source]¶ Return the value as computed from the specified origin Tokens.
The default implementation concatenates the text from all tokens.
-
classmethod
read_tail(tail_origin)[source]¶ Return the value as computed from the specified origin Tokens.
The default implementation concatenates the text from all tokens.
-
write_head()[source]¶ Return the textual output that represents our
headvalue.The default implementation just returns the
headattribute, assuming it is text.
-
write_tail()[source]¶ Return the textual output that represents our
tailvalue.The default implementation just returns the
tailattribute, assuming it is text.
-
head_point()[source]¶ Return the
Pointdescribing the head text.Returns None for elements that don’t have a head text.
-
tail_point()[source]¶ Return the
Pointdescribing the tail text.Returns None for elements that can’t have a tail text.
-
points()[source]¶ Yield Points for this element and all its descendants.
Each point is a
Pointdescribing a text piece and the desired whitespace before and after it.
-
concat(node, next_node)[source]¶ Return the minimum whitespace to apply between these child nodes.
This method is called in the
points()method, when calculating whitespace between two adjacent child nodes. By default, the value of thespace_betweenattribute is returned. Reimplement this method to differentiate whitespacing based on the (type or contents of the) nodes.
-
write()[source]¶ Return the combined output of this node and its children.
To get indented output, use
write_indented()and/or theindentmodule.
-
edits(context, start=None, end=None)[source]¶ Yield three-tuples (pos, end, text) denoting text changes.
The
contextis a parce Context. Ifstartand/orendare not specified, the edits encompass the full context’s range. All added or modified text fragments will still be written to the document, but no text outside the specified range will be deleted.
-
edit(document, context=None, start=None, end=None)[source]¶ Write back the modifications to the original parce document.
Returns the number of changes that are made. If you don’t specify the parce Context
context, the document’s root context will be used.If
startand/orendare not specified, the edits encompass the full context’s range. All added or modified text fragments will still be written to the document, but no text outside the specified range will be deleted.After writing back the modifications to the original document, you should transform a new dom.Document, because some parts need to be rebuilt.
-
signatures()[source]¶ Return an iterable of signature tuples.
A signature is a tuple. Every item in the tuple is an Element type, or a tuple of Element types; and is used with
build_tree()to see whether an element can be a child of this element.By default an empty iterable is returned.
-
add_argument(node)[source]¶ Called by
build_tree()to add a child node as argument.nodeis the node to be appended. You can reimplement this method to perform some manipulation before appending it.
-
child_order()[source]¶ Return an iterable of tuples with element types.
This is almost the same as
signatures()but used when a child node is inserted usingadd().By default an empty iterable is returned.
-
add(node)[source]¶ Add a node, calling
child_order()to get the proper place to insert it.When the node type matches with one of the types in a child order tuple, it is inserted in that position between the other children. Not all node types need to be present, but at least the order is always respected.
If the proper place can’t be found, the node is appended at the end.
-
indent_children()[source]¶ Return True if the children should indent a level, if they appear on a new line.
-
indent_align_indices()[source]¶ Yield zero or more child indices that new lines could align with.
This only makes sense for nodes that trigger a new indent level when pretty-printing their contents, in most cases this will be a
BlockElementnode type.When, within a BlockElement node, a new line is started, it will by default be indented with, say, two spaces. But when there are already child nodes on the current line, the next line’s indent could be aligned to one of them. This method yields the indices of the nodes, in priority, that may be used to align the indent with. The first one that matches will be used.
-
-
class
HeadElement(*children, **attrs)[source]¶ Bases:
quickly.dom.element.ElementElement that has a fixed head value.
-
classmethod
from_origin(head_origin=(), tail_origin=(), *children, **attrs)[source]¶ Instantiate an Element from the origin tokens, but don’t keep the tokens.
-
classmethod
with_origin(head_origin=(), tail_origin=(), *children, **attrs)[source]¶ Instantiate an Element from the origin tokens, and keep the tokens.
This way, this element knows its position in the text source, even if the parce tree changes, or this element changes.
-
head_origin¶
-
classmethod
-
class
BlockElement(*children, **attrs)[source]¶ Bases:
quickly.dom.element.HeadElementElement that has a fixed head and tail value.
-
classmethod
with_origin(head_origin=(), tail_origin=(), *children, **attrs)[source]¶ Instantiate an Element from the origin tokens, and keep the tokens.
This way, this element knows its position in the text source, even if the parce tree changes, or this element changes.
-
tail_origin¶
-
classmethod
-
class
TextElement(head, *children, **attrs)[source]¶ Bases:
quickly.dom.element.HeadElementElement that has a variable/writable head value.
This value must be given to the constructor, and can be modified later.
If you want to, you can implement the
check_head()method, which by default returns True, to perform some checking on theheadvalue of this element. This prevents forgetting to set theheadvalue on manual construction, which can lead to unexpected and difficult to debug bugs. This method is not called when an element is copied, constructed from or with an origin, or when theheadattribute is modified manually later.-
body_equals(other)[source]¶ Compares the head values, called by
Node.equals().
-
classmethod
from_origin(head_origin=(), tail_origin=(), *children, **attrs)[source]¶ Instantiate an Element from the origin tokens, but don’t keep the tokens.
-
-
class
MappingElement(head, *children, **attrs)[source]¶ Bases:
quickly.dom.element.TextElementA TextElement with a fixed set of possible head values.
-
mapping= {}¶ The
mappingclass attribute is a dictionay mapping unique head values to unique output values. Other head values can’t be used, they result in a TypeError.
-
-
class
ToggleElement(head, *children, **attrs)[source]¶ Bases:
quickly.dom.element.MappingElementA TextElement for a toggled item that has two possible values.
E.g.
\breakor\noBreak, or\sustainOnand\sustainOff.The on-value is represented by head value True, the off value by False.
-
toggle_on= '<on>'¶
-
toggle_off= '<off>'¶
-
-
build_tree(nodes, ignore_type=None)[source]¶ Build a tree of a stream of elements, based on their
Element.signatures().nodesis an iterable of nodes. Consumes all nodes, and make some nodes a child of a preceding node. Yields the resulting nodes. When a node specifies what child element types it can have, and those element types follow indeed, they are added as child element.If
ignore_typeis given, it should be an Element type, or a tuple of Element types that are ignored, and added anyway as argument. This can be used to interperse Comment nodes.Existing children are taken into account.