sinol-make 1.6.0.dev2__tar.gz → 1.6.0.dev4__tar.gz

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.
Files changed (53) hide show
  1. {sinol_make-1.6.0.dev2/src/sinol_make.egg-info → sinol_make-1.6.0.dev4}/PKG-INFO +1 -1
  2. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/__init__.py +13 -11
  3. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/commands/doc/__init__.py +3 -3
  4. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/commands/export/__init__.py +4 -5
  5. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/commands/gen/__init__.py +1 -4
  6. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/commands/ingen/__init__.py +4 -6
  7. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/commands/inwer/__init__.py +3 -5
  8. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/commands/outgen/__init__.py +3 -10
  9. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/commands/run/__init__.py +20 -11
  10. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/commands/verify/__init__.py +4 -0
  11. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/helpers/compiler.py +11 -6
  12. sinol_make-1.6.0.dev4/src/sinol_make/helpers/func_cache.py +30 -0
  13. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/helpers/package_util.py +33 -8
  14. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/helpers/parsers.py +11 -3
  15. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/util.py +5 -9
  16. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4/src/sinol_make.egg-info}/PKG-INFO +1 -1
  17. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make.egg-info/SOURCES.txt +1 -0
  18. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/tests/test_util.py +8 -5
  19. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/LICENSE +0 -0
  20. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/README.md +0 -0
  21. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/pyproject.toml +0 -0
  22. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/setup.cfg +0 -0
  23. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/commands/ingen/ingen_util.py +0 -0
  24. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/commands/init/__init__.py +0 -0
  25. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/commands/inwer/inwer_util.py +0 -0
  26. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/commands/outgen/outgen_util.py +0 -0
  27. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/contest_types/__init__.py +0 -0
  28. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/contest_types/default.py +0 -0
  29. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/contest_types/icpc.py +0 -0
  30. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/contest_types/oi.py +0 -0
  31. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/helpers/__init__.py +0 -0
  32. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/helpers/cache.py +0 -0
  33. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/helpers/compile.py +0 -0
  34. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/helpers/paths.py +0 -0
  35. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/helpers/printer.py +0 -0
  36. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/interfaces/BaseCommand.py +0 -0
  37. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/interfaces/Errors.py +0 -0
  38. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/interfaces/__init__.py +0 -0
  39. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/oiejq/__init__.py +0 -0
  40. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/oiejq/perf_test.py +0 -0
  41. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/structs/__init__.py +0 -0
  42. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/structs/cache_structs.py +0 -0
  43. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/structs/compiler_structs.py +0 -0
  44. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/structs/gen_structs.py +0 -0
  45. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/structs/inwer_structs.py +0 -0
  46. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/structs/run_structs.py +0 -0
  47. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make/structs/status_structs.py +0 -0
  48. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make.egg-info/dependency_links.txt +0 -0
  49. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make.egg-info/entry_points.txt +0 -0
  50. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make.egg-info/requires.txt +0 -0
  51. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/src/sinol_make.egg-info/top_level.txt +0 -0
  52. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/tests/test_multiple_arguments.py +0 -0
  53. {sinol_make-1.6.0.dev2 → sinol_make-1.6.0.dev4}/tests/test_oiejq.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sinol_make
3
- Version: 1.6.0.dev2
3
+ Version: 1.6.0.dev4
4
4
  Summary: CLI tool for creating sio2 task packages
5
5
  Author: Mateusz Masiarz
6
6
  Author-email: m.masiarz@fri.edu.pl
@@ -6,7 +6,7 @@ import argcomplete
6
6
 
7
7
  from sinol_make import util, oiejq
8
8
 
9
- __version__ = "1.6.0.dev2"
9
+ __version__ = "1.6.0.dev4"
10
10
 
11
11
 
12
12
  def configure_parsers():
@@ -50,8 +50,10 @@ def main_exn():
50
50
  parser = configure_parsers()
51
51
  arguments = []
52
52
  curr_args = []
53
+ commands = util.get_commands()
54
+ commands_dict = {command.get_name(): command for command in commands}
53
55
  for arg in sys.argv[1:]:
54
- if arg in util.get_command_names() and not (len(curr_args) > 0 and curr_args[0] == 'init'):
56
+ if arg in commands_dict.keys() and not (len(curr_args) > 0 and curr_args[0] == 'init'):
55
57
  if curr_args:
