Skip to content

Commit 466d8e4

Browse files
Michael HallikMichael Hallik
authored andcommitted
refactor: simplify __init__ method of XmlValidator
1 parent aa99075 commit 466d8e4

File tree

2 files changed

+129
-90
lines changed

2 files changed

+129
-90
lines changed

Makefile

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
# Make constants.
2-
PYTHON_VERSION ?= 3.10
3-
VENV_HOME := /c/Python-virt-envs
4-
51
# Declare targets that don't represent actual files.
62
.PHONY: help lint type format unit robot check requirements keydoc
73

src/xmlvalidator/XmlValidator.py

Lines changed: 129 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@
4040
"""
4141

4242

43-
# pylint: disable=C0103:invalid-name # On account of the module name, that is not snake-cased (required by Robot Framework).
44-
# pylint: disable=C0302:too-many-lines # On account of the extensive docstrings and annotations.
45-
# pylint: disable=C0301:line-too-long # On account of tables in docstrings.
43+
# pylint: disable=C0103:invalid-name # On account of the module name, that is not snake-cased (required by Robot Framework).
44+
# pylint: disable=C0302:too-many-lines # On account of the extensive docstrings and annotations.
45+
# pylint: disable=C0301:line-too-long # On account of tables in docstrings.
4646

4747

4848
# Standard library imports.
@@ -82,19 +82,19 @@ class XmlValidator:
8282
The other keywords are convenience/helper functions, e.g. ``Reset
8383
Error Facets``.
8484
85-
The ``Validate Xml Files`` validates one or more XML files against one
86-
or more XSD schema files and collects and reports all encountered
87-
errors.
85+
The ``Validate Xml Files`` validates one or more XML files against
86+
one or more XSD schema files and collects and reports all
87+
encountered errors.
8888
8989
The type of error that the keyword can detect is not limited to XSD
9090
violations, but may also pertain to malformed XML files (e.g. parse
9191
errors), empty files, unmatched XML files (no XSD match found) and
9292
others.
9393
9494
Errors that result from malformed XML files or from XSD violations
95-
support detailed error reporting. Using the ``error_facets`` argument
96-
you may specify the details the keyword should collect and report
97-
about captured errors.
95+
support detailed error reporting. Using the ``error_facets``
96+
argument you may specify the details the keyword should collect and
97+
report about captured errors.
9898
9999
When operating in batch mode, the ``Validate Xml Files`` keyword
100100
always validates the entire set of passed XML files. That is, when
@@ -407,11 +407,11 @@ class XmlValidator:
407407
nr_instances = 0
408408

409409
def __init__(
410-
self,
411-
xsd_path: Optional[str | Path] = None,
412-
base_url: Optional[str] = None,
413-
error_facets: Optional[ List[str] ] = None
414-
) -> None:
410+
self,
411+
xsd_path: Optional[str|Path] = None,
412+
base_url: Optional[str] = None,
413+
error_facets: Optional[List[str]] = None
414+
) -> None:
415415
"""
416416
**Library Scope**
417417
@@ -549,41 +549,10 @@ def __init__(
549549
self.validator_utils = ValidatorUtils()
550550
self.validator_results = ValidatorResultRecorder()
551551
# Initialize the xsd schema from the xsd_path, if provided.
552-
if xsd_path:
553-
# Try to get a single xsd file from the provided xsd_path.
554-
xsd_file_path, is_single_xsd_file = (
555-
self.validator_utils.get_file_paths(
556-
xsd_path, 'xsd'
557-
)
558-
)
559-
# We need (a path to) a single xsd file.
560-
if not is_single_xsd_file:
561-
raise ValueError(f"Got multiple xsd files: {xsd_file_path}.")
562-
# Handle incorrect file extension.
563-
if xsd_file_path[0].suffix != '.xsd':
564-
# Raise a load error.
565-
raise SystemError(
566-
f"ValueError: {xsd_file_path[0]} is not an XSD file."
567-
)
568-
# Try to load the provided XSD file.
569-
result = self._load_schema(xsd_file_path[0], base_url )
570-
if result.success:
571-
# Set the loaded XSD file as default schema.
572-
self.schema = result.value
573-
logger.info(
574-
f"Schema '{self.schema.name}' set.", # type: ignore
575-
also_console=True)
576-
else:
577-
# Or report the load error.
578-
raise SystemError(f"Loading of schema failed: {result.error}")
579-
# Or inform the user on what to do.
580-
else:
581-
logger.info(
582-
"No XSD schema set: provide schema(s) during keyword calls.",
583-
also_console=True
584-
)
585-
# And flag the schema attr as None.
586-
self.schema = None
552+
self.schema = self._try_load_initial_schema(
553+
xsd_path=xsd_path,
554+
base_url=base_url
555+
)
587556
# Set the error facets to collect for failed XML validations.
588557
self.error_facets = error_facets if error_facets else [
589558
'path', 'reason'
@@ -597,14 +566,14 @@ def __init__(
597566
logger.info(f'Number of library instances: {self.nr_instances}.')
598567

599568
def _determine_validations(
600-
self,
601-
xml_paths: List[Path],
602-
xsd_path: Optional[str|Path] = None,
603-
xsd_search_strategy: Optional[
569+
self,
570+
xml_paths: List[Path],
571+
xsd_path: Optional[str|Path] = None,
572+
xsd_search_strategy: Optional[
604573
Literal['by_namespace', 'by_file_name']
605574
] = None,
606-
base_url: Optional[str] = None
607-
) -> Dict[Path, Path | None]:
575+
base_url: Optional[str] = None
576+
) -> Dict[Path, Path | None]:
608577
"""
609578
Constructs a mapping between XML files and the XSD schemas to
610579
use for their validation.
@@ -744,10 +713,10 @@ class instance (i.e. during library initialization).
744713
return validations
745714

746715
def _ensure_schema(
747-
self,
748-
xsd_path: Optional[Path] = None,
749-
base_url: Optional[str] = None
750-
) -> ValidatorResult:
716+
self,
717+
xsd_path: Optional[Path] = None,
718+
base_url: Optional[str] = None
719+
) -> ValidatorResult:
751720
"""
752721
Ensures that a schema is available for validation.
753722
@@ -829,15 +798,12 @@ def _ensure_schema(
829798
return self._load_schema(xsd_path, base_url) # pyright: ignore
830799

831800
def _find_schemas(
832-
self,
833-
xml_file_paths: List[Path],
834-
xsd_file_paths: List[Path],
835-
search_by: Literal[
836-
'by_namespace',
837-
'by_file_name'
838-
] = 'by_namespace',
839-
base_url: Optional[str] = None
840-
) -> Dict[ Path, Path | None ]:
801+
self,
802+
xml_file_paths: List[Path],
803+
xsd_file_paths: List[Path],
804+
search_by: Literal['by_namespace', 'by_file_name'] = 'by_namespace',
805+
base_url: Optional[str] = None
806+
) -> Dict[ Path, Path | None ]:
841807
"""
842808
Finds matching XSD schemas for XML files using the specified
843809
search strategy.
@@ -982,10 +948,10 @@ def _find_schemas(
982948
return validations
983949

984950
def _load_schema(
985-
self,
986-
xsd_path: Path,
987-
base_url: Optional[str] = None
988-
) -> ValidatorResult:
951+
self,
952+
xsd_path: Path,
953+
base_url: Optional[str] = None
954+
) -> ValidatorResult:
989955
"""
990956
This method is responsible for initializing a schema object,
991957
using the `xmlschema` library.
@@ -1036,17 +1002,96 @@ def _load_schema(
10361002
success=False, error={"XMLSchemaValidationError": e}
10371003
)
10381004

1039-
def _validate_xml(self, # pylint: disable=R0913:too-many-arguments disable=R0917:too-many-positional-arguments
1040-
xml_file_path: Path,
1041-
xsd_file_path: Optional[Path] = None,
1042-
base_url: Optional[str] = None,
1043-
error_facets: Optional[ List[str] ] = None,
1044-
pre_parse: Optional[bool] = True
1045-
) -> Tuple[
1046-
bool, Optional[
1047-
List[ dict[str, Any] ]
1048-
]
1049-
]:
1005+
def _try_load_initial_schema(
1006+
self,
1007+
xsd_path: Optional[str|Path] = None,
1008+
base_url: Optional[str] = None
1009+
) -> None:
1010+
"""
1011+
Attempts to resolve, validate, and load a single XSD schema from
1012+
the provided path.
1013+
1014+
This method is invoked during library initialization (i.e.,
1015+
within `__init__`) when an optional `xsd_path` is provided. If a
1016+
path is provided, this method expects the path to resolve to
1017+
exactly one valid`.xsd` file. If successful, the compiled schema
1018+
is returned and stored in `self.schema`.
1019+
1020+
If the path points to a directory, the method searches for a
1021+
single `.xsd` file inside it. If multiple matching files are
1022+
found, or if the file extension is incorrect, an error is
1023+
raised.
1024+
1025+
This method is not intended to be used interactively — it is a
1026+
one-time helper to support declarative schema configuration
1027+
during import of the test library.
1028+
1029+
Args:
1030+
1031+
- xsd_path (str):
1032+
Path to a `.xsd` file or to a directory containing exactly one
1033+
`.xsd` file.
1034+
- base_url (Optional[str]):
1035+
Optional base URL used when parsing the schema, typically to
1036+
resolve includes.
1037+
1038+
Raises:
1039+
1040+
- ValueError:
1041+
If multiple `.xsd` files are found in the provided directory.
1042+
- SystemError:
1043+
If the resolved file does not have a `.xsd` extension or the
1044+
schema fails to load.
1045+
"""
1046+
if xsd_path:
1047+
# Try to get a single xsd file from the provided xsd_path.
1048+
xsd_file_path, is_single_xsd_file = (
1049+
self.validator_utils.get_file_paths(
1050+
xsd_path, 'xsd'
1051+
)
1052+
)
1053+
# We need (a path to) a single xsd file.
1054+
if not is_single_xsd_file:
1055+
raise ValueError(
1056+
f"Got multiple xsd files: {xsd_file_path}."
1057+
)
1058+
# Handle incorrect file extension.
1059+
if xsd_file_path[0].suffix != '.xsd':
1060+
# Raise a load error.
1061+
raise SystemError(
1062+
f"ValueError: {xsd_file_path[0]} is not an XSD file."
1063+
)
1064+
# Try to load the provided XSD file.
1065+
result = self._load_schema(xsd_file_path[0], base_url )
1066+
if result.success:
1067+
# Set the loaded XSD file as default schema.
1068+
logger.info(
1069+
f"Schema '{self.schema.name}' set.", # type: ignore
1070+
also_console=True)
1071+
return result.value
1072+
# Or report the load error.
1073+
raise SystemError(
1074+
f"Loading of schema failed: {result.error}"
1075+
)
1076+
# Or inform the user on what to do.
1077+
logger.info(
1078+
"No XSD schema set: provide schema(s) during keyword calls.",
1079+
also_console=True
1080+
)
1081+
# And explicitly flag the schema attr as None.
1082+
return None
1083+
1084+
def _validate_xml( # pylint: disable=R0913:too-many-arguments disable=R0917:too-many-positional-arguments
1085+
self,
1086+
xml_file_path: Path,
1087+
xsd_file_path: Optional[Path] = None,
1088+
base_url: Optional[str] = None,
1089+
error_facets: Optional[ List[str] ] = None,
1090+
pre_parse: Optional[bool] = True
1091+
) -> Tuple[
1092+
bool,
1093+
Optional[List[dict[str, Any]]]
1094+
]:
10501095
"""
10511096
Validates an XML file against the currently loaded or provided
10521097
XSD schema.
@@ -1259,9 +1304,7 @@ def get_error_facets(self) -> List[str]:
12591304
return self.error_facets
12601305

12611306
@keyword
1262-
def get_schema(
1263-
self,
1264-
return_schema_name: bool = True
1307+
def get_schema(self,return_schema_name: bool = True
12651308
) -> Optional[str|XMLSchema]:
12661309
"""
12671310
.. raw:: html

0 commit comments

Comments
 (0)