Exemple #1
0
    def set_self_href(self, href):
        """Sets the absolute HREF that is represented by the ``rel == 'self'``
        :class:`~pystac.Link`.

        Changing the self HREF of the item will ensure that all asset HREFs
        remain valid. If asset HREFs are relative, the HREFs will change
        to point to the same location based on the new item self HREF,
        either by making them relative to the new location or making them
        absolute links if the new location does not share the same protocol
        as the old location.

        Args:
            href (str): The absolute HREF of this object. If the given HREF
                is not absolute, it will be transformed to an absolute
                HREF based on the current working directory. If this is None
                the call will clear the self HREF link.
        """
        prev_href = self.get_self_href()
        super().set_self_href(href)
        new_href = self.get_self_href()  # May have been made absolute.

        if prev_href is not None:
            # Make sure relative asset links remain valid.
            for asset in self.assets.values():
                asset_href = asset.href
                if not is_absolute_href(asset_href):
                    abs_href = make_absolute_href(asset_href, prev_href)
                    new_relative_href = make_relative_href(abs_href, new_href)
                    asset.href = new_relative_href
Exemple #2
0
    def test_make_relative_href_windows(self):
        utils._pathlib = ntpath
        try:
            # Test cases of (source_href, start_href, expected)
            test_cases = [
                ('C:\\a\\b\\c\\d\\catalog.json', 'C:\\a\\b\\c\\catalog.json', '.\\d\\catalog.json'),
                ('C:\\a\\b\\catalog.json', 'C:\\a\\b\\c\\catalog.json', '..\\catalog.json'),
                ('C:\\a\\catalog.json', 'C:\\a\\b\\c\\catalog.json', '..\\..\\catalog.json'),
                ('a\\b\\c\\catalog.json', 'a\\b\\catalog.json', '.\\c\\catalog.json'),
                ('a\\b\\catalog.json', 'a\\b\\c\\catalog.json', '..\\catalog.json'),
                ('http://stacspec.org/a/b/c/d/catalog.json',
                 'http://stacspec.org/a/b/c/catalog.json', './d/catalog.json'),
                ('http://stacspec.org/a/b/catalog.json', 'http://stacspec.org/a/b/c/catalog.json',
                 '../catalog.json'),
                ('http://stacspec.org/a/catalog.json', 'http://stacspec.org/a/b/c/catalog.json',
                 '../../catalog.json'),
                ('http://stacspec.org/a/catalog.json', 'http://cogeo.org/a/b/c/catalog.json',
                 'http://stacspec.org/a/catalog.json'),
                ('http://stacspec.org/a/catalog.json', 'https://stacspec.org/a/b/c/catalog.json',
                 'http://stacspec.org/a/catalog.json')
            ]

            for source_href, start_href, expected in test_cases:
                actual = make_relative_href(source_href, start_href)
                self.assertEqual(actual, expected)
        finally:
            utils._pathlib = os.path
Exemple #3
0
def merge_items(source_item: pystac.Item,
                target_item: pystac.Item,
                move_assets: bool = False,
                ignore_conflicts: bool = False) -> None:
    """Merges the assets from source_item into target_item.

    The geometry and bounding box of the items will also be merged.

    Args:
        source_item (pystac.Item): The Item that will be merged into target_item.
            This item is not mutated in this operation.
        target_item (pystac.Item): The target item that will be merged into.
            This item will be mutated in this operation.
        move_assets (bool): If true, move the asset files alongside the target item.
        ignore_conflicts (bool): If True, assets with the same keys will not be merged,
            and asset files that would be moved to overwrite an existing file
            will not be moved. If False, either of these situations will throw an error.
    """
    target_item_href = target_item.get_self_href()
    if target_item_href is None:
        raise ValueError(
            f"Target Item {target_item.id} must have an HREF for merge")
    for key, asset in source_item.assets.items():
        if key in target_item.assets:
            if ignore_conflicts:
                continue
            else:
                raise Exception(
                    'Target item {} already has asset with key {}, '
                    'cannot merge asset in from {}'.format(
                        target_item, key, source_item))
        else:
            asset_href = asset.get_absolute_href()
            if asset_href is None:
                raise ValueError(
                    f"Asset {asset.title} must have an HREF for merge")
            if move_assets:
                new_asset_href = move_asset_file_to_item(
                    target_item, asset_href, ignore_conflicts=ignore_conflicts)
            else:
                if not is_absolute_href(asset.href):
                    asset_href = make_relative_href(asset_href,
                                                    target_item_href)
                new_asset_href = asset_href
            new_asset = asset.clone()
            new_asset.href = new_asset_href
            target_item.add_asset(key, new_asset)

    source_geom = shape(source_item.geometry)
    target_geom = shape(target_item.geometry)
    union_geom = source_geom.union(target_geom).buffer(0)
    target_item.geometry = mapping(union_geom)
    target_item.bbox = list(union_geom.bounds)
