check-empty 2.0.0__tar.gz → 3.0.0__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: check-empty
3
- Version: 2.0.0
3
+ Version: 3.0.0
4
4
  Summary: Command-line utility, as well as a hook usable by the Python pre-commit framework, and a GitHub Action, to ensure that selected files are empty.
5
5
  Keywords: check,command-line,empty,files,github-action,helper,hook,lightweight,pre-commit,prek,tool,utility
6
6
  Author: Jonathan Dung
@@ -27,7 +27,7 @@ Classifier: Topic :: Utilities
27
27
  Classifier: Typing :: Typed
28
28
  Requires-Dist: py7zr==1.1.3 ; extra == '7z'
29
29
  Requires-Dist: acefile==0.6.14 ; extra == 'ace'
30
- Requires-Dist: check-empty[7z,ace,ar,lzh,rar]==2.0.0 ; extra == 'all'
30
+ Requires-Dist: check-empty[7z,ace,ar,lzh,rar]==3.0.0 ; extra == 'all'
31
31
  Requires-Dist: arpy==2.4.0 ; extra == 'ar'
32
32
  Requires-Dist: lhafile==0.3.1 ; extra == 'lzh'
33
33
  Requires-Dist: rarfile==4.5 ; extra == 'rar'
@@ -42,7 +42,7 @@ Provides-Extra: lzh
42
42
  Provides-Extra: rar
43
43
  Description-Content-Type: text/markdown
44
44
 
45
- # [check-empty](https://pypi.org/p/check-empty)
45
+ # [check-empty](https://pypi.org/p/check-empty/3.0.0)
46
46
 
47
47
  [![#StandWithPalestine](https://raw.githubusercontent.com/TheBSD/StandWithPalestine/main/badges/StandWithPalestine.svg)](https://github.com/TheBSD/StandWithPalestine/blob/main/docs/README.md)
48
48
 
@@ -57,7 +57,8 @@ specified.
57
57
 
58
58
  ## Prerequisites
59
59
 
60
- Supports every Python 3.10 runtime. There are no other requirements.
60
+ Supports every Python 3.10 runtime. There are no other requirements unless you want to
61
+ check if files in certain types of (compressed) archives are empty.
61
62
 
62
63
  ## Quickstart
63
64
 
@@ -125,7 +126,7 @@ As a pre-commit hook:
125
126
  # .pre-commit-config.yaml
126
127
  repos:
127
128
  - repo: https://github.com/jonathandung/check-empty
128
- rev: v2.0.0 # repository version
129
+ rev: v3.0.0 # repository version
129
130
  hooks:
130
131
  - id: check-empty # the hook
131
132
  args: # example list of arguments
@@ -141,7 +142,7 @@ equivalent in `prek.toml` format:
141
142
  ```toml
142
143
  [[repos]]
143
144
  repo = "https://github.com/jonathandung/check-empty"
144
- rev = "v2.0.0"
145
+ rev = "v3.0.0"
145
146
 
146
147
  [[repos.hooks]]
147
148
  id = "check-empty"
@@ -165,7 +166,7 @@ or (TOML 1.1+):
165
166
  # using multiline inline tables
166
167
  [[repos]]
167
168
  repo = "https://github.com/jonathandung/check-empty"
168
- rev = "v2.0.0"
169
+ rev = "v3.0.0"
169
170
  hooks = [{
170
171
  id = "check-empty",
171
172
  args = ["-Q"],
@@ -185,7 +186,7 @@ As a GitHub Actions workflow step:
185
186
 
186
187
  ```yaml
187
188
  steps:
188
- - uses: jonathandung/check-empty@v2.0.0 # the latest version on the GitHub Actions
189
+ - uses: jonathandung/check-empty@v3.0.0 # the latest version on the GitHub Actions
189
190
  # marketplace; this step will fail and subsequent jobs will not run if any file is
190
191
  # not empty
191
192
  with:
@@ -1,4 +1,4 @@
1
- # [check-empty](https://pypi.org/p/check-empty)
1
+ # [check-empty](https://pypi.org/p/check-empty/3.0.0)
2
2
 
3
3
  [![#StandWithPalestine](https://raw.githubusercontent.com/TheBSD/StandWithPalestine/main/badges/StandWithPalestine.svg)](https://github.com/TheBSD/StandWithPalestine/blob/main/docs/README.md)
4
4
 
@@ -13,7 +13,8 @@ specified.
13
13
 
14
14
  ## Prerequisites
15
15
 
16
- Supports every Python 3.10 runtime. There are no other requirements.
16
+ Supports every Python 3.10 runtime. There are no other requirements unless you want to
17
+ check if files in certain types of (compressed) archives are empty.
17
18
 
18
19
  ## Quickstart
19
20
 
@@ -81,7 +82,7 @@ As a pre-commit hook:
81
82
  # .pre-commit-config.yaml
82
83
  repos:
83
84
  - repo: https://github.com/jonathandung/check-empty
84
- rev: v2.0.0 # repository version
85
+ rev: v3.0.0 # repository version
85
86
  hooks:
86
87
  - id: check-empty # the hook
87
88
  args: # example list of arguments
@@ -97,7 +98,7 @@ equivalent in `prek.toml` format:
97
98
  ```toml
98
99
  [[repos]]
99
100
  repo = "https://github.com/jonathandung/check-empty"
100
- rev = "v2.0.0"
101
+ rev = "v3.0.0"
101
102
 
102
103
  [[repos.hooks]]
103
104
  id = "check-empty"
@@ -121,7 +122,7 @@ or (TOML 1.1+):
121
122
  # using multiline inline tables
122
123
  [[repos]]
123
124
  repo = "https://github.com/jonathandung/check-empty"
124
- rev = "v2.0.0"
125
+ rev = "v3.0.0"
125
126
  hooks = [{
126
127
  id = "check-empty",
127
128
  args = ["-Q"],
@@ -141,7 +142,7 @@ As a GitHub Actions workflow step:
141
142
 
142
143
  ```yaml
143
144
  steps:
144
- - uses: jonathandung/check-empty@v2.0.0 # the latest version on the GitHub Actions
145
+ - uses: jonathandung/check-empty@v3.0.0 # the latest version on the GitHub Actions
145
146
  # marketplace; this step will fail and subsequent jobs will not run if any file is
146
147
  # not empty
147
148
  with:
@@ -7,26 +7,24 @@ Pre-commit hook, command-line tool and GitHub Action all-in-one.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- import os
11
10
  from contextlib import suppress
12
11
 
13
- from . import constants, reporter
12
+ from check_empty import constants, reporter
14
13
 
14
+ __all__ = ('Handler', 'check', 'default_reporter')
15
+ __version__ = '3.0.0'
16
+ """The version of the package."""
17
+ default_reporter: reporter.Reporter = reporter.Reporter()
18
+ """The default reporter used by :func:`check`."""
15
19
  TYPE_CHECKING = False
16
20
  if TYPE_CHECKING:
17
21
  from collections.abc import Callable, Iterable
18
- from types import ModuleType, TracebackType
22
+ from types import TracebackType
19
23
  from typing import Any, SupportsIndex
20
24
 
21
25
  from _typeshed import FileDescriptorOrPath
22
26
  from typing_extensions import Self
23
27
 
24
- __all__ = ('Handler', 'check', 'default_reporter')
25
- __version__ = '2.0.0'
26
- """The version of the package."""
27
- default_reporter: reporter.Reporter = reporter.Reporter()
28
- """The default reporter used by :func:`check`."""
29
-
30
28
 
31
29
  class Handler:
32
30
  """Used to handle errors when opening a file."""
@@ -36,22 +34,18 @@ class Handler:
36
34
  """The file descriptor or string path to the file being handled."""
37
35
  c: bool
38
36
  """Whether an I/O error was handled."""
39
- f: Callable[[str], None]
40
- """The function to call when handling an I/O error.
41
-
42
- Should take a string representing the error message as the only argument and
43
- preferably return ``None``.
44
- """
45
- j: Callable[[str], None]
37
+ f: Callable[[OSError], object]
38
+ """The function to call on the I/O error being handled."""
39
+ j: Callable[[str], object]
46
40
  """The function to call when handling the case where the file is missing.
47
41
 
48
42
  Should take the path to the file or a string encapsulating the validity of the file
49
- descriptor as the only argument and preferably return ``None``.
43
+ descriptor as the only argument.
50
44
  """
51
45
  v: str | None
52
46
  """The cached value of :attr:`e`."""
53
47
 
54
- def __init__(self, *a: Any) -> None: # ruff: ignore[any-type]
48
+ def __init__(self, *a: Any): # ruff: ignore[any-type]
55
49
  """Initialize the handler."""
56
50
  self.j, self.f, self.a = a
57
51
  self.v = None
@@ -71,7 +65,7 @@ class Handler:
71
65
  ...
72
66
 
73
67
  @property
74
- def e(self, s: str = 'invalid fd (negative): %d', t: str = 'fd: %d') -> str: # ruff: ignore[property-with-parameters]
68
+ def e(self, s: str = 'invalid fd (negative): %d', t: str = 'fd: %d') -> str:
75
69
  """The file path itself, or the file descriptor coerced to a string."""
76
70
  r = self.v
77
71
  if r is None:
@@ -92,7 +86,7 @@ class Handler:
92
86
  """
93
87
  if t is None or not isinstance(v, OSError):
94
88
  return False
95
- self.j(self.e) if v.errno == constants.ENOENT else self.f(str(v))
89
+ self.j(self.e) if v.errno == constants.ENOENT else self.f(v)
96
90
  self.c = True
97
91
  return True
98
92
 
@@ -104,7 +98,7 @@ def check(
104
98
  may_not_exist: bool = False,
105
99
  verbosity: SupportsIndex = 2,
106
100
  recurse_into: SupportsIndex = constants.RecurseInto.NONE,
107
- reporter: reporter.abc.ReporterABC = default_reporter,
101
+ reporter: reporter.abcdef.ReporterABC = default_reporter,
108
102
  ) -> int:
109
103
  # ruff: ignore[docstring-missing-exception]
110
104
  r"""Check the emptiness of files, recursing into directories if passed.
@@ -130,13 +124,14 @@ def check(
130
124
  The integer exit code calculated by the reporter.
131
125
 
132
126
  """
127
+ from os import fsdecode, scandir, stat
128
+
133
129
  files = list(files)
134
130
  if not files:
135
131
  return 0
136
132
  k, j, t, n, o = [0] * 5, [], 0, len(files), files.pop
137
133
  u, e, _ = j.extend, j.pop, lambda v: lambda _, k=k: k.__setitem__(v, k[v] + 1)
138
134
  verbosity, recurse_into = (type(x).__index__(x) for x in (verbosity, recurse_into))
139
- # ruff: disable[magic-value-comparison]
140
135
  if verbosity > 4:
141
136
  b = ['']
142
137
  f = b.append
@@ -149,7 +144,7 @@ def check(
149
144
  v = ra = None
150
145
  x = aa = lambda _: None
151
146
  if verbosity > 2:
152
- z, w = [''], ['']
147
+ z, w = [''], []
153
148
  i = z.append, w.append
154
149
  else:
155
150
  z = w = None
@@ -159,11 +154,10 @@ def check(
159
154
  g = r.append
160
155
  else:
161
156
  r, g = None, _(3)
162
- # ruff: enable[magic-value-comparison]
163
157
  zp, tr, rr, z7, ar, lh, ac = map(recurse_into.__and__, constants.ARCHIVE_FORMATS)
164
158
  an = bool(recurse_into)
165
159
  if an:
166
- from . import archives as av
160
+ from check_empty import archives as av
167
161
  md = 'a' if clear else 'r'
168
162
  if TYPE_CHECKING:
169
163
  import tarfile as tr
@@ -208,20 +202,19 @@ def check(
208
202
  else:
209
203
  f(a)
210
204
 
211
- def v(m: ModuleType, e: str) -> bool:
205
+ def v(f: Callable[[str], Any], e: type[BaseException]) -> bool:
212
206
  nonlocal d
213
- with suppress(getattr(m, e)):
214
- d = m.open(a)
207
+ with suppress(e):
208
+ d = f(a)
215
209
  return True
216
210
  return False
217
211
 
218
- if tr and v(tr, 'TarError'):
212
+ if tr and v(tr.open, tr.TarError):
219
213
  aa(a)
220
214
  for r in d.getmembers():
221
215
  a, s = q = r.name, r.size
222
216
  e()
223
- if clear:
224
- av.purge_tar(d)
217
+ av.purge_tar(d) if clear else d.close()
225
218
  elif zp and zp.is_zipfile(a):
226
219
  with zp.ZipFile(a, md) as d:
227
220
  aa(a)
@@ -248,14 +241,14 @@ def check(
248
241
  for r in d.infolist():
249
242
  a, s = q = r.filename, r.file_size
250
243
  w()
251
- elif ar and v(ar, 'ArchiveFormatError'):
244
+ elif ar and v(ar.Archive, ar.ArchiveFormatError):
252
245
  aa(a)
253
246
  for r in d.infolist():
254
247
  a, s = q = r.name, r.size
255
248
  e()
256
249
  if clear:
257
250
  av.purge_ar(d, ar.HEADER_GNU)
258
- elif ac and v(ac, 'AceError'):
251
+ elif ac and v(ac.open, ac.AceError):
259
252
  aa(a)
260
253
  for r in filter(ac.AceMember.is_reg, d):
261
254
  a, s = q = r.filename, r.size
@@ -278,24 +271,25 @@ def check(
278
271
  try:
279
272
  return an and ha(a)
280
273
  except Exception as e: # ruff: ignore[blind-except]
281
- i[1](str(e))
274
+ i[1](e)
282
275
  return True
283
276
 
284
277
  while files:
285
278
  a, q = o(), None
286
279
  m = isinstance(a, int)
287
280
  if not m:
288
- a = os.fsdecode(a)
281
+ a = fsdecode(a)
289
282
  with Handler(*i, a) as h:
290
- q = os.stat(a) # ruff: ignore[os-stat]
283
+ q = stat(a) # ruff: ignore[os-stat]
291
284
  if q is None:
292
285
  continue
293
286
  c = h.e
294
287
  if q.st_mode & constants.TYPE_MASK == constants.S_IFDIR:
295
288
  if m:
296
289
  raise constants.DIRFD_UNSUPPORTED
297
- x(c)
298
- u(os.scandir(c))
290
+ with h:
291
+ u(scandir(c))
292
+ x(c)
299
293
  continue
300
294
  if isinstance(a, str) and hb(a):
301
295
  continue
@@ -312,8 +306,9 @@ def check(
312
306
  m = e()
313
307
  a = m.path
314
308
  if m.is_dir():
315
- x(a)
316
- u(os.scandir(a))
309
+ with Handler(*i, a):
310
+ u(scandir(a))
311
+ x(a)
317
312
  continue
318
313
  if hb(a):
319
314
  continue
@@ -326,8 +321,7 @@ def check(
326
321
  t += s
327
322
  if clear:
328
323
  Handler(*i, a).o()
329
- del j
330
- x, d = k[1] if z is None else len(z) - 1, k[2] if w is None else len(w) - 1
324
+ x, d = k[1] if z is None else len(z) - 1, k[2] if w is None else len(w)
331
325
  y, p = k[3] if r is None else len(r), k[0] if b is None else len(b) - 1
332
326
  reporter.report(z, w, v, b, r, x, y, d, p, n, t, verbosity, clear)
333
327
  reporter.reset_out()
@@ -7,15 +7,6 @@ from itertools import filterfalse
7
7
  from operator import attrgetter
8
8
  from tempfile import NamedTemporaryFile
9
9
 
10
- TYPE_CHECKING = False
11
- if TYPE_CHECKING:
12
- import tarfile
13
- import zipfile
14
- from collections.abc import Callable, Iterable
15
- from typing import Final, Literal
16
-
17
- import arpy
18
- import py7zr
19
10
  __all__ = (
20
11
  'AR_FS',
21
12
  'AR_MAG',
@@ -34,6 +25,15 @@ AR_SKIP: Final[
34
25
  Literal[b'/', b'//', b'/SYM64/', b'__.SYMDEF', b'__.SYMDEF SORTED'] | None
35
26
  ]
36
27
  ] = frozenset((b'/', b'//', b'/SYM64/', b'__.SYMDEF', b'__.SYMDEF SORTED', None))
28
+ TYPE_CHECKING = False
29
+ if TYPE_CHECKING:
30
+ import tarfile
31
+ import zipfile
32
+ from collections.abc import Callable, Iterable
33
+ from typing import Final, Literal
34
+
35
+ import py7zr
36
+ from arpy import Archive
37
37
 
38
38
 
39
39
  def clear_file_in_zip(z: zipfile.ZipFile, i: zipfile.ZipInfo) -> None:
@@ -71,7 +71,7 @@ def purge_tar(t: tarfile.TarFile) -> None:
71
71
  os.replace(p.name, x)
72
72
 
73
73
 
74
- def purge_ar(a: arpy.Archive, g: int) -> None:
74
+ def purge_ar(a: Archive, g: int) -> None:
75
75
  """Clear the contents of each file in a .a, .ar or .lib archive."""
76
76
  a.read_all_headers()
77
77
  i, n = a.headers, a.file.name
@@ -5,19 +5,18 @@ from __future__ import annotations
5
5
  import itertools as i
6
6
  import sys as s
7
7
 
8
- from . import abc
9
-
10
- TYPE_CHECKING = False
11
- if TYPE_CHECKING:
12
- from typing import IO
8
+ from check_empty.reporter import abcdef, dct as dct
13
9
 
14
10
  __all__ = ('DelayedReporter', 'Reporter')
11
+ TYPE_CHECKING = False
15
12
 
16
13
 
17
- class Reporter(abc.ReporterABC):
14
+ class Reporter(abcdef.ReporterABC):
18
15
  """Concrete and default reporter implementation that prints output to a stream."""
19
16
 
20
17
  if TYPE_CHECKING:
18
+ from typing import IO
19
+
21
20
  o: IO[str] | None
22
21
 
23
22
  def to(self, out: IO[str] | None = None) -> IO[str] | None:
@@ -35,7 +34,7 @@ class Reporter(abc.ReporterABC):
35
34
  def report( # ruff: ignore[too-many-arguments, too-many-positional-arguments]
36
35
  self,
37
36
  z: list[str] | None,
38
- w: list[str] | None,
37
+ w: list[OSError] | None,
39
38
  a: list[str] | None,
40
39
  b: list[str] | None,
41
40
  r: list[tuple[str, int]] | None,
@@ -68,7 +67,7 @@ class Reporter(abc.ReporterABC):
68
67
  else '\nAll files were found'
69
68
  )
70
69
  if w is not None:
71
- q('\nError: '.join(w))
70
+ q('\nError: '.join(i.chain(('',), map(str, w))))
72
71
  if d:
73
72
  q(f'\n{d} I/O error{"s" if d > 1 else ""} encountered')
74
73
  if b is not None:
@@ -93,5 +92,8 @@ class Reporter(abc.ReporterABC):
93
92
  q.close()
94
93
 
95
94
 
96
- class DelayedReporter(abc.DelayedReporterMixin, Reporter):
95
+ class DelayedReporter(abcdef.DelayedReporterMixin, Reporter):
97
96
  """The delayed version of the default reporter."""
97
+
98
+
99
+ del TYPE_CHECKING
@@ -1,17 +1,16 @@
1
- """Abstract base classes for reporters."""
1
+ """Abstract base classes definitions ("abcdef") for reporters."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
5
  import abc as a
6
6
 
7
- from .exceptions import NoReport
7
+ from check_empty.reporter.exceptions import NoReport
8
8
 
9
+ __all__ = ('DelayedReporterMixin', 'ReporterABC')
9
10
  TYPE_CHECKING = False
10
11
  if TYPE_CHECKING:
11
12
  from typing import Any
12
13
 
13
- __all__ = ('DelayedReporterMixin', 'ReporterABC')
14
-
15
14
 
16
15
  class ReporterABC(metaclass=a.ABCMeta):
17
16
  """Abstract base class for all reporters accepted by :func:`~check_empty.check`."""
@@ -23,7 +22,7 @@ class ReporterABC(metaclass=a.ABCMeta):
23
22
  def report( # ruff: ignore[too-many-arguments, too-many-positional-arguments]
24
23
  self,
25
24
  z: list[str] | None,
26
- w: list[str] | None,
25
+ w: list[OSError] | None,
27
26
  a: list[str] | None,
28
27
  b: list[str] | None,
29
28
  r: list[tuple[str, int]] | None,
@@ -41,7 +40,7 @@ class ReporterABC(metaclass=a.ABCMeta):
41
40
 
42
41
  Args:
43
42
  z: list of paths to files that were not found.
44
- w: list of error messages for files that could not be processed.
43
+ w: list of I/O errors when processing non-missing files.
45
44
  a: list of directories that were recursed into.
46
45
  b: list of empty file paths.
47
46
  r: list of 2-tuples representing non-empty files and their sizes.
@@ -127,3 +126,6 @@ class DelayedReporterMixin(ReporterABC):
127
126
  if a is None:
128
127
  raise NoReport(self)
129
128
  super().report(*a)
129
+
130
+
131
+ del TYPE_CHECKING
@@ -4,16 +4,15 @@ from __future__ import annotations
4
4
 
5
5
  import itertools as i
6
6
 
7
- from . import exceptions as _
8
- from .abc import ReporterABC
7
+ from check_empty.reporter import exceptions as _
8
+ from check_empty.reporter.abcdef import ReporterABC
9
9
 
10
+ __all__ = ('DictReporter', 'SelfReporter')
10
11
  TYPE_CHECKING = False
11
12
  if TYPE_CHECKING:
12
13
  from collections.abc import Iterable, MutableMapping
13
14
  from typing import Any, Final
14
15
 
15
- __all__ = ('DictReporter', 'SelfReporter')
16
-
17
16
 
18
17
  class DictReporter(ReporterABC):
19
18
  """Dump the metrics into a dictionary-like object."""
@@ -63,7 +62,7 @@ class DictReporter(ReporterABC):
63
62
  The previous output mapping, or ``None`` if no redirection is in effect.
64
63
  """
65
64
 
66
- def __init__(self, keys: Iterable[str | None] | None = None) -> None:
65
+ def __init__(self, keys: Iterable[str | None] | None = None):
67
66
  """Initialize the reporter.
68
67
 
69
68
  Args:
@@ -2,13 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- TYPE_CHECKING = False
6
- if TYPE_CHECKING:
7
- from typing import ClassVar
8
-
9
- from .abc import DelayedReporterMixin, ReporterABC
10
- from .dict import DictReporter
11
-
12
5
  __all__ = (
13
6
  'IncorrectKeynames',
14
7
  'IncorrectKeynamesLength',
@@ -17,6 +10,12 @@ __all__ = (
17
10
  'NoReport',
18
11
  'ReporterError',
19
12
  )
13
+ TYPE_CHECKING = False
14
+ if TYPE_CHECKING:
15
+ from typing import ClassVar
16
+
17
+ from check_empty.reporter.abcdef import DelayedReporterMixin, ReporterABC
18
+ from check_empty.reporter.dct import DictReporter
20
19
 
21
20
 
22
21
  class ReporterError(Exception):
@@ -27,7 +26,7 @@ class ReporterError(Exception):
27
26
  message: ClassVar[str]
28
27
  """The message of the exception."""
29
28
 
30
- def __init__(self, reporter: ReporterABC) -> None:
29
+ def __init__(self, reporter: ReporterABC):
31
30
  """Initialize the exception.
32
31
 
33
32
  Args:
@@ -46,7 +45,7 @@ class NoReport(ReporterError):
46
45
 
47
46
 
48
47
  class IncorrectKeynames(ReporterError):
49
- """A :class:`check_empty.reporter.dict.DictReporter` got invalid ``keys``."""
48
+ """A :class:`check_empty.reporter.dct.DictReporter` got invalid ``keys``."""
50
49
 
51
50
  reporter: DictReporter
52
51
  """The reporter concerned."""
@@ -65,6 +64,11 @@ class IncorrectKeynamesType(IncorrectKeynames):
65
64
 
66
65
 
67
66
  class NoOutputMapping(ReporterError):
68
- """A :class:`check_empty.reporter.dict.DictReporter` had no output mapping."""
67
+ """A :class:`check_empty.reporter.dct.DictReporter` had no output mapping."""
69
68
 
69
+ reporter: DictReporter
70
+ """The reporter concerned."""
70
71
  message = 'no mapping to output to'
72
+
73
+
74
+ del TYPE_CHECKING
@@ -1,5 +1,5 @@
1
1
  [build-system]
2
- requires = ["uv_build>=0.12.18"]
2
+ requires = ["uv_build>=0.12.19"]
3
3
  build-backend = "uv_build"
4
4
 
5
5
  [dependency-groups]
@@ -55,7 +55,7 @@ license-files = [
55
55
  name = "check-empty"
56
56
  readme = "README.md"
57
57
  requires-python = ">=3.10"
58
- version = "2.0.0"
58
+ version = "3.0.0"
59
59
 
60
60
  [[project.authors]]
61
61
  name = "Jonathan Dung"
@@ -68,7 +68,7 @@ email = "jonathandung@yahoo.com"
68
68
  [project.optional-dependencies]
69
69
  7z = ["py7zr==1.1.3"]
70
70
  ace = ["acefile==0.6.14"]
71
- all = ["check-empty[7z,ace,ar,lzh,rar]==2.0.0"]
71
+ all = ["check-empty[7z,ace,ar,lzh,rar]==3.0.0"]
72
72
  ar = ["arpy==2.4.0"]
73
73
  lzh = ["lhafile==0.3.1"]
74
74
  rar = ["rarfile==4.5"]
@@ -77,7 +77,7 @@ rar = ["rarfile==4.5"]
77
77
  check-empty = "check_empty.__main__:main"
78
78
 
79
79
  [tool.ruff]
80
- required-version = ">=0.16.8"
80
+ required-version = ">=0.16.9"
81
81
  target-version = "py310"
82
82
 
83
83
  [tool.ruff.analyze]
@@ -95,17 +95,12 @@ ignore = [
95
95
  "builtin-open",
96
96
  "complex-structure",
97
97
  "error-suffix-on-exception-name",
98
- "implicit-namespace-package",
99
98
  "import-outside-top-level",
100
99
  "incorrect-blank-line-before-class",
101
100
  "meta-class-abc-meta",
102
101
  "multi-line-summary-second-line",
103
102
  "non-empty-init-module",
104
103
  "os-replace",
105
- "too-many-branches",
106
- "too-many-locals",
107
- "too-many-statements",
108
- "unnecessary-dunder-call",
109
104
  ]
110
105
  preview = true
111
106
  select = ["ALL"]
@@ -115,6 +110,9 @@ docstring-quotes = "double"
115
110
  inline-quotes = "single"
116
111
  multiline-quotes = "double"
117
112
 
113
+ [tool.ruff.lint.flake8-annotations]
114
+ mypy-init-return = true
115
+
118
116
  [tool.ruff.lint.isort]
119
117
  combine-as-imports = true
120
118
 
@@ -123,20 +121,18 @@ combine-as-imports = true
123
121
  "D",
124
122
  "missing-type-args",
125
123
  ]
124
+ "!check_empty/__init__.py" = ["missing-copyright-notice"]
125
+ "check_empty/__init__.py" = ["PLR"]
126
+ "check_empty/__main__.py" = ["missing-return-type-private-function"]
127
+ "docs/source/conf.py" = ["implicit-namespace-package"]
126
128
  "test_check_empty.py" = [
127
129
  "ANN",
128
130
  "D",
129
131
  ]
130
- "!check_empty/__init__.py" = ["missing-copyright-notice"]
131
- "check_empty/__main__.py" = ["missing-return-type-private-function"]
132
132
 
133
133
  [tool.ruff.lint.pydocstyle]
134
134
  convention = "google"
135
135
 
136
- [tool.ruff.lint.pylint]
137
- max-args = 6
138
- max-nested-blocks = 6
139
-
140
136
  [tool.ty.analysis]
141
137
  respect-type-ignore-comments = false
142
138
 
@@ -157,7 +153,7 @@ redundant-condition = "ignore"
157
153
  unsound-assignment = "ignore"
158
154
 
159
155
  [tool.uv]
160
- required-version = ">=0.12.18"
156
+ required-version = ">=0.12.19"
161
157
 
162
158
  [tool.uv.build-backend]
163
159
  module-name = "check_empty"
@@ -1,5 +1,5 @@
1
1
  [build-system]
2
- requires = ["uv_build>=0.12.18"]
2
+ requires = ["uv_build>=0.12.19"]
3
3
  build-backend = "uv_build"
4
4
 
5
5
  [dependency-groups]
@@ -16,12 +16,12 @@ maintainers = [{name = "Jonathan Dung", email = "jonathandung@yahoo.com"}]
16
16
  name = "check-empty"
17
17
  readme = "README.md"
18
18
  requires-python = ">=3.10"
19
- version = "2.0.0"
19
+ version = "3.0.0"
20
20
 
21
21
  [project.optional-dependencies]
22
22
  "7z" = ["py7zr==1.1.3"]
23
23
  ace = ["acefile==0.6.14"]
24
- all = ["check-empty[7z,ace,ar,lzh,rar]==2.0.0"]
24
+ all = ["check-empty[7z,ace,ar,lzh,rar]==3.0.0"]
25
25
  ar = ["arpy==2.4.0"]
26
26
  lzh = ["lhafile==0.3.1"]
27
27
  rar = ["rarfile==4.5"]
@@ -30,7 +30,7 @@ rar = ["rarfile==4.5"]
30
30
  check-empty = "check_empty.__main__:main"
31
31
 
32
32
  [tool.ruff]
33
- required-version = ">=0.16.8"
33
+ required-version = ">=0.16.9"
34
34
  target-version = "py310"
35
35
 
36
36
  [tool.ruff.analyze]
@@ -40,7 +40,7 @@ type-checking-imports = false
40
40
  quote-style = "single"
41
41
 
42
42
  [tool.ruff.lint]
43
- ignore = ["COM", "FBT", "PT", "bad-quotes-inline-string", "builtin-open", "complex-structure", "error-suffix-on-exception-name", "implicit-namespace-package", "import-outside-top-level", "incorrect-blank-line-before-class", "meta-class-abc-meta", "multi-line-summary-second-line", "non-empty-init-module", "os-replace", "too-many-branches", "too-many-locals", "too-many-statements", "unnecessary-dunder-call"]
43
+ ignore = ["COM", "FBT", "PT", "bad-quotes-inline-string", "builtin-open", "complex-structure", "error-suffix-on-exception-name", "import-outside-top-level", "incorrect-blank-line-before-class", "meta-class-abc-meta", "multi-line-summary-second-line", "non-empty-init-module", "os-replace"]
44
44
  preview = true
45
45
  select = ["ALL"]
46
46
 
@@ -49,22 +49,23 @@ docstring-quotes = "double"
49
49
  inline-quotes = "single"
50
50
  multiline-quotes = "double"
51
51
 
52
+ [tool.ruff.lint.flake8-annotations]
53
+ mypy-init-return = true
54
+
52
55
  [tool.ruff.lint.isort]
53
56
  combine-as-imports = true
54
57
 
55
58
  [tool.ruff.lint.per-file-ignores]
56
59
  "action.py" = ["D", "missing-type-args"]
57
- "test_check_empty.py" = ["ANN", "D"]
58
60
  "!check_empty/__init__.py" = ["missing-copyright-notice"]
61
+ "check_empty/__init__.py" = ["PLR"]
59
62
  "check_empty/__main__.py" = ["missing-return-type-private-function"]
63
+ "docs/source/conf.py" = ["implicit-namespace-package"]
64
+ "test_check_empty.py" = ["ANN", "D"]
60
65
 
61
66
  [tool.ruff.lint.pydocstyle]
62
67
  convention = "google"
63
68
 
64
- [tool.ruff.lint.pylint]
65
- max-args = 6
66
- max-nested-blocks = 6
67
-
68
69
  [tool.ty.analysis]
69
70
  respect-type-ignore-comments = false
70
71
 
@@ -81,7 +82,7 @@ include = ["check_empty/__init__.py"]
81
82
  rules = {possibly-unresolved-reference = "ignore", redundant-condition = "ignore", unsound-assignment = "ignore"}
82
83
 
83
84
  [tool.uv]
84
- required-version = ">=0.12.18"
85
+ required-version = ">=0.12.19"
85
86
 
86
87
  [tool.uv.build-backend]
87
88
  module-name = "check_empty"
File without changes
File without changes
@@ -4,9 +4,6 @@ from __future__ import annotations
4
4
 
5
5
  import check_empty as c
6
6
 
7
- TYPE_CHECKING = False
8
- if TYPE_CHECKING:
9
- from collections.abc import Iterable
10
7
  __all__ = ('main',)
11
8
  _p = __import__('argparse').ArgumentParser(
12
9
  'check-empty',
@@ -43,6 +40,9 @@ f('-a', '--ar', action='store_true', help='recurse into .a, .ar and .lib archive
43
40
  f('-7', '--7z', action='store_true', dest='z7', help='recurse into .7z archives')
44
41
  f('-l', '--lzh', action='store_true', help='recurse into .lzh and .lha archives')
45
42
  f('-A', '--ace', action='store_true', help='recurse into .ace archives')
43
+ TYPE_CHECKING = False
44
+ if TYPE_CHECKING:
45
+ from collections.abc import Iterable
46
46
 
47
47
 
48
48
  def _r():
@@ -4,9 +4,6 @@ from __future__ import annotations
4
4
 
5
5
  import os
6
6
 
7
- TYPE_CHECKING = False
8
- if TYPE_CHECKING:
9
- from typing import Final
10
7
  __all__ = (
11
8
  'DIRFD_UNSUPPORTED',
12
9
  'ENOENT',
@@ -15,6 +12,9 @@ __all__ = (
15
12
  'TYPE_MASK',
16
13
  'RecurseInto',
17
14
  )
15
+ TYPE_CHECKING = False
16
+ if TYPE_CHECKING:
17
+ from typing import Final
18
18
  TYPE_MASK: Final = 0xF000
19
19
  """This mask extracts the type of a file from its mode bits from :func:`os.stat`."""
20
20
  S_IFDIR: Final = 0x4000