documente_shared 0.1.160__tar.gz → 0.1.161__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 (111) hide show
  1. {documente_shared-0.1.160 → documente_shared-0.1.161}/PKG-INFO +1 -1
  2. documente_shared-0.1.161/documente_shared/domain/entities/workspace.py +63 -0
  3. documente_shared-0.1.161/documente_shared/domain/entities/workspace_document.py +138 -0
  4. documente_shared-0.1.161/documente_shared/domain/entities/workspace_document_filters.py +45 -0
  5. documente_shared-0.1.161/documente_shared/domain/entities/workspace_document_page.py +70 -0
  6. documente_shared-0.1.161/documente_shared/domain/entities/workspace_document_page_filters.py +32 -0
  7. documente_shared-0.1.161/documente_shared/domain/entities/workspace_filters.py +35 -0
  8. documente_shared-0.1.161/documente_shared/domain/enums/workspace.py +19 -0
  9. documente_shared-0.1.161/documente_shared/domain/repositories/workspace.py +28 -0
  10. documente_shared-0.1.161/documente_shared/domain/repositories/workspace_document.py +28 -0
  11. documente_shared-0.1.161/documente_shared/domain/repositories/workspace_document_page.py +28 -0
  12. documente_shared-0.1.161/documente_shared/infrastructure/repositories/http_workspace.py +71 -0
  13. documente_shared-0.1.161/documente_shared/infrastructure/repositories/http_workspace_document.py +71 -0
  14. documente_shared-0.1.161/documente_shared/infrastructure/repositories/http_workspace_document_page.py +71 -0
  15. {documente_shared-0.1.160 → documente_shared-0.1.161}/pyproject.toml +1 -1
  16. {documente_shared-0.1.160 → documente_shared-0.1.161}/uv.lock +1 -1
  17. {documente_shared-0.1.160 → documente_shared-0.1.161}/.github/workflows/publish.yml +0 -0
  18. {documente_shared-0.1.160 → documente_shared-0.1.161}/.gitignore +0 -0
  19. {documente_shared-0.1.160 → documente_shared-0.1.161}/Dockerfile +0 -0
  20. {documente_shared-0.1.160 → documente_shared-0.1.161}/Makefile +0 -0
  21. {documente_shared-0.1.160 → documente_shared-0.1.161}/README.md +0 -0
  22. {documente_shared-0.1.160 → documente_shared-0.1.161}/__init__.py +0 -0
  23. {documente_shared-0.1.160 → documente_shared-0.1.161}/cases.py +0 -0
  24. {documente_shared-0.1.160 → documente_shared-0.1.161}/docker-compose.yml +0 -0
  25. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/__init__.py +0 -0
  26. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/application/__init__.py +0 -0
  27. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/application/dates.py +0 -0
  28. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/application/digest.py +0 -0
  29. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/application/exceptions.py +0 -0
  30. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/application/files.py +0 -0
  31. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/application/json.py +0 -0
  32. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/application/numbers.py +0 -0
  33. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/application/payloads.py +0 -0
  34. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/application/query_params.py +0 -0
  35. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/application/retry_utils.py +0 -0
  36. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/application/time_utils.py +0 -0
  37. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/application/timezone.py +0 -0
  38. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/__init__.py +0 -0
  39. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/base_enum.py +0 -0
  40. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/constants.py +0 -0
  41. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/entities/__init__.py +0 -0
  42. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/entities/document.py +0 -0
  43. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/entities/document_metadata.py +0 -0
  44. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/entities/in_memory_document.py +0 -0
  45. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/entities/processing_case.py +0 -0
  46. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/entities/processing_case_filters.py +0 -0
  47. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/entities/processing_case_item.py +0 -0
  48. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/entities/processing_case_item_filters.py +0 -0
  49. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/entities/processing_documents.py +0 -0
  50. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/entities/processing_event.py +0 -0
  51. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/entities/processing_record.py +0 -0
  52. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/entities/scaling.py +0 -0
  53. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/enums/__init__.py +0 -0
  54. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/enums/circular_oficio.py +0 -0
  55. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/enums/common.py +0 -0
  56. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/enums/document.py +0 -0
  57. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/enums/document_type_record.py +0 -0
  58. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/enums/processing_case.py +0 -0
  59. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/enums/processing_case_validator.py +0 -0
  60. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/exceptions.py +0 -0
  61. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/helpers/__init__.py +0 -0
  62. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/helpers/values.py +0 -0
  63. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/interfaces/__init__.py +0 -0
  64. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/interfaces/queue.py +0 -0
  65. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/interfaces/scaling.py +0 -0
  66. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/repositories/__init__.py +0 -0
  67. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/repositories/document.py +0 -0
  68. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/repositories/processing_case.py +0 -0
  69. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/repositories/processing_case_item.py +0 -0
  70. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/domain/repositories/processing_record.py +0 -0
  71. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/__init__.py +0 -0
  72. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/batch_queue.py +0 -0
  73. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/documente_client.py +0 -0
  74. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/dynamo_table.py +0 -0
  75. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/lambdas.py +0 -0
  76. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/repositories/__init__.py +0 -0
  77. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/repositories/dynamo_document.py +0 -0
  78. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/repositories/dynamo_processing_case.py +0 -0
  79. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/repositories/dynamo_processing_case_item.py +0 -0
  80. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/repositories/http_document.py +0 -0
  81. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/repositories/http_processing_case.py +0 -0
  82. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/repositories/http_processing_case_item.py +0 -0
  83. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/repositories/http_processing_record.py +0 -0
  84. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/repositories/mem_document.py +0 -0
  85. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/repositories/mem_processing_case.py +0 -0
  86. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/repositories/mem_processing_case_item.py +0 -0
  87. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/repositories/mem_processing_record.py +0 -0
  88. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/s3_bucket.py +0 -0
  89. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/services/__init__.py +0 -0
  90. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/services/http_scaling.py +0 -0
  91. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/infrastructure/sqs_queue.py +0 -0
  92. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/presentation/__init__.py +0 -0
  93. {documente_shared-0.1.160 → documente_shared-0.1.161}/documente_shared/presentation/presenters.py +0 -0
  94. {documente_shared-0.1.160 → documente_shared-0.1.161}/publish.sh +0 -0
  95. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/__init__.py +0 -0
  96. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/__init__.py +0 -0
  97. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/application/__init__.py +0 -0
  98. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/application/test_files.py +0 -0
  99. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/application/test_payloads.py +0 -0
  100. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/conftest.py +0 -0
  101. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/domain/__init__.py +0 -0
  102. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/domain/entities/__init__.py +0 -0
  103. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/domain/entities/test_in_memory_document.py +0 -0
  104. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/domain/entities/test_processing_case.py +0 -0
  105. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/domain/entities/test_processing_case_item.py +0 -0
  106. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/domain/entities/test_processing_record.py +0 -0
  107. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/domain/enums/test_processing_case_validator.py +0 -0
  108. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/infrastructure/__init__.py +0 -0
  109. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/infrastructure/repositories/__init__.py +0 -0
  110. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documente_shared/infrastructure/repositories/test_http_processing_record.py +0 -0
  111. {documente_shared-0.1.160 → documente_shared-0.1.161}/tests/documents.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: documente_shared