Exemple #4
0
    def make_asset_hrefs_relative(self):
        """Modify each asset's HREF to be relative to this item's self HREF.

        Returns:
            Item: self
        """
        self_href = self.get_self_href()
        if self_href is None:
            raise STACError('Cannot make asset HREFs relative if no self_href is set.')
        for asset in self.assets.values():
            asset.href = make_relative_href(asset.href, self_href)
        return self
Exemple #5
0
    def test_make_relative_href(self) -> None:
        # Test cases of (source_href, start_href, expected)
        test_cases = [
            ("/a/b/c/d/catalog.json", "/a/b/c/catalog.json",
             "./d/catalog.json"),
            ("/a/b/catalog.json", "/a/b/c/catalog.json", "../catalog.json"),
            ("/a/catalog.json", "/a/b/c/catalog.json", "../../catalog.json"),
            ("/a/b/c/d/", "/a/b/c/catalog.json", "./d/"),
            ("/a/b/c/d/.dotfile", "/a/b/c/d/catalog.json", "./.dotfile"),
        ]

        for source_href, start_href, expected in test_cases:
            actual = make_relative_href(source_href, start_href)
            self.assertEqual(actual, expected)
Exemple #6
0
def move_assets(item: Item,
                asset_subdirectory: Optional[str] = None,
                make_hrefs_relative: bool = True,
                copy: bool = False,
                ignore_conflicts: bool = False) -> Item:
    """Moves assets for an item to be alongside that item.

    Args:
        item (Item): The PySTAC Item
            to perform the asset transformation on.
        asset_subdirectory (str or None): A subdirectory that will be used
            to store the assets. If not supplied, the assets will be moved
            or copied to the same directory as their item.
        make_assets_relative (bool): If True, will make the asset HREFs relative
            to the assets. If false, the asset will be an absolute href.
        copy (bool): If False this function will move the asset file; if True,
            the asset file will be copied.
        ignore_conflicts (bool): If the asset destination file already exists,
            this function will throw an error unless ignore_conflicts is True.

    Returns:
        Item: Returns an updated catalog or collection.
            This operation mutates the Item.
    """
    item_href = item.get_self_href()
    if item_href is None:
        raise ValueError(
            f"Self HREF is not available for item {item.id}. This operation "
            "requires that the Item HREFs are available.")

    for asset in item.assets.values():
        abs_asset_href = asset.get_absolute_href()
        if abs_asset_href is None:
            raise ValueError(
                f"Asset {asset.title} HREF is not available for item {item.id}. This operation "
                "requires that the Asset HREFs are available.")

        new_asset_href = move_asset_file_to_item(
            item,
            abs_asset_href,
            asset_subdirectory=asset_subdirectory,
            copy=copy,
            ignore_conflicts=ignore_conflicts)

        if make_hrefs_relative:
            asset.href = make_relative_href(new_asset_href, item_href)
        else:
            asset.href = new_asset_href

    return item
Exemple #7
0
    def normalize_hrefs(self, root_href):
        if not is_absolute_href(root_href):
            root_href = make_absolute_href(root_href, os.getcwd(), start_is_dir=True)

        old_self_href = self.get_self_href()
        new_self_href = os.path.join(root_href, '{}.json'.format(self.id))
        self.set_self_href(new_self_href)

        # Make sure relative asset links remain valid.
        # This will only work if there is a self href set.
        for asset in self.assets.values():
            asset_href = asset.href
            if not is_absolute_href(asset_href):
                if old_self_href is not None:
                    abs_href = make_absolute_href(asset_href, old_self_href)
                    new_relative_href = make_relative_href(abs_href, new_self_href)
                    asset.href = new_relative_href
Exemple #8
0
    def make_asset_hrefs_relative(self) -> "Item":
        """Modify each asset's HREF to be relative to this item's self HREF.

        Returns:
            Item: self
        """

        self_href = None
        for asset in self.assets.values():
            href = asset.href
            if is_absolute_href(href):
                if self_href is None:
                    self_href = self.get_self_href()
                    if self_href is None:
                        raise STACError("Cannot make asset HREFs relative "
                                        "if no self_href is set.")
                asset.href = make_relative_href(asset.href, self_href)
        return self
Exemple #9
0
    def test_make_relative_href_url(self) -> None:

        test_cases = [
            (
                "http://stacspec.org/a/b/c/d/catalog.json",
                "http://stacspec.org/a/b/c/catalog.json",
                "./d/catalog.json",
            ),
            (
                "http://stacspec.org/a/b/catalog.json",
                "http://stacspec.org/a/b/c/catalog.json",
                "../catalog.json",
            ),
            (
                "http://stacspec.org/a/catalog.json",
                "http://stacspec.org/a/b/c/catalog.json",
                "../../catalog.json",
            ),
            (
                "http://stacspec.org/a/catalog.json",
                "http://cogeo.org/a/b/c/catalog.json",
                "http://stacspec.org/a/catalog.json",
            ),
            (
                "http://stacspec.org/a/catalog.json",
                "https://stacspec.org/a/b/c/catalog.json",
                "http://stacspec.org/a/catalog.json",
            ),
            (
                "http://stacspec.org/a/",
                "https://stacspec.org/a/b/c/catalog.json",
                "http://stacspec.org/a/",
            ),
            (
                "http://stacspec.org/a/b/.dotfile",
                "http://stacspec.org/a/b/catalog.json",
                "./.dotfile",
            ),
        ]

        for source_href, start_href, expected in test_cases:
            actual = make_relative_href(source_href, start_href)
            self.assertEqual(actual, expected)
Exemple #10
0
    def get_href(self):
        """Gets the HREF for this link.

        Returns:
            str: Returns this link's HREF. If the link type is LinkType.RELATIVE,
            and there is an owner of the link, then the HREF returned will be
            relative. In all other cases, this method will return an absolute HREF.
        """
        if self.link_type == LinkType.RELATIVE:
            if self.is_resolved():
                href = self.target.get_self_href()
            else:
                href = self.target

            if href and is_absolute_href(href) and self.owner is not None:
                href = make_relative_href(href, self.owner.get_self_href())
        else:
            href = self.get_absolute_href()

        return href
Exemple #11
0
    def test_make_relative_href(self):
        # Test cases of (source_href, start_href, expected)
        test_cases = [
            ('/a/b/c/d/catalog.json', '/a/b/c/catalog.json', './d/catalog.json'),
            ('/a/b/catalog.json', '/a/b/c/catalog.json', '../catalog.json'),
            ('/a/catalog.json', '/a/b/c/catalog.json', '../../catalog.json'),
            ('http://stacspec.org/a/b/c/d/catalog.json', 'http://stacspec.org/a/b/c/catalog.json',
             './d/catalog.json'),
            ('http://stacspec.org/a/b/catalog.json', 'http://stacspec.org/a/b/c/catalog.json',
             '../catalog.json'),
            ('http://stacspec.org/a/catalog.json', 'http://stacspec.org/a/b/c/catalog.json',
             '../../catalog.json'),
            ('http://stacspec.org/a/catalog.json', 'http://cogeo.org/a/b/c/catalog.json',
             'http://stacspec.org/a/catalog.json'),
            ('http://stacspec.org/a/catalog.json', 'https://stacspec.org/a/b/c/catalog.json',
             'http://stacspec.org/a/catalog.json')
        ]

        for source_href, start_href, expected in test_cases:
            actual = make_relative_href(source_href, start_href)
            self.assertEqual(actual, expected)
Exemple #12
0
    def get_href(self, transform_href: bool = True) -> Optional[str]:
        """Gets the HREF for this link.

        Args:
            transform_href: If True, transform the HREF based on the type of
                catalog the owner belongs to (if any). I.e. if the link owner
                belongs to a root catalog that is RELATIVE_PUBLISHED or SELF_CONTAINED,
                the HREF will be transformed to be relative to the catalog root
                if this is a hierarchical link relation.

        Returns:
            str: Returns this link's HREF. If there is an owner of the link and
            the root catalog (if there is one) is of type RELATIVE_PUBLISHED,
            then the HREF returned will be relative.
            In all other cases, this method will return an absolute HREF.
        """
        # get the self href
        if self._target_object:
            href = self._target_object.get_self_href()
        else:
            href = self._target_href

        if (transform_href and href and is_absolute_href(href) and self.owner
                and self.owner.get_root()):
            root = self.owner.get_root()
            rel_links = [
                *HIERARCHICAL_LINKS,
                *pystac.EXTENSION_HOOKS.get_extended_object_links(self.owner),
            ]
            # if a hierarchical link with an owner and root, and relative catalog
            if root and root.is_relative() and self.rel in rel_links:
                owner_href = self.owner.get_self_href()
                if owner_href is not None:
                    href = make_relative_href(href, owner_href)

        return href
Exemple #13
0
    def save(
        self,
        catalog_type: Optional[CatalogType] = None,
        dest_href: Optional[str] = None,
        stac_io: Optional[pystac.StacIO] = None,
    ) -> None:
        """Save this catalog and all it's children/item to files determined by the
        object's self link HREF or a specified path.

        Args:
            catalog_type : The catalog type that dictates the structure of
                the catalog to save. Use a member of :class:`~pystac.CatalogType`.
                If not supplied, the catalog_type of this catalog will be used.
                If that attribute is not set, an exception will be raised.
            dest_href : The location where the catalog is to be saved.
                If not supplied, the catalog's self link HREF is used to determine
                the location of the catalog file and children's files.
            stac_io : Optional instance of :class:`~pystac.StacIO` to use. If not
                provided, will use the instance set while reading in the catalog,
                or the default instance if this is not available.
        Note:
            If the catalog type is ``CatalogType.ABSOLUTE_PUBLISHED``,
            all self links will be included, and hierarchical links be absolute URLs.
            If the catalog type is ``CatalogType.RELATIVE_PUBLISHED``, this catalog's
            self link will be included, but no child catalog will have self links, and
            hierarchical links will be relative URLs
            If the catalog  type is ``CatalogType.SELF_CONTAINED``, no self links will
            be included and hierarchical links will be relative URLs.
        """

        root = self.get_root()
        if root is None:
            raise Exception("There is no root catalog")

        if catalog_type is not None:
            root.catalog_type = catalog_type

        items_include_self_link = root.catalog_type in [CatalogType.ABSOLUTE_PUBLISHED]

        for child_link in self.get_child_links():
            if child_link.is_resolved():
                child = cast(Catalog, child_link.target)
                if dest_href is not None:
                    rel_href = make_relative_href(child.self_href, self.self_href)
                    child_dest_href = make_absolute_href(
                        rel_href, dest_href, start_is_dir=True
                    )
                    child.save(
                        dest_href=os.path.dirname(child_dest_href),
                        stac_io=stac_io,
                    )
                else:
                    child.save(stac_io=stac_io)

        for item_link in self.get_item_links():
            if item_link.is_resolved():
                item = cast(pystac.Item, item_link.target)
                if dest_href is not None:
                    rel_href = make_relative_href(item.self_href, self.self_href)
                    item_dest_href = make_absolute_href(
                        rel_href, dest_href, start_is_dir=True
                    )
                    item.save_object(
                        include_self_link=items_include_self_link,
                        dest_href=item_dest_href,
                        stac_io=stac_io,
                    )
                else:
                    item.save_object(
                        include_self_link=items_include_self_link, stac_io=stac_io
                    )

        include_self_link = False
        # include a self link if this is the root catalog
        # or if ABSOLUTE_PUBLISHED catalog
        if root.catalog_type == CatalogType.ABSOLUTE_PUBLISHED:
            include_self_link = True
        elif root.catalog_type != CatalogType.SELF_CONTAINED:
            root_link = self.get_root_link()
            if root_link and root_link.get_absolute_href() == self.get_self_href():
                include_self_link = True

        catalog_dest_href = None
        if dest_href is not None:
            rel_href = make_relative_href(self.self_href, self.self_href)
            catalog_dest_href = make_absolute_href(
                rel_href, dest_href, start_is_dir=True
            )
        self.save_object(
            include_self_link=include_self_link,
            dest_href=catalog_dest_href,
            stac_io=stac_io,
        )
        if catalog_type is not None:
            self.catalog_type = catalog_type