Repository: sympy/sympy (python)

Issue:
'(1/20)**(1/30)' and '(1/1)**(1/1)' produce unexpected results

```py
from sympy import S, latex
from IPython.display import display, Math
def show(x, n) -> str:
    return display(Math(latex(S(f"({x})**({n})", evaluate=False))))
```
---
#### Unexpected Format
```py
show('1/10','1/20')
show('1/1','1/1')
```

![Image](https://github.com/user-attachments/assets/4b226d82-df1a-461f-b48b-95c6db03cded)
---

#### Expected Format
```py
show('10/1','20/1')
show('2','3/2')
show('-2','3/2')
```

![Image](https://github.com/user-attachments/assets/5eb42fad-dc5d-47c9-af77-3fd121f14de1)

---


Patch:
diff --git a/sympy/parsing/sympy_parser.py b/sympy/parsing/sympy_parser.py
index 1715bcf31f21..f35087ed1120 100644
--- a/sympy/parsing/sympy_parser.py
+++ b/sympy/parsing/sympy_parser.py
@@ -1163,7 +1163,9 @@ def flatten(self, args, func):
                 arg_func = arg.func
                 if isinstance(arg_func, ast.Call):
                     arg_func = arg_func.func
-                if arg_func.id == func:
+                # Safety check: Ensure arg_func is a Name before accessing `.id`.
+                # Lambda nodes (used in ast.Div) would raise an error if not checked.
+                if isinstance(arg_func, ast.Name) and arg_func.id == func:
                     result.extend(self.flatten(arg.args, func))
                 else:
                     result.append(arg)
@@ -1200,8 +1202,44 @@ def visit_BinOp(self, node):
                     keywords=[ast.keyword(arg='evaluate', value=ast.Constant(value=False))]
                 )
 
-            if rev:  # undo reversal
-                left, right = right, left
+                if rev:  # undo reversal
+                    left, right = right, left
+
+                # This is for checking if numerator is 1, if it is, return just Pow(denom, -1)
+                # For any division operator like x/y, the expression returned is Mul(x, Pow(y,-1))
+                # But if x = 1, returning Mul(1, Pow(y,-1)) is redundant so we strip the extra 1 before Mul node is created
+                #
+                # For ast.Div operators we create a temporary lambda node which eliminates extra 1
+                # a lambda function is passed as an argument (string) to ast.parse, ast.parse creates a module
+                # This module has an expr which can be captured by body[0] (O because there is only one expr)
+                # This expr's value contains the lambda node which is called by .value
+                #
+                # The lambda function works like this:
+                # - if n == 1: it just checks if numerator is 1, (e.g. from "-(-1)"), we strictly return denominator
+                # This ensures that the redundant "1" is stripped.
+                # example: "-(-1)/x" == Pow(x, -1)
+                #
+                # - Flattening (if isinstance(n, Mul)): We are using a lambda function, the AST flatten()
+                # cannot see inside to flatten chained operations. We have to integrate this with lambda function
+                # example: "x/y/z": lambda sees n = 'x/y' (Mul Operator). We unpack it using (*n.args) to ensure
+                # the result we get is Mul(x, Pow(y, -1), Pow(z, -1)), avoiding nested structures
+                # like Mul(Mul(x, Pow(y,-1)), Pow(z, -1))
+                #
+                # - For standard cases (else) : For cases just like "x/y", node has a normal structure.
+                # example: "x/y": Mul(x, Pow(y, -1))
+                temp_node = ast.parse("lambda n, d: d if n == 1 else (Mul(*n.args, d, evaluate=False) \
+                                      if isinstance(n, Mul) else Mul(n, d, evaluate=False))").body[0].value
+
+                # For division we return the node immediately.
+                # func=temp.node: The lambda AST Node created acts as a function.
+                # args=[left, right]: We pass numerator(left) and denominator(right) as arguments (which are n and d)
+                # keywords=[]: If ommited, keywords would have the default value of None, it will just return an AttributeError.
+                return ast.Call(
+                    func=temp_node,
+                    args=[left, right],
+                    keywords=[]
+                )
+
             new_node = ast.Call(
                 func=ast.Name(id=sympy_class, ctx=ast.Load()),
                 args=[left, right],


Test patch:
diff --git a/sympy/core/tests/test_sympify.py b/sympy/core/tests/test_sympify.py
index 137bc26a3e6f..15860581671a 100644
--- a/sympy/core/tests/test_sympify.py
+++ b/sympy/core/tests/test_sympify.py
@@ -436,7 +436,7 @@ def test_evaluate_false():
         '2**2 / 3': Mul(Pow(2, 2, evaluate=False), Pow(3, -1, evaluate=False), evaluate=False),
         '2 + 3 * 5': Add(2, Mul(3, 5, evaluate=False), evaluate=False),
         '2 - 3 * 5': Add(2, Mul(-1, Mul(3, 5,evaluate=False), evaluate=False), evaluate=False),
-        '1 / 3': Mul(1, Pow(3, -1, evaluate=False), evaluate=False),
+        '1 / 3': Pow(3, -1, evaluate=False),
         'True | False': Or(True, False, evaluate=False),
         '1 + 2 + 3 + 5*3 + integrate(x)': Add(1, 2, 3, Mul(5, 3, evaluate=False), x**2/2, evaluate=False),
         '2 * 4 * 6 + 8': Add(Mul(2, 4, 6, evaluate=False), 8, evaluate=False),
diff --git a/sympy/parsing/tests/test_sympy_parser.py b/sympy/parsing/tests/test_sympy_parser.py
index 5c7559c1f485..02b0611a3e7e 100644
--- a/sympy/parsing/tests/test_sympy_parser.py
+++ b/sympy/parsing/tests/test_sympy_parser.py
@@ -7,7 +7,7 @@
 from sympy.assumptions import Q
 from sympy.core import Symbol, Function, Float, Rational, Integer, I, Mul, Pow, Eq, Lt, Le, Gt, Ge, Ne
 from sympy.core.singleton import S
-from sympy.functions import exp, factorial, factorial2, sin, Min, Max
+from sympy.functions import exp, factorial, factorial2, sin, cos, Min, Max
 from sympy.logic import And, Xor
 from sympy.series import Limit
 from sympy.testing.pytest import raises
@@ -384,3 +384,18 @@ def test_issue_22822():
 def test_xor_eval_false():
     p, q = Symbol("p"), Symbol("q")
     assert parse_expr("p ^ q", evaluate=False) == Xor(p, q, evaluate=False)
+
+
+def test_issue_27832():
+    x = Symbol('x')
+    assert parse_expr('1/1', evaluate=False) == Pow(Integer(1), Integer(-1), evaluate=False)
+    assert parse_expr('1/10 * 4', evaluate=False) == Mul(Pow(Integer(10), Integer(-1), evaluate=False), \
+                                                         Integer(4), evaluate=False)
+    assert parse_expr('1/x', evaluate=False) == Pow(x, Integer(-1), evaluate=False)
+    assert parse_expr('+1/20', evaluate=False) == Pow(Integer(20), Integer(-1), evaluate=False)
+    assert parse_expr('~(~1)/20', evaluate=False) == Pow(Integer(20), Integer(-1), evaluate=False)
+    assert parse_expr('-(-1)/10', evaluate=False) == Pow(Integer(10), Integer(-1), evaluate=False)
+    assert parse_expr('-(~0)/10', evaluate=False) == Pow(Integer(10), Integer(-1), evaluate=False)
+    assert parse_expr('+cos(0)/10', evaluate=False) == Mul(cos(Integer(0), evaluate=False), \
+                                                               Pow(Integer(10), Integer(-1), evaluate=False), \
+                                                               evaluate=False)
diff --git a/sympy/polys/tests/test_polytools.py b/sympy/polys/tests/test_polytools.py
index 950a982b9d98..46f1fc327692 100644
--- a/sympy/polys/tests/test_polytools.py
+++ b/sympy/polys/tests/test_polytools.py
@@ -3574,7 +3574,7 @@ def test_cancel():
         evaluate=False)
     assert cancel(q, _signsimp=False) is S.NaN
     assert q.subs(x, 2) is S.NaN
-    assert signsimp(q) is S.NaN
+    assert signsimp(q) is not S.NaN
 
     # issue 9363
     M = MatrixSymbol('M', 5, 5)