dbos 1.13.1__tar.gz → 1.14.0a3__tar.gz

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

Potentially problematic release.


This version of dbos might be problematic. Click here for more details.

Files changed (116) hide show
  1. {dbos-1.13.1 → dbos-1.14.0a3}/PKG-INFO +1 -1
  2. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_core.py +3 -5
  3. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_outcome.py +67 -13
  4. {dbos-1.13.1 → dbos-1.14.0a3}/pyproject.toml +1 -1
  5. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_dbos.py +31 -0
  6. {dbos-1.13.1 → dbos-1.14.0a3}/LICENSE +0 -0
  7. {dbos-1.13.1 → dbos-1.14.0a3}/README.md +0 -0
  8. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/__init__.py +0 -0
  9. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/__main__.py +0 -0
  10. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_admin_server.py +0 -0
  11. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/env.py +0 -0
  12. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/script.py.mako +0 -0
  13. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/01ce9f07bd10_streaming.py +0 -0
  14. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/04ca4f231047_workflow_queues_executor_id.py +0 -0
  15. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/27ac6900c6ad_add_queue_dedup.py +0 -0
  16. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/471b60d64126_dbos_migrations.py +0 -0
  17. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/50f3227f0b4b_fix_job_queue.py +0 -0
  18. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/5c361fc04708_added_system_tables.py +0 -0
  19. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/66478e1b95e5_consolidate_queues.py +0 -0
  20. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/83f3732ae8e7_workflow_timeout.py +0 -0
  21. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/933e86bdac6a_add_queue_priority.py +0 -0
  22. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/a3b18ad34abe_added_triggers.py +0 -0
  23. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/d76646551a6b_job_queue_limiter.py +0 -0
  24. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/d76646551a6c_workflow_queue.py +0 -0
  25. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/d994145b47b6_consolidate_inputs.py +0 -0
  26. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/eab0cc1d9a14_job_queue.py +0 -0
  27. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_alembic_migrations/versions/f4b9b32ba814_functionname_childid_op_outputs.py +0 -0
  28. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_app_db.py +0 -0
  29. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_classproperty.py +0 -0
  30. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_client.py +0 -0
  31. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_conductor/conductor.py +0 -0
  32. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_conductor/protocol.py +0 -0
  33. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_context.py +0 -0
  34. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_croniter.py +0 -0
  35. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_dbos.py +0 -0
  36. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_dbos_config.py +0 -0
  37. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_debug.py +0 -0
  38. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_docker_pg_helper.py +0 -0
  39. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_error.py +0 -0
  40. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_event_loop.py +0 -0
  41. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_fastapi.py +0 -0
  42. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_flask.py +0 -0
  43. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_kafka.py +0 -0
  44. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_kafka_message.py +0 -0
  45. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_logger.py +0 -0
  46. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_migration.py +0 -0
  47. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_queue.py +0 -0
  48. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_recovery.py +0 -0
  49. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_registrations.py +0 -0
  50. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_roles.py +0 -0
  51. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_scheduler.py +0 -0
  52. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_schemas/__init__.py +0 -0
  53. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_schemas/application_database.py +0 -0
  54. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_schemas/system_database.py +0 -0
  55. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_serialization.py +0 -0
  56. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_sys_db.py +0 -0
  57. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_sys_db_postgres.py +0 -0
  58. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_sys_db_sqlite.py +0 -0
  59. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_templates/dbos-db-starter/README.md +0 -0
  60. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_templates/dbos-db-starter/__package/__init__.py +0 -0
  61. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_templates/dbos-db-starter/__package/main.py.dbos +0 -0
  62. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_templates/dbos-db-starter/__package/schema.py +0 -0
  63. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_templates/dbos-db-starter/alembic.ini +0 -0
  64. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_templates/dbos-db-starter/dbos-config.yaml.dbos +0 -0
  65. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_templates/dbos-db-starter/migrations/env.py.dbos +0 -0
  66. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_templates/dbos-db-starter/migrations/script.py.mako +0 -0
  67. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_templates/dbos-db-starter/migrations/versions/2024_07_31_180642_init.py +0 -0
  68. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_templates/dbos-db-starter/start_postgres_docker.py +0 -0
  69. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_tracer.py +0 -0
  70. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_utils.py +0 -0
  71. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/_workflow_commands.py +0 -0
  72. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/cli/_github_init.py +0 -0
  73. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/cli/_template_init.py +0 -0
  74. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/cli/cli.py +0 -0
  75. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/cli/migration.py +0 -0
  76. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/dbos-config.schema.json +0 -0
  77. {dbos-1.13.1 → dbos-1.14.0a3}/dbos/py.typed +0 -0
  78. {dbos-1.13.1 → dbos-1.14.0a3}/tests/__init__.py +0 -0
  79. {dbos-1.13.1 → dbos-1.14.0a3}/tests/atexit_no_ctor.py +0 -0
  80. {dbos-1.13.1 → dbos-1.14.0a3}/tests/atexit_no_launch.py +0 -0
  81. {dbos-1.13.1 → dbos-1.14.0a3}/tests/classdefs.py +0 -0
  82. {dbos-1.13.1 → dbos-1.14.0a3}/tests/client_collateral.py +0 -0
  83. {dbos-1.13.1 → dbos-1.14.0a3}/tests/client_worker.py +0 -0
  84. {dbos-1.13.1 → dbos-1.14.0a3}/tests/conftest.py +0 -0
  85. {dbos-1.13.1 → dbos-1.14.0a3}/tests/dupname_classdefs1.py +0 -0
  86. {dbos-1.13.1 → dbos-1.14.0a3}/tests/dupname_classdefsa.py +0 -0
  87. {dbos-1.13.1 → dbos-1.14.0a3}/tests/more_classdefs.py +0 -0
  88. {dbos-1.13.1 → dbos-1.14.0a3}/tests/queuedworkflow.py +0 -0
  89. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_admin_server.py +0 -0
  90. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_async.py +0 -0
  91. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_async_workflow_management.py +0 -0
  92. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_classdecorators.py +0 -0
  93. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_cli.py +0 -0
  94. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_client.py +0 -0
  95. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_concurrency.py +0 -0
  96. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_config.py +0 -0
  97. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_croniter.py +0 -0
  98. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_debug.py +0 -0
  99. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_docker_secrets.py +0 -0
  100. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_failures.py +0 -0
  101. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_fastapi.py +0 -0
  102. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_fastapi_roles.py +0 -0
  103. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_flask.py +0 -0
  104. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_kafka.py +0 -0
  105. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_outcome.py +0 -0
  106. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_package.py +0 -0
  107. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_queue.py +0 -0
  108. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_scheduler.py +0 -0
  109. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_schema_migration.py +0 -0
  110. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_singleton.py +0 -0
  111. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_spans.py +0 -0
  112. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_sqlalchemy.py +0 -0
  113. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_streaming.py +0 -0
  114. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_workflow_introspection.py +0 -0
  115. {dbos-1.13.1 → dbos-1.14.0a3}/tests/test_workflow_management.py +0 -0
  116. {dbos-1.13.1 → dbos-1.14.0a3}/version/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbos
3
- Version: 1.13.1
3
+ Version: 1.14.0a3
4
4
  Summary: Ultra-lightweight durable execution in Python
5
5
  Author-Email: "DBOS, Inc." <contact@dbos.dev>
6
6
  License: MIT
@@ -19,8 +19,6 @@ from typing import (
19
19
  cast,
20
20
  )
21
21
 
22
- import psycopg
23
-
24
22
  from dbos._outcome import Immediate, NoResult, Outcome, Pending
25
23
  from dbos._utils import GlobalParams, retriable_postgres_exception
26
24
 
@@ -831,10 +829,10 @@ def workflow_wrapper(
831
829
  return r
832
830
 
833
831
  outcome = (
834
- wfOutcome.wrap(init_wf)
832
+ wfOutcome.wrap(init_wf, dbos=dbos)
835
833
  .also(DBOSAssumeRole(rr))
836
834
  .also(enterWorkflowCtxMgr(attributes))
837
- .then(record_get_result)
835
+ .then(record_get_result, dbos=dbos)
838
836
  )
839
837
  return outcome() # type: ignore
840
838
 
@@ -1146,7 +1144,7 @@ def decorate_step(
1146
1144
 
1147
1145
  outcome = (
1148
1146
  stepOutcome.then(record_step_result)
1149
- .intercept(check_existing_result)
1147
+ .intercept(check_existing_result, dbos=dbos)
1150
1148
  .also(EnterDBOSStep(attributes))
1151
1149
  )
1152
1150
  return outcome()
@@ -2,9 +2,24 @@ import asyncio
2
2
  import contextlib
3
3
  import inspect
4
4
  import time
5
- from typing import Any, Callable, Coroutine, Optional, Protocol, TypeVar, Union, cast
5
+ from typing import (
6
+ TYPE_CHECKING,
7
+ Any,
8
+ Callable,
9
+ Coroutine,
10
+ Optional,
11
+ Protocol,
12
+ TypeVar,
13
+ Union,
14
+ cast,
15
+ )
6
16
 
7
17
  from dbos._context import EnterDBOSStepRetry
18
+ from dbos._error import DBOSException
19
+ from dbos._registrations import get_dbos_func_name
20
+
21
+ if TYPE_CHECKING:
22
+ from ._dbos import DBOS
8
23
 
9
24
  T = TypeVar("T")
10
25
  R = TypeVar("R")
@@ -24,10 +39,15 @@ class NoResult:
24
39
  class Outcome(Protocol[T]):
25
40
 
26
41
  def wrap(
27
- self, before: Callable[[], Callable[[Callable[[], T]], R]]
42
+ self,
43
+ before: Callable[[], Callable[[Callable[[], T]], R]],
44
+ *,
45
+ dbos: Optional["DBOS"] = None,
28
46
  ) -> "Outcome[R]": ...
29
47
 
30
- def then(self, next: Callable[[Callable[[], T]], R]) -> "Outcome[R]": ...
48
+ def then(
49
+ self, next: Callable[[Callable[[], T]], R], *, dbos: Optional["DBOS"] = None
50
+ ) -> "Outcome[R]": ...
31
51
 
32
52
  def also(
33
53
  self, cm: contextlib.AbstractContextManager[Any, bool]
@@ -41,7 +61,10 @@ class Outcome(Protocol[T]):
41
61
  ) -> "Outcome[T]": ...
42
62
 
43
63
  def intercept(
44
- self, interceptor: Callable[[], Union[NoResult, T]]
64
+ self,
65
+ interceptor: Callable[[], Union[NoResult, T]],
66
+ *,
67
+ dbos: Optional["DBOS"] = None,
45
68
  ) -> "Outcome[T]": ...
46
69
 
47
70
  def __call__(self) -> Union[T, Coroutine[Any, Any, T]]: ...
@@ -63,11 +86,17 @@ class Immediate(Outcome[T]):
63
86
  def __init__(self, func: Callable[[], T]):
64
87
  self._func = func
65
88
 
66
- def then(self, next: Callable[[Callable[[], T]], R]) -> "Immediate[R]":
89
+ def then(
90
+ self,
91
+ next: Callable[[Callable[[], T]], R],
92
+ dbos: Optional["DBOS"] = None,
93
+ ) -> "Immediate[R]":
67
94
  return Immediate(lambda: next(self._func))
68
95
 
69
96
  def wrap(
70
- self, before: Callable[[], Callable[[Callable[[], T]], R]]
97
+ self,
98
+ before: Callable[[], Callable[[Callable[[], T]], R]],
99
+ dbos: Optional["DBOS"] = None,
71
100
  ) -> "Immediate[R]":
72
101
  return Immediate(lambda: before()(self._func))
73
102
 
@@ -79,7 +108,10 @@ class Immediate(Outcome[T]):
79
108
  return intercepted if not isinstance(intercepted, NoResult) else func()
80
109
 
81
110
  def intercept(
82
- self, interceptor: Callable[[], Union[NoResult, T]]
111
+ self,
112
+ interceptor: Callable[[], Union[NoResult, T]],
113
+ *,
114
+ dbos: Optional["DBOS"] = None,
83
115
  ) -> "Immediate[T]":
84
116
  return Immediate[T](lambda: Immediate._intercept(self._func, interceptor))
85
117
 
@@ -142,7 +174,12 @@ class Pending(Outcome[T]):
142
174
  async def _wrap(
143
175
  func: Callable[[], Coroutine[Any, Any, T]],
144
176
  before: Callable[[], Callable[[Callable[[], T]], R]],
177
+ *,
178
+ dbos: Optional["DBOS"] = None,
145
179
  ) -> R:
180
+ # Make sure the executor pool is configured correctly
181
+ if dbos is not None:
182
+ await dbos._configure_asyncio_thread_pool()
146
183
  after = await asyncio.to_thread(before)
147
184
  try:
148
185
  value = await func()
@@ -151,12 +188,17 @@ class Pending(Outcome[T]):
151
188
  return await asyncio.to_thread(after, lambda: Pending._raise(exp))
152
189
 
153
190
  def wrap(
154
- self, before: Callable[[], Callable[[Callable[[], T]], R]]
191
+ self,
192
+ before: Callable[[], Callable[[Callable[[], T]], R]],
193
+ *,
194
+ dbos: Optional["DBOS"] = None,
155
195
  ) -> "Pending[R]":
156
- return Pending[R](lambda: Pending._wrap(self._func, before))
196
+ return Pending[R](lambda: Pending._wrap(self._func, before, dbos=dbos))
157
197
 
158
- def then(self, next: Callable[[Callable[[], T]], R]) -> "Pending[R]":
159
- return Pending[R](lambda: Pending._wrap(self._func, lambda: next))
198
+ def then(
199
+ self, next: Callable[[Callable[[], T]], R], *, dbos: Optional["DBOS"] = None
200
+ ) -> "Pending[R]":
201
+ return Pending[R](lambda: Pending._wrap(self._func, lambda: next, dbos=dbos))
160
202
 
161
203
  @staticmethod
162
204
  async def _also( # type: ignore
@@ -173,12 +215,24 @@ class Pending(Outcome[T]):
173
215
  async def _intercept(
174
216
  func: Callable[[], Coroutine[Any, Any, T]],
175
217
  interceptor: Callable[[], Union[NoResult, T]],
218
+ *,
219
+ dbos: Optional["DBOS"] = None,
176
220
  ) -> T:
221
+ # Make sure the executor pool is configured correctly
222
+ if dbos is not None:
223
+ await dbos._configure_asyncio_thread_pool()
177
224
  intercepted = await asyncio.to_thread(interceptor)
178
225
  return intercepted if not isinstance(intercepted, NoResult) else await func()
179
226
 
180
- def intercept(self, interceptor: Callable[[], Union[NoResult, T]]) -> "Pending[T]":
181
- return Pending[T](lambda: Pending._intercept(self._func, interceptor))
227
+ def intercept(
228
+ self,
229
+ interceptor: Callable[[], Union[NoResult, T]],
230
+ *,
231
+ dbos: Optional["DBOS"] = None,
232
+ ) -> "Pending[T]":
233
+ return Pending[T](
234
+ lambda: Pending._intercept(self._func, interceptor, dbos=dbos)
235
+ )
182
236
 
183
237
  @staticmethod
184
238
  async def _retry(
@@ -27,7 +27,7 @@ dependencies = [
27
27
  ]
28
28
  requires-python = ">=3.9"
29
29
  readme = "README.md"
30
- version = "1.13.1"
30
+ version = "1.14.0a3"
31
31
 
32
32
  [project.license]
33
33
  text = "MIT"
@@ -1250,12 +1250,43 @@ def test_destroy_semantics(dbos: DBOS, config: DBOSConfig) -> None:
1250
1250
  var = "test"
1251
1251
  assert test_workflow(var) == var
1252
1252
 
1253
+ # Start the workflow asynchornously
1254
+ wf = dbos.start_workflow(test_workflow, var)
1255
+ assert wf.get_result() == var
1256
+
1253
1257
  DBOS.destroy()
1254
1258
  DBOS(config=config)
1255
1259
  DBOS.launch()
1256
1260
 
1257
1261
  assert test_workflow(var) == var
1258
1262
 
1263
+ wf = dbos.start_workflow(test_workflow, var)
1264
+ assert wf.get_result() == var
1265
+
1266
+
1267
+ @pytest.mark.asyncio
1268
+ async def test_destroy_semantics_async(dbos: DBOS, config: DBOSConfig) -> None:
1269
+
1270
+ @DBOS.workflow()
1271
+ async def test_workflow(var: str) -> str:
1272
+ return var
1273
+
1274
+ var = "test"
1275
+ assert await test_workflow(var) == var
1276
+
1277
+ # Start the workflow asynchornously
1278
+ wf = await dbos.start_workflow_async(test_workflow, var)
1279
+ assert await wf.get_result() == var
1280
+
1281
+ DBOS.destroy()
1282
+ DBOS(config=config)
1283
+ DBOS.launch()
1284
+
1285
+ assert await test_workflow(var) == var
1286
+
1287
+ wf = await dbos.start_workflow_async(test_workflow, var)
1288
+ assert await wf.get_result() == var
1289
+
1259
1290
 
1260
1291
  def test_double_decoration(dbos: DBOS) -> None:
1261
1292
  with pytest.raises(
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes