import argparse
import glob
import logging
import os
import platform
import sys
import textwrap
from enum import Enum
from typing import List, Type
from SDF.file_io import InputFormat, SDFConverter
logging.basicConfig() # initialize logging system
logger = logging.getLogger(__name__)
IGNORE_SUFFIXES = (
".oif.files",
".oif.files/",
".oif.files\\",
)
def _get_enum_names(enum_class: Type[Enum]) -> List[str]:
return list(enum_class.__members__.keys())
[docs]def main():
# define args
# noinspection PyTypeChecker
# Type stubs for formatter_class are wrong
# See https://docs.python.org/3/library/argparse.html#argparse.RawDescriptionHelpFormatter for example usage
parser = argparse.ArgumentParser(
description=textwrap.dedent("Converts files into .sdf and possibly additional formats. "
"See details and examples below."),
epilog=textwrap.dedent("""\
additional formats:
if input is force distance curve (currently supported for .ibw and .jpk-force files)
.force.sdf (unless --no-force is set)
.mat (if --mat is set)
examples:
sdf-convert *.lsm
converts all .lsm files in the current directory to .sdf
results will be placed alongside the original files
sdf-convert *.jpk-force -o sdf
converts all .jpk-force files to .sdf and .force.sdf
results will be placed in directory ./sdf
sdf-convert *.jpk-force --no-force --mat
converts all .jpk files to .sdf and .mat
sdf-convert *
converts all files in the current directory to .sdf (and .force.sdf, if possible)
infers input type from individual file extension (fails for invalid inputs like .mat files)
sdf-convert --input-format OIB oib-file-without-extension
reads file `oib-file-without-extension` as .oib file and converts it to .sdf
"""),
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument("input_files", metavar="input-files", nargs="+", help="Files to convert")
parser.add_argument("-i", "--input-format", help=f"Input format (default: infer for each file)",
choices=_get_enum_names(InputFormat))
parser.add_argument("-o", "--output-directory", help=f"The output directory (default: same as input files)",
default=None)
parser.add_argument("--no-force", help="Generate no additional .force.sdf file (only for force distance curves)",
action="store_true")
parser.add_argument("--mat", help="Generate an additional .mat file (only for force distance curves)",
action="store_true")
parser.add_argument("-p", "--progress", help="Show progress", action="store_true")
parser.add_argument("-v", "--verbose", help="Set logging level to INFO", action="store_true")
parser.add_argument("-d", "--debug", help="Set logging level to DEBUG (implies --verbose)", action="store_true")
parser.add_argument("-s", "--silent", help="Set logging level to ERROR (silences warnings)", action="store_true")
parser.add_argument("--dry-run", help="Perform conversions without writing the results", action="store_true")
# parse args
args = parser.parse_args()
converter = SDFConverter(input_format=args.input_format, output_directory=args.output_directory,
generate_mat=args.mat, generate_force=not args.no_force, dry_run=args.dry_run)
filenames = args.input_files
# set logging level
log_level = logging.WARNING
if args.silent:
log_level = logging.ERROR
if args.debug:
log_level = logging.DEBUG
elif args.verbose:
log_level = logging.INFO
logging.getLogger().setLevel(log_level) # set log level of root logger (propagated down to all other loggers)
# do conversion
try:
# check if input is a directory
if len(filenames) == 1 and os.path.isdir(filenames[0]):
if filenames[0].endswith(os.path.sep):
suggestion = filenames[0] + "*"
else:
suggestion = filenames[0] + os.path.sep + "*"
print(f"'{filenames[0]}' is a directory. Did you mean '{suggestion}'?", file=sys.stderr)
return 1
# glob-expand patterns if on Windows
if platform.system() == "Windows":
original_filenames = filenames
if isinstance(original_filenames, str):
filenames = glob.glob(original_filenames)
else:
filenames = []
for filename in original_filenames:
filenames.extend(glob.glob(filename))
logger.info(f"glob-expanded {original_filenames}")
# filter filenames
convert_filenames = []
for filename in filenames:
if filename.endswith(tuple(IGNORE_SUFFIXES)):
logger.info(f"Skipping {filename} because it matches the suffix blacklist")
continue
convert_filenames.append(filename)
# convert
for filenum, filename in enumerate(convert_filenames, start=1):
if args.progress:
print(f"File {filenum}/{len(convert_filenames)}: {filename}")
try:
converter.convert_file(filename)
except KeyboardInterrupt:
# do not print exception traceback
print("\rInterrupted by keyboard")
return 1
return 0
except Exception as exc:
if args.debug:
raise
else:
print(f"An error occurred: {exc!r}\n"
"If you are sure this should have worked, please contact the maintainers.\n"
"To see the full traceback, run again with '--debug'.", file=sys.stderr)
return 2