{
    "file_diffs": [
        {
            "old_file_content": "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"High-level interface for dataset (component) installation\n\n\"\"\"\nfrom datalad.distribution.utils import _install_subds_inplace, \\\n    _fixup_submodule_dotgit_setup\n\n__docformat__ = 'restructuredtext'\n\nimport logging\nfrom os import curdir, linesep\nfrom os.path import join as opj, relpath, pardir, exists\n\nfrom six.moves.urllib.parse import quote as urlquote\n\nfrom .dataset import Dataset, datasetmethod, \\\n    resolve_path, EnsureDataset\n\nfrom datalad.interface.base import Interface\nfrom datalad.interface.common_opts import recursion_flag, recursion_limit, \\\n    dataset_description, git_opts, annex_opts, \\\n    annex_init_opts, git_clone_opts, if_dirty_opt, nosave_opt\nfrom datalad.interface.utils import handle_dirty_dataset\n\nfrom datalad.support.constraints import EnsureStr, EnsureNone\nfrom datalad.support.annexrepo import AnnexRepo\nfrom datalad.support.exceptions import InsufficientArgumentsError\nfrom datalad.support.gitrepo import GitRepo, GitCommandError\nfrom datalad.support.param import Parameter\nfrom datalad.utils import knows_annex, swallow_logs\nfrom datalad.support.network import RI, URL\nfrom datalad.support.network import DataLadRI\nfrom datalad.support.network import is_url, is_datalad_compat_ri\nfrom datalad.utils import rmtree\n\nlgr = logging.getLogger('datalad.distribution.install')\n\n\ndef _get_git_url_from_source(source, none_ok=False):\n    \"\"\"Return URL for cloning associated with a source specification\n\n    For now just resolves DataLadRIs\n    \"\"\"\n    # TODO: Probably RF this into RI.as_git_url(), that would be overridden\n    # by subclasses or sth. like that\n\n    if source is None:\n        if not none_ok:\n            lgr.warning(\"received 'None' as 'source'.\")\n        return source\n\n    if not isinstance(source, RI):\n        source_ri = RI(source)\n    else:\n        source_ri = source\n    if isinstance(source_ri, DataLadRI):\n        # we have got our DataLadRI as the source, so expand it\n        source = source_ri.as_git_url()\n    else:\n        source = str(source_ri)\n    return source\n\n\ndef _get_installationpath_from_url(url):\n    \"\"\"Returns a relative path derived from the trailing end of a URL\n\n    This can be used to determine an installation path of a Dataset\n    from a URL, analog to what `git clone` does.\n    \"\"\"\n    path = url.rstrip('/')\n    if '/' in path:\n        path = path.split('/')\n        if path[-1] == '.git':\n            path = path[-2]\n        else:\n            path = path[-1]\n    if path.endswith('.git'):\n        path = path[:-4]\n    return path\n\n\ndef _install_subds_from_flexible_source(ds, sm_path, sm_url, recursive):\n    \"\"\"Tries to obtain a given subdataset from several meaningful locations\"\"\"\n    # shortcut\n    vcs = ds.repo\n    repo = vcs.repo\n    # compose a list of candidate clone URLs\n    clone_urls = []\n    # if we have a remote, let's check the location of that remote\n    # for the presence of the desired submodule\n    tracking_branch = repo.active_branch.tracking_branch()\n    remote_url = ''\n    # remember suffix\n    url_suffix = ''\n    if tracking_branch:\n        # name of the default remote for the active branch\n        remote_name = repo.active_branch.tracking_branch().remote_name\n        remote_url = vcs.get_remote_url(remote_name, push=False)\n        if remote_url.rstrip('/').endswith('/.git'):\n            url_suffix = '/.git'\n            remote_url = remote_url[:-5]\n        # attempt: submodule checkout at parent remote URL\n        # We might need to quote sm_path portion, e.g. for spaces etc\n        if remote_url and isinstance(RI(remote_url), URL):\n            sm_path_url = urlquote(sm_path)\n        else:\n            sm_path_url = sm_path\n        clone_urls.append('{0}/{1}{2}'.format(\n            remote_url, sm_path_url, url_suffix))\n    # attempt: configured submodule URL\n    # TODO: consider supporting DataLadRI here?  or would confuse\n    #  git and we wouldn't want that (i.e. not allow pure git clone\n    #  --recursive)\n    if sm_url.startswith('/') or is_url(sm_url):\n        # this seems to be an absolute location -> take as is\n        clone_urls.append(sm_url)\n    else:\n        # need to resolve relative URL\n        if not remote_url:\n            # we have no remote URL, hence we need to go with the\n            # local path\n            remote_url = ds.path\n        remote_url_l = remote_url.split('/')\n        sm_url_l = sm_url.split('/')\n        for i, c in enumerate(sm_url_l):\n            if c == pardir:\n                remote_url_l = remote_url_l[:-1]\n            else:\n                clone_urls.append('{0}/{1}{2}'.format(\n                    '/'.join(remote_url_l),\n                    '/'.join(sm_url_l[i:]),\n                    url_suffix))\n                break\n    # now loop over all candidates and try to clone\n    subds = Dataset(opj(ds.path, sm_path))\n    for clone_url in clone_urls:\n        lgr.debug(\"Attempt clone of subdataset from: {0}\".format(clone_url))\n        try:\n            subds = Install.__call__(\n                path=subds.path, source=clone_url,\n                recursive=recursive)\n        except GitCommandError:\n            # TODO: failed clone might leave something behind that causes the\n            # next attempt to fail as well. Implement safe way to remove clone\n            # attempt left-overs.\n            continue\n        lgr.debug(\"Update cloned subdataset {0} in parent\".format(subds))\n        if sm_path in ds.get_subdatasets(absolute=False, recursive=False):\n            ds.repo.update_submodule(sm_path, init=True)\n        else:\n            # submodule is brand-new and previously unknown\n            ds.repo.add_submodule(sm_path, url=clone_url)\n        _fixup_submodule_dotgit_setup(ds, sm_path)\n        return subds\n\n\n# TODO:  git_clone options\n# use --shared by default? => option --no-shared\n\n\nclass Install(Interface):\n    \"\"\"Install a dataset or subdataset.\n\n    This command creates a local :term:`sibling` of an existing dataset from a\n    (remote) location identified via a URL or path, or by the name of a\n    registered subdataset. Optional recursion into potential subdatasets, and\n    download of all referenced data is supported. The new dataset can be\n    optionally registered in an existing :term:`superdataset` (the new\n    dataset's path needs to be located within the superdataset for that, and\n    the superdataset will be detected automatically). It is recommended to\n    provide a brief description to label the dataset's nature *and* location,\n    e.g. \"Michael's music on black laptop\". This helps humans to identify data\n    locations in distributed scenarios.  By default an identifier comprised of\n    user and machine name, plus path will be generated.\n\n    When only partial dataset content shall be obtained, it is recommended to\n    use this command without the :option:`get-data` flag, followed by a\n    :func:`~datalad.api.get` operation to obtain the desired data.\n\n    .. note::\n      Power-user info: This command uses :command:`git clone`, and\n      :command:`git annex init` to prepare the dataset. Registering to a\n      superdataset is performed via a :command:`git submodule add` operation\n      in the discovered superdataset.\n    \"\"\"\n\n    _params_ = dict(\n        dataset=Parameter(\n            args=(\"-d\", \"--dataset\"),\n            # TODO: this probably changes to install into the dataset (add_to_super)\n            # and to install the thing 'just there' without operating 'on' a dataset.\n            # Adapt doc.\n            doc=\"\"\"specify the dataset to perform the install operation on.  If\n            no dataset is given, an attempt is made to identify the dataset\n            in a parent directory of the current working directory and/or the\n            `path` given\"\"\",\n            constraints=EnsureDataset() | EnsureNone()),\n        path=Parameter(\n            args=(\"path\",),\n            doc=\"\"\"path/name of the installation target.  If no `source` is\n            provided, and no `dataset` is given or detected, this is\n            interpreted as the source URL of a dataset and a destination\n            path will be derived from the URL similar to :command:`git\n            clone`\"\"\",\n            nargs=\"?\",\n            constraints=EnsureStr() | EnsureNone()),\n        source=Parameter(\n            args=(\"-s\", \"--source\",),\n            doc=\"URL or local path of the installation source\",\n            constraints=EnsureStr() | EnsureNone()),\n        get_data=Parameter(\n            args=(\"-g\", \"--get-data\",),\n            action=\"store_true\",\n            doc=\"\"\"if given, obtain all data content too\"\"\"),\n        description=dataset_description,\n        recursive=recursion_flag,\n        recursion_limit=recursion_limit,\n        if_dirty=if_dirty_opt,\n        save=nosave_opt,\n        git_opts=git_opts,\n        git_clone_opts=git_clone_opts,\n        annex_opts=annex_opts,\n        annex_init_opts=annex_init_opts)\n\n    @staticmethod\n    @datasetmethod(name='install')\n    def __call__(\n            path=None,\n            source=None,\n            dataset=None,\n            get_data=False,\n            description=None,\n            recursive=False,\n            recursion_limit=None,\n            if_dirty='save-before',\n            save=True,\n            git_opts=None,\n            git_clone_opts=None,\n            annex_opts=None,\n            annex_init_opts=None):\n\n        lgr.debug(\n            \"Installation attempt started. path=%r, source=%r, dataset=%r, \"\n            \"get_data=%r, description=%r, recursive=%r, recursion_limit=%r, \"\n            \"git_opts=%r, git_clone_opts=%r, annex_opts=%r, annex_init_opt=%r\",\n            path, source, dataset, get_data, description, recursive,\n            recursion_limit, git_opts, git_clone_opts, annex_opts,\n            annex_init_opts)\n\n        # shortcut\n        ds = dataset\n\n        _install_into_ds = False  # default\n        # did we explicitly get a dataset to install into?\n        # if we got a dataset, path will be resolved against it.\n        # Otherwise path will be resolved first.\n\n        if ds is not None:\n            _install_into_ds = True\n            if not isinstance(ds, Dataset):\n                ds = Dataset(ds)\n            if not ds.is_installed():\n                # TODO: possible magic: ds.install() for known subdataset 'ds'\n                raise ValueError(\"{0} needs to be installed in order to \"\n                                 \"install something into it.\".format(ds))\n            handle_dirty_dataset(ds, if_dirty)\n\n        # resolve the target location (if local) against the provided dataset\n        # or CWD:\n        if path is not None:\n            # Should work out just fine for regular paths, so no additional\n            # conditioning is necessary\n            path_ri = RI(path)\n            try:\n                # Wouldn't work for SSHRI ATM, see TODO within SSHRI\n                path = resolve_path(path_ri.localpath, ds)\n                # any `path` argument that point to something local now\n                # resolved and is no longer a URL\n            except ValueError:\n                # URL doesn't point to a local something\n                # so we have an actual URL in `path`. Since this is valid as a\n                # single positional argument, `source` has to be None at this\n                # point.\n\n                if is_datalad_compat_ri(path) and source is None:\n                    # we have an actual URL -> this should be the source\n                    lgr.debug(\n                        \"Single argument given to install, that doesn't seem to \"\n                        \"be a local path. \"\n                        \"Assuming the argument identifies a source location.\")\n                    source = path\n                    path = None\n\n                else:\n                    # `path` is neither a valid source nor a local path.\n                    # TODO: The only thing left is a known subdataset with a\n                    # name, that is not a path; Once we correctly distinguish\n                    # between path and name of a submodule, we need to consider\n                    # this.\n                    # For now: Just raise\n                    raise ValueError(\"Invalid path argument {0}\".format(path))\n\n        # `path` resolved, if there was any.\n\n        # we need a source to install from. Either we have one in `source` or\n        # it is implicit, since `path` is an already known subdataset or an\n        # existing dataset, that should be installed into the given dataset as a\n        # subdataset inplace.\n        # Note: For now, we do not consider a subdataset beneath a not yet\n        # installed level, since we do not know, whether this even is something\n        # to install (an actual Dataset) the only thing we know would be,\n        # that it is some path beneath it.\n        _install_sub = False\n\n        if _install_into_ds and source is None and path is not None:\n            # Check for `path` being a known subdataset:\n            if path in [opj(ds.path, sub)\n                        for sub in ds.get_subdatasets(recursive=True)]:\n                _install_sub = True\n                lgr.debug(\"Identified {0} as subdataset to \"\n                          \"install.\".format(path))\n            else:\n                # the only option left is an existing repo to be added inplace:\n                if exists(path) and GitRepo.is_valid_repo(path):\n                    lgr.debug(\"No source given, but path points to an existing \"\n                              \"repository and a dataset to install into was \"\n                              \"given. Assuming we want to install {0} \"\n                              \"inplace into {1}.\".format(path, ds))\n                    source = path\n\n        if source is None and not _install_sub:\n            # we have no source and don't have a dataset to install into.\n            # could be a single positional argument, that points to a known\n            # subdataset.\n            # So, test for that last remaining option:\n\n            # if `path` was a known subdataset to be installed, let's assume\n            # it would be one:\n            assume_ds = Dataset(path)\n            candidate_super_ds = assume_ds.get_superdataset()\n\n            if candidate_super_ds and candidate_super_ds != assume_ds and \\\n                assume_ds.path in candidate_super_ds.get_subdatasets(absolute=True):\n\n                # `path` has a potential superdataset and is known to this\n                # candidate\n                _install_sub = True\n                _install_into_ds = True\n                ds = candidate_super_ds\n\n            else:\n                # no match, we can't deal with that `path` argument\n                # without a `source`:\n                raise InsufficientArgumentsError(\n                    \"Got no source to install from.\")\n\n        _install_inplace = False\n        if source == path:  # TODO: does it make sense to use realpath here?\n            if _install_into_ds:\n                _install_inplace = True\n            else:\n                raise InsufficientArgumentsError(\n                    \"Source and target are the same ({0}). This doesn't make \"\n                    \"sense without a dataset to install into.\".format(path))\n\n        # Possibly do conversion from source into a git-friendly url\n        source_url = _get_git_url_from_source(source, none_ok=True)\n\n        # derive target from source url:\n        if path is None and source_url is not None:\n            # we got nothing but a source. do something similar to git clone\n            # and derive the path from the source_url and continue\n            lgr.debug(\n                \"Neither dataset nor target installation path provided. \"\n                \"Assuming installation of a remote dataset. \"\n                \"Deriving destination path from given source {0}\".format(\n                    source_url))\n            path = _get_installationpath_from_url(source_url)\n            # since this is a relative `path`, resolve it:\n            path = resolve_path(path, ds)\n\n        if path is None:\n            # still no target => fail\n            raise InsufficientArgumentsError(\"Got no target to install to.\")\n\n        lgr.debug(\"Resolved installation target: {0}\".format(path))\n\n        # TODO: expandpath()?\n        # more checks, whether something exists and what it actually is?\n\n        ###########\n        # we should know everything necessary by now\n        # actual installation starts\n        ###########\n        lgr.info(\"Installing {0}{1}\".format(\n            path, \" from %s\" % source_url if source_url else \"\"\n        ))\n\n        installed_items = []\n        # FLOW GUIDE:\n        # four cases:\n        # 1. install into a dataset\n        #   1.1. we install a known subdataset\n        #        => git submodule update --init\n        #   1.2. we install an existing repo as a subdataset inplace\n        #        => git submodule add + magic\n        #   1.3. we install a new subdataset from an explicit source\n        #        => git submodule add\n        # 2. we \"just\" install from an explicit source\n        #    => git clone\n\n        if _install_into_ds:\n            # FLOW GUIDE: 1.\n            lgr.info(\"Install subdataset at: {0}\".format(path))\n\n            # express the destination path relative to the root of\n            # the dataset\n            relativepath = relpath(path, start=ds.path)\n            if relativepath.startswith(pardir):\n                raise ValueError(\"installation path outside dataset \"\n                                 \"({0})\".format(path))\n            lgr.debug(\"Resolved installation target relative to dataset \"\n                      \"{0}: {1}\".format(ds, relativepath))\n\n            if _install_sub:\n                # FLOW_GUIDE: 1.1.\n                submodule = [sm for sm in ds.repo.get_submodules()\n                             if sm.path == relativepath][0]\n\n                _install_subds_from_flexible_source(\n                    ds,\n                    submodule.path,\n                    submodule.url,\n                    recursive=False)\n                #ds.repo.update_submodule(relativepath, init=True)\n\n                # TODO: use _install_subds_from_flexible instead?\n                # it calls install again, but this is based on old install.\n                # So, need to figure it out\n                # Additional note: - does always git clone + add inplace\n\n            elif _install_inplace:\n                # FLOW GUIDE: 1.2.\n                _install_subds_inplace(ds, path, relpath(path, ds.path))\n                # TODO: Some success checks?\n            else:\n                # FLOW_GUIDE 1.3.\n                _install_subds_from_flexible_source(\n                    ds, relativepath,\n                    source_url, recursive=False)\n                #ds.repo.add_submodule(relativepath, url=source_url)\n        else:\n            # FLOW GUIDE: 2.\n            lgr.info(\"Install dataset at: {0}\".format(path))\n\n            # Currently assuming there is nothing at the target to deal with\n            # and rely on failures raising from the git call ...\n\n            target = Dataset(path)\n\n            # TODO\n            assert(target.repo is None)\n\n            # should not be the case, but we need to distinguish between failure\n            # of git-clone, due to existing target and an unsuccessful clone\n            # attempt. See below.\n            existed = target.path and exists(target.path)\n\n            vcs = None\n            # We possibly need to consider /.git URL\n            candidate_source_urls = [source_url]\n            if source_url and not source_url.rstrip('/').endswith('/.git'):\n                candidate_source_urls.append(\n                    '{0}/.git'.format(source_url.rstrip('/')))\n\n            for source_url_ in candidate_source_urls:\n                try:\n                    lgr.debug(\"Retrieving a dataset from URL: \"\n                              \"{0}\".format(source_url_))\n                    with swallow_logs():\n                        vcs = Install._get_new_vcs(target, source_url_)\n                    break  # do not bother with other sources if succeeded\n                except GitCommandError:\n                    lgr.debug(\"Failed to retrieve from URL: \"\n                              \"{0}\".format(source_url_))\n                    if not existed and target.path and exists(target.path):\n                        lgr.debug(\"Wiping out unsuccessful clone attempt at \"\n                                  \"{}\".format(target.path))\n                        rmtree(target.path)\n                    if source_url_ == candidate_source_urls[-1]:\n                        # Re-raise if failed even with the last candidate\n                        lgr.debug(\"Unable to establish repository instance at \"\n                                  \"{0} from {1}\"\n                                  \"\".format(target.path, candidate_source_urls))\n                        raise\n\n            # is automagically re-evaluated in the .repo property:\n            assert(target.repo)\n            # cloning done\n\n        # FLOW GUIDE: All four cases done.\n\n        # in any case check whether we need to annex init the installed thing:\n        if knows_annex(path):\n            # init annex when traces of a remote annex can be detected\n            lgr.info(\"Initializing annex repo at %s\", path)\n            AnnexRepo(path, init=True)\n\n        lgr.debug(\"Installation of {0} done.\".format(path)) ##TODO: installed DS instead of `path`\n        current_dataset = Dataset(path)\n        installed_items.append(current_dataset)\n\n        # Now, recursive calls:\n        if recursive:\n            if description:\n                lgr.warning(\"Description can't be assigned recursively.\")\n            subs = [Dataset(p) for p in\n                    current_dataset.get_subdatasets(recursive=True,\n                                                    recursion_limit=1,\n                                                    absolute=True)]\n            for subds in subs:\n                if subds.is_installed():\n                    lgr.debug(\"subdataset {0} already installed. Skipped.\".format(subds))\n                else:\n                    rec_installed = Install.__call__(\n                        path=subds.path,\n                        dataset=current_dataset,\n                        recursive=True,\n                        recursion_limit=recursion_limit - 1\n                        if recursion_limit else None,\n                        if_dirty=if_dirty,\n                        save=save,\n                        git_opts=git_opts,\n                        git_clone_opts=git_clone_opts,\n                        annex_opts=annex_opts,\n                        annex_init_opts=annex_init_opts)\n                    if isinstance(rec_installed, list):\n                        installed_items.extend(rec_installed)\n                    else:\n                        installed_items.append(rec_installed)\n\n        # get the content of installed (sub-)datasets:\n        if get_data:\n            for d in installed_items:\n                lgr.info(\"Getting data of {0}\".format(d))\n                if isinstance(d.repo, AnnexRepo):\n                    d.get(curdir)\n\n        # everything done => save changes:\n        if save and _install_into_ds:\n            # Note: The only possible changes are installed subdatasets.\n            # This means: We have something to save only, if we installed into\n            # a dataset.\n            lgr.info(\"Saving changes to {0}\".format(ds))\n            ds.save(\n                message='[DATALAD] installed subdataset{0}:{1}'.format(\n                    \"s\" if len(installed_items) > 1 else \"\",\n                    linesep + linesep.join([str(i) for i in installed_items])),\n                auto_add_changes=False,\n                recursive=False)\n\n        if len(installed_items) == 1:\n            return installed_items[0]\n        else:\n            return installed_items\n\n    @staticmethod\n    def _get_new_vcs(ds, source):\n        if source is None:\n            raise RuntimeError(\n                \"No `source` was provided. To create a new dataset \"\n                \"use the `create` command.\")\n        else:\n            # when obtained from remote, try with plain Git\n            lgr.info(\"Creating a new git repo at %s\", ds.path)\n            vcs = GitRepo(ds.path, url=source, create=True)\n            if knows_annex(ds.path):\n                # init annex when traces of a remote annex can be detected\n                lgr.info(\"Initializing annex repo at %s\", ds.path)\n                vcs = AnnexRepo(ds.path, init=True)\n            else:\n                lgr.debug(\"New repository clone has no traces of an annex\")\n        return vcs\n\n    @staticmethod\n    def result_renderer_cmdline(res, args):\n        from datalad.ui import ui\n        if res is None:\n            res = []\n        if not isinstance(res, list):\n            res = [res]\n        if not len(res):\n            ui.message(\"Nothing was installed\")\n            return\n        items = '\\n'.join(map(str, res))\n        msg = \"{n} installed {obj} available at\\n{items}\".format(\n            obj='items are' if len(res) > 1 else 'item is',\n            n=len(res),\n            items=items)\n        ui.message(msg)\n",
            "new_file_content": "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"High-level interface for dataset (component) installation\n\n\"\"\"\nfrom datalad.distribution.utils import _install_subds_inplace, \\\n    _fixup_submodule_dotgit_setup\n\n__docformat__ = 'restructuredtext'\n\nimport logging\nfrom os import curdir, linesep\nfrom os.path import join as opj, relpath, pardir, exists\n\nfrom six.moves.urllib.parse import quote as urlquote\n\nfrom .dataset import Dataset, datasetmethod, \\\n    resolve_path, EnsureDataset\n\nfrom datalad.interface.base import Interface\nfrom datalad.interface.common_opts import recursion_flag, recursion_limit, \\\n    dataset_description, git_opts, annex_opts, \\\n    annex_init_opts, git_clone_opts, if_dirty_opt, nosave_opt\nfrom datalad.interface.utils import handle_dirty_dataset\n\nfrom datalad.support.constraints import EnsureStr, EnsureNone\nfrom datalad.support.annexrepo import AnnexRepo\nfrom datalad.support.exceptions import InsufficientArgumentsError\nfrom datalad.support.gitrepo import GitRepo, GitCommandError\nfrom datalad.support.param import Parameter\nfrom datalad.utils import knows_annex, swallow_logs\nfrom datalad.support.network import RI, URL\nfrom datalad.support.network import DataLadRI\nfrom datalad.support.network import is_url, is_datalad_compat_ri\nfrom datalad.utils import rmtree\n\nlgr = logging.getLogger('datalad.distribution.install')\n\n\ndef _get_git_url_from_source(source, none_ok=False):\n    \"\"\"Return URL for cloning associated with a source specification\n\n    For now just resolves DataLadRIs\n    \"\"\"\n    # TODO: Probably RF this into RI.as_git_url(), that would be overridden\n    # by subclasses or sth. like that\n\n    if source is None:\n        if not none_ok:\n            lgr.warning(\"received 'None' as 'source'.\")\n        return source\n\n    if not isinstance(source, RI):\n        source_ri = RI(source)\n    else:\n        source_ri = source\n    if isinstance(source_ri, DataLadRI):\n        # we have got our DataLadRI as the source, so expand it\n        source = source_ri.as_git_url()\n    else:\n        source = str(source_ri)\n    return source\n\n\ndef _get_installationpath_from_url(url):\n    \"\"\"Returns a relative path derived from the trailing end of a URL\n\n    This can be used to determine an installation path of a Dataset\n    from a URL, analog to what `git clone` does.\n    \"\"\"\n    path = url.rstrip('/')\n    if '/' in path:\n        path = path.split('/')\n        if path[-1] == '.git':\n            path = path[-2]\n        else:\n            path = path[-1]\n    if path.endswith('.git'):\n        path = path[:-4]\n    return path\n\n\ndef _install_subds_from_flexible_source(ds, sm_path, sm_url, recursive):\n    \"\"\"Tries to obtain a given subdataset from several meaningful locations\"\"\"\n    # shortcut\n    vcs = ds.repo\n    repo = vcs.repo\n    # compose a list of candidate clone URLs\n    clone_urls = []\n    # if we have a remote, let's check the location of that remote\n    # for the presence of the desired submodule\n    tracking_branch = repo.active_branch.tracking_branch()\n    remote_url = ''\n    # remember suffix\n    url_suffix = ''\n    if tracking_branch:\n        # name of the default remote for the active branch\n        remote_name = repo.active_branch.tracking_branch().remote_name\n        remote_url = vcs.get_remote_url(remote_name, push=False)\n        if remote_url.rstrip('/').endswith('/.git'):\n            url_suffix = '/.git'\n            remote_url = remote_url[:-5]\n        # attempt: submodule checkout at parent remote URL\n        # We might need to quote sm_path portion, e.g. for spaces etc\n        if remote_url and isinstance(RI(remote_url), URL):\n            sm_path_url = urlquote(sm_path)\n        else:\n            sm_path_url = sm_path\n        clone_urls.append('{0}/{1}{2}'.format(\n            remote_url, sm_path_url, url_suffix))\n    # attempt: configured submodule URL\n    # TODO: consider supporting DataLadRI here?  or would confuse\n    #  git and we wouldn't want that (i.e. not allow pure git clone\n    #  --recursive)\n    if sm_url.startswith('/') or is_url(sm_url):\n        # this seems to be an absolute location -> take as is\n        clone_urls.append(sm_url)\n    else:\n        # need to resolve relative URL\n        if not remote_url:\n            # we have no remote URL, hence we need to go with the\n            # local path\n            remote_url = ds.path\n        remote_url_l = remote_url.split('/')\n        sm_url_l = sm_url.split('/')\n        for i, c in enumerate(sm_url_l):\n            if c == pardir:\n                remote_url_l = remote_url_l[:-1]\n            else:\n                clone_urls.append('{0}/{1}{2}'.format(\n                    '/'.join(remote_url_l),\n                    '/'.join(sm_url_l[i:]),\n                    url_suffix))\n                break\n    # now loop over all candidates and try to clone\n    subds = Dataset(opj(ds.path, sm_path))\n    for clone_url in clone_urls:\n        lgr.debug(\"Attempt clone of subdataset from: {0}\".format(clone_url))\n        try:\n            subds = Install.__call__(\n                path=subds.path, source=clone_url,\n                recursive=recursive)\n        except GitCommandError:\n            # TODO: failed clone might leave something behind that causes the\n            # next attempt to fail as well. Implement safe way to remove clone\n            # attempt left-overs.\n            continue\n        lgr.debug(\"Update cloned subdataset {0} in parent\".format(subds))\n        if sm_path in ds.get_subdatasets(absolute=False, recursive=False):\n            ds.repo.update_submodule(sm_path, init=True)\n        else:\n            # submodule is brand-new and previously unknown\n            ds.repo.add_submodule(sm_path, url=clone_url)\n        _fixup_submodule_dotgit_setup(ds, sm_path)\n        return subds\n\n\n# TODO:  git_clone options\n# use --shared by default? => option --no-shared\n\n\nclass Install(Interface):\n    \"\"\"Install a dataset or subdataset.\n\n    This command creates a local :term:`sibling` of an existing dataset from a\n    (remote) location identified via a URL or path, or by the name of a\n    registered subdataset. Optional recursion into potential subdatasets, and\n    download of all referenced data is supported. The new dataset can be\n    optionally registered in an existing :term:`superdataset` (the new\n    dataset's path needs to be located within the superdataset for that, and\n    the superdataset will be detected automatically). It is recommended to\n    provide a brief description to label the dataset's nature *and* location,\n    e.g. \"Michael's music on black laptop\". This helps humans to identify data\n    locations in distributed scenarios.  By default an identifier comprised of\n    user and machine name, plus path will be generated.\n\n    When only partial dataset content shall be obtained, it is recommended to\n    use this command without the :option:`get-data` flag, followed by a\n    :func:`~datalad.api.get` operation to obtain the desired data.\n\n    .. note::\n      Power-user info: This command uses :command:`git clone`, and\n      :command:`git annex init` to prepare the dataset. Registering to a\n      superdataset is performed via a :command:`git submodule add` operation\n      in the discovered superdataset.\n    \"\"\"\n\n    _params_ = dict(\n        dataset=Parameter(\n            args=(\"-d\", \"--dataset\"),\n            # TODO: this probably changes to install into the dataset (add_to_super)\n            # and to install the thing 'just there' without operating 'on' a dataset.\n            # Adapt doc.\n            doc=\"\"\"specify the dataset to perform the install operation on.  If\n            no dataset is given, an attempt is made to identify the dataset\n            in a parent directory of the current working directory and/or the\n            `path` given\"\"\",\n            constraints=EnsureDataset() | EnsureNone()),\n        path=Parameter(\n            args=(\"path\",),\n            doc=\"\"\"path/name of the installation target.  If no `source` is\n            provided, and no `dataset` is given or detected, this is\n            interpreted as the source URL of a dataset and a destination\n            path will be derived from the URL similar to :command:`git\n            clone`\"\"\",\n            nargs=\"?\",\n            constraints=EnsureStr() | EnsureNone()),\n        source=Parameter(\n            args=(\"-s\", \"--source\",),\n            doc=\"URL or local path of the installation source\",\n            constraints=EnsureStr() | EnsureNone()),\n        get_data=Parameter(\n            args=(\"-g\", \"--get-data\",),\n            action=\"store_true\",\n            doc=\"\"\"if given, obtain all data content too\"\"\"),\n        description=dataset_description,\n        recursive=recursion_flag,\n        recursion_limit=recursion_limit,\n        if_dirty=if_dirty_opt,\n        save=nosave_opt,\n        git_opts=git_opts,\n        git_clone_opts=git_clone_opts,\n        annex_opts=annex_opts,\n        annex_init_opts=annex_init_opts)\n\n    @staticmethod\n    @datasetmethod(name='install')\n    def __call__(\n            path=None,\n            source=None,\n            dataset=None,\n            get_data=False,\n            description=None,\n            recursive=False,\n            recursion_limit=None,\n            if_dirty='save-before',\n            save=True,\n            git_opts=None,\n            git_clone_opts=None,\n            annex_opts=None,\n            annex_init_opts=None):\n\n        lgr.debug(\n            \"Installation attempt started. path=%r, source=%r, dataset=%r, \"\n            \"get_data=%r, description=%r, recursive=%r, recursion_limit=%r, \"\n            \"git_opts=%r, git_clone_opts=%r, annex_opts=%r, annex_init_opt=%r\",\n            path, source, dataset, get_data, description, recursive,\n            recursion_limit, git_opts, git_clone_opts, annex_opts,\n            annex_init_opts)\n\n        # shortcut\n        ds = dataset\n\n        _install_into_ds = False  # default\n        # did we explicitly get a dataset to install into?\n        # if we got a dataset, path will be resolved against it.\n        # Otherwise path will be resolved first.\n\n        if ds is not None:\n            _install_into_ds = True\n            if not isinstance(ds, Dataset):\n                ds = Dataset(ds)\n            if not ds.is_installed():\n                # TODO: possible magic: ds.install() for known subdataset 'ds'\n                raise ValueError(\"{0} needs to be installed in order to \"\n                                 \"install something into it.\".format(ds))\n            handle_dirty_dataset(ds, if_dirty)\n\n        # resolve the target location (if local) against the provided dataset\n        # or CWD:\n        if path is not None:\n            # Should work out just fine for regular paths, so no additional\n            # conditioning is necessary\n            path_ri = RI(path)\n            try:\n                # Wouldn't work for SSHRI ATM, see TODO within SSHRI\n                path = resolve_path(path_ri.localpath, ds)\n                # any `path` argument that point to something local now\n                # resolved and is no longer a URL\n            except ValueError:\n                # URL doesn't point to a local something\n                # so we have an actual URL in `path`. Since this is valid as a\n                # single positional argument, `source` has to be None at this\n                # point.\n\n                if is_datalad_compat_ri(path) and source is None:\n                    # we have an actual URL -> this should be the source\n                    lgr.debug(\n                        \"Single argument given to install, that doesn't seem to \"\n                        \"be a local path. \"\n                        \"Assuming the argument identifies a source location.\")\n                    source = path\n                    path = None\n\n                else:\n                    # `path` is neither a valid source nor a local path.\n                    # TODO: The only thing left is a known subdataset with a\n                    # name, that is not a path; Once we correctly distinguish\n                    # between path and name of a submodule, we need to consider\n                    # this.\n                    # For now: Just raise\n                    raise ValueError(\"Invalid path argument {0}\".format(path))\n\n        # `path` resolved, if there was any.\n\n        # we need a source to install from. Either we have one in `source` or\n        # it is implicit, since `path` is an already known subdataset or an\n        # existing dataset, that should be installed into the given dataset as a\n        # subdataset inplace.\n        # Note: For now, we do not consider a subdataset beneath a not yet\n        # installed level, since we do not know, whether this even is something\n        # to install (an actual Dataset) the only thing we know would be,\n        # that it is some path beneath it.\n        _install_sub = False\n\n        if _install_into_ds and source is None and path is not None:\n            # Check for `path` being a known subdataset:\n            if path in [opj(ds.path, sub)\n                        for sub in ds.get_subdatasets(recursive=True)]:\n                _install_sub = True\n                lgr.debug(\"Identified {0} as subdataset to \"\n                          \"install.\".format(path))\n            else:\n                # the only option left is an existing repo to be added inplace:\n                if exists(path) and GitRepo.is_valid_repo(path):\n                    lgr.debug(\"No source given, but path points to an existing \"\n                              \"repository and a dataset to install into was \"\n                              \"given. Assuming we want to install {0} \"\n                              \"inplace into {1}.\".format(path, ds))\n                    source = path\n\n        if source is None and not _install_sub and path is not None:\n            # we have no source and don't have a dataset to install into.\n            # could be a single positional argument, that points to a known\n            # subdataset.\n            # So, test for that last remaining option:\n\n            # if `path` was a known subdataset to be installed, let's assume\n            # it would be one:\n            assume_ds = Dataset(path)\n            candidate_super_ds = assume_ds.get_superdataset()\n\n            if candidate_super_ds and candidate_super_ds != assume_ds and \\\n                assume_ds.path in candidate_super_ds.get_subdatasets(absolute=True):\n\n                # `path` has a potential superdataset and is known to this\n                # candidate\n                _install_sub = True\n                _install_into_ds = True\n                ds = candidate_super_ds\n\n            else:\n                # no match, we can't deal with that `path` argument\n                # without a `source`:\n                raise InsufficientArgumentsError(\n                    \"Got no source to install from.\")\n\n        _install_inplace = False\n        if source == path:  # TODO: does it make sense to use realpath here?\n            if _install_into_ds:\n                _install_inplace = True\n            else:\n                raise InsufficientArgumentsError(\n                    \"Source and target are the same ({0}). This doesn't make \"\n                    \"sense without a dataset to install into.\".format(path))\n\n        # Possibly do conversion from source into a git-friendly url\n        source_url = _get_git_url_from_source(source, none_ok=True)\n\n        # derive target from source url:\n        if path is None and source_url is not None:\n            # we got nothing but a source. do something similar to git clone\n            # and derive the path from the source_url and continue\n            lgr.debug(\n                \"Neither dataset nor target installation path provided. \"\n                \"Assuming installation of a remote dataset. \"\n                \"Deriving destination path from given source {0}\".format(\n                    source_url))\n            path = _get_installationpath_from_url(source_url)\n            # since this is a relative `path`, resolve it:\n            path = resolve_path(path, ds)\n\n        if path is None:\n            # still no target => fail\n            raise InsufficientArgumentsError(\"Got no target to install to.\")\n\n        lgr.debug(\"Resolved installation target: {0}\".format(path))\n\n        # TODO: expandpath()?\n        # more checks, whether something exists and what it actually is?\n\n        ###########\n        # we should know everything necessary by now\n        # actual installation starts\n        ###########\n        lgr.info(\"Installing {0}{1}\".format(\n            path, \" from %s\" % source_url if source_url else \"\"\n        ))\n\n        installed_items = []\n        # FLOW GUIDE:\n        # four cases:\n        # 1. install into a dataset\n        #   1.1. we install a known subdataset\n        #        => git submodule update --init\n        #   1.2. we install an existing repo as a subdataset inplace\n        #        => git submodule add + magic\n        #   1.3. we install a new subdataset from an explicit source\n        #        => git submodule add\n        # 2. we \"just\" install from an explicit source\n        #    => git clone\n\n        if _install_into_ds:\n            # FLOW GUIDE: 1.\n            lgr.info(\"Install subdataset at: {0}\".format(path))\n\n            # express the destination path relative to the root of\n            # the dataset\n            relativepath = relpath(path, start=ds.path)\n            if relativepath.startswith(pardir):\n                raise ValueError(\"installation path outside dataset \"\n                                 \"({0})\".format(path))\n            lgr.debug(\"Resolved installation target relative to dataset \"\n                      \"{0}: {1}\".format(ds, relativepath))\n\n            if _install_sub:\n                # FLOW_GUIDE: 1.1.\n                submodule = [sm for sm in ds.repo.get_submodules()\n                             if sm.path == relativepath][0]\n\n                _install_subds_from_flexible_source(\n                    ds,\n                    submodule.path,\n                    submodule.url,\n                    recursive=False)\n                #ds.repo.update_submodule(relativepath, init=True)\n\n                # TODO: use _install_subds_from_flexible instead?\n                # it calls install again, but this is based on old install.\n                # So, need to figure it out\n                # Additional note: - does always git clone + add inplace\n\n            elif _install_inplace:\n                # FLOW GUIDE: 1.2.\n                _install_subds_inplace(ds, path, relpath(path, ds.path))\n                # TODO: Some success checks?\n            else:\n                # FLOW_GUIDE 1.3.\n                _install_subds_from_flexible_source(\n                    ds, relativepath,\n                    source_url, recursive=False)\n                #ds.repo.add_submodule(relativepath, url=source_url)\n        else:\n            # FLOW GUIDE: 2.\n            lgr.info(\"Install dataset at: {0}\".format(path))\n\n            # Currently assuming there is nothing at the target to deal with\n            # and rely on failures raising from the git call ...\n\n            target = Dataset(path)\n\n            # TODO\n            assert(target.repo is None)\n\n            # should not be the case, but we need to distinguish between failure\n            # of git-clone, due to existing target and an unsuccessful clone\n            # attempt. See below.\n            existed = target.path and exists(target.path)\n\n            vcs = None\n            # We possibly need to consider /.git URL\n            candidate_source_urls = [source_url]\n            if source_url and not source_url.rstrip('/').endswith('/.git'):\n                candidate_source_urls.append(\n                    '{0}/.git'.format(source_url.rstrip('/')))\n\n            for source_url_ in candidate_source_urls:\n                try:\n                    lgr.debug(\"Retrieving a dataset from URL: \"\n                              \"{0}\".format(source_url_))\n                    with swallow_logs():\n                        vcs = Install._get_new_vcs(target, source_url_)\n                    break  # do not bother with other sources if succeeded\n                except GitCommandError:\n                    lgr.debug(\"Failed to retrieve from URL: \"\n                              \"{0}\".format(source_url_))\n                    if not existed and target.path and exists(target.path):\n                        lgr.debug(\"Wiping out unsuccessful clone attempt at \"\n                                  \"{}\".format(target.path))\n                        rmtree(target.path)\n                    if source_url_ == candidate_source_urls[-1]:\n                        # Re-raise if failed even with the last candidate\n                        lgr.debug(\"Unable to establish repository instance at \"\n                                  \"{0} from {1}\"\n                                  \"\".format(target.path, candidate_source_urls))\n                        raise\n\n            # is automagically re-evaluated in the .repo property:\n            assert(target.repo)\n            # cloning done\n\n        # FLOW GUIDE: All four cases done.\n\n        # in any case check whether we need to annex init the installed thing:\n        if knows_annex(path):\n            # init annex when traces of a remote annex can be detected\n            lgr.info(\"Initializing annex repo at %s\", path)\n            AnnexRepo(path, init=True)\n\n        lgr.debug(\"Installation of {0} done.\".format(path)) ##TODO: installed DS instead of `path`\n        current_dataset = Dataset(path)\n        installed_items.append(current_dataset)\n\n        # Now, recursive calls:\n        if recursive:\n            if description:\n                lgr.warning(\"Description can't be assigned recursively.\")\n            subs = [Dataset(p) for p in\n                    current_dataset.get_subdatasets(recursive=True,\n                                                    recursion_limit=1,\n                                                    absolute=True)]\n            for subds in subs:\n                if subds.is_installed():\n                    lgr.debug(\"subdataset {0} already installed. Skipped.\".format(subds))\n                else:\n                    rec_installed = Install.__call__(\n                        path=subds.path,\n                        dataset=current_dataset,\n                        recursive=True,\n                        recursion_limit=recursion_limit - 1\n                        if recursion_limit else None,\n                        if_dirty=if_dirty,\n                        save=save,\n                        git_opts=git_opts,\n                        git_clone_opts=git_clone_opts,\n                        annex_opts=annex_opts,\n                        annex_init_opts=annex_init_opts)\n                    if isinstance(rec_installed, list):\n                        installed_items.extend(rec_installed)\n                    else:\n                        installed_items.append(rec_installed)\n\n        # get the content of installed (sub-)datasets:\n        if get_data:\n            for d in installed_items:\n                lgr.info(\"Getting data of {0}\".format(d))\n                if isinstance(d.repo, AnnexRepo):\n                    d.get(curdir)\n\n        # everything done => save changes:\n        if save and _install_into_ds:\n            # Note: The only possible changes are installed subdatasets.\n            # This means: We have something to save only, if we installed into\n            # a dataset.\n            lgr.info(\"Saving changes to {0}\".format(ds))\n            ds.save(\n                message='[DATALAD] installed subdataset{0}:{1}'.format(\n                    \"s\" if len(installed_items) > 1 else \"\",\n                    linesep + linesep.join([str(i) for i in installed_items])),\n                auto_add_changes=False,\n                recursive=False)\n\n        if len(installed_items) == 1:\n            return installed_items[0]\n        else:\n            return installed_items\n\n    @staticmethod\n    def _get_new_vcs(ds, source):\n        if source is None:\n            raise RuntimeError(\n                \"No `source` was provided. To create a new dataset \"\n                \"use the `create` command.\")\n        else:\n            # when obtained from remote, try with plain Git\n            lgr.info(\"Creating a new git repo at %s\", ds.path)\n            vcs = GitRepo(ds.path, url=source, create=True)\n            if knows_annex(ds.path):\n                # init annex when traces of a remote annex can be detected\n                lgr.info(\"Initializing annex repo at %s\", ds.path)\n                vcs = AnnexRepo(ds.path, init=True)\n            else:\n                lgr.debug(\"New repository clone has no traces of an annex\")\n        return vcs\n\n    @staticmethod\n    def result_renderer_cmdline(res, args):\n        from datalad.ui import ui\n        if res is None:\n            res = []\n        if not isinstance(res, list):\n            res = [res]\n        if not len(res):\n            ui.message(\"Nothing was installed\")\n            return\n        items = '\\n'.join(map(str, res))\n        msg = \"{n} installed {obj} available at\\n{items}\".format(\n            obj='items are' if len(res) > 1 else 'item is',\n            n=len(res),\n            items=items)\n        ui.message(msg)\n",
            "header": {
                "file": {
                    "path": "datalad/distribution/install.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "f3138ebe4",
                "new_commit_hash": "8ee836b3b",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/datalad/distribution/install.py"
            },
            "plus_file": {
                "path": "b/datalad/distribution/install.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 335,
                            "length": 7
                        },
                        "new_range": {
                            "start": 335,
                            "length": 7
                        },
                        "section": "class Install(Interface):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "                              \"inplace into {1}.\".format(path, ds))",
                                "type": "context"
                            },
                            {
                                "content": "                    source = path",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        if source is None and not _install_sub:",
                                "type": "deleted"
                            },
                            {
                                "content": "        if source is None and not _install_sub and path is not None:",
                                "type": "added"
                            },
                            {
                                "content": "            # we have no source and don't have a dataset to install into.",
                                "type": "context"
                            },
                            {
                                "content": "            # could be a single positional argument, that points to a known",
                                "type": "context"
                            },
                            {
                                "content": "            # subdataset.",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/distribution/install.py",
                            "type": "class",
                            "name": "Install",
                            "content": "class Install(Interface):\n    \"\"\"Install a dataset or subdataset.\n\n    This command creates a local :term:`sibling` of an existing dataset from a\n    (remote) location identified via a URL or path, or by the name of a\n    registered subdataset. Optional recursion into potential subdatasets, and\n    download of all referenced data is supported. The new dataset can be\n    optionally registered in an existing :term:`superdataset` (the new\n    dataset's path needs to be located within the superdataset for that, and\n    the superdataset will be detected automatically). It is recommended to\n    provide a brief description to label the dataset's nature *and* location,\n    e.g. \"Michael's music on black laptop\". This helps humans to identify data\n    locations in distributed scenarios.  By default an identifier comprised of\n    user and machine name, plus path will be generated.\n\n    When only partial dataset content shall be obtained, it is recommended to\n    use this command without the :option:`get-data` flag, followed by a\n    :func:`~datalad.api.get` operation to obtain the desired data.\n\n    .. note::\n      Power-user info: This command uses :command:`git clone`, and\n      :command:`git annex init` to prepare the dataset. Registering to a\n      superdataset is performed via a :command:`git submodule add` operation\n      in the discovered superdataset.\n    \"\"\"\n\n    _params_ = dict(\n        dataset=Parameter(\n            args=(\"-d\", \"--dataset\"),\n            # TODO: this probably changes to install into the dataset (add_to_super)\n            # and to install the thing 'just there' without operating 'on' a dataset.\n            # Adapt doc.\n            doc=\"\"\"specify the dataset to perform the install operation on.  If\n            no dataset is given, an attempt is made to identify the dataset\n            in a parent directory of the current working directory and/or the\n            `path` given\"\"\",\n            constraints=EnsureDataset() | EnsureNone()),\n        path=Parameter(\n            args=(\"path\",),\n            doc=\"\"\"path/name of the installation target.  If no `source` is\n            provided, and no `dataset` is given or detected, this is\n            interpreted as the source URL of a dataset and a destination\n            path will be derived from the URL similar to :command:`git\n            clone`\"\"\",\n            nargs=\"?\",\n            constraints=EnsureStr() | EnsureNone()),\n        source=Parameter(\n            args=(\"-s\", \"--source\",),\n            doc=\"URL or local path of the installation source\",\n            constraints=EnsureStr() | EnsureNone()),\n        get_data=Parameter(\n            args=(\"-g\", \"--get-data\",),\n            action=\"store_true\",\n            doc=\"\"\"if given, obtain all data content too\"\"\"),\n        description=dataset_description,\n        recursive=recursion_flag,\n        recursion_limit=recursion_limit,\n        if_dirty=if_dirty_opt,\n        save=nosave_opt,\n        git_opts=git_opts,\n        git_clone_opts=git_clone_opts,\n        annex_opts=annex_opts,\n        annex_init_opts=annex_init_opts)\n\n    @staticmethod\n    @datasetmethod(name='install')\n    def __call__(\n            path=None,\n            source=None,\n            dataset=None,\n            get_data=False,\n            description=None,\n            recursive=False,\n            recursion_limit=None,\n            if_dirty='save-before',\n            save=True,\n            git_opts=None,\n            git_clone_opts=None,\n            annex_opts=None,\n            annex_init_opts=None):\n\n        lgr.debug(\n            \"Installation attempt started. path=%r, source=%r, dataset=%r, \"\n            \"get_data=%r, description=%r, recursive=%r, recursion_limit=%r, \"\n            \"git_opts=%r, git_clone_opts=%r, annex_opts=%r, annex_init_opt=%r\",\n            path, source, dataset, get_data, description, recursive,\n            recursion_limit, git_opts, git_clone_opts, annex_opts,\n            annex_init_opts)\n\n        # shortcut\n        ds = dataset\n\n        _install_into_ds = False  # default\n        # did we explicitly get a dataset to install into?\n        # if we got a dataset, path will be resolved against it.\n        # Otherwise path will be resolved first.\n\n        if ds is not None:\n            _install_into_ds = True\n            if not isinstance(ds, Dataset):\n                ds = Dataset(ds)\n            if not ds.is_installed():\n                # TODO: possible magic: ds.install() for known subdataset 'ds'\n                raise ValueError(\"{0} needs to be installed in order to \"\n                                 \"install something into it.\".format(ds))\n            handle_dirty_dataset(ds, if_dirty)\n\n        # resolve the target location (if local) against the provided dataset\n        # or CWD:\n        if path is not None:\n            # Should work out just fine for regular paths, so no additional\n            # conditioning is necessary\n            path_ri = RI(path)\n            try:\n                # Wouldn't work for SSHRI ATM, see TODO within SSHRI\n                path = resolve_path(path_ri.localpath, ds)\n                # any `path` argument that point to something local now\n                # resolved and is no longer a URL\n            except ValueError:\n                # URL doesn't point to a local something\n                # so we have an actual URL in `path`. Since this is valid as a\n                # single positional argument, `source` has to be None at this\n                # point.\n\n                if is_datalad_compat_ri(path) and source is None:\n                    # we have an actual URL -> this should be the source\n                    lgr.debug(\n                        \"Single argument given to install, that doesn't seem to \"\n                        \"be a local path. \"\n                        \"Assuming the argument identifies a source location.\")\n                    source = path\n                    path = None\n\n                else:\n                    # `path` is neither a valid source nor a local path.\n                    # TODO: The only thing left is a known subdataset with a\n                    # name, that is not a path; Once we correctly distinguish\n                    # between path and name of a submodule, we need to consider\n                    # this.\n                    # For now: Just raise\n                    raise ValueError(\"Invalid path argument {0}\".format(path))\n\n        # `path` resolved, if there was any.\n\n        # we need a source to install from. Either we have one in `source` or\n        # it is implicit, since `path` is an already known subdataset or an\n        # existing dataset, that should be installed into the given dataset as a\n        # subdataset inplace.\n        # Note: For now, we do not consider a subdataset beneath a not yet\n        # installed level, since we do not know, whether this even is something\n        # to install (an actual Dataset) the only thing we know would be,\n        # that it is some path beneath it.\n        _install_sub = False\n\n        if _install_into_ds and source is None and path is not None:\n            # Check for `path` being a known subdataset:\n            if path in [opj(ds.path, sub)\n                        for sub in ds.get_subdatasets(recursive=True)]:\n                _install_sub = True\n                lgr.debug(\"Identified {0} as subdataset to \"\n                          \"install.\".format(path))\n            else:\n                # the only option left is an existing repo to be added inplace:\n                if exists(path) and GitRepo.is_valid_repo(path):\n                    lgr.debug(\"No source given, but path points to an existing \"\n                              \"repository and a dataset to install into was \"\n                              \"given. Assuming we want to install {0} \"\n                              \"inplace into {1}.\".format(path, ds))\n                    source = path\n\n        if source is None and not _install_sub:\n            # we have no source and don't have a dataset to install into.\n            # could be a single positional argument, that points to a known\n            # subdataset.\n            # So, test for that last remaining option:\n\n            # if `path` was a known subdataset to be installed, let's assume\n            # it would be one:\n            assume_ds = Dataset(path)\n            candidate_super_ds = assume_ds.get_superdataset()\n\n            if candidate_super_ds and candidate_super_ds != assume_ds and \\\n                assume_ds.path in candidate_super_ds.get_subdatasets(absolute=True):\n\n                # `path` has a potential superdataset and is known to this\n                # candidate\n                _install_sub = True\n                _install_into_ds = True\n                ds = candidate_super_ds\n\n            else:\n                # no match, we can't deal with that `path` argument\n                # without a `source`:\n                raise InsufficientArgumentsError(\n                    \"Got no source to install from.\")\n\n        _install_inplace = False\n        if source == path:  # TODO: does it make sense to use realpath here?\n            if _install_into_ds:\n                _install_inplace = True\n            else:\n                raise InsufficientArgumentsError(\n                    \"Source and target are the same ({0}). This doesn't make \"\n                    \"sense without a dataset to install into.\".format(path))\n\n        # Possibly do conversion from source into a git-friendly url\n        source_url = _get_git_url_from_source(source, none_ok=True)\n\n        # derive target from source url:\n        if path is None and source_url is not None:\n            # we got nothing but a source. do something similar to git clone\n            # and derive the path from the source_url and continue\n            lgr.debug(\n                \"Neither dataset nor target installation path provided. \"\n                \"Assuming installation of a remote dataset. \"\n                \"Deriving destination path from given source {0}\".format(\n                    source_url))\n            path = _get_installationpath_from_url(source_url)\n            # since this is a relative `path`, resolve it:\n            path = resolve_path(path, ds)\n\n        if path is None:\n            # still no target => fail\n            raise InsufficientArgumentsError(\"Got no target to install to.\")\n\n        lgr.debug(\"Resolved installation target: {0}\".format(path))\n\n        # TODO: expandpath()?\n        # more checks, whether something exists and what it actually is?\n\n        ###########\n        # we should know everything necessary by now\n        # actual installation starts\n        ###########\n        lgr.info(\"Installing {0}{1}\".format(\n            path, \" from %s\" % source_url if source_url else \"\"\n        ))\n\n        installed_items = []\n        # FLOW GUIDE:\n        # four cases:\n        # 1. install into a dataset\n        #   1.1. we install a known subdataset\n        #        => git submodule update --init\n        #   1.2. we install an existing repo as a subdataset inplace\n        #        => git submodule add + magic\n        #   1.3. we install a new subdataset from an explicit source\n        #        => git submodule add\n        # 2. we \"just\" install from an explicit source\n        #    => git clone\n\n        if _install_into_ds:\n            # FLOW GUIDE: 1.\n            lgr.info(\"Install subdataset at: {0}\".format(path))\n\n            # express the destination path relative to the root of\n            # the dataset\n            relativepath = relpath(path, start=ds.path)\n            if relativepath.startswith(pardir):\n                raise ValueError(\"installation path outside dataset \"\n                                 \"({0})\".format(path))\n            lgr.debug(\"Resolved installation target relative to dataset \"\n                      \"{0}: {1}\".format(ds, relativepath))\n\n            if _install_sub:\n                # FLOW_GUIDE: 1.1.\n                submodule = [sm for sm in ds.repo.get_submodules()\n                             if sm.path == relativepath][0]\n\n                _install_subds_from_flexible_source(\n                    ds,\n                    submodule.path,\n                    submodule.url,\n                    recursive=False)\n                #ds.repo.update_submodule(relativepath, init=True)\n\n                # TODO: use _install_subds_from_flexible instead?\n                # it calls install again, but this is based on old install.\n                # So, need to figure it out\n                # Additional note: - does always git clone + add inplace\n\n            elif _install_inplace:\n                # FLOW GUIDE: 1.2.\n                _install_subds_inplace(ds, path, relpath(path, ds.path))\n                # TODO: Some success checks?\n            else:\n                # FLOW_GUIDE 1.3.\n                _install_subds_from_flexible_source(\n                    ds, relativepath,\n                    source_url, recursive=False)\n                #ds.repo.add_submodule(relativepath, url=source_url)\n        else:\n            # FLOW GUIDE: 2.\n            lgr.info(\"Install dataset at: {0}\".format(path))\n\n            # Currently assuming there is nothing at the target to deal with\n            # and rely on failures raising from the git call ...\n\n            target = Dataset(path)\n\n            # TODO\n            assert(target.repo is None)\n\n            # should not be the case, but we need to distinguish between failure\n            # of git-clone, due to existing target and an unsuccessful clone\n            # attempt. See below.\n            existed = target.path and exists(target.path)\n\n            vcs = None\n            # We possibly need to consider /.git URL\n            candidate_source_urls = [source_url]\n            if source_url and not source_url.rstrip('/').endswith('/.git'):\n                candidate_source_urls.append(\n                    '{0}/.git'.format(source_url.rstrip('/')))\n\n            for source_url_ in candidate_source_urls:\n                try:\n                    lgr.debug(\"Retrieving a dataset from URL: \"\n                              \"{0}\".format(source_url_))\n                    with swallow_logs():\n                        vcs = Install._get_new_vcs(target, source_url_)\n                    break  # do not bother with other sources if succeeded\n                except GitCommandError:\n                    lgr.debug(\"Failed to retrieve from URL: \"\n                              \"{0}\".format(source_url_))\n                    if not existed and target.path and exists(target.path):\n                        lgr.debug(\"Wiping out unsuccessful clone attempt at \"\n                                  \"{}\".format(target.path))\n                        rmtree(target.path)\n                    if source_url_ == candidate_source_urls[-1]:\n                        # Re-raise if failed even with the last candidate\n                        lgr.debug(\"Unable to establish repository instance at \"\n                                  \"{0} from {1}\"\n                                  \"\".format(target.path, candidate_source_urls))\n                        raise\n\n            # is automagically re-evaluated in the .repo property:\n            assert(target.repo)\n            # cloning done\n\n        # FLOW GUIDE: All four cases done.\n\n        # in any case check whether we need to annex init the installed thing:\n        if knows_annex(path):\n            # init annex when traces of a remote annex can be detected\n            lgr.info(\"Initializing annex repo at %s\", path)\n            AnnexRepo(path, init=True)\n\n        lgr.debug(\"Installation of {0} done.\".format(path)) ##TODO: installed DS instead of `path`\n        current_dataset = Dataset(path)\n        installed_items.append(current_dataset)\n\n        # Now, recursive calls:\n        if recursive:\n            if description:\n                lgr.warning(\"Description can't be assigned recursively.\")\n            subs = [Dataset(p) for p in\n                    current_dataset.get_subdatasets(recursive=True,\n                                                    recursion_limit=1,\n                                                    absolute=True)]\n            for subds in subs:\n                if subds.is_installed():\n                    lgr.debug(\"subdataset {0} already installed. Skipped.\".format(subds))\n                else:\n                    rec_installed = Install.__call__(\n                        path=subds.path,\n                        dataset=current_dataset,\n                        recursive=True,\n                        recursion_limit=recursion_limit - 1\n                        if recursion_limit else None,\n                        if_dirty=if_dirty,\n                        save=save,\n                        git_opts=git_opts,\n                        git_clone_opts=git_clone_opts,\n                        annex_opts=annex_opts,\n                        annex_init_opts=annex_init_opts)\n                    if isinstance(rec_installed, list):\n                        installed_items.extend(rec_installed)\n                    else:\n                        installed_items.append(rec_installed)\n\n        # get the content of installed (sub-)datasets:\n        if get_data:\n            for d in installed_items:\n                lgr.info(\"Getting data of {0}\".format(d))\n                if isinstance(d.repo, AnnexRepo):\n                    d.get(curdir)\n\n        # everything done => save changes:\n        if save and _install_into_ds:\n            # Note: The only possible changes are installed subdatasets.\n            # This means: We have something to save only, if we installed into\n            # a dataset.\n            lgr.info(\"Saving changes to {0}\".format(ds))\n            ds.save(\n                message='[DATALAD] installed subdataset{0}:{1}'.format(\n                    \"s\" if len(installed_items) > 1 else \"\",\n                    linesep + linesep.join([str(i) for i in installed_items])),\n                auto_add_changes=False,\n                recursive=False)\n\n        if len(installed_items) == 1:\n            return installed_items[0]\n        else:\n            return installed_items\n\n    @staticmethod\n    def _get_new_vcs(ds, source):\n        if source is None:\n            raise RuntimeError(\n                \"No `source` was provided. To create a new dataset \"\n                \"use the `create` command.\")\n        else:\n            # when obtained from remote, try with plain Git\n            lgr.info(\"Creating a new git repo at %s\", ds.path)\n            vcs = GitRepo(ds.path, url=source, create=True)\n            if knows_annex(ds.path):\n                # init annex when traces of a remote annex can be detected\n                lgr.info(\"Initializing annex repo at %s\", ds.path)\n                vcs = AnnexRepo(ds.path, init=True)\n            else:\n                lgr.debug(\"New repository clone has no traces of an annex\")\n        return vcs\n\n    @staticmethod\n    def result_renderer_cmdline(res, args):\n        from datalad.ui import ui\n        if res is None:\n            res = []\n        if not isinstance(res, list):\n            res = [res]\n        if not len(res):\n            ui.message(\"Nothing was installed\")\n            return\n        items = '\\n'.join(map(str, res))\n        msg = \"{n} installed {obj} available at\\n{items}\".format(\n            obj='items are' if len(res) > 1 else 'item is',\n            n=len(res),\n            items=items)\n        ui.message(msg)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 168,
                            "end_lineno": 607,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/distribution/install.py",
                            "type": "method",
                            "name": "Install.__call__",
                            "content": "class Install(Interface):\n    \"\"\"Install a dataset or subdataset.\n\n    This command creates a local :term:`sibling` of an existing dataset from a\n    (remote) location identified via a URL or path, or by the name of a\n    registered subdataset. Optional recursion into potential subdatasets, and\n    download of all referenced data is supported. The new dataset can be\n    optionally registered in an existing :term:`superdataset` (the new\n    dataset's path needs to be located within the superdataset for that, and\n    the superdataset will be detected automatically). It is recommended to\n    provide a brief description to label the dataset's nature *and* location,\n    e.g. \"Michael's music on black laptop\". This helps humans to identify data\n    locations in distributed scenarios.  By default an identifier comprised of\n    user and machine name, plus path will be generated.\n\n    When only partial dataset content shall be obtained, it is recommended to\n    use this command without the :option:`get-data` flag, followed by a\n    :func:`~datalad.api.get` operation to obtain the desired data.\n\n    .. note::\n      Power-user info: This command uses :command:`git clone`, and\n      :command:`git annex init` to prepare the dataset. Registering to a\n      superdataset is performed via a :command:`git submodule add` operation\n      in the discovered superdataset.\n    \"\"\"\n\n    _params_ = dict(\n        dataset=Parameter(\n            args=(\"-d\", \"--dataset\"),\n            # TODO: this probably changes to install into the dataset (add_to_super)\n            # and to install the thing 'just there' without operating 'on' a dataset.\n            # Adapt doc.\n            doc=\"\"\"specify the dataset to perform the install operation on.  If\n            no dataset is given, an attempt is made to identify the dataset\n            in a parent directory of the current working directory and/or the\n            `path` given\"\"\",\n            constraints=EnsureDataset() | EnsureNone()),\n        path=Parameter(\n            args=(\"path\",),\n            doc=\"\"\"path/name of the installation target.  If no `source` is\n            provided, and no `dataset` is given or detected, this is\n            interpreted as the source URL of a dataset and a destination\n            path will be derived from the URL similar to :command:`git\n            clone`\"\"\",\n            nargs=\"?\",\n            constraints=EnsureStr() | EnsureNone()),\n        source=Parameter(\n            args=(\"-s\", \"--source\",),\n            doc=\"URL or local path of the installation source\",\n            constraints=EnsureStr() | EnsureNone()),\n        get_data=Parameter(\n            args=(\"-g\", \"--get-data\",),\n            action=\"store_true\",\n            doc=\"\"\"if given, obtain all data content too\"\"\"),\n        description=dataset_description,\n        recursive=recursion_flag,\n        recursion_limit=recursion_limit,\n        if_dirty=if_dirty_opt,\n        save=nosave_opt,\n        git_opts=git_opts,\n        git_clone_opts=git_clone_opts,\n        annex_opts=annex_opts,\n        annex_init_opts=annex_init_opts)\n\n    @staticmethod\n    @datasetmethod(name='install')\n    def __call__(\n            path=None,\n            source=None,\n            dataset=None,\n            get_data=False,\n            description=None,\n            recursive=False,\n            recursion_limit=None,\n            if_dirty='save-before',\n            save=True,\n            git_opts=None,\n            git_clone_opts=None,\n            annex_opts=None,\n            annex_init_opts=None):\n\n        lgr.debug(\n            \"Installation attempt started. path=%r, source=%r, dataset=%r, \"\n            \"get_data=%r, description=%r, recursive=%r, recursion_limit=%r, \"\n            \"git_opts=%r, git_clone_opts=%r, annex_opts=%r, annex_init_opt=%r\",\n            path, source, dataset, get_data, description, recursive,\n            recursion_limit, git_opts, git_clone_opts, annex_opts,\n            annex_init_opts)\n\n        # shortcut\n        ds = dataset\n\n        _install_into_ds = False  # default\n        # did we explicitly get a dataset to install into?\n        # if we got a dataset, path will be resolved against it.\n        # Otherwise path will be resolved first.\n\n        if ds is not None:\n            _install_into_ds = True\n            if not isinstance(ds, Dataset):\n                ds = Dataset(ds)\n            if not ds.is_installed():\n                # TODO: possible magic: ds.install() for known subdataset 'ds'\n                raise ValueError(\"{0} needs to be installed in order to \"\n                                 \"install something into it.\".format(ds))\n            handle_dirty_dataset(ds, if_dirty)\n\n        # resolve the target location (if local) against the provided dataset\n        # or CWD:\n        if path is not None:\n            # Should work out just fine for regular paths, so no additional\n            # conditioning is necessary\n            path_ri = RI(path)\n            try:\n                # Wouldn't work for SSHRI ATM, see TODO within SSHRI\n                path = resolve_path(path_ri.localpath, ds)\n                # any `path` argument that point to something local now\n                # resolved and is no longer a URL\n            except ValueError:\n                # URL doesn't point to a local something\n                # so we have an actual URL in `path`. Since this is valid as a\n                # single positional argument, `source` has to be None at this\n                # point.\n\n                if is_datalad_compat_ri(path) and source is None:\n                    # we have an actual URL -> this should be the source\n                    lgr.debug(\n                        \"Single argument given to install, that doesn't seem to \"\n                        \"be a local path. \"\n                        \"Assuming the argument identifies a source location.\")\n                    source = path\n                    path = None\n\n                else:\n                    # `path` is neither a valid source nor a local path.\n                    # TODO: The only thing left is a known subdataset with a\n                    # name, that is not a path; Once we correctly distinguish\n                    # between path and name of a submodule, we need to consider\n                    # this.\n                    # For now: Just raise\n                    raise ValueError(\"Invalid path argument {0}\".format(path))\n\n        # `path` resolved, if there was any.\n\n        # we need a source to install from. Either we have one in `source` or\n        # it is implicit, since `path` is an already known subdataset or an\n        # existing dataset, that should be installed into the given dataset as a\n        # subdataset inplace.\n        # Note: For now, we do not consider a subdataset beneath a not yet\n        # installed level, since we do not know, whether this even is something\n        # to install (an actual Dataset) the only thing we know would be,\n        # that it is some path beneath it.\n        _install_sub = False\n\n        if _install_into_ds and source is None and path is not None:\n            # Check for `path` being a known subdataset:\n            if path in [opj(ds.path, sub)\n                        for sub in ds.get_subdatasets(recursive=True)]:\n                _install_sub = True\n                lgr.debug(\"Identified {0} as subdataset to \"\n                          \"install.\".format(path))\n            else:\n                # the only option left is an existing repo to be added inplace:\n                if exists(path) and GitRepo.is_valid_repo(path):\n                    lgr.debug(\"No source given, but path points to an existing \"\n                              \"repository and a dataset to install into was \"\n                              \"given. Assuming we want to install {0} \"\n                              \"inplace into {1}.\".format(path, ds))\n                    source = path\n\n        if source is None and not _install_sub:\n            # we have no source and don't have a dataset to install into.\n            # could be a single positional argument, that points to a known\n            # subdataset.\n            # So, test for that last remaining option:\n\n            # if `path` was a known subdataset to be installed, let's assume\n            # it would be one:\n            assume_ds = Dataset(path)\n            candidate_super_ds = assume_ds.get_superdataset()\n\n            if candidate_super_ds and candidate_super_ds != assume_ds and \\\n                assume_ds.path in candidate_super_ds.get_subdatasets(absolute=True):\n\n                # `path` has a potential superdataset and is known to this\n                # candidate\n                _install_sub = True\n                _install_into_ds = True\n                ds = candidate_super_ds\n\n            else:\n                # no match, we can't deal with that `path` argument\n                # without a `source`:\n                raise InsufficientArgumentsError(\n                    \"Got no source to install from.\")\n\n        _install_inplace = False\n        if source == path:  # TODO: does it make sense to use realpath here?\n            if _install_into_ds:\n                _install_inplace = True\n            else:\n                raise InsufficientArgumentsError(\n                    \"Source and target are the same ({0}). This doesn't make \"\n                    \"sense without a dataset to install into.\".format(path))\n\n        # Possibly do conversion from source into a git-friendly url\n        source_url = _get_git_url_from_source(source, none_ok=True)\n\n        # derive target from source url:\n        if path is None and source_url is not None:\n            # we got nothing but a source. do something similar to git clone\n            # and derive the path from the source_url and continue\n            lgr.debug(\n                \"Neither dataset nor target installation path provided. \"\n                \"Assuming installation of a remote dataset. \"\n                \"Deriving destination path from given source {0}\".format(\n                    source_url))\n            path = _get_installationpath_from_url(source_url)\n            # since this is a relative `path`, resolve it:\n            path = resolve_path(path, ds)\n\n        if path is None:\n            # still no target => fail\n            raise InsufficientArgumentsError(\"Got no target to install to.\")\n\n        lgr.debug(\"Resolved installation target: {0}\".format(path))\n\n        # TODO: expandpath()?\n        # more checks, whether something exists and what it actually is?\n\n        ###########\n        # we should know everything necessary by now\n        # actual installation starts\n        ###########\n        lgr.info(\"Installing {0}{1}\".format(\n            path, \" from %s\" % source_url if source_url else \"\"\n        ))\n\n        installed_items = []\n        # FLOW GUIDE:\n        # four cases:\n        # 1. install into a dataset\n        #   1.1. we install a known subdataset\n        #        => git submodule update --init\n        #   1.2. we install an existing repo as a subdataset inplace\n        #        => git submodule add + magic\n        #   1.3. we install a new subdataset from an explicit source\n        #        => git submodule add\n        # 2. we \"just\" install from an explicit source\n        #    => git clone\n\n        if _install_into_ds:\n            # FLOW GUIDE: 1.\n            lgr.info(\"Install subdataset at: {0}\".format(path))\n\n            # express the destination path relative to the root of\n            # the dataset\n            relativepath = relpath(path, start=ds.path)\n            if relativepath.startswith(pardir):\n                raise ValueError(\"installation path outside dataset \"\n                                 \"({0})\".format(path))\n            lgr.debug(\"Resolved installation target relative to dataset \"\n                      \"{0}: {1}\".format(ds, relativepath))\n\n            if _install_sub:\n                # FLOW_GUIDE: 1.1.\n                submodule = [sm for sm in ds.repo.get_submodules()\n                             if sm.path == relativepath][0]\n\n                _install_subds_from_flexible_source(\n                    ds,\n                    submodule.path,\n                    submodule.url,\n                    recursive=False)\n                #ds.repo.update_submodule(relativepath, init=True)\n\n                # TODO: use _install_subds_from_flexible instead?\n                # it calls install again, but this is based on old install.\n                # So, need to figure it out\n                # Additional note: - does always git clone + add inplace\n\n            elif _install_inplace:\n                # FLOW GUIDE: 1.2.\n                _install_subds_inplace(ds, path, relpath(path, ds.path))\n                # TODO: Some success checks?\n            else:\n                # FLOW_GUIDE 1.3.\n                _install_subds_from_flexible_source(\n                    ds, relativepath,\n                    source_url, recursive=False)\n                #ds.repo.add_submodule(relativepath, url=source_url)\n        else:\n            # FLOW GUIDE: 2.\n            lgr.info(\"Install dataset at: {0}\".format(path))\n\n            # Currently assuming there is nothing at the target to deal with\n            # and rely on failures raising from the git call ...\n\n            target = Dataset(path)\n\n            # TODO\n            assert(target.repo is None)\n\n            # should not be the case, but we need to distinguish between failure\n            # of git-clone, due to existing target and an unsuccessful clone\n            # attempt. See below.\n            existed = target.path and exists(target.path)\n\n            vcs = None\n            # We possibly need to consider /.git URL\n            candidate_source_urls = [source_url]\n            if source_url and not source_url.rstrip('/').endswith('/.git'):\n                candidate_source_urls.append(\n                    '{0}/.git'.format(source_url.rstrip('/')))\n\n            for source_url_ in candidate_source_urls:\n                try:\n                    lgr.debug(\"Retrieving a dataset from URL: \"\n                              \"{0}\".format(source_url_))\n                    with swallow_logs():\n                        vcs = Install._get_new_vcs(target, source_url_)\n                    break  # do not bother with other sources if succeeded\n                except GitCommandError:\n                    lgr.debug(\"Failed to retrieve from URL: \"\n                              \"{0}\".format(source_url_))\n                    if not existed and target.path and exists(target.path):\n                        lgr.debug(\"Wiping out unsuccessful clone attempt at \"\n                                  \"{}\".format(target.path))\n                        rmtree(target.path)\n                    if source_url_ == candidate_source_urls[-1]:\n                        # Re-raise if failed even with the last candidate\n                        lgr.debug(\"Unable to establish repository instance at \"\n                                  \"{0} from {1}\"\n                                  \"\".format(target.path, candidate_source_urls))\n                        raise\n\n            # is automagically re-evaluated in the .repo property:\n            assert(target.repo)\n            # cloning done\n\n        # FLOW GUIDE: All four cases done.\n\n        # in any case check whether we need to annex init the installed thing:\n        if knows_annex(path):\n            # init annex when traces of a remote annex can be detected\n            lgr.info(\"Initializing annex repo at %s\", path)\n            AnnexRepo(path, init=True)\n\n        lgr.debug(\"Installation of {0} done.\".format(path)) ##TODO: installed DS instead of `path`\n        current_dataset = Dataset(path)\n        installed_items.append(current_dataset)\n\n        # Now, recursive calls:\n        if recursive:\n            if description:\n                lgr.warning(\"Description can't be assigned recursively.\")\n            subs = [Dataset(p) for p in\n                    current_dataset.get_subdatasets(recursive=True,\n                                                    recursion_limit=1,\n                                                    absolute=True)]\n            for subds in subs:\n                if subds.is_installed():\n                    lgr.debug(\"subdataset {0} already installed. Skipped.\".format(subds))\n                else:\n                    rec_installed = Install.__call__(\n                        path=subds.path,\n                        dataset=current_dataset,\n                        recursive=True,\n                        recursion_limit=recursion_limit - 1\n                        if recursion_limit else None,\n                        if_dirty=if_dirty,\n                        save=save,\n                        git_opts=git_opts,\n                        git_clone_opts=git_clone_opts,\n                        annex_opts=annex_opts,\n                        annex_init_opts=annex_init_opts)\n                    if isinstance(rec_installed, list):\n                        installed_items.extend(rec_installed)\n                    else:\n                        installed_items.append(rec_installed)\n\n        # get the content of installed (sub-)datasets:\n        if get_data:\n            for d in installed_items:\n                lgr.info(\"Getting data of {0}\".format(d))\n                if isinstance(d.repo, AnnexRepo):\n                    d.get(curdir)\n\n        # everything done => save changes:\n        if save and _install_into_ds:\n            # Note: The only possible changes are installed subdatasets.\n            # This means: We have something to save only, if we installed into\n            # a dataset.\n            lgr.info(\"Saving changes to {0}\".format(ds))\n            ds.save(\n                message='[DATALAD] installed subdataset{0}:{1}'.format(\n                    \"s\" if len(installed_items) > 1 else \"\",\n                    linesep + linesep.join([str(i) for i in installed_items])),\n                auto_add_changes=False,\n                recursive=False)\n\n        if len(installed_items) == 1:\n            return installed_items[0]\n        else:\n            return installed_items\n\n    @staticmethod\n    def _get_new_vcs(ds, source):\n        if source is None:\n            raise RuntimeError(\n                \"No `source` was provided. To create a new dataset \"\n                \"use the `create` command.\")\n        else:\n            # when obtained from remote, try with plain Git\n            lgr.info(\"Creating a new git repo at %s\", ds.path)\n            vcs = GitRepo(ds.path, url=source, create=True)\n            if knows_annex(ds.path):\n                # init annex when traces of a remote annex can be detected\n                lgr.info(\"Initializing annex repo at %s\", ds.path)\n                vcs = AnnexRepo(ds.path, init=True)\n            else:\n                lgr.debug(\"New repository clone has no traces of an annex\")\n        return vcs\n\n    @staticmethod\n    def result_renderer_cmdline(res, args):\n        from datalad.ui import ui\n        if res is None:\n            res = []\n        if not isinstance(res, list):\n            res = [res]\n        if not len(res):\n            ui.message(\"Nothing was installed\")\n            return\n        items = '\\n'.join(map(str, res))\n        msg = \"{n} installed {obj} available at\\n{items}\".format(\n            obj='items are' if len(res) > 1 else 'item is',\n            n=len(res),\n            items=items)\n        ui.message(msg)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 234,
                            "end_lineno": 572,
                            "parent": {
                                "file_name": "datalad/distribution/install.py",
                                "type": "class",
                                "name": "Install",
                                "content": "class Install(Interface):\n    \"\"\"Install a dataset or subdataset.\n\n    This command creates a local :term:`sibling` of an existing dataset from a\n    (remote) location identified via a URL or path, or by the name of a\n    registered subdataset. Optional recursion into potential subdatasets, and\n    download of all referenced data is supported. The new dataset can be\n    optionally registered in an existing :term:`superdataset` (the new\n    dataset's path needs to be located within the superdataset for that, and\n    the superdataset will be detected automatically). It is recommended to\n    provide a brief description to label the dataset's nature *and* location,\n    e.g. \"Michael's music on black laptop\". This helps humans to identify data\n    locations in distributed scenarios.  By default an identifier comprised of\n    user and machine name, plus path will be generated.\n\n    When only partial dataset content shall be obtained, it is recommended to\n    use this command without the :option:`get-data` flag, followed by a\n    :func:`~datalad.api.get` operation to obtain the desired data.\n\n    .. note::\n      Power-user info: This command uses :command:`git clone`, and\n      :command:`git annex init` to prepare the dataset. Registering to a\n      superdataset is performed via a :command:`git submodule add` operation\n      in the discovered superdataset.\n    \"\"\"\n\n    _params_ = dict(\n        dataset=Parameter(\n            args=(\"-d\", \"--dataset\"),\n            # TODO: this probably changes to install into the dataset (add_to_super)\n            # and to install the thing 'just there' without operating 'on' a dataset.\n            # Adapt doc.\n            doc=\"\"\"specify the dataset to perform the install operation on.  If\n            no dataset is given, an attempt is made to identify the dataset\n            in a parent directory of the current working directory and/or the\n            `path` given\"\"\",\n            constraints=EnsureDataset() | EnsureNone()),\n        path=Parameter(\n            args=(\"path\",),\n            doc=\"\"\"path/name of the installation target.  If no `source` is\n            provided, and no `dataset` is given or detected, this is\n            interpreted as the source URL of a dataset and a destination\n            path will be derived from the URL similar to :command:`git\n            clone`\"\"\",\n            nargs=\"?\",\n            constraints=EnsureStr() | EnsureNone()),\n        source=Parameter(\n            args=(\"-s\", \"--source\",),\n            doc=\"URL or local path of the installation source\",\n            constraints=EnsureStr() | EnsureNone()),\n        get_data=Parameter(\n            args=(\"-g\", \"--get-data\",),\n            action=\"store_true\",\n            doc=\"\"\"if given, obtain all data content too\"\"\"),\n        description=dataset_description,\n        recursive=recursion_flag,\n        recursion_limit=recursion_limit,\n        if_dirty=if_dirty_opt,\n        save=nosave_opt,\n        git_opts=git_opts,\n        git_clone_opts=git_clone_opts,\n        annex_opts=annex_opts,\n        annex_init_opts=annex_init_opts)\n\n    @staticmethod\n    @datasetmethod(name='install')\n    def __call__(\n            path=None,\n            source=None,\n            dataset=None,\n            get_data=False,\n            description=None,\n            recursive=False,\n            recursion_limit=None,\n            if_dirty='save-before',\n            save=True,\n            git_opts=None,\n            git_clone_opts=None,\n            annex_opts=None,\n            annex_init_opts=None):\n\n        lgr.debug(\n            \"Installation attempt started. path=%r, source=%r, dataset=%r, \"\n            \"get_data=%r, description=%r, recursive=%r, recursion_limit=%r, \"\n            \"git_opts=%r, git_clone_opts=%r, annex_opts=%r, annex_init_opt=%r\",\n            path, source, dataset, get_data, description, recursive,\n            recursion_limit, git_opts, git_clone_opts, annex_opts,\n            annex_init_opts)\n\n        # shortcut\n        ds = dataset\n\n        _install_into_ds = False  # default\n        # did we explicitly get a dataset to install into?\n        # if we got a dataset, path will be resolved against it.\n        # Otherwise path will be resolved first.\n\n        if ds is not None:\n            _install_into_ds = True\n            if not isinstance(ds, Dataset):\n                ds = Dataset(ds)\n            if not ds.is_installed():\n                # TODO: possible magic: ds.install() for known subdataset 'ds'\n                raise ValueError(\"{0} needs to be installed in order to \"\n                                 \"install something into it.\".format(ds))\n            handle_dirty_dataset(ds, if_dirty)\n\n        # resolve the target location (if local) against the provided dataset\n        # or CWD:\n        if path is not None:\n            # Should work out just fine for regular paths, so no additional\n            # conditioning is necessary\n            path_ri = RI(path)\n            try:\n                # Wouldn't work for SSHRI ATM, see TODO within SSHRI\n                path = resolve_path(path_ri.localpath, ds)\n                # any `path` argument that point to something local now\n                # resolved and is no longer a URL\n            except ValueError:\n                # URL doesn't point to a local something\n                # so we have an actual URL in `path`. Since this is valid as a\n                # single positional argument, `source` has to be None at this\n                # point.\n\n                if is_datalad_compat_ri(path) and source is None:\n                    # we have an actual URL -> this should be the source\n                    lgr.debug(\n                        \"Single argument given to install, that doesn't seem to \"\n                        \"be a local path. \"\n                        \"Assuming the argument identifies a source location.\")\n                    source = path\n                    path = None\n\n                else:\n                    # `path` is neither a valid source nor a local path.\n                    # TODO: The only thing left is a known subdataset with a\n                    # name, that is not a path; Once we correctly distinguish\n                    # between path and name of a submodule, we need to consider\n                    # this.\n                    # For now: Just raise\n                    raise ValueError(\"Invalid path argument {0}\".format(path))\n\n        # `path` resolved, if there was any.\n\n        # we need a source to install from. Either we have one in `source` or\n        # it is implicit, since `path` is an already known subdataset or an\n        # existing dataset, that should be installed into the given dataset as a\n        # subdataset inplace.\n        # Note: For now, we do not consider a subdataset beneath a not yet\n        # installed level, since we do not know, whether this even is something\n        # to install (an actual Dataset) the only thing we know would be,\n        # that it is some path beneath it.\n        _install_sub = False\n\n        if _install_into_ds and source is None and path is not None:\n            # Check for `path` being a known subdataset:\n            if path in [opj(ds.path, sub)\n                        for sub in ds.get_subdatasets(recursive=True)]:\n                _install_sub = True\n                lgr.debug(\"Identified {0} as subdataset to \"\n                          \"install.\".format(path))\n            else:\n                # the only option left is an existing repo to be added inplace:\n                if exists(path) and GitRepo.is_valid_repo(path):\n                    lgr.debug(\"No source given, but path points to an existing \"\n                              \"repository and a dataset to install into was \"\n                              \"given. Assuming we want to install {0} \"\n                              \"inplace into {1}.\".format(path, ds))\n                    source = path\n\n        if source is None and not _install_sub:\n            # we have no source and don't have a dataset to install into.\n            # could be a single positional argument, that points to a known\n            # subdataset.\n            # So, test for that last remaining option:\n\n            # if `path` was a known subdataset to be installed, let's assume\n            # it would be one:\n            assume_ds = Dataset(path)\n            candidate_super_ds = assume_ds.get_superdataset()\n\n            if candidate_super_ds and candidate_super_ds != assume_ds and \\\n                assume_ds.path in candidate_super_ds.get_subdatasets(absolute=True):\n\n                # `path` has a potential superdataset and is known to this\n                # candidate\n                _install_sub = True\n                _install_into_ds = True\n                ds = candidate_super_ds\n\n            else:\n                # no match, we can't deal with that `path` argument\n                # without a `source`:\n                raise InsufficientArgumentsError(\n                    \"Got no source to install from.\")\n\n        _install_inplace = False\n        if source == path:  # TODO: does it make sense to use realpath here?\n            if _install_into_ds:\n                _install_inplace = True\n            else:\n                raise InsufficientArgumentsError(\n                    \"Source and target are the same ({0}). This doesn't make \"\n                    \"sense without a dataset to install into.\".format(path))\n\n        # Possibly do conversion from source into a git-friendly url\n        source_url = _get_git_url_from_source(source, none_ok=True)\n\n        # derive target from source url:\n        if path is None and source_url is not None:\n            # we got nothing but a source. do something similar to git clone\n            # and derive the path from the source_url and continue\n            lgr.debug(\n                \"Neither dataset nor target installation path provided. \"\n                \"Assuming installation of a remote dataset. \"\n                \"Deriving destination path from given source {0}\".format(\n                    source_url))\n            path = _get_installationpath_from_url(source_url)\n            # since this is a relative `path`, resolve it:\n            path = resolve_path(path, ds)\n\n        if path is None:\n            # still no target => fail\n            raise InsufficientArgumentsError(\"Got no target to install to.\")\n\n        lgr.debug(\"Resolved installation target: {0}\".format(path))\n\n        # TODO: expandpath()?\n        # more checks, whether something exists and what it actually is?\n\n        ###########\n        # we should know everything necessary by now\n        # actual installation starts\n        ###########\n        lgr.info(\"Installing {0}{1}\".format(\n            path, \" from %s\" % source_url if source_url else \"\"\n        ))\n\n        installed_items = []\n        # FLOW GUIDE:\n        # four cases:\n        # 1. install into a dataset\n        #   1.1. we install a known subdataset\n        #        => git submodule update --init\n        #   1.2. we install an existing repo as a subdataset inplace\n        #        => git submodule add + magic\n        #   1.3. we install a new subdataset from an explicit source\n        #        => git submodule add\n        # 2. we \"just\" install from an explicit source\n        #    => git clone\n\n        if _install_into_ds:\n            # FLOW GUIDE: 1.\n            lgr.info(\"Install subdataset at: {0}\".format(path))\n\n            # express the destination path relative to the root of\n            # the dataset\n            relativepath = relpath(path, start=ds.path)\n            if relativepath.startswith(pardir):\n                raise ValueError(\"installation path outside dataset \"\n                                 \"({0})\".format(path))\n            lgr.debug(\"Resolved installation target relative to dataset \"\n                      \"{0}: {1}\".format(ds, relativepath))\n\n            if _install_sub:\n                # FLOW_GUIDE: 1.1.\n                submodule = [sm for sm in ds.repo.get_submodules()\n                             if sm.path == relativepath][0]\n\n                _install_subds_from_flexible_source(\n                    ds,\n                    submodule.path,\n                    submodule.url,\n                    recursive=False)\n                #ds.repo.update_submodule(relativepath, init=True)\n\n                # TODO: use _install_subds_from_flexible instead?\n                # it calls install again, but this is based on old install.\n                # So, need to figure it out\n                # Additional note: - does always git clone + add inplace\n\n            elif _install_inplace:\n                # FLOW GUIDE: 1.2.\n                _install_subds_inplace(ds, path, relpath(path, ds.path))\n                # TODO: Some success checks?\n            else:\n                # FLOW_GUIDE 1.3.\n                _install_subds_from_flexible_source(\n                    ds, relativepath,\n                    source_url, recursive=False)\n                #ds.repo.add_submodule(relativepath, url=source_url)\n        else:\n            # FLOW GUIDE: 2.\n            lgr.info(\"Install dataset at: {0}\".format(path))\n\n            # Currently assuming there is nothing at the target to deal with\n            # and rely on failures raising from the git call ...\n\n            target = Dataset(path)\n\n            # TODO\n            assert(target.repo is None)\n\n            # should not be the case, but we need to distinguish between failure\n            # of git-clone, due to existing target and an unsuccessful clone\n            # attempt. See below.\n            existed = target.path and exists(target.path)\n\n            vcs = None\n            # We possibly need to consider /.git URL\n            candidate_source_urls = [source_url]\n            if source_url and not source_url.rstrip('/').endswith('/.git'):\n                candidate_source_urls.append(\n                    '{0}/.git'.format(source_url.rstrip('/')))\n\n            for source_url_ in candidate_source_urls:\n                try:\n                    lgr.debug(\"Retrieving a dataset from URL: \"\n                              \"{0}\".format(source_url_))\n                    with swallow_logs():\n                        vcs = Install._get_new_vcs(target, source_url_)\n                    break  # do not bother with other sources if succeeded\n                except GitCommandError:\n                    lgr.debug(\"Failed to retrieve from URL: \"\n                              \"{0}\".format(source_url_))\n                    if not existed and target.path and exists(target.path):\n                        lgr.debug(\"Wiping out unsuccessful clone attempt at \"\n                                  \"{}\".format(target.path))\n                        rmtree(target.path)\n                    if source_url_ == candidate_source_urls[-1]:\n                        # Re-raise if failed even with the last candidate\n                        lgr.debug(\"Unable to establish repository instance at \"\n                                  \"{0} from {1}\"\n                                  \"\".format(target.path, candidate_source_urls))\n                        raise\n\n            # is automagically re-evaluated in the .repo property:\n            assert(target.repo)\n            # cloning done\n\n        # FLOW GUIDE: All four cases done.\n\n        # in any case check whether we need to annex init the installed thing:\n        if knows_annex(path):\n            # init annex when traces of a remote annex can be detected\n            lgr.info(\"Initializing annex repo at %s\", path)\n            AnnexRepo(path, init=True)\n\n        lgr.debug(\"Installation of {0} done.\".format(path)) ##TODO: installed DS instead of `path`\n        current_dataset = Dataset(path)\n        installed_items.append(current_dataset)\n\n        # Now, recursive calls:\n        if recursive:\n            if description:\n                lgr.warning(\"Description can't be assigned recursively.\")\n            subs = [Dataset(p) for p in\n                    current_dataset.get_subdatasets(recursive=True,\n                                                    recursion_limit=1,\n                                                    absolute=True)]\n            for subds in subs:\n                if subds.is_installed():\n                    lgr.debug(\"subdataset {0} already installed. Skipped.\".format(subds))\n                else:\n                    rec_installed = Install.__call__(\n                        path=subds.path,\n                        dataset=current_dataset,\n                        recursive=True,\n                        recursion_limit=recursion_limit - 1\n                        if recursion_limit else None,\n                        if_dirty=if_dirty,\n                        save=save,\n                        git_opts=git_opts,\n                        git_clone_opts=git_clone_opts,\n                        annex_opts=annex_opts,\n                        annex_init_opts=annex_init_opts)\n                    if isinstance(rec_installed, list):\n                        installed_items.extend(rec_installed)\n                    else:\n                        installed_items.append(rec_installed)\n\n        # get the content of installed (sub-)datasets:\n        if get_data:\n            for d in installed_items:\n                lgr.info(\"Getting data of {0}\".format(d))\n                if isinstance(d.repo, AnnexRepo):\n                    d.get(curdir)\n\n        # everything done => save changes:\n        if save and _install_into_ds:\n            # Note: The only possible changes are installed subdatasets.\n            # This means: We have something to save only, if we installed into\n            # a dataset.\n            lgr.info(\"Saving changes to {0}\".format(ds))\n            ds.save(\n                message='[DATALAD] installed subdataset{0}:{1}'.format(\n                    \"s\" if len(installed_items) > 1 else \"\",\n                    linesep + linesep.join([str(i) for i in installed_items])),\n                auto_add_changes=False,\n                recursive=False)\n\n        if len(installed_items) == 1:\n            return installed_items[0]\n        else:\n            return installed_items\n\n    @staticmethod\n    def _get_new_vcs(ds, source):\n        if source is None:\n            raise RuntimeError(\n                \"No `source` was provided. To create a new dataset \"\n                \"use the `create` command.\")\n        else:\n            # when obtained from remote, try with plain Git\n            lgr.info(\"Creating a new git repo at %s\", ds.path)\n            vcs = GitRepo(ds.path, url=source, create=True)\n            if knows_annex(ds.path):\n                # init annex when traces of a remote annex can be detected\n                lgr.info(\"Initializing annex repo at %s\", ds.path)\n                vcs = AnnexRepo(ds.path, init=True)\n            else:\n                lgr.debug(\"New repository clone has no traces of an annex\")\n        return vcs\n\n    @staticmethod\n    def result_renderer_cmdline(res, args):\n        from datalad.ui import ui\n        if res is None:\n            res = []\n        if not isinstance(res, list):\n            res = [res]\n        if not len(res):\n            ui.message(\"Nothing was installed\")\n            return\n        items = '\\n'.join(map(str, res))\n        msg = \"{n} installed {obj} available at\\n{items}\".format(\n            obj='items are' if len(res) > 1 else 'item is',\n            n=len(res),\n            items=items)\n        ui.message(msg)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 168,
                                "end_lineno": 607,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"Test install action\n\n\"\"\"\n\nimport os\nimport shutil\nfrom os.path import join as opj, abspath, isdir\nfrom os.path import exists\nfrom os.path import realpath\n\nfrom mock import patch\n\nfrom ..dataset import Dataset\nfrom datalad.api import create\nfrom datalad.api import install\nfrom datalad.consts import DATASETS_TOPURL\nfrom datalad.distribution.install import _get_installationpath_from_url\nfrom datalad.distribution.install import _get_git_url_from_source\nfrom datalad.utils import chpwd\nfrom datalad.support.exceptions import InsufficientArgumentsError\nfrom datalad.support.exceptions import FileInGitError\nfrom datalad.support.gitrepo import GitRepo\nfrom datalad.support.gitrepo import GitCommandError\nfrom datalad.cmd import Runner\n\nfrom datalad.support.annexrepo import AnnexRepo\nfrom datalad.cmd import Runner\n\nfrom nose.tools import ok_, eq_, assert_false\nfrom datalad.tests.utils import with_tempfile, assert_in, with_tree,\\\n    with_testrepos, assert_equal, assert_true\nfrom datalad.tests.utils import SkipTest\nfrom datalad.tests.utils import assert_cwd_unchanged, skip_if_on_windows\nfrom datalad.tests.utils import assure_dict_from_str, assure_list_from_str\nfrom datalad.tests.utils import ok_generator\nfrom datalad.tests.utils import ok_file_has_content\nfrom datalad.tests.utils import assert_not_in\nfrom datalad.tests.utils import assert_raises\nfrom datalad.tests.utils import ok_startswith\nfrom datalad.tests.utils import skip_if_no_module\nfrom datalad.tests.utils import ok_clean_git\nfrom datalad.tests.utils import serve_path_via_http\nfrom datalad.tests.utils import swallow_outputs\nfrom datalad.tests.utils import swallow_logs\nfrom datalad.tests.utils import use_cassette\nfrom datalad.tests.utils import skip_if_no_network\nfrom datalad.utils import _path_\n\n\n###############\n# Test helpers:\n###############\n\ndef test_installationpath_from_url():\n    for p in ('lastbit',\n              'lastbit/',\n              '/lastbit',\n              'lastbit.git',\n              'lastbit.git/',\n              'http://example.com/lastbit',\n              'http://example.com/lastbit.git',\n              ):\n        assert_equal(_get_installationpath_from_url(p), 'lastbit')\n\n\ndef test_get_git_url_from_source():\n\n    # resolves datalad RIs:\n    eq_(_get_git_url_from_source('///subds'), DATASETS_TOPURL + 'subds')\n    assert_raises(NotImplementedError, _get_git_url_from_source,\n                  '//custom/subds')\n\n    # doesn't harm others:\n    eq_(_get_git_url_from_source('http://example.com'), 'http://example.com')\n    eq_(_get_git_url_from_source('/absolute/path'), '/absolute/path')\n    eq_(_get_git_url_from_source('file://localhost/some'),\n        'file://localhost/some')\n    eq_(_get_git_url_from_source('localhost/another/path'),\n        'localhost/another/path')\n    eq_(_get_git_url_from_source('user@someho.st/mydir'),\n        'user@someho.st/mydir')\n    eq_(_get_git_url_from_source('ssh://somewhe.re/else'),\n        'ssh://somewhe.re/else')\n\n\n@with_tree(tree={'file.txt': '123'})\n@serve_path_via_http\n@with_tempfile\ndef _test_guess_dot_git(annex, path, url, tdir):\n    repo = (AnnexRepo if annex else GitRepo)(path, create=True)\n    repo.add('file.txt', commit=True, git=not annex)\n\n    # we need to prepare to be served via http, otherwise it must fail\n    with swallow_logs() as cml:\n        assert_raises(GitCommandError, install, path=tdir, source=url)\n    ok_(not exists(tdir))\n\n    Runner(cwd=path)(['git', 'update-server-info'])\n\n    with swallow_logs() as cml:\n        installed = install(path=tdir, source=url)\n        assert_not_in(\"Failed to get annex.uuid\", cml.out)\n    eq_(realpath(installed.path), realpath(tdir))\n    ok_(exists(tdir))\n    ok_clean_git(tdir, annex=annex)\n\n\ndef test_guess_dot_git():\n    for annex in False, True:\n        yield _test_guess_dot_git, annex\n\n\n######################\n# Test actual Install:\n######################\n\ndef test_insufficient_args():\n    assert_raises(InsufficientArgumentsError, install)\n    assert_raises(TypeError, install, [])\n    assert_raises(InsufficientArgumentsError, install, description=\"some\")\n\n\n@skip_if_no_network\n@use_cassette('test_install_crcns')\n@with_tempfile(mkdir=True)\ndef test_install_crcns(tdir):\n    with chpwd(tdir):\n        install(\"all-nonrecursive\", source=\"///\")\n        # should not hang in infinite recursion\n        install(_path_(\"all-nonrecursive/crcns\"))\n        ok_(exists(_path_(\"all-nonrecursive/crcns/.git/config\")))\n\n\n@skip_if_no_network\n@use_cassette('test_install_crcns')\n@with_tempfile(mkdir=True)\ndef test_install_datasets_root(tdir):\n    with chpwd(tdir):\n        install(\"///\")\n        ok_(exists('datasets.datalad.org'))\n\n\n@with_testrepos('.*basic.*', flavors=['local-url', 'network', 'local'])\n@with_tempfile(mkdir=True)\ndef test_install_simple_local(src, path):\n    origin = Dataset(path)\n\n    # now install it somewhere else\n    ds = install(path=path, source=src)\n    eq_(ds.path, path)\n    ok_(ds.is_installed())\n    if not isinstance(origin.repo, AnnexRepo):\n        # this means it is a GitRepo\n        ok_(isinstance(origin.repo, GitRepo))\n        # stays plain Git repo\n        ok_(isinstance(ds.repo, GitRepo))\n        ok_(not isinstance(ds.repo, AnnexRepo))\n        ok_(GitRepo.is_valid_repo(ds.path))\n        eq_(set(ds.repo.get_indexed_files()),\n            {'test.dat', 'INFO.txt'})\n        ok_clean_git(path, annex=False)\n    else:\n        # must be an annex\n        ok_(isinstance(ds.repo, AnnexRepo))\n        ok_(AnnexRepo.is_valid_repo(ds.path, allow_noninitialized=False))\n        eq_(set(ds.repo.get_indexed_files()),\n            {'test.dat', 'INFO.txt', 'test-annex.dat'})\n        ok_clean_git(path, annex=True)\n        # no content was installed:\n        ok_(not ds.repo.file_has_content('test-annex.dat'))\n\n\n@with_testrepos(flavors=['local-url', 'network', 'local'])\n@with_tempfile\ndef test_install_dataset_from_just_source(url, path):\n    with chpwd(path, mkdir=True):\n        ds = install(source=url)\n\n    ok_startswith(ds.path, path)\n    ok_(ds.is_installed())\n    ok_(GitRepo.is_valid_repo(ds.path))\n    ok_clean_git(ds.path, annex=False)\n    assert_in('INFO.txt', ds.repo.get_indexed_files())\n\n\n@with_testrepos(flavors=['network'])\n@with_tempfile\ndef test_install_dataset_from_just_source_via_path(url, path):\n    # for remote urls only, the source could be given to `path`\n    # to allows for simplistic cmdline calls\n    # Q (ben): remote urls only? Sure? => TODO\n\n    with chpwd(path, mkdir=True):\n        ds = install(path=url)\n\n    ok_startswith(ds.path, path)\n    ok_(ds.is_installed())\n    ok_(GitRepo.is_valid_repo(ds.path))\n    ok_clean_git(ds.path, annex=False)\n    assert_in('INFO.txt', ds.repo.get_indexed_files())\n\n\n@with_tree(tree={\n    'ds': {'test.txt': 'some'},\n    })\n@serve_path_via_http\n@with_tempfile(mkdir=True)\ndef test_install_dataladri(src, topurl, path):\n    # make plain git repo\n    ds_path = opj(src, 'ds')\n    gr = GitRepo(ds_path, create=True)\n    gr.add('test.txt')\n    gr.commit('demo')\n    Runner(cwd=gr.path)(['git', 'update-server-info'])\n    # now install it somewhere else\n    with patch('datalad.support.network.DATASETS_TOPURL', topurl), \\\n        swallow_logs():\n        ds = install(path=path, source='///ds')\n    eq_(ds.path, path)\n    ok_clean_git(path, annex=False)\n    ok_file_has_content(opj(path, 'test.txt'), 'some')\n\n\n@with_testrepos('submodule_annex', flavors=['local', 'local-url', 'network'])\n@with_tempfile(mkdir=True)\n@with_tempfile(mkdir=True)\ndef test_install_recursive(src, path_nr, path_r):\n    # first install non-recursive:\n    ds = install(path=path_nr, source=src, recursive=False)\n    ok_(ds.is_installed())\n    for sub in ds.get_subdatasets(recursive=True):\n        ok_(not Dataset(opj(path_nr, sub)).is_installed(),\n            \"Unintentionally installed: %s\" % opj(path_nr, sub))\n    # this also means, subdatasets to be listed as not fulfilled:\n    eq_(set(ds.get_subdatasets(recursive=True, fulfilled=False)),\n        {'subm 1', 'subm 2'})\n\n    # now recursively:\n    ds_list = install(path=path_r, source=src, recursive=True)\n    # installed a dataset and two subdatasets:\n    eq_(len(ds_list), 3)\n    ok_(all([isinstance(i, Dataset) for i in ds_list]))\n    # we recurse top down during installation, so toplevel should appear at\n    # first position in returned list\n    eq_(ds_list[0].path, path_r)\n    top_ds = ds_list[0]\n    ok_(top_ds.is_installed())\n\n    # the subdatasets are contained in returned list:\n    # (Note: Until we provide proper (singleton) instances for Datasets,\n    # need to check for their paths)\n    assert_in(opj(top_ds.path, 'subm 1'), [i.path for i in ds_list])\n    assert_in(opj(top_ds.path, 'subm 2'), [i.path for i in ds_list])\n\n    eq_(len(top_ds.get_subdatasets(recursive=True)), 2)\n\n    for sub in top_ds.get_subdatasets(recursive=True):\n        subds = Dataset(opj(path_r, sub))\n        ok_(subds.is_installed(),\n            \"Not installed: %s\" % opj(path_r, sub))\n        # no content was installed:\n        ok_(not any(subds.repo.file_has_content(\n            subds.repo.get_annexed_files())))\n    # no unfulfilled subdatasets:\n    ok_(top_ds.get_subdatasets(recursive=True, fulfilled=False) == [])\n\n\n@with_testrepos('submodule_annex', flavors=['local'])\n@with_tempfile(mkdir=True)\ndef test_install_recursive_with_data(src, path):\n\n    # now again; with data:\n    ds = install(path=path, source=src, recursive=True, get_data=True)\n    ok_(ds.is_installed())\n    if isinstance(ds.repo, AnnexRepo):\n        ok_(all(ds.repo.file_has_content(ds.repo.get_annexed_files())))\n    for sub in ds.get_subdatasets(recursive=True):\n        subds = Dataset(opj(path, sub))\n        ok_(subds.is_installed(), \"Not installed: %s\" % opj(path, sub))\n        if isinstance(subds.repo, AnnexRepo):\n            ok_(all(subds.repo.file_has_content(subds.repo.get_annexed_files())))\n\n\n@with_testrepos(flavors=['local-url', 'network', 'local'])\n@with_tempfile\ndef test_install_into_dataset(source, top_path):\n\n    ds = create(top_path)\n    import logging\n    logging.getLogger('datalad.test').error(\"DEBUG: source: %s\" % source)\n    subds = ds.install(path=\"sub\", source=source)\n    if isinstance(subds.repo, AnnexRepo) and subds.repo.is_direct_mode():\n        ok_(exists(opj(subds.path, '.git')))\n    else:\n        ok_(isdir(opj(subds.path, '.git')))\n    ok_(subds.is_installed())\n    assert_in('sub', ds.get_subdatasets())\n    # sub is clean:\n    ok_clean_git(subds.path, annex=False)\n    # top is not:\n    assert_raises(AssertionError, ok_clean_git, ds.path, annex=False)\n    ds.save('addsub')\n    # now it is:\n    ok_clean_git(ds.path, annex=False)\n\n\n@with_testrepos('submodule_annex', flavors=['local', 'local-url', 'network'])\n@with_tempfile(mkdir=True)\ndef test_install_known_subdataset(src, path):\n\n    # get the superdataset:\n    ds = install(path=path, source=src)\n\n    # subdataset not installed:\n    subds = Dataset(opj(path, 'subm 1'))\n    assert_false(subds.is_installed())\n    assert_in('subm 1', ds.get_subdatasets(fulfilled=False))\n    assert_not_in('subm 1', ds.get_subdatasets(fulfilled=True))\n    # install it:\n    ds.install('subm 1')\n    ok_(subds.is_installed())\n    ok_(AnnexRepo.is_valid_repo(subds.path, allow_noninitialized=False))\n    # Verify that it is the correct submodule installed and not\n    # new repository initiated\n    assert_equal(set(subds.repo.get_indexed_files()),\n                 {'test.dat', 'INFO.txt', 'test-annex.dat'})\n    assert_not_in('subm 1', ds.get_subdatasets(fulfilled=False))\n    assert_in('subm 1', ds.get_subdatasets(fulfilled=True))\n\n",
            "new_file_content": "# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"Test install action\n\n\"\"\"\n\nimport os\nimport shutil\nfrom os.path import join as opj, abspath, isdir\nfrom os.path import exists\nfrom os.path import realpath\n\nfrom mock import patch\n\nfrom ..dataset import Dataset\nfrom datalad.api import create\nfrom datalad.api import install\nfrom datalad.consts import DATASETS_TOPURL\nfrom datalad.distribution.install import _get_installationpath_from_url\nfrom datalad.distribution.install import _get_git_url_from_source\nfrom datalad.utils import chpwd\nfrom datalad.support.exceptions import InsufficientArgumentsError\nfrom datalad.support.exceptions import FileInGitError\nfrom datalad.support.gitrepo import GitRepo\nfrom datalad.support.gitrepo import GitCommandError\nfrom datalad.cmd import Runner\n\nfrom datalad.support.annexrepo import AnnexRepo\nfrom datalad.cmd import Runner\n\nfrom nose.tools import ok_, eq_, assert_false\nfrom datalad.tests.utils import with_tempfile, assert_in, with_tree,\\\n    with_testrepos, assert_equal, assert_true\nfrom datalad.tests.utils import SkipTest\nfrom datalad.tests.utils import assert_cwd_unchanged, skip_if_on_windows\nfrom datalad.tests.utils import assure_dict_from_str, assure_list_from_str\nfrom datalad.tests.utils import ok_generator\nfrom datalad.tests.utils import ok_file_has_content\nfrom datalad.tests.utils import assert_not_in\nfrom datalad.tests.utils import assert_raises\nfrom datalad.tests.utils import ok_startswith\nfrom datalad.tests.utils import skip_if_no_module\nfrom datalad.tests.utils import ok_clean_git\nfrom datalad.tests.utils import serve_path_via_http\nfrom datalad.tests.utils import swallow_outputs\nfrom datalad.tests.utils import swallow_logs\nfrom datalad.tests.utils import use_cassette\nfrom datalad.tests.utils import skip_if_no_network\nfrom datalad.utils import _path_\n\n\n###############\n# Test helpers:\n###############\n\ndef test_installationpath_from_url():\n    for p in ('lastbit',\n              'lastbit/',\n              '/lastbit',\n              'lastbit.git',\n              'lastbit.git/',\n              'http://example.com/lastbit',\n              'http://example.com/lastbit.git',\n              ):\n        assert_equal(_get_installationpath_from_url(p), 'lastbit')\n\n\ndef test_get_git_url_from_source():\n\n    # resolves datalad RIs:\n    eq_(_get_git_url_from_source('///subds'), DATASETS_TOPURL + 'subds')\n    assert_raises(NotImplementedError, _get_git_url_from_source,\n                  '//custom/subds')\n\n    # doesn't harm others:\n    eq_(_get_git_url_from_source('http://example.com'), 'http://example.com')\n    eq_(_get_git_url_from_source('/absolute/path'), '/absolute/path')\n    eq_(_get_git_url_from_source('file://localhost/some'),\n        'file://localhost/some')\n    eq_(_get_git_url_from_source('localhost/another/path'),\n        'localhost/another/path')\n    eq_(_get_git_url_from_source('user@someho.st/mydir'),\n        'user@someho.st/mydir')\n    eq_(_get_git_url_from_source('ssh://somewhe.re/else'),\n        'ssh://somewhe.re/else')\n\n\n@with_tree(tree={'file.txt': '123'})\n@serve_path_via_http\n@with_tempfile\ndef _test_guess_dot_git(annex, path, url, tdir):\n    repo = (AnnexRepo if annex else GitRepo)(path, create=True)\n    repo.add('file.txt', commit=True, git=not annex)\n\n    # we need to prepare to be served via http, otherwise it must fail\n    with swallow_logs() as cml:\n        assert_raises(GitCommandError, install, path=tdir, source=url)\n    ok_(not exists(tdir))\n\n    Runner(cwd=path)(['git', 'update-server-info'])\n\n    with swallow_logs() as cml:\n        installed = install(path=tdir, source=url)\n        assert_not_in(\"Failed to get annex.uuid\", cml.out)\n    eq_(realpath(installed.path), realpath(tdir))\n    ok_(exists(tdir))\n    ok_clean_git(tdir, annex=annex)\n\n\ndef test_guess_dot_git():\n    for annex in False, True:\n        yield _test_guess_dot_git, annex\n\n\n######################\n# Test actual Install:\n######################\n\ndef test_insufficient_args():\n    assert_raises(InsufficientArgumentsError, install)\n    assert_raises(TypeError, install, [])\n    assert_raises(InsufficientArgumentsError, install, description=\"some\")\n\n\n@skip_if_no_network\n@use_cassette('test_install_crcns')\n@with_tempfile(mkdir=True)\ndef test_install_crcns(tdir):\n    with chpwd(tdir):\n        install(\"all-nonrecursive\", source=\"///\")\n        # should not hang in infinite recursion\n        install(_path_(\"all-nonrecursive/crcns\"))\n        ok_(exists(_path_(\"all-nonrecursive/crcns/.git/config\")))\n\n\n@skip_if_no_network\n@use_cassette('test_install_crcns')\n@with_tempfile(mkdir=True)\ndef test_install_datasets_root(tdir):\n    with chpwd(tdir):\n        install(\"///\")\n        ok_(exists('datasets.datalad.org'))\n\n\n@with_testrepos('.*basic.*', flavors=['local-url', 'network', 'local'])\n@with_tempfile(mkdir=True)\ndef test_install_simple_local(src, path):\n    origin = Dataset(path)\n\n    # now install it somewhere else\n    ds = install(path=path, source=src)\n    eq_(ds.path, path)\n    ok_(ds.is_installed())\n    if not isinstance(origin.repo, AnnexRepo):\n        # this means it is a GitRepo\n        ok_(isinstance(origin.repo, GitRepo))\n        # stays plain Git repo\n        ok_(isinstance(ds.repo, GitRepo))\n        ok_(not isinstance(ds.repo, AnnexRepo))\n        ok_(GitRepo.is_valid_repo(ds.path))\n        eq_(set(ds.repo.get_indexed_files()),\n            {'test.dat', 'INFO.txt'})\n        ok_clean_git(path, annex=False)\n    else:\n        # must be an annex\n        ok_(isinstance(ds.repo, AnnexRepo))\n        ok_(AnnexRepo.is_valid_repo(ds.path, allow_noninitialized=False))\n        eq_(set(ds.repo.get_indexed_files()),\n            {'test.dat', 'INFO.txt', 'test-annex.dat'})\n        ok_clean_git(path, annex=True)\n        # no content was installed:\n        ok_(not ds.repo.file_has_content('test-annex.dat'))\n\n\n@with_testrepos(flavors=['local-url', 'network', 'local'])\n@with_tempfile\ndef test_install_dataset_from_just_source(url, path):\n    with chpwd(path, mkdir=True):\n        ds = install(source=url)\n\n    ok_startswith(ds.path, path)\n    ok_(ds.is_installed())\n    ok_(GitRepo.is_valid_repo(ds.path))\n    ok_clean_git(ds.path, annex=False)\n    assert_in('INFO.txt', ds.repo.get_indexed_files())\n\n\n@with_testrepos(flavors=['network'])\n@with_tempfile\ndef test_install_dataset_from_just_source_via_path(url, path):\n    # for remote urls only, the source could be given to `path`\n    # to allows for simplistic cmdline calls\n    # Q (ben): remote urls only? Sure? => TODO\n\n    with chpwd(path, mkdir=True):\n        ds = install(path=url)\n\n    ok_startswith(ds.path, path)\n    ok_(ds.is_installed())\n    ok_(GitRepo.is_valid_repo(ds.path))\n    ok_clean_git(ds.path, annex=False)\n    assert_in('INFO.txt', ds.repo.get_indexed_files())\n\n\n@with_tree(tree={\n    'ds': {'test.txt': 'some'},\n    })\n@serve_path_via_http\n@with_tempfile(mkdir=True)\ndef test_install_dataladri(src, topurl, path):\n    # make plain git repo\n    ds_path = opj(src, 'ds')\n    gr = GitRepo(ds_path, create=True)\n    gr.add('test.txt')\n    gr.commit('demo')\n    Runner(cwd=gr.path)(['git', 'update-server-info'])\n    # now install it somewhere else\n    with patch('datalad.support.network.DATASETS_TOPURL', topurl), \\\n        swallow_logs():\n        ds = install(path=path, source='///ds')\n    eq_(ds.path, path)\n    ok_clean_git(path, annex=False)\n    ok_file_has_content(opj(path, 'test.txt'), 'some')\n\n\n@with_testrepos('submodule_annex', flavors=['local', 'local-url', 'network'])\n@with_tempfile(mkdir=True)\n@with_tempfile(mkdir=True)\ndef test_install_recursive(src, path_nr, path_r):\n    # first install non-recursive:\n    ds = install(path=path_nr, source=src, recursive=False)\n    ok_(ds.is_installed())\n    for sub in ds.get_subdatasets(recursive=True):\n        ok_(not Dataset(opj(path_nr, sub)).is_installed(),\n            \"Unintentionally installed: %s\" % opj(path_nr, sub))\n    # this also means, subdatasets to be listed as not fulfilled:\n    eq_(set(ds.get_subdatasets(recursive=True, fulfilled=False)),\n        {'subm 1', 'subm 2'})\n\n    # now recursively:\n    ds_list = install(path=path_r, source=src, recursive=True)\n    # installed a dataset and two subdatasets:\n    eq_(len(ds_list), 3)\n    ok_(all([isinstance(i, Dataset) for i in ds_list]))\n    # we recurse top down during installation, so toplevel should appear at\n    # first position in returned list\n    eq_(ds_list[0].path, path_r)\n    top_ds = ds_list[0]\n    ok_(top_ds.is_installed())\n\n    # the subdatasets are contained in returned list:\n    # (Note: Until we provide proper (singleton) instances for Datasets,\n    # need to check for their paths)\n    assert_in(opj(top_ds.path, 'subm 1'), [i.path for i in ds_list])\n    assert_in(opj(top_ds.path, 'subm 2'), [i.path for i in ds_list])\n\n    eq_(len(top_ds.get_subdatasets(recursive=True)), 2)\n\n    for sub in top_ds.get_subdatasets(recursive=True):\n        subds = Dataset(opj(path_r, sub))\n        ok_(subds.is_installed(),\n            \"Not installed: %s\" % opj(path_r, sub))\n        # no content was installed:\n        ok_(not any(subds.repo.file_has_content(\n            subds.repo.get_annexed_files())))\n    # no unfulfilled subdatasets:\n    ok_(top_ds.get_subdatasets(recursive=True, fulfilled=False) == [])\n\n\n@with_testrepos('submodule_annex', flavors=['local'])\n@with_tempfile(mkdir=True)\ndef test_install_recursive_with_data(src, path):\n\n    # now again; with data:\n    ds_list = install(path=path, source=src, recursive=True, get_data=True)\n    # installed a dataset and two subdatasets:\n    eq_(len(ds_list), 3)\n    ok_(all([isinstance(i, Dataset) for i in ds_list]))\n    # we recurse top down during installation, so toplevel should appear at\n    # first position in returned list\n    eq_(ds_list[0].path, path)\n    top_ds = ds_list[0]\n    ok_(top_ds.is_installed())\n    if isinstance(top_ds.repo, AnnexRepo):\n        ok_(all(top_ds.repo.file_has_content(top_ds.repo.get_annexed_files())))\n    for sub in top_ds.get_subdatasets(recursive=True):\n        subds = Dataset(opj(path, sub))\n        ok_(subds.is_installed(), \"Not installed: %s\" % opj(path, sub))\n        if isinstance(subds.repo, AnnexRepo):\n            ok_(all(subds.repo.file_has_content(subds.repo.get_annexed_files())))\n\n\n@with_testrepos(flavors=['local-url', 'network', 'local'])\n@with_tempfile\ndef test_install_into_dataset(source, top_path):\n\n    ds = create(top_path)\n\n    subds = ds.install(path=\"sub\", source=source, save=False)\n    if isinstance(subds.repo, AnnexRepo) and subds.repo.is_direct_mode():\n        ok_(exists(opj(subds.path, '.git')))\n    else:\n        ok_(isdir(opj(subds.path, '.git')))\n    ok_(subds.is_installed())\n    assert_in('sub', ds.get_subdatasets())\n    # sub is clean:\n    ok_clean_git(subds.path, annex=False)\n    # top is not:\n    assert_raises(AssertionError, ok_clean_git, ds.path, annex=False)\n    ds.save('addsub')\n    # now it is:\n    ok_clean_git(ds.path, annex=False)\n\n\n@with_testrepos('submodule_annex', flavors=['local', 'local-url', 'network'])\n@with_tempfile(mkdir=True)\ndef test_install_known_subdataset(src, path):\n\n    # get the superdataset:\n    ds = install(path=path, source=src)\n\n    # subdataset not installed:\n    subds = Dataset(opj(path, 'subm 1'))\n    assert_false(subds.is_installed())\n    assert_in('subm 1', ds.get_subdatasets(fulfilled=False))\n    assert_not_in('subm 1', ds.get_subdatasets(fulfilled=True))\n    # install it:\n    ds.install('subm 1')\n    ok_(subds.is_installed())\n    ok_(AnnexRepo.is_valid_repo(subds.path, allow_noninitialized=False))\n    # Verify that it is the correct submodule installed and not\n    # new repository initiated\n    assert_equal(set(subds.repo.get_indexed_files()),\n                 {'test.dat', 'INFO.txt', 'test-annex.dat'})\n    assert_not_in('subm 1', ds.get_subdatasets(fulfilled=False))\n    assert_in('subm 1', ds.get_subdatasets(fulfilled=True))\n\n",
            "header": {
                "file": {
                    "path": "datalad/distribution/tests/test_install.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "505a2c6c3",
                "new_commit_hash": "2d9ba5201",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/datalad/distribution/tests/test_install.py"
            },
            "plus_file": {
                "path": "b/datalad/distribution/tests/test_install.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 277,
                            "length": 11
                        },
                        "new_range": {
                            "start": 277,
                            "length": 18
                        },
                        "section": "def test_install_recursive(src, path_nr, path_r):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "def test_install_recursive_with_data(src, path):",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    # now again; with data:",
                                "type": "context"
                            },
                            {
                                "content": "    ds = install(path=path, source=src, recursive=True, get_data=True)",
                                "type": "deleted"
                            },
                            {
                                "content": "    ok_(ds.is_installed())",
                                "type": "deleted"
                            },
                            {
                                "content": "    if isinstance(ds.repo, AnnexRepo):",
                                "type": "deleted"
                            },
                            {
                                "content": "        ok_(all(ds.repo.file_has_content(ds.repo.get_annexed_files())))",
                                "type": "deleted"
                            },
                            {
                                "content": "    for sub in ds.get_subdatasets(recursive=True):",
                                "type": "deleted"
                            },
                            {
                                "content": "    ds_list = install(path=path, source=src, recursive=True, get_data=True)",
                                "type": "added"
                            },
                            {
                                "content": "    # installed a dataset and two subdatasets:",
                                "type": "added"
                            },
                            {
                                "content": "    eq_(len(ds_list), 3)",
                                "type": "added"
                            },
                            {
                                "content": "    ok_(all([isinstance(i, Dataset) for i in ds_list]))",
                                "type": "added"
                            },
                            {
                                "content": "    # we recurse top down during installation, so toplevel should appear at",
                                "type": "added"
                            },
                            {
                                "content": "    # first position in returned list",
                                "type": "added"
                            },
                            {
                                "content": "    eq_(ds_list[0].path, path)",
                                "type": "added"
                            },
                            {
                                "content": "    top_ds = ds_list[0]",
                                "type": "added"
                            },
                            {
                                "content": "    ok_(top_ds.is_installed())",
                                "type": "added"
                            },
                            {
                                "content": "    if isinstance(top_ds.repo, AnnexRepo):",
                                "type": "added"
                            },
                            {
                                "content": "        ok_(all(top_ds.repo.file_has_content(top_ds.repo.get_annexed_files())))",
                                "type": "added"
                            },
                            {
                                "content": "    for sub in top_ds.get_subdatasets(recursive=True):",
                                "type": "added"
                            },
                            {
                                "content": "        subds = Dataset(opj(path, sub))",
                                "type": "context"
                            },
                            {
                                "content": "        ok_(subds.is_installed(), \"Not installed: %s\" % opj(path, sub))",
                                "type": "context"
                            },
                            {
                                "content": "        if isinstance(subds.repo, AnnexRepo):",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/distribution/tests/test_install.py",
                            "type": "function",
                            "name": "test_install_recursive_with_data",
                            "content": "def test_install_recursive_with_data(src, path):\n\n    # now again; with data:\n    ds = install(path=path, source=src, recursive=True, get_data=True)\n    ok_(ds.is_installed())\n    if isinstance(ds.repo, AnnexRepo):\n        ok_(all(ds.repo.file_has_content(ds.repo.get_annexed_files())))\n    for sub in ds.get_subdatasets(recursive=True):\n        subds = Dataset(opj(path, sub))\n        ok_(subds.is_installed(), \"Not installed: %s\" % opj(path, sub))\n        if isinstance(subds.repo, AnnexRepo):\n            ok_(all(subds.repo.file_has_content(subds.repo.get_annexed_files())))",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 277,
                            "end_lineno": 288,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 293,
                            "length": 9
                        },
                        "new_range": {
                            "start": 300,
                            "length": 8
                        },
                        "section": "def test_install_recursive_with_data(src, path):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "def test_install_into_dataset(source, top_path):",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    ds = create(top_path)",
                                "type": "context"
                            },
                            {
                                "content": "    import logging",
                                "type": "deleted"
                            },
                            {
                                "content": "    logging.getLogger('datalad.test').error(\"DEBUG: source: %s\" % source)",
                                "type": "deleted"
                            },
                            {
                                "content": "    subds = ds.install(path=\"sub\", source=source)",
                                "type": "deleted"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    subds = ds.install(path=\"sub\", source=source, save=False)",
                                "type": "added"
                            },
                            {
                                "content": "    if isinstance(subds.repo, AnnexRepo) and subds.repo.is_direct_mode():",
                                "type": "context"
                            },
                            {
                                "content": "        ok_(exists(opj(subds.path, '.git')))",
                                "type": "context"
                            },
                            {
                                "content": "    else:",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/distribution/tests/test_install.py",
                            "type": "function",
                            "name": "test_install_into_dataset",
                            "content": "def test_install_into_dataset(source, top_path):\n\n    ds = create(top_path)\n    import logging\n    logging.getLogger('datalad.test').error(\"DEBUG: source: %s\" % source)\n    subds = ds.install(path=\"sub\", source=source)\n    if isinstance(subds.repo, AnnexRepo) and subds.repo.is_direct_mode():\n        ok_(exists(opj(subds.path, '.git')))\n    else:\n        ok_(isdir(opj(subds.path, '.git')))\n    ok_(subds.is_installed())\n    assert_in('sub', ds.get_subdatasets())\n    # sub is clean:\n    ok_clean_git(subds.path, annex=False)\n    # top is not:\n    assert_raises(AssertionError, ok_clean_git, ds.path, annex=False)\n    ds.save('addsub')\n    # now it is:\n    ok_clean_git(ds.path, annex=False)",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 293,
                            "end_lineno": 311,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "4ed6cceafadfb85ebfbd3fc085bceab433683d95^",
    "new_commit_hash": "4ed6cceafadfb85ebfbd3fc085bceab433683d95",
    "commit_message": "BF: Fixing tests for install",
    "commit_date": "2016-09-15T16:00:00+02:00",
    "metadata": {}
}
{
    "repo_name": "datalad",
    "new_commit_hash": "4ed6cceafadfb85ebfbd3fc085bceab433683d95",
    "test_file_codes": [
        "# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"Test install action\n\n\"\"\"\n\nimport os\nimport shutil\nfrom os.path import join as opj, abspath, isdir\nfrom os.path import exists\nfrom os.path import realpath\n\nfrom mock import patch\n\nfrom datalad.distribution.dataset import Dataset\nfrom datalad.api import create\nfrom datalad.api import install\nfrom datalad.consts import DATASETS_TOPURL\nfrom datalad.distribution.install import _get_installationpath_from_url\nfrom datalad.distribution.install import _get_git_url_from_source\nfrom datalad.utils import chpwd\nfrom datalad.support.exceptions import InsufficientArgumentsError\nfrom datalad.support.exceptions import FileInGitError\nfrom datalad.support.gitrepo import GitRepo\nfrom datalad.support.gitrepo import GitCommandError\nfrom datalad.cmd import Runner\n\nfrom datalad.support.annexrepo import AnnexRepo\nfrom datalad.cmd import Runner\n\nfrom nose.tools import ok_, eq_, assert_false\nfrom datalad.tests.utils import with_tempfile, assert_in, with_tree,\\\n    with_testrepos, assert_equal, assert_true\nfrom datalad.tests.utils import SkipTest\nfrom datalad.tests.utils import assert_cwd_unchanged, skip_if_on_windows\nfrom datalad.tests.utils import assure_dict_from_str, assure_list_from_str\nfrom datalad.tests.utils import ok_generator\nfrom datalad.tests.utils import ok_file_has_content\nfrom datalad.tests.utils import assert_not_in\nfrom datalad.tests.utils import assert_raises\nfrom datalad.tests.utils import ok_startswith\nfrom datalad.tests.utils import skip_if_no_module\nfrom datalad.tests.utils import ok_clean_git\nfrom datalad.tests.utils import serve_path_via_http\nfrom datalad.tests.utils import swallow_outputs\nfrom datalad.tests.utils import swallow_logs\nfrom datalad.tests.utils import use_cassette\nfrom datalad.tests.utils import skip_if_no_network\nfrom datalad.utils import _path_\n\n\n###############\n# Test helpers:\n###############\n\ndef test_installationpath_from_url():\n    for p in ('lastbit',\n              'lastbit/',\n              '/lastbit',\n              'lastbit.git',\n              'lastbit.git/',\n              'http://example.com/lastbit',\n              'http://example.com/lastbit.git',\n              ):\n        assert_equal(_get_installationpath_from_url(p), 'lastbit')\n\n\ndef test_get_git_url_from_source():\n\n    # resolves datalad RIs:\n    eq_(_get_git_url_from_source('///subds'), DATASETS_TOPURL + 'subds')\n    assert_raises(NotImplementedError, _get_git_url_from_source,\n                  '//custom/subds')\n\n    # doesn't harm others:\n    eq_(_get_git_url_from_source('http://example.com'), 'http://example.com')\n    eq_(_get_git_url_from_source('/absolute/path'), '/absolute/path')\n    eq_(_get_git_url_from_source('file://localhost/some'),\n        'file://localhost/some')\n    eq_(_get_git_url_from_source('localhost/another/path'),\n        'localhost/another/path')\n    eq_(_get_git_url_from_source('user@someho.st/mydir'),\n        'user@someho.st/mydir')\n    eq_(_get_git_url_from_source('ssh://somewhe.re/else'),\n        'ssh://somewhe.re/else')\n\n\n@with_tree(tree={'file.txt': '123'})\n@serve_path_via_http\n@with_tempfile\ndef _test_guess_dot_git(annex, path, url, tdir):\n    repo = (AnnexRepo if annex else GitRepo)(path, create=True)\n    repo.add('file.txt', commit=True, git=not annex)\n\n    # we need to prepare to be served via http, otherwise it must fail\n    with swallow_logs() as cml:\n        assert_raises(GitCommandError, install, path=tdir, source=url)\n    ok_(not exists(tdir))\n\n    Runner(cwd=path)(['git', 'update-server-info'])\n\n    with swallow_logs() as cml:\n        installed = install(path=tdir, source=url)\n        assert_not_in(\"Failed to get annex.uuid\", cml.out)\n    eq_(realpath(installed.path), realpath(tdir))\n    ok_(exists(tdir))\n    ok_clean_git(tdir, annex=annex)\n\n\ndef test_guess_dot_git():\n    for annex in False, True:\n        yield _test_guess_dot_git, annex\n\n\n######################\n# Test actual Install:\n######################\n\ndef test_insufficient_args():\n    assert_raises(InsufficientArgumentsError, install)\n    assert_raises(TypeError, install, [])\n    assert_raises(InsufficientArgumentsError, install, description=\"some\")\n\n\n@skip_if_no_network\n@use_cassette('test_install_crcns')\n@with_tempfile(mkdir=True)\ndef test_install_crcns(tdir):\n    with chpwd(tdir):\n        install(\"all-nonrecursive\", source=\"///\")\n        # should not hang in infinite recursion\n        install(_path_(\"all-nonrecursive/crcns\"))\n        ok_(exists(_path_(\"all-nonrecursive/crcns/.git/config\")))\n\n\n@skip_if_no_network\n@use_cassette('test_install_crcns')\n@with_tempfile(mkdir=True)\ndef test_install_datasets_root(tdir):\n    with chpwd(tdir):\n        install(\"///\")\n        ok_(exists('datasets.datalad.org'))\n\n\n@with_testrepos('.*basic.*', flavors=['local-url', 'network', 'local'])\n@with_tempfile(mkdir=True)\ndef test_install_simple_local(src, path):\n    origin = Dataset(path)\n\n    # now install it somewhere else\n    ds = install(path=path, source=src)\n    eq_(ds.path, path)\n    ok_(ds.is_installed())\n    if not isinstance(origin.repo, AnnexRepo):\n        # this means it is a GitRepo\n        ok_(isinstance(origin.repo, GitRepo))\n        # stays plain Git repo\n        ok_(isinstance(ds.repo, GitRepo))\n        ok_(not isinstance(ds.repo, AnnexRepo))\n        ok_(GitRepo.is_valid_repo(ds.path))\n        eq_(set(ds.repo.get_indexed_files()),\n            {'test.dat', 'INFO.txt'})\n        ok_clean_git(path, annex=False)\n    else:\n        # must be an annex\n        ok_(isinstance(ds.repo, AnnexRepo))\n        ok_(AnnexRepo.is_valid_repo(ds.path, allow_noninitialized=False))\n        eq_(set(ds.repo.get_indexed_files()),\n            {'test.dat', 'INFO.txt', 'test-annex.dat'})\n        ok_clean_git(path, annex=True)\n        # no content was installed:\n        ok_(not ds.repo.file_has_content('test-annex.dat'))\n\n\n@with_testrepos(flavors=['local-url', 'network', 'local'])\n@with_tempfile\ndef test_install_dataset_from_just_source(url, path):\n    with chpwd(path, mkdir=True):\n        ds = install(source=url)\n\n    ok_startswith(ds.path, path)\n    ok_(ds.is_installed())\n    ok_(GitRepo.is_valid_repo(ds.path))\n    ok_clean_git(ds.path, annex=False)\n    assert_in('INFO.txt', ds.repo.get_indexed_files())\n\n\n@with_testrepos(flavors=['network'])\n@with_tempfile\ndef test_install_dataset_from_just_source_via_path(url, path):\n    # for remote urls only, the source could be given to `path`\n    # to allows for simplistic cmdline calls\n    # Q (ben): remote urls only? Sure? => TODO\n\n    with chpwd(path, mkdir=True):\n        ds = install(path=url)\n\n    ok_startswith(ds.path, path)\n    ok_(ds.is_installed())\n    ok_(GitRepo.is_valid_repo(ds.path))\n    ok_clean_git(ds.path, annex=False)\n    assert_in('INFO.txt', ds.repo.get_indexed_files())\n\n\n@with_tree(tree={\n    'ds': {'test.txt': 'some'},\n    })\n@serve_path_via_http\n@with_tempfile(mkdir=True)\ndef test_install_dataladri(src, topurl, path):\n    # make plain git repo\n    ds_path = opj(src, 'ds')\n    gr = GitRepo(ds_path, create=True)\n    gr.add('test.txt')\n    gr.commit('demo')\n    Runner(cwd=gr.path)(['git', 'update-server-info'])\n    # now install it somewhere else\n    with patch('datalad.support.network.DATASETS_TOPURL', topurl), \\\n        swallow_logs():\n        ds = install(path=path, source='///ds')\n    eq_(ds.path, path)\n    ok_clean_git(path, annex=False)\n    ok_file_has_content(opj(path, 'test.txt'), 'some')\n\n\n@with_testrepos('submodule_annex', flavors=['local', 'local-url', 'network'])\n@with_tempfile(mkdir=True)\n@with_tempfile(mkdir=True)\ndef test_install_recursive(src, path_nr, path_r):\n    # first install non-recursive:\n    ds = install(path=path_nr, source=src, recursive=False)\n    ok_(ds.is_installed())\n    for sub in ds.get_subdatasets(recursive=True):\n        ok_(not Dataset(opj(path_nr, sub)).is_installed(),\n            \"Unintentionally installed: %s\" % opj(path_nr, sub))\n    # this also means, subdatasets to be listed as not fulfilled:\n    eq_(set(ds.get_subdatasets(recursive=True, fulfilled=False)),\n        {'subm 1', 'subm 2'})\n\n    # now recursively:\n    ds_list = install(path=path_r, source=src, recursive=True)\n    # installed a dataset and two subdatasets:\n    eq_(len(ds_list), 3)\n    ok_(all([isinstance(i, Dataset) for i in ds_list]))\n    # we recurse top down during installation, so toplevel should appear at\n    # first position in returned list\n    eq_(ds_list[0].path, path_r)\n    top_ds = ds_list[0]\n    ok_(top_ds.is_installed())\n\n    # the subdatasets are contained in returned list:\n    # (Note: Until we provide proper (singleton) instances for Datasets,\n    # need to check for their paths)\n    assert_in(opj(top_ds.path, 'subm 1'), [i.path for i in ds_list])\n    assert_in(opj(top_ds.path, 'subm 2'), [i.path for i in ds_list])\n\n    eq_(len(top_ds.get_subdatasets(recursive=True)), 2)\n\n    for sub in top_ds.get_subdatasets(recursive=True):\n        subds = Dataset(opj(path_r, sub))\n        ok_(subds.is_installed(),\n            \"Not installed: %s\" % opj(path_r, sub))\n        # no content was installed:\n        ok_(not any(subds.repo.file_has_content(\n            subds.repo.get_annexed_files())))\n    # no unfulfilled subdatasets:\n    ok_(top_ds.get_subdatasets(recursive=True, fulfilled=False) == [])\n\n\n@with_testrepos('submodule_annex', flavors=['local'])\n@with_tempfile(mkdir=True)\ndef test_install_recursive_with_data(src, path):\n\n    # now again; with data:\n    ds_list = install(path=path, source=src, recursive=True, get_data=True)\n    # installed a dataset and two subdatasets:\n    eq_(len(ds_list), 3)\n    ok_(all([isinstance(i, Dataset) for i in ds_list]))\n    # we recurse top down during installation, so toplevel should appear at\n    # first position in returned list\n    eq_(ds_list[0].path, path)\n    top_ds = ds_list[0]\n    ok_(top_ds.is_installed())\n    if isinstance(top_ds.repo, AnnexRepo):\n        ok_(all(top_ds.repo.file_has_content(top_ds.repo.get_annexed_files())))\n    for sub in top_ds.get_subdatasets(recursive=True):\n        subds = Dataset(opj(path, sub))\n        ok_(subds.is_installed(), \"Not installed: %s\" % opj(path, sub))\n        if isinstance(subds.repo, AnnexRepo):\n            ok_(all(subds.repo.file_has_content(subds.repo.get_annexed_files())))\n\n\n@with_testrepos(flavors=['local-url', 'network', 'local'])\n@with_tempfile\ndef test_install_into_dataset(source, top_path):\n\n    ds = create(top_path)\n\n    subds = ds.install(path=\"sub\", source=source, save=False)\n    if isinstance(subds.repo, AnnexRepo) and subds.repo.is_direct_mode():\n        ok_(exists(opj(subds.path, '.git')))\n    else:\n        ok_(isdir(opj(subds.path, '.git')))\n    ok_(subds.is_installed())\n    assert_in('sub', ds.get_subdatasets())\n    # sub is clean:\n    ok_clean_git(subds.path, annex=False)\n    # top is not:\n    assert_raises(AssertionError, ok_clean_git, ds.path, annex=False)\n    ds.save('addsub')\n    # now it is:\n    ok_clean_git(ds.path, annex=False)\n\n\n@with_testrepos('submodule_annex', flavors=['local', 'local-url', 'network'])\n@with_tempfile(mkdir=True)\ndef test_install_known_subdataset(src, path):\n\n    # get the superdataset:\n    ds = install(path=path, source=src)\n\n    # subdataset not installed:\n    subds = Dataset(opj(path, 'subm 1'))\n    assert_false(subds.is_installed())\n    assert_in('subm 1', ds.get_subdatasets(fulfilled=False))\n    assert_not_in('subm 1', ds.get_subdatasets(fulfilled=True))\n    # install it:\n    ds.install('subm 1')\n    ok_(subds.is_installed())\n    ok_(AnnexRepo.is_valid_repo(subds.path, allow_noninitialized=False))\n    # Verify that it is the correct submodule installed and not\n    # new repository initiated\n    assert_equal(set(subds.repo.get_indexed_files()),\n                 {'test.dat', 'INFO.txt', 'test-annex.dat'})\n    assert_not_in('subm 1', ds.get_subdatasets(fulfilled=False))\n    assert_in('subm 1', ds.get_subdatasets(fulfilled=True))\n\n",
        "import pytest\nimport tempfile\nimport os\n\n\n@pytest.fixture\ndef path():\n    with tempfile.TemporaryDirectory() as tmpdir:\n        yield tmpdir\n\n\n@pytest.fixture(autouse=True)\ndef setup_git_config():\n    with tempfile.TemporaryDirectory() as home:\n        old_home = os.environ.get(\"HOME\")\n        os.environ[\"HOME\"] = home\n        os.system('git config --global user.name \"DataLad Tester\"')\n        os.system('git config --global user.email \"test@example.com\"')\n        yield\n        if old_home:\n            os.environ[\"HOME\"] = old_home\n"
    ],
    "test_file_names": [
        "test_1.py",
        "conftest.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Starting Datalad installation attempts...\nVerifying installation...\n❌ Verification failed\nPython 3.9 installation failed, trying Python 3.7...\nVerifying installation...\nDatalad version: 0.2.3\n✅ Installation successful!\nSuccessfully installed Datalad using Python 3.7\n",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 25 packages in 14ms\nInstalled 25 packages in 5.58s\n + coverage==7.6.10\n + docopt==0.6.2\n + exceptiongroup==1.2.2\n + grabbit==0.2.6\n + importlib-resources==6.4.5\n + iniconfig==2.0.0\n + nibabel==5.3.2\n + num2words==0.5.14\n + numpy==2.0.2\n + packaging==24.2\n + pandas==2.2.3\n + patsy==1.0.1\n + pluggy==1.5.0\n + pybids==0.6.5\n + pytest==8.3.4\n + pytest-cov==6.0.0\n + python-dateutil==2.9.0.post0\n + pytz==2024.2\n + scipy==1.13.1\n + setuptools==75.6.0\n + six==1.17.0\n + tomli==2.2.1\n + typing-extensions==4.12.2\n + tzdata==2024.2\n + zipp==3.21.0\nerror: The build backend returned an error\n  Caused by: Call to `setuptools.build_meta:__legacy__.build_editable` failed (exit status: 1)\n\n[stderr]\nTraceback (most recent call last):\n  File \"<string>\", line 14, in <module>\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpddD3tK/lib/python3.9/site-packages/setuptools/build_meta.py\", line 483, in get_requires_for_build_editable\n    return self.get_requires_for_build_wheel(config_settings)\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpddD3tK/lib/python3.9/site-packages/setuptools/build_meta.py\", line 334, in get_requires_for_build_wheel\n    return self._get_build_requires(config_settings, requirements=[])\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpddD3tK/lib/python3.9/site-packages/setuptools/build_meta.py\", line 304, in _get_build_requires\n    self.run_setup()\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpddD3tK/lib/python3.9/site-packages/setuptools/build_meta.py\", line 522, in run_setup\n    super().run_setup(setup_script=setup_script)\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpddD3tK/lib/python3.9/site-packages/setuptools/build_meta.py\", line 320, in run_setup\n    exec(code, locals())\n  File \"<string>\", line 49, in <module>\nAttributeError: module 'platform' has no attribute 'dist'\n\nhint: This usually indicates a problem with the package or the build environment.\nerror: The build backend returned an error\n  Caused by: Call to `setuptools.build_meta:__legacy__.build_editable` failed (exit status: 1)\n\n[stderr]\nTraceback (most recent call last):\n  File \"<string>\", line 14, in <module>\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpqbCv83/lib/python3.9/site-packages/setuptools/build_meta.py\", line 483, in get_requires_for_build_editable\n    return self.get_requires_for_build_wheel(config_settings)\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpqbCv83/lib/python3.9/site-packages/setuptools/build_meta.py\", line 334, in get_requires_for_build_wheel\n    return self._get_build_requires(config_settings, requirements=[])\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpqbCv83/lib/python3.9/site-packages/setuptools/build_meta.py\", line 304, in _get_build_requires\n    self.run_setup()\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpqbCv83/lib/python3.9/site-packages/setuptools/build_meta.py\", line 522, in run_setup\n    super().run_setup(setup_script=setup_script)\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpqbCv83/lib/python3.9/site-packages/setuptools/build_meta.py\", line 320, in run_setup\n    exec(code, locals())\n  File \"<string>\", line 49, in <module>\nAttributeError: module 'platform' has no attribute 'dist'\n\nhint: This usually indicates a problem with the package or the build environment.\nTraceback (most recent call last):\n  File \"<string>\", line 1, in <module>\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/datalad/__init__.py\", line 17, in <module>\n    from .config import ConfigManager\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/datalad/config.py\", line 17, in <module>\n    from appdirs import AppDirs\nModuleNotFoundError: No module named 'appdirs'\nUsing CPython 3.7.9\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 26 packages in 307ms\nInstalled 26 packages in 6.50s\n + bids==0.0\n + coverage==7.2.7\n + docopt==0.6.2\n + exceptiongroup==1.2.2\n + fasteners==0.19\n + grabbit==0.2.6\n + importlib-metadata==6.7.0\n + iniconfig==2.0.0\n + nibabel==4.0.2\n + num2words==0.5.14\n + numpy==1.21.6\n + packaging==24.0\n + pandas==1.3.5\n + patsy==1.0.1\n + pluggy==1.2.0\n + pybids==0.6.5\n + pytest==7.4.4\n + pytest-cov==4.1.0\n + python-dateutil==2.9.0.post0\n + pytz==2024.2\n + scipy==1.7.3\n + setuptools==68.0.0\n + six==1.17.0\n + tomli==2.0.1\n + typing-extensions==4.7.1\n + zipp==3.15.0\nResolved 73 packages in 3.18s\nPrepared 1 package in 1.11s\nInstalled 67 packages in 23ms\n + appdirs==1.4.4\n + attrs==24.2.0\n + automat==22.10.0\n + beautifulsoup4==4.12.3\n + boto==2.49.0\n + cachetools==5.5.0\n + certifi==2024.12.14\n + cffi==1.15.1\n + charset-normalizer==3.4.1\n + constantly==15.1.0\n + cryptography==44.0.0\n + cssselect==1.2.0\n + datalad==0.2.3 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95)\n + filelock==3.12.2\n + frozendict==2.4.6\n + gitdb==4.0.11\n + gitpython==3.1.43\n + httpretty==1.1.4\n + humanize==4.6.0\n + hyperlink==21.0.0\n + idna==3.10\n + importlib-resources==5.12.0\n + incremental==22.10.0\n + iso8601==2.1.0\n + itemadapter==0.8.0\n + itemloaders==1.1.0\n + jaraco-classes==3.2.3\n + jeepney==0.8.0\n + jmespath==1.0.1\n + jsmin==3.0.1\n + keyring==24.1.1\n + keyrings-alt==4.2.0\n + lxml==5.3.0\n + mock==5.1.0\n + more-itertools==9.1.0\n + msgpack-python==0.5.6\n + multidict==6.0.5\n + nose==1.3.7\n + parsel==1.8.1\n + patool==1.12\n + protego==0.3.0\n + pyasn1==0.5.1\n + pyasn1-modules==0.3.0\n + pycparser==2.21\n + pydispatcher==2.0.7\n + pyld==2.0.4\n + pyopenssl==24.3.0\n + pyyaml==6.0.1\n + queuelib==1.6.2\n + requests==2.31.0\n + requests-file==2.1.0\n + requests-ftp==0.3.1\n + scrapy==2.9.0\n + secretstorage==3.3.3\n + service-identity==21.1.0\n + simplejson==3.19.3\n + smmap==5.0.1\n + soupsieve==2.4.1\n + tldextract==4.0.0\n + tqdm==4.67.1\n + twisted==23.8.0\n + urllib3==2.0.7\n + vcrpy==4.3.0\n + w3lib==2.1.2\n + wrapt==1.16.0\n + yarl==1.9.4\n + zope-interface==6.4.post2\nAudited 1 package in 3ms\n",
    "new_commit_res_code": 1,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.7.9, pytest-7.4.4, pluggy-1.2.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95\nplugins: cov-4.1.0\ncollected 14 items\n\nr2e_tests/test_1.py ..x.EEEEEEEEEE                                       [100%]\n\n==================================== ERRORS ====================================\n_____________________ ERROR at setup of test_install_crcns _____________________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 130\n  @skip_if_no_network\n  @use_cassette('test_install_crcns')\n  @with_tempfile(mkdir=True)\n  def test_install_crcns(tdir):\nE       fixture 'tdir' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:130\n_________________ ERROR at setup of test_install_datasets_root _________________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 141\n  @skip_if_no_network\n  @use_cassette('test_install_crcns')\n  @with_tempfile(mkdir=True)\n  def test_install_datasets_root(tdir):\nE       fixture 'tdir' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:141\n_________________ ERROR at setup of test_install_simple_local __________________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 150\n  @with_testrepos('.*basic.*', flavors=['local-url', 'network', 'local'])\n  @with_tempfile(mkdir=True)\n  def test_install_simple_local(src, path):\nE       fixture 'src' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:150\n___________ ERROR at setup of test_install_dataset_from_just_source ____________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 180\n  @with_testrepos(flavors=['local-url', 'network', 'local'])\n  @with_tempfile\n  def test_install_dataset_from_just_source(url, path):\nE       fixture 'url' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:180\n_______ ERROR at setup of test_install_dataset_from_just_source_via_path _______\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 193\n  @with_testrepos(flavors=['network'])\n  @with_tempfile\n  def test_install_dataset_from_just_source_via_path(url, path):\nE       fixture 'url' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:193\n___________________ ERROR at setup of test_install_dataladri ___________________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 210\n  @with_tree(tree={\n      'ds': {'test.txt': 'some'},\n      })\n  @serve_path_via_http\n  @with_tempfile(mkdir=True)\n  def test_install_dataladri(src, topurl, path):\nE       fixture 'src' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:210\n___________________ ERROR at setup of test_install_recursive ___________________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 231\n  @with_testrepos('submodule_annex', flavors=['local', 'local-url', 'network'])\n  @with_tempfile(mkdir=True)\n  @with_tempfile(mkdir=True)\n  def test_install_recursive(src, path_nr, path_r):\nE       fixture 'src' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:231\n______________ ERROR at setup of test_install_recursive_with_data ______________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 275\n  @with_testrepos('submodule_annex', flavors=['local'])\n  @with_tempfile(mkdir=True)\n  def test_install_recursive_with_data(src, path):\nE       fixture 'src' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:275\n_________________ ERROR at setup of test_install_into_dataset __________________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 298\n  @with_testrepos(flavors=['local-url', 'network', 'local'])\n  @with_tempfile\n  def test_install_into_dataset(source, top_path):\nE       fixture 'source' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:298\n_______________ ERROR at setup of test_install_known_subdataset ________________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 320\n  @with_testrepos('submodule_annex', flavors=['local', 'local-url', 'network'])\n  @with_tempfile(mkdir=True)\n  def test_install_known_subdataset(src, path):\nE       fixture 'src' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:320\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_installationpath_from_url\nPASSED r2e_tests/test_1.py::test_get_git_url_from_source\nPASSED r2e_tests/test_1.py::test_insufficient_args\nXFAIL r2e_tests/test_1.py::test_guess_dot_git - reason: [NOTRUN] yield tests were removed in pytest 4.0 - test_guess_dot_git will be ignored\nERROR r2e_tests/test_1.py::test_install_crcns\nERROR r2e_tests/test_1.py::test_install_datasets_root\nERROR r2e_tests/test_1.py::test_install_simple_local\nERROR r2e_tests/test_1.py::test_install_dataset_from_just_source\nERROR r2e_tests/test_1.py::test_install_dataset_from_just_source_via_path\nERROR r2e_tests/test_1.py::test_install_dataladri\nERROR r2e_tests/test_1.py::test_install_recursive\nERROR r2e_tests/test_1.py::test_install_recursive_with_data\nERROR r2e_tests/test_1.py::test_install_into_dataset\nERROR r2e_tests/test_1.py::test_install_known_subdataset\n=================== 3 passed, 1 xfailed, 10 errors in 1.60s ====================\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.7.9, pytest-7.4.4, pluggy-1.2.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95\nplugins: cov-4.1.0\ncollected 14 items\n\nr2e_tests/test_1.py ..xFEEEEEEEEEE                                       [100%]\n\n==================================== ERRORS ====================================\n_____________________ ERROR at setup of test_install_crcns _____________________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 130\n  @skip_if_no_network\n  @use_cassette('test_install_crcns')\n  @with_tempfile(mkdir=True)\n  def test_install_crcns(tdir):\nE       fixture 'tdir' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:130\n_________________ ERROR at setup of test_install_datasets_root _________________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 141\n  @skip_if_no_network\n  @use_cassette('test_install_crcns')\n  @with_tempfile(mkdir=True)\n  def test_install_datasets_root(tdir):\nE       fixture 'tdir' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:141\n_________________ ERROR at setup of test_install_simple_local __________________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 150\n  @with_testrepos('.*basic.*', flavors=['local-url', 'network', 'local'])\n  @with_tempfile(mkdir=True)\n  def test_install_simple_local(src, path):\nE       fixture 'src' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:150\n___________ ERROR at setup of test_install_dataset_from_just_source ____________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 180\n  @with_testrepos(flavors=['local-url', 'network', 'local'])\n  @with_tempfile\n  def test_install_dataset_from_just_source(url, path):\nE       fixture 'url' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:180\n_______ ERROR at setup of test_install_dataset_from_just_source_via_path _______\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 193\n  @with_testrepos(flavors=['network'])\n  @with_tempfile\n  def test_install_dataset_from_just_source_via_path(url, path):\nE       fixture 'url' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:193\n___________________ ERROR at setup of test_install_dataladri ___________________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 210\n  @with_tree(tree={\n      'ds': {'test.txt': 'some'},\n      })\n  @serve_path_via_http\n  @with_tempfile(mkdir=True)\n  def test_install_dataladri(src, topurl, path):\nE       fixture 'src' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:210\n___________________ ERROR at setup of test_install_recursive ___________________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 231\n  @with_testrepos('submodule_annex', flavors=['local', 'local-url', 'network'])\n  @with_tempfile(mkdir=True)\n  @with_tempfile(mkdir=True)\n  def test_install_recursive(src, path_nr, path_r):\nE       fixture 'src' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:231\n______________ ERROR at setup of test_install_recursive_with_data ______________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 275\n  @with_testrepos('submodule_annex', flavors=['local'])\n  @with_tempfile(mkdir=True)\n  def test_install_recursive_with_data(src, path):\nE       fixture 'src' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:275\n_________________ ERROR at setup of test_install_into_dataset __________________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 298\n  @with_testrepos(flavors=['local-url', 'network', 'local'])\n  @with_tempfile\n  def test_install_into_dataset(source, top_path):\nE       fixture 'source' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:298\n_______________ ERROR at setup of test_install_known_subdataset ________________\nfile /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py, line 320\n  @with_testrepos('submodule_annex', flavors=['local', 'local-url', 'network'])\n  @with_tempfile(mkdir=True)\n  def test_install_known_subdataset(src, path):\nE       fixture 'src' not found\n>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, path, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, setup_git_config, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory\n>       use 'pytest --fixtures [testpath]' for help on them.\n\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_4ed6cceafadfb85ebfbd3fc085bceab433683d95/r2e_tests/test_1.py:320\n=================================== FAILURES ===================================\n____________________________ test_insufficient_args ____________________________\n\n    def test_insufficient_args():\n>       assert_raises(InsufficientArgumentsError, install)\n\nr2e_tests/test_1.py:125: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n../../../../.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib/python3.7/unittest/case.py:756: in assertRaises\n    return context.handle('assertRaises', args, kwargs)\n../../../../.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib/python3.7/unittest/case.py:178: in handle\n    callable_obj(*args, **kwargs)\ndatalad/distribution/install.py:346: in __call__\n    assume_ds = Dataset(path)\ndatalad/distribution/dataset.py:78: in __init__\n    self._path = abspath(path)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def abspath(path):\n        \"\"\"Return an absolute path.\"\"\"\n>       path = os.fspath(path)\nE       TypeError: expected str, bytes or os.PathLike object, not NoneType\n\n../../../../.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib/python3.7/posixpath.py:378: TypeError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_installationpath_from_url\nPASSED r2e_tests/test_1.py::test_get_git_url_from_source\nXFAIL r2e_tests/test_1.py::test_guess_dot_git - reason: [NOTRUN] yield tests were removed in pytest 4.0 - test_guess_dot_git will be ignored\nERROR r2e_tests/test_1.py::test_install_crcns\nERROR r2e_tests/test_1.py::test_install_datasets_root\nERROR r2e_tests/test_1.py::test_install_simple_local\nERROR r2e_tests/test_1.py::test_install_dataset_from_just_source\nERROR r2e_tests/test_1.py::test_install_dataset_from_just_source_via_path\nERROR r2e_tests/test_1.py::test_install_dataladri\nERROR r2e_tests/test_1.py::test_install_recursive\nERROR r2e_tests/test_1.py::test_install_recursive_with_data\nERROR r2e_tests/test_1.py::test_install_into_dataset\nERROR r2e_tests/test_1.py::test_install_known_subdataset\nFAILED r2e_tests/test_1.py::test_insufficient_args - TypeError: expected str,...\n============== 1 failed, 2 passed, 1 xfailed, 10 errors in 0.91s ===============\n",
    "old_commit_res_stderr": ""
}
datalad/distribution/install.py datalad/distribution/tests/test_install.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]

**Title:** `install()` Raises `TypeError` Instead of `InsufficientArgumentsError` When Called Without Arguments

**Description:**

When the `install` function is invoked without the required arguments, it unexpectedly raises a `TypeError` instead of the intended `InsufficientArgumentsError`. This makes it unclear to users why the installation failed and hinders proper error handling.

**Example Code:**

```python
install()
```

**Expected Behavior:**

Calling `install()` without the necessary arguments should raise an `InsufficientArgumentsError` to indicate that required parameters are missing.

**Actual Behavior:**

A `TypeError` is raised with the message:
```
TypeError: expected str, bytes or os.PathLike object, not NoneType
```

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### datalad/distribution/install.py
# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-
# ex: set sts=4 ts=4 sw=4 noet:
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
#
#   See COPYING file distributed along with the datalad package for the
#   copyright and license terms.
#
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
"""High-level interface for dataset (component) installation

"""
from datalad.distribution.utils import _install_subds_inplace, \
    _fixup_submodule_dotgit_setup

__docformat__ = 'restructuredtext'

import logging
from os import curdir, linesep
from os.path import join as opj, relpath, pardir, exists

from six.moves.urllib.parse import quote as urlquote

from .dataset import Dataset, datasetmethod, \
    resolve_path, EnsureDataset

from datalad.interface.base import Interface
from datalad.interface.common_opts import recursion_flag, recursion_limit, \
    dataset_description, git_opts, annex_opts, \
    annex_init_opts, git_clone_opts, if_dirty_opt, nosave_opt
from datalad.interface.utils import handle_dirty_dataset

from datalad.support.constraints import EnsureStr, EnsureNone
from datalad.support.annexrepo import AnnexRepo
from datalad.support.exceptions import InsufficientArgumentsError
from datalad.support.gitrepo import GitRepo, GitCommandError
from datalad.support.param import Parameter
from datalad.utils import knows_annex, swallow_logs
from datalad.support.network import RI, URL
from datalad.support.network import DataLadRI
from datalad.support.network import is_url, is_datalad_compat_ri
from datalad.utils import rmtree

lgr = logging.getLogger('datalad.distribution.install')


def _get_git_url_from_source(source, none_ok=False):
    """Return URL for cloning associated with a source specification

    For now just resolves DataLadRIs
    """
    # TODO: Probably RF this into RI.as_git_url(), that would be overridden
    # by subclasses or sth. like that

    if source is None:
        if not none_ok:
            lgr.warning("received 'None' as 'source'.")
        return source

    if not isinstance(source, RI):
        source_ri = RI(source)
    else:
        source_ri = source
    if isinstance(source_ri, DataLadRI):
        # we have got our DataLadRI as the source, so expand it
        source = source_ri.as_git_url()
    else:
        source = str(source_ri)
    return source


def _get_installationpath_from_url(url):
    """Returns a relative path derived from the trailing end of a URL

    This can be used to determine an installation path of a Dataset
    from a URL, analog to what `git clone` does.
    """
    path = url.rstrip('/')
    if '/' in path:
        path = path.split('/')
        if path[-1] == '.git':
            path = path[-2]
        else:
            path = path[-1]
    if path.endswith('.git'):
        path = path[:-4]
    return path


def _install_subds_from_flexible_source(ds, sm_path, sm_url, recursive):
    """Tries to obtain a given subdataset from several meaningful locations"""
    # shortcut
    vcs = ds.repo
    repo = vcs.repo
    # compose a list of candidate clone URLs
    clone_urls = []
    # if we have a remote, let's check the location of that remote
    # for the presence of the desired submodule
    tracking_branch = repo.active_branch.tracking_branch()
    remote_url = ''
    # remember suffix
    url_suffix = ''
    if tracking_branch:
        # name of the default remote for the active branch
        remote_name = repo.active_branch.tracking_branch().remote_name
        remote_url = vcs.get_remote_url(remote_name, push=False)
        if remote_url.rstrip('/').endswith('/.git'):
            url_suffix = '/.git'
            remote_url = remote_url[:-5]
        # attempt: submodule checkout at parent remote URL
        # We might need to quote sm_path portion, e.g. for spaces etc
        if remote_url and isinstance(RI(remote_url), URL):
            sm_path_url = urlquote(sm_path)
        else:
            sm_path_url = sm_path
        clone_urls.append('{0}/{1}{2}'.format(
            remote_url, sm_path_url, url_suffix))
    # attempt: configured submodule URL
    # TODO: consider supporting DataLadRI here?  or would confuse
    #  git and we wouldn't want that (i.e. not allow pure git clone
    #  --recursive)
    if sm_url.startswith('/') or is_url(sm_url):
        # this seems to be an absolute location -> take as is
        clone_urls.append(sm_url)
    else:
        # need to resolve relative URL
        if not remote_url:
            # we have no remote URL, hence we need to go with the
            # local path
            remote_url = ds.path
        remote_url_l = remote_url.split('/')
        sm_url_l = sm_url.split('/')
        for i, c in enumerate(sm_url_l):
            if c == pardir:
                remote_url_l = remote_url_l[:-1]
            else:
                clone_urls.append('{0}/{1}{2}'.format(
                    '/'.join(remote_url_l),
                    '/'.join(sm_url_l[i:]),
                    url_suffix))
                break
    # now loop over all candidates and try to clone
    subds = Dataset(opj(ds.path, sm_path))
    for clone_url in clone_urls:
        lgr.debug("Attempt clone of subdataset from: {0}".format(clone_url))
        try:
            subds = Install.__call__(
                path=subds.path, source=clone_url,
                recursive=recursive)
        except GitCommandError:
            # TODO: failed clone might leave something behind that causes the
            # next attempt to fail as well. Implement safe way to remove clone
            # attempt left-overs.
            continue
        lgr.debug("Update cloned subdataset {0} in parent".format(subds))
        if sm_path in ds.get_subdatasets(absolute=False, recursive=False):
            ds.repo.update_submodule(sm_path, init=True)
        else:
            # submodule is brand-new and previously unknown
            ds.repo.add_submodule(sm_path, url=clone_url)
        _fixup_submodule_dotgit_setup(ds, sm_path)
        return subds


# TODO:  git_clone options
# use --shared by default? => option --no-shared


class Install(Interface):
    """Install a dataset or subdataset.

    This command creates a local :term:`sibling` of an existing dataset from a
    (remote) location identified via a URL or path, or by the name of a
    registered subdataset. Optional recursion into potential subdatasets, and
    download of all referenced data is supported. The new dataset can be
    optionally registered in an existing :term:`superdataset` (the new
    dataset's path needs to be located within the superdataset for that, and
    the superdataset will be detected automatically). It is recommended to
    provide a brief description to label the dataset's nature *and* location,
    e.g. "Michael's music on black laptop". This helps humans to identify data
    locations in distributed scenarios.  By default an identifier comprised of
    user and machine name, plus path will be generated.

    When only partial dataset content shall be obtained, it is recommended to
    use this command without the :option:`get-data` flag, followed by a
    :func:`~datalad.api.get` operation to obtain the desired data.

    .. note::
      Power-user info: This command uses :command:`git clone`, and
      :command:`git annex init` to prepare the dataset. Registering to a
      superdataset is performed via a :command:`git submodule add` operation
      in the discovered superdataset.
    """

    _params_ = dict(
        dataset=Parameter(
            args=("-d", "--dataset"),
            # TODO: this probably changes to install into the dataset (add_to_super)
            # and to install the thing 'just there' without operating 'on' a dataset.
            # Adapt doc.
            doc="""specify the dataset to perform the install operation on.  If
            no dataset is given, an attempt is made to identify the dataset
            in a parent directory of the current working directory and/or the
            `path` given""",
            constraints=EnsureDataset() | EnsureNone()),
        path=Parameter(
            args=("path",),
            doc="""path/name of the installation target.  If no `source` is
            provided, and no `dataset` is given or detected, this is
            interpreted as the source URL of a dataset and a destination
            path will be derived from the URL similar to :command:`git
            clone`""",
            nargs="?",
            constraints=EnsureStr() | EnsureNone()),
        source=Parameter(
            args=("-s", "--source",),
            doc="URL or local path of the installation source",
            constraints=EnsureStr() | EnsureNone()),
        get_data=Parameter(
            args=("-g", "--get-data",),
            action="store_true",
            doc="""if given, obtain all data content too"""),
        description=dataset_description,
        recursive=recursion_flag,
        recursion_limit=recursion_limit,
        if_dirty=if_dirty_opt,
        save=nosave_opt,
        git_opts=git_opts,
        git_clone_opts=git_clone_opts,
        annex_opts=annex_opts,
        annex_init_opts=annex_init_opts)

    @staticmethod
    @datasetmethod(name='install')
    def __call__(
            path=None,
            source=None,
            dataset=None,
            get_data=False,
            description=None,
            recursive=False,
            recursion_limit=None,
            if_dirty='save-before',
            save=True,
            git_opts=None,
            git_clone_opts=None,
            annex_opts=None,
            annex_init_opts=None):

        lgr.debug(
            "Installation attempt started. path=%r, source=%r, dataset=%r, "
            "get_data=%r, description=%r, recursive=%r, recursion_limit=%r, "
            "git_opts=%r, git_clone_opts=%r, annex_opts=%r, annex_init_opt=%r",
            path, source, dataset, get_data, description, recursive,
            recursion_limit, git_opts, git_clone_opts, annex_opts,
            annex_init_opts)

        # shortcut
        ds = dataset

        _install_into_ds = False  # default
        # did we explicitly get a dataset to install into?
        # if we got a dataset, path will be resolved against it.
        # Otherwise path will be resolved first.

        if ds is not None:
            _install_into_ds = True
            if not isinstance(ds, Dataset):
                ds = Dataset(ds)
            if not ds.is_installed():
                # TODO: possible magic: ds.install() for known subdataset 'ds'
                raise ValueError("{0} needs to be installed in order to "
                                 "install something into it.".format(ds))
            handle_dirty_dataset(ds, if_dirty)

        # resolve the target location (if local) against the provided dataset
        # or CWD:
        if path is not None:
            # Should work out just fine for regular paths, so no additional
            # conditioning is necessary
            path_ri = RI(path)
            try:
                # Wouldn't work for SSHRI ATM, see TODO within SSHRI
                path = resolve_path(path_ri.localpath, ds)
                # any `path` argument that point to something local now
                # resolved and is no longer a URL
            except ValueError:
                # URL doesn't point to a local something
                # so we have an actual URL in `path`. Since this is valid as a
                # single positional argument, `source` has to be None at this
                # point.

                if is_datalad_compat_ri(path) and source is None:
                    # we have an actual URL -> this should be the source
                    lgr.debug(
                        "Single argument given to install, that doesn't seem to "
                        "be a local path. "
                        "Assuming the argument identifies a source location.")
                    source = path
                    path = None

                else:
                    # `path` is neither a valid source nor a local path.
                    # TODO: The only thing left is a known subdataset with a
                    # name, that is not a path; Once we correctly distinguish
                    # between path and name of a submodule, we need to consider
                    # this.
                    # For now: Just raise
                    raise ValueError("Invalid path argument {0}".format(path))

        # `path` resolved, if there was any.

        # we need a source to install from. Either we have one in `source` or
        # it is implicit, since `path` is an already known subdataset or an
        # existing dataset, that should be installed into the given dataset as a
        # subdataset inplace.
        # Note: For now, we do not consider a subdataset beneath a not yet
        # installed level, since we do not know, whether this even is something
        # to install (an actual Dataset) the only thing we know would be,
        # that it is some path beneath it.
        _install_sub = False

        if _install_into_ds and source is None and path is not None:
            # Check for `path` being a known subdataset:
            if path in [opj(ds.path, sub)
                        for sub in ds.get_subdatasets(recursive=True)]:
                _install_sub = True
                lgr.debug("Identified {0} as subdataset to "
                          "install.".format(path))
            else:
                # the only option left is an existing repo to be added inplace:
                if exists(path) and GitRepo.is_valid_repo(path):
                    lgr.debug("No source given, but path points to an existing "
                              "repository and a dataset to install into was "
                              "given. Assuming we want to install {0} "
                              "inplace into {1}.".format(path, ds))
                    source = path

        if source is None and not _install_sub:
            # we have no source and don't have a dataset to install into.
            # could be a single positional argument, that points to a known
            # subdataset.
            # So, test for that last remaining option:

            # if `path` was a known subdataset to be installed, let's assume
            # it would be one:
            assume_ds = Dataset(path)
            candidate_super_ds = assume_ds.get_superdataset()

            if candidate_super_ds and candidate_super_ds != assume_ds and \
                assume_ds.path in candidate_super_ds.get_subdatasets(absolute=True):

                # `path` has a potential superdataset and is known to this
                # candidate
                _install_sub = True
                _install_into_ds = True
                ds = candidate_super_ds

            else:
                # no match, we can't deal with that `path` argument
                # without a `source`:
                raise InsufficientArgumentsError(
                    "Got no source to install from.")

        _install_inplace = False
        if source == path:  # TODO: does it make sense to use realpath here?
            if _install_into_ds:
                _install_inplace = True
            else:
                raise InsufficientArgumentsError(
                    "Source and target are the same ({0}). This doesn't make "
                    "sense without a dataset to install into.".format(path))

        # Possibly do conversion from source into a git-friendly url
        source_url = _get_git_url_from_source(source, none_ok=True)

        # derive target from source url:
        if path is None and source_url is not None:
            # we got nothing but a source. do something similar to git clone
            # and derive the path from the source_url and continue
            lgr.debug(
                "Neither dataset nor target installation path provided. "
                "Assuming installation of a remote dataset. "
                "Deriving destination path from given source {0}".format(
                    source_url))
            path = _get_installationpath_from_url(source_url)
            # since this is a relative `path`, resolve it:
            path = resolve_path(path, ds)

        if path is None:
            # still no target => fail
            raise InsufficientArgumentsError("Got no target to install to.")

        lgr.debug("Resolved installation target: {0}".format(path))

        # TODO: expandpath()?
        # more checks, whether something exists and what it actually is?

        ###########
        # we should know everything necessary by now
        # actual installation starts
        ###########
        lgr.info("Installing {0}{1}".format(
            path, " from %s" % source_url if source_url else ""
        ))

        installed_items = []
        # FLOW GUIDE:
        # four cases:
        # 1. install into a dataset
        #   1.1. we install a known subdataset
        #        => git submodule update --init
        #   1.2. we install an existing repo as a subdataset inplace
        #        => git submodule add + magic
        #   1.3. we install a new subdataset from an explicit source
        #        => git submodule add
        # 2. we "just" install from an explicit source
        #    => git clone

        if _install_into_ds:
            # FLOW GUIDE: 1.
            lgr.info("Install subdataset at: {0}".format(path))

            # express the destination path relative to the root of
            # the dataset
            relativepath = relpath(path, start=ds.path)
            if relativepath.startswith(pardir):
                raise ValueError("installation path outside dataset "
                                 "({0})".format(path))
            lgr.debug("Resolved installation target relative to dataset "
                      "{0}: {1}".format(ds, relativepath))

            if _install_sub:
                # FLOW_GUIDE: 1.1.
                submodule = [sm for sm in ds.repo.get_submodules()
                             if sm.path == relativepath][0]

                _install_subds_from_flexible_source(
                    ds,
                    submodule.path,
                    submodule.url,
                    recursive=False)
                #ds.repo.update_submodule(relativepath, init=True)

                # TODO: use _install_subds_from_flexible instead?
                # it calls install again, but this is based on old install.
                # So, need to figure it out
                # Additional note: - does always git clone + add inplace

            elif _install_inplace:
                # FLOW GUIDE: 1.2.
                _install_subds_inplace(ds, path, relpath(path, ds.path))
                # TODO: Some success checks?
            else:
                # FLOW_GUIDE 1.3.
                _install_subds_from_flexible_source(
                    ds, relativepath,
                    source_url, recursive=False)
                #ds.repo.add_submodule(relativepath, url=source_url)
        else:
            # FLOW GUIDE: 2.
            lgr.info("Install dataset at: {0}".format(path))

            # Currently assuming there is nothing at the target to deal with
            # and rely on failures raising from the git call ...

            target = Dataset(path)

            # TODO
            assert(target.repo is None)

            # should not be the case, but we need to distinguish between failure
            # of git-clone, due to existing target and an unsuccessful clone
            # attempt. See below.
            existed = target.path and exists(target.path)

            vcs = None
            # We possibly need to consider /.git URL
            candidate_source_urls = [source_url]
            if source_url and not source_url.rstrip('/').endswith('/.git'):
                candidate_source_urls.append(
                    '{0}/.git'.format(source_url.rstrip('/')))

            for source_url_ in candidate_source_urls:
                try:
                    lgr.debug("Retrieving a dataset from URL: "
                              "{0}".format(source_url_))
                    with swallow_logs():
                        vcs = Install._get_new_vcs(target, source_url_)
                    break  # do not bother with other sources if succeeded
                except GitCommandError:
                    lgr.debug("Failed to retrieve from URL: "
                              "{0}".format(source_url_))
                    if not existed and target.path and exists(target.path):
                        lgr.debug("Wiping out unsuccessful clone attempt at "
                                  "{}".format(target.path))
                        rmtree(target.path)
                    if source_url_ == candidate_source_urls[-1]:
                        # Re-raise if failed even with the last candidate
                        lgr.debug("Unable to establish repository instance at "
                                  "{0} from {1}"
                                  "".format(target.path, candidate_source_urls))
                        raise

            # is automagically re-evaluated in the .repo property:
            assert(target.repo)
            # cloning done

        # FLOW GUIDE: All four cases done.

        # in any case check whether we need to annex init the installed thing:
        if knows_annex(path):
            # init annex when traces of a remote annex can be detected
            lgr.info("Initializing annex repo at %s", path)
            AnnexRepo(path, init=True)

        lgr.debug("Installation of {0} done.".format(path)) ##TODO: installed DS instead of `path`
        current_dataset = Dataset(path)
        installed_items.append(current_dataset)

        # Now, recursive calls:
        if recursive:
            if description:
                lgr.warning("Description can't be assigned recursively.")
            subs = [Dataset(p) for p in
                    current_dataset.get_subdatasets(recursive=True,
                                                    recursion_limit=1,
                                                    absolute=True)]
            for subds in subs:
                if subds.is_installed():
                    lgr.debug("subdataset {0} already installed. Skipped.".format(subds))
                else:
                    rec_installed = Install.__call__(
                        path=subds.path,
                        dataset=current_dataset,
                        recursive=True,
                        recursion_limit=recursion_limit - 1
                        if recursion_limit else None,
                        if_dirty=if_dirty,
                        save=save,
                        git_opts=git_opts,
                        git_clone_opts=git_clone_opts,
                        annex_opts=annex_opts,
                        annex_init_opts=annex_init_opts)
                    if isinstance(rec_installed, list):
                        installed_items.extend(rec_installed)
                    else:
                        installed_items.append(rec_installed)

        # get the content of installed (sub-)datasets:
        if get_data:
            for d in installed_items:
                lgr.info("Getting data of {0}".format(d))
                if isinstance(d.repo, AnnexRepo):
                    d.get(curdir)

        # everything done => save changes:
        if save and _install_into_ds:
            # Note: The only possible changes are installed subdatasets.
            # This means: We have something to save only, if we installed into
            # a dataset.
            lgr.info("Saving changes to {0}".format(ds))
            ds.save(
                message='[DATALAD] installed subdataset{0}:{1}'.format(
                    "s" if len(installed_items) > 1 else "",
                    linesep + linesep.join([str(i) for i in installed_items])),
                auto_add_changes=False,
                recursive=False)

        if len(installed_items) == 1:
            return installed_items[0]
        else:
            return installed_items

    @staticmethod
    def _get_new_vcs(ds, source):
        if source is None:
            raise RuntimeError(
                "No `source` was provided. To create a new dataset "
                "use the `create` command.")
        else:
            # when obtained from remote, try with plain Git
            lgr.info("Creating a new git repo at %s", ds.path)
            vcs = GitRepo(ds.path, url=source, create=True)
            if knows_annex(ds.path):
                # init annex when traces of a remote annex can be detected
                lgr.info("Initializing annex repo at %s", ds.path)
                vcs = AnnexRepo(ds.path, init=True)
            else:
                lgr.debug("New repository clone has no traces of an annex")
        return vcs

    @staticmethod
    def result_renderer_cmdline(res, args):
        from datalad.ui import ui
        if res is None:
            res = []
        if not isinstance(res, list):
            res = [res]
        if not len(res):
            ui.message("Nothing was installed")
            return
        items = '\n'.join(map(str, res))
        msg = "{n} installed {obj} available at\n{items}".format(
            obj='items are' if len(res) > 1 else 'item is',
            n=len(res),
            items=items)
        ui.message(msg)

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]

**Title:** `install()` Raises `TypeError` Instead of `InsufficientArgumentsError` When Called Without Arguments

**Description:**

When the `install` function is invoked without the required arguments, it unexpectedly raises a `TypeError` instead of the intended `InsufficientArgumentsError`. This makes it unclear to users why the installation failed and hinders proper error handling.

**Example Code:**

```python
install()
```

**Expected Behavior:**

Calling `install()` without the necessary arguments should raise an `InsufficientArgumentsError` to indicate that required parameters are missing.

**Actual Behavior:**

A `TypeError` is raised with the message:
```
TypeError: expected str, bytes or os.PathLike object, not NoneType
```

[/ISSUE]
{
    "test_installationpath_from_url": "PASSED",
    "test_get_git_url_from_source": "PASSED",
    "test_insufficient_args": "PASSED",
    "test_install_crcns": "ERROR",
    "test_install_datasets_root": "ERROR",
    "test_install_simple_local": "ERROR",
    "test_install_dataset_from_just_source": "ERROR",
    "test_install_dataset_from_just_source_via_path": "ERROR",
    "test_install_dataladri": "ERROR",
    "test_install_recursive": "ERROR",
    "test_install_recursive_with_data": "ERROR",
    "test_install_into_dataset": "ERROR",
    "test_install_known_subdataset": "ERROR"
}
diff --git a/datalad/distribution/install.py b/datalad/distribution/install.py
index f3138ebe4..8ee836b3b 100644
--- a/datalad/distribution/install.py
+++ b/datalad/distribution/install.py
@@ -335,7 +335,7 @@ class Install(Interface):
                               "inplace into {1}.".format(path, ds))
                     source = path
 
-        if source is None and not _install_sub:
+        if source is None and not _install_sub and path is not None:
             # we have no source and don't have a dataset to install into.
             # could be a single positional argument, that points to a known
             # subdataset.

{"datalad/distribution/install.py": "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"High-level interface for dataset (component) installation\n\n\"\"\"\nfrom datalad.distribution.utils import _install_subds_inplace, \\\n    _fixup_submodule_dotgit_setup\n\n__docformat__ = 'restructuredtext'\n\nimport logging\nfrom os import curdir, linesep\nfrom os.path import join as opj, relpath, pardir, exists\n\nfrom six.moves.urllib.parse import quote as urlquote\n\nfrom .dataset import Dataset, datasetmethod, \\\n    resolve_path, EnsureDataset\n\nfrom datalad.interface.base import Interface\nfrom datalad.interface.common_opts import recursion_flag, recursion_limit, \\\n    dataset_description, git_opts, annex_opts, \\\n    annex_init_opts, git_clone_opts, if_dirty_opt, nosave_opt\nfrom datalad.interface.utils import handle_dirty_dataset\n\nfrom datalad.support.constraints import EnsureStr, EnsureNone\nfrom datalad.support.annexrepo import AnnexRepo\nfrom datalad.support.exceptions import InsufficientArgumentsError\nfrom datalad.support.gitrepo import GitRepo, GitCommandError\nfrom datalad.support.param import Parameter\nfrom datalad.utils import knows_annex, swallow_logs\nfrom datalad.support.network import RI, URL\nfrom datalad.support.network import DataLadRI\nfrom datalad.support.network import is_url, is_datalad_compat_ri\nfrom datalad.utils import rmtree\n\nlgr = logging.getLogger('datalad.distribution.install')\n\n\ndef _get_git_url_from_source(source, none_ok=False):\n    \"\"\"Return URL for cloning associated with a source specification\n\n    For now just resolves DataLadRIs\n    \"\"\"\n    # TODO: Probably RF this into RI.as_git_url(), that would be overridden\n    # by subclasses or sth. like that\n\n    if source is None:\n        if not none_ok:\n            lgr.warning(\"received 'None' as 'source'.\")\n        return source\n\n    if not isinstance(source, RI):\n        source_ri = RI(source)\n    else:\n        source_ri = source\n    if isinstance(source_ri, DataLadRI):\n        # we have got our DataLadRI as the source, so expand it\n        source = source_ri.as_git_url()\n    else:\n        source = str(source_ri)\n    return source\n\n\ndef _get_installationpath_from_url(url):\n    \"\"\"Returns a relative path derived from the trailing end of a URL\n\n    This can be used to determine an installation path of a Dataset\n    from a URL, analog to what `git clone` does.\n    \"\"\"\n    path = url.rstrip('/')\n    if '/' in path:\n        path = path.split('/')\n        if path[-1] == '.git':\n            path = path[-2]\n        else:\n            path = path[-1]\n    if path.endswith('.git'):\n        path = path[:-4]\n    return path\n\n\ndef _install_subds_from_flexible_source(ds, sm_path, sm_url, recursive):\n    \"\"\"Tries to obtain a given subdataset from several meaningful locations\"\"\"\n    # shortcut\n    vcs = ds.repo\n    repo = vcs.repo\n    # compose a list of candidate clone URLs\n    clone_urls = []\n    # if we have a remote, let's check the location of that remote\n    # for the presence of the desired submodule\n    tracking_branch = repo.active_branch.tracking_branch()\n    remote_url = ''\n    # remember suffix\n    url_suffix = ''\n    if tracking_branch:\n        # name of the default remote for the active branch\n        remote_name = repo.active_branch.tracking_branch().remote_name\n        remote_url = vcs.get_remote_url(remote_name, push=False)\n        if remote_url.rstrip('/').endswith('/.git'):\n            url_suffix = '/.git'\n            remote_url = remote_url[:-5]\n        # attempt: submodule checkout at parent remote URL\n        # We might need to quote sm_path portion, e.g. for spaces etc\n        if remote_url and isinstance(RI(remote_url), URL):\n            sm_path_url = urlquote(sm_path)\n        else:\n            sm_path_url = sm_path\n        clone_urls.append('{0}/{1}{2}'.format(\n            remote_url, sm_path_url, url_suffix))\n    # attempt: configured submodule URL\n    # TODO: consider supporting DataLadRI here?  or would confuse\n    #  git and we wouldn't want that (i.e. not allow pure git clone\n    #  --recursive)\n    if sm_url.startswith('/') or is_url(sm_url):\n        # this seems to be an absolute location -> take as is\n        clone_urls.append(sm_url)\n    else:\n        # need to resolve relative URL\n        if not remote_url:\n            # we have no remote URL, hence we need to go with the\n            # local path\n            remote_url = ds.path\n        remote_url_l = remote_url.split('/')\n        sm_url_l = sm_url.split('/')\n        for i, c in enumerate(sm_url_l):\n            if c == pardir:\n                remote_url_l = remote_url_l[:-1]\n            else:\n                clone_urls.append('{0}/{1}{2}'.format(\n                    '/'.join(remote_url_l),\n                    '/'.join(sm_url_l[i:]),\n                    url_suffix))\n                break\n    # now loop over all candidates and try to clone\n    subds = Dataset(opj(ds.path, sm_path))\n    for clone_url in clone_urls:\n        lgr.debug(\"Attempt clone of subdataset from: {0}\".format(clone_url))\n        try:\n            subds = Install.__call__(\n                path=subds.path, source=clone_url,\n                recursive=recursive)\n        except GitCommandError:\n            # TODO: failed clone might leave something behind that causes the\n            # next attempt to fail as well. Implement safe way to remove clone\n            # attempt left-overs.\n            continue\n        lgr.debug(\"Update cloned subdataset {0} in parent\".format(subds))\n        if sm_path in ds.get_subdatasets(absolute=False, recursive=False):\n            ds.repo.update_submodule(sm_path, init=True)\n        else:\n            # submodule is brand-new and previously unknown\n            ds.repo.add_submodule(sm_path, url=clone_url)\n        _fixup_submodule_dotgit_setup(ds, sm_path)\n        return subds\n\n\n# TODO:  git_clone options\n# use --shared by default? => option --no-shared\n\n\nclass Install(Interface):\n    \"\"\"Install a dataset or subdataset.\n\n    This command creates a local :term:`sibling` of an existing dataset from a\n    (remote) location identified via a URL or path, or by the name of a\n    registered subdataset. Optional recursion into potential subdatasets, and\n    download of all referenced data is supported. The new dataset can be\n    optionally registered in an existing :term:`superdataset` (the new\n    dataset's path needs to be located within the superdataset for that, and\n    the superdataset will be detected automatically). It is recommended to\n    provide a brief description to label the dataset's nature *and* location,\n    e.g. \"Michael's music on black laptop\". This helps humans to identify data\n    locations in distributed scenarios.  By default an identifier comprised of\n    user and machine name, plus path will be generated.\n\n    When only partial dataset content shall be obtained, it is recommended to\n    use this command without the :option:`get-data` flag, followed by a\n    :func:`~datalad.api.get` operation to obtain the desired data.\n\n    .. note::\n      Power-user info: This command uses :command:`git clone`, and\n      :command:`git annex init` to prepare the dataset. Registering to a\n      superdataset is performed via a :command:`git submodule add` operation\n      in the discovered superdataset.\n    \"\"\"\n\n    _params_ = dict(\n        dataset=Parameter(\n            args=(\"-d\", \"--dataset\"),\n            # TODO: this probably changes to install into the dataset (add_to_super)\n            # and to install the thing 'just there' without operating 'on' a dataset.\n            # Adapt doc.\n            doc=\"\"\"specify the dataset to perform the install operation on.  If\n            no dataset is given, an attempt is made to identify the dataset\n            in a parent directory of the current working directory and/or the\n            `path` given\"\"\",\n            constraints=EnsureDataset() | EnsureNone()),\n        path=Parameter(\n            args=(\"path\",),\n            doc=\"\"\"path/name of the installation target.  If no `source` is\n            provided, and no `dataset` is given or detected, this is\n            interpreted as the source URL of a dataset and a destination\n            path will be derived from the URL similar to :command:`git\n            clone`\"\"\",\n            nargs=\"?\",\n            constraints=EnsureStr() | EnsureNone()),\n        source=Parameter(\n            args=(\"-s\", \"--source\",),\n            doc=\"URL or local path of the installation source\",\n            constraints=EnsureStr() | EnsureNone()),\n        get_data=Parameter(\n            args=(\"-g\", \"--get-data\",),\n            action=\"store_true\",\n            doc=\"\"\"if given, obtain all data content too\"\"\"),\n        description=dataset_description,\n        recursive=recursion_flag,\n        recursion_limit=recursion_limit,\n        if_dirty=if_dirty_opt,\n        save=nosave_opt,\n        git_opts=git_opts,\n        git_clone_opts=git_clone_opts,\n        annex_opts=annex_opts,\n        annex_init_opts=annex_init_opts)\n\n    @staticmethod\n    @datasetmethod(name='install')\n    def __call__(\n            path=None,\n            source=None,\n            dataset=None,\n            get_data=False,\n            description=None,\n            recursive=False,\n            recursion_limit=None,\n            if_dirty='save-before',\n            save=True,\n            git_opts=None,\n            git_clone_opts=None,\n            annex_opts=None,\n            annex_init_opts=None):\n\n        lgr.debug(\n            \"Installation attempt started. path=%r, source=%r, dataset=%r, \"\n            \"get_data=%r, description=%r, recursive=%r, recursion_limit=%r, \"\n            \"git_opts=%r, git_clone_opts=%r, annex_opts=%r, annex_init_opt=%r\",\n            path, source, dataset, get_data, description, recursive,\n            recursion_limit, git_opts, git_clone_opts, annex_opts,\n            annex_init_opts)\n\n        # shortcut\n        ds = dataset\n\n        _install_into_ds = False  # default\n        # did we explicitly get a dataset to install into?\n        # if we got a dataset, path will be resolved against it.\n        # Otherwise path will be resolved first.\n\n        if ds is not None:\n            _install_into_ds = True\n            if not isinstance(ds, Dataset):\n                ds = Dataset(ds)\n            if not ds.is_installed():\n                # TODO: possible magic: ds.install() for known subdataset 'ds'\n                raise ValueError(\"{0} needs to be installed in order to \"\n                                 \"install something into it.\".format(ds))\n            handle_dirty_dataset(ds, if_dirty)\n\n        # resolve the target location (if local) against the provided dataset\n        # or CWD:\n        if path is not None:\n            # Should work out just fine for regular paths, so no additional\n            # conditioning is necessary\n            path_ri = RI(path)\n            try:\n                # Wouldn't work for SSHRI ATM, see TODO within SSHRI\n                path = resolve_path(path_ri.localpath, ds)\n                # any `path` argument that point to something local now\n                # resolved and is no longer a URL\n            except ValueError:\n                # URL doesn't point to a local something\n                # so we have an actual URL in `path`. Since this is valid as a\n                # single positional argument, `source` has to be None at this\n                # point.\n\n                if is_datalad_compat_ri(path) and source is None:\n                    # we have an actual URL -> this should be the source\n                    lgr.debug(\n                        \"Single argument given to install, that doesn't seem to \"\n                        \"be a local path. \"\n                        \"Assuming the argument identifies a source location.\")\n                    source = path\n                    path = None\n\n                else:\n                    # `path` is neither a valid source nor a local path.\n                    # TODO: The only thing left is a known subdataset with a\n                    # name, that is not a path; Once we correctly distinguish\n                    # between path and name of a submodule, we need to consider\n                    # this.\n                    # For now: Just raise\n                    raise ValueError(\"Invalid path argument {0}\".format(path))\n\n        # `path` resolved, if there was any.\n\n        # we need a source to install from. Either we have one in `source` or\n        # it is implicit, since `path` is an already known subdataset or an\n        # existing dataset, that should be installed into the given dataset as a\n        # subdataset inplace.\n        # Note: For now, we do not consider a subdataset beneath a not yet\n        # installed level, since we do not know, whether this even is something\n        # to install (an actual Dataset) the only thing we know would be,\n        # that it is some path beneath it.\n        _install_sub = False\n\n        if _install_into_ds and source is None and path is not None:\n            # Check for `path` being a known subdataset:\n            if path in [opj(ds.path, sub)\n                        for sub in ds.get_subdatasets(recursive=True)]:\n                _install_sub = True\n                lgr.debug(\"Identified {0} as subdataset to \"\n                          \"install.\".format(path))\n            else:\n                # the only option left is an existing repo to be added inplace:\n                if exists(path) and GitRepo.is_valid_repo(path):\n                    lgr.debug(\"No source given, but path points to an existing \"\n                              \"repository and a dataset to install into was \"\n                              \"given. Assuming we want to install {0} \"\n                              \"inplace into {1}.\".format(path, ds))\n                    source = path\n\n        if source is None and not _install_sub:\n            # we have no source and don't have a dataset to install into.\n            # could be a single positional argument, that points to a known\n            # subdataset.\n            # So, test for that last remaining option:\n\n            # if `path` was a known subdataset to be installed, let's assume\n            # it would be one:\n            assume_ds = Dataset(path)\n            candidate_super_ds = assume_ds.get_superdataset()\n\n            if candidate_super_ds and candidate_super_ds != assume_ds and \\\n                assume_ds.path in candidate_super_ds.get_subdatasets(absolute=True):\n\n                # `path` has a potential superdataset and is known to this\n                # candidate\n                _install_sub = True\n                _install_into_ds = True\n                ds = candidate_super_ds\n\n            else:\n                # no match, we can't deal with that `path` argument\n                # without a `source`:\n                raise InsufficientArgumentsError(\n                    \"Got no source to install from.\")\n\n        _install_inplace = False\n        if source == path:  # TODO: does it make sense to use realpath here?\n            if _install_into_ds:\n                _install_inplace = True\n            else:\n                raise InsufficientArgumentsError(\n                    \"Source and target are the same ({0}). This doesn't make \"\n                    \"sense without a dataset to install into.\".format(path))\n\n        # Possibly do conversion from source into a git-friendly url\n        source_url = _get_git_url_from_source(source, none_ok=True)\n\n        # derive target from source url:\n        if path is None and source_url is not None:\n            # we got nothing but a source. do something similar to git clone\n            # and derive the path from the source_url and continue\n            lgr.debug(\n                \"Neither dataset nor target installation path provided. \"\n                \"Assuming installation of a remote dataset. \"\n                \"Deriving destination path from given source {0}\".format(\n                    source_url))\n            path = _get_installationpath_from_url(source_url)\n            # since this is a relative `path`, resolve it:\n            path = resolve_path(path, ds)\n\n        if path is None:\n            # still no target => fail\n            raise InsufficientArgumentsError(\"Got no target to install to.\")\n\n        lgr.debug(\"Resolved installation target: {0}\".format(path))\n\n        # TODO: expandpath()?\n        # more checks, whether something exists and what it actually is?\n\n        ###########\n        # we should know everything necessary by now\n        # actual installation starts\n        ###########\n        lgr.info(\"Installing {0}{1}\".format(\n            path, \" from %s\" % source_url if source_url else \"\"\n        ))\n\n        installed_items = []\n        # FLOW GUIDE:\n        # four cases:\n        # 1. install into a dataset\n        #   1.1. we install a known subdataset\n        #        => git submodule update --init\n        #   1.2. we install an existing repo as a subdataset inplace\n        #        => git submodule add + magic\n        #   1.3. we install a new subdataset from an explicit source\n        #        => git submodule add\n        # 2. we \"just\" install from an explicit source\n        #    => git clone\n\n        if _install_into_ds:\n            # FLOW GUIDE: 1.\n            lgr.info(\"Install subdataset at: {0}\".format(path))\n\n            # express the destination path relative to the root of\n            # the dataset\n            relativepath = relpath(path, start=ds.path)\n            if relativepath.startswith(pardir):\n                raise ValueError(\"installation path outside dataset \"\n                                 \"({0})\".format(path))\n            lgr.debug(\"Resolved installation target relative to dataset \"\n                      \"{0}: {1}\".format(ds, relativepath))\n\n            if _install_sub:\n                # FLOW_GUIDE: 1.1.\n                submodule = [sm for sm in ds.repo.get_submodules()\n                             if sm.path == relativepath][0]\n\n                _install_subds_from_flexible_source(\n                    ds,\n                    submodule.path,\n                    submodule.url,\n                    recursive=False)\n                #ds.repo.update_submodule(relativepath, init=True)\n\n                # TODO: use _install_subds_from_flexible instead?\n                # it calls install again, but this is based on old install.\n                # So, need to figure it out\n                # Additional note: - does always git clone + add inplace\n\n            elif _install_inplace:\n                # FLOW GUIDE: 1.2.\n                _install_subds_inplace(ds, path, relpath(path, ds.path))\n                # TODO: Some success checks?\n            else:\n                # FLOW_GUIDE 1.3.\n                _install_subds_from_flexible_source(\n                    ds, relativepath,\n                    source_url, recursive=False)\n                #ds.repo.add_submodule(relativepath, url=source_url)\n        else:\n            # FLOW GUIDE: 2.\n            lgr.info(\"Install dataset at: {0}\".format(path))\n\n            # Currently assuming there is nothing at the target to deal with\n            # and rely on failures raising from the git call ...\n\n            target = Dataset(path)\n\n            # TODO\n            assert(target.repo is None)\n\n            # should not be the case, but we need to distinguish between failure\n            # of git-clone, due to existing target and an unsuccessful clone\n            # attempt. See below.\n            existed = target.path and exists(target.path)\n\n            vcs = None\n            # We possibly need to consider /.git URL\n            candidate_source_urls = [source_url]\n            if source_url and not source_url.rstrip('/').endswith('/.git'):\n                candidate_source_urls.append(\n                    '{0}/.git'.format(source_url.rstrip('/')))\n\n            for source_url_ in candidate_source_urls:\n                try:\n                    lgr.debug(\"Retrieving a dataset from URL: \"\n                              \"{0}\".format(source_url_))\n                    with swallow_logs():\n                        vcs = Install._get_new_vcs(target, source_url_)\n                    break  # do not bother with other sources if succeeded\n                except GitCommandError:\n                    lgr.debug(\"Failed to retrieve from URL: \"\n                              \"{0}\".format(source_url_))\n                    if not existed and target.path and exists(target.path):\n                        lgr.debug(\"Wiping out unsuccessful clone attempt at \"\n                                  \"{}\".format(target.path))\n                        rmtree(target.path)\n                    if source_url_ == candidate_source_urls[-1]:\n                        # Re-raise if failed even with the last candidate\n                        lgr.debug(\"Unable to establish repository instance at \"\n                                  \"{0} from {1}\"\n                                  \"\".format(target.path, candidate_source_urls))\n                        raise\n\n            # is automagically re-evaluated in the .repo property:\n            assert(target.repo)\n            # cloning done\n\n        # FLOW GUIDE: All four cases done.\n\n        # in any case check whether we need to annex init the installed thing:\n        if knows_annex(path):\n            # init annex when traces of a remote annex can be detected\n            lgr.info(\"Initializing annex repo at %s\", path)\n            AnnexRepo(path, init=True)\n\n        lgr.debug(\"Installation of {0} done.\".format(path)) ##TODO: installed DS instead of `path`\n        current_dataset = Dataset(path)\n        installed_items.append(current_dataset)\n\n        # Now, recursive calls:\n        if recursive:\n            if description:\n                lgr.warning(\"Description can't be assigned recursively.\")\n            subs = [Dataset(p) for p in\n                    current_dataset.get_subdatasets(recursive=True,\n                                                    recursion_limit=1,\n                                                    absolute=True)]\n            for subds in subs:\n                if subds.is_installed():\n                    lgr.debug(\"subdataset {0} already installed. Skipped.\".format(subds))\n                else:\n                    rec_installed = Install.__call__(\n                        path=subds.path,\n                        dataset=current_dataset,\n                        recursive=True,\n                        recursion_limit=recursion_limit - 1\n                        if recursion_limit else None,\n                        if_dirty=if_dirty,\n                        save=save,\n                        git_opts=git_opts,\n                        git_clone_opts=git_clone_opts,\n                        annex_opts=annex_opts,\n                        annex_init_opts=annex_init_opts)\n                    if isinstance(rec_installed, list):\n                        installed_items.extend(rec_installed)\n                    else:\n                        installed_items.append(rec_installed)\n\n        # get the content of installed (sub-)datasets:\n        if get_data:\n            for d in installed_items:\n                lgr.info(\"Getting data of {0}\".format(d))\n                if isinstance(d.repo, AnnexRepo):\n                    d.get(curdir)\n\n        # everything done => save changes:\n        if save and _install_into_ds:\n            # Note: The only possible changes are installed subdatasets.\n            # This means: We have something to save only, if we installed into\n            # a dataset.\n            lgr.info(\"Saving changes to {0}\".format(ds))\n            ds.save(\n                message='[DATALAD] installed subdataset{0}:{1}'.format(\n                    \"s\" if len(installed_items) > 1 else \"\",\n                    linesep + linesep.join([str(i) for i in installed_items])),\n                auto_add_changes=False,\n                recursive=False)\n\n        if len(installed_items) == 1:\n            return installed_items[0]\n        else:\n            return installed_items\n\n    @staticmethod\n    def _get_new_vcs(ds, source):\n        if source is None:\n            raise RuntimeError(\n                \"No `source` was provided. To create a new dataset \"\n                \"use the `create` command.\")\n        else:\n            # when obtained from remote, try with plain Git\n            lgr.info(\"Creating a new git repo at %s\", ds.path)\n            vcs = GitRepo(ds.path, url=source, create=True)\n            if knows_annex(ds.path):\n                # init annex when traces of a remote annex can be detected\n                lgr.info(\"Initializing annex repo at %s\", ds.path)\n                vcs = AnnexRepo(ds.path, init=True)\n            else:\n                lgr.debug(\"New repository clone has no traces of an annex\")\n        return vcs\n\n    @staticmethod\n    def result_renderer_cmdline(res, args):\n        from datalad.ui import ui\n        if res is None:\n            res = []\n        if not isinstance(res, list):\n            res = [res]\n        if not len(res):\n            ui.message(\"Nothing was installed\")\n            return\n        items = '\\n'.join(map(str, res))\n        msg = \"{n} installed {obj} available at\\n{items}\".format(\n            obj='items are' if len(res) > 1 else 'item is',\n            n=len(res),\n            items=items)\n        ui.message(msg)\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]

**Title:** `install()` Raises `TypeError` Instead of `InsufficientArgumentsError` When Called Without Arguments

**Description:**

When the `install` function is invoked without the required arguments, it unexpectedly raises a `TypeError` instead of the intended `InsufficientArgumentsError`. This makes it unclear to users why the installation failed and hinders proper error handling.

**Example Code:**

```python
install()
```

**Expected Behavior:**

Calling `install()` without the necessary arguments should raise an `InsufficientArgumentsError` to indicate that required parameters are missing.

**Actual Behavior:**

A `TypeError` is raised with the message:
```
TypeError: expected str, bytes or os.PathLike object, not NoneType
```

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### datalad/distribution/install.py
# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-
# ex: set sts=4 ts=4 sw=4 noet:
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
#
#   See COPYING file distributed along with the datalad package for the
#   copyright and license terms.
#
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
"""High-level interface for dataset (component) installation

"""
from datalad.distribution.utils import _install_subds_inplace, \
    _fixup_submodule_dotgit_setup

__docformat__ = 'restructuredtext'

import logging
from os import curdir, linesep
from os.path import join as opj, relpath, pardir, exists

from six.moves.urllib.parse import quote as urlquote

from .dataset import Dataset, datasetmethod, \
    resolve_path, EnsureDataset

from datalad.interface.base import Interface
from datalad.interface.common_opts import recursion_flag, recursion_limit, \
    dataset_description, git_opts, annex_opts, \
    annex_init_opts, git_clone_opts, if_dirty_opt, nosave_opt
from datalad.interface.utils import handle_dirty_dataset

from datalad.support.constraints import EnsureStr, EnsureNone
from datalad.support.annexrepo import AnnexRepo
from datalad.support.exceptions import InsufficientArgumentsError
from datalad.support.gitrepo import GitRepo, GitCommandError
from datalad.support.param import Parameter
from datalad.utils import knows_annex, swallow_logs
from datalad.support.network import RI, URL
from datalad.support.network import DataLadRI
from datalad.support.network import is_url, is_datalad_compat_ri
from datalad.utils import rmtree

lgr = logging.getLogger('datalad.distribution.install')


def _get_git_url_from_source(source, none_ok=False):
    """Return URL for cloning associated with a source specification

    For now just resolves DataLadRIs
    """
    # TODO: Probably RF this into RI.as_git_url(), that would be overridden
    # by subclasses or sth. like that

    if source is None:
        if not none_ok:
            lgr.warning("received 'None' as 'source'.")
        return source

    if not isinstance(source, RI):
        source_ri = RI(source)
    else:
        source_ri = source
    if isinstance(source_ri, DataLadRI):
        # we have got our DataLadRI as the source, so expand it
        source = source_ri.as_git_url()
    else:
        source = str(source_ri)
    return source


def _get_installationpath_from_url(url):
    """Returns a relative path derived from the trailing end of a URL

    This can be used to determine an installation path of a Dataset
    from a URL, analog to what `git clone` does.
    """
    path = url.rstrip('/')
    if '/' in path:
        path = path.split('/')
        if path[-1] == '.git':
            path = path[-2]
        else:
            path = path[-1]
    if path.endswith('.git'):
        path = path[:-4]
    return path


def _install_subds_from_flexible_source(ds, sm_path, sm_url, recursive):
    """Tries to obtain a given subdataset from several meaningful locations"""
    # shortcut
    vcs = ds.repo
    repo = vcs.repo
    # compose a list of candidate clone URLs
    clone_urls = []
    # if we have a remote, let's check the location of that remote
    # for the presence of the desired submodule
    tracking_branch = repo.active_branch.tracking_branch()
    remote_url = ''
    # remember suffix
    url_suffix = ''
    if tracking_branch:
        # name of the default remote for the active branch
        remote_name = repo.active_branch.tracking_branch().remote_name
        remote_url = vcs.get_remote_url(remote_name, push=False)
        if remote_url.rstrip('/').endswith('/.git'):
            url_suffix = '/.git'
            remote_url = remote_url[:-5]
        # attempt: submodule checkout at parent remote URL
        # We might need to quote sm_path portion, e.g. for spaces etc
        if remote_url and isinstance(RI(remote_url), URL):
            sm_path_url = urlquote(sm_path)
        else:
            sm_path_url = sm_path
        clone_urls.append('{0}/{1}{2}'.format(
            remote_url, sm_path_url, url_suffix))
    # attempt: configured submodule URL
    # TODO: consider supporting DataLadRI here?  or would confuse
    #  git and we wouldn't want that (i.e. not allow pure git clone
    #  --recursive)
    if sm_url.startswith('/') or is_url(sm_url):
        # this seems to be an absolute location -> take as is
        clone_urls.append(sm_url)
    else:
        # need to resolve relative URL
        if not remote_url:
            # we have no remote URL, hence we need to go with the
            # local path
            remote_url = ds.path
        remote_url_l = remote_url.split('/')
        sm_url_l = sm_url.split('/')
        for i, c in enumerate(sm_url_l):
            if c == pardir:
                remote_url_l = remote_url_l[:-1]
            else:
                clone_urls.append('{0}/{1}{2}'.format(
                    '/'.join(remote_url_l),
                    '/'.join(sm_url_l[i:]),
                    url_suffix))
                break
    # now loop over all candidates and try to clone
    subds = Dataset(opj(ds.path, sm_path))
    for clone_url in clone_urls:
        lgr.debug("Attempt clone of subdataset from: {0}".format(clone_url))
        try:
            subds = Install.__call__(
                path=subds.path, source=clone_url,
                recursive=recursive)
        except GitCommandError:
            # TODO: failed clone might leave something behind that causes the
            # next attempt to fail as well. Implement safe way to remove clone
            # attempt left-overs.
            continue
        lgr.debug("Update cloned subdataset {0} in parent".format(subds))
        if sm_path in ds.get_subdatasets(absolute=False, recursive=False):
            ds.repo.update_submodule(sm_path, init=True)
        else:
            # submodule is brand-new and previously unknown
            ds.repo.add_submodule(sm_path, url=clone_url)
        _fixup_submodule_dotgit_setup(ds, sm_path)
        return subds


# TODO:  git_clone options
# use --shared by default? => option --no-shared


class Install(Interface):
    """Install a dataset or subdataset.

    This command creates a local :term:`sibling` of an existing dataset from a
    (remote) location identified via a URL or path, or by the name of a
    registered subdataset. Optional recursion into potential subdatasets, and
    download of all referenced data is supported. The new dataset can be
    optionally registered in an existing :term:`superdataset` (the new
    dataset's path needs to be located within the superdataset for that, and
    the superdataset will be detected automatically). It is recommended to
    provide a brief description to label the dataset's nature *and* location,
    e.g. "Michael's music on black laptop". This helps humans to identify data
    locations in distributed scenarios.  By default an identifier comprised of
    user and machine name, plus path will be generated.

    When only partial dataset content shall be obtained, it is recommended to
    use this command without the :option:`get-data` flag, followed by a
    :func:`~datalad.api.get` operation to obtain the desired data.

    .. note::
      Power-user info: This command uses :command:`git clone`, and
      :command:`git annex init` to prepare the dataset. Registering to a
      superdataset is performed via a :command:`git submodule add` operation
      in the discovered superdataset.
    """

    _params_ = dict(
        dataset=Parameter(
            args=("-d", "--dataset"),
            # TODO: this probably changes to install into the dataset (add_to_super)
            # and to install the thing 'just there' without operating 'on' a dataset.
            # Adapt doc.
            doc="""specify the dataset to perform the install operation on.  If
            no dataset is given, an attempt is made to identify the dataset
            in a parent directory of the current working directory and/or the
            `path` given""",
            constraints=EnsureDataset() | EnsureNone()),
        path=Parameter(
            args=("path",),
            doc="""path/name of the installation target.  If no `source` is
            provided, and no `dataset` is given or detected, this is
            interpreted as the source URL of a dataset and a destination
            path will be derived from the URL similar to :command:`git
            clone`""",
            nargs="?",
            constraints=EnsureStr() | EnsureNone()),
        source=Parameter(
            args=("-s", "--source",),
            doc="URL or local path of the installation source",
            constraints=EnsureStr() | EnsureNone()),
        get_data=Parameter(
            args=("-g", "--get-data",),
            action="store_true",
            doc="""if given, obtain all data content too"""),
        description=dataset_description,
        recursive=recursion_flag,
        recursion_limit=recursion_limit,
        if_dirty=if_dirty_opt,
        save=nosave_opt,
        git_opts=git_opts,
        git_clone_opts=git_clone_opts,
        annex_opts=annex_opts,
        annex_init_opts=annex_init_opts)

    @staticmethod
    @datasetmethod(name='install')
    def __call__(
            path=None,
            source=None,
            dataset=None,
            get_data=False,
            description=None,
            recursive=False,
            recursion_limit=None,
            if_dirty='save-before',
            save=True,
            git_opts=None,
            git_clone_opts=None,
            annex_opts=None,
            annex_init_opts=None):

        lgr.debug(
            "Installation attempt started. path=%r, source=%r, dataset=%r, "
            "get_data=%r, description=%r, recursive=%r, recursion_limit=%r, "
            "git_opts=%r, git_clone_opts=%r, annex_opts=%r, annex_init_opt=%r",
            path, source, dataset, get_data, description, recursive,
            recursion_limit, git_opts, git_clone_opts, annex_opts,
            annex_init_opts)

        # shortcut
        ds = dataset

        _install_into_ds = False  # default
        # did we explicitly get a dataset to install into?
        # if we got a dataset, path will be resolved against it.
        # Otherwise path will be resolved first.

        if ds is not None:
            _install_into_ds = True
            if not isinstance(ds, Dataset):
                ds = Dataset(ds)
            if not ds.is_installed():
                # TODO: possible magic: ds.install() for known subdataset 'ds'
                raise ValueError("{0} needs to be installed in order to "
                                 "install something into it.".format(ds))
            handle_dirty_dataset(ds, if_dirty)

        # resolve the target location (if local) against the provided dataset
        # or CWD:
        if path is not None:
            # Should work out just fine for regular paths, so no additional
            # conditioning is necessary
            path_ri = RI(path)
            try:
                # Wouldn't work for SSHRI ATM, see TODO within SSHRI
                path = resolve_path(path_ri.localpath, ds)
                # any `path` argument that point to something local now
                # resolved and is no longer a URL
            except ValueError:
                # URL doesn't point to a local something
                # so we have an actual URL in `path`. Since this is valid as a
                # single positional argument, `source` has to be None at this
                # point.

                if is_datalad_compat_ri(path) and source is None:
                    # we have an actual URL -> this should be the source
                    lgr.debug(
                        "Single argument given to install, that doesn't seem to "
                        "be a local path. "
                        "Assuming the argument identifies a source location.")
                    source = path
                    path = None

                else:
                    # `path` is neither a valid source nor a local path.
                    # TODO: The only thing left is a known subdataset with a
                    # name, that is not a path; Once we correctly distinguish
                    # between path and name of a submodule, we need to consider
                    # this.
                    # For now: Just raise
                    raise ValueError("Invalid path argument {0}".format(path))

        # `path` resolved, if there was any.

        # we need a source to install from. Either we have one in `source` or
        # it is implicit, since `path` is an already known subdataset or an
        # existing dataset, that should be installed into the given dataset as a
        # subdataset inplace.
        # Note: For now, we do not consider a subdataset beneath a not yet
        # installed level, since we do not know, whether this even is something
        # to install (an actual Dataset) the only thing we know would be,
        # that it is some path beneath it.
        _install_sub = False

        if _install_into_ds and source is None and path is not None:
            # Check for `path` being a known subdataset:
            if path in [opj(ds.path, sub)
                        for sub in ds.get_subdatasets(recursive=True)]:
                _install_sub = True
                lgr.debug("Identified {0} as subdataset to "
                          "install.".format(path))
            else:
                # the only option left is an existing repo to be added inplace:
                if exists(path) and GitRepo.is_valid_repo(path):
                    lgr.debug("No source given, but path points to an existing "
                              "repository and a dataset to install into was "
                              "given. Assuming we want to install {0} "
                              "inplace into {1}.".format(path, ds))
                    source = path

        if source is None and not _install_sub:
            # we have no source and don't have a dataset to install into.
            # could be a single positional argument, that points to a known
            # subdataset.
            # So, test for that last remaining option:

            # if `path` was a known subdataset to be installed, let's assume
            # it would be one:
            assume_ds = Dataset(path)
            candidate_super_ds = assume_ds.get_superdataset()

            if candidate_super_ds and candidate_super_ds != assume_ds and \
                assume_ds.path in candidate_super_ds.get_subdatasets(absolute=True):

                # `path` has a potential superdataset and is known to this
                # candidate
                _install_sub = True
                _install_into_ds = True
                ds = candidate_super_ds

            else:
                # no match, we can't deal with that `path` argument
                # without a `source`:
                raise InsufficientArgumentsError(
                    "Got no source to install from.")

        _install_inplace = False
        if source == path:  # TODO: does it make sense to use realpath here?
            if _install_into_ds:
                _install_inplace = True
            else:
                raise InsufficientArgumentsError(
                    "Source and target are the same ({0}). This doesn't make "
                    "sense without a dataset to install into.".format(path))

        # Possibly do conversion from source into a git-friendly url
        source_url = _get_git_url_from_source(source, none_ok=True)

        # derive target from source url:
        if path is None and source_url is not None:
            # we got nothing but a source. do something similar to git clone
            # and derive the path from the source_url and continue
            lgr.debug(
                "Neither dataset nor target installation path provided. "
                "Assuming installation of a remote dataset. "
                "Deriving destination path from given source {0}".format(
                    source_url))
            path = _get_installationpath_from_url(source_url)
            # since this is a relative `path`, resolve it:
            path = resolve_path(path, ds)

        if path is None:
            # still no target => fail
            raise InsufficientArgumentsError("Got no target to install to.")

        lgr.debug("Resolved installation target: {0}".format(path))

        # TODO: expandpath()?
        # more checks, whether something exists and what it actually is?

        ###########
        # we should know everything necessary by now
        # actual installation starts
        ###########
        lgr.info("Installing {0}{1}".format(
            path, " from %s" % source_url if source_url else ""
        ))

        installed_items = []
        # FLOW GUIDE:
        # four cases:
        # 1. install into a dataset
        #   1.1. we install a known subdataset
        #        => git submodule update --init
        #   1.2. we install an existing repo as a subdataset inplace
        #        => git submodule add + magic
        #   1.3. we install a new subdataset from an explicit source
        #        => git submodule add
        # 2. we "just" install from an explicit source
        #    => git clone

        if _install_into_ds:
            # FLOW GUIDE: 1.
            lgr.info("Install subdataset at: {0}".format(path))

            # express the destination path relative to the root of
            # the dataset
            relativepath = relpath(path, start=ds.path)
            if relativepath.startswith(pardir):
                raise ValueError("installation path outside dataset "
                                 "({0})".format(path))
            lgr.debug("Resolved installation target relative to dataset "
                      "{0}: {1}".format(ds, relativepath))

            if _install_sub:
                # FLOW_GUIDE: 1.1.
                submodule = [sm for sm in ds.repo.get_submodules()
                             if sm.path == relativepath][0]

                _install_subds_from_flexible_source(
                    ds,
                    submodule.path,
                    submodule.url,
                    recursive=False)
                #ds.repo.update_submodule(relativepath, init=True)

                # TODO: use _install_subds_from_flexible instead?
                # it calls install again, but this is based on old install.
                # So, need to figure it out
                # Additional note: - does always git clone + add inplace

            elif _install_inplace:
                # FLOW GUIDE: 1.2.
                _install_subds_inplace(ds, path, relpath(path, ds.path))
                # TODO: Some success checks?
            else:
                # FLOW_GUIDE 1.3.
                _install_subds_from_flexible_source(
                    ds, relativepath,
                    source_url, recursive=False)
                #ds.repo.add_submodule(relativepath, url=source_url)
        else:
            # FLOW GUIDE: 2.
            lgr.info("Install dataset at: {0}".format(path))

            # Currently assuming there is nothing at the target to deal with
            # and rely on failures raising from the git call ...

            target = Dataset(path)

            # TODO
            assert(target.repo is None)

            # should not be the case, but we need to distinguish between failure
            # of git-clone, due to existing target and an unsuccessful clone
            # attempt. See below.
            existed = target.path and exists(target.path)

            vcs = None
            # We possibly need to consider /.git URL
            candidate_source_urls = [source_url]
            if source_url and not source_url.rstrip('/').endswith('/.git'):
                candidate_source_urls.append(
                    '{0}/.git'.format(source_url.rstrip('/')))

            for source_url_ in candidate_source_urls:
                try:
                    lgr.debug("Retrieving a dataset from URL: "
                              "{0}".format(source_url_))
                    with swallow_logs():
                        vcs = Install._get_new_vcs(target, source_url_)
                    break  # do not bother with other sources if succeeded
                except GitCommandError:
                    lgr.debug("Failed to retrieve from URL: "
                              "{0}".format(source_url_))
                    if not existed and target.path and exists(target.path):
                        lgr.debug("Wiping out unsuccessful clone attempt at "
                                  "{}".format(target.path))
                        rmtree(target.path)
                    if source_url_ == candidate_source_urls[-1]:
                        # Re-raise if failed even with the last candidate
                        lgr.debug("Unable to establish repository instance at "
                                  "{0} from {1}"
                                  "".format(target.path, candidate_source_urls))
                        raise

            # is automagically re-evaluated in the .repo property:
            assert(target.repo)
            # cloning done

        # FLOW GUIDE: All four cases done.

        # in any case check whether we need to annex init the installed thing:
        if knows_annex(path):
            # init annex when traces of a remote annex can be detected
            lgr.info("Initializing annex repo at %s", path)
            AnnexRepo(path, init=True)

        lgr.debug("Installation of {0} done.".format(path)) ##TODO: installed DS instead of `path`
        current_dataset = Dataset(path)
        installed_items.append(current_dataset)

        # Now, recursive calls:
        if recursive:
            if description:
                lgr.warning("Description can't be assigned recursively.")
            subs = [Dataset(p) for p in
                    current_dataset.get_subdatasets(recursive=True,
                                                    recursion_limit=1,
                                                    absolute=True)]
            for subds in subs:
                if subds.is_installed():
                    lgr.debug("subdataset {0} already installed. Skipped.".format(subds))
                else:
                    rec_installed = Install.__call__(
                        path=subds.path,
                        dataset=current_dataset,
                        recursive=True,
                        recursion_limit=recursion_limit - 1
                        if recursion_limit else None,
                        if_dirty=if_dirty,
                        save=save,
                        git_opts=git_opts,
                        git_clone_opts=git_clone_opts,
                        annex_opts=annex_opts,
                        annex_init_opts=annex_init_opts)
                    if isinstance(rec_installed, list):
                        installed_items.extend(rec_installed)
                    else:
                        installed_items.append(rec_installed)

        # get the content of installed (sub-)datasets:
        if get_data:
            for d in installed_items:
                lgr.info("Getting data of {0}".format(d))
                if isinstance(d.repo, AnnexRepo):
                    d.get(curdir)

        # everything done => save changes:
        if save and _install_into_ds:
            # Note: The only possible changes are installed subdatasets.
            # This means: We have something to save only, if we installed into
            # a dataset.
            lgr.info("Saving changes to {0}".format(ds))
            ds.save(
                message='[DATALAD] installed subdataset{0}:{1}'.format(
                    "s" if len(installed_items) > 1 else "",
                    linesep + linesep.join([str(i) for i in installed_items])),
                auto_add_changes=False,
                recursive=False)

        if len(installed_items) == 1:
            return installed_items[0]
        else:
            return installed_items

    @staticmethod
    def _get_new_vcs(ds, source):
        if source is None:
            raise RuntimeError(
                "No `source` was provided. To create a new dataset "
                "use the `create` command.")
        else:
            # when obtained from remote, try with plain Git
            lgr.info("Creating a new git repo at %s", ds.path)
            vcs = GitRepo(ds.path, url=source, create=True)
            if knows_annex(ds.path):
                # init annex when traces of a remote annex can be detected
                lgr.info("Initializing annex repo at %s", ds.path)
                vcs = AnnexRepo(ds.path, init=True)
            else:
                lgr.debug("New repository clone has no traces of an annex")
        return vcs

    @staticmethod
    def result_renderer_cmdline(res, args):
        from datalad.ui import ui
        if res is None:
            res = []
        if not isinstance(res, list):
            res = [res]
        if not len(res):
            ui.message("Nothing was installed")
            return
        items = '\n'.join(map(str, res))
        msg = "{n} installed {obj} available at\n{items}".format(
            obj='items are' if len(res) > 1 else 'item is',
            n=len(res),
            items=items)
        ui.message(msg)

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user