def resolve_path(path, ds=None): """Resolve a path specification (against a Dataset location) Any explicit path (absolute or relative) is returned as an absolute path. In case of an explicit relative path, the current working directory is used as a reference. Any non-explicit relative path is resolved against as dataset location, i.e. considered relative to the location of the dataset. If no dataset is provided, the current working directory is used. Returns ------- Absolute path """ # first make sure it's actually a valid path: from datalad.support.network import PathRI if not isinstance(RI(path), PathRI): raise ValueError("%s is not a valid path" % path) path = expandpath(path, force_absolute=False) if is_explicit_path(path): # normalize path consistently between two (explicit and implicit) cases return dlabspath(path, norm=True) # no dataset given, use CWD as reference # note: abspath would disregard symlink in CWD top_path = getpwd() \ if ds is None else ds.path if isinstance(ds, Dataset) else ds return normpath(opj(top_path, path))
def resolve_path(path, ds=None): """Resolve a path specification (against a Dataset location) Any explicit path (absolute or relative) is returned as an absolute path. In case of an explicit relative path, the current working directory is used as a reference. Any non-explicit relative path is resolved against as dataset location, i.e. considered relative to the location of the dataset. If no dataset is provided, the current working directory is used. Returns ------- Absolute path """ # first make sure it's actually a valid path: from datalad.support.network import PathRI if not isinstance(RI(path), PathRI): raise ValueError("%s is not a valid path" % path) path = expandpath(path, force_absolute=False) if is_explicit_path(path): # normalize path consistently between two (explicit and implicit) cases return dlabspath(path, norm=True) # no dataset given, use CWD as reference # note: abspath would disregard symlink in CWD top_path = getpwd() \ if ds is None else ds.path if isinstance(ds, Dataset) else ds return normpath(opj(top_path, path))
def get_containing_subdataset(self, path, recursion_limit=None): """Get the (sub-)dataset containing `path` Note: The "mount point" of a subdataset is classified as belonging to that respective subdataset. WARNING: This function is rather expensive, because it queries for all subdatasets recursively, and repeatedly -- which can take a substantial amount of time for datasets with many (sub-)subdatasets. In Many cases the `subdatasets` command can be used with its `contains` parameter to achieve the desired result in a less expensive way. Parameters ---------- path : str Path to determine the containing (sub-)dataset for recursion_limit: int or None limit the subdatasets to take into account to the given number of hierarchy levels Returns ------- Dataset """ if recursion_limit is not None and (recursion_limit < 1): lgr.warning("recursion limit < 1 (%s) always results in self.", recursion_limit) return self if is_explicit_path(path): path = resolve_path(path, self) if not path.startswith(self.path): raise PathOutsideRepositoryError(file_=path, repo=self) path = relpath(path, self.path) candidates = [] # TODO: this one would follow all the sub-datasets, which might # be inefficient if e.g. there is lots of other sub-datasets already # installed but under another sub-dataset. There is a TODO 'pattern' # option which we could use I guess eventually for subds in self.subdatasets( recursive=True, #pattern= recursion_limit=recursion_limit, result_xfm='relpaths'): common = commonprefix((with_pathsep(subds), with_pathsep(path))) if common.endswith(sep) and common == with_pathsep(subds): candidates.append(common) if candidates: return Dataset(path=opj(self.path, max(candidates, key=len))) return self
def get_containing_subdataset(self, path, recursion_limit=None): """Get the (sub-)dataset containing `path` Note: The "mount point" of a subdataset is classified as belonging to that respective subdataset. Parameters ---------- path : str Path to determine the containing (sub-)dataset for recursion_limit: int or None limit the subdatasets to take into account to the given number of hierarchy levels Returns ------- Dataset """ if recursion_limit is not None and (recursion_limit < 1): lgr.warning("recursion limit < 1 (%s) always results in self.", recursion_limit) return self if is_explicit_path(path): path = resolve_path(path, self) if not path.startswith(self.path): raise PathOutsideRepositoryError(file_=path, repo=self) path = relpath(path, self.path) candidates = [] # TODO: this one would follow all the sub-datasets, which might # be inefficient if e.g. there is lots of other sub-datasets already # installed but under another sub-dataset. There is a TODO 'pattern' # option which we could use I guess eventually for subds in self.get_subdatasets( recursive=True, #pattern= recursion_limit=recursion_limit, absolute=False): common = commonprefix((with_pathsep(subds), with_pathsep(path))) if common.endswith(sep) and common == with_pathsep(subds): candidates.append(common) if candidates: return Dataset(path=opj(self.path, max(candidates, key=len))) return self
def get_containing_subdataset(self, path, recursion_limit=None): """Get the (sub-)dataset containing `path` Note: The "mount point" of a subdataset is classified as belonging to that respective subdataset. Parameters ---------- path : str Path to determine the containing (sub-)dataset for recursion_limit: int or None limit the subdatasets to take into account to the given number of hierarchy levels Returns ------- Dataset """ if recursion_limit is not None and (recursion_limit < 1): lgr.warning("recursion limit < 1 (%s) always results in self.", recursion_limit) return self if is_explicit_path(path): path = resolve_path(path, self) if not path.startswith(self.path): raise PathOutsideRepositoryError(file_=path, repo=self) path = relpath(path, self.path) candidates = [] # TODO: this one would follow all the sub-datasets, which might # be inefficient if e.g. there is lots of other sub-datasets already # installed but under another sub-dataset. There is a TODO 'pattern' # option which we could use I guess eventually for subds in self.get_subdatasets(recursive=True, #pattern= recursion_limit=recursion_limit, absolute=False): common = commonprefix((with_pathsep(subds), with_pathsep(path))) if common.endswith(sep) and common == with_pathsep(subds): candidates.append(common) if candidates: return Dataset(path=opj(self.path, max(candidates, key=len))) return self
def resolve_path(path, ds=None): """Resolve a path specification (against a Dataset location) Any explicit path (absolute or relative) is returned as an absolute path. In case of an explicit relative path, the current working directory is used as a reference. Any non-explicit relative path is resolved against as dataset location, i.e. considered relative to the location of the dataset. If no dataset is provided, the current working directory is used. Returns ------- Absolute path """ path = expandpath(path, force_absolute=False) # TODO: normpath?! if is_explicit_path(path): return abspath(path) # no dataset given, use CWD as reference # note: abspath would disregard symlink in CWD top_path = getpwd() \ if ds is None else ds.path if isinstance(ds, Dataset) else ds return normpath(opj(top_path, path))
def get_containing_subdataset(ds, path): """Given a base dataset and a relative path get containing subdataset Parameters ---------- ds : Dataset Reference or base dataset path : str Path relative to the reference dataset Returns ------- Dataset """ if is_explicit_path(path) and not path.startswith(ds.path): raise ValueError("path {0} not in dataset.".format(path)) for subds in ds.get_dataset_handles(): common = os.path.commonprefix((_with_sep(subds), _with_sep(path))) if common.endswith(sep) and common == _with_sep(subds): return Dataset(path=opj(ds.path, common)) return ds
def resolve_path(path, ds=None): """Resolve a path specification (against a Dataset location) Any explicit path (absolute or relative) is returned as an absolute path. In case of an explicit relative path, the current working directory is used as a reference. Any non-explicit relative path is resolved against as dataset location, i.e. considered relative to the location of the dataset. If no dataset is provided, the current working directory is used. Returns ------- Absolute path """ path = expandpath(path, force_absolute=False) # TODO: normpath?! if is_explicit_path(path): return abspath(path) # no dataset given, use CWD as reference # note: abspath would disregard symlink in CWD top_path = getpwd() \ if ds is None else ds.path if isinstance(ds, Dataset) else ds return normpath(opj(top_path, path))
def resolve_path(path, ds=None): """Resolve a path specification (against a Dataset location) Any explicit path (absolute or relative) is return as an absolute path. In case of an explicit relative path, the current working directory is used as a reference. Any non-explicit relative path is resolved against as dataset location, i.e. considered relative to the location of the dataset. If no dataset is provided, the current working directory is used. Returns ------- Absolute path """ path = expandpath(path, force_absolute=False) if is_explicit_path(path): return abspath(path) if ds is None: # no dataset given, use CWD as reference # TODO: Check whether we should use PWD instead of CWD here. Is it done # by abspath? return abspath(path) else: return normpath(opj(ds.path, path))
def resolve_path(path, ds=None): """Resolve a path specification (against a Dataset location) Any explicit path (absolute or relative) is return as an absolute path. In case of an explicit relative path, the current working directory is used as a reference. Any non-explicit relative path is resolved against as dataset location, i.e. considered relative to the location of the dataset. If no dataset is provided, the current working directory is used. Returns ------- Absolute path """ path = expandpath(path, force_absolute=False) if is_explicit_path(path): return abspath(path) if ds is None: # no dataset given, use CWD as reference # TODO: Check whether we should use PWD instead of CWD here. Is it done # by abspath? return abspath(path) else: return normpath(opj(ds.path, path))
def test_is_explicit_path(): # by default expanded paths are absolute, hence explicit assert_true(is_explicit_path(expandpath('~'))) assert_false(is_explicit_path("here"))