Skip to content

Commit 91ff758

Browse files
committed
stdlib: Fix missing overloads in tarfile.TarFile to prevent None/None case
Add proper overloads to TarFile.__init__, open, taropen, gzopen, bz2open, and xzopen to ensure that at least one of `name` or `fileobj` parameters is not None. This prevents mypy from accepting invalid calls like `tarfile.TarFile(None, fileobj=None)` which would cause runtime errors. Fixes python#14168
1 parent c7e29ec commit 91ff758

File tree

1 file changed

+170
-8
lines changed

1 file changed

+170
-8
lines changed

stdlib/tarfile.pyi

Lines changed: 170 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,11 @@ class TarFile:
125125
extraction_filter: _FilterFunction | None
126126
if sys.version_info >= (3, 13):
127127
stream: bool
128+
# Ensure that at least one of name or fileobj is not None
129+
@overload
128130
def __init__(
129131
self,
130-
name: StrOrBytesPath | None = None,
132+
name: StrOrBytesPath,
131133
mode: Literal["r", "a", "w", "x"] = "r",
132134
fileobj: _Fileobj | None = None,
133135
format: int | None = None,
@@ -142,10 +144,30 @@ class TarFile:
142144
copybufsize: int | None = None, # undocumented
143145
stream: bool = False,
144146
) -> None: ...
147+
@overload
148+
def __init__(
149+
self,
150+
name: None = None,
151+
mode: Literal["r", "a", "w", "x"] = "r",
152+
fileobj: _Fileobj = ...,
153+
format: int | None = None,
154+
tarinfo: type[TarInfo] | None = None,
155+
dereference: bool | None = None,
156+
ignore_zeros: bool | None = None,
157+
encoding: str | None = None,
158+
errors: str = "surrogateescape",
159+
pax_headers: Mapping[str, str] | None = None,
160+
debug: int | None = None,
161+
errorlevel: int | None = None,
162+
copybufsize: int | None = None, # undocumented
163+
stream: bool = False,
164+
) -> None: ...
145165
else:
166+
# Ensure that at least one of name or fileobj is not None
167+
@overload
146168
def __init__(
147169
self,
148-
name: StrOrBytesPath | None = None,
170+
name: StrOrBytesPath,
149171
mode: Literal["r", "a", "w", "x"] = "r",
150172
fileobj: _Fileobj | None = None,
151173
format: int | None = None,
@@ -159,17 +181,35 @@ class TarFile:
159181
errorlevel: int | None = None,
160182
copybufsize: int | None = None, # undocumented
161183
) -> None: ...
184+
@overload
185+
def __init__(
186+
self,
187+
name: None = None,
188+
mode: Literal["r", "a", "w", "x"] = "r",
189+
fileobj: _Fileobj = ...,
190+
format: int | None = None,
191+
tarinfo: type[TarInfo] | None = None,
192+
dereference: bool | None = None,
193+
ignore_zeros: bool | None = None,
194+
encoding: str | None = None,
195+
errors: str = "surrogateescape",
196+
pax_headers: Mapping[str, str] | None = None,
197+
debug: int | None = None,
198+
errorlevel: int | None = None,
199+
copybufsize: int | None = None, # undocumented
200+
) -> None: ...
162201

