From 1c5b4f1a658e2a13a55e6f2fcdb117055bccfb59 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Wed, 6 May 2026 03:08:18 +0400 Subject: [PATCH 1/4] fix: enforce non-empty strings for type and source fields Changed validation error messages in schema_loader.py to require non-empty strings for type and source fields. Updated test_schema_loader.py to reflect these changes. Now, type and source fields must be non-empty strings to pass validation. Signed-off-by: Dmitrii Safronov --- .../schema_loader.py | 7 ++-- tests/private/test_schema_loader.py | 42 +++++++++---------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index 62a300f..7fb7061 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -491,7 +491,7 @@ def _validate_and_create_leaf( problems.append( _SchemaProblem( f"Incomplete leaf at {_format_path(path, key)}: " - f"type cannot be None or empty", + f"type must be a non-empty string", ), ) @@ -499,7 +499,7 @@ def _validate_and_create_leaf( problems.append( _SchemaProblem( f"Incomplete leaf at {_format_path(path, key)}: " - f"source cannot be None or empty", + f"source must be a non-empty string", ), ) @@ -526,8 +526,7 @@ def _validate_and_create_leaf( problems.append( _SchemaProblem( f"Incomplete leaf at {_format_path(path, key)}: " - f"item_type is required for list type and " - f"cannot be None or empty", + f"item_type must be a non-empty string", ), ) return None diff --git a/tests/private/test_schema_loader.py b/tests/private/test_schema_loader.py index 0de060c..5d6169b 100644 --- a/tests/private/test_schema_loader.py +++ b/tests/private/test_schema_loader.py @@ -310,7 +310,7 @@ def test_incomplete_leaf_missing_type( compiled, problems = compile_schema_internal() assert isinstance(compiled, _CompiledSchema) assert compiled.is_empty - assert any("type cannot be None or empty" in p.message for p in problems) + assert any("type must be a non-empty string" in p.message for p in problems) def test_incomplete_leaf_missing_source( @@ -332,7 +332,7 @@ def test_incomplete_leaf_missing_source( compiled, problems = compile_schema_internal() assert isinstance(compiled, _CompiledSchema) assert compiled.is_empty - assert any("source cannot be None or empty" in p.message for p in problems) + assert any("source must be a non-empty string" in p.message for p in problems) def test_incomplete_leaf_empty_source( @@ -354,7 +354,7 @@ def test_incomplete_leaf_empty_source( compiled, problems = compile_schema_internal() assert isinstance(compiled, _CompiledSchema) assert compiled.is_empty - assert any("source cannot be None or empty" in p.message for p in problems) + assert any("source must be a non-empty string" in p.message for p in problems) def test_incomplete_leaf_empty_type( @@ -376,7 +376,7 @@ def test_incomplete_leaf_empty_type( compiled, problems = compile_schema_internal() assert isinstance(compiled, _CompiledSchema) assert compiled.is_empty - assert any("type cannot be None or empty" in p.message for p in problems) + assert any("type must be a non-empty string" in p.message for p in problems) def test_multiple_root_keys_with_valid_leaves( @@ -666,7 +666,7 @@ def test_validate_and_create_leaf_missing_type() -> None: assert leaf is None assert len(problems) == 1 - assert "type cannot be None or empty" in problems[0].message + assert "type must be a non-empty string" in problems[0].message def test_validate_and_create_leaf_missing_source() -> None: @@ -680,7 +680,7 @@ def test_validate_and_create_leaf_missing_source() -> None: assert leaf is None assert len(problems) == 1 - assert "source cannot be None or empty" in problems[0].message + assert "source must be a non-empty string" in problems[0].message def test_validate_and_create_leaf_empty_type() -> None: @@ -694,7 +694,7 @@ def test_validate_and_create_leaf_empty_type() -> None: assert leaf is None assert len(problems) == 1 - assert "type cannot be None or empty" in problems[0].message + assert "type must be a non-empty string" in problems[0].message def test_validate_and_create_leaf_whitespace_type() -> None: @@ -708,7 +708,7 @@ def test_validate_and_create_leaf_whitespace_type() -> None: assert leaf is None assert len(problems) == 1 - assert "type cannot be None or empty" in problems[0].message + assert "type must be a non-empty string" in problems[0].message def test_validate_and_create_leaf_empty_source() -> None: @@ -722,7 +722,7 @@ def test_validate_and_create_leaf_empty_source() -> None: assert leaf is None assert len(problems) == 1 - assert "source cannot be None or empty" in problems[0].message + assert "source must be a non-empty string" in problems[0].message def test_validate_and_create_leaf_whitespace_source() -> None: @@ -736,7 +736,7 @@ def test_validate_and_create_leaf_whitespace_source() -> None: assert leaf is None assert len(problems) == 1 - assert "source cannot be None or empty" in problems[0].message + assert "source must be a non-empty string" in problems[0].message def test_validate_and_create_leaf_unknown_type() -> None: @@ -763,7 +763,7 @@ def test_validate_and_create_leaf_list_missing_item_type() -> None: assert leaf is None assert len(problems) == 1 - assert "item_type is required for list type" in problems[0].message + assert "item_type must be a non-empty string" in problems[0].message def test_validate_and_create_leaf_list_empty_item_type() -> None: @@ -775,7 +775,7 @@ def test_validate_and_create_leaf_list_empty_item_type() -> None: assert leaf is None assert len(problems) == 1 - assert "item_type is required for list type" in problems[0].message + assert "item_type must be a non-empty string" in problems[0].message def test_validate_and_create_leaf_list_invalid_item_type() -> None: @@ -1832,7 +1832,7 @@ def test_node_with_only_item_type_as_string_produces_problem( assert isinstance(compiled, _CompiledSchema) assert compiled.is_empty # Should have problems because type and source are required - assert any("type cannot be None or empty" in p.message for p in problems) + assert any("type must be a non-empty string" in p.message for p in problems) def test_node_with_type_as_number_produces_problem( @@ -1859,7 +1859,7 @@ def test_node_with_type_as_number_produces_problem( assert isinstance(compiled, _CompiledSchema) assert compiled.is_empty # Should have problem because type must be a string, not a number - assert any("type cannot be None or empty" in p.message for p in problems) + assert any("type must be a non-empty string" in p.message for p in problems) def test_node_with_type_as_boolean_produces_problem( @@ -1886,7 +1886,7 @@ def test_node_with_type_as_boolean_produces_problem( assert isinstance(compiled, _CompiledSchema) assert compiled.is_empty # Should have problem because type must be a string, not boolean - assert any("type cannot be None or empty" in p.message for p in problems) + assert any("type must be a non-empty string" in p.message for p in problems) def test_node_with_source_as_boolean_produces_problem( @@ -1913,7 +1913,7 @@ def test_node_with_source_as_boolean_produces_problem( assert isinstance(compiled, _CompiledSchema) assert compiled.is_empty # Should have problem because source must be a string, not boolean - assert any("source cannot be None or empty" in p.message for p in problems) + assert any("source must be a non-empty string" in p.message for p in problems) def test_node_with_source_as_number_produces_problem( @@ -1940,7 +1940,7 @@ def test_node_with_source_as_number_produces_problem( assert isinstance(compiled, _CompiledSchema) assert compiled.is_empty # Should have problem because source must be a string, not number - assert any("source cannot be None or empty" in p.message for p in problems) + assert any("source must be a non-empty string" in p.message for p in problems) def test_node_with_type_and_source_as_numbers_produces_problem( @@ -2021,7 +2021,7 @@ def test_node_with_item_type_as_number_produces_problem( assert isinstance(compiled, _CompiledSchema) assert compiled.is_empty # Should have problem because item_type must be a string, not a number - assert any("item_type is required for list type" in p.message for p in problems) + assert any("item_type must be a non-empty string" in p.message for p in problems) def test_node_with_item_type_as_boolean_produces_problem( @@ -2052,7 +2052,7 @@ def test_node_with_item_type_as_boolean_produces_problem( assert isinstance(compiled, _CompiledSchema) assert compiled.is_empty # Should have problem because item_type must be a string, not a boolean - assert any("item_type is required for list type" in p.message for p in problems) + assert any("item_type must be a non-empty string" in p.message for p in problems) def test_node_with_item_type_as_object_is_determined_as_inner( @@ -2113,7 +2113,7 @@ def test_node_with_type_as_list_produces_problem( assert isinstance(compiled, _CompiledSchema) assert compiled.is_empty # Should have problem because type must be a string, not a list - assert any("type cannot be None or empty" in p.message for p in problems) + assert any("type must be a non-empty string" in p.message for p in problems) def test_node_with_source_as_list_produces_problem( @@ -2143,4 +2143,4 @@ def test_node_with_source_as_list_produces_problem( assert isinstance(compiled, _CompiledSchema) assert compiled.is_empty # Should have problem because source must be a string, not a list - assert any("source cannot be None or empty" in p.message for p in problems) + assert any("source must be a non-empty string" in p.message for p in problems) From b38a2482863244d6fe08102f4583d35ec6cf7b68 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Wed, 6 May 2026 03:08:38 +0400 Subject: [PATCH 2/4] docs: Update type checking in README fix(type checking): clarify type checks using type() instead of isinstance() to ensure strict type matching without implicit conversions Signed-off-by: Dmitrii Safronov --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index a841ec5..47acf75 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,9 @@ systems) can rely on a consistent log structure. problem. - Any mismatch between runtime values and the declared types (wrong types, `None` values, disallowed list elements) is also treated as a data error. + Type checks use `type()`, not `isinstance()`: `bool` is **not** accepted + where `int` is declared, and `int` is **not** accepted where `float` is + declared. There are no implicit type conversions. - All validation problems are aggregated and logged as a single ERROR message **after** the log record has been emitted, ensuring 100% compatibility with standard logger behavior (no exceptions are raised). From e19bd7f4941f44f5e5c35e14f483e45ea04c4e6c Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Wed, 6 May 2026 03:15:47 +0400 Subject: [PATCH 3/4] ci: fix auto-pr-description workflow fix auto-pr-description.yml to exclude dependencies and only run on specific branch combinations Signed-off-by: Dmitrii Safronov --- .github/workflows/auto-pr-description.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/auto-pr-description.yml b/.github/workflows/auto-pr-description.yml index dd31ff3..0d9cb8a 100644 --- a/.github/workflows/auto-pr-description.yml +++ b/.github/workflows/auto-pr-description.yml @@ -17,7 +17,8 @@ jobs: contents: read pull-requests: write if: >- - github.event_name == 'pull_request' && ( + github.event_name == 'pull_request' && + !contains(github.event.pull_request.labels.*.name, 'dependencies') && ( (github.event.pull_request.base.ref == 'release' && github.event.pull_request.head.ref == 'main') || (github.event.pull_request.base.ref == 'main' && github.event.pull_request.head.ref != 'release') ) From 378da7a1b2071fa794eaddf1545e8c2b7856443d Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Wed, 6 May 2026 03:19:50 +0400 Subject: [PATCH 4/4] feat!: promote to stable 1.0.0 BREAKING CHANGE: first stable release, no longer considered experimental Signed-off-by: Dmitrii Safronov