mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Sync stdlib utilities from CPython 3.15.0 final (#9111)
Regenerate nine utility modules and associated tests with scripts/update_lib from CPython d220409a13b77de7a6c30abe16ea90db01528edc. Preserve existing mimetypes fixes by excluding that module from this split. OpenAI Codex assisted with source audit, update_lib execution, and focused release validation: 64 tests passed, one existing WASI-only skip. Assisted-by: OpenAI Codex:model version unavailable
This commit is contained in:
1 parent
0816af6543
commit
a85a6cd762
15 files changed
+341
-95
No files matched your search
Vendored
+4
-2
@@ -618,7 +618,8 @@ class RawConfigParser(MutableMapping):
|
||||
_OPT_TMPL = r"""
|
||||
(?P<option> # very permissive!
|
||||
(?:(?!{delim})\S)* # non-delimiter non-whitespace
|
||||
(?:\s+(?:(?!{delim})\S)+)*) # optionally more words
|
||||
(?:(?:(?!{delim})\s)+ # optionally more
|
||||
(?:(?!{delim})\S)+)*) # space-separated words
|
||||
\s*(?P<vi>{delim})\s* # any number of space/tab,
|
||||
# followed by any of the
|
||||
# allowed delimiters,
|
||||
@@ -628,7 +629,8 @@ class RawConfigParser(MutableMapping):
|
||||
_OPT_NV_TMPL = r"""
|
||||
(?P<option> # very permissive!
|
||||
(?:(?!{delim})\S)* # non-delimiter non-whitespace
|
||||
(?:\s+(?:(?!{delim})\S)+)*) # optionally more words
|
||||
(?:(?:(?!{delim})\s)+ # optionally more
|
||||
(?:(?!{delim})\S)+)*) # space-separated words
|
||||
\s*(?: # any number of space/tab,
|
||||
(?P<vi>{delim})\s* # optionally followed by
|
||||
# any of the allowed
|
||||
|
||||
Vendored
+23
-14
@@ -81,8 +81,6 @@ __all__ = ["QUOTE_MINIMAL", "QUOTE_ALL", "QUOTE_NONNUMERIC", "QUOTE_NONE",
|
||||
"unregister_dialect", "DictReader", "DictWriter",
|
||||
"unix_dialect"]
|
||||
|
||||
__version__ = "1.0"
|
||||
|
||||
|
||||
class Dialect:
|
||||
"""Describe a CSV dialect.
|
||||
@@ -378,31 +376,33 @@ class Sniffer:
|
||||
try and evaluate the smallest portion of the data possible, evaluating
|
||||
additional chunks as necessary.
|
||||
"""
|
||||
from collections import Counter, defaultdict
|
||||
|
||||
data = list(filter(None, data.split('\n')))
|
||||
|
||||
ascii = [chr(c) for c in range(127)] # 7-bit ASCII
|
||||
|
||||
# build frequency tables
|
||||
chunkLength = min(10, len(data))
|
||||
iteration = 0
|
||||
charFrequency = {}
|
||||
num_lines = 0
|
||||
# {char -> {count_per_line -> num_lines_with_that_count}}
|
||||
char_frequency = defaultdict(Counter)
|
||||
modes = {}
|
||||
delims = {}
|
||||
start, end = 0, chunkLength
|
||||
while start < len(data):
|
||||
iteration += 1
|
||||
for line in data[start:end]:
|
||||
for char in ascii:
|
||||
metaFrequency = charFrequency.get(char, {})
|
||||
# must count even if frequency is 0
|
||||
freq = line.count(char)
|
||||
# value is the mode
|
||||
metaFrequency[freq] = metaFrequency.get(freq, 0) + 1
|
||||
charFrequency[char] = metaFrequency
|
||||
num_lines += 1
|
||||
for char, count in Counter(line).items():
|
||||
if char.isascii():
|
||||
char_frequency[char][count] += 1
|
||||
|
||||
for char in charFrequency.keys():
|
||||
items = list(charFrequency[char].items())
|
||||
for char, counts in char_frequency.items():
|
||||
items = list(counts.items())
|
||||
missed_lines = num_lines - sum(counts.values())
|
||||
if missed_lines:
|
||||
# Store the number of lines 'char' was missing from.
|
||||
items.append((0, missed_lines))
|
||||
if len(items) == 1 and items[0][0] == 0:
|
||||
continue
|
||||
# get the mode of the frequencies
|
||||
@@ -525,3 +525,12 @@ class Sniffer:
|
||||
hasHeader -= 1
|
||||
|
||||
return hasHeader > 0
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
if name == "__version__":
|
||||
from warnings import _deprecated
|
||||
|
||||
_deprecated("__version__", remove=(3, 20))
|
||||
return "1.0" # Do not change
|
||||
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
||||
Vendored
+5
-5
@@ -242,11 +242,6 @@ class Fraction(numbers.Rational):
|
||||
self._denominator = 1
|
||||
return self
|
||||
|
||||
elif isinstance(numerator, numbers.Rational):
|
||||
self._numerator = numerator.numerator
|
||||
self._denominator = numerator.denominator
|
||||
return self
|
||||
|
||||
elif (isinstance(numerator, float) or
|
||||
(not isinstance(numerator, type) and
|
||||
hasattr(numerator, 'as_integer_ratio'))):
|
||||
@@ -282,6 +277,11 @@ class Fraction(numbers.Rational):
|
||||
if m.group('sign') == '-':
|
||||
numerator = -numerator
|
||||
|
||||
elif isinstance(numerator, numbers.Rational):
|
||||
self._numerator = numerator.numerator
|
||||
self._denominator = numerator.denominator
|
||||
return self
|
||||
|
||||
else:
|
||||
raise TypeError("argument should be a string or a Rational "
|
||||
"instance or have the as_integer_ratio() method")
|
||||
|
||||
Vendored
+58
-3
@@ -199,6 +199,7 @@ class TopologicalSorter:
|
||||
self._ready_nodes.append(successor)
|
||||
self._nfinished += 1
|
||||
|
||||
# See note "On Finding Cycles" at the bottom.
|
||||
def _find_cycle(self):
|
||||
n2i = self._node2info
|
||||
stack = []
|
||||
@@ -212,8 +213,6 @@ class TopologicalSorter:
|
||||
|
||||
while True:
|
||||
if node in seen:
|
||||
# If we have seen already the node and is in the
|
||||
# current stack we have found a cycle.
|
||||
if node in node2stacki:
|
||||
return stack[node2stacki[node] :] + [node]
|
||||
# else go on to get next successor
|
||||
@@ -228,11 +227,15 @@ class TopologicalSorter:
|
||||
while stack:
|
||||
try:
|
||||
node = itstack[-1]()
|
||||
break
|
||||
break # resume at top of "while True:"
|
||||
except StopIteration:
|
||||
# no more successors; pop the stack
|
||||
# and continue looking up
|
||||
del node2stacki[stack.pop()]
|
||||
itstack.pop()
|
||||
else:
|
||||
# stack is empty; look for a fresh node to
|
||||
# start over from (a node not yet in seen)
|
||||
break
|
||||
return None
|
||||
|
||||
@@ -252,3 +255,55 @@ class TopologicalSorter:
|
||||
self.done(*node_group)
|
||||
|
||||
__class_getitem__ = classmethod(GenericAlias)
|
||||
|
||||
|
||||
# On Finding Cycles
|
||||
# -----------------
|
||||
# There is a (at least one) total order if and only if the graph is
|
||||
# acyclic.
|
||||
#
|
||||
# When it is cyclic, "there's a cycle - somewhere!" isn't very helpful.
|
||||
# In theory, it would be most helpful to partition the graph into
|
||||
# strongly connected components (SCCs) and display those with more than
|
||||
# one node. Then all cycles could easily be identified "by eyeball".
|
||||
#
|
||||
# That's a lot of work, though, and we can get most of the benefit much
|
||||
# more easily just by showing a single specific cycle.
|
||||
#
|
||||
# Approaches to that are based on breadth first or depth first search
|
||||
# (BFS or DFS). BFS is most natural, which can easily be arranged to
|
||||
# find a shortest-possible cycle. But memory burden can be high, because
|
||||
# every path-in-progress has to keep its own idea of what "the path" is
|
||||
# so far.
|
||||
#
|
||||
# DFS is much easier on RAM, only requiring keeping track of _the_ path
|
||||
# from the starting node to the current node at the current recursion
|
||||
# level. But there may be any number of nodes, and so there's no bound
|
||||
# on recursion depth short of the total number of nodes.
|
||||
#
|
||||
# So we use an iterative version of DFS, keeping an exploit list
|
||||
# (`stack`) of the path so far. A parallel stack (`itstack`) holds the
|
||||
# `__next__` method of an iterator over the current level's node's
|
||||
# successors, so when backtracking to a shallower level we can just call
|
||||
# that to get the node's next successor. This is state that a recursive
|
||||
# version would implicitly store in a `for` loop's internals.
|
||||
#
|
||||
# `seen()` is a set recording which nodes have already been, at some
|
||||
# time, pushed on the stack. If a node has been pushed on the stack, DFS
|
||||
# will find any cycle it's part of, so there's no need to ever look at
|
||||
# it again.
|
||||
#
|
||||
# Finally, `node2stacki` maps a node to its index on the current stack,
|
||||
# for and only for nodes currently _on_ the stack. If a successor to be
|
||||
# pushed on the stack is in that dict, the node is already on the path,
|
||||
# at that index. The cycle is then `stack[that_index :] + [node]`.
|
||||
#
|
||||
# As is often the case when removing recursion, the control flow looks a
|
||||
# bit off. The "while True:" loop here rarely actually loops - it's only
|
||||
# looking to go "up the stack" until finding a level that has another
|
||||
# successor to consider, emulating a chain of returns in a recursive
|
||||
# version.
|
||||
#
|
||||
# Worst cases: O(V+E) for time, and O(V) for memory, where V is the
|
||||
# number of nodes and E the number of edges (which may be quadratic in
|
||||
# V!). It requires care to ensure these bounds are met.
|
||||
Vendored
+6
-6
@@ -494,7 +494,7 @@ def nsmallest(n, iterable, key=None):
|
||||
pass
|
||||
else:
|
||||
if n >= size:
|
||||
return sorted(iterable, key=key)[:n]
|
||||
return sorted(iterable, key=key)
|
||||
|
||||
# When key is none, use simpler decoration
|
||||
if key is None:
|
||||
@@ -511,7 +511,7 @@ def nsmallest(n, iterable, key=None):
|
||||
for elem in it:
|
||||
if elem < top:
|
||||
_heapreplace(result, (elem, order))
|
||||
top, _order = result[0]
|
||||
top = result[0][0]
|
||||
order += 1
|
||||
result.sort()
|
||||
return [elem for (elem, order) in result]
|
||||
@@ -529,7 +529,7 @@ def nsmallest(n, iterable, key=None):
|
||||
k = key(elem)
|
||||
if k < top:
|
||||
_heapreplace(result, (k, order, elem))
|
||||
top, _order, _elem = result[0]
|
||||
top = result[0][0]
|
||||
order += 1
|
||||
result.sort()
|
||||
return [elem for (k, order, elem) in result]
|
||||
@@ -554,7 +554,7 @@ def nlargest(n, iterable, key=None):
|
||||
pass
|
||||
else:
|
||||
if n >= size:
|
||||
return sorted(iterable, key=key, reverse=True)[:n]
|
||||
return sorted(iterable, key=key, reverse=True)
|
||||
|
||||
# When key is none, use simpler decoration
|
||||
if key is None:
|
||||
@@ -569,7 +569,7 @@ def nlargest(n, iterable, key=None):
|
||||
for elem in it:
|
||||
if top < elem:
|
||||
_heapreplace(result, (elem, order))
|
||||
top, _order = result[0]
|
||||
top = result[0][0]
|
||||
order -= 1
|
||||
result.sort(reverse=True)
|
||||
return [elem for (elem, order) in result]
|
||||
@@ -587,7 +587,7 @@ def nlargest(n, iterable, key=None):
|
||||
k = key(elem)
|
||||
if top < k:
|
||||
_heapreplace(result, (k, order, elem))
|
||||
top, _order, _elem = result[0]
|
||||
top = result[0][0]
|
||||
order -= 1
|
||||
result.sort(reverse=True)
|
||||
return [elem for (k, order, elem) in result]
|
||||
|
||||
Vendored
+13
-3
@@ -8,9 +8,6 @@ and networks.
|
||||
|
||||
"""
|
||||
|
||||
__version__ = '1.0'
|
||||
|
||||
|
||||
import functools
|
||||
|
||||
IPV4LENGTH = 32
|
||||
@@ -1479,6 +1476,10 @@ class IPv4Interface(IPv4Address):
|
||||
return '%s/%s' % (self._string_from_ip_int(self._ip),
|
||||
self.hostmask)
|
||||
|
||||
@property
|
||||
def is_unspecified(self):
|
||||
return self._ip == 0 and self.network.is_unspecified
|
||||
|
||||
|
||||
class IPv4Network(_BaseV4, _BaseNetwork):
|
||||
|
||||
@@ -2415,3 +2416,12 @@ class _IPv6Constants:
|
||||
|
||||
IPv6Address._constants = _IPv6Constants
|
||||
IPv6Network._constants = _IPv6Constants
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
if name == "__version__":
|
||||
from warnings import _deprecated
|
||||
|
||||
_deprecated("__version__", remove=(3, 20))
|
||||
return "1.0" # Do not change
|
||||
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
||||
Vendored
+31
-25
@@ -48,11 +48,12 @@ class _netrclex:
|
||||
def get_token(self):
|
||||
if self.pushback:
|
||||
return self.pushback.pop(0)
|
||||
token = ""
|
||||
token = None
|
||||
fiter = iter(self._read_char, "")
|
||||
for ch in fiter:
|
||||
if ch in self.whitespace:
|
||||
continue
|
||||
token = ""
|
||||
if ch == '"':
|
||||
for ch in fiter:
|
||||
if ch == '"':
|
||||
@@ -95,10 +96,10 @@ class netrc:
|
||||
while 1:
|
||||
# Look for a machine, default, or macdef top-level keyword
|
||||
saved_lineno = lexer.lineno
|
||||
toplevel = tt = lexer.get_token()
|
||||
if not tt:
|
||||
tt = lexer.get_token()
|
||||
if tt is None:
|
||||
break
|
||||
elif tt[0] == '#':
|
||||
elif tt.startswith('#'):
|
||||
if lexer.lineno == saved_lineno and len(tt) == 1:
|
||||
lexer.instream.readline()
|
||||
continue
|
||||
@@ -135,40 +136,45 @@ class netrc:
|
||||
while 1:
|
||||
prev_lineno = lexer.lineno
|
||||
tt = lexer.get_token()
|
||||
if tt.startswith('#'):
|
||||
if tt is not None and tt.startswith('#'):
|
||||
if lexer.lineno == prev_lineno:
|
||||
lexer.instream.readline()
|
||||
continue
|
||||
if tt in {'', 'machine', 'default', 'macdef'}:
|
||||
if tt in {None, 'machine', 'default', 'macdef'}:
|
||||
self.hosts[entryname] = (login, account, password)
|
||||
lexer.push_token(tt)
|
||||
break
|
||||
elif tt == 'login' or tt == 'user':
|
||||
login = lexer.get_token()
|
||||
login = lexer.get_token() or ''
|
||||
elif tt == 'account':
|
||||
account = lexer.get_token()
|
||||
account = lexer.get_token() or ''
|
||||
elif tt == 'password':
|
||||
password = lexer.get_token()
|
||||
password = lexer.get_token() or ''
|
||||
else:
|
||||
raise NetrcParseError("bad follower token %r" % tt,
|
||||
file, lexer.lineno)
|
||||
self._security_check(fp, default_netrc, self.hosts[entryname][0])
|
||||
|
||||
def _security_check(self, fp, default_netrc, login):
|
||||
if _can_security_check() and default_netrc and login != "anonymous":
|
||||
prop = os.fstat(fp.fileno())
|
||||
current_user_id = os.getuid()
|
||||
if prop.st_uid != current_user_id:
|
||||
fowner = _getpwuid(prop.st_uid)
|
||||
user = _getpwuid(current_user_id)
|
||||
raise NetrcParseError(
|
||||
(f"~/.netrc file owner ({fowner}, {user}) does not match"
|
||||
" current user"))
|
||||
if (prop.st_mode & (stat.S_IRWXG | stat.S_IRWXO)):
|
||||
raise NetrcParseError(
|
||||
"~/.netrc access too permissive: access"
|
||||
" permissions must restrict access to only"
|
||||
" the owner")
|
||||
if _can_security_check() and default_netrc:
|
||||
for entry in self.hosts.values():
|
||||
if entry[0] != "anonymous":
|
||||
# Raises on security issue; once passed once can exit.
|
||||
self._security_check(fp)
|
||||
return
|
||||
|
||||
def _security_check(self, fp):
|
||||
prop = os.fstat(fp.fileno())
|
||||
current_user_id = os.getuid()
|
||||
if prop.st_uid != current_user_id:
|
||||
fowner = _getpwuid(prop.st_uid)
|
||||
user = _getpwuid(current_user_id)
|
||||
raise NetrcParseError(
|
||||
f"~/.netrc file owner ({fowner}) does not match"
|
||||
f" current user ({user})")
|
||||
if (prop.st_mode & (stat.S_IRWXG | stat.S_IRWXO)):
|
||||
raise NetrcParseError(
|
||||
"~/.netrc access too permissive: access"
|
||||
" permissions must restrict access to only"
|
||||
" the owner")
|
||||
|
||||
def authenticators(self, host):
|
||||
"""Return a (user, account, password) tuple for given host."""
|
||||
|
||||
Vendored
+14
-21
@@ -2,7 +2,7 @@ r"""plistlib.py -- a tool to generate and parse MacOSX .plist files.
|
||||
|
||||
The property list (.plist) file format is a simple XML pickle supporting
|
||||
basic object types, like dictionaries, lists, numbers and strings.
|
||||
Usually the top level object is a dictionary.
|
||||
Usually the top level object is a dictionary or a frozen dictionary.
|
||||
|
||||
To write out a plist file, use the dump(value, file)
|
||||
function. 'value' is the top level object, 'file' is
|
||||
@@ -122,13 +122,7 @@ _controlCharPat = re.compile(
|
||||
r"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f]")
|
||||
|
||||
def _encode_base64(s, maxlinelength=76):
|
||||
# copied from base64.encodebytes(), with added maxlinelength argument
|
||||
maxbinsize = (maxlinelength//4)*3
|
||||
pieces = []
|
||||
for i in range(0, len(s), maxbinsize):
|
||||
chunk = s[i : i + maxbinsize]
|
||||
pieces.append(binascii.b2a_base64(chunk))
|
||||
return b''.join(pieces)
|
||||
return binascii.b2a_base64(s, wrapcol=maxlinelength, newline=False)
|
||||
|
||||
def _decode_base64(s):
|
||||
if isinstance(s, str):
|
||||
@@ -363,7 +357,7 @@ class _PlistWriter(_DumbXMLWriter):
|
||||
elif isinstance(value, float):
|
||||
self.simple_element("real", repr(value))
|
||||
|
||||
elif isinstance(value, dict):
|
||||
elif isinstance(value, (dict, frozendict)):
|
||||
self.write_dict(value)
|
||||
|
||||
elif isinstance(value, (bytes, bytearray)):
|
||||
@@ -382,11 +376,10 @@ class _PlistWriter(_DumbXMLWriter):
|
||||
def write_bytes(self, data):
|
||||
self.begin_element("data")
|
||||
self._indent_level -= 1
|
||||
maxlinelength = max(
|
||||
16,
|
||||
76 - len((self.indent * self._indent_level).expandtabs()))
|
||||
|
||||
for line in _encode_base64(data, maxlinelength).split(b"\n"):
|
||||
wrapcol = 76 - len((self.indent * self._indent_level).expandtabs())
|
||||
wrapcol = max(16, wrapcol)
|
||||
encoded = binascii.b2a_base64(data, wrapcol=wrapcol, newline=False)
|
||||
for line in encoded.split(b"\n"):
|
||||
if line:
|
||||
self.writeln(line)
|
||||
self._indent_level += 1
|
||||
@@ -460,7 +453,7 @@ class InvalidFileException (ValueError):
|
||||
def __init__(self, message="Invalid file"):
|
||||
ValueError.__init__(self, message)
|
||||
|
||||
_BINARY_FORMAT = {1: 'B', 2: 'H', 4: 'L', 8: 'Q'}
|
||||
_BINARY_FORMAT = frozendict({1: 'B', 2: 'H', 4: 'L', 8: 'Q'})
|
||||
|
||||
_undefined = object()
|
||||
|
||||
@@ -722,7 +715,7 @@ class _BinaryPlistWriter (object):
|
||||
self._objidtable[id(value)] = refnum
|
||||
|
||||
# And finally recurse into containers
|
||||
if isinstance(value, dict):
|
||||
if isinstance(value, (dict, frozendict)):
|
||||
keys = []
|
||||
values = []
|
||||
items = value.items()
|
||||
@@ -843,7 +836,7 @@ class _BinaryPlistWriter (object):
|
||||
self._write_size(0xA0, s)
|
||||
self._fp.write(struct.pack('>' + self._ref_format * s, *refs))
|
||||
|
||||
elif isinstance(value, dict):
|
||||
elif isinstance(value, (dict, frozendict)):
|
||||
keyRefs, valRefs = [], []
|
||||
|
||||
if self._sort_keys:
|
||||
@@ -876,18 +869,18 @@ def _is_fmt_binary(header):
|
||||
# Generic bits
|
||||
#
|
||||
|
||||
_FORMATS={
|
||||
FMT_XML: dict(
|
||||
_FORMATS=frozendict({
|
||||
FMT_XML: frozendict(
|
||||
detect=_is_fmt_xml,
|
||||
parser=_PlistParser,
|
||||
writer=_PlistWriter,
|
||||
),
|
||||
FMT_BINARY: dict(
|
||||
FMT_BINARY: frozendict(
|
||||
detect=_is_fmt_binary,
|
||||
parser=_BinaryPlistParser,
|
||||
writer=_BinaryPlistWriter,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
def load(fp, *, fmt=None, dict_type=dict, aware_datetime=False):
|
||||
|
||||
Vendored
+10
-9
@@ -136,7 +136,7 @@ import sys
|
||||
|
||||
from fractions import Fraction
|
||||
from decimal import Decimal
|
||||
from itertools import count, groupby, repeat
|
||||
from itertools import compress, count, groupby, repeat
|
||||
from bisect import bisect_left, bisect_right
|
||||
from math import hypot, sqrt, fabs, exp, erfc, tau, log, fsum, sumprod
|
||||
from math import isfinite, isinf, pi, cos, sin, tan, cosh, asin, atan, acos
|
||||
@@ -145,6 +145,7 @@ from operator import itemgetter
|
||||
from collections import Counter, namedtuple, defaultdict
|
||||
|
||||
_SQRT2 = sqrt(2.0)
|
||||
_SQRT2PI = sqrt(tau)
|
||||
_random = random
|
||||
|
||||
## Exceptions ##############################################################
|
||||
@@ -194,9 +195,9 @@ def fmean(data, weights=None):
|
||||
n = len(data)
|
||||
except TypeError:
|
||||
# Handle iterators that do not define __len__().
|
||||
counter = count()
|
||||
total = fsum(map(itemgetter(0), zip(data, counter)))
|
||||
n = next(counter)
|
||||
counter = count(1)
|
||||
total = fsum(compress(data, counter))
|
||||
n = next(counter) - 1
|
||||
else:
|
||||
total = fsum(data)
|
||||
|
||||
@@ -247,7 +248,7 @@ def geometric_mean(data):
|
||||
elif x == 0.0:
|
||||
found_zero = True
|
||||
else:
|
||||
raise StatisticsError('No negative inputs allowed', x)
|
||||
raise StatisticsError(f'No negative inputs allowed: {x!r}')
|
||||
|
||||
total = fsum(map(log, count_positive(data)))
|
||||
|
||||
@@ -1257,11 +1258,11 @@ class NormalDist:
|
||||
|
||||
def pdf(self, x):
|
||||
"Probability density function. P(x <= X < x+dx) / dx"
|
||||
variance = self._sigma * self._sigma
|
||||
if not variance:
|
||||
sigma = self._sigma
|
||||
if not sigma:
|
||||
raise StatisticsError('pdf() not defined when sigma is zero')
|
||||
diff = x - self._mu
|
||||
return exp(diff * diff / (-2.0 * variance)) / sqrt(tau * variance)
|
||||
z = (x - self._mu) / sigma
|
||||
return exp(-0.5 * z * z) / (_SQRT2PI * sigma)
|
||||
|
||||
def cdf(self, x):
|
||||
"Cumulative distribution function. P(X <= x)"
|
||||
|
||||
Vendored
+30
-3
@@ -43,7 +43,7 @@ class CfgParserTestCaseClass:
|
||||
default_section = configparser.DEFAULTSECT
|
||||
interpolation = configparser._UNSET
|
||||
|
||||
def newconfig(self, defaults=None):
|
||||
def newconfig(self, defaults=None, **kwargs):
|
||||
arguments = dict(
|
||||
defaults=defaults,
|
||||
allow_no_value=self.allow_no_value,
|
||||
@@ -56,6 +56,7 @@ class CfgParserTestCaseClass:
|
||||
default_section=self.default_section,
|
||||
interpolation=self.interpolation,
|
||||
)
|
||||
arguments.update(kwargs)
|
||||
instance = self.config_class(**arguments)
|
||||
return instance
|
||||
|
||||
@@ -358,6 +359,32 @@ boolean {0[0]} NO
|
||||
the larch {0[1]} 1
|
||||
""".format(self.delimiters)))
|
||||
|
||||
@support.subTests('data', [
|
||||
'foo bar=baz',
|
||||
'foo bar=baz',
|
||||
'foo=bar=baz',
|
||||
'foo = bar=baz',
|
||||
'foo\t \t=\t \tbar=baz',
|
||||
])
|
||||
def test_space_delimiter(self, data):
|
||||
# gh-156353: Space should be accepted as a delimiter
|
||||
cf = self.newconfig(delimiters=(' ', '='))
|
||||
cf.read_string(f"[all]\n{data}")
|
||||
self.assertEqual(cf.options('all'), ['foo'])
|
||||
self.assertEqual(cf.get('all', 'foo'), 'bar=baz')
|
||||
|
||||
@support.subTests('delimiter', ' =:;#x\t\0\N{RS}\N{CEDILLA}\N{CAT}')
|
||||
@support.subTests('space_before', ['', ' ', '\t', ' \t'])
|
||||
@support.subTests('space_after', ['', ' ', '\t', ' \t'])
|
||||
def test_any_delimiter(self, delimiter, space_before, space_after):
|
||||
cf = self.newconfig(
|
||||
delimiters=(delimiter,),
|
||||
inline_comment_prefixes=None,
|
||||
)
|
||||
cf.read_string(f"[all]\nfoo{space_before}{delimiter}{space_after}bar=baz")
|
||||
self.assertEqual(cf.options('all'), ['foo'])
|
||||
self.assertEqual(cf.get('all', 'foo'), 'bar=baz')
|
||||
|
||||
def test_basic_from_dict(self):
|
||||
config = {
|
||||
"Foo Bar": {
|
||||
@@ -1991,8 +2018,8 @@ class ConvertersTestCase(BasicTestCase, unittest.TestCase):
|
||||
|
||||
config_class = configparser.ConfigParser
|
||||
|
||||
def newconfig(self, defaults=None):
|
||||
instance = super().newconfig(defaults=defaults)
|
||||
def newconfig(self, defaults=None, **kwargs):
|
||||
instance = super().newconfig(defaults=defaults, **kwargs)
|
||||
instance.converters['list'] = lambda v: [e.strip() for e in v.split()
|
||||
if e.strip()]
|
||||
return instance
|
||||
|
||||
Vendored
+74
@@ -1308,6 +1308,19 @@ class TestDialectValidity(unittest.TestCase):
|
||||
self.assertRaises(ValueError, create_invalid, field_name, " ",
|
||||
skipinitialspace=True)
|
||||
|
||||
def test_dialect_getattr_non_attribute_error_propagates(self):
|
||||
# gh-145966: non-AttributeError exceptions raised by __getattr__
|
||||
# during dialect attribute lookup must propagate, not be silenced.
|
||||
class BadDialect:
|
||||
def __getattr__(self, name):
|
||||
raise RuntimeError("boom")
|
||||
|
||||
with self.assertRaises(RuntimeError):
|
||||
csv.reader([], dialect=BadDialect())
|
||||
|
||||
with self.assertRaises(RuntimeError):
|
||||
csv.writer(StringIO(), dialect=BadDialect())
|
||||
|
||||
|
||||
class TestSniffer(unittest.TestCase):
|
||||
sample1 = """\
|
||||
@@ -1502,6 +1515,56 @@ ghi\0jkl
|
||||
dialect = sniffer.sniff(self.sample9)
|
||||
self.assertTrue(dialect.doublequote)
|
||||
|
||||
def test_guess_delimiter_crlf_not_chosen(self):
|
||||
# Ensure that we pick the real delimiter ("|") over "\r" in a tie.
|
||||
sniffer = csv.Sniffer()
|
||||
sample = "a|b\r\nc|d\r\ne|f\r\n"
|
||||
self.assertEqual(sniffer.sniff(sample).delimiter, "|")
|
||||
self.assertNotEqual(sniffer.sniff(sample).delimiter, "\r")
|
||||
|
||||
def test_zero_mode_tie_order_independence(self):
|
||||
sniffer = csv.Sniffer()
|
||||
# ":" appears in half the rows (1, 0, 1, 0) - a tie between
|
||||
# 0 and 1 per line.
|
||||
# "," appears once every row (true delimiter).
|
||||
#
|
||||
# Even if the zero-frequency bucket is appended vs. inserted, the tie
|
||||
# yields an adjusted score of 0, so ":" should not be promoted and
|
||||
# "," must be selected.
|
||||
sample = (
|
||||
"a,b:c\n"
|
||||
"d,e\n"
|
||||
"f,g:c\n"
|
||||
"h,i\n"
|
||||
)
|
||||
dialect = sniffer.sniff(sample)
|
||||
self.assertEqual(dialect.delimiter, ",")
|
||||
|
||||
def test_zero_mode_tie_order_comma_first(self):
|
||||
sniffer = csv.Sniffer()
|
||||
pattern = (
|
||||
"a,b\n"
|
||||
"c:d\n"
|
||||
"e,f\n"
|
||||
"g:h\n"
|
||||
)
|
||||
sample = pattern * 10
|
||||
with self.assertRaisesRegex(csv.Error, "Could not determine delimiter"):
|
||||
sniffer.sniff(sample)
|
||||
|
||||
def test_zero_mode_tie_order_colon_first(self):
|
||||
sniffer = csv.Sniffer()
|
||||
pattern = (
|
||||
"a:b\n"
|
||||
"c,d\n"
|
||||
"e:f\n"
|
||||
"g,h\n"
|
||||
)
|
||||
sample = pattern * 10
|
||||
with self.assertRaisesRegex(csv.Error, "Could not determine delimiter"):
|
||||
sniffer.sniff(sample)
|
||||
|
||||
|
||||
def test_sniff_regex_backtracking(self):
|
||||
# gh-109638: this artificial sample used to take minutes.
|
||||
sniffer = csv.Sniffer()
|
||||
@@ -1719,5 +1782,16 @@ class MiscTestCase(unittest.TestCase):
|
||||
with self.subTest(tp=tp):
|
||||
check_disallow_instantiation(self, tp)
|
||||
|
||||
|
||||
class TestModule(unittest.TestCase):
|
||||
def test_deprecated__version__(self):
|
||||
with self.assertWarnsRegex(
|
||||
DeprecationWarning,
|
||||
"'__version__' is deprecated and slated for removal in Python 3.20",
|
||||
) as cm:
|
||||
getattr(csv, "__version__")
|
||||
self.assertEqual(cm.filename, __file__)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Vendored
+14
@@ -2303,6 +2303,10 @@ class IpaddrUnitTest(unittest.TestCase):
|
||||
self.assertEqual(False, ipaddress.ip_network('240.0.0.0').is_multicast)
|
||||
self.assertEqual(True, ipaddress.ip_network('240.0.0.0').is_reserved)
|
||||
|
||||
self.assertTrue(ipaddress.ip_interface('0.0.0.0/32').is_unspecified)
|
||||
self.assertFalse(ipaddress.ip_interface('0.0.0.0/31').is_unspecified)
|
||||
self.assertFalse(ipaddress.ip_interface('1.2.3.4/32').is_unspecified)
|
||||
|
||||
self.assertEqual(True, ipaddress.ip_interface(
|
||||
'192.168.1.1/17').is_private)
|
||||
self.assertEqual(False, ipaddress.ip_network('192.169.0.0').is_private)
|
||||
@@ -2851,5 +2855,15 @@ class IpaddrUnitTest(unittest.TestCase):
|
||||
)
|
||||
|
||||
|
||||
class TestModule(unittest.TestCase):
|
||||
def test_deprecated__version__(self):
|
||||
with self.assertWarnsRegex(
|
||||
DeprecationWarning,
|
||||
"'__version__' is deprecated and slated for removal in Python 3.20",
|
||||
) as cm:
|
||||
getattr(ipaddress, "__version__")
|
||||
self.assertEqual(cm.filename, __file__)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Vendored
+38
@@ -1,6 +1,9 @@
|
||||
import netrc, os, unittest, sys, textwrap
|
||||
from pathlib import Path
|
||||
from test import support
|
||||
from test.support import os_helper
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
temp_filename = os_helper.TESTFN
|
||||
|
||||
@@ -59,6 +62,9 @@ class NetrcTestCase(unittest.TestCase):
|
||||
"machine host.domain.com login",
|
||||
"machine host.domain.com account",
|
||||
"machine host.domain.com password",
|
||||
"machine host.domain.com login \"\"",
|
||||
"machine host.domain.com account \"\"",
|
||||
"machine host.domain.com password \"\"",
|
||||
"machine host.domain.com login \"\" account",
|
||||
"machine host.domain.com login \"\" password",
|
||||
"machine host.domain.com account \"\" password"
|
||||
@@ -71,6 +77,9 @@ class NetrcTestCase(unittest.TestCase):
|
||||
"default login",
|
||||
"default account",
|
||||
"default password",
|
||||
"default login \"\"",
|
||||
"default account \"\"",
|
||||
"default password \"\"",
|
||||
"default login \"\" account",
|
||||
"default login \"\" password",
|
||||
"default account \"\" password"
|
||||
@@ -79,6 +88,15 @@ class NetrcTestCase(unittest.TestCase):
|
||||
nrc = self.make_nrc(item)
|
||||
self.assertEqual(nrc.hosts['default'], ('', '', ''))
|
||||
|
||||
def test_empty_quoted_token_is_not_eof(self):
|
||||
data = (
|
||||
'"" invalid',
|
||||
'machine host.domain.com "" invalid',
|
||||
)
|
||||
for item in data:
|
||||
with self.subTest(item=item):
|
||||
self.assertRaises(netrc.NetrcParseError, self.make_nrc, item)
|
||||
|
||||
def test_invalid_tokens(self):
|
||||
data = (
|
||||
"invalid host.domain.com",
|
||||
@@ -309,6 +327,26 @@ class NetrcTestCase(unittest.TestCase):
|
||||
self.assertEqual(nrc.hosts['foo.domain.com'],
|
||||
('anonymous', '', 'pass'))
|
||||
|
||||
@unittest.skipUnless(os.name == 'posix', 'POSIX only test')
|
||||
@unittest.skipUnless(hasattr(os, 'getuid'), "os.getuid is required")
|
||||
@os_helper.skip_unless_working_chmod
|
||||
def test_security_only_once(self):
|
||||
# Make sure security check is only run once per parse when multiple
|
||||
# entries are found.
|
||||
with patch.object(netrc.netrc, "_security_check") as mock:
|
||||
with os_helper.temp_dir() as tmp_dir:
|
||||
netrc_path = Path(tmp_dir) / '.netrc'
|
||||
netrc_path.write_text("""\
|
||||
machine foo.domain.com login bar password pass
|
||||
machine bar.domain.com login foo password pass
|
||||
""")
|
||||
netrc_path.chmod(0o600)
|
||||
with os_helper.EnvironmentVarGuard() as environ:
|
||||
environ.set('HOME', tmp_dir)
|
||||
netrc.netrc()
|
||||
|
||||
mock.assert_called_once()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Vendored
+19
@@ -792,6 +792,25 @@ class TestPlistlib(unittest.TestCase):
|
||||
})
|
||||
self.assertIsNot(pl2['first'], pl2['second'])
|
||||
|
||||
def test_frozendict(self):
|
||||
pl = frozendict(
|
||||
aString="Doodah",
|
||||
anInt=728,
|
||||
aDict=frozendict(
|
||||
anotherString="hello",
|
||||
aTrueValue=True,
|
||||
),
|
||||
aList=["A", "B", 12],
|
||||
)
|
||||
|
||||
for fmt in ALL_FORMATS:
|
||||
with self.subTest(fmt=fmt):
|
||||
data = plistlib.dumps(pl, fmt=fmt)
|
||||
pl2 = plistlib.loads(data)
|
||||
self.assertEqual(pl2, dict(pl))
|
||||
self.assertIsInstance(pl2, dict)
|
||||
self.assertIsInstance(pl2['aDict'], dict)
|
||||
|
||||
def test_controlcharacters(self):
|
||||
for i in range(128):
|
||||
c = chr(i)
|
||||
|
||||
Vendored
+2
-4
@@ -2496,8 +2496,7 @@ class TestKDE(unittest.TestCase):
|
||||
|
||||
data = [-2.1, -1.3, -0.4, 1.9, 5.1, 6.2, 7.8, 14.3, 15.1, 15.3, 15.8, 17.0]
|
||||
xarr = [x / 10 for x in range(-100, 250)]
|
||||
# TODO: RUSTPYTHON - n originally 1_000_000 in CPython implementation but sorting is slow
|
||||
n = 30_000
|
||||
n = 1_000_000
|
||||
h = 1.75
|
||||
dx = 0.1
|
||||
|
||||
@@ -2519,8 +2518,7 @@ class TestKDE(unittest.TestCase):
|
||||
F_hat = statistics.kde(data, h, kernel, cumulative=True)
|
||||
|
||||
for x in xarr:
|
||||
# TODO : RUSTPYTHON - abs_tol=0.0005 in CPython implementation but smaller `n` increases variance
|
||||
self.assertTrue(math.isclose(p_observed(x), p_expected(x), abs_tol=0.005))
|
||||
self.assertTrue(math.isclose(p_observed(x), p_expected(x), abs_tol=0.0005))
|
||||
|
||||
# Test online updates to data
|
||||
|
||||
|
||||
Reference in new issue
Block a user