Skip to content

Commit 3645114

Browse files
Merge pull request #290 from matthewhanson/remove_link_type
Remove link type
2 parents e0768a8 + e18d4de commit 3645114

18 files changed

+115
-342
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,21 @@
44

55
### Added
66

7+
- HIERARCHICAL_LINKS array constant of all the types of hierarchical links (self is not included)
8+
79
### Fixed
810

911
- Fixed error when accessing the statistics attribute of the pointcloud extension when no statistics were defined ([#282](https://github.com/stac-utils/pystac/pull/282))
1012
- Fixed exception being thrown when calling set_self_href on items with assets that have relative hrefs ([#291](https://github.com/stac-utils/pystac/pull/291))
1113

1214
### Changed
1315

16+
- Link behavior - link URLs can be either relative or absolute. Hierarchical (e.g., parent, child) links are made relative or absolute based on the value of the root catalog's `catalog_type` field
17+
1418
### Removed
1519

20+
- Removed LinkType class and the `link_type` field from links
21+
1622
## [v0.5.5]
1723

1824
### Added

docs/concepts.rst

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,17 @@ Relative vs Absolute Link HREFs
155155

156156
Absolute links point to their file locations in a fully described way. Relative links
157157
are relative to the linking object's file location. For example, if a catalog at
158-
``/some/location/catalog.json`` has a link to an item that has an HREF set to ``item-id/item-id.json``, then that link should resolve to the absolute path ``/some/location/item-id/item-id.json``.
158+
``/some/location/catalog.json`` has a link to an item that has an HREF set to ``item-id/item-id.json``,
159+
then that link should resolve to the absolute path ``/some/location/item-id/item-id.json``.
159160

160-
The implementation of :class:`~pystac.Link` in PySTAC allows for the link to be marked as
161-
``link_type=LinkType.ABSOLUTE`` or ``link_type=LinkType.RELATIVE``. This means that,
162-
even if the stored HREF of the link is absolute, if the link is marked as relative, serializing
163-
the link will produce a relative link, based on the self link of the parent object.
161+
Links are set as absolute or relative HREFs at save time, as determine by the root catalog's catalog_type
162+
:attribute:`~pystac.Catalog.catalog_type`. This means that, even if the stored HREF of the link is absolute,
163+
if the root ``catalog_type=CatalogType.RELATIVE_PUBLISHED`` or ``catalog_type=CatalogType.SELF_CONTAINED``
164+
and subsequent serializing of the any links in the catalog will produce a relative link,
165+
based on the self link of the parent object.
164166

165-
You can make all the links of a catalog relative or absolute using the :func:`Catalog.make_all_links_relative <pystac.Catalog.make_all_links_relative>` and :func:`Catalog.make_all_links_absolute <pystac.Catalog.make_all_links_absolute>` methods.
167+
You can make all the links of a catalog relative or absolute by setting the :func:`Catalog.catalog_type` field
168+
then resaving the entire catalog.
166169

167170
.. _rel vs abs asset:
168171

docs/tutorials/adding-new-and-custom-extensions.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@
181181
"source": [
182182
"The `from_item` class method simply returns a new instance of the item extension given an item.\n",
183183
"\n",
184-
"The `_object_links` class method returns the `rel` string for any links that point to STAC objects like Catalogs, Collections or Items. PySTAC needs to know which links point to STAC objects because it needs to consider them when fully resolving a STAC into in-memory objects. In a lot of cases, extensions don't add new links to STAC objects, so this is normally an empty list; however, if the extension does do this (like the `source` link in the [Label Extension](https://github.com/radiantearth/stac-spec/tree/v1.0.0-beta.2/extensions/label#links-source-imagery)), make sure to return the correct value (like the LabelItemExt is doing [here](https://github.com/azavea/pystac/blob/v0.5.0/pystac/extensions/label.py#L291-L293))."
184+
"The `_object_links` class method returns the `rel` string for any links that point to STAC objects like Catalogs, Collections or Items. PySTAC needs to know which links point to STAC objects because it needs to consider them when fully resolving a STAC into in-memory objects. It also will use this information when deciding on whether to use absolute or relative HREFs for the links, based on the root catalog type. In a lot of cases, extensions don't add new links to STAC objects, so this is normally an empty list; however, if the extension does do this (like the `source` link in the [Label Extension](https://github.com/radiantearth/stac-spec/tree/v1.0.0-beta.2/extensions/label#links-source-imagery)), make sure to return the correct value (like the LabelItemExt is doing [here](https://github.com/azavea/pystac/blob/v0.5.0/pystac/extensions/label.py#L291-L293))."
185185
]
186186
},
187187
{
@@ -539,4 +539,4 @@
539539
},
540540
"nbformat": 4,
541541
"nbformat_minor": 2
542-
}
542+
}

pystac/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class STACError(Exception):
1818
from pystac.extensions import Extensions
1919
from pystac.stac_object import (STACObject, STACObjectType)
2020
from pystac.media_type import MediaType
21-
from pystac.link import (Link, LinkType)
21+
from pystac.link import (Link, HIERARCHICAL_LINKS)
2222
from pystac.catalog import (Catalog, CatalogType)
2323
from pystac.collection import (Collection, Extent, SpatialExtent, TemporalExtent, Provider)
2424
from pystac.item import (Item, Asset, CommonMetadata)

pystac/catalog.py

Lines changed: 29 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from pystac import STACError
77
from pystac.stac_object import STACObject
88
from pystac.layout import (BestPracticesLayoutStrategy, LayoutTemplate)
9-
from pystac.link import (Link, LinkType)
9+
from pystac.link import Link
1010
from pystac.cache import ResolvedObjectCache
1111
from pystac.utils import (is_absolute_href, make_absolute_href)
1212

@@ -117,7 +117,7 @@ def __init__(self,
117117
stac_extensions=None,
118118
extra_fields=None,
119119
href=None,
120-
catalog_type=None):
120+
catalog_type=CatalogType.ABSOLUTE_PUBLISHED):
121121
super().__init__(stac_extensions)
122122

123123
self.id = id
@@ -142,12 +142,15 @@ def __init__(self,
142142
def __repr__(self):
143143
return '<Catalog id={}>'.format(self.id)
144144

145-
def set_root(self, root, link_type=LinkType.ABSOLUTE):
146-
STACObject.set_root(self, root, link_type)
145+
def set_root(self, root):
146+
STACObject.set_root(self, root)
147147
if root is not None:
148148
root._resolved_objects = ResolvedObjectCache.merge(root._resolved_objects,
149149
self._resolved_objects)
150150

151+
def is_relative(self):
152+
return self.catalog_type in [CatalogType.RELATIVE_PUBLISHED, CatalogType.SELF_CONTAINED]
153+
151154
def add_child(self, child, title=None):
152155
"""Adds a link to a child :class:`~pystac.Catalog` or :class:`~pystac.Collection`.
153156
This method will set the child's parent to this object, and its root to
@@ -405,28 +408,6 @@ def clone(self):
405408

406409
return clone
407410

408-
def make_all_links_relative(self):
409-
"""Makes all the links of this catalog and all children and item
410-
to be relative, recursively
411-
"""
412-
super().make_links_relative()
413-
414-
for child in self.get_children():
415-
child.make_all_links_relative()
416-
for item in self.get_items():
417-
item.make_links_relative()
418-
419-
def make_all_links_absolute(self):
420-
"""Makes all the links of this catalog and all children and item
421-
to be absolute, recursively
422-
"""
423-
super().make_links_absolute()
424-
425-
for child in self.get_children():
426-
child.make_all_links_absolute()
427-
for item in self.get_items():
428-
item.make_links_absolute()
429-
430411
def make_all_asset_hrefs_relative(self):
431412
"""Makes all the HREFs of assets belonging to items in this catalog
432413
and all children to be relative, recursively.
@@ -443,9 +424,8 @@ def make_all_asset_hrefs_absolute(self):
443424
for item in items:
444425
item.make_asset_hrefs_absolute()
445426

446-
def normalize_and_save(self, root_href, catalog_type, strategy=None):
447-
"""Normalizes link HREFs to the given root_href, and saves
448-
the catalog with the given catalog_type.
427+
def normalize_and_save(self, root_href, catalog_type=None, strategy=None):
428+
"""Normalizes link HREFs to the given root_href, and saves the catalog.
449429
450430
This is a convenience method that simply calls :func:`Catalog.normalize_hrefs
451431
<pystac.Catalog.normalize_hrefs>` and :func:`Catalog.save <pystac.Catalog.save>`
@@ -455,6 +435,8 @@ def normalize_and_save(self, root_href, catalog_type, strategy=None):
455435
root_href (str): The absolute HREF that all links will be normalized against.
456436
catalog_type (str): The catalog type that dictates the structure of
457437
the catalog to save. Use a member of :class:`~pystac.CatalogType`.
438+
Defaults to the root catalog.catalog_type or the current catalog catalog_type
439+
if there is no root catalog.
458440
strategy (HrefLayoutStrategy): The layout strategy to use in setting the HREFS
459441
for this catalog. Defaults to :class:`~pystac.layout.BestPracticesLayoutStrategy`
460442
"""
@@ -593,51 +575,37 @@ def save(self, catalog_type=None):
593575
594576
Note:
595577
If the catalog type is ``CatalogType.ABSOLUTE_PUBLISHED``,
596-
all self links will be included, and link type will be set to ABSOLUTE.
578+
all self links will be included, and hierarchical links be absolute URLs.
597579
If the catalog type is ``CatalogType.RELATIVE_PUBLISHED``, this catalog's self
598-
link will be included, but no child catalog will have self links.
599-
Link types will be set to RELATIVE.
580+
link will be included, but no child catalog will have self links, and
581+
hierarchical links will be relative URLs
600582
If the catalog type is ``CatalogType.SELF_CONTAINED``, no self links will be
601-
included. Link types will be set to RELATIVE.
602-
603-
Raises:
604-
ValueError: Raises if the catalog_type argument is not supplied and
605-
there is no catalog_type attribute on this catalog.
583+
included and hierarchical links will be relative URLs.
606584
"""
607-
catalog_type = catalog_type or self.catalog_type
608-
609-
if catalog_type is None:
610-
raise ValueError('Must supply a catalog_type if one is not set on the catalog.')
611-
612-
# Ensure relative vs absolute
613-
if catalog_type == CatalogType.ABSOLUTE_PUBLISHED:
614-
self.make_all_links_absolute()
615-
self.make_all_asset_hrefs_absolute()
616-
elif catalog_type in (CatalogType.SELF_CONTAINED, CatalogType.RELATIVE_PUBLISHED):
617-
self.make_all_links_relative()
618-
self.make_all_asset_hrefs_relative()
619-
else:
620-
raise ValueError(f'catalog_type is not a CatalogType: "{catalog_type}"')
621-
622-
include_self_link = catalog_type in [
623-
CatalogType.ABSOLUTE_PUBLISHED, CatalogType.RELATIVE_PUBLISHED
624-
]
585+
root = self.get_root()
586+
if root is None:
587+
raise Exception('There is no root catalog')
625588

626-
if catalog_type == CatalogType.RELATIVE_PUBLISHED:
627-
child_catalog_type = CatalogType.SELF_CONTAINED
628-
else:
629-
child_catalog_type = catalog_type
589+
if catalog_type is not None:
590+
root.catalog_type = catalog_type
630591

631-
items_include_self_link = catalog_type in [CatalogType.ABSOLUTE_PUBLISHED]
592+
items_include_self_link = root.catalog_type in [CatalogType.ABSOLUTE_PUBLISHED]
632593

633594
for child_link in self.get_child_links():
634595
if child_link.is_resolved():
635-
child_link.target.save(catalog_type=child_catalog_type)
596+
child_link.target.save()
636597

637598
for item_link in self.get_item_links():
638599
if item_link.is_resolved():
639600
item_link.target.save_object(include_self_link=items_include_self_link)
640601

602+
include_self_link = False
603+
# include a self link if this is the root catalog or if ABSOLUTE_PUBLISHED catalog
604+
if ((self.get_self_href() == self.get_root_link().get_absolute_href()
605+
and root.catalog_type != CatalogType.SELF_CONTAINED)
606+
or root.catalog_type == CatalogType.ABSOLUTE_PUBLISHED):
607+
include_self_link = True
608+
641609
self.save_object(include_self_link=include_self_link)
642610

643611
self.catalog_type = catalog_type

pystac/extensions/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88

99
class ExtendedObject:
10-
"""ExtendedObject maps STACObject classes (Catalog, Collecition and Item) to
10+
"""ExtendedObject maps STACObject classes (Catalog, Collection and Item) to
1111
extension classes (classes that implement one of CatalogExtension, CollectionExtesion,
1212
or ItemCollection). When an extension is registered with PySTAC it uses the registered
1313
list of ExtendedObject to determine how to handle extending objects, e.g. when item.ext.label

pystac/item.py

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import pystac
66
from pystac import (STACError, STACObjectType)
7-
from pystac.link import Link, LinkType
7+
from pystac.link import Link
88
from pystac.stac_object import STACObject
99
from pystac.utils import (is_absolute_href, make_absolute_href, make_relative_href, datetime_to_str,
1010
str_to_datetime)
@@ -221,7 +221,7 @@ def make_asset_hrefs_absolute(self):
221221

222222
return self
223223

224-
def set_collection(self, collection, link_type=None):
224+
def set_collection(self, collection):
225225
"""Set the collection of this item.
226226
227227
This method will replace any existing Collection link and attribute for
@@ -230,22 +230,14 @@ def set_collection(self, collection, link_type=None):
230230
Args:
231231
collection (Collection or None): The collection to set as this
232232
item's collection. If None, will clear the collection.
233-
link_type (str): the link type to use for the collection link.
234-
One of :class:`~pystac.LinkType`.
235233
236234
Returns:
237235
Item: self
238236
"""
239-
if not link_type:
240-
prev = self.get_single_link('collection')
241-
if prev is not None:
242-
link_type = prev.link_type
243-
else:
244-
link_type = LinkType.ABSOLUTE
245237
self.remove_links('collection')
246238
self.collection_id = None
247239
if collection is not None:
248-
self.add_link(Link.collection(collection, link_type=link_type))
240+
self.add_link(Link.collection(collection))
249241
self.collection_id = collection.id
250242

251243
return self

0 commit comments

Comments
 (0)