mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-02 07:18:25 +01:00
dvc: refactor dvc project class
1) split Project's methods into separate files; 2) rename Project into Repo(similar to gitpython's Repo) Signed-off-by: Ruslan Kuprieiev <[email protected]>
This commit is contained in:
committed by
Ruslan Kuprieiev
parent
beb45202fd
commit
ba8d83e9b1
+8
-8
@@ -161,8 +161,8 @@ class Analytics(object):
|
||||
"""Collect analytics report."""
|
||||
from dvc.scm import SCM
|
||||
from dvc.utils import is_binary
|
||||
from dvc.project import Project
|
||||
from dvc.exceptions import NotDvcProjectError
|
||||
from dvc.repo import Repo
|
||||
from dvc.exceptions import NotDvcRepoError
|
||||
|
||||
self.info[self.PARAM_DVC_VERSION] = VERSION
|
||||
self.info[self.PARAM_IS_BINARY] = is_binary()
|
||||
@@ -171,9 +171,9 @@ class Analytics(object):
|
||||
self.info[self.PARAM_SYSTEM_INFO] = self._collect_system_info()
|
||||
|
||||
try:
|
||||
scm = SCM(root_dir=Project.find_root())
|
||||
scm = SCM(root_dir=Repo.find_root())
|
||||
self.info[self.PARAM_SCM_CLASS] = type(scm).__name__
|
||||
except NotDvcProjectError:
|
||||
except NotDvcRepoError:
|
||||
pass
|
||||
|
||||
def collect_cmd(self, args, ret):
|
||||
@@ -204,8 +204,8 @@ class Analytics(object):
|
||||
@staticmethod
|
||||
def _is_enabled(cmd=None):
|
||||
from dvc.config import Config
|
||||
from dvc.project import Project
|
||||
from dvc.exceptions import NotDvcProjectError
|
||||
from dvc.repo import Repo
|
||||
from dvc.exceptions import NotDvcRepoError
|
||||
from dvc.command.daemon import CmdDaemonBase
|
||||
|
||||
if os.getenv("DVC_TEST"):
|
||||
@@ -216,10 +216,10 @@ class Analytics(object):
|
||||
|
||||
if cmd is None or not hasattr(cmd, "config"):
|
||||
try:
|
||||
dvc_dir = Project.find_dvc_dir()
|
||||
dvc_dir = Repo.find_dvc_dir()
|
||||
config = Config(dvc_dir)
|
||||
assert config is not None
|
||||
except NotDvcProjectError:
|
||||
except NotDvcRepoError:
|
||||
config = Config(validate=False)
|
||||
assert config is not None
|
||||
else:
|
||||
|
||||
+12
-13
@@ -1,4 +1,4 @@
|
||||
"""Manages cache of a dvc project."""
|
||||
"""Manages cache of a dvc repo."""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
@@ -8,42 +8,41 @@ from dvc.config import Config
|
||||
|
||||
|
||||
class Cache(object):
|
||||
"""Class that manages cache locations of a dvc project.
|
||||
"""Class that manages cache locations of a dvc repo.
|
||||
|
||||
Args:
|
||||
project (dvc.project.Project): project instance that this cache
|
||||
belongs to.
|
||||
repo (dvc.repo.Repo): repo instance that this cache belongs to.
|
||||
"""
|
||||
|
||||
CACHE_DIR = "cache"
|
||||
|
||||
def __init__(self, project):
|
||||
def __init__(self, repo):
|
||||
from dvc.remote import Remote
|
||||
|
||||
self.project = project
|
||||
self.repo = repo
|
||||
|
||||
config = project.config.config[Config.SECTION_CACHE]
|
||||
config = repo.config.config[Config.SECTION_CACHE]
|
||||
local = config.get(Config.SECTION_CACHE_LOCAL)
|
||||
|
||||
if local:
|
||||
name = Config.SECTION_REMOTE_FMT.format(local)
|
||||
sect = project.config.config[name]
|
||||
sect = repo.config.config[name]
|
||||
else:
|
||||
default_cache_dir = os.path.join(project.dvc_dir, self.CACHE_DIR)
|
||||
default_cache_dir = os.path.join(repo.dvc_dir, self.CACHE_DIR)
|
||||
cache_dir = config.get(Config.SECTION_CACHE_DIR, default_cache_dir)
|
||||
cache_type = config.get(Config.SECTION_CACHE_TYPE)
|
||||
protected = config.get(Config.SECTION_CACHE_PROTECTED)
|
||||
|
||||
sect = {
|
||||
Config.PRIVATE_CWD: config.get(
|
||||
Config.PRIVATE_CWD, project.dvc_dir
|
||||
Config.PRIVATE_CWD, repo.dvc_dir
|
||||
),
|
||||
Config.SECTION_REMOTE_URL: cache_dir,
|
||||
Config.SECTION_CACHE_TYPE: cache_type,
|
||||
Config.SECTION_CACHE_PROTECTED: protected,
|
||||
}
|
||||
|
||||
self._local = Remote(project, sect)
|
||||
self._local = Remote(repo, sect)
|
||||
|
||||
self._s3 = self._get_remote(config, Config.SECTION_CACHE_S3)
|
||||
self._gs = self._get_remote(config, Config.SECTION_CACHE_GS)
|
||||
@@ -89,5 +88,5 @@ class Cache(object):
|
||||
return None
|
||||
|
||||
name = Config.SECTION_REMOTE_FMT.format(remote)
|
||||
sect = self.project.config.config[name]
|
||||
return Remote(self.project, sect)
|
||||
sect = self.repo.config.config[name]
|
||||
return Remote(self.repo, sect)
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ class CmdAdd(CmdBase):
|
||||
def run(self):
|
||||
for target in self.args.targets:
|
||||
try:
|
||||
self.project.add(target, recursive=self.args.recursive)
|
||||
self.repo.add(target, recursive=self.args.recursive)
|
||||
except DvcException:
|
||||
logger.error("failed to add file")
|
||||
return 1
|
||||
|
||||
+4
-4
@@ -20,10 +20,10 @@ def fix_subparsers(subparsers):
|
||||
|
||||
class CmdBase(object):
|
||||
def __init__(self, args):
|
||||
from dvc.project import Project
|
||||
from dvc.repo import Repo
|
||||
|
||||
self.project = Project()
|
||||
self.config = self.project.config
|
||||
self.repo = Repo()
|
||||
self.config = self.repo.config
|
||||
self.args = args
|
||||
self.set_loglevel(args)
|
||||
|
||||
@@ -49,7 +49,7 @@ class CmdBase(object):
|
||||
from dvc.lock import LockError
|
||||
|
||||
try:
|
||||
with self.project.lock:
|
||||
with self.repo.lock:
|
||||
return self.run()
|
||||
except LockError:
|
||||
logger.error("failed to lock before running a command")
|
||||
|
||||
@@ -6,10 +6,10 @@ from dvc.command.base import CmdBase
|
||||
class CmdCheckout(CmdBase):
|
||||
def run(self):
|
||||
if not self.args.targets:
|
||||
self.project.checkout(force=self.args.force)
|
||||
self.repo.checkout(force=self.args.force)
|
||||
else:
|
||||
for target in self.args.targets:
|
||||
self.project.checkout(
|
||||
self.repo.checkout(
|
||||
target=target,
|
||||
with_deps=self.args.with_deps,
|
||||
force=self.args.force,
|
||||
|
||||
@@ -11,14 +11,14 @@ from dvc.exceptions import DvcException
|
||||
|
||||
class CmdConfig(CmdBase):
|
||||
def __init__(self, args):
|
||||
from dvc.project import Project, NotDvcProjectError
|
||||
from dvc.repo import Repo, NotDvcRepoError
|
||||
|
||||
self.args = args
|
||||
|
||||
try:
|
||||
dvc_dir = os.path.join(Project.find_root(), Project.DVC_DIR)
|
||||
dvc_dir = os.path.join(Repo.find_root(), Repo.DVC_DIR)
|
||||
saved_exc = None
|
||||
except NotDvcProjectError as exc:
|
||||
except NotDvcRepoError as exc:
|
||||
dvc_dir = None
|
||||
saved_exc = exc
|
||||
|
||||
@@ -34,7 +34,7 @@ class CmdConfig(CmdBase):
|
||||
else:
|
||||
if dvc_dir is None:
|
||||
raise saved_exc
|
||||
self.configobj = self.config._project_config
|
||||
self.configobj = self.config._repo_config
|
||||
|
||||
def run_cmd(self):
|
||||
return self.run()
|
||||
|
||||
@@ -16,11 +16,11 @@ class CmdDaemonBase(CmdBase):
|
||||
class CmdDaemonUpdater(CmdDaemonBase):
|
||||
def run(self):
|
||||
import os
|
||||
from dvc.project import Project
|
||||
from dvc.repo import Repo
|
||||
from dvc.updater import Updater
|
||||
|
||||
root_dir = Project.find_root()
|
||||
dvc_dir = os.path.join(root_dir, Project.DVC_DIR)
|
||||
root_dir = Repo.find_root()
|
||||
dvc_dir = os.path.join(root_dir, Repo.DVC_DIR)
|
||||
updater = Updater(dvc_dir)
|
||||
updater.fetch(detach=False)
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ class CmdDataBase(CmdBase):
|
||||
class CmdDataPull(CmdDataBase):
|
||||
def do_run(self, target=None):
|
||||
try:
|
||||
self.project.pull(
|
||||
self.repo.pull(
|
||||
target=target,
|
||||
jobs=self.args.jobs,
|
||||
remote=self.args.remote,
|
||||
@@ -44,7 +44,7 @@ class CmdDataPull(CmdDataBase):
|
||||
class CmdDataPush(CmdDataBase):
|
||||
def do_run(self, target=None):
|
||||
try:
|
||||
self.project.push(
|
||||
self.repo.push(
|
||||
target=target,
|
||||
jobs=self.args.jobs,
|
||||
remote=self.args.remote,
|
||||
@@ -63,7 +63,7 @@ class CmdDataPush(CmdDataBase):
|
||||
class CmdDataFetch(CmdDataBase):
|
||||
def do_run(self, target=None):
|
||||
try:
|
||||
self.project.fetch(
|
||||
self.repo.fetch(
|
||||
target=target,
|
||||
jobs=self.args.jobs,
|
||||
remote=self.args.remote,
|
||||
@@ -240,7 +240,7 @@ def add_parser(subparsers, _parent_parser):
|
||||
fetch_parser.set_defaults(func=CmdDataFetch)
|
||||
|
||||
# Status
|
||||
STATUS_HELP = "Show the project status."
|
||||
STATUS_HELP = "Show the repo status."
|
||||
status_parser = subparsers.add_parser(
|
||||
"status",
|
||||
parents=[shared_parent_parser()],
|
||||
|
||||
@@ -22,7 +22,7 @@ class CmdDestroy(CmdBase):
|
||||
" Use '-f' to force."
|
||||
)
|
||||
|
||||
self.project.destroy()
|
||||
self.repo.destroy()
|
||||
except Exception:
|
||||
logger.error("failed to destroy DVC")
|
||||
return 1
|
||||
@@ -31,7 +31,7 @@ class CmdDestroy(CmdBase):
|
||||
|
||||
def add_parser(subparsers, parent_parser):
|
||||
DESTROY_HELP = (
|
||||
"Destroy dvc. Will remove all project's information, "
|
||||
"Destroy dvc. Will remove all repo's information, "
|
||||
"data files and cache."
|
||||
)
|
||||
destroy_parser = subparsers.add_parser(
|
||||
|
||||
+8
-7
@@ -19,13 +19,13 @@ class CmdGC(CmdBase):
|
||||
else:
|
||||
msg += "all git branches and all git tags"
|
||||
|
||||
if self.args.projects is not None and len(self.args.projects) > 0:
|
||||
msg += " of the current and the following projects:"
|
||||
if self.args.repos is not None and len(self.args.repos) > 0:
|
||||
msg += " of the current and the following repos:"
|
||||
|
||||
for project_path in self.args.projects:
|
||||
msg += "\n - %s" % os.path.abspath(project_path)
|
||||
for repo_path in self.args.repos:
|
||||
msg += "\n - %s" % os.path.abspath(repo_path)
|
||||
else:
|
||||
msg += " of the current project."
|
||||
msg += " of the current repo."
|
||||
|
||||
logger.warning(msg)
|
||||
|
||||
@@ -33,14 +33,14 @@ class CmdGC(CmdBase):
|
||||
if not self.args.force and not prompt.confirm(msg):
|
||||
return 1
|
||||
|
||||
self.project.gc(
|
||||
self.repo.gc(
|
||||
all_branches=self.args.all_branches,
|
||||
all_tags=self.args.all_tags,
|
||||
cloud=self.args.cloud,
|
||||
remote=self.args.remote,
|
||||
force=self.args.force,
|
||||
jobs=self.args.jobs,
|
||||
projects=self.args.projects,
|
||||
repos=self.args.repos,
|
||||
)
|
||||
return 0
|
||||
|
||||
@@ -91,6 +91,7 @@ def add_parser(subparsers, parent_parser):
|
||||
gc_parser.add_argument(
|
||||
"-p",
|
||||
"--projects",
|
||||
dest="repos",
|
||||
type=str,
|
||||
nargs="*",
|
||||
default=None,
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ class CmdImport(CmdBase):
|
||||
|
||||
out = self.args.out or default_out
|
||||
|
||||
self.project.imp(self.args.url, out, self.args.resume)
|
||||
self.repo.imp(self.args.url, out, self.args.resume)
|
||||
except DvcException:
|
||||
logger.error(
|
||||
"failed to import {}. You could also try downloading "
|
||||
|
||||
+4
-3
@@ -8,13 +8,14 @@ class CmdInit(object):
|
||||
self.args = args
|
||||
|
||||
def run_cmd(self):
|
||||
from dvc.project import Project, InitError
|
||||
from dvc.repo import Repo
|
||||
from dvc.exceptions import InitError
|
||||
|
||||
try:
|
||||
self.project = Project.init(
|
||||
self.repo = Repo.init(
|
||||
".", no_scm=self.args.no_scm, force=self.args.force
|
||||
)
|
||||
self.config = self.project.config
|
||||
self.config = self.repo.config
|
||||
except InitError:
|
||||
logger.error("failed to initiate dvc")
|
||||
return 1
|
||||
|
||||
@@ -7,7 +7,7 @@ from dvc.command.base import CmdBase
|
||||
class CmdInstall(CmdBase):
|
||||
def run_cmd(self):
|
||||
try:
|
||||
self.project.install()
|
||||
self.repo.install()
|
||||
except Exception:
|
||||
logger.error("failed to install dvc hooks")
|
||||
return 1
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ class CmdLockBase(CmdBase):
|
||||
def run(self, unlock=False):
|
||||
for target in self.args.targets:
|
||||
try:
|
||||
self.project.lock_stage(target, unlock=unlock)
|
||||
self.repo.lock_stage(target, unlock=unlock)
|
||||
except DvcException:
|
||||
logger.error(
|
||||
"failed to {}lock '{}'".format(
|
||||
|
||||
@@ -28,7 +28,7 @@ class CmdMetricsShow(CmdBase):
|
||||
typ = self.args.type
|
||||
xpath = self.args.xpath
|
||||
|
||||
self.project.metrics_show(
|
||||
self.repo.metrics.show(
|
||||
self.args.path,
|
||||
typ=typ,
|
||||
xpath=xpath,
|
||||
@@ -46,7 +46,7 @@ class CmdMetricsShow(CmdBase):
|
||||
class CmdMetricsModify(CmdBase):
|
||||
def run(self):
|
||||
try:
|
||||
self.project.metrics_modify(
|
||||
self.repo.metrics.modify(
|
||||
self.args.path, typ=self.args.type, xpath=self.args.xpath
|
||||
)
|
||||
except DvcException:
|
||||
@@ -59,7 +59,7 @@ class CmdMetricsModify(CmdBase):
|
||||
class CmdMetricsAdd(CmdBase):
|
||||
def run(self):
|
||||
try:
|
||||
self.project.metrics_add(
|
||||
self.repo.metrics.add(
|
||||
self.args.path, self.args.type, self.args.xpath
|
||||
)
|
||||
except DvcException:
|
||||
@@ -73,7 +73,7 @@ class CmdMetricsAdd(CmdBase):
|
||||
class CmdMetricsRemove(CmdBase):
|
||||
def run(self):
|
||||
try:
|
||||
self.project.metrics_remove(self.args.path)
|
||||
self.repo.metrics.remove(self.args.path)
|
||||
except DvcException:
|
||||
msg = "failed to remove metric file '{}'".format(self.args.path)
|
||||
logger.error(msg)
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ from dvc.command.base import CmdBase
|
||||
class CmdMove(CmdBase):
|
||||
def run(self):
|
||||
try:
|
||||
self.project.move(self.args.src, self.args.dst)
|
||||
self.repo.move(self.args.src, self.args.dst)
|
||||
except DvcException:
|
||||
msg = "failed to move '{}' -> '{}'".format(
|
||||
self.args.src, self.args.dst
|
||||
|
||||
@@ -14,10 +14,10 @@ class CmdPipelineShow(CmdBase):
|
||||
import networkx
|
||||
from dvc.stage import Stage
|
||||
|
||||
stage = Stage.load(self.project, target)
|
||||
G = self.project.graph()[0]
|
||||
stage = Stage.load(self.repo, target)
|
||||
G = self.repo.graph()[0]
|
||||
stages = networkx.get_node_attributes(G, "stage")
|
||||
node = os.path.relpath(stage.path, self.project.root_dir)
|
||||
node = os.path.relpath(stage.path, self.repo.root_dir)
|
||||
|
||||
for n in networkx.dfs_postorder_nodes(G, node):
|
||||
if commands:
|
||||
@@ -32,11 +32,11 @@ class CmdPipelineShow(CmdBase):
|
||||
import networkx
|
||||
from dvc.stage import Stage
|
||||
|
||||
stage = Stage.load(self.project, target)
|
||||
node = os.path.relpath(stage.path, self.project.root_dir)
|
||||
stage = Stage.load(self.repo, target)
|
||||
node = os.path.relpath(stage.path, self.repo.root_dir)
|
||||
|
||||
pipelines = list(
|
||||
filter(lambda g: node in g.nodes(), self.project.pipelines())
|
||||
filter(lambda g: node in g.nodes(), self.repo.pipelines())
|
||||
)
|
||||
|
||||
assert len(pipelines) == 1
|
||||
@@ -124,7 +124,7 @@ class CmdPipelineList(CmdBase):
|
||||
def run(self):
|
||||
import networkx
|
||||
|
||||
pipelines = self.project.pipelines()
|
||||
pipelines = self.repo.pipelines()
|
||||
for p in pipelines:
|
||||
stages = networkx.get_node_attributes(p, "stage")
|
||||
for stage in stages:
|
||||
|
||||
@@ -76,7 +76,7 @@ class CmdRemoteRemove(CmdConfig):
|
||||
|
||||
for configobj in [
|
||||
self.config._local_config,
|
||||
self.config._project_config,
|
||||
self.config._repo_config,
|
||||
self.config._global_config,
|
||||
self.config._system_config,
|
||||
]:
|
||||
|
||||
@@ -30,7 +30,7 @@ class CmdRemove(CmdBase):
|
||||
for target in self.args.targets:
|
||||
try:
|
||||
outs_only = self._is_outs_only(target)
|
||||
self.project.remove(target, outs_only=outs_only)
|
||||
self.repo.remove(target, outs_only=outs_only)
|
||||
except DvcException:
|
||||
logger.error("failed to remove {}".format(target))
|
||||
return 1
|
||||
|
||||
@@ -24,7 +24,7 @@ class CmdRepro(CmdBase):
|
||||
ret = 0
|
||||
for target in self.args.targets:
|
||||
try:
|
||||
stages = self.project.reproduce(
|
||||
stages = self.repo.reproduce(
|
||||
target,
|
||||
recursive=recursive,
|
||||
force=self.args.force,
|
||||
@@ -39,7 +39,7 @@ class CmdRepro(CmdBase):
|
||||
logger.info(CmdDataStatus.UP_TO_DATE_MSG)
|
||||
|
||||
if self.args.metrics:
|
||||
self.project.metrics_show()
|
||||
self.repo.metrics.show()
|
||||
except DvcException:
|
||||
logger.error()
|
||||
ret = 1
|
||||
@@ -79,7 +79,7 @@ def add_parser(subparsers, parent_parser):
|
||||
"-c",
|
||||
"--cwd",
|
||||
default=os.path.curdir,
|
||||
help="Directory within your project to reroduce from.",
|
||||
help="Directory within your repo to reroduce from.",
|
||||
)
|
||||
repro_parser.add_argument(
|
||||
"-m",
|
||||
@@ -115,7 +115,7 @@ def add_parser(subparsers, parent_parser):
|
||||
"--all-pipelines",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Reproduce all pipelines in the project.",
|
||||
help="Reproduce all pipelines in the repo.",
|
||||
)
|
||||
repro_parser.add_argument(
|
||||
"--ignore-build-cache",
|
||||
|
||||
+2
-2
@@ -11,12 +11,12 @@ class CmdRoot(CmdBase):
|
||||
return self.run()
|
||||
|
||||
def run(self):
|
||||
logger.info(os.path.relpath(self.project.root_dir))
|
||||
logger.info(os.path.relpath(self.repo.root_dir))
|
||||
return 0
|
||||
|
||||
|
||||
def add_parser(subparsers, parent_parser):
|
||||
ROOT_HELP = "Relative path to project's directory."
|
||||
ROOT_HELP = "Relative path to repo's directory."
|
||||
root_parser = subparsers.add_parser(
|
||||
"root", parents=[parent_parser], description=ROOT_HELP, help=ROOT_HELP
|
||||
)
|
||||
|
||||
+2
-2
@@ -29,7 +29,7 @@ class CmdRun(CmdBase):
|
||||
return 1
|
||||
|
||||
try:
|
||||
self.project.run(
|
||||
self.repo.run(
|
||||
cmd=self._parsed_cmd(),
|
||||
outs=self.args.outs,
|
||||
outs_no_cache=self.args.outs_no_cache,
|
||||
@@ -130,7 +130,7 @@ def add_parser(subparsers, parent_parser):
|
||||
"-c",
|
||||
"--cwd",
|
||||
default=os.path.curdir,
|
||||
help="Directory within your project to run your command and place "
|
||||
help="Directory within your repo to run your command and place "
|
||||
"stage file in.",
|
||||
)
|
||||
run_parser.add_argument(
|
||||
|
||||
@@ -28,7 +28,7 @@ class CmdDataStatus(CmdDataBase):
|
||||
def do_run(self, target=None):
|
||||
indent = 1 if self.args.cloud else 0
|
||||
try:
|
||||
st = self.project.status(
|
||||
st = self.repo.status(
|
||||
target=target,
|
||||
jobs=self.args.jobs,
|
||||
cloud=self.args.cloud,
|
||||
|
||||
@@ -9,7 +9,7 @@ class CmdUnprotect(CmdBase):
|
||||
def run(self):
|
||||
for target in self.args.targets:
|
||||
try:
|
||||
self.project.unprotect(target)
|
||||
self.repo.unprotect(target)
|
||||
except DvcException:
|
||||
msg = "failed to unprotect '{}'".format(target)
|
||||
logger.error(msg)
|
||||
|
||||
+6
-6
@@ -108,11 +108,11 @@ def is_percent(val):
|
||||
|
||||
|
||||
class Config(object): # pylint: disable=too-many-instance-attributes
|
||||
"""Class that manages configuration files for a dvc project.
|
||||
"""Class that manages configuration files for a dvc repo.
|
||||
|
||||
Args:
|
||||
dvc_dir (str): optional path to `.dvc` directory, that is used to
|
||||
access project-specific configs like .dvc/config and
|
||||
access repo-specific configs like .dvc/config and
|
||||
.dvc/config.local.
|
||||
validate (bool): optional flag to tell dvc if it should validate the
|
||||
config or just load it as is. 'True' by default.
|
||||
@@ -295,7 +295,7 @@ class Config(object): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
self._system_config = None
|
||||
self._global_config = None
|
||||
self._project_config = None
|
||||
self._repo_config = None
|
||||
self._local_config = None
|
||||
|
||||
self.config = None
|
||||
@@ -347,9 +347,9 @@ class Config(object): # pylint: disable=too-many-instance-attributes
|
||||
self._global_config = configobj.ConfigObj(self.global_config_file)
|
||||
|
||||
if self.config_file is not None:
|
||||
self._project_config = configobj.ConfigObj(self.config_file)
|
||||
self._repo_config = configobj.ConfigObj(self.config_file)
|
||||
else:
|
||||
self._project_config = configobj.ConfigObj()
|
||||
self._repo_config = configobj.ConfigObj()
|
||||
|
||||
if self.config_local_file is not None:
|
||||
self._local_config = configobj.ConfigObj(self.config_local_file)
|
||||
@@ -454,7 +454,7 @@ class Config(object): # pylint: disable=too-many-instance-attributes
|
||||
clist = [
|
||||
self._system_config,
|
||||
self._global_config,
|
||||
self._project_config,
|
||||
self._repo_config,
|
||||
self._local_config,
|
||||
]
|
||||
|
||||
|
||||
+10
-10
@@ -19,9 +19,9 @@ class DataCloud(object):
|
||||
"""Class that manages dvc remotes.
|
||||
|
||||
Args:
|
||||
project (dvc.project.Project): project instance that belongs to the
|
||||
project that we are working on.
|
||||
config (dict): config of the project.
|
||||
repo (dvc.repo.Repo): repo instance that belongs to the repo that
|
||||
we are working on.
|
||||
config (dict): config of the repo.
|
||||
|
||||
Raises:
|
||||
config.ConfigError: thrown when config has invalid format.
|
||||
@@ -38,8 +38,8 @@ class DataCloud(object):
|
||||
"https": RemoteHTTP,
|
||||
}
|
||||
|
||||
def __init__(self, project, config=None):
|
||||
self.project = project
|
||||
def __init__(self, repo, config=None):
|
||||
self.repo = repo
|
||||
self._config = config
|
||||
self._core = self._config[Config.SECTION_CORE]
|
||||
|
||||
@@ -64,7 +64,7 @@ class DataCloud(object):
|
||||
msg = "can't find remote section '{}' in config"
|
||||
raise ConfigError(msg.format(section))
|
||||
|
||||
return Remote(self.project, cloud_config)
|
||||
return Remote(self.repo, cloud_config)
|
||||
|
||||
def _init_compat(self):
|
||||
name = self._core.get(Config.SECTION_CORE_CLOUD, "").strip().lower()
|
||||
@@ -94,7 +94,7 @@ class DataCloud(object):
|
||||
if global_storage_path:
|
||||
logger.warning("using obsoleted config format. Consider updating.")
|
||||
|
||||
cloud = cloud_type(self.project, cloud_config)
|
||||
cloud = cloud_type(self.repo, cloud_config)
|
||||
return cloud
|
||||
|
||||
def _get_cloud(self, remote, cmd):
|
||||
@@ -122,7 +122,7 @@ class DataCloud(object):
|
||||
show_checksums (bool): show checksums instead of file names in
|
||||
information messages.
|
||||
"""
|
||||
return self.project.cache.local.push(
|
||||
return self.repo.cache.local.push(
|
||||
targets,
|
||||
jobs=jobs,
|
||||
remote=self._get_cloud(remote, "push"),
|
||||
@@ -140,7 +140,7 @@ class DataCloud(object):
|
||||
show_checksums (bool): show checksums instead of file names in
|
||||
information messages.
|
||||
"""
|
||||
return self.project.cache.local.pull(
|
||||
return self.repo.cache.local.pull(
|
||||
targets,
|
||||
jobs=jobs,
|
||||
remote=self._get_cloud(remote, "pull"),
|
||||
@@ -160,6 +160,6 @@ class DataCloud(object):
|
||||
information messages.
|
||||
"""
|
||||
cloud = self._get_cloud(remote, "status")
|
||||
return self.project.cache.local.status(
|
||||
return self.repo.cache.local.status(
|
||||
targets, jobs=jobs, remote=cloud, show_checksums=show_checksums
|
||||
)
|
||||
|
||||
@@ -49,8 +49,8 @@ def _get(stage, p, info):
|
||||
parsed = urlparse(p)
|
||||
if parsed.scheme == "remote":
|
||||
name = Config.SECTION_REMOTE_FMT.format(parsed.netloc)
|
||||
sect = stage.project.config.config[name]
|
||||
remote = Remote(stage.project, sect)
|
||||
sect = stage.repo.config.config[name]
|
||||
remote = Remote(stage.repo, sect)
|
||||
return DEP_MAP[remote.scheme](stage, p, info, remote=remote)
|
||||
|
||||
for d in DEPS:
|
||||
|
||||
+15
-3
@@ -125,8 +125,8 @@ class MoveNotDataSourceError(DvcException):
|
||||
super(MoveNotDataSourceError, self).__init__(msg.format(path=path))
|
||||
|
||||
|
||||
class NotDvcProjectError(DvcException):
|
||||
"""Thrown if a directory is not a dvc project.
|
||||
class NotDvcRepoError(DvcException):
|
||||
"""Thrown if a directory is not a dvc repo.
|
||||
|
||||
Args:
|
||||
root (str): path to the directory.
|
||||
@@ -134,7 +134,7 @@ class NotDvcProjectError(DvcException):
|
||||
|
||||
def __init__(self, root):
|
||||
msg = "not a dvc repository (checked up to mount point '{}')"
|
||||
super(NotDvcProjectError, self).__init__(msg.format(root))
|
||||
super(NotDvcRepoError, self).__init__(msg.format(root))
|
||||
|
||||
|
||||
class DvcParserError(DvcException):
|
||||
@@ -163,3 +163,15 @@ class ConfirmRemoveError(DvcException):
|
||||
"unable to remove '{}' without a confirmation from the user. Use "
|
||||
"'-f' to force.".format(path)
|
||||
)
|
||||
|
||||
|
||||
class InitError(DvcException):
|
||||
def __init__(self, msg):
|
||||
super(InitError, self).__init__(msg)
|
||||
|
||||
|
||||
class ReproductionError(DvcException):
|
||||
def __init__(self, dvc_file_name, ex):
|
||||
self.path = dvc_file_name
|
||||
msg = "failed to reproduce '{}'".format(dvc_file_name)
|
||||
super(ReproductionError, self).__init__(msg, cause=ex)
|
||||
|
||||
+4
-4
@@ -10,11 +10,11 @@ from dvc.exceptions import DvcException
|
||||
|
||||
|
||||
class LockError(DvcException):
|
||||
"""Thrown when unable to acquire the lock for dvc project."""
|
||||
"""Thrown when unable to acquire the lock for dvc repo."""
|
||||
|
||||
|
||||
class Lock(object):
|
||||
"""Class for dvc project lock.
|
||||
"""Class for dvc repo lock.
|
||||
|
||||
Args:
|
||||
dvc_dir (str): path to the directory that the lock should be created
|
||||
@@ -39,7 +39,7 @@ class Lock(object):
|
||||
)
|
||||
|
||||
def lock(self):
|
||||
"""Acquire lock for dvc project."""
|
||||
"""Acquire lock for dvc repo."""
|
||||
try:
|
||||
self._do_lock()
|
||||
return
|
||||
@@ -49,7 +49,7 @@ class Lock(object):
|
||||
self._do_lock()
|
||||
|
||||
def unlock(self):
|
||||
"""Release lock for dvc project."""
|
||||
"""Release lock for dvc repo."""
|
||||
self._lock.close()
|
||||
self._lock = None
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
"""Manages logger for dvc project."""
|
||||
"""Manages logger for dvc repo."""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ import dvc.logger as logger
|
||||
from dvc.cli import parse_args
|
||||
from dvc.command.base import CmdBase
|
||||
from dvc.analytics import Analytics
|
||||
from dvc.exceptions import NotDvcProjectError, DvcParserError
|
||||
from dvc.exceptions import NotDvcRepoError, DvcParserError
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
@@ -33,7 +33,7 @@ def main(argv=None):
|
||||
except KeyboardInterrupt:
|
||||
logger.error("interrupted by the user")
|
||||
ret = 252
|
||||
except NotDvcProjectError:
|
||||
except NotDvcRepoError:
|
||||
logger.error()
|
||||
ret = 253
|
||||
except DvcParserError:
|
||||
|
||||
@@ -55,8 +55,8 @@ def _get(stage, p, info, cache, metric):
|
||||
parsed = urlparse(p)
|
||||
if parsed.scheme == "remote":
|
||||
name = Config.SECTION_REMOTE_FMT.format(parsed.netloc)
|
||||
sect = stage.project.config.config[name]
|
||||
remote = Remote(stage.project, sect)
|
||||
sect = stage.repo.config.config[name]
|
||||
remote = Remote(stage.repo, sect)
|
||||
return OUTS_MAP[remote.scheme](
|
||||
stage, p, info, cache=cache, remote=remote, metric=metric
|
||||
)
|
||||
|
||||
+10
-10
@@ -52,16 +52,16 @@ class OutputBase(object):
|
||||
self, stage, path, info=None, remote=None, cache=True, metric=False
|
||||
):
|
||||
self.stage = stage
|
||||
self.project = stage.project
|
||||
self.repo = stage.repo
|
||||
self.url = path
|
||||
self.info = info
|
||||
self.remote = remote or self.REMOTE(self.project, {})
|
||||
self.remote = remote or self.REMOTE(self.repo, {})
|
||||
self.use_cache = False if self.IS_DEPENDENCY else cache
|
||||
self.metric = False if self.IS_DEPENDENCY else metric
|
||||
|
||||
if (
|
||||
self.use_cache
|
||||
and getattr(self.project.cache, self.REMOTE.scheme) is None
|
||||
and getattr(self.repo.cache, self.REMOTE.scheme) is None
|
||||
):
|
||||
raise DvcException(
|
||||
"no cache location setup for '{}' outputs.".format(
|
||||
@@ -118,7 +118,7 @@ class OutputBase(object):
|
||||
if not self.use_cache:
|
||||
return self.info != self.remote.save_info(self.path_info)
|
||||
|
||||
return getattr(self.project.cache, self.scheme).changed(
|
||||
return getattr(self.repo.cache, self.scheme).changed(
|
||||
self.path_info, self.info
|
||||
)
|
||||
|
||||
@@ -126,7 +126,7 @@ class OutputBase(object):
|
||||
if not self.use_cache or not self.checksum:
|
||||
return True
|
||||
|
||||
cache = self.project.cache.__getattribute__(self.scheme)
|
||||
cache = self.repo.cache.__getattribute__(self.scheme)
|
||||
|
||||
return cache.changed_cache(self.checksum)
|
||||
|
||||
@@ -140,7 +140,7 @@ class OutputBase(object):
|
||||
if not self.use_cache:
|
||||
self.info = self.remote.save_info(self.path_info)
|
||||
else:
|
||||
self.info = getattr(self.project.cache, self.scheme).save(
|
||||
self.info = getattr(self.repo.cache, self.scheme).save(
|
||||
self.path_info
|
||||
)
|
||||
|
||||
@@ -171,7 +171,7 @@ class OutputBase(object):
|
||||
if not self.use_cache:
|
||||
return
|
||||
|
||||
getattr(self.project.cache, self.scheme).checkout(
|
||||
getattr(self.repo.cache, self.scheme).checkout(
|
||||
self.path_info, self.info, force=force
|
||||
)
|
||||
|
||||
@@ -181,11 +181,11 @@ class OutputBase(object):
|
||||
return
|
||||
|
||||
if ignore_remove and self.use_cache and self.is_local:
|
||||
self.project.scm.ignore_remove(self.path)
|
||||
self.repo.scm.ignore_remove(self.path)
|
||||
|
||||
def move(self, out):
|
||||
if self.scheme == "local" and self.use_cache and self.is_local:
|
||||
self.project.scm.ignore_remove(self.path)
|
||||
self.repo.scm.ignore_remove(self.path)
|
||||
|
||||
self.remote.move(self.path_info, out.path_info)
|
||||
self.url = out.url
|
||||
@@ -193,4 +193,4 @@ class OutputBase(object):
|
||||
self.save()
|
||||
|
||||
if self.scheme == "local" and self.use_cache and self.is_local:
|
||||
self.project.scm.ignore(self.path)
|
||||
self.repo.scm.ignore(self.path)
|
||||
|
||||
+4
-4
@@ -52,7 +52,7 @@ class OutputLOCAL(OutputBase):
|
||||
|
||||
@property
|
||||
def cache(self):
|
||||
return self.project.cache.local.get(self.checksum)
|
||||
return self.repo.cache.local.get(self.checksum)
|
||||
|
||||
def dumpd(self):
|
||||
ret = super(OutputLOCAL, self).dumpd()
|
||||
@@ -111,10 +111,10 @@ class OutputLOCAL(OutputBase):
|
||||
return
|
||||
|
||||
if self.is_local:
|
||||
if self.project.scm.is_tracked(self.path):
|
||||
if self.repo.scm.is_tracked(self.path):
|
||||
raise OutputAlreadyTrackedError(self.rel_path)
|
||||
|
||||
if self.use_cache:
|
||||
self.project.scm.ignore(self.path)
|
||||
self.repo.scm.ignore(self.path)
|
||||
|
||||
self.info = self.project.cache.local.save(self.path_info)
|
||||
self.info = self.repo.cache.local.save(self.path_info)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
"""Manages progress bars for dvc project."""
|
||||
"""Manages progress bars for dvc repo."""
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
-1395
File diff suppressed because it is too large
Load Diff
@@ -27,5 +27,5 @@ def _get(config):
|
||||
return RemoteLOCAL
|
||||
|
||||
|
||||
def Remote(project, config):
|
||||
return _get(config)(project, config)
|
||||
def Remote(repo, config):
|
||||
return _get(config)(repo, config)
|
||||
|
||||
+2
-2
@@ -36,8 +36,8 @@ class RemoteAzure(RemoteBase):
|
||||
PARAM_CHECKSUM = "etag"
|
||||
COPY_POLL_SECONDS = 5
|
||||
|
||||
def __init__(self, project, config):
|
||||
super(RemoteAzure, self).__init__(project, config)
|
||||
def __init__(self, repo, config):
|
||||
super(RemoteAzure, self).__init__(repo, config)
|
||||
|
||||
self.url = config.get(Config.SECTION_REMOTE_URL, "azure://")
|
||||
match = re.match(self.REGEX, self.url) # backward compatibility
|
||||
|
||||
+2
-2
@@ -59,8 +59,8 @@ class RemoteBase(object):
|
||||
REQUIRES = {}
|
||||
JOBS = 4 * cpu_count()
|
||||
|
||||
def __init__(self, project, config):
|
||||
self.project = project
|
||||
def __init__(self, repo, config):
|
||||
self.repo = repo
|
||||
deps_ok = all(self.REQUIRES.values())
|
||||
if not deps_ok:
|
||||
missing = [k for k, v in self.REQUIRES.items() if v is None]
|
||||
|
||||
+2
-2
@@ -22,8 +22,8 @@ class RemoteGS(RemoteBase):
|
||||
REQUIRES = {"google.cloud.storage": storage}
|
||||
PARAM_CHECKSUM = "md5"
|
||||
|
||||
def __init__(self, project, config):
|
||||
super(RemoteGS, self).__init__(project, config)
|
||||
def __init__(self, repo, config):
|
||||
super(RemoteGS, self).__init__(repo, config)
|
||||
storagepath = "gs://"
|
||||
storagepath += config.get(Config.SECTION_AWS_STORAGEPATH, "/")
|
||||
storagepath.lstrip("/")
|
||||
|
||||
+2
-2
@@ -17,8 +17,8 @@ class RemoteHDFS(RemoteBase):
|
||||
REGEX = r"^hdfs://((?P<user>.*)@)?.*$"
|
||||
PARAM_CHECKSUM = "checksum"
|
||||
|
||||
def __init__(self, project, config):
|
||||
super(RemoteHDFS, self).__init__(project, config)
|
||||
def __init__(self, repo, config):
|
||||
super(RemoteHDFS, self).__init__(repo, config)
|
||||
self.url = config.get(Config.SECTION_REMOTE_URL, "/")
|
||||
self.prefix = self.url
|
||||
self.user = self.group("user")
|
||||
|
||||
+2
-2
@@ -32,8 +32,8 @@ class RemoteHTTP(RemoteBase):
|
||||
CHUNK_SIZE = 2 ** 16
|
||||
PARAM_CHECKSUM = "etag"
|
||||
|
||||
def __init__(self, project, config):
|
||||
super(RemoteHTTP, self).__init__(project, config)
|
||||
def __init__(self, repo, config):
|
||||
super(RemoteHTTP, self).__init__(repo, config)
|
||||
self.cache_dir = config.get(Config.SECTION_REMOTE_URL)
|
||||
self.url = self.cache_dir
|
||||
self.path_info = {"scheme": "http"}
|
||||
|
||||
+3
-3
@@ -38,9 +38,9 @@ class RemoteLOCAL(RemoteBase):
|
||||
"reflink": System.reflink,
|
||||
}
|
||||
|
||||
def __init__(self, project, config):
|
||||
super(RemoteLOCAL, self).__init__(project, config)
|
||||
self.state = self.project.state if self.project else None
|
||||
def __init__(self, repo, config):
|
||||
super(RemoteLOCAL, self).__init__(repo, config)
|
||||
self.state = self.repo.state if self.repo else None
|
||||
self.protected = config.get(Config.SECTION_CACHE_PROTECTED, False)
|
||||
storagepath = config.get(Config.SECTION_AWS_STORAGEPATH, None)
|
||||
self.cache_dir = config.get(Config.SECTION_REMOTE_URL, storagepath)
|
||||
|
||||
+2
-2
@@ -35,8 +35,8 @@ class RemoteS3(RemoteBase):
|
||||
REQUIRES = {"boto3": boto3}
|
||||
PARAM_CHECKSUM = "etag"
|
||||
|
||||
def __init__(self, project, config):
|
||||
super(RemoteS3, self).__init__(project, config)
|
||||
def __init__(self, repo, config):
|
||||
super(RemoteS3, self).__init__(repo, config)
|
||||
|
||||
storagepath = "s3://{}".format(
|
||||
config.get(Config.SECTION_AWS_STORAGEPATH, "").lstrip("/")
|
||||
|
||||
+2
-2
@@ -59,8 +59,8 @@ class RemoteSSH(RemoteBase):
|
||||
DEFAULT_PORT = 22
|
||||
TIMEOUT = 1800
|
||||
|
||||
def __init__(self, project, config):
|
||||
super(RemoteSSH, self).__init__(project, config)
|
||||
def __init__(self, repo, config):
|
||||
super(RemoteSSH, self).__init__(repo, config)
|
||||
self.url = config.get(Config.SECTION_REMOTE_URL, "ssh://")
|
||||
|
||||
parsed = urlparse(self.url)
|
||||
|
||||
@@ -0,0 +1,410 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from dvc.utils.compat import str, builtin_str, open
|
||||
|
||||
import collections
|
||||
import os
|
||||
import dvc.prompt as prompt
|
||||
import dvc.logger as logger
|
||||
|
||||
from dvc.exceptions import DvcException, NotDvcRepoError
|
||||
|
||||
|
||||
class Repo(object):
|
||||
DVC_DIR = ".dvc"
|
||||
|
||||
from dvc.repo.destroy import destroy
|
||||
from dvc.repo.install import install
|
||||
from dvc.repo.add import add
|
||||
from dvc.repo.remove import remove
|
||||
from dvc.repo.lock import lock as lock_stage
|
||||
from dvc.repo.move import move
|
||||
from dvc.repo.run import run
|
||||
from dvc.repo.imp import imp
|
||||
from dvc.repo.reproduce import reproduce
|
||||
from dvc.repo.checkout import checkout
|
||||
from dvc.repo.push import push
|
||||
from dvc.repo.fetch import fetch
|
||||
from dvc.repo.pull import pull
|
||||
from dvc.repo.status import status
|
||||
from dvc.repo.gc import gc
|
||||
|
||||
def __init__(self, root_dir=None):
|
||||
from dvc.config import Config
|
||||
from dvc.state import State
|
||||
from dvc.lock import Lock
|
||||
from dvc.scm import SCM
|
||||
from dvc.cache import Cache
|
||||
from dvc.data_cloud import DataCloud
|
||||
from dvc.updater import Updater
|
||||
from dvc.repo.metrics import Metrics
|
||||
|
||||
root_dir = self.find_root(root_dir)
|
||||
|
||||
self.root_dir = os.path.abspath(os.path.realpath(root_dir))
|
||||
self.dvc_dir = os.path.join(self.root_dir, self.DVC_DIR)
|
||||
|
||||
self.config = Config(self.dvc_dir)
|
||||
|
||||
self.scm = SCM(self.root_dir, repo=self)
|
||||
self.lock = Lock(self.dvc_dir)
|
||||
# NOTE: storing state and link_state in the repository itself to avoid
|
||||
# any possible state corruption in 'shared cache dir' scenario.
|
||||
self.state = State(self, self.config.config)
|
||||
|
||||
core = self.config.config[Config.SECTION_CORE]
|
||||
|
||||
logger.set_level(core.get(Config.SECTION_CORE_LOGLEVEL))
|
||||
|
||||
self.cache = Cache(self)
|
||||
self.cloud = DataCloud(self, config=self.config.config)
|
||||
self.updater = Updater(self.dvc_dir)
|
||||
|
||||
self.metrics = Metrics(self)
|
||||
|
||||
self.files_to_git_add = []
|
||||
|
||||
self._ignore()
|
||||
|
||||
self.updater.check()
|
||||
|
||||
def __repr__(self):
|
||||
return "Repo: '{root_dir}'".format(root_dir=self.root_dir)
|
||||
|
||||
@staticmethod
|
||||
def find_root(root=None):
|
||||
if root is None:
|
||||
root = os.getcwd()
|
||||
else:
|
||||
root = os.path.abspath(os.path.realpath(root))
|
||||
|
||||
while True:
|
||||
dvc_dir = os.path.join(root, Repo.DVC_DIR)
|
||||
if os.path.isdir(dvc_dir):
|
||||
return root
|
||||
if os.path.ismount(root):
|
||||
break
|
||||
root = os.path.dirname(root)
|
||||
raise NotDvcRepoError(root)
|
||||
|
||||
@staticmethod
|
||||
def find_dvc_dir(root=None):
|
||||
root_dir = Repo.find_root(root)
|
||||
return os.path.join(root_dir, Repo.DVC_DIR)
|
||||
|
||||
def remind_to_git_add(self):
|
||||
if not self.files_to_git_add:
|
||||
return
|
||||
|
||||
logger.info(
|
||||
"\n"
|
||||
"To track the changes with git run:\n"
|
||||
"\n"
|
||||
"\tgit add {files}".format(files=" ".join(self.files_to_git_add))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def init(root_dir=os.curdir, no_scm=False, force=False):
|
||||
from dvc.repo.init import init
|
||||
|
||||
init(root_dir=root_dir, no_scm=no_scm, force=force)
|
||||
return Repo(root_dir)
|
||||
|
||||
@staticmethod
|
||||
def unprotect(target):
|
||||
from dvc.repo.unprotect import unprotect
|
||||
|
||||
return unprotect(target)
|
||||
|
||||
def _ignore(self):
|
||||
flist = [
|
||||
self.state.state_file,
|
||||
self.lock.lock_file,
|
||||
self.config.config_local_file,
|
||||
self.updater.updater_file,
|
||||
self.updater.lock.lock_file,
|
||||
] + self.state.temp_files
|
||||
|
||||
if self.cache.local.cache_dir.startswith(self.root_dir):
|
||||
flist += [self.cache.local.cache_dir]
|
||||
|
||||
self.scm.ignore_list(flist)
|
||||
|
||||
def check_dag(self, stages):
|
||||
"""Generate graph including the new stage to check for errors"""
|
||||
self.graph(stages=stages)
|
||||
|
||||
@staticmethod
|
||||
def _check_cyclic_graph(graph):
|
||||
import networkx as nx
|
||||
from dvc.exceptions import CyclicGraphError
|
||||
|
||||
cycles = list(nx.simple_cycles(graph))
|
||||
|
||||
if cycles:
|
||||
raise CyclicGraphError(cycles[0])
|
||||
|
||||
def _get_pipeline(self, node):
|
||||
pipelines = list(filter(lambda g: node in g.nodes(), self.pipelines()))
|
||||
assert len(pipelines) == 1
|
||||
return pipelines[0]
|
||||
|
||||
def collect(self, target, with_deps=False):
|
||||
import networkx as nx
|
||||
from dvc.stage import Stage
|
||||
|
||||
stage = Stage.load(self, target)
|
||||
if not with_deps:
|
||||
return [stage]
|
||||
|
||||
node = os.path.relpath(stage.path, self.root_dir)
|
||||
G = self._get_pipeline(node)
|
||||
stages = nx.get_node_attributes(G, "stage")
|
||||
|
||||
ret = [stage]
|
||||
for n in nx.dfs_postorder_nodes(G, node):
|
||||
ret.append(stages[n])
|
||||
|
||||
return ret
|
||||
|
||||
def _collect_dir_cache(
|
||||
self, out, branch=None, remote=None, force=False, jobs=None
|
||||
):
|
||||
info = out.dumpd()
|
||||
ret = [info]
|
||||
r = out.remote
|
||||
md5 = info[r.PARAM_CHECKSUM]
|
||||
|
||||
if self.cache.local.changed_cache_file(md5):
|
||||
try:
|
||||
self.cloud.pull(
|
||||
ret, jobs=jobs, remote=remote, show_checksums=False
|
||||
)
|
||||
except DvcException as exc:
|
||||
msg = "Failed to pull cache for '{}': {}"
|
||||
logger.debug(msg.format(out, exc))
|
||||
|
||||
if self.cache.local.changed_cache_file(md5):
|
||||
msg = (
|
||||
"Missing cache for directory '{}'. "
|
||||
"Cache for files inside will be lost. "
|
||||
"Would you like to continue? Use '-f' to force. "
|
||||
)
|
||||
if not force and not prompt.confirm(msg):
|
||||
raise DvcException(
|
||||
"unable to fully collect used cache"
|
||||
" without cache for directory '{}'".format(out)
|
||||
)
|
||||
else:
|
||||
return ret
|
||||
|
||||
for i in self.cache.local.load_dir_cache(md5):
|
||||
i["branch"] = branch
|
||||
i[r.PARAM_PATH] = os.path.join(
|
||||
info[r.PARAM_PATH], i[r.PARAM_RELPATH]
|
||||
)
|
||||
ret.append(i)
|
||||
|
||||
return ret
|
||||
|
||||
def _collect_used_cache(
|
||||
self, out, branch=None, remote=None, force=False, jobs=None
|
||||
):
|
||||
if not out.use_cache or not out.info:
|
||||
if not out.info:
|
||||
logger.warning(
|
||||
"Output '{}'({}) is missing version "
|
||||
"info. Cache for it will not be collected. "
|
||||
"Use dvc repro to get your pipeline up to "
|
||||
"date.".format(out, out.stage)
|
||||
)
|
||||
return []
|
||||
|
||||
info = out.dumpd()
|
||||
info["branch"] = branch
|
||||
ret = [info]
|
||||
|
||||
if out.scheme != "local":
|
||||
return ret
|
||||
|
||||
md5 = info[out.remote.PARAM_CHECKSUM]
|
||||
cache = self.cache.local.get(md5)
|
||||
if not out.remote.is_dir_cache(cache):
|
||||
return ret
|
||||
|
||||
return self._collect_dir_cache(
|
||||
out, branch=branch, remote=remote, force=force, jobs=jobs
|
||||
)
|
||||
|
||||
def used_cache(
|
||||
self,
|
||||
target=None,
|
||||
all_branches=False,
|
||||
active=True,
|
||||
with_deps=False,
|
||||
all_tags=False,
|
||||
remote=None,
|
||||
force=False,
|
||||
jobs=None,
|
||||
recursive=False,
|
||||
):
|
||||
cache = {}
|
||||
cache["local"] = []
|
||||
cache["s3"] = []
|
||||
cache["gs"] = []
|
||||
cache["hdfs"] = []
|
||||
cache["ssh"] = []
|
||||
cache["azure"] = []
|
||||
|
||||
for branch in self.scm.brancher(
|
||||
all_branches=all_branches, all_tags=all_tags
|
||||
):
|
||||
if target:
|
||||
if recursive:
|
||||
stages = self.stages(target)
|
||||
else:
|
||||
stages = self.collect(target, with_deps=with_deps)
|
||||
elif active:
|
||||
stages = self.active_stages()
|
||||
else:
|
||||
stages = self.stages()
|
||||
|
||||
for stage in stages:
|
||||
if active and not target and stage.locked:
|
||||
logger.warning(
|
||||
"DVC file '{path}' is locked. Its dependencies are"
|
||||
" not going to be pushed/pulled/fetched.".format(
|
||||
path=stage.relpath
|
||||
)
|
||||
)
|
||||
|
||||
for out in stage.outs:
|
||||
scheme = out.path_info["scheme"]
|
||||
cache[scheme] += self._collect_used_cache(
|
||||
out,
|
||||
branch=branch,
|
||||
remote=remote,
|
||||
force=force,
|
||||
jobs=jobs,
|
||||
)
|
||||
|
||||
return cache
|
||||
|
||||
def graph(self, stages=None, from_directory=None):
|
||||
import networkx as nx
|
||||
from dvc.exceptions import (
|
||||
OutputDuplicationError,
|
||||
WorkingDirectoryAsOutputError,
|
||||
)
|
||||
|
||||
G = nx.DiGraph()
|
||||
G_active = nx.DiGraph()
|
||||
stages = stages or self.stages(from_directory)
|
||||
stages = [stage for stage in stages if stage]
|
||||
outs = []
|
||||
|
||||
for stage in stages:
|
||||
for out in stage.outs:
|
||||
existing = [o.stage for o in outs if o.path == out.path]
|
||||
|
||||
if existing:
|
||||
stages = [stage.relpath, existing[0].relpath]
|
||||
raise OutputDuplicationError(out.path, stages)
|
||||
|
||||
outs.append(out)
|
||||
|
||||
for stage in stages:
|
||||
for out in outs:
|
||||
overlaps = stage.cwd == out.path or stage.cwd.startswith(
|
||||
out.path + os.sep
|
||||
)
|
||||
|
||||
if overlaps:
|
||||
raise WorkingDirectoryAsOutputError(
|
||||
stage.cwd, stage.relpath
|
||||
)
|
||||
|
||||
# collect the whole DAG
|
||||
for stage in stages:
|
||||
node = os.path.relpath(stage.path, self.root_dir)
|
||||
|
||||
G.add_node(node, stage=stage)
|
||||
G_active.add_node(node, stage=stage)
|
||||
|
||||
for dep in stage.deps:
|
||||
for out in outs:
|
||||
if (
|
||||
out.path != dep.path
|
||||
and not dep.path.startswith(out.path + out.sep)
|
||||
and not out.path.startswith(dep.path + dep.sep)
|
||||
):
|
||||
continue
|
||||
|
||||
dep_stage = out.stage
|
||||
dep_node = os.path.relpath(dep_stage.path, self.root_dir)
|
||||
G.add_node(dep_node, stage=dep_stage)
|
||||
G.add_edge(node, dep_node)
|
||||
if not stage.locked:
|
||||
G_active.add_node(dep_node, stage=dep_stage)
|
||||
G_active.add_edge(node, dep_node)
|
||||
|
||||
self._check_cyclic_graph(G)
|
||||
|
||||
return G, G_active
|
||||
|
||||
def pipelines(self, from_directory=None):
|
||||
import networkx as nx
|
||||
|
||||
G, G_active = self.graph(from_directory=from_directory)
|
||||
|
||||
return [
|
||||
G.subgraph(c).copy() for c in nx.weakly_connected_components(G)
|
||||
]
|
||||
|
||||
def stages(self, from_directory=None):
|
||||
"""
|
||||
Walks down the root directory looking for Dvcfiles,
|
||||
skipping the directories that are related with
|
||||
any SCM (e.g. `.git`), DVC itself (`.dvc`), or directories
|
||||
tracked by DVC (e.g. `dvc add data` would skip `data/`)
|
||||
|
||||
NOTE: For large repos, this could be an expensive
|
||||
operation. Consider using some memoization.
|
||||
"""
|
||||
from dvc.stage import Stage
|
||||
|
||||
if not from_directory:
|
||||
from_directory = self.root_dir
|
||||
|
||||
stages = []
|
||||
outs = []
|
||||
for root, dirs, files in os.walk(str(from_directory)):
|
||||
for fname in files:
|
||||
path = os.path.join(root, fname)
|
||||
if not Stage.is_stage_file(path):
|
||||
continue
|
||||
stage = Stage.load(self, path)
|
||||
for out in stage.outs:
|
||||
outs.append(out.path + out.sep)
|
||||
stages.append(stage)
|
||||
|
||||
def filter_dirs(dname, root=root):
|
||||
path = os.path.join(root, dname)
|
||||
if path in (self.dvc_dir, self.scm.dir):
|
||||
return False
|
||||
for out in outs:
|
||||
if path == os.path.normpath(out) or path.startswith(out):
|
||||
return False
|
||||
return True
|
||||
|
||||
dirs[:] = list(filter(filter_dirs, dirs))
|
||||
|
||||
return stages
|
||||
|
||||
def active_stages(self, from_directory=None):
|
||||
import networkx as nx
|
||||
|
||||
stages = []
|
||||
for G in self.pipelines(from_directory):
|
||||
stages.extend(list(nx.get_node_attributes(G, "stage").values()))
|
||||
return stages
|
||||
@@ -0,0 +1,43 @@
|
||||
import os
|
||||
|
||||
|
||||
def add(self, fname, recursive=False):
|
||||
from dvc.stage import Stage
|
||||
|
||||
fnames = []
|
||||
if recursive and os.path.isdir(fname):
|
||||
for root, dirs, files in os.walk(str(fname)):
|
||||
for f in files:
|
||||
path = os.path.join(root, f)
|
||||
if Stage.is_stage_file(path):
|
||||
continue
|
||||
if os.path.basename(path) == self.scm.ignore_file:
|
||||
continue
|
||||
if self.scm.is_tracked(path):
|
||||
continue
|
||||
fnames.append(path)
|
||||
else:
|
||||
fnames = [fname]
|
||||
|
||||
stages = []
|
||||
self.files_to_git_add = []
|
||||
with self.state:
|
||||
for f in fnames:
|
||||
stage = Stage.create(repo=self, outs=[f], add=True)
|
||||
|
||||
if stage is None:
|
||||
stages.append(stage)
|
||||
continue
|
||||
|
||||
stage.save()
|
||||
stages.append(stage)
|
||||
|
||||
self.check_dag(self.stages() + stages)
|
||||
|
||||
for stage in stages:
|
||||
if stage is not None:
|
||||
stage.dump()
|
||||
|
||||
self.remind_to_git_add()
|
||||
|
||||
return stages
|
||||
@@ -0,0 +1,39 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import dvc.logger as logger
|
||||
from dvc.stage import StageFileDoesNotExistError, StageFileBadNameError
|
||||
from dvc.exceptions import DvcException
|
||||
|
||||
|
||||
def _cleanup_unused_links(self, all_stages):
|
||||
used = []
|
||||
for stage in all_stages:
|
||||
for out in stage.outs:
|
||||
used.append(out.path)
|
||||
self.state.remove_unused_links(used)
|
||||
|
||||
|
||||
def checkout(self, target=None, with_deps=False, force=False, recursive=False):
|
||||
if target and not recursive:
|
||||
all_stages = self.active_stages()
|
||||
try:
|
||||
stages = self.collect(target, with_deps=with_deps)
|
||||
except (StageFileDoesNotExistError, StageFileBadNameError) as exc:
|
||||
raise DvcException(
|
||||
str(exc) + " Did you mean 'git checkout {}'?".format(target)
|
||||
)
|
||||
else:
|
||||
all_stages = self.active_stages(target)
|
||||
stages = all_stages
|
||||
|
||||
with self.state:
|
||||
_cleanup_unused_links(self, all_stages)
|
||||
|
||||
for stage in stages:
|
||||
if stage.locked:
|
||||
logger.warning(
|
||||
"DVC file '{path}' is locked. Its dependencies are"
|
||||
" not going to be checked out.".format(path=stage.relpath)
|
||||
)
|
||||
|
||||
stage.checkout(force=force)
|
||||
@@ -0,0 +1,8 @@
|
||||
import shutil
|
||||
|
||||
|
||||
def destroy(self):
|
||||
for stage in self.stages():
|
||||
stage.remove()
|
||||
|
||||
shutil.rmtree(self.dvc_dir)
|
||||
@@ -0,0 +1,28 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
def fetch(
|
||||
self,
|
||||
target=None,
|
||||
jobs=1,
|
||||
remote=None,
|
||||
all_branches=False,
|
||||
show_checksums=False,
|
||||
with_deps=False,
|
||||
all_tags=False,
|
||||
recursive=False,
|
||||
):
|
||||
with self.state:
|
||||
used = self.used_cache(
|
||||
target,
|
||||
all_branches=all_branches,
|
||||
all_tags=all_tags,
|
||||
with_deps=with_deps,
|
||||
force=True,
|
||||
remote=remote,
|
||||
jobs=jobs,
|
||||
recursive=recursive,
|
||||
)["local"]
|
||||
self.cloud.pull(
|
||||
used, jobs, remote=remote, show_checksums=show_checksums
|
||||
)
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import collections
|
||||
|
||||
import dvc.logger as logger
|
||||
|
||||
|
||||
def _merge_cache_lists(clists):
|
||||
merged_cache = collections.defaultdict(list)
|
||||
|
||||
for cache_list in clists:
|
||||
for scheme, cache in cache_list.items():
|
||||
for item in cache:
|
||||
if item not in merged_cache[scheme]:
|
||||
merged_cache[scheme].append(item)
|
||||
|
||||
return merged_cache
|
||||
|
||||
|
||||
def _load_all_used_cache(
|
||||
repos,
|
||||
target=None,
|
||||
all_branches=False,
|
||||
active=True,
|
||||
with_deps=False,
|
||||
all_tags=False,
|
||||
remote=None,
|
||||
force=False,
|
||||
jobs=None,
|
||||
):
|
||||
clists = []
|
||||
|
||||
for repo in repos:
|
||||
with repo.state:
|
||||
repo_clist = repo.used_cache(
|
||||
target=None,
|
||||
all_branches=all_branches,
|
||||
active=False,
|
||||
with_deps=with_deps,
|
||||
all_tags=all_tags,
|
||||
remote=remote,
|
||||
force=force,
|
||||
jobs=jobs,
|
||||
)
|
||||
|
||||
clists.append(repo_clist)
|
||||
|
||||
return clists
|
||||
|
||||
|
||||
def _do_gc(typ, func, clist):
|
||||
removed = func(clist)
|
||||
if not removed:
|
||||
logger.info("No unused {} cache to remove.".format(typ))
|
||||
|
||||
|
||||
def gc(
|
||||
self,
|
||||
all_branches=False,
|
||||
cloud=False,
|
||||
remote=None,
|
||||
with_deps=False,
|
||||
all_tags=False,
|
||||
force=False,
|
||||
jobs=None,
|
||||
repos=None,
|
||||
):
|
||||
from dvc.repo import Repo
|
||||
|
||||
all_repos = [self]
|
||||
|
||||
if repos:
|
||||
all_repos.extend(Repo(path) for path in repos)
|
||||
|
||||
all_clists = _load_all_used_cache(
|
||||
all_repos,
|
||||
target=None,
|
||||
all_branches=all_branches,
|
||||
active=False,
|
||||
with_deps=with_deps,
|
||||
all_tags=all_tags,
|
||||
remote=remote,
|
||||
force=force,
|
||||
jobs=jobs,
|
||||
)
|
||||
|
||||
if len(all_clists) > 1:
|
||||
clist = _merge_cache_lists(all_clists)
|
||||
else:
|
||||
clist = all_clists[0]
|
||||
|
||||
with self.state:
|
||||
_do_gc("local", self.cache.local.gc, clist)
|
||||
|
||||
if self.cache.s3:
|
||||
_do_gc("s3", self.cache.s3.gc, clist)
|
||||
|
||||
if self.cache.gs:
|
||||
_do_gc("gs", self.cache.gs.gc, clist)
|
||||
|
||||
if self.cache.ssh:
|
||||
_do_gc("ssh", self.cache.ssh.gc, clist)
|
||||
|
||||
if self.cache.hdfs:
|
||||
_do_gc("hdfs", self.cache.hdfs.gc, clist)
|
||||
|
||||
if self.cache.azure:
|
||||
_do_gc("azure", self.cache.azure.gc, clist)
|
||||
|
||||
if cloud:
|
||||
_do_gc("remote", self.cloud._get_cloud(remote, "gc -c").gc, clist)
|
||||
@@ -0,0 +1,20 @@
|
||||
from dvc.stage import Stage
|
||||
|
||||
|
||||
def imp(self, url, out, resume=False):
|
||||
stage = Stage.create(repo=self, cmd=None, deps=[url], outs=[out])
|
||||
|
||||
if stage is None:
|
||||
return None
|
||||
|
||||
self.check_dag(self.stages() + [stage])
|
||||
|
||||
self.files_to_git_add = []
|
||||
with self.state:
|
||||
stage.run(resume=resume)
|
||||
|
||||
stage.dump()
|
||||
|
||||
self.remind_to_git_add()
|
||||
|
||||
return stage
|
||||
@@ -0,0 +1,88 @@
|
||||
import os
|
||||
import shutil
|
||||
import colorama
|
||||
|
||||
import dvc.logger as logger
|
||||
from dvc.repo import Repo
|
||||
from dvc.scm import SCM, Base
|
||||
from dvc.config import Config
|
||||
from dvc.exceptions import InitError
|
||||
|
||||
|
||||
def _welcome_message():
|
||||
logger.box(
|
||||
"DVC has enabled anonymous aggregate usage analytics.\n"
|
||||
"Read the analytics documentation (and how to opt-out) here:\n"
|
||||
"{blue}https://dvc.org/doc/user-guide/analytics{nc}".format(
|
||||
blue=colorama.Fore.BLUE, nc=colorama.Fore.RESET
|
||||
),
|
||||
border_color="red",
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"{yellow}What's next?{nc}\n"
|
||||
"{yellow}------------{nc}\n"
|
||||
"- Check out the documentation: {blue}https://dvc.org/doc{nc}\n"
|
||||
"- Get help and share ideas: {blue}https://dvc.org/chat{nc}\n"
|
||||
"- Star us on GitHub: {blue}https://github.com/iterative/dvc{nc}".format(
|
||||
yellow=colorama.Fore.YELLOW,
|
||||
blue=colorama.Fore.BLUE,
|
||||
nc=colorama.Fore.RESET,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def init(root_dir=os.curdir, no_scm=False, force=False):
|
||||
"""
|
||||
Creates an empty repo on the given directory -- basically a
|
||||
`.dvc` directory with subdirectories for configuration and cache.
|
||||
|
||||
It should be tracked by a SCM or use the `--no-scm` flag.
|
||||
|
||||
If the given directory is not empty, you must use the `--force`
|
||||
flag to override it.
|
||||
|
||||
Args:
|
||||
root_dir: Path to repo's root directory.
|
||||
|
||||
Returns:
|
||||
Repo instance.
|
||||
|
||||
Raises:
|
||||
KeyError: Raises an exception.
|
||||
"""
|
||||
root_dir = os.path.abspath(root_dir)
|
||||
dvc_dir = os.path.join(root_dir, Repo.DVC_DIR)
|
||||
scm = SCM(root_dir)
|
||||
if type(scm) == Base and not no_scm:
|
||||
raise InitError(
|
||||
"{repo} is not tracked by any supported scm tool"
|
||||
" (e.g. git). Use '--no-scm' if you don't want to use any scm.".format(
|
||||
repo=root_dir
|
||||
)
|
||||
)
|
||||
|
||||
if os.path.isdir(dvc_dir):
|
||||
if not force:
|
||||
raise InitError(
|
||||
"'{repo}' exists. Use '-f' to force.".format(
|
||||
repo=os.path.relpath(dvc_dir)
|
||||
)
|
||||
)
|
||||
|
||||
shutil.rmtree(dvc_dir)
|
||||
|
||||
os.mkdir(dvc_dir)
|
||||
|
||||
config = Config.init(dvc_dir)
|
||||
proj = Repo(root_dir)
|
||||
|
||||
scm.add([config.config_file])
|
||||
|
||||
if scm.ignore_file:
|
||||
scm.add([os.path.join(dvc_dir, scm.ignore_file)])
|
||||
logger.info("\nYou can now commit the changes to git.\n")
|
||||
|
||||
_welcome_message()
|
||||
|
||||
return proj
|
||||
@@ -0,0 +1,2 @@
|
||||
def install(self):
|
||||
self.scm.install()
|
||||
@@ -0,0 +1,8 @@
|
||||
def lock(self, target, unlock=False):
|
||||
from dvc.stage import Stage
|
||||
|
||||
stage = Stage.load(self, target)
|
||||
stage.locked = False if unlock else True
|
||||
stage.dump()
|
||||
|
||||
return stage
|
||||
@@ -0,0 +1,23 @@
|
||||
class Metrics(object):
|
||||
def __init__(self, repo):
|
||||
self.repo = repo
|
||||
|
||||
def add(self, *args, **kwargs):
|
||||
from dvc.repo.metrics.add import add
|
||||
|
||||
return add(self.repo, *args, **kwargs)
|
||||
|
||||
def modify(self, *args, **kwargs):
|
||||
from dvc.repo.metrics.modify import modify
|
||||
|
||||
return modify(self.repo, *args, **kwargs)
|
||||
|
||||
def show(self, *args, **kwargs):
|
||||
from dvc.repo.metrics.show import show
|
||||
|
||||
return show(self.repo, *args, **kwargs)
|
||||
|
||||
def remove(self, *args, **kwargs):
|
||||
from dvc.repo.metrics.remove import remove
|
||||
|
||||
return remove(self.repo, *args, **kwargs)
|
||||
@@ -0,0 +1,7 @@
|
||||
from dvc.repo.metrics.modify import modify
|
||||
|
||||
|
||||
def add(repo, path, typ=None, xpath=None):
|
||||
if not typ:
|
||||
typ = "raw"
|
||||
modify(repo, path, typ, xpath)
|
||||
@@ -0,0 +1,64 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
from dvc.exceptions import DvcException, OutputDuplicationError
|
||||
|
||||
|
||||
def find_output_by_path(repo, path, outs=None, recursive=False):
|
||||
if not outs:
|
||||
astages = repo.active_stages()
|
||||
outs = [out for stage in astages for out in stage.outs]
|
||||
|
||||
abs_path = os.path.abspath(path)
|
||||
if os.path.isdir(abs_path) and recursive:
|
||||
matched = [
|
||||
out
|
||||
for out in outs
|
||||
if os.path.abspath(out.path).startswith(abs_path)
|
||||
]
|
||||
else:
|
||||
matched = [out for out in outs if out.path == abs_path]
|
||||
stages = [out.stage.relpath for out in matched]
|
||||
if len(stages) > 1:
|
||||
raise OutputDuplicationError(path, stages)
|
||||
|
||||
return matched if matched else []
|
||||
|
||||
|
||||
def modify(repo, path, typ=None, xpath=None, delete=False):
|
||||
outs = find_output_by_path(repo, path)
|
||||
|
||||
if not outs:
|
||||
msg = "unable to find file '{}' in the pipeline".format(path)
|
||||
raise DvcException(msg)
|
||||
|
||||
if len(outs) != 1:
|
||||
msg = (
|
||||
"-R not yet supported for metrics modify. "
|
||||
"Make sure only one metric is referred to by '{}'".format(path)
|
||||
)
|
||||
raise DvcException(msg)
|
||||
|
||||
out = outs[0]
|
||||
|
||||
if out.scheme != "local":
|
||||
msg = "output '{}' scheme '{}' is not supported for metrics"
|
||||
raise DvcException(msg.format(out.path, out.path_info["scheme"]))
|
||||
|
||||
if typ:
|
||||
if not isinstance(out.metric, dict):
|
||||
out.metric = {}
|
||||
out.metric[out.PARAM_METRIC_TYPE] = typ
|
||||
|
||||
if xpath:
|
||||
if not isinstance(out.metric, dict):
|
||||
out.metric = {}
|
||||
out.metric[out.PARAM_METRIC_XPATH] = xpath
|
||||
|
||||
if delete:
|
||||
out.metric = None
|
||||
|
||||
out._verify_metric()
|
||||
|
||||
out.stage.dump()
|
||||
@@ -0,0 +1,5 @@
|
||||
from dvc.repo.metrics.modify import modify
|
||||
|
||||
|
||||
def remove(repo, path):
|
||||
modify(repo, path, delete=True)
|
||||
@@ -0,0 +1,150 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import csv
|
||||
import json
|
||||
from jsonpath_rw import parse
|
||||
|
||||
import dvc.logger as logger
|
||||
from dvc.exceptions import OutputDuplicationError, DvcException
|
||||
from dvc.repo.metrics.modify import find_output_by_path
|
||||
from dvc.utils.compat import str, builtin_str, open
|
||||
|
||||
|
||||
def _read_metric_json(fd, json_path):
|
||||
parser = parse(json_path)
|
||||
return [x.value for x in parser.find(json.load(fd))]
|
||||
|
||||
|
||||
def _do_read_metric_xsv(reader, row, col):
|
||||
if col is not None and row is not None:
|
||||
return [reader[row][col]]
|
||||
elif col is not None:
|
||||
return [r[col] for r in reader]
|
||||
elif row is not None:
|
||||
return reader[row]
|
||||
return None
|
||||
|
||||
|
||||
def _read_metric_hxsv(fd, hxsv_path, delimiter):
|
||||
col, row = hxsv_path.split(",")
|
||||
row = int(row)
|
||||
reader = list(csv.DictReader(fd, delimiter=builtin_str(delimiter)))
|
||||
return _do_read_metric_xsv(reader, row, col)
|
||||
|
||||
|
||||
def _read_metric_xsv(fd, xsv_path, delimiter):
|
||||
col, row = xsv_path.split(",")
|
||||
row = int(row)
|
||||
col = int(col)
|
||||
reader = list(csv.reader(fd, delimiter=builtin_str(delimiter)))
|
||||
return _do_read_metric_xsv(reader, row, col)
|
||||
|
||||
|
||||
def _read_metric(path, typ=None, xpath=None):
|
||||
ret = None
|
||||
|
||||
if not os.path.exists(path):
|
||||
return ret
|
||||
|
||||
try:
|
||||
with open(path, "r") as fd:
|
||||
if typ == "json":
|
||||
ret = _read_metric_json(fd, xpath)
|
||||
elif typ == "csv":
|
||||
ret = _read_metric_xsv(fd, xpath, ",")
|
||||
elif typ == "tsv":
|
||||
ret = _read_metric_xsv(fd, xpath, "\t")
|
||||
elif typ == "hcsv":
|
||||
ret = _read_metric_hxsv(fd, xpath, ",")
|
||||
elif typ == "htsv":
|
||||
ret = _read_metric_hxsv(fd, xpath, "\t")
|
||||
else:
|
||||
ret = fd.read().strip()
|
||||
except Exception:
|
||||
logger.error("unable to read metric in '{}'".format(path))
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def show(
|
||||
self,
|
||||
path=None,
|
||||
typ=None,
|
||||
xpath=None,
|
||||
all_branches=False,
|
||||
all_tags=False,
|
||||
recursive=False,
|
||||
):
|
||||
res = {}
|
||||
for branch in self.scm.brancher(
|
||||
all_branches=all_branches, all_tags=all_tags
|
||||
):
|
||||
astages = self.active_stages()
|
||||
outs = [out for stage in astages for out in stage.outs]
|
||||
|
||||
if path:
|
||||
outs = find_output_by_path(
|
||||
self, path, outs=outs, recursive=recursive
|
||||
)
|
||||
|
||||
metrics = filter(lambda o: o.metric, outs)
|
||||
stages = set()
|
||||
entries = []
|
||||
|
||||
for o in metrics:
|
||||
if not typ and isinstance(o.metric, dict):
|
||||
t = o.metric.get(o.PARAM_METRIC_TYPE, typ)
|
||||
x = o.metric.get(o.PARAM_METRIC_XPATH, xpath)
|
||||
else:
|
||||
t = typ
|
||||
x = xpath
|
||||
entries.append((o.path, t, x))
|
||||
stages.add(o.stage.path)
|
||||
|
||||
if path and not entries:
|
||||
if os.path.isdir(path):
|
||||
logger.warning(
|
||||
"Path '{path}' is a directory. "
|
||||
"Consider running with '-R'.".format(path=path)
|
||||
)
|
||||
return {}
|
||||
|
||||
for fname, t, x in entries:
|
||||
if stages:
|
||||
for stage in stages:
|
||||
self.checkout(stage, force=True)
|
||||
|
||||
rel = os.path.relpath(fname)
|
||||
metric = _read_metric(fname, typ=t, xpath=x)
|
||||
if not metric:
|
||||
continue
|
||||
|
||||
if branch not in res:
|
||||
res[branch] = {}
|
||||
|
||||
res[branch][rel] = metric
|
||||
|
||||
for branch, val in res.items():
|
||||
if all_branches or all_tags:
|
||||
logger.info("{}:".format(branch))
|
||||
for fname, metric in val.items():
|
||||
logger.info("\t{}: {}".format(fname, metric))
|
||||
|
||||
if res:
|
||||
return res
|
||||
|
||||
if path and os.path.isdir(path):
|
||||
return res
|
||||
|
||||
if path:
|
||||
msg = "file '{}' does not exist, not a metric file or is malformed".format(
|
||||
path
|
||||
)
|
||||
else:
|
||||
msg = (
|
||||
"no metric files in this repository."
|
||||
" use 'dvc metrics add' to add a metric file to track."
|
||||
)
|
||||
|
||||
raise DvcException(msg)
|
||||
@@ -0,0 +1,75 @@
|
||||
import os
|
||||
|
||||
from dvc.exceptions import MoveNotDataSourceError, DvcException
|
||||
|
||||
|
||||
def _expand_target_path(from_path, to_path):
|
||||
if os.path.isdir(to_path) and not os.path.isdir(from_path):
|
||||
return os.path.join(to_path, os.path.basename(from_path))
|
||||
return to_path
|
||||
|
||||
|
||||
def move(self, from_path, to_path):
|
||||
"""
|
||||
Renames an output file and modifies the stage associated
|
||||
to reflect the change on the pipeline.
|
||||
|
||||
If the output has the same name as its stage, it would
|
||||
also rename the corresponding stage file.
|
||||
|
||||
E.g.
|
||||
Having: (hello, hello.dvc)
|
||||
|
||||
$ dvc move hello greetings
|
||||
|
||||
Result: (greeting, greeting.dvc)
|
||||
|
||||
It only works with outputs generated by `add` or `import`,
|
||||
also known as data sources.
|
||||
"""
|
||||
import dvc.output as Output
|
||||
from dvc.stage import Stage
|
||||
|
||||
from_out = Output.loads_from(Stage(self, cwd=os.curdir), [from_path])[0]
|
||||
|
||||
to_path = _expand_target_path(from_path, to_path)
|
||||
|
||||
try:
|
||||
stage, out = next(
|
||||
(stage, out)
|
||||
for stage in self.stages()
|
||||
for out in stage.outs
|
||||
if from_out.path == out.path
|
||||
)
|
||||
except StopIteration:
|
||||
raise DvcException(
|
||||
"unable to find stage file with output '{path}'".format(
|
||||
path=from_path
|
||||
)
|
||||
)
|
||||
|
||||
if not stage.is_data_source:
|
||||
raise MoveNotDataSourceError(stage.relpath)
|
||||
|
||||
stage_name = os.path.splitext(os.path.basename(stage.path))[0]
|
||||
from_name = os.path.basename(from_out.path)
|
||||
if stage_name == from_name:
|
||||
os.unlink(stage.path)
|
||||
|
||||
stage.path = os.path.join(
|
||||
os.path.dirname(to_path),
|
||||
os.path.basename(to_path) + Stage.STAGE_FILE_SUFFIX,
|
||||
)
|
||||
|
||||
stage.cwd = os.path.join(self.root_dir, os.path.dirname(to_path))
|
||||
|
||||
to_out = Output.loads_from(
|
||||
stage, [os.path.basename(to_path)], out.cache, out.metric
|
||||
)[0]
|
||||
|
||||
with self.state:
|
||||
out.move(to_out)
|
||||
|
||||
stage.dump()
|
||||
|
||||
self.remind_to_git_add()
|
||||
@@ -0,0 +1,28 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
def pull(
|
||||
self,
|
||||
target=None,
|
||||
jobs=1,
|
||||
remote=None,
|
||||
all_branches=False,
|
||||
show_checksums=False,
|
||||
with_deps=False,
|
||||
all_tags=False,
|
||||
force=False,
|
||||
recursive=False,
|
||||
):
|
||||
self.fetch(
|
||||
target,
|
||||
jobs,
|
||||
remote=remote,
|
||||
all_branches=all_branches,
|
||||
all_tags=all_tags,
|
||||
show_checksums=show_checksums,
|
||||
with_deps=with_deps,
|
||||
recursive=recursive,
|
||||
)
|
||||
self.checkout(
|
||||
target=target, with_deps=with_deps, force=force, recursive=recursive
|
||||
)
|
||||
@@ -0,0 +1,28 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
def push(
|
||||
self,
|
||||
target=None,
|
||||
jobs=1,
|
||||
remote=None,
|
||||
all_branches=False,
|
||||
show_checksums=False,
|
||||
with_deps=False,
|
||||
all_tags=False,
|
||||
recursive=False,
|
||||
):
|
||||
with self.state:
|
||||
used = self.used_cache(
|
||||
target,
|
||||
all_branches=all_branches,
|
||||
all_tags=all_tags,
|
||||
with_deps=with_deps,
|
||||
force=True,
|
||||
remote=remote,
|
||||
jobs=jobs,
|
||||
recursive=recursive,
|
||||
)["local"]
|
||||
self.cloud.push(
|
||||
used, jobs, remote=remote, show_checksums=show_checksums
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
def remove(self, target, outs_only=False):
|
||||
from dvc.stage import Stage
|
||||
|
||||
stage = Stage.load(self, target)
|
||||
if outs_only:
|
||||
stage.remove_outs()
|
||||
else:
|
||||
stage.remove()
|
||||
|
||||
return stage
|
||||
@@ -0,0 +1,134 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
import dvc.logger as logger
|
||||
from dvc.exceptions import ReproductionError
|
||||
|
||||
|
||||
def _reproduce_stage(stages, node, force, dry, interactive):
|
||||
stage = stages[node]
|
||||
|
||||
if stage.locked:
|
||||
logger.warning(
|
||||
"DVC file '{path}' is locked. Its dependencies are"
|
||||
" not going to be reproduced.".format(path=stage.relpath)
|
||||
)
|
||||
|
||||
stage = stage.reproduce(force=force, dry=dry, interactive=interactive)
|
||||
if not stage:
|
||||
return []
|
||||
|
||||
if not dry:
|
||||
stage.dump()
|
||||
|
||||
return [stage]
|
||||
|
||||
|
||||
def reproduce(
|
||||
self,
|
||||
target=None,
|
||||
recursive=True,
|
||||
force=False,
|
||||
dry=False,
|
||||
interactive=False,
|
||||
pipeline=False,
|
||||
all_pipelines=False,
|
||||
ignore_build_cache=False,
|
||||
):
|
||||
from dvc.stage import Stage
|
||||
|
||||
if not target and not all_pipelines:
|
||||
raise ValueError()
|
||||
|
||||
if not interactive:
|
||||
config = self.config
|
||||
core = config.config[config.SECTION_CORE]
|
||||
interactive = core.get(config.SECTION_CORE_INTERACTIVE, False)
|
||||
|
||||
targets = []
|
||||
if pipeline or all_pipelines:
|
||||
if pipeline:
|
||||
stage = Stage.load(self, target)
|
||||
node = os.path.relpath(stage.path, self.root_dir)
|
||||
pipelines = [self._get_pipeline(node)]
|
||||
else:
|
||||
pipelines = self.pipelines()
|
||||
|
||||
for G in pipelines:
|
||||
for node in G.nodes():
|
||||
if G.in_degree(node) == 0:
|
||||
targets.append(os.path.join(self.root_dir, node))
|
||||
else:
|
||||
targets.append(target)
|
||||
|
||||
self.files_to_git_add = []
|
||||
|
||||
ret = []
|
||||
with self.state:
|
||||
for target in targets:
|
||||
stages = _reproduce(
|
||||
self,
|
||||
target,
|
||||
recursive=recursive,
|
||||
force=force,
|
||||
dry=dry,
|
||||
interactive=interactive,
|
||||
ignore_build_cache=ignore_build_cache,
|
||||
)
|
||||
ret.extend(stages)
|
||||
|
||||
self.remind_to_git_add()
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def _reproduce(
|
||||
self,
|
||||
target,
|
||||
recursive=True,
|
||||
force=False,
|
||||
dry=False,
|
||||
interactive=False,
|
||||
ignore_build_cache=False,
|
||||
):
|
||||
import networkx as nx
|
||||
from dvc.stage import Stage
|
||||
|
||||
stage = Stage.load(self, target)
|
||||
G = self.graph()[1]
|
||||
stages = nx.get_node_attributes(G, "stage")
|
||||
node = os.path.relpath(stage.path, self.root_dir)
|
||||
|
||||
if recursive:
|
||||
ret = _reproduce_stages(
|
||||
G, stages, node, force, dry, interactive, ignore_build_cache
|
||||
)
|
||||
else:
|
||||
ret = _reproduce_stage(stages, node, force, dry, interactive)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def _reproduce_stages(
|
||||
G, stages, node, force, dry, interactive, ignore_build_cache
|
||||
):
|
||||
import networkx as nx
|
||||
|
||||
result = []
|
||||
for n in nx.dfs_postorder_nodes(G, node):
|
||||
try:
|
||||
ret = _reproduce_stage(stages, n, force, dry, interactive)
|
||||
|
||||
if len(ret) == 0 and ignore_build_cache:
|
||||
# NOTE: we are walking our pipeline from the top to the
|
||||
# bottom. If one stage is changed, it will be reproduced,
|
||||
# which tells us that we should force reproducing all of
|
||||
# the other stages down below, even if their direct
|
||||
# dependencies didn't change.
|
||||
force = True
|
||||
|
||||
result += ret
|
||||
except Exception as ex:
|
||||
raise ReproductionError(stages[n].relpath, ex)
|
||||
return result
|
||||
@@ -0,0 +1,62 @@
|
||||
import os
|
||||
|
||||
|
||||
def run(
|
||||
self,
|
||||
cmd=None,
|
||||
deps=None,
|
||||
outs=None,
|
||||
outs_no_cache=None,
|
||||
metrics=None,
|
||||
metrics_no_cache=None,
|
||||
fname=None,
|
||||
cwd=os.curdir,
|
||||
no_exec=False,
|
||||
overwrite=False,
|
||||
ignore_build_cache=False,
|
||||
remove_outs=False,
|
||||
):
|
||||
from dvc.stage import Stage
|
||||
|
||||
if outs is None:
|
||||
outs = []
|
||||
if deps is None:
|
||||
deps = []
|
||||
if outs_no_cache is None:
|
||||
outs_no_cache = []
|
||||
if metrics is None:
|
||||
metrics = []
|
||||
if metrics_no_cache is None:
|
||||
metrics_no_cache = []
|
||||
|
||||
with self.state:
|
||||
stage = Stage.create(
|
||||
repo=self,
|
||||
fname=fname,
|
||||
cmd=cmd,
|
||||
cwd=cwd,
|
||||
outs=outs,
|
||||
outs_no_cache=outs_no_cache,
|
||||
metrics=metrics,
|
||||
metrics_no_cache=metrics_no_cache,
|
||||
deps=deps,
|
||||
overwrite=overwrite,
|
||||
ignore_build_cache=ignore_build_cache,
|
||||
remove_outs=remove_outs,
|
||||
)
|
||||
|
||||
if stage is None:
|
||||
return None
|
||||
|
||||
self.check_dag(self.stages() + [stage])
|
||||
|
||||
self.files_to_git_add = []
|
||||
with self.state:
|
||||
if not no_exec:
|
||||
stage.run()
|
||||
|
||||
stage.dump()
|
||||
|
||||
self.remind_to_git_add()
|
||||
|
||||
return stage
|
||||
@@ -0,0 +1,89 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import dvc.logger as logger
|
||||
import dvc.remote.base as cloud
|
||||
|
||||
|
||||
def _local_status(self, target=None, with_deps=False):
|
||||
status = {}
|
||||
|
||||
if target:
|
||||
stages = self.collect(target, with_deps=with_deps)
|
||||
else:
|
||||
stages = self.active_stages()
|
||||
|
||||
for stage in stages:
|
||||
if stage.locked:
|
||||
logger.warning(
|
||||
"DVC file '{path}' is locked. Its dependencies are"
|
||||
" not going to be shown in the status output.".format(
|
||||
path=stage.relpath
|
||||
)
|
||||
)
|
||||
|
||||
status.update(stage.status())
|
||||
|
||||
return status
|
||||
|
||||
|
||||
def _cloud_status(
|
||||
self,
|
||||
target=None,
|
||||
jobs=1,
|
||||
remote=None,
|
||||
show_checksums=False,
|
||||
all_branches=False,
|
||||
with_deps=False,
|
||||
all_tags=False,
|
||||
):
|
||||
used = self.used_cache(
|
||||
target,
|
||||
all_branches=all_branches,
|
||||
all_tags=all_tags,
|
||||
with_deps=with_deps,
|
||||
force=True,
|
||||
remote=remote,
|
||||
jobs=jobs,
|
||||
)["local"]
|
||||
|
||||
ret = {}
|
||||
status_info = self.cloud.status(
|
||||
used, jobs, remote=remote, show_checksums=show_checksums
|
||||
)
|
||||
for md5, info in status_info.items():
|
||||
name = info["name"]
|
||||
status = info["status"]
|
||||
if status == cloud.STATUS_OK:
|
||||
continue
|
||||
|
||||
prefix_map = {cloud.STATUS_DELETED: "deleted", cloud.STATUS_NEW: "new"}
|
||||
|
||||
ret[name] = prefix_map[status]
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def status(
|
||||
self,
|
||||
target=None,
|
||||
jobs=1,
|
||||
cloud=False,
|
||||
remote=None,
|
||||
show_checksums=False,
|
||||
all_branches=False,
|
||||
with_deps=False,
|
||||
all_tags=False,
|
||||
):
|
||||
with self.state:
|
||||
if cloud:
|
||||
return _cloud_status(
|
||||
self,
|
||||
target,
|
||||
jobs,
|
||||
remote=remote,
|
||||
show_checksums=show_checksums,
|
||||
all_branches=all_branches,
|
||||
with_deps=with_deps,
|
||||
all_tags=all_tags,
|
||||
)
|
||||
return _local_status(self, target, with_deps=with_deps)
|
||||
@@ -0,0 +1,48 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import stat
|
||||
import uuid
|
||||
|
||||
import dvc.logger as logger
|
||||
from dvc.system import System
|
||||
from dvc.utils import copyfile, move, remove
|
||||
from dvc.exceptions import DvcException
|
||||
|
||||
|
||||
def _unprotect_file(path):
|
||||
if System.is_symlink(path) or System.is_hardlink(path):
|
||||
logger.debug("Unprotecting '{}'".format(path))
|
||||
|
||||
tmp = os.path.join(os.path.dirname(path), "." + str(uuid.uuid4()))
|
||||
move(path, tmp)
|
||||
|
||||
copyfile(tmp, path)
|
||||
|
||||
remove(tmp)
|
||||
else:
|
||||
logger.debug(
|
||||
"Skipping copying for '{}', since it is not "
|
||||
"a symlink or a hardlink.".format(path)
|
||||
)
|
||||
|
||||
os.chmod(path, os.stat(path).st_mode | stat.S_IWRITE)
|
||||
|
||||
|
||||
def _unprotect_dir(path):
|
||||
for root, dirs, files in os.walk(str(path)):
|
||||
for f in files:
|
||||
path = os.path.join(root, f)
|
||||
_unprotect_file(path)
|
||||
|
||||
|
||||
def unprotect(path):
|
||||
if not os.path.exists(path):
|
||||
raise DvcException(
|
||||
"can't unprotect non-existing data '{}'".format(path)
|
||||
)
|
||||
|
||||
if os.path.isdir(path):
|
||||
_unprotect_dir(path)
|
||||
else:
|
||||
_unprotect_file(path)
|
||||
+6
-7
@@ -6,19 +6,18 @@ from dvc.scm.base import Base
|
||||
from dvc.scm.git import Git
|
||||
|
||||
|
||||
def SCM(root_dir, project=None): # pylint: disable=invalid-name
|
||||
"""Returns SCM instance that corresponds to a project at the specified
|
||||
def SCM(root_dir, repo=None): # pylint: disable=invalid-name
|
||||
"""Returns SCM instance that corresponds to a repo at the specified
|
||||
path.
|
||||
|
||||
Args:
|
||||
root_dir (str): path to a root directory of the project.
|
||||
project (dvc.project.Project): dvc project instance that root_dir
|
||||
belongs to.
|
||||
root_dir (str): path to a root directory of the repo.
|
||||
repo (dvc.repo.Repo): dvc repo instance that root_dir belongs to.
|
||||
|
||||
Returns:
|
||||
dvc.scm.base.Base: SCM instance.
|
||||
"""
|
||||
if Git.is_repo(root_dir) or Git.is_submodule(root_dir):
|
||||
return Git(root_dir, project=project)
|
||||
return Git(root_dir, repo=repo)
|
||||
|
||||
return Base(root_dir, project=project)
|
||||
return Base(root_dir, repo=repo)
|
||||
|
||||
+6
-6
@@ -20,8 +20,8 @@ class FileNotInRepoError(DvcException):
|
||||
class Base(object):
|
||||
"""Base class for source control management driver implementations."""
|
||||
|
||||
def __init__(self, root_dir=os.curdir, project=None):
|
||||
self.project = project
|
||||
def __init__(self, root_dir=os.curdir, repo=None):
|
||||
self.repo = repo
|
||||
self.root_dir = root_dir
|
||||
|
||||
def __repr__(self):
|
||||
@@ -126,16 +126,16 @@ class Base(object):
|
||||
return False
|
||||
|
||||
def active_branch(self): # pylint: disable=no-self-use
|
||||
"""Returns current branch in the project."""
|
||||
"""Returns current branch in the repo."""
|
||||
return ""
|
||||
|
||||
def list_branches(self): # pylint: disable=no-self-use
|
||||
"""Returns a list of available branches in the project."""
|
||||
"""Returns a list of available branches in the repo."""
|
||||
return []
|
||||
|
||||
def list_tags(self): # pylint: disable=no-self-use
|
||||
"""Returns a list of available tags in the project."""
|
||||
"""Returns a list of available tags in the repo."""
|
||||
return []
|
||||
|
||||
def install(self):
|
||||
"""Adds dvc commands to SCM hooks for the project."""
|
||||
"""Adds dvc commands to SCM hooks for the repo."""
|
||||
|
||||
+21
-21
@@ -21,14 +21,14 @@ class Git(Base):
|
||||
GITIGNORE = ".gitignore"
|
||||
GIT_DIR = ".git"
|
||||
|
||||
def __init__(self, root_dir=os.curdir, project=None):
|
||||
super(Git, self).__init__(root_dir, project=project)
|
||||
def __init__(self, root_dir=os.curdir, repo=None):
|
||||
super(Git, self).__init__(root_dir, repo=repo)
|
||||
|
||||
import git
|
||||
from git.exc import InvalidGitRepositoryError
|
||||
|
||||
try:
|
||||
self.repo = git.Repo(root_dir)
|
||||
self.git = git.Repo(root_dir)
|
||||
except InvalidGitRepositoryError:
|
||||
msg = "{} is not a git repository"
|
||||
raise SCMError(msg.format(root_dir))
|
||||
@@ -37,7 +37,7 @@ class Git(Base):
|
||||
# http://pyinstaller.readthedocs.io/en/stable/runtime-information.html
|
||||
env = fix_env(None)
|
||||
libpath = env.get("LD_LIBRARY_PATH", None)
|
||||
self.repo.git.update_environment(LD_LIBRARY_PATH=libpath)
|
||||
self.git.git.update_environment(LD_LIBRARY_PATH=libpath)
|
||||
|
||||
@staticmethod
|
||||
def is_repo(root_dir):
|
||||
@@ -53,7 +53,7 @@ class Git(Base):
|
||||
|
||||
@property
|
||||
def dir(self):
|
||||
return self.repo.git_dir
|
||||
return self.git.git_dir
|
||||
|
||||
@property
|
||||
def ignore_file(self):
|
||||
@@ -94,8 +94,8 @@ class Git(Base):
|
||||
with open(gitignore, "a") as fobj:
|
||||
fobj.write(content)
|
||||
|
||||
if self.project is not None:
|
||||
self.project.files_to_git_add.append(os.path.relpath(gitignore))
|
||||
if self.repo is not None:
|
||||
self.repo.files_to_git_add.append(os.path.relpath(gitignore))
|
||||
|
||||
def ignore_remove(self, path):
|
||||
entry, gitignore = self._get_gitignore(path)
|
||||
@@ -111,14 +111,14 @@ class Git(Base):
|
||||
with open(gitignore, "w") as fobj:
|
||||
fobj.writelines(filtered)
|
||||
|
||||
if self.project is not None:
|
||||
self.project.files_to_git_add.append(os.path.relpath(gitignore))
|
||||
if self.repo is not None:
|
||||
self.repo.files_to_git_add.append(os.path.relpath(gitignore))
|
||||
|
||||
def add(self, paths):
|
||||
# NOTE: GitPython is not currently able to handle index version >= 3.
|
||||
# See https://github.com/iterative/dvc/issues/610 for more details.
|
||||
try:
|
||||
self.repo.index.add(paths)
|
||||
self.git.index.add(paths)
|
||||
except AssertionError:
|
||||
msg = (
|
||||
"failed to add '{}' to git. You can add those files"
|
||||
@@ -130,35 +130,35 @@ class Git(Base):
|
||||
logger.error(msg)
|
||||
|
||||
def commit(self, msg):
|
||||
self.repo.index.commit(msg)
|
||||
self.git.index.commit(msg)
|
||||
|
||||
def checkout(self, branch, create_new=False):
|
||||
if create_new:
|
||||
self.repo.git.checkout("HEAD", b=branch)
|
||||
self.git.git.checkout("HEAD", b=branch)
|
||||
else:
|
||||
self.repo.git.checkout(branch)
|
||||
self.git.git.checkout(branch)
|
||||
|
||||
def branch(self, branch):
|
||||
self.repo.git.branch(branch)
|
||||
self.git.git.branch(branch)
|
||||
|
||||
def tag(self, tag):
|
||||
self.repo.git.tag(tag)
|
||||
self.git.git.tag(tag)
|
||||
|
||||
def untracked_files(self):
|
||||
files = self.repo.untracked_files
|
||||
return [os.path.join(self.repo.working_dir, fname) for fname in files]
|
||||
files = self.git.untracked_files
|
||||
return [os.path.join(self.git.working_dir, fname) for fname in files]
|
||||
|
||||
def is_tracked(self, path):
|
||||
return len(self.repo.git.ls_files(path)) != 0
|
||||
return len(self.git.git.ls_files(path)) != 0
|
||||
|
||||
def active_branch(self):
|
||||
return self.repo.active_branch.name
|
||||
return self.git.active_branch.name
|
||||
|
||||
def list_branches(self):
|
||||
return [h.name for h in self.repo.heads]
|
||||
return [h.name for h in self.git.heads]
|
||||
|
||||
def list_tags(self):
|
||||
return [t.name for t in self.repo.tags]
|
||||
return [t.name for t in self.git.tags]
|
||||
|
||||
def _install_hook(self, name, cmd):
|
||||
hook = os.path.join(self.root_dir, self.GIT_DIR, "hooks", name)
|
||||
|
||||
+14
-14
@@ -63,7 +63,7 @@ class StageFileBadNameError(DvcException):
|
||||
|
||||
class StageBadCwdError(DvcException):
|
||||
def __init__(self, cwd):
|
||||
msg = "stage cwd '{}' is outside of the current dvc project"
|
||||
msg = "stage cwd '{}' is outside of the current dvc repo"
|
||||
super(StageBadCwdError, self).__init__(msg.format(cwd))
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ class Stage(object):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
project,
|
||||
repo,
|
||||
path=None,
|
||||
cmd=None,
|
||||
cwd=os.curdir,
|
||||
@@ -126,7 +126,7 @@ class Stage(object):
|
||||
if outs is None:
|
||||
outs = []
|
||||
|
||||
self.project = project
|
||||
self.repo = repo
|
||||
self.path = path
|
||||
self.cmd = cmd
|
||||
self.cwd = cwd
|
||||
@@ -245,7 +245,7 @@ class Stage(object):
|
||||
for out in self.outs:
|
||||
if out.scheme != "local" or not out.exists:
|
||||
continue
|
||||
self.project.unprotect(out.path)
|
||||
self.repo.unprotect(out.path)
|
||||
|
||||
def remove(self):
|
||||
self.remove_outs(ignore_remove=True)
|
||||
@@ -306,9 +306,9 @@ class Stage(object):
|
||||
return (fname, cwd)
|
||||
|
||||
@staticmethod
|
||||
def _check_inside_project(project, cwd):
|
||||
assert project is not None
|
||||
proj_dir = os.path.realpath(project.root_dir)
|
||||
def _check_inside_repo(repo, cwd):
|
||||
assert repo is not None
|
||||
proj_dir = os.path.realpath(repo.root_dir)
|
||||
if not os.path.realpath(cwd).startswith(proj_dir):
|
||||
raise StageBadCwdError(cwd)
|
||||
|
||||
@@ -320,7 +320,7 @@ class Stage(object):
|
||||
from dvc.remote.local import RemoteLOCAL
|
||||
from dvc.remote.s3 import RemoteS3
|
||||
|
||||
old = Stage.load(self.project, self.path)
|
||||
old = Stage.load(self.repo, self.path)
|
||||
if old._changed_outs():
|
||||
return False
|
||||
|
||||
@@ -345,7 +345,7 @@ class Stage(object):
|
||||
|
||||
@staticmethod
|
||||
def create(
|
||||
project=None,
|
||||
repo=None,
|
||||
cmd=None,
|
||||
deps=None,
|
||||
outs=None,
|
||||
@@ -372,7 +372,7 @@ class Stage(object):
|
||||
if metrics_no_cache is None:
|
||||
metrics_no_cache = []
|
||||
|
||||
stage = Stage(project=project, cwd=cwd, cmd=cmd, locked=locked)
|
||||
stage = Stage(repo=repo, cwd=cwd, cmd=cmd, locked=locked)
|
||||
|
||||
stage.outs = output.loads_from(stage, outs, use_cache=True)
|
||||
stage.outs += output.loads_from(
|
||||
@@ -397,7 +397,7 @@ class Stage(object):
|
||||
|
||||
fname, cwd = Stage._stage_fname_cwd(fname, cwd, stage.outs, add=add)
|
||||
|
||||
Stage._check_inside_project(project, cwd)
|
||||
Stage._check_inside_repo(repo, cwd)
|
||||
|
||||
cwd = os.path.abspath(cwd)
|
||||
path = os.path.join(cwd, fname)
|
||||
@@ -446,7 +446,7 @@ class Stage(object):
|
||||
raise StageFileDoesNotExistError(fname)
|
||||
|
||||
@staticmethod
|
||||
def load(project, fname):
|
||||
def load(repo, fname):
|
||||
Stage._check_file_exists(fname)
|
||||
Stage._check_dvc_filename(fname)
|
||||
|
||||
@@ -459,7 +459,7 @@ class Stage(object):
|
||||
Stage.validate(d, fname=os.path.relpath(fname))
|
||||
|
||||
stage = Stage(
|
||||
project=project,
|
||||
repo=repo,
|
||||
path=os.path.abspath(fname),
|
||||
cwd=os.path.dirname(os.path.abspath(fname)),
|
||||
cmd=d.get(Stage.PARAM_CMD),
|
||||
@@ -499,7 +499,7 @@ class Stage(object):
|
||||
with open(fname, "w") as fd:
|
||||
yaml.safe_dump(self.dumpd(), fd, default_flow_style=False)
|
||||
|
||||
self.project.files_to_git_add.append(os.path.relpath(fname))
|
||||
self.repo.files_to_git_add.append(os.path.relpath(fname))
|
||||
|
||||
def _compute_md5(self):
|
||||
from dvc.output.local import OutputLOCAL
|
||||
|
||||
+8
-9
@@ -24,7 +24,7 @@ class StateVersionTooNewError(DvcException):
|
||||
"you are using an old version '{dvc_version}' of dvc that is "
|
||||
"using state file version '{expected}' which is not compatible "
|
||||
"with the state file version '{actual}' that is used in this "
|
||||
"project. Please upgrade right now!".format(
|
||||
"repo. Please upgrade right now!".format(
|
||||
dvc_version=dvc_version, expected=expected, actual=actual
|
||||
)
|
||||
)
|
||||
@@ -34,8 +34,7 @@ class State(object): # pylint: disable=too-many-instance-attributes
|
||||
"""Class for the state database.
|
||||
|
||||
Args:
|
||||
project (dvc.project.Project): project instance that this state
|
||||
belongs to.
|
||||
repo (dvc.repo.Repo): repo instance that this state belongs to.
|
||||
config (configobj.ConfigObj): config for the state.
|
||||
|
||||
Raises:
|
||||
@@ -71,10 +70,10 @@ class State(object): # pylint: disable=too-many-instance-attributes
|
||||
MAX_INT = 2 ** 63 - 1
|
||||
MAX_UINT = 2 ** 64 - 2
|
||||
|
||||
def __init__(self, project, config):
|
||||
self.project = project
|
||||
self.dvc_dir = project.dvc_dir
|
||||
self.root_dir = project.root_dir
|
||||
def __init__(self, repo, config):
|
||||
self.repo = repo
|
||||
self.dvc_dir = repo.dvc_dir
|
||||
self.root_dir = repo.root_dir
|
||||
|
||||
self.row_limit = 100
|
||||
self.row_cleanup_quota = 50
|
||||
@@ -112,7 +111,7 @@ class State(object): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
def _collect(self, path):
|
||||
if os.path.isdir(path):
|
||||
return self.project.cache.local.collect_dir_cache(path)
|
||||
return self.repo.cache.local.collect_dir_cache(path)
|
||||
return (file_md5(path)[0], None)
|
||||
|
||||
def changed(self, path, md5):
|
||||
@@ -420,7 +419,7 @@ class State(object): # pylint: disable=too-many-instance-attributes
|
||||
"""
|
||||
md5, info = self._do_update(path)
|
||||
if not info:
|
||||
info = self.project.cache.local.load_dir_cache(md5)
|
||||
info = self.repo.cache.local.load_dir_cache(md5)
|
||||
return (md5, info)
|
||||
|
||||
def update_link(self, path):
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ from git.exc import GitCommandNotFound
|
||||
from unittest import TestCase
|
||||
|
||||
import dvc.logger as logger
|
||||
from dvc.project import Project
|
||||
from dvc.repo import Repo as DvcRepo
|
||||
|
||||
|
||||
class TestDir(TestCase):
|
||||
@@ -111,5 +111,5 @@ class TestGitSubmodule(TestGit):
|
||||
class TestDvc(TestGit):
|
||||
def setUp(self):
|
||||
super(TestDvc, self).setUp()
|
||||
self.dvc = Project.init(self._root_dir)
|
||||
self.dvc = DvcRepo.init(self._root_dir)
|
||||
logger.be_verbose()
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ from dvc.utils import file_md5
|
||||
from dvc.stage import Stage
|
||||
from dvc.exceptions import DvcException
|
||||
from dvc.output.base import OutputAlreadyTrackedError
|
||||
from dvc.project import Project
|
||||
from dvc.repo import Repo as DvcRepo
|
||||
|
||||
from tests.basic_env import TestDvc
|
||||
|
||||
@@ -172,7 +172,7 @@ class TestAddLocalRemoteFile(TestDvc):
|
||||
ret = main(["remote", "add", remote, cwd])
|
||||
self.assertEqual(ret, 0)
|
||||
|
||||
self.dvc = Project()
|
||||
self.dvc = DvcRepo()
|
||||
|
||||
foo = "remote://{}/{}".format(remote, self.FOO)
|
||||
ret = main(["add", foo])
|
||||
|
||||
+1
-1
@@ -142,7 +142,7 @@ class TestCmdCacheDir(TestDvc):
|
||||
ret = main(["cache", "dir", dname])
|
||||
self.assertEqual(ret, 0)
|
||||
|
||||
# NOTE: we are in the project's root and config is in .dvc/, so
|
||||
# NOTE: we are in the repo's root and config is in .dvc/, so
|
||||
# dir path written to config should be just one level above.
|
||||
rel = os.path.join("..", dname)
|
||||
config = configobj.ConfigObj(self.dvc.config.config_file)
|
||||
|
||||
@@ -6,7 +6,7 @@ import filecmp
|
||||
import collections
|
||||
|
||||
from dvc.main import main
|
||||
from dvc.project import Project
|
||||
from dvc.repo import Repo as DvcRepo
|
||||
from dvc.system import System
|
||||
from tests.basic_env import TestDvc
|
||||
from tests.test_repro import TestRepro
|
||||
@@ -73,7 +73,7 @@ class TestCheckoutCorruptedCacheDir(TestDvc):
|
||||
ret = main(["config", "cache.type", "copy"])
|
||||
self.assertEqual(ret, 0)
|
||||
|
||||
self.dvc = Project(".")
|
||||
self.dvc = DvcRepo(".")
|
||||
stages = self.dvc.add(self.DATA_DIR)
|
||||
self.assertEqual(len(stages), 1)
|
||||
self.assertEqual(len(stages[0].outs), 1)
|
||||
|
||||
+2
-2
@@ -137,13 +137,13 @@ class TestGC(TestDvc):
|
||||
self.assertIsInstance(args.func(args), CmdGC)
|
||||
|
||||
|
||||
class TestGCMultipleProjects(TestDvc):
|
||||
class TestGCMultipleDvcRepos(TestDvc):
|
||||
def test(self):
|
||||
args = parse_args(["gc", "-p", "/tmp/asdf", "/tmp/xyz"])
|
||||
|
||||
self.assertIsInstance(args.func(args), CmdGC)
|
||||
|
||||
self.assertEqual(args.projects, ["/tmp/asdf", "/tmp/xyz"])
|
||||
self.assertEqual(args.repos, ["/tmp/asdf", "/tmp/xyz"])
|
||||
|
||||
|
||||
class TestConfig(TestDvc):
|
||||
|
||||
@@ -258,7 +258,7 @@ class TestDataCloudBase(TestDvc):
|
||||
info_dir = stage_dir.outs[0].dumpd()
|
||||
md5_dir = info_dir["md5"]
|
||||
|
||||
with self.cloud.project.state:
|
||||
with self.cloud.repo.state:
|
||||
# Check status
|
||||
status = self.cloud.status([info], show_checksums=True)
|
||||
expected = {md5: {"name": md5, "status": STATUS_NEW}}
|
||||
|
||||
+10
-10
@@ -4,7 +4,7 @@ import configobj
|
||||
from git import Repo
|
||||
|
||||
from dvc.main import main
|
||||
from dvc.project import Project
|
||||
from dvc.repo import Repo as DvcRepo
|
||||
|
||||
from tests.basic_env import TestDvc
|
||||
from tests.basic_env import TestDir
|
||||
@@ -104,7 +104,7 @@ class TestGCBranchesTags(TestDvc):
|
||||
self._check_cache(1)
|
||||
|
||||
|
||||
class TestGCMultipleProjects(TestDvc):
|
||||
class TestGCMultipleDvcRepos(TestDvc):
|
||||
def _check_cache(self, num):
|
||||
total = 0
|
||||
for root, dirs, files in os.walk(os.path.join(".dvc", "cache")):
|
||||
@@ -112,10 +112,10 @@ class TestGCMultipleProjects(TestDvc):
|
||||
self.assertEqual(total, num)
|
||||
|
||||
def setUp(self):
|
||||
super(TestGCMultipleProjects, self).setUp()
|
||||
super(TestGCMultipleDvcRepos, self).setUp()
|
||||
self.additional_path = TestDir.mkdtemp()
|
||||
self.additional_git = Repo.init(self.additional_path)
|
||||
self.additional_dvc = Project.init(self.additional_path)
|
||||
self.additional_dvc = DvcRepo.init(self.additional_path)
|
||||
|
||||
cache_path = os.path.join(self._root_dir, ".dvc", "cache")
|
||||
config_path = os.path.join(
|
||||
@@ -126,14 +126,14 @@ class TestGCMultipleProjects(TestDvc):
|
||||
cfg["cache"] = {"dir": cache_path}
|
||||
cfg.write()
|
||||
|
||||
self.additional_dvc = Project(self.additional_path)
|
||||
self.additional_dvc = DvcRepo(self.additional_path)
|
||||
|
||||
def test(self):
|
||||
|
||||
# ADD FILE ONLY IN MAIN PROJECT
|
||||
fname = "only_in_first"
|
||||
with open(fname, "w+") as fobj:
|
||||
fobj.write("only in main project")
|
||||
fobj.write("only in main repo")
|
||||
|
||||
stages = self.dvc.add(fname)
|
||||
self.assertEqual(len(stages), 1)
|
||||
@@ -141,7 +141,7 @@ class TestGCMultipleProjects(TestDvc):
|
||||
# ADD FILE IN MAIN PROJECT THAT IS ALSO IN SECOND PROJECT
|
||||
fname = "in_both"
|
||||
with open(fname, "w+") as fobj:
|
||||
fobj.write("in both projects")
|
||||
fobj.write("in both repos")
|
||||
|
||||
stages = self.dvc.add(fname)
|
||||
self.assertEqual(len(stages), 1)
|
||||
@@ -151,7 +151,7 @@ class TestGCMultipleProjects(TestDvc):
|
||||
# ADD FILE ONLY IN SECOND PROJECT
|
||||
fname = os.path.join(self.additional_path, "only_in_second")
|
||||
with open(fname, "w+") as fobj:
|
||||
fobj.write("only in additional project")
|
||||
fobj.write("only in additional repo")
|
||||
|
||||
stages = self.additional_dvc.add(fname)
|
||||
self.assertEqual(len(stages), 1)
|
||||
@@ -159,7 +159,7 @@ class TestGCMultipleProjects(TestDvc):
|
||||
# ADD FILE IN SECOND PROJECT THAT IS ALSO IN MAIN PROJECT
|
||||
fname = os.path.join(self.additional_path, "in_both")
|
||||
with open(fname, "w+") as fobj:
|
||||
fobj.write("in both projects")
|
||||
fobj.write("in both repos")
|
||||
|
||||
stages = self.additional_dvc.add(fname)
|
||||
self.assertEqual(len(stages), 1)
|
||||
@@ -168,7 +168,7 @@ class TestGCMultipleProjects(TestDvc):
|
||||
|
||||
self._check_cache(3)
|
||||
|
||||
self.dvc.gc(projects=[self.additional_path])
|
||||
self.dvc.gc(repos=[self.additional_path])
|
||||
self._check_cache(3)
|
||||
|
||||
self.dvc.gc()
|
||||
|
||||
+9
-8
@@ -1,18 +1,19 @@
|
||||
import os
|
||||
|
||||
from dvc.main import main
|
||||
from dvc.project import Project, InitError
|
||||
from dvc.repo import Repo as DvcRepo
|
||||
from dvc.exceptions import InitError
|
||||
|
||||
from tests.basic_env import TestGit, TestDir
|
||||
|
||||
|
||||
class TestInit(TestGit):
|
||||
def _test_init(self):
|
||||
self.assertTrue(os.path.exists(Project.DVC_DIR))
|
||||
self.assertTrue(os.path.isdir(Project.DVC_DIR))
|
||||
self.assertTrue(os.path.exists(DvcRepo.DVC_DIR))
|
||||
self.assertTrue(os.path.isdir(DvcRepo.DVC_DIR))
|
||||
|
||||
def test_api(self):
|
||||
Project.init()
|
||||
DvcRepo.init()
|
||||
|
||||
self._test_init()
|
||||
|
||||
@@ -41,7 +42,7 @@ class TestDoubleInit(TestInit):
|
||||
class TestInitNoSCMFail(TestDir):
|
||||
def test_api(self):
|
||||
with self.assertRaises(InitError):
|
||||
Project.init()
|
||||
DvcRepo.init()
|
||||
|
||||
def test_cli(self):
|
||||
ret = main(["init"])
|
||||
@@ -50,11 +51,11 @@ class TestInitNoSCMFail(TestDir):
|
||||
|
||||
class TestInitNoSCM(TestDir):
|
||||
def _test_init(self):
|
||||
self.assertTrue(os.path.exists(Project.DVC_DIR))
|
||||
self.assertTrue(os.path.isdir(Project.DVC_DIR))
|
||||
self.assertTrue(os.path.exists(DvcRepo.DVC_DIR))
|
||||
self.assertTrue(os.path.isdir(DvcRepo.DVC_DIR))
|
||||
|
||||
def test_api(self):
|
||||
Project.init(no_scm=True)
|
||||
DvcRepo.init(no_scm=True)
|
||||
|
||||
self._test_init()
|
||||
|
||||
|
||||
+15
-15
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
import json
|
||||
|
||||
from dvc.project import Project
|
||||
from dvc.repo import Repo as DvcRepo
|
||||
from dvc.main import main
|
||||
from dvc.exceptions import DvcException
|
||||
from tests.basic_env import TestDvc
|
||||
@@ -53,13 +53,13 @@ class TestMetrics(TestDvc):
|
||||
self.dvc.scm.checkout("master")
|
||||
|
||||
def test(self):
|
||||
ret = self.dvc.metrics_show("metric", all_branches=True)
|
||||
ret = self.dvc.metrics.show("metric", all_branches=True)
|
||||
self.assertEqual(len(ret), 3)
|
||||
self.assertTrue(ret["foo"]["metric"] == "foo")
|
||||
self.assertTrue(ret["bar"]["metric"] == "bar")
|
||||
self.assertTrue(ret["baz"]["metric"] == "baz")
|
||||
|
||||
ret = self.dvc.metrics_show(
|
||||
ret = self.dvc.metrics.show(
|
||||
"metric_json", typ="json", xpath="branch", all_branches=True
|
||||
)
|
||||
self.assertEqual(len(ret), 3)
|
||||
@@ -67,7 +67,7 @@ class TestMetrics(TestDvc):
|
||||
self.assertTrue(ret["bar"]["metric_json"] == ["bar"])
|
||||
self.assertTrue(ret["baz"]["metric_json"] == ["baz"])
|
||||
|
||||
ret = self.dvc.metrics_show(
|
||||
ret = self.dvc.metrics.show(
|
||||
"metric_tsv", typ="tsv", xpath="0,0", all_branches=True
|
||||
)
|
||||
self.assertEqual(len(ret), 3)
|
||||
@@ -75,7 +75,7 @@ class TestMetrics(TestDvc):
|
||||
self.assertTrue(ret["bar"]["metric_tsv"] == ["bar"])
|
||||
self.assertTrue(ret["baz"]["metric_tsv"] == ["baz"])
|
||||
|
||||
ret = self.dvc.metrics_show(
|
||||
ret = self.dvc.metrics.show(
|
||||
"metric_htsv", typ="htsv", xpath="branch,0", all_branches=True
|
||||
)
|
||||
self.assertEqual(len(ret), 3)
|
||||
@@ -83,7 +83,7 @@ class TestMetrics(TestDvc):
|
||||
self.assertTrue(ret["bar"]["metric_htsv"] == ["bar"])
|
||||
self.assertTrue(ret["baz"]["metric_htsv"] == ["baz"])
|
||||
|
||||
ret = self.dvc.metrics_show(
|
||||
ret = self.dvc.metrics.show(
|
||||
"metric_csv", typ="csv", xpath="0,0", all_branches=True
|
||||
)
|
||||
self.assertEqual(len(ret), 3)
|
||||
@@ -91,7 +91,7 @@ class TestMetrics(TestDvc):
|
||||
self.assertTrue(ret["bar"]["metric_csv"] == ["bar"])
|
||||
self.assertTrue(ret["baz"]["metric_csv"] == ["baz"])
|
||||
|
||||
ret = self.dvc.metrics_show(
|
||||
ret = self.dvc.metrics.show(
|
||||
"metric_hcsv", typ="hcsv", xpath="branch,0", all_branches=True
|
||||
)
|
||||
self.assertEqual(len(ret), 3)
|
||||
@@ -145,12 +145,12 @@ class TestMetricsRecursive(TestDvc):
|
||||
|
||||
def test(self):
|
||||
|
||||
ret = self.dvc.metrics_show(
|
||||
ret = self.dvc.metrics.show(
|
||||
"nested", all_branches=True, recursive=False
|
||||
)
|
||||
self.assertEqual(len(ret), 0)
|
||||
|
||||
ret = self.dvc.metrics_show(
|
||||
ret = self.dvc.metrics.show(
|
||||
"nested", all_branches=True, recursive=True
|
||||
)
|
||||
self.assertEqual(len(ret), 1)
|
||||
@@ -334,7 +334,7 @@ class TestMetricsCLI(TestMetrics):
|
||||
|
||||
with self.assertRaises(DvcException):
|
||||
self.dvc.run(outs_no_cache=["metrics_dir"])
|
||||
self.dvc.metrics_add("metrics_dir")
|
||||
self.dvc.metrics.add("metrics_dir")
|
||||
|
||||
def test_binary(self):
|
||||
with open("metrics_bin", "w+") as fd:
|
||||
@@ -342,7 +342,7 @@ class TestMetricsCLI(TestMetrics):
|
||||
|
||||
with self.assertRaises(DvcException):
|
||||
self.dvc.run(outs_no_cache=["metrics_bin"])
|
||||
self.dvc.metrics_add("metrics_bin")
|
||||
self.dvc.metrics.add("metrics_bin")
|
||||
|
||||
def test_non_existing(self):
|
||||
ret = main(["metrics", "add", "non-existing"])
|
||||
@@ -370,7 +370,7 @@ class TestCachedMetrics(TestDvc):
|
||||
json.dump({"metrics": branch}, fd)
|
||||
|
||||
stages = self.dvc.add("metrics.json")
|
||||
self.dvc.metrics_add("metrics.json", typ="json", xpath="metrics")
|
||||
self.dvc.metrics.add("metrics.json", typ="json", xpath="metrics")
|
||||
self.assertEqual(len(stages), 1)
|
||||
stage = stages[0]
|
||||
self.assertIsNotNone(stage)
|
||||
@@ -413,9 +413,9 @@ class TestCachedMetrics(TestDvc):
|
||||
func("one")
|
||||
func("two")
|
||||
|
||||
self.dvc = Project(".")
|
||||
self.dvc = DvcRepo(".")
|
||||
|
||||
res = self.dvc.metrics_show(
|
||||
res = self.dvc.metrics.show(
|
||||
"metrics.json", all_branches=True, typ="json", xpath="metrics"
|
||||
)
|
||||
|
||||
@@ -428,7 +428,7 @@ class TestCachedMetrics(TestDvc):
|
||||
},
|
||||
)
|
||||
|
||||
res = self.dvc.metrics_show(
|
||||
res = self.dvc.metrics.show(
|
||||
"", all_branches=True, typ="json", xpath="metrics"
|
||||
)
|
||||
|
||||
|
||||
+2
-2
@@ -51,9 +51,9 @@ class TestCmdMove(TestDvc):
|
||||
|
||||
class TestMoveNotDataSource(TestRepro):
|
||||
def test(self):
|
||||
from dvc.project import Project
|
||||
from dvc.repo import Repo as DvcRepo
|
||||
|
||||
self.dvc = Project(self._root_dir)
|
||||
self.dvc = DvcRepo(self._root_dir)
|
||||
with self.assertRaises(MoveNotDataSourceError):
|
||||
self.dvc.move(self.file1, "dst")
|
||||
|
||||
|
||||
@@ -234,7 +234,7 @@ class TestPipelineListSingle(TestPipelineShowDeep):
|
||||
self.assertEqual(ret, 0)
|
||||
|
||||
|
||||
class TestProjectPipeline(TestDvc):
|
||||
class TestDvcRepoPipeline(TestDvc):
|
||||
def test_no_stages(self):
|
||||
pipelines = self.dvc.pipelines()
|
||||
self.assertEqual(len(pipelines), 0)
|
||||
|
||||
@@ -51,7 +51,7 @@ class TestRemote(TestDvc):
|
||||
ret = main(["remote", "add", "mylocal", dname])
|
||||
self.assertEqual(ret, 0)
|
||||
|
||||
# NOTE: we are in the project's root and config is in .dvc/, so
|
||||
# NOTE: we are in the repo's root and config is in .dvc/, so
|
||||
# dir path written to config should be just one level above.
|
||||
rel = os.path.join("..", dname)
|
||||
config = configobj.ConfigObj(self.dvc.config.config_file)
|
||||
|
||||
+12
-8
@@ -15,13 +15,17 @@ from google.cloud import storage as gc
|
||||
from flaky.flaky_decorator import flaky
|
||||
|
||||
from dvc.main import main
|
||||
from dvc.project import Project, ReproductionError
|
||||
from dvc.repo import Repo as DvcRepo
|
||||
from dvc.utils import file_md5
|
||||
from dvc.utils.compat import urljoin
|
||||
from dvc.remote.local import RemoteLOCAL
|
||||
from dvc.stage import Stage, StageFileDoesNotExistError
|
||||
from dvc.system import System
|
||||
from dvc.exceptions import CyclicGraphError, WorkingDirectoryAsOutputError
|
||||
from dvc.exceptions import (
|
||||
CyclicGraphError,
|
||||
WorkingDirectoryAsOutputError,
|
||||
ReproductionError,
|
||||
)
|
||||
|
||||
from tests.basic_env import TestDvc
|
||||
from tests.test_data_cloud import _should_test_aws, TEST_AWS_REPO_BUCKET
|
||||
@@ -160,7 +164,7 @@ class TestReproWorkingDirectoryAsOutput(TestDvc):
|
||||
|
||||
# NOTE: os.walk() walks in a sorted order and we need dir2 subdirs to
|
||||
# be processed before dir1 to load error.dvc first.
|
||||
with patch.object(Project, "stages") as mock_stages:
|
||||
with patch.object(DvcRepo, "stages") as mock_stages:
|
||||
mock_stages.return_value = [
|
||||
nested_stage,
|
||||
Stage.load(self.dvc, error_stage_path),
|
||||
@@ -582,11 +586,11 @@ class TestReproMetricsAddUnchanged(TestDvc):
|
||||
stages = self.dvc.reproduce(file1_stage)
|
||||
self.assertEqual(len(stages), 0)
|
||||
|
||||
self.dvc.metrics_add(file1)
|
||||
self.dvc.metrics.add(file1)
|
||||
stages = self.dvc.reproduce(file1_stage)
|
||||
self.assertEqual(len(stages), 0)
|
||||
|
||||
self.dvc.metrics_remove(file1)
|
||||
self.dvc.metrics.remove(file1)
|
||||
stages = self.dvc.reproduce(file1_stage)
|
||||
self.assertEqual(len(stages), 0)
|
||||
|
||||
@@ -856,7 +860,7 @@ class TestReproExternalBase(TestDvc):
|
||||
ret = main(["remote", "modify", remote_name, "type", "hardlink"])
|
||||
self.assertEqual(ret, 0)
|
||||
|
||||
self.dvc = Project(".")
|
||||
self.dvc = DvcRepo(".")
|
||||
|
||||
foo_key = remote_key + self.sep + self.FOO
|
||||
bar_key = remote_key + self.sep + self.BAR
|
||||
@@ -1079,7 +1083,7 @@ class TestReproExternalLOCAL(TestReproExternalBase):
|
||||
self.tmpdir = TestDvc.mkdtemp()
|
||||
ret = main(["config", "cache.type", "hardlink"])
|
||||
self.assertEqual(ret, 0)
|
||||
self.dvc = Project(".")
|
||||
self.dvc = DvcRepo(".")
|
||||
|
||||
def should_test(self):
|
||||
return True
|
||||
@@ -1148,7 +1152,7 @@ class TestReproExternalHTTP(TestReproExternalBase):
|
||||
self.assertEqual(ret1, 0)
|
||||
self.assertEqual(ret2, 0)
|
||||
|
||||
self.dvc = Project(".")
|
||||
self.dvc = DvcRepo(".")
|
||||
|
||||
# Import
|
||||
with StaticFileServer():
|
||||
|
||||
@@ -18,7 +18,7 @@ class TestMissingDeps(TestCase):
|
||||
class TestCmdError(TestCase):
|
||||
def test(self):
|
||||
for remote_class in [RemoteSSH, RemoteHDFS]:
|
||||
project = None
|
||||
repo = None
|
||||
config = {}
|
||||
|
||||
remote_name = remote_class.scheme
|
||||
@@ -32,4 +32,4 @@ class TestCmdError(TestCase):
|
||||
side_effect=RemoteCmdError(remote_name, cmd, ret, err),
|
||||
):
|
||||
with self.assertRaises(RemoteCmdError):
|
||||
remote_class(project, config).remove("file")
|
||||
remote_class(repo, config).remove("file")
|
||||
|
||||
Reference in New Issue
Block a user