debian._deb822_repro.parsing module

class debian._deb822_repro.parsing.AbstractDeb822ParagraphWrapper(paragraph: Deb822ParagraphElement, *, auto_resolve_ambiguous_fields: bool = False, discard_comments_on_read: bool = True)

Bases: AutoResolvingMixin[T], ABC

property _auto_resolve_ambiguous_fields: bool
property _discard_comments_on_read: bool
property _paragraph: Deb822ParagraphElement
class debian._deb822_repro.parsing.AutoResolvingMixin

Bases: Generic[T], Mapping[Union[Deb822FieldNameToken, str, Tuple[str, int]], T]

property _auto_resolve_ambiguous_fields: bool
_interpret_value(key: Deb822FieldNameToken | str | Tuple[str, int], value: Deb822KeyValuePairElement) T
property _paragraph: Deb822ParagraphElement
class debian._deb822_repro.parsing.Deb822CommentElement(comment_tokens: Sequence[Deb822CommentToken])

Bases: Deb822Element

_comment_tokens: Sequence[Deb822CommentToken]
property is_comment: bool
iter_parts() Iterable[Deb822Element | Deb822Token]
class debian._deb822_repro.parsing.Deb822DictishParagraphWrapper(paragraph: Deb822ParagraphElement, *, discard_comments_on_read: bool = True, auto_map_initial_line_whitespace: bool = True, auto_resolve_ambiguous_fields: bool = False, preserve_field_comments_on_field_updates: bool = True, auto_map_final_newline_in_multiline_values: bool = True)

Bases: AbstractDeb822ParagraphWrapper[str], Deb822ParagraphToStrWrapperMixin

property _auto_map_final_newline_in_multiline_values: bool
property _auto_map_initial_line_whitespace: bool
property _preserve_field_comments_on_field_updates: bool
class debian._deb822_repro.parsing.Deb822DuplicateFieldsParagraphElement(kvpair_elements: List[Deb822KeyValuePairElement])

Bases: Deb822ParagraphElement

static _find_node_via_name_token(name_token: Deb822FieldNameToken, elements: Iterable[None]) None
_full_size_cache: Range | None
_init_kvpair_fields(kvpairs: Iterable[Deb822KeyValuePairElement]) None
_nodes_being_relocated(field: Deb822FieldNameToken | str | Tuple[str, int]) Tuple[List[None], List[None]]
_parent_element: ReferenceType[Deb822Element] | None
_regenerate_relative_kvapir_order(field_name: _CaseInsensitiveString) None
_resolve_to_single_node(nodes: List[None], key: str, index: int | None, name_token: Deb822FieldNameToken | None, use_get: bool = False) None
contains_kvpair_element(item: object) bool
get_kvpair_element(item: Deb822FieldNameToken | str | Tuple[str, int], use_get: bool = False) Deb822KeyValuePairElement | None
property has_duplicate_fields: bool

Tell whether this paragraph has duplicate fields

iter_keys() Iterable[Deb822FieldNameToken | str | Tuple[str, int]]
iter_parts() Iterable[Deb822Element | Deb822Token]
property kvpair_count: int
order_after(field: Deb822FieldNameToken | str | Tuple[str, int], reference_field: Deb822FieldNameToken | str | Tuple[str, int]) None

Re-order the given field so appears directly before the reference field in the paragraph

The reference field must be present.

order_before(field: Deb822FieldNameToken | str | Tuple[str, int], reference_field: Deb822FieldNameToken | str | Tuple[str, int]) None

Re-order the given field so appears directly after the reference field in the paragraph

The reference field must be present.

order_first(field: Deb822FieldNameToken | str | Tuple[str, int]) None

Re-order the given field so it is “first” in the paragraph

order_last(field: Deb822FieldNameToken | str | Tuple[str, int]) None

Re-order the given field so it is “last” in the paragraph

remove_kvpair_element(key: Deb822FieldNameToken | str | Tuple[str, int]) None
set_kvpair_element(key: Deb822FieldNameToken | str | Tuple[str, int], value: Deb822KeyValuePairElement) None
sort_fields(key: Callable[[str], Any] | None = None) None

Re-order all fields

Parameters:

key – Provide a key function (same semantics as for sorted). Keep in mind that the module preserve the cases for field names - in generally, callers are recommended to use “lower()” to normalize the case.

class debian._deb822_repro.parsing.Deb822Element

Bases: Locatable

Composite elements (consists of 1 or more tokens)

_full_size_cache: Range | None
_init_parent_of_parts() None
_parent_element: ReferenceType[Deb822Element] | None
clear_parent_if_parent(parent: Deb822Element) None
convert_to_text() str
property is_comment: bool
property is_error: bool
property is_separator: bool
property is_whitespace: bool
iter_parts() Iterable[Deb822Element | Deb822Token]
iter_parts_of_type(only_element_or_token_type: Type[TE]) Iterable[TE]
iter_recurse(*, only_element_or_token_type: Type[TE] | None = None) Iterable[TE]
iter_tokens() Iterable[Deb822Token]
property parent_element: Deb822Element | None
size() Range

Describe the objects size as a continuous range

