Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b0ec8ee
Updated bdb.py + test_bdb.py
terryluan12 Dec 30, 2025
91d4447
Deleted _pycodecs.py
terryluan12 Dec 30, 2025
ac9bd54
Updated code.py library
terryluan12 Dec 30, 2025
d5f6198
Updated the _pydatetime.py lib
terryluan12 Dec 30, 2025
f585018
Removed distutils package
terryluan12 Dec 30, 2025
da4a841
Updated doctest package
terryluan12 Dec 30, 2025
d7405c9
* Updated datetimetester.py
terryluan12 Dec 30, 2025
e82917e
Updated enum and test_enum.py
terryluan12 Dec 30, 2025
6e59ca5
Updated filecmp + test_filecmp
terryluan12 Dec 30, 2025
aae2dcf
Updated fractions + test_fractions
terryluan12 Dec 30, 2025
fd34286
Updated ftplib + test_ftplib
terryluan12 Dec 30, 2025
77db70c
Updated hmac + test_hmac
terryluan12 Dec 30, 2025
7c13c61
* Updated mailbox + added test_mailbox.py
terryluan12 Dec 30, 2025
3752174
Updated nturl2path.py
terryluan12 Dec 30, 2025
cd5865e
Added pathlib + test_pathlib packages
terryluan12 Dec 30, 2025
0e3365a
Updated pkgutil.py & test_pkgutil.py
terryluan12 Dec 30, 2025
d313adc
Updated platform.py + test_platform.py
terryluan12 Dec 30, 2025
6da715b
Updated plistlib + test_plistlib
terryluan12 Dec 30, 2025
2ee4e37
Merge branch 'add_tests' into update_simple_packages_2
terryluan12 Dec 30, 2025
28493a7
Updated enum and plistlib tests using the script
terryluan12 Dec 30, 2025
312f7d9
Updated pkgutil test with the script
terryluan12 Dec 30, 2025
39f990e
Ran/updated ftplib +test_hmac + pathlib tests with the script
terryluan12 Dec 30, 2025
1cd4ad6
Added comment to pathlib
terryluan12 Dec 30, 2025
88857d9
Clarified the comments at the top of test_pathlib
terryluan12 Dec 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
473 changes: 287 additions & 186 deletions Lib/enum.py

Large diffs are not rendered by default.

23 changes: 15 additions & 8 deletions Lib/filecmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,15 @@ def _do_cmp(f1, f2):
class dircmp:
"""A class that manages the comparison of 2 directories.

dircmp(a, b, ignore=None, hide=None)
dircmp(a, b, ignore=None, hide=None, *, shallow=True)
A and B are directories.
IGNORE is a list of names to ignore,
defaults to DEFAULT_IGNORES.
HIDE is a list of names to hide,
defaults to [os.curdir, os.pardir].
SHALLOW specifies whether to just check the stat signature (do not read
the files).
defaults to True.

High level usage:
x = dircmp(dir1, dir2)
Expand Down Expand Up @@ -121,7 +124,7 @@ class dircmp:
in common_dirs.
"""

def __init__(self, a, b, ignore=None, hide=None): # Initialize
def __init__(self, a, b, ignore=None, hide=None, *, shallow=True): # Initialize
self.left = a
self.right = b
if hide is None:
Expand All @@ -132,6 +135,7 @@ def __init__(self, a, b, ignore=None, hide=None): # Initialize
self.ignore = DEFAULT_IGNORES
else:
self.ignore = ignore
self.shallow = shallow

def phase0(self): # Compare everything except common subdirectories
self.left_list = _filter(os.listdir(self.left),
Expand Down Expand Up @@ -160,12 +164,14 @@ def phase2(self): # Distinguish files, directories, funnies
ok = True
try:
a_stat = os.stat(a_path)
except OSError:
except (OSError, ValueError):
# See https://github.com/python/cpython/issues/122400
# for the rationale for protecting against ValueError.
# print('Can\'t stat', a_path, ':', why.args[1])
ok = False
try:
b_stat = os.stat(b_path)
except OSError:
except (OSError, ValueError):
# print('Can\'t stat', b_path, ':', why.args[1])
ok = False

Expand All @@ -184,7 +190,7 @@ def phase2(self): # Distinguish files, directories, funnies
self.common_funny.append(x)

def phase3(self): # Find out differences between common files
xx = cmpfiles(self.left, self.right, self.common_files)
xx = cmpfiles(self.left, self.right, self.common_files, self.shallow)
self.same_files, self.diff_files, self.funny_files = xx

def phase4(self): # Find out differences between common subdirectories
Expand All @@ -196,7 +202,8 @@ def phase4(self): # Find out differences between common subdirectories
for x in self.common_dirs:
a_x = os.path.join(self.left, x)
b_x = os.path.join(self.right, x)
self.subdirs[x] = self.__class__(a_x, b_x, self.ignore, self.hide)
self.subdirs[x] = self.__class__(a_x, b_x, self.ignore, self.hide,
shallow=self.shallow)

def phase4_closure(self): # Recursively call phase4() on subdirectories
self.phase4()
Expand Down Expand Up @@ -280,12 +287,12 @@ def cmpfiles(a, b, common, shallow=True):
# Return:
# 0 for equal
# 1 for different
# 2 for funny cases (can't stat, etc.)
# 2 for funny cases (can't stat, NUL bytes, etc.)
#
def _cmp(a, b, sh, abs=abs, cmp=cmp):
try:
return not abs(cmp(a, b, sh))
except OSError:
except (OSError, ValueError):
return 2


Expand Down
107 changes: 81 additions & 26 deletions Lib/fractions.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,23 @@ def _round_to_figures(n, d, figures):
return sign, significand, exponent


# Pattern for matching non-float-style format specifications.
_GENERAL_FORMAT_SPECIFICATION_MATCHER = re.compile(r"""
(?:
(?P<fill>.)?
(?P<align>[<>=^])
)?
(?P<sign>[-+ ]?)
# Alt flag forces a slash and denominator in the output, even for
# integer-valued Fraction objects.
(?P<alt>\#)?
# We don't implement the zeropad flag since there's no single obvious way
# to interpret it.
(?P<minimumwidth>0|[1-9][0-9]*)?
(?P<thousands_sep>[,_])?
""", re.DOTALL | re.VERBOSE).fullmatch


# Pattern for matching float-style format specifications;
# supports 'e', 'E', 'f', 'F', 'g', 'G' and '%' presentation types.
_FLOAT_FORMAT_SPECIFICATION_MATCHER = re.compile(r"""
Expand Down Expand Up @@ -414,27 +431,42 @@ def __str__(self):
else:
return '%s/%s' % (self._numerator, self._denominator)

def __format__(self, format_spec, /):
"""Format this fraction according to the given format specification."""

# Backwards compatiblility with existing formatting.
if not format_spec:
return str(self)
def _format_general(self, match):
"""Helper method for __format__.

Handles fill, alignment, signs, and thousands separators in the
case of no presentation type.
"""
# Validate and parse the format specifier.
match = _FLOAT_FORMAT_SPECIFICATION_MATCHER(format_spec)
if match is None:
raise ValueError(
f"Invalid format specifier {format_spec!r} "
f"for object of type {type(self).__name__!r}"
)
elif match["align"] is not None and match["zeropad"] is not None:
# Avoid the temptation to guess.
raise ValueError(
f"Invalid format specifier {format_spec!r} "
f"for object of type {type(self).__name__!r}; "
"can't use explicit alignment when zero-padding"
)
fill = match["fill"] or " "
align = match["align"] or ">"
pos_sign = "" if match["sign"] == "-" else match["sign"]
alternate_form = bool(match["alt"])
minimumwidth = int(match["minimumwidth"] or "0")
thousands_sep = match["thousands_sep"] or ''

# Determine the body and sign representation.
n, d = self._numerator, self._denominator
if d > 1 or alternate_form:
body = f"{abs(n):{thousands_sep}}/{d:{thousands_sep}}"
else:
body = f"{abs(n):{thousands_sep}}"
sign = '-' if n < 0 else pos_sign

# Pad with fill character if necessary and return.
padding = fill * (minimumwidth - len(sign) - len(body))
if align == ">":
return padding + sign + body
elif align == "<":
return sign + body + padding
elif align == "^":
half = len(padding) // 2
return padding[:half] + sign + body + padding[half:]
else: # align == "="
return sign + padding + body

def _format_float_style(self, match):
"""Helper method for __format__; handles float presentation types."""
fill = match["fill"] or " "
align = match["align"] or ">"
pos_sign = "" if match["sign"] == "-" else match["sign"]
Expand All @@ -449,6 +481,9 @@ def __format__(self, format_spec, /):
trim_point = not alternate_form
exponent_indicator = "E" if presentation_type in "EFG" else "e"

if align == '=' and fill == '0':
zeropad = True

# Round to get the digits we need, figure out where to place the point,
# and decide whether to use scientific notation. 'point_pos' is the
# relative to the _end_ of the digit string: that is, it's the number
Expand Down Expand Up @@ -530,7 +565,25 @@ def __format__(self, format_spec, /):
else: # align == "="
return sign + padding + body

def _operator_fallbacks(monomorphic_operator, fallback_operator):
def __format__(self, format_spec, /):
"""Format this fraction according to the given format specification."""

if match := _GENERAL_FORMAT_SPECIFICATION_MATCHER(format_spec):
return self._format_general(match)

if match := _FLOAT_FORMAT_SPECIFICATION_MATCHER(format_spec):
# Refuse the temptation to guess if both alignment _and_
# zero padding are specified.
if match["align"] is None or match["zeropad"] is None:
return self._format_float_style(match)

raise ValueError(
f"Invalid format specifier {format_spec!r} "
f"for object of type {type(self).__name__!r}"
)

def _operator_fallbacks(monomorphic_operator, fallback_operator,
handle_complex=True):
"""Generates forward and reverse operators given a purely-rational
operator and a function from the operator module.

Expand Down Expand Up @@ -617,7 +670,7 @@ def forward(a, b):
return monomorphic_operator(a, Fraction(b))
elif isinstance(b, float):
return fallback_operator(float(a), b)
elif isinstance(b, complex):
elif handle_complex and isinstance(b, complex):
return fallback_operator(complex(a), b)
else:
return NotImplemented
Expand All @@ -630,7 +683,7 @@ def reverse(b, a):
return monomorphic_operator(Fraction(a), b)
elif isinstance(a, numbers.Real):
return fallback_operator(float(a), float(b))
elif isinstance(a, numbers.Complex):
elif handle_complex and isinstance(a, numbers.Complex):
return fallback_operator(complex(a), complex(b))
else:
return NotImplemented
Expand Down Expand Up @@ -781,22 +834,22 @@ def _floordiv(a, b):
"""a // b"""
return (a.numerator * b.denominator) // (a.denominator * b.numerator)

__floordiv__, __rfloordiv__ = _operator_fallbacks(_floordiv, operator.floordiv)
__floordiv__, __rfloordiv__ = _operator_fallbacks(_floordiv, operator.floordiv, False)

def _divmod(a, b):
"""(a // b, a % b)"""
da, db = a.denominator, b.denominator
div, n_mod = divmod(a.numerator * db, da * b.numerator)
return div, Fraction(n_mod, da * db)

__divmod__, __rdivmod__ = _operator_fallbacks(_divmod, divmod)
__divmod__, __rdivmod__ = _operator_fallbacks(_divmod, divmod, False)

def _mod(a, b):
"""a % b"""
da, db = a.denominator, b.denominator
return Fraction((a.numerator * db) % (b.numerator * da), da * db)

__mod__, __rmod__ = _operator_fallbacks(_mod, operator.mod)
__mod__, __rmod__ = _operator_fallbacks(_mod, operator.mod, False)

def __pow__(a, b):
"""a ** b
Expand Down Expand Up @@ -825,8 +878,10 @@ def __pow__(a, b):
# A fractional power will generally produce an
# irrational number.
return float(a) ** float(b)
else:
elif isinstance(b, (float, complex)):
return float(a) ** b
else:
return NotImplemented

def __rpow__(b, a):
"""a ** b"""
Expand Down
27 changes: 17 additions & 10 deletions Lib/ftplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -900,11 +900,17 @@ def ftpcp(source, sourcename, target, targetname = '', type = 'I'):

def test():
'''Test program.
Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...
Usage: ftplib [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...

-d dir
-l list
-p password
Options:
-d increase debugging level
-r[file] set alternate ~/.netrc file

Commands:
-l[dir] list directory
-d[dir] change the current directory
-p toggle passive and active mode
file retrieve the file and write it to stdout
'''

if len(sys.argv) < 2:
Expand All @@ -930,15 +936,14 @@ def test():
netrcobj = netrc.netrc(rcfile)
except OSError:
if rcfile is not None:
sys.stderr.write("Could not open account file"
" -- using anonymous login.")
print("Could not open account file -- using anonymous login.",
file=sys.stderr)
else:
try:
userid, acct, passwd = netrcobj.authenticators(host)
except KeyError:
except (KeyError, TypeError):
# no account for host
sys.stderr.write(
"No account -- using anonymous login.")
print("No account -- using anonymous login.", file=sys.stderr)
ftp.login(userid, passwd, acct)
for file in sys.argv[2:]:
if file[:2] == '-l':
Expand All @@ -951,7 +956,9 @@ def test():
ftp.set_pasv(not ftp.passiveserver)
else:
ftp.retrbinary('RETR ' + file, \
sys.stdout.write, 1024)
sys.stdout.buffer.write, 1024)
sys.stdout.buffer.flush()
sys.stdout.flush()
ftp.quit()


Expand Down
2 changes: 1 addition & 1 deletion Lib/hmac.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def __init__(self, key, msg=None, digestmod=''):
raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)

if not digestmod:
raise TypeError("Missing required parameter 'digestmod'.")
raise TypeError("Missing required argument 'digestmod'.")

if _hashopenssl and isinstance(digestmod, (str, _functype)):
try:
Expand Down
Loading
Loading