Repository: sympy/sympy (Python)

Issue:
`diff` raises `SympifyError` since sympy version 1.10
Consider the following script:

~~~ python
import sympy

expr_str = "a*x+b"
expr = sympy.sympify(expr_str)
diff = expr.diff("x")

print(diff)
~~~

With sympy 1.9 the script prints `a` as expected. But sympy 1.10 now raises the following error:

~~~
Traceback (most recent call last):
  File ".../sympy_bug.py", line 5, in <module>
    expr.diff("x")
  File "...\lib\site-packages\sympy\core\expr.py", line 3528, in diff
    return _derivative_dispatch(self, *symbols, **assumptions)
  File "...\lib\site-packages\sympy\core\function.py", line 1923, in _derivative_dispatch
    return Derivative(expr, *variables, **kwargs)
  File "...\lib\site-packages\sympy\core\function.py", line 1307, in __new__
    v = _sympify(v)
  File "...\lib\site-packages\sympy\core\sympify.py", line 528, in _sympify
    return sympify(a, strict=True)
  File "...\lib\site-packages\sympy\core\sympify.py", line 449, in sympify
    raise SympifyError(a)
sympy.core.sympify.SympifyError: SympifyError: 'x'
~~~

Is this a bug or are we supposed to use `diff` differently now? I had a quick look at the changelog but I either overlooked it or it wasn't mentioned.


Discussion:
I believe the notion is that you should not use strings as arguments to instantiate sympy expressions except with `sympify`. So either create the `x` or sympify it as an argument.

Any of these ways will create a variable that you used in the expression and allow you to pass it as the correct argument:
```
from sympy.abc import x
x = Symbol('x')
x = symbols('x')
x = [i for i in expr.free_symbols if i.name == 'x']
x = sympify('x')
expr.diff(x)
```
or you can choose not to create an `x` in the namespace and just do

```
expr.diff(sympify('x'))
```
I've bisected this to affdc2f21afc2f5456e75837d31efb07f83cb6d3 from #23162

CC @ThePauliPrinciple 

In general I would prefer it that strings cannot be used directly in this kind of situation but I don't think this was an intentional change.
It was intentional in the sense that I used `_sympify` instead of `sympify`. 

Should we revert this (and then I guess also revert all other commits along these lines)?
The question is whether this should be considered something that only worked accidentally in the first place. For example in 1.9 this doesn't work:
```python
In [1]: x.integrate('x')
---------------------------------------------------------------------------
ValueError
```
Looking through methods on Expr there are a few that work with strings:
```python
In [15]: x.subs('x', 1)
Out[15]: 1

In [16]: x.limit('x', 0)
Out[16]: 0

In [17]: x.collect('x')
Out[17]: x
```
Then there are some that don't:
```python
In [18]: (1/x/(1-x)).apart('x')
---------------------------------------------------------------------------
AttributeError

In [24]: x.has('x')
---------------------------------------------------------------------------
SympifyError
```
Some are inconsistent:
```python
In [31]: x.matches('x')

In [32]: x.matches(x)
Out[32]: {}

In [35]: x.xreplace({'x':2})
Out[35]: x

In [36]: x.xreplace({x:2})
Out[36]: 2
```
Broadly I think that implicit string parsing is not good. There are multiple clear ways to do the parsing explicitly:
```python
x.integrate(S('x'))
x.integrate(sympify('x'))
x.integrate(parse_expr('x'))
```
I guess this is something that would have needed to be at least deprecated if it was going to be changed though. Preserving backwards compatibility here would mean reverting from `_sympify` to `sympify` for now. Maybe there should be a `_sympify_deprecated` function that we could use in situations where we would like to avoid parsing but we are not sure if it's currently being used by anyone.

> all other commits along these lines

Roughly speaking what do you mean by the "other commits"?
> Roughly speaking what do you mean by the "other commits"?

Other commits that replaced `sympify` with `_sympify`. I believe I had done a couple because we would otherwise end up with "non-Basic args" from the uses inside the library.
I've just skimmed through your merged PRs and I found #22643 but that seems fine to me. I think we just need to be careful about widely used things like `diff`.

Can you think of any other cases?
https://github.com/sympy/sympy/pull/22551
> #22551

Is it just the changes in `stochastic_process_types.py` and `array_comprehension.py`? If so I think those are fine. That's relatively new code and not widely used.



Patch:
diff --git a/sympy/core/function.py b/sympy/core/function.py
index b5392026a08c..d08b678faf68 100644
--- a/sympy/core/function.py
+++ b/sympy/core/function.py
@@ -47,7 +47,7 @@
 from .parameters import global_parameters
 from .rules import Transform
 from .singleton import S
-from .sympify import sympify, _sympify
+from .sympify import sympify
 
 from .sorting import default_sort_key, ordered
 from sympy.utilities.exceptions import (sympy_deprecation_warning,
@@ -1304,7 +1304,7 @@ def __new__(cls, expr, *variables, **kwargs):
                 variable_count.append(Tuple(v, count))
                 continue
 
-            v = _sympify(v)
+            v = sympify(v)
             if isinstance(v, Integer):
                 if i == 0:
                     raise ValueError("First variable cannot be a number: %i" % v)


Test patch:
diff --git a/sympy/core/tests/test_function.py b/sympy/core/tests/test_function.py
index 1c22e22b603d..cde6fc6b3ded 100644
--- a/sympy/core/tests/test_function.py
+++ b/sympy/core/tests/test_function.py
@@ -131,6 +131,8 @@ def test_diff_symbols():
     raises(TypeError, lambda: cos(x).diff((x, y)).variables)
     assert cos(x).diff((x, y))._wrt_variables == [x]
 
+    # issue 23222
+    assert sympify("a*x+b").diff("x") == sympify("a")
 
 def test_Function():
     class myfunc(Function):