class debian._deb822_repro.parsing.Deb822ErrorElement(parts: Sequence[Deb822Element | Deb822Token])

Bases: Deb822Element

Element representing elements or tokens that are out of place

Commonly, it will just be instances of Deb822ErrorToken, but it can be other things. As an example if a parser discovers out of order elements/tokens, it can bundle them in a Deb822ErrorElement to signal that the sequence of elements/tokens are invalid (even if the tokens themselves are valid).

_parts
property is_error: bool
iter_parts() Iterable[Deb822Element | Deb822Token]
class debian._deb822_repro.parsing.Deb822FileElement(token_and_elements: LinkedList[Deb822Element | Deb822Token])

Bases: Deb822Element

Represents the entire deb822 file

_full_size_cache: Range | None
_parent_element: ReferenceType[Deb822Element] | None
_set_parent(t: TE) TE
append(paragraph: Deb822ParagraphElement) None

Appends a paragraph to the file

>>> deb822_file = Deb822FileElement.new_empty_file()
>>> para1 = Deb822ParagraphElement.new_empty_paragraph()
>>> para1["Source"] = "foo"
>>> para1["Build-Depends"] = "debhelper-compat (= 13)"
>>> para2 = Deb822ParagraphElement.new_empty_paragraph()
>>> para2["Package"] = "foo"
>>> para2["Depends"] = "${shlib:Depends}, ${misc:Depends}"
>>> deb822_file.append(para1)
>>> deb822_file.append(para2)
>>> expected = '''
... Source: foo
... Build-Depends: debhelper-compat (= 13)
...
... Package: foo
... Depends: ${shlib:Depends}, ${misc:Depends}
... '''.lstrip()
>>> deb822_file.dump() == expected
True
dump(fd)
dump() str
find_first_error_element() Deb822ErrorElement | None

Returns the first Deb822ErrorElement (or None) in the file

insert(idx: int, para: Deb822ParagraphElement) None

Inserts a paragraph into the file at the given “index” of paragraphs

Note that if the index is between two paragraphs containing a “free floating” comment (e.g. paragraph/start-of-file, empty line, comment, empty line, paragraph) then it is unspecified which “side” of the comment the new paragraph will appear and this may change between versions of python-debian.

>>> original = '''
... Package: libfoo-dev
... Depends: libfoo1 (= ${binary:Version}), ${shlib:Depends}, ${misc:Depends}
... '''.lstrip()
>>> deb822_file = parse_deb822_file(original.splitlines())
>>> para1 = Deb822ParagraphElement.new_empty_paragraph()
>>> para1["Source"] = "foo"
>>> para1["Build-Depends"] = "debhelper-compat (= 13)"
>>> para2 = Deb822ParagraphElement.new_empty_paragraph()
>>> para2["Package"] = "libfoo1"
>>> para2["Depends"] = "${shlib:Depends}, ${misc:Depends}"
>>> deb822_file.insert(0, para1)
>>> deb822_file.insert(1, para2)
>>> expected = '''
... Source: foo
... Build-Depends: debhelper-compat (= 13)
...
... Package: libfoo1
... Depends: ${shlib:Depends}, ${misc:Depends}
...
... Package: libfoo-dev
... Depends: libfoo1 (= ${binary:Version}), ${shlib:Depends}, ${misc:Depends}
... '''.lstrip()
>>> deb822_file.dump() == expected
True
property is_valid_file: bool

Returns true if the file is valid

Invalid elements include error elements (Deb822ErrorElement) but also issues such as paragraphs with duplicate fields or “empty” files (a valid deb822 file contains at least one paragraph).

iter_parts() Iterable[Deb822Element | Deb822Token]
classmethod new_empty_file() Deb822FileElement

Creates a new Deb822FileElement with no contents

Note that a deb822 file must be non-empty to be considered valid

position_in_file() Position

The start position of this token/element in this file

This is an expensive operation and in many cases have to traverse the entire file structure to answer the query. Consider whether you can maintain the parent’s position and then use position_in_parent() combined with child_position.relative_to(parent_position)

position_in_parent() Position

The start position of this token/element inside its parent

This is operation is generally linear to the number of “parts” (elements/tokens) inside the parent.

remove(paragraph: Deb822ParagraphElement) None
class debian._deb822_repro.parsing.Deb822InterpretationProxyElement(real_element: Deb822Element, parts: List[Deb822Element | Deb822Token])

Bases: Deb822Element

iter_parts() Iterable[Deb822Element | Deb822Token]
parts
position_in_file() Position

The start position of this token/element in this file

This is an expensive operation and in many cases have to traverse the entire file structure to answer the query. Consider whether you can maintain the parent’s position and then use position_in_parent() combined with child_position.relative_to(parent_position)

position_in_parent() Position

The start position of this token/element inside its parent

This is operation is generally linear to the number of “parts” (elements/tokens) inside the parent.

size() Range

Describe the objects size as a continuous range

class debian._deb822_repro.parsing.Deb822InterpretingParagraphWrapper(paragraph: Deb822ParagraphElement, interpretation: Interpretation[T], *, auto_resolve_ambiguous_fields: bool = False, discard_comments_on_read: bool = True)