3
- Version: 0.1.160
3
+ Version: 0.1.161
4
4
  Summary: Shared utilities for Documente AI projects
5
5
  Author-email: Tech <tech@llamitai.com>
6
6
  License: MIT
@@ -0,0 +1,63 @@
1
+ from dataclasses import dataclass
2
+ from datetime import datetime
3
+ from typing import Optional
4
+ from uuid import UUID
5
+
6
+ from documente_shared.application.time_utils import get_datetime_from_data
7
+
8
+
9
+ @dataclass
10
+ class Workspace(object):
11
+ uuid: UUID
12
+ name: str
13
+ tenant_slug: str
14
+ is_archived: bool = False
15
+ metadata: Optional[dict] = None
16
+ created_at: Optional[datetime] = None
17
+ updated_at: Optional[datetime] = None
18
+ document_types: Optional[list] = None
19
+
20
+ def __post_init__(self):
21
+ self.metadata = self.metadata or {}
22
+ self.document_types = self.document_types or []
23
+
24
+ @property
25
+ def to_persist_dict(self) -> dict:
26
+ return {
27
+ "tenant_slug": self.tenant_slug,
28
+ "name": self.name,
29
+ "is_archived": self.is_archived,
30
+ "metadata": self.metadata or {},
31
+ }
32
+
33
+ @property
34
+ def to_dict(self) -> dict:
35
+ return {
36
+ "uuid": str(self.uuid),
37
+ "name": self.name,
38
+ "tenant_slug": self.tenant_slug,
39
+ "is_archived": self.is_archived,
40
+ "metadata": self.metadata,
41
+ "created_at": (
42
+ self.created_at.isoformat()
43
+ if self.created_at else None
44
+ ),
45
+ "updated_at": (
46
+ self.updated_at.isoformat()
47
+ if self.updated_at else None
48
+ ),
49
+ "document_types": self.document_types,
50
+ }
51
+
52
+ @classmethod
53
+ def from_dict(cls, data: dict) -> 'Workspace':
54
+ return cls(
55
+ uuid=data.get('uuid'),
56
+ name=data.get('name'),
57
+ tenant_slug=data.get('tenant_slug'),
58
+ is_archived=data.get('is_archived', False),
59
+ metadata=data.get('metadata', {}),
60
+ created_at=get_datetime_from_data(input_datetime=data.get('created_at')),
61
+ updated_at=get_datetime_from_data(input_datetime=data.get('updated_at')),
62
+ document_types=data.get('document_types', []),
63
+ )
@@ -0,0 +1,138 @@
1
+ from dataclasses import dataclass
2
+ from datetime import datetime
3
+ from decimal import Decimal
4
+ from typing import Optional
5
+ from uuid import UUID
6
+
7
+ from documente_shared.application.time_utils import get_datetime_from_data
8
+ from documente_shared.domain.entities.in_memory_document import InMemoryDocument
9
+ from documente_shared.domain.enums.common import ProcessingStatus
10
+ from documente_shared.domain.enums.workspace import WorkspaceSource
11
+ from documente_shared.domain.helpers.values import optional_str
12
+
13
+
14
+ @dataclass
15
+ class WorkspaceDocument(object):
16
+ uuid: UUID
17
+ name: str
18
+ status: ProcessingStatus
19
+ tenant_slug: str
20
+ workspace_id: UUID
21
+ digest: Optional[str] = None
22
+ document_type_id: Optional[UUID] = None
23
+ source: Optional[WorkspaceSource] = None
24
+ document: Optional[InMemoryDocument] = None
25
+ document_url: Optional[str] = None
26
+ processing_time: Optional[Decimal] = None
27
+ metadata: Optional[dict] = None
28
+ extraction: Optional[dict] = None
29
+ uploaded_at: Optional[datetime] = None
30
+ created_at: Optional[datetime] = None
31
+ updated_at: Optional[datetime] = None
32
+ started_at: Optional[datetime] = None
33
+ completed_at: Optional[datetime] = None
34
+ failed_at: Optional[datetime] = None
35
+
36
+ def __post_init__(self):
37
+ self.metadata = self.metadata or {}
38
+ self.extraction = self.extraction or {}
39
+
40
+ @property
41
+ def to_persist_dict(self) -> dict:
42
+ return {
43
+ "tenant_slug": self.tenant_slug,
44
+ "workspace_id": str(self.workspace_id),
45
+ "doctype_id": str(self.document_type_id) if self.document_type_id else None,
46
+ "name": self.name,
47
+ "digest": self.digest,
48
+ "status": str(self.status),
49
+ "source": optional_str(self.source),
50
+ "uploaded_at": self.uploaded_at,
51
+ "started_at": self.started_at,
52
+ "completed_at": self.completed_at,
53
+ "failed_at": self.failed_at,
54
+ "processing_time": self.processing_time,
55
+ "metadata": self.metadata or {},
56
+ "extraction": self.extraction or {},
57
+ }
58
+
59
+ @property
60
+ def to_dict(self) -> dict:
61
+ return {
62
+ "uuid": str(self.uuid),
63
+ "name": self.name,
64
+ "digest": self.digest,
65
+ "status": str(self.status),
66
+ "tenant_slug": self.tenant_slug,
67
+ "workspace_id": str(self.workspace_id),
68
+ "document_type_id": str(self.document_type_id) if self.document_type_id else None,
69
+ "source": optional_str(self.source),
70
+ "document": (
71
+ self.document.to_dict
72
+ if self.document else None
73
+ ),
74
+ "document_url": self.document_url,
75
+ "processing_time": (
76
+ str(self.processing_time)
77
+ if self.processing_time else None
78
+ ),
79
+ "metadata": self.metadata,
80
+ "extraction": self.extraction,
81
+ "uploaded_at": (
82
+ self.uploaded_at.isoformat()
83
+ if self.uploaded_at else None
84
+ ),
85
+ "created_at": (
86
+ self.created_at.isoformat()
87
+ if self.created_at else None
88
+ ),
89
+ "updated_at": (
90
+ self.updated_at.isoformat()
91
+ if self.updated_at else None
92
+ ),
93
+ "started_at": (
94
+ self.started_at.isoformat()
95
+ if self.started_at else None
96
+ ),
97
+ "completed_at": (
98
+ self.completed_at.isoformat()
99
+ if self.completed_at else None
100
+ ),
101
+ "failed_at": (
102
+ self.failed_at.isoformat()
103
+ if self.failed_at else None
104
+ ),
105
+ }
106
+
107
+ @classmethod
108
+ def from_dict(cls, data: dict) -> 'WorkspaceDocument':
109
+ return cls(
110
+ uuid=data.get('uuid'),
111
+ name=data.get('name'),
112
+ digest=data.get('digest'),
113
+ status=ProcessingStatus.from_value(data.get('status')),
114
+ tenant_slug=data.get('tenant_slug'),
115
+ workspace_id=data.get('workspace_id'),
116
+ document_type_id=data.get('document_type_id'),
117
+ source=(
118
+ WorkspaceSource.from_value(data.get('source'))
119
+ if data.get('source') else None
120
+ ),
121
+ document=(
122
+ InMemoryDocument.from_dict(data.get('document'))
123
+ if data.get('document') else None
124
+ ),
125
+ document_url=data.get('document_url'),
126
+ processing_time=(
127
+ Decimal(data.get('processing_time'))
128
+ if data.get('processing_time') else None
129
+ ),
130
+ metadata=data.get('metadata', {}),
131
+ extraction=data.get('extraction', {}),
132
+ uploaded_at=get_datetime_from_data(input_datetime=data.get('uploaded_at')),
133
+ created_at=get_datetime_from_data(input_datetime=data.get('created_at')),
134
+ updated_at=get_datetime_from_data(input_datetime=data.get('updated_at')),
135
+ started_at=get_datetime_from_data(input_datetime=data.get('started_at')),
136
+ completed_at=get_datetime_from_data(input_datetime=data.get('completed_at')),
137
+ failed_at=get_datetime_from_data(input_datetime=data.get('failed_at')),
138
+ )
@@ -0,0 +1,45 @@
1
+ from dataclasses import dataclass
2
+ from typing import List, Optional
3
+ from uuid import UUID
4
+
5
+ from documente_shared.application.query_params import QueryParams
6
+ from documente_shared.domain.enums.common import ProcessingStatus
7
+
8
+
9
+ @dataclass
10
+ class WorkspaceDocumentFilters(object):
11
+ workspace_id: Optional[UUID] = None
12
+ sort_order: Optional[str] = None
13
+ search: Optional[str] = None
14
+ digest: Optional[str] = None
15
+ statuses: List[ProcessingStatus] = None
16
+
17
+ def __post_init__(self):
18
+ self.statuses = self.statuses or []
19
+ self.sort_order = self.sort_order or "desc"
20
+
21
+ @property
22
+ def to_params(self) -> dict:
23
+ params = {
24
+ "workspace_id": str(self.workspace_id) if self.workspace_id else None,
25
+ "sort": self.sort_order,
26
+ "search": self.search,
27
+ "digest": self.digest,
28
+ "statuses": ",".join(str(s) for s in self.statuses) if self.statuses else None,
29
+ }
30
+ return {k: v for k, v in params.items() if v is not None}
31
+
32
+ @classmethod
33
+ def from_params(cls, params: QueryParams) -> "WorkspaceDocumentFilters":
34
+ search_term = params.get_str(key="search", default=None)
35
+ return cls(
36
+ workspace_id=params.get_uuid(key="workspace_id", default=None),
37
+ sort_order=params.get(key="sort", default="desc"),
38
+ search=search_term.strip() if search_term else None,
39
+ digest=params.get_str(key="digest", default=None),
40
+ statuses=params.get_enum_list(
41
+ key="statuses",
42
+ enum_class=ProcessingStatus,
43
+ default=None,
44
+ ),
45
+ )
@@ -0,0 +1,70 @@
1
+ from dataclasses import dataclass
2
+ from datetime import datetime
3
+ from typing import Optional
4
+ from uuid import UUID
5
+
6
+ from documente_shared.application.time_utils import get_datetime_from_data
7
+ from documente_shared.domain.entities.in_memory_document import InMemoryDocument
8
+
9
+
10
+ @dataclass
11
+ class WorkspaceDocumentPage(object):
12
+ uuid: UUID
13
+ tenant_slug: str
14
+ workspace_id: UUID
15
+ workspace_document_id: UUID
16
+ page_number: int
17
+ page_file: Optional[InMemoryDocument] = None
18
+ page_file_url: Optional[str] = None
19
+ created_at: Optional[datetime] = None
20
+ synced_at: Optional[datetime] = None
21
+
22
+ @property
23
+ def to_persist_dict(self) -> dict:
24
+ return {
25
+ "tenant_slug": self.tenant_slug,
26
+ "workspace_id": str(self.workspace_id),
27
+ "workspace_document_id": str(self.workspace_document_id),
28
+ "page_number": self.page_number,
29
+ "synced_at": self.synced_at,
30
+ }
31
+
32
+ @property
33
+ def to_dict(self) -> dict:
34
+ return {
35
+ "uuid": str(self.uuid),
36
+ "tenant_slug": self.tenant_slug,
37
+ "workspace_id": str(self.workspace_id),
38
+ "workspace_document_id": str(self.workspace_document_id),
39
+ "page_number": self.page_number,
40
+ "page_file": (
41
+ self.page_file.to_dict
42
+ if self.page_file else None
43
+ ),
44
+ "page_file_url": self.page_file_url,
45
+ "created_at": (
46
+ self.created_at.isoformat()
47
+ if self.created_at else None
48
+ ),
49
+ "synced_at": (
50
+ self.synced_at.isoformat()
51
+ if self.synced_at else None
52
+ ),
53
+ }
54
+
55
+ @classmethod
56
+ def from_dict(cls, data: dict) -> 'WorkspaceDocumentPage':
57
+ return cls(
58
+ uuid=data.get('uuid'),
59
+ tenant_slug=data.get('tenant_slug'),
60
+ workspace_id=data.get('workspace_id'),
61
+ workspace_document_id=data.get('workspace_document_id'),
62
+ page_number=data.get('page_number'),
63
+ page_file=(
64
+ InMemoryDocument.from_dict(data.get('page_file'))
65
+ if data.get('page_file') else None
66
+ ),
67
+ page_file_url=data.get('page_file_url'),
68
+ created_at=get_datetime_from_data(input_datetime=data.get('created_at')),
69
+ synced_at=get_datetime_from_data(input_datetime=data.get('synced_at')),
70
+ )
@@ -0,0 +1,32 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+ from uuid import UUID
4
+
5
+ from documente_shared.application.query_params import QueryParams
6
+
7
+
8
+ @dataclass
9
+ class WorkspaceDocumentPageFilters(object):
10
+ workspace_document_id: Optional[UUID] = None
11
+ sort_order: Optional[str] = None
12
+ page_number: Optional[int] = None
13
+
14
+ def __post_init__(self):
15
+ self.sort_order = self.sort_order or "desc"
16
+
17
+ @property
18
+ def to_params(self) -> dict:
19
+ params = {
20
+ "workspace_document_id": str(self.workspace_document_id) if self.workspace_document_id else None,
21
+ "sort": self.sort_order,
22
+ "page_number": self.page_number,
23
+ }
24
+ return {k: v for k, v in params.items() if v is not None}
25
+
26
+ @classmethod
27
+ def from_params(cls, params: QueryParams) -> "WorkspaceDocumentPageFilters":
28
+ return cls(
29
+ workspace_document_id=params.get_uuid(key="workspace_document_id", default=None),
30
+ sort_order=params.get(key="sort", default="desc"),
31
+ page_number=params.get_int(key="page_number", default=None),
32
+ )
@@ -0,0 +1,35 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+
4
+ from documente_shared.application.query_params import QueryParams
5
+
6
+
7
+ @dataclass
8
+ class WorkspaceFilters(object):
9
+ sort_order: Optional[str] = None
10
+ search: Optional[str] = None
11
+ include_archived: bool = False
12
+
13
+ def __post_init__(self):
14
+ self.sort_order = self.sort_order or "desc"
15
+
16
+ @property
17
+ def to_params(self) -> dict:
18
+ params = {
19
+ "sort": self.sort_order,
20
+ "search": self.search,
21
+ "include_archived": str(self.include_archived).lower(),
22
+ }
23
+ return {k: v for k, v in params.items() if v is not None}
24
+
25
+ @classmethod
26
+ def from_params(cls, params: QueryParams) -> "WorkspaceFilters":
27
+ search_term = params.get_str(key="search", default=None)
28
+ return cls(
29
+ sort_order=params.get(key="sort", default="desc"),
30
+ search=search_term.strip() if search_term else None,
31
+ include_archived=params.get_bool(
32
+ key="include_archived",
33
+ default=False,
34
+ ),
35
+ )
@@ -0,0 +1,19 @@
1
+ from documente_shared.domain.base_enum import BaseEnum
2
+
3
+
4
+ class WorkspaceSource(BaseEnum):
5
+ WEB = "WEB"
6
+ MOBILE = "MOBILE"
7
+ TOOLS = "TOOLS"
8
+
9
+ @property
10
+ def is_web(self):
11
+ return self == self.WEB
12
+
13
+ @property
14
+ def is_mobile(self):
15
+ return self == self.MOBILE
16
+
17
+ @property
18
+ def is_tools(self):
19
+ return self == self.TOOLS
@@ -0,0 +1,28 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any, List, Optional
3
+ from uuid import UUID
4
+
5
+ from documente_shared.domain.entities.workspace import Workspace
6
+ from documente_shared.domain.entities.workspace_filters import WorkspaceFilters
7
+
8
+
9
+ class WorkspaceRepository(ABC):
10
+ @abstractmethod
11
+ def find(self, uuid: UUID) -> Optional[Workspace]:
12
+ raise NotImplementedError
13
+
14
+ @abstractmethod
15
+ def filter(self, filters: WorkspaceFilters) -> List[Workspace]:
16
+ raise NotImplementedError
17
+
18
+ @abstractmethod
19
+ def filter_paginated(self, filters: WorkspaceFilters, page_params: Any) -> Any:
20
+ raise NotImplementedError
21
+
22
+ @abstractmethod
23
+ def persist(self, instance: Workspace) -> Workspace:
24
+ raise NotImplementedError
25
+
26
+ @abstractmethod
27
+ def delete(self, uuid: UUID) -> None:
28
+ raise NotImplementedError
@@ -0,0 +1,28 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any, List, Optional
3
+ from uuid import UUID
4
+
5
+ from documente_shared.domain.entities.workspace_document import WorkspaceDocument
6
+ from documente_shared.domain.entities.workspace_document_filters import WorkspaceDocumentFilters
7
+
8
+
9
+ class WorkspaceDocumentRepository(ABC):
10
+ @abstractmethod
11
+ def find(self, uuid: UUID) -> Optional[WorkspaceDocument]:
12
+ raise NotImplementedError
13
+
14
+ @abstractmethod
15
+ def filter(self, filters: WorkspaceDocumentFilters) -> List[WorkspaceDocument]:
16
+ raise NotImplementedError
17
+
18
+ @abstractmethod
19
+ def filter_paginated(self, filters: WorkspaceDocumentFilters, page_params: Any) -> Any:
20
+ raise NotImplementedError
21
+
22
+ @abstractmethod
23
+ def persist(self, instance: WorkspaceDocument) -> WorkspaceDocument:
24
+ raise NotImplementedError
25
+
26
+ @abstractmethod
27
+ def delete(self, uuid: UUID) -> None:
28
+ raise NotImplementedError
@@ -0,0 +1,28 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any, List, Optional
3
+ from uuid import UUID
4
+
5
+ from documente_shared.domain.entities.workspace_document_page import WorkspaceDocumentPage
6
+ from documente_shared.domain.entities.workspace_document_page_filters import WorkspaceDocumentPageFilters
7
+
8
+
9
+ class WorkspaceDocumentPageRepository(ABC):
10
+ @abstractmethod
11
+ def find(self, uuid: UUID) -> Optional[WorkspaceDocumentPage]:
12
+ raise NotImplementedError
13
+
14
+ @abstractmethod
15
+ def filter(self, filters: WorkspaceDocumentPageFilters) -> List[WorkspaceDocumentPage]:
16
+ raise NotImplementedError
17
+
18
+ @abstractmethod
19
+ def filter_paginated(self, filters: WorkspaceDocumentPageFilters, page_params: Any) -> Any:
20
+ raise NotImplementedError
21
+
22
+ @abstractmethod
23
+ def persist(self, instance: WorkspaceDocumentPage) -> WorkspaceDocumentPage:
24
+ raise NotImplementedError
25
+
26
+ @abstractmethod
27
+ def delete(self, uuid: UUID) -> None:
28
+ raise NotImplementedError
@@ -0,0 +1,71 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, List, Optional
3
+ from uuid import UUID
4
+
5
+ from loguru import logger
6
+ from requests import Response
7
+
8
+ from documente_shared.application.payloads import camel_to_snake
9
+ from documente_shared.domain.entities.workspace import Workspace
10
+ from documente_shared.domain.entities.workspace_filters import WorkspaceFilters
11
+ from documente_shared.domain.repositories.workspace import WorkspaceRepository
12
+ from documente_shared.infrastructure.documente_client import DocumenteClientMixin
13
+
14
+
15
+ @dataclass
16
+ class HttpWorkspaceRepository(
17
+ DocumenteClientMixin,
18
+ WorkspaceRepository,
19
+ ):
20
+ def find(self, uuid: UUID) -> Optional[Workspace]:
21
+ response = self.session.get(
22
+ url=f"{self.api_url}/v1/workspaces/{uuid}/",
23
+ )
24
+ if response.status_code not in [200, 201]:
25
+ return None
26
+ return self._build_workspace(response)
27
+
28
+ def filter(self, filters: WorkspaceFilters) -> List[Workspace]:
29
+ response = self.session.get(
30
+ url=f"{self.api_url}/v1/workspaces/",
31
+ params=filters.to_params,
32
+ )
33
+ if response.status_code not in [200, 201]:
34
+ return []
35
+ raw_response = response.json()
36
+ return [
37
+ Workspace.from_dict(camel_to_snake(item_data))
38
+ for item_data in raw_response.get('data', [])
39
+ ]
40
+
41
+ def filter_paginated(self, filters: WorkspaceFilters, page_params: Any) -> Any:
42
+ params = {**filters.to_params}
43
+ if isinstance(page_params, dict):
44
+ params.update(page_params)
45
+ response = self.session.get(
46
+ url=f"{self.api_url}/v1/workspaces/",
47
+ params=params,
48
+ )
49
+ if response.status_code not in [200, 201]:
50
+ return {"data": [], "count": 0}
51
+ return response.json()
52
+
53
+ def persist(self, instance: Workspace) -> Workspace:
54
+ logger.info(f"PERSISTING_WORKSPACE: data={instance.to_persist_dict}")
55
+ response: Response = self.session.post(
56
+ url=f"{self.api_url}/v1/workspaces/",
57
+ json=instance.to_persist_dict,
58
+ )
59
+ if response.status_code not in [200, 201]:
60
+ logger.info(f"PERSISTING_WORKSPACE ERROR: data={response.text}")
61
+ return instance
62
+ return self._build_workspace(response)
63
+
64
+ def delete(self, uuid: UUID) -> None:
65
+ self.session.delete(f"{self.api_url}/v1/workspaces/{uuid}/")
66
+
67
+ @classmethod
68
+ def _build_workspace(cls, response: Response) -> Workspace:
69
+ response_json = response.json()
70
+ instance_data = response_json.get('data', {})
71
+ return Workspace.from_dict(camel_to_snake(instance_data))
@@ -0,0 +1,71 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, List, Optional
3
+ from uuid import UUID
4
+
5
+ from loguru import logger
6
+ from requests import Response
7
+
8
+ from documente_shared.application.payloads import camel_to_snake
9
+ from documente_shared.domain.entities.workspace_document import WorkspaceDocument
10
+ from documente_shared.domain.entities.workspace_document_filters import WorkspaceDocumentFilters
11
+ from documente_shared.domain.repositories.workspace_document import WorkspaceDocumentRepository
12
+ from documente_shared.infrastructure.documente_client import DocumenteClientMixin
13
+
14
+
15
+ @dataclass
16
+ class HttpWorkspaceDocumentRepository(
17
+ DocumenteClientMixin,
18
+ WorkspaceDocumentRepository,
19
+ ):
20
+ def find(self, uuid: UUID) -> Optional[WorkspaceDocument]:
21
+ response = self.session.get(
22
+ url=f"{self.api_url}/v1/workspace-documents/{uuid}/",
23
+ )
24
+ if response.status_code not in [200, 201]:
25
+ return None
26
+ return self._build_workspace_document(response)
27
+
28
+ def filter(self, filters: WorkspaceDocumentFilters) -> List[WorkspaceDocument]:
29
+ response = self.session.get(
30
+ url=f"{self.api_url}/v1/workspaces/{filters.workspace_id}/documents/",
31
+ params=filters.to_params,
32
+ )
33
+ if response.status_code not in [200, 201]:
34
+ return []
35
+ raw_response = response.json()
36
+ return [
37
+ WorkspaceDocument.from_dict(camel_to_snake(item_data))
38
+ for item_data in raw_response.get('data', [])
39
+ ]
40
+
41
+ def filter_paginated(self, filters: WorkspaceDocumentFilters, page_params: Any) -> Any:
42
+ params = {**filters.to_params}
43
+ if isinstance(page_params, dict):
44
+ params.update(page_params)
45
+ response = self.session.get(
46
+ url=f"{self.api_url}/v1/workspaces/{filters.workspace_id}/documents/",
47
+ params=params,
48
+ )
49
+ if response.status_code not in [200, 201]:
50
+ return {"data": [], "count": 0}
51
+ return response.json()
52
+
53
+ def persist(self, instance: WorkspaceDocument) -> WorkspaceDocument:
54
+ logger.info(f"PERSISTING_WORKSPACE_DOCUMENT: data={instance.to_persist_dict}")
55
+ response: Response = self.session.post(
56
+ url=f"{self.api_url}/v1/workspaces/{instance.workspace_id}/documents/",
57
+ json=instance.to_persist_dict,
58
+ )
59
+ if response.status_code not in [200, 201]:
60
+ logger.info(f"PERSISTING_WORKSPACE_DOCUMENT ERROR: data={response.text}")
61
+ return instance
62
+ return self._build_workspace_document(response)
63
+
64
+ def delete(self, uuid: UUID) -> None:
65
+ self.session.delete(f"{self.api_url}/v1/workspace-documents/{uuid}/")
66
+
67
+ @classmethod
68
+ def _build_workspace_document(cls, response: Response) -> WorkspaceDocument:
69
+ response_json = response.json()
70
+ instance_data = response_json.get('data', {})
71
+ return WorkspaceDocument.from_dict(camel_to_snake(instance_data))
@@ -0,0 +1,71 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, List, Optional
3
+ from uuid import UUID
4
+
5
+ from loguru import logger
6
+ from requests import Response
7
+
8
+ from documente_shared.application.payloads import camel_to_snake
9
+ from documente_shared.domain.entities.workspace_document_page import WorkspaceDocumentPage
10
+ from documente_shared.domain.entities.workspace_document_page_filters import WorkspaceDocumentPageFilters
11
+ from documente_shared.domain.repositories.workspace_document_page import WorkspaceDocumentPageRepository
12
+ from documente_shared.infrastructure.documente_client import DocumenteClientMixin
13
+
14
+
15
+ @dataclass
16
+ class HttpWorkspaceDocumentPageRepository(
17
+ DocumenteClientMixin,
18
+ WorkspaceDocumentPageRepository,
19
+ ):
20
+ def find(self, uuid: UUID) -> Optional[WorkspaceDocumentPage]:
21
+ response = self.session.get(
22
+ url=f"{self.api_url}/v1/workspace-document-pages/{uuid}/",
23
+ )
24
+ if response.status_code not in [200, 201]:
25
+ return None
26
+ return self._build_workspace_document_page(response)
27
+
28
+ def filter(self, filters: WorkspaceDocumentPageFilters) -> List[WorkspaceDocumentPage]:
29
+ response = self.session.get(
30
+ url=f"{self.api_url}/v1/workspace-documents/{filters.workspace_document_id}/pages/",
31
+ params=filters.to_params,
32
+ )
33
+ if response.status_code not in [200, 201]:
34
+ return []
35
+ raw_response = response.json()
36
+ return [
37
+ WorkspaceDocumentPage.from_dict(camel_to_snake(item_data))
38
+ for item_data in raw_response.get('data', [])
39
+ ]
40
+
41
+ def filter_paginated(self, filters: WorkspaceDocumentPageFilters, page_params: Any) -> Any:
42
+ params = {**filters.to_params}
43
+ if isinstance(page_params, dict):
44
+ params.update(page_params)
45
+ response = self.session.get(
46
+ url=f"{self.api_url}/v1/workspace-documents/{filters.workspace_document_id}/pages/",
47
+ params=params,
48
+ )
49
+ if response.status_code not in [200, 201]:
50
+ return {"data": [], "count": 0}
51
+ return response.json()
52
+
53
+ def persist(self, instance: WorkspaceDocumentPage) -> WorkspaceDocumentPage:
54
+ logger.info(f"PERSISTING_WORKSPACE_DOCUMENT_PAGE: data={instance.to_persist_dict}")
55
+ response: Response = self.session.post(
56
+ url=f"{self.api_url}/v1/workspace-documents/{instance.workspace_document_id}/pages/",
57
+ json=instance.to_persist_dict,
58
+ )
59
+ if response.status_code not in [200, 201]:
60
+ logger.info(f"PERSISTING_WORKSPACE_DOCUMENT_PAGE ERROR: data={response.text}")
61
+ return instance
62
+ return self._build_workspace_document_page(response)
63
+
64
+ def delete(self, uuid: UUID) -> None:
65
+ self.session.delete(f"{self.api_url}/v1/workspace-document-pages/{uuid}/")
66
+
67
+ @classmethod
68
+ def _build_workspace_document_page(cls, response: Response) -> WorkspaceDocumentPage:
69
+ response_json = response.json()
70
+ instance_data = response_json.get('data', {})
71
+ return WorkspaceDocumentPage.from_dict(camel_to_snake(instance_data))
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "documente_shared"
3
- version = "0.1.160"
3
+ version = "0.1.161"
4
4
  description = "Shared utilities for Documente AI projects"
5
5
  authors = [{ name = "Tech", email = "tech@llamitai.com" }]
6
6
  license = { text = "MIT" }
@@ -129,7 +129,7 @@ wheels = [
129
129
 
130
130
  [[package]]
131
131
  name = "documente-shared"
132
- version = "0.1.160"
132
+ version = "0.1.161"
133
133
  source = { editable = "." }
134
134
  dependencies = [
135
135
  { name = "boto3" },