file-groups 0.3.1__tar.gz → 0.4.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. {file_groups-0.3.1 → file_groups-0.4.0}/.copier-answers.yml +1 -1
  2. {file_groups-0.3.1 → file_groups-0.4.0}/PKG-INFO +3 -4
  3. {file_groups-0.3.1 → file_groups-0.4.0}/file_groups.egg-info/PKG-INFO +3 -4
  4. {file_groups-0.3.1 → file_groups-0.4.0}/noxfile.py +2 -2
  5. {file_groups-0.3.1 → file_groups-0.4.0}/setup.cfg +1 -2
  6. {file_groups-0.3.1 → file_groups-0.4.0}/src/__init__.py +1 -1
  7. {file_groups-0.3.1 → file_groups-0.4.0}/src/config_files.py +5 -5
  8. {file_groups-0.3.1 → file_groups-0.4.0}/src/groups.py +7 -7
  9. {file_groups-0.3.1 → file_groups-0.4.0}/src/handler.py +16 -22
  10. {file_groups-0.3.1 → file_groups-0.4.0}/src/handler_compare.py +1 -1
  11. file_groups-0.4.0/src/types.py +5 -0
  12. {file_groups-0.3.1 → file_groups-0.4.0}/test/groups/utils.py +1 -1
  13. {file_groups-0.3.1 → file_groups-0.4.0}/test/handler/core_test.py +5 -6
  14. file_groups-0.3.1/src/types.py +0 -6
  15. {file_groups-0.3.1 → file_groups-0.4.0}/.gitignore +0 -0
  16. {file_groups-0.3.1 → file_groups-0.4.0}/.pylintrc +0 -0
  17. {file_groups-0.3.1 → file_groups-0.4.0}/LICENSE.txt +0 -0
  18. {file_groups-0.3.1 → file_groups-0.4.0}/README.rst +0 -0
  19. {file_groups-0.3.1 → file_groups-0.4.0}/file_groups.egg-info/SOURCES.txt +0 -0
  20. {file_groups-0.3.1 → file_groups-0.4.0}/file_groups.egg-info/dependency_links.txt +0 -0
  21. {file_groups-0.3.1 → file_groups-0.4.0}/file_groups.egg-info/requires.txt +0 -0
  22. {file_groups-0.3.1 → file_groups-0.4.0}/file_groups.egg-info/top_level.txt +0 -0
  23. {file_groups-0.3.1 → file_groups-0.4.0}/file_groups.egg-info/zip-safe +0 -0
  24. {file_groups-0.3.1 → file_groups-0.4.0}/pyproject.toml +0 -0
  25. {file_groups-0.3.1 → file_groups-0.4.0}/pytest.ini +0 -0
  26. {file_groups-0.3.1 → file_groups-0.4.0}/setup.py +0 -0
  27. {file_groups-0.3.1 → file_groups-0.4.0}/src/compare_files.py +0 -0
  28. {file_groups-0.3.1 → file_groups-0.4.0}/src/py.typed +0 -0
  29. {file_groups-0.3.1 → file_groups-0.4.0}/test/.coveragerc +0 -0
  30. {file_groups-0.3.1 → file_groups-0.4.0}/test/__init__.py +0 -0
  31. {file_groups-0.3.1 → file_groups-0.4.0}/test/compare_files_test.py +0 -0
  32. {file_groups-0.3.1 → file_groups-0.4.0}/test/config_files_test.py +0 -0
  33. {file_groups-0.3.1 → file_groups-0.4.0}/test/conftest.py +0 -0
  34. {file_groups-0.3.1 → file_groups-0.4.0}/test/groups/__init__.py +0 -0
  35. {file_groups-0.3.1 → file_groups-0.4.0}/test/groups/config_files_test.py +0 -0
  36. {file_groups-0.3.1 → file_groups-0.4.0}/test/groups/core_test.py +0 -0
  37. {file_groups-0.3.1 → file_groups-0.4.0}/test/groups/directory_symlinks_test.py +0 -0
  38. {file_groups-0.3.1 → file_groups-0.4.0}/test/groups/re_protect_test.py +0 -0
  39. {file_groups-0.3.1 → file_groups-0.4.0}/test/handler/__init__.py +0 -0
  40. {file_groups-0.3.1 → file_groups-0.4.0}/test/handler/private_test.py +0 -0
  41. {file_groups-0.3.1 → file_groups-0.4.0}/test/handler/regex_protection_test.py +0 -0
  42. {file_groups-0.3.1 → file_groups-0.4.0}/test/handler/utils.py +0 -0
  43. {file_groups-0.3.1 → file_groups-0.4.0}/test/handler_compare_test.py +0 -0
  44. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/config_files_inherit_global_recursive/home/file_groups.conf +0 -0
  45. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/config_files_inherit_global_recursive/sys/file_groups.conf +0 -0
  46. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/config_files_specified/direct.conf +0 -0
  47. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/config_files_sys_config_file_no_global/sys/file_groups.conf +0 -0
  48. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/config_files_sys_user_config_files_additional_appdirs/home/an_app.conf +0 -0
  49. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/config_files_sys_user_config_files_additional_appdirs/home/file_groups.conf +0 -0
  50. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/config_files_sys_user_config_files_additional_appdirs/sys/file_groups.conf +0 -0
  51. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/config_files_sys_user_config_files_no_global/home/file_groups.conf +0 -0
  52. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/config_files_sys_user_config_files_no_global/sys/file_groups.conf +0 -0
  53. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/config_files_two_in_same_config_dir/home/.file_groups.conf +0 -0
  54. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/config_files_two_in_same_config_dir/home/file_groups.conf +0 -0
  55. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/config_files_unknown_protect_sub_key_config_dir/sys/file_groups.conf +0 -0
  56. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/config_files_user_config_file_no_global/home/file_groups.conf +0 -0
  57. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/file_groups_group_dirs_by_config_file_protect/home/file_groups.conf +0 -0
  58. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/file_groups_group_files_by_config_protect/home/file_groups.conf +0 -0
  59. {file_groups-0.3.1 → file_groups-0.4.0}/test/in/configs/file_groups_group_files_by_config_protect/sys/file_groups.conf +0 -0
  60. {file_groups-0.3.1 → file_groups-0.4.0}/test/mypy_requirements.txt +0 -0
  61. {file_groups-0.3.1 → file_groups-0.4.0}/test/perf/protect_home_work_on_pictures.py +0 -0
  62. {file_groups-0.3.1 → file_groups-0.4.0}/test/perf/requirements.txt +0 -0
  63. {file_groups-0.3.1 → file_groups-0.4.0}/test/pylint_requirements.txt +0 -0
  64. {file_groups-0.3.1 → file_groups-0.4.0}/test/requirements.txt +0 -0
  65. {file_groups-0.3.1 → file_groups-0.4.0}/test/version_test.py +0 -0