Bases: AbstractDeb822ParagraphWrapper[T]

_interpret_value(key: Deb822FieldNameToken | str | Tuple[str, int], value: Deb822KeyValuePairElement) T
class debian._deb822_repro.parsing.Deb822KeyValuePairElement(comment_element: Deb822CommentElement | None, field_token: Deb822FieldNameToken, separator_token: Deb822FieldSeparatorToken, value_element: Deb822ValueElement)

Bases: Deb822Element

_comment_element: Deb822CommentElement | None
_field_token: Deb822FieldNameToken
_separator_token: Deb822FieldSeparatorToken
_value_element: Deb822ValueElement
property comment_element: Deb822CommentElement | None
property field_name: _CaseInsensitiveString
property field_token: Deb822FieldNameToken
interpret_as(interpreter: Interpretation[T], discard_comments_on_read: bool = True) T
iter_parts() Iterable[Deb822Element | Deb822Token]
property value_element: Deb822ValueElement
class debian._deb822_repro.parsing.Deb822NoDuplicateFieldsParagraphElement(kvpair_elements: List[Deb822KeyValuePairElement], kvpair_order: OrderedSet)

Bases: Deb822ParagraphElement

Paragraph implementation optimized for valid deb822 files

When there are no duplicated fields, we can use simpler and faster datastructures for common operations.

_full_size_cache: Range | None
_parent_element: ReferenceType[Deb822Element] | None
contains_kvpair_element(item: object) bool
get_kvpair_element(item: Deb822FieldNameToken | str | Tuple[str, int], use_get: bool = False) Deb822KeyValuePairElement | None
iter_keys() Iterable[str]
iter_parts() Iterable[Deb822Element | Deb822Token]
property kvpair_count: int
order_after(field: Deb822FieldNameToken | str | Tuple[str, int], reference_field: Deb822FieldNameToken | str | Tuple[str, int]) None

Re-order the given field so appears directly before the reference field in the paragraph

The reference field must be present.

order_before(field: Deb822FieldNameToken | str | Tuple[str, int], reference_field: Deb822FieldNameToken | str | Tuple[str, int]) None

Re-order the given field so appears directly after the reference field in the paragraph

The reference field must be present.

order_first(field: Deb822FieldNameToken | str | Tuple[str, int]) None

Re-order the given field so it is “first” in the paragraph

order_last(field: Deb822FieldNameToken | str | Tuple[str, int]) None

Re-order the given field so it is “last” in the paragraph

remove_kvpair_element(key: Deb822FieldNameToken | str | Tuple[str, int]) None
set_kvpair_element(key: Deb822FieldNameToken | str | Tuple[str, int], value: Deb822KeyValuePairElement) None
sort_fields(key: Callable[[str], Any] | None = None) None

Re-order all fields

Parameters:

key – Provide a key function (same semantics as for sorted). Keep in mind that the module preserve the cases for field names - in generally, callers are recommended to use “lower()” to normalize the case.

class debian._deb822_repro.parsing.Deb822ParagraphElement

Bases: Deb822Element, Deb822ParagraphToStrWrapperMixin, ABC

_full_size_cache: Range | None
property _paragraph: Deb822ParagraphElement
_parent_element: ReferenceType[Deb822Element] | None
as_interpreted_dict_view(interpretation: Interpretation[T], *, auto_resolve_ambiguous_fields: bool = True) Deb822InterpretingParagraphWrapper[T]

Provide a Dict-like view of the paragraph

This method returns a dict-like object representing this paragraph and is useful for accessing fields in a given interpretation. It is possible to use multiple versions of this dict-like view with different interpretations on the same paragraph at the same time (for different fields).

>>> example_deb822_paragraph = '''
... Package: foo
... # Field comment (because it becomes just before a field)
... Architecture: amd64
... # Inline comment (associated with the next line)
...               i386
... # We also support arm
...               arm64
...               armel
... '''
>>> dfile = parse_deb822_file(example_deb822_paragraph.splitlines())
>>> paragraph = next(iter(dfile))
>>> list_view = paragraph.as_interpreted_dict_view(LIST_SPACE_SEPARATED_INTERPRETATION)
>>> # With the defaults, you only deal with the semantic values
>>> # - no leading or trailing whitespace on the first part of the value
>>> list(list_view["Package"])
['foo']
>>> with list_view["Architecture"] as arch_list:
...     orig_arch_list = list(arch_list)
...     arch_list.replace('i386', 'kfreebsd-amd64')
>>> orig_arch_list
['amd64', 'i386', 'arm64', 'armel']
>>> list(list_view["Architecture"])
['amd64', 'kfreebsd-amd64', 'arm64', 'armel']
>>> print(paragraph.dump(), end='')
Package: foo
# Field comment (because it becomes just before a field)
Architecture: amd64
# Inline comment (associated with the next line)
              kfreebsd-amd64
# We also support arm
              arm64
              armel
>>> # Format preserved and architecture replaced
>>> with list_view["Architecture"] as arch_list:
...     # Prettify the result as sorting will cause awkward whitespace
...     arch_list.reformat_when_finished()
...     arch_list.sort()
>>> print(paragraph.dump(), end='')
Package: foo
# Field comment (because it becomes just before a field)
Architecture: amd64
# We also support arm
              arm64
              armel
