uber-compose 2.3.1a2002__tar.gz → 2.3.3__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 (64) hide show
  1. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/PKG-INFO +1 -1
  2. uber_compose-2.3.3/setup.cfg +28 -0
  3. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/constants.py +3 -1
  4. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/docker_compose.py +15 -12
  5. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/docker_compose_shell/interface.py +62 -73
  6. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/docker_compose_shell/types.py +2 -2
  7. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/system_docker_compose.py +8 -6
  8. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/utils/compose_files.py +16 -8
  9. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/utils/env_files.py +2 -2
  10. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/utils/state_waiting.py +2 -2
  11. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/env_description/env_types.py +8 -2
  12. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/helpers/broken_services.py +2 -1
  13. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/helpers/exec_result.py +0 -1
  14. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/output/console.py +6 -3
  15. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/uber_compose.py +73 -23
  16. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/utils/services_construction.py +0 -1
  17. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/vedro_plugin/base_structures/common_json_cli.py +7 -7
  18. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/vedro_plugin/helpers/test_env_vars_setter.py +0 -1
  19. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/vedro_plugin/plugin.py +19 -7
  20. uber_compose-2.3.3/uber_compose/version +1 -0
  21. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/version.py +1 -0
  22. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose.egg-info/PKG-INFO +1 -1
  23. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose.egg-info/SOURCES.txt +1 -0
  24. uber_compose-2.3.1a2002/setup.cfg +0 -4
  25. uber_compose-2.3.1a2002/uber_compose/version +0 -1
  26. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/LICENSE +0 -0
  27. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/README.md +0 -0
  28. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/setup.py +0 -0
  29. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/__init__.py +1 -1
  30. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/__init__.py +0 -0
  31. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/docker_compose_shell/__init__.py +0 -0
  32. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/sequence_run_types.py +1 -1
  33. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/utils/__init__.py +0 -0
  34. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/utils/compose_instance_cfg.py +0 -0
  35. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/utils/process_command_output.py +0 -0
  36. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/core/utils/shell_process.py +0 -0
  37. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/env_description/__init__.py +0 -0
  38. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/env_description/env_tools.py +0 -0
  39. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/errors/__init__.py +0 -0
  40. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/errors/migrations.py +0 -0
  41. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/errors/up.py +0 -0
  42. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/helpers/__init__.py +0 -0
  43. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/helpers/bytes_pickle.py +0 -0
  44. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/helpers/countdown_counter.py +0 -0
  45. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/helpers/exec_record.py +0 -0
  46. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/helpers/health_policy.py +0 -0
  47. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/helpers/jobs_result.py +0 -0
  48. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/helpers/labels.py +0 -0
  49. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/helpers/singleton.py +0 -0
  50. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/helpers/state_keeper.py +0 -0
  51. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/output/__init__.py +0 -0
  52. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/output/styles.py +0 -0
  53. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/utils/__init__.py +0 -0
  54. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/utils/docker_compose_files_path.py +0 -0
  55. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/utils/docker_compose_service_deps.py +0 -0
  56. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/utils/search_docker_compose_files.py +0 -0
  57. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/vedro_plugin/__init__.py +0 -0
  58. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/vedro_plugin/base_structures/__init__.py +0 -0
  59. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/vedro_plugin/helpers/__init__.py +0 -0
  60. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/vedro_plugin/helpers/scenario_ordering.py +0 -0
  61. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose/vedro_plugin/helpers/scenario_tag_processing.py +0 -0
  62. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose.egg-info/dependency_links.txt +0 -0
  63. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose.egg-info/requires.txt +0 -0
  64. {uber_compose-2.3.1a2002 → uber_compose-2.3.3}/uber_compose.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uber-compose
3
- Version: 2.3.1a2002
3
+ Version: 2.3.3
4
4
  Summary: docker compose testing env orchestrator
5
5
  Home-page: https://github.com/ko10ok/uber-compose
6
6
  Author: Yuriy Sagitov
@@ -0,0 +1,28 @@
1
+ [isort]
2
+ line_length = 120
3
+ force_single_line = True
4
+ force_sort_within_sections = True
5
+ known_first_party = uber_compose
6
+ skip = .venv,.git,build,dist,tests/mnt,tests/.vedro,tests/deps,tests/up,tests/build
7
+ skip_glob = **/__pycache__/*,**/*.egg-info/*
8
+
9
+ [flake8]
10
+ max-line-length = 120
11
+ exclude =
12
+ .venv,
13
+ .git,
14
+ build,
15
+ dist,
16
+ *.egg-info,
17
+ tests/mnt,
18
+ tests/.vedro,
19
+ tests/deps,
20
+ tests/up,
21
+ tests/build,
22
+ __pycache__
23
+ extend-ignore = E203,W503,E731
24
+
25
+ [egg_info]
26
+ tag_build =
27
+ tag_date = 0
28
+
@@ -11,7 +11,9 @@ class Constants:
11
11
 
12
12
  self.project: str = os.environ.get('COMPOSE_PROJECT_NAME')
13
13
  self.compose_project_name = os.environ.get('COMPOSE_PROJECT_NAME')
14
- assert self.compose_project_name, 'COMPOSE_PROJECT_NAME environment variable is not set: - COMPOSE_PROJECT_NAME=${PWD##*/}'
14
+ assert self.compose_project_name, (
15
+ 'COMPOSE_PROJECT_NAME environment variable is not set: - COMPOSE_PROJECT_NAME=${PWD##*/}'
16
+ )
15
17
 
16
18
  self.docker_host = os.environ.get('DOCKER_HOST', 'unix:///var/run/docker.sock')
17
19
 
@@ -1,11 +1,10 @@
1
- import os
2
- import sys
3
1
  from asyncio import sleep
2
+ import os
4
3
  from pathlib import Path
4
+ import sys
5
5
 
6
6
  from rich.text import Text
7
7
 
8
- from uber_compose.core.constants import Constants
9
8
  from uber_compose.core.docker_compose_shell.interface import ComposeShellInterface
10
9
  from uber_compose.core.sequence_run_types import ComposeInstanceFiles
11
10
  from uber_compose.core.sequence_run_types import EnvInstanceConfig
@@ -118,7 +117,8 @@ class ComposeInstance:
118
117
  kill_after=False,
119
118
  )
120
119
 