163202
def __enter__(self) -> Self: ...
164203
def __exit__(
165204
self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None
166205
) -> None: ...
167206
def __iter__(self) -> Iterator[TarInfo]: ...
207+
# Ensure that at least one of name or fileobj is not None
168208
@overload
169209
@classmethod
170210
def open(
171211
cls,
172-
name: StrOrBytesPath | None = None,
212+
name: StrOrBytesPath,
173213
mode: Literal["r", "r:*", "r:", "r:gz", "r:bz2", "r:xz"] = "r",
174214
fileobj: _Fileobj | None = None,
175215
bufsize: int = 10240,
@@ -184,6 +224,26 @@ class TarFile:
184224
debug: int | None = ...,
185225
errorlevel: int | None = ...,
186226
) -> Self: ...
227+
228+
@overload
229+
@classmethod
230+
def open(
231+
cls,
232+
name: None = None,
233+
mode: Literal["r", "r:*", "r:", "r:gz", "r:bz2", "r:xz"] = "r",
234+
fileobj: _Fileobj = ...,
235+
bufsize: int = 10240,
236+
*,
237+
format: int | None = ...,
238+
tarinfo: type[TarInfo] | None = ...,
239+
dereference: bool | None = ...,
240+
ignore_zeros: bool | None = ...,
241+
encoding: str | None = ...,
242+
errors: str = ...,
243+
pax_headers: Mapping[str, str] | None = ...,
244+
debug: int | None = ...,
245+
errorlevel: int | None = ...,
246+
) -> Self: ...
187247
@overload
188248
@classmethod
189249
def open(
@@ -418,10 +478,12 @@ class TarFile:
418478
errorlevel: int | None = ...,
419479
compresslevel: int = 9,
420480
) -> Self: ...
481+
# Ensure that at least one of name or fileobj is not None
482+
@overload
421483
@classmethod
422484
def taropen(
423485
cls,
424-
name: StrOrBytesPath | None,
486+
name: StrOrBytesPath,
425487
mode: Literal["r", "a", "w", "x"] = "r",
426488
fileobj: _Fileobj | None = None,
427489
*,
@@ -435,11 +497,31 @@ class TarFile:
435497
debug: int | None = ...,
436498
errorlevel: int | None = ...,
437499
) -> Self: ...
500+
501+
@overload
502+
@classmethod
503+
def taropen(
504+
cls,
505+
name: None = None,
506+
mode: Literal["r", "a", "w", "x"] = "r",
507+
fileobj: _Fileobj = ...,
508+
*,
509+
compresslevel: int = ...,
510+
format: int | None = ...,
511+
tarinfo: type[TarInfo] | None = ...,
512+
dereference: bool | None = ...,
513+
ignore_zeros: bool | None = ...,
514+
encoding: str | None = ...,
515+
pax_headers: Mapping[str, str] | None = ...,
516+
debug: int | None = ...,
517+
errorlevel: int | None = ...,
518+
) -> Self: ...
519+
# Ensure that at least one of name or fileobj is not None
438520
@overload
439521
@classmethod
440522
def gzopen(
441523
cls,
442-
name: StrOrBytesPath | None,
524+
name: StrOrBytesPath,
443525
mode: Literal["r"] = "r",
444526
fileobj: _GzipReadableFileobj | None = None,
445527
compresslevel: int = 9,
@@ -453,6 +535,25 @@ class TarFile:
453535
debug: int | None = ...,
454536
errorlevel: int | None = ...,
455537
) -> Self: ...
538+
539+
@overload
540+
@classmethod
541+
def gzopen(
542+
cls,
543+
name: None = None,
544+
mode: Literal["r"] = "r",
545+
fileobj: _GzipReadableFileobj = ...,
546+
compresslevel: int = 9,
547+
*,
548+
format: int | None = ...,
549+
tarinfo: type[TarInfo] | None = ...,
550+
dereference: bool | None = ...,
551+
ignore_zeros: bool | None = ...,
552+
encoding: str | None = ...,
553+
pax_headers: Mapping[str, str] | None = ...,
554+
debug: int | None = ...,
555+
errorlevel: int | None = ...,
556+
) -> Self: ...
456557
@overload
457558
@classmethod
458559
def gzopen(
@@ -471,11 +572,12 @@ class TarFile:
471572
debug: int | None = ...,
472573
errorlevel: int | None = ...,
473574
) -> Self: ...
575+
# Ensure that at least one of name or fileobj is not None
474576
@overload
475577
@classmethod
476578
def bz2open(
477579
cls,
478-
name: StrOrBytesPath | None,
580+
name: StrOrBytesPath,
479581
mode: Literal["w", "x"],
480582
fileobj: _Bz2WritableFileobj | None = None,
481583
compresslevel: int = 9,
@@ -489,11 +591,31 @@ class TarFile:
489591
debug: int | None = ...,
490592
errorlevel: int | None = ...,
491593
) -> Self: ...
594+
492595
@overload
493596
@classmethod
494597
def bz2open(
495598
cls,
496-
name: StrOrBytesPath | None,
599+
name: None = None,
600+
mode: Literal["w", "x"] = ...,
601+
fileobj: _Bz2WritableFileobj = ...,
602+
compresslevel: int = 9,
603+
*,
604+
format: int | None = ...,
605+
tarinfo: type[TarInfo] | None = ...,
606+
dereference: bool | None = ...,
607+
ignore_zeros: bool | None = ...,
608+
encoding: str | None = ...,
609+
pax_headers: Mapping[str, str] | None = ...,
610+
debug: int | None = ...,
611+
errorlevel: int | None = ...,
612+
) -> Self: ...
613+
# Ensure that at least one of name or fileobj is not None
614+
@overload
615+
@classmethod
616+
def bz2open(
617+
cls,
618+
name: StrOrBytesPath,
497619
mode: Literal["r"] = "r",
498620
fileobj: _Bz2ReadableFileobj | None = None,
499621
compresslevel: int = 9,
@@ -507,10 +629,31 @@ class TarFile:
507629
debug: int | None = ...,
508630
errorlevel: int | None = ...,
509631
) -> Self: ...
632+
633+
@overload
634+
@classmethod
635+
def bz2open(
636+
cls,
637+
name: None = None,
638+
mode: Literal["r"] = "r",
639+
fileobj: _Bz2ReadableFileobj = ...,
640+
compresslevel: int = 9,
641+
*,
642+
format: int | None = ...,
643+
tarinfo: type[TarInfo] | None = ...,
644+
dereference: bool | None = ...,
645+
ignore_zeros: bool | None = ...,
646+
encoding: str | None = ...,
647+
pax_headers: Mapping[str, str] | None = ...,
648+
debug: int | None = ...,
649+
errorlevel: int | None = ...,
650+
) -> Self: ...
651+
# Ensure that at least one of name or fileobj is not None
652+
@overload
510653
@classmethod
511654
def xzopen(
512655
cls,
513-
name: StrOrBytesPath | None,
656+
name: StrOrBytesPath,
514657
mode: Literal["r", "w", "x"] = "r",
515658
fileobj: IO[bytes] | None = None,
516659
preset: int | None = None,
@@ -524,6 +667,25 @@ class TarFile:
524667
debug: int | None = ...,
525668
errorlevel: int | None = ...,
526669
) -> Self: ...
670+
671+
@overload
672+
@classmethod
673+
def xzopen(
674+
cls,
675+
name: None = None,
676+
mode: Literal["r", "w", "x"] = "r",
677+
fileobj: IO[bytes] = ...,
678+
preset: int | None = None,
679+
*,
680+
format: int | None = ...,
681+
tarinfo: type[TarInfo] | None = ...,
682+
dereference: bool | None = ...,
683+
ignore_zeros: bool | None = ...,
684+
encoding: str | None = ...,
685+
pax_headers: Mapping[str, str] | None = ...,
686+
debug: int | None = ...,
687+
errorlevel: int | None = ...,
688+
) -> Self: ...
527689
def getmember(self, name: str) -> TarInfo: ...
528690
def getmembers(self) -> _list[TarInfo]: ...
529691
def getnames(self) -> _list[str]: ...

0 commit comments

Comments
 (0)