heurist-api 0.1.3__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of heurist-api might be problematic. Click here for more details.

Files changed (128) hide show
  1. {heurist_api-0.1.3 → heurist_api-0.2.0}/PKG-INFO +15 -1
  2. {heurist_api-0.1.3 → heurist_api-0.2.0}/README.md +17 -3
  3. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/index.md +3 -6
  4. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/usage/index.md +4 -7
  5. {heurist_api-0.1.3 → heurist_api-0.2.0}/mkdocs.yml +1 -1
  6. {heurist_api-0.1.3 → heurist_api-0.2.0}/pyproject.toml +3 -2
  7. heurist_api-0.2.0/src/heurist/cli/parse_log.py +22 -0
  8. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/database/database.py +2 -0
  9. heurist_api-0.2.0/src/heurist/log/__init__.py +2 -0
  10. heurist_api-0.2.0/src/heurist/log/iterator.py +16 -0
  11. heurist_api-0.2.0/src/heurist/log/model.py +42 -0
  12. heurist_api-0.2.0/tests/unit/log_test.py +44 -0
  13. {heurist_api-0.1.3 → heurist_api-0.2.0}/uv.lock +16 -19
  14. {heurist_api-0.1.3 → heurist_api-0.2.0}/.github/workflows/pypi-release.yml +0 -0
  15. {heurist_api-0.1.3 → heurist_api-0.2.0}/.github/workflows/python-package.yml +0 -0
  16. {heurist_api-0.1.3 → heurist_api-0.2.0}/.gitignore +0 -0
  17. {heurist_api-0.1.3 → heurist_api-0.2.0}/.pre-commit-config.yaml +0 -0
  18. {heurist_api-0.1.3 → heurist_api-0.2.0}/LICENSE +0 -0
  19. {heurist_api-0.1.3 → heurist_api-0.2.0}/demos/pandas_dataframe.ipynb +0 -0
  20. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/assets/coverage-badge.svg +0 -0
  21. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/assets/erc-logo.png +0 -0
  22. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/assets/heurist-admin-panel-users.png +0 -0
  23. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/assets/logo-transparent-1.png +0 -0
  24. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/assets/logo-transparent.png +0 -0
  25. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/assets/logo.png +0 -0
  26. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/assets/tests-badge.svg +0 -0
  27. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/development/code_of_conduct.md +0 -0
  28. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/development/contributing.md +0 -0
  29. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/development/coverage.md +0 -0
  30. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/development/heuristdb/temporal.md +0 -0
  31. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/development/publishing.md +0 -0
  32. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/legal.md +0 -0
  33. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/usage/download/date_validation.md +0 -0
  34. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/usage/download/export_csv.md +0 -0
  35. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/usage/download/group_types.md +0 -0
  36. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/usage/download/index.md +0 -0
  37. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/usage/download/logs.md +0 -0
  38. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/usage/download/user_filter.md +0 -0
  39. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/usage/module.md +0 -0
  40. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/usage/records.md +0 -0
  41. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/usage/rstudio.md +0 -0
  42. {heurist_api-0.1.3 → heurist_api-0.2.0}/docs/usage/schema.md +0 -0
  43. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/__init__.py +0 -0
  44. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/api/__init__.py +0 -0
  45. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/api/client.py +0 -0
  46. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/api/connection.py +0 -0
  47. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/api/constants.py +0 -0
  48. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/api/credentials.py +0 -0
  49. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/api/exceptions.py +0 -0
  50. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/api/url_builder.py +0 -0
  51. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/api/utils.py +0 -0
  52. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/cli/__init__.py +0 -0
  53. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/cli/__main__.py +0 -0
  54. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/cli/load.py +0 -0
  55. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/cli/records.py +0 -0
  56. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/cli/schema.py +0 -0
  57. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/database/__init__.py +0 -0
  58. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/database/basedb.py +0 -0
  59. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/__init__.py +0 -0
  60. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/dynamic/__init__.py +0 -0
  61. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/dynamic/annotation.py +0 -0
  62. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/dynamic/create_model.py +0 -0
  63. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/dynamic/date.py +0 -0
  64. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/dynamic/type.py +0 -0
  65. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/structural/DetailTypes.py +0 -0
  66. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/structural/RecStructure.py +0 -0
  67. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/structural/RecTypeGroups.py +0 -0
  68. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/structural/RecTypes.py +0 -0
  69. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/structural/Terms.py +0 -0
  70. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/structural/__init__.py +0 -0
  71. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/structural/dty.py +0 -0
  72. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/structural/hml_structure.py +0 -0
  73. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/structural/rst.py +0 -0
  74. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/structural/rtg.py +0 -0
  75. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/structural/rty.py +0 -0
  76. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/structural/trm.py +0 -0
  77. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/models/structural/utils.py +0 -0
  78. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/schema/__init__.py +0 -0
  79. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/schema/models.py +0 -0
  80. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/schema/rel_to_dict.py +0 -0
  81. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/sql/__init__.py +0 -0
  82. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/sql/joinRecordTypeIDNameByGroupType.sql +0 -0
  83. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/sql/joinRecordTypeMetadata.sql +0 -0
  84. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/sql/selectRecordTypeSchema.sql +0 -0
  85. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/sql/sql_safety.py +0 -0
  86. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/utils/constants.py +0 -0
  87. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/utils/rel_to_dict_array.py +0 -0
  88. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/validators/__init__.py +0 -0
  89. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/validators/detail_validator.py +0 -0
  90. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/validators/exceptions.py +0 -0
  91. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/validators/parse_heurist_date.py +0 -0
  92. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/validators/record_validator.py +0 -0
  93. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/workflows/__init__.py +0 -0
  94. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/heurist/workflows/etl.py +0 -0
  95. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/__init__.py +0 -0
  96. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/blocktext/__init__.py +0 -0
  97. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/blocktext/single.py +0 -0
  98. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/date/__init__.py +0 -0
  99. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/date/compound_repeated.py +0 -0
  100. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/date/compound_single.py +0 -0
  101. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/date/simple_single.py +0 -0
  102. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/date/timestamp_repeated.py +0 -0
  103. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/enum/__init__.py +0 -0
  104. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/enum/repeated.py +0 -0
  105. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/enum/single.py +0 -0
  106. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/file/__init__.py +0 -0
  107. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/file/single.py +0 -0
  108. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/float/__init__.py +0 -0
  109. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/float/single.py +0 -0
  110. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/freetext/__init__.py +0 -0
  111. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/freetext/single.py +0 -0
  112. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/geo/__init__.py +0 -0
  113. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/geo/single.py +0 -0
  114. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/resource/__init__.py +0 -0
  115. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/resource/repeated.py +0 -0
  116. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/mock_data/resource/single.py +0 -0
  117. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/scripts/gen_badges.sh +0 -0
  118. {heurist_api-0.1.3 → heurist_api-0.2.0}/src/scripts/gen_ref_pages.py +0 -0
  119. {heurist_api-0.1.3 → heurist_api-0.2.0}/tests/e2e/download_test.py +0 -0
  120. {heurist_api-0.1.3 → heurist_api-0.2.0}/tests/e2e/schema_test.py +0 -0
  121. {heurist_api-0.1.3 → heurist_api-0.2.0}/tests/integration/api/client_test.py +0 -0
  122. {heurist_api-0.1.3 → heurist_api-0.2.0}/tests/integration/api/connection_test.py +0 -0
  123. {heurist_api-0.1.3 → heurist_api-0.2.0}/tests/unit/database/database_test.py +0 -0
  124. {heurist_api-0.1.3 → heurist_api-0.2.0}/tests/unit/database/modeling_test.py +0 -0
  125. {heurist_api-0.1.3 → heurist_api-0.2.0}/tests/unit/database/skeleton_test.py +0 -0
  126. {heurist_api-0.1.3 → heurist_api-0.2.0}/tests/unit/schema/get_db_schema_test.py +0 -0
  127. {heurist_api-0.1.3 → heurist_api-0.2.0}/tests/unit/validators/detail_validation_test.py +0 -0
  128. {heurist_api-0.1.3 → heurist_api-0.2.0}/tests/unit/validators/repeated_enum_test.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: heurist-api
