This extends the existing XML-based template generator to allow an
additional kind of Python-based input.
The Python code is read as source code to an AST to a typed model
equivalent to the existing XML model, and processed by the existing
code templates into compatible code.
This provides a few benefits, namely readability is much increased,
but more importantly, it allows associating the APIs with Python's new
typing information, which will allow to provide accurate type hinting
without additional downstream processing in the future.
Right now this is just a proof-of-concept but if the approach is
well received, then a more complete implementation can be done with
further conversion of existing binding files.
Here is an example of how it looks, though I still think the metadata
is too verbose and can be made to look nicer with some further work.
```python
from ..Base.Metadata import metadata
from ..Base.Persistence import PersistencePy
from typing import Any, Optional, List
@metadata(
Father="PersistencePy",
Name="DocumentPy",
Twin="Document",
TwinPointer="Document",
Include="Gui/Document.h",
Namespace="Gui",
FatherInclude="Base/PersistencePy.h",
FatherNamespace="Base"
)
class DocumentPy(PersistencePy):
"""
This is a Document class.
Author: Werner Mayer (wmayer@users.sourceforge.net)
Licence: LGPL
"""
def __init__(self, *args: Any, **kwargs: Any) -> None:
"""
Constructor for DocumentPy.
"""
super(DocumentPy, self).__init__(*args, **kwargs)
pass
def show(self, objName: str) -> None:
"""
show(objName) -> None
Show an object.
Parameters:
objName (str): Name of the `Gui.ViewProvider` to show.
"""
pass
```
113 lines
3.0 KiB
Python
113 lines
3.0 KiB
Python
#! python
|
|
# -*- coding: utf-8 -*-
|
|
# (c) 2006 Jürgen Riegel GPL
|
|
|
|
import os
|
|
import sys
|
|
import getopt
|
|
import model.generateModel_Module
|
|
import model.generateModel_Python
|
|
import templates.templateModule
|
|
import templates.templateClassPyExport
|
|
|
|
|
|
Usage = """generate - generates a FreeCAD Module out of an XML or Python model
|
|
|
|
Usage:
|
|
generate [Optionen] Model.xml/py Model2.xml/py Model3.xml/py ...
|
|
|
|
Options:
|
|
-h, --help print this help
|
|
-o, --outputPath specify the output path if differs from source path
|
|
|
|
Generate source code out of an model definition.
|
|
|
|
Author:
|
|
(c) 2006 Juergen Riegel
|
|
juergen.riegel@web.de
|
|
Licence: GPL
|
|
|
|
Version:
|
|
0.3
|
|
"""
|
|
|
|
|
|
# Globals
|
|
|
|
|
|
def generate_model(filename):
|
|
if filename.endswith(".xml"):
|
|
return model.generateModel_Module.parse(filename)
|
|
elif filename.endswith(".pyi"):
|
|
return model.generateModel_Python.parse(filename)
|
|
raise ValueError("invalid file extension")
|
|
|
|
|
|
def generate(filename, outputPath):
|
|
GenerateModelInst = generate_model(filename)
|
|
|
|
if len(GenerateModelInst.Module) != 0:
|
|
Module = templates.templateModule.TemplateModule()
|
|
Module.outputDir = outputPath
|
|
Module.module = GenerateModelInst.Module[0]
|
|
Module.Generate()
|
|
print("Done generating: " + GenerateModelInst.Module[0].Name)
|
|
else:
|
|
Export = templates.templateClassPyExport.TemplateClassPyExport()
|
|
Export.outputDir = outputPath + "/"
|
|
Export.inputDir = os.path.dirname(filename) + "/"
|
|
Export.export = GenerateModelInst.PythonExport[0]
|
|
Export.is_python = filename.endswith(".py")
|
|
Export.Generate()
|
|
if Export.is_python:
|
|
Export.Compare()
|
|
print("Done generating: " + GenerateModelInst.PythonExport[0].Name)
|
|
|
|
|
|
def main():
|
|
verbose = False
|
|
outputPath = ""
|
|
|
|
class generateOutput:
|
|
def write(self, data):
|
|
pass
|
|
|
|
def flush(self): # mandatory for file-like objects
|
|
pass
|
|
|
|
try:
|
|
opts, args = getopt.getopt(sys.argv[1:], "hvo:", ["help", "verbose", "outputPath="])
|
|
except getopt.GetoptError:
|
|
# print help information and exit:
|
|
sys.stderr.write(Usage)
|
|
sys.exit(2)
|
|
|
|
# checking on the options
|
|
for o, a in opts:
|
|
if o in ("-h", "--help"):
|
|
sys.stderr.write(Usage)
|
|
sys.exit()
|
|
if o in ("-o", "--outputPath"):
|
|
outputPath = a
|
|
if o in ("-v", "--verbose"):
|
|
verbose = True
|
|
|
|
if not verbose:
|
|
sys.stdout = generateOutput()
|
|
|
|
# running through the files
|
|
if len(args) == 0:
|
|
sys.stderr.write(Usage)
|
|
else:
|
|
for i in args:
|
|
filename = os.path.abspath(i)
|
|
if outputPath == "":
|
|
head, _ = os.path.split(filename)
|
|
generate(filename, head)
|
|
else:
|
|
generate(filename, outputPath)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|