Repository navigation
feat: ワークスペース登録で arXiv ID からの自動補完に対応 #1947
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop_v2.1.0
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |
|
|
||
| """WEKO3 module docstring.""" | ||
|
|
||
| import re | ||
| import traceback | ||
| import requests | ||
| import urllib.parse | ||
|
|
@@ -425,6 +426,42 @@ def get_data(self): | |
| response['error'] = str(e) | ||
| return response | ||
|
|
||
|
|
||
| ARXIV_ID_PATTERN = re.compile( | ||
| r'^(?:arxiv:)?' | ||
| r'(\d{4}\.\d{4,5}' # new style: 2301.00001 | ||
| r'|[a-z][a-z-]*(?:\.[a-z]{2})?/\d{7})' # old style: hep-th/9901001 | ||
| r'(?:v\d+)?$', | ||
| re.IGNORECASE) | ||
| """arXiv identifier pattern (with optional "arXiv:" prefix and version).""" | ||
|
|
||
| ARXIV_PREFIX_PATTERN = re.compile( | ||
| r'^(?:https?://(?:www\.|export\.)?arxiv\.org/(?:abs|pdf)/' | ||
| r'|(?:https?://(?:dx\.)?doi\.org/)?10\.48550/arxiv\.)', | ||
| re.IGNORECASE) | ||
| """arXiv abstract/PDF URL or arXiv DOI (10.48550/arXiv.) prefix.""" | ||
|
|
||
|
|
||
| def extract_arxiv_id(value): | ||
| """Extract arXiv identifier from input value. | ||
|
|
||
| Accepts a bare arXiv ID (e.g. "2301.00001", "hep-th/9901001"), | ||
| "arXiv:" prefixed ID, arxiv.org abs/pdf URL and arXiv DOI | ||
| (10.48550/arXiv.xxxx). | ||
|
|
||
| :param value: input value. | ||
| :return: arXiv identifier, or None if value is not an arXiv ID. | ||
| """ | ||
| if not isinstance(value, str): | ||
| return None | ||
| value = ARXIV_PREFIX_PATTERN.sub('', value.strip().rstrip('/')) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Medium · Valid arXiv URLs fail autofill When a user pastes an arXiv abstract or PDF URL containing a query string or fragment, Remove the query string or fragment before validating the extracted arXiv identifier. Also at Prompt for AI agentsIn `modules/weko-workspace/weko_workspace/api.py` at line 457:
**Valid arXiv URLs fail autofill**
When a user pastes an arXiv abstract or PDF URL containing a query string or fragment, `extract_arxiv_id` removes the URL prefix but leaves the query string or fragment attached, so `ARXIV_ID_PATTERN` rejects the identifier and the lookup falls back to DOI search without finding arXiv metadata.
Remove the query string or fragment before validating the extracted arXiv identifier.
Also at `modules/weko-workspace/weko_workspace/api.py:438-442`. |
||
| if value.lower().endswith('.pdf'): | ||
| value = value[:-4] | ||
| if not ARXIV_ID_PATTERN.match(value): | ||
| return None | ||
| return re.sub(r'^arxiv:', '', value, flags=re.IGNORECASE) | ||
|
|
||
|
|
||
| class arXivURL: | ||
| """The Class retrieves the metadata from arXiv.""" | ||
|
|
||
|
|
@@ -443,6 +480,7 @@ def __init__(self, doi, timeout=None, http_proxy=None, https_proxy=None): | |
| """ | ||
| if not doi: | ||
| raise ValueError('DOI is required.') | ||
| self._arxiv_id = extract_arxiv_id(doi) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Medium · Cached lookups return wrong metadata When two ID/item-type combinations whose concatenated values are identical are requested within the cache timeout, Build the cache key from an unambiguous representation of both the ID and item-type ID. Prompt for AI agentsIn `modules/weko-workspace/weko_workspace/api.py` at line 483:
**Cached lookups return wrong metadata**
When two ID/item-type combinations whose concatenated values are identical are requested within the cache timeout, `cached_api_json` builds its cache key by concatenating the ID and item-type ID without a separator, so `get_arXiv_record_data` can return the first lookup's cached record for the other combination and the caller receives incorrect metadata.
Build the cache key from an unambiguous representation of both the ID and item-type ID.There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ⚪ Low · arXiv IDs remain documented as DOIs
Update the constructor and Prompt for AI agentsIn `modules/weko-workspace/weko_workspace/api.py` at line 483:
**arXiv IDs remain documented as DOIs**
`arXivURL` now accepts arXiv IDs as well as DOIs, but its constructor documentation still describes only a DOI parameter. Callers relying on that contract can overlook the newly supported input forms.
Update the constructor and `get_arXiv_record_data` docstrings to state that they accept either a DOI or an arXiv identifier/URL. |
||
| self._doi = "/".join(doi.strip().strip("/").split("/")[-2:]) | ||
| if timeout: | ||
| self._timeout = timeout | ||
|
|
@@ -456,6 +494,8 @@ def _create_endpoint(self): | |
|
|
||
| :return: endpoint string. | ||
| """ | ||
| if self._arxiv_id: | ||
| return self._arxiv_id | ||
| endpoint_url = self._doi | ||
| return endpoint_url | ||
|
|
||
|
|
@@ -467,6 +507,8 @@ def _create_url(self): | |
| """ | ||
| endpoint = self._create_endpoint() | ||
|
|
||
| if self._arxiv_id: | ||
| return config.WEKO_WORKSPACE_ARXIV_ID_API_URL + endpoint | ||
| url = config.WEKO_WORKSPACE_ARXIV_API_URL + endpoint | ||
| return url | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2395,6 +2395,15 @@ def get_arXiv_record_data(doi, item_type_id, exclude_duplicate_lang=True): | |
| if api_response["error"] \ | ||
| or not isinstance(api_response['response'], dict): | ||
| return result | ||
| # No hit returns a feed without entry. Invalid ID returns an error entry. | ||
| feed = api_response['response'].get('feed') or {} | ||
| entry = feed.get('entry') if isinstance(feed, dict) else None | ||
| if isinstance(entry, list): | ||
| entry = entry[0] if entry else None | ||
| feed['entry'] = entry | ||
| if not isinstance(entry, dict) \ | ||
| or '/api/errors' in str(entry.get('id', '')): | ||
| return result | ||
|
Comment on lines
+2404
to
+2406
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Medium · API outage appears as no match When the arXiv service responds with a non-200 status, Log non-200 responses and set an error value so the view can distinguish service failures from genuine no-match results. Prompt for AI agentsIn `modules/weko-workspace/weko_workspace/utils.py` at lines 2404-2406:
**API outage appears as no match**
When the arXiv service responds with a non-200 status, `arXivURL.get_data` leaves `response` empty and `error` blank for non-200 statuses, so this guard returns `[]`; the view then reports an ordinary no-result response instead of surfacing the service failure.
Log non-200 responses and set an error value so the view can distinguish service failures from genuine no-match results. |
||
| api_data = get_arXiv_data_by_key(api_response, 'all') | ||
| items = ItemTypes.get_by_id(item_type_id) | ||
| if items is None: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚪ Low · Added tests fail Black formatting
When the module's
black .formatting check runs, black reformats these newly added long patch and fixture lines, so the module's formatting check reports findings instead of passing.Reformat the added test expressions with Black.
Also at
modules/weko-workspace/tests/test_utils.py:3697.Prompt for AI agents
From
AGENTS.mdL70-73: