Skip to content

Commit a1b4983

Browse files
author
Onur Rauf Bingol
committed
Add jinja2 template support to json, yaml and cfg importers
geomdl-cli's jinja2 template processing functionality will be moved to geomdl package for user convenience
1 parent 5f631bc commit a1b4983

File tree

2 files changed

+83
-46
lines changed

2 files changed

+83
-46
lines changed

geomdl/_exchange.py

+15-9
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,12 @@ def tmpl_pow(x, y):
6464
def read_file(file_name, **kwargs):
6565
binary = kwargs.get('binary', False)
6666
skip_lines = kwargs.get('skip_lines', 0)
67-
fp_callback = kwargs.get('callback', None)
67+
callback = kwargs.get('callback', None)
6868
try:
6969
with open(file_name, 'rb' if binary else 'r') as fp:
7070
for _ in range(skip_lines):
7171
next(fp)
72-
content = fp.read() if fp_callback is None else fp_callback(fp)
72+
content = fp.read() if callback is None else callback(fp)
7373
return content
7474
except IOError as e:
7575
print("An error occurred: {}".format(e.args[-1]))
@@ -277,16 +277,19 @@ def export_text_data(obj, sep, col_sep=";", two_dimensional=False):
277277
return result
278278

279279

280-
def import_dict(file_name, delta, callback):
281-
type_map = {'curve': import_dict_crv, 'surface': import_dict_surf}
280+
def import_dict_str(file_src, delta, callback, tmpl):
281+
mapping = {'curve': import_dict_crv, 'surface': import_dict_surf}
282282

283-
# Callback function
284-
imported_data = read_file(file_name, callback=callback)
283+
# Process template
284+
if tmpl:
285+
file_src = process_template(file_src)
286+
# Execute callback function
287+
imported_data = callback(file_src)
285288

286289
# Process imported data
287290
ret_list = []
288291
for data in imported_data['shape']['data']:
289-
temp = type_map[imported_data['shape']['type']](data)
292+
temp = mapping[imported_data['shape']['type']](data)
290293
if 0.0 < delta < 1.0:
291294
temp.delta = delta
292295
ret_list.append(temp)
@@ -295,7 +298,7 @@ def import_dict(file_name, delta, callback):
295298
return ret_list
296299

297300

298-
def export_dict(obj, file_name, callback):
301+
def export_dict_str(obj, callback):
299302
count = 1
300303
if isinstance(obj, abstract.Curve):
301304
export_type = "curve"
@@ -323,4 +326,7 @@ def export_dict(obj, file_name, callback):
323326
)
324327
)
325328

326-
return write_file(file_name, data, callback=callback)
329+
# Execute callback function
330+
exported_data = callback(data)
331+
332+
return exported_data

geomdl/exchange.py

+68-37
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
import os
1111
import struct
1212
import json
13+
from io import StringIO
1314
from . import abstract, NURBS, multi, compatibility, operations, utilities, convert
14-
from . import _exchange
15+
from . import _exchange as exch
1516

1617

1718
def import_txt(file_name, two_dimensional=False, **kwargs):
@@ -69,18 +70,18 @@ def import_txt(file_name, two_dimensional=False, **kwargs):
6970
:raises IOError: an error occurred reading the file
7071
"""
7172
# Read file
72-
content = _exchange.read_file(file_name)
73+
content = exch.read_file(file_name)
7374

7475
# Are we using a Jinja2 template?
7576
j2tmpl = kwargs.get('jinja2', False)
7677
if j2tmpl:
77-
content = _exchange.process_template(content)
78+
content = exch.process_template(content)
7879

7980
# File delimiters
8081
col_sep = kwargs.get('col_separator', ";")
8182
sep = kwargs.get('separator', ",")
8283

83-
return _exchange.import_text_data(content, sep, col_sep, two_dimensional)
84+
return exch.import_text_data(content, sep, col_sep, two_dimensional)
8485

8586

8687
def export_txt(obj, file_name, two_dimensional=False, **kwargs):
@@ -113,8 +114,8 @@ def export_txt(obj, file_name, two_dimensional=False, **kwargs):
113114
col_sep = kwargs.get('col_separator', ";")
114115
sep = kwargs.get('separator', ",")
115116

116-
content = _exchange.export_text_data(obj, sep, col_sep, two_dimensional)
117-
return _exchange.write_file(file_name, content)
117+
content = exch.export_text_data(obj, sep, col_sep, two_dimensional)
118+
return exch.write_file(file_name, content)
118119

119120

120121
def import_csv(file_name, **kwargs):
@@ -143,8 +144,8 @@ def import_csv(file_name, **kwargs):
143144
# File delimiters
144145
sep = kwargs.get('separator', ",")
145146

146-
content = _exchange.read_file(file_name, skip_lines=1)
147-
return _exchange.import_text_data(content, sep)
147+
content = exch.read_file(file_name, skip_lines=1)
148+
return exch.import_text_data(content, sep)
148149

149150

150151
def export_csv(obj, file_name, point_type='evalpts', **kwargs):
@@ -181,7 +182,7 @@ def export_csv(obj, file_name, point_type='evalpts', **kwargs):
181182
line += ",".join([str(p) for p in pt]) + "\n"
182183

183184
# Write to file
184-
return _exchange.write_file(file_name, line)
185+
return exch.write_file(file_name, line)
185186

186187

187188
def import_cfg(file_name, **kwargs):
@@ -191,14 +192,16 @@ def import_cfg(file_name, **kwargs):
191192
192193
Requires `libconf <https://pypi.org/project/libconf/>`_ package.
193194
195+
Use ``jinja2=True`` to activate Jinja2 template processing. Please refer to the documentation for details.
196+
194197
:param file_name: name of the input file
195198
:type file_name: str
196199
:return: a list of NURBS curve(s) or surface(s)
197200
:rtype: list
198201
:raises IOError: an error occurred writing the file
199202
"""
200-
def callback(fp):
201-
return libconf.load(fp)
203+
def callback(data):
204+
return libconf.loads(data)
202205

