Skip to content

Commit 1c99b90

Browse files
author
zhen.chen
committed
feat(utility): add "URL" class for get and update url
1 parent 23c3b59 commit 1c99b90

File tree

9 files changed

+112
-113
lines changed

9 files changed

+112
-113
lines changed

tensorbay/client/cloud_storage.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from tensorbay.client.requests import Client
1515
from tensorbay.dataset import AuthData
16+
from tensorbay.utility import URL
1617

1718

1819
class CloudClient:
@@ -61,5 +62,12 @@ def list_auth_data(self, path: str = "") -> List[AuthData]:
6162
6263
"""
6364
return [
64-
AuthData(cloud_path, _url_getter=self._get_url) for cloud_path in self._list_files(path)
65+
AuthData(
66+
cloud_path,
67+
url=URL.from_getter(
68+
lambda c=cloud_path: self._get_url(c),
69+
lambda c=cloud_path: self._get_url(c), # type: ignore[misc]
70+
),
71+
)
72+
for cloud_path in self._list_files(path)
6573
]

tensorbay/client/segment.py

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import time
2828
from copy import deepcopy
2929
from itertools import zip_longest
30-
from typing import TYPE_CHECKING, Any, Callable, Dict, Generator, Iterable, Optional, Tuple, Union
30+
from typing import TYPE_CHECKING, Any, Dict, Generator, Iterable, Optional, Tuple, Union
3131

3232
import filetype
3333
from requests_toolbelt import MultipartEncoder
@@ -40,7 +40,7 @@
4040
from tensorbay.exception import FrameError, InvalidParamsError, ResponseError
4141
from tensorbay.label import Label
4242
from tensorbay.sensor.sensor import Sensor, Sensors
43-
from tensorbay.utility import FileMixin, chunked, locked
43+
from tensorbay.utility import URL, FileMixin, chunked, locked
4444

4545
if TYPE_CHECKING:
4646
from tensorbay.client.dataset import DatasetClient, FusionDatasetClient
@@ -49,18 +49,6 @@
4949
_MASK_KEYS = ("semantic_mask", "instance_mask", "panoptic_mask")
5050

5151

52-
class _UrlGetters:
53-
def __init__(self, urls: LazyPage[str]) -> None:
54-
self._urls = urls
55-
56-
def __getitem__(self, index: int) -> Callable[[str], str]:
57-
return lambda _: self._urls.items[index].get()
58-
59-
def update(self) -> None:
60-
"""Update all urls."""
61-
self._urls.pull()
62-
63-
6452
class SegmentClientBase:
6553
"""This class defines the basic concept of :class:`SegmentClient`.
6654
@@ -364,41 +352,34 @@ def _generate_data_paths(self, offset: int = 0, limit: int = 128) -> Generator[s
364352
def _generate_data(self, offset: int = 0, limit: int = 128) -> Generator[RemoteData, None, int]:
365353
response = self._list_data_details(offset, limit)
366354

367-
urls = _UrlGetters(
368-
LazyPage.from_items(
369-
offset,
370-
limit,
371-
self._generate_urls,
372-
(item["url"] for item in response["dataDetails"]),
373-
),
355+
urls = LazyPage.from_items(
356+
offset,
357+
limit,
358+
self._generate_urls,
359+
(item["url"] for item in response["dataDetails"]),
374360
)
375361

376362
mask_urls = {}
377363
for key in _MASK_KEYS:
378-
mask_urls[key] = _UrlGetters(
379-
LazyPage(
380-
offset,
381-
limit,
382-
lambda offset, limit, k=key: self._generate_mask_urls( # type: ignore[misc]
383-
k.upper(), offset, limit
384-
),
364+
mask_urls[key] = LazyPage(
365+
offset,
366+
limit,
367+
lambda offset, limit, k=key: self._generate_mask_urls( # type: ignore[misc]
368+
k.upper(), offset, limit
385369
),
386370
)
387371

388372
for i, item in enumerate(response["dataDetails"]):
389373
data = RemoteData.from_response_body(
390374
item,
391-
_url_getter=urls[i],
392-
_url_updater=urls.update,
375+
url=URL.from_getter(urls.items[i].get, urls.pull),
393376
cache_path=self._cache_path,
394377
)
395378
label = data.label
396379
for key in _MASK_KEYS:
397380
mask = getattr(label, key, None)
398381
if mask:
399-
# pylint: disable=protected-access
400-
mask._url_getter = mask_urls[key][i]
401-
mask._url_updater = mask_urls[key].update
382+
mask.url = URL.from_getter(mask_urls[key].items[i].get, mask_urls[key].pull)
402383
mask.cache_path = os.path.join(self._cache_path, key, mask.path)
403384

404385
yield data

tensorbay/dataset/data.py

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
"""
1212

1313
import os
14-
from typing import Any, Callable, Dict, Optional, Type, TypeVar, Union
14+
from typing import Any, Dict, Optional, Type, TypeVar, Union
1515

1616
from tensorbay.label import Label
17-
from tensorbay.utility import FileMixin, RemoteFileMixin, ReprMixin
17+
from tensorbay.utility import URL, FileMixin, RemoteFileMixin, ReprMixin
1818

1919

2020
class DataBase(ReprMixin):
@@ -138,14 +138,15 @@ class RemoteData(DataBase, RemoteFileMixin):
138138
Arguments:
139139
remote_path: The file remote path.
140140
timestamp: The timestamp for the file.
141-
_url_getter: The url getter of the remote file.
141+
url: The URL instance used to get and update url.
142142
cache_path: The path to store the cache.
143143
144144
Attributes:
145145
path: The file remote path.
146146
timestamp: The timestamp for the file.
147147
label: The :class:`~tensorbay.label.label.Label` instance that contains
148148
all the label information of the file.
149+
url: The :class:`~tensorbay.utility.file.URL` instance used to get and update url.
149150
150151
"""
151152

@@ -156,16 +157,14 @@ def __init__(
156157
remote_path: str,
157158
*,
158159
timestamp: Optional[float] = None,
159-
_url_getter: Optional[Callable[[str], str]] = None,
160-
_url_updater: Optional[Callable[[], None]] = None,
160+
url: Optional[URL] = None,
161161
cache_path: str = "",
162162
) -> None:
163163
DataBase.__init__(self, timestamp)
164164
RemoteFileMixin.__init__(
165165
self,
166166
remote_path,
167-
_url_getter=_url_getter,
168-
_url_updater=_url_updater,
167+
url=url,
169168
cache_path=cache_path,
170169
)
171170

@@ -174,10 +173,9 @@ def from_response_body(
174173
cls: Type[_T],
175174
body: Dict[str, Any],
176175
*,
177-
_url_getter: Optional[Callable[[str], str]],
178-
_url_updater: Optional[Callable[[], None]] = None,
179-
cache_path: str = "", # noqa: DAR101
180-
) -> _T:
176+
url: Optional[URL] = None,
177+
cache_path: str = "",
178+
) -> _T: # noqa: DAR101
181179
"""Loads a :class:`RemoteData` object from a response body.
182180
183181
Arguments:
@@ -198,9 +196,7 @@ def from_response_body(
198196
"SENTENCE": {...}
199197
}
200198
}
201-
202-
_url_getter: The url getter of the remote file.
203-
_url_updater: The url updater of the remote file.
199+
url: The URL instance used to get and update url.
204200
cache_path: The path to store the cache.
205201
206202
Returns:
@@ -210,8 +206,7 @@ def from_response_body(
210206
data = cls(
211207
body["remotePath"],
212208
timestamp=body.get("timestamp"),
213-
_url_getter=_url_getter,
214-
_url_updater=_url_updater,
209+
url=url,
215210
cache_path=cache_path,
216211
)
217212
data.label._loads(body["label"]) # pylint: disable=protected-access
@@ -230,13 +225,14 @@ class AuthData(DataBase, RemoteFileMixin):
230225
cloud_path: The cloud file path.
231226
target_remote_path: The file remote path after uploading to tensorbay.
232227
timestamp: The timestamp for the file.
233-
_url_getter: The url getter of the remote file.
228+
url: The URL instance used to get and update url.
234229
235230
Attributes:
236231
path: The cloud file path.
237232
timestamp: The timestamp for the file.
238233
label: The :class:`~tensorbay.label.label.Label` instance that contains
239234
all the label information of the file.
235+
url: The :class:`~tensorbay.utility.file.URL` instance used to get and update url.
240236
241237
"""
242238

@@ -246,10 +242,10 @@ def __init__(
246242
*,
247243
target_remote_path: Optional[str] = None,
248244
timestamp: Optional[float] = None,
249-
_url_getter: Optional[Callable[[str], str]] = None,
245+
url: Optional[URL] = None,
250246
) -> None:
251247
DataBase.__init__(self, timestamp)
252-
RemoteFileMixin.__init__(self, cloud_path, _url_getter=_url_getter)
248+
RemoteFileMixin.__init__(self, cloud_path, url=url)
253249
self._target_remote_path = target_remote_path
254250

255251
@property

tensorbay/dataset/frame.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
from tensorbay.client.lazy import LazyPage
2323
from tensorbay.dataset.data import DataBase, RemoteData
24-
from tensorbay.utility import UserMutableMapping
24+
from tensorbay.utility import URL, UserMutableMapping
2525

2626
logger = logging.getLogger(__name__)
2727

@@ -114,12 +114,10 @@ def from_response_body(
114114
frame = cls(frame_id)
115115
for data_contents in body["frame"]:
116116
sensor_name = data_contents["sensorName"]
117+
url = URL.from_getter(lambda s=sensor_name: urls.items[url_index].get()[s], urls.pull)
117118
frame[sensor_name] = RemoteData.from_response_body(
118119
data_contents,
119-
_url_getter=lambda _, s=sensor_name: urls.items[ # type: ignore[misc]
120-
url_index
121-
].get()[s],
122-
_url_updater=urls.pull,
120+
url=url,
123121
cache_path=cache_path,
124122
)
125123
return frame

tensorbay/dataset/tests/test_data.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
import pytest
1010

1111
from tensorbay.dataset.data import Data, RemoteData
12+
from tensorbay.utility import URL
1213

1314
_REMOTE_DATA = {
1415
"remotePath": "test.json",
1516
"timestamp": 1614667532,
1617
"label": {},
1718
"url": "url",
1819
}
20+
url = URL("url", lambda: "url")
1921

2022

2123
class TestData:
@@ -62,21 +64,19 @@ class TestRemoteData:
6264
def test_init(self):
6365
remote_path = "A/test.json"
6466
timestamp = 1614667532
65-
remote_data = RemoteData(remote_path, timestamp=timestamp, _url_getter=lambda x: x)
67+
remote_data = RemoteData(remote_path, timestamp=timestamp, url=url)
6668
assert remote_data.path == remote_path
6769
assert remote_data.timestamp == timestamp
68-
assert remote_data.get_url() == remote_path
70+
assert remote_data.url.get() == "url"
6971

7072
def test_get_url(self):
7173
remote_data = RemoteData("A/test.josn")
7274
with pytest.raises(ValueError):
73-
remote_data.get_url()
75+
remote_data.open()
7476

7577
def test_from_response_body(self):
76-
data = RemoteData.from_response_body(
77-
_REMOTE_DATA, _url_getter=lambda _: "url", cache_path="cache_path"
78-
)
78+
data = RemoteData.from_response_body(_REMOTE_DATA, url=url, cache_path="cache_path")
7979
assert data.path == _REMOTE_DATA["remotePath"]
8080
assert data.timestamp == _REMOTE_DATA["timestamp"]
81-
assert data.get_url() == "url"
81+
assert data.url.get() == "url"
8282
assert data.cache_path == os.path.join("cache_path", _REMOTE_DATA["remotePath"])

tensorbay/dataset/tests/test_frame.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ def test_from_response_body(self):
5252
assert frame.frame_id == _FRAME_ID
5353
assert frame["sensor1"].path == "test1.png"
5454
assert frame["sensor1"].timestamp == 1614945883
55-
assert frame["sensor1"].get_url() == "url1"
55+
assert frame["sensor1"].url.get() == "url1"
5656
assert frame["sensor1"].cache_path == os.path.join("cache_path", "test1.png")
5757
assert frame["sensor2"].path == "test2.png"
5858
assert frame["sensor2"].timestamp == 1614945884
59-
assert frame["sensor2"].get_url() == "url2"
59+
assert frame["sensor2"].url.get() == "url2"
6060
assert frame["sensor2"].cache_path == os.path.join("cache_path", "test2.png")

tensorbay/label/label_mask.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55

66
"""Mask related classes."""
77

8-
from typing import Any, Callable, Dict, Optional, Type, TypeVar
8+
from typing import Any, Dict, Optional, Type, TypeVar
99

1010
from tensorbay.label.basic import AttributeType, SubcatalogBase
1111
from tensorbay.label.supports import AttributesMixin, IsTrackingMixin, MaskCategoriesMixin
12-
from tensorbay.utility import FileMixin, RemoteFileMixin, ReprMixin
12+
from tensorbay.utility import URL, FileMixin, RemoteFileMixin, ReprMixin
1313

1414

1515
class SemanticMaskSubcatalog(SubcatalogBase, MaskCategoriesMixin, AttributesMixin):
@@ -462,11 +462,9 @@ class RemotePanopticMask(PanopticMaskBase, RemoteFileMixin):
462462

463463
_T = TypeVar("_T", bound="RemotePanopticMask")
464464

465-
def __init__(
466-
self, remote_path: str, *, _url_getter: Optional[Callable[[str], str]] = None
467-
) -> None:
465+
def __init__(self, remote_path: str, *, url: Optional[URL] = None) -> None:
468466
PanopticMaskBase.__init__(self)
469-
RemoteFileMixin.__init__(self, remote_path, _url_getter=_url_getter)
467+
RemoteFileMixin.__init__(self, remote_path, url=url)
470468

471469
@classmethod
472470
def from_response_body(cls: Type[_T], body: Dict[str, Any]) -> _T:

tensorbay/utility/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
Disable,
1414
KwargsDeprecated,
1515
)
16-
from tensorbay.utility.file import FileMixin, RemoteFileMixin
16+
from tensorbay.utility.file import URL, FileMixin, RemoteFileMixin
1717
from tensorbay.utility.itertools import chunked
1818
from tensorbay.utility.name import NameList, NameMixin, SortedNameList
1919
from tensorbay.utility.repr import ReprMixin, ReprType, repr_config
@@ -43,6 +43,7 @@
4343
"TypeEnum",
4444
"TypeMixin",
4545
"TypeRegister",
46+
"URL",
4647
"UserMapping",
4748
"UserMutableMapping",
4849
"UserMutableSequence",

0 commit comments

Comments
 (0)