56
58
  arguments.append(curr_args)
57
59
  curr_args = [arg]
@@ -59,19 +61,19 @@ def main_exn():
59
61
  curr_args.append(arg)
60
62
  if curr_args:
61
63
  arguments.append(curr_args)
62
- commands = util.get_commands()
64
+ if not arguments:
65
+ parser.print_help()
66
+ exit(1)
63
67
  check_oiejq()
64
68
 
65
69
  for curr_args in arguments:
66
70
  args = parser.parse_args(curr_args)
67
- command_found = False
68
- for command in commands:
69
- if command.get_name() == args.command:
70
- command_found = True
71
- if len(arguments) > 1:
72
- print(f' {command.get_name()} command '.center(util.get_terminal_size()[1], '='))
73
- command.run(args)
74
- if not command_found:
71
+ command = commands_dict.get(args.command, None)
72
+ if command:
73
+ if len(arguments) > 1:
74
+ print(f' {command.get_name()} command '.center(util.get_terminal_size()[1], '='))
75
+ command.run(args)
76
+ else:
75
77
  parser.print_help()
76
78
  exit(1)
77
79
 
@@ -18,7 +18,7 @@ class Command(BaseCommand):
18
18
  return "doc"
19
19
 
20
20
  def compile_file_latex_div(self, file_path):
21
- print(util.info(f'Compiling {os.path.basename(file_path)} (latex to dvi)...'))
21
+ print(f'Compiling {os.path.basename(file_path)} (latex to dvi)...')
22
22
  os.chdir(os.path.dirname(file_path))
23
23
  subprocess.run(['latex', file_path])
24
24
  dvi_file = os.path.splitext(file_path)[0] + '.dvi'
@@ -35,7 +35,7 @@ class Command(BaseCommand):
35
35
  return True
36
36
 
37
37
  def compile_pdf_latex(self, file_path):
38
- print(util.info(f'Compiling {os.path.basename(file_path)} (pdflatex)...'))
38
+ print(f'Compiling {os.path.basename(file_path)} (pdflatex)...')
39
39
  os.chdir(os.path.dirname(file_path))
40
40
  subprocess.run(['pdflatex', file_path])
41
41
  pdf_file = os.path.splitext(file_path)[0] + '.pdf'
@@ -62,7 +62,7 @@ class Command(BaseCommand):
62
62
  for pattern in self.LOG_PATTERNS:
63
63
  for file in glob.glob(os.path.join(os.getcwd(), 'doc', pattern)):
64
64
  os.rename(file, os.path.join(output_dir, os.path.basename(file)))
65
- print(util.info(f'Compilation log files can be found in {os.path.relpath(output_dir, os.getcwd())}'))
65
+ print(f'Compilation log files can be found in {os.path.relpath(output_dir, os.getcwd())}')
66
66
 
67
67
  def configure_subparser(self, subparser: argparse.ArgumentParser):
68
68
  parser = subparser.add_parser(
@@ -28,10 +28,7 @@ class Command(BaseCommand):
28
28
  self.get_name(),
29
29
  help='Create archive for oioioi upload',
30
30
  description='Creates archive in the current directory ready to upload to sio2 or szkopul.')
31
- parser.add_argument('-c', '--cpus', type=int,
32
- help=f'number of cpus to use to generate output files '
33
- f'(default: {util.default_cpu_count()})',
34
- default=util.default_cpu_count())
31
+ parsers.add_cpus_argument(parser, 'number of cpus to use to generate output files')
35
32
  parser.add_argument('--no-statement', dest='no_statement', action='store_true',
36
33
  help='allow export without statement')
37
34
  parser.add_argument('--export-ocen', dest='export_ocen', action='store_true',
@@ -118,12 +115,14 @@ class Command(BaseCommand):
118
115
  shutil.copy(test, os.path.join(ocen_dir, ext, os.path.basename(test)))
119
116
  num_tests += 1
120
117
 
118
+ dlazaw_dir = os.path.join(os.getcwd(), 'dlazaw')
121
119
  if num_tests == 0:
122
120
  print(util.warning('No ocen tests found.'))
121
+ elif os.path.exists(dlazaw_dir):
122
+ print(util.warning('Skipping ocen arhive creation because dlazaw directory exists.'))
123
123
  else:
124
124
  shutil.make_archive(os.path.join(attachments_dir, f'{self.task_id}ocen'), 'zip', tmpdir)
125
125
 
126
- dlazaw_dir = os.path.join(os.getcwd(), 'dlazaw')
127
126
  if os.path.exists(dlazaw_dir):
128
127
  print('Archiving dlazaw directory and adding to attachments.')
129
128
  os.makedirs(os.path.join(tmpdir, 'dlazaw'), exist_ok=True)
@@ -31,10 +31,7 @@ class Command(BaseCommand):
31
31
  help='path to ingen source file, for example prog/abcingen.cpp')