# Inline comment (associated with the next line)
              kfreebsd-amd64
>>> list(list_view["Architecture"])
['amd64', 'arm64', 'armel', 'kfreebsd-amd64']
>>> # Format preserved and architecture values sorted
Parameters:
  • interpretation – Decides how the field values are interpreted. As an example, use LIST_SPACE_SEPARATED_INTERPRETATION for fields such as Architecture in the debian/control file.

  • auto_resolve_ambiguous_fields – This parameter is only relevant for paragraphs that contain the same field multiple times (these are generally invalid). If the caller requests an ambiguous field from an invalid paragraph via a plain field name, the return dict-like object will refuse to resolve the field (not knowing which version to pick). This parameter (if set to True) instead changes the error into assuming the caller wants the first variant.

configured_view(*, discard_comments_on_read: bool = True, auto_map_initial_line_whitespace: bool = True, auto_resolve_ambiguous_fields: bool = True, preserve_field_comments_on_field_updates: bool = True, auto_map_final_newline_in_multiline_values: bool = True) Deb822DictishParagraphWrapper

Provide a Dict[str, str]-like view of this paragraph with non-standard parameters

This method returns a dict-like object representing this paragraph that is optionally configured differently from the default view.

>>> example_deb822_paragraph = '''
... Package: foo
... # Field comment (because it becomes just before a field)
... Depends: libfoo,
... # Inline comment (associated with the next line)
...          libbar,
... '''
>>> dfile = parse_deb822_file(example_deb822_paragraph.splitlines())
>>> paragraph = next(iter(dfile))
>>> # With the defaults, you only deal with the semantic values
>>> # - no leading or trailing whitespace on the first part of the value
>>> paragraph["Package"]
'foo'
>>> # - no inline comments in multiline values (but whitespace will be present
>>> #   subsequent lines.)
>>> print(paragraph["Depends"])
libfoo,
         libbar,
>>> paragraph['Foo'] = 'bar'
>>> paragraph.get('Foo')
'bar'
>>> paragraph.get('Unknown-Field') is None
True
>>> # But you get asymmetric behaviour with set vs. get
>>> paragraph['Foo'] = ' bar\n'
>>> paragraph['Foo']
'bar'
>>> paragraph['Bar'] = '     bar\n#Comment\n another value\n'
>>> # Note that the whitespace on the first line has been normalized.
>>> print("Bar: " + paragraph['Bar'])
Bar: bar
 another value
>>> # The comment is present (in case you where wondering)
>>> print(paragraph.get_kvpair_element('Bar').convert_to_text(), end='')
Bar:     bar
#Comment
 another value
>>> # On the other hand, you can choose to see the values as they are
>>> # - We will just reset the paragraph as a "nothing up my sleeve"
>>> dfile = parse_deb822_file(example_deb822_paragraph.splitlines())
>>> paragraph = next(iter(dfile))
>>> nonstd_dictview = paragraph.configured_view(
...     discard_comments_on_read=False,
...     auto_map_initial_line_whitespace=False,
...     # For paragraphs with duplicate fields, you can choose to get an error
...     # rather than the dict picking the first value available.
...     auto_resolve_ambiguous_fields=False,
...     auto_map_final_newline_in_multiline_values=False,
... )
>>> # Because we have reset the state, Foo and Bar are no longer there.
>>> 'Bar' not in paragraph and 'Foo' not in paragraph
True
>>> # We can now see the comments (discard_comments_on_read=False)
>>> # (The leading whitespace in front of "libfoo" is due to
>>> #  auto_map_initial_line_whitespace=False)
>>> print(nonstd_dictview["Depends"], end='')
 libfoo,
# Inline comment (associated with the next line)
         libbar,
>>> # And all the optional whitespace on the first value line
>>> # (auto_map_initial_line_whitespace=False)
>>> nonstd_dictview["Package"] == ' foo\n'
True
>>> # ... which will give you symmetric behaviour with set vs. get
>>> nonstd_dictview['Foo'] = '  bar \n'
>>> nonstd_dictview['Foo']
'  bar \n'
>>> nonstd_dictview['Bar'] = '  bar \n#Comment\n another value\n'
>>> nonstd_dictview['Bar']
'  bar \n#Comment\n another value\n'
>>> # But then you get no help either.
>>> try:
...     nonstd_dictview["Baz"] = "foo"
... except ValueError:
...     print("Rejected")
Rejected
>>> # With auto_map_initial_line_whitespace=False, you have to include minimum a newline
>>> nonstd_dictview["Baz"] = "foo\n"
>>> # The absence of leading whitespace gives you the terse variant at the expensive
>>> # readability
>>> paragraph.get_kvpair_element('Baz').convert_to_text()
'Baz:foo\n'
>>> # But because they are views, changes performed via one view is visible in the other
>>> paragraph['Foo']
'bar'
>>> # The views show the values according to their own rules. Therefore, there is an
>>> # asymmetric between paragraph['Foo'] and nonstd_dictview['Foo']
>>> # Nevertheless, you can read or write the fields via either - enabling you to use
>>> # the view that best suit your use-case for the given field.
>>> 'Baz' in paragraph and nonstd_dictview.get('Baz') is not None
True
>>> # Deletion via the view also works
>>> del nonstd_dictview['Baz']
>>> 'Baz' not in paragraph and nonstd_dictview.get('Baz') is None
True
Parameters:
  • discard_comments_on_read – When getting a field value from the dict, this parameter decides how in-line comments are handled. When setting the value, inline comments are still allowed and will be retained. However, keep in mind that this option makes getter and setter asymmetric as a “get” following a “set” with inline comments will omit the comments even if they are there (see the code example).

  • auto_map_initial_line_whitespace – Special-case the first value line by trimming unnecessary whitespace leaving only the value. For single-line values, all space including newline is pruned. For multi-line values, the newline is preserved / needed to distinguish the first line from the following lines. When setting a value, this option normalizes the whitespace of the initial line of the value field. When this option is set to True makes the dictionary behave more like the original Deb822 module.

  • preserve_field_comments_on_field_updates – Whether to preserve the field comments when mutating the field.

  • auto_resolve_ambiguous_fields – This parameter is only relevant for paragraphs that contain the same field multiple times (these are generally invalid). If the caller requests an ambiguous field from an invalid paragraph via a plain field name, the return dict-like object will refuse to resolve the field (not knowing which version to pick). This parameter (if set to True) instead changes the error into assuming the caller wants the first variant.

  • auto_map_final_newline_in_multiline_values – This parameter controls whether a multiline field with have / need a trailing newline. If True, the trailing newline is hidden on get and automatically added in set (if missing). When this option is set to True makes the dictionary behave more like the original Deb822 module.

contains_kvpair_element(item: object) bool
dump(fd)
dump() str
classmethod from_dict(mapping: Mapping[str, str]) Deb822ParagraphElement
classmethod from_kvpairs(kvpair_elements: List[Deb822KeyValuePairElement]) Deb822ParagraphElement
get_kvpair_element(item: Deb822FieldNameToken | str | Tuple[str, int], use_get: bool = False) Deb822KeyValuePairElement | None
property has_duplicate_fields: bool

Tell whether this paragraph has duplicate fields

iter_keys() Iterable[Deb822FieldNameToken | str | Tuple[str, int]]
property kvpair_count: int
classmethod new_empty_paragraph() Deb822ParagraphElement
order_after(field: Deb822FieldNameToken | str | Tuple[str, int], reference_field: Deb822FieldNameToken | str | Tuple[str, int]) None

Re-order the given field so appears directly before the reference field in the paragraph

The reference field must be present.

order_before(field: Deb822FieldNameToken | str | Tuple[str, int], reference_field: Deb822FieldNameToken | str | Tuple[str, int]) None

Re-order the given field so appears directly after the reference field in the paragraph

The reference field must be present.

order_first(field: Deb822FieldNameToken | str | Tuple[str, int]) None

Re-order the given field so it is “first” in the paragraph

order_last(field: Deb822FieldNameToken | str | Tuple[str, int]) None

Re-order the given field so it is “last” in the paragraph

remove_kvpair_element(key: Deb822FieldNameToken | str | Tuple[str, int]) None
set_field_from_raw_string(item: Deb822FieldNameToken | str | Tuple[str, int], raw_string_value: str, *, preserve_original_field_comment: bool | None = None, field_comment: List[str] | Deb822CommentElement | None = None) None

Sets a field in this paragraph to a given text value

In many cases, it is better for callers to just use the paragraph as if it was a dictionary. However, this method does enable to you choose the field comment (if any) and lets to have a higher degree of control over whitespace (on the first line), which can be a reason for using it.

Example usage:

>>> example_deb822_paragraph = '''
... Package: foo
... '''
>>> dfile = parse_deb822_file(example_deb822_paragraph.splitlines())
>>> p = next(iter(dfile))
>>> raw_value = '''
... Build-Depends: debhelper-compat (= 12),
...                some-other-bd,
... # Comment
...                another-bd,
... '''.lstrip()  # Remove leading newline, but *not* the trailing newline
>>> fname, new_value = raw_value.split(':', 1)
>>> p.set_field_from_raw_string(fname, new_value)
>>> print(p.dump(), end='')
Package: foo
Build-Depends: debhelper-compat (= 12),
               some-other-bd,
# Comment
               another-bd,
