Skip to content

Commit 3f833ce

Browse files
committed
Merge branch 'master' into phanak-travis-pypy
2 parents 134ca57 + 16cc46b commit 3f833ce

File tree

8 files changed

+44
-6
lines changed

8 files changed

+44
-6
lines changed

.pylintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ confidence=
6565
# --enable=similarities". If you want to run only the classes checker, but have
6666
# no Warning level messages displayed, use"--disable=all --enable=classes
6767
# --disable=W"
68-
disable=locally-disabled
68+
disable=locally-disabled, super-with-arguments, raise-missing-from
6969

7070

7171
[REPORTS]

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ env:
1515
- LXML_VERSION=4.2.6
1616
- LXML_VERSION=4.3.5
1717
- LXML_VERSION=4.4.3
18-
- LXML_VERSION=4.5.0
18+
- LXML_VERSION=4.5.2
1919

2020
jobs:
2121
exclude:

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
66

77
## [Unreleased]
88

9+
## [1.7.0]
10+
911
### Added
1012
- Add inlinecount support - Stoyko Stoev
1113
- Add a ProgramError exception - Stoyko Stoev
14+
- Add is_valid schema property - Petr Hanak
1215

1316
### Fixed
1417
- Passing custom URL query parameters for Entity Requests - Sylvain Fankhauser

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.6.0
1+
1.7.0

docs/usage/initialization.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ For parser to use your custom configuration, it needs to be passed as an argumen
141141
142142
northwind = pyodata.Client(SERVICE_URL, requests.Session(), config=custom_config)
143143
144+
Additionally, Schema class has Boolean atribute 'is_valid' that returns if the parser encountered errors. It's value does not depends on used Parser policy.
145+
146+
.. code-block:: python
147+
148+
northwind.schema.is_valid
149+
144150
Set custom namespaces (Deprecated - use config instead)
145151
-------------------------------------------------------
146152

pyodata/v2/model.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,7 @@ def __init__(self, config: Config):
830830

831831
self._decls = Schema.Declarations()
832832
self._config = config
833+
self._is_valid = False
833834

834835
def __str__(self):
835836
return "{0}({1})".format(self.__class__.__name__, ','.join(self.namespaces))
@@ -842,6 +843,14 @@ def namespaces(self):
842843
def config(self):
843844
return self._config
844845

846+
@property
847+
def is_valid(self):
848+
"""Returns if metadata provided were parsed to schema without any problem regardless of Policies (Fatal, Warning, Ignore).
849+
850+
Policies affects behaviour o parser while this property represents status.
851+
"""
852+
return self._is_valid
853+
845854
def typ(self, type_name, namespace=None):
846855
"""Returns either EntityType, ComplexType or EnumType that matches the name.
847856
"""
@@ -1046,6 +1055,7 @@ def check_role_property_names(self, role, entity_type_name, namespace):
10461055
@staticmethod
10471056
def from_etree(schema_nodes, config: Config):
10481057
schema = Schema(config)
1058+
schema._is_valid = True
10491059

10501060
# Parse Schema nodes by parts to get over the problem of not-yet known
10511061
# entity types referenced by entity sets, function imports and
@@ -1063,6 +1073,7 @@ def from_etree(schema_nodes, config: Config):
10631073
except (PyODataParserError, AttributeError) as ex:
10641074
config.err_policy(ParserError.ENUM_TYPE).resolve(ex)
10651075
etype = NullType(enum_type.get('Name'))
1076+
schema._is_valid = False
10661077

10671078
decl.add_enum_type(etype)
10681079

@@ -1072,6 +1083,7 @@ def from_etree(schema_nodes, config: Config):
10721083
except (KeyError, AttributeError) as ex:
10731084
config.err_policy(ParserError.COMPLEX_TYPE).resolve(ex)
10741085
ctype = NullType(complex_type.get('Name'))
1086+
schema._is_valid = False
10751087

10761088
decl.add_complex_type(ctype)
10771089

