55from collections .abc import Callable , Iterable , Iterator , Mapping , Sequence
66from importlib import import_module
77from itertools import chain , count
8- from typing import TYPE_CHECKING , Any , ClassVar , cast
8+ from typing import TYPE_CHECKING , Any , ClassVar , TypeVar , cast
99
1010from lxml import etree
1111from lxml .etree import QName
1212
1313import sdmx .urn
1414from sdmx import message
1515from sdmx .exceptions import XMLParseError # noqa: F401
16- from sdmx .format import Version , list_media_types
16+ from sdmx .format import Version as FormatVersion
17+ from sdmx .format import list_media_types
1718from sdmx .model import common
19+ from sdmx .model .version import Version
1820from sdmx .reader .base import BaseReader
1921
2022if TYPE_CHECKING :
2123 import types
2224
25+ AA = TypeVar ("AA" , bound = common .AnnotableArtefact )
26+ IA = TypeVar ("IA" , bound = common .IdentifiableArtefact )
27+ NA = TypeVar ("NA" , bound = common .NameableArtefact )
28+ MA = TypeVar ("MA" , bound = common .MaintainableArtefact )
29+
2330# Sentinel value for a missing Agency
2431_NO_AGENCY = common .Agency ()
2532
@@ -50,7 +57,9 @@ class BaseReference:
5057 "version" ,
5158 )
5259
53- def __init__ (self , reader , elem , cls_hint = None ):
60+ def __init__ (
61+ self , reader : "XMLEventReader" , elem , cls_hint : type | None = None
62+ ) -> None :
5463 parent_tag = elem .tag
5564
5665 info = self .info_from_element (elem )
@@ -93,7 +102,7 @@ def __init__(self, reader, elem, cls_hint=None):
93102 @abstractmethod
94103 def info_from_element (cls , elem ) -> dict [str , Any ]: ...
95104
96- def __str__ (self ):
105+ def __str__ (self ) -> str :
97106 # NB for debugging only
98107 return ( # pragma: no cover
99108 f"{ self .cls .__name__ } ={ self .agency .id } :{ self .id } ({ self .version } ) → "
@@ -108,7 +117,7 @@ class XMLEventReader(BaseReader):
108117 suffixes = [".xml" ]
109118
110119 #: SDMX-ML version handled by this reader.
111- xml_version : ClassVar [Version ]
120+ xml_version : ClassVar [FormatVersion ]
112121
113122 #: Reference to the module defining the format read.
114123 format : ClassVar ["types.ModuleType" ]
@@ -129,7 +138,9 @@ def __init_subclass__(cls: type["XMLEventReader"]):
129138 # Empty dictionary
130139 cls .parser = {}
131140
132- name = {Version ["2.1" ]: "v21" , Version ["3.0.0" ]: "v30" }[cls .xml_version ]
141+ name = {FormatVersion ["2.1" ]: "v21" , FormatVersion ["3.0.0" ]: "v30" }[
142+ cls .xml_version
143+ ]
133144 cls .format = import_module (f"sdmx.format.xml.{ name } " )
134145 cls .model = import_module (f"sdmx.model.{ name } " )
135146 cls .media_types = list_media_types (base = "xml" , version = cls .xml_version )
@@ -306,7 +317,7 @@ def _dump(self): # pragma: no cover
306317 )
307318 print ("\n Ignore:\n " , self .ignore )
308319
309- def push (self , stack_or_obj , obj = None ):
320+ def push (self , stack_or_obj , obj = None ) -> None :
310321 """Push an object onto a stack."""
311322 if stack_or_obj is None :
312323 return
@@ -335,11 +346,11 @@ def push(self, stack_or_obj, obj=None):
335346
336347 self .stack [s ][id ] = obj
337348
338- def stash (self , * stacks , name : str = "_stash" ):
349+ def stash (self , * stacks , name : str = "_stash" ) -> None :
339350 """Temporarily hide all objects in the given `stacks`."""
340351 self .push (name , {s : self .stack .pop (s , dict ()) for s in stacks })
341352
342- def unstash (self , name : str = "_stash" ):
353+ def unstash (self , name : str = "_stash" ) -> None :
343354 """Restore the objects hidden by the last :meth:`stash` call to their stacks.
344355
345356 Calls to :meth:`.stash` and :meth:`.unstash` should be matched 1-to-1; if the
@@ -361,7 +372,7 @@ def get_single(
361372 self ,
362373 cls_or_name : type | str ,
363374 id : str | None = None ,
364- version : str | None = None ,
375+ version : str | Version | None = None ,
365376 subclass : bool = False ,
366377 ) -> Any | None :
367378 """Return a reference to an object while leaving it in its stack.
@@ -475,7 +486,9 @@ def resolve(self, ref):
475486 return parent .get_hierarchical (ref .target_id )
476487 raise # pragma: no cover
477488
478- def annotable (self , cls , elem , ** kwargs ):
489+ AA = TypeVar ("AA" , bound = common .AnnotableArtefact )
490+
491+ def annotable (self , cls : type ["AA" ], elem , ** kwargs ) -> "AA" :
479492 """Create a AnnotableArtefact of `cls` from `elem` and `kwargs`.
480493
481494 Collects all parsed <com:Annotation>.
@@ -485,12 +498,12 @@ def annotable(self, cls, elem, **kwargs):
485498 kwargs ["annotations" ].extend (self .pop_all (self .model .Annotation ))
486499 return cls (** kwargs )
487500
488- def identifiable (self , cls , elem , ** kwargs ):
501+ def identifiable (self , cls : type [ "IA" ] , elem , ** kwargs ) -> "IA" :
489502 """Create a IdentifiableArtefact of `cls` from `elem` and `kwargs`."""
490503 setdefault_attrib (kwargs , elem , "id" , "urn" , "uri" )
491504 return self .annotable (cls , elem , ** kwargs )
492505
493- def nameable (self , cls , elem , ** kwargs ):
506+ def nameable (self , cls : type [ "NA" ] , elem , ** kwargs ) -> "NA" :
494507 """Create a NameableArtefact of `cls` from `elem` and `kwargs`.
495508
496509 Collects all parsed :class:`.InternationalString` localizations of <com:Name>
@@ -502,7 +515,7 @@ def nameable(self, cls, elem, **kwargs):
502515 add_localizations (obj .description , self .pop_all ("Description" ))
503516 return obj
504517
505- def maintainable (self , cls , elem , ** kwargs ):
518+ def maintainable (self , cls : type [ "MA" ] , elem , ** kwargs ) -> "MA" :
506519 """Create or retrieve a MaintainableArtefact of `cls` from `elem` and `kwargs`.
507520
508521 Following the SDMX-IM class hierarchy, :meth:`maintainable` calls
@@ -578,7 +591,7 @@ def maintainable(self, cls, elem, **kwargs):
578591 return obj
579592
580593
581- def add_localizations (target : common .InternationalString , values : list ) -> None :
594+ def add_localizations (target : common .InternationalString , values : Sequence ) -> None :
582595 """Add localized strings from *values* to *target*."""
583596 target .localizations .update ({locale : label for locale , label in values })
584597
0 commit comments