{"id":37072823,"url":"https://github.com/fischor/protogen-python","last_synced_at":"2026-01-14T08:32:58.000Z","repository":{"id":57455153,"uuid":"398605350","full_name":"fischor/protogen-python","owner":"fischor","description":"The protogen package makes it easy to write protoc plugins in Python","archived":false,"fork":false,"pushed_at":"2025-06-17T23:49:31.000Z","size":170,"stargazers_count":16,"open_issues_count":5,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-26T07:43:51.842Z","etag":null,"topics":["code-generation","protobuf","protoc","protocol-buffers","python","python3"],"latest_commit_sha":null,"homepage":"https://protogen.readthedocs.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fischor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null}},"created_at":"2021-08-21T16:26:17.000Z","updated_at":"2025-08-20T14:38:00.000Z","dependencies_parsed_at":"2025-06-15T12:28:29.032Z","dependency_job_id":null,"html_url":"https://github.com/fischor/protogen-python","commit_stats":{"total_commits":36,"total_committers":1,"mean_commits":36.0,"dds":0.0,"last_synced_commit":"8cbd99fb5131343dde827b25551f3c2835590336"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/fischor/protogen-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fischor%2Fprotogen-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fischor%2Fprotogen-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fischor%2Fprotogen-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fischor%2Fprotogen-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fischor","download_url":"https://codeload.github.com/fischor/protogen-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fischor%2Fprotogen-python/sbom","scorecard":{"id":401283,"data":{"date":"2025-08-11","repo":{"name":"github.com/fischor/protogen-python","commit":"acf3d67c6c83bb1bcef6201ec167c12a92b39fa9"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":2,"reason":"Found 7/24 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":5,"reason":"6 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/black.yaml:1","Warn: no topLevel permission defined: .github/workflows/prepare-release.yaml:1","Warn: no topLevel permission defined: .github/workflows/publish-pypi.yaml:1","Warn: no topLevel permission defined: .github/workflows/test.yaml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/black.yaml:9: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/black.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/black.yaml:10: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/black.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/prepare-release.yaml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/prepare-release.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/prepare-release.yaml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/prepare-release.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/prepare-release.yaml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/prepare-release.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/prepare-release.yaml:33: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/prepare-release.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/prepare-release.yaml:60: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/prepare-release.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/prepare-release.yaml:77: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/prepare-release.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish-pypi.yaml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/publish-pypi.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish-pypi.yaml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/publish-pypi.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish-pypi.yaml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/publish-pypi.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish-pypi.yaml:37: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/publish-pypi.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yaml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/test.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yaml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/test.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yaml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/test.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yaml:37: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/test.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yaml:57: update your workflow using https://app.stepsecurity.io/secureworkflow/fischor/protogen-python/test.yaml/main?enable=pin","Warn: downloadThenRun not pinned by hash: .github/workflows/prepare-release.yaml:40","Warn: downloadThenRun not pinned by hash: .github/workflows/publish-pypi.yaml:27","Warn: downloadThenRun not pinned by hash: .github/workflows/test.yaml:45","Info:   0 out of  13 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   4 third-party GitHubAction dependencies pinned","Info:   0 out of   3 downloadThenRun dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v0.3.1 not signed: https://api.github.com/repos/fischor/protogen-python/releases/130406102","Warn: release artifact v0.3.0 not signed: https://api.github.com/repos/fischor/protogen-python/releases/95497856","Warn: release artifact v0.2.0 not signed: https://api.github.com/repos/fischor/protogen-python/releases/48582835","Warn: release artifact v0.1.0 not signed: https://api.github.com/repos/fischor/protogen-python/releases/48562730","Warn: release artifact v0.3.1 does not have provenance: https://api.github.com/repos/fischor/protogen-python/releases/130406102","Warn: release artifact v0.3.0 does not have provenance: https://api.github.com/repos/fischor/protogen-python/releases/95497856","Warn: release artifact v0.2.0 does not have provenance: https://api.github.com/repos/fischor/protogen-python/releases/48582835","Warn: release artifact v0.1.0 does not have provenance: https://api.github.com/repos/fischor/protogen-python/releases/48562730"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"17 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-8gq9-2x98-w8hf","Warn: Project is vulnerable to: GHSA-8qvm-5x2c-j2w7","Warn: Project is vulnerable to: PYSEC-2024-48 / GHSA-fj7x-q9j7-g6q6","Warn: Project is vulnerable to: PYSEC-2024-230 / GHSA-248v-346w-9cwc","Warn: Project is vulnerable to: PYSEC-2024-60 / GHSA-jjg7-2v4v-x38h","Warn: Project is vulnerable to: GHSA-cpwx-vrp4-4pq7","Warn: Project is vulnerable to: GHSA-gmj6-6f8f-6699","Warn: Project is vulnerable to: GHSA-h5c8-rqwp-cp95","Warn: Project is vulnerable to: GHSA-h75v-3vvj-5mfj","Warn: Project is vulnerable to: GHSA-q2x7-8rv6-6q7h","Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56","Warn: Project is vulnerable to: PYSEC-2025-49 / GHSA-5rjg-fvgr-3xxf","Warn: Project is vulnerable to: GHSA-cx63-2mw6-8hw5","Warn: Project is vulnerable to: GHSA-34jh-p97f-mpxf","Warn: Project is vulnerable to: GHSA-pq67-6m6q-mj2v","Warn: Project is vulnerable to: GHSA-jfmj-5v4g-7637"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 16 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T20:08:58.980Z","repository_id":57455153,"created_at":"2025-08-18T20:08:58.980Z","updated_at":"2025-08-18T20:08:58.980Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28414241,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T08:31:27.429Z","status":"ssl_error","status_checked_at":"2026-01-14T08:31:19.098Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["code-generation","protobuf","protoc","protocol-buffers","python","python3"],"created_at":"2026-01-14T08:32:57.413Z","updated_at":"2026-01-14T08:32:57.979Z","avatar_url":"https://github.com/fischor.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `protogen`\n\n[![PyPI version](https://badge.fury.io/py/protogen.svg)](https://badge.fury.io/py/protogen)\n[![Documentation Status](https://readthedocs.org/projects/protogen/badge/?version=latest)](https://protogen.readthedocs.io/en/latest/?badge=latest)\n[![Test](https://github.com/fischor/protogen-python/actions/workflows/test.yaml/badge.svg?branch=main)](https://github.com/fischor/protogen-python/actions/workflows/test.yaml)\n\nPackage `protogen` makes writing `protoc` plugins easier.\nWorking with the raw protobuf descriptor messages can be cumbersome.\n`protogen` resolves and links the dependencies and references between the raw Protobuf descriptors and turns them into their corresponding `protogen` classes that are easier to work with.\nIt also provides mechanisms that are espacially useful to generate Python code like dealing with Python imports.\n\n## Installation\n\nPackage `protogen` is available via `pip`. To install run:\n\n```\npip install protogen\n```\n\n## API\n\nMost classes in `protogen` are simply replacements of their corresponding Protobuf descriptors: `protogen.File` represents a FileDescriptor, `protogen.Message` a Descriptor, `protogen.Field` a FieldDescriptor and so on. They should be self explanatory. You can [read the docstrings](https://pypi.org/project/protogen/) for more information about them.\n\nThe classes `protogen.Options`, `protogen.Plugin` and `protogen.GeneratedFile` make up a framework to generate files.\nYou can see these in action in the following example plugin:\n\n```python\n#!/usr/bin/env python\n\"\"\"An example plugin.\"\"\"\n\nimport protogen\n\ndef generate(gen: protogen.Plugin):\n    for f in gen.files_to_generate:\n        g = gen.new_generated_file(\n            f.proto.name.replace(\".proto\", \".py\"), \n            f.py_import_path,\n        )\n        g.P(\"# Generated code ahead.\")\n        g.P()\n        g.print_import()\n        g.P()\n        for m in f.messages:\n            g.P(\"class \", m.py_ident, \":\")\n            for ff in m.fields:\n                # ...\n        for s in f.services:\n            g.P(\"class \", s.py_ident, \":\")\n            for m in f.methods:\n                g.P(\"  def \", m.py_name, \"(request):\")\n                g.P(\"    pass\")\n\nif __name__ == \"__main__\":\n    opts = protogen.Options()\n    opts.run(generate)\n```\n\n## class `protogen.Options`\n\nThe `protogen.Options` class can be used to specify options for the resolution process (resolution from plain proto descriptors to `protogen` classes).\n`Option.run(f: func(Plugin))` waits for `protoc` to write the CodeGeneratorRequest to `stdin`, resolves the descriptors contained in it to their corresponding `protogen` classes and initializes a new `Plugin` with the resolved classes.  \n`f` is then called with the `Plugin` as argument.\n\nOnce `f` returns, `Options` will collect the CodeGeneratorResponse from the `Plugin` that contains the all created `GeneratedFile`s and write it to `stdout` for `protoc` to pick it up.\n`protoc` writes the generated files to disk.\n\n## class `protogen.Plugin`\n\nThe `Plugin` class holds the files code generation is requested for in the `Plugin.files_to_generate` attribute. These are the files that were provided as command line arguments to `protoc`.\nAny options/parameters passed to the plugin via the `protoc --plugin_opt=\u003cparam\u003e` command line flag are accessible via `Plugin.parameter`.\nWith `Plugin.new_generated_file` a new `GeneratedFile` gets created that is automatically added to the CodeGeneratorResponse of the plugin.\nTypically, but not necessarily, one file for each file in `Plugin.files_to_generate` is created.\n\n## class `protogen.GeneratedFile`\n\nThe `GeneratedFile` is just a buffer you can add lines to using the `g.P` (print) method.\nA `GeneratedFile` is created with `Plugin.new_generated_file(filename, py_import_path)`.\nThe `filename` is obviously the name of the file to be created.\nThe `py_import_path` is used for *import resolution*.\n\nNote that the following assumes the plugin generates Python code. For other kinds of plugins, the following is not relevant:\n\nIt is often necessary to import Python identifiers that are defined in different Python modules.\nFor example, a Protobuf messages might reference `google.protobuf.Timestamp` in one of its fields.\nThe corresponding Python class `google.protobuf.timestamp_pb2.Timestamp` needs to be imported before its mentioned in the generated code.\n\nThe `protogen.PyImportPath` class represent a Python import path. Is just a wrapper around an import path (for example `\"google.protobuf.timestamp_pb2\"`).\nThe `PyIdent` class represent a Python identifier. It holds a `PyImportPath` together with a name (e.g. a class name like `\"Timestamp\"`).\n\nThe `protogen.GeneratedFile` provides mechanisms to handle Python imports.\nInternally it maintains a list of `PyImportPath`s that it needs to import.\n`PyImportPaths` might be added to this list implictly when calling `GeneratedFile.P(*args)` or rather explicitly when calling `GeneratedFile.qualified_py_ident(PyIdent)`.\nWhen any of the arguments to `GeneratedFile.P` is a `protogen.PyIdent`, the `py_import_path` of the `GeneratedFile` gets compared to the arguments `PyIdent.py_import_path`. \n\nIf they are from different Python modules, the arguments import path will be added to the list of imports and the fully qualified name of the `PyIdent` will be printed. \n\nIf both files are from the same `PyImportPath`, then the import path is not added to the list of imports. In that case it is sufficient to reference the `PyIdent` by its simple name (e.g. `Timestamp`), thus only the `PyIdent.py_name` will be printed.\n\nTo place the import statements in the buffer of the `GeneratedFile` use `GeneratedFile.print_import`. This will put a line `\"import \u003cpath\u003e\"` for each `PyImportPath` that the generated file needs to import (e.g `\"import google.protobuf.timestamp_pb2\"`) in the buffer.\n\nThe following example shows how the `GeneratedFile.P` function behaves for different `PyImportPaths`::\n\n```python\n# g is of type protogen.GeneratedFile\n# message_a and message_b are of type protogen.Message\n\n\u003e\u003e\u003e g.py_import_path\n{ \"mypackage.mymodule\" }\n\n\u003e\u003e\u003e message_a.py_ident\n{ py_import_path: \"google.protobuf.timestamp_pb2\", py_name: \"Timestamp\" }\n\u003e\u003e\u003e g.P(\"hello \", message_a.py_ident) \n# adds \"hello google.protobuf.timestamp_pb2.Timestamp\" to g's line buffer and \"google.protobuf.timestamp_pb2\" to the imports\n\n\u003e\u003e\u003e message_b.py_ident\n{ py_import_path: \"mypackage.mymodule\", py_name: \"MyMessage\" }\n\u003e\u003e\u003e g.P(\"hello \", message_b.py_ident) \n# adds \"hello MyMessage\" to g's line buffer (and nothing to the imports)\n```\n\nNote that you can provide a custom `py_import_func` in the `Options` constructor.\nThis function is used in the resolution process to calculate the `PyImportPath` for `protogen.File`s.\n`protogen.Message`s, `protogen.Service`s and `protogen.Enum`s inherit the `PyImportPath` (that is part of their `PyIdent`) from the file they are defined in.\nBy default the `protogen.default_py_import_func` is used. \nIt is compatible with the style of the offical Python `protoc` plugin that generates for each input file `path/to/file.proto` a corresponding `path/to/file_pb2.py` file.\n\nFor example, assume you know that code generation for proto definitions that are part of the `mypackage.**` proto package happens with a `protoc` plugin that generates one `.py` file per proto package. \nThat `plugin` also omits the `_pb2` suffix.\nFor the proto package `mypackage.api.a`, that might contain any number of files, it creates a `mypackage/api/a.py` file.\nFor the proto package `mypackage.api.b`, a `mypackage/api/b.py` file.\n\nA `py_import_func` describing this would be:\n\n```python\ndef py_import_func(\n    proto_filename: str, \n    proto_package:str,\n) -\u003e protogen.PyImportPath:\n    if proto_package.split(\".\")[0] == \"mypackage\":\n        # Python import path is simply the package name.\n        return protogen.PyImportPath(proto_package) \n    # For every other package, assume its generated with the offical Python plugin.\n    return protogen.default_py_import_func(proto_filename, proto_package)\n```\n\n# Misc\n\n## What is a protoc plugin anyway?\n\n`protoc`, the **Proto**buf **c**ompiler, is used to generate code derived from Protobuf definitions (`.proto` files).\nUnder the hood, `protoc`'s job is to read and parse the definitions into their *Descriptor* types (see [google/protobuf/descriptor.proto](https://github.com/protocolbuffers/protobuf/blob/4f49062a95f18a6c7e21ba17715a2b0a4608151a/src/google/protobuf/descriptor.proto)).\nWhen `protoc` is run (with a plugin) it creates a CodeGeneratorRequest (see [google/protobuf/compiler/plugin.proto#L68](https://github.com/protocolbuffers/protobuf/blob/4f49062a95f18a6c7e21ba17715a2b0a4608151a/src/google/protobuf/compiler/plugin.proto#L68)) that contains the descriptors for the files to generate and everything they import and passes it to the plugin via `stdin`.\n\nA *protoc plugin* is an executable. It reads the CodeGeneratorRequest from `stdin` and returns a CodeGeneratorResponse (see [google/protobuf/compiler/plugin.proto#L99](https://github.com/protocolbuffers/protobuf/blob/4f49062a95f18a6c7e21ba17715a2b0a4608151a/src/google/protobuf/compiler/plugin.proto#L99)) via `stdout`.\nThe plugin can use the descriptors from the CodeGeneratorRequest to create output files (in memory).\nIt returns these output files (consisting of name and content as string) in the CodeGeneratorResponse to `protoc`.\n\n`protoc` then writes these files to disk.\n\n## Run `protoc` with your plugin\n\nAssume you have an executable plugin under `path/to/plugin/main.py`.\nYou can invoke it via:\n\n```\nprotoc \\\n    --plugin=protoc-gen-myplugin=path/to/plugin/main.py \\\n    --myplugin_out=./output_root \\\n    myproto.proto myproto2.proto\n```\n\nCaveats:\n- you must use the `--plugin=protoc-gen-\u003cplugin_name\u003e` prefix, otherwise `protoc` fails with \"plugin not executable\"\n- specify the output path of the plugin with `--\u003cplugin_name\u003e-out` flag where `\u003cplugin_name\u003e` is the same as used in the `--plugin` flag  \n- your plugin must be executable (`chmod +x path/to/plugin/main.py` and put a `#!/usr/bin/env python` at the top of the file)\n\n# See also\n\n- if you want to write protoc plugins with JavaScript/TypeScript: [github.com/fischor/protogen-javascript](https://github.com/fischor/protogen-javascript)\n- if you want to write protoc plugins with Golang: [google.golang.org/protobuf/compiler/protogen](https://google.golang.org/protobuf/compiler/protogen)\n\n# Credits\n\nThis package is inspired by the [google.golang.org/protobuf/compiler/protogen Golang](https://pkg.go.dev/google.golang.org/protobuf@v1.27.1/compiler/protogen) package.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffischor%2Fprotogen-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffischor%2Fprotogen-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffischor%2Fprotogen-python/lists"}