wup 0.2.74__tar.gz → 0.2.76__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. {wup-0.2.74/wup.egg-info → wup-0.2.76}/PKG-INFO +6 -6
  2. {wup-0.2.74 → wup-0.2.76}/README.md +5 -5
  3. {wup-0.2.74 → wup-0.2.76}/pyproject.toml +1 -1
  4. {wup-0.2.74 → wup-0.2.76}/tests/test_genericity.py +26 -0
  5. {wup-0.2.74 → wup-0.2.76}/wup/__init__.py +1 -1
  6. {wup-0.2.74 → wup-0.2.76}/wup/config.py +2 -0
  7. {wup-0.2.74 → wup-0.2.76}/wup/core.py +19 -4
  8. {wup-0.2.74 → wup-0.2.76}/wup/models/config.py +3 -0
  9. {wup-0.2.74 → wup-0.2.76/wup.egg-info}/PKG-INFO +6 -6
  10. {wup-0.2.74 → wup-0.2.76}/LICENSE +0 -0
  11. {wup-0.2.74 → wup-0.2.76}/setup.cfg +0 -0
  12. {wup-0.2.74 → wup-0.2.76}/tests/test_aql.py +0 -0
  13. {wup-0.2.74 → wup-0.2.76}/tests/test_assistant.py +0 -0
  14. {wup-0.2.74 → wup-0.2.76}/tests/test_auto_detection.py +0 -0
  15. {wup-0.2.74 → wup-0.2.76}/tests/test_cli_bridge.py +0 -0
  16. {wup-0.2.74 → wup-0.2.76}/tests/test_cli_filtering.py +0 -0
  17. {wup-0.2.74 → wup-0.2.76}/tests/test_control.py +0 -0
  18. {wup-0.2.74 → wup-0.2.76}/tests/test_discovery_adapters.py +0 -0
  19. {wup-0.2.74 → wup-0.2.76}/tests/test_e2e.py +0 -0
  20. {wup-0.2.74 → wup-0.2.76}/tests/test_endpoints_init_cli.py +0 -0
  21. {wup-0.2.74 → wup-0.2.76}/tests/test_health_summary_passed.py +0 -0
  22. {wup-0.2.74 → wup-0.2.76}/tests/test_monitoring_manifest.py +0 -0
  23. {wup-0.2.74 → wup-0.2.76}/tests/test_multi_project.py +0 -0
  24. {wup-0.2.74 → wup-0.2.76}/tests/test_oql.py +0 -0
  25. {wup-0.2.74 → wup-0.2.76}/tests/test_planfile_reporter_dedupe.py +0 -0
  26. {wup-0.2.74 → wup-0.2.76}/tests/test_probe_mutex.py +0 -0
  27. {wup-0.2.74 → wup-0.2.76}/tests/test_service_inference.py +0 -0
  28. {wup-0.2.74 → wup-0.2.76}/tests/test_status_data.py +0 -0
  29. {wup-0.2.74 → wup-0.2.76}/tests/test_sync.py +0 -0
  30. {wup-0.2.74 → wup-0.2.76}/tests/test_testql_monitor.py +0 -0
  31. {wup-0.2.74 → wup-0.2.76}/tests/test_testql_watcher.py +0 -0
  32. {wup-0.2.74 → wup-0.2.76}/tests/test_visual_diff_periodic_skip.py +0 -0
  33. {wup-0.2.74 → wup-0.2.76}/tests/test_visual_diff_progress.py +0 -0
  34. {wup-0.2.74 → wup-0.2.76}/tests/test_watch_exclude.py +0 -0
  35. {wup-0.2.74 → wup-0.2.76}/tests/test_watch_no_paths_exit.py +0 -0
  36. {wup-0.2.74 → wup-0.2.76}/tests/test_web_client.py +0 -0
  37. {wup-0.2.74 → wup-0.2.76}/tests/test_wup.py +0 -0
  38. {wup-0.2.74 → wup-0.2.76}/tests/test_wup_generate.py +0 -0
  39. {wup-0.2.74 → wup-0.2.76}/wup/_ast_detector.py +0 -0
  40. {wup-0.2.74 → wup-0.2.76}/wup/_base_detector.py +0 -0
  41. {wup-0.2.74 → wup-0.2.76}/wup/_hash_detector.py +0 -0
  42. {wup-0.2.74 → wup-0.2.76}/wup/_yaml_detector.py +0 -0
  43. {wup-0.2.74 → wup-0.2.76}/wup/anomaly_detector.py +0 -0
  44. {wup-0.2.74 → wup-0.2.76}/wup/anomaly_models.py +0 -0
  45. {wup-0.2.74 → wup-0.2.76}/wup/aql.py +0 -0
  46. {wup-0.2.74 → wup-0.2.76}/wup/assistant.py +0 -0
  47. {wup-0.2.74 → wup-0.2.76}/wup/assistant_discovery.py +0 -0
  48. {wup-0.2.74 → wup-0.2.76}/wup/assistant_validator.py +0 -0
  49. {wup-0.2.74 → wup-0.2.76}/wup/bus.py +0 -0
  50. {wup-0.2.74 → wup-0.2.76}/wup/cli.py +0 -0
  51. {wup-0.2.74 → wup-0.2.76}/wup/cli_bridge.py +0 -0
  52. {wup-0.2.74 → wup-0.2.76}/wup/cli_config_generator.py +0 -0
  53. {wup-0.2.74 → wup-0.2.76}/wup/cli_scanner.py +0 -0
  54. {wup-0.2.74 → wup-0.2.76}/wup/control.py +0 -0
  55. {wup-0.2.74 → wup-0.2.76}/wup/dependency_mapper.py +0 -0
  56. {wup-0.2.74 → wup-0.2.76}/wup/discovery.py +0 -0
  57. {wup-0.2.74 → wup-0.2.76}/wup/endpoints.py +0 -0
  58. {wup-0.2.74 → wup-0.2.76}/wup/event_store.py +0 -0
  59. {wup-0.2.74 → wup-0.2.76}/wup/file_watcher/events/file_events.py +0 -0
  60. {wup-0.2.74 → wup-0.2.76}/wup/generate.py +0 -0
  61. {wup-0.2.74 → wup-0.2.76}/wup/init_cli.py +0 -0
  62. {wup-0.2.74 → wup-0.2.76}/wup/models/__init__.py +0 -0
  63. {wup-0.2.74 → wup-0.2.76}/wup/models/target.py +0 -0
  64. {wup-0.2.74 → wup-0.2.76}/wup/monitoring_manifest.py +0 -0
  65. {wup-0.2.74 → wup-0.2.76}/wup/multi.py +0 -0
  66. {wup-0.2.74 → wup-0.2.76}/wup/oql.py +0 -0
  67. {wup-0.2.74 → wup-0.2.76}/wup/paths.py +0 -0
  68. {wup-0.2.74 → wup-0.2.76}/wup/planfile_reporter.py +0 -0
  69. {wup-0.2.74 → wup-0.2.76}/wup/status_data.py +0 -0
  70. {wup-0.2.74 → wup-0.2.76}/wup/sync.py +0 -0
  71. {wup-0.2.74 → wup-0.2.76}/wup/testing/events/health_events.py +0 -0
  72. {wup-0.2.74 → wup-0.2.76}/wup/testing/events/test_results.py +0 -0
  73. {wup-0.2.74 → wup-0.2.76}/wup/testing/handlers/event_handlers.py +0 -0
  74. {wup-0.2.74 → wup-0.2.76}/wup/testing/handlers/health_handlers.py +0 -0
  75. {wup-0.2.74 → wup-0.2.76}/wup/testing/queries/health_queries.py +0 -0
  76. {wup-0.2.74 → wup-0.2.76}/wup/testql_cli_generator.py +0 -0
  77. {wup-0.2.74 → wup-0.2.76}/wup/testql_discovery.py +0 -0
  78. {wup-0.2.74 → wup-0.2.76}/wup/testql_monitor.py +0 -0
  79. {wup-0.2.74 → wup-0.2.76}/wup/testql_watcher.py +0 -0
  80. {wup-0.2.74 → wup-0.2.76}/wup/validate.py +0 -0
  81. {wup-0.2.74 → wup-0.2.76}/wup/visual_diff.py +0 -0
  82. {wup-0.2.74 → wup-0.2.76}/wup/web_client.py +0 -0
  83. {wup-0.2.74 → wup-0.2.76}/wup.egg-info/SOURCES.txt +0 -0
  84. {wup-0.2.74 → wup-0.2.76}/wup.egg-info/dependency_links.txt +0 -0
  85. {wup-0.2.74 → wup-0.2.76}/wup.egg-info/entry_points.txt +0 -0
  86. {wup-0.2.74 → wup-0.2.76}/wup.egg-info/requires.txt +0 -0
  87. {wup-0.2.74 → wup-0.2.76}/wup.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wup
