[Python] Generate `.pyi` stub files when `--python-typing` is on. (#8312)

* [Python] Generate `.pyi` stub files when `--python-typing` is on.

To support this change, the following modifications were made:

-  added a new option to disable `numpy` helpers generation;
-  added a new flag to control the target Python version:

   `--python-version` can be one of the following:

   - `0.x.x` – compatible with any Python version;
   - `2.x.x` – compatible with Python 2;
   - `3.x.x` – compatible with Python 3.
-  added codegen utilities for Python;
-  added a note that the generated .py file is empty.

* [Python] Update Bazel build rules.

* [Python] Update Bazel build rules.

* [Python] Run buildifier on BUILD.bazel files.

---------

Co-authored-by: Derek Bailey <derekbailey@google.com>
This commit is contained in:
Anton Bobukh 2024-05-29 12:47:29 -07:00 committed by GitHub
parent 58c8eb5847
commit 3b27f5396e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 2865 additions and 34 deletions

View File

@ -37,6 +37,7 @@ filegroup(
"pnpm-lock.yaml",
"typescript.bzl",
"//grpc/src/compiler:distribution",
"//include/codegen:distribution",
"//reflection:distribution",
"//src:distribution",
"//ts:distribution",

View File

@ -183,6 +183,8 @@ set(FlatBuffers_Compiler_SRCS
src/bfbs_gen_lua.h
src/bfbs_gen_nim.h
src/bfbs_namer.h
include/codegen/python.h
include/codegen/python.cc
include/flatbuffers/code_generators.h
src/binary_annotator.h
src/binary_annotator.cpp

6
MODULE.bazel Normal file
View File

@ -0,0 +1,6 @@
###############################################################################
# Bazel now uses Bzlmod by default to manage external dependencies.
# Please consider migrating your external dependencies from WORKSPACE to MODULE.bazel.
#
# For more details, please check https://github.com/bazelbuild/bazel/issues/18958
###############################################################################

1632
MODULE.bazel.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
load("@rules_cc//cc:defs.bzl", "cc_library")
package(
default_visibility = ["//visibility:private"],
)
filegroup(
name = "distribution",
srcs = [
"BUILD.bazel",
] + glob([
"*.cc",
"*.h",
]),
visibility = ["//visibility:public"],
)
cc_library(
name = "python",
srcs = ["python.cc"],
hdrs = ["python.h"],
strip_include_prefix = "/include",
visibility = ["//src:__subpackages__"],
)

63
include/codegen/python.cc Normal file
View File

@ -0,0 +1,63 @@
#include "codegen/python.h"
#include <set>
#include <sstream>
#include <string>
#include <utility>
namespace flatbuffers {
namespace python {
Version::Version(const std::string &version) {
std::stringstream ss(version);
char dot;
ss >> major >> dot >> minor >> dot >> micro;
}
bool Version::IsValid() const {
return (major == 0 || major == 2 || major == 3) && minor >= 0 && micro >= 0;
}
std::set<std::string> Keywords(const Version &version) {
switch (version.major) {
case 2:
// https://docs.python.org/2/reference/lexical_analysis.html#keywords
return {
"and", "as", "assert", "break", "class", "continue", "def",
"del", "elif", "else", "except", "exec", "finally", "for",
"from", "global", "if", "import", "in", "is", "lambda",
"not", "or", "pass", "print", "raise", "return", "try",
"while", "with", "yield",
};
case 0:
case 3:
// https://docs.python.org/3/reference/lexical_analysis.html#keywords
return {
"and", "as", "assert", "async", "await", "break",
"class", "continue", "def", "del", "elif", "else",
"except", "False", "finally", "for", "from", "global",
"if", "import", "in", "is", "lambda", "None",
"nonlocal", "not", "or", "pass", "raise", "return",
"True", "try", "while", "with", "yield",
};
default:
return {};
}
}
const python::Import &python::Imports::Import(const std::string &module) {
python::Import import;
import.module = module;
imports.push_back(std::move(import));
return imports.back();
}
const python::Import &python::Imports::Import(const std::string &module,
const std::string &name) {
python::Import import;
import.module = module;
import.name = name;
imports.push_back(std::move(import));
return imports.back();
}
} // namespace python
} // namespace flatbuffers

45
include/codegen/python.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef FLATBUFFERS_INCLUDE_CODEGEN_PYTHON_H_
#define FLATBUFFERS_INCLUDE_CODEGEN_PYTHON_H_
#include <cstdint>
#include <set>
#include <string>
#include <vector>
namespace flatbuffers {
namespace python {
// `Version` represent a Python version.
//
// The zero value (i.e. `Version{}`) represents both Python2 and Python3.
//
// https://docs.python.org/3/faq/general.html#how-does-the-python-version-numbering-scheme-work
struct Version {
explicit Version(const std::string &version);
bool IsValid() const;
int16_t major = 0;
int16_t minor = 0;
int16_t micro = 0;
};
std::set<std::string> Keywords(const Version &version);
struct Import {
bool IsLocal() const { return module == "."; }
std::string module;
std::string name;
};
struct Imports {
const python::Import &Import(const std::string &module);
const python::Import &Import(const std::string &module,
const std::string &name);
std::vector<python::Import> imports;
};
} // namespace python
} // namespace flatbuffers
#endif // FLATBUFFERS_INCLUDE_CODEGEN_PYTHON_H_

View File

@ -706,8 +706,26 @@ struct IDLOptions {
bool no_leak_private_annotations;
bool require_json_eof;
bool keep_proto_id;
/********************************** Python **********************************/
bool python_no_type_prefix_suffix;
bool python_typing;
// The target Python version. Can be one of the following:
// - "0"
// - "2"
// - "3"
// - "2.<minor>"
// - "3.<minor>"
// - "2.<minor>.<micro>"
// - "3.<minor>.<micro>"
//
// https://docs.python.org/3/faq/general.html#how-does-the-python-version-numbering-scheme-work
std::string python_version;
// Whether to generate numpy helpers.
bool python_gen_numpy;
bool ts_omit_entrypoint;
ProtoIdGapAction proto_id_gap_action;
@ -828,6 +846,7 @@ struct IDLOptions {
keep_proto_id(false),
python_no_type_prefix_suffix(false),
python_typing(false),
python_gen_numpy(true),
ts_omit_entrypoint(false),
proto_id_gap_action(ProtoIdGapAction::WARNING),
mini_reflect(IDLOptions::kNone),

View File

@ -155,5 +155,6 @@ cc_library(
"//grpc/src/compiler:python_generator",
"//grpc/src/compiler:swift_generator",
"//grpc/src/compiler:ts_generator",
"//include/codegen:python",
],
)

View File

@ -21,6 +21,7 @@
#include <list>
#include <memory>
#include <sstream>
#include <string>
#include "annotated_binary_text_gen.h"
#include "binary_annotator.h"
@ -254,6 +255,8 @@ const static FlatCOption flatc_options[] = {
{ "", "python-no-type-prefix-suffix", "",
"Skip emission of Python functions that are prefixed with typenames" },
{ "", "python-typing", "", "Generate Python type annotations" },
{ "", "python-version", "", "Generate code for the given Python version." },
{ "", "python-gen-numpy", "", "Whether to generate numpy helpers." },
{ "", "ts-omit-entrypoint", "",
"Omit emission of namespace entrypoint file" },
{ "", "file-names-only", "",
@ -671,6 +674,18 @@ FlatCOptions FlatCompiler::ParseFromCommandLineArguments(int argc,
opts.python_no_type_prefix_suffix = true;
} else if (arg == "--python-typing") {
opts.python_typing = true;
} else if (arg.rfind("--python-version=", 0) == 0) {
opts.python_version =
arg.substr(std::string("--python-version=").size());
} else if (arg == "--python-version") {
if (++argi >= argc) Error("missing value following: " + arg, true);
opts.python_version = argv[argi];
} else if (arg == "--python-gen-numpy" ||
arg == "--python-gen-numpy=true") {
opts.python_gen_numpy = true;
} else if (arg == "--no-python-gen-numpy" ||
arg == "--python-gen-numpy=false") {
opts.python_gen_numpy = false;
} else if (arg == "--ts-omit-entrypoint") {
opts.ts_omit_entrypoint = true;
} else if (arg == "--annotate-sparse-vectors") {

View File

@ -19,13 +19,17 @@
#include "idl_gen_python.h"
#include <algorithm>
#include <cctype>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
#include "codegen/python.h"
#include "flatbuffers/code_generators.h"
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
@ -40,15 +44,6 @@ namespace {
typedef std::pair<std::string, std::string> ImportMapEntry;
typedef std::set<ImportMapEntry> ImportMap;
static std::set<std::string> PythonKeywords() {
return { "False", "None", "True", "and", "as", "assert",
"break", "class", "continue", "def", "del", "elif",
"else", "except", "finally", "for", "from", "global",
"if", "import", "in", "is", "lambda", "nonlocal",
"not", "or", "pass", "raise", "return", "try",
"while", "with", "yield" };
}
static Namer::Config PythonDefaultConfig() {
return { /*types=*/Case::kKeep,
/*constants=*/Case::kScreamingSnake,
@ -72,21 +67,594 @@ static Namer::Config PythonDefaultConfig() {
/*filename_extension=*/".py" };
}
static Namer::Config kStubConfig = {
/*types=*/Case::kKeep,
/*constants=*/Case::kScreamingSnake,
/*methods=*/Case::kUpperCamel,
/*functions=*/Case::kUpperCamel,
/*fields=*/Case::kLowerCamel,
/*variables=*/Case::kLowerCamel,
/*variants=*/Case::kKeep,
/*enum_variant_seperator=*/".",
/*escape_keywords=*/Namer::Config::Escape::AfterConvertingCase,
/*namespaces=*/Case::kKeep, // Packages in python.
/*namespace_seperator=*/".",
/*object_prefix=*/"",
/*object_suffix=*/"T",
/*keyword_prefix=*/"",
/*keyword_suffix=*/"_",
/*filenames=*/Case::kKeep,
/*directories=*/Case::kKeep,
/*output_path=*/"",
/*filename_suffix=*/"",
/*filename_extension=*/".pyi",
};
// Hardcode spaces per indentation.
static const CommentConfig def_comment = { nullptr, "#", nullptr };
static const std::string Indent = " ";
} // namespace
class PythonStubGenerator {
public:
PythonStubGenerator(const Parser &parser, const std::string &path,
const Version &version)
: parser_{parser},
namer_{WithFlagOptions(kStubConfig, parser.opts, path),
Keywords(version)},
version_(version) {}
bool Generate() {
if (parser_.opts.one_file) {
Imports imports;
std::stringstream stub;
DeclareUOffset(stub, &imports);
for (const EnumDef *def : parser_.enums_.vec) {
if (def->generated) continue;
GenerateEnumStub(stub, def, &imports);
}
for (const StructDef *def : parser_.structs_.vec) {
if (def->generated) continue;
GenerateStructStub(stub, def, &imports);
}
std::string filename =
namer_.config_.output_path +
StripPath(StripExtension(parser_.file_being_parsed_)) +
namer_.config_.filename_suffix + namer_.config_.filename_extension;
return SaveFile(filename, imports, stub);
}
for (const EnumDef *def : parser_.enums_.vec) {
if (def->generated) continue;
Imports imports;
std::stringstream stub;
DeclareUOffset(stub, &imports);
GenerateEnumStub(stub, def, &imports);
std::string filename = namer_.Directories(*def->defined_namespace) +
namer_.File(*def, SkipFile::Suffix);
if (!SaveFile(filename, imports, stub)) return false;
}
for (const StructDef *def : parser_.structs_.vec) {
if (def->generated) continue;
Imports imports;
std::stringstream stub;
DeclareUOffset(stub, &imports);
GenerateStructStub(stub, def, &imports);
std::string filename = namer_.Directories(*def->defined_namespace) +
namer_.File(*def, SkipFile::Suffix);
if (!SaveFile(filename, imports, stub)) return false;
}
return true;
}
private:
bool SaveFile(const std::string &filename, const Imports &imports,
const std::stringstream &content) {
std::stringstream ss;
GenerateImports(ss, imports);
ss << '\n';
ss << content.str() << '\n';
EnsureDirExists(StripFileName(filename));
return flatbuffers::SaveFile(filename.c_str(), ss.str(), false);
}
static void DeclareUOffset(std::stringstream &stub, Imports *imports) {
imports->Import("flatbuffers");
imports->Import("typing");
stub << "uoffset: typing.TypeAlias = "
"flatbuffers.number_types.UOffsetTFlags.py_type\n"
<< '\n';
}
std::string ModuleForFile(const std::string &file) const {
if (parser_.file_being_parsed_ == file) return ".";
std::string module = parser_.opts.include_prefix + StripExtension(file) +
parser_.opts.filename_suffix;
std::replace(module.begin(), module.end(), '/', '.');
return module;
}
template <typename T>
std::string ModuleFor(const T *def) const {
if (parser_.opts.one_file) return ModuleForFile(def->file);
return namer_.NamespacedType(*def);
}
const StructDef *GetNestedStruct(const FieldDef *field) const {
const Value *nested = field->attributes.Lookup("nested_flatbuffer");
if (nested == nullptr) return nullptr;
StructDef *nested_def = parser_.LookupStruct(nested->constant);
if (nested_def != nullptr) return nested_def;
return parser_.LookupStruct(namer_.NamespacedType(
parser_.current_namespace_->components, nested->constant));
}
static std::string ScalarType(BaseType type) {
if (IsBool(type)) return "bool";
if (IsInteger(type)) return "int";
if (IsFloat(type)) return "float";
FLATBUFFERS_ASSERT(false);
return "None";
}
template <typename F>
std::string UnionType(const EnumDef &enum_def, Imports *imports,
F type) const {
imports->Import("typing");
std::string result = "";
for (const EnumVal *val : enum_def.Vals()) {
if (!result.empty()) result += ", ";
switch (val->union_type.base_type) {
case BASE_TYPE_STRUCT: {
Import import = imports->Import(ModuleFor(val->union_type.struct_def),
type(*val->union_type.struct_def));
result += import.name;
break;
}
case BASE_TYPE_STRING:
result += "str";
break;
case BASE_TYPE_NONE:
result += "None";
break;
default:
break;
}
}
return "typing.Union[" + result + "]";
}
std::string UnionObjectType(const EnumDef &enum_def, Imports *imports) const {
return UnionType(enum_def, imports, [this](const StructDef &struct_def) {
return namer_.ObjectType(struct_def);
});
}
std::string UnionType(const EnumDef &enum_def, Imports *imports) const {
return UnionType(enum_def, imports, [this](const StructDef &struct_def) {
return namer_.Type(struct_def);
});
}
std::string EnumType(const EnumDef &enum_def, Imports *imports) const {
imports->Import("typing");
const Import &import =
imports->Import(ModuleFor(&enum_def), namer_.Type(enum_def));
std::string result = "";
for (const EnumVal *val : enum_def.Vals()) {
if (!result.empty()) result += ", ";
result += import.name + "." + namer_.Variant(*val);
}
return "typing.Literal[" + result + "]";
}
std::string TypeOf(const Type &type, Imports *imports) const {
if (type.enum_def != nullptr) return EnumType(*type.enum_def, imports);
if (IsScalar(type.base_type)) return ScalarType(type.base_type);
switch (type.base_type) {
case BASE_TYPE_STRUCT: {
const Import &import = imports->Import(ModuleFor(type.struct_def),
namer_.Type(*type.struct_def));
return import.name;
}
case BASE_TYPE_STRING:
return "str";
case BASE_TYPE_ARRAY:
case BASE_TYPE_VECTOR: {
imports->Import("typing");
return "typing.List[" + TypeOf(type.VectorType(), imports) + "]";
}
case BASE_TYPE_UNION:
return UnionType(*type.enum_def, imports);
default:
FLATBUFFERS_ASSERT(0);
return "";
}
}
std::string GenerateObjectFieldStub(const FieldDef *field,
Imports *imports) const {
std::string field_name = namer_.Field(*field);
const Type &field_type = field->value.type;
if (IsScalar(field_type.base_type)) {
std::string result = field_name + ": " + TypeOf(field_type, imports);
if (field->IsOptional()) result += " | None";
return result;
}
switch (field_type.base_type) {
case BASE_TYPE_STRUCT: {
Import import =
imports->Import(ModuleFor(field_type.struct_def),
namer_.ObjectType(*field_type.struct_def));
return field_name + ": " + import.name + " | None";
}
case BASE_TYPE_STRING:
return field_name + ": str | None";
case BASE_TYPE_ARRAY:
case BASE_TYPE_VECTOR: {
imports->Import("typing");
if (field_type.element == BASE_TYPE_STRUCT) {
Import import =
imports->Import(ModuleFor(field_type.struct_def),
namer_.ObjectType(*field_type.struct_def));
return field_name + ": typing.List[" + import.name + "]";
}
if (field_type.element == BASE_TYPE_STRING) {
return field_name + ": typing.List[str]";
}
return field_name + ": typing.List[" +
TypeOf(field_type.VectorType(), imports) + "]";
}
case BASE_TYPE_UNION:
return field_name + ": " +
UnionObjectType(*field->value.type.enum_def, imports);
default:
return field_name;
}
}
void GenerateObjectStub(std::stringstream &stub, const StructDef *struct_def,
Imports *imports) const {
std::string name = namer_.ObjectType(*struct_def);
stub << "class " << name;
if (version_.major != 3) stub << "(object)";
stub << ":\n";
for (const FieldDef *field : struct_def->fields.vec) {
if (field->deprecated) continue;
stub << " " << GenerateObjectFieldStub(field, imports) << "\n";
}
stub << " @classmethod\n";
stub << " def InitFromBuf(cls, buf: bytes, pos: int) -> " << name
<< ": ...\n";
stub << " @classmethod\n";
stub << " def InitFromPackedBuf(cls, buf: bytes, pos: int = 0) -> " << name
<< ": ...\n";
const Import &import =
imports->Import(ModuleFor(struct_def), namer_.Type(*struct_def));
stub << " @classmethod\n";
stub << " def InitFromObj(cls, " << namer_.Variable(*struct_def)
<< ": " + import.name + ") -> " << name << ": ...\n";
stub << " def _UnPack(self, " << namer_.Variable(*struct_def) << ": "
<< import.name << ") -> None: ...\n";
stub << " def Pack(self, builder: flatbuffers.Builder) -> None: ...\n";
if (parser_.opts.gen_compare) {
stub << " def __eq__(self, other: " << name + ") -> bool: ...\n";
}
}
void GenerateStructStub(std::stringstream &stub, const StructDef *struct_def,
Imports *imports) const {
std::string type = namer_.Type(*struct_def);
stub << "class " << type;
if (version_.major != 3) stub << "(object)";
stub << ":\n";
if (struct_def->fixed) {
stub << " @classmethod\n";
stub << " def SizeOf(cls) -> int: ...\n\n";
} else {
stub << " @classmethod\n";
stub << " def GetRootAs(cls, buf: bytes, offset: int) -> " << type
<< ": ...\n";
if (!parser_.opts.python_no_type_prefix_suffix) {
stub << " @classmethod\n";
stub << " def GetRootAs" << type
<< "(cls, buf: bytes, offset: int) -> " << type << ": ...\n";
}
if (parser_.file_identifier_.length()) {
stub << " @classmethod\n";
stub << " def " << type
<< "BufferHasIdentifier(cls, buf: bytes, offset: int, "
"size_prefixed: bool) -> bool: ...\n";
}
}
stub << " def Init(self, buf: bytes, pos: int) -> None: ...\n";
for (const FieldDef *field : struct_def->fields.vec) {
if (field->deprecated) continue;
std::string name = namer_.Method(*field);
const Type &field_type = field->value.type;
if (IsScalar(field_type.base_type)) {
stub << " def " << name << "(self) -> " << TypeOf(field_type, imports);
if (field->IsOptional()) stub << " | None";
stub << ": ...\n";
} else {
switch (field_type.base_type) {
case BASE_TYPE_STRUCT: {
const Import &import =
imports->Import(ModuleFor(field_type.struct_def),
namer_.Type(*field_type.struct_def));
if (struct_def->fixed) {
stub << " def " << name << "(self, obj: " << import.name
<< ") -> " << import.name << ": ...\n";
} else {
stub << " def " << name + "(self) -> " << import.name
<< " | None: ...\n";
}
break;
}
case BASE_TYPE_STRING:
stub << " def " << name << "(self) -> str | None: ...\n";
break;
case BASE_TYPE_ARRAY:
case BASE_TYPE_VECTOR: {
switch (field_type.element) {
case BASE_TYPE_STRUCT: {
const Import &import =
imports->Import(ModuleFor(field_type.struct_def),
namer_.Type(*field_type.struct_def));
stub << " def " << name << "(self, i: int) -> " << import.name
<< " | None: ...\n";
break;
}
case BASE_TYPE_STRING:
stub << " def " << name << "(self, i: int) -> str: ...\n";
break;
default: // scalars
stub << " def " << name << "(self, i: int) -> "
<< TypeOf(field_type, imports) << ": ...\n";
if (parser_.opts.python_gen_numpy) {
stub << " def " << name
<< "AsNumpy(self) -> np.ndarray: ...\n";
}
const StructDef *nested_def = GetNestedStruct(field);
if (nested_def != nullptr) {
const Import &import = imports->Import(
ModuleFor(nested_def), namer_.Type(*nested_def));
stub << " def " << name + "NestedRoot(self) -> "
<< import.name << " | None: ...\n";
}
break;
}
stub << " def " << name << "Length(self) -> int: ...\n";
stub << " def " << name << "IsNone(self) -> bool: ...\n";
break;
}
case BASE_TYPE_UNION: {
imports->Import("flatbuffers", "table");
stub << " def " << name << "(self) -> table.Table | None: ...\n";
break;
}
default:
break;
}
}
}
if (parser_.opts.generate_object_based_api) {
GenerateObjectStub(stub, struct_def, imports);
}
if (struct_def->fixed) {
GenerateStructBuilderStub(stub, struct_def, imports);
} else {
GenerateTableBuilderStub(stub, struct_def, imports);
}
}
void StructBuilderArgs(const StructDef &struct_def, const std::string prefix,
Imports *imports,
std::vector<std::string> *args) const {
for (const FieldDef *field : struct_def.fields.vec) {
const Type type = IsArray(field->value.type)
? field->value.type.VectorType()
: field->value.type;
if (type.base_type == BASE_TYPE_STRUCT) {
StructBuilderArgs(*field->value.type.struct_def,
prefix + namer_.Field(*field) + "_", imports, args);
} else {
args->push_back(prefix + namer_.Field(*field) + ": " +
TypeOf(type, imports));
}
}
}
void GenerateStructBuilderStub(std::stringstream &stub,
const StructDef *struct_def,
Imports *imports) const {
imports->Import("flatbuffers");
std::vector<std::string> args;
StructBuilderArgs(*struct_def, "", imports, &args);
stub << '\n';
stub << "def Create" + namer_.Type(*struct_def)
<< "(builder: flatbuffers.Builder";
for (const std::string &arg : args) {
stub << ", " << arg;
}
stub << ") -> uoffset: ...\n";
}
void GenerateTableBuilderStub(std::stringstream &stub,
const StructDef *struct_def,
Imports *imports) const {
std::string type = namer_.Type(*struct_def);
/**************************** def TableStart ****************************/
stub << "def ";
if (!parser_.opts.python_no_type_prefix_suffix) stub << type;
stub << "Start(builder: flatbuffers.Builder) -> None: ...\n";
if (!parser_.opts.one_file && !parser_.opts.python_no_type_prefix_suffix) {
stub << "def Start(builder: flatbuffers.Builder) -> None: ...\n";
}
/************************** def TableAddField ***************************/
for (const FieldDef *field : struct_def->fields.vec) {
if (field->deprecated) continue;
stub << "def ";
if (!parser_.opts.python_no_type_prefix_suffix) stub << type;
stub << "Add" << namer_.Method(*field)
<< "(builder: flatbuffers.Builder, "
<< namer_.Variable(*field) + ": ";
if (IsScalar(field->value.type.base_type)) {
stub << TypeOf(field->value.type, imports);
} else if (IsArray(field->value.type)) {
stub << TypeOf(field->value.type.VectorType(), imports);
} else {
stub << "uoffset";
}
stub << ") -> None: ...\n";
if (IsVector(field->value.type)) {
stub << "def ";
if (!parser_.opts.python_no_type_prefix_suffix) stub << type;
stub << "Start" << namer_.Method(*field)
<< "Vector(builder: flatbuffers.Builder, num_elems: int) -> "
"uoffset: ...\n";
if (!parser_.opts.one_file &&
!parser_.opts.python_no_type_prefix_suffix) {
stub << "def Start" << namer_.Method(*field)
<< "Vector(builder: flatbuffers.Builder, num_elems: int) -> "
"uoffset: ...\n";
}
if (GetNestedStruct(field) != nullptr) {
stub << "def " << type << "Make" << namer_.Method(*field)
<< "VectorFromBytes(builder: flatbuffers.Builder, buf: "
"bytes) -> uoffset: ...\n";
if (!parser_.opts.one_file) {
stub << "def Make" << namer_.Method(*field)
<< "VectorFromBytes(builder: flatbuffers.Builder, buf: "
"bytes) -> uoffset: ...\n";
}
}
}
}
/***************************** def TableEnd *****************************/
stub << "def ";
if (!parser_.opts.python_no_type_prefix_suffix) stub << type;
stub << "End(builder: flatbuffers.Builder) -> uoffset: ...\n";
if (!parser_.opts.one_file && !parser_.opts.python_no_type_prefix_suffix) {
stub << "def End(builder: flatbuffers.Builder) -> uoffset: ...\n";
}
}
void GenerateEnumStub(std::stringstream &stub, const EnumDef *enum_def,
Imports *imports) const {
stub << "class " << namer_.Type(*enum_def);
if (version_.major != 3) stub << "(object)";
stub << ":\n";
for (const EnumVal *val : enum_def->Vals()) {
stub << " " << namer_.Variant(*val) << ": "
<< ScalarType(enum_def->underlying_type.base_type) << "\n";
}
if (parser_.opts.generate_object_based_api & enum_def->is_union) {
imports->Import("flatbuffers", "table");
stub << "def " << namer_.Function(*enum_def)
<< "Creator(union_type: " << EnumType(*enum_def, imports)
<< ", table: table.Table) -> " << UnionType(*enum_def, imports)
<< ": ...\n";
}
}
void GenerateImports(std::stringstream &ss, const Imports &imports) {
ss << "from __future__ import annotations\n";
ss << '\n';
ss << "import flatbuffers\n";
if (parser_.opts.python_gen_numpy) {
ss << "import numpy as np\n";
}
ss << '\n';
std::set<std::string> modules;
std::map<std::string, std::set<std::string>> names_by_module;
for (const Import &import : imports.imports) {
if (import.IsLocal()) continue; // skip all local imports
if (import.name == "") {
modules.insert(import.module);
} else {
names_by_module[import.module].insert(import.name);
}
}
for (const std::string &module : modules) {
ss << "import " << module << '\n';
}
for (const auto &import : names_by_module) {
ss << "from " << import.first << " import ";
size_t i = 0;
for (const std::string &name : import.second) {
if (i > 0) ss << ", ";
ss << name;
++i;
}
ss << '\n';
}
}
const Parser &parser_;
const IdlNamer namer_;
const Version version_;
};} // namespace
class PythonGenerator : public BaseGenerator {
public:
PythonGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
const std::string &file_name, const Version &version)
: BaseGenerator(parser, path, file_name, "" /* not used */,
"" /* not used */, "py"),
float_const_gen_("float('nan')", "float('inf')", "float('-inf')"),
namer_(WithFlagOptions(PythonDefaultConfig(), parser.opts, path),
PythonKeywords()) {}
Keywords(version)) {}
// Most field accessors need to retrieve and test the field offset first,
// this is the prefix code for that.
@ -940,7 +1508,9 @@ class PythonGenerator : public BaseGenerator {
GetMemberOfVectorOfStruct(struct_def, field, code_ptr, imports);
} else {
GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
if (parser_.opts.python_gen_numpy) {
GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
}
GetVectorAsNestedFlatbuffer(struct_def, field, code_ptr, imports);
}
break;
@ -951,7 +1521,9 @@ class PythonGenerator : public BaseGenerator {
GetArrayOfStruct(struct_def, field, code_ptr, imports);
} else {
GetArrayOfNonStruct(struct_def, field, code_ptr);
GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
if (parser_.opts.python_gen_numpy) {
GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
}
GetVectorAsNestedFlatbuffer(struct_def, field, code_ptr, imports);
}
break;
@ -1480,13 +2052,17 @@ class PythonGenerator : public BaseGenerator {
return;
}
code += GenIndents(3) + "if np is None:";
GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 4);
if (parser_.opts.python_gen_numpy) {
code += GenIndents(3) + "if np is None:";
GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 4);
// If numpy exists, use the AsNumpy method to optimize the unpack speed.
code += GenIndents(3) + "else:";
code += GenIndents(4) + "self." + field_field + " = " + struct_var + "." +
field_method + "AsNumpy()";
// If numpy exists, use the AsNumpy method to optimize the unpack speed.
code += GenIndents(3) + "else:";
code += GenIndents(4) + "self." + field_field + " = " + struct_var + "." +
field_method + "AsNumpy()";
} else {
GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 3);
}
}
void GenUnPackForScalar(const StructDef &struct_def, const FieldDef &field,
@ -1685,14 +2261,20 @@ class PythonGenerator : public BaseGenerator {
return;
}
code_prefix += GenIndents(3) + "if np is not None and type(self." +
field_field + ") is np.ndarray:";
code_prefix += GenIndents(4) + field_field +
" = builder.CreateNumpyVector(self." + field_field + ")";
code_prefix += GenIndents(3) + "else:";
GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 4);
code_prefix += "(self." + field_field + "[i])";
code_prefix += GenIndents(4) + field_field + " = builder.EndVector()";
if (parser_.opts.python_gen_numpy) {
code_prefix += GenIndents(3) + "if np is not None and type(self." +
field_field + ") is np.ndarray:";
code_prefix += GenIndents(4) + field_field +
" = builder.CreateNumpyVector(self." + field_field + ")";
code_prefix += GenIndents(3) + "else:";
GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 4);
code_prefix += "(self." + field_field + "[i])";
code_prefix += GenIndents(4) + field_field + " = builder.EndVector()";
} else {
GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 3);
code_prefix += "(self." + field_field + "[i])";
code_prefix += GenIndents(4) + field_field + " = builder.EndVector()";
}
}
void GenPackForStructField(const StructDef &struct_def, const FieldDef &field,
@ -2113,7 +2695,9 @@ class PythonGenerator : public BaseGenerator {
const std::string local_import = "." + mod;
code += "import flatbuffers\n";
code += "from flatbuffers.compat import import_numpy\n";
if (parser_.opts.python_gen_numpy) {
code += "from flatbuffers.compat import import_numpy\n";
}
if (parser_.opts.python_typing) {
code += "from typing import Any\n";
@ -2129,7 +2713,9 @@ class PythonGenerator : public BaseGenerator {
}
}
}
code += "np = import_numpy()\n\n";
if (parser_.opts.python_gen_numpy) {
code += "np = import_numpy()\n\n";
}
}
}
@ -2140,6 +2726,7 @@ class PythonGenerator : public BaseGenerator {
std::string code = "";
if (classcode.empty()) {
BeginFile(LastNamespacePart(ns), false, &code, "", {});
code += "# NOTE " + defname + " does not declare any structs or enums\n";
} else {
BeginFile(LastNamespacePart(ns), needs_imports, &code, mod, imports);
code += classcode;
@ -2169,8 +2756,17 @@ class PythonGenerator : public BaseGenerator {
static bool GeneratePython(const Parser &parser, const std::string &path,
const std::string &file_name) {
python::PythonGenerator generator(parser, path, file_name);
return generator.generate();
python::Version version{parser.opts.python_version};
if (!version.IsValid()) return false;
python::PythonGenerator generator(parser, path, file_name, version);
if (!generator.generate()) return false;
if (parser.opts.python_typing) {
python::PythonStubGenerator stub_generator(parser, path, version);
if (!stub_generator.Generate()) return false;
}
return true;
}
namespace {

View File

@ -2,3 +2,4 @@
# namespace: OtherNameSpace
# NOTE FromInclude.py does not declare any structs or enums

View File

@ -0,0 +1,50 @@
from __future__ import annotations
import flatbuffers
import numpy as np
import flatbuffers
import typing
from MyGame.Example.ArrayStruct import ArrayStruct
from MyGame.Example.NestedStruct import NestedStruct, NestedStructT
from MyGame.Example.TestEnum import TestEnum
uoffset: typing.TypeAlias = flatbuffers.number_types.UOffsetTFlags.py_type
class ArrayStruct(object):
@classmethod
def SizeOf(cls) -> int: ...
def Init(self, buf: bytes, pos: int) -> None: ...
def A(self) -> float: ...
def B(self, i: int) -> typing.List[int]: ...
def BAsNumpy(self) -> np.ndarray: ...
def BLength(self) -> int: ...
def BIsNone(self) -> bool: ...
def C(self) -> int: ...
def D(self, i: int) -> NestedStruct | None: ...
def DLength(self) -> int: ...
def DIsNone(self) -> bool: ...
def E(self) -> int: ...
def F(self, i: int) -> typing.List[int]: ...
def FAsNumpy(self) -> np.ndarray: ...
def FLength(self) -> int: ...
def FIsNone(self) -> bool: ...
class ArrayStructT(object):
a: float
b: typing.List[int]
c: int
d: typing.List[NestedStructT]
e: int
f: typing.List[int]
@classmethod
def InitFromBuf(cls, buf: bytes, pos: int) -> ArrayStructT: ...
@classmethod
def InitFromPackedBuf(cls, buf: bytes, pos: int = 0) -> ArrayStructT: ...
@classmethod
def InitFromObj(cls, arrayStruct: ArrayStruct) -> ArrayStructT: ...
def _UnPack(self, arrayStruct: ArrayStruct) -> None: ...
def Pack(self, builder: flatbuffers.Builder) -> None: ...
def CreateArrayStruct(builder: flatbuffers.Builder, a: float, b: int, c: int, d_a: int, d_b: typing.Literal[TestEnum.A, TestEnum.B, TestEnum.C], d_c: typing.Literal[TestEnum.A, TestEnum.B, TestEnum.C], d_d: int, e: int, f: int) -> uoffset: ...

View File

@ -0,0 +1,37 @@
from __future__ import annotations
import flatbuffers
import numpy as np
import flatbuffers
import typing
from MyGame.Example.ArrayStruct import ArrayStruct, ArrayStructT
from MyGame.Example.ArrayTable import ArrayTable
uoffset: typing.TypeAlias = flatbuffers.number_types.UOffsetTFlags.py_type
class ArrayTable(object):
@classmethod
def GetRootAs(cls, buf: bytes, offset: int) -> ArrayTable: ...
@classmethod
def GetRootAsArrayTable(cls, buf: bytes, offset: int) -> ArrayTable: ...
@classmethod
def ArrayTableBufferHasIdentifier(cls, buf: bytes, offset: int, size_prefixed: bool) -> bool: ...
def Init(self, buf: bytes, pos: int) -> None: ...
def A(self) -> ArrayStruct | None: ...
class ArrayTableT(object):
a: ArrayStructT | None
@classmethod
def InitFromBuf(cls, buf: bytes, pos: int) -> ArrayTableT: ...
@classmethod
def InitFromPackedBuf(cls, buf: bytes, pos: int = 0) -> ArrayTableT: ...
@classmethod
def InitFromObj(cls, arrayTable: ArrayTable) -> ArrayTableT: ...
def _UnPack(self, arrayTable: ArrayTable) -> None: ...
def Pack(self, builder: flatbuffers.Builder) -> None: ...
def ArrayTableStart(builder: flatbuffers.Builder) -> None: ...
def Start(builder: flatbuffers.Builder) -> None: ...
def ArrayTableAddA(builder: flatbuffers.Builder, a: uoffset) -> None: ...
def ArrayTableEnd(builder: flatbuffers.Builder) -> uoffset: ...
def End(builder: flatbuffers.Builder) -> uoffset: ...

View File

@ -0,0 +1,46 @@
from __future__ import annotations
import flatbuffers
import numpy as np
import flatbuffers
import typing
from MyGame.Example.NestedStruct import NestedStruct
from MyGame.Example.TestEnum import TestEnum
uoffset: typing.TypeAlias = flatbuffers.number_types.UOffsetTFlags.py_type
class NestedStruct(object):
@classmethod
def SizeOf(cls) -> int: ...
def Init(self, buf: bytes, pos: int) -> None: ...
def A(self, i: int) -> typing.List[int]: ...
def AAsNumpy(self) -> np.ndarray: ...
def ALength(self) -> int: ...
def AIsNone(self) -> bool: ...
def B(self) -> typing.Literal[TestEnum.A, TestEnum.B, TestEnum.C]: ...
def C(self, i: int) -> typing.Literal[TestEnum.A, TestEnum.B, TestEnum.C]: ...
def CAsNumpy(self) -> np.ndarray: ...
def CLength(self) -> int: ...
def CIsNone(self) -> bool: ...
def D(self, i: int) -> typing.List[int]: ...
def DAsNumpy(self) -> np.ndarray: ...
def DLength(self) -> int: ...
def DIsNone(self) -> bool: ...
class NestedStructT(object):
a: typing.List[int]
b: typing.Literal[TestEnum.A, TestEnum.B, TestEnum.C]
c: typing.List[typing.Literal[TestEnum.A, TestEnum.B, TestEnum.C]]
d: typing.List[int]
@classmethod
def InitFromBuf(cls, buf: bytes, pos: int) -> NestedStructT: ...
@classmethod
def InitFromPackedBuf(cls, buf: bytes, pos: int = 0) -> NestedStructT: ...
@classmethod
def InitFromObj(cls, nestedStruct: NestedStruct) -> NestedStructT: ...
def _UnPack(self, nestedStruct: NestedStruct) -> None: ...
def Pack(self, builder: flatbuffers.Builder) -> None: ...
def CreateNestedStruct(builder: flatbuffers.Builder, a: int, b: typing.Literal[TestEnum.A, TestEnum.B, TestEnum.C], c: typing.Literal[TestEnum.A, TestEnum.B, TestEnum.C], d: int) -> uoffset: ...

View File

@ -0,0 +1,20 @@
from __future__ import annotations
import flatbuffers
import numpy as np
import flatbuffers
import typing
from MyGame.Example.NestedUnion.Any import Any
from MyGame.Example.NestedUnion.TestSimpleTableWithEnum import TestSimpleTableWithEnum
from MyGame.Example.NestedUnion.Vec3 import Vec3
from flatbuffers import table
uoffset: typing.TypeAlias = flatbuffers.number_types.UOffsetTFlags.py_type
class Any(object):
NONE: int
Vec3: int
TestSimpleTableWithEnum: int
def AnyCreator(union_type: typing.Literal[Any.NONE, Any.Vec3, Any.TestSimpleTableWithEnum], table: table.Table) -> typing.Union[None, Vec3, TestSimpleTableWithEnum]: ...

View File

@ -0,0 +1,15 @@
from __future__ import annotations
import flatbuffers
import numpy as np
import flatbuffers
import typing
uoffset: typing.TypeAlias = flatbuffers.number_types.UOffsetTFlags.py_type
class Color(object):
Red: int
Green: int
Blue: int

View File

@ -0,0 +1,47 @@
from __future__ import annotations
import flatbuffers
import numpy as np
import flatbuffers
import typing
from MyGame.Example.NestedUnion.Any import Any
from MyGame.Example.NestedUnion.NestedUnionTest import NestedUnionTest
from MyGame.Example.NestedUnion.TestSimpleTableWithEnum import TestSimpleTableWithEnumT
from MyGame.Example.NestedUnion.Vec3 import Vec3T
from flatbuffers import table
uoffset: typing.TypeAlias = flatbuffers.number_types.UOffsetTFlags.py_type
class NestedUnionTest(object):
@classmethod
def GetRootAs(cls, buf: bytes, offset: int) -> NestedUnionTest: ...
@classmethod
def GetRootAsNestedUnionTest(cls, buf: bytes, offset: int) -> NestedUnionTest: ...
def Init(self, buf: bytes, pos: int) -> None: ...
def Name(self) -> str | None: ...
def DataType(self) -> typing.Literal[Any.NONE, Any.Vec3, Any.TestSimpleTableWithEnum]: ...
def Data(self) -> table.Table | None: ...
def Id(self) -> int: ...
class NestedUnionTestT(object):
name: str | None
dataType: typing.Literal[Any.NONE, Any.Vec3, Any.TestSimpleTableWithEnum]
data: typing.Union[None, Vec3T, TestSimpleTableWithEnumT]
id: int
@classmethod
def InitFromBuf(cls, buf: bytes, pos: int) -> NestedUnionTestT: ...
@classmethod
def InitFromPackedBuf(cls, buf: bytes, pos: int = 0) -> NestedUnionTestT: ...
@classmethod
def InitFromObj(cls, nestedUnionTest: NestedUnionTest) -> NestedUnionTestT: ...
def _UnPack(self, nestedUnionTest: NestedUnionTest) -> None: ...
def Pack(self, builder: flatbuffers.Builder) -> None: ...
def NestedUnionTestStart(builder: flatbuffers.Builder) -> None: ...
def Start(builder: flatbuffers.Builder) -> None: ...
def NestedUnionTestAddName(builder: flatbuffers.Builder, name: uoffset) -> None: ...
def NestedUnionTestAddDataType(builder: flatbuffers.Builder, dataType: typing.Literal[Any.NONE, Any.Vec3, Any.TestSimpleTableWithEnum]) -> None: ...
def NestedUnionTestAddData(builder: flatbuffers.Builder, data: uoffset) -> None: ...
def NestedUnionTestAddId(builder: flatbuffers.Builder, id: int) -> None: ...
def NestedUnionTestEnd(builder: flatbuffers.Builder) -> uoffset: ...
def End(builder: flatbuffers.Builder) -> uoffset: ...

View File

@ -0,0 +1,32 @@
from __future__ import annotations
import flatbuffers
import numpy as np
import flatbuffers
import typing
from MyGame.Example.NestedUnion.Test import Test
uoffset: typing.TypeAlias = flatbuffers.number_types.UOffsetTFlags.py_type
class Test(object):
@classmethod
def SizeOf(cls) -> int: ...
def Init(self, buf: bytes, pos: int) -> None: ...
def A(self) -> int: ...
def B(self) -> int: ...
class TestT(object):
a: int
b: int
@classmethod
def InitFromBuf(cls, buf: bytes, pos: int) -> TestT: ...
@classmethod
def InitFromPackedBuf(cls, buf: bytes, pos: int = 0) -> TestT: ...
@classmethod
def InitFromObj(cls, test: Test) -> TestT: ...
def _UnPack(self, test: Test) -> None: ...
def Pack(self, builder: flatbuffers.Builder) -> None: ...
def CreateTest(builder: flatbuffers.Builder, a: int, b: int) -> uoffset: ...

View File

@ -0,0 +1,35 @@
from __future__ import annotations
import flatbuffers
import numpy as np
import flatbuffers
import typing
from MyGame.Example.NestedUnion.Color import Color
from MyGame.Example.NestedUnion.TestSimpleTableWithEnum import TestSimpleTableWithEnum
uoffset: typing.TypeAlias = flatbuffers.number_types.UOffsetTFlags.py_type
class TestSimpleTableWithEnum(object):
@classmethod
def GetRootAs(cls, buf: bytes, offset: int) -> TestSimpleTableWithEnum: ...
@classmethod
def GetRootAsTestSimpleTableWithEnum(cls, buf: bytes, offset: int) -> TestSimpleTableWithEnum: ...
def Init(self, buf: bytes, pos: int) -> None: ...
def Color(self) -> typing.Literal[Color.Red, Color.Green, Color.Blue]: ...
class TestSimpleTableWithEnumT(object):
color: typing.Literal[Color.Red, Color.Green, Color.Blue]
@classmethod
def InitFromBuf(cls, buf: bytes, pos: int) -> TestSimpleTableWithEnumT: ...
@classmethod
def InitFromPackedBuf(cls, buf: bytes, pos: int = 0) -> TestSimpleTableWithEnumT: ...
@classmethod
def InitFromObj(cls, testSimpleTableWithEnum: TestSimpleTableWithEnum) -> TestSimpleTableWithEnumT: ...
def _UnPack(self, testSimpleTableWithEnum: TestSimpleTableWithEnum) -> None: ...
def Pack(self, builder: flatbuffers.Builder) -> None: ...
def TestSimpleTableWithEnumStart(builder: flatbuffers.Builder) -> None: ...
def Start(builder: flatbuffers.Builder) -> None: ...
def TestSimpleTableWithEnumAddColor(builder: flatbuffers.Builder, color: typing.Literal[Color.Red, Color.Green, Color.Blue]) -> None: ...
def TestSimpleTableWithEnumEnd(builder: flatbuffers.Builder) -> uoffset: ...
def End(builder: flatbuffers.Builder) -> uoffset: ...

View File

@ -0,0 +1,51 @@
from __future__ import annotations
import flatbuffers
import numpy as np
import flatbuffers
import typing
from MyGame.Example.NestedUnion.Color import Color
from MyGame.Example.NestedUnion.Test import Test, TestT
from MyGame.Example.NestedUnion.Vec3 import Vec3
uoffset: typing.TypeAlias = flatbuffers.number_types.UOffsetTFlags.py_type
class Vec3(object):
@classmethod
def GetRootAs(cls, buf: bytes, offset: int) -> Vec3: ...
@classmethod
def GetRootAsVec3(cls, buf: bytes, offset: int) -> Vec3: ...
def Init(self, buf: bytes, pos: int) -> None: ...
def X(self) -> float: ...
def Y(self) -> float: ...
def Z(self) -> float: ...
def Test1(self) -> float: ...
def Test2(self) -> typing.Literal[Color.Red, Color.Green, Color.Blue]: ...
def Test3(self) -> Test | None: ...
class Vec3T(object):
x: float
y: float
z: float
test1: float
test2: typing.Literal[Color.Red, Color.Green, Color.Blue]
test3: TestT | None
@classmethod
def InitFromBuf(cls, buf: bytes, pos: int) -> Vec3T: ...
@classmethod
def InitFromPackedBuf(cls, buf: bytes, pos: int = 0) -> Vec3T: ...
@classmethod
def InitFromObj(cls, vec3: Vec3) -> Vec3T: ...
def _UnPack(self, vec3: Vec3) -> None: ...
def Pack(self, builder: flatbuffers.Builder) -> None: ...
def Vec3Start(builder: flatbuffers.Builder) -> None: ...
def Start(builder: flatbuffers.Builder) -> None: ...
def Vec3AddX(builder: flatbuffers.Builder, x: float) -> None: ...
def Vec3AddY(builder: flatbuffers.Builder, y: float) -> None: ...
def Vec3AddZ(builder: flatbuffers.Builder, z: float) -> None: ...
def Vec3AddTest1(builder: flatbuffers.Builder, test1: float) -> None: ...
def Vec3AddTest2(builder: flatbuffers.Builder, test2: typing.Literal[Color.Red, Color.Green, Color.Blue]) -> None: ...
def Vec3AddTest3(builder: flatbuffers.Builder, test3: uoffset) -> None: ...
def Vec3End(builder: flatbuffers.Builder) -> uoffset: ...
def End(builder: flatbuffers.Builder) -> uoffset: ...

View File

@ -0,0 +1,15 @@
from __future__ import annotations
import flatbuffers
import numpy as np
import flatbuffers
import typing
uoffset: typing.TypeAlias = flatbuffers.number_types.UOffsetTFlags.py_type
class TestEnum(object):
A: int
B: int
C: int

View File

@ -0,0 +1,74 @@
from __future__ import annotations
import flatbuffers
import numpy as np
import flatbuffers
import typing
from MyGame.MonsterExtra import MonsterExtra
uoffset: typing.TypeAlias = flatbuffers.number_types.UOffsetTFlags.py_type
class MonsterExtra(object):
@classmethod
def GetRootAs(cls, buf: bytes, offset: int) -> MonsterExtra: ...
@classmethod
def GetRootAsMonsterExtra(cls, buf: bytes, offset: int) -> MonsterExtra: ...
@classmethod
def MonsterExtraBufferHasIdentifier(cls, buf: bytes, offset: int, size_prefixed: bool) -> bool: ...
def Init(self, buf: bytes, pos: int) -> None: ...
def D0(self) -> float: ...
def D1(self) -> float: ...
def D2(self) -> float: ...
def D3(self) -> float: ...
def F0(self) -> float: ...
def F1(self) -> float: ...
def F2(self) -> float: ...
def F3(self) -> float: ...
def Dvec(self, i: int) -> typing.List[float]: ...
def DvecAsNumpy(self) -> np.ndarray: ...
def DvecLength(self) -> int: ...
def DvecIsNone(self) -> bool: ...
def Fvec(self, i: int) -> typing.List[float]: ...
def FvecAsNumpy(self) -> np.ndarray: ...
def FvecLength(self) -> int: ...
def FvecIsNone(self) -> bool: ...
class MonsterExtraT(object):
d0: float
d1: float
d2: float
d3: float
f0: float
f1: float
f2: float
f3: float
dvec: typing.List[float]
fvec: typing.List[float]
@classmethod
def InitFromBuf(cls, buf: bytes, pos: int) -> MonsterExtraT: ...
@classmethod
def InitFromPackedBuf(cls, buf: bytes, pos: int = 0) -> MonsterExtraT: ...
@classmethod
def InitFromObj(cls, monsterExtra: MonsterExtra) -> MonsterExtraT: ...
def _UnPack(self, monsterExtra: MonsterExtra) -> None: ...
def Pack(self, builder: flatbuffers.Builder) -> None: ...
def __eq__(self, other: MonsterExtraT) -> bool: ...
def MonsterExtraStart(builder: flatbuffers.Builder) -> None: ...
def Start(builder: flatbuffers.Builder) -> None: ...
def MonsterExtraAddD0(builder: flatbuffers.Builder, d0: float) -> None: ...
def MonsterExtraAddD1(builder: flatbuffers.Builder, d1: float) -> None: ...
def MonsterExtraAddD2(builder: flatbuffers.Builder, d2: float) -> None: ...
def MonsterExtraAddD3(builder: flatbuffers.Builder, d3: float) -> None: ...
def MonsterExtraAddF0(builder: flatbuffers.Builder, f0: float) -> None: ...
def MonsterExtraAddF1(builder: flatbuffers.Builder, f1: float) -> None: ...
def MonsterExtraAddF2(builder: flatbuffers.Builder, f2: float) -> None: ...
def MonsterExtraAddF3(builder: flatbuffers.Builder, f3: float) -> None: ...
def MonsterExtraAddDvec(builder: flatbuffers.Builder, dvec: uoffset) -> None: ...
def MonsterExtraStartDvecVector(builder: flatbuffers.Builder, num_elems: int) -> uoffset: ...
def StartDvecVector(builder: flatbuffers.Builder, num_elems: int) -> uoffset: ...
def MonsterExtraAddFvec(builder: flatbuffers.Builder, fvec: uoffset) -> None: ...
def MonsterExtraStartFvecVector(builder: flatbuffers.Builder, num_elems: int) -> uoffset: ...
def StartFvecVector(builder: flatbuffers.Builder, num_elems: int) -> uoffset: ...
def MonsterExtraEnd(builder: flatbuffers.Builder) -> uoffset: ...
def End(builder: flatbuffers.Builder) -> uoffset: ...

View File

@ -2,3 +2,4 @@
# namespace: OtherNameSpace
# NOTE FromInclude.py does not declare any structs or enums

View File

@ -2,3 +2,4 @@
# namespace: OtherNameSpace
# NOTE TableB.py does not declare any structs or enums

View File

@ -2,3 +2,4 @@
# namespace: OtherNameSpace
# NOTE Unused.py does not declare any structs or enums

View File

@ -2,3 +2,4 @@
# namespace:
# NOTE TableA.py does not declare any structs or enums