🎉 First commit
This commit is contained in:
commit
206c6e1bf0
|
@ -0,0 +1,149 @@
|
|||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/python
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=python
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/python
|
||||
|
||||
|
||||
# VSCode
|
||||
.vscode
|
|
@ -0,0 +1,15 @@
|
|||
import argparse
|
||||
from openscad_pycustomizer import scad_parser
|
||||
import json
|
||||
|
||||
parser = argparse.ArgumentParser(description='Process some integers.')
|
||||
parser.add_argument('file', metavar='N', type=str,
|
||||
help='The .scad file')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
print(json.dumps(
|
||||
scad_parser.parse(args.file),
|
||||
cls=scad_parser.CustomizerProfileEncoder,
|
||||
indent=4
|
||||
))
|
|
@ -0,0 +1,77 @@
|
|||
// Random value with no section
|
||||
Value = 2; // Number
|
||||
|
||||
/* [Drop down box:] */
|
||||
// combo box for number
|
||||
Numbers=2; // [0, 1, 2, 3]
|
||||
|
||||
// combo box for string
|
||||
Strings="foo"; // [foo, bar, baz]
|
||||
|
||||
//labeled combo box for numbers
|
||||
Labeled_values=10; // [10:L, 20:M, 30:XL]
|
||||
|
||||
//labeled combo box for string
|
||||
Labeled_value="S"; // [S:Small, M:Medium, L:Large]
|
||||
|
||||
/*[ Slider ]*/
|
||||
// slider widget for number
|
||||
slider =34; // [10:100]
|
||||
|
||||
//step slider for number
|
||||
stepSlider=2; //[0:5:100]
|
||||
|
||||
/* [Checkbox] */
|
||||
|
||||
//description
|
||||
Variable = true;
|
||||
|
||||
/*[Spinbox] */
|
||||
|
||||
// spinbox with step size 1
|
||||
Spinbox = 5;
|
||||
|
||||
/* [Textbox] */
|
||||
|
||||
//Text box for vector with more than 4 elements
|
||||
Vector6=[12,34,44,43,23,23];
|
||||
|
||||
// Text box for string
|
||||
String="hello";
|
||||
|
||||
/* [Special vector] */
|
||||
//Text box for vector with less than or equal to 4 elements
|
||||
Vector1=[12]; //[0:2:50]
|
||||
Vector2=[12,34]; //[0:2:50]
|
||||
Vector3=[12,34,46]; //[0:2:50]
|
||||
Vector4=[12,34,46,24]; //[0:2:50]
|
||||
|
||||
|
||||
cube([2,3,4]);
|
||||
|
||||
|
||||
echo(version=version());
|
||||
|
||||
intersection()
|
||||
{
|
||||
linear_extrude(height = 100, center = true, convexity= 3)
|
||||
import(file = "advance_intersection.dxf");
|
||||
rotate([0, 90, 0])
|
||||
linear_extrude(height = 100, center = true, convexity= 3)
|
||||
import(file = "advance_intersection.dxf");
|
||||
rotate([90, 0, 0])
|
||||
linear_extrude(height = 100, center = true, convexity= 3)
|
||||
import(file = "advance_intersection.dxf");
|
||||
}
|
||||
|
||||
// Written by Clifford Wolf <clifford@clifford.at> and Marius
|
||||
// Kintel <marius@kintel.net>
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all
|
||||
// copyright and related and neighboring rights to this software to the
|
||||
// public domain worldwide. This software is distributed without any
|
||||
// warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain
|
||||
// Dedication along with this software.
|
||||
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
|
@ -0,0 +1,6 @@
|
|||
[build-system]
|
||||
requires = [
|
||||
"setuptools>=42",
|
||||
"wheel"
|
||||
]
|
||||
build-backend = "setuptools.build_meta"
|
|
@ -0,0 +1,26 @@
|
|||
[metadata]
|
||||
name = openscad_pycustomizer
|
||||
version = 0.0.1
|
||||
author = Rodolphe Houdas
|
||||
author_email = rodolphe@lunai.re
|
||||
description = Parse customizer data from .scad files
|
||||
long_description = file: README.md
|
||||
long_description_content_type = text/markdown
|
||||
url = https://forge.lunai.re/openscad-pycustomizer
|
||||
project_urls =
|
||||
Bug Tracker = https://forge.lunai.re/openscad-pycustomizer/issues
|
||||
classifiers =
|
||||
Programming Language :: Python :: 3
|
||||
License :: OSI Approved :: MIT License
|
||||
Operating System :: OS Independent
|
||||
|
||||
[options]
|
||||
package_dir =
|
||||
= src
|
||||
scripts =
|
||||
bin/customizer.py
|
||||
packages = find:
|
||||
python_requires = >=3.6
|
||||
|
||||
[options.packages.find]
|
||||
where = src
|
|
@ -0,0 +1,167 @@
|
|||
import dataclasses
|
||||
from dataclasses import dataclass
|
||||
import json
|
||||
|
||||
|
||||
"""
|
||||
Types that must be supported:
|
||||
* int
|
||||
* float
|
||||
* string
|
||||
* bool
|
||||
* list
|
||||
"""
|
||||
|
||||
|
||||
@dataclass
|
||||
class Element:
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class Variable(Element):
|
||||
text: str
|
||||
value: str
|
||||
description: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class IntVariable(Variable):
|
||||
value: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class FloatVariable(Variable):
|
||||
value: float
|
||||
|
||||
|
||||
@dataclass
|
||||
class StringVariable(Variable):
|
||||
value: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class BoolVariable(Variable):
|
||||
value: bool
|
||||
|
||||
|
||||
@dataclass
|
||||
class Section(Element):
|
||||
text: str
|
||||
elements: list[Element]
|
||||
|
||||
|
||||
@dataclass
|
||||
class CustomizerData:
|
||||
elements: list[Element]
|
||||
|
||||
@staticmethod
|
||||
def flatten(data):
|
||||
"""
|
||||
Return a list of parameters
|
||||
"""
|
||||
elems = {}
|
||||
for elem in data.elements:
|
||||
if isinstance(elem, Section):
|
||||
for param in elem.elements:
|
||||
elems[param.text] = param.value
|
||||
else:
|
||||
elems[elem.text] = elem.value
|
||||
return elems
|
||||
|
||||
|
||||
class EnhancedJSONEncoder(json.JSONEncoder):
|
||||
def default(self, o):
|
||||
if dataclasses.is_dataclass(o):
|
||||
return dataclasses.asdict(o)
|
||||
return super().default(o)
|
||||
|
||||
|
||||
class CustomizerProfileEncoder(json.JSONEncoder):
|
||||
def default(self, o):
|
||||
if isinstance(o, CustomizerData):
|
||||
return CustomizerData.flatten(o)
|
||||
return super().default(o)
|
||||
|
||||
|
||||
def parse_type(value):
|
||||
# Parse type
|
||||
if ((value[0] == "\"" or value[0] == "'")
|
||||
and (value[-1] == "\"" or value[-1] == "'")):
|
||||
value = value.strip("\"").strip("'")
|
||||
|
||||
elif value == "true" or value == "false":
|
||||
value = bool(value)
|
||||
|
||||
elif value[0] == "[" and value[-1] == "]":
|
||||
value = value[1:-2].split(",")
|
||||
for index in range(len(value)):
|
||||
value[index] = parse_type(value[index])
|
||||
|
||||
elif len(value.split(".")):
|
||||
value = float(value)
|
||||
|
||||
else:
|
||||
value = int(value)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def parse(file):
|
||||
with open(file) as scad_file:
|
||||
section = None
|
||||
all_elems = []
|
||||
elems = []
|
||||
description = None
|
||||
for line in scad_file.readlines():
|
||||
line = line.strip()
|
||||
|
||||
# Checking for section title
|
||||
if line[0:2] == "/*":
|
||||
(middle, end) = line[2:].strip().split("*/")
|
||||
middle = middle.strip()
|
||||
|
||||
if section is None:
|
||||
all_elems.extend(elems)
|
||||
else:
|
||||
all_elems.append(Section(section, elems))
|
||||
|
||||
section = middle
|
||||
elems = []
|
||||
|
||||
# Checking for comment
|
||||
elif line[0:2] == "//":
|
||||
description = line[2:].strip()
|
||||
|
||||
# Checking for text
|
||||
elif len(line.strip()) > 0 and len(line.split("=")) == 2:
|
||||
(name, value) = line.split("=")
|
||||
name = name.strip()
|
||||
value = value.split(";")[0].strip()
|
||||
|
||||
try:
|
||||
value = parse_type(value)
|
||||
except ValueError as e:
|
||||
print(f"Error parsing a value: {e}")
|
||||
print("Stopping parsing")
|
||||
break
|
||||
|
||||
elems.append(
|
||||
Variable(
|
||||
name,
|
||||
value,
|
||||
"" if description is None else description
|
||||
)
|
||||
)
|
||||
description = None
|
||||
|
||||
elif len(line) == 0:
|
||||
pass
|
||||
|
||||
else:
|
||||
break
|
||||
|
||||
all_elems.append(Section(section, elems))
|
||||
|
||||
data = CustomizerData(all_elems)
|
||||
return data
|
Loading…
Reference in New Issue