@@ -1,5 +1,5 @@
1
1
  # Changes here will be overwritten by Copier
2
- _commit: 1ddef8a
2
+ _commit: 451d88a
3
3
  _src_path: git@github.com:lhupfeldt/copier_python_package_template.git
4
4
  author_email: lhn@hupfeldtit.dk
5
5
  author_name: Lars Hupfeldt Nielsen
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: file_groups
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: Group files into 'protect' and 'work_on' and provide operations for safe delete/move and symlink handling.
5
5
  Home-page: https://github.com/lhupfeldt/file_groups.git
6
6
  Author: Lars Hupfeldt Nielsen
@@ -14,9 +14,8 @@ Classifier: Operating System :: OS Independent
14
14
  Classifier: Programming Language :: Python :: 3.13
15
15
  Classifier: Programming Language :: Python :: 3.12
16
16
  Classifier: Programming Language :: Python :: 3.11
17
- Classifier: Programming Language :: Python :: 3.10
18
17
  Classifier: Topic :: Software Development :: Libraries
19
- Requires-Python: >=3.10
18
+ Requires-Python: >=3.11
20
19
  Description-Content-Type: text/x-rst
21
20
  License-File: LICENSE.txt
22
21
  Requires-Dist: appdirs>=1.4.4
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: file_groups
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: Group files into 'protect' and 'work_on' and provide operations for safe delete/move and symlink handling.
5
5
  Home-page: https://github.com/lhupfeldt/file_groups.git
6
6
  Author: Lars Hupfeldt Nielsen
@@ -14,9 +14,8 @@ Classifier: Operating System :: OS Independent
14
14
  Classifier: Programming Language :: Python :: 3.13
15
15
  Classifier: Programming Language :: Python :: 3.12
