From 3608106f7661182afdcb21b193f4d326b570bf01 Mon Sep 17 00:00:00 2001 From: Davide Brunato Date: Sun, 24 Mar 2024 22:05:14 +0100 Subject: [PATCH] Update docs and bump minor release - Clean facets module --- CHANGELOG.rst | 6 +++++ doc/api.rst | 1 + doc/conf.py | 4 ++-- doc/features.rst | 2 +- doc/usage.rst | 14 ++++++++++++ publiccode.yml | 4 ++-- setup.py | 2 +- xmlschema/__init__.py | 2 +- xmlschema/validators/facets.py | 40 +++++++++++++++++----------------- 9 files changed, 48 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 03f64648..bae0dc33 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ CHANGELOG ********* +`v3.2.0`_ (2024-03-25) +====================== +* Add *download_schemas()* to package API (#387) +* Fix issue with facets on list types (#396) + `v3.1.0`_ (2024-03-13) ====================== * Add GData converter (issue #388/PR #391) @@ -679,3 +684,4 @@ v0.9.6 (2017-05-05) .. _v3.0.1: https://github.com/brunato/xmlschema/compare/v3.0.0...v3.0.1 .. _v3.0.2: https://github.com/brunato/xmlschema/compare/v3.0.1...v3.0.2 .. _v3.1.0: https://github.com/brunato/xmlschema/compare/v3.0.2...v3.1.0 +.. _v3.2.0: https://github.com/brunato/xmlschema/compare/v3.1.0...v3.2.0 diff --git a/doc/api.rst b/doc/api.rst index 98cca8fe..36653839 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -193,6 +193,7 @@ XML resources API .. autofunction:: xmlschema.fetch_resource .. autofunction:: xmlschema.fetch_schema_locations .. autofunction:: xmlschema.fetch_schema +.. autofunction:: xmlschema.download_schemas .. autoclass:: xmlschema.XMLResource diff --git a/doc/conf.py b/doc/conf.py index b3397725..a904cf53 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -79,9 +79,9 @@ # built documents. # # The short X.Y version. -version = '3.1' +version = '3.2' # The full version, including alpha/beta/rc tags. -release = '3.1.0' +release = '3.2.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/features.rst b/doc/features.rst index f9e7cf5d..b6617e32 100644 --- a/doc/features.rst +++ b/doc/features.rst @@ -10,7 +10,7 @@ alternative classes or module parameters. XSD 1.0 and 1.1 support ======================= -From release v1.0.14 XSD 1.1 support has been added to the library through the class +Since release v1.0.14 XSD 1.1 support has been added to the library through the class :class:`xmlschema.XMLSchema11`. You have to use this class for XSD 1.1 schemas instead the default class :class:`xmlschema.XMLSchema`, that is linked to XSD 1.0 validator :class:`xmlschema.XMLSchema10`. diff --git a/doc/usage.rst b/doc/usage.rst index 1ad13957..215ccc82 100644 --- a/doc/usage.rst +++ b/doc/usage.rst @@ -131,6 +131,9 @@ Sometimes, it is advantageous to validate XML files using an XSD schema located at a remote location while also having the option to store the same schema locally for offline use. +The first option is to build a schema and then export the XSD sources to a local +directory: + .. code-block:: py import xmlschema @@ -157,6 +160,17 @@ becomes +The alternative option is to download the XSD resources directly: + +.. code-block:: py + + from xmlschema import download_schemas + download_schemas("https://www.omg.org/spec/ReqIF/20110401/reqif.xsd", target='my_schemas') + +For default the original XSD schemas are not changed and a location map is returned. This map +is also written to a LOCATION_MAP dictionary in the target directory as the module `__init__.py`, +so can be used after as *uri_mapper* argument for building the schema instance. + .. note:: Since release v2.5.0 the ``schemaLocation`` attributes are rewritten with diff --git a/publiccode.yml b/publiccode.yml index 7a0dd194..a2c4d38a 100644 --- a/publiccode.yml +++ b/publiccode.yml @@ -6,8 +6,8 @@ publiccodeYmlVersion: '0.2' name: xmlschema url: 'https://github.com/sissaschool/xmlschema' landingURL: 'https://github.com/sissaschool/xmlschema' -releaseDate: '2024-03-13' -softwareVersion: v3.1.0 +releaseDate: '2024-03-25' +softwareVersion: v3.2.0 developmentStatus: stable platforms: - linux diff --git a/setup.py b/setup.py index 6c7b27c9..eef900e3 100755 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ setup( name='xmlschema', - version='3.1.0', + version='3.2.0', packages=find_packages(include=['xmlschema*']), package_data={ 'xmlschema': ['py.typed', 'locale/**/*.mo', 'locale/**/*.po', 'schemas/*/*.xsd'], diff --git a/xmlschema/__init__.py b/xmlschema/__init__.py index 805e6170..d22a9ed4 100644 --- a/xmlschema/__init__.py +++ b/xmlschema/__init__.py @@ -33,7 +33,7 @@ XMLSchema, XMLSchema10, XMLSchema11, XsdComponent, XsdType, XsdElement, XsdAttribute ) -__version__ = '3.1.0' +__version__ = '3.2.0' __author__ = "Davide Brunato" __contact__ = "brunato@sissa.it" __copyright__ = "Copyright 2016-2024, SISSA" diff --git a/xmlschema/validators/facets.py b/xmlschema/validators/facets.py index 3f13d2bd..73b98214 100644 --- a/xmlschema/validators/facets.py +++ b/xmlschema/validators/facets.py @@ -14,8 +14,8 @@ import math import operator from abc import abstractmethod -from typing import TYPE_CHECKING, cast, Any, List, Optional, Pattern, Union, \ - MutableSequence, overload, Tuple, Type, Dict +from typing import TYPE_CHECKING, cast, overload, Any, Dict, List, \ + MutableSequence, Optional, Pattern, Union, Tuple, Type from xml.etree.ElementTree import Element from elementpath import XPathContext, ElementPathError, \ @@ -54,6 +54,7 @@ def __init__(self, elem: ElementType, parent: Union['XsdList', 'XsdAtomicRestriction'], base_type: Optional[BaseXsdType]) -> None: self.base_type = base_type + self._validator = self._skip_validation super(XsdFacet, self).__init__(elem, schema, parent) def __repr__(self) -> str: @@ -66,8 +67,7 @@ def __call__(self, value: Any) -> None: reason = _("invalid type {!r} provided").format(type(value)) raise XMLSchemaValidationError(self, value, reason) from None - @staticmethod - def _validator(_: Any) -> None: + def _skip_validation(self, value: Any) -> None: return def _parse(self) -> None: @@ -102,16 +102,16 @@ def base_facet(self) -> Optional['XsdFacet']: """ base_type: Optional[BaseXsdType] = self.base_type tag = self.elem.tag - while True: - if base_type is None: - return None + while base_type is not None: try: base_facet = base_type.facets[tag] # type: ignore[union-attr] except (AttributeError, KeyError): base_type = base_type.base_type else: - assert isinstance(base_facet, self.__class__) + assert isinstance(base_facet, XsdFacet) return base_facet + else: + return None class XsdWhiteSpaceFacet(XsdFacet): @@ -132,11 +132,11 @@ class XsdWhiteSpaceFacet(XsdFacet): def _parse_value(self, elem: ElementType) -> None: self.value = elem.attrib['value'] if self.value == 'collapse': - self._validator = self.collapse_white_space_validator # type: ignore[assignment] + self._validator = self.collapse_white_space_validator elif self.value == 'replace': if self.base_value == 'collapse': self.parse_error(_("facet value can be only 'collapse'")) - self._validator = self.replace_white_space_validator # type: ignore[assignment] + self._validator = self.replace_white_space_validator elif self.base_value == 'collapse': self.parse_error(_("facet value can be only 'collapse'")) elif self.base_value == 'replace': @@ -181,9 +181,9 @@ def _parse_value(self, elem: ElementType) -> None: primitive_type = getattr(self.base_type, 'primitive_type', None) if primitive_type is None or primitive_type.name not in {XSD_QNAME, XSD_NOTATION_TYPE}: # See: https://www.w3.org/Bugs/Public/show_bug.cgi?id=4009 - self._validator = self._length_validator # type: ignore[assignment] + self._validator = self.length_validator - def _length_validator(self, value: Any) -> None: + def length_validator(self, value: Any) -> None: if len(value) != self.value: reason = _("length has to be {!r}").format(self.value) raise XMLSchemaValidationError(self, value, reason) @@ -215,9 +215,9 @@ def _parse_value(self, elem: ElementType) -> None: primitive_type = getattr(self.base_type, 'primitive_type', None) if primitive_type is None or primitive_type.name not in {XSD_QNAME, XSD_NOTATION_TYPE}: # See: https://www.w3.org/Bugs/Public/show_bug.cgi?id=4009 - self._validator = self._min_length_validator # type: ignore[assignment] + self._validator = self.min_length_validator - def _min_length_validator(self, value: Any) -> None: + def min_length_validator(self, value: Any) -> None: if len(value) < self.value: reason = _("value length cannot be lesser than {!r}").format(self.value) raise XMLSchemaValidationError(self, value, reason) @@ -249,9 +249,9 @@ def _parse_value(self, elem: ElementType) -> None: primitive_type = getattr(self.base_type, 'primitive_type', None) if primitive_type is None or primitive_type.name not in {XSD_QNAME, XSD_NOTATION_TYPE}: # See: https://www.w3.org/Bugs/Public/show_bug.cgi?id=4009 - self._validator = self._max_length_validator # type: ignore[assignment] + self._validator = self.max_length_validator - def _max_length_validator(self, value: Any) -> None: + def max_length_validator(self, value: Any) -> None: if len(value) > self.value: reason = _("value length cannot be greater than {!r}").format(self.value) raise XMLSchemaValidationError(self, value, reason) @@ -509,9 +509,9 @@ class XsdExplicitTimezoneFacet(XsdFacet): def _parse_value(self, elem: ElementType) -> None: self.value = elem.attrib['value'] if self.value == 'prohibited': - self._validator = self._prohibited_timezone_validator # type: ignore[assignment] + self._validator = self.prohibited_timezone_validator elif self.value == 'required': - self._validator = self._required_timezone_validator # type: ignore[assignment] + self._validator = self.required_timezone_validator elif self.value != 'optional': self.value = 'optional' # Error already detected by meta-schema validation @@ -520,12 +520,12 @@ def _parse_value(self, elem: ElementType) -> None: msg = _("invalid restriction from {!r}") self.parse_error(msg.format(facet.value)) - def _required_timezone_validator(self, value: Any) -> None: + def required_timezone_validator(self, value: Any) -> None: if value.tzinfo is None: reason = _("time zone required for value {!r}").format(self.value) raise XMLSchemaValidationError(self, value, reason) - def _prohibited_timezone_validator(self, value: Any) -> None: + def prohibited_timezone_validator(self, value: Any) -> None: if value.tzinfo is not None: reason = _("time zone prohibited for value {!r}").format(self.value) raise XMLSchemaValidationError(self, value, reason)