Describe the bug
Fossology.item_copyrights is documented and type-annotated as returning int, but it actually returns the raw JSON value from the API, which is a string. The Fossology server returns {"total_copyrights": "0"} (note the quotes), and the library passes that through without coercion.
The function signature at fossology/items.py:55-60:
def item_copyrights(
self,
upload: Upload,
item_id: int,
status: CopyrightStatus,
) -> int:
The implementation at fossology/items.py:79:
if response.status_code == 200:
return response.json()["total_copyrights"]
Why this matters more than a type-annotation nit
The most natural usage pattern is a truthiness check:
if foss.item_copyrights(upload, item_id, CopyrightStatus.ACTIVE):
do_something_with_copyrights()
Under the documented int contract, this is False when the count is 0. Under the actual string return, "0" is truthy in Python, so the branch is taken even when there are zero copyrights. The bug silently produces the wrong logic without raising any error — much worse than a clean TypeError.
Similar quiet wrongness for any arithmetic or comparisons (> 0, += 1, etc.).
Reproduction (against Fossology 4.4.0 / API 1.6.2)
import requests, fossology, secrets, time
from fossology.enums import TokenScope, AccessLevel
URL = "http://localhost/repo"
token = fossology.fossology_token(URL, "fossy", "fossy", secrets.token_urlsafe(8), TokenScope.WRITE)
foss = fossology.Fossology(URL, token)
upload = foss.upload_file(foss.rootFolder, file="tests/files/base-files_11.tar.xz",
description="repro", access_level=AccessLevel.PUBLIC, wait_time=10)
# wait for scanner agents to complete (omitted for brevity)
files, _ = foss.search(license="BSD")
result = foss.item_copyrights(upload, files[0].uploadTreeId, CopyrightStatus.ACTIVE)
print(type(result), repr(result)) # <class 'str'> '0'
print(bool(result)) # True -- BUG: count is 0 but truthy
Raw HTTP response confirming the string shape:
GET /api/v1/uploads/{id}/item/{itemId}/totalcopyrights?status=active
200 OK
{"total_copyrights":"0"}
Affected test on a clean clone
FAILED tests/test_items.py::test_item_copyrights — AssertionError: assert '0' == 0
The existing test already encodes the expected int contract; it just doesn't pass today because the library doesn't honour it.
Proposed fix
One-line coercion at fossology/items.py:79:
- return response.json()["total_copyrights"]
+ return int(response.json()["total_copyrights"])
This matches both the type annotation and the docstring. Locally verified — tests/test_items.py::test_item_copyrights passes after the change, no other test regresses.
Open question for maintainers:
- Is the string return from the Fossology server considered a server bug (filed upstream?) or stable behaviour the wrapper is expected to absorb? Either way, coercion on the client side makes the documented contract hold for users.
Happy to open a PR if you'd like.
Environment
- fossology-python version: 3.5.0 (main)
- Fossology server: 4.4.0 / API 1.6.2 (
fossology/fossology:latest Docker image)
- Python: 3.13
Describe the bug
Fossology.item_copyrightsis documented and type-annotated as returningint, but it actually returns the raw JSON value from the API, which is a string. The Fossology server returns{"total_copyrights": "0"}(note the quotes), and the library passes that through without coercion.The function signature at fossology/items.py:55-60:
The implementation at fossology/items.py:79:
Why this matters more than a type-annotation nit
The most natural usage pattern is a truthiness check:
Under the documented
intcontract, this isFalsewhen the count is 0. Under the actual string return,"0"is truthy in Python, so the branch is taken even when there are zero copyrights. The bug silently produces the wrong logic without raising any error — much worse than a cleanTypeError.Similar quiet wrongness for any arithmetic or comparisons (
> 0,+= 1, etc.).Reproduction (against Fossology 4.4.0 / API 1.6.2)
Raw HTTP response confirming the string shape:
Affected test on a clean clone
The existing test already encodes the expected
intcontract; it just doesn't pass today because the library doesn't honour it.Proposed fix
One-line coercion at
fossology/items.py:79:This matches both the type annotation and the docstring. Locally verified —
tests/test_items.py::test_item_copyrightspasses after the change, no other test regresses.Open question for maintainers:
Happy to open a PR if you'd like.
Environment
fossology/fossology:latestDocker image)