worklogs 0.2.0__tar.gz → 0.2.1__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: worklogs
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Local markdown worklog helpers for developer workflows.
5
5
  Project-URL: Homepage, https://github.com/alik-git/worklogs
6
6
  Project-URL: Repository, https://github.com/alik-git/worklogs
@@ -99,6 +99,41 @@ Print created paths for scripts:
99
99
  worklogs new note--personal-site--theme-ideas --scope personal --print-path
100
100
  ```
101
101
 
102
+ Create a dated project workset directory:
103
+
104
+ ```bash
105
+ worklogs workset new backend-api-refactor --worksets-root ~/worksets
106
+ ```
107
+
108
+ Create a dated workset under organizer folders:
109
+
110
+ ```bash
111
+ worklogs workset new release-tools/python-packaging/worklogs-0.2.1 \
112
+ --worksets-root ~/worksets
113
+ ```
114
+
115
+ Worksets are created under:
116
+
117
+ ```text
118
+ <worksets-root>/YYYY/MM/DD/<workset-path>/
119
+ ```
120
+
121
+ Preview a workset path without creating it:
122
+
123
+ ```bash
124
+ worklogs workset new release-tools/python-packaging/worklogs-0.2.1 \
125
+ --worksets-root ~/worksets \
126
+ --dry-run
127
+ ```
128
+
129
+ Print only the created path for scripts:
130
+
131
+ ```bash
132
+ worklogs workset new backend-api-refactor \
133
+ --worksets-root ~/worksets \
134
+ --print-path
135
+ ```
136
+
102
137
  Supported kinds:
103
138
 
104
139
  ```text
@@ -122,13 +157,14 @@ Example:
122
157
  root = "~/worklog"
123
158
  default_scope = "work"
124
159
  timezone = "America/Toronto"
160
+ worksets_root = "~/worksets"
125
161
  ```
126
162
 
127
163
  Resolution order:
128
164
 
129
165
  1. CLI flags
130
166
  2. environment variables: `WORKLOG_ROOT`, `WORKLOG_SCOPE`,
131
- `WORKLOG_TIMEZONE`
167
+ `WORKLOG_TIMEZONE`, `WORKLOG_WORKSETS_ROOT`
132
168
  3. config file
133
169
  4. package defaults
134
170
 
@@ -138,6 +174,12 @@ With `default_scope` configured, the fast path can omit `--scope`:
138
174
  worklogs new plan--backend-api--improve-deploy-notes
139
175
  ```
140
176
 
177
+ With `worksets_root` configured, the workset path can omit `--worksets-root`:
178
+
179
+ ```bash
180
+ worklogs workset new backend-api-refactor
181
+ ```
182
+
141
183
  For shorter personal shell usage, add a local alias:
142
184
 
143
185
  ```bash
@@ -196,9 +238,9 @@ Environment name: pypi
196
238
  Create a GitHub Release for the version in [`pyproject.toml`](pyproject.toml):
197
239
 
198
240
  ```bash
199
- gh release create v0.2.0 \
200
- --title "v0.2.0" \
201
- --notes "Add worklog file creation commands."
241
+ gh release create v0.2.1 \
242
+ --title "v0.2.1" \
243
+ --notes "Add dated workset directory creation."
202
244
  ```
203
245
 
204
246
  Publishing is release-driven on purpose: normal pushes and pull requests build
@@ -72,6 +72,41 @@ Print created paths for scripts:
72
72
  worklogs new note--personal-site--theme-ideas --scope personal --print-path
73
73
  ```
74
74
 
75
+ Create a dated project workset directory:
76
+
77
+ ```bash
78
+ worklogs workset new backend-api-refactor --worksets-root ~/worksets
79
+ ```
80
+
81
+ Create a dated workset under organizer folders:
82
+
83
+ ```bash
84
+ worklogs workset new release-tools/python-packaging/worklogs-0.2.1 \
85
+ --worksets-root ~/worksets
86
+ ```
87
+
88
+ Worksets are created under:
89
+
90
+ ```text
91
+ <worksets-root>/YYYY/MM/DD/<workset-path>/
92
+ ```
93
+
94
+ Preview a workset path without creating it:
95
+
96
+ ```bash
97
+ worklogs workset new release-tools/python-packaging/worklogs-0.2.1 \
98
+ --worksets-root ~/worksets \
99
+ --dry-run
100
+ ```
101
+
102
+ Print only the created path for scripts:
103
+
104
+ ```bash
105
+ worklogs workset new backend-api-refactor \
106
+ --worksets-root ~/worksets \
107
+ --print-path
108
+ ```
109
+
75
110
  Supported kinds:
76
111
 
77
112
  ```text
@@ -95,13 +130,14 @@ Example:
95
130
  root = "~/worklog"
96
131
  default_scope = "work"
97
132
  timezone = "America/Toronto"
133
+ worksets_root = "~/worksets"
98
134
  ```
99
135
 
100
136
  Resolution order:
101
137
 
102
138
  1. CLI flags
103
139
  2. environment variables: `WORKLOG_ROOT`, `WORKLOG_SCOPE`,
104
- `WORKLOG_TIMEZONE`
140
+ `WORKLOG_TIMEZONE`, `WORKLOG_WORKSETS_ROOT`
105
141
  3. config file
106
142
  4. package defaults
107
143
 
@@ -111,6 +147,12 @@ With `default_scope` configured, the fast path can omit `--scope`:
111
147
  worklogs new plan--backend-api--improve-deploy-notes
112
148
  ```
113
149
 
150
+ With `worksets_root` configured, the workset path can omit `--worksets-root`:
151
+
152
+ ```bash
153
+ worklogs workset new backend-api-refactor
154
+ ```
155
+
114
156
  For shorter personal shell usage, add a local alias:
115
157
 
116
158
  ```bash
@@ -169,9 +211,9 @@ Environment name: pypi
169
211
  Create a GitHub Release for the version in [`pyproject.toml`](pyproject.toml):
170
212
 
171
213
  ```bash
172
- gh release create v0.2.0 \
173
- --title "v0.2.0" \
174
- --notes "Add worklog file creation commands."
214
+ gh release create v0.2.1 \
215
+ --title "v0.2.1" \
216
+ --notes "Add dated workset directory creation."
175
217
  ```
176
218
 
177
219
  Publishing is release-driven on purpose: normal pushes and pull requests build
@@ -9,5 +9,11 @@ Use `worklogs new` to create dated markdown worklog files:
9
9
  worklogs new plan--backend-api--improve-deploy-notes --scope work
