Skip to content

Commit 868e9ed

Browse files
authored
Merge pull request #16 from gopythongo/pr14
#14 Allow non-root locations in aptly API URLs
2 parents ac328fb + 2b2a730 commit 868e9ed

File tree

9 files changed

+46
-32
lines changed

9 files changed

+46
-32
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ build
1717
.env
1818
__pycache__
1919
.coverage
20+
.mypy_cache
21+
.tox
22+
.toxenv

aptly_api/base.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ def __init__(self, base_url: str, ssl_verify: Union[str, bool, None]=None,
2828
self.http_auth = http_auth
2929
self.exc_class = AptlyAPIException
3030

31-
while self.base_url.endswith("/"):
32-
self.base_url = self.base_url[:-1]
33-
3431
def _error_from_response(self, resp: requests.Response) -> str:
3532
if resp.status_code == 200:
3633
return "no error (status 200)"

aptly_api/parts/files.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
class FilesAPISection(BaseAPIClient):
1313
def list(self, directory: str=None) -> Sequence[str]:
1414
if directory is None:
15-
resp = self.do_get("/api/files")
15+
resp = self.do_get("api/files")
1616
else:
17-
resp = self.do_get("/api/files/%s" % directory)
17+
resp = self.do_get("api/files/%s" % directory)
1818

1919
return resp.json()
2020

@@ -27,7 +27,7 @@ def upload(self, destination: str, *files: str) -> Sequence[str]:
2727
to_upload.append((f, fh),)
2828

2929
try:
30-
resp = self.do_post("/api/files/%s" % destination,
30+
resp = self.do_post("api/files/%s" % destination,
3131
files=to_upload)
3232
except AptlyAPIException:
3333
raise
@@ -39,4 +39,4 @@ def upload(self, destination: str, *files: str) -> Sequence[str]:
3939
return resp.json()
4040

4141
def delete(self, path: str=None) -> None:
42-
self.do_delete("/api/files/%s" % path)
42+
self.do_delete("api/files/%s" % path)

aptly_api/parts/misc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def graph(self, ext: str, layout: str="horizontal") -> None:
1111
raise NotImplementedError("The Graph API is not yet supported")
1212

1313
def version(self) -> str:
14-
resp = self.do_get("/api/version")
14+
resp = self.do_get("api/version")
1515
if "Version" in resp.json():
1616
return resp.json()["Version"]
1717
else:

aptly_api/parts/packages.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,5 @@ def package_from_response(api_response: Union[str, Dict[str, str]]) -> Package:
3737
)
3838

3939
def show(self, key: str) -> Package:
40-
resp = self.do_get("/api/packages/%s" % quote(key))
40+
resp = self.do_get("api/packages/%s" % quote(key))
4141
return self.package_from_response(resp.json())

aptly_api/parts/publish.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def escape_prefix(prefix: str) -> str:
5151
return prefix
5252

5353
def list(self) -> Sequence[PublishEndpoint]:
54-
resp = self.do_get("/api/publish")
54+
resp = self.do_get("api/publish")
5555
ret = []
5656
for rpe in resp.json():
5757
ret.append(self.endpoint_from_response(rpe))
@@ -84,9 +84,9 @@ def publish(self, *, source_kind: str="local",
8484
if "name" not in source and "Name" not in source:
8585
raise AptlyAPIException("Each source in publish() must contain the 'name' attribute")
8686

87-
url = "/api/publish"
87+
url = "api/publish"
8888
if prefix is not None and prefix != "":
89-
url = "/api/publish/%s" % quote(self.escape_prefix(prefix))
89+
url = "api/publish/%s" % quote(self.escape_prefix(prefix))
9090

9191
body = {
9292
"SourceKind": source_kind,
@@ -171,13 +171,13 @@ def update(self, *, prefix: str, distribution: str,
171171
sign_dict["PassphraseFile"] = sign_passphrase_file
172172
body["Signing"] = sign_dict
173173

174-
resp = self.do_put("/api/publish/%s/%s" %
174+
resp = self.do_put("api/publish/%s/%s" %
175175
(quote(self.escape_prefix(prefix)), quote(distribution),), json=body)
176176
return self.endpoint_from_response(resp.json())
177177

178178
def drop(self, *, prefix: str, distribution: str, force_delete: bool=False) -> None:
179179
params = {}
180180
if force_delete:
181181
params["force"] = "1"
182-
self.do_delete("/api/publish/%s/%s" %
182+
self.do_delete("api/publish/%s/%s" %
183183
(quote(self.escape_prefix(prefix)), quote(distribution),), params=params)

aptly_api/parts/repos.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ def create(self, reponame: str, comment: str=None, default_distribution: str=Non
5252
if default_component:
5353
data["DefaultComponent"] = default_component
5454

55-
resp = self.do_post("/api/repos", json=data)
55+
resp = self.do_post("api/repos", json=data)
5656

5757
return self.repo_from_response(resp.json())
5858

5959
def show(self, reponame: str) -> Repo:
60-
resp = self.do_get("/api/repos/%s" % quote(reponame))
60+
resp = self.do_get("api/repos/%s" % quote(reponame))
6161
return self.repo_from_response(resp.json())
6262

6363
def search_packages(self, reponame: str, query: str=None, with_deps: bool=False,
@@ -75,7 +75,7 @@ def search_packages(self, reponame: str, query: str=None, with_deps: bool=False,
7575
if detailed:
7676
params["format"] = "details"
7777

78-
resp = self.do_get("/api/repos/%s/packages" % quote(reponame), params=params)
78+
resp = self.do_get("api/repos/%s/packages" % quote(reponame), params=params)
7979
ret = []
8080
for rpkg in resp.json():
8181
ret.append(PackageAPISection.package_from_response(rpkg))
@@ -95,11 +95,11 @@ def edit(self, reponame: str, comment: str=None, default_distribution: str=None,
9595
if default_component is not None:
9696
body["DefaultComponent"] = default_component
9797

98-
resp = self.do_put("/api/repos/%s" % quote(reponame), json=body)
98+
resp = self.do_put("api/repos/%s" % quote(reponame), json=body)
9999
return self.repo_from_response(resp.json())
100100

101101
def list(self) -> Sequence[Repo]:
102-
resp = self.do_get("/api/repos")
102+
resp = self.do_get("api/repos")
103103

104104
repos = []
105105
for rdesc in resp.json():
@@ -109,7 +109,7 @@ def list(self) -> Sequence[Repo]:
109109
return repos
110110

111111
def delete(self, reponame: str, force: bool=False) -> None:
112-
self.do_delete("/api/repos/%s" % quote(reponame), params={"force": "1" if force else "0"})
112+
self.do_delete("api/repos/%s" % quote(reponame), params={"force": "1" if force else "0"})
113113

114114
def add_uploaded_file(self, reponame: str, dir: str, filename: str=None, remove_processed_files: bool=True,
115115
force_replace: bool=False) -> FileReport:
@@ -120,21 +120,21 @@ def add_uploaded_file(self, reponame: str, dir: str, filename: str=None, remove_
120120
params["forceReplace"] = "1"
121121

122122
if filename is None:
123-
resp = self.do_post("/api/repos/%s/file/%s" % (quote(reponame), quote(dir),), params=params)
123+
resp = self.do_post("api/repos/%s/file/%s" % (quote(reponame), quote(dir),), params=params)
124124
else:
125-
resp = self.do_post("/api/repos/%s/file/%s/%s" % (quote(reponame), quote(dir), quote(filename),),
125+
resp = self.do_post("api/repos/%s/file/%s/%s" % (quote(reponame), quote(dir), quote(filename),),
126126
params=params)
127127

128128
return self.filereport_from_response(resp.json())
129129

130130
def add_packages_by_key(self, reponame: str, *package_keys: str) -> Repo:
131-
resp = self.do_post("/api/repos/%s/packages" % quote(reponame), json={
131+
resp = self.do_post("api/repos/%s/packages" % quote(reponame), json={
132132
"PackageRefs": package_keys,
133133
})
134134
return self.repo_from_response(resp.json())
135135

136136
def delete_packages_by_key(self, reponame: str, *package_keys: str) -> Repo:
137-
resp = self.do_delete("/api/repos/%s/packages" % quote(reponame), json={
137+
resp = self.do_delete("api/repos/%s/packages" % quote(reponame), json={
138138
"PackageRefs": package_keys,
139139
})
140140
return self.repo_from_response(resp.json())

aptly_api/parts/snapshots.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def list(self, sort: str='name') -> Sequence[Snapshot]:
3131
if sort not in ['name', 'time']:
3232
raise AptlyAPIException("Snapshot LIST only supports two sort modes: 'name' and 'time'. %s is not "
3333
"supported." % sort)
34-
resp = self.do_get("/api/snapshots")
34+
resp = self.do_get("api/snapshots")
3535
ret = []
3636
for rsnap in resp.json():
3737
ret.append(self.snapshot_from_response(rsnap))
@@ -44,7 +44,7 @@ def create_from_repo(self, reponame: str, snapshotname: str, description: str=No
4444
if description is not None:
4545
body["Description"] = description
4646

47-
resp = self.do_post("/api/repos/%s/snapshots" % quote(reponame), json=body)
47+
resp = self.do_post("api/repos/%s/snapshots" % quote(reponame), json=body)
4848
return self.snapshot_from_response(resp.json())
4949

5050
def create_from_packages(self, snapshotname: str, description: str=None,
@@ -62,7 +62,7 @@ def create_from_packages(self, snapshotname: str, description: str=None,
6262
if package_refs is not None:
6363
body["PackageRefs"] = package_refs
6464

65-
resp = self.do_post("/api/snapshots", json=body)
65+
resp = self.do_post("api/snapshots", json=body)
6666
return self.snapshot_from_response(resp.json())
6767

6868
def update(self, snapshotname: str, newname: str=None, newdescription: str=None) -> Snapshot:
@@ -76,11 +76,11 @@ def update(self, snapshotname: str, newname: str=None, newdescription: str=None)
7676
if newdescription is not None:
7777
body["Description"] = newdescription
7878

79-
resp = self.do_put("/api/snapshots/%s" % quote(snapshotname), json=body)
79+
resp = self.do_put("api/snapshots/%s" % quote(snapshotname), json=body)
8080
return self.snapshot_from_response(resp.json())
8181

8282
def show(self, snapshotname: str) -> Snapshot:
83-
resp = self.do_get("/api/snapshots/%s" % quote(snapshotname))
83+
resp = self.do_get("api/snapshots/%s" % quote(snapshotname))
8484
return self.snapshot_from_response(resp.json())
8585

8686
def list_packages(self, snapshotname: str, query: str=None, with_deps: bool=False,
@@ -93,7 +93,7 @@ def list_packages(self, snapshotname: str, query: str=None, with_deps: bool=Fals
9393
if detailed:
9494
params["format"] = "details"
9595

96-
resp = self.do_get("/api/snapshots/%s/packages" % quote(snapshotname), params=params)
96+
resp = self.do_get("api/snapshots/%s/packages" % quote(snapshotname), params=params)
9797
ret = []
9898
for rpkg in resp.json():
9999
ret.append(PackageAPISection.package_from_response(rpkg))
@@ -106,8 +106,8 @@ def delete(self, snapshotname: str, force: bool=False) -> None:
106106
"force": "1",
107107
}
108108

109-
self.do_delete("/api/snapshots/%s" % quote(snapshotname), params=params)
109+
self.do_delete("api/snapshots/%s" % quote(snapshotname), params=params)
110110

111111
def diff(self, snapshot1: str, snapshot2: str) -> Sequence[Dict[str, str]]:
112-
resp = self.do_get("/api/snapshots/%s/diff/%s" % (quote(snapshot1), quote(snapshot2),))
112+
resp = self.do_get("api/snapshots/%s/diff/%s" % (quote(snapshot1), quote(snapshot2),))
113113
return resp.json()

aptly_api/tests/client.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,20 @@ def test_instantiate(self) -> None:
2828
"Client (Aptly API Client) <http://test/>"
2929
)
3030

31+
@requests_mock.Mocker(kw='rmock')
32+
def test_api_subdir_get(self, *, rmock: requests_mock.Mocker) -> None:
33+
# register mock:// scheme with urllib.parse
34+
import urllib.parse
35+
urllib.parse.uses_netloc += ['mock']
36+
urllib.parse.uses_relative += ['mock']
37+
urllib.parse.uses_fragment += ['mock']
38+
urllib.parse.uses_params += ['mock']
39+
40+
cl = AptlyClient("mock://test/basedir/")
41+
rmock.get("mock://test/basedir/api/test", status_code=200, text='')
42+
cl.files.do_get("api/test")
43+
self.assertTrue(rmock.called)
44+
3145
def test_error_no_error(self) -> None:
3246
class MockResponse:
3347
def __init__(self, status_code: int=200) -> None:

0 commit comments

Comments
 (0)