32
32
  parser.add_argument('-i', '--only-inputs', action='store_true', help='generate input files only')
33
33
  parser.add_argument('-o', '--only-outputs', action='store_true', help='generate output files only')
34
- parser.add_argument('-c', '--cpus', type=int,
35
- help=f'number of cpus to use to generate output files '
36
- f'(default: {util.default_cpu_count()})',
37
- default=util.default_cpu_count())
34
+ parsers.add_cpus_argument(parser, 'number of cpus to use to generate output files')
38
35
  parser.add_argument('-n', '--no-validate', default=False, action='store_true',
39
36
  help='do not validate test contents')
40
37
  parser.add_argument('-f', '--fsanitize', default=False, action='store_true',
@@ -30,6 +30,7 @@ class Command(BaseCommand):
30
30
  help='path to ingen source file, for example prog/abcingen.cpp')
31
31
  parser.add_argument('-n', '--no-validate', default=False, action='store_true',
32
32
  help='do not validate test contents')
33
+ parsers.add_cpus_argument(parser, 'number of cpus used for validating tests')
33
34
  parser.add_argument('-f', '--fsanitize', default=False, action='store_true',
34
35
  help='Use -fsanitize=address,undefined for compilation. Warning: this may fail on some '
35
36
  'systems. Tof fix this, run `sudo sysctl vm.mmap_rnd_bits = 28`.')
@@ -45,7 +46,7 @@ class Command(BaseCommand):
45
46
  package_util.validate_test_names(self.task_id)
46
47
  util.change_stack_size_to_unlimited()
47
48
  self.ingen = get_ingen(self.task_id, args.ingen_path)
48
- print(util.info(f'Using ingen file {os.path.basename(self.ingen)}'))
49
+ print(f'Using ingen file {os.path.basename(self.ingen)}')
49
50
  self.ingen_exe = compile_ingen(self.ingen, self.args, self.args.compile_mode, self.args.fsanitize)
50
51
 
51
52
  previous_tests = []
@@ -64,7 +65,7 @@ class Command(BaseCommand):
64
65
  else:
65
66
  util.exit_with_error('Failed to generate input files.')
66
67
 
67
- print(util.info('Cleaning up old input files.'))
68
+ print('Cleaning up old input files.')
68
69
  for test in glob.glob(os.path.join(os.getcwd(), "in", f"{self.task_id}*.in")):
69
70
  basename = os.path.basename(test)
70
71
  if basename in dates and dates[basename] == os.path.getmtime(test):
@@ -74,8 +75,5 @@ class Command(BaseCommand):
74
75
  f.write("\n".join(glob.glob(os.path.join(os.getcwd(), "in", f"{self.task_id}*.in"))))
75
76
 
76
77
  if not self.args.no_validate:
77
- print(util.info('Validating input test contents.'))
78
78
  tests = sorted(glob.glob(os.path.join(os.getcwd(), "in", f"{self.task_id}*.in")))
79
- for test in tests:
80
- package_util.validate_test(test)
81
- print(util.info('Input test contents are valid!'))
79
+ package_util.validate_tests(tests, self.args.cpus, 'input')
@@ -10,8 +10,7 @@ from typing import Dict, List
10
10
 
11
11
  from sinol_make import util
12
12
  from sinol_make.structs.inwer_structs import TestResult, InwerExecution, VerificationResult, TableData
13
- from sinol_make.helpers import package_util, compile, printer, paths
14
- from sinol_make.helpers.parsers import add_compilation_arguments
13
+ from sinol_make.helpers import package_util, printer, paths, parsers
15
14
  from sinol_make.interfaces.BaseCommand import BaseCommand
16
15
  from sinol_make.commands.inwer import inwer_util
17
16
 
@@ -37,12 +36,11 @@ class Command(BaseCommand):
37
36
  help='path to inwer source file, for example prog/abcinwer.cpp')
38
37
  parser.add_argument('-t', '--tests', type=str, nargs='+',
39
38
  help='test to verify, for example in/abc{0,1}*')
40
- parser.add_argument('-c', '--cpus', type=int,
41
- help=f'number of cpus to use (default: {util.default_cpu_count()})')
39
+ parsers.add_cpus_argument(parser, 'number of cpus to use when verifying tests')
42
40
  parser.add_argument('-f', '--fsanitize', default=False, action='store_true',
43
41
  help='Use -fsanitize=address,undefined for compilation. Warning: this may fail on some '
44
42
  'systems. Tof fix this, run `sudo sysctl vm.mmap_rnd_bits = 28`.')
45
- add_compilation_arguments(parser)
43
+ parsers.add_compilation_arguments(parser)
46
44
  return parser
47
45
 
48
46
  @staticmethod
@@ -26,11 +26,7 @@ class Command(BaseCommand):
26
26
  help='Generate output files',
27
27
  description='Generate output files using the correct solution.'
28
28
  )
29
-
30
- parser.add_argument('-c', '--cpus', type=int,
31
- help=f'number of cpus to use to generate output files '
32
- f'(default: {util.default_cpu_count()})',
33
- default=util.default_cpu_count())
29
+ parsers.add_cpus_argument(parser, 'number of cpus to use to generate output files')
34
30
  parser.add_argument('-n', '--no-validate', default=False, action='store_true',
35
31
  help='do not validate test contents')
36
32
  parsers.add_compilation_arguments(parser)
@@ -50,7 +46,7 @@ class Command(BaseCommand):
50
46
  for i, result in enumerate(pool.imap(generate_output, arguments)):
51
47
  results.append(result)
52
48
  if result:
53
- print(util.info(f'Successfully generated output file {os.path.basename(arguments[i].output_test)}'))
49
+ print(f'Successfully generated output file {os.path.basename(arguments[i].output_test)}')
54
50
  else:
55
51
  print(util.error(f'Failed to generate output file {os.path.basename(arguments[i].output_test)}'))
56
52
 
@@ -130,7 +126,4 @@ class Command(BaseCommand):
130
126
  yaml.dump(md5_sums, f)
131
127
 
132
128
  if not self.args.no_validate:
133
- print(util.info('Validating output test contents.'))
134
- for test in sorted(outputs_to_generate):
135
- package_util.validate_test(test)
136
- print(util.info('Output test contents are valid!'))
129
+ package_util.validate_tests(sorted(outputs_to_generate), self.args.cpus, 'outputs')
@@ -8,21 +8,23 @@ import time
8
8
  import psutil
9
9
  import glob
10
10
  import shutil
11
+ import os
12
+ import collections
13
+ import sys
14
+ import math
15
+ import dictdiffer
16
+ import multiprocessing as mp
11
17
  from io import StringIO
12
18
  from typing import Dict
13
19
 
14
- from sinol_make import contest_types, oiejq
20
+ from sinol_make import contest_types, oiejq, util
15
21
  from sinol_make.structs.run_structs import ExecutionData, PrintData
16
22
  from sinol_make.structs.cache_structs import CacheTest, CacheFile
17
- from sinol_make.helpers.parsers import add_compilation_arguments
18
23
  from sinol_make.interfaces.BaseCommand import BaseCommand
19
24
  from sinol_make.interfaces.Errors import CompilationError, CheckerOutputException, UnknownContestType
20
- from sinol_make.helpers import compile, compiler, package_util, printer, paths, cache
25
+ from sinol_make.helpers import compile, compiler, package_util, printer, paths, cache, parsers
21
26
  from sinol_make.structs.status_structs import Status, ResultChange, PointsChange, ValidationResult, ExecutionResult, \
22
27
  TotalPointsChange
23
- import sinol_make.util as util
24
- import yaml, os, collections, sys, re, math, dictdiffer
25
- import multiprocessing as mp
26
28
 
27
29
 
28
30
  def color_memory(memory, limit):
@@ -288,8 +290,7 @@ class Command(BaseCommand):
288
290
  help='solutions to be run, for example prog/abc{b,s}*.{cpp,py}')
289
291
  parser.add_argument('-t', '--tests', type=str, nargs='+',
290
292
  help='tests to be run, for example in/abc{0,1}*')
