def __call__(self, wrapper, name, restype, argtypes, varargs): cls = wrapper.get_pyclass(self.clsname) methname = name methname = self._strip_prefix(methname) meth = cls.new_method(methname) meth.decorators.append('classmethod') args = [] for idx, param in enumerate(argtypes, varargs): argname = 'arg%d' % idx meth.arguments.append('arg%d' % idx) if wrapper.get_wrapper(str(param)): args.append('%s._internal' % argname) else: args.append(argname) if varargs: meth.arguments.append('*varargs') args.append('*varargs') t = template( '$funcname($args)', funcname=name, args=', '.join(args)) t = template("$cls._from_internal($t)", cls=self.clsname, t=t) t = template('return $t', t=t) meth.code.append(t) return True
def __call__(self, wrapper, name, restype, argtypes, varargs): cls = wrapper.get_pyclass(self.clsname) methname = name methname = self._strip_prefix(methname) meth = cls.new_method(methname) args = [] for idx, param in enumerate(argtypes): if idx == self.self_arg: if not str(param) == cls.tag: print '`self` argument tags not matching in %s: parameter: %s / class: %s' % (name, str(param), cls.tag) args.append('self._internal') continue argname = 'arg%d' % idx meth.arguments.append('arg%d' % idx) if wrapper.get_wrapper(str(param)): args.append('%s._internal' % argname) else: args.append(argname) if varargs: meth.arguments.append('*varargs') args.append('*varargs') t = template( '$funcname($args)', funcname=name, args=', '.join(args)) if wrapper.get_wrapper(str(restype)): t = template("$cls._from_internal($t)", cls=wrapper.get_wrapper(str(restype)).name, t=t) t = template('return $t', t=t) meth.code.append(t) return True
def make_lazy_atom_xizer(name, conn='self.conn'): code = [] code.append(template("if isinstance($name, basestring):", name=name)) code.append(INDENT) code.append(template("$name = $conn.atoms[$name]", conn=conn, name=name)) code.append(DEDENT) return lambda code=code: code
def make_rectangles_xizer(list_in='rectangles', list_out='rectangles', length_out='rectangles_length'): code = [] code.append(template("$list_out = []", list_out=list_out)) code.append(template("for rect in $list_in:", list_in=list_in)) code.append(INDENT) code.append(template("$list_out.extend([rect.x, rect.y, rect.width, rect.height])", list_out=list_out)) code.append(DEDENT) code.append(template("$length_out = len($list_in)", length_out=length_out, list_in=list_in)) return lambda code=code: code
def make_string_xizer(seq_in='value', seq_out='value', length_out='value_len'): code = [] code.append(template('if isinstance($seq_in, unicode):', seq_in=seq_in)) code.extend([ INDENT, template('$seq_in = $seq_in.encode("utf-8")', seq_in=seq_in), DEDENT ]) code.append(template('$length_out = len($seq_in)', length_out=length_out, seq_in=seq_in)) code.append(template('$seq_out = map(ord, $seq_in)', seq_out=seq_out, seq_in=seq_in)) return lambda code=code: code
def make_utf16_xizer(seq_in='value', seq_out='value', length_out='value_len'): code = [] code.append(template('if not isinstance($seq_in, unicode):', seq_in=seq_in)) code.extend([ INDENT, template('raise XcbException("`$seq_in` has to be an unicode string")', seq_in=seq_in), DEDENT ]) code.append(template('$seq_out = $seq_in.encode("utf-16be")', seq_out=seq_out, seq_in=seq_in)) code.append(template('$length_out = len($seq_out) / 2 # should work', length_out=length_out, seq_out=seq_out)) return lambda code=code: code
def make_mask_xizer(iterable_in, enum_name, mask_out): code = [] enum = ALL[enum_name] code.append(template("$mask_out = 0", mask_out=mask_out)) for member in enum.members: if not isinstance(member, PyAttribute): continue key = pythonize_camelcase_name(member.name) value = member.value code.extend([ template('if "${key}" in ${iterable_in}:', key=key, iterable_in=iterable_in), INDENT, template('$mask_out |= $value', mask_out=mask_out, value=value), DEDENT]) return lambda code=code: code
def make_values_xizer(enum_name, values_dict_name, mask_out='value_mask', list_out='value_list', xize=()): """ make a simple values xizer code list and return it. A values xizer takes all values from the values dict and stores it in a values list and a values mask. """ enum = ALL[enum_name] code = [] pyvalues = [] code.append(template("$mask_out, $list_out = 0, []", mask_out=mask_out, list_out=list_out )) for member in enum.members:#key, value in enum.values: if not isinstance(member, PyAttribute): continue key = pythonize_camelcase_name(member.name) value = member.value code.append(template('if "${key}" in ${values_dict_name}:', key=key, values_dict_name=values_dict_name)) code.append(INDENT) code.append(template('$mask_out |= $value', mask_out=mask_out, value=value )) s = template('$values_dict_name["$key"]', values_dict_name=values_dict_name, key=key, ) if key in xize: s = 'get_internal(%s)' % s code.append(template('$list_out.append($s)', list_out=list_out, s=s )) code.append(DEDENT) return lambda code=code: code
def _add_fields(fields): read_code.append('_unpacked = unpack_from_stream("=%s", stream)' % fmt) build_fields = [] for idx, field in enumerate(fields): # try if we can get a modifier modifier = get_modifier(field) value = modifier % ('_unpacked[%d]' % idx) read_code.append(template('self.$fieldname = $value', fieldname=prefix_if_needed(field.field_name), value=value )) if modifier != '%s': build_fields.append('get_internal(self.%s)' % prefix_if_needed(field.field_name)) else: build_fields.append('self.%s' % prefix_if_needed(field.field_name)) cls.add_instance_attribute(prefix_if_needed(field.field_name), '') # TODO: description build_code.append('stream.write(pack("=%s", %s))' % (fmt, ', '.join(build_fields)))
def py_complex(self, name, cls): m_init = cls.get_member_by_name('__init__') init_code = m_init.code m_read = cls.new_method('read') m_read.arguments.append('stream') read_code = m_read.code m_build = cls.new_method('build') m_build.arguments.append('stream') build_code = m_build.code def _add_fields(fields): read_code.append('_unpacked = unpack_from_stream("=%s", stream)' % fmt) build_fields = [] for idx, field in enumerate(fields): # try if we can get a modifier modifier = get_modifier(field) value = modifier % ('_unpacked[%d]' % idx) read_code.append(template('self.$fieldname = $value', fieldname=prefix_if_needed(field.field_name), value=value )) if modifier != '%s': build_fields.append('get_internal(self.%s)' % prefix_if_needed(field.field_name)) else: build_fields.append('self.%s' % prefix_if_needed(field.field_name)) cls.add_instance_attribute(prefix_if_needed(field.field_name), '') # TODO: description build_code.append('stream.write(pack("=%s", %s))' % (fmt, ', '.join(build_fields))) need_alignment = False # because of that address storing, we'll only be able to read # from a MemStream. That's sad. But the address of the struct # seems to be needed by some replys, e.g. GetKeyboardMappingReply, # to access `self.length`. read_code.extend(['self._address = stream.address', 'root = stream.tell()']) # Here we store the index of the `root = stream.tell()` line to be able # to remove obsolete calls later. needs_root = False build_code.append('count = 0') # prework to pad to the correct size if cls.base == 'ooxcb.Event': build_code.append('root = stream.tell()') struct = Struct() for field in self.fields: # This hack is ugly, but it seems to be required for valid send_event stuff. # Normally, `response_type` is set automatically, but it isn't if the # event is part of a send_event request. We have to set it explicitly then # to avoid `BadValue` errors. I hope that doesn't have any side effects. if (field.field_name == 'response_type' and isinstance(self, xcbgen.xtypes.Event)): init_code.append('self.response_type = %s' % self.opcodes[name]) struct.push_format(field) continue if field.auto: struct.push_pad(field.type.size) continue if field.type.is_simple: struct.push_format(field) # add a simple default value (needs to be changed by the user, of course) init_code.append('self.%s = None' % (prefix_if_needed(field.field_name))) cls.add_instance_attribute(prefix_if_needed(field.field_name), '') # TODO: description continue if field.type.is_pad: struct.push_pad(field.type.nmemb) continue fields, size, fmt = struct.flush() if fields: _add_fields(fields) if size > 0: if not fields: # if no fields got added, the pad would get lost. add it manually then. read_code.append(template('stream.seek($size, 1)', size=size)) build_code.append(template('count += $size', size=size)) if need_alignment: read_code.append('stream.seek(ooxcb.type_pad(%d, stream.tell() - root), 1)' % align_size(field)) needs_root = True # need to add pad for `build`? # build_code.append(r'stream.write("\0" * ooxcb.type_pad(%d, count)' % align_size(field)) need_alignment = True if field.type.is_list: if field.type.member.py_type == 'void': # It is a void list. The problem about void lists is: # we don't exactly know if it's 8, 16 or 32 bit per item. # Fortunately, there seems to be an complex type # attribute called `self.format` present which has the # value 8, 16 or 32. So, we'll use this value # to get the type of the list members. # That should work for the GetPropertyReply in xproto, # but it might not work for other stuff. TODO? It's not nice. # # If `self.format` is 0 (happens for GetPropertyReply # if we try to access a non-existent property), # we use "B" (which is an unsigned byte) as a fallback. lread_code = ('ooxcb.List(self.conn, stream, %s, SIZES.get(self.format, "B"), self.format // 8)' % \ (get_expr(field.type.expr))) else: lread_code = ('ooxcb.List(self.conn, stream, %s, %s, %d)' % \ (get_expr(field.type.expr), field.py_listtype, field.py_listsize)) if field.py_type == 'char': # convert a list of chars to strings lread_code = '%s.to_string()' % lread_code elif field.py_type in INTERFACE.get('ResourceClasses', []): # is a resource. wrap them. lread_code = '[%s for w in %s]' % (get_modifier(field) % 'w', lread_code) elif field.py_type == 'ATOM': # TODO: hey, to have this hardcoded is not cool! lread_code = 'map(self.conn.atoms.get_by_id, %s)' % lread_code read_code.append('self.%s = %s' % (prefix_if_needed(field.field_name), lread_code)) cls.add_instance_attribute(prefix_if_needed(field.field_name), '') # TODO: description # TODO: add the lazy length property setter ... # e.g. `self.cmaps_length` is set to `len(self.colormaps)`. # The problem is: the field type expr isn't always a simple # expression, it also can be "(self.keycodes_per_modifier * 5)" - # how should we solve that? build_code.append('build_list(self.conn, stream, self.%s, %s)' % ( prefix_if_needed(field.field_name), field.py_listtype)) init_code.append('self.%s = []' % (prefix_if_needed(field.field_name))) elif field.type.is_container and field.type.fixed_size(): read_code.append('self.%s = %s.create_from_stream(self.conn, stream)' % (prefix_if_needed(field.field_name), get_wrapped(field.py_type))) cls.add_instance_attribute(prefix_if_needed(field.field_name), '') # TODO: description build_code.append('self.%s.build(stream)' % prefix_if_needed(field.field_name)) init_code.append('self.%s = None' % (prefix_if_needed(field.field_name))) else: read_code.append('self.%s = %s.create_from_stream(self.conn, stream)' % (prefix_if_needed(field.field_name), get_wrapped(field.py_type))) cls.add_instance_attribute(prefix_if_needed(field.field_name), '') # TODO: description build_code.append('self.%s.build(stream)' % prefix_if_needed(field.field_name)) init_code.append('self.%s = None' % (prefix_if_needed(field.field_name))) fields, size, fmt = struct.flush() if fields: if need_alignment: read_code.append('stream.seek(ooxcb.type_pad(4, stream.tell() - root), 1)') needs_root = True _add_fields(fields) if (not self.fixed_size() and cls.base == 'ooxcb.Struct'): # only do that for variable-length structs. # However, the check above is very nasty. needs_root = True # Events have a fixed size of 32 bytes. Here we pad them to the correct size # in the build code.TODO: this solution is nasty, but at least it works. if cls.base == 'ooxcb.Event': build_code.append(r'stream.write("\0" * (32 - (stream.tell() - root)))') if not needs_root: read_code.remove('root = stream.tell()')
def make_seq_xizer(seq_in='value', seq_out='value', length_out='value_len'): code = [] code.append(template('$length_out = len($seq_in)', length_out=length_out, seq_in=seq_in)) if seq_in != seq_out: code.append(template('$seq_out = $seq_in', seq_out=seq_out, seq_in=seq_in)) return lambda code=code: code