Skip to content

Commit 26bd6b8

Browse files
committed
refactor: remove file_name from Config
1 parent 0e1efdd commit 26bd6b8

File tree

6 files changed

+116
-122
lines changed

6 files changed

+116
-122
lines changed

src/stac_asset/_cli.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@ async def download_async(
163163
alternate_assets=alternate_assets,
164164
include=include,
165165
exclude=exclude,
166-
file_name=file_name,
167166
s3_requester_pays=s3_requester_pays,
168167
s3_retry_mode=s3_retry_mode,
169168
s3_max_attempts=s3_max_attempts,
@@ -200,6 +199,7 @@ async def download() -> Union[Item, ItemCollection]:
200199
return await functions.download_item(
201200
item,
202201
directory_str,
202+
file_name=file_name,
203203
config=config,
204204
queue=queue,
205205
)
@@ -211,6 +211,7 @@ async def download() -> Union[Item, ItemCollection]:
211211
return await functions.download_item_collection(
212212
item_collection,
213213
directory_str,
214+
file_name=file_name,
214215
config=config,
215216
queue=queue,
216217
)

src/stac_asset/_download.py

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
from types import TracebackType
1010
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Type, Union
1111

12-
from pystac import Asset, Collection, Item, STACObject
12+
import pystac.utils
13+
from pystac import Asset, Collection, Item, STACError
1314
from yarl import URL
1415

1516
from .client import Client
@@ -28,6 +29,15 @@
2829
AnyQueue = Queue
2930

3031

32+
class WrappedError:
33+
download: Download
34+
error: Exception
35+
36+
def __init__(self, download: Download, error: Exception) -> None:
37+
self.download = download
38+
self.error = error
39+
40+
3141
@dataclass
3242
class Download:
3343
owner: Union[Item, Collection]
@@ -45,13 +55,6 @@ async def download(
4555
)
4656
except Exception as error:
4757
return WrappedError(self, error)
48-
if "alternate" not in self.asset.extra_fields:
49-
if not has_alternate_assets_extension(self.owner):
50-
self.owner.stac_extensions.append(
51-
"https://stac-extensions.github.io/alternate-assets/v1.1.0/schema.json"
52-
)
53-
self.asset.extra_fields["alternate"] = {}
54-
self.asset.extra_fields["alternate"]["from"] = {"href": self.asset.href}
5558
self.asset.href = str(self.path)
5659
return self
5760

@@ -67,24 +70,43 @@ def __init__(self, config: Config) -> None:
6770
self.downloads = list()
6871
self.clients = dict()
6972

70-
async def add(self, stac_object: Union[Item, Collection], root: Path) -> None:
71-
file_names: Set[str] = set()
72-
73+
async def add(
74+
self, stac_object: Union[Item, Collection], root: Path, file_name: Optional[str]
75+
) -> None:
76+
links = list()
77+
for link in stac_object.links:
78+
absolute_href = link.get_absolute_href()
79+
if absolute_href:
80+
link.target = absolute_href
81+
links.append(link)
82+
stac_object.links = links
83+
# Will fail if the stac object doesn't have a self href and there's
84+
# relative asset hrefs
85+
stac_object = make_asset_hrefs_absolute(stac_object)
86+
87+
if file_name:
88+
item_path = Path(root) / file_name
89+
stac_object.set_self_href(str(item_path))
90+
else:
91+
item_path = None
92+
stac_object.set_self_href(item_path)
93+
94+
asset_file_names: Set[str] = set()
7395
for key, asset in (
7496
(k, a)
7597
for k, a in stac_object.assets.items()
7698
if (not self.config.include or k in self.config.include)
7799
and (not self.config.exclude or k not in self.config.exclude)
78100
):
79101
if self.config.asset_file_name_strategy == FileNameStrategy.FILE_NAME:
80-
file_name = os.path.basename(URL(asset.href).path)
102+
asset_file_name = os.path.basename(URL(asset.href).path)
81103
elif self.config.asset_file_name_strategy == FileNameStrategy.KEY:
82-
file_name = key + Path(asset.href).suffix
104+
asset_file_name = key + Path(asset.href).suffix
83105

84-
if file_name in file_names:
85-
raise AssetOverwriteError(list(file_names))
106+
if asset_file_name in asset_file_names:
107+
raise AssetOverwriteError(list(asset_file_names))
86108
else:
87-
file_names.add(file_name)
109+
asset_file_names.add(asset_file_name)
88110

89111
client_class = guess_client_class(asset, self.config)
90112
if client_class in self.clients:
@@ -98,7 +120,7 @@ async def add(self, stac_object: Union[Item, Collection], root: Path) -> None:
98120
owner=stac_object,
99121
key=key,
100122
asset=asset,
101-
path=root / file_name,
123+
path=root / asset_file_name,
102124
client=client,
103125
)
104126
)
@@ -116,6 +138,7 @@ async def download(self, queue: Optional[AnyQueue]) -> None:
116138
)
117139
)
118140
results = await asyncio.gather(*tasks)
141+
119142
exceptions = set()
120143
for result in results:
121144
if isinstance(result, WrappedError):
@@ -195,17 +218,19 @@ def guess_client_class_from_href(href: str) -> Type[Client]:
195218
raise ValueError(f"could not guess client class for href: {href}")
196219

