diff --git a/.readthedocs.yml b/.readthedocs.yml index b8e28180e..5cacfdd19 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,7 +1,7 @@ version: 2 python: - version: 3.7 + version: "3" install: - method: pip path: . diff --git a/doc/implementation.rst b/doc/implementation.rst index 0cbacda6c..18c611963 100644 --- a/doc/implementation.rst +++ b/doc/implementation.rst @@ -53,7 +53,6 @@ For example, every :class:`.Code` is a ``NameableArtefact``; [1]_ this means it - has a list of :attr:`~.AnnotableArtefact.annotations` :class:`.IdentifiableArtefact` - - has an :attr:`id <.IdentifiableArtefact.id>`, :attr:`URI <.IdentifiableArtefact.uri>`, and :attr:`URN <.IdentifiableArtefact.urn>`. - is “annotable”; this means it *also* has the `annotations` attribute of an AnnotableArtefact. @@ -61,30 +60,24 @@ For example, every :class:`.Code` is a ``NameableArtefact``; [1]_ this means it The URI and URN are *globally* unique. See `Wikipedia `_ for a discussion of the differences between the two. :class:`.NameableArtefact` - - - has a :attr:`name <.NameableArtefact.name>` and :attr:`description <.NameableArtefact.description>`, and - - is identifiable, therefore *also* annotable. + - has a :attr:`name <.NameableArtefact.name>` and :attr:`description <.NameableArtefact.description>`, and + - is identifiable, therefore *also* annotable. :class:`.VersionableArtefact` - - - has a :attr:`version <.VersionableArtefact.version>` number, - - may be valid between certain times (:attr:`valid_from <.VersionableArtefact.valid_from>`, :attr:`valid_to <.VersionableArtefact.valid_to>`), and - - is nameable, identifiable, *and* annotable. + - has a :attr:`version <.VersionableArtefact.version>` number, + - may be valid between certain times (:attr:`valid_from <.VersionableArtefact.valid_from>`, :attr:`valid_to <.VersionableArtefact.valid_to>`), and + - is nameable, identifiable, *and* annotable. :class:`.MaintainableArtefact` + - is under the authority of a particular :attr:`maintainer <.MaintainableArtefact.maintainer>`, and + - is versionable, nameable, identifiable, and annotable. - - is under the authority of a particular :attr:`maintainer <.MaintainableArtefact.maintainer>`, and - - is versionable, nameable, identifiable, and annotable. - - In an SDMX message, a maintainable object might not be given in full; only as a reference (with :attr:`is_external_reference <.MaintainableArtefact.is_external_reference>` set to :obj:`True`). - If so, it might have a :attr:`structure_url <.MaintainableArtefact.structure_url>`, where the maintainer provides more information about the object. - + In an SDMX message, a maintainable object might not be given in full; only as a reference (with :attr:`is_external_reference <.MaintainableArtefact.is_external_reference>` set to :obj:`True`). + If so, it might have a :attr:`structure_url <.MaintainableArtefact.structure_url>`, where the maintainer provides more information about the object. The API reference for :mod:`sdmx.model` shows the parent classes for each class, to describe whether they are versionable, nameable, identifiable, and/or maintainable. -Because SDMX is used worldwide, an :class:`.InternationalString` type is used in -the IM—for instance, the `name` of a Nameable object is an -``InternationalString``, with zero or more :attr:`localizations <.InternationalString.localizations>` in different locales. +Because SDMX is used worldwide, an :class:`.InternationalString` type is used in the IM—for instance, the `name` of a Nameable object is an InternationalString, with zero or more :attr:`localizations <.InternationalString.localizations>` in different locales. .. [1] Indirectly, through :class:`Item`. @@ -102,15 +95,14 @@ Data ==== :class:`.Observation` + A single data point/datum. - A single data point/datum. - The value is stored as the :attr:`~.Observation.value` attribute. + The value is stored as the :attr:`~.Observation.value` attribute. :class:`.DataSet` + A collection of Observations, SeriesKeys, and/or GroupKeys. - A collection of Observations, SeriesKeys, and/or GroupKeys. - - .. note:: **There are no 'Series' or 'Group' classes** in the IM! + .. note:: **There are no 'Series' or 'Group' classes** in the IM! Instead, the *idea* of 'data series' within a DataSet is modeled as: @@ -137,13 +129,13 @@ Data :class:`.SeriesKey` The dimension(s) shared by all Observations in a conceptual series. - :class:`.GroupKey`. + :class:`.GroupKey` The dimension(s) comprising the group. These may be a subset of all the dimensions in the DataSet, in which case all matching Observations are considered part of the 'group'—even if they are associated with different SeriesKeys. GroupKeys are often used to attach AttributeValues; see below. -:class:`AttributeValue` +:class:`.AttributeValue` Value (:attr:`.AttributeValue.value`) for a DataAttribute (:attr:`.AttributeValue.value_for`). May be attached to any of: DataSet, SeriesKey, GroupKey, or Observation. @@ -243,7 +235,7 @@ SDMX-CSV Reference: https://github.com/sdmx-twg/sdmx-csv - :mod:`sdmx` **does not** currently support SDMX-CSV. + :mod:`sdmx` **does not** currently support SDMX-CSV; see :issue:`34`, :issue:`36`. :mod:`sdmx`: diff --git a/doc/whatsnew.rst b/doc/whatsnew.rst index d93cfdfb7..a3b0a9a42 100644 --- a/doc/whatsnew.rst +++ b/doc/whatsnew.rst @@ -14,7 +14,7 @@ Next release Migration notes --------------- -Code such as the following will emit a :class:`DeprecationWarning`: +In order to prepare for future support of SDMX 3.0, code such as the following will emit a :class:`DeprecationWarning`: .. code-block:: python @@ -44,6 +44,7 @@ All changes - :attr:`.xml.Reader.media_types` and :attr:`.json.Reader.media_types` explicitly indicated supported media types. - :attr:`.ItemScheme.is_partial` defaults to :data:`None`. - Add empty/stub :mod:`.format.csv`, :mod:`.reader.csv` (cf. :issue:`34`), and :mod:`.model.v30`. +- Improve readability in :doc:`implementation` (:pull:`121`). v2.7.1 (2023-03-09) =================== diff --git a/pyproject.toml b/pyproject.toml index f47d5ce2c..1c289b3d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ dependencies = [ cache = ["requests-cache"] docs = [ "IPython", - "sphinx >=4,<6", + "sphinx >=4", "sphinx-book-theme", ] tests = [ diff --git a/sdmx/model/common.py b/sdmx/model/common.py index 965323239..26cbaff0b 100644 --- a/sdmx/model/common.py +++ b/sdmx/model/common.py @@ -60,7 +60,7 @@ def __init__(self, *, text: _TInternationalStringInit = None, **kwargs): class AnnotableArtefact(BaseModel): #: :class:`Annotations <.Annotation>` of the object. #: - #: :mod:`pandaSDMX` implementation: The IM does not specify the name of this + #: :mod:`.sdmx` implementation detail: The IM does not specify the name of this #: feature. annotations: List[Annotation] = [] @@ -425,7 +425,7 @@ class ItemScheme(MaintainableArtefact, Generic[IT]): :attr:`items` attribute, in which the keys are the :attr:`~.IdentifiableArtefact.id` of the Item. - Because this may change in future versions of pandaSDMX, user code should not access + Because this may change in future versions, user code should not access :attr:`items` directly. Instead, use the :func:`getattr` and indexing features of ItemScheme, or the public methods, to access and manipulate Items: diff --git a/sdmx/model/v21.py b/sdmx/model/v21.py index 05cfd8415..ae8b8c3a0 100644 --- a/sdmx/model/v21.py +++ b/sdmx/model/v21.py @@ -563,8 +563,8 @@ class DimensionRelationship(AttributeRelationship): class GroupRelationship(AttributeRelationship): - # 'Retained for compatibility reasons' in SDMX 2.1; not used by pandaSDMX. - #: + #: “Retained for compatibility reasons” in SDMX 2.1 versus 2.0; not used by + #: :mod:`sdmx`. group_key: Optional["GroupDimensionDescriptor"] = None diff --git a/sdmx/reader/xml.py b/sdmx/reader/xml.py index 3fe70e30b..975b61306 100644 --- a/sdmx/reader/xml.py +++ b/sdmx/reader/xml.py @@ -12,7 +12,18 @@ from copy import copy from itertools import chain, count, product from sys import maxsize -from typing import Any, Dict, Iterable, Mapping, Optional, Type, Union, cast +from typing import ( + Any, + Dict, + Iterable, + Iterator, + Mapping, + Optional, + Tuple, + Type, + Union, + cast, +) from dateutil.parser import isoparse from lxml import etree @@ -241,8 +252,13 @@ def read_message( try: # Use the etree event-driven parser - for event, element in etree.iterparse( # type: ignore [attr-defined] - source, events=("start", "end") + # NB (typing) iterparse() returns tuples. For "start" and "end", the second + # item is etree._Element, but for other events, e.g. "start-ns", it is + # not. types-lxml accurately reflects this. Narrow the type here for the + # following code. + for event, element in cast( + Iterator[Tuple[str, etree._Element]], + etree.iterparse(source, events=("start", "end")), ): try: # Retrieve the parsing function for this element & event