switching to high quality piper tts and added label translations
This commit is contained in:
@@ -0,0 +1,564 @@
|
||||
"""Miscellaneous stuff that does not really fit anywhere else."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import operator
|
||||
import sys
|
||||
import os
|
||||
import re as _re
|
||||
import struct
|
||||
from textwrap import fill, dedent
|
||||
|
||||
|
||||
class Undecidable(ValueError):
|
||||
# an error to be raised when a decision cannot be made definitively
|
||||
# where a definitive answer is needed
|
||||
pass
|
||||
|
||||
|
||||
def filldedent(s, w=70, **kwargs):
|
||||
"""
|
||||
Strips leading and trailing empty lines from a copy of ``s``, then dedents,
|
||||
fills and returns it.
|
||||
|
||||
Empty line stripping serves to deal with docstrings like this one that
|
||||
start with a newline after the initial triple quote, inserting an empty
|
||||
line at the beginning of the string.
|
||||
|
||||
Additional keyword arguments will be passed to ``textwrap.fill()``.
|
||||
|
||||
See Also
|
||||
========
|
||||
strlines, rawlines
|
||||
|
||||
"""
|
||||
return '\n' + fill(dedent(str(s)).strip('\n'), width=w, **kwargs)
|
||||
|
||||
|
||||
def strlines(s, c=64, short=False):
|
||||
"""Return a cut-and-pastable string that, when printed, is
|
||||
equivalent to the input. The lines will be surrounded by
|
||||
parentheses and no line will be longer than c (default 64)
|
||||
characters. If the line contains newlines characters, the
|
||||
`rawlines` result will be returned. If ``short`` is True
|
||||
(default is False) then if there is one line it will be
|
||||
returned without bounding parentheses.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.utilities.misc import strlines
|
||||
>>> q = 'this is a long string that should be broken into shorter lines'
|
||||
>>> print(strlines(q, 40))
|
||||
(
|
||||
'this is a long string that should be b'
|
||||
'roken into shorter lines'
|
||||
)
|
||||
>>> q == (
|
||||
... 'this is a long string that should be b'
|
||||
... 'roken into shorter lines'
|
||||
... )
|
||||
True
|
||||
|
||||
See Also
|
||||
========
|
||||
filldedent, rawlines
|
||||
"""
|
||||
if not isinstance(s, str):
|
||||
raise ValueError('expecting string input')
|
||||
if '\n' in s:
|
||||
return rawlines(s)
|
||||
q = '"' if repr(s).startswith('"') else "'"
|
||||
q = (q,)*2
|
||||
if '\\' in s: # use r-string
|
||||
m = '(\nr%s%%s%s\n)' % q
|
||||
j = '%s\nr%s' % q
|
||||
c -= 3
|
||||
else:
|
||||
m = '(\n%s%%s%s\n)' % q
|
||||
j = '%s\n%s' % q
|
||||
c -= 2
|
||||
out = []
|
||||
while s:
|
||||
out.append(s[:c])
|
||||
s=s[c:]
|
||||
if short and len(out) == 1:
|
||||
return (m % out[0]).splitlines()[1] # strip bounding (\n...\n)
|
||||
return m % j.join(out)
|
||||
|
||||
|
||||
def rawlines(s):
|
||||
"""Return a cut-and-pastable string that, when printed, is equivalent
|
||||
to the input. Use this when there is more than one line in the
|
||||
string. The string returned is formatted so it can be indented
|
||||
nicely within tests; in some cases it is wrapped in the dedent
|
||||
function which has to be imported from textwrap.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
Note: because there are characters in the examples below that need
|
||||
to be escaped because they are themselves within a triple quoted
|
||||
docstring, expressions below look more complicated than they would
|
||||
be if they were printed in an interpreter window.
|
||||
|
||||
>>> from sympy.utilities.misc import rawlines
|
||||
>>> from sympy import TableForm
|
||||
>>> s = str(TableForm([[1, 10]], headings=(None, ['a', 'bee'])))
|
||||
>>> print(rawlines(s))
|
||||
(
|
||||
'a bee\\n'
|
||||
'-----\\n'
|
||||
'1 10 '
|
||||
)
|
||||
>>> print(rawlines('''this
|
||||
... that'''))
|
||||
dedent('''\\
|
||||
this
|
||||
that''')
|
||||
|
||||
>>> print(rawlines('''this
|
||||
... that
|
||||
... '''))
|
||||
dedent('''\\
|
||||
this
|
||||
that
|
||||
''')
|
||||
|
||||
>>> s = \"\"\"this
|
||||
... is a triple '''
|
||||
... \"\"\"
|
||||
>>> print(rawlines(s))
|
||||
dedent(\"\"\"\\
|
||||
this
|
||||
is a triple '''
|
||||
\"\"\")
|
||||
|
||||
>>> print(rawlines('''this
|
||||
... that
|
||||
... '''))
|
||||
(
|
||||
'this\\n'
|
||||
'that\\n'
|
||||
' '
|
||||
)
|
||||
|
||||
See Also
|
||||
========
|
||||
filldedent, strlines
|
||||
"""
|
||||
lines = s.split('\n')
|
||||
if len(lines) == 1:
|
||||
return repr(lines[0])
|
||||
triple = ["'''" in s, '"""' in s]
|
||||
if any(li.endswith(' ') for li in lines) or '\\' in s or all(triple):
|
||||
rv = []
|
||||
# add on the newlines
|
||||
trailing = s.endswith('\n')
|
||||
last = len(lines) - 1
|
||||
for i, li in enumerate(lines):
|
||||
if i != last or trailing:
|
||||
rv.append(repr(li + '\n'))
|
||||
else:
|
||||
rv.append(repr(li))
|
||||
return '(\n %s\n)' % '\n '.join(rv)
|
||||
else:
|
||||
rv = '\n '.join(lines)
|
||||
if triple[0]:
|
||||
return 'dedent("""\\\n %s""")' % rv
|
||||
else:
|
||||
return "dedent('''\\\n %s''')" % rv
|
||||
|
||||
ARCH = str(struct.calcsize('P') * 8) + "-bit"
|
||||
|
||||
|
||||
# XXX: PyPy does not support hash randomization
|
||||
HASH_RANDOMIZATION = getattr(sys.flags, 'hash_randomization', False)
|
||||
|
||||
_debug_tmp: list[str] = []
|
||||
_debug_iter = 0
|
||||
|
||||
def debug_decorator(func):
|
||||
"""If SYMPY_DEBUG is True, it will print a nice execution tree with
|
||||
arguments and results of all decorated functions, else do nothing.
|
||||
"""
|
||||
from sympy import SYMPY_DEBUG
|
||||
|
||||
if not SYMPY_DEBUG:
|
||||
return func
|
||||
|
||||
def maketree(f, *args, **kw):
|
||||
global _debug_tmp, _debug_iter
|
||||
oldtmp = _debug_tmp
|
||||
_debug_tmp = []
|
||||
_debug_iter += 1
|
||||
|
||||
def tree(subtrees):
|
||||
def indent(s, variant=1):
|
||||
x = s.split("\n")
|
||||
r = "+-%s\n" % x[0]
|
||||
for a in x[1:]:
|
||||
if a == "":
|
||||
continue
|
||||
if variant == 1:
|
||||
r += "| %s\n" % a
|
||||
else:
|
||||
r += " %s\n" % a
|
||||
return r
|
||||
if len(subtrees) == 0:
|
||||
return ""
|
||||
f = []
|
||||
for a in subtrees[:-1]:
|
||||
f.append(indent(a))
|
||||
f.append(indent(subtrees[-1], 2))
|
||||
return ''.join(f)
|
||||
|
||||
# If there is a bug and the algorithm enters an infinite loop, enable the
|
||||
# following lines. It will print the names and parameters of all major functions
|
||||
# that are called, *before* they are called
|
||||
#from functools import reduce
|
||||
#print("%s%s %s%s" % (_debug_iter, reduce(lambda x, y: x + y, \
|
||||
# map(lambda x: '-', range(1, 2 + _debug_iter))), f.__name__, args))
|
||||
|
||||
r = f(*args, **kw)
|
||||
|
||||
_debug_iter -= 1
|
||||
s = "%s%s = %s\n" % (f.__name__, args, r)
|
||||
if _debug_tmp != []:
|
||||
s += tree(_debug_tmp)
|
||||
_debug_tmp = oldtmp
|
||||
_debug_tmp.append(s)
|
||||
if _debug_iter == 0:
|
||||
print(_debug_tmp[0])
|
||||
_debug_tmp = []
|
||||
return r
|
||||
|
||||
def decorated(*args, **kwargs):
|
||||
return maketree(func, *args, **kwargs)
|
||||
|
||||
return decorated
|
||||
|
||||
|
||||
def debug(*args):
|
||||
"""
|
||||
Print ``*args`` if SYMPY_DEBUG is True, else do nothing.
|
||||
"""
|
||||
from sympy import SYMPY_DEBUG
|
||||
if SYMPY_DEBUG:
|
||||
print(*args, file=sys.stderr)
|
||||
|
||||
|
||||
def debugf(string, args):
|
||||
"""
|
||||
Print ``string%args`` if SYMPY_DEBUG is True, else do nothing. This is
|
||||
intended for debug messages using formatted strings.
|
||||
"""
|
||||
from sympy import SYMPY_DEBUG
|
||||
if SYMPY_DEBUG:
|
||||
print(string%args, file=sys.stderr)
|
||||
|
||||
|
||||
def find_executable(executable, path=None):
|
||||
"""Try to find 'executable' in the directories listed in 'path' (a
|
||||
string listing directories separated by 'os.pathsep'; defaults to
|
||||
os.environ['PATH']). Returns the complete filename or None if not
|
||||
found
|
||||
"""
|
||||
from .exceptions import sympy_deprecation_warning
|
||||
sympy_deprecation_warning(
|
||||
"""
|
||||
sympy.utilities.misc.find_executable() is deprecated. Use the standard
|
||||
library shutil.which() function instead.
|
||||
""",
|
||||
deprecated_since_version="1.7",
|
||||
active_deprecations_target="deprecated-find-executable",
|
||||
)
|
||||
if path is None:
|
||||
path = os.environ['PATH']
|
||||
paths = path.split(os.pathsep)
|
||||
extlist = ['']
|
||||
if os.name == 'os2':
|
||||
(base, ext) = os.path.splitext(executable)
|
||||
# executable files on OS/2 can have an arbitrary extension, but
|
||||
# .exe is automatically appended if no dot is present in the name
|
||||
if not ext:
|
||||
executable = executable + ".exe"
|
||||
elif sys.platform == 'win32':
|
||||
pathext = os.environ['PATHEXT'].lower().split(os.pathsep)
|
||||
(base, ext) = os.path.splitext(executable)
|
||||
if ext.lower() not in pathext:
|
||||
extlist = pathext
|
||||
for ext in extlist:
|
||||
execname = executable + ext
|
||||
if os.path.isfile(execname):
|
||||
return execname
|
||||
else:
|
||||
for p in paths:
|
||||
f = os.path.join(p, execname)
|
||||
if os.path.isfile(f):
|
||||
return f
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def func_name(x, short=False):
|
||||
"""Return function name of `x` (if defined) else the `type(x)`.
|
||||
If short is True and there is a shorter alias for the result,
|
||||
return the alias.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.utilities.misc import func_name
|
||||
>>> from sympy import Matrix
|
||||
>>> from sympy.abc import x
|
||||
>>> func_name(Matrix.eye(3))
|
||||
'MutableDenseMatrix'
|
||||
>>> func_name(x < 1)
|
||||
'StrictLessThan'
|
||||
>>> func_name(x < 1, short=True)
|
||||
'Lt'
|
||||
"""
|
||||
alias = {
|
||||
'GreaterThan': 'Ge',
|
||||
'StrictGreaterThan': 'Gt',
|
||||
'LessThan': 'Le',
|
||||
'StrictLessThan': 'Lt',
|
||||
'Equality': 'Eq',
|
||||
'Unequality': 'Ne',
|
||||
}
|
||||
typ = type(x)
|
||||
if str(typ).startswith("<type '"):
|
||||
typ = str(typ).split("'")[1].split("'")[0]
|
||||
elif str(typ).startswith("<class '"):
|
||||
typ = str(typ).split("'")[1].split("'")[0]
|
||||
rv = getattr(getattr(x, 'func', x), '__name__', typ)
|
||||
if '.' in rv:
|
||||
rv = rv.split('.')[-1]
|
||||
if short:
|
||||
rv = alias.get(rv, rv)
|
||||
return rv
|
||||
|
||||
|
||||
def _replace(reps):
|
||||
"""Return a function that can make the replacements, given in
|
||||
``reps``, on a string. The replacements should be given as mapping.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.utilities.misc import _replace
|
||||
>>> f = _replace(dict(foo='bar', d='t'))
|
||||
>>> f('food')
|
||||
'bart'
|
||||
>>> f = _replace({})
|
||||
>>> f('food')
|
||||
'food'
|
||||
"""
|
||||
if not reps:
|
||||
return lambda x: x
|
||||
D = lambda match: reps[match.group(0)]
|
||||
pattern = _re.compile("|".join(
|
||||
[_re.escape(k) for k, v in reps.items()]), _re.MULTILINE)
|
||||
return lambda string: pattern.sub(D, string)
|
||||
|
||||
|
||||
def replace(string, *reps):
|
||||
"""Return ``string`` with all keys in ``reps`` replaced with
|
||||
their corresponding values, longer strings first, irrespective
|
||||
of the order they are given. ``reps`` may be passed as tuples
|
||||
or a single mapping.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.utilities.misc import replace
|
||||
>>> replace('foo', {'oo': 'ar', 'f': 'b'})
|
||||
'bar'
|
||||
>>> replace("spamham sha", ("spam", "eggs"), ("sha","md5"))
|
||||
'eggsham md5'
|
||||
|
||||
There is no guarantee that a unique answer will be
|
||||
obtained if keys in a mapping overlap (i.e. are the same
|
||||
length and have some identical sequence at the
|
||||
beginning/end):
|
||||
|
||||
>>> reps = [
|
||||
... ('ab', 'x'),
|
||||
... ('bc', 'y')]
|
||||
>>> replace('abc', *reps) in ('xc', 'ay')
|
||||
True
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://stackoverflow.com/questions/6116978/how-to-replace-multiple-substrings-of-a-string
|
||||
"""
|
||||
if len(reps) == 1:
|
||||
kv = reps[0]
|
||||
if isinstance(kv, dict):
|
||||
reps = kv
|
||||
else:
|
||||
return string.replace(*kv)
|
||||
else:
|
||||
reps = dict(reps)
|
||||
return _replace(reps)(string)
|
||||
|
||||
|
||||
def translate(s, a, b=None, c=None):
|
||||
"""Return ``s`` where characters have been replaced or deleted.
|
||||
|
||||
SYNTAX
|
||||
======
|
||||
|
||||
translate(s, None, deletechars):
|
||||
all characters in ``deletechars`` are deleted
|
||||
translate(s, map [,deletechars]):
|
||||
all characters in ``deletechars`` (if provided) are deleted
|
||||
then the replacements defined by map are made; if the keys
|
||||
of map are strings then the longer ones are handled first.
|
||||
Multicharacter deletions should have a value of ''.
|
||||
translate(s, oldchars, newchars, deletechars)
|
||||
all characters in ``deletechars`` are deleted
|
||||
then each character in ``oldchars`` is replaced with the
|
||||
corresponding character in ``newchars``
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.utilities.misc import translate
|
||||
>>> abc = 'abc'
|
||||
>>> translate(abc, None, 'a')
|
||||
'bc'
|
||||
>>> translate(abc, {'a': 'x'}, 'c')
|
||||
'xb'
|
||||
>>> translate(abc, {'abc': 'x', 'a': 'y'})
|
||||
'x'
|
||||
|
||||
>>> translate('abcd', 'ac', 'AC', 'd')
|
||||
'AbC'
|
||||
|
||||
There is no guarantee that a unique answer will be
|
||||
obtained if keys in a mapping overlap are the same
|
||||
length and have some identical sequences at the
|
||||
beginning/end:
|
||||
|
||||
>>> translate(abc, {'ab': 'x', 'bc': 'y'}) in ('xc', 'ay')
|
||||
True
|
||||
"""
|
||||
|
||||
mr = {}
|
||||
if a is None:
|
||||
if c is not None:
|
||||
raise ValueError('c should be None when a=None is passed, instead got %s' % c)
|
||||
if b is None:
|
||||
return s
|
||||
c = b
|
||||
a = b = ''
|
||||
else:
|
||||
if isinstance(a, dict):
|
||||
short = {}
|
||||
for k in list(a.keys()):
|
||||
if len(k) == 1 and len(a[k]) == 1:
|
||||
short[k] = a.pop(k)
|
||||
mr = a
|
||||
c = b
|
||||
if short:
|
||||
a, b = [''.join(i) for i in list(zip(*short.items()))]
|
||||
else:
|
||||
a = b = ''
|
||||
elif len(a) != len(b):
|
||||
raise ValueError('oldchars and newchars have different lengths')
|
||||
|
||||
if c:
|
||||
val = str.maketrans('', '', c)
|
||||
s = s.translate(val)
|
||||
s = replace(s, mr)
|
||||
n = str.maketrans(a, b)
|
||||
return s.translate(n)
|
||||
|
||||
|
||||
def ordinal(num):
|
||||
"""Return ordinal number string of num, e.g. 1 becomes 1st.
|
||||
"""
|
||||
# modified from https://codereview.stackexchange.com/questions/41298/producing-ordinal-numbers
|
||||
n = as_int(num)
|
||||
k = abs(n) % 100
|
||||
if 11 <= k <= 13:
|
||||
suffix = 'th'
|
||||
elif k % 10 == 1:
|
||||
suffix = 'st'
|
||||
elif k % 10 == 2:
|
||||
suffix = 'nd'
|
||||
elif k % 10 == 3:
|
||||
suffix = 'rd'
|
||||
else:
|
||||
suffix = 'th'
|
||||
return str(n) + suffix
|
||||
|
||||
|
||||
def as_int(n, strict=True):
|
||||
"""
|
||||
Convert the argument to a builtin integer.
|
||||
|
||||
The return value is guaranteed to be equal to the input. ValueError is
|
||||
raised if the input has a non-integral value. When ``strict`` is True, this
|
||||
uses `__index__ <https://docs.python.org/3/reference/datamodel.html#object.__index__>`_
|
||||
and when it is False it uses ``int``.
|
||||
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.utilities.misc import as_int
|
||||
>>> from sympy import sqrt, S
|
||||
|
||||
The function is primarily concerned with sanitizing input for
|
||||
functions that need to work with builtin integers, so anything that
|
||||
is unambiguously an integer should be returned as an int:
|
||||
|
||||
>>> as_int(S(3))
|
||||
3
|
||||
|
||||
Floats, being of limited precision, are not assumed to be exact and
|
||||
will raise an error unless the ``strict`` flag is False. This
|
||||
precision issue becomes apparent for large floating point numbers:
|
||||
|
||||
>>> big = 1e23
|
||||
>>> type(big) is float
|
||||
True
|
||||
>>> big == int(big)
|
||||
True
|
||||
>>> as_int(big)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: ... is not an integer
|
||||
>>> as_int(big, strict=False)
|
||||
99999999999999991611392
|
||||
|
||||
Input that might be a complex representation of an integer value is
|
||||
also rejected by default:
|
||||
|
||||
>>> one = sqrt(3 + 2*sqrt(2)) - sqrt(2)
|
||||
>>> int(one) == 1
|
||||
True
|
||||
>>> as_int(one)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: ... is not an integer
|
||||
"""
|
||||
if strict:
|
||||
try:
|
||||
if isinstance(n, bool):
|
||||
raise TypeError
|
||||
return operator.index(n)
|
||||
except TypeError:
|
||||
raise ValueError('%s is not an integer' % (n,))
|
||||
else:
|
||||
try:
|
||||
result = int(n)
|
||||
except TypeError:
|
||||
raise ValueError('%s is not an integer' % (n,))
|
||||
if n - result:
|
||||
raise ValueError('%s is not an integer' % (n,))
|
||||
return result
|
||||
Reference in New Issue
Block a user