diff --git a/docs/requirements.txt b/docs/requirements.txt index f1a7f110..808e5477 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,4 +2,3 @@ m2r sphinx_rtd_theme docutils<0.18 mistune<2.0.0 - diff --git a/examples/Getting_started.ipynb b/examples/Getting_started.ipynb index ed195572..91c8fec1 100644 --- a/examples/Getting_started.ipynb +++ b/examples/Getting_started.ipynb @@ -310,7 +310,7 @@ "outputs": [], "source": [ "outdir = \"example_output\"\n", - "submission.create_files(outdir)" + "submission.create_files(outdir,remove_old=True)" ] }, { diff --git a/examples/combine_limits.ipynb b/examples/combine_limits.ipynb index ea9ad677..2a1fa151 100644 --- a/examples/combine_limits.ipynb +++ b/examples/combine_limits.ipynb @@ -276,7 +276,7 @@ "table.add_variable(obs)\n", "table.add_variable(exp)\n", "submission.add_table(table)\n", - "submission.create_files(\"example_output\")" + "submission.create_files(\"example_output\",remove_old=True)" ] }, { diff --git a/examples/correlation.ipynb b/examples/correlation.ipynb index a3e14d8a..589047b0 100644 --- a/examples/correlation.ipynb +++ b/examples/correlation.ipynb @@ -282,7 +282,7 @@ "# Create the submission object and write output\n", "sub = Submission()\n", "sub.add_table(table)\n", - "sub.create_files(\"./output/\")\n", + "sub.create_files(\"./output/\",remove_old=True)\n", "\n", "!ls -l submission.tar.gz" ] diff --git a/examples/read_c_file.ipynb b/examples/read_c_file.ipynb index 31fc5feb..7dd057cf 100644 --- a/examples/read_c_file.ipynb +++ b/examples/read_c_file.ipynb @@ -152,7 +152,7 @@ "table.add_variable(obs)\n", "table.add_variable(exp)\n", "submission.add_table(table)\n", - "submission.create_files(\"example_output\")" + "submission.create_files(\"example_output\",remove_old=True)" ] }, { diff --git a/examples/reading_histograms.ipynb b/examples/reading_histograms.ipynb index fba39ae4..961c0a3e 100644 --- a/examples/reading_histograms.ipynb +++ b/examples/reading_histograms.ipynb @@ -258,7 +258,7 @@ "\n", "submission.add_table(table)\n", "\n", - "submission.create_files(\"example_output\")" + "submission.create_files(\"example_output\",remove_old=True)" ] }, { @@ -311,7 +311,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.5" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/hepdata_lib/__init__.py b/hepdata_lib/__init__.py index 34b36fa9..f8c3b5e4 100644 --- a/hepdata_lib/__init__.py +++ b/hepdata_lib/__init__.py @@ -11,7 +11,6 @@ import numpy as np import yaml from future.utils import raise_from - # try to use LibYAML bindings if possible try: from yaml import CLoader as Loader, CSafeDumper as Dumper @@ -19,6 +18,7 @@ from yaml import Loader, SafeDumper as Dumper from yaml.representer import SafeRepresenter +from hepdata_validator.full_submission_validator import FullSubmissionValidator from hepdata_lib import helpers from hepdata_lib.root_utils import RootFileReader @@ -538,13 +538,21 @@ def files_to_copy_nested(self): files = files + table.files_to_copy return files - def create_files(self, outdir="."): + def create_files(self, outdir=".", validate=True, remove_old=True): """ Create the output files. Implicitly triggers file creation for all tables that have been added to the submission, all variables associated to the tables and all uncertainties associated to the variables. + + If `validate` is True, the hepdata-validator package will be used to validate the + output tar ball. + + If `remove_old` is True, the output directory will be deleted before recreation. """ + if remove_old and os.path.exists(outdir): + shutil.rmtree(outdir) + if not os.path.exists(outdir): os.makedirs(outdir) @@ -580,13 +588,21 @@ def create_files(self, outdir="."): files_to_add.extend( [os.path.join(outdir, os.path.basename(x)) for x in self.files_to_copy_nested()] ) - with tarfile.open("submission.tar.gz", "w:gz") as tar: + tarfile_path = "submission.tar.gz" + with tarfile.open(tarfile_path, "w:gz") as tar: for filepath in files_to_add: tar.add( filepath, arcname=os.path.basename(filepath) ) + if validate: + full_submission_validator = FullSubmissionValidator() + is_archive_valid = full_submission_validator.validate(archive=tarfile_path) + if not is_archive_valid: + for filename in full_submission_validator.get_messages(): + full_submission_validator.print_errors(filename) + assert is_archive_valid, "The tar ball is not valid" class Uncertainty(object): """ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..508915ee --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +numpy +PyYAML>4.* +future +six +hepdata-validator>=0.3.2 \ No newline at end of file diff --git a/setup.py b/setup.py index 7a40e368..650b6e45 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,8 @@ except ImportError: print("ROOT is required by this library.") -DEPS = ['numpy', 'PyYAML>4.*', 'future', 'six'] +with open("requirements.txt","r") as f: + DEPS = f.readlines() HERE = path.abspath(path.dirname(__file__)) @@ -27,8 +28,6 @@ classifiers=[ 'Development Status :: 4 - Beta', 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', @@ -39,7 +38,6 @@ install_requires=DEPS, setup_requires=['pytest-runner', 'pytest-cov'], tests_require=['pytest', 'papermill', 'six', - 'pylint==1.9.5; python_version<"3"', 'pylint==2.9.6; python_version>="3"', ], project_urls={ diff --git a/tests/test_output.py b/tests/test_output.py index 868d5ac2..a007316f 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -2,11 +2,12 @@ # -*- coding:utf-8 -*- """Test Output.""" from __future__ import print_function -import os from collections import defaultdict from unittest import TestCase import shutil +import os import yaml +from test_utilities import tmp_directory_name from hepdata_lib import Submission, Table, Variable class TestOutput(TestCase): @@ -14,6 +15,7 @@ class TestOutput(TestCase): def test_yaml_output(self): """Test yaml dump""" + tmp_dir = tmp_directory_name() # Create test dictionary testlist = [("x", 1.2), ("x", 2.2), ("y", 0.12), ("y", 0.22)] @@ -23,7 +25,6 @@ def test_yaml_output(self): # Create test submission test_submission = Submission() - testdir = "./output" test_table = Table("TestTable") x_variable = Variable("X", is_independent=True, is_binned=False) x_variable.values = testdict['x'] @@ -32,11 +33,12 @@ def test_yaml_output(self): test_table.add_variable(x_variable) test_table.add_variable(y_variable) test_submission.add_table(test_table) - test_submission.create_files(testdir) + test_submission.create_files(tmp_dir) # Test read yaml file + table_file = os.path.join(tmp_dir, "testtable.yaml") try: - with open("output/testtable.yaml", 'r') as testfile: + with open(table_file, 'r') as testfile: testyaml = yaml.safe_load(testfile) except yaml.YAMLError as exc: print(exc) @@ -45,10 +47,10 @@ def test_yaml_output(self): testtxt = ("dependent_variables:\n- header:\n name: Y\n values:\n" + " - value: 0.12\n - value: 0.22\nindependent_variables:\n" + "- header:\n name: X\n values:\n - value: 1.2\n - value: 2.2\n") - with open("output/testtable.yaml", 'r') as testfile: + with open(table_file, 'r') as testfile: testyaml = testfile.read() self.assertEqual(str(testyaml), testtxt) self.addCleanup(os.remove, "submission.tar.gz") - self.addCleanup(shutil.rmtree, testdir) + self.addCleanup(shutil.rmtree, tmp_dir) self.doCleanups() diff --git a/tests/test_submission.py b/tests/test_submission.py index c7372cba..2b20cbb3 100644 --- a/tests/test_submission.py +++ b/tests/test_submission.py @@ -7,6 +7,7 @@ from builtins import bytes from unittest import TestCase import tarfile +from test_utilities import tmp_directory_name from hepdata_lib import Submission, Table, Variable, Uncertainty class TestSubmission(TestCase): @@ -71,15 +72,45 @@ def test_additional_resource_size(self): def test_create_files(self): """Test create_files() for Submission.""" - testdir = "test_output" + testdir = tmp_directory_name() test_submission = Submission() - self.addCleanup(os.remove, "submission.tar.gz") - self.addCleanup(shutil.rmtree, testdir) - + tab = Table("test") + test_submission.add_table(tab) test_submission.create_files(testdir) self.doCleanups() + def test_create_files_with_removal(self): + """Test the removal of old files in create_files()""" + testdir = tmp_directory_name() + + # Step 1: Create test directory containing random file + os.makedirs(testdir) + self.addCleanup(shutil.rmtree, testdir) + testfile = os.path.join(testdir, "test.txt") + with open(testfile, "w") as f: + f.write("test") + self.assertTrue(os.path.isfile(testfile)) + + # Step 2: Create submission and write output to test directory + # Without overwriting of files + test_submission = Submission() + tab = Table("test") + test_submission.add_table(tab) + test_submission.create_files(testdir, remove_old=False) + + # Test file should still exist + self.assertTrue(os.path.isfile(testfile)) + + # Step 3: Recreate submission files with removal + test_submission.create_files(testdir, remove_old=True) + + # Test file should no longer exist + self.assertFalse(os.path.isfile(testfile)) + + + + def test_read_abstract(self): """Test read_abstract function.""" some_string = string.ascii_lowercase diff --git a/tests/test_table.py b/tests/test_table.py index 189d2a30..85517357 100644 --- a/tests/test_table.py +++ b/tests/test_table.py @@ -5,6 +5,7 @@ import shutil from unittest import TestCase +from test_utilities import tmp_directory_name from hepdata_lib import Table, Variable, Uncertainty class TestTable(TestCase): @@ -61,7 +62,7 @@ def test_write_yaml(self): test_table = Table("Some Table") test_variable = Variable("Some Variable") test_table.add_variable(test_variable) - testdir = "test_output" + testdir = tmp_directory_name() self.addCleanup(shutil.rmtree, testdir) try: test_table.write_yaml(testdir) @@ -110,7 +111,7 @@ def test_write_images(self): # This should work fine test_table.add_image(some_pdf) - testdir = "test_output" + testdir = tmp_directory_name() self.addCleanup(shutil.rmtree, testdir) try: test_table.write_images(testdir) @@ -182,7 +183,7 @@ def test_copy_files(self): """Test the copy_files function.""" test_table = Table("Some Table") some_pdf = "%s/minimal.pdf" % os.path.dirname(__file__) - testdir = "test_output" + testdir = tmp_directory_name() self.addCleanup(shutil.rmtree, testdir) os.makedirs(testdir) diff --git a/tests/test_utilities.py b/tests/test_utilities.py index 45b5d09f..71975eed 100644 --- a/tests/test_utilities.py +++ b/tests/test_utilities.py @@ -62,6 +62,17 @@ def get_random_id(length=12): return "".join(random.sample(string.ascii_uppercase+string.digits, length)) +def tmp_directory_name(): + """ + Generate a random directory name for testing. + + Guaranteed to not exist. + """ + tmp_name = "/tmp/hepdata_lib_test_" + get_random_id() + if os.path.exists(tmp_name): + return tmp_directory_name() + return tmp_name + def remove_if_exist(path_to_file): """Remove file if it exists.""" if os.path.exists(path_to_file):