16
16
  Classifier: Programming Language :: Python :: 3.11
17
- Classifier: Programming Language :: Python :: 3.10
18
17
  Classifier: Topic :: Software Development :: Libraries
19
- Requires-Python: >=3.10
18
+ Requires-Python: >=3.11
20
19
  Description-Content-Type: text/x-rst
21
20
  License-File: LICENSE.txt
22
21
  Requires-Dist: appdirs>=1.4.4
@@ -11,7 +11,7 @@ import nox
11
11
 
12
12
  _HERE = Path(__file__).absolute().parent
13
13
  _TEST_DIR = _HERE/"test"
14
- _PY_VERSIONS = ['3.13', '3.12', '3.11', '3.10']
14
+ _PY_VERSIONS = ['3.13', '3.12', '3.11']
15
15
 
16
16
  nox.options.error_on_missing_interpreters = True
17
17
 
@@ -19,7 +19,7 @@ nox.options.error_on_missing_interpreters = True
19
19
  @nox.session(python=_PY_VERSIONS, reuse_venv=True)
20
20
  def typecheck(session):
21
21
  session.install("-e", ".", "mypy>=1.5.1")
22
- session.run("mypy", str(_HERE/"src"))
22
+ session.run("mypy", "--strict", "--check-untyped", "--implicit-optional", "--disable-error-code=type-arg", str(_HERE/"src"))
23
23
 
24
24
 
25
25
  @nox.session(python=_PY_VERSIONS[0], reuse_venv=True)
@@ -16,7 +16,6 @@ classifiers =
16
16
  Programming Language :: Python :: 3.13
17
17
  Programming Language :: Python :: 3.12
18
18
  Programming Language :: Python :: 3.11
19
- Programming Language :: Python :: 3.10
20
19
  Topic :: Software Development :: Libraries
21
20
 
22
21
  [options]
@@ -24,7 +23,7 @@ zip_safe = True
24
23
  include_package_data = True
25
24
  install_requires =
26
25
  appdirs>=1.4.4
27
- python_requires = >= 3.10
26
+ python_requires = >= 3.11
28
27
  packages =
29
28
  file_groups
30
29
  package_dir =
@@ -1,6 +1,6 @@
1
1
  """Set __version__ property."""
2
2
 
3
- from importlib.metadata import version # type: ignore
3
+ from importlib.metadata import version
4
4
 
5
5
 
6
6
  __version__ = version("file_groups")
@@ -26,7 +26,7 @@ class ProtectConfig():
26
26
  """Hold global (site or user) protect config."""
27
27
  protect_recursive: set[re.Pattern]
28
28
 
