altcodepro-polydb-python 2.3.28__tar.gz → 2.3.29__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 (93) hide show
  1. {altcodepro_polydb_python-2.3.28/src/altcodepro_polydb_python.egg-info → altcodepro_polydb_python-2.3.29}/PKG-INFO +1 -1
  2. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/pyproject.toml +1 -1
  3. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29/src/altcodepro_polydb_python.egg-info}/PKG-INFO +1 -1
  4. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/AzureQueueAdapter.py +31 -2
  5. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/tests/test_azure_queue_receipt_handle.py +44 -0
  6. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/LICENSE +0 -0
  7. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/MANIFEST.in +0 -0
  8. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/README.md +0 -0
  9. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/requirements-aws.txt +0 -0
  10. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/requirements-azure.txt +0 -0
  11. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/requirements-dev.txt +0 -0
  12. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/requirements-gcp.txt +0 -0
  13. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/requirements-generic.txt +0 -0
  14. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/requirements.txt +0 -0
  15. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/setup.cfg +0 -0
  16. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/setup.py +0 -0
  17. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/altcodepro_polydb_python.egg-info/SOURCES.txt +0 -0
  18. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/altcodepro_polydb_python.egg-info/dependency_links.txt +0 -0
  19. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/altcodepro_polydb_python.egg-info/requires.txt +0 -0
  20. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/altcodepro_polydb_python.egg-info/top_level.txt +0 -0
  21. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/PolyDB.py +0 -0
  22. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/__init__.py +0 -0
  23. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/AzureBlobStorageAdapter.py +0 -0
  24. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/AzureFileStorageAdapter.py +0 -0
  25. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/AzureTableStorageAdapter.py +0 -0
  26. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/BlockchainBlobAdapter.py +0 -0
  27. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/BlockchainFileAdapter.py +0 -0
  28. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/BlockchainKVAdapter.py +0 -0
  29. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/BlockchainQueueAdapter.py +0 -0
  30. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/DynamoDBAdapter.py +0 -0
  31. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/EFSAdapter.py +0 -0
  32. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/FirestoreAdapter.py +0 -0
  33. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/GCPFilestoreAdapter.py +0 -0
  34. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/GCPPubSubAdapter.py +0 -0
  35. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/GCPStorageAdapter.py +0 -0
  36. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/MongoDBAdapter.py +0 -0
  37. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/PostgreSQLAdapter.py +0 -0
  38. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/S3Adapter.py +0 -0
  39. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/S3CompatibleAdapter.py +0 -0
  40. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/SQSAdapter.py +0 -0
  41. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/VercelBlobAdapter.py +0 -0
  42. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/VercelFileAdapter.py +0 -0
  43. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/VercelKVAdapter.py +0 -0
  44. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/VercelQueueAdapter.py +0 -0
  45. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/adapters/__init__.py +0 -0
  46. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/advanced_query.py +0 -0
  47. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/audit/AuditStorage.py +0 -0
  48. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/audit/__init__.py +0 -0
  49. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/audit/context.py +0 -0
  50. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/audit/manager.py +0 -0
  51. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/audit/models.py +0 -0
  52. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/base/NoSQLKVAdapter.py +0 -0
  53. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/base/ObjectStorageAdapter.py +0 -0
  54. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/base/QueueAdapter.py +0 -0
  55. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/base/SharedFilesAdapter.py +0 -0
  56. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/base/__init__.py +0 -0
  57. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/batch.py +0 -0
  58. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/cache.py +0 -0
  59. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/cloudDatabaseFactory.py +0 -0
  60. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/databaseFactory.py +0 -0
  61. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/decorators.py +0 -0
  62. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/errors.py +0 -0
  63. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/json_safe.py +0 -0
  64. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/models.py +0 -0
  65. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/monitoring.py +0 -0
  66. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/multitenancy.py +0 -0
  67. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/observability/__init__.py +0 -0
  68. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/observability/logging.py +0 -0
  69. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/py.typed +0 -0
  70. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/query.py +0 -0
  71. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/registry.py +0 -0
  72. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/retry.py +0 -0
  73. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/schema.py +0 -0
  74. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/security.py +0 -0
  75. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/services/__init__.py +0 -0
  76. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/services/compliance_service.py +0 -0
  77. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/services/security_service.py +0 -0
  78. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/types.py +0 -0
  79. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/utils.py +0 -0
  80. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/src/polydb/validation.py +0 -0
  81. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/tests/test_atomic_decrement.py +0 -0
  82. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/tests/test_aws.py +0 -0
  83. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/tests/test_azure.py +0 -0
  84. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/tests/test_azure_table_empty_filter.py +0 -0
  85. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/tests/test_azure_table_unpack_entity.py +0 -0
  86. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/tests/test_blockchain.py +0 -0
  87. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/tests/test_cloud_factory.py +0 -0
  88. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/tests/test_gcp.py +0 -0
  89. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/tests/test_mongodb.py +0 -0
  90. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/tests/test_multi_engine.py +0 -0
  91. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/tests/test_observability.py +0 -0
  92. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/tests/test_postgresql.py +0 -0
  93. {altcodepro_polydb_python-2.3.28 → altcodepro_polydb_python-2.3.29}/tests/test_vercel.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: altcodepro-polydb-python
