diff --git a/entityshape/api_v1/api_v1_blueprint.py b/entityshape/api_v1/api_v1_blueprint.py index ca9e2ca..42cbdbb 100644 --- a/entityshape/api_v1/api_v1_blueprint.py +++ b/entityshape/api_v1/api_v1_blueprint.py @@ -5,17 +5,18 @@ api_v1 = Blueprint('api_v1', __name__,) + @api_v1.route('/') def v1(): """ Compares an entityschema with a wikidata item :return: a response to the query """ - schema: str = request.args.get("entityschema", type=str) - entity: str = request.args.get("entity", type=str) + schema: str = request.args.get("entityschema", default="", type=str) + entity: str = request.args.get("entity", default="", type=str) if "Lexeme" in entity: entity = entity[7:] - language: str = request.args.get("language", type=str) + language: str = request.args.get("language", default="", type=str) try: valid: dict = {} entity_shape: Shape = Shape(schema, language) @@ -41,4 +42,4 @@ def v1(): response: Response = Response(response=json.dumps(payload), status=status, mimetype="application/json") - return response \ No newline at end of file + return response diff --git a/entityshape/api_v1/shape.py b/entityshape/api_v1/shape.py index 4c8a882..c642c0c 100644 --- a/entityshape/api_v1/shape.py +++ b/entityshape/api_v1/shape.py @@ -89,7 +89,10 @@ def _convert_shape(self, shape: str) -> None: for line in shape_array: if re.match(r".+:P\d", line): child: dict = {} - selected_property: str = re.search(r"P\d+", line).group(0) + selected_property: str = "" + match = re.search(r"P\d+", line) + if match: + selected_property = match.group(0) if shape_json.get(selected_property): child = shape_json[selected_property] shape_json[selected_property] = self._assess_property(line, child) @@ -109,10 +112,16 @@ def _assess_property(self, line: str, child: dict) -> dict: """ snak: str = self._get_snak_type(line) if "@<" in line: - sub_shape_name: str = re.search(r"<.*>", line).group(0) + sub_shape_name: str = "" + match = re.search(r"<.*>", line) + if match: + sub_shape_name = match.group(0) child["shape"] = sub_shape_name[1:-1] if re.search(r"\[.*]", line): - required_parameters_string: str = re.search(r"\[.*]", line).group(0) + required_parameters_string: str = "" + match = re.search(r"\[.*]", line) + if match: + required_parameters_string = match.group(0) required_parameters_string = required_parameters_string.replace("wd:", "") if "^" in line: child["not_allowed"] = required_parameters_string[1:-1].split() @@ -208,9 +217,15 @@ def _get_specific_shape(self, shape_name: str) -> str: % shape_name) parentheses = self._find_parentheses(self._schema_text) try: - shape_index: int = re.search(search, self._schema_text).start() + shape_index: int = 0 + match = re.search(search, self._schema_text) + if match: + shape_index = match.start() except AttributeError: - shape_index = re.search("<%s>" % shape_name, self._schema_text).start() + shape_index: int = 0 + match = re.search("<%s>" % shape_name, self._schema_text) + if match: + shape_index = match.start() closest = None for character in parentheses: if (character >= shape_index) and (closest is None or character < closest): @@ -285,7 +300,7 @@ def _get_cardinality(schema_line: str) -> dict: cardinality["min"] = 0 elif re.search(r"{.+}", schema_line): match = re.search(r"{((\d+)|(\d+,\d+))}", schema_line) - if hasattr(match, "group"): + if match is not None and hasattr(match, "group"): match = match.group() cardinalities = match[1:-1].split(",") cardinality["min"] = int(cardinalities[0]) @@ -339,7 +354,7 @@ def _assess_sub_shape_key(self, schema_json["required"] = sub_shape_json if sub_shape[key]["status"] == "statement" and "allowed" in sub_shape[key]: value = sub_shape[key]["allowed"] - schema_json["required"] = {key: value} + schema_json["required"] = {str(key): value} if sub_shape[key]["status"] == "qualifier": qualifier_child[key] = sub_shape[key] if sub_shape[key]["status"] == "reference": diff --git a/entityshape/api_v2/api_v2_blueprint.py b/entityshape/api_v2/api_v2_blueprint.py index b6384da..0c78698 100644 --- a/entityshape/api_v2/api_v2_blueprint.py +++ b/entityshape/api_v2/api_v2_blueprint.py @@ -6,18 +6,25 @@ api_v2 = Blueprint('api_v2', __name__,) + @api_v2.route('/') def v2(): """ Compares an entityschema with a wikidata item :return: a response to the query """ - schema: str = request.args.get("entityschema", type=str) - schema_list: list = schema.split(', ') - entity: str = request.args.get("entity", type=str) + schema: (str | None) = request.args.get("entityschema", type=str) + schema_list: list[str] = [] + if schema: + schema_list = schema.split(', ') + entity: (str | None) = request.args.get("entity", type=str) + if entity is None: + entity = "" if "Lexeme" in entity: entity = entity[7:] - language: str = request.args.get("language", type=str) + language: (str | None) = request.args.get("language", type=str) + if language is None: + language = "" try: valid: dict = {} names: list = [] @@ -52,4 +59,4 @@ def v2(): response: Response = Response(response=json.dumps(payload), status=status, mimetype="application/json") - return response \ No newline at end of file + return response diff --git a/entityshape/api_v2/getjsonld.py b/entityshape/api_v2/getjsonld.py index b285dcd..7841f63 100644 --- a/entityshape/api_v2/getjsonld.py +++ b/entityshape/api_v2/getjsonld.py @@ -2,7 +2,7 @@ import requests from jsonasobj import as_json -from pyshexc.parser_impl.generate_shexj import parse +from pyshexc.parser_impl.generate_shexj import Schema, parse class JSONLDShape: @@ -25,7 +25,14 @@ def get_json_ld(self) -> dict: Gets the JSON_LD form of the Schema """ try: - return json.loads(as_json(parse(self._json_text["schemaText"]))) + schema_text: (str | None) = self._json_text.get("schemaText") + if not schema_text: + return {} + parsed_schema: (Schema | None) = parse(schema_text) + if parsed_schema is None: + return {} + + return json.loads(as_json(parsed_schema)) except (KeyError, IndexError, AttributeError, ValueError): return {} @@ -51,4 +58,4 @@ def get_name(self) -> str: return "" if self._language in self._json_text["labels"]: return self._json_text["labels"][self._language] - return "" \ No newline at end of file + return "" diff --git a/tests/fixtures/E438.json b/tests/fixtures/E438.json index 70475f7..d5111ff 100644 --- a/tests/fixtures/E438.json +++ b/tests/fixtures/E438.json @@ -2,8 +2,7 @@ "id": "E438", "serializationVersion": "3.0", "labels": { - "en": "Wikimedia Disambiguation Page", - "ja": "ウィキメディアの曖昧さ回避ページ" + "en": "Wikimedia Disambiguation Page" }, "descriptions": { "en": "Entity schema of Wikimedia Disambiguation Page" diff --git a/tests/fixtures/E56.json b/tests/fixtures/E56.json index de8ba80..cd62e17 100644 --- a/tests/fixtures/E56.json +++ b/tests/fixtures/E56.json @@ -6,7 +6,6 @@ "en": "Danish verb", "eo": "dana verbo", "fr": "verbe danois", - "ja": "デンマーク語の動詞", "nl": "Deens werkwoord", "pl": "czasownik duński", "pt": "verbo (danês)", @@ -16,7 +15,6 @@ "descriptions": { "en": "basic schema for Danish verbs", "fr": "lexème danois", - "ja": "デンマーク語の動詞を記述するための基本的なスキーマ", "nl": "basisschema voor een Deens werkwoord", "pl": "podstawowy schemat czasowników duńskich", "szl": "bazowy schymat czasowników duńskich" diff --git a/tests/tests_api_v1/test_v1.py b/tests/tests_api_v1/test_v1.py index 410ba4b..56f1ddc 100644 --- a/tests/tests_api_v1/test_v1.py +++ b/tests/tests_api_v1/test_v1.py @@ -40,6 +40,7 @@ def dynamic_mock_response(self, url, *args, **kwargs): params = kwargs.get('params', {}) action = params.get('action') + target_id: str = "" if url == "https://www.wikidata.org/w/api.php": if action == "wbgetentities": target_id = "names" @@ -60,7 +61,7 @@ def dynamic_mock_response(self, url, *args, **kwargs): # Final fallback mock_resp.status_code = 404 return mock_resp - + def test_specific_wikidata_item_against_schema(self): """ Tests a specific entity against a certain schema and checks that @@ -73,6 +74,7 @@ def test_specific_wikidata_item_against_schema(self): value = test_pairs[key] response = self.app.get(f'/api?entityschema={key}&entity={value}&language=en', follow_redirects=True) + assert response.json is not None self.assertIsNotNone(response.json["statements"]) self.assertIsNotNone(response.json["properties"]) @@ -87,6 +89,7 @@ def test_lexical_category(self): value = test_pairs[key] response = self.app.get(f'/api?entityschema={key}&entity={value}&language=en', follow_redirects=True) + assert response.json is not None self.assertIsNotNone(response.json["general"]["lexicalCategory"]) self.assertIsNotNone(response.json["general"]["language"]) @@ -128,6 +131,7 @@ def test_specific_entityschema(self) -> None: schema: str = "E236" response = self.app.get(f'/api?entityschema={schema}&entity=Q100532807&language=en', follow_redirects=True) + assert response.json is not None self.assertEqual(200, response.status_code) self.assertEqual("Member of the Oireachtas", response.json["name"]) self.assertEqual({'name': 'occupation', 'necessity': 'required', 'response': 'missing'}, @@ -146,6 +150,7 @@ def test_entityschema_e236(self): properties: list = ["P102", "P18", "P31", "P734", "P735", "P39", "P21", "P27", "P106", "P569", "P4690"] for prop in properties: + assert response.json is not None with self.subTest(prop=prop): self.assertIn(response.json["properties"][prop]["response"], ["correct", "present"]) @@ -163,6 +168,7 @@ def test_entityschema_e297(self): self.assertEqual(200, response.status_code) properties: list = ["P2043", "P2067"] for prop in properties: + assert response.json is not None with self.subTest(prop=prop): self.assertIn(response.json["properties"][prop]["response"], ["correct", "present"]) @@ -179,6 +185,7 @@ def test_entityschema_e295(self): self.assertEqual(200, response.status_code) properties: list = ["P361"] for prop in properties: + assert response.json is not None with self.subTest(prop=prop): self.assertIn(response.json["properties"][prop]["response"], ["too many statements"]) self.assertIn(response.json["properties"][prop]["necessity"], ["absent"]) @@ -196,6 +203,7 @@ def test_entityschema_e300(self): self.assertEqual(200, response.status_code) properties: list = ["P3450"] for prop in properties: + assert response.json is not None with self.subTest(prop=prop): self.assertIn(response.json["properties"][prop]["response"], ["present"]) self.assertIn(response.json["properties"][prop]["necessity"], ["required"]) diff --git a/tests/tests_api_v2/test_compare_properties.py b/tests/tests_api_v2/test_compare_properties.py index 695412e..0849b56 100644 --- a/tests/tests_api_v2/test_compare_properties.py +++ b/tests/tests_api_v2/test_compare_properties.py @@ -5,28 +5,36 @@ class ComparePropertiesTests(unittest.TestCase): def setUp(self): - entity = {'entities': - {'Q1': - {'title': 'Q1', - 'type': 'item', - 'id': 'Q1', - 'claims': {'P31': [{'mainsnak': - {'snaktype': 'value', - 'property': 'P31', - 'hash': '1', - 'datavalue': {'value': - {'entity-type': 'item', 'numeric-id': 2, 'id': 'Q2'}, - 'type': 'wikibase-entityid'}, - 'datatype': 'wikibase-item'}, - 'type': 'statement', - 'id': '1', - 'rank': 'normal'}], - }, - 'sitelinks': {}}}} + entity = {'entities': { + 'Q1': { + 'title': 'Q1', + 'type': 'item', + 'id': 'Q1', + 'claims': { + 'P31': [{ + 'mainsnak': { + 'snaktype': 'value', + 'property': 'P31', + 'hash': '1', + 'datavalue': { + 'value': { + 'entity-type': 'item', + 'numeric-id': 2, + 'id': 'Q2'}, + 'type': 'wikibase-entityid'}, + 'datatype': 'wikibase-item' + }, + 'type': 'statement', + 'id': '1', + 'rank': 'normal' + } + ], + }, + 'sitelinks': {}}}} entities = "Q1" - statement = { "type": "Shape", - "id": "test", - "expression": { + statement = {"type": "Shape", + "id": "test", + "expression": { "type": "EachOf", "expressions": [ { @@ -60,23 +68,27 @@ def test_check_claims_for_prop_with_nothing(self): self.assertEqual('not enough correct statements', self.compare_properties.check_claims_for_props(claims, prop)) def test_check_claims_for_prop_with_values(self): - claims = {'Q1': - {'title': 'Q1', - 'type': 'item', - 'id': 'Q1', - 'claims': {'P31': [{'mainsnak': - {'snaktype': 'value', - 'property': 'P31', - 'hash': '1', - 'datavalue': {'value': - {'entity-type': 'item', 'numeric-id': 2, 'id': 'Q2'}, - 'type': 'wikibase-entityid'}, - 'datatype': 'wikibase-item'}, - 'type': 'statement', - 'id': '1', - 'rank': 'normal'}], - }, - 'sitelinks': {}}} + claims = {'Q1': { + 'title': 'Q1', + 'type': 'item', + 'id': 'Q1', + 'claims': {'P31': [{ + 'mainsnak': { + 'snaktype': 'value', + 'property': 'P31', + 'hash': '1', + 'datavalue': { + 'value': { + 'entity-type': 'item', + 'numeric-id': 2, + 'id': 'Q2'}, + 'type': 'wikibase-entityid'}, + 'datatype': 'wikibase-item'}, + 'type': 'statement', + 'id': '1', + 'rank': 'normal'}], + }, + 'sitelinks': {}}} prop = "P31" self.assertEqual('not enough correct statements', self.compare_properties.check_claims_for_props(claims, prop)) @@ -87,23 +99,28 @@ def test_get_allowed_list_with_nothing(self): self.assertEqual([], self.compare_properties._get_allowed_list(claims, prop, expression)) def test_get_allowed_list_with_values(self): - claims = {'Q1': - {'title': 'Q1', - 'type': 'item', - 'id': 'Q1', - 'claims': {'P31': [{'mainsnak': - {'snaktype': 'value', - 'property': 'P31', - 'hash': '1', - 'datavalue': {'value': - {'entity-type': 'item', 'numeric-id': 2, 'id': 'Q2'}, - 'type': 'wikibase-entityid'}, - 'datatype': 'wikibase-item'}, - 'type': 'statement', - 'id': '1', - 'rank': 'normal'}], + claims = {'Q1': { + 'title': 'Q1', + 'type': 'item', + 'id': 'Q1', + 'claims': { + 'P31': [{ + 'mainsnak': { + 'snaktype': 'value', + 'property': 'P31', + 'hash': '1', + 'datavalue': { + 'value': { + 'entity-type': 'item', + 'numeric-id': 2, + 'id': 'Q2'}, + 'type': 'wikibase-entityid'}, + 'datatype': 'wikibase-item'}, + 'type': 'statement', + 'id': '1', + 'rank': 'normal'}], }, - 'sitelinks': {}}} + 'sitelinks': {}}} prop = "P31" expression = {'type': 'TripleConstraint', 'predicate': 'http://www.wikidata.org/prop/direct/P31', @@ -121,9 +138,12 @@ def test_process_cardinalities_with_values(self): expression = {'snaktype': 'value', 'property': 'P31', 'hash': '1', - 'datavalue': {'value': - {'entity-type': 'item', 'numeric-id': 2, 'id': 'Q2'}, - 'type': 'wikibase-entityid'}, + 'datavalue': { + 'value': { + 'entity-type': 'item', + 'numeric-id': 2, + 'id': 'Q2'}, + 'type': 'wikibase-entityid'}, 'datatype': 'wikibase-item'} shape = {'type': 'TripleConstraint', 'predicate': 'http://www.wikidata.org/prop/direct/P31', @@ -142,9 +162,12 @@ def test_get_cardinalities_with_values(self): expression = {'snaktype': 'value', 'property': 'P31', 'hash': '1', - 'datavalue': {'value': - {'entity-type': 'item', 'numeric-id': 2, 'id': 'Q2'}, - 'type': 'wikibase-entityid'}, + 'datavalue': { + 'value': { + 'entity-type': 'item', + 'numeric-id': 2, + 'id': 'Q2'}, + 'type': 'wikibase-entityid'}, 'datatype': 'wikibase-item'} self.assertEqual("correct", self.compare_properties._get_cardinalities(occurrences, expression)) @@ -158,9 +181,12 @@ def test_process_triple_constraint_with_values(self): statement = {'snaktype': 'value', 'property': 'P31', 'hash': '1', - 'datavalue': {'value': - {'entity-type': 'item', 'numeric-id': 2, 'id': 'Q2'}, - 'type': 'wikibase-entityid'}, + 'datavalue': { + 'value': { + 'entity-type': 'item', + 'numeric-id': 2, + 'id': 'Q2'}, + 'type': 'wikibase-entityid'}, 'datatype': 'wikibase-item'} expression = {'type': 'TripleConstraint', 'predicate': 'http://www.wikidata.org/prop/direct/P31', diff --git a/tests/tests_api_v2/test_compare_statements.py b/tests/tests_api_v2/test_compare_statements.py index ded0c24..8963215 100644 --- a/tests/tests_api_v2/test_compare_statements.py +++ b/tests/tests_api_v2/test_compare_statements.py @@ -5,24 +5,29 @@ class CompareStatementsTests(unittest.TestCase): def setUp(self): - entities = {"entities": - {'Q1': - {'title': 'Q1', - 'type': 'item', - 'id': 'Q1', - 'claims': {'P31': [{'mainsnak': - {'snaktype': 'value', - 'property': 'P31', - 'hash': '1', - 'datavalue': {'value': - {'entity-type': 'item', 'numeric-id': 2, 'id': 'Q2'}, - 'type': 'wikibase-entityid'}, - 'datatype': 'wikibase-item'}, - 'type': 'statement', - 'id': '1', - 'rank': 'normal'}], - }, - 'sitelinks': {}}}} + entities = {"entities": { + 'Q1': { + 'title': 'Q1', + 'type': 'item', + 'id': 'Q1', + 'claims': { + 'P31': [{ + 'mainsnak': { + 'snaktype': 'value', + 'property': 'P31', + 'hash': '1', + 'datavalue': { + 'value': { + 'entity-type': 'item', + 'numeric-id': 2, + 'id': 'Q2'}, + 'type': 'wikibase-entityid'}, + 'datatype': 'wikibase-item'}, + 'type': 'statement', + 'id': '1', + 'rank': 'normal'}], + }, + 'sitelinks': {}}}} entity = "Q1" statement = {"type": "Shape", "id": "test", @@ -62,9 +67,12 @@ def test_process_shape_with_values(self): statement = {'snaktype': 'value', 'property': 'P31', 'hash': '1', - 'datavalue': {'value': - {'entity-type': 'item', 'numeric-id': 2, 'id': 'Q2'}, - 'type': 'wikibase-entityid'}, + 'datavalue': { + 'value': { + 'entity-type': 'item', + 'numeric-id': 2, + 'id': 'Q2'}, + 'type': 'wikibase-entityid'}, 'datatype': 'wikibase-item'} shape = {"type": "Shape", "id": "test", @@ -107,9 +115,12 @@ def test_process_expressions_with_values(self): statement = {'snaktype': 'value', 'property': 'P31', 'hash': '1', - 'datavalue': {'value': - {'entity-type': 'item', 'numeric-id': 2, 'id': 'Q2'}, - 'type': 'wikibase-entityid'}, + 'datavalue': { + 'value': { + 'entity-type': 'item', + 'numeric-id': 2, + 'id': 'Q2'}, + 'type': 'wikibase-entityid'}, 'datatype': 'wikibase-item'} allowed = "allowed" self.assertEqual("allowed", self.compare_statements.process_expressions(expression, shape, statement, allowed)) @@ -127,9 +138,12 @@ def test_process_triple_constraint_with_values(self): statement = {'snaktype': 'value', 'property': 'P31', 'hash': '1', - 'datavalue': {'value': - {'entity-type': 'item', 'numeric-id': 2, 'id': 'Q2'}, - 'type': 'wikibase-entityid'}, + 'datavalue': { + 'value': { + 'entity-type': 'item', + 'numeric-id': 2, + 'id': 'Q2'}, + 'type': 'wikibase-entityid'}, 'datatype': 'wikibase-item'} allowed = "allowed" self.assertEqual("allowed", self.compare_statements._process_triple_constraint(statement, expression, allowed)) diff --git a/tests/tests_api_v2/test_compare_v1_v2.py b/tests/tests_api_v2/test_compare_v1_v2.py index 093e36e..ac1cd76 100644 --- a/tests/tests_api_v2/test_compare_v1_v2.py +++ b/tests/tests_api_v2/test_compare_v1_v2.py @@ -38,6 +38,7 @@ def tearDown(self) -> None: def dynamic_mock_response(self, url, *args, **kwargs): mock_resp = MagicMock() mock_resp.status_code = 200 + target_id: str = "" if url == "https://www.wikidata.org/w/api.php": target_id = "names" else: @@ -55,7 +56,7 @@ def dynamic_mock_response(self, url, *args, **kwargs): # Final fallback mock_resp.status_code = 404 return mock_resp - + def test_lexical_category(self): """ This test checks that a lexicalCategory response is returned when a @@ -67,6 +68,7 @@ def test_lexical_category(self): value = test_pairs[key] response = self.app.get(f'/api/v2?entityschema={key}&entity={value}&language=en', follow_redirects=True) + assert response.json is not None self.assertIsNotNone(response.json["general"][0]["lexicalCategory"]) self.assertIsNotNone(response.json["general"][0]["language"]) @@ -106,6 +108,7 @@ def test_specific_entityschema(self) -> None: schema: str = "E236" response = self.app.get(f'/api/v2?entityschema={schema}&entity=Q100532807&language=en', follow_redirects=True) + assert response.json is not None self.assertEqual(200, response.status_code) self.assertEqual("Member of the Oireachtas", response.json["name"][0]) self.assertEqual({'name': 'occupation', 'necessity': 'required', 'response': 'missing'}, @@ -206,6 +209,7 @@ def test_entityschema_e236(self): properties: list = ["P102", "P18", "P31", "P734", "P735", "P39", "P21", "P27", "P106", "P569", "P4690"] for prop in properties: + assert response.json is not None with self.subTest(prop=prop): self.assertIn(response.json["properties"][0][prop]["response"], ["correct", "present"]) @@ -223,6 +227,8 @@ def test_entityschema_e236_2(self): self.assertEqual(200, response.status_code) properties: list = ["P39", "P106", "P18", "P4690"] for prop in properties: + assert response.json is not None + assert response2.json is not None with self.subTest(prop=prop): self.assertIn(response.json["properties"][0][prop]["response"], ["correct", "present", "allowed"]) @@ -289,6 +295,7 @@ def test_entityschema_e295(self): self.assertEqual(200, response.status_code) properties: list = ["P361"] for prop in properties: + assert response.json is not None with self.subTest(prop=prop): self.assertIn(response.json["properties"][0][prop]["response"], ["too many statements"]) self.assertIn(response.json["properties"][0][prop]["necessity"], ["absent"]) @@ -307,6 +314,7 @@ def test_entityschema_e297(self): self.assertEqual(200, response.status_code) properties: list = ["P2043", "P2067"] for prop in properties: + assert response.json is not None with self.subTest(prop=prop): self.assertIn(response.json["properties"][0][prop]["response"], ["correct", "present", "too many statements"]) @@ -324,6 +332,7 @@ def test_entityschema_e300(self): self.assertEqual(200, response.status_code) properties: list = ["P3450"] for prop in properties: + assert response.json is not None with self.subTest(prop=prop): self.assertIn(response.json["properties"][0][prop]["response"], ["present"]) self.assertIn(response.json["properties"][0][prop]["necessity"], ["required"]) @@ -359,6 +368,7 @@ def test_entityschema_e351(self): """ response = self.app.get('/api/v2?entityschema=E351&entity=Q743656&language=en', follow_redirects=True) + assert response.json is not None self.assertIn(response.json["properties"][0]["P31"]["response"], ["not enough correct statements"]) diff --git a/tests/tests_api_v2/test_jsonld.py b/tests/tests_api_v2/test_jsonld.py index 5b82d8e..7720e0b 100644 --- a/tests/tests_api_v2/test_jsonld.py +++ b/tests/tests_api_v2/test_jsonld.py @@ -26,7 +26,7 @@ def setUpClass(cls) -> None: cls.patcher_schema_v1 = patch('entityshape.api_v1.shape.requests.get') cls.patcher_item_v2 = patch('entityshape.api_v2.comparejsonld.requests.get') cls.patcher_schema_v2 = patch('entityshape.api_v2.getjsonld.requests.get') - + cls.mock_item_v1 = cls.patcher_item_v1.start() cls.mock_schema_v1 = cls.patcher_schema_v1.start() cls.mock_item_v2 = cls.patcher_item_v2.start() @@ -58,6 +58,7 @@ def dynamic_mock_response(url, *args, **kwargs): """Smart resolver to find JSON fixtures by ID""" mock_resp = MagicMock() mock_resp.status_code = 200 + target_id: str = "" if url == "https://www.wikidata.org/w/api.php": target_id = "names" # Extract ID from URL (e.g., E236 or Q1728820) @@ -67,12 +68,12 @@ def dynamic_mock_response(url, *args, **kwargs): # Re-calculating path inside static method parent_dir = os.path.dirname(os.path.dirname(__file__)) fixture_file = os.path.join(parent_dir, 'fixtures', f"{target_id}.json") - + if os.path.exists(fixture_file): with open(fixture_file, 'r') as f: mock_resp.json.return_value = json.load(f) return mock_resp - + mock_resp.status_code = 404 return mock_resp diff --git a/tests/tests_api_v2/test_schemas.py b/tests/tests_api_v2/test_schemas.py index dc37b1b..d99a3e4 100644 --- a/tests/tests_api_v2/test_schemas.py +++ b/tests/tests_api_v2/test_schemas.py @@ -9,7 +9,6 @@ from unittest.mock import patch, MagicMock -from urllib.parse import urlparse, parse_qs from entityshape.app import app @@ -34,7 +33,6 @@ def setUp(self) -> None: self.mock_schema_get.side_effect = self.dynamic_mock_response self.mock_entity_get.side_effect = self.dynamic_mock_response - def tearDown(self) -> None: self.schema_patcher.stop() self.entity_patcher.stop() @@ -46,6 +44,7 @@ def load_fixture(self, filename): def dynamic_mock_response(self, url, *args, **kwargs): mock_resp = MagicMock() mock_resp.status_code = 200 + target_id: str = "" if url == "https://www.wikidata.org/w/api.php": target_id = "names" else: @@ -76,6 +75,7 @@ def test_specific_wikidata_item_against_schema(self): value: str = test_pairs[key] response = self.app.get(f'/api/v2?entityschema={key}&entity={value}&language=en', follow_redirects=True) + assert response.json is not None self.assertIsNotNone(response.json["statements"]) self.assertIsNotNone(response.json["properties"]) @@ -90,6 +90,7 @@ def test_lexical_category(self): value = test_pairs[key] response = self.app.get(f'/api/v2?entityschema={key}&entity={value}&language=en', follow_redirects=True) + assert response.json is not None self.assertIsNotNone(response.json["general"][0]["lexicalCategory"]) self.assertIsNotNone(response.json["general"][0]["language"]) @@ -134,22 +135,22 @@ def test_specific_entityschema(self) -> None: schema: str = "E236" response = self.app.get(f'/api/v2?entityschema={schema}&entity=Q100532807&language=en', follow_redirects=True) + assert response.json is not None self.assertEqual(200, response.status_code) self.assertEqual("Member of the Oireachtas", response.json["name"][0]) self.assertEqual({'name': 'occupation', 'necessity': 'required', 'response': 'missing'}, response.json["properties"][0]["P106"]) - #@patch('entityshape.api_v2.getjsonld.requests.get') - #@patch('entityshape.api_v2.comparejsonld.requests.get') def test_mocked_specific_entityschema(self) -> None: """ Tests the app by mocking both the Entity and the EntitySchema data. """ - + response = self.app.get('/api/v2/?entityschema=E236&entity=Q100532807&language=en') # 5. ASSERTIONS self.assertEqual(200, response.status_code) + assert response.json is not None self.assertEqual("Member of the Oireachtas", response.json["name"][0]) self.assertEqual('missing', response.json["properties"][0]["P106"]["response"]) @@ -248,6 +249,7 @@ def test_entityschema_e236(self): properties: list = ["P102", "P18", "P31", "P734", "P735", "P39", "P21", "P27", "P106", "P569", "P4690"] for prop in properties: + assert response.json is not None with self.subTest(prop=prop): self.assertIn(response.json["properties"][0][prop]["response"], ["correct", "present"]) @@ -265,6 +267,8 @@ def test_entityschema_e236_2(self): self.assertEqual(200, response.status_code) properties: list = ["P39", "P106", "P18", "P4690"] for prop in properties: + assert response.json is not None + assert response2.json is not None with self.subTest(prop=prop): self.assertIn(response.json["properties"][0][prop]["response"], ["correct", "present", "allowed"]) self.assertEqual(response.json["properties"][0][prop]["response"], @@ -330,6 +334,7 @@ def test_entityschema_e295(self): self.assertEqual(200, response.status_code) properties: list = ["P361"] for prop in properties: + assert response.json is not None with self.subTest(prop=prop): self.assertIn(response.json["properties"][0][prop]["response"], ["too many statements"]) self.assertIn(response.json["properties"][0][prop]["necessity"], ["absent"]) @@ -348,6 +353,7 @@ def test_entityschema_e297(self): self.assertEqual(200, response.status_code) properties: list = ["P2043", "P2067"] for prop in properties: + assert response.json is not None with self.subTest(prop=prop): self.assertIn(response.json["properties"][0][prop]["response"], ["correct", "present", "too many statements"]) @@ -365,6 +371,7 @@ def test_entityschema_e300(self): self.assertEqual(200, response.status_code) properties: list = ["P3450"] for prop in properties: + assert response.json is not None with self.subTest(prop=prop): self.assertIn(response.json["properties"][0][prop]["response"], ["present"]) self.assertIn(response.json["properties"][0][prop]["necessity"], ["required"]) @@ -400,6 +407,7 @@ def test_entityschema_e351(self): """ response = self.app.get('/api/v2?entityschema=E351&entity=Q743656&language=en', follow_redirects=True) + assert response.json is not None self.assertIn(response.json["properties"][0]["P31"]["response"], ["not enough correct statements"]) def test_entityschema_e438(self): @@ -411,6 +419,7 @@ def test_entityschema_e438(self): """ response = self.app.get('/api/v2?entityschema=E438&entity=Q11645745&language=en', follow_redirects=True) + assert response.json is not None self.assertIn(response.json["properties"][0]["P31"]["response"], ["correct", "present"]) def test_non_existent_entityschema(self): diff --git a/tests/tests_api_v2/test_utilities.py b/tests/tests_api_v2/test_utilities.py index 1b4bde3..3ec0927 100644 --- a/tests/tests_api_v2/test_utilities.py +++ b/tests/tests_api_v2/test_utilities.py @@ -108,8 +108,8 @@ def test_process_cardinalities_with_max(self): 'predicate': 'http://www.wikidata.org/prop/direct/P31', 'max': 0, } - claim = {'mainsnak': - {'snaktype': 'value', + claim = {'mainsnak': { + 'snaktype': 'value', 'property': 'P31', 'hash': '851b1c24539bd7aa725376baba4bcf0928099a66', 'datatype': 'wikibase-item' @@ -124,8 +124,8 @@ def test_process_cardinalities_with_min(self): 'predicate': 'http://www.wikidata.org/prop/direct/P31', 'min': 0, } - claim = {'mainsnak': - {'snaktype': 'value', + claim = {'mainsnak': { + 'snaktype': 'value', 'property': 'P31', 'hash': '851b1c24539bd7aa725376baba4bcf0928099a66', 'datatype': 'wikibase-item' @@ -140,8 +140,8 @@ def test_process_cardinalities_with_max_and_min(self): 'min': 0, 'max': 0 } - claim = {'mainsnak': - {'snaktype': 'value', + claim = {'mainsnak': { + 'snaktype': 'value', 'property': 'P31', 'hash': '851b1c24539bd7aa725376baba4bcf0928099a66', 'datatype': 'wikibase-item'