29
- def __json__(self):
29
+ def __json__(self) -> dict[str, Any]:
30
30
  return {
31
31
  ProtectConfig.__name__: {
32
32
  "protect_recursive": [str(pat) for pat in self.protect_recursive],
@@ -41,13 +41,13 @@ class DirConfig(ProtectConfig):
41
41
  config_dir: Path|None
42
42
  config_files: list[str]
43
43
 
44
- def is_protected(self, ff: FsPath):
44
+ def is_protected(self, ff: FsPath) -> re.Pattern|None:
45
45
  """If ff id protected by a regex pattern then return the pattern, otherwise return None."""
46
46
 
47
47
  # _LOG.debug("ff '%s'", ff)
48
48
  for pattern in itertools.chain(self.protect_local, self.protect_recursive):
49
49
  if os.sep in str(pattern):
50
- # _LOG.debug("Pattern '%s' has path sep", pattern)
50
+ # _LOG.debug("re.Pattern '%s' has path sep", pattern)
51
51
  assert os.path.isabs(ff), f"Expected absolute path, got '{ff}'"
52
52
 
53
53
  # Search against full path
@@ -68,7 +68,7 @@ class DirConfig(ProtectConfig):
68
68
 
69
69
  return None
70
70
 
71
- def __json__(self):
71
+ def __json__(self) -> dict[str, Any]:
72
72
  return {
73
73
  DirConfig.__name__: super().__json__()[ProtectConfig.__name__] | {
74
74
  "protect_local": [str(pat) for pat in self.protect_local],
@@ -159,7 +159,7 @@ class ConfigFiles():
159
159
 
160
160
  def __init__( # pylint: disable=too-many-positional-arguments,too-many-arguments
161
161
  self, protect: Sequence[re.Pattern] = (),
162
- ignore_config_dirs_config_files=False, ignore_per_directory_config_files=False, remember_configs=True,
162
+ ignore_config_dirs_config_files: bool = False, ignore_per_directory_config_files: bool =False, remember_configs: bool =True,
163
163
  app_dirs: Sequence[AppDirs]|None = None,
164
164
  *,
165
165
  config_file: Path|None = None,
@@ -35,14 +35,14 @@ class _Group():
35
35
  num_directories: int = 0
36
36
  num_directory_symlinks: int = 0
37
37
 
38
- def add_entry_match(self, entry: DirEntry):
38
+ def add_entry_match(self, entry: DirEntry) -> None:
39
39
  """Abstract, but abstract and dataclass does not work with mypy. https://github.com/python/mypy/issues/500"""
40
40
 
41
41
  @dataclass
42
42
  class _IncludeMatchGroup(_Group):
43
43
  include: re.Pattern|None = None
44
44
 
45
- def add_entry_match(self, entry: DirEntry):
45
+ def add_entry_match(self, entry: DirEntry) -> None:
46
46
  if not self.include:
47
47
  self.files[entry.path] = entry
48
48
  return
@@ -58,7 +58,7 @@ class _IncludeMatchGroup(_Group):
58
58
  class _ExcludeMatchGroup(_Group):
59
59
  exclude: re.Pattern|None = None
60
60
 
61
- def add_entry_match(self, entry: DirEntry):
61
+ def add_entry_match(self, entry: DirEntry) -> None:
62
62
  if not self.exclude:
63
63
  self.files[entry.path] = entry
64
64
  return
@@ -169,7 +169,7 @@ class FileGroups():
169
169
 
170
170
  checked_dirs: set[str] = set()
171
171
 
172
- def handle_entry(abs_dir_path: str, group: _Group, other_group: _Group, dir_config: DirConfig, entry: DirEntry):
172
+ def handle_entry(abs_dir_path: str, group: _Group, other_group: _Group, dir_config: DirConfig, entry: DirEntry) -> None:
173
173
  """Put entry in the correct group. Call 'find_group' if entry is a directory."""
174
174
  if group.typ is GroupType.MAY_WORK_ON:
175
175
  # Check for match against configured protect patterns, if match, then the file must got to protect group instead
@@ -207,7 +207,7 @@ class FileGroups():
207
207
  _LOG.debug("find %s - entry name: %s", group.typ.name, entry.name)
208
208
  group.add_entry_match(entry)
209
209
 
210
- def find_group(abs_dir_path: str, group: _Group, other_group: _Group, parent_conf: DirConfig|None):
210
+ def find_group(abs_dir_path: str, group: _Group, other_group: _Group, parent_conf: DirConfig|None) -> None:
211
211
  """Recursively find all files belonging to 'group'"""
212
212
  _LOG.debug("find %s: %s", group.typ.name, abs_dir_path)
213
213
  if abs_dir_path in checked_dirs:
@@ -238,7 +238,7 @@ class FileGroups():
238
238
  else:
239
239
  find_group(any_dir, self.may_work_on, self.must_protect, parent_conf)
240
240
 
241
- def dump(self):
241
+ def dump(self) -> None:
242
242
  """Log collected files. This may be A LOT of output for large directories."""
243
243
 
244
244
  log = _LOG.getChild("dump")
@@ -280,7 +280,7 @@ class FileGroups():
280
280
 
281
281
  log.log(lvl, "")
282
282
 
283
- def stats(self):
283
+ def stats(self) -> None:
284
284
  """Log collection numbers."""
285
285
  log = _LOG.getChild("stats")
286
286
  lvl = logging.INFO
@@ -2,13 +2,12 @@ import os
2
2
  from pathlib import Path
3
3
  import shutil
4
4
  import re
5
- from contextlib import contextmanager
6
5
  import logging
7
6
  from typing import Sequence
8
7
 
9
8
  from .groups import FileGroups
10
9
  from .config_files import ConfigFiles
11
-
10
+ from .types import FsPath
12
11
 
13
12
  _LOG = logging.getLogger(__name__)
14
13
 
@@ -35,7 +34,7 @@ class FileHandler(FileGroups):
35
34
  protect_exclude: re.Pattern|None = None, work_include: re.Pattern|None = None,
36
35
  config_files: ConfigFiles|None = None,
37
36
  dry_run: bool,
38
- delete_symlinks_instead_of_relinking=False):
37
+ delete_symlinks_instead_of_relinking: bool =False):
39
38
  super().__init__(
40
39
  protect_dirs_seq=protect_dirs_seq, work_dirs_seq=work_dirs_seq,
41
40
  protect_exclude=protect_exclude, work_include=work_include,
@@ -55,7 +54,7 @@ class FileHandler(FileGroups):
55
54
  self.num_moved = 0
56
55
  self.num_relinked = 0
57
56
 
58
- def reset(self):
57
+ def reset(self) -> None:
59
58
  """Reset internal housekeeping of deleted/renamed/moved files.
60
59
 
61
60
  This makes it possible to do a 'dry_run' and an actual run without collecting files again.
@@ -69,7 +68,7 @@ class FileHandler(FileGroups):
69
68
  self.num_moved = 0
70
69
  self.num_relinked = 0
71
70
 
72
- def _no_symlink_check_registered_delete(self, delete_path: str):
71
+ def _no_symlink_check_registered_delete(self, delete_path: str) -> None:
73
72
  """Does a registered delete without checking for symlinks, so that we can use this in the symlink handling."""
74
73
  assert isinstance(delete_path, str)
75
74
  assert os.path.isabs(delete_path), f"Expected absolute path, got '{delete_path}'"
@@ -84,7 +83,7 @@ class FileHandler(FileGroups):
84
83
  if delete_path in self.may_work_on.symlinks:
85
84
  self.deleted_symlinks.add(delete_path)
86
85
 
87
- def _handle_single_symlink_chain(self, symlnk_path: str, keep_path):
86
+ def _handle_single_symlink_chain(self, symlnk_path: str, keep_path: str|FsPath|None) -> None:
88
87
  """TODO doc - Symlink will only be deleted if it is in self.may_work_on.files."""
89
88
 
90
89
  assert os.path.isabs(symlnk_path), f"Expected an absolute path, got '{symlnk_path}'"
@@ -141,8 +140,12 @@ class FileHandler(FileGroups):
141
140
 
142
141
  self.num_relinked += 1
143
142
 
144
- def _fix_symlinks_to_deleted_or_moved_files(self, from_path: str, to_path):
145
- """Any symlinks pointing to 'from_path' will be change to point to 'to_path'"""
143
+ def _fix_symlinks_to_deleted_or_moved_files(self, from_path: str, to_path: str|FsPath|None) -> None:
144
+ """Any symlinks pointing to 'from_path' will be change to point to 'to_path' or deleted.
145
+
146
+ If 'to_path' is None then delete full chains of symlinks in 'may_work_on' dirs.
147
+ """
148
+
146
149
  _LOG.debug("_fix_symlinks_to_deleted_or_moved_files(self, %s, %s)", from_path, to_path)
147
150
 
148
151
  for symlnk in self.must_protect.symlinks_by_abs_points_to.get(from_path, ()):
@@ -153,13 +156,13 @@ class FileHandler(FileGroups):
153
156
  _LOG.debug("_fix_symlinks_to_deleted_or_moved_files, may_work_on symlink: '%s'.", symlnk)
154
157
  self._handle_single_symlink_chain(os.fspath(symlnk), to_path)
155
158
 
156
- def registered_delete(self, delete_path: str, corresponding_keep_path) -> Path|None:
159
+ def registered_delete(self, delete_path: str, corresponding_keep_path: str|FsPath|None) -> Path|None:
157
160
  """Return `corresponding_keep_path` as absolute Path"""
158
161
  self._no_symlink_check_registered_delete(delete_path)
159
162
  self._fix_symlinks_to_deleted_or_moved_files(delete_path, corresponding_keep_path)
160
163
  return Path(corresponding_keep_path).absolute() if corresponding_keep_path else None
161
164
 
162
- def _registered_move_or_rename(self, from_path: str, to_path, *, is_move) -> Path:
165
+ def _registered_move_or_rename(self, from_path: str, to_path: str|FsPath, *, is_move: bool) -> Path:
163
166
  """Return `to_path` as absolute Path"""
164
167
  assert isinstance(from_path, str)
165
168
  assert os.path.isabs(from_path), f"Expected absolute path, got '{from_path}'"
@@ -189,20 +192,18 @@ class FileHandler(FileGroups):
189
192
  self._fix_symlinks_to_deleted_or_moved_files(from_path, to_path)
190
193
  return res
191
194
 
192
- def registered_move(self, from_path: str, to_path) -> Path:
195
+ def registered_move(self, from_path: str, to_path: str|FsPath) -> Path:
193
196
  """Return `to_path` as absolute Path"""
194
197
  return self._registered_move_or_rename(from_path, to_path, is_move=True)
195
198
 
196
- def registered_rename(self, from_path: str, to_path) -> Path:
199
+ def registered_rename(self, from_path: str, to_path: str|FsPath) -> Path:
197
200
  """Return `to_path` as absolute Path"""
198
201
  return self._registered_move_or_rename(from_path, to_path, is_move=False)
199
202
 
200
- @contextmanager
201
- def stats(self):
203
+ def stats(self) -> None:
202
204
  log = _LOG.getChild("stats")
203
205
  lvl = logging.INFO
204
206
  if not log.isEnabledFor(lvl):
205
- yield
206
207
  return
207
208
 
208
209
  prefix = ''
@@ -218,10 +219,3 @@ class FileHandler(FileGroups):
218
219
  log.log(lvl, "%srenamed: %s", prefix, self.num_renamed)
219
220
  log.log(lvl, "%smoved: %s", prefix, self.num_moved)
220
221
  log.log(lvl, "%srelinked: %s", prefix, self.num_relinked)
221
-
222
- try:
223
- yield
224
-
225
- finally:
226
- if self.dry_run:
227
- log.log(lvl, "*** DRY RUN ***")
@@ -29,7 +29,7 @@ class FileHandlerCompare(FileHandler):
29
29
  protect_exclude: re.Pattern|None = None, work_include: re.Pattern|None = None,
30
30
  config_files: ConfigFiles|None = None,
31
31
  dry_run: bool,
32
- delete_symlinks_instead_of_relinking=False):
32
+ delete_symlinks_instead_of_relinking: bool = False):
33
33
  super().__init__(
34
34
  protect_dirs_seq=protect_dirs_seq, work_dirs_seq=work_dirs_seq,
35
35
  protect_exclude=protect_exclude, work_include=work_include,
@@ -0,0 +1,5 @@
1
+ from os import DirEntry
2
+ from pathlib import Path
3
+
4
+
5
+ FsPath = DirEntry|Path
@@ -58,7 +58,7 @@ class FGC():
58
58
  group = getattr(self.fg, group_name)
59
59
  return getattr(group, attr_name)
60
60
 
61
- def ckfl(self, attr_name, *rel_paths: str):
61
+ def ckfl(self, attr_name, *rel_paths: str|os.PathLike):
62
62
  self.checked.add(attr_name)
63
63
  return ckfl(attr_name, self._ggetattr(attr_name), *rel_paths)
64
64
 
@@ -412,8 +412,8 @@ def test_stats(duplicates_dir, log_debug):
412
412
  ck = FP(fh, str(Path('df/f11').absolute()), 'df/z', log_debug)
413
413
 
414
414
  assert ck.check_rename(dry=True)
415
- with fh.stats():
416
- print('did nothing')
415
+ fh.stats()
416
+ print('did nothing')
417
417
 
418
418
  out = log_debug.text
419
419
  assert 'DRY' in out
@@ -421,8 +421,8 @@ def test_stats(duplicates_dir, log_debug):
421
421
  log_debug.clear()
422
422
 
423
423
  assert ck.check_rename(dry=False)
424
- with fh.stats():
425
- print('did stuff')
424
+ fh.stats()
425
+ print('did stuff')
426
426
 
427
427
  out = log_debug.text
428
428
  assert 'DRY' not in out
@@ -436,8 +436,7 @@ def test_no_info_log_stats(duplicates_dir, caplog):
436
436
  FP(fh, str(Path('df/f11').absolute()), 'df/z', caplog)
437
437
 
438
438
  caplog.set_level(logging.WARNING)
439
- with fh.stats():
440
- pass
439
+ fh.stats()
441
440
 
442
441
  out = caplog.text
443
442
  assert "DRY" not in out
@@ -1,6 +0,0 @@
1
- from os import DirEntry
2
- from pathlib import Path
3
- from typing import Union
4
-
5
-
6
- FsPath = Union[DirEntry, Path]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes