Skip to content

Commit

Permalink
23.10.1 released
Browse files Browse the repository at this point in the history
  • Loading branch information
SRBuilds committed Oct 31, 2023
1 parent 6f30219 commit 7b8e404
Show file tree
Hide file tree
Showing 23 changed files with 2,407 additions and 696 deletions.
5 changes: 2 additions & 3 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
author = 'Nokia'

# The full version, including alpha/beta/rc tags
version = '23.7.1'
release = '23.7.1'
version = '23.10.1'
release = '23.10.1'


# -- General configuration ---------------------------------------------------
Expand Down Expand Up @@ -49,4 +49,3 @@
html_static_path = ['_static']
html_logo = "_static/nokia-logo-blue-2023.png"
html_favicon = '_static/favicon.png'

1 change: 0 additions & 1 deletion docs/source/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,6 @@ User-ordered lists are therefore represented as ordered dictionaries in Python.
.. Reviewed by PLM 20221012
.. _pysros-examples-connecting-to-md-interfaces:

Connecting to the SR OS model-driven interface
Expand Down
8 changes: 8 additions & 0 deletions docs/source/features/22.10.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Release 22.10
*************

22.10.6
#######

* Minimum supported Python 3 version now 3.10

.. Reviewed by PLM 20230801
22.10.5
#######

Expand Down
6 changes: 6 additions & 0 deletions docs/source/features/23.07.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
Release 23.7
************

23.7.2
######

* No additional features


23.7.1
######

Expand Down
20 changes: 20 additions & 0 deletions docs/source/features/23.10.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Release 23.10
*************

23.10.1
#######

* Introduction of YANG annotation (metadata) handling for
:py:meth:`pysros.management.Datastore.get`, :py:meth:`pysros.management.Datastore.set`
and :py:meth:`pysros.management.Connection.convert`

* Introduction of the :py:class:`pysros.wrappers.Annotations` class
* Introduction of the :py:class:`pysros.wrappers.Annotation` class

* Change of the default method for :py:meth:`pysros.management.Datastore.set` from ``merge``
to ``default``. Due to the default operation of NETCONF on SR OS being ``merge`` this change
will not impact any currently implemented pySROS applications.




6 changes: 3 additions & 3 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ documentation will be updated accordingly.
.. list-table::
:header-rows: 0

* - pySROS release: 23.7.1
* - Document Number: 3HE 19211 AAAD TQZZA
* - pySROS release: 23.10.1
* - Document Number: 3HE 19211 AAAF TQZZA

.. todo: Change release numbers for new branch
.. Reviewed by PLM 20220621
.. Reviewed by TechComms 20230621
.. Reviewed by TechComms 20220624
.. toctree::
Expand Down
32 changes: 32 additions & 0 deletions docs/source/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,38 @@ Example:
.. Reviewed by TechComms 20221012
Annotations and metadata
************************

Annotations and metadata are terms often used interchangeably for additional supporting information
applied to a node in a YANG tree without being included as part of the actual value of that node and
without the need to create a new node to contain the information.

Annotations are defined in YANG and fall into two broad categories:

* **User defined annotations**

Supporting information provided and consumed by the user of pySROS attached to a YANG
node. An example is a configuration comment applied to a node in an SR OS configuration
using the MD-CLI ``annotate`` command.

* **System or protocol defined annotations**

Defined in a specification for a specific purpose only. These may be added, removed, or edited by a user
but they have very specific meanings and perform very specific functions in a protocol. An example is the ``operation`` attribute of an XML document used with NETCONF when manipulating user-ordered
lists.

Annotations (metadata) are defined in `RFC 7952 <https://www.rfc-editor.org/rfc/rfc7952>`_ and are
supported in XML and JSON (IETF) encodings.

Annotations in pySROS are similar to the :py:class:`pysros.wrappers.Schema` class but, unlike the
:py:class:`pysros.wrappers.Schema` class, the :py:class:`pysros.wrappers.Annotations` is writable.

See the :py:class:`pysros.wrappers.Annotations` class for more details.

.. Reviewed by PLM 20231003
.. Reviewed by TechComms 20231009
Getting Started
###############

Expand Down
154 changes: 154 additions & 0 deletions examples/annotations_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#!/usr/bin/env python3

### annotations_example.py
# Copyright 2023 Nokia
###

"""Example showing manipulation of Annotations and Annotation classes."""

from pysros.wrappers import Annotation, Annotations, Leaf


def usage(command_name=None):
"""Return the usage information."""
usage_string = (
"Usage: %s username@host[:port]\n\nport is optional and will default to 830" # pylint: disable=consider-using-f-string
% command_name
)
return usage_string


def demo_index_functions(myleaf, one):
"""Demonstrates the use of index and index_annotation methods."""
print("\n---- INDEX FUNCTIONS ----\n")
print(
"The index method takes an input and returns the location of the match. This function "
"must match exactly and completely, meaning in the case of annotation one "
"the full one object must be used on input:",
one,
)
print("")
print(
"Running index on the one annotation myleaf.annotations.index(one) or "
"myleaf.annotations.index(Annotation(key='key1', data='value1')) provides the location"
"of this annotation in the list of annotations:",
myleaf.annotations.index(one),
)
print("")
print(
"The index_annotation method also returns the location of the annotation in the list, "
"however this method accepts any combination the elements of the annotation: "
"myleaf.annotations.index_annotation('key1'):",
myleaf.annotations.index_annotation("key1"),
)


def demo_get_functions(myleaf, one):
"""Demonstrates the use of get and get_annotation methods."""
print("\n---- GET FUNCTIONS ----\n")
print(
"The get method takes an input and returns the annotation instance of the match. This function "
"must match exactly and completely, meaning in the case of annotation one "
"the full one object must be used on input:",
one,
)
print("")
print(
"Running get on the one annotation myleaf.annotations.get(one) or "
"myleaf.annotations.get(Annotation(key='key1', data='value1')) provides the annotation"
"instance of this annotation:",
myleaf.annotations.get(one),
)
print("")
print(
"The get_annotation method also returns the annotation instance of the match, "
"however this method accepts any combination the elements of the annotation: "
"myleaf.annotations.get_annotation('key1'):",
myleaf.annotations.get_annotation("key1"),
)


def demo_remove_functions(myleaf, one):
"""Demonstrates the use of remove and remove_annotation methods."""
print("\n---- REMOVE FUNCTIONS ----\n")
print(
"The remove method takes an input and removes the matching annotation instance from the list. "
"This function must match exactly and completely, meaning in the case of annotation one "
"the full one object must be used on input:",
one,
)
print("")
print(
"Running remove on the one annotation myleaf.annotations.delete(one) or "
"myleaf.annotations.delete(Annotation(key='key1', data='value1')) removes the annotation"
"instance from the list."
)
myleaf.annotations.remove(one)
print("The contents of the list is now:", myleaf.annotations)
print("")
print(
"The remove_annotation method also remoevs the annotation instance of the match, "
"however this method accepts any combination the elements of the annotation: "
"myleaf.annotations.remove_annotation('key2')."
)
myleaf.annotations.remove_annotation("key2")
print("The contents of the list is now:", myleaf.annotations)


def demo_annotations():
"""Demonstrate the use of Annotation and Annotations classes in pySROS."""
print(
"This demonstration is not designed to configure the router with any of these "
"annotations or to validate any of the input against any YANG schema. "
"It is designed to demonstrate the data structures and the methods "
"available to manipulate annotations."
)
print("\n---- INTRODUCTION ----\n")
myleaf = Leaf("Example")
print("Consider this leaf (called myleaf):", repr(myleaf))
print("")
print(
"The annotations (YANG metadata) assigned to the leaf can be seen by issuing myleaf.annotations:",
myleaf.annotations,
)
print("")
print("Let's create two annotations to attach to this leaf:")
print(" one = Annotation('key1', 'value1')")
print(" two = Annotation('key2', 'value2')")
one = Annotation("key1", "value1")
two = Annotation("key2", "value2")
print("")
print("Assign these annotations to the leaf:")
print(" myleaf.annotations = Annotations([one, two])")
myleaf.annotations = Annotations([one, two])
print("")
print(
"Looking again at the annotations on the leaf using myleaf.annotations:",
myleaf.annotations,
)
print("")
print(
"The annotations attached to the leaf are treated as a list and therefore in addition to "
"simply setting the values as above, standard list functions such as append also work:"
)
print(" three = Annotation('key3','value3')")
three = Annotation("key3", "value3")
print(" myleaf.annotations.append(three)")
myleaf.annotations.append(three)
print("")
print(
"Looking again at the annotations on the leaf using myleaf.annotations:",
myleaf.annotations,
)
demo_index_functions(myleaf, one)
demo_get_functions(myleaf, one)
demo_remove_functions(myleaf, one)


def main():
"""Program starts from here."""
demo_annotations()


if __name__ == "__main__":
main()
26 changes: 21 additions & 5 deletions pysros/errors.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Copyright 2021-2023 Nokia

from .exceptions import *
from .exceptions import make_exception
from .exceptions import (ActionTerminatedIncompleteError, InternalError,
InvalidPathError, JsonDecodeError,
ModelProcessingError, SrosConfigConflictError,
SrosMgmtError, XmlDecodeError, make_exception)