121
- migration_errors = [error for error in migration_result.stderr.split(b'\n') if error] # empty or none skips
120
+ # empty or none skips
121
+ migration_errors = [error for error in migration_result.stderr.split(b'\n') if error]
122
122
  skipper_migration_errors = [
123
123
  current_error
124
124
  for current_error in migration_errors
@@ -142,20 +142,25 @@ class ComposeInstance:
142
142
  ]
143
143
  if not migration_result.finished or critical_migration_errors:
144
144
  services_status = await self.compose_executor.dc_state()
145
- error = Text(f"Can't migrate service {target_service}, with {substituted_cmd}", style=Style.bad).append(
146
- Text(f"\n{migration_result.stdout=}\n",style=Style.regular)
145
+ error = Text(
146
+ f"Can't migrate service {target_service}, with {substituted_cmd}", style=Style.bad,
147
+ ).append(
148
+ Text(f"\n{migration_result.stdout=}\n", style=Style.regular)
147
149
  ).append(
148
150
  Text(f"{migration_result.stderr=}\n", style=Style.bad)
149
151
  ).append(
150
- Text(f"Services status:\n", style=Style.info)
152
+ Text("Services status:\n", style=Style.info)
151
153
  ).append(
152
154
  services_status.as_rich_text()
153
155
  )
154
156
  self.logger.error(error)
155
157
  self.logger.error_details(f"\nServices logs:\n {await self.logs(services)}")
156
- raise ServicesUpError(f"Can't migrate service {target_service}, with {substituted_cmd}: {migration_result.finished=}"
157
- f"\n{migration_result.stdout=}\n{migration_result.stderr=}\n"
158
- f"\nServices status:\n {services_status.as_rich_text()}") from None
158
+ raise ServicesUpError(
159
+ f"Can't migrate service {target_service}, with {substituted_cmd}: "
160
+ f"{migration_result.finished=}"
161
+ f"\n{migration_result.stdout=}\n{migration_result.stderr=}\n"
162
+ f"\nServices status:\n {services_status.as_rich_text()}"
163
+ ) from None
159
164
 
160
165
  async def run_services_pack(self, services: list[str], migrations):
161
166
 
@@ -184,7 +189,6 @@ class ComposeInstance:
184
189
  f"\nServices status:\n {services_status.as_rich_text()}"
185
190
  ) from None
186
191
 
187
-
188
192
  await self.run_migration(
189
193
  [EventStage.AFTER_SERVICE_START],
190
194
  services,
@@ -275,7 +279,6 @@ class ComposeInstance:
275
279
  f"\nServices status:\n {services_status.as_rich_text()}"
276
280
  ) from None
277
281
 
278
-
279
282
  async def logs(self, services=None) -> str:
280
283
  job_result, log = await self.compose_executor.dc_logs(services, logs_param='')
281
284
  return log.decode('utf-8') if job_result == JobResult.GOOD else ''
@@ -1,13 +1,12 @@
1
1
  import asyncio
2
+ from asyncio import subprocess
3
+ from dataclasses import dataclass
2
4
  import os
5
+ from pathlib import Path
3
6
  import pprint
4
7
  import shlex
5
8
  import sys
6
- from asyncio import subprocess
7
- from dataclasses import dataclass
8
- from pathlib import Path
9
9
  from typing import Callable
10
- from typing import Coroutine
11
10
  from typing import NamedTuple
12
11
 
13
12
  from rich.text import Text
@@ -19,13 +18,9 @@ from uber_compose.core.utils.process_command_output import process_output_till_d
19
18
  from uber_compose.core.utils.shell_process import parse_process_command_name
20
19
  from uber_compose.helpers.jobs_result import JobResult
21
20
  from uber_compose.helpers.jobs_result import OperationError
22
- from uber_compose.output.console import CONSOLE
23
21
  from uber_compose.output.console import Logger
24
22
  from uber_compose.output.styles import Style
25
23
 
26
- DC_BIN = '/usr/bin/docker'
27
- COMPOSE = f'{DC_BIN} compose'
28
-
29
24
 
30
25
  class NoDockerCompose(BaseException):
31
26
  ...
@@ -68,28 +63,25 @@ class ComposeShellInterface:
68
63
  self.execution_envs |= execution_envs
69
64
  self.extra_exec_params = self.cfg_constants.docker_compose_extra_exec_params
70
65
 
66
+ self.compose_bin = '/usr/bin/docker'
67
+ self.compose_cmd = f'{self.compose_bin} compose'
68
+
71
69
  if self.cfg_constants.cli_compose_util_override:
72
70
  logger.system_commands(
73
71
  f'Using overridden {self.cfg_constants.cli_compose_util_override} CLI compose command'
74
72
  )
73
+ self.compose_bin = self.cfg_constants.cli_compose_util_override
74
+ self.compose_cmd = self.cfg_constants.cli_compose_util_override
75
75
 
76
- # for check binary existance
77
- global DC_BIN
78
- DC_BIN = self.cfg_constants.cli_compose_util_override
79
-
80
- # for binary usage
81
- global COMPOSE
82
- COMPOSE = self.cfg_constants.cli_compose_util_override
83
-
84
- # check if DC_BIN exists
85
- if not Path(DC_BIN).exists():
76
+ if not Path(self.compose_bin).exists():
86
77
  raise NoDockerCompose(
87
- f'Docker Compose binary not found at {DC_BIN}. Please install Docker Client with compose: \n Alpine - apk add docker-cli docker-cli-compose\n Debian/Ubuntu - apt install docker-ce-cli docker-compose-plugin')
88
-
89
- @retry(attempts=10, delay=1, until=lambda x: x == JobResult.BAD)
90
- async def dc_state(self, env: dict = None, root: Path | str = None) -> ServicesComposeState | OperationError:
91
- sys.stdout.flush()
78
+ f'Docker Compose binary not found at {self.compose_bin}. '
79
+ 'Please install Docker Client with compose: \n'
80
+ ' Alpine - apk add docker-cli docker-cli-compose\n'
81
+ ' Debian/Ubuntu - apt install docker-ce-cli docker-compose-plugin'
82
+ )
92
83
 
84
+ def _prepare_env_root(self, env: dict = None, root: Path | str = None) -> tuple[dict, str]:
93
85
  if env is None:
94
86
  env = {}
95
87
  env = self.execution_envs | env
@@ -97,8 +89,16 @@ class ComposeShellInterface:
97
89
  if root is None:
