Skip to content

Commit d4c8b7c

Browse files
committed
add user agent tracking
1 parent 107b85f commit d4c8b7c

File tree

10 files changed

+257
-292
lines changed

10 files changed

+257
-292
lines changed

src/nutrient_dws/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
NutrientError,
1212
ValidationError,
1313
)
14+
from nutrient_dws.inputs import (
15+
is_remote_file_input,
16+
process_file_input,
17+
process_remote_file_input,
18+
validate_file_input,
19+
)
20+
from nutrient_dws.utils import get_library_version, get_user_agent
1421

1522
__all__ = [
1623
"APIError",
@@ -19,4 +26,10 @@
1926
"NutrientClient",
2027
"NutrientError",
2128
"ValidationError",
29+
"get_library_version",
30+
"get_user_agent",
31+
"is_remote_file_input",
32+
"process_file_input",
33+
"process_remote_file_input",
34+
"validate_file_input",
2235
]

src/nutrient_dws/http.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
)
2828
from nutrient_dws.types.redact_data import RedactData
2929
from nutrient_dws.types.sign_request import CreateDigitalSignature
30+
from nutrient_dws.utils import get_user_agent
3031

3132

3233
class BuildRequestData(TypedDict):
@@ -515,6 +516,7 @@ async def send_request(
515516

516517
headers = config.get("headers") or {}
517518
headers["Authorization"] = f"Bearer {api_key}"
519+
headers["User-Agent"] = get_user_agent()
518520

519521
# Prepare request configuration
520522
request_config: dict[str, Any] = {

src/nutrient_dws/utils/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .version import get_library_version, get_user_agent
2+
3+
__all__ = ["get_library_version", "get_user_agent"]

src/nutrient_dws/utils/version.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from importlib.metadata import PackageNotFoundError, version
2+
3+
4+
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
11+
12+
return metadata("nutrient-dws")["Version"]
13+
14+
15+
def get_user_agent() -> str:
16+
"""Creates a User-Agent string for HTTP requests."""
17+
return f"nutrient-dws/{get_library_version()}"

tests/conftest.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import os
2+
from unittest.mock import AsyncMock
3+
4+
import pytest
5+
from dotenv import load_dotenv
6+
from nutrient_dws import NutrientClient
7+
from tests.helpers import TestDocumentGenerator
8+
9+
load_dotenv() # Load environment variables
10+
11+
@pytest.fixture
12+
def mock_workflow_instance():
13+
"""Create a mock workflow instance for testing."""
14+
mock_output_stage = AsyncMock()
15+
mock_output_stage.execute.return_value = {
16+
"success": True,
17+
"output": {
18+
"buffer": b"test-buffer",
19+
"mimeType": "application/pdf",
20+
"filename": "output.pdf",
21+
},
22+
}
23+
mock_output_stage.dry_run.return_value = {"success": True}
24+
25+
mock_workflow = AsyncMock()
26+
mock_workflow.add_file_part.return_value = mock_workflow
27+
mock_workflow.add_html_part.return_value = mock_workflow
28+
mock_workflow.add_new_page.return_value = mock_workflow
29+
mock_workflow.add_document_part.return_value = mock_workflow
30+
mock_workflow.apply_actions.return_value = mock_workflow
31+
mock_workflow.apply_action.return_value = mock_workflow
32+
mock_workflow.output_pdf.return_value = mock_output_stage
33+
mock_workflow.output_pdfa.return_value = mock_output_stage
34+
mock_workflow.output_pdfua.return_value = mock_output_stage
35+
mock_workflow.output_image.return_value = mock_output_stage
36+
mock_workflow.output_office.return_value = mock_output_stage
37+
mock_workflow.output_html.return_value = mock_output_stage
38+
mock_workflow.output_markdown.return_value = mock_output_stage
39+
mock_workflow.output_json.return_value = mock_output_stage
40+
41+
return mock_workflow
42+
43+
44+
@pytest.fixture
45+
def valid_client_options():
46+
"""Valid client options for testing."""
47+
return {"apiKey": "test-api-key", "baseUrl": "https://api.test.com/v1"}
48+
49+
@pytest.fixture(scope="class")
50+
def client():
51+
"""Create client instance for testing."""
52+
options = {
53+
"apiKey": os.getenv("NUTRIENT_API_KEY", ""),
54+
"baseUrl": os.getenv("NUTRIENT_BASE_URL", "https://api.nutrient.io"),
55+
}
56+
return NutrientClient(options)
57+
58+
59+
@pytest.fixture
60+
def test_table_pdf():
61+
"""Generate PDF with table for annotation tests."""
62+
return TestDocumentGenerator.generate_pdf_with_table()
63+
64+
@pytest.fixture
65+
def test_xfdf_content():
66+
"""Generate XFDF content for testing."""
67+
return TestDocumentGenerator.generate_xfdf_content()
68+
69+
@pytest.fixture
70+
def test_instant_json_content():
71+
"""Generate Instant JSON content for testing."""
72+
return TestDocumentGenerator.generate_instant_json_content()
73+
74+
@pytest.fixture
75+
def test_sensitive_pdf():
76+
"""Generate PDF with sensitive data for redaction testing."""
77+
return TestDocumentGenerator.generate_pdf_with_sensitive_data()
78+
79+
@pytest.fixture
80+
def test_html_content():
81+
"""Generate HTML content for testing."""
82+
return TestDocumentGenerator.generate_html_content()

0 commit comments

Comments
 (0)