Exemple #1
0
    def _emit_key_maybe(self, m):
        ann = m.has_annotation(self, annotate.key)
        if ann is None:
            return
        assert ann.annotation.value.is_text()
        allfields = [ensure_unicode(f.name) for f in self.struct.fields]
        # we expect keyfields to be something like "x, y, z" or "*"
        txt = ensure_unicode(ann.annotation.value.text.strip())
        if txt == '*':
            fieldnames = allfields
        else:
            fieldnames = [fn.strip() for fn in txt.split(',')]

        #
        # sanity check
        for f in fieldnames:
            if f not in allfields:
                raise ValueError(
                    "Error in $Py.key: the field '%s' does not exist" % f)
        #
        ns = m.code.new_scope()
        ns.key = ', '.join(
            ['self.%s' % m._convert_name(f) for f in fieldnames])
        ns.w()
        ns.ww(
            """
            def _key(self):
                return ({key},)
        """
        )  # the trailing comma is to ensure a tuple even if there is a single field
        #
        if m.pyx:
            self._emit_fash_hash(m, fieldnames)
Exemple #2
0
 def _declare_imports(self, m):
     for imp in self.imports:
         ns = m.code.new_scope()
         try:
             filenode = m.allnodes[imp.id]
         except KeyError:
             # this means that the file was imported but not used
             # anywhere. Simply ignore it
             continue
         fname = ensure_unicode(filenode.displayName)
         ns.importname = m.register_import(fname)
         ns.fullpath = ensure_unicode(imp.name)
         if ns.fullpath == '/capnp/c++.capnp':
             # ignore this file as it's useless for python
             continue
         elif m.standalone:
             assert ns.fullpath.endswith('.capnp')
             ns.modname = ns.fullpath[:-6].replace('/', '.')
             if ns.modname.startswith('/'):
                 ns.modname = ns.modname[1:]
             ns.w('import {modname} as {importname}')
         else:
             ns.pyx = m.pyx
             ns.w(
                 '{importname} = __compiler.load_schema(importname="{fullpath}", pyx={pyx})'
             )
Exemple #3
0
 def _emit_fash_hash(self, m, fieldnames):
     # emit a specialized, fast __hash__.
     fields = dict([(ensure_unicode(f.name), f)
                    for f in self.struct.fields])
     m.w()
     with m.code.block('def __hash__(self):') as ns:
         ns.n = len(fieldnames)
         ns.w('cdef long h[{n}]')
         # compute the hash of each field
         for ns.i, fname in enumerate(fieldnames):
             f = fields[fname]
             ns.fname = m._convert_name(fname)
             if f.is_text():
                 ns.offset = f.slot.offset * f.slot.get_size()
                 ns.w('h[{i}] = self._hash_str_text({offset})')
             else:
                 ns.hash = self._fasthash_for_field(f)
                 ns.w('h[{i}] = {hash}(self.{fname})')
         #
         # compute the hash of the whole tuple
         ns.w('return _hash.tuplehash(h, {n})')
     #
     # XXX this is a hack/workaround for what it looks like a Cython bug:
     # apparently, we need to redefine __richcmp__ together with __hash__,
     # else the base one is not going to be called.  Moreover, for no good
     # reason "self" is typed as PyObject* instead of being given the
     # precise type, so we cast to Struct_ to force early binding
     ns.w()
     ns.ww("""
         def __richcmp__(self, other, op):
             return (<_Struct>self)._richcmp(other, op)
     """)
Exemple #4
0
    def emit_declaration(self, m):
        children = m.children[self.id]
        for child in children:
            child.emit_declaration(m)
        #
        # find and register all groups having a $key annotation. We need to do
        # it here because we need this info when we emit the definition for
        # the group class
        for field in self.struct.fields or []:
            ann = m.has_annotation(field, annotate.key)
            if ann:
                if field.is_void():
                    # Register the fake node_group.
                    field = m.field_override[field]
                assert field.is_group()
                group_node = m.allnodes[field.group.typeId]
                m.register_extra_annotation(group_node, ann)

        ns = m.code.new_scope()
        ns.name = ensure_unicode(self.compile_name(m))
        ns.dotname = self.runtime_name(m)
        if m.pyx:
            ns.w("cdef class {name}(_Struct)")
        else:
            ns.w("class {name}(_Struct): pass")
            ns.w("{name}.__name__ = '{dotname}'")
        #
        self._emit_union_tag_declaration(m)
        ns.w()
