Skip to content

Commit 83db393

Browse files
committed
Replace 'rauth' with 'requests-oauthlib' for OAuth1 support and refactor related code for improved readability
1 parent 679509a commit 83db393

File tree

6 files changed

+109
-63
lines changed

6 files changed

+109
-63
lines changed

microSALT/utils/pubmlst/authentication.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from datetime import datetime, timedelta
55

66
from dateutil import parser
7-
from rauth import OAuth1Session
7+
from requests_oauthlib import OAuth1Session
88

99
from microSALT.config import Folders, PubMLSTCredentials, PasteurCredentials
1010
from microSALT.utils.pubmlst.constants import CREDENTIALS_KEY
@@ -27,7 +27,13 @@
2727

2828

2929
class ClientAuthentication:
30-
def __init__(self, service: str, folders: Folders, pubmlst: PubMLSTCredentials, pasteur: PasteurCredentials):
30+
def __init__(
31+
self,
32+
service: str,
33+
folders: Folders,
34+
pubmlst: PubMLSTCredentials,
35+
pasteur: PasteurCredentials,
36+
):
3137
"""Initialize the client with the specified service."""
3238
self.service: str = service
3339
self.folders = folders
@@ -53,10 +59,10 @@ def get_new_session_token(self, db: str):
5359
logger.debug(f"Requesting session token from URL: {url}")
5460

5561
session = OAuth1Session(
56-
consumer_key=consumer_key,
57-
consumer_secret=consumer_secret,
58-
access_token=access_token,
59-
access_token_secret=access_secret,
62+
client_key=consumer_key,
63+
client_secret=consumer_secret,
64+
resource_owner_key=access_token,
65+
resource_owner_secret=access_secret,
6066
)
6167

6268
response = session.get(url, headers={"User-Agent": "BIGSdb API downloader"})

microSALT/utils/pubmlst/client.py

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import logging
33
import requests
44
from werkzeug.exceptions import NotFound
5-
from rauth import OAuth1Session
5+
from requests_oauthlib import OAuth1Session
66

77
from microSALT.config import Folders, PubMLSTCredentials, PasteurCredentials
88
from microSALT.utils.pubmlst.authentication import ClientAuthentication
@@ -27,7 +27,14 @@
2727
class BaseClient:
2828
"""Base client for interacting with authenticated APIs."""
2929

