mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Update the fractions and ftplib libraries + associated tests - v.3.13.10 (#6607)
* Updated ftplib + test library * Updated fractions + test library
This commit is contained in:
1 parent
52dd8292c4
commit
5ae75a679b
4 files changed
+338
-197
No files matched your search
Vendored
+81
-26
@@ -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"""
|
||||
@@ -414,27 +431,42 @@ class Fraction(numbers.Rational):
|
||||
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"]
|
||||
@@ -449,6 +481,9 @@ class Fraction(numbers.Rational):
|
||||
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
|
||||
@@ -530,7 +565,25 @@ class Fraction(numbers.Rational):
|
||||
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.
|
||||
|
||||
@@ -617,7 +670,7 @@ class Fraction(numbers.Rational):
|
||||
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
|
||||
@@ -630,7 +683,7 @@ class Fraction(numbers.Rational):
|
||||
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
|
||||
@@ -781,7 +834,7 @@ class Fraction(numbers.Rational):
|
||||
"""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)"""
|
||||
@@ -789,14 +842,14 @@ class Fraction(numbers.Rational):
|
||||
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
|
||||
@@ -825,8 +878,10 @@ class Fraction(numbers.Rational):
|
||||
# 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"""
|
||||
|
||||
Vendored
+17
-10
@@ -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:
|
||||
@@ -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':
|
||||
@@ -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()
|
||||
|
||||
|
||||
|
||||
Vendored
+186
-129
@@ -2,7 +2,7 @@
|
||||
|
||||
import cmath
|
||||
from decimal import Decimal
|
||||
# from test.support import requires_IEEE_754
|
||||
from test.support import requires_IEEE_754, adjust_int_max_str_digits
|
||||
import math
|
||||
import numbers
|
||||
import operator
|
||||
@@ -19,7 +19,7 @@ F = fractions.Fraction
|
||||
|
||||
#locate file with float format test values
|
||||
test_dir = os.path.dirname(__file__) or os.curdir
|
||||
format_testfile = os.path.join(test_dir, 'formatfloat_testcases.txt')
|
||||
format_testfile = os.path.join(test_dir, 'mathdata', 'formatfloat_testcases.txt')
|
||||
|
||||
class DummyFloat(object):
|
||||
"""Dummy float class for testing comparisons with Fractions"""
|
||||
@@ -97,7 +97,7 @@ def typed_approx_eq(a, b):
|
||||
|
||||
class Symbolic:
|
||||
"""Simple non-numeric class for testing mixed arithmetic.
|
||||
It is not Integral, Rational, Real or Complex, and cannot be conveted
|
||||
It is not Integral, Rational, Real or Complex, and cannot be converted
|
||||
to int, float or complex. but it supports some arithmetic operations.
|
||||
"""
|
||||
def __init__(self, value):
|
||||
@@ -331,7 +331,7 @@ class FractionTest(unittest.TestCase):
|
||||
self.assertRaises(TypeError, F, 3, 1j)
|
||||
self.assertRaises(TypeError, F, 1, 2, 3)
|
||||
|
||||
# @requires_IEEE_754
|
||||
@requires_IEEE_754
|
||||
def testInitFromFloat(self):
|
||||
self.assertEqual((5, 2), _components(F(2.5)))
|
||||
self.assertEqual((0, 1), _components(F(-0.0)))
|
||||
@@ -357,12 +357,14 @@ class FractionTest(unittest.TestCase):
|
||||
|
||||
def testFromString(self):
|
||||
self.assertEqual((5, 1), _components(F("5")))
|
||||
self.assertEqual((5, 1), _components(F("005")))
|
||||
self.assertEqual((3, 2), _components(F("3/2")))
|
||||
self.assertEqual((3, 2), _components(F("3 / 2")))
|
||||
self.assertEqual((3, 2), _components(F(" \n +3/2")))
|
||||
self.assertEqual((-3, 2), _components(F("-3/2 ")))
|
||||
self.assertEqual((13, 2), _components(F(" 013/02 \n ")))
|
||||
self.assertEqual((13, 2), _components(F(" 0013/002 \n ")))
|
||||
self.assertEqual((16, 5), _components(F(" 3.2 ")))
|
||||
self.assertEqual((16, 5), _components(F("003.2")))
|
||||
self.assertEqual((-16, 5), _components(F(" -3.2 ")))
|
||||
self.assertEqual((-3, 1), _components(F(" -3. ")))
|
||||
self.assertEqual((3, 5), _components(F(" .6 ")))
|
||||
@@ -381,116 +383,102 @@ class FractionTest(unittest.TestCase):
|
||||
self.assertRaisesMessage(
|
||||
ZeroDivisionError, "Fraction(3, 0)",
|
||||
F, "3/0")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '3/'",
|
||||
F, "3/")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '/2'",
|
||||
F, "/2")
|
||||
self.assertRaisesMessage(
|
||||
# Denominators don't need a sign.
|
||||
ValueError, "Invalid literal for Fraction: '3/+2'",
|
||||
F, "3/+2")
|
||||
self.assertRaisesMessage(
|
||||
# Imitate float's parsing.
|
||||
ValueError, "Invalid literal for Fraction: '+ 3/2'",
|
||||
F, "+ 3/2")
|
||||
self.assertRaisesMessage(
|
||||
# Avoid treating '.' as a regex special character.
|
||||
ValueError, "Invalid literal for Fraction: '3a2'",
|
||||
F, "3a2")
|
||||
self.assertRaisesMessage(
|
||||
# Don't accept combinations of decimals and rationals.
|
||||
ValueError, "Invalid literal for Fraction: '3/7.2'",
|
||||
F, "3/7.2")
|
||||
self.assertRaisesMessage(
|
||||
# Don't accept combinations of decimals and rationals.
|
||||
ValueError, "Invalid literal for Fraction: '3.2/7'",
|
||||
F, "3.2/7")
|
||||
self.assertRaisesMessage(
|
||||
# Allow 3. and .3, but not .
|
||||
ValueError, "Invalid literal for Fraction: '.'",
|
||||
F, ".")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '_'",
|
||||
F, "_")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '_1'",
|
||||
F, "_1")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1__2'",
|
||||
F, "1__2")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '/_'",
|
||||
F, "/_")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1_/'",
|
||||
F, "1_/")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '_1/'",
|
||||
F, "_1/")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1__2/'",
|
||||
F, "1__2/")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1/_'",
|
||||
F, "1/_")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1/_1'",
|
||||
F, "1/_1")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1/1__2'",
|
||||
F, "1/1__2")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1._111'",
|
||||
F, "1._111")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1.1__1'",
|
||||
F, "1.1__1")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1.1e+_1'",
|
||||
F, "1.1e+_1")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1.1e+1__1'",
|
||||
F, "1.1e+1__1")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '123.dd'",
|
||||
F, "123.dd")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '123.5_dd'",
|
||||
F, "123.5_dd")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: 'dd.5'",
|
||||
F, "dd.5")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '7_dd'",
|
||||
F, "7_dd")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1/dd'",
|
||||
F, "1/dd")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1/123_dd'",
|
||||
F, "1/123_dd")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '789edd'",
|
||||
F, "789edd")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '789e2_dd'",
|
||||
F, "789e2_dd")
|
||||
|
||||
def check_invalid(s):
|
||||
msg = "Invalid literal for Fraction: " + repr(s)
|
||||
self.assertRaisesMessage(ValueError, msg, F, s)
|
||||
|
||||
check_invalid("3/")
|
||||
check_invalid("/2")
|
||||
# Denominators don't need a sign.
|
||||
check_invalid("3/+2")
|
||||
check_invalid("3/-2")
|
||||
# Imitate float's parsing.
|
||||
check_invalid("+ 3/2")
|
||||
check_invalid("- 3/2")
|
||||
# Avoid treating '.' as a regex special character.
|
||||
check_invalid("3a2")
|
||||
# Don't accept combinations of decimals and rationals.
|
||||
check_invalid("3/7.2")
|
||||
check_invalid("3.2/7")
|
||||
# No space around dot.
|
||||
check_invalid("3 .2")
|
||||
check_invalid("3. 2")
|
||||
# No space around e.
|
||||
check_invalid("3.2 e1")
|
||||
check_invalid("3.2e 1")
|
||||
# Fractional part don't need a sign.
|
||||
check_invalid("3.+2")
|
||||
check_invalid("3.-2")
|
||||
# Only accept base 10.
|
||||
check_invalid("0x10")
|
||||
check_invalid("0x10/1")
|
||||
check_invalid("1/0x10")
|
||||
check_invalid("0x10.")
|
||||
check_invalid("0x10.1")
|
||||
check_invalid("1.0x10")
|
||||
check_invalid("1.0e0x10")
|
||||
# Only accept decimal digits.
|
||||
check_invalid("³")
|
||||
check_invalid("³/2")
|
||||
check_invalid("3/²")
|
||||
check_invalid("³.2")
|
||||
check_invalid("3.²")
|
||||
check_invalid("3.2e²")
|
||||
check_invalid("¼")
|
||||
# Allow 3. and .3, but not .
|
||||
check_invalid(".")
|
||||
check_invalid("_")
|
||||
check_invalid("_1")
|
||||
check_invalid("1__2")
|
||||
check_invalid("/_")
|
||||
check_invalid("1_/")
|
||||
check_invalid("_1/")
|
||||
check_invalid("1__2/")
|
||||
check_invalid("1/_")
|
||||
check_invalid("1/_1")
|
||||
check_invalid("1/1__2")
|
||||
check_invalid("1._111")
|
||||
check_invalid("1.1__1")
|
||||
check_invalid("1.1e+_1")
|
||||
check_invalid("1.1e+1__1")
|
||||
check_invalid("123.dd")
|
||||
check_invalid("123.5_dd")
|
||||
check_invalid("dd.5")
|
||||
check_invalid("7_dd")
|
||||
check_invalid("1/dd")
|
||||
check_invalid("1/123_dd")
|
||||
check_invalid("789edd")
|
||||
check_invalid("789e2_dd")
|
||||
# Test catastrophic backtracking.
|
||||
val = "9"*50 + "_"
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '" + val + "'",
|
||||
F, val)
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1/" + val + "'",
|
||||
F, "1/" + val)
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1." + val + "'",
|
||||
F, "1." + val)
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Fraction: '1.1+e" + val + "'",
|
||||
F, "1.1+e" + val)
|
||||
check_invalid(val)
|
||||
check_invalid("1/" + val)
|
||||
check_invalid("1." + val)
|
||||
check_invalid("." + val)
|
||||
check_invalid("1.1+e" + val)
|
||||
check_invalid("1.1e" + val)
|
||||
|
||||
def test_limit_int(self):
|
||||
maxdigits = 5000
|
||||
with adjust_int_max_str_digits(maxdigits):
|
||||
msg = 'Exceeds the limit'
|
||||
val = '1' * maxdigits
|
||||
num = (10**maxdigits - 1)//9
|
||||
self.assertEqual((num, 1), _components(F(val)))
|
||||
self.assertRaisesRegex(ValueError, msg, F, val + '1')
|
||||
self.assertEqual((num, 2), _components(F(val + '/2')))
|
||||
self.assertRaisesRegex(ValueError, msg, F, val + '1/2')
|
||||
self.assertEqual((1, num), _components(F('1/' + val)))
|
||||
self.assertRaisesRegex(ValueError, msg, F, '1/1' + val)
|
||||
self.assertEqual(((10**(maxdigits+1) - 1)//9, 10**maxdigits),
|
||||
_components(F('1.' + val)))
|
||||
self.assertRaisesRegex(ValueError, msg, F, '1.1' + val)
|
||||
self.assertEqual((num, 10**maxdigits), _components(F('.' + val)))
|
||||
self.assertRaisesRegex(ValueError, msg, F, '.1' + val)
|
||||
self.assertRaisesRegex(ValueError, msg, F, '1.1e1' + val)
|
||||
self.assertEqual((11, 10), _components(F('1.1e' + '0' * maxdigits)))
|
||||
self.assertRaisesRegex(ValueError, msg, F, '1.1e' + '0' * (maxdigits+1))
|
||||
|
||||
def testImmutable(self):
|
||||
r = F(7, 3)
|
||||
@@ -922,21 +910,21 @@ class FractionTest(unittest.TestCase):
|
||||
self.assertTypedEquals(Root(4) ** F(2, 1), Root(4, F(1)))
|
||||
self.assertTypedEquals(Root(4) ** F(-2, 1), Root(4, -F(1)))
|
||||
self.assertTypedEquals(Root(4) ** F(-2, 3), Root(4, -3.0))
|
||||
self.assertEqual(F(3, 2) ** SymbolicReal('X'), SymbolicReal('1.5 ** X'))
|
||||
self.assertEqual(F(3, 2) ** SymbolicReal('X'), SymbolicReal('3/2 ** X'))
|
||||
self.assertEqual(SymbolicReal('X') ** F(3, 2), SymbolicReal('X ** 1.5'))
|
||||
|
||||
self.assertTypedEquals(F(3, 2) ** Rect(2, 0), Polar(2.25, 0.0))
|
||||
self.assertTypedEquals(F(1, 1) ** Rect(2, 3), Polar(1.0, 0.0))
|
||||
self.assertTypedEquals(F(3, 2) ** Rect(2, 0), Polar(F(9,4), 0.0))
|
||||
self.assertTypedEquals(F(1, 1) ** Rect(2, 3), Polar(F(1), 0.0))
|
||||
self.assertTypedEquals(F(3, 2) ** RectComplex(2, 0), Polar(2.25, 0.0))
|
||||
self.assertTypedEquals(F(1, 1) ** RectComplex(2, 3), Polar(1.0, 0.0))
|
||||
self.assertTypedEquals(Polar(4, 2) ** F(3, 2), Polar(8.0, 3.0))
|
||||
self.assertTypedEquals(Polar(4, 2) ** F(3, 1), Polar(64, 6))
|
||||
self.assertTypedEquals(Polar(4, 2) ** F(-3, 1), Polar(0.015625, -6))
|
||||
self.assertTypedEquals(Polar(4, 2) ** F(-3, 2), Polar(0.125, -3.0))
|
||||
self.assertEqual(F(3, 2) ** SymbolicComplex('X'), SymbolicComplex('1.5 ** X'))
|
||||
self.assertEqual(F(3, 2) ** SymbolicComplex('X'), SymbolicComplex('3/2 ** X'))
|
||||
self.assertEqual(SymbolicComplex('X') ** F(3, 2), SymbolicComplex('X ** 1.5'))
|
||||
|
||||
self.assertEqual(F(3, 2) ** Symbolic('X'), Symbolic('1.5 ** X'))
|
||||
self.assertEqual(F(3, 2) ** Symbolic('X'), Symbolic('3/2 ** X'))
|
||||
self.assertEqual(Symbolic('X') ** F(3, 2), Symbolic('X ** 1.5'))
|
||||
|
||||
def testMixingWithDecimal(self):
|
||||
@@ -1165,12 +1153,50 @@ class FractionTest(unittest.TestCase):
|
||||
self.assertEqual(type(f.denominator), myint)
|
||||
|
||||
def test_format_no_presentation_type(self):
|
||||
# Triples (fraction, specification, expected_result)
|
||||
# Triples (fraction, specification, expected_result).
|
||||
testcases = [
|
||||
(F(1, 3), '', '1/3'),
|
||||
(F(-1, 3), '', '-1/3'),
|
||||
(F(3), '', '3'),
|
||||
(F(-3), '', '-3'),
|
||||
# Explicit sign handling
|
||||
(F(2, 3), '+', '+2/3'),
|
||||
(F(-2, 3), '+', '-2/3'),
|
||||
(F(3), '+', '+3'),
|
||||
(F(-3), '+', '-3'),
|
||||
(F(2, 3), ' ', ' 2/3'),
|
||||
(F(-2, 3), ' ', '-2/3'),
|
||||
(F(3), ' ', ' 3'),
|
||||
(F(-3), ' ', '-3'),
|
||||
(F(2, 3), '-', '2/3'),
|
||||
(F(-2, 3), '-', '-2/3'),
|
||||
(F(3), '-', '3'),
|
||||
(F(-3), '-', '-3'),
|
||||
# Padding
|
||||
(F(0), '5', ' 0'),
|
||||
(F(2, 3), '5', ' 2/3'),
|
||||
(F(-2, 3), '5', ' -2/3'),
|
||||
(F(2, 3), '0', '2/3'),
|
||||
(F(2, 3), '1', '2/3'),
|
||||
(F(2, 3), '2', '2/3'),
|
||||
# Alignment
|
||||
(F(2, 3), '<5', '2/3 '),
|
||||
(F(2, 3), '>5', ' 2/3'),
|
||||
(F(2, 3), '^5', ' 2/3 '),
|
||||
(F(2, 3), '=5', ' 2/3'),
|
||||
(F(-2, 3), '<5', '-2/3 '),
|
||||
(F(-2, 3), '>5', ' -2/3'),
|
||||
(F(-2, 3), '^5', '-2/3 '),
|
||||
(F(-2, 3), '=5', '- 2/3'),
|
||||
# Fill
|
||||
(F(2, 3), 'X>5', 'XX2/3'),
|
||||
(F(-2, 3), '.<5', '-2/3.'),
|
||||
(F(-2, 3), '\n^6', '\n-2/3\n'),
|
||||
# Thousands separators
|
||||
(F(1234, 5679), ',', '1,234/5,679'),
|
||||
(F(-1234, 5679), '_', '-1_234/5_679'),
|
||||
(F(1234567), '_', '1_234_567'),
|
||||
(F(-1234567), ',', '-1,234,567'),
|
||||
# Alternate form forces a slash in the output
|
||||
(F(123), '#', '123/1'),
|
||||
(F(-123), '#', '-123/1'),
|
||||
(F(0), '#', '0/1'),
|
||||
]
|
||||
for fraction, spec, expected in testcases:
|
||||
with self.subTest(fraction=fraction, spec=spec):
|
||||
@@ -1385,11 +1411,8 @@ class FractionTest(unittest.TestCase):
|
||||
(F('-1234.5678'), '08,.0f', '-001,235'),
|
||||
(F('-1234.5678'), '09,.0f', '-0,001,235'),
|
||||
# Corner-case - zero-padding specified through fill and align
|
||||
# instead of the zero-pad character - in this case, treat '0' as a
|
||||
# regular fill character and don't attempt to insert commas into
|
||||
# the filled portion. This differs from the int and float
|
||||
# behaviour.
|
||||
(F('1234.5678'), '0=12,.2f', '00001,234.57'),
|
||||
# instead of the zero-pad character.
|
||||
(F('1234.5678'), '0=12,.2f', '0,001,234.57'),
|
||||
# Corner case where it's not clear whether the '0' indicates zero
|
||||
# padding or gives the minimum width, but there's still an obvious
|
||||
# answer to give. We want this to work in case the minimum width
|
||||
@@ -1534,13 +1557,17 @@ class FractionTest(unittest.TestCase):
|
||||
'.%',
|
||||
# Z instead of z for negative zero suppression
|
||||
'Z.2f'
|
||||
# z flag not supported for general formatting
|
||||
'z',
|
||||
# zero padding not supported for general formatting
|
||||
'05',
|
||||
]
|
||||
for spec in invalid_specs:
|
||||
with self.subTest(spec=spec):
|
||||
with self.assertRaises(ValueError):
|
||||
format(fraction, spec)
|
||||
|
||||
# @requires_IEEE_754
|
||||
@requires_IEEE_754
|
||||
def test_float_format_testfile(self):
|
||||
with open(format_testfile, encoding="utf-8") as testfile:
|
||||
for line in testfile:
|
||||
@@ -1564,6 +1591,36 @@ class FractionTest(unittest.TestCase):
|
||||
self.assertEqual(float(format(f, fmt2)), float(rhs))
|
||||
self.assertEqual(float(format(-f, fmt2)), float('-' + rhs))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
# TypeError: '%' not supported between instances of 'Fraction' and 'complex'
|
||||
@unittest.expectedFailure
|
||||
def test_complex_handling(self):
|
||||
# See issue gh-102840 for more details.
|
||||
|
||||
a = F(1, 2)
|
||||
b = 1j
|
||||
message = "unsupported operand type(s) for %s: '%s' and '%s'"
|
||||
# test forward
|
||||
self.assertRaisesMessage(TypeError,
|
||||
message % ("%", "Fraction", "complex"),
|
||||
operator.mod, a, b)
|
||||
self.assertRaisesMessage(TypeError,
|
||||
message % ("//", "Fraction", "complex"),
|
||||
operator.floordiv, a, b)
|
||||
self.assertRaisesMessage(TypeError,
|
||||
message % ("divmod()", "Fraction", "complex"),
|
||||
divmod, a, b)
|
||||
# test reverse
|
||||
self.assertRaisesMessage(TypeError,
|
||||
message % ("%", "complex", "Fraction"),
|
||||
operator.mod, b, a)
|
||||
self.assertRaisesMessage(TypeError,
|
||||
message % ("//", "complex", "Fraction"),
|
||||
operator.floordiv, b, a)
|
||||
self.assertRaisesMessage(TypeError,
|
||||
message % ("divmod()", "complex", "Fraction"),
|
||||
divmod, b, a)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Vendored
+54
-32
@@ -18,6 +18,7 @@ except ImportError:
|
||||
|
||||
from unittest import TestCase, skipUnless
|
||||
from test import support
|
||||
from test.support import requires_subprocess
|
||||
from test.support import threading_helper
|
||||
from test.support import socket_helper
|
||||
from test.support import warnings_helper
|
||||
@@ -32,7 +33,7 @@ TIMEOUT = support.LOOPBACK_TIMEOUT
|
||||
DEFAULT_ENCODING = 'utf-8'
|
||||
# the dummy data returned by server over the data channel when
|
||||
# RETR, LIST, NLST, MLSD commands are issued
|
||||
RETR_DATA = 'abcde12345\r\n' * 1000 + 'non-ascii char \xAE\r\n'
|
||||
RETR_DATA = 'abcde\xB9\xB2\xB3\xA4\xA6\r\n' * 1000
|
||||
LIST_DATA = 'foo\r\nbar\r\n non-ascii char \xAE\r\n'
|
||||
NLST_DATA = 'foo\r\nbar\r\n non-ascii char \xAE\r\n'
|
||||
MLSD_DATA = ("type=cdir;perm=el;unique==keVO1+ZF4; test\r\n"
|
||||
@@ -67,11 +68,11 @@ class DummyDTPHandler(asynchat.async_chat):
|
||||
def __init__(self, conn, baseclass):
|
||||
asynchat.async_chat.__init__(self, conn)
|
||||
self.baseclass = baseclass
|
||||
self.baseclass.last_received_data = ''
|
||||
self.baseclass.last_received_data = bytearray()
|
||||
self.encoding = baseclass.encoding
|
||||
|
||||
def handle_read(self):
|
||||
new_data = self.recv(1024).decode(self.encoding, 'replace')
|
||||
new_data = self.recv(1024)
|
||||
self.baseclass.last_received_data += new_data
|
||||
|
||||
def handle_close(self):
|
||||
@@ -80,7 +81,7 @@ class DummyDTPHandler(asynchat.async_chat):
|
||||
# (behaviour witnessed with test_data_connection)
|
||||
if not self.dtp_conn_closed:
|
||||
self.baseclass.push('226 transfer complete')
|
||||
self.close()
|
||||
self.shutdown()
|
||||
self.dtp_conn_closed = True
|
||||
|
||||
def push(self, what):
|
||||
@@ -94,6 +95,9 @@ class DummyDTPHandler(asynchat.async_chat):
|
||||
def handle_error(self):
|
||||
default_error_handler()
|
||||
|
||||
def shutdown(self):
|
||||
self.close()
|
||||
|
||||
|
||||
class DummyFTPHandler(asynchat.async_chat):
|
||||
|
||||
@@ -107,7 +111,7 @@ class DummyFTPHandler(asynchat.async_chat):
|
||||
self.in_buffer = []
|
||||
self.dtp = None
|
||||
self.last_received_cmd = None
|
||||
self.last_received_data = ''
|
||||
self.last_received_data = bytearray()
|
||||
self.next_response = ''
|
||||
self.next_data = None
|
||||
self.rest = None
|
||||
@@ -226,7 +230,7 @@ class DummyFTPHandler(asynchat.async_chat):
|
||||
|
||||
def cmd_quit(self, arg):
|
||||
self.push('221 quit ok')
|
||||
self.close()
|
||||
self.shutdown()
|
||||
|
||||
def cmd_abor(self, arg):
|
||||
self.push('226 abor ok')
|
||||
@@ -313,7 +317,7 @@ class DummyFTPServer(asyncore.dispatcher, threading.Thread):
|
||||
self.handler_instance = self.handler(conn, encoding=self.encoding)
|
||||
|
||||
def handle_connect(self):
|
||||
self.close()
|
||||
self.shutdown()
|
||||
handle_read = handle_connect
|
||||
|
||||
def writable(self):
|
||||
@@ -325,8 +329,8 @@ class DummyFTPServer(asyncore.dispatcher, threading.Thread):
|
||||
|
||||
if ssl is not None:
|
||||
|
||||
CERTFILE = os.path.join(os.path.dirname(__file__), "keycert3.pem")
|
||||
CAFILE = os.path.join(os.path.dirname(__file__), "pycacert.pem")
|
||||
CERTFILE = os.path.join(os.path.dirname(__file__), "certdata", "keycert3.pem")
|
||||
CAFILE = os.path.join(os.path.dirname(__file__), "certdata", "pycacert.pem")
|
||||
|
||||
class SSLConnection(asyncore.dispatcher):
|
||||
"""An asyncore.dispatcher subclass supporting TLS/SSL."""
|
||||
@@ -425,12 +429,12 @@ if ssl is not None:
|
||||
def handle_error(self):
|
||||
default_error_handler()
|
||||
|
||||
def close(self):
|
||||
def shutdown(self):
|
||||
if (isinstance(self.socket, ssl.SSLSocket) and
|
||||
self.socket._sslobj is not None):
|
||||
self._do_ssl_shutdown()
|
||||
else:
|
||||
super(SSLConnection, self).close()
|
||||
self.close()
|
||||
|
||||
|
||||
class DummyTLS_DTPHandler(SSLConnection, DummyDTPHandler):
|
||||
@@ -542,8 +546,8 @@ class TestFTPClass(TestCase):
|
||||
self.assertFalse(self.client.passiveserver)
|
||||
|
||||
def test_voidcmd(self):
|
||||
self.client.voidcmd('echo 200')
|
||||
self.client.voidcmd('echo 299')
|
||||
self.assertEqual(self.client.voidcmd('echo 200'), '200')
|
||||
self.assertEqual(self.client.voidcmd('echo 299'), '299')
|
||||
self.assertRaises(ftplib.error_reply, self.client.voidcmd, 'echo 199')
|
||||
self.assertRaises(ftplib.error_reply, self.client.voidcmd, 'echo 300')
|
||||
|
||||
@@ -589,37 +593,44 @@ class TestFTPClass(TestCase):
|
||||
def test_abort(self):
|
||||
self.client.abort()
|
||||
|
||||
@unittest.skip('TODO: RUSTPYTHON')
|
||||
# TimeoutError: The read operation timed out
|
||||
def test_retrbinary(self):
|
||||
def callback(data):
|
||||
received.append(data.decode(self.client.encoding))
|
||||
received = []
|
||||
self.client.retrbinary('retr', callback)
|
||||
self.check_data(''.join(received), RETR_DATA)
|
||||
self.client.retrbinary('retr', received.append)
|
||||
self.check_data(b''.join(received),
|
||||
RETR_DATA.encode(self.client.encoding))
|
||||
|
||||
@unittest.skip('TODO: RUSTPYTHON')
|
||||
# TimeoutError: The read operation timed out
|
||||
def test_retrbinary_rest(self):
|
||||
def callback(data):
|
||||
received.append(data.decode(self.client.encoding))
|
||||
for rest in (0, 10, 20):
|
||||
received = []
|
||||
self.client.retrbinary('retr', callback, rest=rest)
|
||||
self.check_data(''.join(received), RETR_DATA[rest:])
|
||||
self.client.retrbinary('retr', received.append, rest=rest)
|
||||
self.check_data(b''.join(received),
|
||||
RETR_DATA[rest:].encode(self.client.encoding))
|
||||
|
||||
@unittest.skip('TODO: RUSTPYTHON')
|
||||
# TimeoutError: The read operation timed out
|
||||
def test_retrlines(self):
|
||||
received = []
|
||||
self.client.retrlines('retr', received.append)
|
||||
self.check_data(''.join(received), RETR_DATA.replace('\r\n', ''))
|
||||
|
||||
@unittest.skip("TODO: RUSTPYTHON; weird limiting to 8192, something w/ buffering?")
|
||||
@unittest.skip('TODO: RUSTPYTHON; weird limiting to 8192, something w/ buffering?')
|
||||
def test_storbinary(self):
|
||||
f = io.BytesIO(RETR_DATA.encode(self.client.encoding))
|
||||
self.client.storbinary('stor', f)
|
||||
self.check_data(self.server.handler_instance.last_received_data, RETR_DATA)
|
||||
self.check_data(self.server.handler_instance.last_received_data,
|
||||
RETR_DATA.encode(self.server.encoding))
|
||||
# test new callback arg
|
||||
flag = []
|
||||
f.seek(0)
|
||||
self.client.storbinary('stor', f, callback=lambda x: flag.append(None))
|
||||
self.assertTrue(flag)
|
||||
|
||||
@unittest.skip('TODO: RUSTPYTHON')
|
||||
# ssl_error.SSLWantReadError: The operation did not complete (read)
|
||||
def test_storbinary_rest(self):
|
||||
data = RETR_DATA.replace('\r\n', '\n').encode(self.client.encoding)
|
||||
f = io.BytesIO(data)
|
||||
@@ -628,11 +639,14 @@ class TestFTPClass(TestCase):
|
||||
self.client.storbinary('stor', f, rest=r)
|
||||
self.assertEqual(self.server.handler_instance.rest, str(r))
|
||||
|
||||
@unittest.skip('TODO: RUSTPYTHON')
|
||||
# ssl_error.SSLWantReadError: The operation did not complete (read)
|
||||
def test_storlines(self):
|
||||
data = RETR_DATA.replace('\r\n', '\n').encode(self.client.encoding)
|
||||
f = io.BytesIO(data)
|
||||
self.client.storlines('stor', f)
|
||||
self.check_data(self.server.handler_instance.last_received_data, RETR_DATA)
|
||||
self.check_data(self.server.handler_instance.last_received_data,
|
||||
RETR_DATA.encode(self.server.encoding))
|
||||
# test new callback arg
|
||||
flag = []
|
||||
f.seek(0)
|
||||
@@ -644,15 +658,21 @@ class TestFTPClass(TestCase):
|
||||
with warnings_helper.check_warnings(('', BytesWarning), quiet=True):
|
||||
self.assertRaises(TypeError, self.client.storlines, 'stor foo', f)
|
||||
|
||||
@unittest.skip('TODO: RUSTPYTHON')
|
||||
# TimeoutError: The read operation timed out
|
||||
def test_nlst(self):
|
||||
self.client.nlst()
|
||||
self.assertEqual(self.client.nlst(), NLST_DATA.split('\r\n')[:-1])
|
||||
|
||||
@unittest.skip('TODO: RUSTPYTHON')
|
||||
# TimeoutError: The read operation timed out
|
||||
def test_dir(self):
|
||||
l = []
|
||||
self.client.dir(lambda x: l.append(x))
|
||||
self.client.dir(l.append)
|
||||
self.assertEqual(''.join(l), LIST_DATA.replace('\r\n', ''))
|
||||
|
||||
@unittest.skip('TODO: RUSTPYTHON')
|
||||
# TimeoutError: The read operation timed out
|
||||
def test_mlsd(self):
|
||||
list(self.client.mlsd())
|
||||
list(self.client.mlsd(path='/'))
|
||||
@@ -839,6 +859,8 @@ class TestFTPClass(TestCase):
|
||||
f = io.BytesIO(b'x' * self.client.maxline * 2)
|
||||
self.assertRaises(ftplib.Error, self.client.storlines, 'stor', f)
|
||||
|
||||
@unittest.skip('TODO: RUSTPYTHON')
|
||||
# TimeoutError: The read operation timed out
|
||||
def test_encoding_param(self):
|
||||
encodings = ['latin-1', 'utf-8']
|
||||
for encoding in encodings:
|
||||
@@ -890,12 +912,10 @@ class TestIPv6Environment(TestCase):
|
||||
|
||||
def test_transfer(self):
|
||||
def retr():
|
||||
def callback(data):
|
||||
received.append(data.decode(self.client.encoding))
|
||||
received = []
|
||||
self.client.retrbinary('retr', callback)
|
||||
self.assertEqual(len(''.join(received)), len(RETR_DATA))
|
||||
self.assertEqual(''.join(received), RETR_DATA)
|
||||
self.client.retrbinary('retr', received.append)
|
||||
self.assertEqual(b''.join(received),
|
||||
RETR_DATA.encode(self.client.encoding))
|
||||
self.client.set_pasv(True)
|
||||
retr()
|
||||
self.client.set_pasv(False)
|
||||
@@ -903,7 +923,7 @@ class TestIPv6Environment(TestCase):
|
||||
|
||||
|
||||
@skipUnless(ssl, "SSL not available")
|
||||
@unittest.skip("TODO: RUSTPYTHON; figure out why do_handshake() is throwing 'ssl session has been shut down'. SslSession object?")
|
||||
@requires_subprocess()
|
||||
class TestTLS_FTPClassMixin(TestFTPClass):
|
||||
"""Repeat TestFTPClass tests starting the TLS layer for both control
|
||||
and data connections first.
|
||||
@@ -920,7 +940,7 @@ class TestTLS_FTPClassMixin(TestFTPClass):
|
||||
|
||||
|
||||
@skipUnless(ssl, "SSL not available")
|
||||
@unittest.skip("TODO: RUSTPYTHON; fix ssl")
|
||||
@requires_subprocess()
|
||||
class TestTLS_FTPClass(TestCase):
|
||||
"""Specific TLS_FTP class tests."""
|
||||
|
||||
@@ -1004,6 +1024,8 @@ class TestTLS_FTPClass(TestCase):
|
||||
self.assertIs(sock.context, ctx)
|
||||
self.assertIsInstance(sock, ssl.SSLSocket)
|
||||
|
||||
@unittest.skip('TODO: RUSTPYTHON')
|
||||
# ssl_error.SSLWantReadError: The operation did not complete (read)
|
||||
def test_ccc(self):
|
||||
self.assertRaises(ValueError, self.client.ccc)
|
||||
self.client.login(secure=True)
|
||||
|
||||
Reference in new issue
Block a user