Repository: sympy/sympy

Issue:
Cannot use typing.Generic[T] with Symbol
I'm trying to subclass `Symbol` generically, but I cannot:

```python
In [35]: from typing import Generic, TypeVar

In [36]: T = TypeVar("T")

In [37]: class A(Symbol, Generic[T]):
    ...:     pass
    ...: 

In [38]: class B(A[T]):
    ...:     pass
    ...: 
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[38], line 1
----> 1 class B(A[T]):
      2     pass

File /usr/lib/python3.10/typing.py:309, in _tp_cache.<locals>.decorator.<locals>.inner(*args, **kwds)
    306 @functools.wraps(func)
    307 def inner(*args, **kwds):
    308     try:
--> 309         return cached(*args, **kwds)
    310     except TypeError:
    311         pass  # All real errors (not unhashable args) are raised below.

File /usr/lib/python3.10/typing.py:1342, in Generic.__class_getitem__(cls, params)
   1338         raise TypeError(
   1339             f"Parameters to {cls.__name__}[...] must all be unique")
   1340 else:
   1341     # Subscripting a regular Generic subclass.
-> 1342     if any(isinstance(t, ParamSpec) for t in cls.__parameters__):
   1343         params = _prepare_paramspec_params(cls, params)
   1344     else:

AttributeError: type object 'A' has no attribute '__parameters__'
```

This is linked to `sympy.Symbol`, because subclassing from anything else works (here with an empty class, but I tried with other classes not linked to Sympy and couldn't reproduce):

```python
In [40]: class K():
    ...:     pass
    ...: 

In [41]: class A(K, Generic[T]):
    ...:     pass
    ...: 

In [42]: class B(A[T]):
    ...:     pass
    ...: 
# no exception
```

I'm not sure if all classes are supposed to support this or not. Does the `Symbol` class modify/delete `__parameters__` ? `typing.Generics` work with multiple inheritance, is there something in `Symbol` which is uncompatible ?

Thank you for the help!

---

python: 3.10
sympy: 1.12

Discussion:

Patch:
diff --git a/sympy/core/basic.py b/sympy/core/basic.py
index 9237a282ca..98d21dbae6 100644
--- a/sympy/core/basic.py
+++ b/sympy/core/basic.py
@@ -118,6 +118,7 @@ def __init_subclass__(cls):
         # property methods. This method will only be called for subclasses of
         # Basic but not for Basic itself so we call
         # _prepare_class_assumptions(Basic) below the class definition.
+        super().__init_subclass__()
         _prepare_class_assumptions(cls)
 
     # To be overridden with True in the appropriate subclasses
diff --git a/sympy/parsing/latex/lark/latex.lark b/sympy/parsing/latex/lark/latex.lark
index 378f661086..357028bb25 100644
--- a/sympy/parsing/latex/lark/latex.lark
+++ b/sympy/parsing/latex/lark/latex.lark
@@ -44,8 +44,6 @@ FUNC_EXP:  "\\exp"
 FUNC_LOG:  "\\log"
 FUNC_LN:   "\\ln"
 FUNC_LG:   "\\lg"
-FUNC_MIN: "\\min"
-FUNC_MAX: "\\max"
 
 // trigonometric functions
 FUNC_SIN:  "\\sin"
@@ -80,8 +78,6 @@ CMD_DIV:   "\\div"
 CMD_FRAC:  "\\frac" | "\\dfrac" | "\\tfrac" | "\\nicefrac"
 CMD_BINOM: "\\binom" | "\\dbinom" | "\\tbinom"
 CMD_OVERLINE: "\\overline"
-CMD_LANGLE: "\\langle"
-CMD_RANGLE: "\\rangle"
 
 CMD_MATHIT: "\\mathit"
 
@@ -247,18 +243,6 @@ list_of_expressions: _expression ("," _expression)*
 
 function_applied: _oneletter_symbol L_PAREN list_of_expressions R_PAREN
 
-min: FUNC_MIN L_PAREN list_of_expressions R_PAREN
-
-max: FUNC_MAX L_PAREN list_of_expressions R_PAREN
-
-bra: CMD_LANGLE _expression BAR
-
-ket: BAR _expression CMD_RANGLE
-
-inner_product: CMD_LANGLE _expression BAR _expression CMD_RANGLE
-
-// outer_product: BAR _expression CMD_RANGLE CMD_LANGLE _expression BAR
-
 _function: function_applied
     | abs | floor | ceil
     | _trigonometric_function | _inverse_trigonometric_function
@@ -269,8 +253,6 @@ _function: function_applied
     | square_root
     | factorial
     | conjugate
-    | max | min
-    | bra | ket | inner_product
 
 exponential: FUNC_EXP _expression
 
diff --git a/sympy/parsing/latex/lark/latex_parser.py b/sympy/parsing/latex/lark/latex_parser.py
index deab4a5973..4b3f1e5d2a 100644
--- a/sympy/parsing/latex/lark/latex_parser.py
+++ b/sympy/parsing/latex/lark/latex_parser.py
@@ -291,28 +291,6 @@ def remove_tokens(args):
     def function_applied(self, tokens):
         return sympy.Function(tokens[0])(*tokens[2])
 
-    def min(self, tokens):
-        return sympy.Min(*tokens[2])
-
-    def max(self, tokens):
-        return sympy.Max(*tokens[2])
-
-    def bra(self, tokens):
-        # TODO: Change or update the below code (or remove this comment) when the issue #25551 is resolved
-        from sympy.physics.quantum import Bra
-        return Bra(tokens[1])
-
-    def ket(self, tokens):
-        # TODO: Change or update the below code (or remove this comment) when the issue #25551 is resolved
-        from sympy.physics.quantum import Ket
-        return Ket(tokens[1])
-
-    def inner_product(self, tokens):
-        # TODO: Change or update the below code (or remove this comment) when the issue #25551 is resolved
-        from sympy.physics.quantum import Bra, Ket, InnerProduct
-        return InnerProduct(Bra(tokens[1]), Ket(tokens[3]))
-
-
     def sin(self, tokens):
         return sympy.sin(tokens[1])
 
diff --git a/sympy/physics/_biomechanics/__init__.py b/sympy/physics/_biomechanics/__init__.py
index 0f273a17f6..0a25329372 100644
--- a/sympy/physics/_biomechanics/__init__.py
+++ b/sympy/physics/_biomechanics/__init__.py
@@ -6,7 +6,7 @@
 
 """
 
-from .curve import (
+from .characteristic import (
    FiberForceLengthActiveDeGroote2016,
    FiberForceLengthPassiveDeGroote2016,
    FiberForceLengthPassiveInverseDeGroote2016,


Test patch:
diff --git a/sympy/core/tests/test_args.py b/sympy/core/tests/test_args.py
index 9d6e238a19..b086b5e5af 100644
--- a/sympy/core/tests/test_args.py
+++ b/sympy/core/tests/test_args.py
@@ -3362,41 +3362,41 @@ def test_sympy__physics__vector__frame__CoordinateSym():
 
 
 @SKIP("abstract class")
-def test_sympy__physics___biomechanics__curve__CharacteristicCurveFunction():
+def test_sympy__physics___biomechanics__characteristic__CharacteristicCurveFunction():
     pass
 
 
-def test_sympy__physics___biomechanics__curve__TendonForceLengthDeGroote2016():
+def test_sympy__physics___biomechanics__characteristic__TendonForceLengthDeGroote2016():
     from sympy.physics._biomechanics import TendonForceLengthDeGroote2016
     l_T_tilde, c0, c1, c2, c3 = symbols('l_T_tilde, c0, c1, c2, c3')
     assert _test_args(TendonForceLengthDeGroote2016(l_T_tilde, c0, c1, c2, c3))
 
 
-def test_sympy__physics___biomechanics__curve__TendonForceLengthInverseDeGroote2016():
+def test_sympy__physics___biomechanics__characteristic__TendonForceLengthInverseDeGroote2016():
     from sympy.physics._biomechanics import TendonForceLengthInverseDeGroote2016
     fl_T, c0, c1, c2, c3 = symbols('fl_T, c0, c1, c2, c3')
     assert _test_args(TendonForceLengthInverseDeGroote2016(fl_T, c0, c1, c2, c3))
 
 
-def test_sympy__physics___biomechanics__curve__FiberForceLengthPassiveDeGroote2016():
+def test_sympy__physics___biomechanics__characteristic__FiberForceLengthPassiveDeGroote2016():
     from sympy.physics._biomechanics import FiberForceLengthPassiveDeGroote2016
     l_M_tilde, c0, c1 = symbols('l_M_tilde, c0, c1')
     assert _test_args(FiberForceLengthPassiveDeGroote2016(l_M_tilde, c0, c1))
 
 
-def test_sympy__physics___biomechanics__curve__FiberForceLengthPassiveInverseDeGroote2016():
+def test_sympy__physics___biomechanics__characteristic__FiberForceLengthPassiveInverseDeGroote2016():
     from sympy.physics._biomechanics import FiberForceLengthPassiveInverseDeGroote2016
     fl_M_pas, c0, c1 = symbols('fl_M_pas, c0, c1')
     assert _test_args(FiberForceLengthPassiveInverseDeGroote2016(fl_M_pas, c0, c1))
 
 
-def test_sympy__physics___biomechanics__curve__FiberForceLengthActiveDeGroote2016():
+def test_sympy__physics___biomechanics__characteristic__FiberForceLengthActiveDeGroote2016():
     from sympy.physics._biomechanics import FiberForceLengthActiveDeGroote2016
     l_M_tilde, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11 = symbols('l_M_tilde, c0:12')
     assert _test_args(FiberForceLengthActiveDeGroote2016(l_M_tilde, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11))
 
 
-def test_sympy__physics___biomechanics__curve__FiberForceVelocityDeGroote2016():
+def test_sympy__physics___biomechanics__characteristic__FiberForceVelocityDeGroote2016():
     from sympy.physics._biomechanics import FiberForceVelocityDeGroote2016
     v_M_tilde, c0, c1, c2, c3 = symbols('v_M_tilde, c0, c1, c2, c3')
     assert _test_args(FiberForceVelocityDeGroote2016(v_M_tilde, c0, c1, c2, c3))
diff --git a/sympy/core/tests/test_basic.py b/sympy/core/tests/test_basic.py
index dcb3f5e12c..962b3c7a16 100644
--- a/sympy/core/tests/test_basic.py
+++ b/sympy/core/tests/test_basic.py
@@ -1,7 +1,7 @@
 """This tests sympy/core/basic.py with (ideally) no reference to subclasses
 of Basic or Atom."""
-
 import collections
+from typing import TypeVar, Generic
 
 from sympy.assumptions.ask import Q
 from sympy.core.basic import (Basic, Atom, as_Basic,
@@ -22,6 +22,7 @@
 b2 = Basic(b1)
 b3 = Basic(b2)
 b21 = Basic(b2, b1)
+T = TypeVar('T')
 
 
 def test__aresame():
@@ -317,3 +318,12 @@ class MySubclass(Basic, metaclass=MyMeta):
         exec(code)
 
     assert myclasses == ['executed']
+
+
+def test_generic():
+    # https://github.com/sympy/sympy/issues/25399
+    class A(Symbol, Generic[T]):
+        pass
+
+    class B(A[T]):
+        pass
diff --git a/sympy/parsing/tests/test_latex_lark.py b/sympy/parsing/tests/test_latex_lark.py
index 8cb05445d9..c8a52c03dc 100644
--- a/sympy/parsing/tests/test_latex_lark.py
+++ b/sympy/parsing/tests/test_latex_lark.py
@@ -16,14 +16,14 @@
 from sympy.functions.elementary.complexes import Abs, conjugate
 from sympy.functions.elementary.exponential import exp, log
 from sympy.functions.elementary.integers import ceiling, floor
-from sympy.functions.elementary.miscellaneous import root, sqrt, Min, Max
+from sympy.functions.elementary.miscellaneous import root, sqrt
 from sympy.functions.elementary.trigonometric import asin, cos, csc, sec, sin, tan
 from sympy.integrals.integrals import Integral
 from sympy.series.limits import Limit
 
 from sympy.core.relational import Eq, Ne, Lt, Le, Gt, Ge
-from sympy.physics.quantum import Bra, Ket, InnerProduct
-from sympy.abc import x, y, z, a, b, c, d, t, k, n
+from sympy.physics.quantum.state import Bra, Ket
+from sympy.abc import x, y, z, a, b, c, t, k, n
 
 lark = import_module("lark")
 
@@ -59,12 +59,6 @@ def _Conjugate(a):
 def _Abs(a):
     return Abs(a, evaluate=False)
 
-def _Min(*args):
-    return Min(*args, evaluate=False)
-
-def _Max(*args):
-    return Max(*args, evaluate=False)
-
 
 def _factorial(a):
     return factorial(a, evaluate=False)
@@ -388,15 +382,7 @@ def _binomial(n, k):
     (r"\overline{z}", _Conjugate(z)),
     (r"\overline{\overline{z}}", _Conjugate(_Conjugate(z))),
     (r"\overline{x + y}", _Conjugate(_Add(x, y))),
-    (r"\overline{x} + \overline{y}", _Conjugate(x) + _Conjugate(y)),
-    (r"\min(a, b)", _Min(a, b)),
-    (r"\min(a, b, c - d, xy)", _Min(a, b, c - d, x * y)),
-    (r"\max(a, b)", _Max(a, b)),
-    (r"\max(a, b, c - d, xy)", _Max(a, b, c - d, x * y)),
-    # physics things don't have an `evaluate=False` variant
-    (r"\langle x |", Bra('x')),
-    (r"| x \rangle", Ket('x')),
-    (r"\langle x | y \rangle", InnerProduct(Bra('x'), Ket('y'))),
+    (r"\overline{x} + \overline{y}", _Conjugate(x) + _Conjugate(y))
 ]
 
 EVALUATED_COMMON_FUNCTION_EXPRESSION_PAIRS = [
@@ -422,14 +408,7 @@ def _binomial(n, k):
     (r"\overline{z}", conjugate(z)),
     (r"\overline{\overline{z}}", conjugate(conjugate(z))),
     (r"\overline{x + y}", conjugate(x + y)),
-    (r"\overline{x} + \overline{y}", conjugate(x) + conjugate(y)),
-    (r"\min(a, b)", Min(a, b)),
-    (r"\min(a, b, c - d, xy)", Min(a, b, c - d, x * y)),
-    (r"\max(a, b)", Max(a, b)),
-    (r"\max(a, b, c - d, xy)", Max(a, b, c - d, x * y)),
-    (r"\langle x |", Bra('x')),
-    (r"| x \rangle", Ket('x')),
-    (r"\langle x | y \rangle", InnerProduct(Bra('x'), Ket('y'))),
+    (r"\overline{x} + \overline{y}", conjugate(x) + conjugate(y))
 ]
 
 SPACING_RELATED_EXPRESSION_PAIRS = [
@@ -467,6 +446,8 @@ def _binomial(n, k):
     (r"\left(x + y\right) z", _Mul(_Add(x, y), z)),
     (r"\left( x + y\right ) z", _Mul(_Add(x, y), z)),
     (r"\left(  x + y\right ) z", _Mul(_Add(x, y), z)),
+    (r"\langle x |", Bra('x')),
+    (r"| x \rangle", Ket('x')),
 ]
 
 
diff --git a/sympy/physics/_biomechanics/curve.py b/sympy/physics/_biomechanics/characteristic.py
similarity index 100%
rename from sympy/physics/_biomechanics/curve.py
rename to sympy/physics/_biomechanics/characteristic.py
diff --git a/sympy/physics/_biomechanics/tests/test_curve.py b/sympy/physics/_biomechanics/tests/test_characteristic.py
similarity index 99%
rename from sympy/physics/_biomechanics/tests/test_curve.py
rename to sympy/physics/_biomechanics/tests/test_characteristic.py
index 98cfc9023a..a55955aa23 100644
--- a/sympy/physics/_biomechanics/tests/test_curve.py
+++ b/sympy/physics/_biomechanics/tests/test_characteristic.py
@@ -9,7 +9,7 @@
 from sympy.external.importtools import import_module
 from sympy.functions.elementary.exponential import exp, log
 from sympy.functions.elementary.miscellaneous import sqrt
-from sympy.physics._biomechanics.curve import (
+from sympy.physics._biomechanics.characteristic import (
     CharacteristicCurveFunction,
     FiberForceLengthActiveDeGroote2016,
     FiberForceLengthPassiveDeGroote2016,