30-
def __init__(self, service: str, database: str = None, folders: Folders = None, pubmlst: PubMLSTCredentials = None, pasteur: PasteurCredentials = None):
30+
def __init__(
31+
self,
32+
service: str,
33+
database: str = None,
34+
folders: Folders = None,
35+
pubmlst: PubMLSTCredentials = None,
36+
pasteur: PasteurCredentials = None,
37+
):
3138
"""Initialize the client with the specified service."""
3239
try:
3340
self.service = service
@@ -101,10 +108,10 @@ def _make_request(
101108

102109
# Create session with OAuth1
103110
session = OAuth1Session(
104-
self.consumer_key,
105-
self.consumer_secret,
106-
access_token=token,
107-
access_token_secret=secret,
111+
client_key=self.consumer_key,
112+
client_secret=self.consumer_secret,
113+
resource_owner_key=token,
114+
resource_owner_secret=secret,
108115
)
109116

110117
response = session.request(method.value, url)
@@ -204,20 +211,39 @@ def list_schemes(self, db: str):
204211
class PubMLSTClient(BaseClient):
205212
"""Client for interacting with the PubMLST authenticated API."""
206213

207-
def __init__(self, folders: Folders = None, pubmlst: PubMLSTCredentials = None, pasteur: PasteurCredentials = None):
214+
def __init__(
215+
self,
216+
folders: Folders = None,
217+
pubmlst: PubMLSTCredentials = None,
218+
pasteur: PasteurCredentials = None,
219+
):
208220
"""Initialize the PubMLST client."""
209221
super().__init__(service="pubmlst", folders=folders, pubmlst=pubmlst, pasteur=pasteur)
210222

211223

212224
class PasteurClient(BaseClient):
213225
"""Client for interacting with the Pasteur authenticated API."""
214226

215-
def __init__(self, database: str, folders: Folders = None, pubmlst: PubMLSTCredentials = None, pasteur: PasteurCredentials = None):
227+
def __init__(
228+
self,
229+
database: str,
230+
folders: Folders = None,
231+
pubmlst: PubMLSTCredentials = None,
232+
pasteur: PasteurCredentials = None,
233+
):
216234
"""Initialize the Pasteur client."""
217-
super().__init__(service="pasteur", database=database, folders=folders, pubmlst=pubmlst, pasteur=pasteur)
235+
super().__init__(
236+
service="pasteur", database=database, folders=folders, pubmlst=pubmlst, pasteur=pasteur
237+
)
218238

219239

220-
def get_client(service: str, database: str = None, folders: Folders = None, pubmlst: PubMLSTCredentials = None, pasteur: PasteurCredentials = None):
240+
def get_client(
241+
service: str,
242+
database: str = None,
243+
folders: Folders = None,
244+
pubmlst: PubMLSTCredentials = None,
245+
pasteur: PasteurCredentials = None,
246+
):
221247
"""Get the appropriate client for the specified service."""
222248
if service == "pasteur":
223249
return PasteurClient(database=database, folders=folders, pubmlst=pubmlst, pasteur=pasteur)

microSALT/utils/pubmlst/get_credentials.py

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@
22
import sys
33
from argparse import ArgumentParser
44

5-
from rauth import OAuth1Service
6-
7-
from microSALT.config import load_config
8-
from microSALT.config import Folders, PubMLSTCredentials, PasteurCredentials
5+
from requests_oauthlib import OAuth1Session
6+
7+
from microSALT.config import (
8+
Folders,
9+
PasteurCredentials,
10+
PubMLSTCredentials,
11+
load_config,
12+
MicroSALTConfig,
13+
)
914
from microSALT.utils.pubmlst.constants import CREDENTIALS_KEY
1015
from microSALT.utils.pubmlst.helpers import get_path, get_service_config
1116

@@ -18,48 +23,44 @@ def validate_credentials(client_id, client_secret):
1823
raise ValueError("Invalid CLIENT_SECRET: It must not be empty.")
1924

2025

21-
def get_request_token(service):
22-
"""Handle JSON response from the request token endpoint."""
23-
response = service.get_raw_request_token(params={"oauth_callback": "oob"})
24-
if not response.ok:
25-
print(f"Error obtaining request token: {response.text}")
26+
def get_new_access_token(
27+
client_id, client_secret, db: str, base_api: str, base_web: str
28+
) -> tuple[str, str]:
29+
"""Obtain a new access token and secret."""
30+
# Step 1: fetch request token
31+
oauth = OAuth1Session(client_id, client_secret=client_secret, callback_uri="oob")
32+
response = oauth.fetch_request_token(f"{base_api}/db/{db}/oauth/get_request_token")
33+
if not response:
34+
print("Error obtaining request token.")
2635
sys.exit(1)
27-
data = response.json()
28-
return data["oauth_token"], data["oauth_token_secret"]
29-
36+
request_token = response["oauth_token"]
37+
request_secret = response["oauth_token_secret"]
3038

31-
def get_new_access_token(client_id, client_secret, db: str, base_api: str, base_web: str):
32-
"""Obtain a new access token and secret."""
33-
service = OAuth1Service(
34-
name="BIGSdb_downloader",
35-
consumer_key=client_id,
36-
consumer_secret=client_secret,
37-
request_token_url=f"{base_api}/db/{db}/oauth/get_request_token",
38-
access_token_url=f"{base_api}/db/{db}/oauth/get_access_token",
39-
base_url=base_api,
40-
)
41-
request_token, request_secret = get_request_token(service)
4239
print(
4340
"Please log in using your user account at "
4441
f"{base_web}?db={db}&page=authorizeClient&oauth_token={request_token} "
4542
"using a web browser to obtain a verification code."
4643
)
4744
verifier = input("Please enter verification code: ")
4845

49-
raw_access = service.get_raw_access_token(
50-
request_token, request_secret, params={"oauth_verifier": verifier}
46+
# Step 2: exchange for access token
47+
oauth = OAuth1Session(
48+
client_id,
49+
client_secret=client_secret,
50+
resource_owner_key=request_token,
51+
resource_owner_secret=request_secret,
52+
verifier=verifier,
5153
)
52-
if not raw_access.ok:
53-
print(f"Error obtaining access token: {raw_access.text}")
54+
access_data = oauth.fetch_access_token(f"{base_api}/db/{db}/oauth/get_access_token")
55+
if not access_data:
56+
print("Error obtaining access token.")
5457
sys.exit(1)
55-
56-
access_data = raw_access.json()
5758
return access_data["oauth_token"], access_data["oauth_token_secret"]
5859

5960

6061
def save_to_credentials_py(
6162
client_id, client_secret, access_token, access_secret, credentials_path, credentials_file
62-
):
63+
) -> None:
6364
"""Save tokens in the credentials.py file."""
6465
credentials_path.mkdir(parents=True, exist_ok=True)
6566

@@ -71,7 +72,7 @@ def save_to_credentials_py(
7172
print(f"Tokens saved to {credentials_file}")
7273

7374

74-
def main(service, config, species=None):
75+
def main(service: str, config: MicroSALTConfig, species: str | None = None):
7576
try:
7677
service_config = get_service_config(service, pubmlst=config.pubmlst, pasteur=config.pasteur)
7778
bigsd_config = service_config["config"]
@@ -89,7 +90,7 @@ def main(service, config, species=None):
8990
else:
9091
raise ValueError(f"Unknown service: {service}")
9192

92-
credentials_path = get_path(config.folders, CREDENTIALS_KEY)
93+
credentials_path = get_path(folders=config.folders, config_key=CREDENTIALS_KEY)
9394
credentials_file = os.path.join(
9495
credentials_path, service_config.get("auth_credentials_file_name")
9596
)

microSALT/utils/pubmlst/helpers.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
logger = logging.getLogger("main_logger")
1919

2020

21-
def get_path(config, config_key: str):
21+
def get_path(folders: Folders, config_key: str) -> Path:
2222
"""Get and expand the file path from the configuration."""
2323
try:
24-
path = getattr(config, config_key, None)
24+
path = getattr(folders, config_key, None)
2525
if not path:
2626
raise PathResolutionError(config_key)
2727

@@ -34,7 +34,7 @@ def get_path(config, config_key: str):
3434
raise PathResolutionError(config_key) from e
3535

3636

37-
def get_service_config(service: str, pubmlst: PubMLSTCredentials = None, pasteur: PasteurCredentials = None):
37+
def get_service_config(service: str, pubmlst: PubMLSTCredentials | None = None, pasteur: PasteurCredentials | None= None):
3838
"""
3939
Get the configuration for the specified service (e.g., 'pubmlst' or 'pasteur').
4040

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ dependencies = [
2020
"pymysql>=1.0",
2121
"pyyaml>=6.0",
2222
"sqlalchemy>=2.0",
23-
"rauth==0.7.3",
23+
"requests-oauthlib>=1.3",
2424
"werkzeug>=3.1.6",
2525
]
2626

uv.lock

Lines changed: 24 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)