Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

I think it is a bug, so thank you for pointing it out.

Generally when seeking help or clarification on an error, it is best to post the full traceback. Even if it looks like meaningless gibberish to you, it does not look meaningless to the developers. In this case I get:

sage: 'hello' in CC
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-2-2a4614162c6a> in <module>()
----> 1 'hello' in CC

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/structure/parent.pyx in sage.structure.parent.Parent.__conta_ (build/cythonized/sage/structure/parent.c:9863)()
   1090             return True
   1091         try:
-> 1092             x2 = self(x)
   1093             EQ = (x2 == x)
   1094             if EQ is True:

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/rings/complex_field.pyc in __call__(self, x, im)
    385         if im is not None:
    386             x = x, im
--> 387         return Parent.__call__(self, x)
    388
    389     def _element_constructor_(self, x):

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/structure/parent.pyx in sage.structure.parent.Parent.__call_uild/cythonized/sage/structure/parent.c:9197)()
    898         if mor is not None:
    899             if no_extra_args:
--> 900                 return mor._call_(x)
    901             else:
    902                 return mor._call_with_args(x, args, kwds)

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/structure/coerce_maps.pyx in sage.structure.coerce_maps.DefaonvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4556)()
    160                 print(type(C), C)
    161                 print(type(C._element_constructor), C._element_constructor)
--> 162             raise
    163
    164     cpdef Element _call_with_args(self, x, args=(), kwds={}):

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/structure/coerce_maps.pyx in sage.structure.coerce_maps.DefaonvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4448)()
    155         cdef Parent C = self._codomain
    156         try:
--> 157             return C._element_constructor(x)
    158         except Exception:
    159             if print_warnings:

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/rings/complex_field.pyc in _element_constructor_(self, x)
    411                 # efficient way to do this.  -- Martin Albrecht
    412                 return ComplexNumber(self,
--> 413                             sage_eval(x.replace(' ',''), locals={"I":self.gen(),"i":self.gen()}))
    414
    415             late_import()

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/misc/sage_eval.pyc in sage_eval(source, locals, cmds, prepar
    201         return locals['_sage_eval_returnval_']
    202     else:
--> 203         return eval(source, sage.all.__dict__, locals)
    204
    205

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/all.pyc in <module>()

NameError: name 'hello' is not defined

Sage definitely shouldn't be throwing seemingly bizarre NameErrors in such cases.

Looking two frames up we see a fragment of a strange comment ending with "efficient way to do this." so let's start there in sage/rings/complex_field.py, line 413 or thereabout:

389     def _element_constructor_(self, x):
390         """
391         Construct a complex number.
392
393         EXAMPLES::
394
395             sage: CC((1,2)) # indirect doctest
396             1.00000000000000 + 2.00000000000000*I
397
398         Check that :trac:`14989` is fixed::
399
400             sage: QQi = NumberField(x^2+1, 'i', embedding=CC(0,1))
401             sage: i = QQi.order(QQi.gen()).gen(1)
402             sage: CC(i)
403             1.00000000000000*I
404
405         """
406         if not isinstance(x, (RealNumber, tuple)):
407             if isinstance(x, ComplexDoubleElement):
408                 return ComplexNumber(self, x.real(), x.imag())
409             elif isinstance(x, str):
410                 # TODO: this is probably not the best and most
411                 # efficient way to do this.  -- Martin Albrecht
412                 return ComplexNumber(self,
413                             sage_eval(x.replace(' ',''), locals={"I":self.gen(),"i":self.gen()}))

Okay, so the full comment was not all that helpful. But I can still kind of see what's happening here. When you do something like x in F where F is some field, and x is some element that may or may not belong to that field, one of the first things it will do is try to convert x to an element of F if possible.

This process passes through CC._element_constructor_, where it seems if x is not already a RealNumber, a (real, imag) tuple, or a ComplexDoubleElement, it will check if x was a string. Then there is some code which, as far as I can tell, is trying to see if the string is a valid string representation of a complex number (using either i or I as the complex unit). It is doing this by calling eval on the given string. It's expecting that you're going to try to do something like '1+2*i' in CC (which, incidentally, returns False for some reason, so it doesn't even work as expected). But this is double bad because it could fail in all sorts of ways beyond just giving a NameError. For example:

sage: '@@@@@@@@@@@@@@@@' in CC
  File "<string>", line 1
    @@@@@@@@@@@@@@@@
    ^
SyntaxError: invalid syntax

Or

sage: # DON'T TRY THIS AT HOME
sage: # NO, REALLY
sage: # 'import shutil; shutil.rmtree(sage.__path__[0])' in CC

So yes, I think this is a bug. sage_eval has no business being used in this context, and I suspect this code isn't even tested.