Skip to content

Commit 9ca6eeb

Browse files
committed
feat: set UserAgent version to 0.0.0-dev when developing
1 parent 00cb859 commit 9ca6eeb

File tree

10 files changed

+47
-26
lines changed

10 files changed

+47
-26
lines changed

.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
# Nutrient DWS Processor API Configuration for Testing
22
NUTRIENT_API_KEY=your_api_key_here
33
NUTRIENT_BASE_URL=https://api.nutrient.io
4+
5+
# Development Settings
6+
DEBUG=true
7+
PYTHON_ENV=development

examples/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
NUTRIENT_API_KEY=your_api_key_here
2+
PYTHON_ENV=development

src/nutrient_dws/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def _validate_options(self, options: NutrientClientOptions) -> None:
152152
raise ValidationError("API key is required")
153153

154154
api_key = options["apiKey"]
155-
if not isinstance(api_key, (str, type(lambda: None))):
155+
if not (isinstance(api_key, str) or callable(api_key)):
156156
raise ValidationError(
157157
"API key must be a string or a function that returns a string"
158158
)

src/nutrient_dws/inputs.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ def is_url(string: str) -> bool:
3333

3434
def is_valid_pdf(file_bytes: bytes) -> bool:
3535
"""Check if a file is a valid PDF."""
36-
pdf_header = file_bytes[:5].decode("ascii")
37-
return pdf_header == "%PDF-"
36+
return file_bytes.startswith(b"%PDF-")
3837

3938

4039
def is_remote_file_input(file_input: FileInput) -> TypeGuard[str]:

src/nutrient_dws/utils/version.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1-
from importlib.metadata import PackageNotFoundError, version
1+
import os
2+
from importlib.metadata import version as pkg_version
23

34

45
def get_library_version() -> str:
5-
"""Gets the current version of the Nutrient DWS Python Client library."""
6-
try:
7-
return version("nutrient-dws")
8-
except PackageNotFoundError:
9-
# fallback for when running from source (not installed yet)
10-
from importlib.metadata import metadata
6+
"""Gets the current version of the Nutrient DWS Python Client library.
117
12-
return metadata("nutrient-dws")["Version"]
8+
Strategy: Try importlib.metadata.version("nutrient-dws"); on any failure, return "0.0.0-dev".
9+
"""
10+
if os.getenv("PYTHON_ENV") == "development":
11+
return "0.0.0-dev"
12+
try:
13+
return pkg_version("nutrient-dws")
14+
except Exception:
15+
return "0.0.0-dev"
1316

1417

1518
def get_user_agent() -> str:
1619
"""Creates a User-Agent string for HTTP requests."""
17-
return f"nutrient-dws/{get_library_version()}"
20+
package_version = get_library_version()
21+
return f"nutrient-dws/{package_version}"

tests/conftest.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
import os
21
from unittest.mock import AsyncMock
32

43
import pytest
5-
from dotenv import load_dotenv
64
from nutrient_dws import NutrientClient
75
from tests.helpers import TestDocumentGenerator
86

9-
load_dotenv() # Load environment variables
10-
117
@pytest.fixture
128
def mock_workflow_instance():
139
"""Create a mock workflow instance for testing."""
@@ -50,12 +46,6 @@ def valid_client_options():
5046
def unit_client():
5147
return NutrientClient(api_key="test-api-key", base_url="https://api.test.com/v1")
5248

53-
@pytest.fixture(scope="class")
54-
def integration_client():
55-
"""Create client instance for testing."""
56-
return NutrientClient(api_key=os.getenv("NUTRIENT_API_KEY", ""), base_url=os.getenv("NUTRIENT_BASE_URL", "https://api.nutrient.io"))
57-
58-
5949
@pytest.fixture
6050
def test_table_pdf():
6151
"""Generate PDF with table for annotation tests."""

tests/test_integration.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434
reason="Integration tests require NUTRIENT_API_KEY environment variable",
3535
)
3636

37+
@pytest.fixture(scope="class")
38+
def integration_client():
39+
"""Create client instance for testing."""
40+
return NutrientClient(api_key=os.getenv("NUTRIENT_API_KEY", ""), base_url=os.getenv("NUTRIENT_BASE_URL", "https://api.nutrient.io"))
41+
3742

3843
class TestIntegrationDirectMethods:
3944
"""Integration tests with live API - direct client methods."""
@@ -165,7 +170,7 @@ async def test_convert_formats(
165170
if output_type not in ["markdown", "html"]:
166171
assert isinstance(result.get("buffer"), (bytes, bytearray))
167172
else:
168-
assert isinstance(result.get("content"), bytes)
173+
assert isinstance(result.get("content"), str)
169174
assert result["mimeType"] == expected_mime
170175

171176
@pytest.mark.asyncio

tests/unit/test_builder.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,7 @@ async def mock_request(endpoint, data):
840840
assert result["success"] is True
841841
assert (
842842
result["output"]["content"]
843-
== b"<html><body>Content</body></html>"
843+
== "<html><body>Content</body></html>"
844844
)
845845
assert result["output"]["mimeType"] == "text/html"
846846
assert result["output"]["filename"] == "output.html"
@@ -873,7 +873,7 @@ async def mock_request(endpoint, data):
873873
result = await builder.execute()
874874

875875
assert result["success"] is True
876-
assert result["output"]["content"] == b"# Header\n\nContent"
876+
assert result["output"]["content"] == "# Header\n\nContent"
877877
assert result["output"]["mimeType"] == "text/markdown"
878878
assert result["output"]["filename"] == "output.md"
879879

tests/unit/test_http.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ async def test_successful_get_request(self):
178178
assert call_kwargs["method"] == "GET"
179179
assert call_kwargs["url"] == "https://api.test.com/v1/account/info"
180180
assert call_kwargs["headers"]["Authorization"] == "Bearer test-api-key"
181-
assert re.match(r'^nutrient-dws/\d+\.\d+\.\d+', call_kwargs["headers"]["User-Agent"])
181+
assert re.match(r'^nutrient-dws/\d+\.\d+\.\d+(?:-[a-zA-Z0-9.-]+)?', call_kwargs["headers"]["User-Agent"])
182182
assert call_kwargs["timeout"] is None
183183

184184
assert result["data"] == {"result": "success"}

tests/unit/test_utils.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import os
2+
from unittest import mock
3+
14
import pytest
25
import re
36
from nutrient_dws.utils import (
@@ -46,6 +49,21 @@ def test_get_user_agent_follows_expected_format(self):
4649
expected_pattern = r'^nutrient-dws/\d+\.\d+\.\d+(?:-[a-zA-Z0-9.-]+)?$'
4750
assert re.match(expected_pattern, user_agent)
4851

52+
@mock.patch.dict(
53+
os.environ,
54+
{
55+
"PYTHON_ENV": "development",
56+
},
57+
clear=True,
58+
)
59+
def test_get_user_agent_follows_expected_format_development(self):
60+
"""Should follow the expected User-Agent format in development"""
61+
user_agent = get_user_agent()
62+
63+
# Should match: nutrient-dws/VERSION
64+
assert user_agent == "nutrient-dws/0.0.0-dev"
65+
66+
4967
def test_get_user_agent_includes_correct_library_name(self):
5068
"""Should include the correct library name"""
5169
user_agent = get_user_agent()

0 commit comments

Comments
 (0)