3
- Version: 0.1.3
3
+ Version: 0.2.0
4
4
  Dynamic: Description
5
5
  Dynamic: Description-Content-Type
6
6
  Summary: API wrapper and CLI for Heurist database.
@@ -451,3 +451,17 @@ Requires-Dist: python-dotenv>=1.1.0
451
451
  Requires-Dist: requests>=2.32.3
452
452
  Requires-Dist: rich>=14.0.0
453
453
  Requires-Dist: tenacity>=9.1.2
454
+ Provides-Extra: dev
455
+ Requires-Dist: coverage>=7.8.0; extra == 'dev'
456
+ Requires-Dist: genbadge[coverage]>=1.1.2; extra == 'dev'
457
+ Requires-Dist: isort>=6.0.1; extra == 'dev'
458
+ Requires-Dist: mkdocs-gen-files>=0.5.0; extra == 'dev'
459
+ Requires-Dist: mkdocs-literate-nav>=0.6.2; extra == 'dev'
460
+ Requires-Dist: mkdocs-material[imaging]>=9.6.14; extra == 'dev'
461
+ Requires-Dist: mkdocs>=1.6.1; extra == 'dev'
462
+ Requires-Dist: mkdocstrings-python>=1.16.10; extra == 'dev'
463
+ Requires-Dist: pre-commit>=4.2.0; extra == 'dev'
464
+ Requires-Dist: pymdown-extensions>=10.15; extra == 'dev'
465
+ Requires-Dist: pytest>=8.3.5; extra == 'dev'
466
+ Requires-Dist: ruff>=0.11.10; extra == 'dev'
467
+ Requires-Dist: uv>=0.7.5; extra == 'dev'
@@ -8,11 +8,25 @@
8
8
 
