csrd-utils 0.3.54__tar.gz → 0.3.55__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 (87) hide show
  1. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/PKG-INFO +1 -1
  2. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/pyproject.toml +1 -1
  3. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/__main__.py +33 -2
  4. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/generator.py +14 -0
  5. csrd_utils-0.3.55/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/acceptance/__init__.py +0 -0
  6. csrd_utils-0.3.55/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/__init__.py +0 -0
  7. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/.gitignore +0 -0
  8. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/README.md +0 -0
  9. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/__init__.py +0 -0
  10. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/audit.py +0 -0
  11. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/augmentor.py +0 -0
  12. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/cluster.py +0 -0
  13. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/doctor.py +0 -0
  14. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/caching/conftest.fragment.py +0 -0
  15. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/caching/docker-compose.fragment.yaml +0 -0
  16. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/caching/manifest.yaml +0 -0
  17. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/caching/requirements.fragment +0 -0
  18. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/caching/settings.fragment.py +0 -0
  19. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/caching/src/app/cache.py +0 -0
  20. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/caching/tests/test_cache.py +0 -0
  21. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/logging/conftest.fragment.py +0 -0
  22. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/logging/manifest.yaml +0 -0
  23. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/logging/requirements.fragment +0 -0
  24. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/logging/settings.fragment.py +0 -0
  25. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/logging/src/app/middleware/logging.py +0 -0
  26. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/logging/tests/test_logging_middleware.py +0 -0
  27. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/metrics/conftest.fragment.py +0 -0
  28. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/metrics/docker-compose.fragment.yaml +0 -0
  29. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/metrics/manifest.yaml +0 -0
  30. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/metrics/requirements.fragment +0 -0
  31. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/metrics/settings.fragment.py +0 -0
  32. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/metrics/src/app/middleware/metrics.py +0 -0
  33. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/metrics/tests/test_metrics_middleware.py +0 -0
  34. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/tracing/conftest.fragment.py +0 -0
  35. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/tracing/manifest.yaml +0 -0
  36. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/tracing/requirements.fragment +0 -0
  37. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/tracing/settings.fragment.py +0 -0
  38. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/tracing/src/app/middleware/tracing.py +0 -0
  39. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/tracing/tests/test_tracing_middleware.py +0 -0
  40. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/workers/conftest.fragment.py +0 -0
  41. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/workers/docker-compose.fragment.yaml +0 -0
  42. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/workers/manifest.yaml +0 -0
  43. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/workers/requirements.fragment +0 -0
  44. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/workers/settings.fragment.py +0 -0
  45. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/workers/src/app/workers/__init__.py +0 -0
  46. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/workers/src/app/workers/celery_app.py +0 -0
  47. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/workers/src/app/workers/tasks.py +0 -0
  48. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/features/workers/tests/test_workers.py +0 -0
  49. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/fragments.py +0 -0
  50. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/resources.py +0 -0
  51. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/README.md +0 -0
  52. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/cookiecutter.json +0 -0
  53. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/hooks/post_gen_project.py +0 -0
  54. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/.cookiecutterignore +0 -0
  55. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
  56. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
  57. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
  58. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
  59. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/cache.py +0 -0
  60. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/delegates/__init__.py +0 -0
  61. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/delegates/upstreams.py +0 -0
  62. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
  63. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/delegates.py +0 -0
  64. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/item_repository.py +0 -0
  65. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/worker_broker.py +0 -0
  66. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/docker-compose.yml +0 -0
  67. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/middleware/__init__.py +0 -0
  68. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/middleware/logging.py +0 -0
  69. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
  70. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/repositories/item_repository.py +0 -0
  71. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
  72. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
  73. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/__init__.py +0 -0
  74. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/acceptance/test_logging_middleware.py +0 -0
  75. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/conftest.py +0 -0
  76. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/test_items.py +0 -0
  77. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_cache.py +0 -0
  78. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_database_settings.py +0 -0
  79. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_delegates.py +0 -0
  80. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_settings_contracts.py +0 -0
  81. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_worker_broker.py +0 -0
  82. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
  83. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
  84. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
  85. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/items_view.py +0 -0
  86. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/workers/__init__.py +0 -0
  87. {csrd_utils-0.3.54 → csrd_utils-0.3.55}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/workers/tasks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csrd-utils
3
- Version: 0.3.54
3
+ Version: 0.3.55
4
4
  Summary: CLI utilities for csrd service generation and feature augmentation
5
5
  Project-URL: Repository, https://github.com/csrd-api/fastapi-common
