{"id":13500355,"url":"https://github.com/yihuang/cprotobuf","last_synced_at":"2025-04-05T00:10:17.946Z","repository":{"id":18499260,"uuid":"21695348","full_name":"yihuang/cprotobuf","owner":"yihuang","description":"protocol buffer implemented in cython","archived":false,"fork":false,"pushed_at":"2025-03-14T11:35:08.000Z","size":296,"stargazers_count":82,"open_issues_count":7,"forks_count":13,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-28T23:09:19.970Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Cython","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yihuang.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-07-10T13:34:08.000Z","updated_at":"2025-03-14T11:35:13.000Z","dependencies_parsed_at":"2024-06-20T21:57:22.230Z","dependency_job_id":"2262607e-f6ea-4a5f-9101-bcb0362c56ce","html_url":"https://github.com/yihuang/cprotobuf","commit_stats":{"total_commits":140,"total_committers":2,"mean_commits":70.0,"dds":0.0357142857142857,"last_synced_commit":"32283bc02f8e0d2a63fd67e568c2b1e9ce3b9152"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yihuang%2Fcprotobuf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yihuang%2Fcprotobuf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yihuang%2Fcprotobuf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yihuang%2Fcprotobuf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yihuang","download_url":"https://codeload.github.com/yihuang/cprotobuf/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247266565,"owners_count":20910836,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T22:00:57.164Z","updated_at":"2025-04-05T00:10:17.928Z","avatar_url":"https://github.com/yihuang.png","language":"Cython","funding_links":[],"categories":["Cython"],"sub_categories":[],"readme":"A minimal fast protobuf implementation with cython.\nBenchmark shows that it's much faster than google official expremental cpp-python implementation.\n\nI've been using it in production since 2013, only tested with python2.7, feedback on other python release is welcome.\n\nBenchmark\n=========\n\n.. code-block:: bash\n\n  $ ./setup.py build_ext --inplace\n  $ cd benchmark\n  $ ./bench.sh\n  encode[google official pure python]:\n  10 loops, best of 3: 68.8 msec per loop\n  encode[google official cpp python]:\n  100 loops, best of 3: 19.4 msec per loop\n  encode[py-protobuf][cprotobuf]:\n  100 loops, best of 3: 3.58 msec per loop\n  decode[google official pure python]:\n  10 loops, best of 3: 47.5 msec per loop\n  decode[google official cpp python]:\n  100 loops, best of 3: 4.55 msec per loop\n  decode[py-protobuf][cprotobuf]:\n  100 loops, best of 3: 3.98 msec per loop\n\nTutorial\n========\n\nUse plugin\n----------\n\nYou write a ``person.proto`` file like this:\n\n.. code-block:: protobuf\n\n    package foo;\n\n    message Person {\n      required int32 id = 1;\n      required string name = 2;\n      optional string email = 3;\n    }\n\nAnd a ``people.proto`` file like this:\n\n.. code-block:: protobuf\n\n    package foo;\n    import \"person.proto\";\n\n    message People {\n      repeated Person people = 1;\n    }\n\nThen you compile it with provided plugin:\n\n.. code-block:: bash\n\n    $ protoc --cprotobuf_out=. person.proto people.proto\n\nIf you have trouble to run a protobuf plugin like on windows, you can directly run ``protoc-gen-cprotobuf`` like this:\n\n.. code-block:: bash\n\n    $ protoc -ofoo.pb person.proto people.proto\n    $ protoc-gen-cprotobuf foo.pb -d .\n\nThen you get a python module ``foo_pb.py`` , cprotobuf generate a python module for each package rather than each protocol file.\n\nThe generated code is quite readable:\n\n.. code-block:: python\n\n    # coding: utf-8\n    from cprotobuf import ProtoEntity, Field\n    # file: person.proto\n    class Person(ProtoEntity):\n        id              = Field('int32',\t1)\n        name            = Field('string',\t2)\n        email           = Field('string',\t3, required=False)\n\n    # file: people.proto\n    class People(ProtoEntity):\n        people          = Field(Person,\t1, repeated=True)\n\nActually, if you only use python, you can write this python module, avoid code generation.\n\nThe API\n-------\n\nNow, you have this lovely python module, how to parse and serialize messages?\n\nWhen design this package, We try to minimise the effort of migration, so we keep the names of api akin to protocol buffer's.\n\n.. note::\n    \n    Since this is no need to reuse a message instance and call ``Clear`` on it in python, It don't provide ``Clear`` api,\n    so ``ParseFromString`` is more like ``MergeFromString`` in official implementation, because it don't call ``Clear`` at first.\n\nencode/decode\n~~~~~~~~~~~~~\n\n.. code-block:: python\n\n    \u003e\u003e\u003e from foo_pb import Person, People\n    \u003e\u003e\u003e msg = People()\n    \u003e\u003e\u003e msg.people.add(\n    ...    id = 1,\n    ...    name = 'jim',\n    ...    email = 'jim@gmail.com',\n    ... )\n    \u003e\u003e\u003e s = msg.SerializeToString()\n    \u003e\u003e\u003e msg2 = People()\n    \u003e\u003e\u003e msg2.ParseFromString(s)\n    \u003e\u003e\u003e len(msg2)\n    1\n    \u003e\u003e\u003e msg2.people[0].name\n    'jim'\n\nreflection\n~~~~~~~~~~\n\n.. code-block:: python\n\n    \u003e\u003e\u003e from foo_pb import Person, People\n    \u003e\u003e\u003e dir(Person._fields[0])\n    ['__class__', '__delattr__', '__doc__', '__format__', '__get__', '__getattribute__', '__hash__', '__init__', '__new__', '__pyx_vtable__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'index', 'name', 'packed', 'repeated', 'required', 'wire_type']\n    \u003e\u003e\u003e Person._fields[0].name\n    'email'\n    \u003e\u003e\u003e Person._fieldsmap\n    {1: \u003ccprotobuf.Field object at 0xb74a538c\u003e, 2: \u003ccprotobuf.Field object at 0xb74a541c\u003e, 3: \u003ccprotobuf.Field object at 0xb74a5c8c\u003e}\n    \u003e\u003e\u003e Person._fieldsmap_by_name\n    {'email': \u003ccprotobuf.Field object at 0xb74a5c8c\u003e, 'name': \u003ccprotobuf.Field object at 0xb74a541c\u003e, 'id': \u003ccprotobuf.Field object at 0xb74a538c\u003e}\n\nrepeated container\n~~~~~~~~~~~~~~~~~~\n\nWe use ``RepeatedContainer`` to represent repeated field, ``RepeatedContainer`` is inherited from ``list``, so you can manipulate it like a ``list``, or with apis like google's implementation.\n\n.. code-block:: python\n\n    \u003e\u003e\u003e from foo_pb import Person, People\n    \u003e\u003e\u003e msg = People()\n    \u003e\u003e\u003e msg.people.add(\n    ...    id = 1,\n    ...    name = 'jim',\n    ...    email = 'jim@gmail.com',\n    ... )\n    \u003e\u003e\u003e p = msg.people.add()\n    \u003e\u003e\u003e p.id = 2\n    \u003e\u003e\u003e p.name = 'jake'\n    \u003e\u003e\u003e p.email = 'jake@gmail.com'\n    \u003e\u003e\u003e p2 = Person(id=3, name='lucy', email='lucy@gmail.com')\n    \u003e\u003e\u003e msg.people.append(p2)\n    \u003e\u003e\u003e msg.people.append({\n    ...     'id' : 4,\n    ...     'name' : 'lily',\n    ...     'email' : 'lily@gmail.com',\n    ... })\n\nencode raw data fast\n~~~~~~~~~~~~~~~~~~~~\n\nIf you already have your messages represented as ``list`` and ``dict``, you can encode it without constructing intermidiate objects, getting ride of a lot of overhead:\n\n.. code-block:: python\n\n    \u003e\u003e\u003e from cprotobuf import encode_data\n    \u003e\u003e\u003e from foo_pb import Person, People\n    \u003e\u003e\u003e s = encode_data(People, [\n    ...     { 'id': 1, 'name': 'tom', 'email': 'tom@gmail.com' }\n    ... ])\n    \u003e\u003e\u003e msg = People()\n    \u003e\u003e\u003e msg.ParseFromString(s)\n    \u003e\u003e\u003e msg.people[0].name\n    'tom'\n\nUtility APIs\n------------\n\n.. code-block:: python\n\n    \u003e\u003e\u003e from cprotobuf import encode_primitive, decode_primitive\n    \u003e\u003e\u003e encode_primitive('uint64', 10)\n    bytearray(b'\\x01')\n    \u003e\u003e\u003e decode_primitive(b'\\n', 'uint64')\n    (10, 1)\n\nRun Tests\n=========\n\n.. code-block::\n\n    $ nosetests\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyihuang%2Fcprotobuf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyihuang%2Fcprotobuf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyihuang%2Fcprotobuf/lists"}