fastws-cli 0.0.18__tar.gz → 0.0.19__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastws-cli
3
- Version: 0.0.18
3
+ Version: 0.0.19
4
4
  Summary: Fast workspace tools for multi-repo management
5
5
  Author: Jeremy Howard
6
6
  License: Apache-2.0
@@ -208,7 +208,7 @@ By default, `ws-sync` uses the active venv's parent as the workspace root. It cr
208
208
 
209
209
  Project scanning respects `tool.uv.workspace.members` and `exclude`. If a member directory lacks `pyproject.toml`, such as a fresh empty clone, sync warns and skips the `uv sync` step.
210
210
 
211
- Fastws maintains `tool.uv.workspace.exclude`. It excludes unlisted top-level directories without a valid Python project. It also excludes listed Rust or JavaScript projects without `pyproject.toml`. For a listed checkout with none of `pyproject.toml`, `Cargo.toml`, or `package.json`, sync warns and skips installation.
211
+ Fastws maintains `tool.uv.workspace.exclude`. It excludes unlisted top-level directories without a valid Python project. It also excludes listed Rust or JavaScript projects without `pyproject.toml`. It also excludes listed project templates, whose `[project].name` still holds a `{placeholder}`, because uv cannot parse that name. For a listed checkout with none of `pyproject.toml`, `Cargo.toml`, or `package.json`, sync warns and skips installation.
212
212
 
213
213
  Existing globs, entries for missing directories, and entries for checkouts that are still not Python projects are retained. Use `exclude = [...]` under `[tool.fastws]` to specify exclusions the scan cannot infer, such as keeping a valid project out of the workspace. Adding members preserves hand-written `[tool.uv.sources]` entries, including path and Git sources.
214
214
 
@@ -183,7 +183,7 @@ By default, `ws-sync` uses the active venv's parent as the workspace root. It cr
183
183
 
184
184
  Project scanning respects `tool.uv.workspace.members` and `exclude`. If a member directory lacks `pyproject.toml`, such as a fresh empty clone, sync warns and skips the `uv sync` step.
185
185
 
186
- Fastws maintains `tool.uv.workspace.exclude`. It excludes unlisted top-level directories without a valid Python project. It also excludes listed Rust or JavaScript projects without `pyproject.toml`. For a listed checkout with none of `pyproject.toml`, `Cargo.toml`, or `package.json`, sync warns and skips installation.
186
+ Fastws maintains `tool.uv.workspace.exclude`. It excludes unlisted top-level directories without a valid Python project. It also excludes listed Rust or JavaScript projects without `pyproject.toml`. It also excludes listed project templates, whose `[project].name` still holds a `{placeholder}`, because uv cannot parse that name. For a listed checkout with none of `pyproject.toml`, `Cargo.toml`, or `package.json`, sync warns and skips installation.
187
187
 
188
188
  Existing globs, entries for missing directories, and entries for checkouts that are still not Python projects are retained. Use `exclude = [...]` under `[tool.fastws]` to specify exclusions the scan cannot infer, such as keeping a valid project out of the workspace. Adding members preserves hand-written `[tool.uv.sources]` entries, including path and Git sources.
189
189
 
@@ -1,4 +1,5 @@
1
- __version__ = "0.0.18"
1
+ __version__ = "0.0.19"
2
+
2
3
 
3
4
 
4
5
 
@@ -176,13 +176,21 @@ def _remove_from_pyproject(pyproject_path: Path, names: list[str]) -> list[str]:
176
176
  pyproject_path.write_text(content)
177
177
  return removed
178
178
 
179
- def _read_pyproject_name(path: Path) -> str|None:
179
+ def _pyproject_name(path: Path) -> str|None:
180
+ "`[project].name` as written, with any `{placeholder}` slots left in"
180
181
  try: data = tomllib.loads(path.read_text())
181
182
  except tomllib.TOMLDecodeError:
182
183
  print(f"Skipping invalid TOML: {path}")
183
184
  return None
184
185
  name = data.get("project", {}).get("name")