203206
# Check if it is possible to import 'libconf'
204207
try:
@@ -209,9 +212,13 @@ def callback(fp):
209212

210213
# Get keyword arguments
211214
delta = kwargs.get('delta', -1.0)
215+
use_template = kwargs.get('jinja2', False)
216+
217+
# Read file
218+
file_src = exch.read_file(file_name)
212219

213220
# Import data
214-
return _exchange.import_dict(file_name, delta, callback)
221+
return exch.import_dict_str(file_src=file_src, delta=delta, callback=callback, tmpl=use_template)
215222

216223

217224
def export_cfg(obj, file_name):
@@ -231,8 +238,8 @@ def export_cfg(obj, file_name):
231238
:raises IOError: an error occurred writing the file
232239
"""
233240

234-
def callback(fp, data):
235-
fp.write(libconf.dumps(data))
241+
def callback(data):
242+
return libconf.dumps(data)
236243

237244
# Check if it is possible to import 'libconf'
238245
try:
@@ -241,8 +248,11 @@ def callback(fp, data):
241248
print("Please install 'libconf' package to use libconfig format: pip install libconf")
242249
return
243250

244-
# Export data as a file
245-
_exchange.export_dict(obj, file_name, callback)
251+
# Export data
252+
exported_data = exch.export_dict_str(obj=obj, callback=callback)
253+
254+
# Write to file
255+
return exch.write_file(file_name, exported_data)
246256

247257

248258
def import_yaml(file_name, **kwargs):
@@ -252,15 +262,17 @@ def import_yaml(file_name, **kwargs):
252262
253263
Requires `ruamel.yaml <https://pypi.org/project/ruamel.yaml/>`_ package.
254264
265+
Use ``jinja2=True`` to activate Jinja2 template processing. Please refer to the documentation for details.
266+
255267
:param file_name: name of the input file
256268
:type file_name: str
257269
:return: a list of NURBS curve(s) or surface(s)
258270
:rtype: list
259271
:raises IOError: an error occurred reading the file
260272
"""
261-
def callback(fp):
273+
def callback(data):
262274
yaml = YAML()
263-
return yaml.load(fp)
275+
return yaml.load(data)
264276

265277
# Check if it is possible to import 'ruamel.yaml'
266278
try:
@@ -271,9 +283,13 @@ def callback(fp):
271283

272284
# Get keyword arguments
273285
delta = kwargs.get('delta', -1.0)
286+
use_template = kwargs.get('jinja2', False)
287+
288+
# Read file
289+
file_src = exch.read_file(file_name)
274290

275291
# Import data
276-
return _exchange.import_dict(file_name, delta, callback)
292+
return exch.import_dict_str(file_src=file_src, delta=delta, callback=callback, tmpl=use_template)
277293

278294

