Repository: sympy/sympy

Issue:
Mechanics vector.diff() needs a clear error message if you swap the two arguments.
Run:

```python
import sympy as sm
import sympy.physics.mechanics as me
me.init_vprinting(use_latex='mathjax')
q1, q2, u1, u2 = me.dynamicsymbols('q1, q2, u1, u2')
N = me.ReferenceFrame('N')
N_v_A = u1*N.x
N_v_A.diff(N, u1), N_v_A.diff(N, u2)
```

in a Jupyter notebook to get:

```
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
ValueError: Error from parse_expr with transformed code: 'N .x '

The above exception was the direct cause of the following exception:

AttributeError                            Traceback (most recent call last)
Input In [6], in <cell line: 7>()
      5 N = me.ReferenceFrame('N')
      6 N_v_A = u1*N.x
----> 7 N_v_A.diff(N, u1), N_v_A.diff(N, u2)

File ~/miniconda/lib/python3.8/site-packages/sympy/physics/vector/vector.py:536, in Vector.diff(self, var, frame, var_in_dcm)
    494 """Returns the partial derivative of the vector with respect to a
    495 variable in the provided reference frame.
    496 
   (...)
    531 
    532 """
    534 from sympy.physics.vector.frame import _check_frame
--> 536 var = sympify(var)
    537 _check_frame(frame)
    539 inlist = []

File ~/miniconda/lib/python3.8/site-packages/sympy/core/sympify.py:453, in sympify(a, locals, convert_xor, strict, rational, evaluate)
    451 if iterable(a):
    452     try:
--> 453         return type(a)([sympify(x, locals=locals, convert_xor=convert_xor,
    454             rational=rational, evaluate=evaluate) for x in a])
    455     except TypeError:
    456         # Not all iterables are rebuildable with their type.
    457         pass

File ~/miniconda/lib/python3.8/site-packages/sympy/core/sympify.py:453, in <listcomp>(.0)
    451 if iterable(a):
    452     try:
--> 453         return type(a)([sympify(x, locals=locals, convert_xor=convert_xor,
    454             rational=rational, evaluate=evaluate) for x in a])
    455     except TypeError:
    456         # Not all iterables are rebuildable with their type.
    457         pass

File ~/miniconda/lib/python3.8/site-packages/sympy/core/sympify.py:495, in sympify(a, locals, convert_xor, strict, rational, evaluate)
    493 try:
    494     a = a.replace('\n', '')
--> 495     expr = parse_expr(a, local_dict=locals, transformations=transformations, evaluate=evaluate)
    496 except (TokenError, SyntaxError) as exc:
    497     raise SympifyError('could not parse %r' % a, exc)

File ~/miniconda/lib/python3.8/site-packages/sympy/parsing/sympy_parser.py:1105, in parse_expr(s, local_dict, transformations, global_dict, evaluate)
   1103 for i in local_dict.pop(null, ()):
   1104     local_dict[i] = null
-> 1105 raise e from ValueError(f"Error from parse_expr with transformed code: {code!r}")

File ~/miniconda/lib/python3.8/site-packages/sympy/parsing/sympy_parser.py:1096, in parse_expr(s, local_dict, transformations, global_dict, evaluate)
   1093     code = compile(evaluateFalse(code), '<string>', 'eval')
   1095 try:
-> 1096     rv = eval_expr(code, local_dict, global_dict)
   1097     # restore neutral definitions for names
   1098     for i in local_dict.pop(null, ()):

File ~/miniconda/lib/python3.8/site-packages/sympy/parsing/sympy_parser.py:915, in eval_expr(code, local_dict, global_dict)
    909 def eval_expr(code, local_dict, global_dict):
    910     """
    911     Evaluate Python code generated by ``stringify_expr``.
    912 
    913     Generally, ``parse_expr`` should be used.
    914     """
--> 915     expr = eval(
    916         code, global_dict, local_dict)  # take local objects in preference
    917     return expr

File <string>:1, in <module>

AttributeError: 'function' object has no attribute 'x'
```

SymPy 1.10.1

Discussion:

Patch:
diff --git a/sympy/physics/vector/vector.py b/sympy/physics/vector/vector.py
index 172d305851..49c523a9c4 100644
--- a/sympy/physics/vector/vector.py
+++ b/sympy/physics/vector/vector.py
@@ -537,8 +537,8 @@ def diff(self, var, frame, var_in_dcm=True):
 
         from sympy.physics.vector.frame import _check_frame
 
-        var = sympify(var)
         _check_frame(frame)
+        var = sympify(var)
 
         inlist = []
 


Test patch:
diff --git a/sympy/physics/vector/tests/test_vector.py b/sympy/physics/vector/tests/test_vector.py
index 7f5eec69aa..19701ddf25 100644
--- a/sympy/physics/vector/tests/test_vector.py
+++ b/sympy/physics/vector/tests/test_vector.py
@@ -4,6 +4,7 @@
 from sympy.functions.elementary.trigonometric import (cos, sin)
 from sympy.matrices.immutable import ImmutableDenseMatrix as Matrix
 from sympy.physics.vector import ReferenceFrame, Vector, dynamicsymbols, dot
+from sympy.physics.vector.vector import VectorTypeError
 from sympy.abc import x, y, z
 from sympy.testing.pytest import raises
 
@@ -238,3 +239,9 @@ def test_vector_xreplace():
     assert v.xreplace({x:1, z:0}) == A.x + y * A.y
     raises(TypeError, lambda: v.xreplace())
     raises(TypeError, lambda: v.xreplace([x, y]))
+
+def test_issue_23366():
+    u1 = dynamicsymbols('u1')
+    N = ReferenceFrame('N')
+    N_v_A = u1*N.x
+    raises(VectorTypeError, lambda: N_v_A.diff(N, u1))