abstract-block-dumper 0.0.1__tar.gz → 0.0.2__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 (80) hide show
  1. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/CHANGELOG.md +5 -0
  2. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/PKG-INFO +22 -6
  3. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/README.md +21 -5
  4. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/README.md +1 -1
  5. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/block_explorer/tasks.py +1 -1
  6. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/docker-compose.yml +1 -1
  7. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/example_project/settings.py +10 -0
  8. {abstract_block_dumper-0.0.1/src/abstract_block_dumper → abstract_block_dumper-0.0.2/src/abstract_block_dumper/_internal}/dal/django_dal.py +4 -3
  9. {abstract_block_dumper-0.0.1/src/abstract_block_dumper → abstract_block_dumper-0.0.2/src/abstract_block_dumper/_internal}/dal/memory_registry.py +6 -14
  10. {abstract_block_dumper-0.0.1/src/abstract_block_dumper → abstract_block_dumper-0.0.2/src/abstract_block_dumper/_internal}/discovery.py +1 -1
  11. {abstract_block_dumper-0.0.1/src/abstract_block_dumper → abstract_block_dumper-0.0.2/src/abstract_block_dumper/_internal}/exceptions.py +1 -1
  12. {abstract_block_dumper-0.0.1/src/abstract_block_dumper → abstract_block_dumper-0.0.2/src/abstract_block_dumper/_internal}/services/block_processor.py +6 -5
  13. {abstract_block_dumper-0.0.1/src/abstract_block_dumper → abstract_block_dumper-0.0.2/src/abstract_block_dumper/_internal}/services/executor.py +2 -2
  14. {abstract_block_dumper-0.0.1/src/abstract_block_dumper → abstract_block_dumper-0.0.2/src/abstract_block_dumper/_internal}/services/scheduler.py +3 -3
  15. {abstract_block_dumper-0.0.1/src/abstract_block_dumper → abstract_block_dumper-0.0.2/src/abstract_block_dumper/_internal}/services/utils.py +3 -7
  16. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/src/abstract_block_dumper/_version.py +2 -2
  17. abstract_block_dumper-0.0.1/src/abstract_block_dumper/management/commands/block_tasks.py → abstract_block_dumper-0.0.2/src/abstract_block_dumper/management/commands/block_tasks_v1.py +3 -3
  18. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/src/abstract_block_dumper/models.py +1 -1
  19. {abstract_block_dumper-0.0.1/src/abstract_block_dumper → abstract_block_dumper-0.0.2/src/abstract_block_dumper/v1}/decorators.py +7 -8
  20. {abstract_block_dumper-0.0.1/src/abstract_block_dumper → abstract_block_dumper-0.0.2/src/abstract_block_dumper/v1}/tasks.py +3 -3
  21. abstract_block_dumper-0.0.2/tests/__init__.py +0 -0
  22. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/tests/conftest.py +2 -2
  23. abstract_block_dumper-0.0.2/tests/integration/__init__.py +0 -0
  24. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/tests/integration/test_block_processor.py +3 -3
  25. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/tests/integration/test_concurrent_processing.py +6 -6
  26. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/tests/integration/test_multi_arguments_tasks.py +4 -4
  27. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/tests/integration/test_registered_celery_tasks.py +5 -5
  28. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/tests/integration/test_scheduler.py +5 -5
  29. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/tests/integration/test_task_registration.py +4 -4
  30. abstract_block_dumper-0.0.2/tests/unit/test_decorator.py +0 -0
  31. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/.cruft.json +0 -0
  32. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/.github/dependabot.yml +0 -0
  33. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/.github/workflows/ci.yml +0 -0
  34. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/.github/workflows/publish.yml +0 -0
  35. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/.gitignore +0 -0
  36. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/.pre-commit-config.yaml +0 -0
  37. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/.shellcheckrc +0 -0
  38. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/SECURITY.md +0 -0
  39. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/docs/3rd_party/cookiecutter-rt-pkg/CHANGELOG.md +0 -0
  40. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/.dockerignore +0 -0
  41. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/.gitignore +0 -0
  42. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/Dockerfile +0 -0
  43. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/block_explorer/__init__.py +0 -0
  44. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/block_explorer/admin.py +0 -0
  45. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/block_explorer/apps.py +0 -0
  46. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/block_explorer/management/__init__.py +0 -0
  47. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/block_explorer/management/commands/__init__.py +0 -0
  48. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/block_explorer/management/commands/create_admin.py +0 -0
  49. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/block_explorer/migrations/__init__.py +0 -0
  50. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/block_explorer/models.py +0 -0
  51. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/block_explorer/tests.py +0 -0
  52. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/block_explorer/views.py +0 -0
  53. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/example_project/__init__.py +0 -0
  54. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/example_project/asgi.py +0 -0
  55. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/example_project/celery.py +0 -0
  56. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/example_project/urls.py +0 -0
  57. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/example_project/wsgi.py +0 -0
  58. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/main.py +0 -0
  59. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/manage.py +0 -0
  60. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/pyproject.toml +0 -0
  61. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/pytest.ini +0 -0
  62. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/example_project/uv.lock +0 -0
  63. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/noxfile.py +0 -0
  64. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/pyproject.toml +0 -0
  65. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/src/abstract_block_dumper/__init__.py +0 -0
  66. {abstract_block_dumper-0.0.1/src/abstract_block_dumper/dal → abstract_block_dumper-0.0.2/src/abstract_block_dumper/_internal}/__init__.py +0 -0
  67. {abstract_block_dumper-0.0.1/src/abstract_block_dumper/management → abstract_block_dumper-0.0.2/src/abstract_block_dumper/_internal/dal}/__init__.py +0 -0
  68. {abstract_block_dumper-0.0.1/src/abstract_block_dumper/migrations → abstract_block_dumper-0.0.2/src/abstract_block_dumper/_internal/services}/__init__.py +0 -0
  69. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/src/abstract_block_dumper/admin.py +0 -0
  70. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/src/abstract_block_dumper/apps.py +0 -0
  71. {abstract_block_dumper-0.0.1/src/abstract_block_dumper/services → abstract_block_dumper-0.0.2/src/abstract_block_dumper/management}/__init__.py +0 -0
  72. {abstract_block_dumper-0.0.1/tests → abstract_block_dumper-0.0.2/src/abstract_block_dumper/management/commands}/__init__.py +0 -0
  73. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/src/abstract_block_dumper/migrations/0001_initial.py +0 -0
  74. {abstract_block_dumper-0.0.1/tests/integration → abstract_block_dumper-0.0.2/src/abstract_block_dumper/migrations}/__init__.py +0 -0
  75. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/src/abstract_block_dumper/py.typed +0 -0
  76. /abstract_block_dumper-0.0.1/tests/unit/test_decorator.py → /abstract_block_dumper-0.0.2/src/abstract_block_dumper/v1/__init__.py +0 -0
  77. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/tests/django_fixtures.py +0 -0
  78. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/tests/fatories.py +0 -0
  79. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/tests/settings.py +0 -0
  80. {abstract_block_dumper-0.0.1 → abstract_block_dumper-0.0.2}/uv.lock +0 -0
