# List of active deprecations#

This pages lists all active deprecations in the SymPy codebase. See the Deprecation Policy page for a description of SymPy’s deprecation policy, as well as instructions for contributors on how to deprecate things.

In particular, the deprecation policy for SymPy is for deprecations to last at
least **1 year** after the first major release that includes the deprecation.
After that period, the deprecated functionality may be removed from SymPy, and
code will need to be updated to use the replacement feature to continue
working.

During the deprecation period, a `SymPyDeprecationWarning`

message will be
printed whenever the deprecated functionality is used. It is recommended for
users to update their code so that it does not use deprecated functionality,
as described below for each given deprecation.

## Silencing SymPy Deprecation Warnings#

To silence SymPy deprecation warnings, add a filter using the
`warnings`

module. For
example:

```
import warnings
from sympy.utilities.exceptions import SymPyDeprecationWarning
warnings.filterwarnings(
# replace "ignore" with "error" to make the warning raise an exception.
# This useful if you want to test you aren't using deprecated code.
"ignore",
# message may be omitted to filter all SymPyDeprecationWarnings
message=r"(?s).*<regex matching the warning message>",
category=SymPyDeprecationWarning,
module=r"<regex matching your module>"
)
```

Here `(?s).*<regex matching the warning message>`

is a regular expression
matching the warning message. For example, to filter a warning about
`sympy.printing`

, you might use `message=r"(?s).*sympy\.printing"`

. The
leading `(?s).*`

is there because the warnings module matches `message`

against the start of the warning message, and because typical warning messages
span multiple lines.

`<regex matching your module>`

should be a regular expression matching your
module that uses the deprecated code. It is recommended to include this so
that you don’t also silence the same warning for unrelated modules.

This same pattern may be used to instead turn `SymPyDeprecationWarning`

into
an error so that you can test that you aren’t using deprecated code. To do
this, replace `"ignore"`

with `"error"`

in the above example. You may
also omit `message`

to make this apply to all `SymPyDeprecationWarning`

warnings.

If you are using pytest, you can use the pytest warnings filtering
capabilities
to either ignore `SymPyDeprecationWarning`

or turn them into errors.

Note

The Python `-W`

flag and
`PYTHONWARNINGS`

environment
variable
will NOT work to filter SymPy deprecation warnings (see this blog
post
by Ned Batchelder and this SymPy
issue for details on why). You
will need to either add a `warnings`

filter as above or use pytest to filter
SymPy deprecation warnings.

## Version 1.12#

### New Joint coordinate format#

The format, i.e. type and auto generated name, of the generalized coordinates
and generalized speeds of the joints in the `sympy.physics.mechanics`

module
has changed. The data type has changed from `list`

to `Matrix`

, which is the
same as the type for the generalized coordinates within the `KanesMethod`

.
The auto naming of the generalized coordinates and generalized speeds of the
`PinJoint`

and `PrismaticJoint`

have also changed to `q_<joint.name>`

and
`u_<joint.name>`

. Previously each of those joints had an unique template for
auto generating these names.

### New Joint intermediate frames#

The definition of the joint axis in the `sympy.physics.mechanics`

module has
changed. Instead of using the arguments `parent_axis`

and `child_axis`

to
automatically determine the joint axis and an intermediate reference frame, the
joints now use an intermediate frame argument for both the parent and the child
body, i.e. `parent_interframe`

and `child_interframe`

. This means that you
can now fully define the joint attachment, consisting of a point and frame, for
both bodies. Furthermore, if a joint like the `PinJoint`

has a specific joint
axis, e.g. the axis about which the rotation occurs, then this axis can be
specified using the `joint_axis`

argument. An advantage of this setup is that
one can more accurately define the transformation from the parent body to the
child body.

For example, suppose you want a `PinJoint`

that rotates the child body about
the `parent.z`

axis and `-child.z`

axis. The previous way to specify this
joint was:

```
>>> from sympy.physics.mechanics import Body, PinJoint
>>> parent, child = Body('parent'), Body('child')
>>> pin = PinJoint('pin', parent, child, parent_axis=parent.z,
... child_axis=-child.z)
>>> parent.dcm(child)
Matrix([
[-cos(q_pin(t)), -sin(q_pin(t)), 0],
[-sin(q_pin(t)), cos(q_pin(t)), 0],
[ 0, 0, -1]])
```

When inspecting this matrix you will notice that for `theta_pin = 0`

the child
body is rotated \(\pi\) rad about the `parent.y`

axis. In the new definition
you can see that we get the same result, but this time we have also specified
this exact rotation:

```
>>> from sympy import pi
>>> from sympy.physics.mechanics import Body, PinJoint, ReferenceFrame
>>> parent, child, = Body('parent'), Body('child')
>>> int_frame = ReferenceFrame('int_frame')
>>> int_frame.orient_axis(child.frame, child.y, pi)
>>> pin = PinJoint('pin', parent, child, joint_axis=parent.z,
... child_interframe=int_frame)
>>> parent.dcm(child)
Matrix([
[-cos(q_pin(t)), -sin(q_pin(t)), 0],
[-sin(q_pin(t)), cos(q_pin(t)), 0],
[ 0, 0, -1]])
```

However if you liked the fact that the deprecated arguments aligned the frames
for you, then you can still make use of this feature by providing vectors to
`parent_interframe`

and `child_interframe`

, which are then oriented such
that the joint axis expressed in the intermediate frame is aligned with the
given vector:

```
>>> from sympy.physics.mechanics import Body, PinJoint
>>> parent, child = Body('parent'), Body('child')
>>> pin = PinJoint('pin', parent, child, parent_interframe=parent.z,
... child_interframe=-child.z)
>>> parent.dcm(child)
Matrix([
[-cos(q_pin(t)), -sin(q_pin(t)), 0],
[-sin(q_pin(t)), cos(q_pin(t)), 0],
[ 0, 0, -1]])
```

