示例#1
0
    def test_templates_item_start_datetime(self) -> None:
        year = 2020
        month = 11
        day = 3
        date = "2020-11-03"
        dt = datetime(year, month, day, 18, 30)

        template = LayoutTemplate("${year}/${month}/${day}/${date}/item.json")

        item = pystac.Item(
            "test",
            geometry=ARBITRARY_GEOM,
            bbox=ARBITRARY_BBOX,
            datetime=None,
            properties={
                "start_datetime": dt.isoformat(),
                "end_datetime": (dt + timedelta(days=1)).isoformat(),
            },
        )

        parts = template.get_template_values(item)

        self.assertEqual(set(parts), set(["year", "month", "day", "date"]))

        self.assertEqual(parts["year"], year)
        self.assertEqual(parts["month"], month)
        self.assertEqual(parts["day"], day)
        self.assertEqual(parts["date"], date)

        path = template.substitute(item)
        self.assertEqual(path, "2020/11/3/2020-11-03/item.json")
示例#2
0
    def test_nested_properties(self) -> None:
        dt = datetime(2020, 11, 3, 18, 30)

        template = LayoutTemplate(
            "${test.prop}/${ext:extra.test.prop}/item.json")

        item = pystac.Item(
            "test",
            geometry=ARBITRARY_GEOM,
            bbox=ARBITRARY_BBOX,
            datetime=dt,
            properties={"test": {
                "prop": 4326
            }},
            extra_fields={"ext:extra": {
                "test": {
                    "prop": 3857
                }
            }},
        )

        parts = template.get_template_values(item)

        self.assertEqual(set(parts), set(["test.prop", "ext:extra.test.prop"]))

        self.assertEqual(parts["test.prop"], 4326)
        self.assertEqual(parts["ext:extra.test.prop"], 3857)

        path = template.substitute(item)

        self.assertEqual(path, "4326/3857/item.json")
示例#3
0
    def test_defaults(self) -> None:
        template = LayoutTemplate("${doesnotexist}/collection.json",
                                  defaults={"doesnotexist": "yes"})

        catalog = TestCases.test_case_4().get_child("acc")
        assert catalog is not None
        catalog.extra_fields = {"one": "two"}
        path = template.substitute(catalog)

        self.assertEqual(path, "yes/collection.json")
示例#4
0
    def test_throws_for_no_collection(self) -> None:
        template = LayoutTemplate("${collection}/item.json")

        collection = TestCases.test_case_4().get_child("acc")
        assert collection is not None
        item = next(iter(collection.get_all_items()))
        item.set_collection(None)
        assert item.collection_id is None

        with self.assertRaises(TemplateError):
            template.get_template_values(item)
示例#5
0
    def test_templates_item_collection(self) -> None:
        template = LayoutTemplate("${collection}/item.json")

        collection = TestCases.test_case_4().get_child("acc")
        assert collection is not None
        item = next(iter(collection.get_all_items()))
        assert item.collection_id is not None

        parts = template.get_template_values(item)
        self.assertEqual(len(parts), 1)
        self.assertIn("collection", parts)
        self.assertEqual(parts["collection"], item.collection_id)

        path = template.substitute(item)
        self.assertEqual(path, "{}/item.json".format(item.collection_id))
示例#6
0
    def test_substitute_with_colon_properties(self) -> None:
        dt = datetime(2020, 11, 3, 18, 30)

        template = LayoutTemplate("${ext:prop}/item.json")

        item = pystac.Item(
            "test",
            geometry=ARBITRARY_GEOM,
            bbox=ARBITRARY_BBOX,
            datetime=dt,
            properties={"ext:prop": 1},
        )

        path = template.substitute(item)

        self.assertEqual(path, "1/item.json")
