diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 568815e..a7cf0d6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,8 +2,9 @@ repos: - repo: meta hooks: - id: check-hooks-apply + - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0 hooks: - id: check-ast - id: check-xml @@ -12,12 +13,15 @@ repos: exclude: \.html$|\.txt$ - id: trailing-whitespace - id: debug-statements - - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.9.1 + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: aca6d4c8045a504e2812ea4bedff1d0a09e437bc # frozen: v0.15.8 hooks: - - id: ruff + - id: ruff-check args: [--fix, --exit-non-zero-on-fix] + - id: ruff-format + - repo: https://github.com/crate-ci/typos - rev: v1.29.4 + rev: 5745f2a8dd91cd7b684680e2e10a2b388ba6e5cf # frozen: v1 hooks: - id: typos diff --git a/README.md b/README.md index ce861ea..00ecd85 100644 --- a/README.md +++ b/README.md @@ -49,3 +49,9 @@ ROR_PROVIDER_HEADERS = { 'User-Agent': 'rdmo.example.com/1.0 (mail@rdmo.example.com) rdmo-plugins-ror/1.0' } ``` + +By default, the plugin stores the name of the institution and the link to the ROR page as `text` in RDMO (the ROR itself is stored as `external_id`). The name of the institution can be omitted by setting: + +```python +ROR_STORE_NAME = False +``` diff --git a/pyproject.toml b/pyproject.toml index e68e393..297599d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,31 +1,33 @@ [build-system] -requires = ["setuptools", "setuptools-scm"] -build-backend = "setuptools.build_meta" +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" [project] name = "rdmo-plugins-ror" authors = [ - {name = "RDMO Arbeitsgemeinschaft", email = "rdmo-team@listserv.dfn.de"}, + {name = "RDMO Community and individual contributors", email = "contact@rdmo.org"}, ] maintainers = [ {name = "Jochen Klar", email = "mail@jochenklar.de"}, ] description = "Plugin for RDMO to query the ROR API" readme = "README.md" -requires-python = ">=3.9" -license = {file = "LICENSE"} +requires-python = ">=3.10" +license = "Apache-2.0" +license-files = ["LICENSE", "NOTICE", "AUTHORS"] classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', - 'Framework :: Django :: 2.2', + 'Operating System :: OS Independent', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: Apache Software License', - 'Operating System :: OS Independent', "Programming Language :: Python :: 3 :: Only", 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', + 'Programming Language :: Python :: 3.14', ] dependencies = [ "requests>=2.31" @@ -43,15 +45,19 @@ dev = [ "twine", ] -[tool.setuptools] -packages = ["rdmo_ror"] +[tool.hatch.version] +source = "vcs" -[tool.setuptools.dynamic] -version = {attr = "rdmo_ror.__version__"} +[tool.hatch.build.targets.wheel] +packages = ["rdmo_ror"] [tool.ruff] -target-version = "py38" line-length = 120 + +[tool.ruff.format] +quote-style = "single" + +[tool.ruff.lint] select = [ "B", # flake8-bugbear "C4", # flake8-comprehensions @@ -71,7 +77,7 @@ ignore = [ "RUF012", # mutable-class-default ] -[tool.ruff.isort] +[tool.ruff.lint.isort] section-order = [ "future", "standard-library", @@ -84,7 +90,7 @@ section-order = [ "local-folder" ] -[tool.ruff.isort.sections] +[tool.ruff.lint.isort.sections] pytest = ["pytest"] django = ["django"] rest_framework = ["rest_framework"] diff --git a/rdmo_ror/__init__.py b/rdmo_ror/__init__.py index 0b0dd21..d6ebe0f 100644 --- a/rdmo_ror/__init__.py +++ b/rdmo_ror/__init__.py @@ -1 +1,7 @@ -VERSION = __version__ = '1.0.0' +from importlib.metadata import PackageNotFoundError +from importlib.metadata import version as _version + +try: + VERSION = __version__ = _version(__package__) +except PackageNotFoundError: + VERSION = __version__ = '0.0.0+unknown' diff --git a/rdmo_ror/handlers.py b/rdmo_ror/handlers.py index 6267375..f8cc83b 100644 --- a/rdmo_ror/handlers.py +++ b/rdmo_ror/handlers.py @@ -41,15 +41,18 @@ def ror_handler(signal, sender, instance=None, **kwargs): except (requests.exceptions.RequestException, requests.exceptions.HTTPError): return - acronym = next(iter([ + acronym_list = [ name['value'] for name in data.get('names', []) if 'acronym' in name['types'] - ]), None) - - name = next(iter([ + ] # fmt: skip + label_list = [ name['value'] for name in data.get('names', []) if 'label' in name['types'] and name['lang'] == lang - ]), None) or next(iter([ + ] # fmt: skip + ror_display_list = [ name['value'] for name in data.get('names', []) if 'ror_display' in name['types'] - ]), None) + ] # fmt: skip + + acronym = next(iter(acronym_list), None) + name = next(iter(label_list), None) or next(iter(ror_display_list), None) if acronym and 'acronym' in attribute_map: Value.objects.update_or_create( @@ -59,8 +62,8 @@ def ror_handler(signal, sender, instance=None, **kwargs): set_prefix=instance.set_prefix, set_index=instance.set_index, defaults={ - 'text': acronym - } + 'text': acronym, + }, ) if name and 'name' in attribute_map: @@ -71,6 +74,6 @@ def ror_handler(signal, sender, instance=None, **kwargs): set_prefix=instance.set_prefix, set_index=instance.set_index, defaults={ - 'text': name - } + 'text': name, + }, ) diff --git a/rdmo_ror/providers.py b/rdmo_ror/providers.py index 14754f3..0f80b1f 100644 --- a/rdmo_ror/providers.py +++ b/rdmo_ror/providers.py @@ -10,7 +10,6 @@ class RorProvider(Provider): - search = True refresh = True @@ -19,9 +18,13 @@ def get_options(self, project, search=None, user=None, site=None): url = getattr(settings, 'ROR_PROVIDER_URL', 'https://api.ror.org/v2/').rstrip('/') headers = getattr(settings, 'ROR_PROVIDER_HEADERS', {}) - response = requests.get(url + '/organizations', params={ - 'query': self.get_search(search) - }, headers=headers) + response = requests.get( + url + '/organizations', + params={ + 'query': self.get_search(search), + }, + headers=headers, + ) try: data = response.json() @@ -32,8 +35,10 @@ def get_options(self, project, search=None, user=None, site=None): return [ { 'id': self.get_id(item), - 'text': self.get_text(item) - } for item in data['items'] + 'text': self.get_text(item), + 'help': self.get_help(item), + } + for item in data['items'] ] # return an empty list by default @@ -44,7 +49,7 @@ def get_id(self, item): def get_text(self, item): ror_id = item['id'] - ror_name = self.get_name(item) + ror_name = self.get_name(item) if getattr(settings, 'ROR_STORE_NAME', True) else '' ror_img = static('ror/img/ROR.png') ror_link = f'ROR logo {ror_id}' return f'{ror_name} {ror_link}' if ror_name else ror_link @@ -52,11 +57,17 @@ def get_text(self, item): def get_name(self, item): lang = get_language() - return next(iter([ + label_list = [ name['value'] for name in item.get('names', []) if 'label' in name['types'] and name['lang'] == lang - ]), None) or next(iter([ + ] # fmt: skip + ror_display_list = [ name['value'] for name in item.get('names', []) if 'ror_display' in name['types'] - ]), None) + ] # fmt: skip + + return next(iter(label_list), None) or next(iter(ror_display_list), None) + + def get_help(self, item): + return '' if getattr(settings, 'ROR_STORE_NAME', True) else f'[{self.get_name(item)}]' def get_search(self, search): # reverse get_text to perform the search, remove everything after [