Page Menu
Home
Software Heritage
Search
Configure Global Search
Log In
Files
F8394556
D4431.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
18 KB
Subscribers
None
D4431.diff
View Options
diff --git a/swh/deposit/cli/client.py b/swh/deposit/cli/client.py
--- a/swh/deposit/cli/client.py
+++ b/swh/deposit/cli/client.py
@@ -12,7 +12,7 @@
# control
import os
import sys
-from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
+from typing import TYPE_CHECKING, Any, Collection, Dict, List, Optional
import click
@@ -111,22 +111,6 @@
return xmltodict.unparse(codemetadata, pretty=True)
-def _client(url: str, username: str, password: str) -> PublicApiDepositClient:
- """Instantiate a client to access the deposit api server
-
- Args:
- url (str): Deposit api server
- username (str): User
- password (str): User's password
-
- """
- from swh.deposit.client import PublicApiDepositClient
-
- return PublicApiDepositClient(
- {"url": url, "auth": {"username": username, "password": password},}
- )
-
-
def _collection(client: PublicApiDepositClient) -> str:
"""Retrieve the client's collection
@@ -140,13 +124,13 @@
def client_command_parse_input(
+ client,
username: str,
- password: str,
archive: Optional[str],
metadata: Optional[str],
+ collection: Optional[str],
archive_deposit: bool,
metadata_deposit: bool,
- collection: Optional[str],
slug: Optional[str],
partial: bool,
deposit_id: Optional[int],
@@ -189,9 +173,8 @@
'archive': the software archive to deposit
'username': username
- 'password': associated password
'metadata': the metadata file to deposit
- 'collection': the username's associated client
+ 'collection: the user's collection under which to put the deposit
'slug': the slug or external id identifying the deposit to make
'partial': if the deposit is partial or not
'client': instantiated class
@@ -265,20 +248,16 @@
if replace and not deposit_id:
raise InputError("To update an existing deposit, you must provide its id")
- client = _client(url, username, password)
-
if not collection:
collection = _collection(client)
return {
"archive": archive,
"username": username,
- "password": password,
"metadata": metadata,
"collection": collection,
"slug": slug,
"in_progress": partial,
- "client": client,
"url": url,
"deposit_id": deposit_id,
"swhid": swhid,
@@ -286,42 +265,11 @@
}
-def _subdict(d: Dict[str, Any], keys: Tuple[str, ...]) -> Dict[str, Any]:
+def _subdict(d: Dict[str, Any], keys: Collection[str]) -> Dict[str, Any]:
"return a dict from d with only given keys"
return {k: v for k, v in d.items() if k in keys}
-def deposit_create(config: Dict[str, Any]) -> Dict[str, Any]:
- """Delegate the actual deposit to the deposit client.
-
- """
- logger.debug("Create deposit")
-
- client = config["client"]
- keys = ("collection", "archive", "metadata", "slug", "in_progress")
- return client.deposit_create(**_subdict(config, keys))
-
-
-def deposit_update(config: Dict[str, Any]) -> Dict[str, Any]:
- """Delegate the actual deposit to the deposit client.
-
- """
- logger.debug("Update deposit")
-
- client = config["client"]
- keys = (
- "collection",
- "deposit_id",
- "archive",
- "metadata",
- "slug",
- "in_progress",
- "replace",
- "swhid",
- )
- return client.deposit_update(**_subdict(config, keys))
-
-
@deposit.command()
@click.option("--username", required=True, help="(Mandatory) User's name")
@click.option(
@@ -439,22 +387,22 @@
"""
import tempfile
- from swh.deposit.client import MaintenanceError
+ from swh.deposit.client import MaintenanceError, PublicApiDepositClient
url = _url(url)
- config = {}
+ client = PublicApiDepositClient(url=url, auth=(username, password))
with tempfile.TemporaryDirectory() as temp_dir:
try:
logger.debug("Parsing cli options")
config = client_command_parse_input(
+ client,
username,
- password,
archive,
metadata,
+ collection,
archive_deposit,
metadata_deposit,
- collection,
slug,
partial,
deposit_id,
@@ -475,12 +423,13 @@
if verbose:
logger.info("Parsed configuration: %s", config)
- deposit_id = config["deposit_id"]
-
- if deposit_id:
- data = deposit_update(config)
+ keys = ["archive", "collection", "in_progress", "metadata", "slug"]
+ if config["deposit_id"]:
+ keys += ["deposit_id", "replace", "swhid"]
+ data = client.deposit_update(**_subdict(config, keys))
else:
- data = deposit_create(config)
+ data = client.deposit_create(**_subdict(config, keys))
+
print_result(data, output_format)
@@ -509,12 +458,12 @@
"""Deposit's status
"""
- from swh.deposit.client import MaintenanceError
+ from swh.deposit.client import MaintenanceError, PublicApiDepositClient
url = _url(url)
logger.debug("Status deposit")
try:
- client = _client(url, username, password)
+ client = PublicApiDepositClient(url=url, auth=(username, password))
collection = _collection(client)
except InputError as e:
logger.error("Problem during parsing options: %s", e)
diff --git a/swh/deposit/client.py b/swh/deposit/client.py
--- a/swh/deposit/client.py
+++ b/swh/deposit/client.py
@@ -11,8 +11,9 @@
import hashlib
import logging
import os
-from typing import Any, Dict, Optional
+from typing import Any, Dict, Optional, Tuple
from urllib.parse import urljoin
+import warnings
import requests
import xmltodict
@@ -131,20 +132,43 @@
return m
+def handle_deprecated_config(config: Dict) -> Tuple[str, Optional[Tuple[str, str]]]:
+ warnings.warn(
+ '"config" argument is deprecated, please '
+ 'use "url" and "auth" arguments instead; note that "auth" '
+ "expects now a couple (username, password) and not a dict.",
+ DeprecationWarning,
+ )
+ url: str = config["url"]
+ auth: Optional[Tuple[str, str]] = None
+
+ if config.get("auth"):
+ auth = (config["auth"]["username"], config["auth"]["password"])
+
+ return (url, auth)
+
+
class BaseApiDepositClient:
"""Deposit client base class
"""
- def __init__(self, config=None, _client=requests):
- self.config: Dict[str, Any] = config or load_from_envvar()
- self._client = _client
- self.base_url = self.config["url"].strip("/") + "/"
- auth = self.config["auth"]
- if auth == {}:
- self.auth = None
- else:
- self.auth = (auth["username"], auth["password"])
+ def __init__(
+ self,
+ config: Optional[Dict] = None,
+ url: Optional[str] = None,
+ auth: Optional[Tuple[str, str]] = None,
+ ):
+ if not url and not config:
+ config = load_from_envvar()
+ if config:
+ url, auth = handle_deprecated_config(config)
+
+ # needed to help mypy not be fooled by the Optional nature of url
+ assert url is not None
+
+ self.base_url = url.strip("/") + "/"
+ self.auth = auth
def do(self, method, url, *args, **kwargs):
"""Internal method to deal with requests, possibly with basic http
@@ -157,10 +181,7 @@
The request's execution
"""
- if hasattr(self._client, method):
- method_fn = getattr(self._client, method)
- else:
- raise ValueError("Development error, unsupported method %s" % (method))
+ method_fn = getattr(requests, method)
if self.auth:
kwargs["auth"] = self.auth
@@ -278,8 +299,10 @@
"""
- def __init__(self, config, error_msg=None, empty_result={}):
- super().__init__(config)
+ def __init__(
+ self, config=None, url=None, auth=None, error_msg=None, empty_result={}
+ ):
+ super().__init__(url=url, auth=auth, config=config)
self.error_msg = error_msg
self.empty_result = empty_result
@@ -382,9 +405,11 @@
"""
- def __init__(self, config):
+ def __init__(self, config=None, url=None, auth=None):
super().__init__(
- config,
+ url=url,
+ auth=auth,
+ config=config,
error_msg="Service document failure at %s: %s",
empty_result={"collection": None},
)
@@ -407,9 +432,11 @@
"""
- def __init__(self, config):
+ def __init__(self, config=None, url=None, auth=None):
super().__init__(
- config,
+ url=url,
+ auth=auth,
+ config=config,
error_msg="Status check failure at %s: %s",
empty_result={
"deposit_status": None,
@@ -446,9 +473,11 @@
"""
- def __init__(self, config):
+ def __init__(self, config=None, url=None, auth=None):
super().__init__(
- config,
+ url=url,
+ auth=auth,
+ config=config,
error_msg="Post Deposit failure at %s: %s",
empty_result={"deposit_id": None, "deposit_status": None,},
)
@@ -606,11 +635,13 @@
def service_document(self):
"""Retrieve service document endpoint's information."""
- return ServiceDocumentDepositClient(self.config).execute()
+ return ServiceDocumentDepositClient(url=self.base_url, auth=self.auth).execute()
def deposit_status(self, collection: str, deposit_id: int):
"""Retrieve status information on a deposit."""
- return StatusDepositClient(self.config).execute(collection, deposit_id)
+ return StatusDepositClient(url=self.base_url, auth=self.auth).execute(
+ collection, deposit_id
+ )
def deposit_create(
self,
@@ -622,15 +653,17 @@
):
"""Create a new deposit (archive, metadata, both as multipart)."""
if archive and not metadata:
- return CreateArchiveDepositClient(self.config).execute(
- collection, in_progress, slug, archive_path=archive
- )
+ return CreateArchiveDepositClient(
+ url=self.base_url, auth=self.auth
+ ).execute(collection, in_progress, slug, archive_path=archive)
elif not archive and metadata:
- return CreateMetadataDepositClient(self.config).execute(
- collection, in_progress, slug, metadata_path=metadata
- )
+ return CreateMetadataDepositClient(
+ url=self.base_url, auth=self.auth
+ ).execute(collection, in_progress, slug, metadata_path=metadata)
else:
- return CreateMultipartDepositClient(self.config).execute(
+ return CreateMultipartDepositClient(
+ url=self.base_url, auth=self.auth
+ ).execute(
collection,
in_progress,
slug,
@@ -670,7 +703,7 @@
"deposit_id": deposit_id,
}
if archive and not metadata:
- r = UpdateArchiveDepositClient(self.config).execute(
+ r = UpdateArchiveDepositClient(url=self.base_url, auth=self.auth).execute(
collection,
in_progress,
slug,
@@ -679,7 +712,9 @@
replace=replace,
)
elif not archive and metadata and swhid is None:
- r = UpdateMetadataOnPartialDepositClient(self.config).execute(
+ r = UpdateMetadataOnPartialDepositClient(
+ url=self.base_url, auth=self.auth
+ ).execute(
collection,
in_progress,
slug,
@@ -688,7 +723,9 @@
replace=replace,
)
elif not archive and metadata and swhid is not None:
- r = UpdateMetadataOnDoneDepositClient(self.config).execute(
+ r = UpdateMetadataOnDoneDepositClient(
+ url=self.base_url, auth=self.auth
+ ).execute(
collection,
in_progress,
slug,
@@ -697,7 +734,7 @@
swhid=swhid,
)
else:
- r = UpdateMultipartDepositClient(self.config).execute(
+ r = UpdateMultipartDepositClient(url=self.base_url, auth=self.auth).execute(
collection,
in_progress,
slug,
diff --git a/swh/deposit/tests/cli/test_client.py b/swh/deposit/tests/cli/test_client.py
--- a/swh/deposit/tests/cli/test_client.py
+++ b/swh/deposit/tests/cli/test_client.py
@@ -18,7 +18,6 @@
from swh.deposit.cli import deposit as cli
from swh.deposit.cli.client import (
InputError,
- _client,
_collection,
_url,
generate_metadata,
@@ -30,14 +29,6 @@
from ..conftest import TEST_USER
-@pytest.fixture
-def deposit_config():
- return {
- "url": "https://deposit.swh.test/1",
- "auth": {"username": "test", "password": "test",},
- }
-
-
@pytest.fixture
def datadir(request):
"""Override default datadir to target main test datadir"""
@@ -64,7 +55,7 @@
"""
mock_client = MagicMock()
- mocker.patch("swh.deposit.cli.client._client", return_value=mock_client)
+ mocker.patch("swh.deposit.client.PublicApiDepositClient", return_value=mock_client)
mock_client.service_document.side_effect = MaintenanceError(
"Database backend maintenance: Temporarily unavailable, try again later."
)
@@ -76,11 +67,6 @@
assert _url("https://other/1") == "https://other/1"
-def test_cli_client():
- client = _client("http://deposit", "user", "pass")
- assert isinstance(client, PublicApiDepositClient)
-
-
def test_cli_collection_error():
mock_client = MagicMock()
mock_client.service_document.return_value = {"error": "something went wrong"}
@@ -91,8 +77,10 @@
assert "Service document retrieval: something went wrong" == str(e.value)
-def test_cli_collection_ok(deposit_config, requests_mock_datadir):
- client = PublicApiDepositClient(deposit_config)
+def test_cli_collection_ok(requests_mock_datadir):
+ client = PublicApiDepositClient(
+ url="https://deposit.swh.test/1", auth=("test", "test")
+ )
collection_name = _collection(client)
assert collection_name == "test"
diff --git a/swh/deposit/tests/loader/test_client.py b/swh/deposit/tests/loader/test_client.py
--- a/swh/deposit/tests/loader/test_client.py
+++ b/swh/deposit/tests/loader/test_client.py
@@ -6,7 +6,6 @@
import json
import os
from typing import Any, Callable, Optional
-import unittest
from urllib.parse import urlparse
import pytest
@@ -14,7 +13,6 @@
from swh.deposit.client import PrivateApiDepositClient
from swh.deposit.config import DEPOSIT_STATUS_LOAD_FAILURE, DEPOSIT_STATUS_LOAD_SUCCESS
-
CLIENT_TEST_CONFIG = {
"url": "https://nowhere.org/",
"auth": {}, # no authentication in test scenario
@@ -28,12 +26,13 @@
def test_client_config(deposit_config_path):
for client in [
- # config passed as constructor parameter
- PrivateApiDepositClient(config=CLIENT_TEST_CONFIG),
- # config loaded from environment
- PrivateApiDepositClient()
+ # config passed as constructor parameter
+ PrivateApiDepositClient(config=CLIENT_TEST_CONFIG),
+ # config loaded from environment
+ PrivateApiDepositClient(),
]:
- assert client.config == CLIENT_TEST_CONFIG
+ assert client.base_url == CLIENT_TEST_CONFIG["url"]
+ assert client.auth is None
def build_expected_path(datadir, base_url: str, api_url: str) -> str:
@@ -205,58 +204,36 @@
# private api update status
-class FakeRequestClientPut:
- """Fake Request client dedicated to put request method calls.
+def test_status_update(mocker):
+ """Update status
+
+ """
+ mocked_put = mocker.patch("swh.deposit.client.requests.put")
+
+ deposit_client = PrivateApiDepositClient(config=CLIENT_TEST_CONFIG)
+ deposit_client.status_update(
+ "/update/status", DEPOSIT_STATUS_LOAD_SUCCESS, revision_id="some-revision-id",
+ )
+
+ mocked_put.assert_called_once_with(
+ "https://nowhere.org/update/status",
+ json={
+ "status": DEPOSIT_STATUS_LOAD_SUCCESS,
+ "revision_id": "some-revision-id",
+ },
+ )
+
+
+def test_status_update_with_no_revision_id(mocker):
+ """Reading metadata can fail for some reasons
"""
+ mocked_put = mocker.patch("swh.deposit.client.requests.put")
+
+ deposit_client = PrivateApiDepositClient(config=CLIENT_TEST_CONFIG)
+ deposit_client.status_update("/update/status/fail", DEPOSIT_STATUS_LOAD_FAILURE)
- args = None
- kwargs = None
-
- def put(self, *args, **kwargs):
- self.args = args
- self.kwargs = kwargs
-
-
-class PrivateApiDepositClientStatusUpdateTest(unittest.TestCase):
- def test_status_update(self):
- """Update status
-
- """
- _client = FakeRequestClientPut()
- deposit_client = PrivateApiDepositClient(
- config=CLIENT_TEST_CONFIG, _client=_client
- )
-
- deposit_client.status_update(
- "/update/status",
- DEPOSIT_STATUS_LOAD_SUCCESS,
- revision_id="some-revision-id",
- )
-
- self.assertEqual(_client.args, ("https://nowhere.org/update/status",))
- self.assertEqual(
- _client.kwargs,
- {
- "json": {
- "status": DEPOSIT_STATUS_LOAD_SUCCESS,
- "revision_id": "some-revision-id",
- }
- },
- )
-
- def test_status_update_with_no_revision_id(self):
- """Reading metadata can fail for some reasons
-
- """
- _client = FakeRequestClientPut()
- deposit_client = PrivateApiDepositClient(
- config=CLIENT_TEST_CONFIG, _client=_client
- )
-
- deposit_client.status_update("/update/status/fail", DEPOSIT_STATUS_LOAD_FAILURE)
-
- self.assertEqual(_client.args, ("https://nowhere.org/update/status/fail",))
- self.assertEqual(
- _client.kwargs, {"json": {"status": DEPOSIT_STATUS_LOAD_FAILURE,}}
- )
+ mocked_put.assert_called_once_with(
+ "https://nowhere.org/update/status/fail",
+ json={"status": DEPOSIT_STATUS_LOAD_FAILURE,},
+ )
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Jun 3, 7:26 PM (1 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3229514
Attached To
D4431: Refactor BaseApiDepositClient to get rid of the _client argument
Event Timeline
Log In to Comment