>>> # Format preserved
Parameters:
  • item – Name of the field to set. If the paragraph already contains the field, then it will be replaced. Otherwise, it is added to the end of the paragraph. Note this can be a “paragraph key”, which enables you to control which instance of a field is being replaced (in case of duplicate fields).

  • raw_string_value

    The text to use as the value. The text must be valid deb822 syntax and is used exactly as it is given. Accordingly, multi-line values must include mandatory leading space on continuation lines, newlines after the value, etc. On the flip-side, any optional space or comments will be included.

    Note that the first line will never be read as a comment (if the first line of the value starts with a “#” then it will result in “Field-Name:#…” which is parsed as a value starting with “#” rather than a comment).

  • preserve_original_field_comment – If True, then if there is an existing field and that has a comment, then the comment will remain after this operation. This is the default is the field_comment parameter is omitted. Note that if the parameter is True and the item is ambiguous, this will raise an AmbiguousDeb822FieldKeyError. When the parameter is omitted, the ambiguity is resolved automatically and if the resolved field has a comment then that will be preserved (assuming field_comment is None).

  • field_comment

    If not None, add or replace the comment for the field. Each string in the list will become one comment line (inserted directly before the field name). Will appear in the same order as they do in the list.

    If you want complete control over the formatting of the comments, then ensure that each line start with “#” and end with “n” before the call. Otherwise, leading/trailing whitespace is normalized and the missing “#”/”n” character is inserted.

set_field_to_simple_value(item: Deb822FieldNameToken | str | Tuple[str, int], simple_value: str, *, preserve_original_field_comment: bool | None = None, field_comment: List[str] | Deb822CommentElement | None = None) None

Sets a field in this paragraph to a simple “word” or “phrase”

In many cases, it is better for callers to just use the paragraph as if it was a dictionary. However, this method does enable to you choose the field comment (if any), which can be a reason for using it.

This is suitable for “simple” fields like “Package”. Example:

>>> example_deb822_paragraph = '''
... Package: foo
... '''
>>> dfile = parse_deb822_file(example_deb822_paragraph.splitlines())
>>> p = next(iter(dfile))
>>> p.set_field_to_simple_value("Package", "mscgen")
>>> p.set_field_to_simple_value("Architecture", "linux-any kfreebsd-any",
...                             field_comment=['Only ported to linux and kfreebsd'])
>>> p.set_field_to_simple_value("Priority", "optional")
>>> print(p.dump(), end='')
Package: mscgen
# Only ported to linux and kfreebsd
Architecture: linux-any kfreebsd-any
Priority: optional
>>> # Values are formatted nicely by default, but it does not work with
>>> # multi-line values
>>> p.set_field_to_simple_value("Foo", "bar\nbin\n")
Traceback (most recent call last):
    ...
ValueError: Cannot use set_field_to_simple_value for values with newlines
Parameters:
  • item – Name of the field to set. If the paragraph already contains the field, then it will be replaced. If the field exists, then it will preserve its order in the paragraph. Otherwise, it is added to the end of the paragraph. Note this can be a “paragraph key”, which enables you to control which instance of a field is being replaced (in case of duplicate fields).

  • simple_value – The text to use as the value. The value must not contain newlines. Leading and trailing will be stripped but space within the value is preserved. The value cannot contain comments (i.e. if the “#” token appears in the value, then it is considered a value rather than “start of a comment)

  • preserve_original_field_comment – See the description for the parameter with the same name in the set_field_from_raw_string method.

  • field_comment – See the description for the parameter with the same name in the set_field_from_raw_string method.

set_kvpair_element(key: Deb822FieldNameToken | str | Tuple[str, int], value: Deb822KeyValuePairElement) None
sort_fields(key: Callable[[str], Any] | None = None) None

Re-order all fields

Parameters:

key – Provide a key function (same semantics as for sorted). Keep in mind that the module preserve the cases for field names - in generally, callers are recommended to use “lower()” to normalize the case.

class debian._deb822_repro.parsing.Deb822ParagraphToStrWrapperMixin

Bases: AutoResolvingMixin[str], ABC

property _auto_map_final_newline_in_multiline_values: bool
property _auto_map_initial_line_whitespace: bool
_convert_value_to_str(kvpair_element: Deb822KeyValuePairElement) str
property _discard_comments_on_read: bool
_interpret_value(key: Deb822FieldNameToken | str | Tuple[str, int], value: Deb822KeyValuePairElement) str
property _preserve_field_comments_on_field_updates: bool
class debian._deb822_repro.parsing.Deb822ParsedTokenList(kvpair_element: Deb822KeyValuePairElement, interpreted_value_element: Deb822InterpretationProxyElement, vtype: Type[VE], stype: Type[ST], str2value_parser: StrToValueParser[VE], default_separator_factory: Callable[[], ST], render: Callable[[VE], str])

Bases: Generic[VE, ST], AbstractContextManager[Deb822ParsedTokenList[VE, ST]]

_append_continuation_line_token_if_necessary() None
property _continuation_line_char: str
_enable_reformatting() None
_generate_field_content() str
_generate_kvpair() Deb822KeyValuePairElement
_generate_reformatted_field_content() str
_iter_content_as_tokens() Iterable[Deb822Token]
_mark_changed() None
_previous_is_newline() bool
_remove_node(node_to_remove: LinkedListNode[Deb822Element | Deb822Token]) None
_update_field() None
append(value: str) None
append_comment(comment_text: str) None
append_newline() None
append_separator(space_after_separator: bool = True) None
append_value(vt: VE) None
clear() None

Like list.clear() - removes all content (including comments and spaces)

convert_to_text(*, with_field_name: bool = False) str
iter_parts() Iterable[Deb822Element | Deb822Token]
iter_value_references() Iterator[ValueReference[VE]]

Iterate over all values in the list (as ValueReferences)

This is useful for doing inplace modification of the values or even streaming removal of field values. It is in general also more efficient when more than one value is updated or removed.

no_reformatting_when_finished() None
reformat_when_finished() None
remove(value: str) None

Remove the first instance of a value

Removal will invalidate ValueReferences to the value being removed. ValueReferences to other values will be unaffected.

replace(orig_value: str, new_value: str) None

Replace the first instance of a value with another

This method will not affect the validity of ValueReferences.

sort(*, key: Callable[[str], Any] | None = None, **kwargs: Any) None

Sort the values (rendered as str) in this list.

This method will sort the logical values of the list. It will attempt to preserve comments associated with a given value where possible. Whether space and separators are preserved depends on the contents of the field as well as the formatting settings.

Sorting (without reformatting) is likely to leave you with “awkward” whitespace. Therefore, you almost always want to apply reformatting such as the reformat_when_finished() method.

Sorting will invalidate all ValueReferences.

sort_elements(*, key: Callable[[VE], Any] | None = None, reverse: bool = False) None

Sort the elements (abstract values) in this list.

This method will sort the logical values of the list. It will attempt to preserve comments associated with a given value where possible. Whether space and separators are preserved depends on the contents of the field as well as the formatting settings.

Sorting (without reformatting) is likely to leave you with “awkward” whitespace. Therefore, you almost always want to apply reformatting such as the reformat_when_finished() method.

Sorting will invalidate all ValueReferences.

value_formatter(formatter: Callable[[str, FormatterContentToken, Iterator[FormatterContentToken]], Iterator[FormatterContentToken | str]], force_reformat: bool = False) None

Use a custom formatter when formatting the value

Parameters:
  • formatter – A formatter (see debian._deb822_repro.formatter.format_field for details)

  • force_reformat – If True, always reformat the field even if there are no (other) changes performed. By default, fields are only reformatted if they are changed.

property value_parts: Iterator[VE]
class debian._deb822_repro.parsing.Deb822ParsedValueElement(tokens: List[Deb822Token])

Bases: Deb822Element

_text_cached: str | None
_text_no_comments_cached: str | None
_token_list
convert_to_text() str
convert_to_text_without_comments() str
iter_parts() Iterable[Deb822Element | Deb822Token]
class debian._deb822_repro.parsing.Deb822ValueElement(value_entry_elements: Sequence[Deb822ValueLineElement])

Bases: Deb822Element

_value_entry_elements: Sequence[Deb822ValueLineElement]
add_final_newline_if_missing() bool
iter_parts() Iterable[Deb822Element | Deb822Token]
property value_lines: Sequence[Deb822ValueLineElement]

Read-only list of value entries

class debian._deb822_repro.parsing.Deb822ValueLineElement(comment_element: Deb822CommentElement | None, continuation_line_token: Deb822ValueContinuationToken | None, leading_whitespace_token: Deb822WhitespaceToken | None, value_parts: List[Deb822Element | Deb822Token], trailing_whitespace_token: Deb822WhitespaceToken | None, newline_token: Deb822WhitespaceToken | None)

Bases: Deb822Element

Consists of one “line” of a value

_comment_element: Deb822CommentElement | None
_continuation_line_token
_iter_content_parts() Iterable[Deb822Element | Deb822Token]
_iter_content_tokens() Iterable[Deb822Token]
_leading_whitespace_token: Deb822WhitespaceToken | None
_newline_token: Deb822WhitespaceToken | None
_trailing_whitespace_token
_value_tokens: List[Deb822Element | Deb822Token]
add_newline_if_missing() bool
property comment_element: Deb822CommentElement | None
property continuation_line_token: Deb822ValueContinuationToken | None
convert_content_to_text() str
iter_parts() Iterable[Deb822Element | Deb822Token]
property newline_token: Deb822WhitespaceToken | None
class debian._deb822_repro.parsing.GenericContentBasedInterpretation(tokenizer: Callable[[str], Iterable['Deb822Token']], value_parser: StreamingValueParser[VE])

Bases: Interpretation[T], Generic[T, VE]

_high_level_interpretation(kvpair_element: Deb822KeyValuePairElement, proxy_element: Deb822InterpretationProxyElement, discard_comments_on_read: bool = True) T
_parse_kvpair(kvpair: Deb822KeyValuePairElement) Deb822InterpretationProxyElement
_parse_str(content: str) Iterable[Deb822Token | VE]
_parse_stream(buffered_iterator: BufferingIterator[Deb822Token]) Iterable[Deb822Token | VE]
interpret(kvpair_element: Deb822KeyValuePairElement, discard_comments_on_read: bool = True) T
class debian._deb822_repro.parsing.Interpretation

Bases: Generic[T]

interpret(kvpair_element: Deb822KeyValuePairElement, discard_comments_on_read: bool = True) T
class debian._deb822_repro.parsing.ListInterpretation(tokenizer: Callable[[str], Iterable['Deb822Token']], value_parser: StreamingValueParser[VE], vtype: Type[VE], stype: Type[ST], default_separator_factory: Callable[[], ST], render_factory: Callable[[bool], Callable[[VE], str]])

Bases: GenericContentBasedInterpretation[Deb822ParsedTokenList[VE, ST], VE]

_high_level_interpretation(kvpair_element: Deb822KeyValuePairElement, proxy_element: Deb822InterpretationProxyElement, discard_comments_on_read: bool = True) Deb822ParsedTokenList[VE, ST]
class debian._deb822_repro.parsing.ValueReference(node, render, value_factory, removal_handler, mutation_notifier)

Bases: Generic[TE]

Reference to a value inside a Deb822 paragraph

This is useful for cases where want to modify values “in-place” or maybe conditionally remove a value after looking at it.

ValueReferences can be invalidated by various changes or actions performed to the underlying provider of the value reference. As an example, sorting a list of values will generally invalidate all ValueReferences related to that list.

The ValueReference will raise validity issues where it detects them but most of the time it will not notice. As a means to this end, the ValueReference will not keep a strong reference to the underlying value. This enables it to detect when the container goes out of scope. However, keep in mind that the timeliness of garbage collection is implementation defined (e.g., pypy does not use ref-counting).

_mutation_notifier
_node: ReferenceType[LinkedListNode[TE]] | None
_removal_handler
_render
_resolve_node() LinkedListNode[TE]
_value_factory
property locatable: Locatable

Reference to a locatable that can be used to determine where this value is

remove() None

Remove the underlying value

This will invalidate the ValueReference (and any other ValueReferences pointing to that exact value). The validity of other ValueReferences to that container remains unaffected.

property value: str

Resolve the reference into a str

debian._deb822_repro.parsing._abort_on_error_tokens(sequence: Iterable[Deb822Element | Deb822Token]) Iterable[Deb822Element | Deb822Token]
debian._deb822_repro.parsing._build_field_with_value(token_stream: Iterable[Deb822Element | Deb822Token | Deb822ValueElement]) Iterable[Deb822Element | Deb822Token | Deb822KeyValuePairElement]
debian._deb822_repro.parsing._build_value_line(token_stream: Iterable[Deb822Element | Deb822Token | Deb822CommentElement]) Iterable[Deb822Element | Deb822Token | Deb822ValueLineElement]

Parser helper - consumes tokens part of a Deb822ValueEntryElement and turns them into one

debian._deb822_repro.parsing._convert_value_lines_to_lines(value_lines: Iterable[Deb822ValueLineElement], strip_comments: bool) Iterable[str]
debian._deb822_repro.parsing._format_comment(c: str) str
debian._deb822_repro.parsing._is_comma_token(v: Deb822Element | Deb822Token) bool
debian._deb822_repro.parsing._non_end_of_line_token(v: Deb822Element | Deb822Token) bool
debian._deb822_repro.parsing._parse_comma_list_value(token: Deb822Token, buffered_iterator: BufferingIterator[Deb822Token]) Deb822ParsedValueElement
debian._deb822_repro.parsing._parse_uploaders_list_value(token: Deb822Token, buffered_iterator: BufferingIterator[Deb822Token]) Deb822ParsedValueElement
debian._deb822_repro.parsing._parse_whitespace_list_value(token: Deb822Token, _: BufferingIterator[Deb822Token]) Deb822ParsedValueElement
debian._deb822_repro.parsing._parsed_value_render_factory(discard_comments: bool) Callable[[Deb822ParsedValueElement], str]
debian._deb822_repro.parsing._parser_to_value_factory(parser: StrToValueParser[VE], vtype: Type[VE]) Callable[[str], VE]
debian._deb822_repro.parsing._unpack_key(item: Deb822FieldNameToken | str | Tuple[str, int], raise_if_indexed: bool = False) Tuple[_CaseInsensitiveString, int | None, Deb822FieldNameToken | None]
debian._deb822_repro.parsing.parse_deb822_file(sequence: Iterable[str | bytes] | str, *, accept_files_with_error_tokens: bool = False, accept_files_with_duplicated_fields: bool = False, encoding: str = 'utf-8') Deb822FileElement
Parameters:
  • sequence – An iterable over lines of str or bytes (an open file for reading will do). If line endings are provided in the input, then they must be present on every line (except the last) will be preserved as-is. If omitted and the content is at least 2 lines, then parser will assume implicit newlines.

  • accept_files_with_error_tokens – If True, files with critical syntax or parse errors will be returned as “successfully” parsed. Usually, working on files with this kind of errors are not desirable as it is hard to make sense of such files (and they might in fact not be a deb822 file at all). When set to False (the default) a ValueError is raised if there is a critical syntax or parse error. Note that duplicated fields in a paragraph is not considered a critical parse error by this parser as the implementation can gracefully cope with these. Use accept_files_with_duplicated_fields to determine if such files should be accepted.

  • accept_files_with_duplicated_fields – If True, then files containing paragraphs with duplicated fields will be returned as “successfully” parsed even though they are invalid according to the specification. The paragraphs will prefer the first appearance of the field unless caller explicitly requests otherwise (e.g., via Deb822ParagraphElement.configured_view). If False, then this method will raise a ValueError if any duplicated fields are seen inside any paragraph.

  • encoding – The encoding to use (this is here to support Deb822-like APIs, new code should not use this parameter).