__doc__ = """This module contains error definitions for pySROS.
Expand Down Expand Up @@ -31,7 +33,6 @@
pysros_err_convert_root_not_support_pysros = (SrosMgmtError, "'pysros' format is not supported for root")
pysros_err_convert_wrong_payload_type = (TypeError, "Invalid payload type for convert")
pysros_err_could_not_create_conn = (RuntimeError, "Cannot create connection - {reason}")
pysros_err_data_missing = (SrosMgmtError, "Entry does not exist")
pysros_err_depth_must_be_positive = (ValueError, "Depth must be > 0")
pysros_err_duplicate_found = (SrosMgmtError, "Entry cannot contain duplicates - {duplicate}")
pysros_err_empty_path = (InvalidPathError, "Empty path")
Expand All @@ -50,6 +51,7 @@
pysros_err_invalid_identifier = (InvalidPathError, "Invalid identifier")
pysros_err_invalid_json_structure = (ValueError, "Invalid JSON structure")
pysros_err_invalid_key_in_path = (SrosMgmtError, "Invalid key value in path")
pysros_err_invalid_annotation_type = (SrosMgmtError, "Invalid annotation value type")
pysros_err_invalid_module_set_id_or_content_id = (RuntimeError, "Invalid module-set-id")
pysros_err_invalid_operation_on_key = (InvalidPathError, "Operation cannot be performed on key")
pysros_err_invalid_operation_on_leaflist = (InvalidPathError, "Operation cannot be performed on leaflist")
Expand All @@ -68,15 +70,13 @@
pysros_err_malformed_xml = (ValueError, "Malformed XML")
pysros_err_missing_keys = (InvalidPathError, "Missing keys on element '{element}'")
pysros_err_multiple_occurences_of_entry = (SrosMgmtError, "Multiple occurrences of list entry")
pysros_err_multiple_occurences_of_node = (SrosMgmtError, "Multiple occurrences of node")
pysros_err_no_data_found = (LookupError, "No data found")
pysros_err_not_connected = (RuntimeError, "Not connected")
pysros_err_not_found_slash_before_name = (InvalidPathError, "'/' not found before element name")
pysros_err_path_should_be_string = (TypeError, "path argument should be a string")
pysros_err_prefix_does_not_have_ns = (LookupError, "prefix '{prefix}' of '{name}' does not have corresponding namespace")
pysros_err_root_path = (InvalidPathError, "Operation cannot be performed on root")
pysros_err_target_should_be_list = (InvalidPathError, "Target should be a list")
pysros_err_type_must_be = (TypeError, "must be {expected:.50s}, not {actual:.50s}")
pysros_err_unended_quoted_string = (InvalidPathError, "Unended quoted string")
pysros_err_unexpected_change_of_path_ctx = (ModelProcessingError, "Unexpected change of path ctx")
pysros_err_unexpected_end_of_yang = (ModelProcessingError, "Unexpected end of YANG")
Expand Down Expand Up @@ -105,3 +105,19 @@
pysros_err_wrong_json_root = (JsonDecodeError, "JSON root must be object")
pysros_err_wrong_netconf_response = (SrosMgmtError, "Wrong NETCONF response")
pysros_err_wrong_rhs = (ModelProcessingError, "Invalid argument to the right of the plus symbol")
pysros_err_unknown_attribute = (SrosMgmtError, "Unknown attribute '{name}'")
pysros_err_multiple_occurences_of_xml_attribute = (SrosMgmtError, "Multiple occurrences of xml attribute")
pysros_err_multiple_occurences_of_node = (SrosMgmtError, "Multiple occurrences of node")
pysros_err_multiple_occurences_of_annotation = (SrosMgmtError, "Multiple occurrences of annotation")
pysros_err_annotation_incorrect_value = (SrosMgmtError, "Invalid value for annotation '{name}'")
pysros_err_annotation_not_found = (ValueError, "Annotation not found")
pysros_err_annotation_too_many_instances = (ValueError, "Too many annotations match the criteria")
pysros_err_annotation_without_value = (SrosMgmtError, "Missing value for '{child_name}' in path '{path}', but metadata set")
pysros_err_annotation_type_key = (TypeError, """Annotation argument "key" must be a string""")
pysros_err_annotation_invalid_type = (TypeError, "Invalid type of argument annotations_only")
pysros_err_annotation_invalid = (TypeError, "Cannot find annotation")
pysros_err_annotation_cannot_delete = (TypeError, "Cannot delete annotation")
pysros_err_annotation_invalid_key = (SrosMgmtError, "Invalid annotation key")
pysros_err_too_many_leaflist_annotations = (SrosMgmtError, "Too many annotations in leaflist")
pysros_err_expected_type_but_got_another = (TypeError, "expected {expected} object but got {type_name}")
pysros_err_annotation_invalid_module = (SrosMgmtError, "Invalid annotation module")
Loading

0 comments on commit 7b8e404

Please sign in to comment.