diff --git a/clif/python/pytd2proto.py b/clif/python/pytd2proto.py index f0f6385..627245f 100644 --- a/clif/python/pytd2proto.py +++ b/clif/python/pytd2proto.py @@ -35,16 +35,19 @@ from clif.python import ast_manipulations from clif.python import pytd_parser -CLIF_USE = re.compile(r'// *CLIF:? +use(?P2*)' - r' +`(?P.+)` +as +(?P[\w.]+)') +CLIF_USE = re.compile( + r'// *CLIF:? +use(?P2*)' + r' +`(?P.+)` +as +(?P[\w.]+)' +) CLIF_INIT = re.compile(r'// *CLIF:? +init_module +(?P.+)') CLIF_MACRO = re.compile(r'// *CLIF:? +macro +(?P.+) +(?P.+)$') CLIF_INCLUDE = re.compile(r'// *CLIF:? +include +"(?P[^"]+)"') KEEP_GIL_DECORATOR = 'do_not_release_gil' -def _read_include(input_stream, fname, prefix, typetable, capsules, interfaces, - extra_init): +def _read_include( + input_stream, fname, prefix, typetable, capsules, interfaces, extra_init +): """Reads a C++ .h file generated by CLIF to check wrapper information.""" for s in input_stream: use = CLIF_USE.match(s) @@ -59,16 +62,22 @@ def _read_include(input_stream, fname, prefix, typetable, capsules, interfaces, raise SyntaxError('Invalid "use" pragma in "%s": %s' % (fname, s)) pyname = prefix + pyname if pyname in capsules: - raise NameError('C++ type "%s" already wrapped as capsule by name %s' - % (cname, pyname)) + raise NameError( + 'C++ type "%s" already wrapped as capsule by name %s' + % (cname, pyname) + ) if typetable.has_type(pyname) and cname.endswith('*'): - raise NameError('C++ type "%s" already wrapped by name %s' - % (cname, pyname)) + raise NameError( + 'C++ type "%s" already wrapped by name %s' % (cname, pyname) + ) existing_pyname = typetable.find_pyname_for_cpp_type(cname) if existing_pyname: - raise NameError('C++ type {!r} already wrapped by name {!r}'.format( - cname, existing_pyname)) + raise NameError( + 'C++ type {!r} already wrapped by name {!r}'.format( + cname, existing_pyname + ) + ) if cname.endswith('*'): capsules[pyname] = cname else: @@ -91,12 +100,14 @@ def _read_include(input_stream, fname, prefix, typetable, capsules, interfaces, except Exception: # pylint: disable=broad-except raise ImportError('Macro %s loading error' % name) if sysver != sys.hexversion or ppver != pytd_parser.version: - raise ValueError('Interface name "%s" from file %s is from ' - 'incompatible version (%s, %s)' - % (name, fname, sysver, ppver)) + raise ValueError( + 'Interface name "%s" from file %s is from ' + 'incompatible version (%s, %s)' % (name, fname, sysver, ppver) + ) if name in interfaces: - raise NameError('Interface name "%s" from file %s already used' - % (name, fname)) + raise NameError( + 'Interface name "%s" from file %s already used' % (name, fname) + ) interfaces[name] = src + (False,) continue @@ -107,7 +118,7 @@ class Postprocessor: def __init__(self, config_headers=None, include_paths=('.',), preamble=''): self._options = [] self._names = {} # Keep name->FQN for all 'from path import' statements. - self._capsules = {} # Keep raw pointer names (pytype -> cpptype). + self._capsules = {} # Keep raw pointer names (pytype -> cpptype). self._typenames = {} # Keep typedef aliases (pytype -> type_ir). self._typetable = _TypeTable() self._macros = {} # Keep interfaces (name -> (num_args, subtree, local)). @@ -120,18 +131,20 @@ def __init__(self, config_headers=None, include_paths=('.',), preamble=''): self._macro_values = [] def is_pyname_known(self, name): - return (name in self._capsules or - self._typetable.has_type(name) or - name in self._typenames) + return ( + name in self._capsules + or self._typetable.has_type(name) + or name in self._typenames + ) def check_known_name(self, name, allowed=None): """Check that a type name is not defined or defined with the given value. Args: name: str, the name of the type in the type table. - allowed: optional str, if a type is already defined in the - typetable, then the existing C++ type for `name` must match this - value. This only applies if `name` already exists. + allowed: optional str, if a type is already defined in the typetable, then + the existing C++ type for `name` must match this value. This only + applies if `name` already exists. Raises: NameError: if the name is not defined, or if it is defined but doesn't @@ -144,11 +157,13 @@ def check_known_name(self, name, allowed=None): if not allowed: raise NameError( 'Name %r already defined as type %r, but it was expected to ' - 'be undefined' % (name, self._typetable.get_last_cpp_type(name))) + 'be undefined' % (name, self._typetable.get_last_cpp_type(name)) + ) elif self._typetable.get_last_cpp_type(name) != allowed: raise NameError( - 'Name %r already defined as type %r, but %r was expected' % - (name, self._typetable.get_last_cpp_type(name), allowed)) + 'Name %r already defined as type %r, but %r was expected' + % (name, self._typetable.get_last_cpp_type(name), allowed) + ) if name in self._typenames: raise NameError('Name "%s" already defined as type alias.' % name) @@ -173,7 +188,7 @@ def Translate(self, pytd_file): # pylint: disable=invalid-name nm = pb.namemaps.add() nm.name = name nm.fq_name = fq_name - for pytype, cpp_types in order(self._typetable.iter_types()): + for pytype, cpp_types in order(self._typetable.iter_types()): tm = pb.typemaps.add() tm.lang_type = pytype for cpp_type in order(set(cpp_types)): @@ -188,7 +203,8 @@ def Translate(self, pytd_file): # pylint: disable=invalid-name m.name = name # Use protocol 0 to keep version independence. m.definition = pickle.dumps( - (sys.hexversion, pytd_parser.version, (nargs, src)), 0) + (sys.hexversion, pytd_parser.version, (nargs, src)), 0 + ) ast_manipulations.MoveExtendsOutOfClassesInPlace(pb) return pb @@ -215,7 +231,7 @@ def _parse_pytd_ast(self, source, ast, pb): if ir: # IR is specific to the parser. # IR[0] is a statement name. - getattr(self, '_'+ir[0])(self.line(ir[1]), ir[2:], pb) + getattr(self, '_' + ir[0])(self.line(ir[1]), ir[2:], pb) self.source = None def line(self, loc): @@ -244,7 +260,8 @@ def _gather_dispatch(self, ast, **kwargs): func_name = '_gather_{}'.format(ast_type) func = getattr(self, func_name, None) assert func, 'No gather_types function for AST node type {!r}'.format( - ast_type) + ast_type + ) func(ast, **kwargs) # pylint: disable=not-callable def _gather_from(self, ast): @@ -257,8 +274,8 @@ def _gather_class(self, ast, namespace=None): Args: ast: pyparsing.ParseResults - namespace: Optional[str], the cpp namespace the class is within; this - is only used by top-level class definitions. + namespace: Optional[str], the cpp namespace the class is within; this is + only used by top-level class definitions. """ # The ast name is either: # * 1 element: [Foo] from "class Foo" @@ -266,7 +283,9 @@ def _gather_class(self, ast, namespace=None): if len(ast.name) not in (1, 2): raise ValueError( 'Class name ast node must be length 1 or 2, got {!r}'.format( - list(ast.name))) + list(ast.name) + ) + ) if namespace: cpp_name = '{}::{}'.format(namespace, ast.name[0]) @@ -284,7 +303,8 @@ def _gather_class(self, ast, namespace=None): # Explicitly clear namespace to prevent the namespace from being # redundantly and erroneously prepended to nested types. This # also mimics the normal parsing behavior. - namespace=None) + namespace=None, + ) def _gather_namespace(self, ast): """Visit a namespace node for gathering types.""" @@ -311,7 +331,8 @@ def _OPTION(self, ln, p, pb): # pylint: disable=invalid-name if value not in ('False', 'True'): raise ValueError( 'Invalid OPTION value at line %d: %s (must be False or True)' - % (ln, value)) + % (ln, value) + ) pb.options[name] = value def _interface(self, ln, p, unused_pb=None): @@ -321,9 +342,11 @@ def _interface(self, ln, p, unused_pb=None): name = p[0] self.check_known_name(name) args = {name: pos for pos, name in enumerate(p[:-1])} - if len(args) != nargs+1: - raise NameError('all interface args must be different ' - 'at line %d, got %s<%s>' % (ln, name, ', '.join(p[1:-1]))) + if len(args) != nargs + 1: + raise NameError( + 'all interface args must be different at line %d, got %s<%s>' + % (ln, name, ', '.join(p[1:-1])) + ) src = p[-1] if nargs: for ast in src: @@ -335,8 +358,10 @@ def _interface(self, ln, p, unused_pb=None): elif ast[0] == 'var': _subst_type_formal(ast, args) else: - raise NameError('Only def and var allowed in interface,' - ' found "%s" at line %d' % (ast[0], ln)) + raise NameError( + 'Only def and var allowed in interface, found "%s" at line %d' + % (ast[0], ln) + ) self._macros[name] = nargs, src, True def _from(self, unused_ln, p, pb): @@ -351,7 +376,7 @@ def _from(self, unused_ln, p, pb): elif s[0] != 'pass': decl = pb.decls.add() decl.cpp_file = hdr - getattr(self, '_'+s[0])(self.line(s[1]), s, decl) + getattr(self, '_' + s[0])(self.line(s[1]), s, decl) def _namespace(self, unused_ln, p, pb, hdr): """namespace `x::y::z` processing.""" @@ -366,22 +391,24 @@ def _namespace(self, unused_ln, p, pb, hdr): decl = pb.decls.add() decl.cpp_file = hdr decl.namespace_ = ns - getattr(self, '_'+s[0])(self.line(s[1]), s, decl, ns=ns) + getattr(self, '_' + s[0])(self.line(s[1]), s, decl, ns=ns) def _staticmethods(self, ln, p, pb, hdr, ns=''): """staticmethods from `SomeType` processing.""" assert len(p) == 4, str(p) assert hdr if ns and p[2].startswith(':'): - raise NameError('Invalid reference to global class %s inside namespace %s' - ' at line %d' % (p[2], ns, ln)) - cns = ns + '::' + p[2] + raise NameError( + 'Invalid reference to global class %s inside namespace %s at line %d' + % (p[2], ns, ln) + ) + cns = ns + '::' + p[2] for s in p[-1]: decl = pb.decls.add() decl.cpp_file = hdr if ns: decl.namespace_ = ns - getattr(self, '_'+s[0])(self.line(s[1]), s, decl, ns=cns) + getattr(self, '_' + s[0])(self.line(s[1]), s, decl, ns=cns) def _include(self, unused_ln, p, pb, scan_only=False): """from "full/project/path/cheader.h" import *.""" @@ -390,15 +417,23 @@ def _include(self, unused_ln, p, pb, scan_only=False): if not scan_only: pb.usertype_includes.append(hdr) # Scan hdr for new types - namespace = p[1]+'.' if len(p) > 1 else '' + namespace = p[1] + '.' if len(p) > 1 else '' for root in self._include_paths: try: - with codecs.open(os.path.join(root, hdr), - encoding='utf-8') as include_file: + with codecs.open( + os.path.join(root, hdr), encoding='utf-8' + ) as include_file: pb.usertype_includes.extend( - _read_include(include_file, hdr, namespace, - self._typetable, self._capsules, self._macros, - pb.extra_init)) + _read_include( + include_file, + hdr, + namespace, + self._typetable, + self._capsules, + self._macros, + pb.extra_init, + ) + ) break except IOError: pass @@ -435,8 +470,9 @@ def _use(self, ln, p, unused_pb): if p[0].endswith('*'): raise NameError('Wrap type %s before use' % p[0][:-1]) if not self.is_pyname_known(p[1]): - raise NameError('Type %s should be defined before use at line %s' - % (p[1], ln)) + raise NameError( + 'Type %s should be defined before use at line %s' % (p[1], ln) + ) self._typetable.add_type(0, p[1], p[0]) # decl @@ -453,6 +489,7 @@ def _extract_template_base_name(self, cpp_class_name): Args: cpp_class_name: The name of the cpp class, i.e. `Class` or `Template<...>`. + Returns: The base name of the template (left of first "<") when cpp_class_name is templated, None otherwise. @@ -474,7 +511,8 @@ def _class(self, ln, ast, pb, ns=None): ast.name, ns, allow_fqcppname=is_iterator, - template_name=self._extract_template_base_name(cpp_name)) + template_name=self._extract_template_base_name(cpp_name), + ) pyname = p.name.native self.check_known_name(pyname, p.name.cpp_name) decorators = ast.decorators.asList() @@ -493,8 +531,9 @@ def _class(self, ln, ast, pb, ns=None): p.suppress_shared_ptr_const_conversion = True decorators.remove('suppress_shared_ptr_const_conversion') if decorators: - raise NameError('Unknown class decorator(s)%s: %s' - % (atln, ', '.join(decorators))) + raise NameError( + 'Unknown class decorator(s)%s: %s' % (atln, ', '.join(decorators)) + ) _set_bases(p.bases, ast.bases, self._names, self._typetable) # Iterators don't add themselves to the type table (see above), so we can't @@ -515,10 +554,14 @@ def _class(self, ln, ast, pb, ns=None): continue line_number = self.line(decl[1]) if is_iterator: - if (len(ast[-1]) != 1 or - decl[0] != 'func' or decl.name[-1] != '__next__'): - raise SyntaxError('__iter__ class must only def __next__ at line %d' - % line_number) + if ( + len(ast[-1]) != 1 + or decl[0] != 'func' + or decl.name[-1] != '__next__' + ): + raise SyntaxError( + '__iter__ class must only def __next__ at line %d' % line_number + ) else: if decl[0] == 'implements': name = decl[2] @@ -527,49 +570,62 @@ def _class(self, ln, ast, pb, ns=None): nargs, src, _ = self._macros[name] except KeyError: raise NameError('interface %s not defined' % name + atln) - if len(self._macro_values) != nargs+1: - raise NameError('interface %s needs %d args (%d given)' - % (name, len(self._macro_values)-1, nargs) + atln) + if len(self._macro_values) != nargs + 1: + raise NameError( + 'interface %s needs %d args (%d given)' + % (name, len(self._macro_values) - 1, nargs) + + atln + ) for d in src: ln = self.line(d[1]) if d[0] == 'func': if not self.unproperty(ln, d, pyname, p.members, local_names): - _add_uniq(pyname, local_names, - self._func(ln, d, p.members.add())) + _add_uniq( + pyname, local_names, self._func(ln, d, p.members.add()) + ) elif d[0] == 'var': _add_uniq(pyname, local_names, self._var(ln, d, p.members.add())) else: - raise SyntaxError('implements %s contains disallowed %s%s' - % (name, d[0], atln)) + raise SyntaxError( + 'implements %s contains disallowed %s%s' % (name, d[0], atln) + ) self._macro_values = [] continue if decl[0] == 'func' and self.unproperty( - line_number, decl, pyname, p.members, local_names): + line_number, decl, pyname, p.members, local_names + ): continue - name = getattr(self, '_'+decl[0])(line_number, decl, p.members.add()) + name = getattr(self, '_' + decl[0])(line_number, decl, p.members.add()) _add_uniq(pyname, local_names, name) funcs = [m.func for m in p.members if m.decltype == m.FUNC] is_sequential = any(f.name.native.endswith('#') for f in funcs) if is_sequential and any(f.name.native in _RIGHT_OPS for f in funcs): - raise NameError("class %s %s can't be sequence and number" - ' at the same time' % (p.name.native, atln)) + raise NameError( + "class %s %s can't be sequence and number at the same time" + % (p.name.native, atln) + ) for f in funcs: # Fix ctor name to be the class name. if f.name.native == '__init__': - if (f.name.cpp_name and - f.name.cpp_name not in [cpp_name, '__init__']): - print('Arbitrary names (like "{0}") for {1} ctor not allowed.' - ' Set to {1}'.format(f.name.cpp_name, cpp_name), - file=sys.stderr) + if f.name.cpp_name and f.name.cpp_name not in [cpp_name, '__init__']: + print( + 'Arbitrary names (like "{0}") for {1} ctor not allowed.' + ' Set to {1}'.format(f.name.cpp_name, cpp_name), + file=sys.stderr, + ) f.name.cpp_name = cpp_name f.constructor = True elif f.name.native == cpp_name: - raise NameError('Use __init__ to wrap a "%s" constructor'%pyname + atln) + raise NameError( + 'Use __init__ to wrap a "%s" constructor' % pyname + atln + ) elif f.name.cpp_name == cpp_name: # @add__init__ will reset cpp_name to be empty. - raise NameError('Use @add__init__ to wrap additional "%s" constructor' - '(s).' % pyname + atln) + raise NameError( + 'Use @add__init__ to wrap additional "%s" constructor(s).' % pyname + + atln + ) elif not f.name.cpp_name: # An additional ctor. f.name.cpp_name = cpp_name f.constructor = True @@ -577,8 +633,9 @@ def _class(self, ln, ast, pb, ns=None): # Fix 'self' for C++ operator function (implemented out of class). elif f.name.native in _RIGHT_OPS: if len(f.params) != 1: - raise ValueError('%s must have only 1 input parameter' - % f.name.native + atln) + raise ValueError( + '%s must have only 1 input parameter' % f.name.native + atln + ) f.cpp_opfunction = True # Request a non-member function. self._set_this(f.params.add(), cpp_name, p.name.cpp_name) elif '::' in f.name.cpp_name: @@ -597,8 +654,9 @@ def _class(self, ln, ast, pb, ns=None): self._set_this(f.params[0], cpp_name, p.name.cpp_name) # Fix 'item|add__' for a 'sequential' class. - elif is_sequential and (f.name.native.endswith('item__') or - f.name.native.endswith('add__')): + elif is_sequential and ( + f.name.native.endswith('item__') or f.name.native.endswith('add__') + ): f.name.native += '#' # Move '+' to tp_as_sequence slots. if not is_iterator: @@ -621,6 +679,7 @@ def unproperty(self, ln, ast, class_name, members, known_names): class_name: Python name of the wrapped C++ class members: wrapped C++ class memebers known_names: names already defined in a C++ class wrapper + Returns: True if ast is a @getter/@setter func that describes 'unproperty' C++ var. Raises: @@ -633,13 +692,15 @@ def unproperty(self, ln, ast, class_name, members, known_names): do_not_release_gil = True except ValueError: do_not_release_gil = False - if getset not in (['getter'], ['setter']): return False + if getset not in (['getter'], ['setter']): + return False ast.decorators[:] = [] # Convert func to var. f = ast_pb2.Decl() self._func(ln, ast, f) f = f.func - if do_not_release_gil: f.py_keep_gil = True + if do_not_release_gil: + f.py_keep_gil = True cname = f.name.cpp_name pyname = f.name.native for m in members: @@ -700,13 +761,15 @@ def _var(self, ln, ast, pb): if ast.getter: f = p.cpp_get f.name.cpp_name = ast.getter - self.set_type(f.returns.add().type, ast, - lambda x, f=f: _set_keep_gil(f, x)) + self.set_type( + f.returns.add().type, ast, lambda x, f=f: _set_keep_gil(f, x) + ) if ast.setter: f = p.cpp_set f.name.cpp_name = ast.setter - self.set_type(f.params.add().type, ast, - lambda x, f=f: _set_keep_gil(f, x)) + self.set_type( + f.params.add().type, ast, lambda x, f=f: _set_keep_gil(f, x) + ) f.ignore_return_value = True if ast.docstring: p.docstring = ast.docstring[0][2] @@ -735,16 +798,21 @@ def _func(self, ln, ast, pb, ns=None): f = pb.func modified_ast_name = ast.name if modified_ast_name[-1] == '__reduce__': - raise NameError('Please define `__reduce_ex__` instead of `__reduce__`. ' - 'Pickle prefers `__reduce_ex__` over `__reduce__`. ' - '`__reduce__` is a legacy API and only used if ' - '`__reduce_ex__` does not exist. See go/pyclif-pickle ' - 'for details.') + raise NameError( + 'Please define `__reduce_ex__` instead of `__reduce__`. ' + 'Pickle prefers `__reduce_ex__` over `__reduce__`. ' + '`__reduce__` is a legacy API and only used if ' + '`__reduce_ex__` does not exist. See go/pyclif-pickle ' + 'for details.' + ) if modified_ast_name[-1] == '__nonzero__': - raise NameError('Please define `__bool__` instead of `__nonzero__`. ' - 'See b/62796379 for details.') - _set_name(f.name, _fix_special_names(modified_ast_name), ns, - allow_fqcppname=True) + raise NameError( + 'Please define `__bool__` instead of `__nonzero__`. ' + 'See b/62796379 for details.' + ) + _set_name( + f.name, _fix_special_names(modified_ast_name), ns, allow_fqcppname=True + ) if ast.returns and ast.returns.asList() == [['', [['self']]]]: del ast['returns'] return_self = True @@ -754,15 +822,19 @@ def _func(self, ln, ast, pb, ns=None): decorators = ast.decorators.asList() if ast.self == 'cls': if 'classmethod' not in decorators: - raise ValueError('Method %s with the first arg cls should be ' - '@classmethod' % f.name.native) + raise ValueError( + 'Method %s with the first arg cls should be @classmethod' + % f.name.native + ) if 'virtual' in decorators: raise ValueError("Classmethods can't be @virtual") f.classmethod = True decorators.remove('classmethod') elif 'classmethod' in decorators: - raise ValueError('Method %s with the first arg self should not be ' - '@classmethod' % f.name.native) + raise ValueError( + 'Method %s with the first arg self should not be @classmethod' + % f.name.native + ) elif 'virtual' in decorators: if ast.self != 'self': raise ValueError('@virtual method first arg must be self') @@ -775,11 +847,20 @@ def _func(self, ln, ast, pb, ns=None): f.name.cpp_name = '' # A hack to flag an extra ctor. decorators.remove('add__init__') if 'sequential' in decorators: - if f.name.native not in ('__getitem__', '__setitem__', '__delitem__', - '__add__', '__iadd__', - '__mul__', '__imul__'): - raise NameError('Only __{get/set/del}item__, __*add__, or __*mul__' - ' can be @sequential (not %s).' % f.name.native) + if f.name.native not in ( + '__getitem__', + '__setitem__', + '__delitem__', + '__add__', + '__iadd__', + '__mul__', + '__imul__', + ): + raise NameError( + 'Only __{get/set/del}item__, __*add__, or __*mul__' + ' can be @sequential (not %s).' + % f.name.native + ) f.name.native += '#' # A hack to flag a sq_* slot. decorators.remove('sequential') if 'extend' in decorators: @@ -796,17 +877,22 @@ def _func(self, ln, ast, pb, ns=None): decorators.remove('__enter__') elif f.name.native == '__enter__': if f.postproc or f.params or len(f.returns) != 1: - raise NameError('Use @__enter__ decorator for %s instead of rename' - % f.name.cpp_name) + raise NameError( + 'Use @__enter__ decorator for %s instead of rename' + % f.name.cpp_name + ) if '__exit__' in decorators: f.name.native = '__exit__@' # A hack to flag a ctx mgr. decorators.remove('__exit__') elif f.name.native == '__exit__': - if (len(f.params) != 3 + if ( + len(f.params) != 3 or len(f.returns) > 1 - or any(p.type.lang_type != 'object' for p in f.params)): - raise NameError('Use @__exit__ decorator for %s instead of rename' - % f.name.cpp_name) + or any(p.type.lang_type != 'object' for p in f.params) + ): + raise NameError( + 'Use @__exit__ decorator for %s instead of rename' % f.name.cpp_name + ) elif f.name.native in _IGNORE_RETURN_VALUE: f.ignore_return_value = True if f.name.native in _INPLACE_OPS: @@ -827,9 +913,14 @@ def _func(self, ln, ast, pb, ns=None): raise NameError('Should import name "%s" before use.' % name) name = f.name.native.rstrip('@#') if decorators: - raise ValueError('Unknown decorator%s for def %s: %s' - % ('s' if len(decorators) > 1 else '', - name, ', '.join('@'+f for f in decorators))) + raise ValueError( + 'Unknown decorator%s for def %s: %s' + % ( + 's' if len(decorators) > 1 else '', + name, + ', '.join('@' + f for f in decorators), + ) + ) if ast.docstring: f.docstring = ast.docstring[0][2] return name @@ -841,10 +932,12 @@ def set_type(self, pb, ast, has_object=lambda x: None): assert isinstance(pb, ast_pb2.Type), repr(pb) if ast.callable: self.set_func(pb.callable, ast.callable) - inputs = (a.name.native+':'+a.type.lang_type for a in pb.callable.params) + inputs = ( + a.name.native + ':' + a.type.lang_type for a in pb.callable.params + ) inputs = '(%s)' % ', '.join(inputs) if len(pb.callable.returns) > 1: - outputs = (':'+r.type.lang_type for r in pb.callable.returns) + outputs = (':' + r.type.lang_type for r in pb.callable.returns) outputs = '(%s)' % ', '.join(outputs) elif pb.callable.returns: outputs = pb.callable.returns[0].type.lang_type or 'None' @@ -860,12 +953,14 @@ def set_type(self, pb, ast, has_object=lambda x: None): if ast.named: self.set_typename(pb, ast.named) if len(ast.named) > 1: - pb.lang_type += '<%s>' % ', '.join(self.set_type( - pb.params.add(), t, has_object) for t in ast.named[1:]) + pb.lang_type += '<%s>' % ', '.join( + self.set_type(pb.params.add(), t, has_object) for t in ast.named[1:] + ) if len(ast.named.name) > 1: # Has an explicit C++ type. pb.cpp_type = ast.named.name[0] assert pb.lang_type, 'Parameter AST is not "named" or "callable":\n%r' % ast - if pb.lang_type == 'object': has_object(True) + if pb.lang_type == 'object': + has_object(True) return pb.lang_type def set_typename(self, pb, ast): @@ -876,8 +971,10 @@ def set_typename(self, pb, ast): assert self._macro_values pytype = self._macro_values[int(pytype[1:])] if not self.is_pyname_known(pytype): - raise NameError('Type %s should be defined before use. Did you forget to' - ' import a CLIF-generated C++ header?' % pytype) + raise NameError( + 'Type %s should be defined before use. Did you forget to' + ' import a CLIF-generated C++ header?' % pytype + ) pb.lang_type = pytype if len(ast.name) > 1: # Has an explicit C++ type. pb.cpp_type = ast.name[0] @@ -891,8 +988,9 @@ def set_typename(self, pb, ast): alias_ir = self._typenames.get(pytype) if alias_ir: pytype = alias_ir.name[-1] - assert self._typetable.has_type(pytype), ('alias %s not in typetable' - % pytype) + assert self._typetable.has_type(pytype), ( + 'alias %s not in typetable' % pytype + ) ctype = self._typetable.get_last_cpp_type(pytype) assert ctype, 'C++ type for %s not found' % pytype pb.cpp_type = ctype @@ -914,8 +1012,10 @@ def set_func(self, pb, ast): p.default_value = arg[2] must_be_optional = True elif must_be_optional: - raise ValueError('Arg "%s" (and all after) must be optional because ' - 'arg(s) before it marked optional.') + raise ValueError( + 'Arg "%s" (and all after) must be optional because ' + 'arg(s) before it marked optional.' + ) for t in ast.returns: p = pb.returns.add() self.set_type(p.type, t, lambda x, f=pb: _set_keep_gil(f, x)) @@ -952,6 +1052,7 @@ def scope(self, pyname): Args: pyname: str, Python type name; see `push_scope()` + Yields: None """ @@ -988,12 +1089,12 @@ def set_type(self, pyname, cpp_name): definitions in a Clif file. Args: - pyname: str, the Python name of the type. It will be added to the - current scope. A dotted name is not allowed: the name should - be the base name for the type in the current scope. + pyname: str, the Python name of the type. It will be added to the current + scope. A dotted name is not allowed: the name should be the base name + for the type in the current scope. cpp_name: str, the C++ type name, relative to the current scope, or an - absolute type name. This _may_ begin with a namespace (MyNs::MyCls), - but shouldn't include sub-types (MyType::MySubType). + absolute type name. This _may_ begin with a namespace (MyNs::MyCls), but + shouldn't include sub-types (MyType::MySubType). """ assert not isinstance(cpp_name, list) assert '.' not in pyname @@ -1011,14 +1112,14 @@ def add_type(self, priority, pyname, cpp_name): Args: priority: int, 2 for prepend, any other value for append. - pyname: str, the Python name for the type. It can be a dotted name, - e.g., 'Foo.Bar'. If intermediate types don't exist, empty scopes - will be created. + pyname: str, the Python name for the type. It can be a dotted name, e.g., + 'Foo.Bar'. If intermediate types don't exist, empty scopes will be + created. cpp_name: str, the C++ name for the type. If a dotted `pyname` is used, - then `cpp_name` should reflect the properly qualified C++ name - for `pyname` relative to the current scope. e.g., if - pyname=Foo.Bar, then `cpp_name` should likely be 'Foo::Bar'. An absolute - C++ name can also be used instead (e.g. ::Foo::Bar). + then `cpp_name` should reflect the properly qualified C++ name for + `pyname` relative to the current scope. e.g., if pyname=Foo.Bar, then + `cpp_name` should likely be 'Foo::Bar'. An absolute C++ name can also be + used instead (e.g. ::Foo::Bar). """ assert not isinstance(cpp_name, list) if '.' in pyname: @@ -1080,7 +1181,8 @@ def get_last_cpp_type(self, pyname): # names that are malformed, usually by joining two empty names or # a relative and absolute name. This helps catch that simple case. assert ':::' not in full_cpp_type, 'Malformed C++ typename: {}'.format( - full_cpp_type) + full_cpp_type + ) return full_cpp_type def _find_entry(self, pyname): @@ -1146,7 +1248,8 @@ def __repr__(self): # The type table can be pretty big, so format it in a nice way so that # its intelligible. types = '\n'.join( - '{:<20} -> {}'.format(*entry) for entry in sorted(self.iter_types())) + '{:<20} -> {}'.format(*entry) for entry in sorted(self.iter_types()) + ) return '_TypeTable(types=\n{types}\n)'.format(types=types) @@ -1164,14 +1267,14 @@ def __init__(self, pyname=None, cpp_name=None, parent=None): for creating instances to ensure correct creation. Args: - pyname: Optional[str], name of the Python type. Optional for - the root-level _TypeEntry, otherwise required. - cpp_name: Optiona[str], name of the corresponding C++ type, - if any. Additional names may be added later. Root instances - and "namespace" instances (i.e., names created through an - aliased import) won't have a C++ type. - parent: Optional[_TypeEntry], the outer scope for this entry. - Root level entries don't have it, all others do. + pyname: Optional[str], name of the Python type. Optional for the + root-level _TypeEntry, otherwise required. + cpp_name: Optiona[str], name of the corresponding C++ type, if any. + Additional names may be added later. Root instances and "namespace" + instances (i.e., names created through an aliased import) won't have a + C++ type. + parent: Optional[_TypeEntry], the outer scope for this entry. Root level + entries don't have it, all others do. """ # Optional[str] self._pyname = pyname @@ -1196,9 +1299,9 @@ def _create_child_entry(self, pyname, cpp_name): Args: pyname: str, the Python type name, required. - cpp_name: Optional[str], C++ type name; it may be omitted if - the child entry is just a "namespace" for containing other types, - e.g., as part of an aliased import. + cpp_name: Optional[str], C++ type name; it may be omitted if the child + entry is just a "namespace" for containing other types, e.g., as part of + an aliased import. Returns: _TypeEntry @@ -1235,13 +1338,13 @@ def set_nested_type(self, pyname, cpp_name): there should only be a single C++ type. Args: - pyname: str, the Python name for the type. No dots allowed. If - the name already exists, then `cpp_name` must match the pre-existing - entry. + pyname: str, the Python name for the type. No dots allowed. If the name + already exists, then `cpp_name` must match the pre-existing entry. cpp_name: str, the C++ type name. """ - assert '.' not in pyname, ('pyname {!r} cannot contain dots: you probably ' - 'meant to use _TypeTable').format(pyname) + assert '.' not in pyname, ( + 'pyname {!r} cannot contain dots: you probably meant to use _TypeTable' + ).format(pyname) try: existing = self._types[pyname] except KeyError: @@ -1252,8 +1355,9 @@ def set_nested_type(self, pyname, cpp_name): existing_cpp_names = existing._cpp_names # pylint: disable=protected-access if existing_cpp_names != desired_cpp_names: raise ValueError( - 'Python type {!r}: existing C++ types {!r} don\'t match desired ' - 'types {!r}'.format(pyname, existing_cpp_names, desired_cpp_names)) + "Python type {!r}: existing C++ types {!r} don't match desired " + 'types {!r}'.format(pyname, existing_cpp_names, desired_cpp_names) + ) def add_nested_type(self, priority, pyname, cpp_name): """Append a C++ type to a Python type. @@ -1270,8 +1374,9 @@ def add_nested_type(self, priority, pyname, cpp_name): cpp_name: str, the C++ type name. """ assert pyname, 'Non-empty pyname required' - assert '.' not in pyname, ('pyname {!r} cannot contain dots: you probably ' - 'meant to use _TypeTable').format(pyname) + assert '.' not in pyname, ( + 'pyname {!r} cannot contain dots: you probably meant to use _TypeTable' + ).format(pyname) assert cpp_name, 'Non-empty cpp_name required' try: existing = self._types[pyname] @@ -1284,8 +1389,9 @@ def add_nested_type(self, priority, pyname, cpp_name): def add_empty_nested_type(self, pyname): """Create an empty nested type, e.g., to act as a namespace.""" assert pyname, 'Non-empty pyname required' - assert '.' not in pyname, ('pyname {!r} cannot contain dots: you probably ' - 'meant to use _TypeTable').format(pyname) + assert '.' not in pyname, ( + 'pyname {!r} cannot contain dots: you probably meant to use _TypeTable' + ).format(pyname) try: existing = self._types[pyname] except KeyError: @@ -1298,16 +1404,17 @@ def add_empty_nested_type(self, pyname): def has_nested_type(self, pyname): """Tell if the Python type is present.""" assert pyname, 'Non-empty pyname required' - assert '.' not in pyname, ('pyname {!r} cannot contain dots: you probably ' - 'meant to use _TypeTable').format(pyname) + assert '.' not in pyname, ( + 'pyname {!r} cannot contain dots: you probably meant to use _TypeTable' + ).format(pyname) return pyname in self._types def get_nested_type(self, pyname): """Get the type entry for the Python name. Args: - pyname: str, the Python name, no dots allowed. For dotted-name - lookup, use the _TypeTable APIs. + pyname: str, the Python name, no dots allowed. For dotted-name lookup, use + the _TypeTable APIs. Returns: _TypeEntry of the nested type. @@ -1316,8 +1423,9 @@ def get_nested_type(self, pyname): _TypeNotFoundError: if the nested type isn't found. """ assert pyname, 'Non-empty pyname required' - assert '.' not in pyname, ('pyname {!r} cannot contain dots: you probably ' - 'meant to use _TypeTable').format(pyname) + assert '.' not in pyname, ( + 'pyname {!r} cannot contain dots: you probably meant to use _TypeTable' + ).format(pyname) try: child = self._types[pyname] except KeyError: @@ -1356,9 +1464,12 @@ def _build_cpp_type(self, parent_prefix, child_cpp_type): def __repr__(self): return ( '_TypeEntry(pyname={pyname!r}, cpp_types={ctypes!r}, ' - 'nested_types={nested_names}').format( - pyname=self._pyname, ctypes=self._cpp_names, - nested_names=sorted(self._types.keys())) + 'nested_types={nested_names}' + ).format( + pyname=self._pyname, + ctypes=self._cpp_names, + nested_names=sorted(self._types.keys()), + ) class _TypeNotFoundError(Exception): @@ -1379,11 +1490,9 @@ def _set_bases(pb, ast_bases, names, typetable): base.native = n -def _set_name(pb, - ast, - namespace=None, - allow_fqcppname=False, - template_name=None): +def _set_name( + pb, ast, namespace=None, allow_fqcppname=False, template_name=None +): """Fill AST Name protobuf from PYTD IR ast. Args: @@ -1415,11 +1524,12 @@ def _set_keep_gil(f, val): def _add_uniq(class_name, names_set, new_name): - assert new_name, class_name+' has %s' % names_set + assert new_name, class_name + ' has %s' % names_set if new_name: if new_name in names_set: - raise NameError('Name "%s" already defined in class %s' - % (new_name, class_name)) + raise NameError( + 'Name "%s" already defined in class %s' % (new_name, class_name) + ) names_set.add(new_name) @@ -1439,7 +1549,9 @@ def _subst_type_formal(ast, from_map): p = n[-1] if p in from_map: if len(n) > 1: # Has an explicit C++ type. - raise NameError('C++ name not allowed in interface parameters (%s)'%p) + raise NameError( + 'C++ name not allowed in interface parameters (%s)' % p + ) n[-1] = '%' + str(from_map[p]) @@ -1462,12 +1574,15 @@ def _subst_type_formal(ast, from_map): '__ior__', ]) # Special methods that don't use returning C++ value, so we can ignore it. -_IGNORE_RETURN_VALUE = frozenset([ - '__setitem__', - '__delitem__', - '__setattr__', - '__delattr__', -] + list(_INPLACE_OPS)) +_IGNORE_RETURN_VALUE = frozenset( + [ + '__setitem__', + '__delitem__', + '__setattr__', + '__delattr__', + ] + + list(_INPLACE_OPS) +) # Python special method name -> C++ operator rename table. _SPECIAL = { @@ -1545,8 +1660,9 @@ def _subst_type_formal(ast, from_map): '__ror__', '__rxor__', ]) -assert _RIGHT_OPS - set(_SPECIAL), frozenset('__r%s__' % op for op in ( - 'divmod pow'.split(' '))) +assert _RIGHT_OPS - set(_SPECIAL), frozenset( + '__r%s__' % op for op in ('divmod pow'.split(' ')) +) def _fix_special_names(ast_name):