diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a64aede67..c73e3248d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,9 +55,7 @@ jobs: matrix: postgres-version: [ 14 ] os-version: [ '2.11.0' ] - python-version: [ '3.8', '3.9' ] - exclude: - - python-version: ${{ github.event.act && '3.8' }} + python-version: [ '3.9' ] # Service containers to run with `runner-job` services: diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index abcb111cb..5fb573258 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -92,7 +92,7 @@ Before you submit a pull request, check that it meets these guidelines: 1. The pull request should include tests and must not decrease test coverage. 2. If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring. -3. The pull request should work for Python 3.8 and 3.9. Check +3. The pull request should work for Python 3.9. Check https://github.com/HEPData/hepdata/actions?query=event%3Apull_request and make sure that the tests pass. Sometimes there are temporary failures, for example, due to unavailability of an external service or the test infrastructure. diff --git a/INSTALL.rst b/INSTALL.rst index 06477b2d1..a6550d767 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -29,7 +29,7 @@ Running services locally Prerequisites ============= -HEPData runs with Python 3.8 or 3.9. It also uses several services, which you will need to install before running HEPData. +HEPData runs with Python 3.9. It also uses several services, which you will need to install before running HEPData. These services can be installed using the relevant package manager for your system, for example, using ``yum`` or ``apt-get`` for Linux or ``brew`` for macOS: @@ -84,7 +84,7 @@ Installation Python ------ -The HEPData code is only compatible with Python 3.8 or 3.9 (not Python 2 or other 3.x versions). We recommend Python 3.9. +The HEPData code is only compatible with Python 3.9 (not Python 2 or other 3.x versions). First install all requirements in a Python virtual environment. (Use `virtualenv `_ or diff --git a/hepdata/cli.py b/hepdata/cli.py index d0b9c64fe..36b4d54fd 100644 --- a/hepdata/cli.py +++ b/hepdata/cli.py @@ -223,9 +223,9 @@ def do_unload(records_to_unload): @utils.command() @with_appcontext -@click.option('--endpoint', '-e', type=str, help='Specific endpoint to update (e.g. "rivet" or "MadAnalysis"). Omit for all.') +@click.option('--endpoint', '-e', type=str, help='Specific endpoint to update (e.g. "rivet" or "MadAnalysis" or "SModelS"). Omit for all.') def find_and_add_record_analyses(endpoint): - """Finds analyses such as Rivet and MadAnalysis 5 and adds them to records.""" + """Finds analyses such as Rivet, MadAnalysis 5 and SModelS and adds them to records.""" update_analyses(endpoint) diff --git a/hepdata/config.py b/hepdata/config.py index 9bf7c4794..5d0d1c6a9 100644 --- a/hepdata/config.py +++ b/hepdata/config.py @@ -328,6 +328,11 @@ def _(x): 'endpoint_url': 'https://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/MA5SandBox/analyses.json', 'url_template': 'https://doi.org/{0}' }, + 'SModelS': { + 'endpoint_url': 'https://zenodo.org/records/13952092/files/smodels-analyses.hepdata.json?download=1', + 'url_template': '{0}', + 'subscribe_user_id': 7766 + } #'ufo': {}, #'xfitter': {}, #'applgrid': {}, diff --git a/hepdata/ext/opensearch/document_enhancers.py b/hepdata/ext/opensearch/document_enhancers.py index 1f1a0dd7d..6ca9173ac 100644 --- a/hepdata/ext/opensearch/document_enhancers.py +++ b/hepdata/ext/opensearch/document_enhancers.py @@ -94,7 +94,7 @@ def add_shortened_authors(doc): def add_analyses(doc): """ - Add analyses links such as Rivet, MadAnalysis 5, HistFactory and NUISANCE to the index. + Add analyses links such as Rivet, MadAnalysis 5, SModelS, HistFactory and NUISANCE to the index. :param doc: :return: diff --git a/hepdata/modules/inspire_api/parser.py b/hepdata/modules/inspire_api/parser.py index e10a61c8c..52c3c70fb 100644 --- a/hepdata/modules/inspire_api/parser.py +++ b/hepdata/modules/inspire_api/parser.py @@ -202,7 +202,8 @@ def updated_parsed_content_for_thesis(content, parsed_content): if 'date' in content['metadata']['thesis_info'].keys(): parsed_content['year'] = content['metadata']['thesis_info']['date'] if parsed_content['year'] is not None: - if content['metadata']['legacy_creation_date'][:4] == parsed_content['year']: + if ('legacy_creation_date' in content['metadata'].keys() and + content['metadata']['legacy_creation_date'][:4] == parsed_content['year']): parsed_content['creation_date'] = content['metadata']['legacy_creation_date'] else: parsed_content['creation_date'] = expand_date(parsed_content['year']) diff --git a/hepdata/modules/records/assets/js/hepdata_common.js b/hepdata/modules/records/assets/js/hepdata_common.js index 70b4f2d7e..a55d69633 100644 --- a/hepdata/modules/records/assets/js/hepdata_common.js +++ b/hepdata/modules/records/assets/js/hepdata_common.js @@ -45,6 +45,7 @@ HEPDATA.file_type_to_details = { "fastnlo": {"icon": "area-chart", "description": "fastNLO Analysis"}, "rivet": {"icon": "area-chart", "description": "Rivet Analysis"}, "madanalysis": {"icon": "area-chart", "description": "MadAnalysis 5 Analysis"}, + "smodels": {"icon": "area-chart", "description": "SModelS Analysis"}, "xfitter": {"icon": "area-chart", "description": "xFitter Analysis"}, "applgrid": {"icon": "area-chart", "description": "APPLgrid Analysis"}, "ufo": {"icon": "rocket", "description": "Universal Feynrules Output (UFO)"}, diff --git a/hepdata/modules/records/subscribers/api.py b/hepdata/modules/records/subscribers/api.py index 7aad6f03f..feeebe8bb 100644 --- a/hepdata/modules/records/subscribers/api.py +++ b/hepdata/modules/records/subscribers/api.py @@ -31,12 +31,14 @@ from .models import Subscribers -def is_current_user_subscribed_to_record(recid): - if not current_user.is_authenticated: - return False +def is_current_user_subscribed_to_record(recid, user=None): + if not user: + user = current_user + if not current_user.is_authenticated: + return False return Subscribers.query.filter(Subscribers.publication_recid == recid, - Subscribers.subscribers.contains(current_user)).count() > 0 + Subscribers.subscribers.contains(user)).count() > 0 def get_users_subscribed_to_record(recid): diff --git a/hepdata/modules/records/subscribers/rest.py b/hepdata/modules/records/subscribers/rest.py index 1312f6576..78c0f2d23 100644 --- a/hepdata/modules/records/subscribers/rest.py +++ b/hepdata/modules/records/subscribers/rest.py @@ -34,13 +34,17 @@ def list_subscriptions_for_user(): @blueprint.route('/subscribe/', methods=['POST']) -@login_required -def subscribe(recid): +def subscribe(recid, user=None): + if not user: + user = current_user + if not current_user.is_authenticated: + return jsonify({"success": False, "status_code": 500}) + record_subscribers = get_or_create(db.session, Subscribers, publication_recid=recid) try: - if not current_user in record_subscribers.subscribers: - record_subscribers.subscribers.append(current_user) + if not user in record_subscribers.subscribers: + record_subscribers.subscribers.append(user) db.session.add(record_subscribers) db.session.commit() diff --git a/hepdata/modules/records/templates/hepdata_records/components/resources-widget.html b/hepdata/modules/records/templates/hepdata_records/components/resources-widget.html index 396017f49..17c295b57 100644 --- a/hepdata/modules/records/templates/hepdata_records/components/resources-widget.html +++ b/hepdata/modules/records/templates/hepdata_records/components/resources-widget.html @@ -40,6 +40,7 @@