3
- Version: 2.3.28
3
+ Version: 2.3.29
4
4
  Summary: Production-ready multi-cloud database abstraction layer with connection pooling, retry logic, and thread safety
5
5
  Author: AltCodePro
6
6
  Project-URL: Homepage, https://github.com/altcodepro/polydb-python
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "altcodepro-polydb-python"
7
- version = "2.3.28"
7
+ version = "2.3.29"
8
8
  description = "Production-ready multi-cloud database abstraction layer with connection pooling, retry logic, and thread safety"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: altcodepro-polydb-python
3
- Version: 2.3.28
3
+ Version: 2.3.29
4
4
  Summary: Production-ready multi-cloud database abstraction layer with connection pooling, retry logic, and thread safety
5
5
  Author: AltCodePro
6
6
  Project-URL: Homepage, https://github.com/altcodepro/polydb-python
@@ -110,15 +110,38 @@ class AzureQueueAdapter(QueueAdapter):
110
110
  except Exception as e:
111
111
  raise QueueError(f"Azure Queue send failed: {e}")
112
112
 
113
+ # How long a delivered message stays invisible to other consumers before
114
+ # Azure hands it out again. The SDK's own default is 30s — far shorter
115
+ # than a real task (an LLM generation call alone can run 30-120s+), so
116
+ # a still-in-flight message was becoming visible again and getting
117
+ # picked up by a second worker mid-processing: two concurrent
118
+ # executions of the same task, one of which stomps/duplicates the
119
+ # other's result. 300s covers realistic worst-case processing; ack()
120
+ # deletes the message immediately on completion regardless; a genuinely
121
+ # crashed worker still recovers the message after this timeout.
122
+ DEFAULT_VISIBILITY_TIMEOUT = 300
123
+
113
124
  @retry(max_attempts=3, delay=1.0, exceptions=(QueueError,))
114
- def receive(self, queue_name: str = "default", max_messages: int = 1) -> List[Dict[str, Any]]:
125
+ def receive(
126
+ self,
127
+ queue_name: str = "default",
128
+ max_messages: int = 1,
129
+ visibility_timeout: Optional[int] = None,
130
+ ) -> List[Dict[str, Any]]:
115
131
  """Receive messages"""
116
132
  try:
117
133
 
118
134
  queue_name = self._normalize_queue_name(queue_name)
119
135
  queue_client = self._get_queue(queue_name)
120
136
 
121
- messages = queue_client.receive_messages(max_messages=max_messages)
137
+ messages = queue_client.receive_messages(
138
+ max_messages=max_messages,
139
+ visibility_timeout=(
140
+ visibility_timeout
141
+ if visibility_timeout is not None
142
+ else self.DEFAULT_VISIBILITY_TIMEOUT
143
+ ),
144
+ )
122
145
 
