documente_shared 0.1.187__tar.gz → 0.1.188__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.
Files changed (128) hide show
  1. documente_shared-0.1.188/.claude/commands/commit.md +34 -0
  2. {documente_shared-0.1.187 → documente_shared-0.1.188}/Makefile +14 -0
  3. {documente_shared-0.1.187 → documente_shared-0.1.188}/PKG-INFO +2 -1
  4. documente_shared-0.1.188/documente_shared/application/digest.py +7 -0
  5. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/application/exceptions.py +5 -2
  6. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/application/files.py +8 -6
  7. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/application/json.py +2 -2
  8. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/application/numbers.py +1 -1
  9. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/application/payloads.py +3 -3
  10. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/application/query_params.py +0 -1
  11. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/application/retry_utils.py +16 -9
  12. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/base_enum.py +3 -3
  13. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/constants.py +4 -1
  14. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/document.py +127 -143
  15. documente_shared-0.1.188/documente_shared/domain/entities/document_metadata.py +62 -0
  16. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/document_type.py +13 -11
  17. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/in_memory_document.py +7 -3
  18. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/processing_case.py +50 -62
  19. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/processing_case_item.py +91 -119
  20. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/processing_case_item_filters.py +1 -2
  21. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/processing_event.py +14 -17
  22. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/workspace.py +15 -18
  23. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/workspace_document.py +3 -9
  24. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/workspace_document_page.py +21 -35
  25. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/enums/common.py +24 -25
  26. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/enums/document.py +26 -27
  27. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/enums/document_type_record.py +4 -4
  28. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/enums/processing_case.py +17 -17
  29. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/enums/processing_case_validator.py +3 -4
  30. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/exceptions.py +1 -4
  31. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/filters/document_type.py +6 -4
  32. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/filters/workspace.py +7 -5
  33. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/filters/workspace_document.py +13 -11
  34. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/filters/workspace_document_page.py +6 -4
  35. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/helpers/dicts.py +1 -5
  36. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/interfaces/scaling.py +0 -1
  37. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/pagination/entities.py +1 -0
  38. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/pagination/response.py +0 -1
  39. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/repositories/document.py +0 -1
  40. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/repositories/processing_case.py +0 -1
  41. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/repositories/processing_case_item.py +0 -1
  42. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/repositories/processing_record.py +0 -1
  43. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/repositories/workspace_document_page.py +3 -1
  44. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/batch_queue.py +3 -2
  45. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/documente_client.py +28 -9
  46. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/dynamo_table.py +11 -17
  47. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/lambdas.py +3 -3
  48. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/dynamo_document.py +6 -9
  49. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/dynamo_processing_case.py +6 -9
  50. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/dynamo_processing_case_item.py +7 -10
  51. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/http_document.py +6 -9
  52. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/http_processing_case.py +6 -10
  53. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/http_processing_case_item.py +4 -7
  54. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/http_processing_record.py +5 -1
  55. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/http_workspace_document_page.py +10 -6
  56. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/mem_document.py +2 -5
  57. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/mem_processing_case.py +1 -1
  58. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/mem_processing_case_item.py +2 -7
  59. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/s3_bucket.py +5 -9
  60. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/services/http_scaling.py +1 -3
  61. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/sqs_queue.py +10 -13
  62. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/presentation/presenters.py +1 -1
  63. documente_shared-0.1.188/pyproject.toml +215 -0
  64. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/application/test_files.py +7 -4
  65. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/application/test_payloads.py +8 -17
  66. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/conftest.py +1 -1
  67. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/domain/entities/test_in_memory_document.py +19 -14
  68. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/domain/entities/test_processing_case.py +16 -16
  69. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documents.py +44 -34
  70. {documente_shared-0.1.187 → documente_shared-0.1.188}/uv.lock +39 -1
  71. documente_shared-0.1.187/documente_shared/application/digest.py +0 -7
  72. documente_shared-0.1.187/documente_shared/domain/entities/document_metadata.py +0 -64
  73. documente_shared-0.1.187/pyproject.toml +0 -48
  74. {documente_shared-0.1.187 → documente_shared-0.1.188}/.github/workflows/publish.yml +0 -0
  75. {documente_shared-0.1.187 → documente_shared-0.1.188}/.gitignore +0 -0
  76. {documente_shared-0.1.187 → documente_shared-0.1.188}/.vscode/settings.json +0 -0
  77. {documente_shared-0.1.187 → documente_shared-0.1.188}/Dockerfile +0 -0
  78. {documente_shared-0.1.187 → documente_shared-0.1.188}/README.md +0 -0
  79. {documente_shared-0.1.187 → documente_shared-0.1.188}/__init__.py +0 -0
  80. {documente_shared-0.1.187 → documente_shared-0.1.188}/cases.py +0 -0
  81. {documente_shared-0.1.187 → documente_shared-0.1.188}/docker-compose.yml +0 -0
  82. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/__init__.py +0 -0
  83. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/application/__init__.py +0 -0
  84. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/application/dates.py +0 -0
  85. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/application/logging.py +0 -0
  86. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/application/time_utils.py +0 -0
  87. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/application/timezone.py +0 -0
  88. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/__init__.py +0 -0
  89. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/__init__.py +0 -0
  90. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/processing_case_filters.py +0 -0
  91. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/processing_documents.py +0 -0
  92. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/processing_record.py +0 -0
  93. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/entities/scaling.py +0 -0
  94. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/enums/__init__.py +0 -0
  95. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/enums/circular_oficio.py +0 -0
  96. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/enums/workspace.py +0 -0
  97. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/filters/__init__.py +0 -0
  98. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/helpers/__init__.py +0 -0
  99. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/helpers/encoding.py +0 -0
  100. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/helpers/lists.py +0 -0
  101. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/helpers/values.py +0 -0
  102. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/interfaces/__init__.py +0 -0
  103. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/interfaces/queue.py +0 -0
  104. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/pagination/__init__.py +0 -0
  105. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/repositories/__init__.py +0 -0
  106. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/repositories/document_type.py +0 -0
  107. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/repositories/workspace.py +0 -0
  108. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/domain/repositories/workspace_document.py +0 -0
  109. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/__init__.py +0 -0
  110. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/__init__.py +0 -0
  111. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/http_document_type.py +0 -0
  112. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/http_workspace.py +0 -0
  113. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/http_workspace_document.py +0 -0
  114. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/repositories/mem_processing_record.py +0 -0
  115. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/infrastructure/services/__init__.py +0 -0
  116. {documente_shared-0.1.187 → documente_shared-0.1.188}/documente_shared/presentation/__init__.py +0 -0
  117. {documente_shared-0.1.187 → documente_shared-0.1.188}/publish.sh +0 -0
  118. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/__init__.py +0 -0
  119. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/__init__.py +0 -0
  120. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/application/__init__.py +0 -0
  121. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/domain/__init__.py +0 -0
  122. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/domain/entities/__init__.py +0 -0
  123. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/domain/entities/test_processing_case_item.py +0 -0
  124. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/domain/entities/test_processing_record.py +0 -0
  125. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/domain/enums/test_processing_case_validator.py +0 -0
  126. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/infrastructure/__init__.py +0 -0
  127. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/infrastructure/repositories/__init__.py +0 -0
  128. {documente_shared-0.1.187 → documente_shared-0.1.188}/tests/documente_shared/infrastructure/repositories/test_http_processing_record.py +0 -0