98
90
  root = self.in_docker_project_root
99
91
 
92
+ return env, root
93
+
94
+ @retry(attempts=10, delay=1, until=lambda x: x == JobResult.BAD)
95
+ async def dc_state(self, env: dict = None, root: Path | str = None) -> ServicesComposeState | OperationError:
96
+ sys.stdout.flush()
97
+
98
+ env, root = self._prepare_env_root(env, root)
99
+
100
100
  process = await asyncio.create_subprocess_shell(
101
- cmd := f"{COMPOSE} --project-directory {root}" + " ps -a --format='{{json .}}'",
101
+ cmd := f"{self.compose_cmd} --project-directory {root}" + " ps -a --format='{{json .}}'",
102
102
  env=env,
103
103
  cwd=root,
104
104
  stdout=subprocess.PIPE,
@@ -122,15 +122,10 @@ class ComposeShellInterface:
122
122
  async def dc_up(self, services: list[str], env: dict = None, root: Path | str = None) -> JobResult | OperationError:
123
123
  sys.stdout.flush()
124
124
 
125
- if env is None:
126
- env = {}
127
- env = self.execution_envs | env
128
-
129
- if root is None:
130
- root = self.in_docker_project_root
125
+ env, root = self._prepare_env_root(env, root)
131
126
 
132
127
  process = await asyncio.create_subprocess_shell(
133
- cmd := f'{COMPOSE} --project-directory {root} up --timestamps --no-deps --pull missing '
128
+ cmd := f'{self.compose_cmd} --project-directory {root} up --timestamps --no-deps --pull missing '
134
129
  '--timeout 300 -d ' + ' '.join(services),
135
130
  env=env,
136
131
  cwd=root,
@@ -157,19 +152,14 @@ class ComposeShellInterface:
157
152
  ) -> tuple[JobResult, bytes] | tuple[OperationError, None]:
158
153
  sys.stdout.flush()
159
154
 
160
- if env is None:
161
- env = {}
162
- env = self.execution_envs | env
163
-
164
- if root is None:
165
- root = self.in_docker_project_root
155
+ env, root = self._prepare_env_root(env, root)
166
156
 
167
157
  if services is None:
168
158
  services = []
169
159
  services = ' '.join(services)
170
160
 
171
161
  process = await asyncio.create_subprocess_shell(
172
- cmd := f'{COMPOSE} --project-directory {root} logs {logs_param} {services}',
162
+ cmd := f'{self.compose_cmd} --project-directory {root} logs {logs_param} {services}',
173
163
  env=env,
174
164
  cwd=root,
175
165
  stdout=asyncio.subprocess.PIPE,
@@ -186,9 +176,12 @@ class ComposeShellInterface:
186
176
  state_result = await self.dc_state()
187
177
  if state_result == JobResult.GOOD:
188
178
  return OperationError(
189
- f'Command: {cmd}\nStdout:\n{stdout}\n\nStderr:\n{stderr}\n\nComposeState:\n{state_result.as_rich_text()}'
179
+ f'Command: {cmd}\nStdout:\n{stdout}\n\nStderr:\n{stderr}\n\n'
180
+ f'ComposeState:\n{state_result.as_rich_text()}'
190
181
  ), None
191
- return OperationError(f'Command: {cmd}\nStdout:\n{stdout}\n\nStderr:\n{stderr}\n\nComposeState:\n{state_result}'), None
182
+ return OperationError(
183
+ f'Command: {cmd}\nStdout:\n{stdout}\n\nStderr:\n{stderr}\n\nComposeState:\n{state_result}'
184
+ ), None
192
185
 
193
186
  return JobResult.GOOD, stdout
194
187
 
@@ -205,19 +198,17 @@ class ComposeShellInterface:
205
198
  f'-e {key}={shlex.quote(str(value))}' for key, value in extra_env.items()
206
199
  )
207
200
 
208
- if env is None:
209
- env = {}
210
- env = self.execution_envs | env
211
-
212
- if root is None:
213
- root = self.in_docker_project_root
201
+ env, root = self._prepare_env_root(env, root)
214
202
 
215
203
  detached_param_str = '-d' if detached else ''
216
204
  detached_end_str = ' &' if detached else ''
217
205
  detached_end_str = ''
218
206
 
219
207
  process = await asyncio.create_subprocess_shell(
220
- cmd := f'{COMPOSE} --project-directory {root} exec {extra_env_str} {detached_param_str} {self.extra_exec_params} {container} {cmd} {detached_end_str}',
208
+ cmd := (
209
+ f'{self.compose_cmd} --project-directory {root} exec {extra_env_str} '
210
+ f'{detached_param_str} {self.extra_exec_params} {container} {cmd} {detached_end_str}'
211
+ ),
221
212
  env=env,
222
213
  cwd=root,
223
214
  stdout=asyncio.subprocess.PIPE,
@@ -237,7 +228,8 @@ class ComposeShellInterface:
237
228
  state_result = await self.dc_state()
238
229
  if state_result == JobResult.GOOD:
239
230
  return OperationError(
240
- f'Command: {cmd}\nStdout:\n{stdout}\n\nStderr:\n{stderr}\n\nComposeState:\n{state_result.as_rich_text()}'
231
+ f'Command: {cmd}\nStdout:\n{stdout}\n\nStderr:\n{stderr}\n\n'
232
+ f'ComposeState:\n{state_result.as_rich_text()}'
241
233
  ), stdout, stderr
242
234
  return OperationError(
243
235
  f'Command: {cmd}\nStdout:\n{stdout}\n\nStderr:\n{stderr}\n\nComposeState:\n{state_result}'
@@ -249,17 +241,19 @@ class ComposeShellInterface:
249
241
  cmd: str,
250
242
  env: dict = None,
251
243
  root: Path | str = None,
252
- ) -> tuple[JobResult, bytes, bytes] | list[int] | tuple[OperationError, bytes, bytes]:
253
- if env is None:
254
- env = {}
255
- env = self.execution_envs | env
256
-
257
- if root is None:
258
- root = self.in_docker_project_root
244
+ ) -> (
245
+ tuple[JobResult, bytes, bytes]
246
+ | list[int]
247
+ | tuple[OperationError, bytes, bytes]
248
+ ):
249
+ env, root = self._prepare_env_root(env, root)
259
250
 
260
251
  cmd = parse_process_command_name(cmd)
261
252
  process_state = await asyncio.create_subprocess_shell(
262
- check_cmd := f'{COMPOSE} --project-directory {root} exec {self.extra_exec_params} {container} pidof {cmd}',
253
+ check_cmd := (
254
+ f'{self.compose_cmd} --project-directory {root} exec '
255
+ f'{self.extra_exec_params} {container} pidof {cmd}'
256
+ ),
263
257
  env=env,
264
258
  cwd=root,
265
259
  stdout=asyncio.subprocess.PIPE,
@@ -272,7 +266,9 @@ class ComposeShellInterface:
272
266
  check_output = stdout.decode('utf-8')
273
267
  sys_error = stderr.decode("utf-8")
274
268
 
275
- self.logger.system_commands_debug(f'Pids of command "{cmd}" in "{container}":\n {check_output} \nErr: {sys_error}')
269
+ self.logger.system_commands_debug(
270
+ f'Pids of command "{cmd}" in "{container}":\n {check_output} \nErr: {sys_error}'
271
+ )
276
272
 
277
273
  if check_output != '':
278
274
  try:
@@ -295,15 +291,10 @@ class ComposeShellInterface:
295
291
  env: dict = None,
296
292
  root: Path | str = None,
297
293
  ) -> None:
298
- if env is None:
299
- env = {}
300
- env = self.execution_envs | env
301
-
302
- if root is None:
303
- root = self.in_docker_project_root
294
+ env, root = self._prepare_env_root(env, root)
304
295
 
305
296
  processes_state = await asyncio.create_subprocess_shell(
306
- get_cmd := f'{COMPOSE} --project-directory {root} exec {self.extra_exec_params} {container} top -n 1',
297
+ f'{self.compose_cmd} --project-directory {root} exec {self.extra_exec_params} {container} top -n 1',
307
298
  env=env,
308
299
  cwd=root,
309
300
  stdout=asyncio.subprocess.PIPE,
@@ -403,15 +394,10 @@ class ComposeShellInterface:
403
394
  self.logger.stage_info(f'Downing {services} containers')
404
395
  sys.stdout.flush()
405
396
 
406
- if env is None:
407
- env = {}
408
- env = self.execution_envs | env
409
-
410
- if root is None:
411
- root = self.in_docker_project_root
397
+ env, root = self._prepare_env_root(env, root)
412
398
 
413
399
  process = await asyncio.create_subprocess_shell(
414
- cmd := f'{COMPOSE} --project-directory {root} down ' + ' '.join(services),
400
+ cmd := f'{self.compose_cmd} --project-directory {root} down ' + ' '.join(services),
415
401
  env=env,
416
402
  cwd=root,
417
403
  stdout=asyncio.subprocess.PIPE,
@@ -433,8 +419,11 @@ class ComposeShellInterface:
433
419
  state_result = await self.dc_state()
434
420
  if state_result == JobResult.GOOD:
435
421
  return OperationError(
436
- f'Command: {cmd}\nStdout:\n{stdout}\n\nStderr:\n{stderr}\n\nComposeState:\n{state_result.as_rich_text()}'
422
+ f'Command: {cmd}\nStdout:\n{stdout}\n\nStderr:\n{stderr}\n\n'
423
+ f'ComposeState:\n{state_result.as_rich_text()}'
437
424
  )
438
- return OperationError(f'Command: {cmd}\nStdout:\n{stdout}\n\nStderr:\n{stderr}\n\nComposeState:\n{state_result}')
425
+ return OperationError(
426
+ f'Command: {cmd}\nStdout:\n{stdout}\n\nStderr:\n{stderr}\n\nComposeState:\n{state_result}'
427
+ )
439
428
 
440
429
  return JobResult.GOOD
@@ -1,5 +1,5 @@
1
- import json
2
1
  from dataclasses import dataclass
2
+ import json
3
3
  from typing import Callable
4
4
  from typing import Iterator
5
5
 
@@ -173,7 +173,7 @@ class ServicesComposeState:
173
173
  if service_state.check(label, value):
174
174
  return service_state
175
175
 
176
- return
176
+ return None
177
177
 
178
178
  def __len__(self):
179
179
  return len(self._services)
@@ -1,17 +1,15 @@
1
- import pprint
2
- from itertools import groupby
3
1
  from pathlib import Path
2
+ import pprint
4
3
 
5
4
  from rich.text import Text
5
+
6
6
  from uber_compose.core.constants import Constants
7
7
  from uber_compose.core.docker_compose_shell.interface import ComposeShellInterface
8
8
  from uber_compose.core.docker_compose_shell.types import ServicesComposeState
9
- from uber_compose.core.utils.compose_instance_cfg import get_service_map
10
9
  from uber_compose.env_description.env_types import Environment
11
10
  from uber_compose.helpers.bytes_pickle import base64_pickled
12
11
  from uber_compose.helpers.bytes_pickle import debase64_pickled
13
12
  from uber_compose.helpers.labels import Label
14
- from uber_compose.output.console import CONSOLE
15
13
  from uber_compose.output.console import Logger
16
14
  from uber_compose.output.styles import Style
17
15
  from uber_compose.utils.docker_compose_files_path import get_absolute_compose_files
@@ -29,7 +27,9 @@ class SystemDockerCompose:
29
27
  scan_for_compose_files(inner_project_root, self.cfg_constants.docker_compose_files_scan_depth)
30
28
  )
31
29
  self.logger.commands(f'All found compose files: {self.default_compose_files}')
32
- assert self.default_compose_files, f'No docker-compose files found in the project root {inner_project_root} directory.'
30
+ assert self.default_compose_files, (
31
+ f'No docker-compose files found in the project root {inner_project_root} directory.'
32
+ )
33
33
 
34
34
  self.default_environment = make_default_environment(
35
35
  compose_files=get_absolute_compose_files(self.default_compose_files, inner_project_root),
@@ -54,7 +54,9 @@ class SystemDockerCompose:
54
54
  services_state = await self.dc_shell.dc_state()
55
55
  services_states = services_state.get_all_for(
56
56
  lambda service_state: (
57
- service_state.check(Label.ENV_CONFIG_TEMPLATE, base64_pickled(Environment.from_environment(config_template)))
57
+ service_state.check(
58
+ Label.ENV_CONFIG_TEMPLATE, base64_pickled(Environment.from_environment(config_template))
59
+ )
58
60
  and service_state.check(Label.COMPOSE_FILES, compose_files)
59
61
  )
60
62
  )
@@ -1,12 +1,10 @@
1
1
  import collections
2
- import os
3
- import shutil
4
- from _warnings import warn
5
2
  from copy import deepcopy
3
+ import os
6
4
  from pathlib import Path
5
+ import shutil
7
6
 
8
7
  import yaml
9
- from uber_compose.env_description.env_types import OverridenService
10
8
 
11
9
  from uber_compose.core.sequence_run_types import ComposeInstanceFiles
12
10
  from uber_compose.core.sequence_run_types import EnvInstanceConfig
@@ -14,6 +12,7 @@ from uber_compose.core.utils.compose_instance_cfg import made_up_instance_compos
14
12
  from uber_compose.env_description.env_types import Environment
15
13
  from uber_compose.env_description.env_types import EventStage
16
14
  from uber_compose.env_description.env_types import Handler
15
+ from uber_compose.env_description.env_types import OverridenService
17
16
  from uber_compose.errors.migrations import ServicesMigrationsError
18
17
  from uber_compose.helpers.bytes_pickle import base64_pickled
19
18
  from uber_compose.helpers.labels import Label
@@ -110,7 +109,12 @@ def patch_service_set(dc_cfg: dict, services_map: dict[str, str] | None):
110
109
  return new_dc_cfg
111
110
 
112
111
 
113
- def patch_envs(dc_cfg: dict, services_environment_vars: Environment, run_id, overridden_services: list[OverridenService] | None = None) -> dict:
112
+ def patch_envs(
113
+ dc_cfg: dict,
114
+ services_environment_vars: Environment,
115
+ run_id,
116
+ overridden_services: list[OverridenService] | None = None,
117
+ ) -> dict:
114
118
  # TODO envs order and override question!!
115
119
  # if we overrides env, should we save order? or insert before, for allow to override codegen
116
120
  new_dc_cfg = deepcopy(dc_cfg)
@@ -160,7 +164,11 @@ def patch_envs(dc_cfg: dict, services_environment_vars: Environment, run_id, ove
160
164
  return new_dc_cfg
161
165
 
162
166
 
163
- def patch_services_names(dc_cfg: dict, services_map: dict[str, str], overridden_services: list[OverridenService] | None = None) -> dict:
167
+ def patch_services_names(
168
+ dc_cfg: dict,
169
+ services_map: dict[str, str],
170
+ overridden_services: list[OverridenService] | None = None,
171
+ ) -> dict:
164
172
  new_service_dc_cfg = deepcopy(dc_cfg)
165
173
  new_service_dc_cfg['services'] = {}
166
174
 
@@ -438,7 +446,8 @@ def parse_docker_compose(file_paths):
438
446
 
439
447
 
440
448
  def topological_sort(services_dict):
441
- from collections import defaultdict, deque
449
+ from collections import defaultdict
450
+ from collections import deque
442
451
 
443
452
  # Prepare the adjacency list
444
453
  graph = defaultdict(list)
@@ -456,7 +465,6 @@ def topological_sort(services_dict):
456
465
  topologically_sorted_services = []
457
466
 
458
467
  while zero_in_degree_queue:
459
- level_services = list(zero_in_degree_queue)
460
468
  for _ in range(len(zero_in_degree_queue)):
461
469
  node = zero_in_degree_queue.popleft()
462
470
  topologically_sorted_services.append(node)
@@ -12,9 +12,9 @@ def make_debug_bash_env(env_config_compose_instance: ComposeInstanceFiles,
12
12
  )
13
13
 
14
14
  with open(env_config_compose_instance.directory / '.env', 'w') as f:
15
- f.write(f'alias dc="docker-compose --project-directory ."\n')
15
+ f.write('alias dc="docker-compose --project-directory ."\n')
16
16
  f.write(f'export COMPOSE_FILE={new_external_compose_file}\n')
17
- f.write(f'alias deactivate-env="unset COMPOSE_FILE"\n')
17
+ f.write('alias deactivate-env="unset COMPOSE_FILE"\n')
18
18
  # TODO Envs
19
19
  # for k,value in updated_envs.items():
20
20
  # f.write(f'{k}={value}\n')
@@ -42,7 +42,7 @@ async def wait_all_services_up(attempts, delay_s, logger_func: Callable, get_com
42
42
  ]
43
43
 
44
44
  if not non_ready_services:
45
- logger_func(Text(f' ✔ All services up\n', style=output_style.mark_neutral))
45
+ logger_func(Text(' ✔ All services up\n', style=output_style.mark_neutral))
46
46
  return JobResult.GOOD
47
47
 
48
48
  # some service not ready routine
@@ -54,7 +54,7 @@ async def wait_all_services_up(attempts, delay_s, logger_func: Callable, get_com
54
54
  return JobResult.BAD
55
55
 
56
56
  if state_keeper.not_in_state(services_state):
57
- logger_func(Text(f' ✗ Still not ready services:', style=output_style.bad))
57
+ logger_func(Text(' ✗ Still not ready services:', style=output_style.bad))
58
58
  logger_func(services_state.as_rich_text(
59
59
  filter=is_service_in_bad_state,
60
60
  style=output_style
@@ -84,6 +84,8 @@ class Service(NamedTuple):
84
84
  mode: ServiceMode = ServiceMode.ON
85
85
 
86
86
  def __eq__(self, other):
87
+ if not isinstance(other, Service):
88
+ return False
87
89
  return self.name == other.name
88
90
 
89
91
  def __repr__(self):
@@ -129,7 +131,9 @@ def remove_dups(*services: Service) -> List[Service]:
129
131
 
130
132
  class Environment: # TODO rename Environment
131
133
  @classmethod
132
- def from_environment(cls, env: 'Environment', *services: Service, description='', services_override = None) -> 'Environment':
134
+ def from_environment(
135
+ cls, env: 'Environment', *services: Service, description='', services_override=None,
136
+ ) -> 'Environment':
133
137
  # TODO duplicated services merging
134
138
  description = description or env._description
135
139
  services_overrides = []
@@ -139,7 +143,9 @@ class Environment: # TODO rename Environment
139
143
  services_overrides += env._services_override
140
144
  return Environment(*env._services, *services, description=description, services_override=services_overrides)
141
145
 
142
- def __init__(self, *services: Service | str, description='', services_override: List[OverridenService] | None = None):
146
+ def __init__(
147
+ self, *services: Service | str, description='', services_override: List[OverridenService] | None = None,
148
+ ):
143
149
  # TODO duplicated services merging
144
150
  self._description = description
145
151
  services = [
@@ -24,5 +24,6 @@ def calc_broken_services(
24
24
  if service.service.name not in services_state.get_services_names()
25
25
  ]
26
26
  return list(
27
- set(non_ready_services) | set(not_included_services) - set(excluded_from_check) - set(skipped_overridden_services)
27
+ set(non_ready_services) | set(not_included_services)
28
+ - set(excluded_from_check) - set(skipped_overridden_services)
28
29
  )
@@ -1,4 +1,3 @@
1
- from dataclasses import dataclass
2
1
  from typing import NamedTuple
3
2
 
4
3
 
@@ -37,7 +37,10 @@ class LogPolicySet:
37
37
 
38
38
  class LogPolicy:
39
39
  DEFAULT = LogPolicySet(LogEvents.STAGE, LogEvents.ERROR)
40
- VERBOSE = LogPolicySet(LogEvents.STAGE, LogEvents.STAGE_INFO, LogEvents.STAGE_DETAILS, LogEvents.ERROR, LogEvents.COMMANDS, LogEvents.COMMAND_OUTPUT)
40
+ VERBOSE = LogPolicySet(
41
+ LogEvents.STAGE, LogEvents.STAGE_INFO, LogEvents.STAGE_DETAILS,
42
+ LogEvents.ERROR, LogEvents.COMMANDS, LogEvents.COMMAND_OUTPUT,
43
+ )
41
44
  DEBUG = LogPolicySet(LogEvents.GLOBAL_DEBUG)
42
45
 
43
46
  @staticmethod
@@ -51,7 +54,7 @@ class LogPolicy:
51
54
 
52
55
  # TODO collect all into file and on level in stdout
53
56
  class Logger:
54
- def __init__(self, log_policy: LogPolicySet = None, cfg_constants = None):
57
+ def __init__(self, log_policy: LogPolicySet = None, cfg_constants=None):
55
58
  if cfg_constants is None:
56
59
  cfg_constants = Constants()
57
60
  if log_policy is None:
@@ -64,7 +67,7 @@ class Logger:
64
67
  if LogEvents.GLOBAL_DEBUG in self.log_policy:
65
68
  if line_no == 0:
66
69
  self.stream.print(f'{level}:', style='bold grey15 on green', end='')
67
- self.stream.print(f'', style='white on default')
70
+ self.stream.print('', style='white on default')
68
71
  self.stream.print(text)
69
72
  return
70
73
 
@@ -1,19 +1,17 @@
1
- import shlex
2
1
  from dataclasses import dataclass
3
- from typing import Any
2
+ import shlex
4
3
  from typing import Callable
5
4
  from uuid import uuid4
6
5
 
7
6
  from rich.text import Text
8
7
 
9
- from uber_compose.core.docker_compose_shell.types import ExecLifeCyclePolicy
10
- from uber_compose.core.docker_compose_shell.interface import TimeOutCheck
11
- from uber_compose.core.docker_compose_shell.types import ServicesComposeState
12
-
13
8
  from uber_compose.core.constants import Constants
14
9
  from uber_compose.core.docker_compose import ComposeInstance
15
10
  from uber_compose.core.docker_compose_shell.interface import ComposeShellInterface
16
11
  from uber_compose.core.docker_compose_shell.interface import ProcessExit
12
+ from uber_compose.core.docker_compose_shell.interface import TimeOutCheck
13
+ from uber_compose.core.docker_compose_shell.types import ExecLifeCyclePolicy
14
+ from uber_compose.core.docker_compose_shell.types import ServicesComposeState
17
15
  from uber_compose.core.sequence_run_types import DEFAULT_ENV_ID
18
16
  from uber_compose.core.system_docker_compose import SystemDockerCompose
19
17
  from uber_compose.core.utils.compose_instance_cfg import get_new_env_id
@@ -71,9 +69,30 @@ class SystemUberCompose:
71
69
  services_override: list[OverridenService] | None = None,
72
70
  ) -> ReadyEnv:
73
71
 
72
+ compose_files = self._resolve_compose_files(compose_files)
73
+ config_template = self._resolve_config_template(config_template, compose_files, services_override)
74
+
75
+ services_state = await self._get_current_state(config_template, compose_files)
76
+
77
+ reusable_env = self._find_reusable_env(services_state, config_template, force_restart)
78
+ if reusable_env is not None:
79
+ return reusable_env
80
+
81
+ self._log_inflight_and_restart_info(services_state, force_restart)
82
+
83
+ return await self._start_new_environment(config_template, compose_files, release_id, parallelism_limit)
84
+
85
+ def _resolve_compose_files(self, compose_files: str | None) -> str:
74
86
  if not compose_files:
75
87
  compose_files = self.system_docker_compose.get_default_compose_files()
76
-
88
+ return compose_files
89
+
90
+ def _resolve_config_template(
91
+ self,
92
+ config_template: Environment | None,
93
+ compose_files: str,
94
+ services_override: list[OverridenService] | None,
95
+ ) -> Environment:
77
96
  if not config_template:
78
97
  config_template = make_default_environment(
79
98
  compose_files=get_absolute_compose_files(compose_files, self.cfg_constants.in_docker_project_root_path),
@@ -82,6 +101,9 @@ class SystemUberCompose:
82
101
  if services_override:
83
102
  config_template = config_template.from_environment(config_template, services_override=services_override)
84
103
 
104
+ return config_template
105
+
106
+ async def _get_current_state(self, config_template: Environment, compose_files: str) -> ServicesComposeState:
85
107
  self.logger.stage_debug(
86
108
  f'Searching for environment {config_template} with template: {base64_pickled(config_template)}'
87
109
  )
@@ -92,28 +114,50 @@ class SystemUberCompose:
92
114
  self.logger.stage_debug(
93
115
  f'Found environments containers: {services_state}'
94
116
  )
117
+ return services_state
118
+
119
+ def _should_restart(self, services_state: ServicesComposeState, broken_services: list, force_restart: bool) -> bool:
120
+ return len(services_state) == 0 or len(broken_services) != 0 or force_restart
121
+
122
+ def _find_reusable_env(
123
+ self,
124
+ services_state: ServicesComposeState,
125
+ config_template: Environment,
126
+ force_restart: bool,
127
+ ) -> ReadyEnv | None:
95
128
  broken_services = calc_broken_services(services_state, config_template, self.cfg_constants.non_stop_containers)
96
129
  if broken_services:
97
130
  self.logger.stage(
98
131
  Text(
99
- f'Not started or not ready containers in current environment: ', style=Style.suspicious
132
+ 'Not started or not ready containers in current environment: ', style=Style.suspicious
100
133
  ).append(Text(f'{broken_services}', style=Style.regular))
101
134
  )
102
- if len(services_state) != 0 and len(broken_services) == 0 and not force_restart:
103
- existing_env_id = services_state.get_any().labels.get(Label.ENV_ID, None)
104
- env_config = debase64_pickled(services_state.get_any().labels.get(Label.ENV_CONFIG))
105
- _for = f' for {config_template.description}' if config_template.description else ''
106
- self.logger.stage_details(Text(
107
- f'Found suitable{_for} ready env: ', style=Style.info
108
- ).append(Text(existing_env_id, style=Style.mark)))
109
-
110
- last_release_id = services_state.get_any().labels.get(Label.RELEASE_ID)
111
- self.last_release_id = last_release_id
112
- return ReadyEnv(existing_env_id, env_config, last_release_id)
113
135
 
136
+ if self._should_restart(services_state, broken_services, force_restart):
137
+ return None
138
+
139
+ existing_env_id = services_state.get_any().labels.get(Label.ENV_ID, None)
140
+ env_config = debase64_pickled(services_state.get_any().labels.get(Label.ENV_CONFIG))
141
+ _for = f' for {config_template.description}' if config_template.description else ''
142
+ self.logger.stage_details(Text(
143
+ f'Found suitable{_for} ready env: ', style=Style.info
144
+ ).append(Text(existing_env_id, style=Style.mark)))
145
+
146
+ last_release_id = services_state.get_any().labels.get(Label.RELEASE_ID)
147
+ self.last_release_id = last_release_id
148
+ return ReadyEnv(existing_env_id, env_config, last_release_id)
149
+
150
+ def _log_inflight_and_restart_info(self, services_state: ServicesComposeState, force_restart: bool) -> None:
151
+ in_flight_templates = [
152
+ (
153
+ debase64_pickled(service["labels"][Label.ENV_CONFIG_TEMPLATE]),
154
+ service["labels"][Label.ENV_CONFIG_TEMPLATE],
155
+ )
156
+ for service in services_state.as_json()
157
+ ]
114
158
  self.logger.stage_debug(
115
159
  f'In-flight containers:\n'
116
- f'{[(debase64_pickled(service["labels"][Label.ENV_CONFIG_TEMPLATE]), service["labels"][Label.ENV_CONFIG_TEMPLATE]) for service in services_state.as_json()]}'
160
+ f'{in_flight_templates}'
117
161
  )
118
162
  if force_restart:
119
163
  self.logger.stage_details(Text(
@@ -123,7 +167,13 @@ class SystemUberCompose:
123
167
  f'Previous state {services_state.as_json()}', style=Style.info
124
168
  ))
125
169
 
126
-
170
+ async def _start_new_environment(
171
+ self,
172
+ config_template: Environment,
173
+ compose_files: str,
174
+ release_id: str | None,
175
+ parallelism_limit: int,
176
+ ) -> ReadyEnv:
127
177
  _for = f' {config_template.description}' if config_template.description else ''
128
178
  self.logger.stage(Text(f'Starting new{_for} environment', style=Style.info))
129
179
  self.logger.stage_details(f'Use compose files: {compose_files}')
@@ -164,7 +214,7 @@ class SystemUberCompose:
164
214
 
165
215
  # TODO check if ready by state checking
166
216
 
167
- self.logger.stage_info(Text(f'New environment started'))
217
+ self.logger.stage_info(Text('New environment started'))
168
218
 
169
219
  return ReadyEnv(
170
220
  new_env_id,
@@ -191,7 +241,7 @@ class SystemUberCompose:
191
241
 
192
242
  service_state = dc_state.get_all_for(
193
243
  lambda service_state: service_state.check(Label.ENV_ID, env_id)
194
- and service_state.check(Label.TEMPLATE_SERVICE_NAME, container)
244
+ and service_state.check(Label.TEMPLATE_SERVICE_NAME, container)
195
245
  )
196
246
  if len(service_state.as_json()) != 1:
197
247
  raise ValueError(f'Container {container} not found in environment {env_id}')
@@ -1,6 +1,5 @@
1
1
  from uber_compose.env_description.env_types import Environment
2
2
  from uber_compose.env_description.env_types import Service
3
- from uber_compose.utils.docker_compose_files_path import get_absolute_compose_files
4
3
  from uber_compose.utils.docker_compose_service_deps import parse_docker_compose_services_deps
5
4
 
6
5
 
@@ -1,6 +1,6 @@
1
+ from dataclasses import dataclass
1
2
  import json
2
3
  import re
3
- from dataclasses import dataclass
4
4
  from typing import Callable
5
5
  from typing import Generic
6
6
  from typing import List
@@ -9,13 +9,10 @@ from typing import Type
9
9
  from typing import TypeVar
10
10
  from warnings import warn
11
11
 
12
- from uber_compose.core.docker_compose_shell.types import ExecLifeCyclePolicy
13
- from uber_compose.helpers.exec_result import ExecResult
14
-
12
+ from uber_compose.core.docker_compose_shell.interface import ProcessExit
15
13
  from uber_compose.core.docker_compose_shell.interface import TimeOutCheck
14
+ from uber_compose.core.docker_compose_shell.types import ExecLifeCyclePolicy
16
15
  from uber_compose.uber_compose import SystemUberCompose
17
-
18
- from uber_compose.core.docker_compose_shell.interface import ProcessExit
19
16
  from uber_compose.uber_compose import TheUberCompose
20
17
 
21
18
 
@@ -246,7 +243,10 @@ class CommonJsonCli(Generic[TCommandResult]):
246
243
  timeout = self._timeout
247
244
 
248
245
  if container is None:
249
- assert self._container is not None, 'No container specified. Container must be specified either in method call or in CommonJsonCli initialization'
246
+ assert self._container is not None, (
247
+ 'No container specified. Container must be specified either in method call '
248
+ 'or in CommonJsonCli initialization'
249
+ )
250
250
  container = self._container
251
251
 
252
252
  if life_cycle_policy is None:
@@ -1,5 +1,4 @@
1
1
  import os
2
- from _warnings import warn
3
2
 
4
3
  from uber_compose.env_description.env_types import Environment
5
4
  from uber_compose.env_description.env_types import OverridenService
@@ -1,24 +1,22 @@
1
- from collections import OrderedDict
2
1
  import sys
3
2
  from typing import Type
4
3
  from typing import Union
5
4
  from uuid import uuid4
6
5
 
7
- import vedro.events
8
6
  from rich.text import Text
9
7
  from vedro.core import ConfigType
10
8
  from vedro.core import Dispatcher
11
9
  from vedro.core import Plugin
12
10
  from vedro.core import PluginConfig
11
+ import vedro.events
13
12
  from vedro.events import ArgParseEvent
14
13
  from vedro.events import ArgParsedEvent
15
14
  from vedro.events import ConfigLoadedEvent
16
15
  from vedro.events import ScenarioRunEvent
17
16
  from vedro.events import StartupEvent
18
17
 
19
- from uber_compose import SystemUberCompose
20
- from uber_compose.output.styles import Style
21
18
  from uber_compose import Environment
19
+ from uber_compose import SystemUberCompose
22
20
  from uber_compose.core.constants import Constants
23
21
  from uber_compose.core.sequence_run_types import ComposeConfig
24
22
  from uber_compose.env_description.env_types import DEFAULT_ENV_DESCRIPTION
@@ -26,6 +24,7 @@ from uber_compose.env_description.env_types import OverridenService
26
24
  from uber_compose.helpers.health_policy import UpHealthPolicy
27
25
  from uber_compose.output.console import LogPolicy
28
26
  from uber_compose.output.console import Logger
27
+ from uber_compose.output.styles import Style
29
28
  from uber_compose.uber_compose import TheUberCompose as TheUberCompose
30
29
  from uber_compose.vedro_plugin.helpers.scenario_ordering import EnvTagsOrderer
31
30
  from uber_compose.vedro_plugin.helpers.scenario_tag_processing import extract_scenario_config
@@ -35,12 +34,15 @@ from uber_compose.vedro_plugin.helpers.test_env_vars_setter import setup_env_for
35
34
 
36
35
  DEFAULT_COMPOSE = 'default'
37
36
 
37
+
38
38
  class VedroUberComposePlugin(Plugin):
39
39
  def __init__(self, config: Type["VedroUberCompose"], client: SystemUberCompose = None) -> None:
40
40
  super().__init__(config)
41
41
  self._enabled = config.enabled
42
42
  if config.default_env:
43
- assert config.default_env._description == DEFAULT_ENV_DESCRIPTION, 'default_env must have description set to DEFAULT_ENV_DESCRIPTION'
43
+ assert config.default_env._description == DEFAULT_ENV_DESCRIPTION, (
44
+ 'default_env must have description set to DEFAULT_ENV_DESCRIPTION'
45
+ )
44
46
  self._default_env: Environment = config.default_env
45
47
 
46
48
  # cli args
@@ -94,8 +96,18 @@ class VedroUberComposePlugin(Plugin):
94
96
  try:
95
97
  if self._compose_choice.parallel_env_limit >= len(needed_configs):
96
98
  for env_config in list(needed_configs):
97
- if env_config == None:
99
+ if self._default_env is None and env_config is None:
100
+ self._logger.stage(
101
+ Text(
102
+ '[UberCompose] Warning: some scenarios has no "env" field set.\n'
103
+ 'Consider adding "env = Envs.DEFAULT" to your scenario.',
104
+ style=Style.suspicious
105
+ )
106
+ )
107
+
108
+ if env_config is None:
98
109
  env_config = self._default_env
110
+
99
111
  await self._uber_compose_client.up(
100
112
  config_template=env_config,
101
113
  compose_files=self._compose_choice.compose_files,
@@ -115,7 +127,7 @@ class VedroUberComposePlugin(Plugin):
115
127
  if self._just_up:
116
128
  self._logger.stage(
117
129
  Text(
118
- f'Environment has been started successfully. Exiting as requested.',
130
+ 'Environment has been started successfully. Exiting as requested.',
119
131
  style=Style.good
120
132
  )
121
133
  )
@@ -0,0 +1 @@
1
+ 2.3.3
@@ -2,5 +2,6 @@ import os
2
2
 
3
3
  path = os.path.abspath(os.path.dirname(__file__))
4
4
 
5
+
5
6
  def get_version(filename=f'{path}/version'):
6
7
  return open(filename, "r").read().strip()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uber-compose
3
- Version: 2.3.1a2002
3
+ Version: 2.3.3
4
4
  Summary: docker compose testing env orchestrator
5
5
  Home-page: https://github.com/ko10ok/uber-compose
6
6
  Author: Yuriy Sagitov
@@ -1,5 +1,6 @@
1
1
  LICENSE
2
2
  README.md
3
+ setup.cfg
3
4
  setup.py
4
5
  uber_compose/__init__.py
5
6
  uber_compose/uber_compose.py
@@ -1,4 +0,0 @@
1
- [egg_info]
2
- tag_build =
3
- tag_date = 0
4
-
@@ -1 +0,0 @@
1
- 2.3.1
File without changes
File without changes
@@ -1,6 +1,6 @@
1
- from uber_compose.core.docker_compose_shell.types import ExecLifeCyclePolicy
2
1
  from uber_compose.core.docker_compose_shell.interface import ProcessExit
3
2
  from uber_compose.core.docker_compose_shell.interface import TimeOutCheck
3
+ from uber_compose.core.docker_compose_shell.types import ExecLifeCyclePolicy
4
4
  from uber_compose.core.sequence_run_types import ComposeConfig
5
5
  from uber_compose.core.sequence_run_types import DEFAULT_ENV_ID
6
6
  from uber_compose.env_description.env_types import DEFAULT_ENV_DESCRIPTION
@@ -2,8 +2,8 @@ from pathlib import Path
2
2
  from typing import NamedTuple
3
3
  from typing import Union
4
4
 
5
- from uber_compose.env_description.env_types import OverridenService
6
5
  from uber_compose.env_description.env_types import Environment
6
+ from uber_compose.env_description.env_types import OverridenService
7
7
 
8
8
  DEFAULT_ENV_ID = 'default_env_id'
9
9