class_docstr: Representation of a DataLad dataset/repository
  
  This is the core data type of DataLad: a representation of a dataset.
  At its core, datasets are (git-annex enabled) Git repositories. This
  class provides all operations that can be performed on a dataset.
  
  Creating a dataset instance is cheap, all actual operations are
  delayed until they are actually needed. Creating multiple `Dataset`
  class instances for the same Dataset location will automatically
  yield references to the same object.
  
  A dataset instance comprises of two major components: a `repo`
  attribute, and a `config` attribute. The former offers access to
  low-level functionality of the Git or git-annex repository. The
  latter gives access to a dataset's configuration manager.
  
  Most functionality is available via methods of this class, but also
  as stand-alone functions with the same name in `datalad.api`.
class_docstr_tok: ["Representation","of","a","DataLad","dataset\/repository","This","is","the","core","data","type","of","DataLad",":","a","representation","of","a","dataset",".","At","its","core",",","datasets","are","(","git-annex","enabled",")","Git","repositories",".","This","class","provides","all","operations","that","can","be","performed","on","a","dataset",".","Creating","a","dataset","instance","is","cheap",",","all","actual","operations","are","delayed","until","they","are","actually","needed",".","Creating","multiple","`","Dataset","`","class","instances","for","the","same","Dataset","location","will","automatically","yield","references","to","the","same","object",".","A","dataset","instance","comprises","of","two","major","components",":","a","`","repo","`","attribute",",","and","a","`","config","`","attribute",".","The","former","offers","access","to","low-level","functionality","of","the","Git","or","git-annex","repository",".","The","latter","gives","access","to","a","dataset","'s","configuration","manager",".","Most","functionality","is","available","via","methods","of","this","class",",","but","also","as","stand-alone","functions","with","the","same","name","in","`","datalad.api","`","."]
docstr: Get an instance of the version control system/repo for this dataset,
  or None if there is none yet (or none anymore).
  
  If testing the validity of an instance of GitRepo is guaranteed to be
  really cheap this could also serve as a test whether a repo is present.
  
  Note, that this property is evaluated every time it is used. If used
  multiple times within a function it's probably a good idea to store its
  value in a local variable and use this variable instead.
  
  Returns
  -------
  GitRepo or AnnexRepo
docstr_tok: ["Get","an","instance","of","the","version","control","system\/repo","for","this","dataset",",","or","None","if","there","is","none","yet","(","or","none","anymore",")",".","If","testing","the","validity","of","an","instance","of","GitRepo","is","guaranteed","to","be","really","cheap","this","could","also","serve","as","a","test","whether","a","repo","is","present",".","Note",",","that","this","property","is","evaluated","every","time","it","is","used",".","If","used","multiple","times","within","a","function","it","'s","probably","a","good","idea","to","store","its","value","in","a","local","variable","and","use","this","variable","instead",".","Returns","--","--","--","-","GitRepo","or","AnnexRepo"]
code: def repo(self):
      """Get an instance of the version control system/repo for this dataset,
      or None if there is none yet (or none anymore).
  
      If testing the validity of an instance of GitRepo is guaranteed to be
      really cheap this could also serve as a test whether a repo is present.
  
      Note, that this property is evaluated every time it is used. If used
      multiple times within a function it's probably a good idea to store its
      value in a local variable and use this variable instead.
  
      Returns
      -------
      GitRepo or AnnexRepo
      """
  
      # If we already got a *Repo instance, check whether it's still valid;
      # Note, that this basically does part of the testing that would
      # (implicitly) be done in the loop below again. So, there's still
      # potential to speed up when we actually need to get a new instance
      # (or none). But it's still faster for the vast majority of cases.
      #
      # TODO: Dig deeper into it and melt with new instance guessing. This
      # should also involve to reduce redundancy of testing such things from
      # within Flyweight.__call__, AnnexRepo.__init__ and GitRepo.__init__!
      #
      # Also note, that this could be forged into a single big condition, but
      # that is hard to read and we should be well aware of the actual
      # criteria here:
      if (
          self._repo is not None
          and self.pathobj.resolve() == self._repo.pathobj
      ):
          # we got a repo and path references still match
          if isinstance(self._repo, AnnexRepo):
              # it's supposed to be an annex
              # Here we do the same validation that Flyweight would do beforehand if there was a call to AnnexRepo()
              if (
                  self._repo
                  is AnnexRepo._unique_instances.get(
                      self._repo.path, None
                  )
                  and not self._repo._flyweight_invalid()
              ):
                  # it's still the object registered as flyweight and it's a
                  # valid annex repo
                  return self._repo
          elif isinstance(self._repo, GitRepo):
              # it's supposed to be a plain git
              # same kind of checks as for AnnexRepo above, but additionally check whether it was changed to have an
              # annex now.
              # TODO: Instead of is_with_annex, we might want the cheaper check for an actually initialized annex.
              #       However, that's not completely clear. On the one hand, if it really changed to be an annex
              #       it seems likely that this happened locally and it would also be an initialized annex. On the
              #       other hand, we could have added (and fetched) a remote with an annex, which would turn it into
              #       our current notion of an uninitialized annex. Question is whether or not such a change really
              #       need to be detected. For now stay on the safe side and detect it.
              if (
                  self._repo
                  is GitRepo._unique_instances.get(
                      self._repo.path, None
                  )
                  and not self._repo._flyweight_invalid()
                  and not self._repo.is_with_annex()
              ):
                  # it's still the object registered as flyweight, it's a
                  # valid git repo and it hasn't turned into an annex
                  return self._repo
  
      # Note: Although it looks like the "self._repo = None" assignments
      # could be used instead of variable "valid", that's a big difference!
      # The *Repo instances are flyweights, not singletons. self._repo might
      # be the last reference, which would lead to those objects being
      # destroyed and therefore the constructor call would result in an
      # actually new instance. This is unnecessarily costly.
      try:
          self._repo = repo_from_path(self._path)
      except ValueError:
          lgr.log(5, "Failed to detect a valid repo at %s", self.path)
          self._repo = None
          return
  
      if due.active:
          # TODO: Figure out, when exactly this is needed. Don't think it
          #       makes sense to do this for every dataset,
          #       no matter what => we want .repo to be as cheap as it gets.
          # Makes sense only on installed dataset - @never_fail'ed
          duecredit_dataset(self)
  
      return self._repo
  
imports: import inspect
  import logging
  from functools import wraps
  from os.path import curdir, exists, join, normpath, pardir
  from weakref import WeakValueDictionary
  from datalad import cfg
  from datalad.config import ConfigManager
  from datalad.core.local.repo import repo_from_path
  from datalad.support.annexrepo import AnnexRepo
  from datalad.support.constraints import Constraint
  from datalad.support.due import due
  from datalad.support.due_utils import duecredit_dataset
  from datalad.support.exceptions import NoDatasetFound
  from datalad.dataset.repo import path_based_str_repr, PathBasedFlyweight
  from datalad.support.gitrepo import GitRepo
  from datalad.support import path
  import datalad.utils
  from datalad.utils import getpwd, optional_args, get_dataset_root, get_sig_param_names, get_dataset_root, Path, PurePath, ensure_list
label_desc: Use image node_id 11 for calling the Dataset obj's underlying member method code with example usage: obj.repo() and returns: self, self, self