10
10
  ```
11
11
 
12
+ Use `worklogs workset new` to create dated project workset directories:
13
+
14
+ ```bash
15
+ worklogs workset new backend-api-refactor --worksets-root ~/worksets
16
+ ```
17
+
12
18
  Public Python helpers will be documented here if the package grows a stable API
13
19
  outside the CLI.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "worklogs"
7
- version = "0.2.0"
7
+ version = "0.2.1"
8
8
  description = "Local markdown worklog helpers for developer workflows."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -2,6 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "0.2.0"
5
+ __version__ = "0.2.1"
6
6
 
7
7
  __all__ = ["__version__"]
@@ -8,7 +8,7 @@ import re
8
8
  import sys
9
9
  import tomllib
10
10
  from dataclasses import dataclass
11
- from datetime import UTC, datetime, tzinfo
11
+ from datetime import UTC, date, datetime, tzinfo
12
12
  from pathlib import Path
13
13
  from typing import TYPE_CHECKING
14
14
  from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
@@ -55,6 +55,14 @@ class WorklogConfig:
55
55
  timezone: tzinfo
56
56
 
57
57
 
58
+ @dataclass(frozen=True)
59
+ class WorksetConfig:
60
+ """Resolved user defaults for workset directory creation."""
61
+
62
+ root: Path
63
+ timezone: tzinfo
64
+
65
+
58
66
  @dataclass(frozen=True)
59
67
  class WorklogEntry:
60
68
  """A worklog file that should be created."""
@@ -122,6 +130,51 @@ def build_parser() -> argparse.ArgumentParser:
122
130
  action="store_true",
123
131
  help="print created path or paths",
124
132
  )
133
+
134
+ workset_parser = subparsers.add_parser(
135
+ "workset",
136
+ help="create and maintain project workset directories",
137
+ description="Create and maintain project workset directories.",
138
+ )
139
+ workset_subparsers = workset_parser.add_subparsers(
140
+ dest="workset_command",
141
+ required=True,
142
+ )
143
+ workset_new_parser = workset_subparsers.add_parser(
144
+ "new",
145
+ help="create a dated project workset directory",
146
+ description="Create a dated project workset directory.",
147
+ )
148
+ workset_new_parser.add_argument(
149
+ "path",
150
+ metavar="PATH",
151
+ help="relative workset path under YYYY/MM/DD, for example app/refactor",
152
+ )
153
+ workset_new_parser.add_argument(
154
+ "--worksets-root",
155
+ metavar="PATH",
156
+ help="root directory for dated workset folders",
157
+ )
158
+ workset_new_parser.add_argument(
159
+ "--timezone",
160
+ metavar="ZONE",
161
+ help="IANA timezone name used when choosing today's date",
162
+ )
163
+ workset_new_parser.add_argument(
164
+ "--date",
165
+ metavar="YYYY-MM-DD",
166
+ help="explicit date for reproducible workset creation",
167
+ )
168
+ workset_new_parser.add_argument(
169
+ "--dry-run",
170
+ action="store_true",
171
+ help="print the intended path without creating it",
172
+ )
173
+ workset_new_parser.add_argument(
174
+ "--print-path",
175
+ action="store_true",
176
+ help="print only the created or intended path",
177
+ )
125
178
  return parser
126
179
 
127
180
 
@@ -137,6 +190,8 @@ def main(argv: Sequence[str] | None = None) -> int:
137
190
  try:
138
191
  if args.command == "new":
139
192
  return _run_new(args)
193
+ if args.command == "workset" and args.workset_command == "new":
194
+ return _run_workset_new(args)
140
195
  except WorklogsError as error:
141
196
  print(f"worklogs: error: {error}", file=sys.stderr)
142
197
  return 2
@@ -176,6 +231,34 @@ def _run_new(args: argparse.Namespace) -> int:
176
231
  return 0
177
232
 
178
233
 
234
+ def _run_workset_new(args: argparse.Namespace) -> int:
235
+ config = _resolve_workset_config(args, os.environ)
236
+ workset_date = _resolve_workset_date(args.date, config.timezone)
237
+ path_parts = _parse_workset_path(args.path)
238
+ workset_path = _build_workset_path(
239
+ config=config,
240
+ workset_date=workset_date,
241
+ path_parts=path_parts,
242
+ )
243
+
244
+ if args.dry_run:
245
+ if args.print_path:
246
+ print(workset_path)
247
+ else:
248
+ print("Would create workset:")
249
+ print(workset_path)
250
+ return 0
251
+
252
+ created = _create_workset_directory(workset_path)
253
+ if args.print_path:
254
+ print(workset_path)
255
+ elif created:
256
+ print(f"Created workset directory: {workset_path}")
257
+ else:
258
+ print(f"Workset directory already exists and is empty: {workset_path}")
259
+ return 0
260
+
261
+
179
262
  def _resolve_identity(args: argparse.Namespace) -> WorklogIdentity:
180
263
  explicit_fields = (args.kind, args.project, args.slug)
181
264
  has_explicit_fields = any(value is not None for value in explicit_fields)
@@ -267,6 +350,35 @@ def _resolve_config(
267
350
  )
268
351
 
269
352
 
353
+ def _resolve_workset_config(
354
+ args: argparse.Namespace,
355
+ environment: Mapping[str, str],
356
+ ) -> WorksetConfig:
357
+ file_config = _load_config()
358
+
359
+ root_value = _first_string(
360
+ args.worksets_root,
361
+ environment.get("WORKLOG_WORKSETS_ROOT"),
362
+ file_config.get("worksets_root"),
363
+ )
364
+ if root_value is None:
365
+ msg = (
366
+ "worksets root is required; set --worksets-root, "
367
+ "WORKLOG_WORKSETS_ROOT, or worksets_root in config"
368
+ )
369
+ raise WorklogsError(msg)
370
+
371
+ timezone_value = _first_string(
372
+ args.timezone,
373
+ environment.get("WORKLOG_TIMEZONE"),
374
+ file_config.get("timezone"),
375
+ )
376
+ return WorksetConfig(
377
+ root=Path(root_value).expanduser(),
378
+ timezone=_resolve_timezone(timezone_value),
379
+ )
380
+
381
+
270
382
  def _load_config() -> dict[str, str]:
271
383
  config_path = CONFIG_PATH.expanduser()
272
384
  if not config_path.exists():
@@ -283,7 +395,7 @@ def _load_config() -> dict[str, str]:
283
395
  raise WorklogsError(msg) from error
284
396
 
285
397
  config: dict[str, str] = {}
286
- for key in ("root", "default_scope", "timezone"):
398
+ for key in ("root", "default_scope", "timezone", "worksets_root"):
287
399
  value = raw_config.get(key)
288
400
  if value is None:
289
401
  continue
@@ -311,6 +423,77 @@ def _resolve_timezone(timezone_name: str | None) -> tzinfo:
311
423
  raise WorklogsError(msg) from error
312
424
 
313
425
 
426
+ def _resolve_workset_date(value: str | None, timezone: tzinfo) -> date:
427
+ if value is None:
428
+ return datetime.now(UTC).astimezone(timezone).date()
429
+ try:
430
+ return date.fromisoformat(value)
431
+ except ValueError as error:
432
+ msg = f"invalid date {value!r}; expected YYYY-MM-DD"
433
+ raise WorklogsError(msg) from error
434
+
435
+
436
+ def _parse_workset_path(value: str) -> tuple[str, ...]:
437
+ if not value:
438
+ msg = "workset path cannot be empty"
439
+ raise WorklogsError(msg)
440
+ if Path(value).is_absolute():
441
+ msg = "workset path must be relative"
442
+ raise WorklogsError(msg)
443
+
444
+ parts = tuple(value.split("/"))
445
+ for part in parts:
446
+ if part in {"", ".", ".."}:
447
+ msg = "workset path cannot contain empty, '.', or '..' components"
448
+ raise WorklogsError(msg)
449
+ if not SLUG_PATTERN.fullmatch(part):
450
+ msg = (
451
+ "workset path components must start with a lowercase letter or "
452
+ "digit and contain only lowercase letters, digits, dots, "
453
+ "underscores, or hyphens"
454
+ )
455
+ raise WorklogsError(msg)
456
+ return parts
457
+
458
+
459
+ def _build_workset_path(
460
+ *,
461
+ config: WorksetConfig,
462
+ workset_date: date,
463
+ path_parts: Sequence[str],
464
+ ) -> Path:
465
+ return (
466
+ config.root
467
+ / f"{workset_date:%Y}"
468
+ / f"{workset_date:%m}"
469
+ / f"{workset_date:%d}"
470
+ / Path(*path_parts)
471
+ )
472
+
473
+
474
+ def _create_workset_directory(path: Path) -> bool:
475
+ if path.exists():
476
+ if not path.is_dir():
477
+ msg = f"workset path exists but is not a directory: {path}"
478
+ raise WorklogsError(msg)
479
+ try:
480
+ has_contents = next(path.iterdir(), None) is not None
481
+ except OSError as error:
482
+ msg = f"could not inspect existing workset directory {path}: {error}"
483
+ raise WorklogsError(msg) from error
484
+ if has_contents:
485
+ msg = f"refusing to use existing non-empty workset directory: {path}"
486
+ raise WorklogsError(msg)
487
+ return False
488
+
489
+ try:
490
+ path.mkdir(parents=True)
491
+ except OSError as error:
492
+ msg = f"could not create workset directory {path}: {error}"
493
+ raise WorklogsError(msg) from error
494
+ return True
495
+
496
+
314
497
  def _build_entries(
315
498
  *,
316
499
  identity: WorklogIdentity,
@@ -14,8 +14,11 @@ from worklogs.cli import (
14
14
  WorklogEntry,
15
15
  WorklogIdentity,
16
16
  WorklogsError,
17
+ WorksetConfig,
17
18
  _build_entries,
19
+ _build_workset_path,
18
20
  _parse_identity_token,
21
+ _parse_workset_path,
19
22
  _write_entries,
20
23
  main,
21
24
  )
@@ -26,7 +29,7 @@ if TYPE_CHECKING:
26
29
 
27
30
  def test_version_is_exposed() -> None:
28
31
  """Verify the package exposes its current version."""
29
- assert worklogs.__version__ == "0.2.0"
32
+ assert worklogs.__version__ == "0.2.1"
30
33
 
31
34
 
32
35
  def test_cli_accepts_no_arguments() -> None:
@@ -210,6 +213,185 @@ def test_dry_run_writes_nothing(
210
213
  assert not root.exists()
211
214
 
212
215
 
216
+ def test_workset_new_uses_config_root_and_explicit_date(
217
+ tmp_path: Path,
218
+ monkeypatch: pytest.MonkeyPatch,
219
+ capsys: pytest.CaptureFixture[str],
220
+ ) -> None:
221
+ """Verify workset creation uses the configured root and dated layout."""
222
+ worksets_root = tmp_path / "Projects" / "worksets"
223
+ _write_config(
224
+ tmp_path,
225
+ monkeypatch,
226
+ root=tmp_path / "worklog",
227
+ default_scope="work",
228
+ worksets_root=worksets_root,
229
+ )
230
+
231
+ assert (
232
+ main(
233
+ [
234
+ "workset",
235
+ "new",
236
+ "release-tools/worklogs-0.2.1",
237
+ "--date",
238
+ "2026-05-29",
239
+ ]
240
+ )
241
+ == 0
242
+ )
243
+
244
+ created_path = (
245
+ worksets_root / "2026" / "05" / "29" / "release-tools" / "worklogs-0.2.1"
246
+ )
247
+ assert created_path.is_dir()
248
+ assert f"Created workset directory: {created_path}" in capsys.readouterr().out
249
+
250
+
251
+ def test_workset_new_dry_run_writes_nothing(
252
+ tmp_path: Path,
253
+ monkeypatch: pytest.MonkeyPatch,
254
+ capsys: pytest.CaptureFixture[str],
255
+ ) -> None:
256
+ """Verify workset dry-run prints the intended path without writing."""
257
+ _isolate_home(tmp_path, monkeypatch)
258
+ worksets_root = tmp_path / "worksets"
259
+
260
+ assert (
261
+ main(
262
+ [
263
+ "workset",
264
+ "new",
265
+ "release-tools/python-packaging/worklogs-0.2.1",
266
+ "--worksets-root",
267
+ str(worksets_root),
268
+ "--date",
269
+ "2026-05-29",
270
+ "--dry-run",
271
+ ]
272
+ )
273
+ == 0
274
+ )
275
+
276
+ output = capsys.readouterr().out
277
+ assert "Would create workset:" in output
278
+ assert (
279
+ str(
280
+ worksets_root
281
+ / "2026"
282
+ / "05"
283
+ / "29"
284
+ / "release-tools"
285
+ / "python-packaging"
286
+ / "worklogs-0.2.1"
287
+ )
288
+ in output
289
+ )
290
+ assert not worksets_root.exists()
291
+
292
+
293
+ def test_workset_new_print_path_is_script_friendly(
294
+ tmp_path: Path,
295
+ monkeypatch: pytest.MonkeyPatch,
296
+ capsys: pytest.CaptureFixture[str],
297
+ ) -> None:
298
+ """Verify --print-path prints only the created workset path."""
299
+ _isolate_home(tmp_path, monkeypatch)
300
+ worksets_root = tmp_path / "worksets"
301
+
302
+ assert (
303
+ main(
304
+ [
305
+ "workset",
306
+ "new",
307
+ "worklogs-0.2.1",
308
+ "--worksets-root",
309
+ str(worksets_root),
310
+ "--date",
311
+ "2026-05-29",
312
+ "--print-path",
313
+ ]
314
+ )
315
+ == 0
316
+ )
317
+
318
+ expected_path = worksets_root / "2026" / "05" / "29" / "worklogs-0.2.1"
319
+ assert capsys.readouterr().out == f"{expected_path}\n"
320
+ assert expected_path.is_dir()
321
+
322
+
323
+ def test_workset_new_refuses_existing_non_empty_directory(
324
+ tmp_path: Path,
325
+ monkeypatch: pytest.MonkeyPatch,
326
+ capsys: pytest.CaptureFixture[str],
327
+ ) -> None:
328
+ """Verify workset creation refuses to reuse non-empty directories."""
329
+ _isolate_home(tmp_path, monkeypatch)
330
+ worksets_root = tmp_path / "worksets"
331
+ existing_path = worksets_root / "2026" / "05" / "29" / "worklogs-0.2.1"
332
+ existing_path.mkdir(parents=True)
333
+ (existing_path / "README.md").write_text("existing\n", encoding="utf-8")
334
+
335
+ assert (
336
+ main(
337
+ [
338
+ "workset",
339
+ "new",
340
+ "worklogs-0.2.1",
341
+ "--worksets-root",
342
+ str(worksets_root),
343
+ "--date",
344
+ "2026-05-29",
345
+ ]
346
+ )
347
+ == 2
348
+ )
349
+ assert "existing non-empty workset directory" in capsys.readouterr().err
350
+
351
+
352
+ def test_workset_new_requires_configured_root(
353
+ tmp_path: Path,
354
+ monkeypatch: pytest.MonkeyPatch,
355
+ capsys: pytest.CaptureFixture[str],
356
+ ) -> None:
357
+ """Verify workset creation does not guess a local machine default."""
358
+ _isolate_home(tmp_path, monkeypatch)
359
+
360
+ assert main(["workset", "new", "worklogs-0.2.1", "--date", "2026-05-29"]) == 2
361
+ assert "worksets root is required" in capsys.readouterr().err
362
+
363
+
364
+ def test_parse_workset_path_rejects_unsafe_components() -> None:
365
+ """Verify workset path parsing rejects absolute or escaping paths."""
366
+ for value in (
367
+ "/absolute/workset",
368
+ "release-tools/../workset",
369
+ "release-tools//workset",
370
+ ):
371
+ with pytest.raises(WorklogsError):
372
+ _parse_workset_path(value)
373
+
374
+
375
+ def test_build_workset_path_renders_date_folders(tmp_path: Path) -> None:
376
+ """Verify workset paths include YYYY/MM/DD before organizer folders."""
377
+ workset_path = _build_workset_path(
378
+ config=WorksetConfig(root=tmp_path / "worksets", timezone=ZoneInfo("UTC")),
379
+ workset_date=datetime(2026, 5, 29, tzinfo=ZoneInfo("UTC")).date(),
380
+ path_parts=("release-tools", "worklogs-0.2.1"),
381
+ )
382
+
383
+ assert (
384
+ workset_path
385
+ == tmp_path
386
+ / "worksets"
387
+ / "2026"
388
+ / "05"
389
+ / "29"
390
+ / "release-tools"
391
+ / "worklogs-0.2.1"
392
+ )
393
+
394
+
213
395
  def test_scope_is_required_without_config_or_flag(
214
396
  tmp_path: Path,
215
397
  monkeypatch: pytest.MonkeyPatch,
@@ -249,16 +431,19 @@ def _write_config(
249
431
  *,
250
432
  root: Path,
251
433
  default_scope: str,
434
+ worksets_root: Path | None = None,
252
435
  ) -> None:
253
436
  home = _isolate_home(tmp_path, monkeypatch)
254
437
  config_path = home / ".config" / "worklogs" / "config.toml"
255
438
  config_path.parent.mkdir(parents=True)
256
- config_path.write_text(
257
- f'root = "{root}"\n'
258
- f'default_scope = "{default_scope}"\n'
259
- 'timezone = "America/Toronto"\n',
260
- encoding="utf-8",
261
- )
439
+ lines = [
440
+ f'root = "{root}"',
441
+ f'default_scope = "{default_scope}"',
442
+ 'timezone = "America/Toronto"',
443
+ ]
444
+ if worksets_root is not None:
445
+ lines.append(f'worksets_root = "{worksets_root}"')
446
+ config_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
262
447
 
263
448
 
264
449
  def _isolate_home(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
@@ -268,4 +453,5 @@ def _isolate_home(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
268
453
  monkeypatch.delenv("WORKLOG_ROOT", raising=False)
269
454
  monkeypatch.delenv("WORKLOG_SCOPE", raising=False)
270
455
  monkeypatch.delenv("WORKLOG_TIMEZONE", raising=False)
456
+ monkeypatch.delenv("WORKLOG_WORKSETS_ROOT", raising=False)
271
457
  return home
@@ -420,7 +420,7 @@ wheels = [
420
420
 
421
421
  [[package]]
422
422
  name = "worklogs"
423
- version = "0.2.0"
423
+ version = "0.2.1"
424
424
  source = { editable = "." }
425
425
 
426
426
  [package.optional-dependencies]
File without changes
File without changes
File without changes
File without changes