psdi-data-conversion 0.0.36__py3-none-any.whl → 0.0.38__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,7 @@ Created 2025-01-14 by Bryan Gillis.
7
7
  Entry-point file for the command-line interface for data conversion.
8
8
  """
9
9
 
10
+ from itertools import product
10
11
  import logging
11
12
  from argparse import ArgumentParser
12
13
  import os
@@ -17,10 +18,10 @@ from psdi_data_conversion import constants as const
17
18
  from psdi_data_conversion.constants import CL_SCRIPT_NAME, CONVERTER_DEFAULT, TERM_WIDTH
18
19
  from psdi_data_conversion.converter import (D_CONVERTER_ARGS, D_SUPPORTED_CONVERTERS, L_REGISTERED_CONVERTERS,
19
20
  L_SUPPORTED_CONVERTERS, run_converter)
20
- from psdi_data_conversion.converters.base import (FileConverterAbortException, FileConverterInputException,
21
- FileConverterHelpException)
22
- from psdi_data_conversion.database import (get_conversion_quality, get_converter_info, get_format_info,
23
- get_in_format_args, get_out_format_args, get_possible_converters,
21
+ from psdi_data_conversion.converters.base import (FileConverterAbortException, FileConverterException,
22
+ FileConverterInputException)
23
+ from psdi_data_conversion.database import (FormatInfo, get_conversion_quality, get_converter_info, get_format_info,
24
+ get_in_format_args, get_out_format_args, get_possible_conversions,
24
25
  get_possible_formats)
25
26
  from psdi_data_conversion.file_io import split_archive_ext
26
27
  from psdi_data_conversion.log_utility import get_log_level_from_str
@@ -84,9 +85,21 @@ class ConvertArgs:
84
85
  try:
85
86
  self.log_level = get_log_level_from_str(args.log_level)
86
87
  except ValueError as e:
87
- # A ValueError indicates an unrecognised logging level, so we reraise this as a help exception to
88
+ # A ValueError indicates an unrecognised logging level, so we reraise this with the help flag to
88
89
  # indicate we want to provide this as feedback to the user so they can correct their command
89
- raise FileConverterHelpException(str(e))
90
+ raise FileConverterInputException(str(e), help=True)
91
+
92
+ # If formats were provided as ints, convert them to the int type now
93
+ try:
94
+ if self.from_format:
95
+ self.from_format = int(self.from_format)
96
+ except ValueError:
97
+ pass
98
+ try:
99
+ if self.to_format:
100
+ self.to_format = int(self.to_format)
101
+ except ValueError:
102
+ pass
90
103
 
91
104
  # Special handling for listing converters
92
105
  if self.list:
@@ -114,40 +127,40 @@ class ConvertArgs:
114
127
  # Check validity of input
115
128
 
116
129
  if len(self.l_args) == 0:
117
- raise FileConverterHelpException("One or more names of files to convert must be provided")
130
+ raise FileConverterInputException("One or more names of files to convert must be provided", help=True)
118
131
 
119
132
  if self._input_dir is not None and not os.path.isdir(self._input_dir):
120
- raise FileConverterHelpException(f"The provided input directory '{self._input_dir}' does not exist as a "
121
- "directory")
133
+ raise FileConverterInputException(f"The provided input directory '{self._input_dir}' does not exist as a "
134
+ "directory", help=True)
122
135
 
123
136
  if self.to_format is None:
124
137
  msg = textwrap.fill("ERROR Output format (-t or --to) must be provided. For information on supported "
125
138
  "formats and converters, call:\n")
126
139
  msg += f"{CL_SCRIPT_NAME} -l"
127
- raise FileConverterHelpException(msg, msg_preformatted=True)
140
+ raise FileConverterInputException(msg, msg_preformatted=True, help=True)
128
141
 
129
142
  # If the output directory doesn't exist, silently create it
130
143
  if self._output_dir is not None and not os.path.isdir(self._output_dir):
131
144
  if os.path.exists(self._output_dir):
132
- raise FileConverterHelpException(f"Output directory '{self._output_dir}' exists but is not a "
133
- "directory")
145
+ raise FileConverterInputException(f"Output directory '{self._output_dir}' exists but is not a "
146
+ "directory", help=True)
134
147
  os.makedirs(self._output_dir, exist_ok=True)
135
148
 
136
149
  # Check the converter is recognized
137
150
  if self.name not in L_SUPPORTED_CONVERTERS:
138
151
  msg = textwrap.fill(f"ERROR: Converter '{self.name}' not recognised", width=TERM_WIDTH)
139
152
  msg += f"\n\n{get_supported_converters()}"
140
- raise FileConverterHelpException(msg, msg_preformatted=True)
153
+ raise FileConverterInputException(msg, help=True, msg_preformatted=True)
141
154
  elif self.name not in L_REGISTERED_CONVERTERS:
142
155
  msg = textwrap.fill(f"ERROR: Converter '{self.name}' is not registered. It may be possible to register "
143
156
  "it by installing an appropriate binary for your platform.", width=TERM_WIDTH)
144
157
  msg += f"\n\n{get_supported_converters()}"
145
- raise FileConverterHelpException(msg, msg_preformatted=True)
158
+ raise FileConverterInputException(msg, help=True, msg_preformatted=True)
146
159
 
147
160
  # Logging mode is valid
148
161
  if self.log_mode not in const.L_ALLOWED_LOG_MODES:
149
- raise FileConverterHelpException(f"Unrecognised logging mode: {self.log_mode}. Allowed "
150
- f"modes are: {const.L_ALLOWED_LOG_MODES}")
162
+ raise FileConverterInputException(f"Unrecognised logging mode: {self.log_mode}. Allowed "
163
+ f"modes are: {const.L_ALLOWED_LOG_MODES}", help=True)
151
164
 
152
165
  # Arguments specific to this converter
153
166
  self.d_converter_args = {}
@@ -194,10 +207,10 @@ class ConvertArgs:
194
207
  if os.path.isfile(test_filename):
195
208
  first_filename = test_filename
196
209
  else:
197
- raise FileConverterHelpException(f"Input file {first_filename} cannot be found. Also "
198
- f"checked for {test_filename}.")
210
+ raise FileConverterInputException(f"Input file {first_filename} cannot be found. Also "
211
+ f"checked for {test_filename}.", help=True)
199
212
  else:
200
- raise FileConverterHelpException(f"Input file {first_filename} cannot be found.")
213
+ raise FileConverterInputException(f"Input file {first_filename} cannot be found.", help=True)
201
214
 
202
215
  filename_base = os.path.split(split_archive_ext(first_filename)[0])[1]
203
216
  if self.log_mode == const.LOG_FULL:
@@ -345,7 +358,7 @@ def detail_converter_use(args: ConvertArgs):
345
358
  print_wrap(converter_class.info, break_long_words=False, break_on_hyphens=False, newline=True)
346
359
 
347
360
  # If both an input and output format are specified, provide the degree of success for this conversion. Otherwise
348
- # list possible input output formats
361
+ # list possible input/output formats
349
362
  if args.from_format is not None and args.to_format is not None:
350
363
  qual = get_conversion_quality(args.name, args.from_format, args.to_format)
351
364
  if qual is None:
@@ -375,19 +388,19 @@ def detail_converter_use(args: ConvertArgs):
375
388
  print_wrap(f"Conversion {to_or_from} {format_name} is {optional_not}supported by {args.name}.\n")
376
389
 
377
390
  # List all possible formats, and which can be used for input and which for output
378
- s_all_formats: set[str] = set(l_input_formats)
391
+ s_all_formats: set[FormatInfo] = set(l_input_formats)
379
392
  s_all_formats.update(l_output_formats)
380
- l_all_formats: list[str] = list(s_all_formats)
381
- l_all_formats.sort(key=lambda s: s.lower())
393
+ l_all_formats: list[FormatInfo] = list(s_all_formats)
394
+ l_all_formats.sort(key=lambda x: x.disambiguated_name.lower())
382
395
 
383
396
  print_wrap(f"File formats supported by {args.name}:", newline=True)
384
- max_format_length = max([len(x) for x in l_all_formats])
397
+ max_format_length = max([len(x.disambiguated_name) for x in l_all_formats])
385
398
  print(" "*(max_format_length+4) + " INPUT OUTPUT")
386
399
  print(" "*(max_format_length+4) + " ----- ------")
387
400
  for file_format in l_all_formats:
388
401
  in_yes_or_no = "yes" if file_format in l_input_formats else "no"
389
402
  out_yes_or_no = "yes" if file_format in l_output_formats else "no"
390
- print(f" {file_format:>{max_format_length}}{in_yes_or_no:>8}{out_yes_or_no:>8}")
403
+ print(f" {file_format.disambiguated_name:>{max_format_length}}{in_yes_or_no:>8}{out_yes_or_no:>8}")
391
404
  print("")
392
405
 
393
406
  if converter_class.allowed_flags is None:
@@ -472,10 +485,16 @@ def list_supported_formats(err=False):
472
485
  """Prints a list of all formats recognised by at least one registered converter
473
486
  """
474
487
  # Make a list of all formats recognised by at least one registered converter
475
- s_all_formats: set[str] = set()
476
- s_registered_formats: set[str] = set()
488
+ s_all_formats: set[FormatInfo] = set()
489
+ s_registered_formats: set[FormatInfo] = set()
477
490
  for converter_name in L_SUPPORTED_CONVERTERS:
478
491
  l_in_formats, l_out_formats = get_possible_formats(converter_name)
492
+
493
+ # To make sure we don't see any unexpected duplicates in the set due to cached/uncached values, get the
494
+ # disambiguated name of each format first
495
+ [x.disambiguated_name for x in l_in_formats]
496
+ [x.disambiguated_name for x in l_out_formats]
497
+
479
498
  s_all_formats.update(l_in_formats)
480
499
  s_all_formats.update(l_out_formats)
481
500
  if converter_name in L_REGISTERED_CONVERTERS:
@@ -486,14 +505,14 @@ def list_supported_formats(err=False):
486
505
 
487
506
  # Convert the sets to lists and alphabetise them
488
507
  l_registered_formats = list(s_registered_formats)
489
- l_registered_formats.sort(key=lambda s: s.lower())
508
+ l_registered_formats.sort(key=lambda x: x.disambiguated_name.lower())
490
509
  l_unregistered_formats = list(s_unregistered_formats)
491
- l_unregistered_formats.sort(key=lambda s: s.lower())
510
+ l_unregistered_formats.sort(key=lambda x: x.disambiguated_name.lower())
492
511
 
493
512
  # Pad the format strings to all be the same length. To keep columns aligned, all padding is done with non-
494
513
  # breaking spaces (\xa0), and each format is followed by a single normal space
495
- longest_format_len = max([len(x) for x in l_registered_formats])
496
- l_padded_formats = [f"{x:\xa0<{longest_format_len}} " for x in l_registered_formats]
514
+ longest_format_len = max([len(x.disambiguated_name) for x in l_registered_formats])
515
+ l_padded_formats = [f"{x.disambiguated_name:\xa0<{longest_format_len}} " for x in l_registered_formats]
497
516
 
498
517
  print_wrap("Formats supported by registered converters: ", err=err, newline=True)
499
518
  print_wrap("".join(l_padded_formats), err=err, initial_indent=" ", subsequent_indent=" ", newline=True)
@@ -508,9 +527,33 @@ def list_supported_formats(err=False):
508
527
  initial_indent=" ", subsequent_indent=" ", newline=True)
509
528
 
510
529
  print_wrap("Note that not all formats are supported with all converters, or both as input and as output.")
530
+ if err:
531
+ print("")
532
+ print_wrap("For more details on a format, call:")
533
+ print(f"{CL_SCRIPT_NAME} -l -f <format>")
511
534
 
512
535
 
513
- def detail_possible_converters(from_format: str, to_format: str):
536
+ def detail_format(format_name: str):
537
+ """Prints details on a format
538
+ """
539
+
540
+ l_format_info: list[FormatInfo] = get_format_info(format_name, which="all")
541
+
542
+ if len(l_format_info) == 0:
543
+ print_wrap(f"ERROR: Format '{format_name}' not recognised", err=True, newline=True)
544
+ list_supported_formats(err=True)
545
+ exit(1)
546
+
547
+ if len(l_format_info) > 1:
548
+ print_wrap(f"WARNING: Format '{format_name}' is ambiguous and could refer to multiple formats. It may be "
549
+ "necessary to explicitly specify which you want to use when calling this script, e.g. with "
550
+ f"'-f {format_name}-0' - see the disambiguated names in the list below:", newline=True)
551
+
552
+ for format_info in l_format_info:
553
+ print_wrap(f"{format_info.id}: {format_info.disambiguated_name} ({format_info.note})")
554
+
555
+
556
+ def detail_formats_and_possible_converters(from_format: str, to_format: str):
514
557
  """Prints details on converters that can perform a conversion from one format to another
515
558
  """
516
559
 
@@ -518,13 +561,13 @@ def detail_possible_converters(from_format: str, to_format: str):
518
561
  either_format_failed = False
519
562
 
520
563
  try:
521
- get_format_info(from_format)
564
+ get_format_info(from_format, which=0)
522
565
  except KeyError:
523
566
  either_format_failed = True
524
567
  print_wrap(f"ERROR: Input format '{from_format}' not recognised", newline=True, err=True)
525
568
 
526
569
  try:
527
- get_format_info(to_format)
570
+ get_format_info(to_format, which=0)
528
571
  except KeyError:
529
572
  either_format_failed = True
530
573
  print_wrap(f"ERROR: Output format '{from_format}' not recognised", newline=True, err=True)
@@ -534,32 +577,58 @@ def detail_possible_converters(from_format: str, to_format: str):
534
577
  list_supported_formats(err=True)
535
578
  exit(1)
536
579
 
537
- l_possible_converters = get_possible_converters(from_format, to_format)
580
+ # Provide details on both the input and output formats
581
+ detail_format(from_format)
582
+ print()
583
+ detail_format(to_format)
538
584
 
539
- l_possible_registered_converters = [x for x in l_possible_converters if x in L_REGISTERED_CONVERTERS]
540
- l_possible_unregistered_converters = [x for x in l_possible_converters if
541
- x in L_SUPPORTED_CONVERTERS and x not in L_REGISTERED_CONVERTERS]
585
+ l_possible_conversions = get_possible_conversions(from_format, to_format)
542
586
 
543
- if len(l_possible_registered_converters)+len(l_possible_unregistered_converters) == 0:
544
- print_wrap(f"No converters are available which can perform a conversion from {from_format} to {to_format}")
545
- return
546
- elif len(l_possible_registered_converters) == 0:
547
- print_wrap(f"No registered converters can perform a conversion from {from_format} to {to_format}, however "
548
- "the following converters are supported by this package on other platforms and can perform this "
549
- "conversion:", newline=True)
550
- print("\n ".join(l_possible_unregistered_converters))
551
- return
587
+ # Get a list of all different formats which share the provided name, cutting out duplicates
588
+ l_from_formats = list(set([x[1] for x in l_possible_conversions]))
589
+ l_from_formats.sort(key=lambda x: x.disambiguated_name)
590
+ l_to_formats = list(set([x[2] for x in l_possible_conversions]))
591
+ l_to_formats.sort(key=lambda x: x.disambiguated_name)
552
592
 
553
- print_wrap(f"The following registered converters can convert from {from_format} to {to_format}:", newline=True)
554
- print(" " + "\n ".join(l_possible_registered_converters) + "\n")
555
- if l_possible_unregistered_converters:
556
- print("")
557
- print_wrap("Additionally, the following converters are supported by this package on other platforms and can "
558
- "perform this conversion:", newline=True)
559
- print(" " + "\n ".join(l_possible_unregistered_converters) + "\n")
593
+ # Loop over all possible combinations of formats
560
594
 
561
- print_wrap("For details on input/output flags and options allowed by a converter for this conversion, call:")
562
- print(f"{CL_SCRIPT_NAME} -l <converter name> -f {from_format} -t {to_format}")
595
+ for possible_from_format, possible_to_format in product(l_from_formats, l_to_formats):
596
+
597
+ from_name = possible_from_format.disambiguated_name
598
+ to_name = possible_to_format.disambiguated_name
599
+
600
+ l_conversions_matching_formats = [x for x in l_possible_conversions
601
+ if x[1] == possible_from_format and x[2] == possible_to_format]
602
+
603
+ l_possible_registered_converters = [x[0] for x in l_conversions_matching_formats
604
+ if x[0] in L_REGISTERED_CONVERTERS]
605
+ l_possible_unregistered_converters = [x[0] for x in l_conversions_matching_formats
606
+ if x[0] in L_SUPPORTED_CONVERTERS and x[0] not in L_REGISTERED_CONVERTERS]
607
+
608
+ print()
609
+
610
+ if len(l_possible_registered_converters)+len(l_possible_unregistered_converters) == 0:
611
+ print_wrap(f"No converters are available which can perform a conversion from {from_name} to "
612
+ f"{to_name}")
613
+ continue
614
+ elif len(l_possible_registered_converters) == 0:
615
+ print_wrap(f"No registered converters can perform a conversion from {from_name} to "
616
+ f"{to_name}, however the following converters are supported by this package on other "
617
+ "platforms and can perform this conversion:", newline=True)
618
+ print("\n ".join(l_possible_unregistered_converters))
619
+ continue
620
+
621
+ print_wrap(f"The following registered converters can convert from {from_name} to "
622
+ f"{to_name}:", newline=True)
623
+ print(" " + "\n ".join(l_possible_registered_converters) + "\n")
624
+ if l_possible_unregistered_converters:
625
+ print("")
626
+ print_wrap("Additionally, the following converters are supported by this package on other platforms and "
627
+ "can perform this conversion:", newline=True)
628
+ print(" " + "\n ".join(l_possible_unregistered_converters) + "\n")
629
+
630
+ print_wrap("For details on input/output flags and options allowed by a converter for this conversion, call:")
631
+ print(f"{CL_SCRIPT_NAME} -l <converter name> -f {from_name} -t {to_name}")
563
632
 
564
633
 
565
634
  def get_supported_converters():
@@ -612,7 +681,13 @@ def detail_converters_and_formats(args: ConvertArgs):
612
681
  list_supported_converters(err=True)
613
682
  exit(1)
614
683
  elif args.from_format and args.to_format:
615
- detail_possible_converters(args.from_format, args.to_format)
684
+ detail_formats_and_possible_converters(args.from_format, args.to_format)
685
+ return
686
+ elif args.from_format:
687
+ detail_format(args.from_format)
688
+ return
689
+ elif args.to_format:
690
+ detail_format(args.to_format)
616
691
  return
617
692
 
618
693
  list_supported_converters()
@@ -623,6 +698,9 @@ def detail_converters_and_formats(args: ConvertArgs):
623
698
  print_wrap("For more details on a converter, call:")
624
699
  print(f"{CL_SCRIPT_NAME} -l <converter name>\n")
625
700
 
701
+ print_wrap("For more details on a format, call:")
702
+ print(f"{CL_SCRIPT_NAME} -l -f <format>\n")
703
+
626
704
  print_wrap("For a list of converters that can perform a desired conversion, call:")
627
705
  print(f"{CL_SCRIPT_NAME} -l -f <input format> -t <output format>\n")
628
706
 
@@ -693,12 +771,6 @@ def run_from_args(args: ConvertArgs):
693
771
  log_level=args.log_level,
694
772
  delete_input=args.delete_input,
695
773
  refresh_local_log=False)
696
- except FileConverterHelpException as e:
697
- if not e.logged:
698
- print_wrap(f"ERROR: {e}", err=True)
699
- e.logged = True
700
- success = False
701
- continue
702
774
  except FileConverterAbortException as e:
703
775
  if not e.logged:
704
776
  print_wrap(f"ERROR: Attempt to convert file {filename} aborted with status code {e.status_code} and "
@@ -706,11 +778,19 @@ def run_from_args(args: ConvertArgs):
706
778
  e.logged = True
707
779
  success = False
708
780
  continue
709
- except FileConverterInputException as e:
710
- if "Conversion from" in str(e) and "is not supported" in str(e):
781
+ except FileConverterException as e:
782
+ if e.help and not e.logged:
783
+ print_wrap(f"ERROR: {e}", err=True)
784
+ e.logged = True
785
+ elif "Conversion from" in str(e) and "is not supported" in str(e):
711
786
  if not e.logged:
712
787
  print_wrap(f"ERROR: {e}", err=True, newline=True)
713
- detail_possible_converters(args.from_format, args.to_format)
788
+ detail_formats_and_possible_converters(args.from_format, args.to_format)
789
+ elif e.help and not e.logged:
790
+ if e.msg_preformatted:
791
+ print(e, file=sys.stderr)
792
+ else:
793
+ print_wrap(f"ERROR: {e}", err=True)
714
794
  elif not e.logged:
715
795
  print_wrap(f"ERROR: Attempt to convert file {filename} failed at converter initialization with "
716
796
  f"exception type {type(e)} and message: \n{e}\n", err=True)
@@ -748,9 +828,11 @@ def main():
748
828
 
749
829
  try:
750
830
  args = parse_args()
751
- except FileConverterHelpException as e:
752
- # If we get a Help exception, it's likely due to user error, so don't bother them with a traceback and simply
753
- # print the message to stderr
831
+ except FileConverterInputException as e:
832
+ if not e.help:
833
+ raise
834
+ # If we get an exception with the help flag set, it's likely due to user error, so don't bother them with a
835
+ # traceback and simply print the message to stderr
754
836
  if e.msg_preformatted:
755
837
  print(e, file=sys.stderr)
756
838
  else:
@@ -43,6 +43,8 @@
43
43
  Python library.
44
44
  </p>
45
45
 
46
+ <h2>Installation</h2>
47
+
46
48
  <h3>Install via pip</h3>
47
49
 
48
50
  <ul>
@@ -63,12 +65,6 @@
63
65
  Python library.
64
66
  </p>
65
67
 
66
- <p>
67
- If you do wish to run the local version of this webpage, you'll need to create a helper script to set up the
68
- proper parameters and start the server. See the README provided on the front page of this project's PyPI page,
69
- linked above, for the source of this helper script, which you can paste and use locally.
70
- </p>
71
-
72
68
  <h3>Source Code</h3>
73
69
 
74
70
  <ul>
@@ -86,11 +82,28 @@
86
82
  for other possible optional dependencies sets that can be installed.
87
83
  </p>
88
84
 
89
- <p>When installed in this manner, the helper script to run the local webpage is provided in the root directory
90
- of the repository as <code class="secondary">run_local.sh</code>. It can be run from this directory, copied to
91
- your <code class="secondary">$PATH</code>, or aliased as desired.
85
+ <h2>Use</h2>
86
+
87
+ <p>
88
+ Once installed, the project can be used in one of three ways:
92
89
  </p>
93
90
 
91
+ <ul>
92
+ <li><strong>Local Gui:</strong> Run the script <code class="secondary">psdi-data-convert-gui</code> to start the
93
+ server. Append the <code class="secondary">--help</code> option for to see optional arguments (generally not
94
+ required for end-users)
95
+ </li>
96
+ <li><strong>Command-Line Application:</strong> Run the script <code class="secondary">psdi-data-convert</code>
97
+ to use the application at the command-line. Append the <code class="secondary">--help</code> option to see
98
+ arguments for it, and/or find documentation in the project's README.
99
+ </li>
100
+ <li><strong>Python Library:</strong> Within a Python script, library, or terminal, the project can be imported
101
+ via <code class="secondary">import psdi_data_conversion</code>, with the most useful function being <code
102
+ class="secondary">psdi_data_conversion.converter.run_converter</code> - see the <code
103
+ class="secondary">help()</code> of this function and/or find documentation in the project's README.
104
+ </li>
105
+ </ul>
106
+
94
107
  <h2>Documentation</h2>
95
108
 
96
109
  <ul>
@@ -1,7 +1,21 @@
1
1
  // data.js
2
2
 
3
3
  const response = await fetch("/static/data/data.json");
4
- const data = JSON.parse(await response.text());
4
+
5
+ let data = null;
6
+ try {
7
+ data = JSON.parse(await response.text());
8
+ } catch (err) {
9
+ console.log("ERROR: Database could not be loaded, error: " + err)
10
+ }
11
+
12
+ /**
13
+ * Indicates whether or not the database was successfully loaded
14
+ * @returns {boolean}
15
+ */
16
+ export function databaseLoaded() {
17
+ return data !== null;
18
+ }
5
19
 
6
20
  const collator = new Intl.Collator();
7
21
 
@@ -84,7 +98,7 @@ export async function getConverters(inExtension, inNote, outExtension, outNote)
84
98
  const inputFormat = (data.formats.filter(format => (format.extension === inExtension) && (format.note === inNote)))[0];
85
99
  const outputFormat = (data.formats.filter(format => (format.extension === outExtension) && (format.note === outNote)))[0];
86
100
 
87
- if ((inputFormat === undefined) || (outputFormat === undefined)) {
101
+ if ((inputFormat === undefined) || (outputFormat === undefined)) {
88
102
  return [];
89
103
  }
90
104
 
@@ -96,7 +110,7 @@ export async function getConverters(inExtension, inNote, outExtension, outNote)
96
110
  name: convertersById.get(conversion.converters_id).name
97
111
  }));
98
112
 
99
- return convertersWithDegreeOfSuccess.sort((a, b) => compare(a.name, b.name ));
113
+ return convertersWithDegreeOfSuccess.sort((a, b) => compare(a.name, b.name));
100
114
  }
101
115
 
102
116
  export async function getConverterByName(name) {
@@ -170,7 +184,7 @@ export async function getOutputArgFlags(extension, note) {
170
184
  export async function getLevelChemInfo(inExtension, inNote, outExtension, outNote) {
171
185
 
172
186
  const inputFormat = (data.formats.filter(format => (format.extension === inExtension) && (format.note === inNote)))[0],
173
- outputFormat = (data.formats.filter(format => (format.extension === outExtension) && (format.note === outNote)))[0];
187
+ outputFormat = (data.formats.filter(format => (format.extension === outExtension) && (format.note === outNote)))[0];
174
188
 
175
189
  return [inputFormat, outputFormat];
176
190
  }
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { disableDirtyForms, cleanDirtyForms, initDirtyForms, loadServiceMode, loadProductionMode } from "./common.js";
9
9
  import {
10
- getInputFormats, getOutputFormats, getOutputFormatsForInputFormat,
10
+ databaseLoaded, getInputFormats, getOutputFormats, getOutputFormatsForInputFormat,
11
11
  getInputFormatsForOutputFormat, getConverters, getConverterByName, getLevelChemInfo
12
12
  } from "./data.js";
13
13
 
@@ -18,15 +18,20 @@ var fromList = new Array(),
18
18
 
19
19
  $(document).ready(function () {
20
20
 
21
- // Populates the "Convert from" selection list
22
- getInputFormats().then((formats) => {
23
- populateList(formats, "from");
24
- });
21
+ // Populate the available formats if the database successfully loaded, otherwise display an error message
22
+ if (databaseLoaded()) {
23
+ // Populates the "Convert from" selection list
24
+ getInputFormats().then((formats) => {
25
+ populateList(formats, "from");
26
+ });
25
27
 
26
- // Populates the "Convert to" selection list
27
- getOutputFormats().then((formats) => {
28
- populateList(formats, "to");
29
- });
28
+ // Populates the "Convert to" selection list
29
+ getOutputFormats().then((formats) => {
30
+ populateList(formats, "to");
31
+ });
32
+ } else {
33
+ displayDatabaseLoadError();;
34
+ }
30
35
 
31
36
  sessionStorage.setItem("token", token);
32
37
  sessionStorage.setItem("max_file_size", max_file_size);
@@ -52,6 +57,14 @@ $(document).ready(function () {
52
57
  initDirtyForms();
53
58
  });
54
59
 
60
+ /**
61
+ * Hides the format and converter selection and displays an error message that the database could not be loaded.
62
+ */
63
+ function displayDatabaseLoadError() {
64
+ $("#format-selection").css({ display: "none" });
65
+ $("#database-error").css({ display: "block" });
66
+ }
67
+
55
68
  /**
56
69
  * Gets the input and output extensions and their notes from what's currently selected in the search boxes.
57
70
  * @returns {Array<str>} Input extension, Input note, Output extension, Output note
@@ -228,7 +228,7 @@ body {
228
228
  top : 0;
229
229
  left : 0;
230
230
  background: var(--ifm-background-color);
231
- z-index : 9999;
231
+ z-index : 99999;
232
232
  }
233
233
 
234
234
  select,
@@ -412,7 +412,8 @@ h6 {
412
412
  }
413
413
 
414
414
  p {
415
- margin: 0 0 1.25rem 0;
415
+ margin : 0 0 1.25rem 0;
416
+ padding-bottom: 0;
416
417
  }
417
418
 
418
419
  .text--center {
@@ -546,9 +547,9 @@ a svg {
546
547
  }
547
548
 
548
549
  .navbar__title h5 {
549
- display: unset;
550
+ display: flex;
550
551
  color : var(--ifm-heading-color);
551
- margin : 0 0 0.5rem 0.5rem;
552
+ margin : 0 0 0.5rem 1.5rem;
552
553
  }
553
554
 
554
555
  .navbar__logo img {