except ImportError:
from builtins import str as basestring
+
+non_portable_builtins_map = {
+ 'bytes' : ('PY_MAJOR_VERSION < 3', 'str'),
+ 'unicode' : ('PY_MAJOR_VERSION >= 3', 'str'),
+ 'xrange' : ('PY_MAJOR_VERSION >= 3', 'range'),
+ 'BaseException' : ('PY_VERSION_HEX < 0x02050000', 'Exception'),
+ }
+
class UtilityCode(object):
# Stores utility code to add during code generation.
#
return "%s%s%d" % (Naming.const_prefix, prefix, n)
def add_cached_builtin_decl(self, entry):
- if Options.cache_builtins:
+ if entry.is_builtin and entry.is_const:
if self.should_declare(entry.cname, entry):
self.put_pyobject_decl(entry)
w = self.parts['cached_builtins']
- conditional_name = False
- if entry.name == 'xrange':
- # replaced by range() in Py3
- conditional_name = True
- w.putln('#if PY_MAJOR_VERSION >= 3')
- self.put_cached_builtin_init(
- entry.pos, StringEncoding.EncodedString('range'),
- entry.cname)
- elif entry.name == 'BaseException':
- # replace BaseException by Exception in Py<2.5
- conditional_name = True
- w.putln('#if PY_VERSION_HEX < 0x02050000')
+ condition = None
+ if entry.name in non_portable_builtins_map:
+ condition, replacement = non_portable_builtins_map[entry.name]
+ w.putln('#if %s' % condition)
self.put_cached_builtin_init(
- entry.pos, StringEncoding.EncodedString('Exception'),
+ entry.pos, StringEncoding.EncodedString(replacement),
entry.cname)
- if conditional_name:
w.putln('#else')
self.put_cached_builtin_init(
entry.pos, StringEncoding.EncodedString(entry.name),
entry.cname)
- if conditional_name:
+ if condition:
w.putln('#endif')
def put_cached_builtin_init(self, pos, name, cname):
else:
objstruct = "struct %s" % type.objstruct_cname
module_name = type.module_name
+ condition = None
if module_name not in ('__builtin__', 'builtins'):
module_name = '"%s"' % module_name
else:
module_name = '__Pyx_BUILTIN_MODULE_NAME'
- if type.name in self.py3_type_name_map:
- code.putln("#if PY_MAJOR_VERSION >= 3")
- code.putln('%s = __Pyx_ImportType(%s, "%s", sizeof(%s), 1); %s' % (
- type.typeptr_cname,
- module_name,
- self.py3_type_name_map[type.name],
- objstruct,
- error_code))
- code.putln("#else")
+ if type.name in Code.non_portable_builtins_map:
+ condition, replacement = Code.non_portable_builtins_map[entry.name]
+ code.putln("#if %s" % condition)
+ code.putln('%s = __Pyx_ImportType(%s, "%s", sizeof(%s), 1); %s' % (
+ type.typeptr_cname,
+ module_name,
+ replacement,
+ objstruct,
+ error_code))
+ code.putln("#else")
code.putln('%s = __Pyx_ImportType(%s, "%s", sizeof(%s), %i); %s' % (
type.typeptr_cname,
module_name,
objstruct,
not type.is_external or type.is_subclassed,
error_code))
- if type.name in self.py3_type_name_map:
+ if condition:
code.putln("#endif")
def generate_type_ready_code(self, env, entry, code):
# Cython - Compilation-wide options and pragma declarations
#
-cache_builtins = True # Perform lookups on builtin names only once
+# Perform lookups on builtin names only once, at module initialisation
+# time. This will prevent the module from getting imported if a
+# builtin name that it uses cannot be found during initialisation.
+cache_builtins = True
embed_pos_in_docstring = False
gcc_branch_hints = True
# Make all warnings into errors.
warning_errors = False
+# Make unknown names an error. Python raises a NameError when
+# encountering unknown names at runtime, whereas this option makes
+# them a compile time error. If you want full Python compatibility,
+# you should disable this option and also 'cache_builtins'.
+error_on_unknown_names = True
+
# This will convert statements of the form "for i in range(...)"
# to "for i from ..." when i is a cdef'd integer type, and the direction
# (i.e. sign of step) can be determined.
if self.outer_scope is not None:
return self.outer_scope.declare_builtin(name, pos)
else:
- warning(pos, "undeclared name not builtin: %s" % name, 2)
+ if Options.error_on_unknown_names:
+ error(pos, "undeclared name not builtin: %s" % name)
+ else:
+ warning(pos, "undeclared name not builtin: %s" % name, 2)
def declare_builtin_cfunction(self, name, type, cname, python_equiv = None,
utility_code = None):
var_entry.is_readonly = 1
var_entry.is_builtin = 1
var_entry.utility_code = utility_code
+ if Options.cache_builtins:
+ var_entry.is_const = True
entry.as_variable = var_entry
return type
return self.outer_scope.lookup(name, language_level = self.context.language_level)
def declare_builtin(self, name, pos):
- if not hasattr(builtins, name) and name not in ('xrange', 'BaseException'):
+ if not hasattr(builtins, name) and name not in Code.non_portable_builtins_map:
# 'xrange' and 'BaseException' are special cased in Code.py
if self.has_import_star:
entry = self.declare_var(name, py_object_type, pos)
## return entry
else:
# unknown - assume it's builtin and look it up at runtime
- warning(pos, "undeclared name not builtin: %s" % name, 2)
+ if Options.error_on_unknown_names:
+ error(pos, "undeclared name not builtin: %s" % name)
+ else:
+ warning(pos, "undeclared name not builtin: %s" % name, 2)
entry = self.declare(name, None, py_object_type, pos, 'private')
entry.is_builtin = 1
return entry
entry = self.declare(None, None, py_object_type, pos, 'private')
if Options.cache_builtins:
entry.is_builtin = 1
- entry.is_const = 1
+ entry.is_const = 1 # cached
entry.name = name
entry.cname = Naming.builtin_prefix + name
self.cached_builtins.append(entry)