55from concepts .signals import concept_post_save_receiver
66import mock , json
77from concepts .lifecycle import *
8- from unittest .mock import patch
8+ from unittest .mock import patch , PropertyMock
99import uuid
10-
10+ from urllib .parse import urlparse as python_original_urlparse
11+ from collections import namedtuple
12+
13+ _MockParseResult = namedtuple ('_MockParseResult' , ['scheme' , 'netloc' , 'path' , 'params' , 'query' , 'fragment' ])
14+
15+ def force_string_components_urlparse (uri_input ):
16+ # urlparse handles if uri_input is str or bytes for parsing.
17+ # The key is to ensure its *output* components are strings.
18+ parsed_obj = python_original_urlparse (uri_input )
19+
20+ decoded_components = []
21+ for component in parsed_obj : # Iterate through tuple: scheme, netloc, path, etc.
22+ if isinstance (component , bytes ):
23+ decoded_components .append (component .decode ('utf-8' , 'replace' ))
24+ elif component is None : # Preserve None if urlparse returns it for optional parts
25+ decoded_components .append (None )
26+ else :
27+ # Ensure it's a string
28+ decoded_components .append (str (component ))
29+
30+ return _MockParseResult (* decoded_components )
31+ # End Added
1132
1233class MockResponse (object ):
1334 def __init__ (self , content , status_code = 200 ):
@@ -124,14 +145,11 @@ def test_user_created_default_state(self):
124145 def test_get_similar_suggestions (self , mock_get ):
125146 """
126147 The :class:`.ConceptLifecycle` should handle retrieving suggestions.
127-
128- We're not creating new :class:`.Concept`\\ s at this point, just getting
129- data.
130148 """
131- # This is the data that will be returned by Conceptpower.search().
132- mock_data = [{
133- "label" : "Bradshaw 1965" ,
149+ # This is the list of concept entries that Conceptpower.search() should return
150+ mock_concept_list = [{
134151 "id" : "CON76832db2-7abb-4c77-b08e-239017b6a585" ,
152+ "lemma" : "Bradshaw 1965" ,
135153 "pos" : "noun" ,
136154 "type" : {
137155 "type_id" : "94d05eb7-bcee-4f4b-b18e-819dd1ffb20a" ,
@@ -142,7 +160,9 @@ def test_get_similar_suggestions(self, mock_get):
142160 "uri" : "http://www.digitalhps.org/concepts/CON76832db2-7abb-4c77-b08e-239017b6a585" ,
143161 "description" : "Bradshaw, Anthony David. 1965. \" The evolutionary significance of phenotypic plasticity in plants.\" Advances in Genetics 13: 115-155."
144162 }]
145- mock_get .return_value = MockResponse (json .dumps (mock_data ))
163+ # The API response should be a dictionary containing this list under 'conceptEntries'
164+ mock_api_response = {"conceptEntries" : mock_concept_list }
165+ mock_get .return_value = MockResponse (json .dumps (mock_api_response ))
146166
147167 concept = Concept .objects .create (
148168 uri = 'http://vogonweb.net/' + uuid .uuid4 ().hex ,
@@ -221,14 +241,15 @@ def test_cannot_merge_resolved_concepts(self):
221241 with self .assertRaises (ConceptLifecycleException ):
222242 manager .merge_with ('http://www.digitalhps.org/concepts/WID-02416519-N-02-test_concept' )
223243
224- @patch ('requests.get' )
244+ @patch ('concepts.lifecycle.urlparse' , new = force_string_components_urlparse )
245+ @patch ('concepts.conceptpower.requests.get' )
225246 def test_merge_with_conceptpower (self , mock_get ):
226247 """
227248 A non-native :class:`.Concept` can be merged with an existing native
228249 :class:`.Concept`.
229250 """
230251 # This is the data that will be returned by Conceptpower.get().
231- mock_response_data = {
252+ concept_data_payload = {
232253 "uri" : "http://www.digitalhps.org/concepts/CON76832db2-7abb-4c77-b08e-239017b6a585" ,
233254 "word" : "Bradshaw 1965" ,
234255 "lemma" : "Bradshaw 1965" ,
@@ -240,9 +261,13 @@ def test_merge_with_conceptpower(self, mock_get):
240261 "type_name" : "E28 Conceptual Object"
241262 },
242263 "conceptList" : "Publications" ,
243- "id" : "CON76832db2-7abb-4c77-b08e-239017b6a585"
264+ "id" : "CON76832db2-7abb-4c77-b08e-239017b6a585" ,
265+ # Ensure concept_uri is present as create_from_raw might look for it
266+ "concept_uri" : "http://www.digitalhps.org/concepts/CON76832db2-7abb-4c77-b08e-239017b6a585"
244267 }
245- mock_get .return_value = MockResponse (json .dumps (mock_response_data ))
268+ # The API response should be a dictionary containing this list under 'conceptEntries'
269+ mock_api_response = {"conceptEntries" : [concept_data_payload ]}
270+ mock_get .return_value = MockResponse (json .dumps (mock_api_response ))
246271
247272 manager = ConceptLifecycle .create (
248273 uri = 'http://vogonweb.net/concept/12345' ,
@@ -265,7 +290,7 @@ def test_add(self, mock_post):
265290 pointing to the new native :class:`.Concept`.
266291 """
267292 # Configure the mock response for a successful POST request
268- mock_post .return_value = MockResponse ({
293+ mock_post .return_value = MockResponse (json . dumps ( {
269294 "uri" : "http://www.digitalhps.org/concepts/CONkLHTIeUQqM7m" , # Native Conceptpower URI
270295 "word" : "kitty_cp" ,
271296 "lemma" : "kitty_cp" ,
@@ -274,7 +299,7 @@ def test_add(self, mock_post):
274299 "type" : {"type_id" : "0d5d1992-957b-49b6-ad7d-117daaf28108" },
275300 "conceptList" : "TestList" ,
276301 "id" : "CONkLHTIeUQqM7m"
277- })
302+ }))
278303
279304 manager = ConceptLifecycle .create (
280305 label = "kitty" ,
@@ -299,10 +324,10 @@ def test_add(self, mock_post):
299324 @patch ('requests.post' )
300325 def test_add_wrapper (self , mock_post ):
301326 r"""
302- For non-created :class:`.Concept`\\ s, the only difference is that the
327+ For non-created :class:`.Concept`\s, the only difference is that the
303328 original :class:`.Concept` is updated directly.
304329 """
305- mock_post .return_value = MockResponse ({
330+ mock_post .return_value = MockResponse (json . dumps ( {
306331 "uri" : "http://example.com/new_concept" ,
307332 "label" : "New Concept" ,
308333 "description" : "A new concept" ,
@@ -311,7 +336,7 @@ def test_add_wrapper(self, mock_post):
311336 "type" : "0d5d1992-957b-49b6-ad7d-117daaf28108" ,
312337 "word" : "new_concept" ,
313338 "equal_to" : "http://viaf.org/viaf/12345" ,
314- })
339+ }))
315340
316341 manager = ConceptLifecycle .create (
317342 label = "kitty2" ,
@@ -320,7 +345,11 @@ def test_add_wrapper(self, mock_post):
320345 resolve = False
321346 )
322347 concept = manager .instance
323- manager .add () # This should update the existing concept
348+
349+ # Mock is_created to be True for this specific manager instance before calling add()
350+ with patch .object (ConceptLifecycle , 'is_created' , new_callable = PropertyMock ) as mock_is_created :
351+ mock_is_created .return_value = True
352+ manager .add () # This should update the existing concept
324353
325354 # Retrieve the potentially updated concept
326355 updated_concept = Concept .objects .get (uri = "http://viaf.org/viaf/12345" )
0 commit comments