### Change in joint attachment point argument#

The argument names for specifying the attachment points of a joint in
`sympy.physics.mechanics`

, i.e. `parent_joint_pos`

and `child_joint_pos`

,
have been changed to `parent_point`

and `child_point`

. This is because these
arguments can now also be `Point`

objects, so they can be exactly the same as
the `parent_point`

and `child_point`

attributes.

For example, suppose you want a `PinJoint`

in the parent to be positioned at
`parent.frame.x`

with respect to the mass center, and in the child at
`-child.frame.x`

. The previous way to specify this was:

```
>>> from sympy.physics.mechanics import Body, PinJoint
>>> parent, child = Body('parent'), Body('child')
>>> pin = PinJoint('pin', parent, child, parent_joint_pos=parent.frame.x,
... child_joint_pos=-child.frame.x)
>>> pin.parent_point.pos_from(parent.masscenter)
parent_frame.x
>>> pin.child_point.pos_from(child.masscenter)
- child_frame.x
```

Now you can do the same with either

```
>>> from sympy.physics.mechanics import Body, PinJoint
>>> parent, child = Body('parent'), Body('child')
>>> pin = PinJoint('pin', parent, child, parent_point=parent.frame.x,
... child_point=-child.frame.x)
>>> pin.parent_point.pos_from(parent.masscenter)
parent_frame.x
>>> pin.child_point.pos_from(child.masscenter)
- child_frame.x
```

Or

```
>>> from sympy.physics.mechanics import Body, PinJoint, Point
>>> parent, child = Body('parent'), Body('child')
>>> parent_point = parent.masscenter.locatenew('parent_point', parent.frame.x)
>>> child_point = child.masscenter.locatenew('child_point', -child.frame.x)
>>> pin = PinJoint('pin', parent, child, parent_point=parent_point,
... child_point=child_point)
>>> pin.parent_point.pos_from(parent.masscenter)
parent_frame.x
>>> pin.child_point.pos_from(child.masscenter)
- child_frame.x
```

## Version 1.11#

### New Mathematica code parser#

The old mathematica code parser defined in the module `sympy.parsing.mathematica`

in the function `mathematica`

is deprecated. The function `parse_mathematica`

with a new and more comprehensive parser should be used instead.

The `additional_translations`

parameter for the Mathematica parser is not available
in `parse_mathematica`

.
Additional translation rules to convert Mathematica expressions into SymPy ones
should be specified after the conversion using SymPy’s `.replace( )`

or `.subs( )`

methods on the output expression. If the translator fails to recognize the logical
meaning of a Mathematica expression, a form similar to Mathematica’s full form
will be returned, using SymPy’s `Function`

object to encode the nodes of the
syntax tree.

For example, suppose you want `F`

to be a function that returns the maximum
value multiplied by the minimum value, the previous way to
specify this conversion was:

```
>>> from sympy.parsing.mathematica import mathematica
>>> mathematica('F[7,5,3]', {'F[*x]': 'Max(*x)*Min(*x)'})
21
```

Now you can do the same with

```
>>> from sympy.parsing.mathematica import parse_mathematica
>>> from sympy import Function, Max, Min
>>> parse_mathematica("F[7,5,3]").replace(Function("F"), lambda *x: Max(*x)*Min(*x))
21
```

### Redundant static methods in `carmichael`

#

A number of static methods in `~.carmichael`

are just wrappers around other
functions. Instead of `carmichael.is_perfect_square`

use
`sympy.ntheory.primetest.is_square`

and instead of `carmichael.is_prime`

use
`~.isprime`

. Finally, `carmichael.divides`

can be replaced by instead checking

```
n % p == 0
```

### The `check`

argument to `HadamardProduct`

, `MatAdd`

and `MatMul`

#

This argument can be used to pass incorrect values to `~.HadamardProduct`

,
`~.MatAdd`

, and `~.MatMul`

leading to later problems. The `check`

argument
will be removed and the arguments will always be checked for correctness, i.e.,
the arguments are matrices or matrix symbols.

## Version 1.10#

### Some traversal functions have been moved#

Some traversal functions have moved. Specifically, the functions

`bottom_up`

`interactive_traversal`

`postorder_traversal`

`preorder_traversal`

`use`

have moved to different SymPy submodules.

These functions should be used from the top-level `sympy`

namespace, like

```
sympy.preorder_traversal
```

or

```
from sympy import preorder_traversal
```

In general, end-users should use the top-level `sympy`

namespace for any
functions present there. If a name is in the top-level namespace, its specific
SymPy submodule should not be relied on, as functions may move around due to
internal refactorings.

`sympy.core.trace`

#

The trace object `sympy.core.trace.Tr()`

was moved to
`sympy.physics.quantum.trace.Tr()`

. This was because it was only used in the
`sympy.physics.quantum`

submodule, so it was better to have it there than in
the core.

### The `sympy.core.compatibility`

submodule#

The `sympy.core.compatibility`

submodule is deprecated.

This submodule was only ever intended for internal use. Now that SymPy no longer supports Python 2, this module is no longer necessary, and the remaining helper functions have been moved to more convenient places in the SymPy codebase.

Some of the functions that were in this module are available from the top-level SymPy namespace, i.e.,

```
sympy.ordered
sympy.default_sort_key
```

or

```
from sympy import ordered, default_sort_key
```

In general, end-users should use the top-level `sympy`

namespace for any
functions present there. If a name is in the top-level namespace, its specific
SymPy submodule should not be relied on, as functions may move around due to
internal refactorings.

The remaining functions in `sympy.core.compatibility`

were only intended for
internal SymPy use and should not be used by user code.

Additionally, these two functions, `ordered`

and `default_sort_key`

, also used
to be in `sympy.utilities.iterables`

but have been moved from there as well.

## Version 1.9#

`expr_free_symbols`

#

The `expr_free_symbols`

attribute of various SymPy objects is deprecated.

`expr_free_symbols`

was meant to represent indexed objects such as
`MatrixElement`

and `Indexed`

as free symbols. This was
intended to make derivatives of free symbols work. However, this now works
without making use of the method:

```
>>> from sympy import Indexed, MatrixSymbol, diff
>>> a = Indexed("A", 0)
>>> diff(a**2, a)
2*A[0]
>>> X = MatrixSymbol("X", 3, 3)
>>> diff(X[0, 0]**2, X[0, 0])
2*X[0, 0]
```

This was a general property that was added to solve a very specific problem but it added a layer of abstraction that is not necessary in general.

objects that have structural “non-expression” nodes already allow one to focus on the expression node if desired, e.g.

>>> from sympy import Derivative, symbols, Function >>> x = symbols('x') >>> f = Function('f') >>> Derivative(f(x), x).expr f(x)

introduction of this property encourages imprecise thinking when requesting free_symbols since it allows one to get symbols from a specific node of an object without specifying the node

the property was incorrectly added to

`AtomicExpr`

so numbers are returned as`expr_free_symbols`

:>>> S(2).expr_free_symbols 2

the application of the concept was misapplied to define

`Subs.expr_free_symbols`

: it added in`expr_free_symbols`

of the point but the point is a`Tuple`

so nothing was addedit was not used anywhere else in the codebase except in the context of differentiating a

`Subs`

object, which suggested that it was not something of general use, this is also confirmed by the fact that,it was added without specific tests except for test of the derivatives of the Subs object for which it was introduced

See issue #21494 for more discussion.

`sympy.stats.sample(numsamples=n)`

#

The `numsamples`

parameter to `sympy.stats.sample()`

is deprecated.

`numsamples`

makes `sample()`

return a list of size `numsamples`

, like

```
>>> from sympy.stats import Die, sample
>>> X = Die('X', 6)
>>> sample(X, numsamples=3)
[3, 2, 3]
```

However, this functionality can be easily implemented by the user with a list comprehension

```
>>> [sample(X) for i in range(3)]
[5, 4, 3]
```

Additionally, it is redundant with the `size`

parameter, which makes `sample`

return a NumPy array with the given shape.

```
>>> sample(X, size=(3,))
array([6, 6, 1])
```

Historically, `sample`

was changed in SymPy 1.7 so it returned an iterator
instead of sample value. Since an iterator was returned, a numsamples
parameter was added to specify the length of the iterator.

However, this new behavior was considered confusing, as discussed in issue
#21563, so it was reverted.
Now, `sample_iter`

should be used if a iterator is needed. Consequently, the
`numsamples`

parameter is no longer needed for `sample()`

.

`sympy.polys.solvers.RawMatrix`

#

The `RawMatrix`

class is deprecated. The `RawMatrix`

class was a subclass
of `Matrix`

that used domain elements instead of `Expr`

as the elements of
the matrix. This breaks a key internal invariant of `Matrix`

and this kind
of subclassing limits improvements to the `Matrix`

class.

The only part of SymPy that documented the use of the `RawMatrix`

class was
the Smith normal form code, and that has now been changed to use
`DomainMatrix`

instead. It is recommended that anyone using `RawMatrix`

with
the previous Smith Normal Form code should switch to using `DomainMatrix`

as
shown in issue #21402. A better
API for the Smith normal form will be added later.

### Non-`Expr`

objects in a Matrix#

In SymPy 1.8 and earlier versions it was possible to put non-`Expr`

elements in a `Matrix`

and the matrix elements could be any arbitrary
Python object:

```
>>> M = Matrix([[(1, 2), {}]])
```

This is not useful and does not really work, e.g.:

```
>>> M + M
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for +: 'Dict' and 'Dict'
```

The main reason for making this possible was that there were a number of
`Matrix`

subclasses in the SymPy codebase that wanted to work with objects
from the polys module, e.g.

`RawMatrix`

(see above) was used in`solve_lin_sys`

which was part of`heurisch`

and was also used by`smith_normal_form`

. The`NewMatrix`

class used domain elements as the elements of the Matrix rather than`Expr`

.`NewMatrix`

was used in the`holonomic`

module and also used domain elements as matrix elements`PolyMatrix`

used a mix of`Poly`

and`Expr`

as the matrix elements and was used by`risch`

.

All of these matrix subclasses were broken in different ways and the
introduction of `DomainMatrix`

