Skip to content

Container

pystac.Container

Bases: STACObject

Base class for Catalog and Collection.

While collections are very similar to catalogs, they technically are to distinct data structures. To reflect that in code, Collection does not inherit from Catalog. Instead, they both inherit from this Container class, which doesn't exist in the STAC spec but provides us a useful place to store shared behavior.

Source code in src/pystac/container.py
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
class Container(STACObject):
    """Base class for [Catalog][pystac.Catalog] and [Collection][pystac.Collection].

    While collections are very similar to catalogs, they _technically_ are to
    distinct data structures. To reflect that in code, `Collection` does not
    inherit from `Catalog`. Instead, they both inherit from this `Container`
    class, which doesn't exist in the STAC spec but provides us a useful place
    to store shared behavior.
    """

    def set_stac_version(self, version: str) -> None:
        """Sets the STAC version for this object and all of its children and items.

        Args:
            version: The STAC version
        """
        for root, _, items in self.walk():
            root.stac_version = version
            for item in items:
                item.stac_version = version

    def walk(self) -> Iterator[tuple[Container, list[Container], list[Item]]]:
        """Walks this container, yielding a tuple of this container, its
        children, and its items.

        This works a bit like `os.walk`, but for STAC.

        Returns:
            An iterator over a container, its children, and its items.

        Examples:
            >>> for root, children, items in catalog.walk():
            ...     print(root, children, items)
        """
        children: list[Container] = []
        items: list[Item] = []
        for link in self.iter_links(CHILD, ITEM):
            stac_object = link.get_stac_object()
            if isinstance(stac_object, Container):
                children.append(stac_object)
            if isinstance(stac_object, Item):
                items.append(stac_object)
        yield self, children, items
        for child in children:
            yield from child.walk()

    def add_item(self, item: Item) -> None:
        """Adds an item to this container."""
        self.add_link(Link.item(item))

    def get_items(self, recursive: bool = False) -> Iterator[Item]:
        """Iterates over all items in this container.

        Args:
            recursive: If true, include all items belonging to children as well.
        """
        for link in self.iter_links():
            if link.is_item():
                stac_object = link.get_stac_object()
                if isinstance(stac_object, Item):
                    yield stac_object
            if recursive and link.is_child():
                child = link.get_stac_object()
                if isinstance(child, Container):
                    yield from child.get_items(recursive=recursive)

    def add_child(self, child: Container) -> None:
        """Adds a child to this container."""
        self.add_link(Link.child(child))

    def get_child(
        self, id: str, recursive: bool = False, sort_links_by_id: bool = True
    ) -> Container | None:
        # TODO handle sort links by id
        for child in self.get_children(recursive=recursive):
            if child.id == id:
                return child
        return None

    def get_children(self, recursive: bool = False) -> Iterator[Container]:
        """Iterates over all children in this container.

        Args:
            recursive: If true, include all children's children, and so on.
        """
        for link in filter(lambda link: link.is_child(), self.iter_links()):
            stac_object = link.get_stac_object()
            if isinstance(stac_object, Container):
                yield stac_object
                if recursive:
                    yield from stac_object.get_children(recursive=recursive)

    def get_children_and_items(self) -> Iterator[STACObject]:
        """Iterates over all children and items in this container.

        If you'd like to do recursive iteration over all children and items, use
        [walk][pystac.Container.walk].
        """
        for link in filter(
            lambda link: link.is_child() or link.is_item(), self.iter_links()
        ):
            yield link.get_stac_object()

    def get_collections(self, recursive: bool = False) -> Iterator[Collection]:
        """Iterates over all collections in this container.

        Args:
            recursive: If true, include all children's collections, and so on.
        """
        from .collection import Collection

        for link in filter(lambda link: link.is_child(), self.iter_links()):
            stac_object = link.get_stac_object()
            if isinstance(stac_object, Collection):
                yield stac_object
            if recursive and isinstance(stac_object, Container):
                yield from stac_object.get_collections(recursive=recursive)

    def save(
        self,
        catalog_type: Any = None,
        dest_href: str | Path | None = None,
        stac_io: Any = None,
        *,
        writer: Write | None = None,
    ) -> None:
        if catalog_type:
            deprecate.argument("catalog_type")
        if dest_href:
            deprecate.argument("dest_href")
        if stac_io:
            deprecate.argument("stac_io")
        if writer is None:
            writer = self.writer

        self.save_object(stac_io=stac_io, writer=writer)
        for stac_object in self.get_children_and_items():
            if isinstance(stac_object, Container):
                stac_object.save(
                    writer=writer
                )  # TODO do we need to pass through any of the deprecated arguments?
            else:
                stac_object.save_object(writer=writer)

    @deprecate.function("Use render() and then save()")
    def normalize_and_save(
        self,
        root_href: str,
        catalog_type: Any = None,
        strategy: Any = None,
        stac_io: Any = None,
        skip_unresolved: bool = False,
    ) -> None:
        self.render(root_href)
        self.save()

