Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions flickr_api/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,7 @@ class Photo(FlickrObject):
),
dict_converter(["posted", "lastupdate"], int),
dict_converter(["views", "comments"], int),
dict_converter(["safety_level"], int),
]
__display__ = ["id", "title"]
__self_name__ = "photo_id"
Expand Down Expand Up @@ -1182,6 +1183,21 @@ def format_result(r, token=None):

return args, format_result

def getSafetyLevel(self) -> int:
"""Return the safety level of the photo.

Flickr does not provide a dedicated ``flickr.photos.getSafetyLevel``
method, so the value is read from ``flickr.photos.getInfo`` (loading
the photo first if it has not been loaded yet).

Returns an integer safety level:
``0`` (none), ``1`` (safe), ``2`` (moderate) or ``3`` (restricted).
These match the values accepted by :meth:`setSafetyLevel`.
"""
if not hasattr(self, "safety_level"):
self.load()
return int(self.safety_level)

@caller("flickr.photos.getContactsPhotos")
def getContactsPhotos(self, **args):
def format_result(r, token=None):
Expand Down
68 changes: 68 additions & 0 deletions test/test_photos.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,74 @@ def test_photo_get_info(self, mock_post):
# Note: _content is renamed to text by clean_content
self.assertEqual(photo.notes[0].text, "foo")

@patch.object(method_call.requests, "post")
def test_photo_get_info_safety_level(self, mock_post):
"""Test that getInfo exposes safety_level as an int (issue #173)"""
json_response = {
"photo": {
"id": "2733",
"secret": "123456",
"server": "12",
"safety_level": "2",
"owner": {"nsid": "12037949754@N01"},
"title": {"_content": "t"},
"visibility": {"ispublic": 1, "isfriend": 0, "isfamily": 0},
"dates": {"posted": "1100897479", "lastupdate": "1093022469"},
"usage": {"candownload": 1},
"publiceditability": {"cancomment": 1, "canaddmeta": 1},
"tags": {"tag": []},
"notes": {"note": []},
}
}
mock_post.return_value = self._mock_response(json_response)

photo = f.Photo(id="2733")
photo.getInfo()

# safety_level is converted from the API string to an int
self.assertEqual(photo.safety_level, 2)

@patch.object(method_call.requests, "post")
def test_photo_get_safety_level_loads(self, mock_post):
"""Test Photo.getSafetyLevel loads the photo when needed (issue #173)"""
json_response = {
"photo": {
"id": "2733",
"secret": "123456",
"server": "12",
"safety_level": "3",
"owner": {"nsid": "12037949754@N01"},
"title": {"_content": "t"},
"visibility": {"ispublic": 1, "isfriend": 0, "isfamily": 0},
"dates": {"posted": "1100897479", "lastupdate": "1093022469"},
"usage": {"candownload": 1},
"publiceditability": {"cancomment": 1, "canaddmeta": 1},
"tags": {"tag": []},
"notes": {"note": []},
}
}
mock_post.return_value = self._mock_response(json_response)

# Photo has not been loaded, so getSafetyLevel triggers getInfo
photo = f.Photo(id="2733")
level = photo.getSafetyLevel()

self.assertEqual(level, 3)
self.assertIsInstance(level, int)
# getInfo was called exactly once to load the photo
self.assertEqual(mock_post.call_count, 1)

@patch.object(method_call.requests, "post")
def test_photo_get_safety_level_already_loaded(self, mock_post):
"""Test Photo.getSafetyLevel avoids a call when already known (issue #173)"""
# safety_level already present (e.g. from search extras="safety_level")
photo = f.Photo(id="2733", safety_level="1")
level = photo.getSafetyLevel()

self.assertEqual(level, 1)
self.assertIsInstance(level, int)
# No API call needed
self.assertEqual(mock_post.call_count, 0)

@patch.object(method_call.requests, "post")
def test_person_get_not_in_set_photos(self, mock_post):
Expand Down
Loading