Repository navigation
Send a roboflow-python User-Agent on every SDK request - #559
Merged
Merged
Conversation
The helpers wrap requests' get, post, put, patch, delete, head and request and add `User-Agent: roboflow-python/<version>`; headers the caller passes take precedence. `http.Session` is a requests.Session that sends the same header. `__version__` moves to the top of roboflow/__init__.py, so the helper can read it while the package's own imports are still running. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every requests.<verb>(...) call in roboflow/, and the request functions the Batch Processing adapters pass by reference, now calls the roboflow.util.http helper of the same name. Workspace.search_export builds its session with http.Session, and the two urllib image fetches in roboflow.util.prediction send the header too. ruff's banned-api (TID251) rejects requests.get, post, put, patch, delete, head and request outside roboflow/util/http.py, so a new call can't skip the header. Tests that mocked roboflow.<module>.requests.<verb> now mock roboflow.util.http.requests.<verb>, where the call happens, and the three that compared the whole headers dict expect the User-Agent too. New tests check the header end to end on Roboflow() -> workspace -> project -> version and on an annotated image upload. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 of 7 tasks
iurisilvio
added a commit
that referenced
this pull request
Oct 19, 2026
Image uploads and annotation saves keep going through the per-thread upload session, which is now an http.Session so they send the SDK's User-Agent (#559). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Every HTTP request the SDK and the CLI make now sends
User-Agent: roboflow-python/<version>(todayroboflow-python/1.7.1). Onmainthey send requests' default,python-requests/<version>, which any other Python client sends too, so SDK traffic can't be told apart in the API's request logs, which already record the User-Agent.roboflow/util/http.py(new):get,post,put,patch,delete,headandrequestwrap therequestsfunctions of the same name and add the header. Headers the caller passes take precedence, including aUser-Agentof its own.http.Sessionis arequests.Sessionthat sends the header.requests.<verb>(...)calls in 24 modules underroboflow/call the helper of the same name, and so do the five Batch Processing adapters that handrequests.get/requests.postto_batch_processing_request.Workspace.search_exportbuilds its session withhttp.Session(). The twourllibimage fetches inroboflow/util/prediction.pysend the header too.roboflow/__init__.py:__version__moves to the top, soroboflow.util.httpcan read it while the package's imports run.setup.pyreads it with a regex, which still matches.pyproject.toml: ruff'sbanned-api(TID251) rejectsrequests.get,post,put,patch,delete,headandrequestoutsideroboflow/util/http.py, with a message that names the helper to use instead.requests.Sessionstays allowed because type annotations use it.requestsitself is not patched: code in the user's process that callsrequestsdirectly keeps its own User-Agent.Two commits: the helper, then the switch of the call sites and tests, which is mechanical.
Related Issue(s): none.
Type of Change
Testing
Test details:
tests/util/test_http.py:http.Sessionsend the header, the caller's headers are kept, and a caller's ownUser-Agentwins;Roboflow()→ workspace → project → version, andProject.uploadwith an annotation (the upload and annotate POSTs), send it on every request. Both fail when the header is dropped, and the upload test also fails if the upload goes through a plainrequests.Session();PredictionGroup.savesends it.roboflow.<module>.requests.<verb>now mockroboflow.util.http.requests.<verb>, where the call happens (153 patch targets in 11 files, nothing else changed in them). The three tests that compared the whole headers dict now expect the User-Agent too.python -m unittest: 1241 tests OK, 1 skipped, on Python 3.12 and 3.10 (macOS). The slim job (requirements-slim.txt, thentests.test_slim_compat tests.test_vision_events) passes on 3.10.make check_code_qualitypasses (ruff 0.17.1, mypy 2.4.0).API_URL:Roboflow(api_key=...)androboflow --json auth status --api-key ...sendpython-requests/2.34.2onmainandroboflow-python/1.7.1on this branch.Checklist
Additional Context
requests.Session(). Whichever of the two PRs merges second should build that session withhttp.Session();test_uploading_an_annotated_imagefails until it does.🤖 Generated with Claude Code