Exemple #5
0
 def _exec(self, *cmd):
     #print ' '.join(cmd)
     proc = subprocess.Popen(cmd,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
     stdout, stderr = proc.communicate()
     ret = proc.wait()
     if ret != 0:
         raise CompilerError(ensure_unicode(stderr))
     return stdout
Exemple #6
0
 def decode(self, obj):
     from capnpy.message import dumps
     from subprocess import Popen, PIPE
     cmd = ['capnp', 'decode', '--short', self.mod.__schema__, obj.__class__.__name__]
     proc = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE)
     proc.stdin.write(dumps(obj))
     stdout, stderr = proc.communicate()
     ret = proc.wait()
     if ret != 0:
         raise ValueError(stderr)
     return ensure_unicode(stdout.strip())
Exemple #7
0
    def from_group_annotation(cls, m, parent_id, field_void, annotation):
        """
        `parent_id` is the id of the struct that contains the field which is annotated by `Py.group`.
        """
        parent = m.allnodes[parent_id]
        annotation_text = ensure_unicode(annotation.value.text.strip())
        # we expect arguments to be something like "x, y, z"
        group_field_names = [fn.strip() for fn in annotation_text.split(',')]
        all_fields = {ensure_unicode(f.name): f for f in parent.struct.fields}
        fields = [all_fields[f] for f in group_field_names]

        # Make sure it is bytes.
        displayName = parent.displayName + b'.' + field_void.name
        displayNamePrefixLength = len(parent.displayName) + 1
        scopeId = parent_id

        node_id = parent_id + hash(field_void.name) % 10000
        # Need a better way to get a UID.
        # Todo: Use proper md5
        assert node_id not in m.allnodes

        # There shouldn't be any unions inside the group.
        # So do not have to deal with discriminantCount
        struct = cls.Struct(
            dataWordCount=parent.struct.dataWordCount,
            pointerCount=parent.struct.pointerCount,
            # Not sure if this is correct.
            preferredListEncoding=parent.struct.preferredListEncoding,
            isGroup=True,
            fields=fields,
        )

        ret = cls(
            id=node_id,
            displayName=displayName,
            displayNamePrefixLength=displayNamePrefixLength,
            scopeId=scopeId,
            struct=struct,
        )
        return ret
Exemple #8
0
 def _capnp_check_version(self):
     version = self._exec('capnp', '--version')
     if PY3:
         version = ensure_unicode(version)
     version = version.strip()
     if not version.startswith("Cap'n Proto version"):
         raise CompilerError("capnp version string not recognized: %s" %
                             version)
     _, version = version.rsplit(' ', 1)
     if version < LooseVersion('0.5.0'):
         raise CompilerError(
             "The capnp executable is too old: the minimum required "
             "version is 0.5.0")
Exemple #9
0
 def _convert_name(self, name):
     name = ensure_unicode(name) if PY3 else name
     if self.convert_case:
         return from_camel_case(name)
     else:
         return name
Exemple #10
0
 def compile_name(self, m, prefix=''):
     if self.is_imported(m):
         return ensure_unicode(self.runtime_name(m, sep='.' + prefix))
     return ensure_unicode(prefix + self._fullname(m, '_'))
Exemple #11
0
 def shortname(self, m):
     name = self.displayName[self.displayNamePrefixLength:]
     if self.is_file():
         filename = ensure_unicode(self.displayName)
         return ensure_unicode(m.importnames[filename])
     return ensure_unicode(name)
