Repository: LMFDB/lmfdb

Issue:
ComplexDoubleElement element encoding

Some downloads for nonrational L-function are failing as JSON does not know how to encode ComplexDoubleElement:
```
Exception on /L/download_euler/1-5971-5971.2412-r0-0-0/ [GET]
Traceback (most recent call last):
  File "/home/sage/sage-9.2/local/lib/python3.6/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/sage/sage-9.2/local/lib/python3.6/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/sage/sage-9.2/local/lib/python3.6/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/sage/sage-9.2/local/lib/python3.6/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/home/sage/sage-9.2/local/lib/python3.6/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/sage/sage-9.2/local/lib/python3.6/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/lfunctions/main.py", line 1510, in wrapper
    return f(label=label, L=L)
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/lfunctions/main.py", line 1517, in download_euler_factors
    return L.download_euler_factors()
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/lfunctions/Lfunction.py", line 547, in download_euler_factors
    Json.dumps(data),
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/backend/encoding.py", line 138, in dumps
    return json.dumps(cls.prep(obj))
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/backend/encoding.py", line 192, in prep
    return {k: cls.prep(v, escape_backslashes) for k, v in obj.items()}
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/backend/encoding.py", line 192, in <dictcomp>
    return {k: cls.prep(v, escape_backslashes) for k, v in obj.items()}
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/backend/encoding.py", line 181, in prep
    return [cls.prep(x, escape_backslashes) for x in obj]
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/backend/encoding.py", line 181, in <listcomp>
    return [cls.prep(x, escape_backslashes) for x in obj]
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/backend/encoding.py", line 181, in prep
    return [cls.prep(x, escape_backslashes) for x in obj]
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/backend/encoding.py", line 181, in <listcomp>
    return [cls.prep(x, escape_backslashes) for x in obj]
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/backend/encoding.py", line 181, in prep
    return [cls.prep(x, escape_backslashes) for x in obj]
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/backend/encoding.py", line 181, in <listcomp>
    return [cls.prep(x, escape_backslashes) for x in obj]
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/backend/encoding.py", line 297, in prep
    raise ValueError("Unsupported type: %s" % (type(obj)))
ValueError: Unsupported type: <class 'sage.rings.complex_double.ComplexDoubleElement'>
[2021-02-01 20:45:55 UTC] 500 error on URL https://beta.lmfdb.org/L/download_euler/1-5971-5971.2412-r0-0-0/ ()
Exception on /L/download_dirichlet_coeff/1-5971-5971.2412-r0-0-0/ [GET]
Traceback (most recent call last):
  File "/home/sage/sage-9.2/local/lib/python3.6/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/sage/sage-9.2/local/lib/python3.6/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/sage/sage-9.2/local/lib/python3.6/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/sage/sage-9.2/local/lib/python3.6/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/home/sage/sage-9.2/local/lib/python3.6/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/sage/sage-9.2/local/lib/python3.6/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/lfunctions/main.py", line 1510, in wrapper
    return f(label=label, L=L)
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/lfunctions/main.py", line 1529, in download_dirichlet_coeff
    return L.download_dirichlet_coeff()
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/lfunctions/Lfunction.py", line 569, in download_dirichlet_coeff
    data['an'] = an_from_data(self.localfactors, next_prime(nth_prime(len(self.localfactors)+1)) - 1)
  File "/home/lmfdb/lmfdb-git-dev/lmfdb/lfunctions/Lfunction.py", line 80, in an_from_data
    f = (1 / (PP(euler_factors[i]))).padded_list(Integer(upperbound).nbits())
  File "sage/structure/parent.pyx", line 900, in sage.structure.parent.Parent.__call__ (build/cythonized/sage/structure/parent.c:9336)
    return mor._call_(x)
  File "sage/structure/coerce_maps.pyx", line 161, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4623)
    raise
  File "sage/structure/coerce_maps.pyx", line 156, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4515)
    return C._element_constructor(x)
  File "/home/sage/sage-9.2/local/lib/python3.6/site-packages/sage/rings/power_series_ring.py", line 812, in _element_constructor_
    return self.element_class(self, f, prec, check=check)
  File "sage/rings/power_series_poly.pyx", line 67, in sage.rings.power_series_poly.PowerSeries_poly.__init__ (build/cythonized/sage/rings/power_series_poly.c:4182)
    f = R(f, check=check)
  File "sage/structure/parent.pyx", line 902, in sage.structure.parent.Parent.__call__ (build/cythonized/sage/structure/parent.c:9363)
    return mor._call_with_args(x, args, kwds)
  File "sage/structure/coerce_maps.pyx", line 180, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_with_args (build/cythonized/sage/structure/coerce_maps.c:5154)
    raise
  File "sage/structure/coerce_maps.pyx", line 170, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_with_args (build/cythonized/sage/structure/coerce_maps.c:4944)
    return C._element_constructor(x, **kwds)
  File "/home/sage/sage-9.2/local/lib/python3.6/site-packages/sage/rings/polynomial/polynomial_ring.py", line 419, in _element_constructor_
    return C(self, x, check=check, is_gen=False, construct=construct)
  File "sage/rings/polynomial/polynomial_integer_dense_flint.pyx", line 288, in sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint.__init__ (build/cythonized/sage/rings/polynomial/polynomial_integer_dense_flint.cpp:6662)
    a = ZZ(a)
  File "sage/structure/parent.pyx", line 900, in sage.structure.parent.Parent.__call__ (build/cythonized/sage/structure/parent.c:9336)
    return mor._call_(x)
  File "sage/structure/coerce_maps.pyx", line 161, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4623)
    raise
  File "sage/structure/coerce_maps.pyx", line 156, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4515)
    return C._element_constructor(x)
  File "sage/rings/integer.pyx", line 747, in sage.rings.integer.Integer.__init__ (build/cythonized/sage/rings/integer.c:7080)
    raise TypeError("unable to coerce %s to an integer" % type(x))
TypeError: unable to coerce <class 'sage.rings.complex_double.ComplexDoubleElement'> to an integer
[2021-02-01 20:46:54 UTC] 500 error on URL https://beta.lmfdb.org/L/download_dirichlet_coeff/1-5971-5971.2412-r0-0-0/ ()
```


Discussion:

Resolving patch:
diff --git a/lmfdb/backend/encoding.py b/lmfdb/backend/encoding.py
--- a/lmfdb/backend/encoding.py
+++ b/lmfdb/backend/encoding.py
@@ -20,6 +20,7 @@
     except ImportError:
         from sage.rings.complex_number import ComplexNumber
     from sage.rings.complex_field import ComplexField
+    from sage.rings.complex_double import ComplexDoubleElement
     from sage.rings.real_mpfr import RealLiteral, RealField, RealNumber
     from sage.rings.integer import Integer
     from sage.rings.rational import Rational
@@ -221,6 +222,8 @@ def prep(cls, obj, escape_backslashes=False):
                 "prec": int(obj.prec()),
                 "data": [str(obj.real()), str(obj.imag())],
             }
+        elif SAGE_MODE and isinstance(obj, ComplexDoubleElement):
+            return [float(obj.real()), float(obj.imag())]
         elif SAGE_MODE and isinstance(obj, NumberFieldElement):
             return {
                 "__NFElt__": 0,  # encoding version


Test patch: