Skip to content

Commit 05e2f08

Browse files
authored
Fix remaining mypy errors in mathics.core (#1147)
This fixes the remaining mypy errors in `mathics.core`, with the exception of `mathics.core.expression` which needs a bit more work.
1 parent dcc607e commit 05e2f08

24 files changed

+247
-173
lines changed

mathics/core/assignment.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,8 @@ def eval_assign_numericq(self, lhs, rhs, evaluation: Evaluation, tags, upset):
592592
if isinstance(target, Symbol):
593593
name = target.get_name()
594594
definition = evaluation.definitions.get_definition(name)
595-
definition.is_numeric = rhs is SymbolTrue
595+
if definition is not None:
596+
definition.is_numeric = rhs is SymbolTrue
596597
return True
597598
else:
598599
evaluation.message("NumericQ", "set", lhs, rhs)

mathics/core/atoms.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import re
77
from typing import Any, Dict, Generic, Optional, Tuple, TypeVar, Union
88

9-
import mpmath
9+
import mpmath # type: ignore[import-untyped]
1010
import sympy
1111

1212
from mathics.core.element import BoxElementMixin, ImmutableValueMixin

mathics/core/builtin.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,20 @@
1313
from abc import ABC
1414
from functools import total_ordering
1515
from itertools import chain
16-
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union, cast
16+
from typing import (
17+
Any,
18+
Callable,
19+
Dict,
20+
Iterable,
21+
List,
22+
Optional,
23+
Sequence,
24+
Tuple,
25+
Union,
26+
cast,
27+
)
1728

18-
import mpmath
29+
import mpmath # type: ignore[import-untyped]
1930
import pkg_resources
2031
import sympy
2132

@@ -84,7 +95,7 @@
8495
try:
8596
import ujson
8697
except ImportError:
87-
import json as ujson
98+
import json as ujson # type: ignore[no-redef]
8899

89100
ROOT_DIR = pkg_resources.resource_filename("mathics", "")
90101

@@ -551,6 +562,12 @@ def get_sympy_names(self) -> List[str]:
551562
return [self.sympy_name]
552563
return []
553564

565+
def to_sympy(self, expr=None, **kwargs):
566+
raise NotImplementedError
567+
568+
def from_sympy(self, elements: Tuple[BaseElement, ...]) -> Expression:
569+
raise NotImplementedError
570+
554571

555572
# This has to come before MPMathFunction
556573
class SympyFunction(SympyObject):
@@ -651,6 +668,8 @@ def eval(self, z, evaluation: Evaluation):
651668

652669
if not all(isinstance(arg, Number) for arg in args):
653670
return
671+
# mypy isn't yet smart enough to recognise that we can only reach this point if all args are Numbers
672+
args = cast(Sequence[Number], args)
654673

655674
mpmath_function = self.get_mpmath_function(tuple(args))
656675
if mpmath_function is None:
@@ -663,7 +682,9 @@ def eval(self, z, evaluation: Evaluation):
663682
d = dps(prec)
664683
args = tuple([arg.round(d) for arg in args])
665684

666-
return eval_mpmath_function(mpmath_function, *args, prec=prec)
685+
return eval_mpmath_function(
686+
mpmath_function, *cast(Sequence[Number], args), prec=prec
687+
)
667688

668689

669690
class MPMathMultiFunction(MPMathFunction):
@@ -1235,7 +1256,7 @@ def get_match_candidates(
12351256
) -> Tuple[BaseElement]:
12361257
return elements
12371258

1238-
def get_match_count(self, vars_dict: dict = {}):
1259+
def get_match_count(self, vars_dict: Optional[dict] = None):
12391260
return (1, 1)
12401261

12411262
def get_sort_key(self, pattern_sort=False) -> tuple:

mathics/core/convert/expression.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,16 +83,16 @@ def to_mathics_list(
8383
return list_expression
8484

8585

86-
def to_numeric_args(mathics_args: Type[BaseElement], evaluation) -> list:
86+
def to_numeric_args(mathics_args: BaseElement, evaluation) -> tuple:
8787
"""
8888
Convert Mathics arguments, such as the arguments in an evaluation
8989
method a Python list that is suitable for feeding as arguments
9090
into SymPy, NumPy, or mpmath.
9191
9292
We make use of fast conversions for literals.
9393
"""
94-
return (
95-
tuple(mathics_args.value)
94+
return tuple(
95+
mathics_args.value # type: ignore[attr-defined]
9696
if mathics_args.is_literal
9797
else numerify(mathics_args, evaluation).get_sequence()
9898
)

mathics/core/convert/function.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ def _pythonized_mathics_expr(*x):
8383

8484

8585
def expression_to_callable_and_args(
86-
expr: Expression, vars: list = None, evaluation: Optional[Evaluation] = None
86+
expr: Expression,
87+
vars: Optional[list] = None,
88+
evaluation: Optional[Evaluation] = None,
8789
) -> Tuple[Optional[Callable], Optional[list]]:
8890
"""
8991
Return a tuple of Python callable and a list of CompileArgs.

mathics/core/convert/mpmath.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from functools import lru_cache
44
from typing import Optional, Union
55

6-
import mpmath
6+
import mpmath # type: ignore[import-untyped]
77
import sympy
88

99
from mathics.core.atoms import Complex, MachineReal, MachineReal0, PrecisionReal

mathics/core/convert/op.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
try:
1111
import ujson
1212
except ImportError:
13-
import json as ujson
13+
import json as ujson # type: ignore[no-redef]
1414

1515
ROOT_DIR = pkg_resources.resource_filename("mathics", "")
1616

mathics/core/convert/regex.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ def to_regex_internal(
9696
(None, "") is returned if there is an error of some sort.
9797
"""
9898

99-
def recurse(x: Expression, quantifiers=q) -> Tuple[Optional[str], str]:
99+
def recurse(x: Expression, quantifiers=q) -> Optional[str]:
100100
"""
101101
Shortened way to call to_regexp_internal -
102102
only the expr and quantifiers change here.

mathics/core/convert/sympy.py

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Converts expressions from SymPy to Mathics expressions.
55
Conversion to SymPy is handled directly in BaseElement descendants.
66
"""
7-
from typing import Optional, Type, Union
7+
from typing import TYPE_CHECKING, Dict, List, Optional, Sequence, Tuple, Union, cast
88

99
import sympy
1010
from sympy import Symbol as Sympy_Symbol, false as SympyFalse, true as SympyTrue
@@ -66,6 +66,9 @@
6666
SymbolUnequal,
6767
)
6868

69+
if TYPE_CHECKING:
70+
from mathics.core.builtin import SympyObject
71+
6972
BasicSympy = sympy.Expr
7073

7174

@@ -74,8 +77,8 @@
7477
SymbolRootSum = Symbol("RootSum")
7578

7679

77-
mathics_to_sympy = {} # here we have: name -> sympy object
78-
sympy_to_mathics = {}
80+
mathics_to_sympy: Dict[str, "SympyObject"] = {} # here we have: name -> sympy object
81+
sympy_to_mathics: Dict[str, "SympyObject"] = {}
7982

8083

8184
sympy_singleton_to_mathics = {
@@ -104,14 +107,14 @@
104107
}
105108

106109

107-
def is_Cn_expr(name) -> bool:
110+
def is_Cn_expr(name: str) -> bool:
108111
"""Check if name is of the form {prefix}Cnnn"""
109112
if name.startswith(sympy_symbol_prefix) or name.startswith(sympy_slot_prefix):
110113
return False
111114
if not name.startswith("C"):
112115
return False
113116
number = name[1:]
114-
return number and number.isdigit()
117+
return number != "" and number.isdigit()
115118

116119

117120
def to_sympy_matrix(data, **kwargs) -> Optional[sympy.MutableDenseMatrix]:
@@ -131,6 +134,7 @@ class SympyExpression(BasicSympy):
131134

132135
is_Function = True
133136
nargs = None
137+
expr: Expression
134138

135139
def __new__(cls, *exprs):
136140
# sympy simplify may also recreate the object if simplification occurred
@@ -167,7 +171,11 @@ def __new__(cls, *args):
167171

168172
def has_any_symbols(self, *syms) -> bool:
169173
"""Check if any of the symbols in syms appears in the expression."""
170-
result = any(arg.has_any_symbols(*syms) for arg in self.args)
174+
result = any(
175+
arg.has_any_symbols(*syms)
176+
for arg in self.args
177+
if isinstance(arg, SympyExpression)
178+
)
171179
return result
172180

173181
def _eval_subs(self, old, new):
@@ -185,10 +193,14 @@ def _eval_rewrite(self, rule, args, **hints):
185193
return self
186194

187195
@property
188-
def is_commutative(self) -> bool:
196+
def is_commutative(self) -> Optional[bool]:
189197
"""Check if the arguments are commutative."""
190198
return all(getattr(t, "is_commutative", False) for t in self.args)
191199

200+
@is_commutative.setter
201+
def is_commutative(self, value: bool) -> None:
202+
return
203+
192204
def __str__(self) -> str:
193205
return f"{super().__str__()}[{self.expr}])"
194206

@@ -257,7 +269,7 @@ def symbol_to_sympy(symbol: Symbol, **kwargs) -> Sympy_Symbol:
257269
return builtin.to_sympy(symbol, **kwargs)
258270

259271

260-
def to_numeric_sympy_args(mathics_args: Type[BaseElement], evaluation) -> list:
272+
def to_numeric_sympy_args(mathics_args: BaseElement, evaluation) -> list:
261273
"""
262274
Convert Mathics arguments, such as the arguments in an evaluation
263275
method a Python list that is sutiable for feeding as arguments
@@ -268,6 +280,7 @@ def to_numeric_sympy_args(mathics_args: Type[BaseElement], evaluation) -> list:
268280
from mathics.eval.numerify import numerify
269281

270282
if mathics_args.is_literal:
283+
assert hasattr(mathics_args, "value")
271284
sympy_args = [mathics_args.value]
272285
else:
273286
args = numerify(mathics_args, evaluation).get_sequence()
@@ -352,16 +365,16 @@ def old_from_sympy(expr) -> BaseElement:
352365
if expr.is_Symbol:
353366
name = str(expr)
354367
if isinstance(expr, sympy.Dummy):
355-
name = name + (f"__Dummy_{expr.dummy_index}")
368+
name = name + (f"__Dummy_{expr.dummy_index}") # type: ignore[attr-defined]
356369
# Probably, this should be the value attribute
357370
return Symbol(name, sympy_dummy=expr)
358371
if is_Cn_expr(name):
359372
return Expression(SymbolC, Integer(int(name[1:])))
360373
if name.startswith(sympy_symbol_prefix):
361374
name = name[len(sympy_symbol_prefix) :]
362375
if name.startswith(sympy_slot_prefix):
363-
index = name[len(sympy_slot_prefix) :]
364-
return Expression(SymbolSlot, Integer(int(index)))
376+
index = int(name[len(sympy_slot_prefix) :])
377+
return Expression(SymbolSlot, Integer(index))
365378
elif expr.is_NumberSymbol:
366379
name = str(expr)
367380
if name is not None:
@@ -427,25 +440,26 @@ def old_from_sympy(expr) -> BaseElement:
427440
return expr.expr
428441

429442
if isinstance(expr, sympy.Piecewise):
430-
args = expr.args
431443
return Expression(
432444
SymbolPiecewise,
433445
ListExpression(
434446
*[
435447
to_mathics_list(from_sympy(case), from_sympy(cond))
436-
for case, cond in args
448+
for case, cond in cast(
449+
Sequence[Tuple[sympy.Basic, sympy.Basic]], expr.args
450+
)
437451
]
438452
),
439453
)
440454

441455
if isinstance(expr, SympyPrime):
442456
return Expression(SymbolPrime, from_sympy(expr.args[0]))
443457
if isinstance(expr, sympy.RootSum):
444-
return Expression(SymbolRootSum, from_sympy(expr.poly), from_sympy(expr.fun))
458+
return Expression(SymbolRootSum, from_sympy(expr.poly), from_sympy(expr.fun)) # type: ignore[attr-defined]
445459
if isinstance(expr, sympy.PurePoly):
446460
coeffs = expr.coeffs()
447461
monoms = expr.monoms()
448-
result = []
462+
result: List[BaseElement] = []
449463
for coeff, monom in zip(coeffs, monoms):
450464
factors = []
451465
if coeff != 1:
@@ -500,12 +514,14 @@ def old_from_sympy(expr) -> BaseElement:
500514
else:
501515
margs.append(from_sympy(arg))
502516
builtin = sympy_to_mathics.get(name)
503-
return builtin.from_sympy(margs)
517+
assert builtin is not None
518+
return builtin.from_sympy(tuple(margs))
504519

505520
elif isinstance(expr, sympy.sign):
506521
name = "Sign"
507522
else:
508523
name = expr.func.__name__
524+
assert name is not None
509525
if is_Cn_expr(name):
510526
return Expression(
511527
Expression(Symbol("C"), Integer(int(name[1:]))),
@@ -516,7 +532,7 @@ def old_from_sympy(expr) -> BaseElement:
516532
args = [from_sympy(arg) for arg in expr.args]
517533
builtin = sympy_to_mathics.get(name)
518534
if builtin is not None:
519-
return builtin.from_sympy(args)
535+
return builtin.from_sympy(tuple(args))
520536
return Expression(Symbol(name), *args)
521537

522538
if isinstance(expr, sympy.Tuple):

0 commit comments

Comments
 (0)