Exemple #12
0
 def emit(self, m):
     m.modname = py.path.local(ensure_unicode(self.filename)).purebasename
     if not PY3:
         m.modname = m.modname.encode('utf-8')
     m.tmpname = '%s_tmp' % m.modname
     m.code.global_scope.extname = '%s_extended' % m.modname
     #
     # some lines need to be different when in pyx mode: here we define
     # some global kwarg which are "turned off" when in pure python mode
     if m.pyx:
         # pyx mode
         m.code.global_scope.cimport = 'cimport'
         m.code.global_scope.cpdef = 'cpdef'
         m.code.global_scope.__dict__['cdef class'] = 'cdef class'
     else:
         m.code.global_scope.cimport = 'import'
         m.code.global_scope.cpdef = 'def'
         m.code.global_scope.__dict__['cdef class'] = 'class'
     #
     filenode = m.allnodes[self.id]
     assert filenode.is_file()
     m.current_scope = filenode
     m.w("# THIS FILE HAS BEEN GENERATED AUTOMATICALLY BY capnpy")
     m.w("# do not edit by hand")
     m.w("# generated on %s" % datetime.now().strftime("%Y-%m-%d %H:%M"))
     m.w("")
     m.w("from capnpy {cimport} ptr as _ptr")
     m.w("from capnpy.struct_ {cimport} Struct as _Struct")
     m.w("from capnpy.struct_ {cimport} check_tag as _check_tag")
     m.w("from capnpy.struct_ import undefined as _undefined")
     m.w("from capnpy.enum import enum as _enum, fill_enum as _fill_enum")
     m.w("from capnpy.enum {cimport} BaseEnum as _BaseEnum")
     m.w("from capnpy.type import Types as _Types")
     m.w("from capnpy.segment.builder {cimport} SegmentBuilder as _SegmentBuilder"
         )
     m.w("from capnpy.list {cimport} List as _List")
     m.w("from capnpy.list {cimport} PrimitiveItemType as _PrimitiveItemType"
         )
     m.w("from capnpy.list {cimport} BoolItemType as _BoolItemType")
     m.w("from capnpy.list {cimport} TextItemType as _TextItemType")
     m.w("from capnpy.list {cimport} StructItemType as _StructItemType")
     m.w("from capnpy.list {cimport} EnumItemType as _EnumItemType")
     m.w("from capnpy.list {cimport} VoidItemType as _VoidItemType")
     m.w("from capnpy.list {cimport} ListItemType as _ListItemType")
     m.w("from capnpy.util import text_repr as _text_repr")
     m.w("from capnpy.util import float32_repr as _float32_repr")
     m.w("from capnpy.util import float64_repr as _float64_repr")
     m.w("from capnpy.util import extend_module_maybe as _extend_module_maybe"
         )
     m.w("from capnpy.util import check_version as _check_version")
     #
     if m.pyx:
         m.w("from capnpy cimport _hash")
         for t in Types.__all__:
             name = '%s_list_item_type' % t.name
             m.w("from capnpy.list {cimport} {name} as _{name}", name=name)
     if m.pyx and not m.standalone:
         # load the compiler from the outside. See the comment in
         # _compile_pyx for a detailed explanation
         m.w('from %s import __compiler, __schema__' % m.tmpname)
     #
     m.w('__capnpy_version__ = {version!r}', version=capnpy.__version__)
     if m.version_check:
         m.w('_check_version(__capnpy_version__)')
     else:
         m.w('# schema compiled with --no-version-check, skipping the call to _check_version'
             )
     self._declare_imports(m)
     m.w("")
     #
     # visit the children in two passes: first the declaration, then the
     # definition
     children = m.children[filenode.id]
     m.w("#### FORWARD DECLARATIONS ####")
     m.w()
     for child in children:
         child.emit_declaration(m)
     m.w()
     m.w("#### DEFINITIONS ####")
     m.w()
     for child in children:
         child.emit_definition(m)
     #
     for child in children:
         child.emit_reference_as_child(m)
     #
     m.w()
     if m.standalone:
         m.w('_extend_module_maybe(globals(), modname=__name__)')
     else:
         m.w('_extend_module_maybe(globals(), filename=__schema__)')
Exemple #13
0
 def test_ensure_unicode(self):
     assert isinstance(ensure_unicode( 'b'), text_type)
     assert isinstance(ensure_unicode(u'b'), text_type)
     assert isinstance(ensure_unicode(b'b'), text_type)