codestare.compiletools package¶
- codestare.compiletools.has_module(*modules: str)[source]¶
Try importing module, catch ImportError
- Parameters
*modules – module names
Returns: True if module is importable else False
- codestare.compiletools.find_proto_files(*paths: pathlib.Path, recursive: bool = True) List[pathlib.Path][source]¶
Return relative paths of .proto files in paths
- Parameters
*paths – We
glob()the files in the pathsrecursive – check recursively in all paths if True
- Returns
List of unique paths of found .proto files, relative to search path
Submodules¶
codestare.compiletools.cmd module¶
Googles own python plugin implementation for protoc does not compile files with relative imports, like
e.g. betterproto (related issue). Several third party tools try to “fix” this by either pre- or post-processing
the generated files, or using a custom protoc plugin (like betterproto).
Conversely, betterproto’s relative imports only succeed when all sources are compiled simultaneously
(all proto files as arguments to protoc invocation, otherwise files might be overwritten).
This would break support for build tools like cmake / make, allowing parallel compilation of .proto files
i.e. it seems not possible to implement in the official plugin.
Google itself develops an alternative protobuf module which aims to use protocol buffers with more idiomatic python code but has no official compiler plugin as of now. A third party plugin plusplugin loosely based on the mypy plugin is available (experimental).
- codestare.compiletools.cmd.compare_files()[source]¶
Context manager to monkey patch
distutils.file_util.copy_file()to only copy files which are not equal according tofilecmp.cmp().- Yields
None
Example
Use the context manager with methods implicitly using
distutils.file_util.copy_file():class CustomCommand(distutils.cmd.Command): def copy_not_equal(new, old): with compare_files(): self.copy_tree(new, old)
- codestare.compiletools.cmd.temp_dir()[source]¶
Context manager to redirect build directory to temporary directory. This is the easiest way to only “build” changed protobuf modules: We build to temp dir, then copy to real build dir if files are different.
Note
There is no way to tell the
protoccompiler to only build files that have changed / updated sources. This is typically the task ofmakeor some other build script, and all files passed toprotocwill be built (in theory the plugin could also handle this, but none of the default plugins do). This means they will have new file generation timestamps and willprobably be marked as changed in the version control system
be copied to the build directory by the python build toolchain
Because of this, we need to compare the file contents instead of the timestamps, even when building to a temporary directory, see
compare_files().- Yields
pathlib.Path – new build dir
- class codestare.compiletools.cmd.PathCommand(dist)[source]¶
Bases:
distutils.cmd.Command,abc.ABCAbstract command class supporting verification of options representing path and directory lists
- class codestare.compiletools.cmd.CompileBase(dist)[source]¶
Bases:
codestare.compiletools.cmd.PathCommandBase class for setuptools commands handling compilation of
.protofiles.- includes¶
Directories containing
.protofiles to pass as includes toprotoc- Type
List[pathlib.Path]
- output¶
compilation output directory
- Type
- files¶
actual list of
.protofiles to compile- Type
List[pathlib.Path], optional
- proto_package¶
if
filesis missing, search this path for.protofiles- Type
pathlib.Path, optional
- force¶
Force compilation / copying of all generated files disregarding changed contents. Defaults to False.
- Type
- dry_run¶
Don’t copy generated files to build dir, only print list of generated files. Defaults to False.
- Type
- options¶
List of
option flagsto trigger compilation flavors- Type
List[str]
- protoc¶
Path to
protocexecutable. If not supplied,protocneeds to be in$PATH- Type
- user_options = [('protoc=', None, 'protoc compiler location'), ('output=', None, 'Output directory for compiled files'), ('includes=', None, 'Include directories for .proto files'), ('force', 'f', 'forcibly build everything (ignore file timestamps)'), ('files=', None, 'Protobuf source files to compile'), ('plugin_params=', None, 'parameters passed to protoc plugin'), ('options=', 'o', 'Options for compilation, possible values are [<CompileOption.JAVA: 1>, <CompileOption.JSLIBRARY: 2>, <CompileOption.JSINDIVIDUAL: 4>, <CompileOption.CSHARP: 8>, <CompileOption.CPP: 16>, <CompileOption.PYTHON_BETTER_PROTO: 32>, <CompileOption.PYTHON_MYPY: 64>, <CompileOption.PYTHON_PROTOPLUS: 128>, <CompileOption.PYTHON_BASIC: 256>] (default)')]¶
User options for
distutils.cmd.Command. SeeCompileBase.run()for more info about how they are used in particular.Each option is used to supply the corresponding attribute: for more information about e.g.
user_options['force']refer toforce.User options are passed between build steps. If not supplied specifically for this build command, the following mapping occurs (options specified multiple times will take the first existing default value):
option
default
{command_name}.{option_name}includes
rewrite_proto.outputs
output
compile_proto.build_lib
includes
compile_proto.include_proto
proto_package
compile_proto.proto_package
force
compile_proto.force
dry_run
compile_proto.force
- run()[source]¶
Calls
Compiler.compile()withuser_optionsas keyword arguments.This triggers a compilation of
filesusing theprotocexecutable, passingincludesas includes (-Iflag) andplugin_params, using the plugin and default options foroptions(see :mod:codestare.compiletools.options) with output directoryoutput.If
forceis not set, only generated files that don’t exist with the same contents inoutputwill be copied from the temporary build directory.If
dry_runis set, no files will be copied whatsoever, and only theprotocinvocation will be shown.
- class codestare.compiletools.cmd.CompileProtoPython(dist)[source]¶
Bases:
codestare.compiletools.cmd.CompileBaseCommand to compile with compilation option
PYTHON_BASICand generate__init__.pyfiles withGenerateInits
- class codestare.compiletools.cmd.CompileProtoMypy(dist)[source]¶
Bases:
codestare.compiletools.cmd.CompileBaseCommand to compile with compilation option
PYTHON_MYPY, to generate.pyistubs.
- class codestare.compiletools.cmd.CompileBetterproto(dist)[source]¶
Bases:
codestare.compiletools.cmd.CompileBaseCommand to compile with compilation option
PYTHON_BETTER_PROTOand generate__init__.pyfiles withGenerateInits
- class codestare.compiletools.cmd.CompileProtoPlus(dist)[source]¶
Bases:
codestare.compiletools.cmd.CompileBaseCommand to compile with compilation option
PYTHON_BETTER_PROTOand generate__init__.pyfiles withGenerateInitsNote
Although generating
__init__.pyfiles via theGenerateInitssetuptools command is supported forCompileProtoPlus, theprotocplugin used in this compilation handles generation of init files.It is recommended to not use the
generate_inits commandor at least not to useforceto avoid overwriting the files.
- class codestare.compiletools.cmd.CompileProto(dist)[source]¶
Bases:
codestare.compiletools.cmd.PathCommandTriggers compilation of all available python flavors that are turned on via
flavor. Ifproto_packageandinclude_protoare supplied, enforce package structure according toproto_packageby rewriting included source files withrewrite subcommand- include_proto¶
root dir for proto files
- Type
List[pathlib.Path]
- build_lib¶
output directory for protobuf library
- Type
os.path.PathLike
- flavors = {'better': Flavor.BETTER, 'mypy': Flavor.MYPY, 'plus': Flavor.PLUS, 'python': Flavor.BASIC}¶
Mapping of options to enums
- user_options = [('include-proto', None, 'root dir for proto files'), ('proto-package', None, 'parent package that will be enforced for protobuf modules'), ('build-lib', None, 'output directory for protobuf library'), ('flavor', None, 'flavor of compiled code, one of mypy,python,better,plus'), ('force', 'f', 'forcibly build everything (ignore file timestamps)'), ('dry-run', None, "don't do anything but show protoc commands")]¶
User options for
distutils.cmd.Commandbehaviour.Each option is used to supply the corresponding attribute: for more information about e.g.
user_options['force']refer toforce.User options are passed between build steps. If not supplied specifically for this build command, the following mapping occurs (options specified multiple times will take the first existing default value):
option
default
{command_name}.{option_name}build_lib
build_py_proto.build_lib
include_proto
build_py_proto.include_proto
force
build_py_proto.force
dry_run
build_py_proto.dry_run
keep_proto_files
build_py_proto.keep_proto_files
- class codestare.compiletools.cmd.CleanProto(dist)[source]¶
Bases:
codestare.compiletools.cmd.PathCommandSetuptools command to clean
.protosources after compilation. Respects dry-run setting from compile_proto.Attributes: clean_dirs (List[str]): directories where all *.proto files will be removed recursive (bool): also remove files in sub-directories of clean_dir [default] dry_run (bool): fake clean only print paths
- class codestare.compiletools.cmd.RewriteProto(dist)[source]¶
Bases:
codestare.compiletools.cmd.PathCommandSetuptools command to rewrite
.protosources in a way that produces a specified python package structure. Respects dry-run setting from compile_proto.
codestare.compiletools.compile module¶
Protoc compiler wrapper CLI (using fire)
- class codestare.compiletools.compile.Compiler(protoc=distutils.spawn.find_executable('protoc'))[source]¶
Bases:
objectWrapper around protobuf compiler.
See
compile-proto OPTIONSfor all possible compilation options. Seecompile-proto(no args) andcompile-proto --helpfor more help- OPTIONS = ['[java] java', '[cs] csharp', '[cpp] cpp', '[better] python with `better_proto` plugin', '[mypy] mypy python stubs', '[plus] python_protoplus', '[py] python', '[js] javascript as library | javascript individual', '[all] java | javascript as library | javascript individual | csharp | cpp | python with `better_proto` plugin | mypy python stubs | python_protoplus | python']¶
Supported compile options, multiple options may be specified.
- call(*proto_files, includes: Optional[str] = None, protohelp=False, dry_run=False, **options)[source]¶
Just a wrapper around the protoc compiler.
See
compile-proto call --helpto print help of protoc command Seecompile-proto call -- --helpfor additonal help with the call command Seecompile-proto protocfor the path of the used protoc compiler executable- Parameters
includes – Directories to use as includes
protohelp – Use this flag to pass
--helpto protoc invocationoptions – Will be passed as flags to the protoc command (only
--flagsyntax supported, no single dash)dry_run – If True, don’t do anything except printing the command
- compile(*protoc_files, options=_DEFAULT, quiet=False, plugin_params: str = '', output=os.getcwd(), **kwargs) Optional[str][source]¶
Compile for given options, see
compile-proto compile -- --help- Parameters
quiet – Don’t print output from protoc plugin if possible
output – output directory (default: working directory)
options – one or multiple options see compile-proto OPTIONS default: [py]
protoc_files – files to compile, passed through to protoc
plugin_params – mapping of additional parameters for the protoc plugin (not the compiler itself)
kwargs – Passed to protoc invocation, see compile-proto call – –help.
- Returns
the output path
- class codestare.compiletools.compile.Rewriter(root_package: str, output_root: os.PathLike = './')[source]¶
Bases:
objectRewrite proto files to force python package structure which mirrors protobuf package declarations.
- read(*dirs: os.PathLike)[source]¶
Reads .proto files from directories, manipulate them with the other commands afterwards.
- property root_package¶
root package for generated directory structure
- Returns
root package which is enforced
- Return type
- property output_root¶
Root directory of new directory structure.
- property calculated_packages¶
- Returns
Dictionary mapping file contents to package names
- Return type
- fix_imports()[source]¶
Modify internal file content representation to match internal file locations, so that imports are importing the right files.
- fix_packages()[source]¶
Modify internal content representation such that
packagedeclarations in.protosource files match the internal directory structure
- content(filename: os.PathLike) str[source]¶
View the internal file representations
- Parameters
filename – Input file path
- Returns
contents of internal file representation
- Return type
- write(dry_run=True) List[str][source]¶
Write internal content representation to
output_rootaccording to internalpackage mapping
codestare.compiletools.options module¶
Options for compilation are represented using CompileOption
- class codestare.compiletools.options.CompileOption(value)[source]¶
Bases:
enum.FlagDescribes available compile options
- JAVA = 1¶
- JSLIBRARY = 2¶
- JSINDIVIDUAL = 4¶
- CSHARP = 8¶
- CPP = 16¶
- PYTHON_BETTER_PROTO = 32¶
- PYTHON_MYPY = 64¶
- PYTHON_PROTOPLUS = 128¶
- PYTHON_BASIC = 256¶
- JAVASCRIPT = 6¶
- PYTHON = 480¶
- ALL = 511¶
- classmethod from_str(value) codestare.compiletools.options.CompileOption[source]¶
Convert a string to an enum value
- Parameters
- Returns
Enum flag
- Return type
- classmethod from_string_list(values)[source]¶
Convert a string list to an enum value (combined flag for all values in list)
- Parameters
- Returns
combined flag
- Return type
- property arguments: List¶
Arguments that can be used to trigger this compilation
- property disjunct: List[codestare.compiletools.options.CompileOption]¶
Return all options which are not combinations of other options
- property is_composite¶
Like normal integer flags, individual flags are all powers of 2, see https://docs.python.org/3/library/enum.html#flag combined flags are not, so we test that with
o.value & (o.value - 1)
- parameters(*args, **kwargs)[source]¶
some options can use request parameters for the plugin, this is e.g. how the javascript plugin implements “library / binary” compilation.
JSLIBRARYaddslibrary='protobuf_library',binaryJSINDIVIDUALaddsimport_style='commonjs',binaryPYTHON_PROTOPLUSaddsreadable_imports