From 58c061d086d1e80ca6dd8cdee20b95916d01dc24 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Mon, 11 May 2026 06:27:07 +0000 Subject: [PATCH 1/2] Fixed Python SDK keys to camelCase. Co-authored-by: Divkix --- sdks/python/src/logwell/client.py | 4 ++-- sdks/python/src/logwell/types.py | 8 ++++---- sdks/python/tests/conftest.py | 4 ++-- sdks/python/tests/integration/test_e2e.py | 10 +++++----- sdks/python/tests/unit/test_client.py | 22 +++++++++++----------- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/sdks/python/src/logwell/client.py b/sdks/python/src/logwell/client.py index 52bcbc6..dd5b6f0 100644 --- a/sdks/python/src/logwell/client.py +++ b/sdks/python/src/logwell/client.py @@ -111,9 +111,9 @@ def _add_log(self, entry: LogEntry, skip_frames: int) -> None: # Add source location if captured if source_file is not None: - full_entry["source_file"] = source_file + full_entry["sourceFile"] = source_file if line_number is not None: - full_entry["line_number"] = line_number + full_entry["lineNumber"] = line_number self._queue.add(full_entry) diff --git a/sdks/python/src/logwell/types.py b/sdks/python/src/logwell/types.py index 31dedac..cd395bb 100644 --- a/sdks/python/src/logwell/types.py +++ b/sdks/python/src/logwell/types.py @@ -24,8 +24,8 @@ class LogEntry(TypedDict, total=False): timestamp: ISO8601 timestamp (auto-generated if not provided) service: Service name for this log metadata: Arbitrary key-value metadata - source_file: Source file path where log was called - line_number: Line number where log was called + sourceFile: Source file path where log was called + lineNumber: Line number where log was called """ level: Required[LogLevel] @@ -33,8 +33,8 @@ class LogEntry(TypedDict, total=False): timestamp: str service: str metadata: dict[str, Any] - source_file: str - line_number: int + sourceFile: str + lineNumber: int class LogwellConfig(TypedDict, total=False): diff --git a/sdks/python/tests/conftest.py b/sdks/python/tests/conftest.py index faec2d6..71da5d9 100644 --- a/sdks/python/tests/conftest.py +++ b/sdks/python/tests/conftest.py @@ -345,8 +345,8 @@ def sample_log_entry_full() -> LogEntry: "timestamp": datetime.now(timezone.utc).isoformat(), "service": "test-service", "metadata": {"user_id": "123", "request_id": "abc-def"}, - "source_file": "/app/main.py", - "line_number": 42, + "sourceFile": "/app/main.py", + "lineNumber": 42, } diff --git a/sdks/python/tests/integration/test_e2e.py b/sdks/python/tests/integration/test_e2e.py index 8a96330..1c0b3da 100644 --- a/sdks/python/tests/integration/test_e2e.py +++ b/sdks/python/tests/integration/test_e2e.py @@ -644,9 +644,9 @@ async def test_source_location_captured_when_enabled( # Verify source location is present body = json.loads(mock_server.calls.last.request.content) - assert "source_file" in body[0] - assert "line_number" in body[0] - assert body[0]["source_file"].endswith("test_e2e.py") + assert "sourceFile" in body[0] + assert "lineNumber" in body[0] + assert body[0]["sourceFile"].endswith("test_e2e.py") @pytest.mark.asyncio async def test_source_location_not_captured_when_disabled( @@ -668,8 +668,8 @@ async def test_source_location_not_captured_when_disabled( # Verify source location is not present body = json.loads(mock_server.calls.last.request.content) - assert "source_file" not in body[0] - assert "line_number" not in body[0] + assert "sourceFile" not in body[0] + assert "lineNumber" not in body[0] # ============================================================================= diff --git a/sdks/python/tests/unit/test_client.py b/sdks/python/tests/unit/test_client.py index 5cbb3a1..c04b42e 100644 --- a/sdks/python/tests/unit/test_client.py +++ b/sdks/python/tests/unit/test_client.py @@ -804,8 +804,8 @@ def test_source_location_disabled_by_default(self, valid_config: LogwellConfig) client.info("Test") - assert "source_file" not in captured[0] - assert "line_number" not in captured[0] + assert "sourceFile" not in captured[0] + assert "lineNumber" not in captured[0] def test_source_location_captured_when_enabled( self, valid_api_key: str, valid_endpoint: str @@ -821,10 +821,10 @@ def test_source_location_captured_when_enabled( client.info("Test") - assert "source_file" in captured[0] - assert "line_number" in captured[0] - assert isinstance(captured[0]["line_number"], int) - assert captured[0]["line_number"] > 0 + assert "sourceFile" in captured[0] + assert "lineNumber" in captured[0] + assert isinstance(captured[0]["lineNumber"], int) + assert captured[0]["lineNumber"] > 0 def test_source_location_points_to_caller( self, valid_api_key: str, valid_endpoint: str @@ -841,7 +841,7 @@ def test_source_location_points_to_caller( client.info("Test") # Line number should point to this line # Source file should be this test file - assert "test_client.py" in captured[0]["source_file"] + assert "test_client.py" in captured[0]["sourceFile"] def test_source_location_for_all_log_methods( self, valid_api_key: str, valid_endpoint: str @@ -862,8 +862,8 @@ def test_source_location_for_all_log_methods( client.fatal("fatal") for entry in captured: - assert "source_file" in entry - assert "line_number" in entry + assert "sourceFile" in entry + assert "lineNumber" in entry def test_child_inherits_source_location_setting( self, valid_api_key: str, valid_endpoint: str @@ -880,8 +880,8 @@ def test_child_inherits_source_location_setting( child.info("Child log") - assert "source_file" in captured[0] - assert "line_number" in captured[0] + assert "sourceFile" in captured[0] + assert "lineNumber" in captured[0] # ============================================================================= From 3f33a1c340c5fb890a6fa841f22e953cd538b0a8 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Mon, 11 May 2026 08:35:37 +0000 Subject: [PATCH 2/2] Fixed Python SDK CI: ruff, mypy, twine Co-authored-by: Divkix --- sdks/python/pyproject.toml | 6 +++--- sdks/python/src/logwell/queue.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sdks/python/pyproject.toml b/sdks/python/pyproject.toml index 48bac51..0c06900 100644 --- a/sdks/python/pyproject.toml +++ b/sdks/python/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["hatchling"] +requires = ["hatchling<1.27.0"] build-backend = "hatchling.build" [project] @@ -7,7 +7,7 @@ name = "logwell" version = "1.0.3" description = "Official Python SDK for Logwell logging platform" readme = "README.md" -license = "MIT" +license = {text = "MIT"} authors = [{ name = "Divkix", email = "divkix@divkix.me" }] keywords = ["logging", "logs", "observability", "logwell", "python"] classifiers = [ @@ -47,7 +47,7 @@ Issues = "https://github.com/Divkix/Logwell/issues" packages = ["src/logwell"] [tool.mypy] -python_version = "3.9" +python_version = "3.10" strict = true warn_return_any = true warn_unused_configs = true diff --git a/sdks/python/src/logwell/queue.py b/sdks/python/src/logwell/queue.py index cb42b91..e18f994 100644 --- a/sdks/python/src/logwell/queue.py +++ b/sdks/python/src/logwell/queue.py @@ -136,7 +136,7 @@ def add(self, entry: LogEntry) -> None: self._queue.append(entry) # Start timer on first entry - timer_future = getattr(self, '_timer_future', None) + timer_future = getattr(self, "_timer_future", None) if (timer_future is None or timer_future.done()) and not self._stopped: self._start_timer() @@ -276,7 +276,7 @@ def _stop_timer(self) -> None: Note: Must be called while holding the lock. """ - future = getattr(self, '_timer_future', None) + future = getattr(self, "_timer_future", None) if future is not None: if not future.done(): future.cancel() @@ -284,7 +284,7 @@ def _stop_timer(self) -> None: async def _timer_coro(self) -> None: """Handle timer expiration by triggering a flush.""" - my_future = getattr(self, '_timer_future', None) + my_future = getattr(self, "_timer_future", None) try: await asyncio.sleep(self._config.flush_interval) with self._lock: @@ -294,5 +294,5 @@ async def _timer_coro(self) -> None: except asyncio.CancelledError: pass finally: - if getattr(self, '_timer_future', None) is my_future: + if getattr(self, "_timer_future", None) is my_future: self._timer_future = None