@@ -1081,6 +1093,7 @@ def from_etree(schema_nodes, config: Config):
10811093
except (KeyError, AttributeError) as ex:
10821094
config.err_policy(ParserError.ENTITY_TYPE).resolve(ex)
10831095
etype = NullType(entity_type.get('Name'))
1096+
schema._is_valid = False
10841097

10851098
decl.add_entity_type(etype)
10861099

@@ -1101,6 +1114,7 @@ def from_etree(schema_nodes, config: Config):
11011114
except PyODataModelError as ex:
11021115
config.err_policy(ParserError.PROPERTY).resolve(ex)
11031116
prop.typ = NullType(prop.type_info.name)
1117+
schema._is_valid = False
11041118

11051119
# pylint: disable=too-many-nested-blocks
11061120
# Then, process Associations nodes because they refer EntityTypes and
@@ -1122,6 +1136,7 @@ def from_etree(schema_nodes, config: Config):
11221136

11231137
end_role.entity_type = etype
11241138
except KeyError:
1139+
schema._is_valid = False
11251140
raise PyODataModelError(
11261141
f'EntityType {end_role.entity_type_info.name} does not exist in Schema '
11271142
f'Namespace {end_role.entity_type_info.namespace}')
@@ -1132,6 +1147,7 @@ def from_etree(schema_nodes, config: Config):
11321147

11331148
# Check if the role was defined in the current association
11341149
if principal_role.name not in role_names:
1150+
schema._is_valid = False
11351151
raise RuntimeError(
11361152
'Role {} was not defined in association {}'.format(principal_role.name, assoc.name))
11371153

@@ -1144,6 +1160,7 @@ def from_etree(schema_nodes, config: Config):
11441160

11451161
# Check if the role was defined in the current association
11461162
if dependent_role.name not in role_names:
1163+
schema._is_valid = False
11471164
raise RuntimeError(
11481165
'Role {} was not defined in association {}'.format(dependent_role.name, assoc.name))
11491166

@@ -1154,6 +1171,7 @@ def from_etree(schema_nodes, config: Config):
11541171
except (PyODataModelError, RuntimeError) as ex:
11551172
config.err_policy(ParserError.ASSOCIATION).resolve(ex)
11561173
decl.associations[assoc.name] = NullAssociation(assoc.name)
1174+
schema._is_valid = False
11571175
else:
11581176
decl.associations[assoc.name] = assoc
11591177

@@ -1174,6 +1192,7 @@ def from_etree(schema_nodes, config: Config):
11741192
except KeyError as ex:
11751193
config.err_policy(ParserError.ASSOCIATION).resolve(ex)
11761194
nav_prop.association = NullAssociation(nav_prop.association_info.name)
1195+
schema._is_valid = False
11771196

11781197
# Then, process EntitySet, FunctionImport and AssociationSet nodes.
11791198
for schema_node in schema_nodes:
@@ -1202,6 +1221,7 @@ def from_etree(schema_nodes, config: Config):
12021221
assoc_set.association_type = schema.association(assoc_set.association_type_name,
12031222
assoc_set.association_type_namespace)
12041223
except KeyError:
1224+
schema._is_valid = False
12051225
raise PyODataModelError(
12061226
'Association {} does not exist in namespace {}'
12071227
.format(assoc_set.association_type_name, assoc_set.association_type_namespace))
@@ -1213,15 +1233,18 @@ def from_etree(schema_nodes, config: Config):
12131233
entity_set = schema.entity_set(end.entity_set_name, namespace)
12141234
end.entity_set = entity_set
12151235
except KeyError:
1236+
schema._is_valid = False
12161237
raise PyODataModelError('EntitySet {} does not exist in Schema Namespace {}'
12171238
.format(end.entity_set_name, namespace))
12181239
# Check if role is defined in Association
12191240
if assoc_set.association_type.end_by_role(end.role) is None:
1241+
schema._is_valid = False
12201242
raise PyODataModelError('Role {} is not defined in association {}'
12211243
.format(end.role, assoc_set.association_type_name))
12221244
except (PyODataModelError, KeyError) as ex:
12231245
config.err_policy(ParserError.ASSOCIATION).resolve(ex)
12241246
decl.association_sets[assoc_set.name] = NullAssociation(assoc_set.name)
1247+
schema._is_valid = False
12251248
else:
12261249
decl.association_sets[assoc_set.name] = assoc_set
12271250

@@ -1240,25 +1263,29 @@ def from_etree(schema_nodes, config: Config):
12401263
annotation.entity_set = schema.entity_set(
12411264
annotation.collection_path, namespace=annotation.element_namespace)
12421265
except KeyError:
1266+
schema._is_valid = False
12431267
raise RuntimeError(f'Entity Set {annotation.collection_path} '
12441268
f'for {annotation} does not exist')
12451269

12461270
try:
12471271
vh_type = schema.typ(annotation.proprty_entity_type_name,
12481272
namespace=annotation.element_namespace)
12491273
except KeyError:
1274+
schema._is_valid = False
12501275
raise RuntimeError(f'Target Type {annotation.proprty_entity_type_name} '
12511276
f'of {annotation} does not exist')
12521277

12531278
try:
12541279
target_proprty = vh_type.proprty(annotation.proprty_name)
12551280
except KeyError:
1281+
schema._is_valid = False
12561282
raise RuntimeError(f'Target Property {annotation.proprty_name} '
12571283
f'of {vh_type} as defined in {annotation} does not exist')
12581284

12591285
annotation.proprty = target_proprty
12601286
target_proprty.value_helper = annotation
12611287
except (RuntimeError, PyODataModelError) as ex:
1288+
schema._is_valid = False
12621289
config.err_policy(ParserError.ANNOTATION).resolve(ex)
12631290

12641291
return schema

tests/test_client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def test_create_client_for_local_metadata(metadata):
2929
client = pyodata.Client(SERVICE_URL, requests, metadata=metadata)
3030

3131
assert isinstance(client, pyodata.v2.service.Service)
32+
assert client.schema.is_valid == True
3233

3334
assert len(client.schema.entity_sets) != 0
3435

@@ -53,7 +54,7 @@ def test_create_service_application_xml(metadata):
5354
client = pyodata.Client(SERVICE_URL + '/', requests)
5455

5556
assert isinstance(client, pyodata.v2.service.Service)
56-
57+
assert client.schema.is_valid == True
5758

5859
@responses.activate
5960
def test_create_service_text_xml(metadata):
@@ -75,7 +76,7 @@ def test_create_service_text_xml(metadata):
7576
client = pyodata.Client(SERVICE_URL + '/', requests)
7677

7778
assert isinstance(client, pyodata.v2.service.Service)
78-
79+
assert client.schema.is_valid == True
7980

8081
@responses.activate
8182
def test_metadata_not_reachable():
@@ -92,7 +93,6 @@ def test_metadata_not_reachable():
9293

9394
assert str(e_info.value).startswith('Metadata request failed')
9495

95-
9696
@responses.activate
9797
def test_metadata_saml_not_authorized():
9898
"""Check handling of not SAML / OAuth unauthorized response"""

tests/test_model_v2.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,7 @@ def test_faulty_association(xml_builder_factory):
10091009
))
10101010

10111011
schema = metadata.build()
1012+
assert schema.is_valid == False
10121013
assert isinstance(schema.associations[0], NullAssociation)
10131014

10141015
with pytest.raises(PyODataModelError) as typ_ex_info:
@@ -1035,6 +1036,7 @@ def test_faulty_association_set(xml_builder_factory):
10351036
))
10361037

10371038
schema = metadata.build()
1039+
assert schema.is_valid == False
10381040
assert isinstance(schema.association_set('toDataEntitySet'), NullAssociation)
10391041

10401042
with pytest.raises(PyODataModelError) as typ_ex_info:

0 commit comments

Comments
 (0)