291
- parser.add_argument('-c', '--cpus', type=int,
292
- help=f'number of cpus to use (default: {util.default_cpu_count()}')
293
+ parsers.add_cpus_argument(parser, 'number of cpus to use when running solutions')
293
294
  parser.add_argument('--tl', type=float, help='time limit for all tests (in s)')
294
295
  parser.add_argument('--ml', type=float, help='memory limit for all tests (in MB)')
295
296
  parser.add_argument('--hide-memory', dest='hide_memory', action='store_true',
@@ -300,7 +301,10 @@ class Command(BaseCommand):
300
301
  help='path to oiejq executable (default: `~/.local/bin/oiejq`)')
301
302
  parser.add_argument('-a', '--apply-suggestions', dest='apply_suggestions', action='store_true',
302
303
  help='apply suggestions from expected scores report')
303
- add_compilation_arguments(parser)
304
+ parser.add_argument('--ignore-expected', dest='ignore_expected', action='store_true',
305
+ help='ignore expected scores from config.yml. When this flag is set, '
306
+ 'the expected scores are not compared with the actual scores.')
307
+ parsers.add_compilation_arguments(parser)
304
308
  return parser
305
309
 
306
310
  def parse_time(self, time_str):
@@ -1017,7 +1021,7 @@ class Command(BaseCommand):
1017
1021
 
1018
1022
  self.config["sinol_expected_scores"] = self.convert_status_to_string(config_expected_scores)
1019
1023
  util.save_config(self.config)
1020
- print(util.info("Saved suggested expected scores description."))
1024
+ print("Saved suggested expected scores description.")
1021
1025
  else:
1022
1026
  util.exit_with_error("Use flag --apply-suggestions to apply suggestions.")
1023
1027
 
@@ -1211,7 +1215,7 @@ class Command(BaseCommand):
1211
1215
 
1212
1216
  checker = package_util.get_files_matching_pattern(self.ID, f'{self.ID}chk.*')
1213
1217
  if len(checker) != 0:
1214
- print(util.info("Checker found: %s" % os.path.basename(checker[0])))
1218
+ print("Checker found: %s" % os.path.basename(checker[0]))
1215
1219
  self.checker = checker[0]
1216
1220
  self.compile_checker()
1217
1221
  else:
@@ -1238,6 +1242,11 @@ class Command(BaseCommand):
1238
1242
 
1239
1243
  results, all_results = self.compile_and_run(solutions)
1240
1244
  self.check_errors(all_results)
1245
+ if self.args.ignore_expected:
1246
+ print(util.warning("Ignoring expected scores."))
1247
+ self.exit()
1248
+ return
1249
+
1241
1250
  try:
1242
1251
  validation_results = self.validate_expected_scores(results)
1243
1252
  except Exception:
@@ -40,6 +40,10 @@ class Command(BaseCommand):
40
40
  help=f'number of cpus that sinol-make will use '
41
41
  f'(default: {util.default_cpu_count()})',
42
42
  default=util.default_cpu_count())
43
+ parser.add_argument('--ignore-expected', dest='ignore_expected', action='store_true',
44
+ help='ignore expected scores from config.yml. When this flag is set, '
45
+ 'the expected scores are not compared with the actual scores. '
46
+ 'This flag will be passed to the run command.')
43
47
  parsers.add_compilation_arguments(parser)
44
48
 
45
49
  def remove_cache(self):
@@ -1,12 +1,12 @@
1
1
  from typing import List
2
-
2
+ import subprocess
3
3
  import argparse
4
+ import sys
4
5
  import os
5
6
 
6
- import sinol_make.util as util
7
- import sys, subprocess
8
-
7
+ from sinol_make import util
9
8
  from sinol_make.structs.compiler_structs import Compilers
9
+ from sinol_make.helpers.func_cache import cache_result
10
10
 
11
11
 
12
12
  def check_if_installed(compiler):
@@ -22,6 +22,7 @@ def check_if_installed(compiler):
22
22
  return True
23
23
 
24
24
 
25
+ @cache_result()
25
26
  def get_c_compiler_path():
26
27
  """
27
28
  Get the C compiler
@@ -41,6 +42,7 @@ def get_c_compiler_path():
41
42
  return None
42
43
 
43
44
 
45
+ @cache_result()
44
46
  def get_cpp_compiler_path():
45
47
  """
46
48
  Get the C++ compiler