@@ -0,0 +1,34 @@
1
+ ---
2
+ allowed-tools: Bash(git add:*), Bash(git status:*), Bash(git commit:*)
3
+ argument-hint: [message]
4
+ description: Create a git commit
5
+ ---
6
+
7
+ ## Context
8
+
9
+ - Current git status: !`git status`
10
+ - Current git diff: !`git diff HEAD`
11
+ - Current branch: !`git branch --show-current`
12
+ - Recent commits: !`git log --oneline -10`
13
+
14
+ ## Your task
15
+
16
+ Based on the above changes, create a single git commit following the **Conventional Commits** specification.
17
+
18
+ ### Commit message format
19
+
20
+ ```
21
+ <type>(<scope>): <description>
22
+
23
+ [optional body]
24
+ ```
25
+
26
+ ### Rules
27
+
28
+ 1. **type** must be one of: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`
29
+ 2. **scope** is optional but recommended — use the domain or module affected (e.g., `auth`, `transactions`, `ui`)
30
+ 3. **description** must be lowercase, imperative mood, no period at the end
31
+ 4. Add a **body** only if the changes need further explanation
32
+ 5. If the argument `$ARGUMENTS` is provided, use it as guidance for the commit message
33
+ 6. Do not include any "Co-Authored-By" lines in the commit message
34
+ 7. Before committing, stage all modified, deleted, and untracked files that are part of the changes using `git add`. Include both tracked changes and new untracked files relevant to the work. Do NOT stage files that contain secrets (`.env`, credentials, etc.)
@@ -25,6 +25,20 @@ clean:
25
25
  docker ps -aq | xargs docker stop
26
26
  docker ps -aq | xargs docker rm
27
27
 
28
+ lint:
29
+ uv run ruff check documente_shared tests
30
+
31
+ lint_fix:
32
+ uv run ruff check --fix documente_shared tests
33
+
34
+ format:
35
+ uv run ruff format documente_shared tests
36
+
37
+ format_check:
38
+ uv run ruff format --check documente_shared tests
39
+
40
+ check: lint format_check
41
+
28
42
  test:
29
43
  $(COMPOSE_PACKAGE) bash -c "uv run pytest --pyargs $(ARG)"
30
44
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: documente_shared
3
- Version: 0.1.187
3
+ Version: 0.1.188
4
4
  Summary: Shared utilities for LlamitAI projects
5
5
  Author-email: Tech <tech@llamitai.com>
6
6
  License: MIT
@@ -11,6 +11,7 @@ Requires-Dist: pydantic>=2.12.5
11
11
  Requires-Dist: requests>=2.32.5
12
12
  Requires-Dist: sentry-sdk>=2.52.0
13
13
  Requires-Dist: structlog>=25.5.0
14
+ Requires-Dist: tenacity>=9.1.4
14
15
  Requires-Dist: unidecode>=1.4.0
15
16
  Description-Content-Type: text/markdown
16
17
 
@@ -0,0 +1,7 @@
1
+ import hashlib
2
+
3
+
4
+ def get_file_digest(file_bytes: bytes) -> str:
5
+ sha256_hash = hashlib.sha256()
6
+ sha256_hash.update(file_bytes)
7
+ return sha256_hash.hexdigest()
@@ -4,13 +4,15 @@ from typing import Callable, Any, TypeVar
4
4
 
5
5
  F = TypeVar("F", bound=Callable[..., Any])
6
6
 
7
- def initialize_sentry(dsn: str, environment: str = 'dev') -> None:
8
- if not sentry_sdk.Hub.current.client:
7
+
8
+ def initialize_sentry(dsn: str, environment: str = "dev") -> None:
9
+ if not sentry_sdk.Hub.current.client:
9
10
  sentry_sdk.init(
10
11
  dsn=dsn,
11
12
  environment=environment,
12
13
  )
13
14
 
15
+
14
16
  def track_exceptions(func: F) -> F:
15
17
  @wraps(func)
16
18
  def wrapper(*args: Any, **kwargs: Any) -> Any:
@@ -20,4 +22,5 @@ def track_exceptions(func: F) -> F:
20
22
  sentry_sdk.capture_exception(e)
21
23
  sentry_sdk.flush()
22
24
  raise
25
+
23
26
  return wrapper # type: ignore
@@ -7,7 +7,7 @@ def split_file_params(filepath: str) -> Tuple[str, str, str]:
7
7
  folder_path = path.dirname(filepath)
8
8
  filename = path.splitext(path.basename(filepath))[0]
9
9
  extension = path.splitext(filepath)[1]
10
- extension = extension.replace('.', '')
10
+ extension = extension.replace(".", "")
11
11
  return folder_path, filename, extension
12
12
 
13
13
 
@@ -18,20 +18,22 @@ def get_filename_from_path(file_path: Optional[str]) -> Optional[str]:
18
18
 
19
19
 
20
20
  def remove_slash_from_path(file_path: str) -> str:
21
- if file_path and file_path.startswith('/'):
21
+ if file_path and file_path.startswith("/"):
22
22
  return file_path[1:]
23
23
  return file_path
24
24
 
25
+
25
26
  def remove_extension(filename: str) -> str:
26
- if filename and '.' in filename:
27
- return filename.rsplit('.', 1)[0]
27
+ if filename and "." in filename:
28
+ return filename.rsplit(".", 1)[0]
28
29
  return filename
29
30
 
31
+
30
32
  def build_bucket_file_key(file_path: str) -> str:
31
33
  if not file_path:
32
- return ''
34
+ return ""
33
35
  parsed = urlparse(file_path)
34
36
  if parsed.scheme and parsed.netloc:
35
- return parsed.path.lstrip('/')
37
+ return parsed.path.lstrip("/")
36
38
 
37
39
  return remove_slash_from_path(file_path)
@@ -32,8 +32,8 @@ def safe_format(data: Any) -> Any:
32
32
 
33
33
 
34
34
  def normalize_key(key: str) -> str:
35
- normalized = unicodedata.normalize('NFC', key)
36
- underscored = re.sub(r'\s+', '_', normalized)
35
+ normalized = unicodedata.normalize("NFC", key)
36
+ underscored = re.sub(r"\s+", "_", normalized)
37
37
  return underscored
38
38
 
39
39
 
@@ -4,4 +4,4 @@ from decimal import Decimal
4
4
  def normalize_number(number: str | float | Decimal) -> str:
5
5
  if not isinstance(number, Decimal):
6
6
  number = Decimal(number)
7
- return str(number.quantize(Decimal('0.001')))
7
+ return str(number.quantize(Decimal("0.001")))
@@ -2,8 +2,9 @@ import re
2
2
 
3
3
 
4
4
  def camel_to_snake_key(name: str) -> str:
5
- s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
6
- return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
5
+ s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name)
6
+ return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower()
7
+
7
8
 
8
9
  def camel_to_snake(data: dict | list) -> dict | list:
9
10
  if isinstance(data, dict):
@@ -26,4 +27,3 @@ def snake_to_camel(data: dict | list) -> dict | list:
26
27
  return [snake_to_camel(item) for item in data]
27
28
  else:
28
29
  return data
29
-
@@ -6,7 +6,6 @@ from typing import List, Optional, Type, Union
6
6
  from uuid import UUID
7
7
 
8
8
 
9
-
10
9
  def camelize_string(value: str) -> str:
11
10
  if not value:
12
11
  return value
@@ -2,6 +2,7 @@ import time
2
2
  import random
3
3
  from functools import wraps
4
4
  from typing import Optional, Callable
5
+
5
6
  import structlog
6
7
 
7
8
  logger = structlog.get_logger()
@@ -23,12 +24,12 @@ def retry_on_size_integrity(base_delay: float = 0.8, max_retries: int = 3):
23
24
  file_key=file_key,
24
25
  )
25
26
  if attempt < max_retries - 1:
26
- delay = base_delay * (2 ** attempt) + random.uniform(0, base_delay)
27
+ delay = base_delay * (2**attempt) + random.uniform(0, base_delay)
27
28
  time.sleep(delay)
28
29
  continue
29
30
  raise RuntimeError(f"No se pudo obtener file_context para {file_key}")
30
31
 
31
- if 'Body' not in file_context:
32
+ if "Body" not in file_context:
32
33
  logger.warning(
33
34
  "[shared.retry.body_not_found]",
34
35
  attempt=attempt + 1,
@@ -36,19 +37,23 @@ def retry_on_size_integrity(base_delay: float = 0.8, max_retries: int = 3):
36
37
  file_key=file_key,
37
38
  )
38
39
  if attempt < max_retries - 1:
39
- delay = base_delay * (2 ** attempt) + random.uniform(0, base_delay)
40
+ delay = base_delay * (2**attempt) + random.uniform(0, base_delay)
40
41
  time.sleep(delay)
41
42
  continue
42
43
  raise RuntimeError(f"'Body' no encontrado en file_context para {file_key}")
43
44
 
44
- expected_size = file_context.get('ContentLength', 0)
45
- body = file_context['Body'].read()
45
+ expected_size = file_context.get("ContentLength", 0)
46
+ body = file_context["Body"].read()
46
47
  actual_size = len(body)
47
48
 
48
49
  if expected_size == actual_size:
49
- file_context['Body'] = body
50
+ file_context["Body"] = body
50
51
  if attempt > 0:
51
- logger.info("[shared.retry.download_success]", file_key=file_key, attempts=attempt + 1)
52
+ logger.info(
53
+ "[shared.retry.download_success]",
54
+ file_key=file_key,
55
+ attempts=attempt + 1,
56
+ )
52
57
  return file_context
53
58
 
54
59
  logger.warning(
@@ -61,7 +66,7 @@ def retry_on_size_integrity(base_delay: float = 0.8, max_retries: int = 3):
61
66
  )
62
67
 
63
68
  if attempt < max_retries - 1:
64
- delay = base_delay * (2 ** attempt) + random.uniform(0, base_delay)
69
+ delay = base_delay * (2**attempt) + random.uniform(0, base_delay)
65
70
  time.sleep(delay)
66
71
 
67
72
  except Exception as e:
@@ -74,7 +79,7 @@ def retry_on_size_integrity(base_delay: float = 0.8, max_retries: int = 3):
74
79
  error=str(e),
75
80
  )
76
81
  if attempt < max_retries - 1:
77
- delay = base_delay * (2 ** attempt) + random.uniform(0, base_delay)
82
+ delay = base_delay * (2**attempt) + random.uniform(0, base_delay)
78
83
  time.sleep(delay)
79
84
  continue
80
85
  raise
@@ -82,5 +87,7 @@ def retry_on_size_integrity(base_delay: float = 0.8, max_retries: int = 3):
82
87
  raise RuntimeError(
83
88
  f"Descarga incompleta/inconsistente de S3 para {file_key} después de {max_retries} intentos"
84
89
  )
90
+
85
91
  return wrapper
92
+
86
93
  return decorator
@@ -38,17 +38,17 @@ class BaseEnum(Enum):
38
38
  return [
39
39
  value
40
40
  for key, value in cls.__dict__.items()
41
- if isinstance(value, str) and not key.startswith('__')
41
+ if isinstance(value, str) and not key.startswith("__")
42
42
  ]
43
43
 
44
44
  @classmethod
45
45
  def from_value(
46
46
  cls,
47
47
  value: Union[str, int],
48
- ) -> Optional['BaseEnum']:
48
+ ) -> Optional["BaseEnum"]:
49
49
  for tag in cls:
50
50
  if isinstance(tag.value, str) and str(tag.value).upper() == str(value).upper():
51
51
  return tag
52
52
  elif not isinstance(tag.value, str) and tag.value == value:
53
53
  return tag
54
- return None
54
+ return None
@@ -7,4 +7,7 @@ la_paz_tz = ZoneInfo("America/La_Paz")
7
7
  DOCUMENTE_API_URL = environ.get("DOCUMENTE_API_URL")
8
8
  DOCUMENTE_API_KEY = environ.get("DOCUMENTE_API_KEY")
9
9
 
10
- DEFAULT_PAGINATION_PAGE_SIZE = 50
10
+ DEFAULT_PAGINATION_PAGE_SIZE = 50
11
+
12
+ HTTP_RETRY_TOTAL = 3
13
+ HTTP_RETRY_BACKOFF_FACTOR = 0.5