Skip to content

Commit 9ecade1

Browse files
author
Andrew Yang
committed
Factor out more multisave helper functions
1 parent 59e4c9f commit 9ecade1

File tree

3 files changed

+98
-48
lines changed

3 files changed

+98
-48
lines changed

diffpy/pdfmorph/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,7 @@
2222
# top-level import
2323
from diffpy.pdfmorph.pdfmorph_api import pdfmorph, morph_default_config, plot_morph
2424

25+
# key used when saving multiple morphs
26+
__save_morph_as__ = "save_morph_as"
27+
2528
# End of file

diffpy/pdfmorph/pdfmorph_io.py

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import numpy
2323

24+
from diffpy.pdfmorph import __save_morph_as__
2425
import diffpy.pdfmorph.tools as tools
2526

2627

@@ -53,7 +54,7 @@ def single_morph_output(morph_inputs, morph_results,
5354

5455
# Saving to file
5556
if save_file is not None:
56-
path_name = Path(morph_file).resolve().as_posix()
57+
path_name = str(Path(morph_file).resolve())
5758
header = "# PDF created by pdfmorph\n"
5859
header += f"# from {path_name}"
5960

@@ -71,7 +72,7 @@ def single_morph_output(morph_inputs, morph_results,
7172
numpy.savetxt(outfile, numpy.transpose(xy_out))
7273

7374
if stdout_flag:
74-
# Indicate successful save to terminal
75+
# Indicate successful save
7576
save_message = f"# Morph saved to {save_file}\n"
7677
print(save_message)
7778

@@ -81,6 +82,57 @@ def single_morph_output(morph_inputs, morph_results,
8182
numpy.savetxt(sys.stdout, numpy.transpose(xy_out))
8283

8384

85+
def create_morphs_directory(save_directory):
86+
"""Create a directory for saving multiple morphed PDFs.
87+
88+
Takes in a user-given path to a directory save_directory and create a subdirectory named Morphs.
89+
PDFmorph will save all morphs into the Morphs subdirectory while metadata about the morphs will
90+
be stored in save_directory outside Morphs.
91+
92+
:param save_directory: path to a directory. PDFmorph will save all generated files within
93+
this directory.
94+
95+
:return: Returns the absolute path to the Morph subdirectory as a string.
96+
"""
97+
# Make directory to save files in if it does not already exist
98+
Path(save_directory).mkdir(parents=True, exist_ok=True)
99+
100+
# Morphs will be saved in the subdirectory "Morphs"
101+
morphs_subdirectory = Path(save_directory).joinpath("Morphs")
102+
morphs_subdirectory.mkdir(exist_ok=True)
103+
104+
return str(morphs_subdirectory.resolve())
105+
106+
107+
def get_multisave_names(target_list: list, save_names_file=None):
108+
"""Create or import a dictionary that specifies names to save morphs as.
109+
First attempt to import names from a specified file. If names for certain morphs not found,
110+
use default naming scheme: 'Morph_with_Target_<target file name>.cgr'.
111+
112+
Used when saving multiple morphs.
113+
114+
:param target_list: List of target PDFs used for each morph.
115+
:param save_names_file: name of file to import save names dictionary from (default None).
116+
117+
:return: Returns a dictionary containing names to save each morph as. Keys are the target
118+
PDF file names used to produce that morph.
119+
"""
120+
121+
# Dictionary storing save file names
122+
save_names = {}
123+
124+
# Import names from a serial file
125+
if save_names_file is not None:
126+
# Names should be stored properly in save_names_file
127+
save_names = tools.deserialize(save_names_file)
128+
# Apply default naming scheme to missing targets
129+
for target_file in target_list:
130+
if target_file.name not in save_names.keys():
131+
save_names.update({target_file.name:
132+
{__save_morph_as__: f"Morph_with_Target_{target_file.stem}.cgr"}})
133+
return save_names
134+
135+
84136
def multiple_morph_output(morph_inputs, morph_results, target_files,
85137
field=None, field_list=None,
86138
save_directory=None, morph_file=None, target_directory=None,
@@ -141,12 +193,14 @@ def multiple_morph_output(morph_inputs, morph_results, target_files,
141193
table += f"{row}\n"
142194
table = table[:-1] # Remove extra indent
143195

196+
# Printing summary to terminal
144197
if stdout_flag:
145198
print(f"{inputs}\n{verbose_outputs}{table}\n")
146199

200+
# Saving summary as a file
147201
if save_directory is not None:
148-
morph_path_name = Path(morph_file).resolve().as_posix()
149-
target_path_name = Path(target_directory).resolve().as_posix()
202+
morph_path_name = str(Path(morph_file).resolve())
203+
target_path_name = str(Path(target_directory).resolve())
150204

151205
header = "# Data generated by pdfmorph\n"
152206
header += f"# from morphing {morph_path_name}\n"
@@ -156,6 +210,7 @@ def multiple_morph_output(morph_inputs, morph_results, target_files,
156210
print(f"{header}\n{inputs}\n{verbose_outputs}{table}", file=reference)
157211

158212
if stdout_flag:
213+
# Indicate successful save
159214
save_message = f"# Morphs saved in the directory {save_directory}\n"
160215
print(save_message)
161216

diffpy/pdfmorph/pdfmorphapp.py

Lines changed: 36 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@
1818
import sys
1919
from pathlib import Path
2020

21+
from diffpy.pdfmorph import __save_morph_as__
2122
from diffpy.pdfmorph.version import __version__
2223
import diffpy.pdfmorph.tools as tools
2324
import diffpy.pdfmorph.pdfplot as pdfplot
2425
import diffpy.pdfmorph.morphs as morphs
2526
import diffpy.pdfmorph.morph_helpers as helpers
2627
import diffpy.pdfmorph.refine as refine
27-
from diffpy.pdfmorph.pdfmorph_io import single_morph_output, multiple_morph_output, tabulate_results
28+
import diffpy.pdfmorph.pdfmorph_io as io
2829

2930

3031
def create_option_parser():
@@ -71,13 +72,13 @@ def custom_error(self, msg):
7172
'--snf',
7273
'--save-names-file',
7374
metavar="NAMESFILE",
74-
dest="snfile",
75-
help="""Used only when both -s and --multiple are enabled.
75+
dest="snamesfile",
76+
help=f"""Used only when both -s and --multiple are enabled.
7677
Specify names for each manipulated PDF when saving (see -s) using a serial file
7778
NAMESFILE. The format of NAMESFILE should be as follows: each target PDF
78-
is an entry in NAMESFILE. For each entry, there should be a key 'save_morph_as'
79+
is an entry in NAMESFILE. For each entry, there should be a key {__save_morph_as__}
7980
whose value specifies the name to save the manipulated PDF as.
80-
(See sample names files in the pdfmorph tutorial).""",
81+
(See sample names files in the PDFmorph tutorial).""",
8182
)
8283
parser.add_option(
8384
'-v',
@@ -407,15 +408,14 @@ def single_morph(parser, opts, pargs, stdout_flag=True):
407408

408409
# Print summary to terminal and save morph to file if requested
409410
try:
410-
single_morph_output(morph_inputs, morph_results,
411-
save_file=opts.slocation, morph_file=pargs[0],
412-
xy_out=[chain.x_morph_out, chain.y_morph_out],
413-
verbose=opts.verbose, stdout_flag=stdout_flag)
411+
io.single_morph_output(morph_inputs, morph_results,
412+
save_file=opts.slocation, morph_file=pargs[0],
413+
xy_out=[chain.x_morph_out, chain.y_morph_out],
414+
verbose=opts.verbose, stdout_flag=stdout_flag)
414415

415-
except FileNotFoundError as e:
416+
except (FileNotFoundError, RuntimeError) as e:
416417
save_fail_message = "Unable to save to designated location."
417-
print(save_fail_message)
418-
parser.custom_error(str(e))
418+
parser.custom_error(save_fail_message)
419419

420420
if opts.plot:
421421
pairlist = [chain.xy_morph_out, chain.xy_target_out]
@@ -449,7 +449,6 @@ def multiple_morphs(parser, opts, pargs, stdout_flag=True):
449449

450450
# Parse paths
451451
morph_file = Path(pargs[0])
452-
target_directory = Path(pargs[1])
453452
if not morph_file.is_file():
454453
parser.custom_error(f"{morph_file} is not a file. Go to --help for usage.")
455454
target_directory = Path(pargs[1])
@@ -489,41 +488,34 @@ def multiple_morphs(parser, opts, pargs, stdout_flag=True):
489488
opts.plot = False
490489

491490
# Set up saving
492-
save_directory = opts.slocation
493-
save_names = {}
494-
save_morphs_here = ""
491+
save_directory = opts.slocation # User-given directory for saves
492+
save_names_file = opts.snamesfile # User-given serialfile with names for each morph
493+
save_morphs_here = None # Subdirectory for saving morphed PDFs
494+
save_names = {} # Dictionary of names to save each morph as
495495
if save_directory is not None:
496496
try:
497-
# Make directory to save files in if it does not already exist
498-
Path(save_directory).mkdir(parents=True, exist_ok=True)
499-
500-
# Morphs will be saved in the subdirectory "Morphs"
501-
save_morphs_here = Path(save_directory).joinpath("Morphs")
502-
save_morphs_here.mkdir(exist_ok=True)
503-
504-
# Get names for the saved morphs
505-
if opts.snfile is not None:
506-
# Names should be stored properly in opts.snfile
507-
save_names = tools.deserialize(opts.snfile)
508-
# Default naming scheme
509-
else:
510-
for target_file in target_list:
511-
save_names.update({target_file.name: {"save_morph_as":
512-
f"Morph_with_Target_{target_file.stem}.cgr"}})
497+
save_morphs_here = io.create_morphs_directory(save_directory)
513498

514-
# Could not create directory
515-
except FileNotFoundError as e:
499+
# Could not create directory or find names to save morphs as
500+
except (FileNotFoundError, RuntimeError) as e:
516501
save_fail_message = "\nUnable to create directory"
517-
print(save_fail_message)
518-
parser.custom_error(str(e))
502+
parser.custom_error(save_fail_message)
503+
504+
try:
505+
save_names = io.get_multisave_names(target_list, save_names_file=save_names_file)
506+
# Could not create directory or find names to save morphs as
507+
except FileNotFoundError:
508+
save_fail_message = "\nUnable to read from save names file"
509+
parser.custom_error(save_fail_message)
519510

520511
# Morph morph_file against all other files in target_directory
521512
morph_results = {}
522513
for target_file in target_list:
523514
if target_file.is_file:
524515
# Set the save file destination to be a file within the SLOC directory
525516
if save_directory is not None:
526-
opts.slocation = Path(save_morphs_here).joinpath(save_names.get(target_file.name).get("save_morph_as"))
517+
save_as = save_names[target_file.name][__save_morph_as__]
518+
opts.slocation = Path(save_morphs_here).joinpath(save_as)
527519
# Perform a morph of morph_file against target_file
528520
pargs = [morph_file, target_file]
529521
morph_results.update({
@@ -539,18 +531,18 @@ def multiple_morphs(parser, opts, pargs, stdout_flag=True):
539531

540532
try:
541533
# Print summary of morphs to terminal and to file (if requested)
542-
multiple_morph_output(morph_inputs, morph_results, target_file_names,
543-
save_directory=save_directory, morph_file=morph_file, target_directory=target_directory,
544-
field=field, field_list=field_list, verbose=opts.verbose, stdout_flag=stdout_flag)
545-
except FileNotFoundError as e:
534+
io.multiple_morph_output(morph_inputs, morph_results, target_file_names,
535+
save_directory=save_directory, morph_file=morph_file,
536+
target_directory=target_directory, field=field, field_list=field_list,
537+
verbose=opts.verbose, stdout_flag=stdout_flag)
538+
except (FileNotFoundError, RuntimeError) as e:
546539
save_fail_message = "Unable to save summary to directory."
547-
print(save_fail_message)
548-
parser.custom_error(str(e))
540+
parser.custom_error(save_fail_message)
549541

550542
# Plot the rw values for each target if requested
551543
# FIXME: create functionality to plot other data (scale, stretch, smear, etc.)
552544
if plot_opt:
553-
plot_results = tabulate_results(morph_results)
545+
plot_results = io.tabulate_results(morph_results)
554546
if field_list is not None:
555547
pdfplot.plot_rws(field_list, plot_results["Rw"], field)
556548
else:

0 commit comments

Comments
 (0)