197220

198-
def has_alternate_assets_extension(stac_object: STACObject) -> bool:
199-
return any(
200-
extension.startswith("https://stac-extensions.github.io/alternate-assets")
201-
for extension in stac_object.stac_extensions
202-
)
203-
204-
205-
class WrappedError:
206-
download: Download
207-
error: Exception
208-
209-
def __init__(self, download: Download, error: Exception) -> None:
210-
self.download = download
211-
self.error = error
221+
def make_asset_hrefs_absolute(
222+
stac_object: Union[Item, Collection]
223+
) -> Union[Item, Collection]:
224+
# Copied from
225+
# https://github.com/stac-utils/pystac/blob/381cf89fc25c15142fb5a187d905e22681de42a2/pystac/item.py#L309C3-L319C1
226+
# until a fix for https://github.com/stac-utils/pystac/issues/1199 is
227+
# released.
228+
self_href = stac_object.get_self_href()
229+
for asset in stac_object.assets.values():
230+
if not pystac.utils.is_absolute_href(asset.href):
231+
if self_href is None:
232+
raise STACError(
233+
"Cannot make asset HREFs absolute if no self_href is set."
234+
)
235+
asset.href = pystac.utils.make_absolute_href(asset.href, self_href)
236+
return stac_object

src/stac_asset/config.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,6 @@ class Config:
3737
Mutually exclusive with ``exclude``.
3838
"""
3939

40-
file_name: Optional[str] = None
41-
"""The file name of the output item.
42-
43-
If not provided, the output item will not be saved.
44-
"""
45-
4640
make_directory: bool = True
4741
"""Whether to create the output directory.
4842

src/stac_asset/functions.py

Lines changed: 41 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
TYPE_CHECKING,
66
Any,
77
Optional,
8-
TypeVar,
8+
Union,
99
)
1010

