Repository: sympy/sympy

Issue:
sympy generates exception on integrate(log(abs(x)),x)
copied from 

https://stackoverflow.com/questions/45181469/sympy-generates-exception-on-integratelogabsx-x

If sympy can't do an integral, should it not return the input unevaluated? Why does it generate an exception here?

integrate(log(abs(x)),x) gives exception. But integrate(log(x),x) does not. Why?

```
>python
Python 3.6.1 |Anaconda custom (64-bit)| (default, May 11 2017, 13:09:58) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from sympy import *
>>> x=symbols('x')
>>> integrate(log(x),x)
x*log(x) - x
>>> integrate(log(abs(x)),x)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/me/anaconda3/lib/python3.6/site-packages/sympy/integrals/integrals.py", line 1295, in integrate
    risch=risch, manual=manual)
  File "/home/me/anaconda3/lib/python3.6/site-packages/sympy/integrals/integrals.py", line 486, in doit
    conds=conds)
  File "/home/me/anaconda3/lib/python3.6/site-packages/sympy/integrals/integrals.py", line 926, in _eval_integral
    for arg in result.args
  File "/home/me/anaconda3/lib/python3.6/site-packages/sympy/integrals/integrals.py", line 926, in <listcomp>
    for arg in result.args
  File "/home/me/anaconda3/lib/python3.6/site-packages/sympy/core/basic.py", line 1554, in doit
    for term in self.args]
  File "/home/me/anaconda3/lib/python3.6/site-packages/sympy/core/basic.py", line 1554, in <listcomp>
    for term in self.args]
  File "/home/me/anaconda3/lib/python3.6/site-packages/sympy/integrals/integrals.py", line 397, in doit
    function = function.doit(**hints)
  File "/home/me/anaconda3/lib/python3.6/site-packages/sympy/core/basic.py", line 1554, in doit
    for term in self.args]
  File "/home/me/anaconda3/lib/python3.6/site-packages/sympy/core/basic.py", line 1554, in <listcomp>
    for term in self.args]
  File "/home/me/anaconda3/lib/python3.6/site-packages/sympy/core/function.py", line 1315, in doit
    return self.func(expr, *self.variables, **hints)
  File "/home/me/anaconda3/lib/python3.6/site-packages/sympy/core/function.py", line 1208, in __new__
    expr = Expr.__new__(cls, expr, *unhandled_variables, **assumptions)
TypeError: __new__() got an unexpected keyword argument 'manual'
```

Posting it here in case this is new issue.



Discussion:

Patch:
diff --git a/sympy/core/function.py b/sympy/core/function.py
index d14e2e2954..952fc0d786 100644
--- a/sympy/core/function.py
+++ b/sympy/core/function.py
@@ -1097,7 +1097,7 @@ def _diff_wrt(self):
         else:
             return False
 
-    def __new__(cls, expr, *variables, **assumptions):
+    def __new__(cls, expr, *variables, **kwargs):
 
         from sympy.matrices.common import MatrixCommon
         from sympy import Integer
@@ -1192,9 +1192,7 @@ def __new__(cls, expr, *variables, **assumptions):
         if len(variable_count) == 0:
             return expr
 
-        # Pop evaluate because it is not really an assumption and we will need
-        # to track it carefully below.
-        evaluate = assumptions.pop('evaluate', False)
+        evaluate = kwargs.get('evaluate', False)
 
         # Look for a quick exit if there are symbols that don't appear in
         # expression at all. Note, this cannot check non-symbols like
@@ -1219,10 +1217,7 @@ def __new__(cls, expr, *variables, **assumptions):
             if evaluate:
                 #TODO: check if assumption of discontinuous derivatives exist
                 variable_count = cls._sort_variable_count(variable_count)
-            # Here we *don't* need to reinject evaluate into assumptions
-            # because we are done with it and it is not an assumption that
-            # Expr knows about.
-            obj = Expr.__new__(cls, expr, *variable_count, **assumptions)
+            obj = Expr.__new__(cls, expr, *variable_count)
             return obj
 
         # Compute the derivative now by repeatedly calling the
@@ -1292,7 +1287,7 @@ def __new__(cls, expr, *variables, **assumptions):
 
         if unhandled_variable_count:
             unhandled_variable_count = cls._sort_variable_count(unhandled_variable_count)
-            expr = Expr.__new__(cls, expr, *unhandled_variable_count, **assumptions)
+            expr = Expr.__new__(cls, expr, *unhandled_variable_count)
         else:
             # We got a Derivative at the end of it all, and we rebuild it by
             # sorting its variables.
@@ -1301,7 +1296,7 @@ def __new__(cls, expr, *variables, **assumptions):
                     expr.args[0], *cls._sort_variable_count(expr.args[1:])
                 )
 
-        if (nderivs > 1) == True and assumptions.get('simplify', True):
+        if (nderivs > 1) == True and kwargs.get('simplify', True):
             from sympy.core.exprtools import factor_terms
             from sympy.simplify.simplify import signsimp
             expr = factor_terms(signsimp(expr))


Test patch:
diff --git a/sympy/core/tests/test_function.py b/sympy/core/tests/test_function.py
index 0b233aa708..aa5dfb12a5 100644
--- a/sympy/core/tests/test_function.py
+++ b/sympy/core/tests/test_function.py
@@ -740,6 +740,12 @@ def g(w, theta):
     expr = functools.reduce(g,ws)
 
 
+def test_issue_12996():
+    # foo=True imitates the sort of arguments that Derivative can get
+    # from Integral when it passes doit to the expression
+    assert Derivative(im(x), x).doit(foo=True) == Derivative(im(x), x)
+
+
 def test_should_evalf():
     # This should not take forever to run (see #8506)
     assert isinstance(sin((1.0 + 1.0*I)**10000 + 1), sin)