@@ -62,6 +64,7 @@ def get_cpp_compiler_path():
62
64
  return None
63
65
 
64
66
 
67
+ @cache_result()
65
68
  def get_python_interpreter_path():
66
69
  """
67
70
  Get the Python interpreter
@@ -75,6 +78,7 @@ def get_python_interpreter_path():
75
78
  return None
76
79
 
77
80
 
81
+ @cache_result()
78
82
  def get_java_compiler_path():
79
83
  """
80
84
  Get the Java compiler
@@ -94,7 +98,8 @@ def get_default_compilers():
94
98
  c_compiler_path=get_c_compiler_path(),
95
99
  cpp_compiler_path=get_cpp_compiler_path(),
96
100
  python_interpreter_path=get_python_interpreter_path(),
97
- java_compiler_path=get_java_compiler_path()
101
+ # Java is not currently supported by sinol-make
102
+ # java_compiler_path=get_java_compiler_path()
98
103
  )
99
104
 
100
105
 
@@ -141,5 +146,5 @@ def verify_compilers(args: argparse.Namespace, solutions: List[str]) -> Compiler
141
146
  c_compiler_path=args.c_compiler_path,
142
147
  cpp_compiler_path=args.cpp_compiler_path,
143
148
  python_interpreter_path=args.python_interpreter_path,
144
- java_compiler_path=args.java_compiler_path
149
+ java_compiler_path=None
145
150
  )
@@ -0,0 +1,30 @@
1
+ import os
2
+
3
+ __cache = {}
4
+
5
+
6
+ def cache_result(cwd=False):
7
+ """
8
+ Function to cache the result of a function.
9
+ """
10
+ def decorator(func):
11
+ def wrapper(*args, **kwargs):
12
+ if cwd:
13
+ key = (func.__name__, os.getcwd())
14
+ else:
15
+ key = func.__name__
16
+
17
+ if key in __cache:
18
+ return __cache[key]
19
+ result = func(*args, **kwargs)
20
+ __cache[key] = result
21
+ return result
22
+ return wrapper
23
+ return decorator
24
+
25
+
26
+ def clear_cache():
27
+ """
28
+ Function to clear the cache.
29
+ """
30
+ __cache.clear()
@@ -3,13 +3,16 @@ import re
3
3
  import yaml
4
4
  import glob
5
5
  import fnmatch
6
+ import multiprocessing as mp
6
7
  from enum import Enum
7
- from typing import List, Union, Dict, Any
8
+ from typing import List, Union, Dict, Any, Tuple
8
9
 
10
+ from sinol_make.helpers.func_cache import cache_result
9
11
  from sinol_make import util
10
12
  from sinol_make.helpers import paths
11
13
 
12
14
 
15
+ @cache_result(cwd=True)
13
16
  def get_task_id() -> str:
14
17
  config = get_config()
15
18
  if "sinol_task_id" in config:
@@ -353,11 +356,12 @@ def save_contest_type_to_cache(contest_type):
353
356
  contest_type_file.write(contest_type)
354
357
 
355
358
 
356
- def validate_test(test_path: str):
359
+ def validate_test(test_path: str) -> Tuple[bool, str]:
357
360
  """
358
361
  Check if test doesn't contain leading/trailing whitespaces,
359
362
  has only one space between tokens and ends with newline.
360
363
  Exits with error if any of the conditions is not met.
364
+ :return: Tuple of two values: True if test is valid, error message otherwise.
361
365
  """
362
366
  basename = os.path.basename(test_path)
363
367
  num_empty = 0
@@ -366,24 +370,45 @@ def validate_test(test_path: str):
366
370
  for i, line in enumerate(lines):
367
371
  line = line.decode('utf-8')
368
372
  if len(line) > 0 and line[0] == ' ':
369
- util.exit_with_error(f'Leading whitespace in {basename}:{i + 1}')
373
+ return False, util.error(f'Leading whitespace in {basename}:{i + 1}')
370
374
  if len(line) > 0 and (line[-2:] == '\r\n' or line[-2:] == '\n\r' or line[-1] == '\r'):
371
- util.exit_with_error(f'Carriage return at the end of {basename}:{i + 1}')
375
+ return False, util.error(f'Carriage return at the end of {basename}:{i + 1}')
372
376
  if len(line) > 0 and line[-1] != '\n':