@@ -9,6 +9,11 @@ upcoming release can be found in [changelog.d](changelog.d).
9
9
 
10
10
  <!-- towncrier release notes start -->
11
11
 
12
+ ## [0.0.2](https://github.com/bactensor/abstract-block-dumper/releases/tag/v0.0.2) - 2025-10-24
13
+
14
+ No significant changes.
15
+
16
+
12
17
  ## [0.0.1](https://github.com/bactensor/abstract-block-dumper/releases/tag/v0.0.1) - 2025-10-21
13
18
 
14
19
  No significant changes.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: abstract-block-dumper
3
- Version: 0.0.1
3
+ Version: 0.0.2
4
4
  Project-URL: Source, https://github.com/bactensor/abstract-block-dumper
5
5
  Project-URL: Issue Tracker, https://github.com/bactensor/abstract-block-dumper/issues
6
6
  Author-email: Reef Technologies <opensource@reef.pl>
@@ -26,6 +26,22 @@ Description-Content-Type: text/markdown
26
26
  This package provides a simplified framework for creating block processing tasks in Django applications.
27
27
  Define tasks with lambda conditions using the @block_task decorator and run them asynchronously with Celery.
28
28
 
29
+ ## Usage
30
+
31
+ > [!IMPORTANT]
32
+ > This package uses [ApiVer](#versioning), make sure to import `abstract_block_dumper.v1`.
33
+
34
+
35
+ ## Versioning
36
+
37
+ This package uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
38
+ TL;DR you are safe to use [compatible release version specifier](https://packaging.python.org/en/latest/specifications/version-specifiers/#compatible-release) `~=MAJOR.MINOR` in your `pyproject.toml` or `requirements.txt`.
39
+
40
+ Additionally, this package uses [ApiVer](https://www.youtube.com/watch?v=FgcoAKchPjk) to further reduce the risk of breaking changes.
41
+ This means, the public API of this package is explicitly versioned, e.g. `abstract_block_dumper.v1`, and will not change in a backwards-incompatible way even when `abstract_block_dumper.v2` is released.
42
+
43
+ Internal packages, i.e. prefixed by `abstract_block_dumper._` do not share these guarantees and may change in a backwards-incompatible way at any time even in patch releases.
44
+
29
45
  ## Implementation Details
30
46
 
31
47
  ### General Workflow:
@@ -93,7 +109,7 @@ Create block processing tasks in `tasks.py` or `block_tasks.py` file inside any
93
109
  ### 3. Start the Block Scheduler
94
110
  Run the scheduler to start processing blocks:
95
111
  ```bash
96
- $ python manage.py block_tasks
112
+ $ python manage.py block_tasks_v1
97
113
  ```
98
114
 
99
115
  This command will:
@@ -112,7 +128,7 @@ See examples below:
112
128
  Use the `@block_task` decorator with lambda conditions to create block processing tasks:
113
129
 
114
130
  ```python
115
- from abstract_block_dumper.decorators import block_task
131
+ from abstract_block_dumper.api.v1.decorators import block_task
116
132
 
117
133
 
118
134
  # Process every block
@@ -144,7 +160,7 @@ def process_multi_netuid_task(block_number: int, netuid: int):
144
160
  The framework provides a maintenance task to clean up old task records and maintain database performance:
145
161
 
146
162
  ```python
147
- from abstract_block_dumper.tasks import cleanup_old_tasks
163
+ from abstract_block_dumper.v1.tasks import cleanup_old_tasks
148
164
 
149
165
  # Delete tasks older than 7 days (default)
150
166
  cleanup_old_tasks.delay()
@@ -160,13 +176,13 @@ This task deletes all succeeded or unrecoverable failed tasks older than the spe
160
176
  **Option 1: Manual Execution**
161
177
  ```bash
162
178
  # Using Django shell
163
- python manage.py shell -c "from abstract_block_dumper.tasks import cleanup_old_tasks; cleanup_old_tasks.delay()"
179
+ python manage.py shell -c "from abstract_block_dumper.v1.tasks import cleanup_old_tasks; cleanup_old_tasks.delay()"
164
180
  ```
165
181
 
166
182
  **Option 2: Cron Job (Recommended - once per day)**
167
183
  ```bash
168
184
  # Add to crontab (daily at 2 AM)
169
- 0 2 * * * cd /path/to/your/project && python manage.py shell -c "from abstract_block_dumper.tasks import cleanup_old_tasks; cleanup_old_tasks.delay()"
185
+ 0 2 * * * cd /path/to/your/project && python manage.py shell -c "from abstract_block_dumper.v1.tasks import cleanup_old_tasks; cleanup_old_tasks.delay()"
170
186
  ```
171
187
 
172
188
  **Option 3: Celery Beat (Automated Scheduling)**
@@ -4,6 +4,22 @@
4
4
  This package provides a simplified framework for creating block processing tasks in Django applications.
5
5
  Define tasks with lambda conditions using the @block_task decorator and run them asynchronously with Celery.
6
6
 
7
+ ## Usage
8
+
9
+ > [!IMPORTANT]
10
+ > This package uses [ApiVer](#versioning), make sure to import `abstract_block_dumper.v1`.
11
+
12
+
13
+ ## Versioning
14
+
15
+ This package uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
16
+ TL;DR you are safe to use [compatible release version specifier](https://packaging.python.org/en/latest/specifications/version-specifiers/#compatible-release) `~=MAJOR.MINOR` in your `pyproject.toml` or `requirements.txt`.
17
+
18
+ Additionally, this package uses [ApiVer](https://www.youtube.com/watch?v=FgcoAKchPjk) to further reduce the risk of breaking changes.
19
+ This means, the public API of this package is explicitly versioned, e.g. `abstract_block_dumper.v1`, and will not change in a backwards-incompatible way even when `abstract_block_dumper.v2` is released.
20
+
21
+ Internal packages, i.e. prefixed by `abstract_block_dumper._` do not share these guarantees and may change in a backwards-incompatible way at any time even in patch releases.
22
+
7
23
  ## Implementation Details
8
24
 
9
25
  ### General Workflow:
@@ -71,7 +87,7 @@ Create block processing tasks in `tasks.py` or `block_tasks.py` file inside any
71
87
  ### 3. Start the Block Scheduler
72
88
  Run the scheduler to start processing blocks:
73
89
  ```bash
74
- $ python manage.py block_tasks
90
+ $ python manage.py block_tasks_v1
75
91
  ```
76
92
 
77
93
  This command will:
@@ -90,7 +106,7 @@ See examples below:
90
106
  Use the `@block_task` decorator with lambda conditions to create block processing tasks:
91
107
 
92
108
  ```python
93
- from abstract_block_dumper.decorators import block_task
109
+ from abstract_block_dumper.api.v1.decorators import block_task
94
110
 
95
111
 
96
112
  # Process every block
@@ -122,7 +138,7 @@ def process_multi_netuid_task(block_number: int, netuid: int):
122
138
  The framework provides a maintenance task to clean up old task records and maintain database performance:
123
139
 
124
140
  ```python
125
- from abstract_block_dumper.tasks import cleanup_old_tasks
141
+ from abstract_block_dumper.v1.tasks import cleanup_old_tasks
126
142
 
127
143
  # Delete tasks older than 7 days (default)
128
144
  cleanup_old_tasks.delay()
@@ -138,13 +154,13 @@ This task deletes all succeeded or unrecoverable failed tasks older than the spe
138
154
  **Option 1: Manual Execution**
139
155
  ```bash
140
156
  # Using Django shell
141
- python manage.py shell -c "from abstract_block_dumper.tasks import cleanup_old_tasks; cleanup_old_tasks.delay()"
157
+ python manage.py shell -c "from abstract_block_dumper.v1.tasks import cleanup_old_tasks; cleanup_old_tasks.delay()"
142
158
  ```
143
159
 
144
160
  **Option 2: Cron Job (Recommended - once per day)**
145
161
  ```bash
146
162
  # Add to crontab (daily at 2 AM)
147
- 0 2 * * * cd /path/to/your/project && python manage.py shell -c "from abstract_block_dumper.tasks import cleanup_old_tasks; cleanup_old_tasks.delay()"
163
+ 0 2 * * * cd /path/to/your/project && python manage.py shell -c "from abstract_block_dumper.v1.tasks import cleanup_old_tasks; cleanup_old_tasks.delay()"
148
164
  ```
149
165
 
150
166
  **Option 3: Celery Beat (Automated Scheduling)**
@@ -15,5 +15,5 @@ docker-compose up --build
15
15
  2. Access the Django admin interface at `http://localhost:8000/admin` with username `admin` and password `admin` (automatically created).
16
16
  3. Start the block dumper scheduler:
17
17
  ```bash
18
- docker-compose exec web python manage.py block_tasks
18
+ docker-compose exec web python manage.py block_tasks_v1
19
19
  ```
@@ -1,4 +1,4 @@
1
- from abstract_block_dumper.decorators import block_task
1
+ from abstract_block_dumper.v1.decorators import block_task
2
2
 
3
3
 
4
4
  @block_task(
@@ -69,7 +69,7 @@ services:
69
69
  build:
70
70
  context: ..
71
71
  dockerfile: example_project/Dockerfile
72
- command: uv run python manage.py block_tasks
72
+ command: uv run python manage.py block_tasks_v1
73
73
  volumes:
74
74
  - .:/app/example_project
75
75
  - ../src:/app/src
@@ -3,6 +3,7 @@ import sys
3
3
  from pathlib import Path
4
4
 
5
5
  import dj_database_url # type: ignore
6
+ from celery.schedules import crontab
6
7
 
7
8
  # Build paths inside the project like this: BASE_DIR / 'subdir'.
8
9
  BASE_DIR = Path(__file__).resolve().parent.parent
@@ -133,3 +134,12 @@ BLOCK_DUMPER_POLL_INTERVAL = 1 # seconds - ultra-fast polling for real-time pro
133
134
  BLOCK_DUMPER_START_FROM_BLOCK = "current" # None = resume from DB, 'current' = current block, or block number
134
135
  BLOCK_TASK_RETRY_BACKOFF = 2
135
136
  BLOCK_DUMPER_MAX_ATTEMPTS = 3
137
+
138
+
139
+ CELERY_BEAT_SCHEDULE = {
140
+ "cleanup-old-tasks": {
141
+ "task": "abstract_block_dumper.cleanup_old_tasks",
142
+ "schedule": crontab(hour=2, minute=0), # Daily at 2 AM
143
+ "kwargs": {"days": 7}, # Customize retention period
144
+ },
145
+ }
@@ -6,8 +6,8 @@ from django.db import transaction
6
6
  from django.db.models.query import QuerySet
7
7
  from django.utils import timezone
8
8
 
9
+ import abstract_block_dumper._internal.services.utils as abd_utils
9
10
  import abstract_block_dumper.models as abd_models
10
- import abstract_block_dumper.services.utils as abd_utils
11
11
 
12
12
 
13
13
  def get_ready_to_retry_attempts() -> QuerySet[abd_models.TaskAttempt]:
@@ -76,7 +76,7 @@ def task_mark_as_success(task: abd_models.TaskAttempt, result_data: dict) -> Non
76
76
  task.save()
77
77
 
78
78
 
79
- def task_mark_as_failed(task) -> None:
79
+ def task_mark_as_failed(task: abd_models.TaskAttempt) -> None:
80
80
  DEFAULT_BLOCK_TASK_RETRY_BACKOFF = 1
81
81
  MAX_RETRY_DELAY_MINUTES = 1440 # 24 hours max delay
82
82
 
@@ -98,7 +98,7 @@ def task_mark_as_failed(task) -> None:
98
98
  task.save()
99
99
 
100
100
 
101
- def task_schedule_to_retry(task):
101
+ def task_schedule_to_retry(task: abd_models.TaskAttempt) -> None:
102
102
  task.status = abd_models.TaskAttempt.Status.PENDING
103
103
  task.save()
104
104
 
@@ -110,6 +110,7 @@ def task_create_or_get_pending(
110
110
  ) -> tuple[abd_models.TaskAttempt, bool]:
111
111
  """
112
112
  Create or get a pending task attempt.
113
+
113
114
  Returns (task, created) where created indicates if a new task was created.
114
115
 
115
116
  For failed tasks that can retry:
@@ -6,7 +6,7 @@ from typing import Any
6
6
  import structlog
7
7
  from celery import Task
8
8
 
9
- from abstract_block_dumper.exceptions import ConditionEvaluationError
9
+ from abstract_block_dumper._internal.exceptions import ConditionEvaluationError
10
10
 
11
11
  logger = structlog.getLogger(__name__)
12
12
 
@@ -19,10 +19,8 @@ class RegistryItem:
19
19
  backfilling_lookback: int | None = None
20
20
  celery_kwargs: dict[str, Any] = field(default_factory=dict)
21
21
 
22
- def match_condition(self, block_number: int, **kwargs) -> bool:
23
- """
24
- Check if condition matches for given block and arguments
25
- """
22
+ def match_condition(self, block_number: int, **kwargs: dict[str, Any]) -> bool:
23
+ """Check if condition matches for given block and arguments."""
26
24
  try:
27
25
  return self.condition(block_number, **kwargs)
28
26
  except Exception as e:
@@ -35,25 +33,19 @@ class RegistryItem:
35
33
  raise ConditionEvaluationError(f"Failed to evaluate condition: {e}") from e
36
34
 
37
35
  def get_execution_args(self) -> list[dict[str, Any]]:
38
- """
39
- Get list of argument sets for execution
40
- """
36
+ """Get list of argument sets for execution."""
41
37
  return self.args or [{}]
42
38
 
43
39
  @property
44
40
  def executable_path(self) -> str:
45
- """
46
- Get the importable path to the function.
47
- """
41
+ """Get the importable path to the function."""
48
42
  if hasattr(self.function, "name") and self.function.name is not None:
49
43
  return self.function.name
50
44
 
51
45
  return ".".join([self.function.__module__, self.function.__name__])
52
46
 
53
47
  def requires_backfilling(self) -> bool:
54
- """
55
- Check if this item requires backfilling.
56
- """
48
+ """Check if this item requires backfilling."""
57
49
  return self.backfilling_lookback is not None
58
50
 
59
51
 
@@ -11,7 +11,7 @@ def ensure_modules_loaded() -> None:
11
11
 
12
12
  @block_task must be loaded, otherwise it won't be registered.
13
13
  """
14
- from django.apps import apps
14
+ from django.apps import apps # noqa: PLC0415
15
15
 
16
16
  for app_config in apps.get_app_configs():
17
17
  for module_suffix in ["tasks", "block_tasks"]:
@@ -10,7 +10,7 @@ class ConditionEvaluationError(AbstractBlockDumperError):
10
10
  pass
11
11
 
12
12
 
13
- class CeleryTaskLocked(Exception):
13
+ class CeleryTaskLockedError(AbstractBlockDumperError):
14
14
  """Celery task execution is locked"""
15
15
 
16
16
  pass
@@ -1,12 +1,12 @@
1
1
  import structlog
2
2
  from django.db import transaction
3
3
 
4
- import abstract_block_dumper.dal.django_dal as abd_dal
5
- from abstract_block_dumper.dal.memory_registry import BaseRegistry, RegistryItem, task_registry
6
- from abstract_block_dumper.exceptions import ConditionEvaluationError
4
+ import abstract_block_dumper._internal.dal.django_dal as abd_dal
5
+ from abstract_block_dumper._internal.dal.memory_registry import BaseRegistry, RegistryItem, task_registry
6
+ from abstract_block_dumper._internal.exceptions import ConditionEvaluationError
7
+ from abstract_block_dumper._internal.services.executor import CeleryExecutor
8
+ from abstract_block_dumper._internal.services.utils import serialize_args
7
9
  from abstract_block_dumper.models import TaskAttempt
8
- from abstract_block_dumper.services.executor import CeleryExecutor
9
- from abstract_block_dumper.services.utils import serialize_args
10
10
 
11
11
  logger = structlog.get_logger(__name__)
12
12
 
@@ -170,6 +170,7 @@ class BlockProcessor:
170
170
  def _cleanup_phantom_tasks(self) -> None:
171
171
  """
172
172
  Clean up tasks marked as SUCCESS but never actually started.
173
+
173
174
  Only removes tasks that were created recently (within last hour) to avoid
174
175
  deleting legitimate tasks marked as success by external processes.
175
176
  """
@@ -2,8 +2,8 @@ from typing import Any
2
2
 
3
3
  import structlog
4
4
 
5
- import abstract_block_dumper.dal.django_dal as abd_dal
6
- from abstract_block_dumper.dal.memory_registry import RegistryItem
5
+ import abstract_block_dumper._internal.dal.django_dal as abd_dal
6
+ from abstract_block_dumper._internal.dal.memory_registry import RegistryItem
7
7
  from abstract_block_dumper.models import TaskAttempt
8
8
 
9
9
  logger = structlog.get_logger(__name__)
@@ -4,9 +4,9 @@ import bittensor as bt
4
4
  import structlog
5
5
  from django.conf import settings
6
6
 
7
- import abstract_block_dumper.dal.django_dal as abd_dal
8
- import abstract_block_dumper.services.utils as abd_utils
9
- from abstract_block_dumper.services.block_processor import BlockProcessor, block_processor_factory
7
+ import abstract_block_dumper._internal.dal.django_dal as abd_dal
8
+ import abstract_block_dumper._internal.services.utils as abd_utils
9
+ from abstract_block_dumper._internal.services.block_processor import BlockProcessor, block_processor_factory
10
10
 
11
11
  logger = structlog.get_logger(__name__)
12
12
 
@@ -20,14 +20,12 @@ def get_bittensor_client() -> bt.Subtensor:
20
20
  """
21
21
  DEFAULT_BITTENSOR_NETWORK = "finney"
22
22
  network = getattr(settings, "BITTENSOR_NETWORK", DEFAULT_BITTENSOR_NETWORK)
23
- logger.info(f"Creating new bittensor client for network: {network}")
23
+ logger.info("Creating new bittensor client for network", network=network)
24
24
  return bt.subtensor(network=network)
25
25
 
26
26
 
27
27
  def get_current_celery_task_id() -> str:
28
- """
29
- Get current celery task id
30
- """
28
+ """Get current celery task id."""
31
29
  try:
32
30
  celery_task_id = current_task.id
33
31
  except Exception:
@@ -36,9 +34,7 @@ def get_current_celery_task_id() -> str:
36
34
 
37
35
 
38
36
  def get_executable_path(func: Callable) -> str:
39
- """
40
- Get executable path for the callable `func`
41
- """
37
+ """Get executable path for the callable `func`."""
42
38
  return ".".join([func.__module__, func.__name__])
43
39
 
44
40
 
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.0.1'
32
- __version_tuple__ = version_tuple = (0, 0, 1)
31
+ __version__ = version = '0.0.2'
32
+ __version_tuple__ = version_tuple = (0, 0, 2)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -1,8 +1,8 @@
1
1
  from django.core.management.base import BaseCommand
2
2
 
3
- from abstract_block_dumper.dal.memory_registry import task_registry
4
- from abstract_block_dumper.discovery import ensure_modules_loaded
5
- from abstract_block_dumper.services.scheduler import task_scheduler_factory
3
+ from abstract_block_dumper._internal.dal.memory_registry import task_registry
4
+ from abstract_block_dumper._internal.discovery import ensure_modules_loaded
5
+ from abstract_block_dumper._internal.services.scheduler import task_scheduler_factory
6
6
 
7
7
 
8
8
  class Command(BaseCommand):
@@ -3,7 +3,7 @@ from typing import Any
3
3
 
4
4
  from django.db import models
5
5
 
6
- import abstract_block_dumper.services.utils as abd_utils
6
+ import abstract_block_dumper._internal.services.utils as abd_utils
7
7
 
8
8
 
9
9
  class TaskAttempt(models.Model):
@@ -5,10 +5,10 @@ import structlog
5
5
  from celery import Task, shared_task
6
6
  from django.db import OperationalError, transaction
7
7
 
8
- import abstract_block_dumper.dal.django_dal as abd_dal
9
- import abstract_block_dumper.services.utils as abd_utils
10
- from abstract_block_dumper.dal.memory_registry import RegistryItem, task_registry
11
- from abstract_block_dumper.exceptions import CeleryTaskLocked
8
+ import abstract_block_dumper._internal.dal.django_dal as abd_dal
9
+ import abstract_block_dumper._internal.services.utils as abd_utils
10
+ from abstract_block_dumper._internal.dal.memory_registry import RegistryItem, task_registry
11
+ from abstract_block_dumper._internal.exceptions import CeleryTaskLockedError
12
12
  from abstract_block_dumper.models import TaskAttempt
13
13
 
14
14
  logger = structlog.get_logger(__name__)
@@ -20,7 +20,6 @@ def schedule_retry(task_attempt: TaskAttempt) -> None:
20
20
 
21
21
  Task must already be in FAILED state with next_retry_at set by mark_failed()
22
22
  """
23
-
24
23
  if not task_attempt.next_retry_at:
25
24
  logger.error(
26
25
  "Cannot schedule retry without next_retry_at",
@@ -79,7 +78,7 @@ def _celery_task_wrapper(func, block_number: int, **kwargs) -> dict[str, Any] |
79
78
  block_number=block_number,
80
79
  executable_path=executable_path,
81
80
  )
82
- raise CeleryTaskLocked("TaskAttempt not found - task may have been canceled directly")
81
+ raise CeleryTaskLockedError("TaskAttempt not found - task may have been canceled directly")
83
82
  except OperationalError as e:
84
83
  logger.info(
85
84
  "Task already being processed by another worker",
@@ -87,7 +86,7 @@ def _celery_task_wrapper(func, block_number: int, **kwargs) -> dict[str, Any] |
87
86
  executable_path=executable_path,
88
87
  operational_error=str(e),
89
88
  )
90
- raise CeleryTaskLocked("Task already being processed by another worker")
89
+ raise CeleryTaskLockedError("Task already being processed by another worker")
91
90
 
92
91
  if task_attempt.status != TaskAttempt.Status.PENDING:
93
92
  logger.info(
@@ -146,7 +145,7 @@ def block_task(
146
145
  celery_kwargs: dict[str, Any] | None = None,
147
146
  ) -> Callable[..., Any]:
148
147
  """
149
- Decorator for registering block tasks.
148
+ Register a block task.
150
149
 
151
150
  Args:
152
151
  condition: Lambda function that determines when to execute
@@ -14,7 +14,7 @@ from django.utils import timezone
14
14
  from abstract_block_dumper.models import TaskAttempt
15
15
 
16
16
 
17
- @shared_task(name="abstract_block_dumper.cleanup_old_tasks")
17
+ @shared_task(name="abstract_block_dumper.v1.cleanup_old_tasks")
18
18
  def cleanup_old_tasks(days: int = 7) -> dict[str, int | str]:
19
19
  """
20
20
  Delete all succeeded or unrecoverable failed tasks older than the specified number of days.
@@ -47,12 +47,12 @@ def cleanup_old_tasks(days: int = 7) -> dict[str, int | str]:
47
47
 
48
48
  Example cron (daily at 2 AM):
49
49
  0 2 * * * python manage.py shell -c \
50
- "from abstract_block_dumper.tasks import cleanup_old_tasks; cleanup_old_tasks.delay()"
50
+ "from abstract_block_dumper.v1.tasks import cleanup_old_tasks; cleanup_old_tasks.delay()"
51
51
 
52
52
  Example Celery beat schedule (in settings.py):
53
53
  CELERY_BEAT_SCHEDULE = {
54
54
  'cleanup-old-tasks': {
55
- 'task': 'abstract_block_dumper.cleanup_old_tasks',
55
+ 'task': 'abstract_block_dumper.v1.cleanup_old_tasks',
56
56
  'schedule': crontab(hour=2, minute=0), # Daily at 2 AM
57
57
  'kwargs': {'days': 7},
58
58
  },
File without changes
@@ -3,7 +3,7 @@ import pytest
3
3
  from celery import Celery
4
4
  from django.conf import settings
5
5
 
6
- from abstract_block_dumper.dal.memory_registry import task_registry
6
+ from abstract_block_dumper._internal.dal.memory_registry import task_registry
7
7
 
8
8
  from .django_fixtures import * # noqa: F401, F403
9
9
 
@@ -45,7 +45,7 @@ def failing_task_func(block_number: int):
45
45
  @pytest.fixture
46
46
  def setup_test_tasks():
47
47
  # Register test tasks using decorators
48
- from abstract_block_dumper.decorators import block_task
48
+ from abstract_block_dumper.v1.decorators import block_task
49
49
 
50
50
  # every block
51
51
  block_task(condition=lambda bn: True)(every_block_task_func)
@@ -2,12 +2,12 @@ from unittest.mock import patch
2
2
 
3
3
  import pytest
4
4
 
5
+ from abstract_block_dumper._internal.services.scheduler import task_scheduler_factory
5
6
  from abstract_block_dumper.models import TaskAttempt
6
- from abstract_block_dumper.services.scheduler import task_scheduler_factory
7
7
 
8
8
 
9
9
  @pytest.mark.django_db
10
- @patch("abstract_block_dumper.services.utils.get_bittensor_client")
10
+ @patch("abstract_block_dumper._internal.services.utils.get_bittensor_client")
11
11
  def test_complete_e2e_workflow(mock_get_bittensor_client, setup_test_tasks) -> None:
12
12
  block_number = 300
13
13
  mock_subtensor = mock_get_bittensor_client.return_value
@@ -28,7 +28,7 @@ def test_complete_e2e_workflow(mock_get_bittensor_client, setup_test_tasks) -> N
28
28
 
29
29
 
30
30
  @pytest.mark.django_db
31
- @patch("abstract_block_dumper.services.utils.get_bittensor_client")
31
+ @patch("abstract_block_dumper._internal.services.utils.get_bittensor_client")
32
32
  def test_block_processing_flow(mock_get_bittensor_client, setup_test_tasks):
33
33
  current_block = 100
34
34
 
@@ -6,12 +6,12 @@ import pytest
6
6
  from celery.result import EagerResult
7
7
  from django.conf import settings
8
8
 
9
- import abstract_block_dumper.dal.django_dal as abd_dal
10
- from abstract_block_dumper.dal.memory_registry import task_registry
11
- from abstract_block_dumper.decorators import block_task
12
- from abstract_block_dumper.exceptions import CeleryTaskLocked
9
+ import abstract_block_dumper._internal.dal.django_dal as abd_dal
10
+ from abstract_block_dumper._internal.dal.memory_registry import task_registry
11
+ from abstract_block_dumper._internal.exceptions import CeleryTaskLockedError
12
+ from abstract_block_dumper._internal.services.utils import get_executable_path
13
13
  from abstract_block_dumper.models import TaskAttempt
14
- from abstract_block_dumper.services.utils import get_executable_path
14
+ from abstract_block_dumper.v1.decorators import block_task
15
15
 
16
16
 
17
17
  def simple_task(block_number: int) -> str:
@@ -37,7 +37,7 @@ def test_concurrent_celery_task_call() -> None:
37
37
  registry_item = task_registry.get_by_executable_path(task.executable_path)
38
38
  try:
39
39
  output = registry_item.function.delay(task.block_number)
40
- except CeleryTaskLocked:
40
+ except CeleryTaskLockedError:
41
41
  return None
42
42
  return output.result
43
43
 
@@ -1,10 +1,10 @@
1
1
  import pytest
2
2
 
3
- import abstract_block_dumper.dal.django_dal as abd_dal
4
- from abstract_block_dumper.dal.memory_registry import task_registry
5
- from abstract_block_dumper.decorators import block_task
3
+ import abstract_block_dumper._internal.dal.django_dal as abd_dal
4
+ from abstract_block_dumper._internal.dal.memory_registry import task_registry
5
+ from abstract_block_dumper._internal.services.utils import get_executable_path
6
6
  from abstract_block_dumper.models import TaskAttempt
7
- from abstract_block_dumper.services.utils import get_executable_path
7
+ from abstract_block_dumper.v1.decorators import block_task
8
8
 
9
9
 
10
10
  def multi_arg_task(block_number: int, netuid: int, custom_param: str) -> str:
@@ -1,11 +1,11 @@
1
1
  import pytest
2
2
 
3
- import abstract_block_dumper.dal.django_dal as abd_dal
3
+ import abstract_block_dumper._internal.dal.django_dal as abd_dal
4
+ import abstract_block_dumper._internal.services.utils as abd_utils
4
5
  import abstract_block_dumper.models as abd_models
5
- import abstract_block_dumper.services.utils as abd_utils
6
- from abstract_block_dumper.dal.memory_registry import task_registry
7
- from abstract_block_dumper.decorators import block_task
8
- from abstract_block_dumper.services.block_processor import block_processor_factory
6
+ from abstract_block_dumper._internal.dal.memory_registry import task_registry
7
+ from abstract_block_dumper._internal.services.block_processor import block_processor_factory
8
+ from abstract_block_dumper.v1.decorators import block_task
9
9
  from tests.conftest import every_block_task_func, failing_task_func
10
10
  from tests.fatories import TaskAttemptFactory
11
11
 
@@ -4,12 +4,12 @@ from unittest.mock import patch
4
4
  import pytest
5
5
  from django.utils import timezone
6
6
 
7
- import abstract_block_dumper.dal.django_dal as abd_dal
8
- import abstract_block_dumper.services.utils as abd_utils
9
- from abstract_block_dumper.dal.memory_registry import task_registry
10
- from abstract_block_dumper.decorators import block_task
7
+ import abstract_block_dumper._internal.dal.django_dal as abd_dal
8
+ import abstract_block_dumper._internal.services.utils as abd_utils
9
+ from abstract_block_dumper._internal.dal.memory_registry import task_registry
10
+ from abstract_block_dumper._internal.services.block_processor import block_processor_factory
11
11
  from abstract_block_dumper.models import TaskAttempt
12
- from abstract_block_dumper.services.block_processor import block_processor_factory
12
+ from abstract_block_dumper.v1.decorators import block_task
13
13
  from tests.fatories import TaskAttemptFactory
14
14
 
15
15
 
@@ -1,9 +1,9 @@
1
1
  import pytest
2
2
 
3
- import abstract_block_dumper.dal.django_dal as abd_dal
4
- import abstract_block_dumper.services.utils as abd_utils
5
- from abstract_block_dumper.dal.memory_registry import task_registry
6
- from abstract_block_dumper.discovery import ensure_modules_loaded
3
+ import abstract_block_dumper._internal.dal.django_dal as abd_dal
4
+ import abstract_block_dumper._internal.services.utils as abd_utils
5
+ from abstract_block_dumper._internal.dal.memory_registry import task_registry
6
+ from abstract_block_dumper._internal.discovery import ensure_modules_loaded
7
7
  from abstract_block_dumper.models import TaskAttempt
8
8
  from tests.conftest import every_block_task_func
9
9