add_child

add_child(child: Container) -> None

Adds a child to this container.

Source code in src/pystac/container.py
83
84
85
def add_child(self, child: Container) -> None:
    """Adds a child to this container."""
    self.add_link(Link.child(child))

add_item

add_item(item: Item) -> None

Adds an item to this container.

Source code in src/pystac/container.py
63
64
65
def add_item(self, item: Item) -> None:
    """Adds an item to this container."""
    self.add_link(Link.item(item))

get_children

get_children(
    recursive: bool = False,
) -> Iterator[Container]

Iterates over all children in this container.

Parameters:

Name Type Description Default
recursive bool

If true, include all children's children, and so on.

False
Source code in src/pystac/container.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
def get_children(self, recursive: bool = False) -> Iterator[Container]:
    """Iterates over all children in this container.

    Args:
        recursive: If true, include all children's children, and so on.
    """
    for link in filter(lambda link: link.is_child(), self.iter_links()):
        stac_object = link.get_stac_object()
        if isinstance(stac_object, Container):
            yield stac_object
            if recursive:
                yield from stac_object.get_children(recursive=recursive)

get_children_and_items

get_children_and_items() -> Iterator[STACObject]

Iterates over all children and items in this container.

If you'd like to do recursive iteration over all children and items, use walk.

Source code in src/pystac/container.py
109
110
111
112
113
114
115
116
117
118
def get_children_and_items(self) -> Iterator[STACObject]:
    """Iterates over all children and items in this container.

    If you'd like to do recursive iteration over all children and items, use
    [walk][pystac.Container.walk].
    """
    for link in filter(
        lambda link: link.is_child() or link.is_item(), self.iter_links()
    ):
        yield link.get_stac_object()

get_collections

get_collections(
    recursive: bool = False,
) -> Iterator[Collection]

Iterates over all collections in this container.

Parameters:

Name Type Description Default
recursive bool

If true, include all children's collections, and so on.

False
Source code in src/pystac/container.py
120
121
122
123
124
125
126
127
128
129
130
131
132
133
def get_collections(self, recursive: bool = False) -> Iterator[Collection]:
    """Iterates over all collections in this container.

    Args:
        recursive: If true, include all children's collections, and so on.
    """
    from .collection import Collection

    for link in filter(lambda link: link.is_child(), self.iter_links()):
        stac_object = link.get_stac_object()
        if isinstance(stac_object, Collection):
            yield stac_object
        if recursive and isinstance(stac_object, Container):
            yield from stac_object.get_collections(recursive=recursive)

get_items

get_items(recursive: bool = False) -> Iterator[Item]

Iterates over all items in this container.

Parameters:

Name Type Description Default
recursive bool

If true, include all items belonging to children as well.

False
Source code in src/pystac/container.py
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
def get_items(self, recursive: bool = False) -> Iterator[Item]:
    """Iterates over all items in this container.

    Args:
        recursive: If true, include all items belonging to children as well.
    """
    for link in self.iter_links():
        if link.is_item():
            stac_object = link.get_stac_object()
            if isinstance(stac_object, Item):
                yield stac_object
        if recursive and link.is_child():
            child = link.get_stac_object()
            if isinstance(child, Container):
                yield from child.get_items(recursive=recursive)

set_stac_version

set_stac_version(version: str) -> None

Sets the STAC version for this object and all of its children and items.

Parameters:

Name Type Description Default
version str

The STAC version

required
Source code in src/pystac/container.py
27
28
29
30
31
32
33
34
35
36
def set_stac_version(self, version: str) -> None:
    """Sets the STAC version for this object and all of its children and items.

    Args:
        version: The STAC version
    """
    for root, _, items in self.walk():
        root.stac_version = version
        for item in items:
            item.stac_version = version

walk

walk() -> Iterator[
    tuple[Container, list[Container], list[Item]]
]

Walks this container, yielding a tuple of this container, its children, and its items.

This works a bit like os.walk, but for STAC.

Returns:

Type Description
Iterator[tuple[Container, list[Container], list[Item]]]

An iterator over a container, its children, and its items.

Examples:

>>> for root, children, items in catalog.walk():
...     print(root, children, items)
Source code in src/pystac/container.py
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
def walk(self) -> Iterator[tuple[Container, list[Container], list[Item]]]:
    """Walks this container, yielding a tuple of this container, its
    children, and its items.

    This works a bit like `os.walk`, but for STAC.

    Returns:
        An iterator over a container, its children, and its items.

    Examples:
        >>> for root, children, items in catalog.walk():
        ...     print(root, children, items)
    """
    children: list[Container] = []
    items: list[Item] = []
    for link in self.iter_links(CHILD, ITEM):
        stac_object = link.get_stac_object()
        if isinstance(stac_object, Container):
            children.append(stac_object)
        if isinstance(stac_object, Item):
            items.append(stac_object)
    yield self, children, items
    for child in children:
        yield from child.walk()