373
- util.exit_with_error(f'No newline at the end of {basename}')
377
+ return False, util.error(f'No newline at the end of {basename}')
374
378
  if line == '\n' or line == '':
375
379
  num_empty += 1
376
380
  continue
377
381
  elif i == len(lines) - 1:
378
382
  num_empty = 0
379
383
  if line[-2] == ' ':
380
- util.exit_with_error(f'Trailing whitespace in {basename}:{i + 1}')
384
+ return False, util.error(f'Trailing whitespace in {basename}:{i + 1}')
381
385
  for j in range(len(line) - 1):
382
386
  if line[j] == ' ' and line[j + 1] == ' ':
383
- util.exit_with_error(f'Tokens not separated by one space in {basename}:{i + 1}')
387
+ return False, util.error(f'Tokens not separated by one space in {basename}:{i + 1}')
384
388
 
385
389
  if num_empty != 0:
386
- util.exit_with_error(f'Exactly one empty line expected in {basename}')
390
+ return False, util.error(f'Exactly one empty line expected in {basename}')
391
+
392
+ return True, ''
393
+
394
+
395
+ def validate_tests(tests: List[str], cpus: int, type: str = 'input'):
396
+ """
397
+ Validate all tests in parallel.
398
+ """
399
+ if not tests:
400
+ return
401
+ print(f'Validating {type} test contents.')
402
+ num_tests = len(tests)
403
+ finished = 0
404
+ with mp.Pool(cpus) as pool:
405
+ for valid, message in pool.imap(validate_test, tests):
406
+ if not valid:
407
+ util.exit_with_error(message)
408
+ finished += 1
409
+ print(f'Validated {finished}/{num_tests} tests', end='\r')
410
+ print()
411
+ print(util.info(f'All {type} tests are valid!'))
387
412
 
388
413
 
389
414
  def get_all_inputs(task_id):
@@ -1,7 +1,7 @@
1
1
  import sys
2
-
3
2
  import argparse
4
3
 
4
+ from sinol_make import util
5
5
  from sinol_make.helpers import compiler
6
6
 
7
7
 
@@ -20,8 +20,9 @@ def add_compilation_arguments(parser: argparse.ArgumentParser):
20
20
  parser.add_argument('--python-interpreter-path', dest='python_interpreter_path', type=str,
21
21
  default=compiler.get_python_interpreter_path(),
22
22
  help='Python interpreter to use (default: python3)')
23
- parser.add_argument('--java-compiler-path', dest='java_compiler_path', type=str,
24
- default=compiler.get_java_compiler_path(), help='Java compiler to use (default: javac)')
23
+ # Java is not currently supported by sinol-make
24
+ # parser.add_argument('--java-compiler-path', dest='java_compiler_path', type=str,
25
+ # default=compiler.get_java_compiler_path(), help='Java compiler to use (default: javac)')
25
26
  parser.add_argument('--compile-mode', '-C', dest='compile_mode', choices=['default', 'oioioi', 'weak', 'd', 'o', 'w'],
26
27
  help='Warning flag groups used to compile C/C++ files. Available options:\n'
27
28
  ' default / d - uses default flags: \n'
@@ -29,3 +30,10 @@ def add_compilation_arguments(parser: argparse.ArgumentParser):
29
30
  ' oioioi / o - uses the same flags as oioioi:\n'
30
31
  ' (-Wall -Wno-unused-result -Werror)'
31
32
  ' weak / w - disable all warning flags during C and C++ compilation', default='default')
33
+
34
+
35
+ def add_cpus_argument(parser: argparse.ArgumentParser, help: str):
36
+ parser.add_argument('-c', '--cpus', type=int,
37
+ help=f'{help} '
38
+ f'(default: {util.default_cpu_count()})',
39
+ default=util.default_cpu_count())
@@ -1,6 +1,5 @@
1
1
  import glob, importlib, os, sys, requests, yaml
2
2
  import math
3
- import multiprocessing
4
3
  import platform
5
4
  import tarfile
6
5
  import hashlib
@@ -11,19 +10,15 @@ from packaging.version import parse as parse_version
11
10
 
12
11
  from sinol_make.contest_types import get_contest_type
13
12
  from sinol_make.helpers import paths, cache
13
+ from sinol_make.helpers.func_cache import cache_result
14
14
  from sinol_make.structs.status_structs import Status
15
15
 
16
16
 
