16
16
# Copyright (c) OWASP Foundation. All Rights Reserved.
17
17
18
18
19
- __all__ = ['XmlValidator' ]
19
+ __all__ = ['XmlValidator' , 'XmlValidationError' ]
20
20
21
21
from abc import ABC
22
22
from collections .abc import Iterable
37
37
XMLSchema ,
38
38
fromstring as xml_fromstring ,
39
39
)
40
+
41
+ if TYPE_CHECKING : # pragma: no cover
42
+ from lxml .etree import _LogEntry as _XmlLogEntry
40
43
except ImportError as err :
41
44
_missing_deps_error = MissingOptionalDependencyException (
42
45
'This functionality requires optional dependencies.\n '
43
46
'Please install `cyclonedx-python-lib` with the extra "xml-validation".\n '
44
47
), err
45
48
46
49
50
+ class XmlValidationError (ValidationError ):
51
+ @classmethod
52
+ def _make_from_xle (cls , e : '_XmlLogEntry' ) -> 'XmlValidationError' :
53
+ """⚠️ This is an internal API. It is not part of the public interface and may change without notice."""
54
+ # in preparation for https://github.com/CycloneDX/cyclonedx-python-lib/pull/836
55
+ return cls (e )
56
+
57
+
47
58
class _BaseXmlValidator (BaseSchemabasedValidator , ABC ):
48
59
49
60
@property
@@ -57,16 +68,16 @@ def __init__(self, schema_version: 'SchemaVersion') -> None:
57
68
# region typing-relevant copy from parent class - needed for mypy and doc tools
58
69
59
70
@overload
60
- def validate_str (self , data : str , * , all_errors : Literal [False ] = ...) -> Optional [ValidationError ]:
71
+ def validate_str (self , data : str , * , all_errors : Literal [False ] = ...) -> Optional [XmlValidationError ]:
61
72
... # pragma: no cover
62
73
63
74
@overload
64
- def validate_str (self , data : str , * , all_errors : Literal [True ]) -> Optional [Iterable [ValidationError ]]:
75
+ def validate_str (self , data : str , * , all_errors : Literal [True ]) -> Optional [Iterable [XmlValidationError ]]:
65
76
... # pragma: no cover
66
77
67
78
def validate_str (
68
79
self , data : str , * , all_errors : bool = False
69
- ) -> Union [None , ValidationError , Iterable [ValidationError ]]:
80
+ ) -> Union [None , XmlValidationError , Iterable [XmlValidationError ]]:
70
81
... # pragma: no cover
71
82
72
83
# endregion typing-relevant
@@ -76,13 +87,13 @@ def validate_str(
76
87
77
88
def validate_str ( # type:ignore[no-redef] # noqa:F811 # typing-relevant headers go first
78
89
self , data : str , * , all_errors : bool = False
79
- ) -> Union [None , ValidationError , Iterable [ValidationError ]]:
90
+ ) -> Union [None , XmlValidationError , Iterable [XmlValidationError ]]:
80
91
raise self .__MDERROR [0 ] from self .__MDERROR [1 ]
81
92
82
93
else :
83
94
def validate_str ( # type:ignore[no-redef] # noqa:F811 # typing-relevant headers go first
84
95
self , data : str , * , all_errors : bool = False
85
- ) -> Union [None , ValidationError , Iterable [ValidationError ]]:
96
+ ) -> Union [None , XmlValidationError , Iterable [XmlValidationError ]]:
86
97
validator = self ._validator # may throw on error that MUST NOT be caught
87
98
valid = validator .validate (
88
99
xml_fromstring ( # nosec B320 -- we use a custom prepared safe parser
@@ -91,9 +102,9 @@ def validate_str( # type:ignore[no-redef] # noqa:F811 # typing-relevant headers
91
102
if valid :
92
103
return None
93
104
errors = validator .error_log
94
- return map (ValidationError , errors ) \
105
+ return map (XmlValidationError . _make_from_xle , errors ) \
95
106
if all_errors \
96
- else ValidationError (errors .last_error )
107
+ else XmlValidationError . _make_from_xle (errors .last_error )
97
108
98
109
__validator : Optional ['XMLSchema' ] = None
99
110
0 commit comments