123
146
  results = []
124
147
 
@@ -135,6 +158,12 @@ class AzureQueueAdapter(QueueAdapter):
135
158
  # Azure's visibility timeout elapses — replaying the
136
159
  # same task forever even after it already ran.
137
160
  "receipt_handle": self._encode_receipt(msg.id, msg.pop_receipt),
161
+ # How many times Azure has handed this same message
162
+ # out (1 on first delivery). Lets a consumer (e.g.
163
+ # WorkerPool) detect a poison message that keeps
164
+ # failing to ack/process and dead-letter it instead
165
+ # of retrying forever.
166
+ "dequeue_count": msg.dequeue_count,
138
167
  "body": payload,
139
168
  }
140
169
  )
@@ -75,6 +75,23 @@ class TestReceiveReturnsReceiptHandle:
75
75
  assert "receipt_handle" in received
76
76
  assert received["receipt_handle"] # truthy -- WorkerPool checks `if receipt_handle`
77
77
 
78
+ def test_receive_surfaces_dequeue_count(self):
79
+ """WorkerPool's poison-message guard thresholds on this to
80
+ dead-letter a message the queue keeps redelivering."""
81
+ adapter = _make_adapter()
82
+ client = _mock_queue_client(adapter)
83
+
84
+ raw_msg = MagicMock()
85
+ raw_msg.id = "msg-123"
86
+ raw_msg.pop_receipt = "pop-abc"
87
+ raw_msg.content = json.dumps({"hello": "world"})
88
+ raw_msg.dequeue_count = 7
89
+ client.receive_messages.return_value = [raw_msg]
90
+
91
+ [received] = adapter.receive(queue_name="default", max_messages=1)
92
+
93
+ assert received["dequeue_count"] == 7
94
+
78
95
  def test_receipt_handle_round_trips_through_decode(self):
79
96
  message_id, pop_receipt = AzureQueueAdapter._decode_receipt(
80
97
  AzureQueueAdapter._encode_receipt("msg-123", "pop-abc")
@@ -82,6 +99,33 @@ class TestReceiveReturnsReceiptHandle:
82
99
  assert message_id == "msg-123"
83
100
  assert pop_receipt == "pop-abc"
84
101
 
102
+ def test_receive_defaults_to_a_long_visibility_timeout(self):
103
+ """The Azure SDK's own default (30s) is shorter than a real task
104
+ can take (an LLM call alone can run 30-120s+), so a still-in-flight
105
+ message became visible again and got picked up by a second worker
106
+ mid-processing -- two concurrent executions of the same task. This
107
+ guards against that default silently regressing back to 30s (or
108
+ being dropped entirely, which is the SDK's fallback)."""
109
+ adapter = _make_adapter()
110
+ client = _mock_queue_client(adapter)
111
+ client.receive_messages.return_value = []
112
+
113
+ adapter.receive(queue_name="default", max_messages=1)
114
+
115
+ _, kwargs = client.receive_messages.call_args
116
+ assert kwargs["visibility_timeout"] == AzureQueueAdapter.DEFAULT_VISIBILITY_TIMEOUT
117
+ assert kwargs["visibility_timeout"] >= 300
118
+
119
+ def test_receive_honours_an_explicit_visibility_timeout(self):
120
+ adapter = _make_adapter()
121
+ client = _mock_queue_client(adapter)
122
+ client.receive_messages.return_value = []
123
+
124
+ adapter.receive(queue_name="default", max_messages=1, visibility_timeout=45)
125
+
126
+ _, kwargs = client.receive_messages.call_args
127
+ assert kwargs["visibility_timeout"] == 45
128
+
85
129
 
86
130
  class TestAckAcceptsSingleReceiptHandle:
87
131
  def test_ack_with_generic_single_arg_deletes_using_decoded_parts(self):