From 96db57564e294872388169fdb5e2f43808453cfd Mon Sep 17 00:00:00 2001 From: Martin Habedank Date: Thu, 22 May 2025 11:25:39 +0100 Subject: [PATCH 01/12] add support for yoda-H5 --- README.md | 4 ++-- hepdata_cli/api.py | 5 +++-- hepdata_cli/cli.py | 4 ++-- tests/test_download.py | 1 + 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2a47bdf..c4f6744 100644 --- a/README.md +++ b/README.md @@ -74,11 +74,11 @@ An exact match of the keyword is first attempted, otherwise partial matches are The argument ```[-i/--ids IDTYPE]``` accepts ```IDTYPE``` equal to ```arxiv```, ```hepdata``` or```inspire```. -The argument ```[-f/--file-format FORMAT]``` accepts ```FORMAT``` equal to ```csv```, ```root```, ```yaml```, ```yoda```, ```yoda1```, or ```json```. +The argument ```[-f/--file-format FORMAT]``` accepts ```FORMAT``` equal to ```csv```, ```root```, ```yaml```, ```yoda```, ```yoda1```, ```yoda.h5```, or ```json```. In the first four cases a .tar.gz archive is downloaded and unpacked as a directory, whereas in the last case a .json file is downloaded. The argument ```[-t/--table-name TABLE-NAME]``` accepts a string giving the table name as input. -In this case only the specified table is downloaded as a .csv, .root, .yaml, .yoda, .yoda1 or .json file. +In this case only the specified table is downloaded as a .csv, .root, .yaml, .yoda, .yoda1, .yoda.h5, or .json file. The argument ```[-d/--download-dir DOWNLOAD-DIR]``` specifies the directory to download the files. If not specified, the default download directory is ```./hepdata-downloads```. diff --git a/hepdata_cli/api.py b/hepdata_cli/api.py index e15da06..460600e 100644 --- a/hepdata_cli/api.py +++ b/hepdata_cli/api.py @@ -13,6 +13,7 @@ # SITE_URL = "http://127.0.0.1:5000" UPLOAD_MAX_SIZE = 52000000 # Upload limit in bytes +ALLOWED_FORMATS = ['csv', 'root', 'yaml', 'yoda', 'yoda1', 'yoda.h5', 'json'] MAX_MATCHES, MATCHES_PER_PAGE = (10000, 10) if "pytest" not in sys.modules else (144, 12) @@ -82,7 +83,7 @@ def download(self, id_list, file_format=None, ids=None, table_name='', download_ Downloads from the hepdata database the specified records. :param id_list: list of ids to download. These can be obtained by the find function. - :param file_format: accepts one of ('csv', 'root', 'yaml', 'yoda', 'yoda1', 'json'). Specifies the download file format. + :param file_format: accepts one of ('csv', 'root', 'yaml', 'yoda', 'yoda1', 'yoda.h5', 'json'). Specifies the download file format. :param ids: accepts one of ('inspire', 'hepdata'). It specifies what type of ids have been passed. :param table_name: restricts download to specific tables. :param download_dir: defaults to ./hepdata-downloads. Specifies where to download the files. @@ -139,7 +140,7 @@ def _build_urls(self, id_list, file_format, ids, table_name): if type(id_list) not in (tuple, list): id_list = id_list.split() assert len(id_list) > 0, 'Ids are required.' - assert file_format in ['csv', 'root', 'yaml', 'yoda', 'yoda1', 'json'], "allowed formats are: csv, root, yaml, yoda, yoda1 and json." + assert file_format in ALLOWED_FORMATS, f"allowed formats are: {ALLOWED_FORMATS}" assert ids in ['inspire', 'hepdata'], "allowed ids are: inspire and hepdata." if table_name == '': params = {'format': file_format} diff --git a/hepdata_cli/cli.py b/hepdata_cli/cli.py index 9a9a1ff..541a0ab 100644 --- a/hepdata_cli/cli.py +++ b/hepdata_cli/cli.py @@ -3,7 +3,7 @@ import click from .version import __version__ -from .api import Client +from .api import Client, ALLOWED_FORMATS @click.group() @@ -27,7 +27,7 @@ def find(client, query, keyword, ids): @cli.command() @click.argument('id_list', nargs=-1, required=True, type=str) -@click.option('-f', '--file-format', required=True, type=str, help='Specify file format (csv, root, yaml, yoda, yoda1, or json) to be downloaded.') +@click.option('-f', '--file-format', required=True, type=str, help=f'Specify file format (from {ALLOWED_FORMATS}) to be downloaded.') @click.option('-i', '--ids', required=True, type=str, help='Specify which ids (hepdata or inspire) are given.') @click.option('-t', '--table-name', default='', type=str, help='Specify table to be downloaded.') @click.option('-d', '--download-dir', default='./hepdata-downloads', type=str, help='Specify where to download the files.') diff --git a/tests/test_download.py b/tests/test_download.py index 9acd71d..6f835ad 100644 --- a/tests/test_download.py +++ b/tests/test_download.py @@ -38,6 +38,7 @@ def cleanup(directory): (["1222326", "1694381", "1462258", "1309874"], "csv", "inspire", ''), (["61434"], "yaml", "hepdata", "Table1"), (["1762350"], "yoda", "inspire", "Number density and Sum p_T pT>0.15 GeV/c"), + (["2862529"], "yoda.h5", "inspire", "95% CL upper limit on XSEC times BF"), ] From a276c3f7d2dd245c23279ab910a1aee626924d0f Mon Sep 17 00:00:00 2001 From: Graeme Watt Date: Fri, 22 Aug 2025 11:57:47 +0100 Subject: [PATCH 02/12] ci: remove Python 3.6 and add 3.12/3.13 * Also upgrade actions/checkout and actions/setup-python. --- .github/workflows/ci.yml | 20 ++++++++++---------- setup.py | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c37f33..f2d7502 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,15 +15,15 @@ jobs: strategy: matrix: runner: ['ubuntu-latest'] - python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11' ] + python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ] include: - - runner: 'ubuntu-20.04' - python-version: '3.6' + - runner: 'ubuntu-22.04' + python-version: '3.7' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install pip dependencies @@ -34,7 +34,7 @@ jobs: run: | pytest --cov=hepdata_cli - name: Run coveralls - if: startsWith(matrix.python-version, '3.11') + if: startsWith(matrix.python-version, '3.13') env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} COVERALLS_SERVICE_NAME: github @@ -51,11 +51,11 @@ jobs: permissions: id-token: write # IMPORTANT: this permission is mandatory for trusted publishing steps: - - uses: actions/checkout@v4 - - name: Set up Python 3.11 - uses: actions/setup-python@v4 + - uses: actions/checkout@v5 + - name: Set up Python 3.13 + uses: actions/setup-python@v5 with: - python-version: '3.11' + python-version: '3.13' - name: Build PyPI package run: | pip install wheel diff --git a/setup.py b/setup.py index 969ace9..f74d491 100644 --- a/setup.py +++ b/setup.py @@ -45,7 +45,7 @@ install_requires=install_requirements, tests_require=test_requirements, extras_require=extras_require, - python_requires='>=3.6', + python_requires='>=3.7', entry_points={ 'console_scripts': [ 'hepdata-cli = hepdata_cli.cli:cli', From d372f3cf647a0e64fdb3878536c04df2f99a0fd3 Mon Sep 17 00:00:00 2001 From: Graeme Watt Date: Fri, 22 Aug 2025 11:59:20 +0100 Subject: [PATCH 03/12] api: fix problem with % in table name * '%' encoded as '%2525' instead of '%25', so replace in URL. --- hepdata_cli/api.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hepdata_cli/api.py b/hepdata_cli/api.py index 460600e..9614d19 100644 --- a/hepdata_cli/api.py +++ b/hepdata_cli/api.py @@ -146,7 +146,9 @@ def _build_urls(self, id_list, file_format, ids, table_name): params = {'format': file_format} else: params = {'format': file_format, 'table': table_name} - urls = [resilient_requests('get', SITE_URL + '/record/' + ('ins' if ids == 'inspire' else '') + id_entry, params=params).url for id_entry in id_list] + urls = [resilient_requests('get', SITE_URL + '/record/' + ('ins' if ids == 'inspire' else '') + id_entry, params=params).url.replace('%2525', '%25') for id_entry in id_list] + print('params = ', params) + print('urls = ', urls) return urls def _query(self, query, page, size): From 1ce949cbb57ac04eee7d8e4d0946d196ce7b3117 Mon Sep 17 00:00:00 2001 From: Graeme Watt Date: Fri, 22 Aug 2025 12:06:19 +0100 Subject: [PATCH 04/12] README: remove Python 3.6, modify venv, correction * Remove explanation of Click problem with Python 3.6. * Install virtual environment in subdirectory 'venv'. * Correct typo: 'four' to 'six' when counting non-JSON file formats. --- README.md | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index c4f6744..6317015 100644 --- a/README.md +++ b/README.md @@ -23,15 +23,6 @@ $ pip install --user hepdata-cli $ hepdata-cli --help ``` -With Python 3 (<3.7), if the `LANG` environment variable is not set, you might get an error like: - -``` -RuntimeError: Click will abort further execution because Python 3 was configured to use ASCII as encoding for the environment. Consult https://click.palletsprojects.com/python3/ for mitigation steps. -``` - -In this case, you will need to export a Unicode locale as described in the -[Click documentation](https://click.palletsprojects.com/en/7.x/python3/#python-3-surrogate-handling). - ## Installation (for developers) Install from GitHub in a [virtual environment](https://docs.python.org/3/tutorial/venv.html): @@ -39,11 +30,11 @@ Install from GitHub in a [virtual environment](https://docs.python.org/3/tutoria ```code $ git clone https://github.com/HEPData/hepdata-cli.git $ cd hepdata-cli -$ python3 -m venv ~/venv/hepdata-cli -$ source ~/venv/hepdata-cli/bin/activate -(hepdata-cli) $ pip install -e '.[tests]' -(hepdata-cli) $ hepdata-cli --help -(hepdata-cli) $ pytest --cov=hepdata_cli +$ python3 -m venv venv +$ source venv/bin/activate +(venv) $ pip install -e '.[tests]' +(venv) $ hepdata-cli --help +(venv) $ pytest --cov=hepdata_cli ``` ## Usage @@ -75,7 +66,7 @@ An exact match of the keyword is first attempted, otherwise partial matches are The argument ```[-i/--ids IDTYPE]``` accepts ```IDTYPE``` equal to ```arxiv```, ```hepdata``` or```inspire```. The argument ```[-f/--file-format FORMAT]``` accepts ```FORMAT``` equal to ```csv```, ```root```, ```yaml```, ```yoda```, ```yoda1```, ```yoda.h5```, or ```json```. -In the first four cases a .tar.gz archive is downloaded and unpacked as a directory, whereas in the last case a .json file is downloaded. +In the first six cases a .tar.gz archive is downloaded and unpacked as a directory, whereas in the last case a .json file is downloaded. The argument ```[-t/--table-name TABLE-NAME]``` accepts a string giving the table name as input. In this case only the specified table is downloaded as a .csv, .root, .yaml, .yoda, .yoda1, .yoda.h5, or .json file. From b0a5b559d2d39f28f298dd8669ca345aed170590 Mon Sep 17 00:00:00 2001 From: Graeme Watt Date: Fri, 22 Aug 2025 12:08:24 +0100 Subject: [PATCH 05/12] tests: use separate download args for API and CLI * Necessary to avoid "429 Client Error: TOO MANY REQUESTS" error. --- tests/test_download.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/test_download.py b/tests/test_download.py index 6f835ad..1c2371f 100644 --- a/tests/test_download.py +++ b/tests/test_download.py @@ -33,18 +33,28 @@ def cleanup(directory): # arguments for testing -test_download_arguments = [ +test_api_download_arguments = [ (["73322"], "json", "hepdata", ''), (["1222326", "1694381", "1462258", "1309874"], "csv", "inspire", ''), (["61434"], "yaml", "hepdata", "Table1"), (["1762350"], "yoda", "inspire", "Number density and Sum p_T pT>0.15 GeV/c"), (["2862529"], "yoda.h5", "inspire", "95% CL upper limit on XSEC times BF"), + (["2862529"], "yoda.h5", "inspire", '') +] + +test_cli_download_arguments = [ + (["1462258"], "json", "inspire", ''), + (["1222326", "1694381", "1462258", "1309874"], "root", "inspire", ''), + (["61434"], "yaml", "hepdata", "Table2"), + (["1762350"], "yoda1", "inspire", "Number density and Sum p_T pT>0.15 GeV/c"), + (["2862529"], "yoda.h5", "inspire", "95% CL upper limit on BF"), + (["158153"], "yoda.h5", "hepdata", '') ] # api testing -@pytest.mark.parametrize("id_list, file_format, ids, table", test_download_arguments) +@pytest.mark.parametrize("id_list, file_format, ids, table", test_api_download_arguments) def test_api_download(id_list, file_format, ids, table): test_download_dir = './.pytest_downloads/' mkdir(test_download_dir) @@ -57,7 +67,7 @@ def test_api_download(id_list, file_format, ids, table): # cli testing -@pytest.mark.parametrize("id_list, file_format, ids, table", test_download_arguments) +@pytest.mark.parametrize("id_list, file_format, ids, table", test_cli_download_arguments) def test_cli_download(id_list, file_format, ids, table): test_download_dir = './.pytest_downloads/' mkdir(test_download_dir) From f4a778c3d1cacde62841c412cba620ddea9678c8 Mon Sep 17 00:00:00 2001 From: Graeme Watt Date: Fri, 22 Aug 2025 12:09:33 +0100 Subject: [PATCH 06/12] version: bump to 0.2.3 for new release --- hepdata_cli/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hepdata_cli/version.py b/hepdata_cli/version.py index b5fdc75..d31c31e 100644 --- a/hepdata_cli/version.py +++ b/hepdata_cli/version.py @@ -1 +1 @@ -__version__ = "0.2.2" +__version__ = "0.2.3" From 8f461dee5254cdd7c79147abf9ac517364052882 Mon Sep 17 00:00:00 2001 From: Graeme Watt Date: Fri, 22 Aug 2025 12:26:43 +0100 Subject: [PATCH 07/12] tests: split test_find_arguments between CLI/API * Try to avoid "too many 429 error responses". --- tests/test_search.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/test_search.py b/tests/test_search.py index 4094fbe..10d05fc 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -10,20 +10,22 @@ # arguments for testing -test_find_arguments = [ +test_api_find_arguments = [ ('reactions:"P P--> LQ LQ X"', None, None), - ('reactions:"P P --> gamma gamma"', None, None), ('reactions:"P P--> LQ LQ"', 'year', None), - ('reactions:"P P--> LQ LQ"', 'arxiv', None), ('reactions:"P P--> LQ LQ"', None, 'arxiv'), - ('reactions:"P P--> LQ LQ"', None, 'hepdata'), ('reactions:"P P"', None, 'hepdata'), ] +test_cli_find_arguments = [ + ('reactions:"P P --> gamma gamma"', None, None), + ('reactions:"P P--> LQ LQ"', 'arxiv', None), + ('reactions:"P P--> LQ LQ"', None, 'hepdata'), +] # api test -@pytest.mark.parametrize("query, keyword, ids", test_find_arguments) +@pytest.mark.parametrize("query, keyword, ids", test_api_find_arguments) def test_api_find(query, keyword, ids): client = Client(verbose=True) search_result = client.find(query, keyword, ids) @@ -37,7 +39,7 @@ def test_api_find(query, keyword, ids): # cli testing -@pytest.mark.parametrize("query, keyword, ids", test_find_arguments) +@pytest.mark.parametrize("query, keyword, ids", test_cli_find_arguments) def test_cli_find(query, keyword, ids): runner = CliRunner() result = runner.invoke(cli, ['find', query, '-kw', keyword, '-i', ids]) From 7597bc2b5d4686277f0ff34bea4ef07df77c35f6 Mon Sep 17 00:00:00 2001 From: Graeme Watt Date: Fri, 22 Aug 2025 12:39:51 +0100 Subject: [PATCH 08/12] tests: further changes to arguments for API/CLI --- tests/test_download.py | 4 ++-- tests/test_search.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_download.py b/tests/test_download.py index 1c2371f..d2efb44 100644 --- a/tests/test_download.py +++ b/tests/test_download.py @@ -43,12 +43,12 @@ def cleanup(directory): ] test_cli_download_arguments = [ - (["1462258"], "json", "inspire", ''), + (["2862529"], "json", "inspire", ''), (["1222326", "1694381", "1462258", "1309874"], "root", "inspire", ''), (["61434"], "yaml", "hepdata", "Table2"), (["1762350"], "yoda1", "inspire", "Number density and Sum p_T pT>0.15 GeV/c"), (["2862529"], "yoda.h5", "inspire", "95% CL upper limit on BF"), - (["158153"], "yoda.h5", "hepdata", '') + (["61434"], "yoda.h5", "hepdata", '') ] diff --git a/tests/test_search.py b/tests/test_search.py index 10d05fc..ebbd71f 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -13,14 +13,14 @@ test_api_find_arguments = [ ('reactions:"P P--> LQ LQ X"', None, None), ('reactions:"P P--> LQ LQ"', 'year', None), - ('reactions:"P P--> LQ LQ"', None, 'arxiv'), + ('phrases:(diffractive OR elastic)"', None, 'arxiv'), ('reactions:"P P"', None, 'hepdata'), ] test_cli_find_arguments = [ ('reactions:"P P --> gamma gamma"', None, None), - ('reactions:"P P--> LQ LQ"', 'arxiv', None), - ('reactions:"P P--> LQ LQ"', None, 'hepdata'), + ('abstract:"baryon production"', 'arxiv', None), + ('observables:ASYM', None, 'hepdata'), ] # api test From 9b550244a3df94754aa4dd1b0846755aa4d07de8 Mon Sep 17 00:00:00 2001 From: Graeme Watt Date: Fri, 22 Aug 2025 14:03:49 +0100 Subject: [PATCH 09/12] tests: simplify download and search arguments * Use fewer test cases to avoid 429 error responses, keeping coverage. --- tests/test_download.py | 3 --- tests/test_search.py | 9 ++++----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/test_download.py b/tests/test_download.py index d2efb44..28a727b 100644 --- a/tests/test_download.py +++ b/tests/test_download.py @@ -46,9 +46,6 @@ def cleanup(directory): (["2862529"], "json", "inspire", ''), (["1222326", "1694381", "1462258", "1309874"], "root", "inspire", ''), (["61434"], "yaml", "hepdata", "Table2"), - (["1762350"], "yoda1", "inspire", "Number density and Sum p_T pT>0.15 GeV/c"), - (["2862529"], "yoda.h5", "inspire", "95% CL upper limit on BF"), - (["61434"], "yoda.h5", "hepdata", '') ] diff --git a/tests/test_search.py b/tests/test_search.py index ebbd71f..6bbc0af 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -13,14 +13,13 @@ test_api_find_arguments = [ ('reactions:"P P--> LQ LQ X"', None, None), ('reactions:"P P--> LQ LQ"', 'year', None), - ('phrases:(diffractive OR elastic)"', None, 'arxiv'), - ('reactions:"P P"', None, 'hepdata'), + ('phrases:"(diffractive AND elastic)"', None, 'arxiv'), ] test_cli_find_arguments = [ - ('reactions:"P P --> gamma gamma"', None, None), - ('abstract:"baryon production"', 'arxiv', None), - ('observables:ASYM', None, 'hepdata'), + ('reactions:"P P --> gamma gamma"', 'arxiv', None), + ('abstract:"baryon production"', 'arxiv', 'hepdata'), + ('abstract:"charmed baryon production"', 'arxiv', 'arxiv'), ] # api test From bd4ba29e2527372788286a1d0f29262012244f1a Mon Sep 17 00:00:00 2001 From: Graeme Watt Date: Fri, 22 Aug 2025 14:08:35 +0100 Subject: [PATCH 10/12] ci: only run tests for Python 3.13 * Avoid 429 responses from running tests for multiple Python versions. * Check installation and "hepdata-cli --help" for all Python versions. --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f2d7502..98220cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,9 @@ jobs: run: | pip install --upgrade pip setuptools coveralls pip install -e '.[tests]' + hepdata-cli --help - name: Run tests + if: startsWith(matrix.python-version, '3.13') run: | pytest --cov=hepdata_cli - name: Run coveralls From b6717acc775c993490d07ff53a95e9341054d300 Mon Sep 17 00:00:00 2001 From: Graeme Watt Date: Fri, 22 Aug 2025 14:29:10 +0100 Subject: [PATCH 11/12] ci: use Python 3.12 for tests and release * Problem w/ Python 3.13 & Coveralls (TheKevJames/coveralls-python#549). --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 98220cd..c91fc5b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,11 +32,11 @@ jobs: pip install -e '.[tests]' hepdata-cli --help - name: Run tests - if: startsWith(matrix.python-version, '3.13') + if: startsWith(matrix.python-version, '3.12') run: | pytest --cov=hepdata_cli - name: Run coveralls - if: startsWith(matrix.python-version, '3.13') + if: startsWith(matrix.python-version, '3.12') env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} COVERALLS_SERVICE_NAME: github @@ -54,10 +54,10 @@ jobs: id-token: write # IMPORTANT: this permission is mandatory for trusted publishing steps: - uses: actions/checkout@v5 - - name: Set up Python 3.13 + - name: Set up Python 3.12 uses: actions/setup-python@v5 with: - python-version: '3.13' + python-version: '3.12' - name: Build PyPI package run: | pip install wheel From 81eca5ceb4e50be014a6aece6259949d0dacae38 Mon Sep 17 00:00:00 2001 From: Graeme Watt Date: Fri, 22 Aug 2025 15:01:52 +0100 Subject: [PATCH 12/12] api: remove debug print statements and add TODO * Comment to investigate double URL encoding (new issue #8). --- hepdata_cli/api.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hepdata_cli/api.py b/hepdata_cli/api.py index 9614d19..bf263c2 100644 --- a/hepdata_cli/api.py +++ b/hepdata_cli/api.py @@ -147,8 +147,7 @@ def _build_urls(self, id_list, file_format, ids, table_name): else: params = {'format': file_format, 'table': table_name} urls = [resilient_requests('get', SITE_URL + '/record/' + ('ins' if ids == 'inspire' else '') + id_entry, params=params).url.replace('%2525', '%25') for id_entry in id_list] - print('params = ', params) - print('urls = ', urls) + # TODO: Investigate root cause of double URL encoding (https://github.com/HEPData/hepdata-cli/issues/8). return urls def _query(self, query, page, size):