17
- __cache = {}
18
-
19
-
17
+ @cache_result()
20
18
  def get_commands():
21
19
  """
22
20
  Function to get an array of all available commands.
23
21
  """
24
- global __cache
25
- if 'commands' in __cache:
26
- return __cache['commands']
27
22
  commands_path = glob.glob(
28
23
  os.path.join(
29
24
  os.path.dirname(os.path.realpath(__file__)),
@@ -35,7 +30,6 @@ def get_commands():
35
30
  temp = importlib.import_module('sinol_make.commands.' + os.path.basename(path), 'Command')
36
31
  commands.append(temp.Command())
37
32
 
38
- __cache['commands'] = commands
39
33
  return commands
40
34
 
41
35
 
@@ -214,7 +208,9 @@ def check_version():
214
208
  return
215
209
 
216
210
  data = request.json()
217
- latest_version = data["info"]["version"]
211
+ versions = list(data["releases"].keys())
212
+ versions.sort(key=parse_version)
213
+ latest_version = versions[-1]
218
214
 
219
215
  version_file = importlib.files("sinol_make").joinpath("data/version")
220
216
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sinol_make
3
- Version: 1.6.0.dev2
3
+ Version: 1.6.0.dev4
4
4
  Summary: CLI tool for creating sio2 task packages
5
5
  Author: Mateusz Masiarz
6
6
  Author-email: m.masiarz@fri.edu.pl
@@ -30,6 +30,7 @@ src/sinol_make/helpers/__init__.py
30
30
  src/sinol_make/helpers/cache.py
31
31
  src/sinol_make/helpers/compile.py
32
32
  src/sinol_make/helpers/compiler.py
33
+ src/sinol_make/helpers/func_cache.py
33
34
  src/sinol_make/helpers/package_util.py
34
35
  src/sinol_make/helpers/parsers.py
35
36
  src/sinol_make/helpers/paths.py
@@ -52,24 +52,27 @@ def test_check_version(**kwargs):
52
52
  """
53
53
  mocker = kwargs["mocker"]
54
54
 
55
- mocker.get("https://pypi.python.org/pypi/sinol-make/json", json={"info": {"version": "1.0.0.dev2"}})
55
+ def create_response(version):
56
+ return {"releases": {version: "something"}}
57
+
58
+ mocker.get("https://pypi.python.org/pypi/sinol-make/json", json=create_response("1.0.0.dev2"))
56
59
  util.check_version()
57
60
  version = util.check_for_updates("1.0.0.dev1", False)
58
61
  assert version == "1.0.0.dev2"
59
62
  assert util.is_dev(version)
60
63
 
61
- mocker.get("https://pypi.python.org/pypi/sinol-make/json", json={"info": {"version": "1.0.0"}})
64
+ mocker.get("https://pypi.python.org/pypi/sinol-make/json", json=create_response("1.0.0"))
62
65
  util.check_version()
63
66
  version = util.check_for_updates("1.0.0.dev1", False)
64
67
  assert version == "1.0.0"
65
68
  assert not util.is_dev(version)
66
69
 
67
- mocker.get("https://pypi.python.org/pypi/sinol-make/json", json={"info": {"version": "2.0.0.dev1"}})
70
+ mocker.get("https://pypi.python.org/pypi/sinol-make/json", json=create_response("2.0.0.dev1"))
68
71
  util.check_version()
69
72
  version = util.check_for_updates("1.0.0", False)
70
73
  assert version is None
71
74
 
72
- mocker.get("https://pypi.python.org/pypi/sinol-make/json", json={"info": {"version": "1.0.1"}})
75
+ mocker.get("https://pypi.python.org/pypi/sinol-make/json", json=create_response("1.0.1"))
73
76
  util.check_version()
74
77
  version = util.check_for_updates("1.0.0", False)
75
78
  assert version == "1.0.1"
@@ -86,7 +89,7 @@ def test_check_version(**kwargs):
86
89
  version_file.unlink()
87
90
 
88
91
  # Test correct request
89
- mocker.get("https://pypi.python.org/pypi/sinol-make/json", json={"info": {"version": "1.0.0"}})
92
+ mocker.get("https://pypi.python.org/pypi/sinol-make/json", json=create_response(("1.0.0")))
90
93
  util.check_version()
91
94
  assert version_file.is_file()
92
95
  assert version_file.read_text() == "1.0.0"
File without changes