3
- Version: 0.2.74
3
+ Version: 0.2.76
4
4
  Summary: WUP (What's Up) - Intelligent file watcher for regression testing in large projects
5
5
  Author-email: Tom Sapletta <tom@sapletta.com>
6
6
  License-Expression: Apache-2.0
@@ -42,17 +42,17 @@ Dynamic: license-file
42
42
 
43
43
  ## AI Cost Tracking
44
44
 
45
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.74-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
46
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$7.19-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-52.4h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
45
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.76-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
46
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$6.77-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-53.0h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
47
47
 
48
- - 🤖 **LLM usage:** $7.1945 (102 commits)
49
- - 👤 **Human dev:** ~$5242 (52.4h @ $100/h, 30min dedup)
48
+ - 🤖 **LLM usage:** $6.7652 (105 commits)
49
+ - 👤 **Human dev:** ~$5295 (53.0h @ $100/h, 30min dedup)
50
50
 
51
51
  Generated on 2026-07-17 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
52
52
 
53
53
  ---
54
54
 
55
- ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.74-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
55
+ ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.76-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
56
56
 
57
57
  **WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
58
58
 
@@ -3,17 +3,17 @@
3
3
 
4
4
  ## AI Cost Tracking
5
5
 
6
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.74-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
7
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$7.19-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-52.4h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
6
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.76-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
7
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$6.77-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-53.0h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
8
8
 
9
- - 🤖 **LLM usage:** $7.1945 (102 commits)
10
- - 👤 **Human dev:** ~$5242 (52.4h @ $100/h, 30min dedup)
9
+ - 🤖 **LLM usage:** $6.7652 (105 commits)
10
+ - 👤 **Human dev:** ~$5295 (53.0h @ $100/h, 30min dedup)
11
11
 
12
12
  Generated on 2026-07-17 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
13
13
 
14
14
  ---
15
15
 
16
- ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.74-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
16
+ ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.76-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
17
17
 
18
18
  **WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
19
19
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "wup"
7
- version = "0.2.74"
7
+ version = "0.2.76"
8
8
  description = "WUP (What's Up) - Intelligent file watcher for regression testing in large projects"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -96,6 +96,32 @@ def test_reject_prefixes_explicit_override() -> None:
96
96
  assert reject_prefixes_for_config(cfg) == ("/internal",)
97
97
 
98
98
 
99
+ def _prefix_matches(cfg, top: str) -> bool:
100
+ import re
101
+ from wup.core import WupWatcher
102
+
103
+ watcher = WupWatcher(project_root=".", config=cfg)
104
+ pat = "|".join(re.escape(p) for p in watcher._service_name_prefixes())
105
+ return bool(re.match(rf"^({pat})[-_]", top))
106
+
107
+
108
+ def test_service_prefix_generic_default() -> None:
109
+ cfg = validate_config({"project": {"name": "p"}})
110
+ assert _prefix_matches(cfg, "api-gateway") # generic prefix
111
+ assert not _prefix_matches(cfg, "connect-foo") # fleet prefix is opt-in
112
+
113
+
114
+ def test_service_prefix_connect_profile() -> None:
115
+ cfg = validate_config({"project": {"name": "p"}, "testql": {"service_map_profile": "connect"}})
116
+ assert _prefix_matches(cfg, "connect-foo")
117
+
118
+
119
+ def test_service_prefix_custom() -> None:
120
+ cfg = validate_config({"project": {"name": "p"}, "testql": {"service_name_prefixes": ["svc"]}})
121
+ assert _prefix_matches(cfg, "svc-auth")
122
+ assert not _prefix_matches(cfg, "connect-foo")
123
+
124
+
99
125
  def test_config_roundtrips_docker_service_map() -> None:
100
126
  raw = {
101
127
  "project": {"name": "p"},
@@ -7,7 +7,7 @@ WUP monitors file changes and runs intelligent regression tests using a 3-layer
7
7
  3. Detail Layer: Full tests with blame reports (only on failure)
8
8
  """
9
9
 
10
- __version__ = "0.2.74"
10
+ __version__ = "0.2.76"
11
11
  __author__ = "Tom Sapletta"
12
12
 
13
13
  from .config import load_config, save_config, get_default_config
@@ -233,6 +233,7 @@ def _parse_testql_config(raw: dict) -> TestQLConfig:
233
233
  docker_service_map=testql_raw.get("docker_service_map", {}),
234
234
  service_map_profile=testql_raw.get("service_map_profile", ""),
235
235
  monitoring_reject_prefixes=testql_raw.get("monitoring_reject_prefixes", []),
236
+ service_name_prefixes=testql_raw.get("service_name_prefixes", []),
236
237
  base_url=testql_raw.get("base_url", ""),
237
238
  api_base_url=testql_raw.get("api_base_url", ""),
238
239
  base_url_env=testql_raw.get("base_url_env", "WUP_BASE_URL"),
@@ -499,6 +500,7 @@ def save_config(config: WupConfig, output_path: Path):
499
500
  "docker_service_map": config.testql.docker_service_map,
500
501
  "service_map_profile": config.testql.service_map_profile,
501
502
  "monitoring_reject_prefixes": config.testql.monitoring_reject_prefixes,
503
+ "service_name_prefixes": config.testql.service_name_prefixes,
502
504
  "base_url": config.testql.base_url,
503
505
  "api_base_url": config.testql.api_base_url,
504
506
  "base_url_env": config.testql.base_url_env,
@@ -115,10 +115,22 @@ class WupWatcher:
115
115
  except ValueError:
116
116
  return file_path_obj
117
117
 
118
+ # Generic top-level directory prefixes that name a service on their own.
119
+ _GENERIC_SERVICE_PREFIXES = ("backend", "frontend", "api", "app", "worker", "service")
120
+
121
+ def _service_name_prefixes(self) -> List[str]:
122
+ """Effective service-name prefixes: generic set + config + profile."""
123
+ prefixes = list(self._GENERIC_SERVICE_PREFIXES)
124
+ testql = getattr(self.config, "testql", None)
125
+ prefixes.extend(getattr(testql, "service_name_prefixes", None) or [])
126
+ if (getattr(testql, "service_map_profile", "") or "").lower() == "connect":
127
+ prefixes.append("connect")
128
+ return prefixes
129
+
118
130
  def infer_service(self, file_path: str) -> Optional[str]:
119
131
  """
120
132
  Infer service name from file path.
121
-
133
+
122
134
  Uses config services first, then dependency mapper, then heuristics.
123
135
  """
124
136
  rel_path = self._to_relative_path(file_path)
@@ -144,12 +156,15 @@ class WupWatcher:
144
156
  if re.search(pattern, path_lower):
145
157
  return svc.name
146
158
 
147
- # Heuristic: if top-level directory matches known prefix patterns (e.g. connect-*)
148
- # use it directly as the service name — takes priority over stale deps.json
159
+ # Heuristic: if the top-level directory starts with a known service prefix
160
+ # (e.g. api-*, worker-*), use it directly — takes priority over stale
161
+ # deps.json. Prefixes are generic by default; projects add their own via
162
+ # testql.service_name_prefixes, and the "connect" profile adds connect-*.
149
163
  if parts:
150
164
  top = parts[0]
151
165
  import re as _re
152
- if _re.match(r'^(connect|backend|frontend|api|app|worker|service)[-_]', top):
166
+ prefixes = "|".join(_re.escape(p) for p in self._service_name_prefixes())
167
+ if prefixes and _re.match(rf'^({prefixes})[-_]', top):
153
168
  return top
154
169
 
155
170
  # Use dependency mapper if available
@@ -79,6 +79,9 @@ class TestQLConfig:
79
79
  # URL path prefixes that are NOT valid health probes (rejected in probe
80
80
  # discovery). Empty = accept everything (generic). Overrides the profile.
81
81
  monitoring_reject_prefixes: List[str] = field(default_factory=list)
82
+ # Extra top-level directory prefixes treated as a service name (added to the
83
+ # generic backend/frontend/api/app/worker/service set). Empty = generic only.
84
+ service_name_prefixes: List[str] = field(default_factory=list)
82
85
  base_url: str = ""
83
86
  api_base_url: str = "" # Core API (c2004: http://localhost:8101) — used for backend probes
84
87
  base_url_env: str = "WUP_BASE_URL"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wup
3
- Version: 0.2.74
3
+ Version: 0.2.76
4
4
  Summary: WUP (What's Up) - Intelligent file watcher for regression testing in large projects
5
5
  Author-email: Tom Sapletta <tom@sapletta.com>
6
6
  License-Expression: Apache-2.0
@@ -42,17 +42,17 @@ Dynamic: license-file
42
42
 
43
43
  ## AI Cost Tracking
44
44
 
45
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.74-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
46
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$7.19-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-52.4h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
45
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.76-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
46
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$6.77-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-53.0h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
47
47
 
48
- - 🤖 **LLM usage:** $7.1945 (102 commits)
49
- - 👤 **Human dev:** ~$5242 (52.4h @ $100/h, 30min dedup)
48
+ - 🤖 **LLM usage:** $6.7652 (105 commits)
49
+ - 👤 **Human dev:** ~$5295 (53.0h @ $100/h, 30min dedup)
50
50
 
51
51
  Generated on 2026-07-17 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
52
52
 
53
53
  ---
54
54
 
55
- ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.74-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
55
+ ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.76-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
56
56
 
57
57
  **WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
58
58
 
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