Add Resource for Submission

+ diff --git a/hepdata/modules/records/utils/analyses.py b/hepdata/modules/records/utils/analyses.py index 983a407f6..35b4b7305 100644 --- a/hepdata/modules/records/utils/analyses.py +++ b/hepdata/modules/records/utils/analyses.py @@ -32,6 +32,9 @@ from hepdata.ext.opensearch.api import index_record_ids from hepdata.modules.submission.api import get_latest_hepsubmission, is_resource_added_to_submission from hepdata.modules.submission.models import DataResource, HEPSubmission, data_reference_link +from hepdata.utils.users import get_user_from_id +from hepdata.modules.records.subscribers.rest import subscribe +from hepdata.modules.records.subscribers.api import is_current_user_subscribed_to_record logging.basicConfig() log = logging.getLogger(__name__) @@ -40,9 +43,10 @@ @shared_task def update_analyses(endpoint=None): """ - Update (Rivet and MadAnalysis 5) analyses and remove outdated resources. + Update (Rivet, MadAnalysis 5 and SModelS) analyses and remove outdated resources. + Allow bulk subscription to record update notifications if "subscribe_user_id" in endpoint. - :param endpoint: either "Rivet" or "MadAnalysis" or None (default) for both + :param endpoint: either "rivet" or "MadAnalysis" or "SModelS" or None (default) for both """ endpoints = current_app.config["ANALYSES_ENDPOINTS"] for analysis_endpoint in endpoints: @@ -137,5 +141,14 @@ def update_analyses(endpoint=None): db.session.rollback() log.error(e) + # Allow bulk subscription to record update notifications. + if "subscribe_user_id" in endpoints[analysis_endpoint]: + user = get_user_from_id(endpoints[analysis_endpoint]["subscribe_user_id"]) + if user: + for record in analyses: + submission = get_latest_hepsubmission(inspire_id=record, overall_status='finished') + if submission and not is_current_user_subscribed_to_record(submission.publication_recid, user): + subscribe(submission.publication_recid, user) + else: log.debug("No endpoint url configured for {0}".format(analysis_endpoint)) diff --git a/hepdata/modules/search/templates/hepdata_search/modals/search_help.html b/hepdata/modules/search/templates/hepdata_search/modals/search_help.html index 4b583fe91..58e3410d0 100644 --- a/hepdata/modules/search/templates/hepdata_search/modals/search_help.html +++ b/hepdata/modules/search/templates/hepdata_search/modals/search_help.html @@ -236,6 +236,13 @@