6
6
  Project-URL: Documentation, https://github.com/csrd-api/fastapi-common/tree/main/packages/utils
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "csrd-utils"
3
- version = "0.3.54"
3
+ version = "0.3.55"
4
4
  description = "CLI utilities for csrd service generation and feature augmentation"
5
5
  license = { text = "MIT" }
6
6
  requires-python = ">=3.12"
@@ -213,12 +213,19 @@ def _collect_new_service_config(args: argparse.Namespace) -> GenerateServiceArgs
213
213
  has_database = args.database != "none"
214
214
  selected_database = "sqlite" if not has_database else args.database
215
215
  normalized_name = _normalize_service_name(args.name)
216
+ # Auto-advance port when default (8080) is already taken in the workspace spec.
217
+ output_root = args.output.resolve()
218
+ effective_port = (
219
+ _next_free_port(output_root, args.port)
220
+ if _is_workspace(output_root) and args.port == 8080
221
+ else args.port
222
+ )
216
223
  return GenerateServiceArgs(
217
224
  {
218
225
  "name": normalized_name,
219
226
  "output_dir": args.output,
220
227
  "description": args.description,
221
- "port": args.port,
228
+ "port": effective_port,
222
229
  "model_name": args.model_name,
223
230
  "model_name_plural": args.model_name_plural,
224
231
  "has_database": has_database,
@@ -242,7 +249,15 @@ def _collect_new_service_config(args: argparse.Namespace) -> GenerateServiceArgs
242
249
  else:
243
250
  output_dir = Path(_prompt_text("Output directory", str(args.output)))
244
251
  description = _prompt_text("Service description", args.description)
245
- port = _prompt_int("HTTP port", args.port)
252
+
253
+ # Suggest the next available port based on what's already in the workspace spec.
254
+ workspace_root_candidate = output_dir.resolve()
255
+ default_port = (
256
+ _next_free_port(workspace_root_candidate, args.port)
257
+ if _is_workspace(workspace_root_candidate)
258
+ else args.port
259
+ )
260
+ port = _prompt_int("HTTP port", default_port)
246
261
  model_name = _prompt_text("Model name", args.model_name)
247
262
 
248
263
  plural_default = args.model_name_plural
@@ -461,6 +476,22 @@ def _is_workspace(path: Path) -> bool:
461
476
  return (path / WORKSPACE_MARKER).is_file()
462
477
 
463
478
 
479
+ def _next_free_port(workspace_root: Path, start: int = 8080) -> int:
480
+ """Return the lowest port >= start that is not already used in the workspace cluster spec."""
481
+ spec_path = workspace_root / WORKSPACE_CLUSTER_SPEC
482
+ if not spec_path.is_file():
483
+ return start
484
+ try:
485
+ raw = yaml.safe_load(spec_path.read_text(encoding="utf-8")) or {}
486
+ used = {int(svc["port"]) for svc in raw.get("services", []) if "port" in svc}
487
+ except Exception:
488
+ return start
489
+ port = start
490
+ while port in used:
491
+ port += 1
492
+ return port
493
+
494
+
464
495
  def _service_is_interactive(args: argparse.Namespace) -> bool:
465
496
  explicit_interactive = getattr(args, "interactive", None)
466
497
  return bool(explicit_interactive) if explicit_interactive is not None else args.name is None
@@ -49,6 +49,7 @@ dev = [
49
49
  asyncio_mode = "auto"
50
50
  testpaths = ["tests"]
51
51
  pythonpath = ["src"]
52
+ consider_namespace_packages = true
52
53
 
53
54
  [tool.mypy]
54
55
  python_version = "3.12"
@@ -289,6 +290,19 @@ def _move_tests_to_workspace_root(
289
290
  unit_dst.mkdir(parents=True, exist_ok=True)
290
291
  acceptance_dst.mkdir(parents=True, exist_ok=True)
291
292
 
293
+ # Ensure every test directory level has an __init__.py so pytest uses
294
+ # package-based import paths and avoids module-name collisions across services.
295
+ def _ensure_init(dir_path: Path) -> None:
296
+ init = dir_path / "__init__.py"
297
+ if not init.exists():
298
+ init.write_text("", encoding="utf-8")
299
+
300
+ _ensure_init(tests_root)
301
+ _ensure_init(tests_root / "unit")
302
+ _ensure_init(tests_root / "acceptance")
303
+ _ensure_init(unit_dst)
304
+ _ensure_init(acceptance_dst)
305
+
292
306
  def _copy_tree(src_dir: Path, dst_dir: Path) -> None:
293
307
  if not src_dir.is_dir():
294
308
  return
File without changes
File without changes