You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Is there a way to query an individual photo's safety level? I don't see a call for that in the Flickr API. They have flickr.photos.setSafetyLevel but no flickr.photos.getSafetyLevel. Basically I want to find all photos with a specific tag, test the safety level, and if it's not set to what I want, then set it.
Hi @rodmur — you're right that there's no flickr.photos.getSafetyLevel endpoint, but the safety level is returned by flickr.photos.getInfo (and by search with extras="safety_level"), so you can read it without any new code.
With the currently released version
Load the photo (which calls getInfo under the hood) and read the safety_level attribute. Note it comes back as a string ("0", "1", "2", "3"):
photo=flickr_api.Photo(id="12345")
photo.load()
print(photo.safety_level) # e.g. "3"
For your exact use case — find photos by tag, check the level, fix it if wrong — ask search to include the value via extras so you don't need a separate getInfo call per photo:
forpinflickr_api.Photo.search(tags="mytag", extras="safety_level"):
ifp.safety_level!="3": # string comparison, or int(p.safety_level)p.setSafetyLevel(safety_level=3)
getSafetyLevel() also loads the photo for you if the value isn't already present, so flickr_api.Photo(id="12345").getSafetyLevel() works directly. The integer values match what setSafetyLevel accepts.
I've done a little bit of testing, and off hand it appears getSafetyLevel() returns 0=safe, 1=moderate, 2=restricted, but if you want to set the safety level, setSafetyLevel(safety_level=#) needs 1=safe, 2=moderate, 3=restricted. So everything is offset by 1.
Also I get to a point where flickr_api.Photo.search() just seems to be loading the same set or page of photos over and over again, is there way to get it to advance? I do provide it a "page=p" argument, but it seems to be ignoring it, like it hit some max and can't continue.
Good catches. Thanks for testing!! Two different things going on:
Safety level. You're right about the offset, but it's not a bug on either side. Flickr's own API is asymmetric: getInfo/search report the level 0-indexed (0=safe, 1=moderate, 2=restricted), while setSafetyLevel wants it 1-indexed (1/2/3). This wrapper passes both through unchanged on purpose, so you inherit Flickr's mismatch. My fault was the 0.8.1 docstring claiming they matched. I've corrected in #175. To round-trip, add one:
Pagination. The library does pass page= through. What you hit is a Flickr limit: flickr.photos.search only lets you page through roughly the first 4,000 results, then keeps returning the last reachable page. The workaround is to narrow each query (e.g. slice by min_upload_date/max_upload_date and walk the windows, with sort="date-posted-asc" for stable ordering) so no single query exceeds the cap.
Activity
Add Photo.getSafetyLevel() and int-convert safety_level (#173) (#174)
beaufour commentedon Jul 1, 2026
Hi @rodmur — you're right that there's no
flickr.photos.getSafetyLevelendpoint, but the safety level is returned byflickr.photos.getInfo(and bysearchwithextras="safety_level"), so you can read it without any new code.With the currently released version
Load the photo (which calls
getInfounder the hood) and read thesafety_levelattribute. Note it comes back as a string ("0","1","2","3"):For your exact use case — find photos by tag, check the level, fix it if wrong — ask
searchto include the value viaextrasso you don't need a separategetInfocall per photo:With the latest code (PR #174, now merged)
There's now a
Photo.getSafetyLevel()helper, andsafety_levelis converted to anintautomatically, so you don't have to deal with strings:getSafetyLevel()also loads the photo for you if the value isn't already present, soflickr_api.Photo(id="12345").getSafetyLevel()works directly. The integer values match whatsetSafetyLevelaccepts.Hope that helps!
rodmur commentedon Jul 4, 2026
Thanks! I'm not all that expert with git, how do I build this? I've cloned the repo, but just running make gives me
` python-flickr-api git:(master) make
bash ./release.sh
++ uv run python -c 'from flickr_api._version import version as v; print(v)'
fatal: tag 'v0.8.0' already exists
make: *** [release] Error 128
`
Should I increment that tab? Or should I just wait for a new release?
I realize now, I should probably be using
uv build, and maybeuv pip install?beaufour commentedon Jul 5, 2026
No sweat. I just released 0.8.1, so you should be able to just install that.
rodmur commentedon Jul 6, 2026
Thanks, upgraded.
I've done a little bit of testing, and off hand it appears
getSafetyLevel()returns 0=safe, 1=moderate, 2=restricted, but if you want to set the safety level,setSafetyLevel(safety_level=#)needs 1=safe, 2=moderate, 3=restricted. So everything is offset by 1.Also I get to a point where
flickr_api.Photo.search()just seems to be loading the same set or page of photos over and over again, is there way to get it to advance? I do provide it a "page=p" argument, but it seems to be ignoring it, like it hit some max and can't continue.beaufour commentedon Jul 7, 2026
Good catches. Thanks for testing!! Two different things going on:
Safety level. You're right about the offset, but it's not a bug on either side. Flickr's own API is asymmetric:
getInfo/searchreport the level 0-indexed (0=safe,1=moderate,2=restricted), whilesetSafetyLevelwants it 1-indexed (1/2/3). This wrapper passes both through unchanged on purpose, so you inherit Flickr's mismatch. My fault was the 0.8.1 docstring claiming they matched. I've corrected in #175. To round-trip, add one:Pagination. The library does pass
page=through. What you hit is a Flickr limit:flickr.photos.searchonly lets you page through roughly the first 4,000 results, then keeps returning the last reachable page. The workaround is to narrow each query (e.g. slice bymin_upload_date/max_upload_dateand walk the windows, withsort="date-posted-asc"for stable ordering) so no single query exceeds the cap.