279295
def export_yaml(obj, file_name):
@@ -292,9 +308,12 @@ def export_yaml(obj, file_name):
292308
:type file_name: str
293309
:raises IOError: an error occurred writing the file
294310
"""
295-
def callback(fp, data):
311+
def callback(data):
312+
# Ref: https://yaml.readthedocs.io/en/latest/example.html#output-of-dump-as-a-string
313+
stream = StringIO()
296314
yaml = YAML()
297-
yaml.dump(data, fp)
315+
yaml.dump(data, stream)
316+
return stream.getvalue()
298317

299318
# Check if it is possible to import 'ruamel.yaml'
300319
try:
@@ -303,27 +322,36 @@ def callback(fp, data):
303322
print("Please install 'ruamel.yaml' package to use YAML format: pip install ruamel.yaml")
304323
return
305324

306-
# Export data as a file
307-
_exchange.export_dict(obj, file_name, callback)
325+
# Export data
326+
exported_data = exch.export_dict_str(obj=obj, callback=callback)
327+
328+
# Write to file
329+
return exch.write_file(file_name, exported_data)
308330

309331

310332
def import_json(file_name, **kwargs):
311333
""" Imports curves and surfaces from files in JSON format.
312334
335+
Use ``jinja2=True`` to activate Jinja2 template processing. Please refer to the documentation for details.
336+
313337
:param file_name: name of the input file
314338
:type file_name: str
315339
:return: a list of NURBS curve(s) or surface(s)
316340
:rtype: list
317341
:raises IOError: an error occurred reading the file
318342
"""
319-
def callback(fp):
320-
return json.load(fp)
343+
def callback(data):
344+
return json.loads(data)
321345

322346
# Get keyword arguments
323347
delta = kwargs.get('delta', -1.0)
348+
use_template = kwargs.get('jinja2', False)
349+
350+
# Read file
351+
file_src = exch.read_file(file_name)
324352

325353
# Import data
326-
return _exchange.import_dict(file_name, delta, callback)
354+
return exch.import_dict_str(file_src=file_src, delta=delta, callback=callback, tmpl=use_template)
327355

328356

329357
def export_json(obj, file_name):
@@ -338,11 +366,14 @@ def export_json(obj, file_name):
338366
:type file_name: str
339367
:raises IOError: an error occurred writing the file
340368
"""
341-
def callback(fp, data):
342-
fp.write(json.dumps(data, indent=4))
369+
def callback(data):
370+
return json.dumps(data, indent=4)
371+
372+
# Export data
373+
exported_data = exch.export_dict_str(obj=obj, callback=callback)
343374

344-
# Export data as a file
345-
_exchange.export_dict(obj, file_name, callback)
375+
# Write to file
376+
return exch.write_file(file_name, exported_data)
346377

347378

348379
def export_obj(surface, file_name, **kwargs):
@@ -360,7 +391,7 @@ def export_obj(surface, file_name, **kwargs):
360391
:raises IOError: an error occurred writing the file
361392
"""
362393
content = export_obj_str(surface, **kwargs)
363-
return _exchange.write_file(file_name, content)
394+
return exch.write_file(file_name, content)
364395

365396

366397
def export_obj_str(surface, **kwargs):
@@ -465,7 +496,7 @@ def export_stl(surface, file_name, **kwargs):
465496
if 'binary' in kwargs:
466497
kwargs.pop('binary')
467498
content = export_stl_str(surface, binary=binary, **kwargs)
468-
return _exchange.write_file(file_name, content, binary=binary)
499+
return exch.write_file(file_name, content, binary=binary)
469500

470501

471502
def export_stl_str(surface, **kwargs):
@@ -546,7 +577,7 @@ def export_off(surface, file_name, **kwargs):
546577
:raises IOError: an error occurred writing the file
547578
"""
548579
content = export_off_str(surface, **kwargs)
549-
return _exchange.write_file(file_name, content)
580+
return exch.write_file(file_name, content)
550581

551582

552583
def export_off_str(surface, **kwargs):
@@ -643,12 +674,12 @@ def import_smesh(file):
643674
:raises IOError: an error occurred reading the file
644675
"""
645676
if os.path.isfile(file):
646-
return _exchange.import_smesh_single(file)
677+
return exch.import_smesh_single(file)
647678
elif os.path.isdir(file):
648679
files = sorted([os.path.join(file, f) for f in os.listdir(file)])
649680
surf = multi.SurfaceContainer()
650681
for f in files:
651-
surf.add(_exchange.import_smesh_single(f))
682+
surf.add(exch.import_smesh_single(f))
652683
return surf
653684
else:
654685
raise IOError("Input is not a file or a directory")
@@ -695,7 +726,7 @@ def export_smesh(surface, file_name, **kwargs):
695726

696727
# Write to file
697728
fname_curr = fname + "." + str(idx + 1)
698-
_exchange.write_file(fname_curr + fext, line)
729+
exch.write_file(fname_curr + fext, line)
699730

700731

701732
def export_vmesh(volume, file_name, **kwargs):
@@ -742,7 +773,7 @@ def export_vmesh(volume, file_name, **kwargs):
742773

743774
# Write to file
744775
fname_curr = fname + "." + str(idx + 1)
745-
_exchange.write_file(fname_curr + fext, line)
776+
exch.write_file(fname_curr + fext, line)
746777

747778

748779
def import_3dm(file_name, **kwargs):

0 commit comments

Comments
 (0)