示例#7
0
    def generate_subcatalogs(self, template, defaults=None, **kwargs):
        """Walks through the catalog and generates subcatalogs
        for items based on the template string. See :class:`~pystac.layout.LayoutTemplate`
        for details on the construction of template strings. This template string
        will be applied to the items, and subcatalogs will be created that separate
        and organize the items based on template values.

        Args:
            template (str):   A template string that
                can be consumed by a :class:`~pystac.layout.LayoutTemplate`
            defaults (dict):  Default values for the template variables
                that will be used if the property cannot be found on
                the item.

        Returns:
            [catalog]: List of new catalogs created
        """
        result = []
        for child in self.get_children():
            result.extend(
                child.generate_subcatalogs(template, defaults=defaults))

        layout_template = LayoutTemplate(template, defaults=defaults)
        subcat_id_to_cat = {}
        items = list(self.get_items())
        for item in items:
            item_parts = layout_template.get_template_values(item)
            curr_parent = self
            for k, v in item_parts.items():
                subcat_id = '{}'.format(v)
                subcat = subcat_id_to_cat.get(subcat_id)
                if subcat is None:
                    subcat_desc = 'Catalog of items from {} with {} of {}'.format(
                        curr_parent.id, k, v)
                    subcat = pystac.Catalog(id=subcat_id,
                                            description=subcat_desc)
                    curr_parent.add_child(subcat)
                    subcat_id_to_cat[subcat_id] = subcat
                    result.append(subcat)
                curr_parent = subcat
            self.remove_item(item.id)
            curr_parent.add_item(item)

        return result
示例#8
0
    def test_docstring_examples(self) -> None:
        item = pystac.Item.from_file(
            TestCases.get_path("data-files/examples/1.0.0-beta.2/item-spec/"
                               "examples/landsat8-sample.json"))
        item.common_metadata.license = "CC-BY-3.0"
        # Uses the year, month and day of the item
        template1 = LayoutTemplate("${year}/${month}/${day}")
        path1 = template1.substitute(item)
        self.assertEqual(path1, "2014/6/2")

        # Uses a custom extension properties found on in the item properties.
        template2 = LayoutTemplate("${landsat:path}/${landsat:row}")
        path2 = template2.substitute(item)
        self.assertEqual(path2, "107/18")

        # Uses the collection ID and a common metadata property for an item.
        template3 = LayoutTemplate("${collection}/${common_metadata.license}")
        path3 = template3.substitute(item)
        self.assertEqual(path3, "landsat-8-l1/CC-BY-3.0")
示例#9
0
    def generate_subcatalogs(
        self,
        template: str,
        defaults: Optional[Dict[str, Any]] = None,
        parent_ids: Optional[List[str]] = None,
    ) -> List["Catalog"]:
        """Walks through the catalog and generates subcatalogs
        for items based on the template string.

        See :class:`~pystac.layout.LayoutTemplate`
        for details on the construction of template strings. This template string
        will be applied to the items, and subcatalogs will be created that separate
        and organize the items based on template values.

        Args:
            template :   A template string that
                can be consumed by a :class:`~pystac.layout.LayoutTemplate`
            defaults :  Default values for the template variables
                that will be used if the property cannot be found on
                the item.
            parent_ids : Optional list of the parent catalogs'
                identifiers. If the bottom-most subcatalogs already match the
                template, no subcatalog is added.

        Returns:
            [catalog]: List of new catalogs created
        """
        result: List[Catalog] = []
        parent_ids = parent_ids or list()
        parent_ids.append(self.id)
        for child in self.get_children():
            result.extend(
                child.generate_subcatalogs(
                    template, defaults=defaults, parent_ids=parent_ids.copy()
                )
            )

        layout_template = LayoutTemplate(template, defaults=defaults)

        keep_item_links: List[Link] = []
        item_links = [lk for lk in self.links if lk.rel == pystac.RelType.ITEM]
        for link in item_links:
            link.resolve_stac_object(root=self.get_root())
            item = cast(pystac.Item, link.target)
            subcat_ids = layout_template.substitute(item).split("/")
            id_iter = reversed(parent_ids)
            if all(
                ["{}".format(id) == next(id_iter, None) for id in reversed(subcat_ids)]
            ):
                # Skip items for which the sub-catalog structure already
                # matches the template. The list of parent IDs can include more
                # elements on the root side, so compare the reversed sequences.
                keep_item_links.append(link)
                continue
            curr_parent = self
            for subcat_id in subcat_ids:
                subcat = curr_parent.get_child(subcat_id)
                if subcat is None:
                    subcat_desc = "Catalog of items from {} with id {}".format(
                        curr_parent.id, subcat_id
                    )
                    subcat = pystac.Catalog(id=subcat_id, description=subcat_desc)
                    curr_parent.add_child(subcat)
                    result.append(subcat)
                curr_parent = subcat

            # resolve collection link so when added back points to correct location
            col_link = item.get_single_link(pystac.RelType.COLLECTION)
            if col_link is not None:
                col_link.resolve_stac_object()

            curr_parent.add_item(item)

        # keep only non-item links and item links that have not been moved elsewhere
        self.links = [
            lk for lk in self.links if lk.rel != pystac.RelType.ITEM
        ] + keep_item_links

        return result