Other useful searches

(MadAnalysis 5 analysis) +
  • + analysis:SModelS + + (SModelS analysis) + +
  • analysis:HistFactory diff --git a/hepdata/modules/theme/templates/hepdata_theme/pages/about.html b/hepdata/modules/theme/templates/hepdata_theme/pages/about.html index ed8ab9b27..6b2384419 100644 --- a/hepdata/modules/theme/templates/hepdata_theme/pages/about.html +++ b/hepdata/modules/theme/templates/hepdata_theme/pages/about.html @@ -243,6 +243,11 @@

      {% with talks = [ + {'meeting': 'IAEA Technical Meeting', + 'location': 'IAEA Headquarters, Vienna (remote by Webex)', + 'speaker': 'Graeme Watt', + 'date': 'Nov 2024', + 'link': 'https://conferences.iaea.org/event/395/contributions/33566/attachments/18373/31069/watt_hepdata_nov2024.pdf'}, {'meeting': 'Reinterpretation & OpenMAPP', 'location': 'LPSC Grenoble (remote by Zoom)', 'speaker': 'Graeme Watt', diff --git a/hepdata/version.py b/hepdata/version.py index ab77b8272..eeef8cfc9 100644 --- a/hepdata/version.py +++ b/hepdata/version.py @@ -28,4 +28,4 @@ and parsed by ``setup.py``. """ -__version__ = "0.9.4dev20241003" +__version__ = "0.9.4dev20241112" diff --git a/requirements.txt b/requirements.txt index d7d14537b..0e6c00fc6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,12 +1,12 @@ beautifulsoup4==4.12.3 -bleach==6.1.0 +bleach==6.2.0 datacite==1.1.4 gunicorn==23.0.0 hepdata-converter-ws-client==0.2.2 hepdata-validator==0.3.5 invenio-access==2.0.0 # Indirect (needed by invenio-admin) -invenio-accounts==5.1.2 -invenio-admin==1.5.0 +invenio-accounts==5.1.3 +invenio-admin==1.5.1 invenio-assets==3.0.3 invenio-config==1.0.4 invenio-db[postgresql]==1.1.5 @@ -15,8 +15,8 @@ invenio-oauthclient==4.0.2 invenio-pidstore==1.3.1 invenio-records==2.3.0 invenio-search[opensearch2]==2.4.1 -invenio-theme==3.4.1 +invenio-theme==3.4.3 invenio-userprofiles==3.0.0 -python-twitter-v2==0.9.1 +python-twitter-v2==0.9.2 responses==0.25.3 unicodeit==0.7.5 diff --git a/setup.py b/setup.py index 93995a73d..ab971b3de 100644 --- a/setup.py +++ b/setup.py @@ -141,9 +141,8 @@ 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development :: Libraries :: Python Modules', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Development Status :: Production', ], - python_requires='>=3.8, <3.10', + python_requires='>=3.9, <3.10', ) diff --git a/tests/records_test.py b/tests/records_test.py index 22c10feac..988f7692d 100644 --- a/tests/records_test.py +++ b/tests/records_test.py @@ -68,6 +68,7 @@ get_inspire_records_updated_on, update_record_info, RECORDS_PER_PAGE from hepdata.modules.inspire_api.views import get_inspire_record_information from hepdata.config import CFG_TMPDIR +from hepdata.modules.records.subscribers.api import is_current_user_subscribed_to_record def test_record_creation(app): @@ -1030,7 +1031,7 @@ def test_create_breadcrumb_text(): def test_update_analyses(app): - """ Test update of Rivet analyses """ + """ Test update of Rivet, MadAnalyses 5 and SModelS analyses """ # Import a record that already has a Rivet analysis attached (but with '#' in the URL) import_records(['ins1203852'], synchronous=True) @@ -1059,6 +1060,20 @@ def test_update_analyses(app): assert len(analysis_resources) == 1 assert analysis_resources[0].file_location == 'https://doi.org/10.14428/DVN/I2CZWU' + # Import a record that has an associated SModelS analysis + import_records(['ins1847779'], synchronous=True) + analysis_resources = DataResource.query.filter_by(file_type='SModelS').all() + assert len(analysis_resources) == 0 + user = User(email='test@test.com', password='hello1', active=True, id=7766) + db.session.add(user) + db.session.commit() + update_analyses('SModelS') + analysis_resources = DataResource.query.filter_by(file_type='SModelS').all() + assert len(analysis_resources) == 1 + assert analysis_resources[0].file_location == 'https://smodels.github.io/docs/ListOfAnalyses#ATLAS-EXOT-2018-06' + submission = get_latest_hepsubmission(inspire_id='1847779', overall_status='finished') + assert is_current_user_subscribed_to_record(submission.publication_recid, user) + def test_generate_license_data_by_id(app): """