185
- return name if isinstance(name, str) and name and "{" not in name and "}" not in name else None
186
+ return name if isinstance(name, str) and name else None
187
+
188
+ def _is_placeholder(name: str|None) -> bool: return bool(name) and ("{" in name or "}" in name)
189
+
190
+ def _read_pyproject_name(path: Path) -> str|None:
191
+ "`[project].name`, or None when it is missing or still a template placeholder"
192
+ name = _pyproject_name(path)
193
+ return None if _is_placeholder(name) else name
186
194
 
187
195
  def _ws_projects(root: Path) -> list[str]:
188
196
  return [name for d in (o for o in _ws_dirs(root) if (o/"pyproject.toml").exists())
@@ -208,6 +216,10 @@ def _non_python_project(d: Path) -> bool:
208
216
  "A Rust or JS project without a Python layer is not a pending Python scaffold."
209
217
  return not (d/"pyproject.toml").exists() and any((d/f).exists() for f in ("Cargo.toml", "package.json"))
210
218
 
219
+ def _template_dir(d: Path) -> bool:
220
+ "A project template. Its `[project].name` still holds `{placeholder}` slots, so uv cannot parse it."
221
+ return (d/"pyproject.toml").exists() and _is_placeholder(_pyproject_name(d/"pyproject.toml"))
222
+
211
223
  def _pending_dirs(root: Path) -> list[str]:
212
224
  "uv workspace dirs that are not Python projects yet; sync stops rather than let uv fail on them"
213
225
  return [d.name for d in _ws_dirs(root) if not (d/"pyproject.toml").exists()]
@@ -218,7 +230,7 @@ def _sync_ws_excludes(pyproject_path: Path, root: Path, tracked: set[str]) -> tu
218
230
  Kept as-is: `[tool.fastws].exclude` entries (intent), globs, missing dirs, and tracked dirs
219
231
  (repos.txt checkouts) that are still not valid Python projects. Auto-managed: entries for other
220
232
  existing dirs are regenerated each sync, excluding dirs without a valid pyproject (tracked dirs
221
- only when they are Cargo-only crates or npm-only packages, since a tracked dir with none of those files is a pending member
233
+ only when they are Cargo-only crates, npm-only packages, or templates with a `{placeholder}` name, since a tracked dir with none of those files is a pending member
222
234
  awaiting scaffolding) and un-excluding dirs that gained one; deliberately excluding a real
223
235
  project takes a `[tool.fastws]` entry."""
224
236
  if not pyproject_path.exists(): return [], []
@@ -231,7 +243,7 @@ def _sync_ws_excludes(pyproject_path: Path, root: Path, tracked: set[str]) -> tu
231
243
  kept = [e for e in cur if e in intent or any(c in e for c in "*?[") or not (root/e).is_dir() or (e in tracked and not _valid_project_dir(root/e))]
232
244
  kept += [e for e in intent if e not in kept]
233
245
  auto = [d.name for d in _project_dirs(root, exclude=kept) if not d.name.startswith(".") and any(_matches_ws(d.name, m) for m in members)
234
- and (d.name not in tracked or _non_python_project(d)) and not _valid_project_dir(d)]
246
+ and (d.name not in tracked or _non_python_project(d) or _template_dir(d)) and not _valid_project_dir(d)]
235
247
  survivors = set(kept) | set(auto)
236
248
  new = [e for e in cur if e in survivors] + [e for e in kept + auto if e not in cur]
237
249
  if new == cur: return [], []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastws-cli
3
- Version: 0.0.18
3
+ Version: 0.0.19
4
4
  Summary: Fast workspace tools for multi-repo management
5
5
  Author: Jeremy Howard
6
6
  License: Apache-2.0
@@ -208,7 +208,7 @@ By default, `ws-sync` uses the active venv's parent as the workspace root. It cr
208
208
 
209
209
  Project scanning respects `tool.uv.workspace.members` and `exclude`. If a member directory lacks `pyproject.toml`, such as a fresh empty clone, sync warns and skips the `uv sync` step.
210
210
 
211
- Fastws maintains `tool.uv.workspace.exclude`. It excludes unlisted top-level directories without a valid Python project. It also excludes listed Rust or JavaScript projects without `pyproject.toml`. For a listed checkout with none of `pyproject.toml`, `Cargo.toml`, or `package.json`, sync warns and skips installation.
211
+ Fastws maintains `tool.uv.workspace.exclude`. It excludes unlisted top-level directories without a valid Python project. It also excludes listed Rust or JavaScript projects without `pyproject.toml`. It also excludes listed project templates, whose `[project].name` still holds a `{placeholder}`, because uv cannot parse that name. For a listed checkout with none of `pyproject.toml`, `Cargo.toml`, or `package.json`, sync warns and skips installation.
212
212
 
213
213
  Existing globs, entries for missing directories, and entries for checkouts that are still not Python projects are retained. Use `exclude = [...]` under `[tool.fastws]` to specify exclusions the scan cannot infer, such as keeping a valid project out of the workspace. Adding members preserves hand-written `[tool.uv.sources]` entries, including path and Git sources.
214
214
 
@@ -123,19 +123,19 @@ def test_ws_excludes_generates_from_intent_and_auto(tmp_path):
123
123
  pyproject.write_text(
124
124
  '[project]\nname = "uvws"\n\n[tool.uv.workspace]\nmembers = ["./*"]\n'
125
125
  'exclude = ["_*", "tmp", "example", "stale", "pending"]\n\n[tool.fastws]\nexclude = ["wanted-out"]\n')
126
- for name in ('junk', 'fresh-clone', 'realpkg', 'tmpl', 'example', 'stale', 'wanted-out', 'pending', 'rustcrate'): (tmp_path/name).mkdir()
126
+ for name in ('junk', 'fresh-clone', 'realpkg', 'tmpl', 'tracked-tmpl', 'example', 'stale', 'wanted-out', 'pending', 'rustcrate'): (tmp_path/name).mkdir()
127
127
  (tmp_path/'realpkg'/'pyproject.toml').write_text('[project]\nname = "realpkg"\n')
128
- (tmp_path/'tmpl'/'pyproject.toml').write_text('[project]\nname = "{repo}"\n')
128
+ for name in ('tmpl', 'tracked-tmpl'): (tmp_path/name/'pyproject.toml').write_text('[project]\nname = "{repo}"\n')
129
129
  (tmp_path/'rustcrate'/'Cargo.toml').write_text('[package]\nname = "rustcrate"\n')
130
130
  for name in ('example', 'stale', 'wanted-out'): (tmp_path/name/'pyproject.toml').write_text(f'[project]\nname = "{name}"\n')
131
131
 
132
- tracked = {'fresh-clone', 'example', 'pending', 'rustcrate'}
132
+ tracked = {'fresh-clone', 'example', 'pending', 'rustcrate', 'tracked-tmpl'}
133
133
  added, removed = core._sync_ws_excludes(pyproject, tmp_path, tracked)
134
134
  data = core.tomllib.loads(pyproject.read_text())
135
135
 
136
- # kept: glob, missing dir, tracked non-project; auto: junk, placeholder tmpl, tracked Cargo-only crate; intent: wanted-out; dropped: valid projects, tracked or not
137
- assert set(data['tool']['uv']['workspace']['exclude']) == {'_*', 'tmp', 'pending', 'wanted-out', 'junk', 'tmpl', 'rustcrate'}
138
- assert set(added) == {'wanted-out', 'junk', 'tmpl', 'rustcrate'}
136
+ # kept: glob, missing dir, tracked non-project; auto: junk, placeholder templates tracked or not, tracked Cargo-only crate; intent: wanted-out; dropped: valid projects, tracked or not
137
+ assert set(data['tool']['uv']['workspace']['exclude']) == {'_*', 'tmp', 'pending', 'wanted-out', 'junk', 'tmpl', 'tracked-tmpl', 'rustcrate'}
138
+ assert set(added) == {'wanted-out', 'junk', 'tmpl', 'tracked-tmpl', 'rustcrate'}
139
139
  assert set(removed) == {'example', 'stale'}
140
140
  assert data['tool']['fastws']['exclude'] == ['wanted-out'] # fastws table untouched
141
141
 
File without changes
File without changes
File without changes