[pypy-commit] cffi default: Avoid cyclic imports by moving exceptions to a separate module
rlamy
pypy.commits at gmail.com
Fri Jan 20 03:24:34 EST 2017
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch:
Changeset: r2862:b87441f6f36c
Date: 2017-01-20 03:05 +0000
http://bitbucket.org/cffi/cffi/changeset/b87441f6f36c/
Log: Avoid cyclic imports by moving exceptions to a separate module
diff --git a/cffi/__init__.py b/cffi/__init__.py
--- a/cffi/__init__.py
+++ b/cffi/__init__.py
@@ -1,8 +1,8 @@
__all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError',
'FFIError']
-from .api import FFI, CDefError, FFIError
-from .ffiplatform import VerificationError, VerificationMissing
+from .api import FFI
+from .error import CDefError, FFIError, VerificationError, VerificationMissing
__version__ = "1.9.2"
__version_info__ = (1, 9, 2)
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -1,5 +1,7 @@
import sys, types
from .lock import allocate_lock
+from .error import CDefError
+from . import cparser, model
try:
callable
@@ -15,17 +17,6 @@
basestring = str
-class FFIError(Exception):
- pass
-
-class CDefError(Exception):
- def __str__(self):
- try:
- line = 'line %d: ' % (self.args[1].coord.line,)
- except (AttributeError, TypeError, IndexError):
- line = ''
- return '%s%s' % (line, self.args[0])
-
class FFI(object):
r'''
@@ -49,7 +40,6 @@
"""Create an FFI instance. The 'backend' argument is used to
select a non-default backend, mostly for tests.
"""
- from . import cparser, model
if backend is None:
# You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with
# _cffi_backend.so compiled.
@@ -221,7 +211,7 @@
def offsetof(self, cdecl, *fields_or_indexes):
"""Return the offset of the named field inside the given
- structure or array, which must be given as a C type name.
+ structure or array, which must be given as a C type name.
You can give several field names in case of nested structures.
You can also give numeric values which correspond to array
items, in case of an array type.
@@ -309,7 +299,7 @@
return self._backend.string(cdata, maxlen)
def unpack(self, cdata, length):
- """Unpack an array of C data of the given length,
+ """Unpack an array of C data of the given length,
returning a Python string/unicode/list.
If 'cdata' is a pointer to 'char', returns a byte string.
@@ -461,7 +451,6 @@
return self._backend.getwinerror(code)
def _pointer_to(self, ctype):
- from . import model
with self._lock:
return model.pointer_cache(self, ctype)
@@ -773,7 +762,6 @@
return backend.load_library(path, flags)
def _make_ffi_library(ffi, libname, flags):
- import os
backend = ffi._backend
backendlib = _load_backend_lib(backend, libname, flags)
#
@@ -811,7 +799,6 @@
if accessors_version[0] is ffi._cdef_version:
return
#
- from . import model
for key, (tp, _) in ffi._parser._declarations.items():
if not isinstance(tp, model.EnumType):
tag, name = key.split(' ', 1)
diff --git a/cffi/cffi_opcode.py b/cffi/cffi_opcode.py
--- a/cffi/cffi_opcode.py
+++ b/cffi/cffi_opcode.py
@@ -1,3 +1,4 @@
+from .error import VerificationError
class CffiOp(object):
def __init__(self, op, arg):
@@ -19,7 +20,6 @@
% (self.arg,))
return format_four_bytes(value)
if isinstance(self.arg, str):
- from .ffiplatform import VerificationError
raise VerificationError("cannot emit to Python: %r" % (self.arg,))
return format_four_bytes((self.arg << 8) | self.op)
diff --git a/cffi/commontypes.py b/cffi/commontypes.py
--- a/cffi/commontypes.py
+++ b/cffi/commontypes.py
@@ -1,5 +1,6 @@
import sys
-from . import api, model
+from . import model
+from .error import FFIError
COMMON_TYPES = {}
@@ -31,11 +32,11 @@
elif cdecl in model.PrimitiveType.ALL_PRIMITIVE_TYPES:
result, quals = model.PrimitiveType(cdecl), 0
elif cdecl == 'set-unicode-needed':
- raise api.FFIError("The Windows type %r is only available after "
- "you call ffi.set_unicode()" % (commontype,))
+ raise FFIError("The Windows type %r is only available after "
+ "you call ffi.set_unicode()" % (commontype,))
else:
if commontype == cdecl:
- raise api.FFIError(
+ raise FFIError(
"Unsupported type: %r. Please look at "
"http://cffi.readthedocs.io/en/latest/cdef.html#ffi-cdef-limitations "
"and file an issue if you think this type should really "
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -1,5 +1,6 @@
-from . import api, model
+from . import model
from .commontypes import COMMON_TYPES, resolve_common_type
+from .error import FFIError, CDefError
try:
from . import _pycparser as pycparser
except ImportError:
@@ -113,7 +114,7 @@
# grouping variant
closing = csource.find('}', endpos)
if closing < 0:
- raise api.CDefError("'extern \"Python\" {': no '}' found")
+ raise CDefError("'extern \"Python\" {': no '}' found")
if csource.find('{', endpos + 1, closing) >= 0:
raise NotImplementedError("cannot use { } inside a block "
"'extern \"Python\" { ... }'")
@@ -123,7 +124,7 @@
# non-grouping variant
semicolon = csource.find(';', endpos)
if semicolon < 0:
- raise api.CDefError("'extern \"Python\": no ';' found")
+ raise CDefError("'extern \"Python\": no ';' found")
parts.append(csource[endpos:semicolon+1])
csource = csource[semicolon+1:]
parts.append(' void __cffi_extern_python_stop;')
@@ -288,7 +289,7 @@
msg = 'cannot parse "%s"\n%s' % (line.strip(), msg)
else:
msg = 'parse error\n%s' % (msg,)
- raise api.CDefError(msg)
+ raise CDefError(msg)
def parse(self, csource, override=False, packed=False, dllexport=False):
prev_options = self._options
@@ -318,8 +319,8 @@
self._parse_decl(decl)
elif isinstance(decl, pycparser.c_ast.Typedef):
if not decl.name:
- raise api.CDefError("typedef does not declare any name",
- decl)
+ raise CDefError("typedef does not declare any name",
+ decl)
quals = 0
if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType)
and decl.type.type.names[-1] == '__dotdotdot__'):
@@ -337,8 +338,8 @@
elif decl.__class__.__name__ == 'Pragma':
pass # skip pragma, only in pycparser 2.15
else:
- raise api.CDefError("unrecognized construct", decl)
- except api.FFIError as e:
+ raise CDefError("unrecognized construct", decl)
+ except FFIError as e:
msg = self._convert_pycparser_error(e, csource)
if msg:
e.args = (e.args[0] + "\n *** Err: %s" % msg,)
@@ -348,7 +349,7 @@
if key in self._int_constants:
if self._int_constants[key] == val:
return # ignore identical double declarations
- raise api.FFIError(
+ raise FFIError(
"multiple declarations of constant: %s" % (key,))
self._int_constants[key] = val
@@ -375,7 +376,7 @@
elif value == '...':
self._declare('macro ' + key, value)
else:
- raise api.CDefError(
+ raise CDefError(
'only supports one of the following syntax:\n'
' #define %s ... (literally dot-dot-dot)\n'
' #define %s NUMBER (with NUMBER an integer'
@@ -410,8 +411,8 @@
elif isinstance(node, pycparser.c_ast.Enum):
self._get_struct_union_enum_type('enum', node)
elif not decl.name:
- raise api.CDefError("construct does not declare any variable",
- decl)
+ raise CDefError("construct does not declare any variable",
+ decl)
#
if decl.name:
tp, quals = self._get_type_and_quals(node,
@@ -438,7 +439,7 @@
self._inside_extern_python = decl.name
else:
if self._inside_extern_python !='__cffi_extern_python_stop':
- raise api.CDefError(
+ raise CDefError(
"cannot declare constants or "
"variables with 'extern \"Python\"'")
if (quals & model.Q_CONST) and not tp.is_array_type:
@@ -454,7 +455,7 @@
assert not macros
exprnode = ast.ext[-1].type.args.params[0]
if isinstance(exprnode, pycparser.c_ast.ID):
- raise api.CDefError("unknown identifier '%s'" % (exprnode.name,))
+ raise CDefError("unknown identifier '%s'" % (exprnode.name,))
return self._get_type_and_quals(exprnode.type)
def _declare(self, name, obj, included=False, quals=0):
@@ -463,7 +464,7 @@
if prevobj is obj and prevquals == quals:
return
if not self._options.get('override'):
- raise api.FFIError(
+ raise FFIError(
"multiple declarations of %s (for interactive usage, "
"try cdef(xx, override=True))" % (name,))
assert '__dotdotdot__' not in name.split()
@@ -551,7 +552,7 @@
if ident == 'void':
return model.void_type, quals
if ident == '__dotdotdot__':
- raise api.FFIError(':%d: bad usage of "..."' %
+ raise FFIError(':%d: bad usage of "..."' %
typenode.coord.line)
tp0, quals0 = resolve_common_type(self, ident)
return tp0, (quals | quals0)
@@ -583,14 +584,14 @@
return self._get_struct_union_enum_type('union', typenode, name,
nested=True), 0
#
- raise api.FFIError(":%d: bad or unsupported type declaration" %
+ raise FFIError(":%d: bad or unsupported type declaration" %
typenode.coord.line)
def _parse_function_type(self, typenode, funcname=None):
params = list(getattr(typenode.args, 'params', []))
for i, arg in enumerate(params):
if not hasattr(arg, 'type'):
- raise api.CDefError("%s arg %d: unknown type '%s'"
+ raise CDefError("%s arg %d: unknown type '%s'"
" (if you meant to use the old C syntax of giving"
" untyped arguments, it is not supported)"
% (funcname or 'in expression', i + 1,
@@ -604,7 +605,7 @@
if ellipsis:
params.pop()
if not params:
- raise api.CDefError(
+ raise CDefError(
"%s: a function with only '(...)' as argument"
" is not correct C" % (funcname or 'in expression'))
args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type))
@@ -705,7 +706,7 @@
return tp
#
if tp.fldnames is not None:
- raise api.CDefError("duplicate declaration of struct %s" % name)
+ raise CDefError("duplicate declaration of struct %s" % name)
fldnames = []
fldtypes = []
fldbitsize = []
@@ -749,7 +750,7 @@
def _make_partial(self, tp, nested):
if not isinstance(tp, model.StructOrUnion):
- raise api.CDefError("%s cannot be partial" % (tp,))
+ raise CDefError("%s cannot be partial" % (tp,))
if not tp.has_c_name() and not nested:
raise NotImplementedError("%s is partial but has no C name" %(tp,))
tp.partial = True
@@ -769,7 +770,7 @@
len(s) == 3 or (len(s) == 4 and s[1] == "\\")):
return ord(s[-2])
else:
- raise api.CDefError("invalid constant %r" % (s,))
+ raise CDefError("invalid constant %r" % (s,))
#
if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and
exprnode.op == '+'):
@@ -788,12 +789,12 @@
if partial_length_ok:
self._partial_length = True
return '...'
- raise api.FFIError(":%d: unsupported '[...]' here, cannot derive "
- "the actual array length in this context"
- % exprnode.coord.line)
+ raise FFIError(":%d: unsupported '[...]' here, cannot derive "
+ "the actual array length in this context"
+ % exprnode.coord.line)
#
- raise api.FFIError(":%d: unsupported expression: expected a "
- "simple numeric constant" % exprnode.coord.line)
+ raise FFIError(":%d: unsupported expression: expected a "
+ "simple numeric constant" % exprnode.coord.line)
def _build_enum_type(self, explicit_name, decls):
if decls is not None:
@@ -843,8 +844,8 @@
for t in typenames[:-1]:
if t not in ['int', 'short', 'long', 'signed',
'unsigned', 'char']:
- raise api.FFIError(':%d: bad usage of "..."' %
- decl.coord.line)
+ raise FFIError(':%d: bad usage of "..."' %
+ decl.coord.line)
result = model.UnknownIntegerType(decl.name)
if self._uses_new_feature is None:
diff --git a/cffi/error.py b/cffi/error.py
new file mode 100644
--- /dev/null
+++ b/cffi/error.py
@@ -0,0 +1,20 @@
+
+class FFIError(Exception):
+ pass
+
+class CDefError(Exception):
+ def __str__(self):
+ try:
+ line = 'line %d: ' % (self.args[1].coord.line,)
+ except (AttributeError, TypeError, IndexError):
+ line = ''
+ return '%s%s' % (line, self.args[0])
+
+class VerificationError(Exception):
+ """ An error raised when verification fails
+ """
+
+class VerificationMissing(Exception):
+ """ An error raised when incomplete structures are passed into
+ cdef, but no verification has been done
+ """
diff --git a/cffi/ffiplatform.py b/cffi/ffiplatform.py
--- a/cffi/ffiplatform.py
+++ b/cffi/ffiplatform.py
@@ -1,14 +1,5 @@
import sys, os
-
-
-class VerificationError(Exception):
- """ An error raised when verification fails
- """
-
-class VerificationMissing(Exception):
- """ An error raised when incomplete structures are passed into
- cdef, but no verification has been done
- """
+from .error import VerificationError, VerificationMissing
LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs',
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -1,8 +1,8 @@
-import types, sys
+import types
import weakref
from .lock import allocate_lock
-
+from .error import CDefError, VerificationError, VerificationMissing
# type qualifiers
Q_CONST = 0x01
@@ -39,7 +39,6 @@
replace_with = qualify(quals, replace_with)
result = result.replace('&', replace_with)
if '$' in result:
- from .ffiplatform import VerificationError
raise VerificationError(
"cannot generate '%s' in %s: unknown type name"
% (self._get_c_name(), context))
@@ -223,9 +222,8 @@
is_raw_function = True
def build_backend_type(self, ffi, finishlist):
- from . import api
- raise api.CDefError("cannot render the type %r: it is a function "
- "type, not a pointer-to-function type" % (self,))
+ raise CDefError("cannot render the type %r: it is a function "
+ "type, not a pointer-to-function type" % (self,))
def as_function_pointer(self):
return FunctionPtrType(self.args, self.result, self.ellipsis, self.abi)
@@ -307,9 +305,8 @@
def build_backend_type(self, ffi, finishlist):
if self.length == '...':
- from . import api
- raise api.CDefError("cannot render the type %r: unknown length" %
- (self,))
+ raise CDefError("cannot render the type %r: unknown length" %
+ (self,))
self.item.get_cached_btype(ffi, finishlist) # force the item BType
BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist)
return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length)
@@ -455,13 +452,11 @@
self.completed = 2
def _verification_error(self, msg):
- from .ffiplatform import VerificationError
raise VerificationError(msg)
def check_not_partial(self):
if self.partial and self.fixedlayout is None:
- from . import ffiplatform
- raise ffiplatform.VerificationMissing(self._get_c_name())
+ raise VerificationMissing(self._get_c_name())
def build_backend_type(self, ffi, finishlist):
self.check_not_partial()
@@ -499,8 +494,7 @@
def check_not_partial(self):
if self.partial and not self.partial_resolved:
- from . import ffiplatform
- raise ffiplatform.VerificationMissing(self._get_c_name())
+ raise VerificationMissing(self._get_c_name())
def build_backend_type(self, ffi, finishlist):
self.check_not_partial()
@@ -514,7 +508,6 @@
if self.baseinttype is not None:
return self.baseinttype.get_cached_btype(ffi, finishlist)
#
- from . import api
if self.enumvalues:
smallest_value = min(self.enumvalues)
largest_value = max(self.enumvalues)
@@ -549,8 +542,8 @@
if (smallest_value >= ((-1) << (8*size2-1)) and
largest_value < (1 << (8*size2-sign))):
return btype2
- raise api.CDefError("%s values don't all fit into either 'long' "
- "or 'unsigned long'" % self._get_c_name())
+ raise CDefError("%s values don't all fit into either 'long' "
+ "or 'unsigned long'" % self._get_c_name())
def unknown_type(name, structname=None):
if structname is None:
More information about the pypy-commit
mailing list