9
9
  Extract, transform, and load data from your Heurist database into local formats. Great for freeing up your data analysis pipeline!
10
10
 
11
- ## Documentation
11
+ ## Quick Start
12
12
 
13
- For information about installation, usage, etc., navigate to the documentation site below:
13
+ Install (Python version +3.10) with pip.
14
14
 
15
- - [Documentation](https://lostma-erc.github.io/heurist-etl-pipeline/)
15
+ ```shell
16
+ pip install heurist-api
17
+ ```
18
+
19
+ Download your record types in a [DuckDB](https://duckdb.org/) database file.
20
+
21
+ ```shell
22
+ heurist -d 'YOUR.DATABASE' -u 'YOUR.LOGIN' -p 'YOUR.PASSWORD' download -f 'FILE.DB'
23
+ ```
24
+
25
+ ## Full Documentation
26
+
27
+ For detailed information about installation, usage, etc., navigate to the documentation site below:
28
+
29
+ - [Documentation](https://lostma-erc.github.io/heurist-api/)
16
30
 
17
31
  ## License
18
32
 
@@ -1,10 +1,10 @@
1
- # Heurist ETL
1
+ # Heurist API
2
2
 
3
3
  [![Python package](https://github.com/LostMa-ERC/heurist-etl-pipeline/actions/workflows/python-package.yml/badge.svg)](https://github.com/LostMa-ERC/heurist-etl-pipeline/actions/workflows/python-package.yml) [![License: CC BY-SA 4.0](https://img.shields.io/badge/License-CC_BY--SA_4.0-lightgrey.svg)](https://creativecommons.org/licenses/by-sa/4.0/)
4
4
  [![coverage](https://github.com/LostMa-ERC/heurist-etl-pipeline/raw/main/docs/assets/coverage-badge.svg)](https://github.com/LostMa-ERC/heurist-etl-pipeline/raw/main/docs/assets/coverage-badge.svg)
5
5
  [![tests](https://github.com/LostMa-ERC/heurist-etl-pipeline/raw/main/docs/assets/tests-badge.svg)](https://github.com/LostMa-ERC/heurist-etl-pipeline/raw/main/docs/assets/tests-badge.svg)
6
6
 
7
- This Python package Extracts, Transforms, and Loads (ETL) data from a Heurist database server into a local [DuckDB](https://duckdb.org) database file.
7
+ This Python package provides an API wrapper for Heurist as well as a command-line interface (CLI) that Extracts, Transforms, and Loads (ETL) data from a Heurist database server into a local [DuckDB](https://duckdb.org) database file.
8
8
 
9
9
  - [Installation & configuration](usage/index.md#installation)
10
10
  - [Basic command-line usage](usage/index.md#cli-commands)
@@ -14,10 +14,7 @@ This Python package Extracts, Transforms, and Loads (ETL) data from a Heurist da
14
14
  [![Logo](https://github.com/LostMa-ERC/heurist-etl-pipeline/raw/main/docs/assets/logo-transparent-1.png)](https://github.com/LostMa-ERC/heurist-etl-pipeline/raw/main/docs/assets/logo-transparent-1.png)
15
15
 
16
16
  ```shell
17
- $ pip install \
18
- --index-url https://test.pypi.org/simple/ \
19
- --extra-index-url https://pypi.org/simple \
20
- heurist
17
+ $ pip install heurist-api
21
18
  ```
22
19
 
23
20
  ## Commands
@@ -9,7 +9,7 @@ Secondarily, you can also exploit certain modules, such as the API client, for y
9
9
  ### Requirements
10
10
 
11
11
  - Python version 3.10 or greater
12
- - Virtual Python environment, i.e. [`pyenv`](https://github.com/pyenv/pyenv?tab=readme-ov-file#installation).
12
+ - A way to manage your virtual Python environment, i.e. [`pyenv`](https://github.com/pyenv/pyenv?tab=readme-ov-file#installation).
13
13
 
14
14
  ### Steps
15
15
 
@@ -17,14 +17,11 @@ Secondarily, you can also exploit certain modules, such as the API client, for y
17
17
  - Need help installing Python? Check out the [Real Python](https://realpython.com/installing-python/) blog's tutorial.
18
18
  2. Create a new virtual environment for the package. Then activate it.
19
19
  - What's the simplest way? Check out [Real Python](https://realpython.com/python-virtual-environments-a-primer/)'s thorough blog post.
20
- - I recommend naming the environment `heurist`.
21
- 3. Use `pip install` to install the `heurist` Python package.
20
+ - I recommend naming the environment `heurist-api`.
21
+ 3. Use `pip install` to install the `heurist-api` Python package.
22
22
 
23
23
  ```console
24
- $ pip install \
25
- --index-url https://test.pypi.org/simple/ \
26
- --extra-index-url https://pypi.org/simple \
27
- heurist
24
+ $ pip install heurist-api
28
25
  ```
29
26
 
30
27
  ## Configure the CLI
@@ -1,4 +1,4 @@
1
- site_name: Heurist ETL
1
+ site_name: Heurist API
2
2
  site_url: https://lostma-erc.github.io/heurist-api/
3
3
 
4
4
  theme:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "heurist-api"
3
- version = "0.1.3"
3
+ version = "0.2.0"
4
4
  description = "API wrapper and CLI for Heurist database."
5
5
  keywords = [ "duckdb", "etl" ]
6
6
  dynamic = [ "readme" ]
@@ -37,7 +37,7 @@ build-backend = "hatchling.build"
37
37
  [tool.hatch.build.targets.wheel]
38
38
  packages = ["src/heurist", "src/mock_data"]
39
39
 
40
- [dependency-groups]
40
+ [project.optional-dependencies]
41
41
  dev = [
42
42
  "coverage>=7.8.0",
43
43
  "genbadge[coverage]>=1.1.2",
@@ -56,6 +56,7 @@ dev = [
56
56
 
57
57
  [project.scripts]
58
58
  heurist = "heurist.cli.__main__:cli"
59
+ heurist-log = "heurist.cli.parse_log:cli"
59
60
 
60
61
  [tool.isort]
61
62
  profile = "black"
@@ -0,0 +1,22 @@
1
+ import click
2
+ import csv
3
+ from heurist.log import yield_log_blocks, LogDetail
4
+
5
+
6
+ log_detail_fieldnames = list(LogDetail.__annotations__.keys())
7
+
8
+
9
+ @click.command()
10
+ @click.argument("csvfile", type=click.Path())
11
+ @click.option("-l", "--log-file", required=None, default="validation.log")
12
+ def cli(csvfile, log_file):
13
+ with open(log_file) as f, open(csvfile, "w") as of:
14
+ writer = csv.DictWriter(of, fieldnames=log_detail_fieldnames)
15
+ writer.writeheader()
16
+ lines = f.readlines()
17
+ for block in yield_log_blocks(lines):
18
+ writer.writerow(block.__dict__)
19
+
20
+
21
+ if __name__ == "__main__":
22
+ cli()
@@ -20,6 +20,8 @@ class TransformedDatabase(HeuristDatabase):
20
20
  ) -> None:
21
21
  super().__init__(hml_xml, conn, db)
22
22
 
23
+ self.conn.execute("SET GLOBAL pandas_analyze_sample=100000")
24
+
23
25
  # Create an empty index of targeted record types' Pydantic models
24
26
  self.pydantic_models = {}
25
27
 
@@ -0,0 +1,2 @@
1
+ from .iterator import yield_log_blocks as yield_log_blocks
2
+ from .model import LogDetail as LogDetail
@@ -0,0 +1,16 @@
1
+ from typing import Generator
2
+
3
+ from .model import LogDetail
4
+
5
+
6
+ def yield_log_blocks(lines: list[str]) -> Generator[LogDetail, None, None]:
7
+ line_iterator = iter(lines)
8
+ l1 = next(line_iterator, None)
9
+ while l1 is not None:
10
+ if l1 and not l1.startswith("\t"):
11
+ l2 = next(line_iterator)
12
+ l3 = next(line_iterator)
13
+ l4 = next(line_iterator)
14
+ l5 = next(line_iterator)
15
+ yield LogDetail.load_lines(l1, l2, l3, l4, l5)
16
+ l1 = next(line_iterator, None)
@@ -0,0 +1,42 @@
1
+ from dataclasses import dataclass
2
+ import re
3
+
4
+
5
+ @dataclass
6
+ class LogDetail:
7
+ time: str
8
+ level: str
9
+ recType: int
10
+ recID: int
11
+ rule: str
12
+ problem: str
13
+
14
+ @classmethod
15
+ def load_lines(cls, *block_lines) -> "LogDetail":
16
+ l1, l2, l3, l4, l5 = block_lines
17
+ for indented_line in [l2, l3, l4, l5]:
18
+ assert indented_line.startswith("\t")
19
+ return LogDetail(
20
+ time=cls.parse_time(l1),
21
+ level=cls.parse_level(l1),
22
+ recType=cls.parse_number(l2),
23
+ recID=cls.parse_number(l3),
24
+ rule=l4.removeprefix("\t").strip(),
25
+ problem=l5.removeprefix("\t").strip(),
26
+ )
27
+
28
+ @staticmethod
29
+ def parse_number(line) -> int:
30
+ parts = line.split()
31
+ suffix: str = parts[-1]
32
+ number = suffix.removesuffix("]")
33
+ return int(number)
34
+
35
+ @staticmethod
36
+ def parse_time(l1: str) -> str:
37
+ parts = l1.split(" - ")
38
+ return parts[0].strip()
39
+
40
+ @staticmethod
41
+ def parse_level(l1: str) -> str:
42
+ return re.search(r"[A-Z]+", l1).group(0).strip()
@@ -0,0 +1,44 @@
1
+ import unittest
2
+ from pathlib import Path
3
+
4
+ from heurist.log import yield_log_blocks, LogDetail
5
+
6
+
7
+ LOG_FILE = Path(__file__).parent.joinpath("mock_log.txt")
8
+
9
+ LINES = [
10
+ "2025-05-26 18:50 - WARNING - ",
11
+ " [rec_Type 104]",
12
+ " [rec_ID 834]",
13
+ " The detail 'note' is limited to a maximum of 1 values.",
14
+ " Count of values = 3.",
15
+ "2025-05-26 18:50 - WARNING - ",
16
+ " [rec_Type 104]",
17
+ " [rec_ID 834]",
18
+ " The detail 'contam' is limited to a maximum of 1 values.",
19
+ " Count of values = 2.",
20
+ ]
21
+
22
+
23
+ class TestLog(unittest.TestCase):
24
+ def assess_log_block(self, log: LogDetail):
25
+ self.assertEqual(log.level, "WARNING")
26
+ self.assertIsNotNone(log.rule)
27
+ self.assertIsNotNone(log.problem)
28
+ self.assertGreater(log.recID, 100)
29
+ self.assertGreater(log.recType, 99)
30
+
31
+ def test_parsed_lines(self):
32
+ for log in yield_log_blocks(LINES):
33
+ self.assess_log_block(log)
34
+
35
+ def test_log_file(self):
36
+ print(LOG_FILE)
37
+ with open(LOG_FILE) as f:
38
+ lines = f.readlines()
39
+ for log in yield_log_blocks(lines):
40
+ self.assess_log_block(log)
41
+
42
+
43
+ if __name__ == "__main__":
44
+ unittest.main()
@@ -421,7 +421,7 @@ wheels = [
421
421
 
422
422
  [[package]]
423
423
  name = "heurist-api"
424
- version = "0.1.3"
424
+ version = "0.1.4"
425
425
  source = { editable = "." }
426
426
  dependencies = [
427
427
  { name = "click" },
@@ -438,7 +438,7 @@ dependencies = [
438
438
  { name = "tenacity" },
439
439
  ]
440
440
 
441
- [package.dev-dependencies]
441
+ [package.optional-dependencies]
442
442
  dev = [
443
443
  { name = "coverage" },
444
444
  { name = "genbadge", extra = ["coverage"] },
@@ -458,35 +458,32 @@ dev = [
458
458
  [package.metadata]
459
459
  requires-dist = [
460
460
  { name = "click", specifier = ">=8.2.0" },
461
+ { name = "coverage", marker = "extra == 'dev'", specifier = ">=7.8.0" },
461
462
  { name = "duckdb", specifier = ">=1.2.2" },
463
+ { name = "genbadge", extras = ["coverage"], marker = "extra == 'dev'", specifier = ">=1.1.2" },
464
+ { name = "isort", marker = "extra == 'dev'", specifier = ">=6.0.1" },
462
465
  { name = "lxml", specifier = ">=5.4.0" },
466
+ { name = "mkdocs", marker = "extra == 'dev'", specifier = ">=1.6.1" },
467
+ { name = "mkdocs-gen-files", marker = "extra == 'dev'", specifier = ">=0.5.0" },
468
+ { name = "mkdocs-literate-nav", marker = "extra == 'dev'", specifier = ">=0.6.2" },
469
+ { name = "mkdocs-material", extras = ["imaging"], marker = "extra == 'dev'", specifier = ">=9.6.14" },
470
+ { name = "mkdocstrings-python", marker = "extra == 'dev'", specifier = ">=1.16.10" },
463
471
  { name = "pandas", specifier = ">=2.2.3" },
464
472
  { name = "polars", specifier = ">=1.29.0" },
473
+ { name = "pre-commit", marker = "extra == 'dev'", specifier = ">=4.2.0" },
465
474
  { name = "pyarrow", specifier = ">=20.0.0" },
466
475
  { name = "pydantic", specifier = ">=2.11.4" },
467
476
  { name = "pydantic-xml", specifier = ">=2.16.0" },
477
+ { name = "pymdown-extensions", marker = "extra == 'dev'", specifier = ">=10.15" },
478
+ { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.3.5" },
468
479
  { name = "python-dotenv", specifier = ">=1.1.0" },
469
480
  { name = "requests", specifier = ">=2.32.3" },
470
481
  { name = "rich", specifier = ">=14.0.0" },
482
+ { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.11.10" },
471
483
  { name = "tenacity", specifier = ">=9.1.2" },
484
+ { name = "uv", marker = "extra == 'dev'", specifier = ">=0.7.5" },
472
485
  ]
473
-
474
- [package.metadata.requires-dev]
475
- dev = [
476
- { name = "coverage", specifier = ">=7.8.0" },
477
- { name = "genbadge", extras = ["coverage"], specifier = ">=1.1.2" },
478
- { name = "isort", specifier = ">=6.0.1" },
479
- { name = "mkdocs", specifier = ">=1.6.1" },
480
- { name = "mkdocs-gen-files", specifier = ">=0.5.0" },
481
- { name = "mkdocs-literate-nav", specifier = ">=0.6.2" },
482
- { name = "mkdocs-material", extras = ["imaging"], specifier = ">=9.6.14" },
483
- { name = "mkdocstrings-python", specifier = ">=1.16.10" },
484
- { name = "pre-commit", specifier = ">=4.2.0" },
485
- { name = "pymdown-extensions", specifier = ">=10.15" },
486
- { name = "pytest", specifier = ">=8.3.5" },
487
- { name = "ruff", specifier = ">=0.11.10" },
488
- { name = "uv", specifier = ">=0.7.5" },
489
- ]
486
+ provides-extras = ["dev"]
490
487
 
491
488
  [[package]]
492
489
  name = "identify"
File without changes
File without changes
File without changes