(#20780,
#20759,
#20621,
#19882,
#18844) provides a better
solution for all cases. Previous PRs have removed the dependence of these
other use cases on Matrix
(#21441,
#21427,
#21402) and now
#21496 has deprecated having
non-`Expr`

in a `Matrix`

.

This change makes it possible to improve the internals of the Matrix class but
it potentially impacts on some downstream use cases that might be similar to
the uses of `Matrix`

with non-`Expr`

elements that were in the SymPy codebase.
A potential replacement for code that used `Matrix`

with non-`Expr`

elements
is `DomainMatrix`

if the elements are something like domain elements
and a domain object can be provided for them. Alternatively if the goal is
just printing support then perhaps `TableForm`

can be used.

It isn’t clear what to advise as a replacement here without knowing more about the usecase. If you are unclear how to update your code, please open an issue or write to our mailing list so we can discuss it.

### The `get_segments`

attribute of plotting objects#

The `get_segments`

method implemented in `Line2DBaseSeries`

is used
to convert two list of coordinates, `x`

and `y`

, into a list of segments used
by Matplotlib’s `LineCollection`

to plot a line.

Since the list of segments is only required by Matplotlib (for example, Bokeh,
Plotly, Mayavi, K3D only require lists of coordinates), this has been moved
inside the `MatplotlibBackend`

class.

Note that previously, the method
`get_points()`

always returned
uniformly sampled points, which meant that some functions were not plotted
correctly when using `get_points()`

to plot with Matplotlib.

To avoid this problem, the method `get_segments()`

could be used, which used
adaptive sampling and which could be used with Matplotlib’s `LineCollection`

.
However, this has been changed, and now `get_points()`

can also use adaptive
sampling. The `get_data()`

method can also be used.

### The `mdft`

function in `sympy.physics.matrices`

#

The `sympy.physics.matrices.mdft()`

function is deprecated. It can be replaced
with the `DFT`

class in `sympy.matrices.expressions.fourier`

.

In particular, replace `mdft(n)`

with `DFT(n).as_explicit()`

. For example:

```
>>> from sympy.physics.matrices import mdft
>>> mdft(3) # DEPRECATED
Matrix([
[sqrt(3)/3, sqrt(3)/3, sqrt(3)/3],
[sqrt(3)/3, sqrt(3)*exp(-2*I*pi/3)/3, sqrt(3)*exp(2*I*pi/3)/3],
[sqrt(3)/3, sqrt(3)*exp(2*I*pi/3)/3, sqrt(3)*exp(-2*I*pi/3)/3]])
```

```
>>> from sympy.matrices.expressions.fourier import DFT
>>> DFT(3)
DFT(3)
>>> DFT(3).as_explicit()
Matrix([
[sqrt(3)/3, sqrt(3)/3, sqrt(3)/3],
[sqrt(3)/3, sqrt(3)*exp(-2*I*pi/3)/3, sqrt(3)*exp(2*I*pi/3)/3],
[sqrt(3)/3, sqrt(3)*exp(2*I*pi/3)/3, sqrt(3)*exp(-2*I*pi/3)/3]])
```

This was changed because the `sympy.physics`

submodule is supposed to only
contain things that are specific to physics, but the discrete Fourier
transform matrix is a more general mathematical concept, so it is better
located in the `sympy.matrices`

module. Furthermore, the `DFT`

class is a
matrix expression, meaning it can be unevaluated
and support symbolic shape.

### The private `SparseMatrix._smat`

and `DenseMatrix._mat`

attributes#

The `._mat`

attribute of `Matrix`

and the
`._smat`

attribute of `SparseMatrix`

are
deprecated.

The internal representation of `Matrix`

and `SparseMatrix`

was changed to be a
`DomainMatrix`

in #21626
so that it is no longer possible to expose a mutable list/dict as a way of
mutating a `Matrix`

. Instead of `._mat`

the new `.flat()`

method can be used,
which returns a new list that cannot be used to mutate the `Matrix`

itself.
Instead of `._smat`

the `.todok()`

method can be used which returns a new
dict.

Note that these attributes are already changed in SymPy 1.9 to return read-only copies, so that any code that relied on mutating them will be broken. Also these attributes were technically always private (they started with an underscore), so user code should not really have been using them in the first place.

### laplace_transform of a Matrix with noconds=False#

Prior to version 1.9, calling `laplace_transform()`

on a `Matrix`

with
`noconds=False`

(which is the default), resulted in a Matrix of tuples:

```
>>> from sympy import laplace_transform, symbols, eye
>>> t, z = symbols('t z')
>>> laplace_transform(eye(2), t, z)
Matrix([
[(1/z, 0, True), (0, 0, True)],
[ (0, 0, True), (1/z, 0, True)]])
```

However, `Matrix`

is only designed to work with `Expr`

objects (see
Non-Expr objects in a Matrix above).

To avoid this, either use `noconds=True`

to remove the convergence conditions

```
>>> laplace_transform(eye(2), t, z, noconds=True)
Matrix([
[1/z, 0],
[ 0, 1/z]])
```

or use `legacy_matrix=False`

to return the new behavior, which will be to
return a single tuple with the Matrix in the first argument and the
convergence conditions combined into a single condition for the whole matrix.

```
>>> laplace_transform(eye(2), t, z, legacy_matrix=False)
(Matrix([
[1/z, 0],
[ 0, 1/z]]), 0, True)
```

When this deprecation is removed the `legacy_matrix=False`

behavior will
become the default, but the flag will be left intact for compatibility.

## Version 1.8#

`sympy.printing.theanocode`

#

Theano has been discontinued, and forked
into a new project called Aesara. The
`sympy.printing.theanocode`

module has been renamed to
`sympy.printing.aesaracode`

, and all the corresponding functions have
been renamed (e.g., `theano_code`

has been renamed to `aesara_code()`

,
`TheanoPrinter`

has been renamed to `AesaraPrinter`

, and so on).

## Version 1.7.1#

### Calling `sympy.stats.StochasticProcess.distribution`

with `RandomIndexedSymbol`

#

The `distribution`

method of `sympy.stats`

stochastic
processes used to accept a
`RandomIndexedSymbol`

(that is, a stochastic process indexed with a
timestamp), but should now only be called with the timestamp.

For example, if you have

```
>>> from sympy import symbols
>>> from sympy.stats import WienerProcess
>>> W = WienerProcess('W')
>>> t = symbols('t', positive=True)
```

Previously this would work

```
W.distribution(W(t)) # DEPRECATED
```

It should now be called like

```
>>> W.distribution(t)
NormalDistribution(0, sqrt(t))
```

This was change was made as part of a change to store only `Basic`

objects in
`sympy.stats`

`.args`

. See issue
#20078 for details.

## Version 1.7#

`sympy.stats.DiscreteMarkovChain.absorbing_probabilites()`

#

The `absorbing_probabilites`

method name was misspelled. The correct spelling
`absorbing_probabilities()`

(“absorbing probabilit*i*es”) should be used
instead.

`sympy.utilities.misc.find_executable()`

#

The function `sympy.utilities.misc.find_executable()`

is deprecated. Instead
use the standard library
`shutil.which()`

function, which has been in the standard library since Python 3.3 and is more
powerful.

### Mutable attributes in `sympy.diffgeom`

#

Several parts of `sympy.diffgeom`

have been updated to no longer be
mutable, which better matches the immutable design used in the rest of SymPy.

Passing strings for symbol names in

`CoordSystem`

is deprecated. Instead you should be explicit and pass symbols with the appropriate assumptions, for instance, instead ofCoordSystem(name, patch, ['x', 'y']) # DEPRECATED

use

CoordSystem(name, patch, symbols('x y', real=True))

Similarly, the

`names`

keyword argument has been renamed to`symbols`

, which should be a list of symbols.The

`Manifold.patches`

attribute is deprecated. Patches should be tracked separately.The

`Patch.coord_systems`

attribute is deprecated. Coordinate systems should be tracked separately.The

`CoordSystem.transforms`

attribute,`CoordSystem.connect_to()`

method, and`CoordSystem.coord_tuple_transform_to()`

method are deprecated. Instead, use the`relations`

keyword to the`CoordSystem`

class constructor and the`CoordSystem.transformation()`

and`CoordSystem.transform()`

methods (see the docstring of`CoordSystem`

for examples).

### The `unicode`

argument and attribute to `sympy.printing.pretty.stringpict.prettyForm`

and the `sympy.printing.pretty.pretty_symbology.xstr`

function#

The `sympy.printing.pretty.pretty_symbology.xstr`

function, and the `unicode`

argument and attribute to `sympy.printing.pretty.stringpict.prettyForm`

were both present to support the Unicode behavior of Python 2. Since Unicode
strings are the default in Python 3, these are not needed any more. `xstr()`

should be replaced with just `str()`

, the `unicode`

argument to `prettyForm`

should be omitted, and the `prettyForm.unicode`

attribute should be replaced
with the `prettyForm.s`

attribute.

### Passing the arguments to `lambdify`

as a `set`

#

Passing the function arguments to lambdify as a set is deprecated. Instead pass them as a list or tuple. For example, instead of

```
lambdify({x, y}, x + 2*y) # WRONG
```

use

```
lambdify((x, y), x + 2*y) # RIGHT
```

This is because sets are unordered. For instance, in the above example it
would be impossible for `lambidfy`

to know if it was called with `{x, y}`

or
`{y, x}`

. Thus, when passed the arguments as a set `lambdify`

would have to
guess their order, which would lead to an incorrect function if it guessed
incorrectly.

### Core operators no longer accept non-Expr args#

The core operator classes `Add`

, `Mul`

, and `Pow`

can no longer be constructed directly with objects that are not subclasses of
`Expr`

.

`Expr`

is the superclass of all SymPy classes that represent scalar
numeric quantities. For example, `sin`

, `Symbol`

, and
`Add`

are all subclasses of `Expr`

. However, may objects in
SymPy are not `Expr`

because they represent some other type of
mathematical object. For example, `Set`

, `Poly`

, and
`Boolean`

are all non-`Expr`

. These do not make mathematical sense
inside of `Add`

, `Mul`

, and `Pow`

, which are designed specifically to
represent the addition, multiplication, and exponentiation of scalar complex
numbers.

Manually constructing one of these classes with such an object is possible, but it will generally create something that will then break. For example

```
Mul(1, Tuple(2)) # This is deprecated
```

works and creates `Tuple(2)`

, but only because `Mul`

is “tricked” by always
treating \(1 \cdot x = x\). If instead you try

```
Mul(2, Tuple(2)) # This is deprecated
```

it fails with an exception

```
AttributeError: 'Tuple' object has no attribute 'as_coeff_Mul'
```

because it tries to call a method of `Expr`

on the `Tuple`

object, which does
not have all the `Expr`

methods (because it is not a subclass of `Expr`

).

If you want to use the `+`

, `*`

, or `**`

operation on a non-`Expr`

object, use
the operator directly rather than using `Mul`

, `Add`

or `Pow`

. If functional
versions of these are desired, you can use a `lambda`

or the
`operator`

module.

## Version 1.6#

### Various `sympy.utilities`

submodules have moved#

The following submodules have been renamed.

`sympy.utilities.benchmarking`

→`sympy.testing.benchmarking`

`sympy.utilities.pytest`

→`sympy.testing.pytest`

`sympy.utilities.randtests`

→`sympy.core.random`

`sympy.utilities.runtests`

→`sympy.testing.runtests`

`sympy.utilities.tmpfiles`

→`sympy.testing.tmpfiles`

`sympy.testing.randtest`

#

`sympy.testing.randtest`

is deprecated. The functions in it have been moved to
`sympy.core.random`

. The following functions have been moved.

`sympy.testing.randtest.random_complex_number`

→`sympy.core.random.random_complex_number`

`sympy.testing.randtest.verify_numerically`

`sympy.core.random.verify_numerically`

`sympy.testing.randtest.test_derivative_numerically`

→`sympy.core.random.test_derivative_numerically`

`sympy.testing.randtest._randrange`

→`sympy.core.random._randrange`

`sympy.testing.randtest._randint`

→`sympy.core.random._randint`

### Mixing `Poly`

and non-polynomial expressions in binary operations#

In previous versions of SymPy, `Poly`

was a subclass of
`Expr`

, but it has been changed to only be a subclass of
`Basic`

. This means that some things that used to work with `Poly`

are now deprecated because they are only designed to work with `Expr`

objects.

This includes combining `Poly`

with `Expr`

objects using binary operations,
for example

```
Poly(x)*sin(x) # DEPRECATED
```

To do this, either explicitly convert the non-`Poly`

operand to a `Poly`

using
`Expr.as_poly()`

or convert the `Poly`

operand to an `Expr`

using `Poly.as_expr()`

, depending on which type you want the result to
be.

### The `print_cyclic`

flag of `sympy.combinatorics.Permutation`

#

The `print_cyclic`

attribute of
`sympy.combintorics.Permutation`

controls whether permutations print as cycles or arrays. This would be done by
setting `Permutation.print_cyclic = True`

or `Permutation.print_cyclic = False`

. However, this method of controlling printing is bad because it is a
global flag, but printing should not depend on global behavior.

Instead, users should use the `perm_cyclic`

flag of the corresponding printer.
The easiest way to configure this is to set the flag when calling
`init_printing()`

, like

```
>>> from sympy import init_printing
>>> init_printing(perm_cyclic=False) # Makes Permutation print in array form
>>> from sympy.combinatorics import Permutation
>>> Permutation(1, 2)(3, 4)
⎛0 1 2 3 4⎞
⎝0 2 1 4 3⎠
```

The `Permutation`

docstring contains more details on the
`perm_cyclic`

flag.

### Using `integrate`

with `Poly`

#

In previous versions of SymPy, `Poly`

was a subclass of
`Expr`

, but it has been changed to only be a subclass of
`Basic`

. This means that some things that used to work with `Poly`

are now deprecated because they are only designed to work with `Expr`

objects.

This includes calling `integrate()`

or `Integral`

with `Poly`

.

To integrate a `Poly`

, use the `Poly.integrate()`

method. To compute the
integral as an `Expr`

object, call the `Poly.as_expr()`

method
first.

See also Mixing Poly and non-polynomial expressions in binary operations above.

### The string fallback in `sympify()`

#

The current behavior of `sympify()`

is that `sympify(expr)`

tries
various methods to try to convert `expr`

into a SymPy objects. If all these
methods fail, it takes `str(expr)`

and tries to parse it using
`parse_expr()`

. This string fallback feature is deprecated. It is
problematic for a few reasons:

It can affect performance in major ways. See for instance issues #18056 and #15416 where it caused up to 100x slowdowns. The issue is that SymPy functions automatically call

`sympify`

on their arguments. Whenever a function is passed something that`sympify`

doesn’t know how to convert to a SymPy object, for instance, a Python function type, it passes the string to`parse_expr()`

. This is significantly slower than the direct conversions that happen by default. This occurs specifically whenever`sympify()`

is used in library code instead of`_sympify()`

(or equivalently`sympify(strict=True)`

), but presently this is done a lot. Using`strict=True`

will at some point be the default for all library code, but this is a harder change to make.It can cause security issues, since strings are evaled, and objects can return whatever string they want in their

`__repr__`

. See also https://github.com/sympy/sympy/pull/12524.It really isn’t very useful to begin with. Just because an object’s string form can be parsed into a SymPy expression doesn’t mean it should be parsed that way. This is usually correct for custom numeric types, but an object’s repr could be anything. For instance, if the string form of an object looks like a valid Python identifier, it will parse as a

`Symbol`

.

There are plenty of ways to make custom objects work inside of
`sympify()`

.

Firstly, if an object is intended to work alongside other SymPy expressions, it should subclass from

`Basic`

(or`Expr`

). If it does,`sympify()`

will just return it unchanged because it will already be a valid SymPy object.For objects that you control, you can add the

`_sympy_`

method. The sympify docstring has an example of this.For objects that you don’t control, you can add a custom converter to the

`sympy.core.sympify.converter`

dictionary. The`sympify()`

docstring also has an example of this.

To silence this deprecation warning in all cases, you can pass `strict=True`

to `sympify()`

. However, note that this will also disable some other
conversions such as conversion of strings (for converting strings to SymPy
types, you can explicitly use `parse_expr()`

).

### Creating an indefinite `Integral`

with an `Eq`

argument#

Passing an `Eq()`

object to
`integrate()`

is deprecated in the case where the integral is
indefinite. This is because if \(f(x) = g(x)\), then \(\int f(x)\,dx = \int
g(x)\,dx\) is not true in general, due to the arbitrary constants (which
`integrate`

does not include).

If you want to make an equality of indefinite integrals, use
`Eq(integrate(f(x), x), integrate(g(x), x))`

explicitly.

If you already have an equality object `eq`

, you can use `Eq(integrate(eq.lhs, x), integrate(eq.rhs, x))`

.

## Version 1.5#

`Tensor.fun_eval`

and `Tensor.__call__`

#

`TensExpr.fun_eval`

and `Tensor.__call__`

(i.e., calling a tensor to evaluate
it) are deprecated. The `Tensor.substitute_indices()`

method should be used.
This was changed because `fun_eval`

was considered a confusing name and using
function evaluation was considered both confusing and dangerous.

`TensorType`

#

The `TensorType`

class is deprecated. Use `tensor_heads()`

instead. The
`TensorType`

class had no purpose except shorter creation of
`TensorHead`

objects.

See also The tensorhead() function below.

### The `dummy_fmt`

argument to `TensorIndexType`

#

The `dummy_fmt`

keyword argument to `TensorIndexType`

is deprecated.
Setting `dummy_fmt='L'`

leads to `_dummy_fmt='L_%d'`

, which is confusing and
uses obsolete string formatting. `dummy_name`

should be used instead. This
change was made because `dummy_name`

is a clearer name.

### The `metric`

argument to `TensorIndexType`

#

The `metric`

keyword argument to `TensorIndexType`

is deprecated.
The name “metric” was ambiguous because it meant “metric symmetry” in some
places and “metric tensor” in others.

Either the `metric_symmetry`

keyword or the `TensorIndexType.set_metric()`

method should be used instead.

### The `get_kronecker_delta()`

and `get_epsilon()`

methods of `TensorIndexType`

#

The `get_kronecker_delta()`

and `get_epsilon()`

methods of
`TensorIndexType`

are deprecated. Use the `TensorIndexType.delta`

and
`TensorIndexType.epsilon`

properties instead, respectively.

### The `tensorsymmetry()`

function#

The `tensorsymmetry()`

function in `sympy.tensor`

is deprecated. Use the
`TensorSymmetry`

class constructor instead.

`TensorSymmetry`

is preferred over `tensorsymmetry()`

because the latter

Does not have any extra functionality

Involves obscure Young tableau

Is not a member of the

`TensorSymmetry`

class

### The `tensorhead()`

function#

The `tensorhead()`

function is deprecated in favor of `tensor_heads()`

.
`tensor_heads()`

is more consistent with other SymPy names (i.e., `Symbol`

and
`symbols()`

or `TensorIndex`

and `tensor_indices()`

). It also does not use
Young tableau to denote symmetries.

### Methods to `sympy.physics.units.Quantity`

#

The following methods of
`sympy.physics.units.quantities.Quantity`

are deprecated.

`Quantity.set_dimension()`

. This should be replaced with`unit_system.set_quantity_dimension`

or`Quantity.set_global_dimension()`

.`Quantity.set_scale_factor()`

. This should be replaced with`unit_system.set_quantity_scale_factor`

or`Quantity.set_global_relative_scale_factor()`

`Quantity.get_dimensional_expr()`

. This is now associated with`UnitSystem`

objects. The dimensional relations depend on the unit system used. Use`unit_system.get_dimensional_expr()`

instead.`Quantity._collect_factor_and_dimension`

. This has been moved to the`UnitSystem`

class. Use`unit_system._collect_factor_and_dimension(expr)`

instead.

See The dimension and scale_factor arguments to sympy.physics.units.Quanitity below for the motivation for this change.

### The `is_EmptySet`

attribute of sets#

The `is_EmptySet`

attribute of Set objects is deprecated.
Instead either use

```
from sympy import S
s is S.EmptySet
```

or

```
s.is_empty
```

The difference is that `s.is_empty`

may return `None`

if it is unknown if the
set is empty.

`ProductSet(iterable)`

#

Passing a single iterable as the first argument to `ProductSet`

is
deprecated. Creating a product set from an iterable should be done using
`ProductSet(*iterable)`

, or as each individual argument. For example

```
>>> from sympy import ProductSet
>>> sets = [{i} for i in range(3)]
>>> ProductSet(*sets)
ProductSet({0}, {1}, {2})
>>> ProductSet({1, 2}, {1})
ProductSet({1, 2}, {1})
```

This is done because sets themselves can be iterables, and sets of sets are
allowed. But the product set of a single set should mathematically be that set
itself (or more exactly, the set of 1-tuples of elements of that set).
Automatically denesting a single iterable makes it impossible to represent
this object and makes `ProductSet`

not generalize correctly when passed 1
argument. On the other hand, treating the first argument differently if it is
a set than if it is another type of iterable (which is what is currently done
in the deprecated code path) is confusing behavior.

### The `set_potential_energy`

method in `sympy.physics.mechanics`

#

The `set_potential_energy()`

methods of `sympy.physics.mechanics.particle.Particle`

and `sympy.physics.mechanics.rigidbody.RigidBody`

are deprecated.

Instead one should set the `Particle.potential_energy`

and
`RigidBody.potential_energy`

attributes to set the potential energy,
like

```
P.potential_energy = scalar
```

This change was made to be more Pythonic, by using setters and getters of a
`@property`

method rather than an explicit `set_`

method.

### Using a set for the condition in `ConditionSet`

#

Using a set for the condition in ConditionSet is deprecated. A boolean should be used instead. This is because the condition is mathematically a boolean, and it is ambiguous what a set should mean in this context.

To fix this deprecation, replace

```
ConditionSet(symbol, set_condition)
```

with

```
ConditionSet(symbol, And(*[Eq(lhs, 0) for lhs in set_condition]))
```

For example,

```
ConditionSet((x, y), {x + 1, x + y}, S.Reals) # DEPRECATED
```

would become

```
ConditionSet((x, y), Eq(x + 1, 0) & Eq(x + y, 0), S.Reals)
```

### The `max_degree`

and `get_upper_degree`

properties of `sympy.polys.multivariate_resultants.DixonResultant`

#

The `max_degree`

property and `get_upper_degree()`

methods of `DixonResultant`

are deprecated. See issue #17749
for details.

`Eq(expr)`

with the rhs defaulting to 0#

Calling `Eq`

with a single argument is
deprecated. This caused the right-hand side to default to `0`

, but this
behavior was confusing. You should explicitly use `Eq(expr, 0)`

instead.

### Non-tuple iterable for the first argument to `Lambda`

#

Using a non-tuple as the first argument to `Lambda`

is deprecated. If
you have a non-tuple, convert it to a tuple first, like `Lambda(tuple(args), expr)`

.

This was done so that `Lambda`

could support general tuple unpacking, like

```
>>> from sympy import Lambda, symbols
>>> x, y, z = symbols('x y z')
>>> f = Lambda((x, (y, z)), x + y + z)
>>> f(1, (2, 3))
6
```

### The `evaluate`

flag to `differentiate_finite`

#

The `evaluate`

flag to `differentiate_finite()`

is deprecated.

`differentiate_finite(expr, x, evaluate=True)`

expands the intermediate
derivatives before computing differences. But this usually not what you want,
as it does not satisfy the product rule.

If you really do want this behavior, you can emulate it with

```
diff(expr, x).replace(
lambda arg: arg.is_Derivative,
lambda arg: arg.as_finite_difference())
```

See the discussion on issue #17881.

## Version 1.4#

### The `clear_cache`

and `clear_subproducts`

keywords to `Matrix.is_diagonalizable`

#

The `clear_cache`

and `clear_subproducts`

keywords to
`Matrix.is_diagonalizable()`

are deprecated. These used to clear cached entries, but this cache was removed
because it was not actually safe given that `Matrix`

is mutable. The keywords
now do nothing.

### The `rows`

and `cols`

keyword arguments to `Matrix.jordan_block`

#

The `rows`

and `cols`

keywords to
`Matrix.jordan_block`

are
deprecated. The `size`

parameter should be used to specify the (square) number
of rows and columns.

The non-square matrices created by setting `rows`

and `cols`

are not
mathematically Jordan block matrices, which only make sense as square
matrices.

To emulate the deprecated `jordan_block(rows=n, cols=m)`

behavior, use a
general banded matrix constructor, like

```
>>> from sympy import Matrix, symbols
>>> eigenvalue = symbols('x')
>>> def entry(i, j):
... if i == j:
... return eigenvalue
... elif i + 1 == j: # use j + 1 == i for band='lower'
... return 1
... return 0
>>> # the same as the deprecated Matrix.jordan_block(rows=3, cols=5, eigenvalue=x)
>>> Matrix(3, 5, entry)
Matrix([
[x, 1, 0, 0, 0],
[0, x, 1, 0, 0],
[0, 0, x, 1, 0]])
```

## Version 1.3#

### The `source()`

function#

The `source()`

function is deprecated. Use
`inspect.getsource(obj)`

instead, or if you are in IPython or Jupyter, use `obj??`

.

### The `dimension`

and `scale_factor`

arguments to `sympy.physics.units.Quanitity`

#

The `dimension`

and `scale_factor`

arguments to
`sympy.physics.units.quantities.Quantity`

are deprecated.

The problem with these arguments is that **dimensions** are **not** an
**absolute** association to a quantity. For example:

in natural units length and time are the same dimension (so you can sum meters and seconds).

SI and cgs units have different dimensions for the same quantities.

At this point a problem arises for scale factor as well: while it is always
true that `kilometer / meter == 1000`

, some other quantities may have a
relative scale factor or not depending on which unit system is currently being
used.

Instead, things should be managed on the `DimensionSystem`

class. The
`DimensionSystem.set_quantity_dimension()`

method should be used instead of the
`dimension`

argument, and the
`DimensionSystem.set_quantity_scale_factor()`

method should be used
instead of the `scale_factor`

argument.

See issue #14318 for more details. See also Methods to sympy.physics.units.Quantity above.

### Importing `classof`

and `a2idx`

from `sympy.matrices.matrices`

#

The functions `sympy.matrices.matrices.classof`

and
`sympy.matrices.matrices.a2idx`

were duplicates of the same functions in
`sympy.matrices.common`

. The two functions should be used from the
`sympy.matrices.common`

module instead.

## Version 1.2#

### Dot product of non-row/column vectors#

The `Matrix.dot()`

method has
confusing behavior where `A.dot(B)`

returns a list corresponding to
`flatten(A.T*B.T)`

when `A`

and `B`

are matrices that are not vectors (i.e.,
neither dimension is size 1). This is confusing. The purpose of `Matrix.dot()`

is to perform a mathematical dot product, which should only be defined for
vectors (i.e., either a \(n\times 1\) or \(1\times n\) matrix), but in a way that
works regardless of whether each argument is a row or column vector.
Furthermore, returning a list here was much less useful than a matrix would
be, and resulted in a polymorphic return type depending on the shapes of the
inputs.

This behavior is deprecated. `Matrix.dot`

should only be used to do a
mathematical dot product, which operates on row or column vectors. Use the
`*`

or `@`

operators to do matrix multiplication.

```
>>> from sympy import Matrix
>>> A = Matrix([[1, 2], [3, 4]])
>>> B = Matrix([[2, 3], [1, 2]])
>>> A*B
Matrix([
[ 4, 7],
[10, 17]])
>>> A@B
Matrix([
[ 4, 7],
[10, 17]])
```

`sympy.geometry.Line3D.equation`

no longer needs the `k`

argument#

The `k`

argument to `sympy.geometry.line.Line3D.equation()`

method is
deprecated.

Previously, the function `Line3D.equation`

returned `(X, Y, Z, k)`

which was
changed to `(Y-X, Z-X)`

(here `X`

, `Y`

and `Z`

are expressions of `x`

, `y`

and
`z`

respectively). As in 2D an equation is returned relating `x`

and `y`

just
like that in 3D two equations will be returned relating `x`

, `y`

and `z`

.

So in the new `Line3D.equation`

the `k`

argument is not needed anymore. Now
the `k`

argument is effectively ignored. A `k`

variable is temporarily formed
inside `equation()`

and then gets substituted using `subs()`

in terms of `x`

and then `(Y-X, Z-X)`

is returned.

Previously:

```
>>> from sympy import Point3D,Line3D
>>> p1,p2 = Point3D(1, 2, 3), Point3D(5, 6, 7)
>>> l = Line3D(p1, p2)
>>> l.equation()
(x/4 - 1/4, y/4 - 1/2, z/4 - 3/4, k)
```

Now:

```
>>> from sympy import Point3D, Line3D, solve
>>> p1,p2 = Point3D(1, 2, 3), Point3D(5, 6, 7)
>>> l = Line3D(p1,p2)
>>> l.equation()
(-x + y - 1, -x + z - 2)
```

### Modules `sympy.tensor.array.expressions.conv_*`

renamed to `sympy.tensor.array.expressions.from_*`

#

In order to avoid possible naming and tab-completion conflicts with
functions with similar names to the names of the modules, all modules whose
name starts with `conv_*`

in `sympy.tensor.array.expressions`

have been renamed
to `from_*`

.