1111
import pystac.utils
@@ -25,6 +25,7 @@
2525
async def download_item(
2626
item: Item,
2727
directory: PathLikeObject,
28+
file_name: Optional[str] = None,
2829
config: Optional[Config] = None,
2930
queue: Optional[AnyQueue] = None,
3031
) -> Item:
@@ -33,6 +34,8 @@ async def download_item(
3334
Args:
3435
item: The :py:class:`pystac.Item`.
3536
directory: The output directory that will hold the items and assets.
37+
file_name: The name of the item file to save. If not provided, will not
38+
be saved.
3639
config: The download configuration
3740
queue: An optional queue to use for progress reporting
3841
@@ -42,14 +45,24 @@ async def download_item(
4245
Raises:
4346
ValueError: Raised if the item doesn't have any assets.
4447
"""
45-
return await _download_stac_object(
46-
item, directory, config=config or Config(), queue=queue
47-
)
48+
async with Downloads(config or Config()) as downloads:
49+
await downloads.add(item, Path(directory), file_name)
50+
await downloads.download(queue)
51+
52+
self_href = item.get_self_href()
53+
if self_href:
54+
_make_asset_hrefs_relative(item)
55+
d = item.to_dict(include_self_link=True, transform_hrefs=False)
56+
with open(self_href, "w") as f:
57+
json.dump(d, f)
58+
59+
return item
4860

4961

5062
async def download_collection(
5163
collection: Collection,
5264
directory: PathLikeObject,
65+
file_name: Optional[str] = None,
5366
config: Optional[Config] = None,
5467
queue: Optional[AnyQueue] = None,
5568
) -> Collection:
@@ -61,6 +74,8 @@ async def download_collection(
6174
Args:
6275
collection: A pystac collection
6376
directory: The destination directory
77+
file_name: The name of the collection file to save. If not provided,
78+
will not be saved.
6479
config: The download configuration
6580
queue: An optional queue to use for progress reporting
6681
@@ -70,14 +85,24 @@ async def download_collection(
7085
Raises:
7186
CantIncludeAndExclude: Raised if both include and exclude are not None.
7287
"""
73-
return await _download_stac_object(
74-
collection, directory, config or Config(), queue=queue
75-
)
88+
async with Downloads(config or Config()) as downloads:
89+
await downloads.add(collection, Path(directory), file_name)
90+
await downloads.download(queue)
91+
92+
self_href = collection.get_self_href()
93+
if self_href:
94+
_make_asset_hrefs_relative(collection)
95+
d = collection.to_dict(include_self_link=True, transform_hrefs=False)
96+
with open(self_href, "w") as f:
97+
json.dump(d, f)
98+
99+
return collection
76100

77101

78102
async def download_item_collection(
79103
item_collection: ItemCollection,
80104
directory: PathLikeObject,
105+
file_name: Optional[str] = None,
81106
config: Optional[Config] = None,
82107
queue: Optional[AnyQueue] = None,
83108
) -> ItemCollection:
@@ -86,6 +111,8 @@ async def download_item_collection(
86111
Args:
87112
item_collection: The item collection to download
88113
directory: The destination directory
114+
file_name: The name of the item collection file to save. If not
115+
provided, will not be saved.
89116
config: The download configuration
90117
queue: An optional queue to use for progress reporting
91118
@@ -95,16 +122,14 @@ async def download_item_collection(
95122
Raises:
96123
CantIncludeAndExclude: Raised if both include and exclude are not None.
97124
"""
98-
if config is None:
99-
config = Config()
100-
async with Downloads(config) as downloads:
125+
async with Downloads(config or Config()) as downloads:
101126
for item in item_collection.items:
102127
item.set_self_href(None)
103128
root = Path(directory) / item.id
104-
await downloads.add(item, root)
129+
await downloads.add(item, root, None)
105130
await downloads.download(queue)
106-
if config.file_name:
107-
dest_href = Path(directory) / config.file_name
131+
if file_name:
132+
dest_href = Path(directory) / file_name
108133
for item in item_collection.items:
109134
for asset in item.assets.values():
110135
asset.href = pystac.utils.make_relative_href(
@@ -115,48 +140,9 @@ async def download_item_collection(
115140
return item_collection
116141

117142

118-
_T = TypeVar("_T", Collection, Item)
119-
120-
121-
async def _download_stac_object(
122-
stac_object: _T,
123-
directory: PathLikeObject,
124-
config: Config,
125-
queue: Optional[AnyQueue],
126-
) -> _T:
127-
links = list()
128-
for link in stac_object.links:
129-
absolute_href = link.get_absolute_href()
130-
if absolute_href:
131-
link.target = absolute_href
132-
links.append(link)
133-
stac_object.links = links
134-
# Will fail if the stac object doesn't have a self href and there's
135-
# relative asset hrefs
136-
stac_object = _make_asset_hrefs_absolute(stac_object)
137-
138-
if config.file_name:
139-
item_path = Path(directory) / config.file_name
140-
stac_object.set_self_href(str(item_path))
141-
else:
142-
item_path = None
143-
stac_object.set_self_href(item_path)
144-
145-
async with Downloads(config) as downloads:
146-
await downloads.add(stac_object, Path(directory))
147-
await downloads.download(queue)
148-
149-
self_href = stac_object.get_self_href()
150-
if self_href:
151-
_make_asset_hrefs_relative(stac_object)
152-
d = stac_object.to_dict(include_self_link=True, transform_hrefs=False)
153-
with open(self_href, "w") as f:
154-
json.dump(d, f)
155-
156-
return stac_object
157-
158-
159-
def _make_asset_hrefs_relative(stac_object: _T) -> _T:
143+
def _make_asset_hrefs_relative(
144+
stac_object: Union[Item, Collection]
145+
) -> Union[Item, Collection]:
160146
# Copied from
161147
# https://github.com/stac-utils/pystac/blob/381cf89fc25c15142fb5a187d905e22681de42a2/pystac/item.py#L284C5-L298C20
162148
# until a fix for https://github.com/stac-utils/pystac/issues/1199 is
@@ -170,19 +156,3 @@ def _make_asset_hrefs_relative(stac_object: _T) -> _T:
170156
)
171157
asset.href = pystac.utils.make_relative_href(asset.href, self_href)
172158
return stac_object
173-
174-
175-
def _make_asset_hrefs_absolute(stac_object: _T) -> _T:
176-
# Copied from
177-
# https://github.com/stac-utils/pystac/blob/381cf89fc25c15142fb5a187d905e22681de42a2/pystac/item.py#L309C3-L319C1
178-
# until a fix for https://github.com/stac-utils/pystac/issues/1199 is
179-
# released.
180-
self_href = stac_object.get_self_href()
181-
for asset in stac_object.assets.values():
182-
if not pystac.utils.is_absolute_href(asset.href):
183-
if self_href is None:
184-
raise STACError(
185-
"Cannot make asset HREFs absolute if no self_href is set."
186-
)
187-
asset.href = pystac.utils.make_absolute_href(asset.href, self_href)
188-
return stac_object

0 commit comments

Comments
 (0)