Skip to content

Commit be238f2

Browse files
committed
Move single-use imports from top level
Python import times are noticeable during interactive use of CLI applications, so push the (near) single-use imports into the functions where they are used so the import cost is paid when calling the functions instead of when starting the CLI to print the help or do some other unrelated action. Timings on top of #1583 inside a Python:3.10-bookworm container. Before this change: $ uv run hyperfine --warmup 3 "python3 -c 'import pystac'" Benchmark 1: python3 -c 'import pystac' Time (mean ± σ): 67.2 ms ± 1.6 ms [User: 58.6 ms, System: 8.6 ms] Range (min … max): 62.5 ms … 69.9 ms 45 runs After this change: $ uv run hyperfine --warmup 3 "python3 -c 'import pystac'" Benchmark 1: python3 -c 'import pystac' Time (mean ± σ): 59.9 ms ± 1.5 ms [User: 52.0 ms, System: 7.8 ms] Range (min … max): 56.9 ms … 64.2 ms 48 runs
1 parent a5e0408 commit be238f2

27 files changed

+109
-54
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## [Unreleased]
44

5+
- Speed up importing pystac ([#1584](https://github.com/stac-utils/pystac/pull/1584))
6+
57
## [v1.14.1] - 2025-09-18
68

79
### Fixed

pystac/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
"set_stac_version",
4545
]
4646

47-
import os
4847
import warnings
4948
from typing import Any
5049

@@ -199,6 +198,8 @@ def write_file(
199198
"""
200199
if stac_io is None:
201200
stac_io = StacIO.default()
201+
import os
202+
202203
dest_href = None if dest_href is None else str(os.fspath(dest_href))
203204
obj.save_object(
204205
include_self_link=include_self_link, dest_href=dest_href, stac_io=stac_io

pystac/asset.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
from __future__ import annotations
22

3-
import os
43
import shutil
54
from copy import copy, deepcopy
6-
from html import escape
75
from typing import TYPE_CHECKING, Any, Protocol, TypeVar
86

97
from pystac import MediaType, STACError, common_metadata, utils
10-
from pystac.html.jinja_env import get_jinja_env
118
from pystac.utils import is_absolute_href, make_absolute_href, make_relative_href
129

1310
if TYPE_CHECKING:
@@ -182,6 +179,10 @@ def __repr__(self) -> str:
182179
return f"<Asset href={self.href}>"
183180

184181
def _repr_html_(self) -> str:
182+
from html import escape
183+
184+
from pystac.html.jinja_env import get_jinja_env
185+
185186
jinja_env = get_jinja_env()
186187
if jinja_env:
187188
template = jinja_env.get_template("JSON.jinja2")
@@ -259,6 +260,8 @@ def delete(self) -> None:
259260
260261
Does not modify the asset.
261262
"""
263+
import os
264+
262265
href = _absolute_href(self.href, self.owner, "delete")
263266
os.remove(href)
264267

pystac/catalog.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
from __future__ import annotations
22

33
import os
4-
import warnings
54
from collections.abc import Callable, Iterable, Iterator
65
from copy import deepcopy
7-
from itertools import chain
86
from typing import (
97
TYPE_CHECKING,
108
Any,
@@ -521,6 +519,8 @@ def get_item(self, id: str, recursive: bool = False) -> Item | None:
521519
Return:
522520
Item or None: The item with the given ID, or None if not found.
523521
"""
522+
import warnings
523+
524524
warnings.warn(
525525
"get_item is deprecated and will be removed in v2. "
526526
"Use next(self.get_items(id), None) instead",
@@ -549,6 +549,8 @@ def get_items(self, *ids: str, recursive: bool = False) -> Iterator[Item]:
549549
(if recursive) all catalogs or collections connected to this catalog
550550
through child links.
551551
"""
552+
from itertools import chain
553+
552554
items: Iterator[Item]
553555
if not recursive:
554556
items = map(
@@ -615,6 +617,9 @@ def get_all_items(self) -> Iterator[Item]:
615617
catalogs or collections connected to this catalog through
616618
child links.
617619
"""
620+
import warnings
621+
from itertools import chain
622+
618623
warnings.warn(
619624
"get_all_items is deprecated and will be removed in v2",
620625
DeprecationWarning,

pystac/collection.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import annotations
22

3-
import warnings
43
from collections.abc import Iterable, Sequence
54
from copy import deepcopy
65
from datetime import datetime, timezone
@@ -12,8 +11,6 @@
1211
cast,
1312
)
1413

15-
from dateutil import tz
16-
1714
import pystac
1815
from pystac import CatalogType, STACObjectType
1916
from pystac.asset import Asset, Assets
@@ -257,6 +254,8 @@ def from_dict(d: dict[str, Any]) -> TemporalExtent:
257254
parsed_intervals: list[list[datetime | None]] = []
258255
for i in d["interval"]:
259256
if isinstance(i, str):
257+
import warnings
258+
260259
# d["interval"] is a list of strings, so we correct the list and
261260
# try again
262261
# https://github.com/stac-utils/pystac/issues/1221
@@ -384,6 +383,8 @@ def from_items(
384383
Extent: An Extent that spatially and temporally covers all of the
385384
given items.
386385
"""
386+
from dateutil import tz
387+
387388
bounds_values: list[list[float]] = [
388389
[float("inf")],
389390
[float("inf")],
@@ -635,6 +636,8 @@ def from_dict(
635636
migrate: bool = True,
636637
preserve_dict: bool = True,
637638
) -> C:
639+
import warnings
640+
638641
from pystac.extensions.version import CollectionVersionExtension
639642

640643
if migrate:

pystac/extensions/eo.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from __future__ import annotations
44

5-
import warnings
65
from collections.abc import Iterable
76
from typing import (
87
Any,
@@ -386,6 +385,8 @@ def get_schema_uri(cls) -> str:
386385

387386
@classmethod
388387
def get_schema_uris(cls) -> list[str]:
388+
import warnings
389+
389390
warnings.warn(
390391
"get_schema_uris is deprecated and will be removed in v2",
391392
DeprecationWarning,

pystac/extensions/file.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from __future__ import annotations
44

5-
import warnings
65
from collections.abc import Iterable
76
from typing import Any, Generic, Literal, TypeVar, cast
87

@@ -370,6 +369,8 @@ def migrate(
370369
found_fields[asset_key] = values
371370

372371
if found_fields:
372+
import warnings
373+
373374
warnings.warn(
374375
f"Assets {list(found_fields.keys())} contain fields: "
375376
f"{list(set.union(*found_fields.values()))} which "

pystac/extensions/grid.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from __future__ import annotations
44

55
import re
6-
import warnings
76
from re import Pattern
87
from typing import Any, Literal
98

@@ -92,6 +91,8 @@ def get_schema_uri(cls) -> str:
9291

9392
@classmethod
9493
def get_schema_uris(cls) -> list[str]:
94+
import warnings
95+
9596
warnings.warn(
9697
"get_schema_uris is deprecated and will be removed in v2",
9798
DeprecationWarning,

pystac/extensions/item_assets.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from __future__ import annotations
44

5-
import warnings
65
from typing import Any, Literal
76

87
import pystac
@@ -27,6 +26,8 @@ class AssetDefinition(ItemAssetDefinition):
2726
"""
2827

2928
def __init__(cls, *args: Any, **kwargs: Any) -> None:
29+
import warnings
30+
3031
warnings.warn(
3132
(
3233
"``AssetDefinition`` is deprecated. "
@@ -49,6 +50,8 @@ class ItemAssetsExtension(ExtensionManagementMixin[pystac.Collection]):
4950
collection: pystac.Collection
5051

5152
def __init__(self, collection: pystac.Collection) -> None:
53+
import warnings
54+
5255
warnings.warn(
5356
(
5457
"The ``item_assets`` extension is deprecated. "

pystac/extensions/projection.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
from __future__ import annotations
44

5-
import json
6-
import warnings
75
from collections.abc import Iterable
86
from typing import (
97
Any,
@@ -223,6 +221,8 @@ def crs_string(self) -> str | None:
223221
elif self.wkt2:
224222
return self.wkt2
225223
elif self.projjson:
224+
import json
225+
226226
return json.dumps(self.projjson)
227227
else:
228228
return None
@@ -321,6 +321,8 @@ def get_schema_uri(cls) -> str:
321321

322322
@classmethod
323323
def get_schema_uris(cls) -> list[str]:
324+
import warnings
325+
324326
warnings.warn(
325327
"get_schema_uris is deprecated and will be removed in v2",
326328
DeprecationWarning,

0 commit comments

Comments
 (0)