Compare commits

...
696 Commits
Author SHA1 Message Date
Peter Rowlands 761422638f output: add progress for commit 2023-08-03 18:19:19 +09:00
Peter Rowlands d01e2355d4 push/pull: generate explicit progress bars for dvc-data transfers 2023-08-03 18:19:19 +09:00
Peter Rowlands aa94bfd66b deps: bump dvc-data to 2.9.1 2023-08-03 18:19:19 +09:00
skshetry b9b9f91084 ruff: enable autofix (#9790) 2023-08-03 11:08:29 +05:45
Ruslan Kuprieiev 8a382f51fd deps: bump dvc-data to 2.9.0 2023-08-03 02:05:14 +03:00
Ruslan Kuprieiev b235487ecc ls/import/get: introduce --remote and --remote-config
Fixes #9656
2023-08-02 16:28:16 +03:00
pre-commit-ci[bot]andSaugat Pachhai 502b3df6c9 [pre-commit.ci] pre-commit autoupdate (#9756)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/asottile/pyupgrade: v3.9.0 → v3.10.1](https://github.com/asottile/pyupgrade/compare/v3.9.0...v3.10.1)
- [github.com/astral-sh/ruff-pre-commit: v0.0.278 → v0.0.281](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.278...v0.0.281)
- [github.com/PyCQA/flake8: 6.0.0 → 6.1.0](https://github.com/PyCQA/flake8/compare/6.0.0...6.1.0)

* fix issues reported by ruff

- also remove redundant flake8 plugins
- remove beautysh as we don't have any scripts now
- remove pyupgrade as it is redundant due to ruff

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Saugat Pachhai (सौगात) <[email protected]>
2023-08-02 18:08:30 +05:45
dependabot[bot] 5c2fd67e6d build(deps-dev): bump pylint from 2.17.4 to 2.17.5 (#9769)
Bumps [pylint](https://github.com/pylint-dev/pylint) from 2.17.4 to 2.17.5.
- [Release notes](https://github.com/pylint-dev/pylint/releases)
- [Commits](https://github.com/pylint-dev/pylint/compare/v2.17.4...v2.17.5)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-31 16:35:40 +05:45
Fabian Zills ed34c0f0bd dvc commit update description (#9760)
* Update commit.py

* fix formatting
2023-07-31 08:45:52 +00:00
Ruslan Kuprieiev 7c60dfd3c5 deps: bump dvc-data to >=2.8.1 2023-07-30 04:18:09 +03:00
Ruslan Kuprieiev 225814fdde dvc: don't use realpath where not needed 2023-07-30 02:24:00 +03:00
Ruslan Kuprieiev ca0ad239f7 deps: bump dvc-data to 0.28.0 2023-07-28 01:37:46 +03:00
Ruslan Kuprieiev f57ac609e9 deps: bump dvc-data to 0.27.1 2023-07-27 20:44:34 +03:00
Ruslan Kuprieiev cc4f505f99 api: open/read: introduce remote_config 2023-07-26 16:29:14 +03:00
Ruslan Kuprieiev 4d011718a6 out: str: don't try to relpath paths outside of the repo
This is not very useful overall, but also results in a ValueError from
relpath on windows if your repo and output are on different drives.
2023-07-25 23:49:27 +03:00
Ruslan Kuprieiev 9c89841637 fetch: support passing config
For now not exposing it in CLI since there is no need/use yet.

Requirement for https://github.com/iterative/studio/pull/6541
2023-07-25 20:03:38 +03:00
Peter Rowlands 92cae74512 exp.collect: strip metrics from queued experiments 2023-07-25 20:57:15 +09:00
Ruslan Kuprieiev 73dad4780f repo: brancher: reset parsed fields
Related #9754 and fixes `dvc fetch`.
2023-07-25 14:00:33 +03:00
Ruslan Kuprieiev 65ba9ba527 fs: get_cloud_fs: accept config instead of repo
Config is a more immutable thing and using `repo` is confusing and might be error
prone in the bigger picture.

Related to #9754
2023-07-25 00:58:47 +03:00
Peter Rowlands 7806afd4ad fs: prefer generic.copy over fsspec fs.get() 2023-07-24 17:01:34 +09:00
Ivan Shcheklein a9d0ac2ba9 fix(exceptions): add parent ctr init in InvalidArgumentError 2023-07-21 08:27:53 +02:00
Ruslan Kuprieiev 41df96fcdb cli: ls/import/get: fix help
Leftover from https://github.com/iterative/dvc/pull/9747
2023-07-20 21:53:14 +03:00
Ruslan Kuprieiev 53ec0fa41d ls/import/get: introduce --config
Adds support for `--config` to all three commands. For `ls` and `get`, it is
a purely runtime option that will merge the config you provide with target
repo's configs (similar to how .dvc/config.local works). E.g.

```
$ cat myconfig
[remote "myremote"]
    access_key_id = 12345
    secret_access_key = 98765

$ dvc get https://github.com/efiop/mydataregistry recent-grads.csv --config myconfig
```

In case of `dvc import`, the semantics are the same, but the value is also
recorded in the resulting dvcfile. E.g.

```
$ dvc import https://github.com/efiop/mydataregistry recent-grads.csv --config myconfig
...
$ cat recent-grads.csv.dvc
md5: 85c86eeb3afa6d1f7d11beedc644d28e
frozen: true
deps:
- path: recent-grads.csv
  repo:
    url: https://github.com/efiop/mydataregistry
    config: myconfig
    rev_lock: af22e06bbfe34d62a140437abf32f48b535944a7
outs:
- md5: f447e23a170a9f25a7799f069a1ba934
  size: 26872
  hash: md5
  path: recent-grads.csv
```

This is the most general and powerful mechanism that we can give, that works
for everything from reconfiguring your default remote to completely changing
your remote layout and beyond (will be handy in the future).

Fixes #2466
2023-07-20 18:41:10 +03:00
Dave BerenbaumandRuslan Kuprieiev 41194b7975 dvcfs: handle NotADirectoryError from datafs.ls (#9746)
* dvc_fs: ignore NotADirectoryError in ls

* deps: bump dvc-data to >= 2.6.0

* add test

---------

Co-authored-by: Ruslan Kuprieiev <[email protected]>
2023-07-19 20:54:55 +03:00
skshetry ea5f7d40c1 ruff: enable a few more rules, and merge tests' config with the main config (#9739) 2023-07-15 14:33:34 +05:45
dependabot[bot] eb06351062 build(deps-dev): bump mypy from 1.3.0 to 1.4.1 (#9664)
Bumps [mypy](https://github.com/python/mypy) from 1.3.0 to 1.4.1.
- [Commits](https://github.com/python/mypy/compare/v1.3.0...v1.4.1)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-14 20:30:47 +05:45
pre-commit-ci[bot]andSaugat Pachhai ca3704997b [pre-commit.ci] pre-commit autoupdate (#9632)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/asottile/pyupgrade: v3.3.1 → v3.9.0](https://github.com/asottile/pyupgrade/compare/v3.3.1...v3.9.0)
- https://github.com/charliermarsh/ruff-pre-commit → https://github.com/astral-sh/ruff-pre-commit
- [github.com/astral-sh/ruff-pre-commit: v0.0.261 → v0.0.277](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.261...v0.0.277)
- [github.com/codespell-project/codespell: v2.2.4 → v2.2.5](https://github.com/codespell-project/codespell/compare/v2.2.4...v2.2.5)

* fix ruff complaints

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Saugat Pachhai (सौगात) <[email protected]>
2023-07-14 20:11:15 +05:45
Saugat Pachhai (सौगात) f1764bdc77 stage add: remove --external 2023-07-14 15:38:57 +03:00
skshetry eb212a7ba3 repro: introduce --keep-going/--ignore to continue on error (#9712)
* repro: introduce --keep-going/--ignore to continue on error

`-k`/`--keep-going` will skip all dependents of a stage if it fails.
It'll still try to reproduce the other dependencies of the pending
targets, before it exits with a non-zero status.

`--ignore-errors` will treat any error during stage execution as a
success, and will continue executing other dependencies as if it
succeeded. Exits with 0 even on failure.

Also fixes:
* --force-downstream used to force everything even if one upstream nodes changed.
  This used to work when we supported a single targets, but there could be independent
  pipelines, so  we should not force everything if any node changes.
  Now we'll force reproduce the stage only if one of its dependency changed upstream
  or it's upstream node was also forced.

* Makes `--downstream` more correct, in relation to `--allow-missing` and `--pull`.
  Now we use an active graph for downstream/upstream logic instead of a subgraph.
  Note that this does not affect the downstream logic though, as dvc always goes
  downstream, so subgraph was no different than active graph.
  The subgraph only did not have the upstream nodes.

* add tests

* add spacing in the message
2023-07-12 21:52:41 +05:45
skshetry 4c8f539c56 plots: log failures during datapoint conversions (#9726)
Fixes #9441.

Note that we do merge props, and use that for all revision. So you may
see warning for multiple revisions.
2023-07-12 19:14:31 +05:45
skshetry 45aefc8423 parsing: pass config instead of loading every time (#9729) 2023-07-12 17:22:42 +05:45
Peter Rowlands 67a747a356 stage.cache: override both legacy+local cache link types on save/commit 2023-07-12 17:17:49 +09:00
Peter Rowlands a5dda1b8ad open_repo: return without entering context for both local and erepo 2023-07-12 14:45:11 +09:00
Peter Rowlands dd4035bc05 repo: add get_data_index_entry to handle subrepo lookup 2023-07-12 14:45:11 +09:00
Peter Rowlands f69b3533e4 erepo: drop dvcx for_write support 2023-07-12 14:45:11 +09:00
Ruslan Kuprieiev 1b2291ca83 fetch: catch collection errors in revisions
https://github.com/iterative/studio/pull/6541
2023-07-11 04:03:26 +03:00
Ruslan Kuprieiev 4de4f0fd65 fetch: introduce --type metrics/plots
Needed for https://github.com/iterative/studio/pull/6541 but is also generally useful.
2023-07-10 15:24:30 +03:00
Ruslan Kuprieiev 2ef2caafd3 deps: bump dvc-data to 2.5.0 2023-07-09 20:30:35 +03:00
Ruslan Kuprieiev adcefbec66 output: pass explicit callback to hashfile.build() 2023-07-09 17:40:49 +03:00
Ruslan Kuprieiev 2102ba8465 output: fix formatting (#9716)
Regression from https://github.com/iterative/dvc/pull/9715
2023-07-09 19:50:00 +05:45
skshetry d736d0a3ef output: checkout: use f-string (#9715)
Regression from https://github.com/iterative/dvc/pull/9673.
2023-07-09 11:49:22 +05:45
dberenbaum 0d1f1f6436 update link for external data sources 2023-07-05 19:42:07 +03:00
Ruslan Kuprieiev 63de16ced1 readme: point to dvc.org for packages
We no longer attach bin packages to github releases, so old link is completely misleading.
2023-07-04 18:47:32 +03:00
Ruslan Kuprieiev 2f6c308c84 repo: site_cache_dir: take major version into account
So that different major dvc versions don't use the same cache path.
2023-07-04 18:24:20 +03:00
skshetry c8d180d2b0 repro: move code around (#9701)
emphasizing on building the graph correctly,
and preparing for being able to work with graph directly.
2023-07-04 21:02:53 +05:45
skshetry d69972d199 repro: ignore --downstream if used together with --pipeline (#9692)
* repro: no need to build pipelines for --all-pipeline

* repro: ignore --downstream when using --pipeline
2023-07-04 19:03:09 +05:45
Peter Rowlands eb1ed40228 repo.open_repo: use abspath for local fs URL 2023-07-04 12:28:09 +03:00
Peter Rowlands 120289128e dvcfs: cleanup subrepo contexts on close() 2023-07-04 12:28:09 +03:00
Peter Rowlands a607e7b3d7 dvcfs: return md5-dos2unix in info 2023-07-04 12:28:09 +03:00
Peter Rowlands 86e199c6f2 api.get_url: use index remote storage for getting remote URL 2023-07-04 12:28:09 +03:00
Ruslan Kuprieiev 8661abf224 fetch: introduce --max-size (#9696)
Needed for iterative/studio#4782
2023-07-04 02:17:53 +03:00
Jon Crallandskshetry 541def388b environment variable to show debug options (#9693)
* environment variable to show debug options

* lint

[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Add message to debug opts

* spelling

* Add argument group and move cprofile-dump

line length

linelen

lint

* use DVC_DEBUG instead of DVC_SHOW_DEBUG_OPTIONS

* use -v instead of environ

* Update dvc/_debug.py

Co-authored-by: skshetry <[email protected]>

* fix

---------

Co-authored-by: skshetry <[email protected]>
2023-07-04 01:35:33 +03:00
Ruslan Kuprieiev 58eb145b6a Delete hook-google_compute_engine.logger.py 2023-07-03 22:13:22 +03:00
Ruslan Kuprieiev 16465e0b63 Delete hook-dvc.system.py 2023-07-03 22:13:22 +03:00
Ruslan Kuprieiev 6614efd35a Delete hook-dvc.tree.gs.py 2023-07-03 22:13:22 +03:00
skshetry 2becfd9344 refactor repro: split logic for planning stages to run for repro (#9690)
The planning logic has now been moved to `plan_repro` api, that allows us
to test without creating stages.
2023-07-03 17:53:48 +05:45
skshetry b7b6642428 repro: do not autostage stage files (#9689)
The logic is now moved to experiments, where it tracks all the stage related files
itself. The `_get_stage_files()` has been modified to also return lockfile path,
so that it can be staged, and has been moved to `stage/utils.py`, and out of `reproduce.py`.

Fixes #9688.
2023-07-03 14:42:22 +05:45
skshetry fea2e6bb30 repro: simplify _reproduce_stages (#9687) 2023-07-03 12:25:25 +05:45
skshetry bfa5b1a0c3 repro: make stages run in order of the graph (#9675)
* repro: make stages run in order of the graph.

In case of --single-item, this means it'll run in the order of arguments passed.
For --downstream, this fixes running of stage out of order when multiple arguments are passed.
For normal case, this enforces the same logic, so that they are never run out-of-order.

* add tests

* tests: repro: add test for --single-item with multiple targets

* graph: support when no nodes are provided
2023-07-03 11:44:51 +05:45
Peter Rowlands 24d9a05d69 fetch: warn if cloud-versioned file has no version ID 2023-07-03 14:05:15 +09:00
skshetry 1f31a9c696 bandit: add exclusion for dvc/repo/experiments/utils.py back (#9686)
See https://github.com/PyCQA/bandit/pull/940.

Will not be needed when new version of bandit comes.
2023-07-03 09:56:45 +05:45
skshetry 097e48fcc9 remove scripts/ related suppresses (#9685) 2023-07-03 09:46:27 +05:45
skshetry 453a8f9516 ci: use kebab-case (#9684) 2023-07-03 09:16:53 +05:45
skshetry 9f59d8652e remove build scripts and scripts directory (#9683) 2023-07-03 09:05:06 +05:45
Ruslan Kuprieiev b1834f34e7 deps: limit flufl-lock to <8 (#9681)
Looks like flufl-lock switched to pdm in 8.0 which triggered a

```
pkg_resources.DistributionNotFound: The 'flufl.lock>=5' distribution was not found and is required by dvc
```

error in multiple scenarious. Can't put my finger on anything specific
in flufl-lock yet, so will just limit its version for now.

Fixes https://github.com/iterative/dvc/issues/9654
2023-07-03 03:13:50 +03:00
Ruslan Kuprieiev 536273ab1e build: pyinstaller: use __pyinstaller (#9680) 2023-07-03 01:47:31 +03:00
Ruslan Kuprieiev 5cff4891fd deps: bump dvc-data to >=2.3.2 (#9679)
Fixes #9462
Fixes #9512
2023-07-02 23:09:27 +03:00
Jon Crall e29da6eae1 Add doctest for dagascii.draw (#9678) 2023-07-01 20:36:14 +03:00
Ruslan Kuprieiev 046ebb05dd stage: cache: catch CollectCacheError (#9677) 2023-07-01 02:19:52 +03:00
skshetry 36ec25ffd7 repro: remove on_unchanged kwarg and _repro_callback (#9674)
repro: remove on_unchaged kwarg and _repro_callback
2023-06-30 10:05:44 +05:45
Ruslan Kuprieiev 6e6d9253d6 output: use path instead of relpath (#9673)
Relpath might not exist (e.g. on windows between different drives),
we should just use path as is and not get too fancy with the ui,
unless we want to constantly keep ValueError in mind when using
relpath for ui needs all over the place.

These operations should use index, where we always have current
directory and relative paths, so the ui will change accordingly
anyway.
2023-06-29 14:52:49 +03:00
Ruslan Kuprieievandpre-commit-ci[bot] 910c232077 output: save: error out on cached external outputs (#9672)
* output: save: error out on cached external outputs

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-06-29 13:05:17 +03:00
skshetry c90947f33c make it a dvc repo (#9670) 2023-06-29 08:50:03 +05:45
Peter Rowlands 4ee4f137f2 exp pull: update for index fetch 2023-06-26 14:09:24 +09:00
Oded Messer a750a75016 Stable experiment range sorting (#9660)
* secondary sorting by rev alphanumerically. to introduce determinism

* add UT
2023-06-26 10:53:39 +09:00
Ruslan Kuprieiev cf976f17ae data: status: use ui.progress instead of ui.status (#9662)
With all fetch and checkout related things that we've done in the recent past,
we now have all the mechanisms necessary to provide actual progress (no total,
but still better than spinner) during `dvc data status` operations.
2023-06-26 00:10:44 +03:00
Ruslan Kuprieiev 7041fa5f42 checkout: use ui.progress (#9661)
* fs: callbacks: create our own TqdmCallback

We have a near identical implementation in dvc-objects, but this one is
meant to work with our Tqdm progress instance.

dvc-objects one is useful on other levels, but dvc should have itsown
that inherits from dvc-objects' Callback.

* progress: add as_callback

* checkout: use ui.progress
2023-06-25 23:14:49 +03:00
Ruslan Kuprieiev d898877175 checkout: use single tics instead of curly braces (#9659)
Typo during recent changes 🤦 

Related https://github.com/iterative/dvc/issues/9658
2023-06-24 00:06:05 +03:00
skshetry 1ca1d78b38 deps: bump gdrive to 2.20 (#9657) 2023-06-23 09:13:35 +05:45
David de la Iglesia Castro da6ebdbf8c Update schema.py 2023-06-23 00:10:11 +09:00
Peter Rowlands e995492095 output: check legacy hash name in output.add() 2023-06-22 22:21:34 +09:00
Peter Rowlands 276d499c9b deps: bump scmrepo minver 2023-06-22 22:04:16 +09:00
skshetry fd4696cc50 Revert "drop stage-level vars" (#9647)
Revert "drop stage-level vars (#9556)"

This reverts commit 358c5e0c39.
2023-06-22 18:44:51 +05:45
Peter Rowlands 90b9193250 output: preserve legacy hash_name on save() for unchanged data 2023-06-22 16:20:56 +09:00
Ruslan Kuprieiev 77e35145a9 checkout: delete output if we can't create it fully (#9642) 2023-06-22 02:54:53 +03:00
Dave Berenbaum 49c7c55ba3 exp: push/pull --rev help text shows default val (#9636) 2023-06-21 02:05:50 +03:00
Dave BerenbaumandRuslan Kuprieiev f28d5ee9e0 output: set remove to recursive=false (#9574)
* output: set remove to recursive=false

* try to make test pass on windows

* Update dvc/output.py

---------

Co-authored-by: Ruslan Kuprieiev <[email protected]>
2023-06-21 01:33:04 +03:00
Ruslan Kuprieiev 621fe07a3b checkout: friendlier UI when tryint to remove uncached files
Related #9618
2023-06-20 21:09:00 +03:00
Ruslan Kuprieiev 8323923ce9 deps: bump dvc-data to >= 2.1.1 2023-06-20 18:29:52 +03:00
dberenbaum 04b50c5cd0 exp push/pull: default to head rev 2023-06-20 15:53:46 +09:00
dberenbaum b20a59d748 exp push/pull: default to all exps on head 2023-06-20 15:53:46 +09:00
dberenbaum bf2f08da09 exp list: fix ui for tags/branches 2023-06-20 15:52:18 +09:00
Ruslan Kuprieiev 1835c8c6e9 tests: unit: explicitly ask for dvc repo
Currently these rely on the root of the repo being in the dvc repo.
2023-06-19 03:44:10 +03:00
Ruslan Kuprieiev 7e1bb07f10 gha: don't build binary packages
The build process is much more stable these days and there is no reason
to keep building these packages here. Instead every package has itsown
building process (dvc-osxpkg, dvc-exe, dvc-s3-repo) and knows best how
to build and sign correctly.

pyinstaller hooks need to go into a `__pyinstaller` later on.
2023-06-19 03:04:04 +03:00
Ruslan Kuprieiev 92dc1f31f5 outputs: is_in_repo: don't try to realpath fs_path
Fixes #9621
2023-06-19 01:19:46 +03:00
Ruslan Kuprieiev e16c0c8b2f checkout/fetch: finer control over steps
See https://github.com/iterative/dvc-data/pull/390 and https://github.com/iterative/dvc-data/pull/391
2023-06-18 18:58:30 +03:00
Ruslan Kuprieiev 33e7645603 tests: odb: index: simplify test
For some unknown reason the mock in this test leaks into the outside tests.

I wasn't able to determine why in the reasonable amount of time, so instead just
simplifying it to not use mocker at all.

That whole file should really be migrated to dvc-data, but that needs some time.
2023-06-18 18:58:30 +03:00
Ruslan Kuprieiev c827654fe7 tests: use mocker instead of unittest.mock where possible
Had the "pleasure" of finding a mocker.patch leak into other tests and one
of the suspicions is that mixing unittest.mock and mocker might be somehow
related.

In any case, we should use mocker where possible anyway.
2023-06-18 17:10:45 +03:00
dberenbaum b8c666b1b7 exp show: quick fix for handling defaultdict in py<3.11.0 2023-06-16 22:54:40 +03:00
Ruslan Kuprieiev fd73b389c6 api: show/exp: add config option
Fixes #9613
2023-06-16 17:09:38 +03:00
Ruslan Kuprieiev 0433565f1f api: add config support for open/read
Fixes #9610
2023-06-15 18:30:14 +03:00
Peter Rowlands b5449503f0 benchmarks: update min dvc version for test_exp_show 2023-06-15 12:58:21 +09:00
Peter Rowlands fa14507bc8 benchmarks: use bench_dvc for commands that generate dvcfiles 2023-06-15 10:44:58 +09:00
Peter Rowlands 21458796ed benchmarks: update test_exp_show to use example-get-started 2023-06-15 10:44:58 +09:00
Ruslan Kuprieiev a6e49a72de diff: handle revisions pointing to the same sha
Fixes #9604
2023-06-14 18:48:18 +03:00
Ruslan Kuprieiev 97348cfba7 Revert "checkout/fetch: finer control over steps"
This reverts commit c5e3d42899.
2023-06-14 03:39:43 +03:00
Ruslan Kuprieiev c5e3d42899 checkout/fetch: finer control over steps
See https://github.com/iterative/dvc-data/pull/390 and https://github.com/iterative/dvc-data/pull/391
2023-06-13 23:11:14 +03:00
skshetry c6c2ce130a remove dvc._build (#9597) 2023-06-13 20:31:22 +05:45
skshetry be975ad9eb pyproject.toml: reformat project table (#9596) 2023-06-13 20:02:34 +05:45
daavoo d0aa1ce776 repro: Check for hash mismatch bewteen deleted dependencies and upstream outputs.
Only if `--allow-missing` is passed.

- Create `tests/func/repro` and extract `pull` and `allow_missing` to separate test files.

Closes #9530
2023-06-13 15:46:34 +03:00
Peter Rowlands 5ec4fa473c cache migrate: add utility for migrating local cache files to 3.x 2023-06-13 21:33:46 +09:00
Peter Rowlands 5fd54679c7 dvc-data: bump to 1.11.0 2023-06-13 21:33:46 +09:00
Ruslan Kuprieiev 5c1487e2ec deps: bump dvc-data to >=1.10.0 2023-06-13 14:45:36 +03:00
skshetry 30517f6676 deps: update dvc-task/dvc-s3/pytest-cov (#9592)
* remove deprecation warnings

* Update pyproject.toml
2023-06-13 15:39:34 +05:45
Ruslan Kuprieiev bbb77360e9 deps: bump dvc-data to >=1.9.0
Fixes #9541
2023-06-12 22:03:29 +03:00
Ruslan Kuprieiev 1af150a5e9 index: use out.hash_info for complete imports 2023-06-12 16:55:36 +03:00
Peter Rowlands cf59d801ce repo.index: use correct hash when rebuilding index entries 2023-06-12 16:22:25 +09:00
Peter Rowlands b733dea4c2 dvc-data: bump to 1.7.0 2023-06-12 16:22:25 +09:00
Ruslan Kuprieiev 2ed677057d fetch: cache collected
This avoids recollecting the cache files over and over again.

For example, `dvc fetch` noop in `dvc-bench` went from ~30sec down to ~10sec
for me.

Next step is to also cache remote index, so we don't have to waste those
~10sec checking files in the remote.

Related https://github.com/iterative/dvc-data/pull/376
2023-06-12 04:31:37 +03:00
Ruslan Kuprieiev 0597311439 deps: bump dvc-data to >=1.5.0 2023-06-12 01:04:24 +03:00
Ruslan Kuprieiev fc8ec6aa95 fetch: show progress when collecting 2023-06-10 22:48:16 +03:00
Ruslan Kuprieiev 3dca69b678 deps: bump dvc-data to >= 1.2.0
This brings https://github.com/iterative/dvc-data/pull/373 , which improves UI for `checkout` by not visually hanging during `diff` stage inside.
2023-06-10 21:33:25 +03:00
Ruslan Kuprieiev 4c0bb8d316 fetch: use index fetch 2023-06-10 21:18:57 +03:00
Ruslan Kuprieiev 1cb371d4d7 repo: commit: don't require target
Same as CLI.
2023-06-10 19:19:40 +03:00
Ruslan Kuprieiev c96795dcfb tests: checkout: fix test_checkout_relink_protected on windows 2023-06-09 22:36:33 +03:00
Ruslan Kuprieiev 8f768addf9 checkout: don't validate cache
Part of #9561
2023-06-09 18:41:19 +03:00
Ruslan Kuprieiev af1fb722c8 dvc: drop cached external outputs
Fixes #9531

Docs https://github.com/iterative/dvc.org/pull/4574 Kudos @dberenbaum
2023-06-09 18:34:36 +03:00
Ruslan Kuprieiev 8b1c1a31f3 deps: bump dvc-data to >=1.0.3 2023-06-09 18:16:51 +03:00
Ruslan Kuprieiev 262419ef35 deps: bump dvc-data to >=1.0.2
Related https://github.com/iterative/dvc/issues/9566
2023-06-09 16:26:31 +03:00
Peter Rowlands 265fc581c0 dvc-data: bump to 1.0.0 2023-06-09 15:49:44 +03:00
Peter Rowlands 80f414c19d remote: support legacy cache push/fetch 2023-06-09 15:49:44 +03:00
Peter Rowlands 2cd33e10ac output: serialize 3.x hash name in 'hash' field 2023-06-09 15:49:44 +03:00
Peter Rowlands 603f5fdba1 cache: move 3.x data objects into files/md5/ prefix 2023-06-09 15:49:44 +03:00
Dave Berenbaum 528eab0418 import: drop --file (#9562) 2023-06-09 10:03:32 +05:45
skshetry ed664143b4 dvc.build: move logic out of __init__ to dvc.build (#9563) 2023-06-08 08:19:59 +05:45
Saugat Pachhai (सौगात) 21a2504bcb dvc.utils.pkg: move PKG to top-level dvc
PKG has to be specified in dvc/_build.py now, and can be
imported using:

    from dvc import PKG

This is done to avoid importing from dvc/utils pkg which can
be expensive.
Also it's not an utility, so it is better that it remains at
the top-level namespace.
Note that we may have to fix the path for a few packages that we build,
like conda/snap/chocolatey.
2023-06-08 00:31:00 +03:00
Ruslan Kuprieiev d0291e8039 checkout: let index checkout error-out on missing hashes
This ensures we don't assume that everything needs to have hash_info to be
checked out (e.g. we can totally checkout directly from FileStorage).

Related https://github.com/iterative/dvc/pull/9424
2023-06-07 14:56:19 +03:00
skshetry 358c5e0c39 drop stage-level vars (#9556)
drop stage-level vars support
2023-06-07 11:10:08 +05:45
skshetry 9d7fba5c61 fix tests (#9555) 2023-06-07 10:28:54 +05:45
skshetry a1e339b4fa .dvc file: remove cmd support (#9554) 2023-06-07 09:30:13 +05:45
skshetry 6c58d438b3 tests: remove single_stage tests from repro/run tests (#9553) 2023-06-07 09:25:08 +05:45
skshetry 0c709b6ec1 .dvc file: remove metrics/plots support (#9552) 2023-06-06 20:42:09 +05:45
skshetry 0aeb7a8662 .dvc file: remove params support (#9551) 2023-06-06 20:05:36 +05:45
skshetry 46f3157f43 add: rename jobs to remote_jobs to mirror CLI; move validation to CLI (#9550)
- Follow up on https://github.com/iterative/dvc/pull/9522, renames jobs kwarg to remote_jobs
  to mirror CLI.
- Also moves validation logic to CLI.
2023-06-06 19:30:39 +05:45
skshetry 36fd69be21 add: remove file (#9548)
* add: remove `file`

Follow up to #9547.

* Update add.py

* fix tests
2023-06-06 18:44:19 +05:45
skshetry 3759535d43 tests: remove single_stage stage runs (#9549) 2023-06-06 18:38:07 +05:45
dberenbaum 2c4365513e add: deprecate --file 2023-06-06 14:57:07 +03:00
skshetry 26152292aa remove support for reading and generating Dvcfile (#9546) 2023-06-06 15:29:10 +05:45
skshetry 3e0f2bafbb add: small misc refactoring (#9540) 2023-06-05 18:41:17 +05:45
Ruslan Kuprieiev 78637713cf checkout: use index checkout
Needed for https://github.com/iterative/dvc/pull/9424
2023-06-04 23:27:01 +03:00
Ruslan Kuprieiev f9104275f3 deps: install tzdata for testing with celery (#9537)
Temporary fix for CI on windows with py >=3.9.
2023-06-04 22:18:23 +03:00
Ruslan Kuprieiev bce3b5d2a1 update: make sure we update hashes/checksums on --to-remote (#9536)
Discovered in #9444
2023-06-04 19:36:54 +03:00
Dave Berenbaum 6ace5ed380 add: tweak stage overlap error message (#9514)
* add: tweak stage overlap error message

* add: instructions for how to fix overlap error
2023-06-02 00:46:55 +03:00
Ruslan Kuprieiev 6543580100 dvcfs: don't use datafs isout/isdvc 2023-05-31 23:14:28 +03:00
David de la Iglesia Castro a1b891ce01 deps: bumps dvc-azure>=2.21.2
Closes #9506 via https://github.com/iterative/dvc-azure/pull/48
2023-05-31 14:22:27 +02:00
Dave Berenbaum 3a85326df3 add: rename jobs to remote-jobs (#9522) 2023-05-31 01:14:30 +03:00
skshetry 355ebc72eb add: remove --recursive, rename fname to file (#9513)
add: remove --recursive
2023-05-26 12:07:13 +05:45
daavoo 5a6f834088 repro: Skip pulling run cache if no-run-cache was passed. 2023-05-25 16:35:30 +02:00
daavoo e98bf38d4c repro: Continue on RunCacheNotSupported
Closes #9470
2023-05-25 16:35:30 +02:00
skshetry 192c9cc577 remove original PR from backport PR title (#9510) 2023-05-25 16:37:25 +05:45
skshetry 0e38525d8d cli: remove dvc run (#9508)
Note that `Repo.run()` API still exists, which will be removed in
successive PRs. A lot of tests depend on it that it'll take time
before removing it.
2023-05-25 16:27:14 +05:45
Dave Berenbaum 8acd943d52 exp list: show experiment shas (#9501)
* exp list: include sha; still needs remote support

* exp list: ignore rev for remotes

* exp list: update output format

* refactor
2023-05-25 15:05:12 +09:00
dependabot[bot] 79c88008f8 build(deps-dev): bump dvc-gs from 2.22.0 to 2.22.1
Bumps [dvc-gs](https://github.com/iterative/dvc-gs) from 2.22.0 to 2.22.1.
- [Release notes](https://github.com/iterative/dvc-gs/releases)
- [Commits](https://github.com/iterative/dvc-gs/compare/2.22.0...2.22.1)

---
updated-dependencies:
- dependency-name: dvc-gs
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-05-24 13:53:00 +09:00
Peter Rowlands 9c9ca39fb4 exp: fix rebased imports 2023-05-23 15:50:58 +09:00
Peter Rowlands 89109fafcf exp: always log running experiment name at the start of a run 2023-05-23 15:43:50 +09:00
Peter Rowlands aa19e24670 exp: support switching to live workspace exp name 2023-05-23 15:43:50 +09:00
Peter Rowlands 629223cbc2 exp: drop deprecated get_running_exps()
- replaced with queue.collect_active()
2023-05-23 15:43:50 +09:00
Peter Rowlands 96449f157c plots diff: use exp switch_repo context instead of brancher 2023-05-23 15:43:50 +09:00
Peter Rowlands 8cb2646023 exp: add contextmanager for switching to active tempdir repo 2023-05-23 15:43:50 +09:00
David de la Iglesia Castro 25313f5d82 exp: Drop checkpoints (#9271)
exp: Drop `checkpoints`.

Closes #9221
2023-05-23 11:32:18 +05:45
David de la Iglesia Castro 182728d674 exp run / repro: Drop --metrics. (#9458)
* exp run / repro: Drop `--metrics`.

* exp run: Rename `-M` to `-m`.
2023-05-22 19:13:22 +05:45
David de la Iglesia Castro f245567613 exp: Drop gc. (#9273)
Closes #7991
2023-05-22 16:08:25 +05:45
skshetry 4163c8f57d set destination branch to PR title on backport (#9492) 2023-05-22 16:03:36 +05:45
skshetry 6532258e4a drop top-level plots definition as mapping support (#9486) 2023-05-22 15:08:22 +05:45
daavooandIvan Shcheklein eb45cda5d0 get_random_exp_name: Use custom random generator.
See https://github.com/iterative/dvclive/pull/576

Co-authored-by: Ivan Shcheklein <[email protected]>
2023-05-22 10:46:41 +02:00
skshetry abd4f4a2a8 drop Repo.stages (#9489)
Use repo.index.stages instead.
2023-05-22 12:51:40 +05:45
skshetry f41e535857 remove dvc.main.main alias (#9488)
You can import it using:
```python
from dvc.cli import main

main(...)
```
2023-05-22 12:46:46 +05:45
skshetry 1989c0fe98 stage add: introduce --run option (#9480)
* stage add: introduce --run option

Part of #5846.

* fix ui message
2023-05-22 12:27:20 +05:45
daavoo 3ddd4b87fc exp: Fix --rev args for ls pull and remove.
Closes #9471
2023-05-21 13:25:40 +02:00
skshetry e089ee0365 remove data ls and support for --meta/--desc/--label/--type cli flags (#9481) 2023-05-19 20:10:34 +05:45
David de la Iglesia Castro 02f7fcae73 exp show: Drop --pcp. (#9270)
Closes #9268
2023-05-19 15:36:33 +05:45
David de la Iglesia Castro cdba65f27e exp: Drop init. (#9269)
Drop `exp init`.

Closes #9267
2023-05-19 14:39:16 +05:45
skshetry 3959c51373 lockfile: drop 1.0 lockfile support (#9476) 2023-05-18 17:36:05 +05:45
skshetry 90aaf5a296 commands: remove --show-json/--show-md/--show-csv flags (#9475) 2023-05-18 16:36:14 +05:45
Dave Berenbaum 45c5c83699 show hydra dumped results in debug mode (#9460)
* show hydra dumped results in debug mode

* update hydra composition trace msg
2023-05-18 13:47:58 +05:45
daavoo ecb71c8263 exp push: Handle rev arg as list. 2023-05-18 09:54:10 +02:00
David de la Iglesia Castro e6e3912da0 testing: Lazy import pytest_virtualenv (#9469) 2023-05-17 16:27:57 +03:00
Dave Berenbaum 7f6890ff25 Live metrics config (#9433)
* exp: live metrics config token and offline

* refactor live metrics config

* use get_studio_config

* revert to using env vars for studio config

* update dvc-studio-client to support live metrics config changes

* upgrade dvc-studio-client

* don't change environ when posting live metrics events
2023-05-17 09:21:01 +00:00
skshetry 99daf5d113 add: fail loudly if there's no dir cache (#9466) 2023-05-17 12:03:06 +05:45
dependabot[bot]andskshetry 83ffb8803e build(deps-dev): bump pylint from 2.17.2 to 2.17.4 (#9418)
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.17.2 to 2.17.4.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.17.2...v2.17.4)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: skshetry <[email protected]>
2023-05-17 09:22:30 +05:45
dependabot[bot] ace8464acb build(deps-dev): bump mypy from 1.2.0 to 1.3.0 (#9439)
Bumps [mypy](https://github.com/python/mypy) from 1.2.0 to 1.3.0.
- [Commits](https://github.com/python/mypy/compare/v1.2.0...v1.3.0)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-17 09:21:45 +05:45
skshetry 0dbdfd2b9b run tests and codeql on 2.x branch (#9465) 2023-05-17 09:17:36 +05:45
skshetryandpre-commit-ci[bot] 6d4251798a ci(Mergify): configuration update (#9463)
* ci(Mergify): configuration update

Signed-off-by: null <null>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Signed-off-by: null <null>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-05-17 09:09:33 +05:45
skshetry 11d031935d packaging: use PyPI trusted publishers (#9459)
https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers
2023-05-17 06:26:19 +05:45
daavoo 64beb1578a repro: Add --allow-missing.
Point 2 in https://github.com/iterative/dvc/pull/9375#issuecomment-1531683194
2023-05-16 22:43:24 +02:00
dberenbaum f888544554 gc: disallow --remote without other flags 2023-05-16 17:18:57 +02:00
daavoo 1e538ed87b repro: Move pull logic to inside Stage. 2023-05-16 16:11:43 +02:00
Ruslan Kuprieiev e69deaa132 import: don't forget to set other cache config options (#9423) 2023-05-16 15:53:41 +03:00
Peter Rowlands be0a1a4a12 exp: fix temporary ref namespacing 2023-05-16 15:59:48 +09:00
skshetry 004f49744e tests: isolate dvc config and directories (#9450)
* tests: isolate dvc config and directories

by introducing envvars to change default values. This lets pytest
handle the deletion of tmpdirs, instead of filling /var/tmp with
hundreds of thousands of directories. Also isolates test run from
faulty global/system config files.

* move to dvc/env and sort
2023-05-15 18:16:02 +05:45
Alexander GuschinandOded Messer 45181504ea Add API to add artifacts (#9345)
* api call to add/write artifact

* return dvcyaml path on add

* create dir for dvc.yaml if needed

* create dir for dvc.yaml if needed - fix

* allow nested artifact names

* make dvc get download artifacts

* Apply suggestions from code review

Co-authored-by: Oded Messer <[email protected]>

* use feedback

* remove 'dvc get' from this PR, keep only adding artifacts

* allow first char of artifact name to be a number

* add note about constants

* fix parsing artifact name

* remove 'parse_name' and write tests for 'add'

* Apply suggestions from code review

Co-authored-by: Oded Messer <[email protected]>

* updates from comments

* fix for studio

* fix again

* making check_name_format to raise an exception

* Update dvc/repo/artifacts.py

---------

Co-authored-by: Oded Messer <[email protected]>
2023-05-15 07:55:43 +00:00
skshetry 915dd5062e disable nested progress bar during checkout (#9446) 2023-05-12 18:43:33 +05:45
skshetry d08c85f7d1 fix checkout callback during add/commit (#9445)
* fix checkout callback

Fix https://github.com/iterative/dvc/issues/6226.

* bump minversion of dvc-data to 0.49.1
2023-05-12 18:14:13 +05:45
skshetry 2342099bd8 add: support virtual operation (#9389) 2023-05-11 08:31:25 +05:45
dberenbaum 06d8e3c639 add random seed to benchmark stories 2023-05-10 11:08:57 +02:00
David de la Iglesia Castro 195e67c0c1 repro: pull all missing files (#9395)
* reproduce: Update `pull` to also pull `run cache`.

* reproduce: Update `pull` to also pull changed stages.
2023-05-10 00:29:44 +03:00
Peter Rowlands c75a5583b3 testing: sanitize venv names containing slashes 2023-05-09 18:52:42 +09:00
David de la Iglesia Castro 981baa8c30 studio: Send message on start event.
- Bump `dvc-studio-client>=0.9.0,<1`

Part of #8870
2023-05-08 20:08:47 +02:00
David de la Iglesia Castro aa517bc90e exp save: Support --message.
Custom commit message to use when committing the experiment.

Part of #8870
2023-05-08 20:08:47 +02:00
David de la Iglesia Castro c74dc20b97 exp run: Support --message.
Custom commit message to use when committing the experiment.

Part of #8870
2023-05-08 20:08:47 +02:00
David de la Iglesia Castro 1ba3944944 api: exp_show: Postprocess empty strings as None.
Makes it easier to manipulate when converting to pandas DataFrame.
2023-05-08 17:10:27 +02:00
David de la Iglesia Castro 8620b6e5af exp: Update --rev to support append action.
Closes #9390
2023-05-08 14:15:07 +02:00
Ruslan Kuprieiev 6b6084a848 tests: import: check that dvcfs is using main repo's cache (#9417)
Followup for https://github.com/iterative/dvc/pull/9415
2023-05-08 00:34:00 +03:00
Ruslan Kuprieiev 967dd5ea2b import: don't forget to set cache.dir (#9415)
* import: don't forget to set cache.dir

* repo: open: try setting remote for local repos
2023-05-07 05:28:58 +03:00
Ruslan Kuprieiev ad39bf14ed repo: external_repo -> _external_repo 2023-05-07 04:14:25 +03:00
Ruslan Kuprieiev 01416df5a4 get: use Repo.open instead of external_repo
This should use `Repo.open` just like `dvc import`, to benefit from
handling local repos without cloning and redundant downloaads.
2023-05-07 04:14:25 +03:00
Ruslan Kuprieiev eb592e7e33 repo: consolidate Repo.open logic 2023-05-07 04:14:25 +03:00
dberenbaum 2db07b047e data status: exclude remote status by default 2023-05-06 18:21:11 +03:00
pre-commit-ci[bot] 8ecc66ae9a [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2023-05-05 22:25:38 +02:00
paulourbano dfa5f4d9a0 utils: removing diff key from result dictionary 2023-05-05 22:25:38 +02:00
paulourbano 75952c4e36 tests: changing tests to reverted diff functionality 2023-05-05 22:25:38 +02:00
paulourbano 31b0b8de73 tests: adapting tests to new diff output
Issue #7960
2023-05-05 22:25:38 +02:00
paulourbano fae47e6122 metrics: adds support for strings in metrics
Fixes #7960
2023-05-05 22:25:38 +02:00
Ruslan Kuprieiev ac3eef439f gha: try setting PYTHONUTF8
Trying to see if that will help with encoding error on windows with python 3.11
2023-05-05 21:55:31 +03:00
Ruslan Kuprieiev b044bcce5e tests: lockfile: use different way of changing a cmd 2023-05-05 04:16:58 +03:00
Ruslan Kuprieiev a251cffdb5 deps: unpin ruamel.yaml 2023-05-05 04:16:58 +03:00
Peter Rowlands 37858be02f testing: separate session and function level scope behavior for dvc_bin 2023-05-04 17:05:43 +09:00
Ruslan Kuprieiev 9b7240e9e0 deps: temporarily pin ruamel.yaml
Temporary workaround for https://github.com/iterative/dvc/issues/9397
2023-05-04 03:22:48 +03:00
Peter Rowlands e362438f03 testing.benchmarks: support installing remote deps in benchmark venv 2023-05-03 18:19:31 +09:00
Peter Rowlands 6c79f6bbfc testing: register pytest plugin 2023-05-03 14:58:54 +09:00
Peter Rowlands 58cd1cbc09 testing.benchmarks: separate fixtures and config 2023-05-03 14:58:54 +09:00
Peter Rowlands 96e3b48afd testing: import dvc-bench benchmarks 2023-05-03 14:58:54 +09:00
dberenbaum 1f03c40dbe add: msg for overlapping parent 2023-05-02 19:03:19 +03:00
skshetry e93e8f05a3 exp push: notify studio even if cache push fails (#9380)
* exp push: notify Studio even when cache push fails

* exp push: refactor and extract exp_ref resolving logic as the function is getting complex
2023-05-02 08:46:10 +05:45
David de la Iglesia Castro 0f1326e547 api: exp_show: Cleanup flags.
Per https://github.com/iterative/dvc/pull/9356#discussion_r1180782320
2023-05-01 19:29:47 +02:00
David de la Iglesia Castro 2a04263f02 api: Add scm module with all_{X} methods for listing revs. 2023-04-28 12:33:03 +02:00
David de la Iglesia Castro 348446050e api: Add exp_show.
Closes #8775
Closes #7167
2023-04-28 12:33:03 +02:00
Ruslan Kuprieiev 7e1036b30d doctor: add system/global config location 2023-04-28 01:23:44 +03:00
Ruslan Kuprieiev a15dbc8e03 info: get_fs_type -> _get_fs_type
This is not used anywhere outside so should be private like the rest. Likely a leftover from the past.
2023-04-28 00:53:03 +03:00
Ruslan Kuprieiev 4e02197245 info: replace self -> repo
Minor cleanup of an old leftover.
2023-04-28 00:40:11 +03:00
Peter Rowlands 4ab7ef06e5 exp: pass -v loglevel into dvc-task workers 2023-04-27 20:39:26 +09:00
Peter Rowlands dae2faf36d dvc-task: bump to 0.2.1 2023-04-27 20:39:26 +09:00
David de la Iglesia Castro 58f10a4661 gc: Add ui hint for not_in_remote. 2023-04-27 10:30:39 +02:00
David de la Iglesia Castro 64e787fa02 gc: Handle remote field in --cloud and --not-in-remote. 2023-04-27 10:30:39 +02:00
David de la Iglesia Castro c7e2ec9707 gc: Add --not-in-remote arg.
Closes #2036
2023-04-27 10:30:39 +02:00
skshetry a4cc198ac7 exp push: soft wrap link so that the URL does not break (#9368)
soft wrap link so that URL does not break
2023-04-27 06:50:33 +05:45
Oded Messer d203bf9024 Fix: Prettifying unexpected error on FileExists for get/get-url/imp-url/add and introducing --force (#9365) 2023-04-27 00:41:09 +00:00
David de la Iglesia Castro baeec8ec2d Update pyproject.toml 2023-04-26 10:38:08 +02:00
dependabot[bot] 9c689a3b51 build(deps-dev): update dvc-render requirement
Updates the requirements on [dvc-render](https://github.com/iterative/dvc-render) to permit the latest version.
- [Release notes](https://github.com/iterative/dvc-render/releases)
- [Commits](https://github.com/iterative/dvc-render/compare/0.3.1...0.4.0)

---
updated-dependencies:
- dependency-name: dvc-render
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-04-26 10:38:08 +02:00
skshetry e1bf418e72 tests: lazy tpi imports, ignore deprecation warning from setuptools (#9362) 2023-04-24 21:34:07 +05:45
David de la Iglesia Castro b6d8c07d4d studio: Ensure studio_repo_url works with exp run --queue.
Closes #9349
2023-04-21 21:04:48 +02:00
Peter Rowlands b814531c84 exp: use mocked queue in test_apply_failed 2023-04-21 16:17:01 +09:00
Peter Rowlands 3b3cd0a0b2 exp: drop test_queue_remove_done func test in favor of mocked unit test 2023-04-21 16:17:01 +09:00
skshetry b2101a85ad reproduce: remove callback (#9354)
Callback was added for working around scm_context, since we don't use it, we don't need callback now.
2023-04-21 13:01:00 +05:45
dberenbaum ba760c56e5 exp: show active experiments first 2023-04-21 12:51:34 +09:00
dependabot[bot] 787c72ea18 build(deps-dev): bump dvc-gdrive from 2.19.1 to 2.19.2
Bumps [dvc-gdrive](https://github.com/iterative/dvc-gdrive) from 2.19.1 to 2.19.2.
- [Release notes](https://github.com/iterative/dvc-gdrive/releases)
- [Commits](https://github.com/iterative/dvc-gdrive/compare/2.19.1...2.19.2)

---
updated-dependencies:
- dependency-name: dvc-gdrive
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-04-20 17:01:04 +09:00
dependabot[bot] a2b7a59322 build(deps-dev): bump dvc-s3 from 2.21 to 2.22.0
Bumps [dvc-s3](https://github.com/iterative/dvc-s3) from 2.21 to 2.22.0.
- [Release notes](https://github.com/iterative/dvc-s3/releases)
- [Commits](https://github.com/iterative/dvc-s3/compare/2.21.0...2.22.0)

---
updated-dependencies:
- dependency-name: dvc-s3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-04-20 17:00:21 +09:00
Peter Rowlands ec090c5680 exp: use new collection in show/cli commands
- Updates 'dvc exp show --json' to use new data format
2023-04-20 16:58:32 +09:00
Peter Rowlands 58f74ae543 exp: standardize exp data collection 2023-04-20 16:58:32 +09:00
Peter Rowlands 2e8bcbf719 exp: add structured datatypes for collection 2023-04-20 16:58:32 +09:00
skshetry 10f523430b exp run: do not autostage on dvc repro (#9344) 2023-04-19 16:11:13 +05:45
skshetry 5563a595d5 utils.studio: allow any base url to be set, not just the hostname (#9341)
This keeps it in symmetry with
https://github.com/iterative/dvc-studio-client/pull/28, and allows
setting the base url with path, not just limited to netloc.

This was always intended to work, urljoin with the added slash was
causing this bug.
2023-04-18 22:22:26 +05:45
skshetry dd3deb6cbd add DVC_STUDIO_URL envvar support (#9340)
add DVC_STUDIO_URL envvar
2023-04-18 09:56:17 +05:45
skshetry 7841020b2b [DO NOT MERGE] release: remove feature flags for experiment sharing (#9257)
release: remove feature flags for experiment sharing
2023-04-17 12:53:27 +05:45
dberenbaum 1c394986db fix tests 2023-04-15 23:46:47 +03:00
dberenbaum 870935ebdc import-url: make version-aware and to-remote exclusive 2023-04-15 23:46:47 +03:00
Saugat Pachhai (सौगात) 1be82fa56d tests: remove unnecessary variable interpolation
dvc.run does not expand variables. It is only done when it's actually read from dvc.yaml file.
So during dvc run, the shell will try to expand the variable, which does not exist.

I don't think that the intention was to use shell variables. But I don't think we should ever
use them, as they will fail on some shells (eg: fish) and keep the scripts as simple as possible.
2023-04-14 13:01:53 +02:00
Ruslan Kuprieiev ce0f6c187e deps: put lower bound on dvc-http
People are still running into `ImportError: cannot import name 'fsspec_loop' from 'fsspec.asyn' ` because of it.
2023-04-12 22:26:31 +03:00
pre-commit-ci[bot] 559ec392f6 [pre-commit.ci] pre-commit autoupdate (#9319)
updates:
- [github.com/charliermarsh/ruff-pre-commit: v0.0.260 → v0.0.261](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.260...v0.0.261)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-04-11 14:58:43 +03:00
Peter Rowlands c71a4082e6 testing: expose force=... in scm_add 2023-04-10 13:17:47 +03:00
Peter Rowlands ce269ffa58 exp: use explicit scm.add(force=True) when necessary
- add test for dir dep containing gitignored files
2023-04-10 13:17:47 +03:00
Peter Rowlands 61d0893d7c deps: bump scmrepo to 1.0.0 2023-04-10 13:17:47 +03:00
dependabot[bot] eef5fb9b37 build(deps-dev): bump mypy from 1.1.1 to 1.2.0 (#9313)
Bumps [mypy](https://github.com/python/mypy) from 1.1.1 to 1.2.0.
- [Release notes](https://github.com/python/mypy/releases)
- [Commits](https://github.com/python/mypy/compare/v1.1.1...v1.2.0)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-07 10:39:06 +05:45
Peter Rowlands f03d555747 deps: bump dvc-ssh to 2.22.1 2023-04-06 19:28:30 +09:00
skshetry a91993616f logger: add DVC_SHOW_TRACEBACK envvar to show traceback on exception (#9310)
This will come useful in debugging, where you don't have to add --verbose just to
see where it failed or go through verbose logs (which might be useful when working
with UI issues as you want to see what the user sees).

Ideally this should be handled in main when we exit with error instead of using
logger.{warning,error,exception} to log exception as the intention is to only log
last exception that makes it exit. But since we don't have that capability and
we don't abuse logging.{warning,error,exception} to log and suppress exceptions, this is a good
enough solution for now without complicating `dvc.cli.main()`.
2023-04-06 09:56:19 +05:45
skshetry 3c570a2177 exp push: improve ui (#9308)
* exp push: improve ui

* fix misc suggestions
- show url even when the refs are up-to-date.
- show url at the end
- add Git remote information in up-to-date UI message.

* fix diverged exps message
2023-04-06 09:54:39 +05:45
David de la Iglesia Castro 3312a90949 exp run: Add --copy-paths arg.
List of paths to copy inside the temp directory. Only used if `--temp` or `--queue` is specified.

Closes #5800
2023-04-05 23:17:07 +02:00
Alexander Guschin 32bebc0246 Add top-level artifacts: section (#9220)
* add artifacts section

* adding and removing artifacts

* delete code for add/remove; add tests

* fix pre-commit

* remove extra piece of writing to dvc.yaml

* remove extra piece

* simplify kwargs

* allow same names for artifacts in different dvc.yaml files

* set ID as path; don't return dvc.yaml(s) with no artifacts

* fix PR feedback

* issue warning at incorrect artifact name

* issue warning at incorrect artifact name

* reference right schema

* add r to regexp

* add tests for regexp

* set artifacts for SingleStageFile

* fix windows test

* make path required; simplify regexp and remove slash from it

* allow to use gto's artifacts.yaml

* remove extra piece of code for migration from gto
2023-04-05 13:31:35 +00:00
David de la Iglesia Castro 35648134f7 exp run: git add param files that will be modified.
Only if they are currently untracked and `--temp` or `--queue` is passed.

Closes #7842
2023-04-05 10:28:18 +02:00
Peter Rowlands df09e522ec deps: bump scmrepo minver to 0.2.1 2023-04-05 16:50:03 +09:00
Ruslan Kuprieiev 40f7f34889 api: data: set default remote instead of using it directly
Fixes #9139
Fixes #7341 (see https://github.com/iterative/dvc/pull/7363#issuecomment-1032959843)
2023-04-05 02:47:35 +03:00
skshetry cf52efb8c3 notify_refs; rename studio_url to base_url (#9303) 2023-04-04 17:43:05 +05:45
skshetry 8be71be540 utils.studio: disallow redirects, misc API refactoring (#9301) 2023-04-04 13:15:08 +05:45
pre-commit-ci[bot]andskshetry 071a5b7ba4 [pre-commit.ci] pre-commit autoupdate (#9251)
updates:
- [github.com/psf/black: 23.1.0 → 23.3.0](https://github.com/psf/black/compare/23.1.0...23.3.0)
- [github.com/charliermarsh/ruff-pre-commit: v0.0.257 → v0.0.260](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.257...v0.0.260)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: skshetry <[email protected]>
2023-04-04 10:12:52 +05:45
dependabot[bot] ed6cf093a8 build(deps-dev): bump pylint from 2.17.1 to 2.17.2 (#9299)
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.17.1 to 2.17.2.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.17.1...v2.17.2)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-04 10:11:47 +05:45
skshetry 7c3c47b4a2 bump ruff to 0.0.260 and enable bandit (#9300)
* bump ruff to 0.0.260 and enable bandit

* install toml extra for bandit

* suppress insecure use of hash md5
2023-04-04 10:01:43 +05:45
David de la Iglesia Castro 3a2259821b exp save: Include LOCK_FILE 2023-04-03 10:33:52 +02:00
Ruslan Kuprieiev 649ee67e4b config: introduce core.site_cache_dir 2023-04-03 00:29:44 +03:00
Ruslan Kuprieiev 7cdb3b0ae2 repo: site_cache_dir: isolate by user
Related #9249
2023-04-03 00:29:44 +03:00
Ruslan Kuprieiev ecdc44e010 dep: repo: use dvcfs
Makes dvc get/import/etc use dvcfs, which already supports cloud versioning,
circular imports and other stuff.

Also makes dvc import behave more like dvc import-url, so that we can use
the same existing logic for fetching those using index instead of objects.

Fixes #8789
Related iterative/studio#4782
2023-04-02 03:55:02 +03:00
David de la Iglesia Castro 24e10e0278 exp save: Track top level files 2023-03-31 19:23:40 +02:00
David de la Iglesia Castro 7c8e6e3156 exp run: Track top level files. 2023-03-31 19:23:40 +02:00
David de la Iglesia Castro d2812fa48f studio: Don't fail on empty params. 2023-03-31 19:23:40 +02:00
skshetry 086d51d9de plots json: return definition errors unrelated to renderers (#9293) 2023-03-31 16:34:26 +05:45
David de la Iglesia Castro 1d8b2e5fa6 exp run: Propagate .dvc/config.local in TempDirExecutor.
Closes #7254
2023-03-31 09:02:22 +02:00
David de la Iglesia Castro 894f530d22 deps: bump dvc-studio-client>=0.6.1,<1 2023-03-30 11:23:07 +02:00
skshetry 1b9d40960f utils.studio: reduce verbosity on exception logging (#9284) 2023-03-30 12:55:19 +05:45
skshetry 696fabc745 exp-push: show url to the Studio project (#9283) 2023-03-30 12:52:09 +05:45
skshetry 780dc72301 Revert "exp-push: show url to the Studio project" (#9282)
Revert "exp-push: show url to the Studio project (#9278)"

This reverts commit 1ca3ef14a3.
2023-03-30 08:28:44 +05:45
skshetry 1ca3ef14a3 exp-push: show url to the Studio project (#9278) 2023-03-30 08:27:47 +05:45
skshetry a6c89cac8d replace funcy.cat with itertools.chain.from_iterable (#9279)
It's just an alias to the function from itertools.
2023-03-29 20:56:26 +05:45
skshetry 593f1064cf utils.studio: refactor to return json response (#9277) 2023-03-29 20:02:40 +05:45
Ruslan Kuprieiev 35bb261b89 config: don't look for .dvc dir implicitly
Currently if dvc_dir doesn't exists (e.g. we are creating an uninitialized
repo), config will try looking for `.dvc` dir in the current directory,
which might be inside of another dvc repository resulting in mixed configs.

Use explicit `from_cwd` method to make `Config` try to find repo configs
if available to avoid the usage mixup.
2023-03-29 16:27:54 +03:00
David de la Iglesia Castro fe6d543c1f tests: Add UnresolvedExpNamesError check in test_remove_remote 2023-03-29 12:56:59 +02:00
dberenbaum 4351d32de4 exp remove: fix ui for removing from git remotes 2023-03-29 12:56:59 +02:00
skshetry efc2d7ad3d remove unused type-ignore comment (#9258) 2023-03-28 14:30:33 +05:45
skshetry 7c65739e7e refactor notify_refs_to_studio to take in repo instance as dependency (#9256) 2023-03-28 13:53:31 +05:45
skshetry cc4816f652 utils.studio: require token (#9255)
This is a simple refactoring which makes the caller to choose appropriate token instead of
the studio.notify_refs making a decision for them.
2023-03-28 13:32:05 +05:45
skshetry faa1bdfbce use git remote to find out remote repo url when pinging Studio (#9254) 2023-03-28 12:17:48 +05:45
skshetry 006b6f3513 exp push/remove: show message on failure when notifying to Studio (#9253) 2023-03-28 09:40:41 +05:45
skshetry 1bc4c1dceb exp share refactor - ping on exp:remove, do not fail on error (#9248)
studio experiments share refactor

1) Pings Studio on exp remove
2) Does not fail on any error during request.post
3) UI improvement on exp remove
2023-03-27 22:51:50 +05:45
skshetry 531b2110cf Revert "exp push: add trailing slash to the endpoint url" (#9243)
Revert "exp push: add trailing slash to the endpoint url (#9240)"

This reverts commit 5485275b92.
2023-03-27 14:19:12 +05:45
skshetry c1917ed751 output: ignore missing size from files when calculating total size (#9242)
output: ignore missing size from files when calculating hash info
2023-03-27 12:56:43 +05:45
skshetry 43195a806d plots: return errors in json format (#9146)
* plots: return errors in json format

* plots --json: move plots data into data key

* rename  revision key to rev

* move imports to top-level

* add tests
2023-03-27 12:53:43 +05:45
Ruslan Kuprieiev d41512c85c deps: bump dvc-data to 0.46.0 (#9241)
* utils: determine_linecol: ignore mypy attr-defined error

* deps: bump dvc-data to 0.46.0
2023-03-26 22:06:23 +03:00
David de la Iglesia CastroandDave Berenbaum e9fb0b92aa exp branch: Make branch arg optional.
Default to `f"{ref_info.name}-branch"` where ref_info is inferred from the `exp_rev` argument.

Co-authored-by: Dave Berenbaum <[email protected]>
2023-03-24 19:11:06 +01:00
skshetry 5485275b92 exp push: add trailing slash to the endpoint url (#9240) 2023-03-24 22:35:20 +05:45
Peter Rowlands 1f80f2f2ed deps: bump scmrepo to 0.1.17 2023-03-24 19:31:27 +09:00
David de la Iglesia Castro 6b6dc01ac4 exp save: Reintroduce implementation based on executor/queue.
Closes #9058 .

Ensures behavior of `_stash_exp` in `exp run` is matched in `exp save` without duplicating logic.

The simpler implementation ended up being worse for maintenance when wanting to make `exp run` and `exp save` behavior in sync.
2023-03-24 10:43:24 +01:00
Peter Rowlands 91d3ff0f69 exp: mark q remove test as flaky 2023-03-24 17:53:40 +09:00
dependabot[bot] 701f48197e build(deps): bump pyinstaller from 5.8.0 to 5.9.0 (#9169)
Bumps [pyinstaller](https://github.com/pyinstaller/pyinstaller) from 5.8.0 to 5.9.0.
- [Release notes](https://github.com/pyinstaller/pyinstaller/releases)
- [Changelog](https://github.com/pyinstaller/pyinstaller/blob/develop/doc/CHANGES.rst)
- [Commits](https://github.com/pyinstaller/pyinstaller/compare/v5.8.0...v5.9.0)

---
updated-dependencies:
- dependency-name: pyinstaller
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-23 16:45:11 +00:00
Dave Berenbaum da3bbccf66 Update duplicate output error msg (#9138)
* update dup output error msg

* update dup output error msg

* stage add: add test for duplicated output error msg

* cleanup OutputDuplicationError code
2023-03-23 15:54:44 +00:00
Ruslan Kuprieiev 40484e8d57 dvcfs: handle broken symlink/TreeError (#9231)
* plots: handle broken symlink/TreeError

* dvcfs: ls: raise FileNotFoundError on broken symlink/TreeError

* deps: bump dvc-data to 0.45.1
2023-03-23 15:38:21 +02:00
pre-commit-ci[bot]andDavid de la Iglesia Castro 48b56c83dc [pre-commit.ci] pre-commit autoupdate (#9168)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/charliermarsh/ruff-pre-commit: v0.0.254 → v0.0.257](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.254...v0.0.257)
- [github.com/codespell-project/codespell: v2.2.2 → v2.2.4](https://github.com/codespell-project/codespell/compare/v2.2.2...v2.2.4)

* pre-commit: fix ruff errors

* pre-commit: fix flake8

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: David de la Iglesia Castro <[email protected]>
2023-03-23 13:05:31 +00:00
Peter Rowlands f8bbf20b77 exp: use individual q for timeout dependent tests 2023-03-23 19:18:52 +09:00
Peter Rowlands cd2c4d0caf tests: remark flaky queue tests as xfail on windows 2023-03-23 19:18:52 +09:00
David de la Iglesia Castro 9b329d01bf api: Add exp_save. 2023-03-23 10:33:55 +01:00
dependabot[bot] 5c442cb867 build(deps-dev): bump pylint from 2.17.0 to 2.17.1 (#9229)
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.17.0 to 2.17.1.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.17.0...v2.17.1)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-23 09:24:52 +01:00
Ruslan Kuprieiev 2d5c15bee1 erepo: move legacy exceptions to api (#9228)
* erepo: get rid of NoRemoteInExternalRepoError

This exception hasn't been making any sense at all since we've introduced
get and import, as they can be chained in repos.

* erepo: get rid of NoOutputInExternalRepoError

This is dead code these days.

* erepo: get rid of FileMissingError and PathMissingError

* api: preserve legacy exc wrappers
2023-03-23 01:40:42 +02:00
Peter Rowlands 7868c1301c exp: enforce waiting for task completion in CI 2023-03-22 18:58:42 +09:00
Ruslan Kuprieiev dfe76c54d7 erepo: set subrepos/uninitialized explicitly 2023-03-22 02:26:44 +02:00
Ruslan Kuprieiev 392c15e1d4 erepo: pass rev instead of fs/scm
Towards unifying `Repo.open` and `external_repo` behaviour to get rid
of the latter.
2023-03-22 00:21:25 +02:00
David de la Iglesia Castro 121d56b739 hydra: resolve OmegaConf interpolations. (#9212)
Closes #9196
2023-03-20 21:38:22 +05:45
skshetry 66406e6c99 scm: fetch_all_exps pass kwargs to scm.fetch_refspecs (#9214) 2023-03-20 21:26:24 +05:45
skshetry 8399bf612a sconfig: add support for studio token (#9213)
config: add support for studio token
2023-03-20 20:59:52 +05:45
daniele 6c1b786564 parsing: fix foreach resolution with int keys (#8904) 2023-03-20 18:40:30 +05:45
Oded Messerandpre-commit-ci[bot] d1c5fcc1b8 Add template for epic/story issues (#9208)
* Add template

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-03-20 09:56:55 +01:00
skshetry 4ee3271b0c dvc.repo.exp: import some modules lazily (#9207) 2023-03-18 17:24:01 +05:45
skshetry dae8515933 plots: small refactorings (#9206) 2023-03-17 19:42:27 +05:45
Saugat Pachhai (सौगात) f02dd83e53 close all streams in child 2023-03-17 14:43:44 +02:00
skshetry a2066d75f9 add a note why we are flushing (#9205) 2023-03-17 17:52:04 +05:45
skshetry 283d8245e1 flush streams before fork (#9203) 2023-03-17 17:14:34 +05:45
skshetry c52b12ac2a dvcfs: support caching remote streams; use that in plots (#9183)
* dvcfs: support caching remote streams; use that in plots

* plots: show progress bar, cap max_workers to 16

* bump dvc-data to 0.44.1
2023-03-17 16:04:16 +05:45
Peter Rowlands 440cb9d2bc ui: flush stdout/stderr before colorama re-init 2023-03-17 14:52:30 +09:00
David de la Iglesia Castro 2d820cccad deps: bump dvc-render>=0.3.1<0.4.0.
For https://github.com/iterative/dvc-render/pull/124
2023-03-16 21:36:02 +01:00
skshetry 30c3e3e4d4 exp push: set default endpoint (#9198) 2023-03-16 17:50:38 +05:45
skshetry 58029e9719 exp push: push experiments revs to studio (#9160)
* exp push: push experiments revs to studio

* log json data that is sent
2023-03-16 11:24:50 +05:45
Ruslan Kuprieiev 990e834f1d repo: open: handle bare git repos
If we are asked to open a potentially unitialized repo, we need to make sure
it is not a bare git repo, so that we don't accidentally start putting dvc
files inside git control dir.

Discovered while working on #8789
2023-03-16 02:03:31 +02:00
Ruslan Kuprieiev 33a2449c91 deps: repo: use _get_rev when creating dvcfs 2023-03-16 01:05:04 +02:00
Ruslan Kuprieiev e2ce95e17e deps: repo: pass url explicitly to DVCFileSystem
Otherwise our wrapper ignores it.
2023-03-16 00:35:15 +02:00
Ruslan Kuprieiev 53f9953cd1 index: data: support imports
Stepping stone to simplifying `dvc fetch/pull` by using index.

Fetch handles regular imports through index already, but not repo
imports because their processing is much more involved (e.g. chained
imports) in the current arch.

With `FileStorage` support introduced into `DataIndex` and `datafs`
supporting imports overall, `dvcfs` can now handle repo imports (even
chained ones). This will soon allow us to handle repo imports the same
way we handle regular ones, improve performance and get rid of a lot of
messy code (e.g. DependencyRepo).

Related https://github.com/iterative/scmrepo/issues/207
Related https://github.com/iterative/dvc-data/pull/315
Related https://github.com/iterative/studio/issues/5261
2023-03-15 20:32:13 +02:00
skshetry e6419b939d do not disable colorama in tests (#9187)
skip disabling colorama in tests

It might affect pytest as it wraps sys.stderr/sys.stdout for capsys fixture.
This is a temporary hack, as we might get rid of colorama soon.
2023-03-15 18:23:26 +05:45
Ruslan Kuprieiev 37ccc5e8d8 repo: create site_cache_dir with proper perms
Fixes #9184
2023-03-15 14:26:17 +02:00
skshetry 8312eb9b42 ui: disable colorama on write_json when highlighting is disabled (#9186)
On a large json output (say ~300MB), this saves about ~6 seconds of time.
2023-03-15 17:42:45 +05:45
Ruslan Kuprieiev c8745dd580 deps: bump dvc-data to 0.44.0 2023-03-15 03:41:19 +02:00
Ruslan Kuprieiev 1cf8b5e582 install: pre-commit: install all deps by default
Fixes #9178
2023-03-15 01:19:42 +02:00
Dave Berenbaum 12955da3c3 exp: fail fast in empty git repo (#8840) 2023-03-14 17:16:17 +00:00
David de la Iglesia Castro e73cc9b40a exp: Include STUDIO_REPO_URL in run_env.
Closes #8951.
2023-03-14 13:43:03 +01:00
Ruslan Kuprieiev b56f6b69dd exp: push/pull: don't include baseline commit
Fixes #6592
2023-03-14 14:00:14 +02:00
Ruslan Kuprieiev 54a6709d99 Update pyproject.toml 2023-03-13 21:03:33 +02:00
Ruslan Kuprieiev e4a5a2aec5 deps: bump dvc-data to >=0.43.0 2023-03-13 21:03:33 +02:00
skshetry 16ecd53b71 tests: remove gc.collect() from windows (#9159) 2023-03-13 13:37:57 +05:45
Ruslan Kuprieiev 612f3039e0 repo: move state/index/data_index to site_cache_dir
We use all of these for optimization and should not depend on a potentially slow or broken
filesystem on which repository resides (could be HDD or CIFS/NFS/overlayfs/etc).

This PR means a few things:
    * all odd filesystems that dvc repo might be on will work quickly out of the box
    * when we start caching cloned repositories for `dvc get/import`, we will be
      able to cache indexes for them as well (note that bare clones don't have a
      worktree so there is no place for .dvc/tmp with the old approach).
    * `index.dir` and `state.dir` are now obsolete.
    * `dvc init` will cleanup site_cache_dir.

Related #5562
2023-03-13 02:58:23 +02:00
Ruslan Kuprieiev 17f523bf86 deps: bump dvc-data to >=0.42.3 2023-03-11 02:01:31 +02:00
Ruslan Kuprieiev a0bf2d997a repo: data_index: fallback to in-memory
Makes for a much simpler resource management elsewhere.
2023-03-11 01:23:12 +02:00
Ruslan Kuprieiev 8ed9b911db deps: bump dvc-data to >= 0.42.2 2023-03-10 22:40:59 +02:00
skshetry ef22b1d77e plots: disable syntax highlighting on plots json output (#9155)
I don't think it's worth it to highlight given the size of json output.
2023-03-11 00:50:06 +05:45
skshetry aaa825a9a8 config: ignore unspecified keys from feature section (#9153)
A warning is shown to the user for the unsupported/ignored keys, and then ignored.
The warning is raised only once per interpreter session.
2023-03-10 21:52:05 +05:45
Ivan Shcheklein 2a40a55bb4 fix(exp): cleanup help messages 2023-03-10 11:13:06 +09:00
Ruslan Kuprieiev 3aa9f51e36 output: suppress cloud.pull errors on cache collection
Fixes https://github.com/iterative/studio/issues/5261
2023-03-09 22:44:32 +02:00
dependabot[bot] 1cfdc22549 build(deps-dev): bump pylint from 2.16.4 to 2.17.0 (#9141)
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.16.4 to 2.17.0.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.16.4...v2.17.0)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-09 16:23:47 +05:45
skshetry 2b889baa5e plots: avoid printing anything on --json output (#9144) 2023-03-09 16:10:46 +05:45
Peter Rowlands 8589aa4001 tests: mark test_queue_remove_done xfail 2023-03-09 16:25:09 +09:00
Peter Rowlands 8cbc4c43f1 tests: use session-scoped exp celery fixtures when possible 2023-03-09 16:25:09 +09:00
Peter Rowlands 417c327143 exp: add session-scoped celery test fixtures 2023-03-09 16:25:09 +09:00
Peter Rowlands 204eebaf15 tests: use brancher.switch 2023-03-09 15:02:26 +09:00
Peter Rowlands 3a6fd75d98 repo: use brancher.switch 2023-03-09 15:02:26 +09:00
Peter Rowlands 351b952d5f brancher: add brancher.switch helper 2023-03-09 15:02:26 +09:00
dberenbaum fe7db32311 studio: handle revision errors when posting 2023-03-08 22:19:32 +01:00
Ivan Shcheklein 0bd34c8977 fix(push): allow no default remote 2023-03-08 21:26:47 +02:00
skshetry 48a63ca588 try to improve test speed (#9136)
* tests: fix logic to gc.collect() on Windows + 3.11

* dvc.cli: cache get_main_parser()

* tests: isolate environment on a session-level

* bring back gc.collect()
2023-03-08 22:11:42 +05:45
Gao 4459d6ac57 Add back an dvc ignore test
Original from
https://github.com/iterative/dvc/pull/8767#discussion_r1070778749
2023-03-08 12:03:07 +02:00
skshetry 08a50ee36e tests: error on ResourceWarning (#9123)
* tests: error on ResourceWarning

* run-cache: avoid leaking temp files on Windows

* set returncode to popen to avoid ResourceWarning on gc.collect()
2023-03-08 15:36:10 +05:45
David de la Iglesia Castro f1ea64c4ef studio: Send metrics on done event. (#9027) 2023-03-07 19:47:22 +01:00
dependabot[bot] 7ede45af2d build(deps-dev): bump mypy from 1.0.1 to 1.1.1 (#9126)
Bumps [mypy](https://github.com/python/mypy) from 1.0.1 to 1.1.1.
- [Release notes](https://github.com/python/mypy/releases)
- [Commits](https://github.com/python/mypy/compare/v1.0.1...v1.1.1)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-07 23:13:54 +05:45
skshetry 51db1765ee migrate from appdirs to platformdirs (#9131)
appdirs has been deprecated/unmaintained, platformdirs is now recommended.
Closes #9130.
2023-03-07 23:13:28 +05:45
Peter Rowlands 9101fce761 proc: remove dvc.proc 2023-03-07 18:17:01 +09:00
Peter Rowlands 3f842a205f exp show: fix cached running checkpoint state bug 2023-03-07 16:55:23 +09:00
dependabot[bot] 77e900fed2 build(deps-dev): bump pylint from 2.16.3 to 2.16.4 (#9127)
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.16.3 to 2.16.4.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.16.3...v2.16.4)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-07 10:17:04 +05:45
David de la Iglesia Castro dde456c923 plots: Fix match_defs_renderers when plots are defined in nt format.
`plots.show` returned `definitions` in native `nt` format but sources in `posixpath` format so the matching was failing.

Closes #8689

- Add `test_show_plots_defined_with_native_os_path`.
2023-03-06 19:16:29 +01:00
David de la Iglesia Castro cb9d3529af plots: Remove --from-config 2023-03-06 19:16:29 +01:00
David de la Iglesia Castro 876c10fcf5 plots: Remove unnecessary OrderedDict usage in load_sv. 2023-03-06 19:16:29 +01:00
skshetry 93eea0cd42 deps: bump scmrepo to 0.1.15; close subrepo.dvc on tests teardown (#9122) 2023-03-06 20:21:42 +05:45
skshetry 25fd274090 increase timeout for tests to 40 minutes 2023-03-06 20:04:26 +05:45
skshetry ddfa607437 tests: don't leak files/descriptors when tests finish (#9119)
close open files/descriptors when tests finish
2023-03-06 18:06:37 +05:45
skshetry c5a3566e49 deps (tests): require pytest-xdist>=3.2, use -n=logical workers and workstealing scheduler (#9116) 2023-03-06 15:54:45 +05:45
skshetry e7d4f5b24e tests: filter warnings (#9115) 2023-03-06 15:41:45 +05:45
Peter Rowlands 1d2892efac exp show: don't cache collection errors 2023-03-06 15:25:27 +09:00
dependabot[bot] 83835afa69 build(deps-dev): bump pylint from 2.16.2 to 2.16.3 (#9113)
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.16.2 to 2.16.3.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.16.2...v2.16.3)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-06 10:33:02 +05:45
skshetry 4c5d052d8c update ruff to v0.0.254 (#9110) 2023-03-04 17:26:59 +05:45
David de la Iglesia Castro e4d514c990 scm: Remove unused GitMergeError.
Not used after https://github.com/iterative/dvc/pull/9096
2023-03-03 18:09:57 +01:00
David de la Iglesia Castro baeecd1972 deps: Bump scmrepo>=0.1.14 2023-03-03 15:42:41 +01:00
David de la Iglesia Castro dbd098506c deps: Drop dvclive.
See https://github.com/iterative/dvclive/pull/481
2023-03-03 14:45:48 +01:00
Ruslan Kuprieiev 4779c248f8 deps: bump dvc-data to >=0.42.1 2023-03-02 17:53:07 +02:00
Peter Rowlands 2cf3a12e46 tests: unmark exp celery tests as xfail 2023-03-02 15:44:34 +09:00
Peter Rowlands 78fb5275e5 exp: add dvc exp clean command 2023-03-02 12:35:54 +09:00
Peter Rowlands ccbe2de89e exp: auto cleanup celery on queue worker exit 2023-03-02 12:35:54 +09:00
Peter Rowlands 54e39e4abd deps: bump dvc-task to >=0.2.0 2023-03-02 12:35:54 +09:00
Ruslan Kuprieiev 59a4c4f67c remote: set hash_name as md5
Fixes #7977
2023-03-01 13:26:24 +02:00
Peter Rowlands 1a7ae16f69 exp: use stash-apply instead of merge 2023-03-01 19:11:12 +09:00
Peter Rowlands 286f4fda3e repo: call Repo.close() on Repo.__exit__() 2023-03-01 17:49:27 +09:00
Peter Rowlands d2c63bffcb exp: ensure repo instance is closed after executor.reproduce 2023-03-01 17:49:27 +09:00
Peter Rowlands 2b41305c51 exp: fix queued run file descriptor leak 2023-03-01 17:49:27 +09:00
Ruslan Kuprieiev 546becddaf deps: bump dvc-gs to 2.22.0 2023-03-01 08:36:33 +02:00
David de la Iglesia Castro c6015a05a3 exp save: Don't relink during commit
Same change as in https://github.com/iterative/dvc/pull/9076 but for `exp save`
2023-02-28 22:29:57 +02:00
Ruslan Kuprieiev c0754ee5b3 deps: bump dvc-data to 0.42.0 2023-02-28 14:48:34 +02:00
skshetry 4db2e89938 build: use macos-11 to build package (#9091)
macos-10.15 image has been deprecated for a while, see https://github.blog/changelog/2022-07-20-github-actions-the-macos-10-15-actions-runner-image-is-being-deprecated-and-will-be-removed-by-8-30-22/ and https://github.com/actions/runner-images/issues/5583.

setup-ruby removed the support for these images yesterday: https://github.com/ruby/setup-ruby/pull/467.

which fails our package builds. Now using macos-11 to build packages.
2023-02-28 17:33:05 +05:45
skshetry 4a6f3ed64a dvc.testing: fix lockfile in docker_services fixture (#9088)
dvc.testing.docker_services: rollback to previous state

where we were not tearing down the containers
2023-02-28 16:54:33 +05:45
David de la Iglesia Castro 9f0c4350bd deps: Bump scmrepo>=0.1.13.
Closes #9080
2023-02-28 17:46:09 +09:00
Ruslan Kuprieiev a91528c3c9 Revert "testing: fixtures: fix docker regression"
This reverts commit b80d84e689.
2023-02-27 15:02:22 +02:00
Ruslan Kuprieiev b80d84e689 testing: fixtures: fix docker regression 2023-02-27 14:17:07 +02:00
skshetry 2a2c02c184 remove typing.cast (#9082) 2023-02-26 13:15:54 +05:45
Dave Berenbaum 35b648bbcf plots: shorten names in the legend (#8900)
* plots: shorten field names

* plots: handle missing field names

* plots: make compatible with py3.8

* plots: fix for missing data

* plots: add test for field shortening

* plots: strip separators regardless of os

* plots: don't shorten field name

* plots: drop test for shortening field name
2023-02-24 17:26:16 +01:00
Peter Rowlands 96ac321dd5 repo: use local root when determining state/index db dirname 2023-02-24 16:33:42 +09:00
Peter Rowlands 50fd8ca15d exp show: cache git refs per show() call 2023-02-24 16:33:26 +09:00
David de la Iglesia Castro 184cc35cf0 pull: Add allow_missing flag.
Allows `pull` to succeed even if some files or directories are missing.

Closes #4746
2023-02-24 09:11:50 +02:00
Ruslan Kuprieiev 81da91a973 exp: run: don't relink during commit
Part of #8809
2023-02-24 08:09:35 +02:00
Peter Rowlands ad5b91e51a exp show: cache collected git revs 2023-02-24 14:18:58 +09:00
Peter Rowlands 391cf80e7b exp: support caching collected exp data 2023-02-24 14:18:58 +09:00
Peter Rowlands 8d13486048 exp: add SerializableExp dataclasses 2023-02-24 14:18:58 +09:00
Ruslan Kuprieiev 37761a2627 data: status: get rid of --not-in-remote 2023-02-21 12:32:40 +02:00
Ruslan Kuprieiev 968a8fde99 data: status: introduce --remote-refresh 2023-02-21 12:32:40 +02:00
David de la Iglesia Castro 3043b6588f exp save: Use pathspec to handle include_untracked.
Closes #9061
2023-02-21 09:43:25 +01:00
47208533a2 Add metrics_show to dvc.api (#9042)
* refactor: add metrics_show, rename module to show

* tests: add functional tests for metrics_show

* api.show: return empty dict for no params/metrics

* test_show: Return relpaths in `metrics_repo`.

---------

Co-authored-by: codamuse <[email protected]>
Co-authored-by: David de la Iglesia Castro <[email protected]>
2023-02-20 21:53:38 +00:00
Ruslan Kuprieiev 09ccd9c7e4 repo: data_index: store in .dvc/tmp/index/data 2023-02-20 21:57:27 +02:00
Ruslan Kuprieiev cd9dd0a312 index: use has_node instead of ls
Current code doesn't work for prefixes longer than one, which makes index cache
effectively not work and it should've used has_node from the very start anyway.
2023-02-20 17:45:15 +02:00
Ruslan Kuprieiev 6fbbbeccc5 index: store data index under tree prefix
Tidying it up, so root of the index will look like this:

```
tree/
remote/
```

This hasn't been released yet, so we are not breaking anything.
2023-02-20 13:33:22 +02:00
Ruslan Kuprieiev c34cbf63af data: status: introduce --not-in-remote
Also supports cloud versioning.

Fixes #8761
2023-02-20 12:25:17 +02:00
Ruslan Kuprieiev b76aad8d56 data: status: rename with_missing to not_in_cache 2023-02-20 12:25:17 +02:00
Ruslan Kuprieiev 68bf095eae remote: rename index prefix from remotes to remote 2023-02-20 12:24:46 +02:00
Ruslan Kuprieiev ea6e01d0e0 dvcfs: implement get_file
Currently we use `open`, which is much slower. For example,

```
$ dvc get dvc-bench data/small/dataset
```

goes down from 110sec to 50sec.

Discovered as a part of https://github.com/iterative/dvc-bench/issues/419
2023-02-20 11:10:13 +02:00
dependabot[bot]andSaugat Pachhai 19038b32bd build(deps-dev): unpin pytest-docker
* fix docker fixtures and unpin pytest-docker
* git_server: mount volume to different /custom-cont-init.d

---------
Co-authored-by: Saugat Pachhai (सौगात) <[email protected]>
2023-02-20 12:57:31 +05:45
Peter Rowlands 648edd71eb exp: move apply tests into their own module 2023-02-20 14:36:38 +09:00
Peter Rowlands 0c95cde712 exp: remove unused ApplyConflictError 2023-02-20 14:36:38 +09:00
Peter Rowlands e218431f64 apply: add --no-force deprecation message 2023-02-20 14:36:38 +09:00
Peter Rowlands d3182e0dd9 exp apply: drop --no-force CLI option 2023-02-20 14:36:38 +09:00
Peter Rowlands e040e875dc exp apply: simplify apply behavior to use checkout instead of merge 2023-02-20 14:36:38 +09:00
Peter Rowlands 303da84b18 exp: add ApplyStash implementation 2023-02-20 14:36:38 +09:00
Peter Rowlands 03bfdf2663 deps: use ranges for dvc sub-packages 2023-02-20 14:35:08 +09:00
skshetry 8edaef0103 deps: drop importlib-resources and typing-extensions (#9055)
deps: remove importlib-resources and typing-extensions
2023-02-19 11:36:48 +05:45
skshetry fd8a8c2729 pyproject: format using pyproject-fmt (#9053)
I haven't added pyproject-fmt to pre-commit hook because of two reasons:
1. There is a bug that keeps adding empty lines after `[[tool.mypy.overrides]]`.
2. The list gets exploded to multiple lines. However, this is a minor issue.
2023-02-18 23:07:57 +05:45
dependabot[bot] 30337bf0ba build(deps): bump pyinstaller from 5.7.0 to 5.8.0 (#9013)
Bumps [pyinstaller](https://github.com/pyinstaller/pyinstaller) from 5.7.0 to 5.8.0.
- [Release notes](https://github.com/pyinstaller/pyinstaller/releases)
- [Changelog](https://github.com/pyinstaller/pyinstaller/blob/develop/doc/CHANGES.rst)
- [Commits](https://github.com/pyinstaller/pyinstaller/compare/v5.7.0...v5.8.0)

---
updated-dependencies:
- dependency-name: pyinstaller
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-18 22:53:17 +05:45
skshetry 5426ca6f79 deps (tests): unpin test deps (#9052) 2023-02-18 22:41:50 +05:45
skshetry a89c25700f pyproject.toml: cleanup metadata (#9051) 2023-02-18 17:40:36 +05:45
dependabot[bot] 0e0bb8ad76 build(deps-dev): bump mypy from 0.991 to 1.0.1 (#9049)Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [mypy](https://github.com/python/mypy) from 0.991 to 1.0.1.
- [Release notes](https://github.com/python/mypy/releases)
- [Commits](https://github.com/python/mypy/compare/v0.991...v1.0.1)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-18 17:03:41 +05:45
skshetry 1de37556d5 bump ruff to v0.0.247 (#9050)
* bump ruff to v0.0.247

* ruff: enable pep8-naming check

rename some camelCased APIs, especially in logger
rename G variables to graph
ignore some variable namings and help messages in dvc.commands
2023-02-18 16:50:35 +05:45
Ruslan Kuprieiev 098685b8f3 deps: bump dvc-data to 0.40.4
Improves index view related performance (e.g. `dvc diff`).
2023-02-18 11:35:01 +02:00
Ruslan Kuprieiev 8f549c8a8d config: enable data index caching by default 2023-02-18 08:00:58 +02:00
Ruslan Kuprieiev e56d97bb28 gha: user ubuntu 20.04 for deb packages
18.04 will reach EOL in april and will be dropped by gha.

18.04 also comes with an old sqlite version which forces us to use obsolete
syntax.
2023-02-18 08:00:58 +02:00
Ruslan Kuprieiev 07b72c20e9 repo: move data_index to .dvc/tmp/index 2023-02-17 21:43:57 +02:00
Ruslan Kuprieiev 592f251481 repo: use tmp_dir if available 2023-02-17 21:43:57 +02:00
Ruslan Kuprieiev 890c0020ed Revert "repo: use tmp_dir if available"
This reverts commit 7ccf35b47e.
2023-02-17 21:25:46 +02:00
Ruslan Kuprieiev 7ce0b1cba2 Revert "repo: move data_index to .dvc/tmp/index"
This reverts commit d68599a5f7.
2023-02-17 21:25:46 +02:00
Ruslan Kuprieiev b8a9c37af5 Revert "config: enable data index caching by default"
This reverts commit 1af63acae5.
2023-02-17 21:25:46 +02:00
Ruslan Kuprieiev 1af63acae5 config: enable data index caching by default 2023-02-17 19:55:25 +02:00
Ruslan Kuprieiev d68599a5f7 repo: move data_index to .dvc/tmp/index 2023-02-17 19:55:25 +02:00
Ruslan Kuprieiev 7ccf35b47e repo: use tmp_dir if available 2023-02-17 19:55:25 +02:00
Ruslan Kuprieiev 4f49023a08 config: don't set default cache dir
Setting default values is very untypical for all other applications and the
info config has is not enough to make a decision on the default cache dir,
especially when dealing with gitfs.

Fixes #8705
2023-02-17 07:57:39 +02:00
skshetry d7ea7c358d Revert "scm: use dulwich backend when fetching exps during clone/pull" (#9041)
Revert "scm: use dulwich backend when fetching exps during clone/pull (#9023)"

This reverts commit ed1ab7fa75.
2023-02-16 18:07:45 +05:45
dependabot[bot] 3f0da8f6cc build(deps-dev): bump scmrepo from 0.1.10 to 0.1.11 (#9039)Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [scmrepo](https://github.com/iterative/scmrepo) from 0.1.10 to 0.1.11.
- [Release notes](https://github.com/iterative/scmrepo/releases)
- [Commits](https://github.com/iterative/scmrepo/compare/0.1.10...0.1.11)

---
updated-dependencies:
- dependency-name: scmrepo
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-16 18:03:13 +05:45
David de la Iglesia Castro b7b7eff4a3 tests: Fix test_deleted.
Closes #6297
#9017 actually fixed this but the test was incorrect (something wrong with caplog).
2023-02-16 11:43:09 +01:00
skshetry ddeb32ed33 ui: log footer support message to standard error (#9034) 2023-02-16 11:31:31 +05:45
Ruslan Kuprieiev c7be921f44 cachemgr: don't use tmp_dir
We used to use it in gdrive before https://github.com/iterative/PyDrive2/pull/211
2023-02-16 06:43:20 +02:00
Ruslan Kuprieiev c95c3f0f7a deps: limit types-tqdm
See https://github.com/iterative/dvc/pull/9036
2023-02-16 06:43:20 +02:00
skshetry be824ede0d render: avoid deepcopying (#9033)
* render: avoid deepcopying

* remove unnecessary line
2023-02-15 16:25:45 +05:45
Ruslan Kuprieiev cbe46cccd8 data: status: fix typo
Leftover from #9031
2023-02-15 07:18:19 +02:00
Ruslan Kuprieiev 49b5157abe diff: use index 2023-02-15 06:40:02 +02:00
Ruslan Kuprieiev 6f87c14bf9 data: status: bring back ui.status 2023-02-15 05:57:50 +02:00
Ruslan Kuprieiev 0f80d16ba7 data: status: fix typing 2023-02-15 05:57:50 +02:00
Ruslan Kuprieiev 4b23b4f8ae repo: cache index for cloud versioning
This allows us to reuse cloud versioning index that we've built in other
operations like `data status`.

Note, this only works with `dvc config feature.data_index_cache true`
right now.

Also note that index is not populated for regular remotes, it will come
in a separate PR as there are some http-related issues to figure out.

Related #8962
2023-02-15 04:53:48 +02:00
Ruslan Kuprieiev 446871d84f index: build_data_index: use dvcignore
Fixes #9008
2023-02-14 21:33:43 +02:00
dependabot[bot] 99bbe15980 build(deps-dev): bump pylint from 2.16.1 to 2.16.2 (#9020)
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.16.1 to 2.16.2.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.16.1...v2.16.2)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-14 22:35:59 +05:45
David de la Iglesia Castro 320771551b exp: Preserve staged changes after experiments.
- Detach head after stashing workspace.
- Use reinstate_index.
2023-02-14 16:59:10 +01:00
David de la Iglesia Castro 1676d1f344 Add test_stash_exp. 2023-02-14 16:59:10 +01:00
David de la Iglesia Castro c8ae2895f0 deps: bump scmrepo==0.1.10
https://github.com/iterative/scmrepo/releases/tag/0.1.10
2023-02-14 16:59:10 +01:00
skshetry ed1ab7fa75 scm: use dulwich backend when fetching exps during clone/pull (#9023)
refspecs uses pygit2 backend by default, which does not support git credential
helpers. This PR forces to use dulwich backend during clone/pull operations.
2023-02-14 19:18:40 +05:45
Karan Jakhar 73497dae9e Handle filenames which has ":" (#9000)
* Fixes #8773 issue

* added test for #8773 issue

* skip test for windows
2023-02-14 11:21:32 +00:00
skshetry eff775c760 brancher: add trace when switching filesystem (#9022)
brancher: add trace info when switching filesystem
2023-02-14 15:27:18 +05:45
Ruslan Kuprieiev e73d662686 repo: introduce data_index
Extracting from `index.data` as a "root" data index that contains indexes
for different revisions/workspaces.

This is a setup for putting cloud versioning remote indexes and also replacing
old state.
2023-02-13 06:31:44 +02:00
Ruslan Kuprieiev 86a6fb104a index: experimental persistent data index
Related https://github.com/iterative/dvc-data/issues/208
2023-02-13 02:57:30 +02:00
Ruslan Kuprieiev 3b097dcccd deps: bump dvc-data to 0.40.1 2023-02-12 09:12:08 +02:00
David de la Iglesia Castro e910dac0dc Update pyproject.toml 2023-02-10 10:59:32 +01:00
David de la Iglesia Castro 17a71d6011 plots: Rename template_path to html_template. 2023-02-10 10:59:32 +01:00
dependabot[bot] 5a6ccc8027 build(deps-dev): bump dvc-render from 0.1.1 to 0.1.2
Bumps [dvc-render](https://github.com/iterative/dvc-render) from 0.1.1 to 0.1.2.
- [Release notes](https://github.com/iterative/dvc-render/releases)
- [Commits](https://github.com/iterative/dvc-render/compare/0.1.1...0.1.2)

---
updated-dependencies:
- dependency-name: dvc-render
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-02-10 10:59:32 +01:00
pre-commit-ci[bot] 6dccfcb3f9 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2023-02-10 04:47:57 +02:00
karajan1001 2b0c365f35 Fix some mypy error. 2023-02-10 04:47:57 +02:00
dberenbaum 611e2f4311 update rich 2023-02-09 23:18:50 +02:00
dberenbaum 561a375b48 update: drop worktree from cli 2023-02-09 23:03:50 +02:00
skshetry e51345e276 get/import: lazy import dvc.scm; reduces dvc --help by ~20% (#8996) 2023-02-09 15:04:55 +05:45
skshetry 00e61e18ae logging: do not disable other loggers (#8995)
Closes https://github.com/iterative/dvc/issues/8631
2023-02-09 15:04:29 +05:45
skshetry 5490fc00d1 logger: check isatty stream to print colored logs or not instead of depending on colorama (#8993
logger: check isatty stream to print colored logs or not
2023-02-09 13:50:38 +05:45
skshetry f1043676da [WIP] logging: change from dictConfig to equivalent code for creating logge… (#8985
logging: change from dictConfig to equivalent code for creating loggers/handlers/formatters

dictConfig clears all handlers, and potentially disables existing loggers (we disabled this functionality
though). There's much more code than necessary in dictConfig than what we need.

I have tried to keep the setup equivalent to what we had in the config, so I have not tried to cleanup
the code.
2023-02-09 09:34:14 +05:45
Ruslan Kuprieiev f7ebcbb974 deps: bump dvc-data to 0.39.3 2023-02-09 05:44:50 +02:00
dependabot[bot] c637b963e0 build(deps-dev): bump dvc-azure from 2.21.0 to 2.21.1 (#8991)
Bumps [dvc-azure](https://github.com/iterative/dvc-azure) from 2.21.0 to 2.21.1.
- [Release notes](https://github.com/iterative/dvc-azure/releases)
- [Commits](https://github.com/iterative/dvc-azure/compare/2.21.0...2.21.1)

---
updated-dependencies:
- dependency-name: dvc-azure
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-09 08:31:13 +05:45
Ruslan Kuprieiev 9156bb80db output: rename odb -> cache 2023-02-09 00:44:18 +02:00
Ruslan Kuprieiev 58295ca0ab repo: rename odb -> cache
We used to have it named `cache` before, but these days it is clear that
you can have three odbs: just odb (e.g. in-memory), cache (typically local)
or remote (typically cloud). Fixing naming here before proceeding with
introducing `out.odb` and `out.cache`.

In preparation for migration to https://github.com/iterative/dvc-data/pull/304
2023-02-08 23:05:45 +02:00
skshetry 4176007493 push: check if versioning is supported or not during checkout on cloud versioning (#8949)Fixes https://github.com/iterative/dvc/issues/8824
* push: check if versioning is supported or not during checkout on cloud versioning

* bump dvc-data to 0.38.4
2023-02-08 17:05:27 +05:45
dependabot[bot]andGao 9d7883f529 build(deps-dev): bump pytest-xdist from 3.1.0 to 3.2.0 (#8981)
Bumps [pytest-xdist](https://github.com/pytest-dev/pytest-xdist) from 3.1.0 to 3.2.0.
- [Release notes](https://github.com/pytest-dev/pytest-xdist/releases)
- [Changelog](https://github.com/pytest-dev/pytest-xdist/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-xdist/compare/v3.1.0...v3.2.0)

---
updated-dependencies:
- dependency-name: pytest-xdist
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Gao <[email protected]>
2023-02-08 07:31:21 +00:00
Peter Rowlands 93c556acdd index: fix index entries for partial import stages 2023-02-08 15:34:15 +09:00
Peter Rowlands 676b1e47e9 import-url: update stage md5 after unpartialing imports 2023-02-08 15:34:15 +09:00
Peter Rowlands 0b141ac08a testing: test cloud versioned import-url --no-download 2023-02-08 15:34:15 +09:00
dependabot[bot] b4db1e06a1 build(deps-dev): bump dvc-render from 0.1.0 to 0.1.1 (#8982)
Bumps [dvc-render](https://github.com/iterative/dvc-render) from 0.1.0 to 0.1.1.
- [Release notes](https://github.com/iterative/dvc-render/releases)
- [Commits](https://github.com/iterative/dvc-render/compare/0.1.0...0.1.1)

---
updated-dependencies:
- dependency-name: dvc-render
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-08 09:11:42 +05:45
dependabot[bot] 0d0fff6ddc build(deps-dev): bump dvc-data from 0.38.1 to 0.38.3 (#8983)
Bumps [dvc-data](https://github.com/iterative/dvc-data) from 0.38.1 to 0.38.3.
- [Release notes](https://github.com/iterative/dvc-data/releases)
- [Commits](https://github.com/iterative/dvc-data/compare/0.38.1...0.38.3)

---
updated-dependencies:
- dependency-name: dvc-data
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-08 09:11:28 +05:45
Hagai Kariti 6c8c26f741 Support setting a exp name prefix in hydra sweeps 2023-02-07 18:49:23 +01:00
Peter Rowlands f68a12558a testing: mark 00 prefix tests xfail on fs without find() 2023-02-07 15:17:29 +09:00
Ruslan Kuprieiev a8a5b29fb7 deps: bump dvc-data to 0.38.1 (#8976) 2023-02-07 06:58:15 +02:00
skshetry 037e2e54f0 serialization: reorder files section metadata (#8950
serialization: reorder files section
2023-02-07 10:05:36 +05:45
skshetry ae80889477 logging: defer calling colorama.init() in jupyter, otherwise initialize immediately (#8969)Closes https://github.com/iterative/dvc/issues/8957
logging: init colorama before logging if outside jupyter env

Otherwise, tty detection does not work as `colorama.init()` mutates
sys.stdout/sys.stderr, and after `dictConfig()`, the handlers will hold
on to the stream.
2023-02-07 10:05:05 +05:45
Gao e1acab5113 Use pygit2 backend for fetch_refspecs (#8907)
fix: #8762
1. partly solve #8787 and #8477
2. Improve the performance
3. Bump `scmrepo` into 0.1.9
2023-02-06 16:07:00 +02:00
d84196db62 studio: Move post_live_metrics from queue to executor (#8955)
* studio: Move `post_live_metrics` from `queue/workspace` to `executor/base`.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update dvc/repo/experiments/utils.py

Co-authored-by: skshetry <[email protected]>

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: skshetry <[email protected]>
2023-02-06 13:31:10 +00:00
Peter Rowlands 80c2815e67 deps: bump dvc-data to 0.37.8 2023-02-06 21:18:44 +09:00
Peter Rowlands e42a01a3dd testing: re-add 00 prefix remote traverse tests 2023-02-06 21:18:44 +09:00
Ruslan Kuprieiev 8e1b75feb5 index: build_data_index: handle empty dirs (#8959)
Fixes https://github.com/iterative/dvc/issues/8958
2023-02-06 01:44:15 +02:00
Saugat Pachhai (सौगात) 4ec6d64629 add .git-blame-ignore-revs 2023-02-04 10:02:31 +05:45
skshetry a86470ccbc update black and change line-length to 88 (#8953) 2023-02-04 05:28:07 +02:00
dependabot[bot] 5d2701341b build(deps-dev): bump pylint from 2.16.0 to 2.16.1 (#8944)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-03 14:06:36 +05:45
Peter Rowlands 97589a1358 testing: add tests for pull after import-url --version-aware 2023-02-03 15:50:57 +09:00
Peter Rowlands 9e72ce53cd deps: bump dvc-data to 0.37.5 2023-02-03 15:50:57 +09:00
Peter Rowlands e34a6d3b30 update: fix meta & version ID merge on worktree update 2023-02-03 13:23:04 +09:00
Peter Rowlands 25dcc33580 output: build from files in get_obj() regardless is hash_info set 2023-02-03 13:23:04 +09:00
frederik-sandfort 18fa1a0272 Custom header for dvc webdav (#8933)Fix https://github.com/iterative/dvc/issues/8931
* include custom auth header for webdav

* Revert "include custom auth header for webdav"

This reverts commit d2f2b2889b6bcf0429e4a28076f709a04642ae3a.

* include custom auth header for dvc webdav, ran unit tests

* update dvc-webdav version
2023-02-02 16:36:11 +05:45
dependabot[bot] 49a27f4140 build(deps-dev): bump dvc-render from 0.0.17 to 0.1.0 (#8935)
Bumps [dvc-render](https://github.com/iterative/dvc-render) from 0.0.17 to 0.1.0.
- [Release notes](https://github.com/iterative/dvc-render/releases)
- [Commits](https://github.com/iterative/dvc-render/compare/0.0.17...0.1.0)

---
updated-dependencies:
- dependency-name: dvc-render
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-02 14:13:27 +05:45
dependabot[bot] 9b2aa79c18 build(deps-dev): bump pylint from 2.15.10 to 2.16.0 (#8936)
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.15.10 to 2.16.0.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.15.10...v2.16.0)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-02 14:12:53 +05:45
Ruslan Kuprieiev 24023c6977 index: introduce data_keys (#8938)
`data_keys` are similar to `outs`, but they provide more granularity, so we
can use them in `build_data_index` to rebuild index views with filtered
outputs. E.g. when running `dvc diff dir/file`, workspace index should only
have `dir/file` in it.

This also could be used for standalone (non-output) data in the future.

Pre-requisite for #8930
2023-02-02 05:50:16 +02:00
Ruslan Kuprieiev 5310bcdcec deps: bump dvc-data to 0.37.3 (#8923) 2023-02-02 04:18:18 +02:00
dependabot[bot] ae92154cec build(deps-dev): bump beautifulsoup4 from 4.11.1 to 4.11.2 (#8928)
Bumps [beautifulsoup4](https://www.crummy.com/software/BeautifulSoup/bs4/) from 4.11.1 to 4.11.2.

---
updated-dependencies:
- dependency-name: beautifulsoup4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-01 09:10:50 +05:45
Ruslan Kuprieiev f661cee8f6 stage: use repo.fs directly without copying (#8929)
Otherwise when using brancher we end up in a strange situation where even
though we are collecting targets from `gitfs`, we are still using `localfs`
as `self.fs`, which make operations like `self.fs.abspath` in
`collect_granular` return invalid paths.
2023-02-01 05:21:53 +02:00
Ruslan Kuprieiev e07c85a993 index: collect_targets: introduce onerror (#8925) 2023-02-01 03:49:27 +02:00
Ruslan Kuprieiev 58d9e379fe tests: gc: use timedelta again (#8926)
Leftover from #8912
2023-02-01 03:14:22 +02:00
skshetry 524162dc3f version/info: match dashes' length below DVC version (#8921) 2023-01-31 18:32:04 +05:45
skshetry aa15b21dce logging: log pkg version/type, platform info and cli arguments (#8918)
logging: log pkg version and type, platform info and cli arguments
2023-01-31 15:46:14 +05:45
Peter Rowlands 0404967591 deps: bump dvc-gs to 2.21.1 2023-01-31 17:26:44 +09:00
Peter Rowlands 465d886c29 testing: add tests for version-aware import-url 2023-01-31 15:55:44 +09:00
Peter Rowlands 459adfb40f import-url: disable push on version aware imports before saving 2023-01-31 15:55:44 +09:00
Peter Rowlands fe9f8654a3 testing: add test for worktree update 2023-01-31 15:55:44 +09:00
skshetry 8208846003 bump ruff to 0.0.238 (#8915) 2023-01-31 11:24:03 +05:45
Peter Rowlands 73aea2d972 ci: run dvc-s3 tests on DVC pull requests 2023-01-31 14:13:55 +09:00
Ruslan Kuprieiev 10184e9370 tests: gc: use timedelta (#8912)
Bug from https://github.com/iterative/dvc/pull/8880
2023-01-31 05:18:09 +02:00
Ruslan Kuprieiev 2690f05cee pre-commit: bump isort to 5.12.0
https://github.com/PyCQA/isort/issues/2077
2023-01-31 04:02:24 +02:00
Ruslan Kuprieiev 34c2c95115 index: expose rev property (#8909)
index: add rev property

This is very useful to identify indexes that are built from git revisions
and so are describing an immutable state and can be used for caching.

We were already using this for `__repr__`.
2023-01-30 20:18:54 +02:00
skshetry 5c6c1dc719 mypy: unignore module override (#8902) 2023-01-28 15:08:52 +05:45
98bcfad8e7 build(deps-dev): bump scmrepo from 0.1.6 to 0.1.7 (#8821)
* build(deps-dev): bump scmrepo from 0.1.6 to 0.1.7

Bumps [scmrepo](https://github.com/iterative/scmrepo) from 0.1.6 to 0.1.7.
- [Release notes](https://github.com/iterative/scmrepo/releases)
- [Commits](https://github.com/iterative/scmrepo/compare/0.1.6...0.1.7)

---
updated-dependencies:
- dependency-name: scmrepo
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

* mypy: remove scmrepo from ignored modules

* Fix mypy issues

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: skshetry <[email protected]>
Co-authored-by: Saugat Pachhai (सौगात) <[email protected]>
2023-01-28 14:26:00 +05:45
skshetry 7ab4c59d70 test: run pytest-style checks (#8901) 2023-01-28 14:10:53 +05:45
skshetry a137b2a6bc update ruff and enable flake8-logging-format and flake8-type-checking (#8894)
* update ruff and enable flake8-logging-format and flake8-type-checking check

* Update dvc/external_repo.py

* Update dvc/fs/dvc.py

* Update dvc/repo/experiments/__init__.py

* Update dvc/repo/experiments/queue/base.py

* Update pyproject.toml
2023-01-27 19:14:19 +05:45
Daniele Trifirò 6f0e8a8db5 tests: fix test_iter_revs mock 2023-01-27 12:52:46 +01:00
Daniele Trifirò d294945499 gc: fix usage with --date 2023-01-27 12:52:46 +01:00
Dave Berenbaum db70d1cc5c analytics: differentiate ci users (#8838) 2023-01-26 21:50:14 +05:45
Andrii Korzhuk ed6e11e856 Fixed typo in _format_field function 2023-01-26 13:50:40 +01:00
skshetry c1cd13c34f serialize: fix loading of cloud metadata from .dvc/dvc.lock files (#8889) 2023-01-26 16:18:03 +05:45
David de la Iglesia Castro 12dd746165 output: Pass version_aware=True to fs if files is present.
This will be ignored by filesystems that don't support `version_aware`.

Closes #8853
2023-01-26 10:48:59 +01:00
5165fb67a1 [pre-commit.ci] pre-commit autoupdate (#8869)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/charliermarsh/ruff-pre-commit: v0.0.223 → v0.0.230](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.223...v0.0.230)

* Update .pre-commit-config.yaml

* fix lint issues

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: skshetry <[email protected]>
Co-authored-by: Saugat Pachhai (सौगात) <[email protected]>
2023-01-26 14:24:09 +05:45
Peter Rowlands b2c1c4dccd data_cloud: move version_aware config check to get_remote 2023-01-26 17:21:47 +09:00
Peter Rowlands b060cadbf1 deps: bump dvc-data to 0.36.2 2023-01-26 17:21:47 +09:00
Peter Rowlands 7c55a9c7cd testing: add initial versioned remote tests 2023-01-26 17:03:50 +09:00
Peter Rowlands 037b5b2e0a testing: add cloud versioning remote fixtures 2023-01-26 17:03:50 +09:00
dependabot[bot] 99acb8e335 build(deps-dev): bump dvc-data from 0.36.0 to 0.36.1 (#8887)
Bumps [dvc-data](https://github.com/iterative/dvc-data) from 0.36.0 to 0.36.1.
- [Release notes](https://github.com/iterative/dvc-data/releases)
- [Commits](https://github.com/iterative/dvc-data/compare/0.36.0...0.36.1)

---
updated-dependencies:
- dependency-name: dvc-data
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-26 08:32:02 +05:45
Ruslan Kuprieiev b46cfbda5d deps: bump dvc-data to 0.36.0 (#8885) 2023-01-26 00:22:12 +02:00
Dave Berenbaum a8d193bf2a queue: update kill ui messages (#8798)
* queue: update kill ui messages

* queue kill: update ui, kill all valid tasks

* queue kill: update wording of ui
2023-01-25 20:08:27 +05:45
dependabot[bot] 0b1cf6c771 build(deps-dev): bump dvc-gs from 2.20.0 to 2.21.0 (#8841)
Bumps [dvc-gs](https://github.com/iterative/dvc-gs) from 2.20.0 to 2.21.0.
- [Release notes](https://github.com/iterative/dvc-gs/releases)
- [Commits](https://github.com/iterative/dvc-gs/compare/2.20.0...2.21.0)

---
updated-dependencies:
- dependency-name: dvc-gs
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-25 19:29:21 +05:45
skshetry b3aa698cd4 dumpd: serialize files at the end in .dvc files (#8879) 2023-01-25 18:52:15 +05:45
skshetry bb9a3a0403 import/import-url: try not to delete dvcfile before import/import-url completes (#8876)
* import/import-url: try not to delete dvcfile before import/import-url completes

* use repo.stage.create instead of internal create_stage utility
2023-01-25 18:16:45 +05:45
skshetry 3427e115eb data status: check if change.old.hash_info is None or not (#8878)
data:status: check if change.old.hash_info is None or not
2023-01-25 14:24:38 +02:00
skshetry 3d5f4dc66c add support for output-specific remotes (#8862)
Also splits metadata in `files` to cloud vs local. But this happens
during dump/load, so actual behaviour is changed. During runtime,
the metadata is merged and loaded. During dump, the metadata
are split if there is a `remote` set.
2023-01-25 18:06:12 +05:45
David de la Iglesia Castro 80633f4fad stage.save: Remove merge_versioned option.
If we want `add`, `commit` and `move` to work for cloud versioning, option must be always True so it is the same as not having it.

Closes #8828
(We were not passing `merge_versioned=True` in `dvc commit`)
2023-01-25 10:35:37 +01:00
Ruslan Kuprieiev 8bda3650c5 deps: bump dvc-data to 0.35.3 2023-01-24 23:06:34 +02:00
David de la Iglesia Castro ea2e5dc3e5 output: Don't serialize hash_info or meta in cloud versioning.
Closes #8357
2023-01-24 18:40:39 +01:00
dependabot[bot] 61afdca3a6 build(deps-dev): bump dvc-data from 0.35.1 to 0.35.2 (#8871)
Bumps [dvc-data](https://github.com/iterative/dvc-data) from 0.35.1 to 0.35.2.
- [Release notes](https://github.com/iterative/dvc-data/releases)
- [Commits](https://github.com/iterative/dvc-data/compare/0.35.1...0.35.2)

---
updated-dependencies:
- dependency-name: dvc-data
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-24 20:47:16 +05:45
Ruslan Kuprieiev 6a6bc7035a data: status: use data index (#8846)
Pre-requisite for #8761
2023-01-23 21:29:32 +02:00
Ruslan Kuprieiev ccc97622fa deps: bump dvc-ssh to 2.21.0 (#8865)
* deps: bump dvc-ssh to 2.21.0

* Update pyproject.toml
2023-01-23 01:36:52 +02:00
Ruslan Kuprieiev 916b5d169f deps: bump dvc-azure to 2.21.0 2023-01-23 00:46:58 +02:00
Peter Rowlands 38e9b2ba95 deps: bump dvc-data to 0.35.1 2023-01-21 03:44:02 +09:00
Dave Berenbaumandskshetry 18f039d7c7 add viztracer async option (#8856)
* add viztracer async option

* Update dvc/_debug.py

Co-authored-by: skshetry <[email protected]>
2023-01-20 22:29:11 +05:45
skshetry f1c9e9365b remove setup.py file (#8851) 2023-01-20 20:26:13 +05:45
Ruslan Kuprieiev b50d1ee674 deps: bump dvc-data to 0.35.0 2023-01-20 04:16:12 +02:00
Peter Rowlands 1c33024b2c deps: bump dvc-data to 0.34.0 2023-01-19 19:09:45 +09:00
David de la Iglesia CastroandPeter Rowlands dd2d2dce19 param: Fix status check for Tuples.
Closes #8803

Update dvc/dependency/param.py

Co-authored-by: Peter Rowlands (변기호) <[email protected]>
2023-01-19 08:19:16 +01:00
David de la Iglesia Castro 5f558d003a deps: bump dvc-data to 0.33.0
- Update `test_gc`
2023-01-18 15:17:07 +02:00
David de la Iglesia Castro 3676f35b7c output.remove: Pass explicit recursive flag.
Per changes in https://github.com/iterative/dvc-objects/pull/176
2023-01-18 15:17:07 +02:00
David de la Iglesia Castro 9af6fcad4a exp run: Fix --dry option.
Closes #8831
2023-01-17 13:32:20 +01:00
skshetry 6d80b72434 lint: run lint checks on all platforms (#8832) 2023-01-17 10:51:57 +05:45
pre-commit-ci[bot] 46d9290fc2 [pre-commit.ci] pre-commit autoupdate (#8830)
updates:
- [github.com/charliermarsh/ruff-pre-commit: v0.0.222 → v0.0.223](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.222...v0.0.223)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-01-17 08:55:33 +05:45
skshetry c47c2123fb cleanup linters: get rid of pylint-pytest, run pylint only on dvc/ directory, etc (#8822)
* cleanup linters: get rid of pylint-pytest, run pylint only on dvc/ directory, etc.

* remove pylint direcitves

* Apply suggestions from code review

* Update pyproject.toml
2023-01-17 08:35:19 +05:45
Dave Berenbaum d25d26ff74 exp: drop some words from exp names (#8811) 2023-01-16 17:11:04 +01:00
Peter Rowlands c2e4f51479 serialize: fix mypy error 2023-01-16 15:58:21 +09:00
Peter Rowlands 977a1f9f43 tests: update for dvc-objects batched transfer 2023-01-16 15:58:21 +09:00
Peter Rowlands 608269dc88 status: remove deprecated/unused dvc-data.hashfile.status flag 2023-01-16 15:58:21 +09:00
Peter Rowlands e48d0d1d9c tests: remove duplicated dvc-objects/dvc-data tests 2023-01-16 15:58:21 +09:00
Peter Rowlands bf08bd3f12 deps: bump dvc-data to 0.32.0 2023-01-16 15:58:21 +09:00
dependabot[bot] db5dfdd6bc build(deps-dev): bump pytest from 7.2.0 to 7.2.1 (#8819)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.2.0 to 7.2.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.2.0...7.2.1)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-16 08:37:15 +05:45
dependabot[bot] 3b10f40ca3 build(deps-dev): bump dvc-task from 0.1.10 to 0.1.11 (#8820)
Bumps [dvc-task](https://github.com/iterative/dvc-task) from 0.1.10 to 0.1.11.
- [Release notes](https://github.com/iterative/dvc-task/releases)
- [Commits](https://github.com/iterative/dvc-task/compare/0.1.10...0.1.11)

---
updated-dependencies:
- dependency-name: dvc-task
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-16 08:36:39 +05:45
Ruslan Kuprieiev 4660443d0e deps: bump dvc-data to 0.31.4 2023-01-16 04:09:00 +02:00
Ruslan Kuprieiev a92ace0054 deps: bump dvc-data to 0.31.3 2023-01-16 01:16:35 +02:00
skshetry 309ae4d995 mypy: enable check-untyped-defs (#8815) 2023-01-15 21:40:40 +05:45
daniele e1254c9ece Add misc type hints (#8430) 2023-01-15 17:58:34 +05:45
skshetry 7a65ac06b2 mypy: don't ignore all imports, also disallow implicit optional (#8814)
* mypy: don't ignore all imports

* mypy: disallow implicit_optional
2023-01-15 16:25:03 +05:45
skshetry b0052aa666 pre-commit update: flake8/ruff/pyupgrade/black/isort (#8813) 2023-01-15 14:56:54 +05:45
skshetry da27174e02 dvcfile: rename PipelineFile to ProjectFile, get rid of Dvcfile class, cleanups, etc. (#8812)
dvcfile: rename PipelineFile to ProjectFile, get rid of Dvcfile class, cleanups etc
2023-01-15 12:45:10 +05:45
Ruslan Kuprieiev aabdddc2b7 index: introduce build_data_index
This is a generally useful function that builds a data index from repo index.

This is currently only used in cloud versioning, but it is going to be used in
`status`, `diff` and other data-centric operations
2023-01-15 01:45:09 +02:00
karajan1001 fc1a192c90 Bump pathspec to 0.10.3
fix: #8217
1. Replace group name to avoid conflict.
2. Disable failed tests.
3. Bump pathspec to 0.10.3
2023-01-13 22:47:36 +08:00
dependabot[bot]andSaugat Pachhai 178244f666 build(deps-dev): bump dvc-task from 0.1.9 to 0.1.10 (#8807)
* build(deps-dev): bump dvc-task from 0.1.9 to 0.1.10

Bumps [dvc-task](https://github.com/iterative/dvc-task) from 0.1.9 to 0.1.10.
- [Release notes](https://github.com/iterative/dvc-task/releases)
- [Commits](https://github.com/iterative/dvc-task/compare/0.1.9...0.1.10)

---
updated-dependencies:
- dependency-name: dvc-task
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

* remove xfail on json.JSONDecodeError/PermissionError

JSONDecodeError should be fixed by the new release. Next we need to investigate
PermissionError.

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Saugat Pachhai (सौगात) <[email protected]>
2023-01-13 17:25:36 +05:45
skshetry dba7d3c320 mypy: use typesafe cached_property (#8799) 2023-01-13 09:08:59 +05:45
David de la Iglesia Castro 8b075eb754 stage: Skip run-cache if any out has cache: false.
Closes https://github.com/iterative/dvc/issues/4428
2023-01-12 19:10:01 +01:00
David de la Iglesia Castro f507e4d9c0 config: Reraise ConfigError from ConfigObjError.
Closes #8801
2023-01-12 18:11:54 +01:00
skshetry 5169205229 deps: bump minimum version req for grandalf to 0.7. 2023-01-12 18:38:45 +05:45
skshetry 3bcd683677 repo.check_graph: rename method (#8800) 2023-01-12 16:03:51 +05:45
Saugat Pachhai (सौगात) 30ec1cf5e9 index/stage: move repo collection logic to index 2023-01-11 19:38:43 +02:00
skshetry a814f04ee0 tests: xfail test_apply_failed on JSONDecodeError/PermissionError (#8796) 2023-01-11 18:04:23 +05:45
skshetry 90a27179eb ruff: ignore complex functions and remove dvc.utils.fs.makedirs (#8795)
We may want to prevent any new functions from getting complex.
2023-01-11 17:58:51 +05:45
skshetry 175c578579 ruff: ban relative parent/grandparent imports (#8794) 2023-01-11 16:48:46 +05:45
skshetry 5441964fdb add ruff (#8793)
* add ruff linter

* enable few more checks
2023-01-11 15:20:38 +05:45
Ivan Shcheklein d4bfe38a54 perf: remove fs exists check in plots, parallel data collect 2023-01-10 20:27:02 -08:00
dependabot[bot] a060049186 build(deps-dev): unpin grandalf
See https://github.com/bdcht/grandalf/issues/26#issuecomment-1378175273.
2023-01-11 08:44:49 +05:45
Ruslan Kuprieiev c02285ab49 deps: bump dvc-data to 0.29.0 2023-01-11 03:03:38 +02:00
Jorge Orpinel bccbbc1d94 Update dvc/commands/imp_url.py 2023-01-10 19:05:18 +02:00
Jorge Orpinel d736b31d8b import-url: Update options order
Per https://github.com/iterative/dvc.org/pull/3934
2023-01-10 19:05:18 +02:00
Peter Rowlands 68c1cc095c deps: bump dvc-data to 0.28.6 2023-01-11 00:20:22 +09:00
Peter Rowlands c94d28594d worktree push: remove existing version id optimization for file outs 2023-01-10 16:21:31 +09:00
Peter Rowlands d3d429ef7f push/fetch: respect --jobs on worktree push/fetch 2023-01-10 16:21:31 +09:00
dependabot[bot] 6ac88104da build(deps-dev): Bump pylint from 2.15.9 to 2.15.10
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.15.9 to 2.15.10.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.15.9...v2.15.10)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-10 10:39:48 +05:45
skshetry d87cdba6d8 gha: remove env vars SHELL 2023-01-10 10:19:29 +05:45
Ruslan Kuprieiev b25ef5cdfb metrics/params: show: add hide_workspace flag 2023-01-09 16:57:18 +02:00
dberenbaum 435407185f params/metrics diff: address test failures for missing branch key 2023-01-09 16:57:18 +02:00
dberenbaum 0b192af6f4 params: fix diff bt active branch and workspace 2023-01-09 16:57:18 +02:00
dberenbaum c6b602a167 metrics: fix diff bt active branch and workspace 2023-01-09 16:57:18 +02:00
David de la Iglesia Castro 1d5de9c5ba repro: Disable run-cache if --no-commit.
As described in https://github.com/iterative/dvc/issues/4428#issuecomment-778263005.

Add `run_cache` argument to `Stage.save`. Set it to `False` if `no_commit`.
2023-01-09 12:38:57 +01:00
Ruslan Kuprieiev 0e5674ffea ls: compute relparts once for every dir
Cuts down `dvc ls . data/mnist/dataset --recursive` for me from ~25 to ~12
seconds.

`relparts` is an expensive operation as it calls `relpath` that calls `abspath`,
so we want to avoid calling it as much as possible.
2023-01-08 03:44:50 +02:00
Ruslan Kuprieiev 684fc32e36 dvcfs: ls: don't call info()
Cuts down `dvc ls . data/mnist/dataset --recursive` for me from ~37 to ~25
seconds.

Note that this also changes behaviour for ls with a broken symlink, as we
were not able to see it before because of a failing `info()` call, but now
we can follow a normal UNIX ls behaviour more closely.
2023-01-08 00:37:40 +02:00
Saugat Pachhai (सौगात) 81f37be9d6 ci: timeout tests if it takes >5min
It most likely means it's frozen and unlikely to resume again. We'd want
to see where it froze, so this will provide us with a traceback.
2023-01-06 20:16:20 +05:45
Saugat Pachhai (सौगात) 3dfdd577e7 tests: xfail experiments-related flakey tests 2023-01-06 18:59:53 +05:45
dependabot[bot] bfb6a32b51 build(deps-dev): Bump dvc-data from 0.28.4 to 0.28.5
Bumps [dvc-data](https://github.com/iterative/dvc-data) from 0.28.4 to 0.28.5.
- [Release notes](https://github.com/iterative/dvc-data/releases)
- [Commits](https://github.com/iterative/dvc-data/compare/0.28.4...0.28.5)

---
updated-dependencies:
- dependency-name: dvc-data
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-06 16:36:48 +09:00
Daniele Trifirò 33de761560 deps: unpin dvc-http 2023-01-05 21:15:33 +01:00
Daniele Trifirò ff38aed927 config: expose timeouts in http config
- `read_timeout` timeout for reading new data portions from the peer
- `connect_timeout` timeout for establishing new connections

For more information about individual timeouts meanings:

- `read_timeout` maps to `aiohttp`'s `sock_read` timeout
- `connect_timeout` applies to `aiohttp`'s `connect`, `sock_connect`
  timeouts

https://docs.aiohttp.org/en/stable/client_reference.html?highlight=clienttimeout#clienttimeout
2023-01-05 21:15:33 +01:00
Daniele Trifirò b62f17ffaf tests: move tests/unit/remote/test_http.py to dvc-http repo 2023-01-05 19:54:14 +01:00
Daniele Trifirò a0c781a676 exp save: fix help for --force 2023-01-04 17:57:29 +01:00
dberenbaum 6ac7dfc008 exp: fix tests and remove reset checks 2023-01-04 17:29:12 +01:00
dberenbaum b0372918ea exp: stop checking for unchanged experiments 2023-01-04 17:29:12 +01:00
Daniele Trifirò 4b0fa4d559 update: prevent re-download on every update 2023-01-03 18:52:48 +01:00
Saugat Pachhai (सौगात) a24c389674 internal: hoist resolver/top-level metrics/plots/params data into file level 2023-01-03 17:46:06 +05:45
karajan1001 f386f7c082 exp apply can accept exp names and failed exps as target
fix: #8182

1. `exp apply` can apply to failed experiments.
2. `exp apply` can accept exp names as target.
3. Add a new functional test for it.
2022-12-30 17:40:18 +08:00
karajan1001 eadd0da394 Refactor get_ref_and_entry_by_names
1. Move get_ref_and_entry_by_names from `exp remove` to `celery` for
   other commands usage.
2022-12-30 17:40:18 +08:00
karajan1001 06673dd212 Use SIGINT as the default signal in queue kill
fix: #8624
1. Add a new flag `--force` for `queue kill`
2. Make `SIGINT` to be the default option and `SIGKILL` to be with
   `--force`
3. Add tests for `queue kill`
4. Bump dvc-task into 0.1.9
2022-12-30 16:19:39 +08:00
dependabot[bot] 5f0b1edb40 build(deps-dev): Bump filelock from 3.8.2 to 3.9.0
Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.8.2 to 3.9.0.
- [Release notes](https://github.com/tox-dev/py-filelock/releases)
- [Changelog](https://github.com/tox-dev/py-filelock/blob/main/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/py-filelock/compare/3.8.2...3.9.0)

---
updated-dependencies:
- dependency-name: filelock
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-12-30 09:20:26 +05:45
dependabot[bot] 05701e26db build(deps-dev): Bump scmrepo from 0.1.4 to 0.1.5
Bumps [scmrepo](https://github.com/iterative/scmrepo) from 0.1.4 to 0.1.5.
- [Release notes](https://github.com/iterative/scmrepo/releases)
- [Commits](https://github.com/iterative/scmrepo/compare/0.1.4...0.1.5)

---
updated-dependencies:
- dependency-name: scmrepo
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-12-30 11:23:42 +09:00
Daniele Trifirò 109288e1cd exp save: update --help 2022-12-29 20:51:52 +01:00
Daniele Trifirò 9e6f44bc1c get/ls/import: improve clone error messages 2022-12-29 20:13:39 +01:00
David de la Iglesia Castro 68b24307f9 post_live_metrics: Pass params on start event. 2022-12-28 11:43:37 +01:00
skshetry ea8a4a3db4 GHA: remove unused env from tests workflow 2022-12-27 10:26:29 +05:45
karajan1001 08ae68caf4 Make temp dir executed checkpoint experiment return result to workspace.
fix: #8612
For checkpoint experiment in some case users might want to give it a early
stopping to reduce variance.  But currently if we interrupt/kill the
experiment it will be marked as failed, and all of the completed
checkpoints will be removed as we cleanup all the running directly after
the process failed.

1. We raise CheckpointKilledError intead of StageCmdFailed error if at
   least one checkpoint had been commited.
2. Temp_dir executor will continue collecting data if the Checkpoint
   stage was interrupted.
3. Raise warnings if a checkpoint stage was incomplete and the other
   stages were not forwarded.
4. Add a new functional test for this
2022-12-26 18:25:43 +05:45
karajan1001 4400fb4090 queue stop --kill can kill false running status tasks
fix: #8702

1. replace simple `proc.kill` in `queue stop --kill` with the same logic as in
   `queue kill` to make it possible to set false status `running` tasks
    as faileed.
2. Modified the tests.
2022-12-26 17:16:46 +09:00
Fabian Zills 28848c5407 exp run --run-all: re-enable --jobs concurrency (#8608)
* re-enable --jobs concurrency

* use `start_workers` instead of `spawn_worker`

* make `spawn_worker` a private method.

* update tests: make `spawn_worker` a private method.
2022-12-26 16:49:46 +09:00
David de la Iglesia Castro b13184fcec tests: Fix flaky test_show_only_changed.
Some of the random exp names could start with `bar`.

https://github.com/iterative/dvc/actions/runs/3757008396/jobs/6383731723#step:5:79
2022-12-22 13:01:46 +01:00
dependabot[bot] ee5fbc72ab build(deps-dev): Bump dvc-render from 0.0.15 to 0.0.17
Bumps [dvc-render](https://github.com/iterative/dvc-render) from 0.0.15 to 0.0.17.
- [Release notes](https://github.com/iterative/dvc-render/releases)
- [Commits](https://github.com/iterative/dvc-render/compare/0.0.15...0.0.17)

---
updated-dependencies:
- dependency-name: dvc-render
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-12-22 12:17:56 +01:00
David de la Iglesia Castro d7fd68a1ae Add start and done calls with post_live_metrics. 2022-12-22 11:33:59 +01:00
Daniele Trifirò 59d6d5ea98 exp save: simplify implementation 2022-12-22 11:01:41 +01:00
dberenbaum 6fc0a6ff98 plots: accept any number of y data sources 2022-12-20 14:32:40 +01:00
dberenbaum b4b5db4b4e plots: accept list of y vals 2022-12-20 14:32:40 +01:00
Saugat Pachhai (सौगात) 23e4d376c9 index: remove unused APIs
These are being used by some users, but removing it for easier refactoring.
We are not using it ourselves.
2022-12-20 13:17:28 +05:45
dependabot[bot] 089a90c969 build(deps-dev): Bump pylint from 2.15.8 to 2.15.9
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.15.8 to 2.15.9.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.15.8...v2.15.9)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-12-19 11:28:58 +05:45
dependabot[bot] 198daec421 build(deps): Bump pyinstaller from 5.6.2 to 5.7.0
Bumps [pyinstaller](https://github.com/pyinstaller/pyinstaller) from 5.6.2 to 5.7.0.
- [Release notes](https://github.com/pyinstaller/pyinstaller/releases)
- [Changelog](https://github.com/pyinstaller/pyinstaller/blob/develop/doc/CHANGES.rst)
- [Commits](https://github.com/pyinstaller/pyinstaller/compare/v5.6.2...v5.7.0)

---
updated-dependencies:
- dependency-name: pyinstaller
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-12-15 19:05:41 +05:45
dependabot[bot] 04eb6a9f00 build(deps-dev): Bump mypy from 0.990 to 0.991
Bumps [mypy](https://github.com/python/mypy) from 0.990 to 0.991.
- [Release notes](https://github.com/python/mypy/releases)
- [Commits](https://github.com/python/mypy/compare/v0.990...v0.991)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-12-15 19:05:27 +05:45
Saugat Pachhai (सौगात) 0467f6a036 add index._plot_sources 2022-12-15 13:00:27 +05:45
David de la Iglesia Castro dc3d9c9677 bump DVCLive lower bound 2022-12-14 20:45:57 +01:00
Daniele Trifirò fcf92b2755 remove a few experiments names 2022-12-14 18:14:36 +01:00
David de la Iglesia CastroandDave Berenbaum c806275167 Bump dvclive lower bound (#8683)
* Bump dvclive lower bound

* Update pyproject.toml

Co-authored-by: Dave Berenbaum <[email protected]>

Co-authored-by: Dave Berenbaum <[email protected]>
2022-12-14 14:13:20 +00:00
dependabot[bot] bd1add0b95 build(deps-dev): Bump dvc-task from 0.1.6 to 0.1.8
Bumps [dvc-task](https://github.com/iterative/dvc-task) from 0.1.6 to 0.1.8.
- [Release notes](https://github.com/iterative/dvc-task/releases)
- [Commits](https://github.com/iterative/dvc-task/compare/0.1.6...0.1.8)

---
updated-dependencies:
- dependency-name: dvc-task
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-12-14 11:23:26 +08:00
Ivan Shcheklein e36f0e9d85 reset all indecies of brancher switch 2022-12-13 23:43:23 +02:00
dependabot[bot] bc1b8f3494 build(deps-dev): Bump pylint from 2.15.7 to 2.15.8
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.15.7 to 2.15.8.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.15.7...v2.15.8)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-12-13 14:53:57 +01:00
dependabot[bot] 9169d273e3 build(deps-dev): Bump filelock from 3.8.0 to 3.8.2
Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.8.0 to 3.8.2.
- [Release notes](https://github.com/tox-dev/py-filelock/releases)
- [Changelog](https://github.com/tox-dev/py-filelock/blob/main/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/py-filelock/compare/3.8.0...3.8.2)

---
updated-dependencies:
- dependency-name: filelock
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-12-12 20:38:22 +01:00
David de la Iglesia Castro bb7512687c exp: Generate a human-readable name beforehand.
- Add `get_random_exp_name` to utils.
Generates a name (`f"{adjective}-{noun}"`) by randomly chosing pairs of adjetive, noun.
Recieves `scm` and `baseline_rev` and retries the random choice until a non-existing ref is found.

Closes https://github.com/iterative/dvc/issues/8650
2022-12-09 10:32:38 +01:00
Saugat Pachhai (सौगात) 334f297ad3 deps: remove 3.11 checks for hydra; has 3.11 support now 2022-12-09 10:32:12 +05:45
Peter Rowlands ace3ba0ef9 worktree push: disable rev flags 2022-12-09 09:21:19 +09:00
Peter Rowlands 959d149381 worktree fetch: support revs flags 2022-12-09 09:21:19 +09:00
Peter Rowlands 7a65d67e7f worktree: support recursive/with_deps targets 2022-12-09 09:21:19 +09:00
Peter Rowlands e9be6779ea worktree: disable run-cache push/fetch 2022-12-09 09:21:19 +09:00
Peter Rowlands 876d123f04 index: use lazy view loading 2022-12-08 20:56:05 +09:00
Peter Rowlands 2bfe403a28 deps: bump dvc-data to 0.28.4 2022-12-08 20:56:05 +09:00
Peter Rowlands 9bef123182 worktree: fix default worktree remote/odb exception 2022-12-08 11:01:42 +09:00
Peter Rowlands e98ca36f39 worktree push: only index known (tracked) files/dirs in the remote 2022-12-07 18:48:34 +09:00
Peter Rowlands b9bf73f043 push/fetch: support targets in cloud version push/fetch 2022-12-07 18:48:34 +09:00
dependabot[bot] 7628fe9d44 build(deps-dev): Bump pytest-xdist from 3.0.2 to 3.1.0
Bumps [pytest-xdist](https://github.com/pytest-dev/pytest-xdist) from 3.0.2 to 3.1.0.
- [Release notes](https://github.com/pytest-dev/pytest-xdist/releases)
- [Changelog](https://github.com/pytest-dev/pytest-xdist/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-xdist/compare/v3.0.2...v3.1.0)

---
updated-dependencies:
- dependency-name: pytest-xdist
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-12-06 20:16:21 +05:45
Peter Rowlands d415a05460 remote: disable gc and status -c for versioned remotes 2022-12-06 19:33:52 +09:00
Peter Rowlands f5699ce16b update: disable rev/to-remote/no-download for worktrees 2022-12-06 15:14:17 +09:00
Peter Rowlands baeedead3a update: add support for worktree update 2022-12-06 15:14:17 +09:00
Peter Rowlands 5630db55ad worktree: add support for updating outs 2022-12-06 15:14:17 +09:00
Peter Rowlands f1bd47ce0e index: make collect_targets public 2022-12-06 15:14:17 +09:00
dependabot[bot] 74a13a4d9a build(deps-dev): Bump dvc-render from 0.0.14 to 0.0.15
Bumps [dvc-render](https://github.com/iterative/dvc-render) from 0.0.14 to 0.0.15.
- [Release notes](https://github.com/iterative/dvc-render/releases)
- [Commits](https://github.com/iterative/dvc-render/compare/0.0.14...0.0.15)

---
updated-dependencies:
- dependency-name: dvc-render
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-12-02 08:30:37 +01:00
528 changed files with 20407 additions and 22151 deletions
+1 -10
View File
@@ -1,12 +1,3 @@
/state
/lock
/config.local
/updater
/updater.lock
/state-journal
/state-wal
/cache
/pkg
/repos
/tmp
/experiments
/cache
-4
View File
@@ -1,4 +0,0 @@
['remote "dvc"']
url = https://remote.dvc.org/dvc
[core]
remote = dvc
+16 -8
View File
@@ -1,12 +1,20 @@
[flake8]
ignore=
E203, # Whitespace before ':'
E266, # Too many leading '#' for block comment
W503, # Line break occurred before a binary operator
P1, # unindexed parameters in the str.format, see:
max_line_length = 88
extend-ignore=
# Whitespace before ':'
E203
# Line break occurred before a binary operator
W503
# unindexed parameters in the str.format, see:
# https://pypi.org/project/flake8-string-format/
max_line_length = 79
max-complexity = 15
select = B,C,E,F,W,T4,B902,T,P
P1
max-complexity = 10
show_source = true
count = true
min_python_version = 3.8.0
per-file-ignores =
dvc/testing/benchmarks/conftest.py:F401
dvc/testing/conftest.py:F401
dvc/testing/plugin.py:F401
tests/conftest.py:F401
tests/func/experiments/executor/test_ssh.py:F401
+10
View File
@@ -0,0 +1,10 @@
# The following commits will be ignored by the GitHub blame view.
# You can configure `git blame` to use this file as the default ignore file:
# git config blame.ignoreRevsFile .git-blame-ignore-revs
# or, you can also manually ignore commits from this file by doing:
# git blame --ignore-revs-file .git-blame-ignore-revs <filepath>
# see the `blame.markIgnoredLines` and `blame.markUnblamableLines` options as well.
# Refer to: https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revs-fileltfilegt
# update black to 2023 stable style and change line-length to 88
a86470ccbc693d6f0a4f8066cbd1357e5191c4ff
+60
View File
@@ -0,0 +1,60 @@
---
name: Epic/Story Issue Template
about: Template for "top" level issues - Epics (>2 weeks) / Stories (<2 weeks)
title: 'Epic: New Feature'
labels: epic
assignees:
---
## Summary / Background
What do you want to achieve, why? business context
...
## Scope
What will be impacted and what won't be?
What needs implementation and what is invariant?
e.g.
- user should be able to run workflow X from UI
- enable workflow Y, Z from CLI
## Assumptions
Product / UX assumptions as well as technical assumptions / limitations
e.g.
* Support only Python Runtime
* Focus on DVC experiments only
* Deployment environments don't change often and can be picked up from shared configuration
## Open Questions
e.g.
- How should access control work for shared artifacts (workflow X)
- Python runtime assumption - is it really valid? in light of <...>
## Blockers / Dependencies
List issues or other conditions / blockers
## General Approach
Invocation example:
```shell
$ mapper-run task.tar.gz --ray-cluster <ip>:<port>
```
## Steps
### Must have (p1)
- [ ] subissue2
- [ ] step 2
- info
- info
### Optional / followup (p2)
- [ ] ⌛ step 3 wip
- [ ] step 4
## Timelines
Put your estimations here. Update once certainty changes
- end of week (Feb 3) for prototype with workflows X, Y
- Feb 15 - MVP in production
- Low priority followups can be done later
+10
View File
@@ -0,0 +1,10 @@
pull_request_rules:
- name: backport patches to 2.x
conditions:
- base=main
- label=backport
actions:
backport:
branches:
- "2.x"
title: ({{ destination_branch }}) {{ title }}
+47
View File
@@ -0,0 +1,47 @@
name: Build package
on:
push:
branches:
- main
release:
types: [released, prereleased]
workflow_dispatch:
permissions:
contents: read
id-token: write
jobs:
pip:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-python@v4
with:
python-version: 3.8
- run: python -m pip install --upgrade pip setuptools_scm build twine
- name: Force version for Test PyPI upload
if: ${{ !startsWith(github.ref, 'refs/tags') }}
run: echo version=$(python -m setuptools_scm | awk -F+ '{print $1}' | tail -1) >> $GITHUB_ENV
- run: |
echo 'PKG = "pip"'>dvc/_build.py
python -m build
env:
SETUPTOOLS_SCM_PRETEND_VERSION: ${{ env.version }}
- run: twine check --strict dist/*
- name: Publish to PyPI
if: github.event_name == 'release'
uses: pypa/gh-action-pypi-publish@release/v1
- name: Publish to Test PyPI
if: ${{ github.event_name == 'release' || (github.event_name == 'push' && github.ref == 'refs/heads/main') }}
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
skip-existing: true
+1 -1
View File
@@ -2,7 +2,7 @@ name: "CodeQL"
on:
push:
branches: ["main"]
branches: ["main", "2.x"]
pull_request:
branches: ["main"]
schedule:
-112
View File
@@ -1,112 +0,0 @@
name: Build packages
on:
push:
branches:
- main
release:
types: [released, prereleased]
workflow_dispatch:
permissions: # added using https://github.com/step-security/secure-workflows
contents: read
jobs:
binary:
permissions:
contents: write # for actions/upload-release-asset to upload release asset
strategy:
matrix:
include:
- {pkg: "deb", os: "ubuntu-18.04", asset: "dvc_${{ github.event.release.tag_name }}_amd64.deb"}
- {pkg: "rpm", os: "ubuntu-18.04", asset: "dvc-${{ github.event.release.tag_name }}-1.x86_64.rpm"}
- {pkg: "osxpkg", os: "macos-10.15", asset: "dvc-${{ github.event.release.tag_name }}.pkg"}
- {pkg: "exe", os: "windows-2019", asset: "dvc-${{ github.event.release.tag_name }}.exe"}
name: ${{ matrix.pkg }}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: "3.10"
cache: pip
cache-dependency-path: |
pyproject.toml
scripts/build-requirements.txt
- name: Set up Ruby 2.6
uses: ruby/setup-ruby@v1
if: matrix.pkg != 'exe'
with:
ruby-version: '2.6'
- name: Install fpm
if: matrix.pkg != 'exe'
run: gem install --no-document fpm
- name: Install deps
run: |
pip install --upgrade pip wheel setuptools
pip install .[all]
pip install -r scripts/build-requirements.txt
- name: Pull images
run: dvc pull
- name: Build ${{ matrix.pkg }}
run: python scripts/build.py ${{ matrix.pkg }}
- name: Publish ${{ matrix.pkg }}
if: github.event_name == 'release'
uses: actions/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: scripts/${{ matrix.pkg == 'exe' && 'innosetup' || 'fpm' }}/${{ matrix.asset }}
asset_name: ${{ matrix.asset }}
asset_content_type: binary/octet-stream
pip:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Python 3.8
uses: actions/setup-python@v4
with:
python-version: 3.8
- name: Install
run: pip install --upgrade pip wheel
- name: Force version for Test PyPI uploads
if: ${{ !startsWith(github.ref, 'refs/tags') }}
run: |
pip install setuptools_scm
echo version=$(python -m setuptools_scm | awk -F+ '{print $1}' | tail -1) >> $GITHUB_ENV
- name: Build packages
run: ./scripts/build_package.sh
env:
SETUPTOOLS_SCM_PRETEND_VERSION: ${{ env.version }}
- name: Publish packages to PyPI
if: github.event_name == 'release'
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_TOKEN }}
- name: Publish to Test PyPI
if: ${{ github.event_name == 'release' || (github.event_name == 'push' && github.ref == 'refs/heads/main') }}
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.TEST_PYPI_TOKEN }}
repository_url: https://test.pypi.org/legacy/
skip_existing: true
+54
View File
@@ -0,0 +1,54 @@
name: Remote Plugin Tests
on:
pull_request:
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
jobs:
tests:
timeout-minutes: 45
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04]
pyv: ["3.10"]
plugin: ["dvc-s3"]
steps:
- uses: actions/checkout@v3
with:
path: dvc
- uses: actions/checkout@v3
with:
repository: iterative/${{ matrix.plugin }}
ref: main
path: ${{ matrix.plugin }}
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.pyv }}
cache: pip
cache-dependency-path: |
dvc/pyproject.toml
${{ matrix.plugin }}/setup.cfg
- name: Install plugin + DVC@PR
run: |
pip install --upgrade pip wheel
pip install "./dvc[testing]"
pip install -e "./${{ matrix.plugin }}[tests]"
- name: Run plugin tests
timeout-minutes: 15
working-directory: ${{ matrix.plugin }}
run: pytest -v -n=auto
+13 -39
View File
@@ -2,59 +2,28 @@ name: Tests
on:
push:
branches: [main]
branches: [main, 2.x]
pull_request:
schedule:
- cron: '5 1 * * *' # every day at 01:05
workflow_dispatch:
env:
DVC_TEST: "true"
HOMEBREW_NO_AUTO_UPDATE: 1
SHELL: /bin/bash
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions: # added using https://github.com/step-security/secure-workflows
permissions:
contents: read
jobs:
lint:
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Python 3.8
uses: actions/setup-python@v4
with:
python-version: 3.8
cache: pip
cache-dependency-path: pyproject.toml
- name: Install requirements
run: |
pip install --upgrade pip wheel
pip install ".[dev]"
- uses: pre-commit/[email protected]
tests:
timeout-minutes: 45
timeout-minutes: 50
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, windows-latest]
os: [ubuntu-20.04, windows-latest, macos-latest]
pyv: ["3.8", "3.9", "3.10", "3.11"]
pytest-filter:
- "import or plot or live or experiment"
- "not (import or plot or live or experiment)"
include:
- {os: macos-latest, pyv: "3.8"}
- {os: macos-latest, pyv: "3.9"}
- {os: macos-latest, pyv: "3.10"}
- {os: macos-latest, pyv: "3.11"}
steps:
- uses: actions/checkout@v3
@@ -70,9 +39,14 @@ jobs:
run: |
pip install --upgrade pip wheel
pip install -e ".[dev]"
- uses: pre-commit/[email protected]
- name: run tests
timeout-minutes: 20
run: pytest -nauto --durations 100 --cov --cov-report=xml --cov-report=term -k "${{ matrix.pytest-filter }}"
timeout-minutes: 40
env:
PYTHONUTF8: 1
run: >
pytest -n=logical --timeout=300 --durations=100
--cov --cov-report=xml --cov-report=term
- name: upload coverage report
uses: codecov/codecov-action@v3
with:
@@ -80,7 +54,7 @@ jobs:
fail_ci_if_error: false
check:
if: always()
needs: [lint, tests]
needs: [tests]
runs-on: ubuntu-latest
steps:
- uses: re-actors/alls-green@release/v1
@@ -88,7 +62,7 @@ jobs:
jobs: ${{ toJSON(needs) }}
notify:
if: github.ref == 'refs/heads/main' && failure()
needs: [lint, tests]
needs: [tests]
runs-on: ubuntu-latest
steps:
- name: Slack Notification
+21 -20
View File
@@ -6,7 +6,7 @@ ci:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
rev: v4.4.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
@@ -23,40 +23,38 @@ repos:
- id: mixed-line-ending
- id: sort-simple-yaml
- id: trailing-whitespace
- repo: https://github.com/lovesegfault/beautysh
rev: v6.2.1
hooks:
- id: beautysh
args: ["-i", "2"]
- repo: https://github.com/asottile/pyupgrade
rev: v3.2.0
hooks:
- id: pyupgrade
args:
- --py38-plus
- repo: https://github.com/psf/black
rev: 22.10.0
rev: 23.7.0
hooks:
- id: black
- repo: https://github.com/PyCQA/isort
rev: 5.10.1
rev: 5.12.0
hooks:
- id: isort
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.0.282'
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/codespell-project/codespell
rev: v2.2.2
rev: v2.2.5
hooks:
- id: codespell
additional_dependencies: ["tomli"]
- repo: https://github.com/PyCQA/flake8
rev: 5.0.4
rev: 6.1.0
hooks:
- id: flake8
additional_dependencies:
- flake8-broken-line
- flake8-bugbear
- flake8-comprehensions
- flake8-debugger
- flake8-string-format
- flake8-typing-imports
- repo: https://github.com/PyCQA/bandit
rev: '1.7.5'
hooks:
- id: bandit
args: ["-c", "pyproject.toml", "--quiet", "--format=custom"]
files: ^dvc/
additional_dependencies: [".[toml]"]
- repo: local
hooks:
- id: mypy
@@ -65,11 +63,14 @@ repos:
files: ^dvc/
language: system
types: [python]
require_serial: true
- id: pylint
name: pylint
entry: pylint
files: ^dvc/
language: system
types: [python]
require_serial: true
- hooks:
- args:
- git-hook
+2 -2
View File
@@ -280,8 +280,8 @@ Barrak, A., Eghan, E.E. and Adams, B. `On the Co-evolution of ML Pipelines and S
:target: https://pypi.org/project/dvc
:alt: PyPI Downloads
.. |Packages| image:: https://img.shields.io/github/v/release/iterative/dvc?label=deb|pkg|rpm|exe&logo=GitHub
:target: https://github.com/iterative/dvc/releases/latest
.. |Packages| image:: https://img.shields.io/badge/deb|pkg|rpm|exe-blue
:target: https://dvc.org/doc/install
:alt: deb|pkg|rpm|exe
.. |DOI| image:: https://img.shields.io/badge/DOI-10.5281/zenodo.3677553-blue.svg
+1
View File
@@ -4,6 +4,7 @@ DVC
Make your data science projects reproducible and shareable.
"""
import dvc.logger
from dvc.build import PKG # noqa: F401
from dvc.version import __version__, version_tuple # noqa: F401
dvc.logger.setup()
+5
View File
@@ -0,0 +1,5 @@
import os
def get_hook_dirs():
return [os.path.dirname(__file__)]
@@ -1 +1,2 @@
# ruff: noqa: N999
hiddenimports = ["win32timezone"]
@@ -1,3 +1,4 @@
# ruff: noqa: N999
# pylint: disable=import-error
from PyInstaller.utils.hooks import collect_submodules, is_module_or_submodule
@@ -1,6 +1,5 @@
from PyInstaller.utils.hooks import ( # pylint:disable=import-error
copy_metadata,
)
# ruff: noqa: N999
from PyInstaller.utils.hooks import copy_metadata # pylint:disable=import-error
# needed for `dvc doctor` to show dep versions
datas = copy_metadata("adlfs", recursive=True)
@@ -0,0 +1,4 @@
# ruff: noqa: N999
from PyInstaller.utils.hooks import copy_metadata # pylint:disable=import-error
datas = copy_metadata("flatten-dict")
@@ -1,3 +1,4 @@
# ruff: noqa: N999
# pylint: disable=import-error
from PyInstaller.utils.hooks import collect_submodules
@@ -1 +1,2 @@
# ruff: noqa: N999
hiddenimports = ["fsspec.implementations.memory"]
+4
View File
@@ -0,0 +1,4 @@
# ruff: noqa: N999
from PyInstaller.utils.hooks import copy_metadata # pylint:disable=import-error
datas = copy_metadata("pydrive2")
+89 -29
View File
@@ -8,15 +8,19 @@ if TYPE_CHECKING:
@contextmanager
def viztracer_profile(path: Union[Callable[[], str], str], depth: int = -1):
def viztracer_profile(
path: Union[Callable[[], str], str],
depth: int = -1,
log_async: bool = False,
):
try:
import viztracer # pylint: disable=import-error
except ImportError:
print("Failed to run profiler, viztracer is not installed")
print("Failed to run profiler, viztracer is not installed") # noqa: T201
yield
return
tracer = viztracer.VizTracer(max_stack_depth=depth)
tracer = viztracer.VizTracer(max_stack_depth=depth, log_async=log_async)
tracer.start()
yield
@@ -27,14 +31,14 @@ def viztracer_profile(path: Union[Callable[[], str], str], depth: int = -1):
@contextmanager
def yappi_profile(
path: Union[Callable[[], str], str] = None,
path: Optional[Union[Callable[[], str], str]] = None,
wall_clock: Optional[bool] = True,
separate_threads: Optional[bool] = False,
):
try:
import yappi # pylint: disable=import-error
except ImportError:
print("Failed to run profiler, yappi is not installed")
print("Failed to run profiler, yappi is not installed") # noqa: T201
yield
return
@@ -60,7 +64,7 @@ def yappi_profile(
st.save(out, type="callgrind")
else:
if ctx_id is not None:
print(f"\nThread {ctx_id}")
print(f"\nThread {ctx_id}") # noqa: T201
st.print_all() # pylint:disable=no-member
if ctx_id is None:
threads.print_all() # pylint:disable=no-member
@@ -74,7 +78,7 @@ def instrument(html_output=False):
try:
from pyinstrument import Profiler # pylint: disable=import-error
except ImportError:
print("Failed to run profiler, pyinstrument is not installed")
print("Failed to run profiler, pyinstrument is not installed") # noqa: T201
yield
return
@@ -87,11 +91,11 @@ def instrument(html_output=False):
if html_output:
profiler.open_in_browser()
return
print(profiler.output_text(unicode=True, color=True))
print(profiler.output_text(unicode=True, color=True)) # noqa: T201
@contextmanager
def profile(dump_path: str = None):
def profile(dump_path: Optional[str] = None):
"""Run a cprofile"""
import cProfile
@@ -115,28 +119,31 @@ def debug():
try:
import ipdb as pdb # noqa: T100, pylint: disable=import-error
except ImportError:
import pdb # noqa: T100
import pdb # type: ignore[no-redef] # noqa: T100
pdb.post_mortem()
raise # prevent from jumping ahead
def _sigshow(_, frame: Optional["FrameType"]) -> None:
import sys
from shutil import get_terminal_size
from traceback import format_stack
from dvc.ui import ui
lines = "\u2015" * get_terminal_size().columns
ui.error_write(lines, "\n", *format_stack(frame), lines, sep="")
stack = format_stack(frame)
print(lines, "\n", *stack, lines, sep="", file=sys.stderr) # noqa: T201
@contextmanager
def show_stack():
r"""Show stack trace on SIGQUIT (Ctrl-\) or SIGINFO (Ctrl-T on macOS)."""
import signal
import sys
if sys.platform != "win32":
signal.signal(signal.SIGQUIT, _sigshow)
signal.signal(signal.SIGQUIT, _sigshow)
try:
signal.signal(signal.SIGINFO, _sigshow) # only available on macOS
except AttributeError:
@@ -154,7 +161,7 @@ def _get_path_func(tool: str, ext: str):
@contextmanager
def debugtools(args: "Namespace" = None, **kwargs):
def debugtools(args: Optional["Namespace"] = None, **kwargs):
kw = vars(args) if args else {}
kw.update(kwargs)
@@ -175,10 +182,15 @@ def debugtools(args: "Namespace" = None, **kwargs):
separate_threads=kw.get("yappi_separate_threads"),
)
)
if kw.get("viztracer") or kw.get("viztracer_depth"):
if (
kw.get("viztracer")
or kw.get("viztracer_depth")
or kw.get("viztracer_async")
):
path_func = _get_path_func("viztracer", "json")
depth = kw.get("viztracer_depth") or -1
prof = viztracer_profile(path=path_func, depth=depth)
log_async = kw.get("viztracer_async") or False
prof = viztracer_profile(path=path_func, depth=depth, log_async=log_async)
stack.enter_context(prof)
yield
@@ -186,36 +198,84 @@ def debugtools(args: "Namespace" = None, **kwargs):
def add_debugging_flags(parser):
from argparse import SUPPRESS
# For detailed info see:
# https://github.com/iterative/dvc/wiki/Debugging,-Profiling-and-Benchmarking-DVC
args, _ = parser.parse_known_args()
verbose = args.verbose
def debug_help(msg):
if verbose:
return msg
return SUPPRESS
parser = parser.add_argument_group("debug options")
parser.add_argument(
"--cprofile", action="store_true", default=False, help=SUPPRESS
"--cprofile",
action="store_true",
default=False,
help=debug_help("Generate cprofile data for tools like snakeviz / tuna"),
)
parser.add_argument(
"--yappi", action="store_true", default=False, help=SUPPRESS
"--cprofile-dump", help=debug_help("Location to dump cprofile file")
)
parser.add_argument(
"--yappi",
action="store_true",
default=False,
help=debug_help(
"Generate a callgrind file for use with tools like "
"kcachegrind / qcachegrind"
),
)
parser.add_argument(
"--yappi-separate-threads",
action="store_true",
default=False,
help=SUPPRESS,
help=debug_help("Generate one callgrind file per thread"),
)
parser.add_argument(
"--viztracer", action="store_true", default=False, help=SUPPRESS
)
parser.add_argument("--viztracer-depth", type=int, help=SUPPRESS)
parser.add_argument("--cprofile-dump", help=SUPPRESS)
parser.add_argument(
"--pdb", action="store_true", default=False, help=SUPPRESS
"--viztracer",
action="store_true",
default=False,
help=debug_help("Generate a viztracer file for use with vizviewer"),
)
parser.add_argument(
"--instrument", action="store_true", default=False, help=SUPPRESS
"--viztracer-depth",
type=int,
help=debug_help("Set viztracer maximum stack depth"),
)
parser.add_argument(
"--instrument-open", action="store_true", default=False, help=SUPPRESS
"--viztracer-async",
action="store_true",
default=False,
help=debug_help("Treat async tasks as threads"),
)
parser.add_argument(
"--pdb",
action="store_true",
default=False,
help=debug_help("Drop into the pdb/ipdb debugger on any exception"),
)
parser.add_argument(
"--instrument",
action="store_true",
default=False,
help=debug_help("Use pyinstrument CLI profiler"),
)
parser.add_argument(
"--instrument-open",
action="store_true",
default=False,
help=debug_help("Use pyinstrument web profiler"),
)
parser.add_argument(
"--show-stack",
"--ss",
action="store_true",
default=False,
help=SUPPRESS,
help=debug_help(
r"Use Ctrl+T on macOS or Ctrl+\ on Linux to print the stack "
"frame currently executing. Unavailable on Windows."
),
)
+12 -6
View File
@@ -47,7 +47,7 @@ def is_enabled():
enabled = not os.getenv(DVC_NO_ANALYTICS)
if enabled:
enabled = to_bool(
Config(validate=False).get("core", {}).get("analytics", "true")
Config.from_cwd(validate=False).get("core", {}).get("analytics", "true")
)
logger.debug("Analytics is %sabled.", "en" if enabled else "dis")
@@ -82,10 +82,9 @@ def send(path):
def _scm_in_use():
from scmrepo.noscm import NoSCM
from dvc.exceptions import NotDvcRepoError
from dvc.repo import Repo
from dvc.scm import NoSCM
from .scm import SCM, SCMError
@@ -102,17 +101,24 @@ def _runtime_info():
"""
Gather information from the environment where DVC runs to fill a report.
"""
from iterative_telemetry import find_or_create_user_id
from iterative_telemetry import _generate_ci_id, find_or_create_user_id
from dvc import __version__
from dvc.utils import is_binary
ci_id = _generate_ci_id()
if ci_id:
group_id, user_id = ci_id
else:
group_id, user_id = None, find_or_create_user_id()
return {
"dvc_version": __version__,
"is_binary": is_binary(),
"scm_class": _scm_in_use(),
"system_info": _system_info(),
"user_id": find_or_create_user_id(),
"user_id": user_id,
"group_id": group_id,
}
@@ -125,7 +131,7 @@ def _system_info():
system = platform.system()
if system == "Windows":
version = sys.getwindowsversion()
version = sys.getwindowsversion() # type: ignore[attr-defined]
return {
"os": "windows",
+23 -6
View File
@@ -2,6 +2,7 @@ from dataclasses import asdict, dataclass, field, fields
from typing import Any, ClassVar, Dict, List, Optional
from funcy import compact
from voluptuous import Required
@dataclass
@@ -12,15 +13,27 @@ class Annotation:
PARAM_META: ClassVar[str] = "meta"
desc: Optional[str] = None
type: Optional[str] = None
type: Optional[str] = None # noqa: A003
labels: List[str] = field(default_factory=list)
meta: Dict[str, Any] = field(default_factory=dict)
def update(self, **kwargs) -> "Annotation":
for attr, value in kwargs.items():
if value and hasattr(self, attr):
setattr(self, attr, value)
return self
def to_dict(self) -> Dict[str, str]:
return compact(asdict(self))
@dataclass
class Artifact:
PARAM_PATH: ClassVar[str] = "path"
PARAM_DESC: ClassVar[str] = "desc"
PARAM_TYPE: ClassVar[str] = "type"
PARAM_LABELS: ClassVar[str] = "labels"
PARAM_META: ClassVar[str] = "meta"
path: str
desc: Optional[str] = None
type: Optional[str] = None # noqa: A003
labels: List[str] = field(default_factory=list)
meta: Dict[str, Any] = field(default_factory=dict)
def to_dict(self) -> Dict[str, str]:
return compact(asdict(self))
@@ -33,3 +46,7 @@ ANNOTATION_SCHEMA = {
Annotation.PARAM_LABELS: [str],
Annotation.PARAM_META: object,
}
ARTIFACT_SCHEMA = {
Required(Artifact.PARAM_PATH): str,
**ANNOTATION_SCHEMA, # type: ignore[arg-type]
}
+9 -3
View File
@@ -2,14 +2,20 @@ from dvc.fs.dvc import _DVCFileSystem as DVCFileSystem
from .data import open # pylint: disable=redefined-builtin
from .data import get_url, read
from .experiments import make_checkpoint
from .params import params_show
from .experiments import exp_save, exp_show
from .scm import all_branches, all_commits, all_tags
from .show import metrics_show, params_show
__all__ = [
"all_branches",
"all_commits",
"all_tags",
"exp_save",
"exp_show",
"get_url",
"make_checkpoint",
"open",
"params_show",
"metrics_show",
"read",
"DVCFileSystem",
]
+120 -31
View File
@@ -1,12 +1,30 @@
from contextlib import _GeneratorContextManager as GCM
from typing import Optional
from contextlib import contextmanager
from typing import Any, Dict, Optional
from funcy import reraise
from dvc.exceptions import OutputNotFoundError, PathMissingError
from dvc.exceptions import FileMissingError, OutputNotFoundError, PathMissingError
from dvc.repo import Repo
@contextmanager
def _wrap_exceptions(repo, url):
from dvc.config import NoRemoteError
from dvc.exceptions import NoOutputInExternalRepoError, NoRemoteInExternalRepoError
try:
yield
except NoRemoteError as exc:
raise NoRemoteInExternalRepoError(url) from exc
except OutputNotFoundError as exc:
if exc.repo is repo:
raise NoOutputInExternalRepoError(exc.output, repo.root_dir, url) from exc
raise
except FileMissingError as exc:
raise PathMissingError(exc.path, url) from exc
def get_url(path, repo=None, rev=None, remote=None):
"""
Returns the URL to the storage location of a data file or directory tracked
@@ -18,41 +36,46 @@ def get_url(path, repo=None, rev=None, remote=None):
NOTE: This function does not check for the actual existence of the file or
directory in the remote storage.
"""
with Repo.open(repo, rev=rev, subrepos=True, uninitialized=True) as _repo:
fs_path = _repo.dvcfs.from_os_path(path)
with reraise(FileNotFoundError, PathMissingError(path, repo)):
info = _repo.dvcfs.info(fs_path)
from dvc.config import NoRemoteError
from dvc_data.index import StorageKeyError
dvc_info = info.get("dvc_info")
if not dvc_info:
raise OutputNotFoundError(path, repo)
dvc_repo = info["repo"]
md5 = dvc_info["md5"]
return dvc_repo.cloud.get_url_for(remote, checksum=md5)
repo_kwargs: Dict[str, Any] = {}
if remote:
repo_kwargs["config"] = {"core": {"remote": remote}}
with Repo.open(
repo, rev=rev, subrepos=True, uninitialized=True, **repo_kwargs
) as _repo:
index, entry = _repo.get_data_index_entry(path)
with reraise(
(StorageKeyError, ValueError),
NoRemoteError(f"no remote specified in {_repo}"),
):
remote_fs, remote_path = index.storage_map.get_remote(entry)
return remote_fs.unstrip_protocol(remote_path)
class _OpenContextManager(GCM):
def __init__(
self, func, args, kwds
): # pylint: disable=super-init-not-called
def __init__(self, func, args, kwds): # pylint: disable=super-init-not-called
self.gen = func(*args, **kwds)
self.func, self.args, self.kwds = func, args, kwds
def __getattr__(self, name):
raise AttributeError(
"dvc.api.open() should be used in a with statement."
self.func, self.args, self.kwds = ( # type: ignore[assignment]
func,
args,
kwds,
)
def __getattr__(self, name):
raise AttributeError("dvc.api.open() should be used in a with statement.")
def open( # noqa, pylint: disable=redefined-builtin
def open( # noqa: A001, pylint: disable=redefined-builtin
path: str,
repo: Optional[str] = None,
rev: Optional[str] = None,
remote: Optional[str] = None,
mode: str = "r",
encoding: Optional[str] = None,
config: Optional[Dict[str, Any]] = None,
remote_config: Optional[Dict[str, Any]] = None,
):
"""
Opens a file tracked in a DVC project.
@@ -94,6 +117,11 @@ def open( # noqa, pylint: disable=redefined-builtin
Defaults to None.
This should only be used in text mode.
Mirrors the namesake parameter in builtin `open()`_.
config(dict, optional): config to be passed to the DVC repository.
Defaults to None.
remote_config(dict, optional): remote config to be passed to the DVC
repository.
Defaults to None.
Returns:
_OpenContextManager: A context manager that generatse a corresponding
@@ -189,25 +217,86 @@ def open( # noqa, pylint: disable=redefined-builtin
"rev": rev,
"mode": mode,
"encoding": encoding,
"config": config,
"remote_config": remote_config,
}
return _OpenContextManager(_open, args, kwargs)
def _open(path, repo=None, rev=None, remote=None, mode="r", encoding=None):
with Repo.open(repo, rev=rev, subrepos=True, uninitialized=True) as _repo:
with _repo.open_by_relpath(
path, remote=remote, mode=mode, encoding=encoding
) as fd:
yield fd
def _open(
path,
repo=None,
rev=None,
remote=None,
mode="r",
encoding=None,
config=None,
remote_config=None,
):
repo_kwargs: Dict[str, Any] = {
"subrepos": True,
"uninitialized": True,
"remote": remote,
"config": config,
"remote_config": remote_config,
}
with Repo.open(repo, rev=rev, **repo_kwargs) as _repo:
with _wrap_exceptions(_repo, path):
import os
from typing import TYPE_CHECKING, Union
from dvc.exceptions import IsADirectoryError as DvcIsADirectoryError
from dvc.fs.data import DataFileSystem
from dvc.fs.dvc import DVCFileSystem
if TYPE_CHECKING:
from dvc.fs import FileSystem
fs: Union["FileSystem", DataFileSystem, DVCFileSystem]
if os.path.isabs(path):
fs = DataFileSystem(index=_repo.index.data["local"])
fs_path = path
else:
fs = DVCFileSystem(repo=_repo, subrepos=True)
fs_path = fs.from_os_path(path)
try:
with fs.open(
fs_path,
mode=mode,
encoding=encoding,
) as fobj:
yield fobj
except FileNotFoundError as exc:
raise FileMissingError(path) from exc
except IsADirectoryError as exc:
raise DvcIsADirectoryError(f"'{path}' is a directory") from exc
def read(path, repo=None, rev=None, remote=None, mode="r", encoding=None):
def read(
path,
repo=None,
rev=None,
remote=None,
mode="r",
encoding=None,
config=None,
remote_config=None,
):
"""
Returns the contents of a tracked file (by DVC or Git). For Git repos, HEAD
is used unless a rev argument is supplied. The default remote is tried
unless a remote argument is supplied.
"""
with open(
path, repo=repo, rev=rev, remote=remote, mode=mode, encoding=encoding
path,
repo=repo,
rev=rev,
remote=remote,
mode=mode,
encoding=encoding,
config=config,
remote_config=remote_config,
) as fd:
return fd.read()
+111 -24
View File
@@ -1,33 +1,120 @@
import builtins
import os
from time import sleep
from typing import Dict, List, Optional, Union
from rich.text import Text
from dvc.env import DVC_CHECKPOINT, DVC_ROOT
from dvc.repo import Repo
from dvc.stage.monitor import CheckpointTask
from dvc.repo.experiments.show import tabulate
def make_checkpoint():
def exp_save(
name: Optional[str] = None,
force: bool = False,
include_untracked: Optional[List[str]] = None,
):
"""
Signal DVC to create a checkpoint experiment.
Create a new DVC experiment using `exp save`.
If the current process is being run from DVC, this function will block
until DVC has finished creating the checkpoint. Otherwise, this function
will return immediately.
See https://dvc.org/doc/command-reference/exp/save.
Args:
name (str, optional): specify a name for this experiment.
If `None`, a default one will be generated, such as `urban-sign`.
Defaults to `None`.
force (bool): overwrite the experiment if an experiment with the same
name already exists.
Defaults to `False`.
include_untracked (List[str], optional): specify untracked file(s) to
be included in the saved experiment.
Defaults to `None`.
Returns:
str: The `Git revision`_ of the created experiment.
Raises:
ExperimentExistsError: If an experiment with `name` already exists and
`force=False`.
.. _Git revision:
https://git-scm.com/docs/revisions
"""
if os.getenv(DVC_CHECKPOINT) is None:
return
with Repo() as repo:
return repo.experiments.save(
name=name, force=force, include_untracked=include_untracked
)
root_dir = os.getenv(DVC_ROOT, Repo.find_root())
signal_file = os.path.join(
root_dir, Repo.DVC_DIR, "tmp", CheckpointTask.SIGNAL_FILE
)
with builtins.open(signal_file, "w", encoding="utf-8") as fobj:
# NOTE: force flushing/writing empty file to disk, otherwise when
# run in certain contexts (pytest) file may not actually be written
fobj.write("")
fobj.flush()
os.fsync(fobj.fileno())
while os.path.exists(signal_file):
sleep(0.1)
def _postprocess(exp_rows):
for exp_row in exp_rows:
for k, v in exp_row.items():
if isinstance(v, Text):
v_str = str(v)
try:
exp_row[k] = float(v_str)
except ValueError:
exp_row[k] = v_str
if not exp_row[k]:
exp_row[k] = None
return exp_rows
def exp_show(
repo: Optional[str] = None,
revs: Optional[Union[str, List[str]]] = None,
num: int = 1,
param_deps: bool = False,
force: bool = False,
config: Optional[Dict] = None,
) -> List[Dict]:
"""Get DVC experiments tracked in `repo`.
Without arguments, this function will retrieve all experiments derived from
the Git `HEAD`.
See the options below to customize the experiments retrieved.
Args:
repo (str, optional): location of the DVC repository.
Defaults to the current project (found by walking up from the
current working directory tree).
It can be a URL or a file system path.
Both HTTP and SSH protocols are supported for online Git repos
(e.g. [user@]server:project.git).
revs (Union[str, List[str]], optional): Git revision(s) (e.g. branch,
tag, SHA commit) to use as a reference point to start listing
experiments.
Defaults to `None`, which will use `HEAD` as starting point.
num (int, optional): show experiments from the last `num` commits
(first parents) starting from the `revs` baseline.
Give a negative value to include all first-parent commits (similar
to `git log -n`).
Defaults to 1.
param_deps (bool, optional): include only parameters that are stage
dependencies.
Defaults to `False`.
force (bool, optional): force re-collection of experiments instead of
loading from internal experiments cache.
DVC caches `exp_show` data for completed experiments to improve
performance of subsequent calls.
When `force` is specified, DVC will reload all experiment data and
ignore any previously cached results.
Defaults to `False`.
config (dict, optional): config to be passed through to DVC project.
Defaults to `None`.
Returns:
List[Dict]: Each item in the list will contain a dictionary with
the info for an individual experiment.
See Examples below.
"""
with Repo.open(repo, config=config) as _repo:
experiments = _repo.experiments.show(
revs=revs,
num=num,
param_deps=param_deps,
force=force,
)
td, _ = tabulate(experiments, fill_value=None)
return _postprocess(td.as_dict())
+54
View File
@@ -0,0 +1,54 @@
from typing import List, Optional
from dvc.repo import Repo
def all_branches(repo: Optional[str] = None) -> List[str]:
"""Get all Git branches in a DVC repository.
Args:
repo (str, optional): location of the DVC repository.
Defaults to the current project (found by walking up from the
current working directory tree).
It can be a URL or a file system path.
Both HTTP and SSH protocols are supported for online Git repos
(e.g. [user@]server:project.git).
Returns:
List[str]: Names of the Git branches.
"""
with Repo.open(repo) as _repo:
return _repo.scm.list_branches()
def all_commits(repo: Optional[str] = None) -> List[str]:
"""Get all Git commits in a DVC repository.
Args:
repo (str, optional): location of the DVC repository.
Defaults to the current project (found by walking up from the
current working directory tree).
It can be a URL or a file system path.
Both HTTP and SSH protocols are supported for online Git repos
(e.g. [user@]server:project.git).
Returns:
List[str]: SHAs of the Git commits.
"""
with Repo.open(repo) as _repo:
return _repo.scm.list_all_commits()
def all_tags(repo: Optional[str] = None) -> List[str]:
"""Get all Git tags in a DVC repository.
Args:
repo (str, optional): location of the DVC repository.
Defaults to the current project (found by walking up from the
current working directory tree).
It can be a URL or a file system path.
Both HTTP and SSH protocols are supported for online Git repos
(e.g. [user@]server:project.git).
Returns:
List[str]: Names of the Git tags.
"""
with Repo.open(repo) as _repo:
return _repo.scm.list_tags()
+158 -34
View File
@@ -1,18 +1,166 @@
import typing
from collections import Counter
from typing import Dict, Iterable, Optional, Union
from funcy import first
from dvc.exceptions import DvcException
from dvc.repo import Repo
def _onerror_raise(exception: Exception, *args, **kwargs):
raise exception
def _postprocess(results):
processed: Dict[str, Dict] = {}
for rev, rev_data in results.items():
if not rev_data:
continue
processed[rev] = {}
counts: typing.Counter[str] = Counter()
for file_data in rev_data["data"].values():
for k in file_data["data"]:
counts[k] += 1
for file_name, file_data in rev_data["data"].items():
to_merge = {
(k if counts[k] == 1 else f"{file_name}:{k}"): v
for k, v in file_data["data"].items()
}
processed[rev] = {**processed[rev], **to_merge}
if "workspace" in processed:
del processed["workspace"]
return processed
def metrics_show(
*targets: str,
repo: Optional[str] = None,
rev: Optional[str] = None,
config: Optional[Dict] = None,
) -> Dict:
"""Get metrics tracked in `repo`.
Without arguments, this function will retrieve all metrics from all tracked
metric files, for the current working tree.
See the options below to restrict the metrics retrieved.
Args:
*targets (str, optional): Names of the metric files to retrieve
metrics from. For example, "classifier_eval.json,
clustering_eval.json".
If no `targets` are provided, all metric files tracked in `dvc.yaml`
will be used.
Note that targets don't necessarily have to be defined in `dvc.yaml`.
repo (str, optional): Location of the DVC repository.
Defaults to the current project (found by walking up from the
current working directory tree).
It can be a URL or a file system path.
Both HTTP and SSH protocols are supported for online Git repos
(e.g. [user@]server:project.git).
rev (str, optional): Name of the `Git revision`_ to retrieve metrics
from.
Defaults to `None`.
An example of git revision can be a branch or tag name, a commit
hash or a dvc experiment name.
If `repo` is not a Git repo, this option is ignored.
If `None`, the current working tree will be used.
config (dict, optional): config to be passed through to DVC project.
Defaults to `None`.
Returns:
Dict: See Examples below.
Examples:
- No arguments.
Working on https://github.com/iterative/example-get-started
>>> import dvc.api
>>> metrics = dvc.api.metrics_show()
>>> print(json.dumps(metrics, indent=4))
{
"avg_prec": 0.9249974999612706,
"roc_auc": 0.9460213440787918
}
---
- Using `rev`.
Working on https://github.com/iterative/example-get-started
>>> import json
>>> import dvc.api
>>> metrics = dvc.api.metrics_show(rev="tune-hyperparams")
>>> print(json.dumps(metrics, indent=4))
{
"avg_prec": 0.9268792615819422,
"roc_auc": 0.945093365854111
}
---
- Using `targets`.
Working on https://github.com/iterative/example-get-started
>>> import json
>>> import dvc.api
>>> metrics = dvc.api.metrics_show("evaluation.json")
>>> print(json.dumps(metrics, indent=4))
{
"avg_prec": 0.9249974999612706,
"roc_auc": 0.9460213440787918
}
---
- Git URL as `repo`.
>>> import json
>>> import dvc.api
>>> metrics = dvc.api.metrics_show(
... repo="https://github.com/iterative/demo-fashion-mnist")
>>> print(json.dumps(metrics, indent=4))
{
"loss": 0.25284987688064575,
"accuracy": 0.9071000218391418
}
.. _Git revision:
https://git-scm.com/docs/revisions
"""
with Repo.open(repo, config=config) as _repo:
metrics = _repo.metrics.show(
targets=targets,
revs=rev if rev is None else [rev],
onerror=_onerror_raise,
)
metrics = _postprocess(metrics)
if not metrics:
return {}
return metrics[first(metrics)]
def params_show(
*targets: str,
repo: Optional[str] = None,
stages: Optional[Union[str, Iterable[str]]] = None,
rev: Optional[str] = None,
deps: bool = False,
config: Optional[Dict] = None,
) -> Dict:
"""Get parameters tracked in `repo`.
@@ -51,13 +199,12 @@ def params_show(
deps (bool, optional): Whether to retrieve only parameters that are
stage dependencies or not.
Defaults to `False`.
config (dict, optional): config to be passed through to DVC project.
Defaults to `None`.
Returns:
Dict: See Examples below.
Raises:
DvcException: If no params are found in `repo`.
Examples:
- No arguments.
@@ -238,35 +385,7 @@ def params_show(
if isinstance(stages, str):
stages = [stages]
def _onerror_raise(result: Dict, exception: Exception, *args, **kwargs):
raise exception
def _postprocess(params):
processed = {}
for rev, rev_data in params.items():
processed[rev] = {}
counts = Counter()
for file_data in rev_data["data"].values():
for k in file_data["data"]:
counts[k] += 1
for file_name, file_data in rev_data["data"].items():
to_merge = {
(k if counts[k] == 1 else f"{file_name}:{k}"): v
for k, v in file_data["data"].items()
}
processed[rev] = {**processed[rev], **to_merge}
if "workspace" in processed:
del processed["workspace"]
if not processed:
raise DvcException("No params found")
return processed[first(processed)]
with Repo.open(repo) as _repo:
with Repo.open(repo, config=config) as _repo:
params = _repo.params.show(
revs=rev if rev is None else [rev],
targets=targets,
@@ -275,4 +394,9 @@ def params_show(
stages=stages,
)
return _postprocess(params)
params = _postprocess(params)
if not params:
return {}
return params[first(params)]
+10
View File
@@ -0,0 +1,10 @@
from typing import Optional
try:
# file is created during dvc build
# pylint:disable=unused-import
from . import _build # type: ignore[attr-defined, import]
PKG: Optional[str] = _build.PKG # type: ignore[assignment]
except ImportError:
PKG = None # type: ignore[assignment]
+138
View File
@@ -0,0 +1,138 @@
import os
from typing import TYPE_CHECKING, Optional, Tuple
from dvc.fs import GitFileSystem, Schemes
from dvc_data.hashfile.db import get_odb
from dvc_data.hashfile.hash import DEFAULT_ALGORITHM
if TYPE_CHECKING:
from dvc.repo import Repo
LEGACY_HASH_NAMES = {"md5-dos2unix", "params"}
def _get_odb(
repo,
settings,
fs=None,
prefix: Optional[Tuple[str, ...]] = None,
hash_name: Optional[str] = None,
**kwargs,
):
from dvc.fs import get_cloud_fs
if not settings:
return None
cls, config, fs_path = get_cloud_fs(repo.config, **settings)
fs = fs or cls(**config)
if prefix:
fs_path = fs.path.join(fs_path, *prefix)
if hash_name:
config["hash_name"] = hash_name
return get_odb(fs, fs_path, state=repo.state, **config)
class CacheManager:
CACHE_DIR = "cache"
FILES_DIR = "files"
def __init__(self, repo):
self._repo = repo
self.config = config = repo.config["cache"]
self._odb = {}
default = None
if repo and repo.local_dvc_dir:
default = os.path.join(repo.local_dvc_dir, self.CACHE_DIR)
local = config.get("local")
if local:
settings = {"name": local}
elif "dir" not in config and not default:
settings = None
else:
from dvc.config_schema import LOCAL_COMMON
url = config.get("dir") or default
settings = {"url": url}
for opt in LOCAL_COMMON:
if opt in config:
settings[str(opt)] = config.get(opt)
kwargs = {}
if not isinstance(repo.fs, GitFileSystem):
kwargs["fs"] = repo.fs
odb = _get_odb(
repo,
settings,
prefix=(self.FILES_DIR, DEFAULT_ALGORITHM),
**kwargs,
)
self._odb["repo"] = odb
self._odb[Schemes.LOCAL] = odb
legacy_odb = _get_odb(repo, settings, hash_name="md5-dos2unix", **kwargs)
self._odb["legacy"] = legacy_odb
def _init_odb(self, schemes):
for scheme in schemes:
remote = self.config.get(scheme)
settings = {"name": remote} if remote else None
self._odb[scheme] = _get_odb(
self._repo,
settings,
prefix=(self.FILES_DIR, DEFAULT_ALGORITHM),
)
def __getattr__(self, name):
try:
return self._odb[name]
except KeyError as exc:
raise AttributeError from exc
def by_scheme(self):
yield from self._odb.items()
@property
def local_cache_dir(self) -> str:
"""Return base local cache directory without any prefixes.
(i.e. `dvc cache dir`).
"""
return self.legacy.path
def migrate_2_to_3(repo: "Repo", dry: bool = False):
"""Migrate legacy 2.x objects to 3.x cache.
Legacy 'md5-dos2unix' objects will be re-hashed with 'md5', added to 3.x cache,
and then a link from the legacy 2.x location to the 3.x location will be created.
"""
from dvc.fs.callbacks import TqdmCallback
from dvc.ui import ui
from dvc_data.hashfile.db.migrate import migrate, prepare
src = repo.cache.legacy
dest = repo.cache.local
if dry:
oids = list(src._list_oids()) # pylint: disable=protected-access
ui.write(
f"{len(oids)} files will be re-hashed and migrated to the DVC 3.0 cache "
"location."
)
return
with TqdmCallback(
desc="Computing DVC 3.0 hashes",
unit="files",
) as cb:
migration = prepare(src, dest, callback=cb)
with TqdmCallback(
desc="Migrating to DVC 3.0 cache",
unit="files",
) as cb:
count = migrate(migration, callback=cb)
ui.write(f"Migrated {count} files to DVC 3.0 cache location.")
+49 -25
View File
@@ -39,13 +39,17 @@ def parse_args(argv=None):
def _log_unknown_exceptions() -> None:
from dvc.info import get_dvc_info
from dvc.logger import FOOTER
from dvc.ui import ui
from dvc.utils import colorize
logger.exception("unexpected error")
if logger.isEnabledFor(logging.DEBUG):
logger.debug("Version info for developers:\n%s", get_dvc_info())
logger.info(FOOTER)
return None
q = colorize("Having any troubles?", "yellow")
link = colorize("https://dvc.org/support", "blue")
footer = f"\n{q} Hit us up at {link}, we are always happy to help!"
ui.error_write(footer)
def _log_exceptions(exc: Exception) -> Optional[int]:
@@ -57,9 +61,11 @@ def _log_exceptions(exc: Exception) -> Optional[int]:
if exc.errno == errno.EMFILE:
logger.exception(
"too many open files, please visit "
"{} to see how to handle this "
"problem".format(error_link("many-files")),
(
"too many open files, please visit "
"%s to see how to handle this problem"
),
error_link("many-files"),
extra={"tb_only": True},
)
else:
@@ -69,7 +75,7 @@ def _log_exceptions(exc: Exception) -> Optional[int]:
from dvc.fs import AuthError, ConfigError, RemoteMissingDepsError
if isinstance(exc, RemoteMissingDepsError):
from dvc.utils.pkg import PKG
from dvc import PKG
proto = exc.protocol
by_pkg = {
@@ -77,11 +83,11 @@ def _log_exceptions(exc: Exception) -> Optional[int]:
"conda": f"conda install -c conda-forge dvc-{proto}",
}
cmd = by_pkg.get(PKG)
if cmd:
if PKG in by_pkg:
link = format_link("https://dvc.org/doc/install")
cmd = by_pkg.get(PKG)
hint = (
f"To install dvc with those dependencies, run:\n"
"To install dvc with those dependencies, run:\n"
"\n"
f"\t{cmd}\n"
"\n"
@@ -92,8 +98,10 @@ def _log_exceptions(exc: Exception) -> Optional[int]:
hint = f"\nPlease report this bug to {link}. Thank you!"
logger.exception(
f"URL '{exc.url}' is supported but requires these missing "
f"dependencies: {exc.missing_deps}. {hint}",
"URL '%s' is supported but requires these missing dependencies: %s. %s",
exc.url,
exc.missing_deps,
hint,
extra={"tb_only": True},
)
return None
@@ -102,7 +110,9 @@ def _log_exceptions(exc: Exception) -> Optional[int]:
link = format_link("https://man.dvc.org/remote/modify")
logger.exception("configuration error")
logger.exception(
f"{exc!s}\nLearn more about configuration settings at {link}.",
"%s\nLearn more about configuration settings at %s.",
exc,
link,
extra={"tb_only": True},
)
return 251
@@ -114,9 +124,14 @@ def _log_exceptions(exc: Exception) -> Optional[int]:
directory = relpath(exc.directory)
logger.exception(
f"Could not open pickled '{exc.type}' cache.\n"
f"Remove the '{directory}' directory and then retry this command."
f"\nSee {error_link('pickle')} for more information.",
(
"Could not open pickled '%s' cache.\n"
"Remove the '%s' directory and then retry this command."
"\nSee %s for more information."
),
exc.type,
directory,
error_link("pickle"),
extra={"tb_only": True},
)
return None
@@ -131,7 +146,7 @@ def _log_exceptions(exc: Exception) -> Optional[int]:
return None
def main(argv=None): # noqa: C901
def main(argv=None): # noqa: C901, PLR0912, PLR0915
"""Main entry point for dvc CLI.
Args:
@@ -143,7 +158,7 @@ def main(argv=None): # noqa: C901
from dvc._debug import debugtools
from dvc.config import ConfigError
from dvc.exceptions import DvcException, NotDvcRepoError
from dvc.logger import disable_other_loggers, set_loggers_level
from dvc.logger import set_loggers_level
# NOTE: stderr/stdout may be closed if we are running from dvc.daemon.
# On Linux we directly call cli.main after double forking and closing
@@ -156,9 +171,8 @@ def main(argv=None): # noqa: C901
logging.disable(logging.INFO)
args = None
disable_other_loggers()
outerLogLevel = logger.level
outer_log_level = logger.level
try:
args = parse_args(argv)
@@ -168,12 +182,22 @@ def main(argv=None): # noqa: C901
elif args.verbose == 1:
level = logging.DEBUG
elif args.verbose > 1:
level = logging.TRACE
level = logging.TRACE # type: ignore[attr-defined]
if level is not None:
set_loggers_level(level)
logger.trace(args)
if level and level <= logging.DEBUG:
from platform import platform, python_implementation, python_version
from dvc import PKG, __version__
pyv = f"{python_implementation()} {python_version()}"
pkg = f" ({PKG})" if PKG else ""
logger.debug("v%s%s, %s on %s", __version__, pkg, pyv, platform())
logger.debug("command: %s", " ".join(argv or sys.argv))
logger.trace(args) # type: ignore[attr-defined]
if not sys.stdout.closed and not args.quiet:
from dvc.ui import ui
@@ -206,7 +230,7 @@ def main(argv=None): # noqa: C901
logger.exception("")
except DvcParserError:
ret = 254
except Exception as exc: # noqa, pylint: disable=broad-except
except Exception as exc: # noqa: BLE001, pylint: disable=broad-except
# pylint: disable=no-member
ret = _log_exceptions(exc) or 255
@@ -218,9 +242,9 @@ def main(argv=None): # noqa: C901
return ret
finally:
logger.setLevel(outerLogLevel)
logger.setLevel(outer_log_level)
from dvc.external_repo import clean_repos
from dvc.repo.open_repo import clean_repos
# Remove cached repos in the end of the call, these are anonymous
# so won't be reused by any other subsequent run anyway.
-20
View File
@@ -1,20 +0,0 @@
from argparse import _AppendAction
class CommaSeparatedArgs(_AppendAction): # pylint: disable=protected-access
def __call__(self, parser, namespace, values, option_string=None):
from funcy import ldistinct
items = getattr(namespace, self.dest) or []
items.extend(map(str.strip, values.split(",")))
setattr(namespace, self.dest, ldistinct(items))
class KeyValueArgs(_AppendAction):
def __call__(self, parser, namespace, values, option_string=None):
items = getattr(namespace, self.dest) or {}
for value in filter(bool, values):
key, _, value = value.partition("=")
items[key.strip()] = value
setattr(namespace, self.dest, items)
+6 -2
View File
@@ -1,6 +1,10 @@
import logging
import os
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from dvc.config import Config
logger = logging.getLogger(__name__)
@@ -8,13 +12,13 @@ logger = logging.getLogger(__name__)
class CmdBase(ABC):
UNINITIALIZED = False
def __init__(self, args):
def __init__(self, args: Any):
from dvc.repo import Repo
os.chdir(args.cd)
self.repo: "Repo" = Repo(uninitialized=self.UNINITIALIZED)
self.config = self.repo.config
self.config: "Config" = self.repo.config
self.args = args
def do_run(self):
+3 -3
View File
@@ -2,6 +2,7 @@
import argparse
import logging
import os
from functools import lru_cache
from dvc import __version__
from dvc.commands import (
@@ -40,7 +41,6 @@ from dvc.commands import (
remove,
repro,
root,
run,
stage,
unprotect,
update,
@@ -61,7 +61,6 @@ COMMANDS = [
remove,
move,
unprotect,
run,
repro,
data_sync,
gc,
@@ -138,7 +137,6 @@ def get_parent_parser():
from dvc._debug import add_debugging_flags
parent_parser = argparse.ArgumentParser(add_help=False)
add_debugging_flags(parent_parser)
log_level_group = parent_parser.add_mutually_exclusive_group()
log_level_group.add_argument(
"-q", "--quiet", action="count", default=0, help="Be quiet."
@@ -146,10 +144,12 @@ def get_parent_parser():
log_level_group.add_argument(
"-v", "--verbose", action="count", default=0, help="Be verbose."
)
add_debugging_flags(parent_parser)
return parent_parser
@lru_cache(maxsize=1)
def get_main_parser():
parent_parser = get_parent_parser()
+26 -6
View File
@@ -1,3 +1,27 @@
import argparse
class DictAction(argparse.Action):
def __call__(self, parser, args, values, option_string=None): # noqa: ARG002
d = getattr(args, self.dest) or {}
if isinstance(values, list):
kvs = values
else:
kvs = [values]
for kv in kvs:
key, value = kv.split("=")
if not value:
raise argparse.ArgumentError(
self,
f'Could not parse argument "{values}" as k1=v1 k2=v2 ... format',
)
d[key] = value
setattr(args, self.dest, d)
def fix_subparsers(subparsers):
"""Workaround for bug in Python 3. See more info at:
https://bugs.python.org/issue16308
@@ -16,9 +40,7 @@ def append_doc_link(help_message, path):
if not path:
return help_message
doc_base = "https://man.dvc.org/"
return "{message}\nDocumentation: {link}".format(
message=help_message, link=format_link(doc_base + path)
)
return f"{help_message}\nDocumentation: {format_link(doc_base + path)}"
def hide_subparsers_from_help(subparsers):
@@ -28,7 +50,5 @@ def hide_subparsers_from_help(subparsers):
# Need to set `add_help=False`, but avoid setting `help`
# (not even to `argparse.SUPPPRESS`).
# NOTE: The argument is the parent subparser, not the subcommand parser.
cmds = [
cmd for cmd, parser in subparsers.choices.items() if parser.add_help
]
cmds = [cmd for cmd, parser in subparsers.choices.items() if parser.add_help]
subparsers.metavar = "{{{}}}".format(",".join(cmds))
+44 -68
View File
@@ -2,71 +2,61 @@ import argparse
import logging
from dvc.cli import completion
from dvc.cli.actions import KeyValueArgs
from dvc.cli.command import CmdBase
from dvc.cli.utils import append_doc_link
logger = logging.getLogger(__name__)
def _add_annotating_args(parser: argparse.ArgumentParser) -> None:
parser.add_argument(
"--desc",
type=str,
metavar="<text>",
help="User description of the data.",
)
parser.add_argument(
"--meta",
metavar="key=value",
nargs=1,
action=KeyValueArgs,
help="Custom metadata to add to the data.",
)
parser.add_argument(
"--label",
dest="labels",
type=str,
action="append",
metavar="<str>",
help="Label for the data.",
)
parser.add_argument(
"--type",
type=str,
metavar="<str>",
help="Type of the data.",
)
class CmdAdd(CmdBase):
def validate_args(self) -> None:
from dvc.exceptions import InvalidArgumentError
args = self.args
invalid_opt = None
if args.to_remote or args.out:
message = "{option} can't be used with "
message += "--to-remote" if args.to_remote else "--out"
if len(args.targets) != 1:
invalid_opt = "multiple targets"
elif args.glob:
invalid_opt = "--glob option"
elif args.no_commit:
invalid_opt = "--no-commit option"
else:
message = "{option} can't be used without --to-remote"
if args.remote:
invalid_opt = "--remote"
elif args.remote_jobs:
invalid_opt = "--remote-jobs"
if invalid_opt is not None:
raise InvalidArgumentError(message.format(option=invalid_opt))
def run(self):
from dvc.exceptions import (
DvcException,
RecursiveAddingWhileUsingFilename,
)
from dvc.exceptions import DvcException, InvalidArgumentError
try:
if len(self.args.targets) > 1 and self.args.file:
raise RecursiveAddingWhileUsingFilename()
self.validate_args()
except InvalidArgumentError:
logger.exception("")
return 1
try:
self.repo.add(
self.args.targets,
recursive=self.args.recursive,
no_commit=self.args.no_commit,
fname=self.args.file,
external=self.args.external,
glob=self.args.glob,
desc=self.args.desc,
out=self.args.out,
type=self.args.type,
labels=self.args.labels,
meta=self.args.meta,
remote=self.args.remote,
to_remote=self.args.to_remote,
jobs=self.args.jobs,
remote_jobs=self.args.remote_jobs,
force=self.args.force,
)
except FileNotFoundError:
logger.exception("")
return 1
except DvcException:
logger.exception("")
return 1
@@ -83,36 +73,18 @@ def add_parser(subparsers, parent_parser):
help=ADD_HELP,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
"-R",
"--recursive",
action="store_true",
default=False,
help="Recursively add files under directory targets.",
)
parser.add_argument(
"--no-commit",
action="store_true",
default=False,
help="Don't put files/directories into cache.",
)
parser.add_argument(
"--external",
action="store_true",
default=False,
help="Allow targets that are outside of the DVC repository.",
)
parser.add_argument(
"--glob",
action="store_true",
default=False,
help="Allows targets containing shell-style wildcards.",
)
parser.add_argument(
"--file",
help="Specify name of the .dvc file this command will generate.",
metavar="<filename>",
)
parser.add_argument(
"-o",
"--out",
@@ -132,8 +104,7 @@ def add_parser(subparsers, parent_parser):
metavar="<name>",
)
parser.add_argument(
"-j",
"--jobs",
"--remote-jobs",
type=int,
help=(
"Only used along with '--to-remote'. "
@@ -143,8 +114,13 @@ def add_parser(subparsers, parent_parser):
),
metavar="<number>",
)
_add_annotating_args(parser)
parser.add_argument(
"-f",
"--force",
action="store_true",
default=False,
help="Override local file or folder if exists.",
)
parser.add_argument(
"targets", nargs="+", help="Input files/directories to add."
).complete = completion.FILE
+47 -9
View File
@@ -1,6 +1,8 @@
import argparse
import os
from dvc.cli import completion
from dvc.cli.command import CmdBase
from dvc.cli.utils import append_doc_link, fix_subparsers
from dvc.commands.config import CmdConfig
from dvc.ui import ui
@@ -9,13 +11,21 @@ from dvc.ui import ui
class CmdCacheDir(CmdConfig):
def run(self):
if self.args.value is None and not self.args.unset:
from dvc.config import ConfigError
if self.args.level:
conf = self.config.read(level=self.args.level)
else:
# Use merged config with default values
conf = self.config
self._check(conf, False, "cache", "dir")
ui.write(conf["cache"]["dir"])
try:
self._check(conf, False, "cache", "dir")
path = conf["cache"]["dir"]
except ConfigError:
if not self.config.dvc_dir or self.args.level:
raise
path = os.path.join(self.config.dvc_dir, "cache")
ui.write(path)
return 0
with self.config.edit(level=self.args.level) as conf:
if self.args.unset:
@@ -27,6 +37,14 @@ class CmdCacheDir(CmdConfig):
return 0
class CmdCacheMigrate(CmdBase):
def run(self):
from dvc.cachemgr import migrate_2_to_3
migrate_2_to_3(self.repo, dry=self.args.dry)
return 0
def add_parser(subparsers, parent_parser):
from dvc.commands.config import parent_config_parser
@@ -42,11 +60,9 @@ def add_parser(subparsers, parent_parser):
cache_subparsers = cache_parser.add_subparsers(
dest="cmd",
help="Use `dvc cache CMD --help` for command-specific " "help.",
help="Use `dvc cache CMD --help` for command-specific help.",
)
fix_subparsers(cache_subparsers)
parent_cache_config_parser = argparse.ArgumentParser(
add_help=False, parents=[parent_config_parser]
)
@@ -68,10 +84,32 @@ def add_parser(subparsers, parent_parser):
)
cache_dir_parser.add_argument(
"value",
help="Path to cache directory. Relative paths are resolved relative "
"to the current directory and saved to config relative to the "
"config file location. If no path is provided, it returns the "
"current cache directory.",
help=(
"Path to cache directory. Relative paths are resolved relative "
"to the current directory and saved to config relative to the "
"config file location. If no path is provided, it returns the "
"current cache directory."
),
nargs="?",
).complete = completion.DIR
cache_dir_parser.set_defaults(func=CmdCacheDir)
CACHE_MIGRATE_HELP = "Migrate cached files to the DVC 3.0 cache location."
cache_migrate_parser = cache_subparsers.add_parser(
"migrate",
parents=[parent_parser],
description=append_doc_link(CACHE_HELP, "cache/migrate"),
help=CACHE_MIGRATE_HELP,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
cache_migrate_parser.add_argument(
"--dry",
help=(
"Only print actions which would be taken without actually migrating "
"any data."
),
action="store_true",
)
cache_migrate_parser.set_defaults(func=CmdCacheMigrate)
fix_subparsers(cache_subparsers)
+11 -11
View File
@@ -39,7 +39,7 @@ class CmdCheckIgnore(CmdBase):
target = input()
except (KeyboardInterrupt, EOFError):
break
if target == "":
if not target:
break
if not self._check_one_file(target):
ret = 0
@@ -62,9 +62,7 @@ class CmdCheckIgnore(CmdBase):
raise DvcException("cannot have both `targets` and `--stdin`")
if self.args.non_matching and not self.args.details:
raise DvcException(
"`--non-matching` is only valid with `--details`"
)
raise DvcException("`--non-matching` is only valid with `--details`")
if self.args.all and not self.args.details:
raise DvcException("`--all` is only valid with `--details`")
@@ -80,9 +78,7 @@ class CmdCheckIgnore(CmdBase):
def add_parser(subparsers, parent_parser):
ADD_HELP = (
"Check whether files or directories are excluded due to `.dvcignore`."
)
ADD_HELP = "Check whether files or directories are excluded due to `.dvcignore`."
parser = subparsers.add_parser(
"check-ignore",
@@ -103,16 +99,20 @@ def add_parser(subparsers, parent_parser):
"--all",
action="store_true",
default=False,
help="Include the target paths which don’t match any pattern "
"in the `--details` list.",
help=(
"Include the target paths which don't match any pattern "
"in the `--details` list."
),
)
parser.add_argument(
"-n",
"--non-matching",
action="store_true",
default=False,
help="Include the target paths which don’t match any pattern "
"in the `--details` list.",
help=(
"Include the target paths which don't match any pattern "
"in the `--details` list."
),
)
parser.add_argument(
"--stdin",
+2 -6
View File
@@ -22,9 +22,7 @@ def log_changes(stats):
continue
for entry in entries:
ui.write(
f"[{color}]{state[0].upper()}", entry, styled=True, sep="\t"
)
ui.write(f"[{color}]{state[0].upper()}", entry, styled=True, sep="\t")
class CmdCheckout(CmdBase):
@@ -46,9 +44,7 @@ class CmdCheckout(CmdBase):
if self.args.summary:
default_message = "No changes."
msg = get_summary(
sorted(stats.items(), key=operator.itemgetter(0))
)
msg = get_summary(sorted(stats.items(), key=operator.itemgetter(0)))
ui.write(msg or default_message)
else:
log_changes(stats)
+5 -6
View File
@@ -24,11 +24,7 @@ class CmdCommit(CmdBase):
force=self.args.force,
)
except DvcException:
logger.exception(
"failed to commit{}".format(
(" " + target) if target else ""
)
)
logger.exception("failed to commit%s", (" " + target) if target else "")
return 1
return 0
@@ -51,7 +47,10 @@ def add_parser(subparsers, parent_parser):
"--force",
action="store_true",
default=False,
help="Commit even if hash value for dependencies/outputs changed.",
help=(
"Commit data even if hash values for dependencies or",
"outputs did not change.",
),
)
commit_parser.add_argument(
"-d",
+1 -1
View File
@@ -15,7 +15,7 @@ class CmdCompletion(CmdBaseNoRepo):
shell = self.args.shell
parser = self.args.parser
script = shtab.complete(parser, shell=shell, preamble=PREAMBLE)
script = shtab.complete(parser, shell=shell, preamble=PREAMBLE) # nosec B604
ui.write(script, force=True)
return 0
+10 -17
View File
@@ -17,9 +17,7 @@ def _name_type(value):
match = re.match(NAME_REGEX, value)
if not match:
raise argparse.ArgumentTypeError(
"name argument should look like "
"remote.name.option or "
"section.option"
"name argument should look like remote.name.option or section.option"
)
return (
bool(match.group("remote")),
@@ -34,16 +32,15 @@ class CmdConfig(CmdBaseNoRepo):
super().__init__(args)
self.config = Config(validate=False)
self.config = Config.from_cwd(validate=False)
def run(self):
if self.args.show_origin:
if any((self.args.value, self.args.unset)):
logger.error(
"--show-origin can't be used together with any of these "
"options: -u/--unset, value"
)
return 1
if self.args.show_origin and (self.args.value or self.args.unset):
logger.error(
"--show-origin can't be used together with any of these "
"options: -u/--unset, value"
)
return 1
if self.args.list:
return self._list()
@@ -71,9 +68,7 @@ class CmdConfig(CmdBaseNoRepo):
for level in levels:
conf = self.config.read(level)
prefix = self._config_file_prefix(
self.args.show_origin, self.config, level
)
prefix = self._config_file_prefix(self.args.show_origin, self.config, level)
configs = list(self._format_config(conf, prefix))
if configs:
ui.write("\n".join(configs))
@@ -132,9 +127,7 @@ class CmdConfig(CmdBaseNoRepo):
raise ConfigError(f"{name} '{section}' doesn't exist")
if opt and opt not in conf[section]:
raise ConfigError(
f"option '{opt}' doesn't exist in {name} '{section}'"
)
raise ConfigError(f"option '{opt}' doesn't exist in {name} '{section}'")
def _get_appropriate_levels(self, levels):
if levels:
+1 -1
View File
@@ -46,7 +46,7 @@ def add_parser(subparsers, parent_parser):
daemon_subparsers = daemon_parser.add_subparsers(
dest="cmd",
help="Use `dvc daemon CMD --help` for command-specific " "help.",
help="Use `dvc daemon CMD --help` for command-specific help.",
)
fix_subparsers(daemon_subparsers)
+28 -30
View File
@@ -9,11 +9,11 @@ if TYPE_CHECKING:
from networkx import DiGraph
def _show_ascii(G: "DiGraph"):
def _show_ascii(graph: "DiGraph"):
from dvc.dagascii import draw
from dvc.repo.graph import get_pipelines
pipelines = get_pipelines(G)
pipelines = get_pipelines(graph)
ret = []
for pipeline in pipelines:
@@ -31,7 +31,7 @@ def _quote_label(node):
return label
def _show_dot(G: "DiGraph"):
def _show_dot(graph: "DiGraph"):
import io
import networkx as nx
@@ -39,15 +39,15 @@ def _show_dot(G: "DiGraph"):
dot_file = io.StringIO()
nx.relabel_nodes(G, _quote_label, copy=False)
write_dot(G.reverse(), dot_file)
nx.relabel_nodes(graph, _quote_label, copy=False)
write_dot(graph.reverse(), dot_file)
return dot_file.getvalue()
def _show_mermaid(G, markdown: bool = False):
def _show_mermaid(graph, markdown: bool = False):
from dvc.repo.graph import get_pipelines
pipelines = get_pipelines(G)
pipelines = get_pipelines(graph)
graph = "flowchart TD"
@@ -86,9 +86,7 @@ def _collect_targets(repo, target, outs):
targets.extend([str(out) for out in stage.outs])
continue
for out in outs_trie.itervalues( # noqa: B301
prefix=repo.fs.path.parts(path)
):
for out in outs_trie.itervalues(prefix=repo.fs.path.parts(path)): # noqa: B301
targets.extend(str(out))
return targets
@@ -102,43 +100,42 @@ def _transform(index, outs):
def _relabel(node) -> str:
return node.addressing if isinstance(node, Stage) else str(node)
G = index.outs_graph if outs else index.graph
return nx.relabel_nodes(G, _relabel, copy=True)
graph = index.outs_graph if outs else index.graph
return nx.relabel_nodes(graph, _relabel, copy=True)
def _filter(G, targets, full):
def _filter(graph, targets, full):
import networkx as nx
if not targets:
return G
return graph
H = G.copy()
new_graph = graph.copy()
if not full:
descendants = set()
for target in targets:
descendants.update(nx.descendants(G, target))
descendants.update(nx.descendants(graph, target))
descendants.add(target)
H.remove_nodes_from(set(G.nodes()) - descendants)
new_graph.remove_nodes_from(set(graph.nodes()) - descendants)
undirected = H.to_undirected()
undirected = new_graph.to_undirected()
connected = set()
for target in targets:
connected.update(nx.node_connected_component(undirected, target))
H.remove_nodes_from(set(H.nodes()) - connected)
return H
new_graph.remove_nodes_from(set(new_graph.nodes()) - connected)
return new_graph
def _build(repo, target=None, full=False, outs=False):
targets = _collect_targets(repo, target, outs)
G = _transform(repo.index, outs)
return _filter(G, targets, full)
graph = _transform(repo.index, outs)
return _filter(graph, targets, full)
class CmdDAG(CmdBase):
def run(self):
G = _build(
graph = _build(
self.repo,
target=self.args.target,
full=self.args.full,
@@ -146,12 +143,12 @@ class CmdDAG(CmdBase):
)
if self.args.dot:
ui.write(_show_dot(G))
ui.write(_show_dot(graph))
elif self.args.mermaid or self.args.markdown:
ui.write(_show_mermaid(G, self.args.markdown))
ui.write(_show_mermaid(graph, self.args.markdown))
else:
with ui.pager():
ui.write(_show_ascii(G))
ui.write(_show_ascii(graph))
return 0
@@ -179,7 +176,6 @@ def add_parser(subparsers, parent_parser):
)
dag_parser.add_argument(
"--md",
"--show-md",
action="store_true",
default=False,
dest="markdown",
@@ -204,7 +200,9 @@ def add_parser(subparsers, parent_parser):
dag_parser.add_argument(
"target",
nargs="?",
help="Stage name or output to show pipeline for. "
"Finds all stages in the workspace by default.",
help=(
"Stage name or output to show pipeline for. "
"Finds all stages in the workspace by default."
),
)
dag_parser.set_defaults(func=CmdDAG)
+31 -138
View File
@@ -1,18 +1,11 @@
import argparse
import logging
from operator import itemgetter
from typing import TYPE_CHECKING, Any, Dict, Iterable, Set
from typing import TYPE_CHECKING
from funcy import chunks, compact, log_durations
from dvc.cli import completion
from dvc.cli.actions import CommaSeparatedArgs
from dvc.cli.command import CmdBase
from dvc.cli.utils import (
append_doc_link,
fix_subparsers,
hide_subparsers_from_help,
)
from dvc.cli.utils import append_doc_link, fix_subparsers
from dvc.ui import ui
from dvc.utils import colorize
@@ -25,12 +18,14 @@ logger = logging.getLogger(__name__)
class CmdDataStatus(CmdBase):
COLORS = {
"not_in_remote": "red",
"not_in_cache": "red",
"committed": "green",
"uncommitted": "yellow",
"untracked": "cyan",
}
LABELS = {
"not_in_remote": "Not in remote",
"not_in_cache": "Not in cache",
"committed": "DVC committed changes",
"uncommitted": "DVC uncommitted changes",
@@ -38,21 +33,21 @@ class CmdDataStatus(CmdBase):
"unchanged": "DVC unchanged files",
}
HINTS = {
"not_in_remote": ('use "dvc push <file>..." to upload files',),
"not_in_cache": ('use "dvc fetch <file>..." to download files',),
"committed": (
"git commit the corresponding dvc files to update the repo",
),
"committed": ("git commit the corresponding dvc files to update the repo",),
"uncommitted": (
'use "dvc commit <file>..." to track changes',
'use "dvc checkout <file>..." to discard changes',
),
"untracked": (
'use "git add <file> ..." or '
'"dvc add <file>..." to commit to git or to dvc',
(
'use "git add <file> ..." or '
'"dvc add <file>..." to commit to git or to dvc'
),
),
"git_dirty": (
"there are {}changes not tracked by dvc, "
'use "git status" to see',
'there are {}changes not tracked by dvc, use "git status" to see',
),
}
@@ -72,7 +67,7 @@ class CmdDataStatus(CmdBase):
yield stage, items
@classmethod
def _show_status(cls, status: "DataStatus") -> int:
def _show_status(cls, status: "DataStatus") -> int: # noqa: C901
git_info = status.pop("git") # type: ignore[misc]
result = dict(cls._process_status(status))
if not result:
@@ -95,10 +90,7 @@ class CmdDataStatus(CmdBase):
ui.write(f" ({hint})")
if isinstance(stage_status, dict):
items = [
": ".join([state, file])
for file, state in stage_status.items()
]
items = [f"{state}: {file}" for file, state in stage_status.items()]
else:
items = stage_status
@@ -114,10 +106,14 @@ class CmdDataStatus(CmdBase):
return 0
def run(self) -> int:
with log_durations(logger.trace, "in data_status"): # type: ignore
with log_durations(
logger.trace, "in data_status" # type: ignore[attr-defined]
):
status = self.repo.data_status(
granular=self.args.granular,
untracked_files=self.args.untracked_files,
not_in_remote=self.args.not_in_remote,
remote_refresh=self.args.remote_refresh,
)
if not self.args.unchanged:
@@ -131,65 +127,6 @@ class CmdDataStatus(CmdBase):
return self._show_status(status)
class CmdDataLs(CmdBase):
@staticmethod
def _show_table(
d: Iterable[Dict[str, Any]],
filter_types: Set[str],
filter_labels: Set[str],
markdown: bool = False,
) -> None:
from rich.style import Style
from dvc.compare import TabularData
td = TabularData(
columns=["Path", "Type", "Labels", "Description"], fill_value="-"
)
for entry in sorted(d, key=itemgetter("path")):
typ = entry.get("type", "")
desc = entry.get("desc", "-")
labels = entry.get("labels", [])
if filter_types and typ not in filter_types:
continue
if filter_labels and filter_labels.isdisjoint(labels):
continue
rich_label = ui.rich_text()
for index, label in enumerate(labels):
if index:
rich_label.append(",")
style = Style(bold=label in filter_labels, color="green")
rich_label.append(label, style=style)
if markdown and desc:
desc = desc.partition("\n")[0]
path = ui.rich_text(entry["path"], style="cyan")
type_style = Style(bold=typ in filter_types, color="yellow")
typ = ui.rich_text(entry.get("type", ""), style=type_style)
td.append([path, typ or "-", rich_label or "-", desc])
td.render(markdown=markdown, rich_table=True)
def run(self):
from dvc.repo.data import ls
filter_labels = set(self.args.labels)
filter_types = set(self.args.type)
d = ls(
self.repo, targets=self.args.targets, recursive=self.args.recursive
)
self._show_table(
d,
filter_labels=filter_labels,
filter_types=filter_types,
markdown=self.args.markdown,
)
return 0
def add_parser(subparsers, parent_parser):
data_parser = subparsers.add_parser(
"data",
@@ -203,8 +140,7 @@ def add_parser(subparsers, parent_parser):
fix_subparsers(data_subparsers)
DATA_STATUS_HELP = (
"Show changes between the last git commit, "
"the dvcfiles and the workspace."
"Show changes between the last git commit, the dvcfiles and the workspace."
)
data_status_parser = data_subparsers.add_parser(
"status",
@@ -219,13 +155,6 @@ def add_parser(subparsers, parent_parser):
default=False,
help="Show output in JSON format.",
)
data_status_parser.add_argument(
"--show-json",
action="store_true",
default=False,
dest="json",
help=argparse.SUPPRESS,
)
data_status_parser.add_argument(
"--granular",
action="store_true",
@@ -246,52 +175,16 @@ def add_parser(subparsers, parent_parser):
nargs="?",
help="Show untracked files.",
)
data_status_parser.add_argument(
"--not-in-remote",
action="store_true",
default=False,
help="Show files not in remote.",
)
data_status_parser.add_argument(
"--no-remote-refresh",
dest="remote_refresh",
action="store_false",
help="Use cached remote index (don't check remote).",
)
data_status_parser.set_defaults(func=CmdDataStatus)
DATA_LS_HELP = "List data tracked by DVC with its metadata."
data_ls_parser = data_subparsers.add_parser(
"ls",
aliases=["list"],
parents=[parent_parser],
description=append_doc_link(DATA_LS_HELP, "data/ls"),
formatter_class=argparse.RawDescriptionHelpFormatter,
add_help=False,
)
data_ls_parser.add_argument(
"--md",
"--show-md",
dest="markdown",
action="store_true",
default=False,
help="Show tabulated output in the Markdown format (GFM).",
)
data_ls_parser.add_argument(
"--type",
action=CommaSeparatedArgs,
default=[],
help="Comma-separated list of type to filter.",
)
data_ls_parser.add_argument(
"--labels",
action=CommaSeparatedArgs,
default=[],
help="Comma-separated list of labels to filter.",
)
data_ls_parser.add_argument(
"-R",
"--recursive",
action="store_true",
default=False,
help="Recursively list from the specified directories.",
)
data_ls_parser.add_argument(
"targets",
default=None,
nargs="*",
help=(
"Limit command scope to these tracked files/directories, "
".dvc files, or stage names."
),
).complete = completion.DVCFILES_AND_STAGE
data_ls_parser.set_defaults(func=CmdDataLs)
hide_subparsers_from_help(data_subparsers)
+40 -15
View File
@@ -40,6 +40,7 @@ class CmdDataPull(CmdDataBase):
recursive=self.args.recursive,
run_cache=self.args.run_cache,
glob=self.args.glob,
allow_missing=self.args.allow_missing,
)
self.log_summary(stats)
except (CheckoutError, DvcException) as exc:
@@ -90,6 +91,8 @@ class CmdDataFetch(CmdDataBase):
with_deps=self.args.with_deps,
recursive=self.args.recursive,
run_cache=self.args.run_cache,
max_size=self.args.max_size,
types=self.args.types,
)
self.log_summary({"fetched": processed_files_count})
except DvcException:
@@ -122,7 +125,7 @@ def shared_parent_parser():
"Limit command scope to these tracked files/directories, "
".dvc files and stage names."
),
).complete = completion.DVC_FILE
).complete = completion.DVC_FILE # type: ignore[attr-defined]
return parent_parser
@@ -197,6 +200,12 @@ def add_parser(subparsers, _parent_parser):
default=False,
help=argparse.SUPPRESS,
)
pull_parser.add_argument(
"--allow-missing",
action="store_true",
default=False,
help="Ignore errors if some of the files or directories are missing.",
)
pull_parser.set_defaults(func=CmdDataPull)
# Push
@@ -262,9 +271,7 @@ def add_parser(subparsers, _parent_parser):
push_parser.set_defaults(func=CmdDataPush)
# Fetch
FETCH_HELP = (
"Download files or directories from remote storage to the cache."
)
FETCH_HELP = "Download files or directories from remote storage to the cache."
fetch_parser = subparsers.add_parser(
"fetch",
@@ -302,7 +309,7 @@ def add_parser(subparsers, _parent_parser):
"--with-deps",
action="store_true",
default=False,
help="Fetch cache for all dependencies of the " "specified target.",
help="Fetch cache for all dependencies of the specified target.",
)
fetch_parser.add_argument(
"-R",
@@ -317,12 +324,26 @@ def add_parser(subparsers, _parent_parser):
default=False,
help="Fetch run history for all stages.",
)
fetch_parser.add_argument(
"--max-size",
type=int,
help="Fetch data files/directories that are each below specified size (bytes).",
)
fetch_parser.add_argument(
"--type",
dest="types",
action="append",
default=[],
help=(
"Only fetch data files/directories that are of a particular "
"type (metrics, plots)."
),
choices=["metrics", "plots"],
)
fetch_parser.set_defaults(func=CmdDataFetch)
# Status
STATUS_HELP = (
"Show changed stages, compare local cache and a remote storage."
)
STATUS_HELP = "Show changed stages, compare local cache and a remote storage."
status_parser = subparsers.add_parser(
"status",
@@ -360,24 +381,29 @@ def add_parser(subparsers, _parent_parser):
"--all-branches",
action="store_true",
default=False,
help="Show status of a local cache compared to a remote repository "
"for all branches.",
help=(
"Show status of a local cache compared to a remote repository "
"for all branches."
),
)
status_parser.add_argument(
"-T",
"--all-tags",
action="store_true",
default=False,
help="Show status of a local cache compared to a remote repository "
"for all tags.",
help=(
"Show status of a local cache compared to a remote repository for all tags."
),
)
status_parser.add_argument(
"-A",
"--all-commits",
action="store_true",
default=False,
help="Show status of a local cache compared to a remote repository "
"for all commits.",
help=(
"Show status of a local cache compared to a remote repository "
"for all commits."
),
)
status_parser.add_argument(
"-d",
@@ -395,7 +421,6 @@ def add_parser(subparsers, _parent_parser):
)
status_parser.add_argument(
"--json",
"--show-json",
action="store_true",
default=False,
help="Show status in JSON format.",
+1 -1
View File
@@ -21,7 +21,7 @@ class CmdDestroy(CmdBase):
)
if not self.args.force and not ui.confirm(statement):
raise DvcException(
raise DvcException( # noqa: TRY301
"cannot destroy without a confirmation from the user."
" Use `-f` to force."
)
+10 -17
View File
@@ -109,12 +109,10 @@ class CmdDiff(CmdBase):
ui.write()
if not sum(summary.values()):
return None
return
states_summary = ", ".join(
f"{summary[state]} {state}"
for state in states
if summary[state] > 0
f"{summary[state]} {state}" for state in states if summary[state] > 0
)
ui.write("files summary:", states_summary)
@@ -122,9 +120,7 @@ class CmdDiff(CmdBase):
from dvc.exceptions import DvcException
try:
diff = self.repo.diff(
self.args.a_rev, self.args.b_rev, self.args.targets
)
diff = self.repo.diff(self.args.a_rev, self.args.b_rev, self.args.targets)
show_hash = self.args.show_hash
hide_missing = self.args.b_rev or self.args.hide_missing
if hide_missing:
@@ -133,9 +129,11 @@ class CmdDiff(CmdBase):
for key, entries in diff.items():
entries = sorted(
entries,
key=lambda entry: entry["path"]["old"]
if isinstance(entry["path"], dict)
else entry["path"],
key=lambda entry: (
entry["path"]["old"]
if isinstance(entry["path"], dict)
else entry["path"]
),
)
if not show_hash:
for entry in entries:
@@ -170,10 +168,7 @@ def add_parser(subparsers, parent_parser):
diff_parser.add_argument(
"--targets",
nargs="*",
help=(
"Specific DVC-tracked files to compare. "
"Accepts one or more file paths."
),
help="Specific DVC-tracked files to compare. Accepts one or more file paths.",
metavar="<paths>",
).complete = completion.FILE
diff_parser.add_argument(
@@ -184,12 +179,11 @@ def add_parser(subparsers, parent_parser):
)
diff_parser.add_argument(
"b_rev",
help=("New Git commit to compare (defaults to the current workspace)"),
help="New Git commit to compare (defaults to the current workspace)",
nargs="?",
)
diff_parser.add_argument(
"--json",
"--show-json",
help="Format the output into a JSON",
action="store_true",
default=False,
@@ -202,7 +196,6 @@ def add_parser(subparsers, parent_parser):
)
diff_parser.add_argument(
"--md",
"--show-md",
help="Show tabulated output in the Markdown format (GFM).",
action="store_true",
dest="markdown",
+5 -11
View File
@@ -1,17 +1,12 @@
import argparse
from dvc.cli.utils import (
append_doc_link,
fix_subparsers,
hide_subparsers_from_help,
)
from dvc.cli.utils import append_doc_link, fix_subparsers, hide_subparsers_from_help
from dvc.commands.experiments import (
apply,
branch,
clean,
diff,
exec_run,
gc,
init,
ls,
pull,
push,
@@ -25,10 +20,9 @@ from dvc.commands.experiments import (
SUB_COMMANDS = [
apply,
branch,
clean,
diff,
exec_run,
gc,
init,
ls,
pull,
push,
@@ -54,8 +48,7 @@ def add_parser(subparsers, parent_parser):
experiments_subparsers = experiments_parser.add_subparsers(
dest="cmd",
help="Use `dvc experiments CMD --help` to display "
"command-specific help.",
help="Use `dvc experiments CMD --help` to display command-specific help.",
)
fix_subparsers(experiments_subparsers)
@@ -85,6 +78,7 @@ def add_rev_selection_flags(
experiments_subcmd_parser.add_argument(
"--rev",
type=str,
action="append",
default=None,
help=msg,
metavar="<commit>",
+10 -8
View File
@@ -4,25 +4,27 @@ import logging
from dvc.cli import completion
from dvc.cli.command import CmdBase
from dvc.cli.utils import append_doc_link
from dvc.ui import ui
logger = logging.getLogger(__name__)
class CmdExperimentsApply(CmdBase):
def run(self):
self.repo.experiments.apply(
self.args.experiment, force=self.args.force
)
if not self.args.force:
ui.write(
"The --no-force option is deprecated and will be removed in a future"
" DVC release. To revert the result of 'exp apply', run:\n"
"\n\tgit reset --hard\n"
"\tgit stash apply refs/exps/apply/stash\n"
)
self.repo.experiments.apply(self.args.experiment)
return 0
def add_parser(experiments_subparsers, parent_parser):
EXPERIMENTS_APPLY_HELP = (
"Apply the changes from an experiment to your workspace."
)
EXPERIMENTS_APPLY_HELP = "Apply the changes from an experiment to your workspace."
experiments_apply_parser = experiments_subparsers.add_parser(
"apply",
parents=[parent_parser],
+7 -3
View File
@@ -9,14 +9,12 @@ logger = logging.getLogger(__name__)
class CmdExperimentsBranch(CmdBase):
def run(self):
self.repo.experiments.branch(self.args.experiment, self.args.branch)
return 0
def add_parser(experiments_subparsers, parent_parser):
EXPERIMENTS_BRANCH_HELP = "Promote an experiment to a Git branch."
experiments_branch_parser = experiments_subparsers.add_parser(
"branch",
@@ -29,6 +27,12 @@ def add_parser(experiments_subparsers, parent_parser):
"experiment", help="Experiment to be promoted."
)
experiments_branch_parser.add_argument(
"branch", help="Name for the new Git branch"
"branch",
nargs="?",
default=None,
help=(
"Optional name for the new Git branch. "
"Defaults to '{experiment-name}-branch'."
),
)
experiments_branch_parser.set_defaults(func=CmdExperimentsBranch)
+25
View File
@@ -0,0 +1,25 @@
import argparse
import logging
from dvc.cli.command import CmdBase
from dvc.cli.utils import append_doc_link
logger = logging.getLogger(__name__)
class CmdExperimentsClean(CmdBase):
def run(self):
self.repo.experiments.clean()
return 0
def add_parser(experiments_subparsers, parent_parser):
EXPERIMENTS_CLEAN_HELP = "Cleanup experiments temporary internal files."
experiments_clean_parser = experiments_subparsers.add_parser(
"clean",
parents=[parent_parser],
description=append_doc_link(EXPERIMENTS_CLEAN_HELP, "exp/clean"),
help=EXPERIMENTS_CLEAN_HELP,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
experiments_clean_parser.set_defaults(func=CmdExperimentsClean)
+1 -7
View File
@@ -13,7 +13,6 @@ logger = logging.getLogger(__name__)
class CmdExperimentsDiff(CmdBase):
def run(self):
try:
diff = self.repo.experiments.diff(
a_rev=self.args.a_rev,
@@ -53,10 +52,7 @@ class CmdExperimentsDiff(CmdBase):
def add_parser(experiments_subparsers, parent_parser):
EXPERIMENTS_DIFF_HELP = (
"Show changes between experiments in the DVC repository."
)
EXPERIMENTS_DIFF_HELP = "Show changes between experiments."
experiments_diff_parser = experiments_subparsers.add_parser(
"diff",
@@ -87,14 +83,12 @@ def add_parser(experiments_subparsers, parent_parser):
)
experiments_diff_parser.add_argument(
"--json",
"--show-json",
action="store_true",
default=False,
help="Show output in JSON format.",
)
experiments_diff_parser.add_argument(
"--md",
"--show-md",
action="store_true",
default=False,
dest="markdown",
+20 -4
View File
@@ -9,10 +9,7 @@ class CmdExecutorRun(CmdBaseNoRepo):
"""Run an experiment executor."""
def run(self):
from dvc.repo.experiments.executor.base import (
BaseExecutor,
ExecutorInfo,
)
from dvc.repo.experiments.executor.base import BaseExecutor, ExecutorInfo
from dvc.utils.serialize import load_json
info = ExecutorInfo.from_dict(load_json(self.args.infofile))
@@ -22,6 +19,8 @@ class CmdExecutorRun(CmdBaseNoRepo):
queue=None,
log_level=logger.getEffectiveLevel(),
infofile=self.args.infofile,
copy_paths=self.args.copy_paths,
message=self.args.message,
)
return 0
@@ -39,4 +38,21 @@ def add_parser(experiments_subparsers, parent_parser):
help="Path to executor info file",
default=None,
)
exec_run_parser.add_argument(
"-C",
"--copy-paths",
action="append",
default=[],
help=(
"List of ignored or untracked paths to copy into the temp directory."
" Only used if `--temp` or `--queue` is specified."
),
)
exec_run_parser.add_argument(
"-M",
"--message",
type=str,
default=None,
help="Custom commit message to use when committing the experiment.",
)
exec_run_parser.set_defaults(func=CmdExecutorRun)
-150
View File
@@ -1,150 +0,0 @@
import argparse
import logging
from dvc.cli.command import CmdBase
from dvc.cli.utils import append_doc_link
from dvc.exceptions import InvalidArgumentError
from dvc.ui import ui
logger = logging.getLogger(__name__)
def _raise_error_if_all_disabled(**kwargs):
if not any(kwargs.values()):
raise InvalidArgumentError(
"Either of `-w|--workspace`, `-a|--all-branches`, `-T|--all-tags`,"
" `--all-commits` or `--date` needs to be set."
)
class CmdExperimentsGC(CmdBase):
def run(self):
_raise_error_if_all_disabled(
all_branches=self.args.all_branches,
all_tags=self.args.all_tags,
all_commits=self.args.all_commits,
commit_date=self.args.commit_date,
workspace=self.args.workspace,
)
msg = "This will remove all experiments except those derived from "
msg += "the workspace"
if self.args.all_commits:
msg += " and all git commits"
else:
if self.args.all_branches and self.args.all_tags:
msg += " and all git branches and tags"
elif self.args.all_branches:
msg += " and all git branches"
elif self.args.all_tags:
msg += " and all git tags"
if self.args.commit_date:
msg += (
" and all git commits before date "
f"{self.args.commit_date}"
)
msg += " of the current repo."
if self.args.queued:
msg += " Run queued experiments will be preserved."
else:
msg += " Run queued experiments will be removed."
logger.warning(msg)
msg = "Are you sure you want to proceed?"
if not self.args.force and not ui.confirm(msg):
return 1
removed = self.repo.experiments.gc(
all_branches=self.args.all_branches,
all_tags=self.args.all_tags,
all_commits=self.args.all_commits,
workspace=self.args.workspace,
commit_date=self.args.commit_date,
queued=self.args.queued,
)
if removed:
ui.write(
f"Removed {removed} experiments.",
"To remove unused cache files",
"use 'dvc gc'.",
)
else:
ui.write("No experiments to remove.")
return 0
def add_parser(experiments_subparsers, parent_parser):
EXPERIMENTS_GC_HELP = "Garbage collect unneeded experiments."
EXPERIMENTS_GC_DESCRIPTION = (
"Removes all experiments which are not derived from the specified"
"Git revisions."
)
experiments_gc_parser = experiments_subparsers.add_parser(
"gc",
parents=[parent_parser],
description=append_doc_link(EXPERIMENTS_GC_DESCRIPTION, "exp/gc"),
help=EXPERIMENTS_GC_HELP,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
experiments_gc_parser.add_argument(
"-w",
"--workspace",
action="store_true",
default=False,
help="Keep experiments derived from the current workspace.",
)
experiments_gc_parser.add_argument(
"-a",
"--all-branches",
action="store_true",
default=False,
help="Keep experiments derived from the tips of all Git branches.",
)
experiments_gc_parser.add_argument(
"-T",
"--all-tags",
action="store_true",
default=False,
help="Keep experiments derived from all Git tags.",
)
experiments_gc_parser.add_argument(
"-A",
"--all-commits",
action="store_true",
default=False,
help="Keep experiments derived from all Git commits.",
)
experiments_gc_parser.add_argument(
"--date",
type=str,
dest="commit_date",
metavar="<YYYY-MM-DD>",
default=None,
help=(
"Keep experiments from the commits after (inclusive) a certain "
"date. Date must match the extended ISO 8601 format (YYYY-MM-DD)."
),
)
experiments_gc_parser.add_argument(
"--queued",
action="store_true",
default=False,
help=(
"Keep queued experiments (experiments run queue will be cleared "
"by default)."
),
)
experiments_gc_parser.add_argument(
"-f",
"--force",
action="store_true",
default=False,
help="Force garbage collection - automatically agree to all prompts.",
)
experiments_gc_parser.set_defaults(func=CmdExperimentsGC)
-210
View File
@@ -1,210 +0,0 @@
import argparse
import logging
from typing import TYPE_CHECKING, List
from funcy import compact
from dvc.cli.command import CmdBase
from dvc.cli.utils import append_doc_link
from dvc.exceptions import InvalidArgumentError
from dvc.ui import ui
if TYPE_CHECKING:
from dvc.dependency import Dependency
from dvc.stage import PipelineStage
logger = logging.getLogger(__name__)
class CmdExperimentsInit(CmdBase):
DEFAULT_NAME = "train"
CODE = "src"
DATA = "data"
MODELS = "models"
DEFAULT_METRICS = "metrics.json"
DEFAULT_PARAMS = "params.yaml"
PLOTS = "plots"
DEFAULTS = {
"code": CODE,
"data": DATA,
"models": MODELS,
"metrics": DEFAULT_METRICS,
"params": DEFAULT_PARAMS,
"plots": PLOTS,
}
def run(self):
from dvc.commands.stage import parse_cmd
cmd = parse_cmd(self.args.command)
if not self.args.interactive and not cmd:
raise InvalidArgumentError("command is not specified")
from dvc.repo.experiments.init import init
defaults = {}
if not self.args.explicit:
config = self.repo.config["exp"]
defaults.update({**self.DEFAULTS, **config})
cli_args = compact(
{
"cmd": cmd,
"code": self.args.code,
"data": self.args.data,
"models": self.args.models,
"metrics": self.args.metrics,
"params": self.args.params,
"plots": self.args.plots,
"live": self.args.live,
}
)
initialized_stage, initialized_deps, initialized_out_dirs = init(
self.repo,
name=self.args.name,
type=self.args.type,
defaults=defaults,
overrides=cli_args,
interactive=self.args.interactive,
force=self.args.force,
)
self._post_init_display(
initialized_stage, initialized_deps, initialized_out_dirs
)
if self.args.run:
self.repo.experiments.run(targets=[initialized_stage.addressing])
return 0
def _post_init_display(
self,
stage: "PipelineStage",
new_deps: List["Dependency"],
new_out_dirs: List[str],
) -> None:
from dvc.utils import humanize
path_fmt = "[green]{}[/green]".format
if new_deps:
deps_paths = humanize.join(map(path_fmt, new_deps))
ui.write(f"Creating dependencies: {deps_paths}", styled=True)
if new_out_dirs:
out_dirs_paths = humanize.join(map(path_fmt, new_out_dirs))
ui.write(
f"Creating output directories: {out_dirs_paths}", styled=True
)
ui.write(
f"Creating [b]{self.args.name}[/b] stage in [green]dvc.yaml[/]",
styled=True,
)
if stage.outs or not self.args.run:
# separate the above status-like messages with help/tips section
ui.write(styled=True)
if stage.outs:
outs_paths = humanize.join(map(path_fmt, stage.outs))
tips = f"Ensure your experiment command creates {outs_paths}."
ui.write(tips, styled=True)
if not self.args.run:
ui.write(
'You can now run your experiment using [b]"dvc exp run"[/].',
styled=True,
)
else:
# separate between `exp.run` output and `dvc exp init` output
ui.write(styled=True)
def add_parser(experiments_subparsers, parent_parser):
EXPERIMENTS_INIT_HELP = "Quickly setup any project to use experiments."
experiments_init_parser = experiments_subparsers.add_parser(
"init",
parents=[parent_parser],
description=append_doc_link(EXPERIMENTS_INIT_HELP, "exp/init"),
formatter_class=argparse.RawDescriptionHelpFormatter,
help=EXPERIMENTS_INIT_HELP,
)
experiments_init_parser.add_argument(
"command",
nargs=argparse.REMAINDER,
help="Command to execute.",
metavar="command",
)
experiments_init_parser.add_argument(
"--run",
action="store_true",
help="Run the experiment after initializing it",
)
experiments_init_parser.add_argument(
"--interactive",
"-i",
action="store_true",
help="Prompt for values that are not provided",
)
experiments_init_parser.add_argument(
"-f",
"--force",
action="store_true",
default=False,
help="Overwrite existing stage",
)
experiments_init_parser.add_argument(
"--explicit",
action="store_true",
default=False,
help="Only use the path values explicitly provided",
)
experiments_init_parser.add_argument(
"--name",
"-n",
help="Name of the stage to create (default: %(default)s)",
default=CmdExperimentsInit.DEFAULT_NAME,
)
experiments_init_parser.add_argument(
"--code",
help="Path to the source file or directory "
"which your experiments depend"
f" (default: {CmdExperimentsInit.CODE})",
)
experiments_init_parser.add_argument(
"--data",
help="Path to the data file or directory "
"which your experiments depend"
f" (default: {CmdExperimentsInit.DATA})",
)
experiments_init_parser.add_argument(
"--models",
help="Path to the model file or directory for your experiments"
f" (default: {CmdExperimentsInit.MODELS})",
)
experiments_init_parser.add_argument(
"--params",
help="Path to the parameters file for your experiments"
f" (default: {CmdExperimentsInit.DEFAULT_PARAMS})",
)
experiments_init_parser.add_argument(
"--metrics",
help="Path to the metrics file for your experiments"
f" (default: {CmdExperimentsInit.DEFAULT_METRICS})",
)
experiments_init_parser.add_argument(
"--plots",
help="Path to the plots file or directory for your experiments"
f" (default: {CmdExperimentsInit.PLOTS})",
)
experiments_init_parser.add_argument(
"--live",
help="Path to log dvclive outputs for your experiments",
)
experiments_init_parser.add_argument(
"--type",
choices=["default", "checkpoint"],
default="default",
help="Select type of stage to create (default: %(default)s)",
)
experiments_init_parser.set_defaults(func=CmdExperimentsInit)
+33 -8
View File
@@ -3,6 +3,7 @@ import logging
from dvc.cli.command import CmdBase
from dvc.cli.utils import append_doc_link
from dvc.exceptions import InvalidArgumentError
from dvc.ui import ui
logger = logging.getLogger(__name__)
@@ -11,19 +12,36 @@ logger = logging.getLogger(__name__)
class CmdExperimentsList(CmdBase):
def run(self):
name_only = self.args.name_only
sha_only = self.args.sha_only
git_remote = self.args.git_remote
if sha_only and git_remote:
raise InvalidArgumentError("--sha-only not supported with git_remote.")
exps = self.repo.experiments.ls(
all_commits=self.args.all_commits,
rev=self.args.rev,
num=self.args.num,
git_remote=self.args.git_remote,
git_remote=git_remote,
)
for baseline in exps:
if not name_only:
ui.write(f"{baseline}:")
for exp_name in exps[baseline]:
indent = "" if name_only else "\t"
ui.write(f"{indent}{exp_name}")
if not (name_only or sha_only):
tag_base = "refs/tags/"
branch_base = "refs/heads/"
name = baseline[:7]
if baseline.startswith(tag_base):
name = baseline[len(tag_base) :]
elif baseline.startswith(branch_base):
name = baseline[len(branch_base) :]
ui.write(f"{name}:")
for exp_name, rev in exps[baseline]:
if name_only:
ui.write(exp_name)
elif sha_only:
ui.write(rev)
elif rev:
ui.write(f"\t{rev[:7]} [{exp_name}]")
else:
ui.write(f"\t{exp_name}")
return 0
@@ -40,11 +58,18 @@ def add_parser(experiments_subparsers, parent_parser):
formatter_class=argparse.RawDescriptionHelpFormatter,
)
add_rev_selection_flags(experiments_list_parser, "List")
experiments_list_parser.add_argument(
display_group = experiments_list_parser.add_mutually_exclusive_group()
display_group.add_argument(
"--name-only",
"--names-only",
action="store_true",
help="Only output experiment names (without parent commits).",
help="Only output experiment names (without SHAs or parent commits).",
)
display_group.add_argument(
"--sha-only",
"--shas-only",
action="store_true",
help="Only output experiment commit SHAs (without names or parent commits).",
)
experiments_list_parser.add_argument(
"git_remote",
+4 -20
View File
@@ -3,25 +3,13 @@ import logging
from dvc.cli.command import CmdBase
from dvc.cli.utils import append_doc_link
from dvc.exceptions import InvalidArgumentError
from dvc.ui import ui
logger = logging.getLogger(__name__)
class CmdExperimentsPull(CmdBase):
def raise_error_if_all_disabled(self):
if not any(
[self.args.experiment, self.args.all_commits, self.args.rev]
):
raise InvalidArgumentError(
"Either provide an `experiment` argument, or use the "
"`--rev` or `--all-commits` flag."
)
def run(self):
self.raise_error_if_all_disabled()
pulled_exps = self.repo.experiments.pull(
self.args.git_remote,
self.args.experiment,
@@ -63,21 +51,18 @@ def add_parser(experiments_subparsers, parent_parser):
help=EXPERIMENTS_PULL_HELP,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
add_rev_selection_flags(experiments_pull_parser, "Pull", False)
add_rev_selection_flags(experiments_pull_parser, "Pull", True)
experiments_pull_parser.add_argument(
"-f",
"--force",
action="store_true",
help="Replace local experiment already exists.",
help="Replace local experiment if it already exists.",
)
experiments_pull_parser.add_argument(
"--no-cache",
action="store_false",
dest="pull_cache",
help=(
"Do not pull cached outputs for this experiment from DVC remote "
"storage."
),
help="Do not pull cached outputs for this experiment from DVC remote storage.",
)
experiments_pull_parser.add_argument(
"-r",
@@ -92,8 +77,7 @@ def add_parser(experiments_subparsers, parent_parser):
type=int,
metavar="<number>",
help=(
"Number of jobs to run simultaneously when pulling from DVC "
"remote storage."
"Number of jobs to run simultaneously when pulling from DVC remote storage."
),
)
experiments_pull_parser.add_argument(
+61 -40
View File
@@ -1,54 +1,81 @@
import argparse
import logging
from typing import Any, Dict
from dvc.cli import completion
from dvc.cli.command import CmdBase
from dvc.cli.utils import append_doc_link
from dvc.exceptions import InvalidArgumentError
from dvc.ui import ui
logger = logging.getLogger(__name__)
class CmdExperimentsPush(CmdBase):
def raise_error_if_all_disabled(self):
if not any(
[self.args.experiment, self.args.all_commits, self.args.rev]
):
raise InvalidArgumentError(
"Either provide an `experiment` argument, or use the "
"`--rev` or `--all-commits` flag."
@staticmethod
def log_result(result: Dict[str, Any], remote: str):
from dvc.utils import humanize
def join_exps(exps):
return humanize.join([f"[bold]{e}[/]" for e in exps])
if diverged_exps := result.get("diverged"):
exps = join_exps(diverged_exps)
ui.error_write(
f"[yellow]Local experiment {exps} has diverged "
"from remote experiment with the same name.\n"
"To override the remote experiment re-run with '--force'.",
styled=True,
)
if uptodate_exps := result.get("up_to_date"):
exps = join_exps(uptodate_exps)
verb = "are" if len(uptodate_exps) > 1 else "is"
ui.write(
f"Experiment {exps} {verb} up to date on Git remote {remote!r}.",
styled=True,
)
if pushed_exps := result.get("success"):
exps = join_exps(pushed_exps)
ui.write(f"Pushed experiment {exps} to Git remote {remote!r}.", styled=True)
if not uptodate_exps and not pushed_exps:
ui.write("No experiments to push.")
if uploaded := result.get("uploaded"):
stats = {"uploaded": uploaded}
ui.write(humanize.get_summary(stats.items()))
if project_url := result.get("url"):
ui.rich_print(
"View your experiments at", project_url, style="yellow", soft_wrap=True
)
def run(self):
from dvc.repo.experiments.push import UploadError
self.raise_error_if_all_disabled()
pushed_exps = self.repo.experiments.push(
self.args.git_remote,
self.args.experiment,
all_commits=self.args.all_commits,
rev=self.args.rev,
num=self.args.num,
force=self.args.force,
push_cache=self.args.push_cache,
dvc_remote=self.args.dvc_remote,
jobs=self.args.jobs,
run_cache=self.args.run_cache,
)
if pushed_exps:
ui.write(
f"Pushed experiment '{pushed_exps}'"
f"to Git remote '{self.args.git_remote}'."
try:
result = self.repo.experiments.push(
self.args.git_remote,
self.args.experiment,
all_commits=self.args.all_commits,
rev=self.args.rev,
num=self.args.num,
force=self.args.force,
push_cache=self.args.push_cache,
dvc_remote=self.args.dvc_remote,
jobs=self.args.jobs,
run_cache=self.args.run_cache,
)
else:
ui.write("No experiments to push.")
except UploadError as e:
self.log_result(e.result, self.args.git_remote)
raise
self.log_result(result, self.args.git_remote)
if not self.args.push_cache:
ui.write(
"To push cached outputs",
"for this experiment to DVC remote storage,"
"re-run this command without '--no-cache'.",
(
"for this experiment to DVC remote storage,"
"re-run this command without '--no-cache'."
),
)
return 0
@@ -65,7 +92,7 @@ def add_parser(experiments_subparsers, parent_parser):
help=EXPERIMENTS_PUSH_HELP,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
add_rev_selection_flags(experiments_push_parser, "Push", False)
add_rev_selection_flags(experiments_push_parser, "Push", True)
experiments_push_parser.add_argument(
"-f",
"--force",
@@ -76,10 +103,7 @@ def add_parser(experiments_subparsers, parent_parser):
"--no-cache",
action="store_false",
dest="push_cache",
help=(
"Do not push cached outputs for this experiment to DVC remote "
"storage."
),
help="Do not push cached outputs for this experiment to DVC remote storage.",
)
experiments_push_parser.add_argument(
"-r",
@@ -93,10 +117,7 @@ def add_parser(experiments_subparsers, parent_parser):
"--jobs",
type=int,
metavar="<number>",
help=(
"Number of jobs to run simultaneously when pushing to DVC remote "
"storage."
),
help="Number of jobs to run simultaneously when pushing to DVC remote storage.",
)
experiments_push_parser.add_argument(
"--run-cache",
+8 -1
View File
@@ -9,7 +9,9 @@ class CmdQueueWorker(CmdBase):
"""Run the exp queue worker."""
def run(self):
self.repo.experiments.celery_queue.worker.start(self.args.name)
self.repo.experiments.celery_queue.worker.start(
self.args.name, fsapp_clean=self.args.clean
)
return 0
@@ -22,4 +24,9 @@ def add_parser(experiments_subparsers, parent_parser):
add_help=False,
)
parser.add_argument("name", help="Celery worker name.")
parser.add_argument(
"--clean",
action="store_true",
help="Automatically cleanup celery broker on shutdown.",
)
parser.set_defaults(func=CmdQueueWorker)
+6 -3
View File
@@ -24,10 +24,11 @@ class CmdExperimentsRemove(CmdBase):
)
def run(self):
from dvc.utils import humanize
self.check_arguments()
removed_list = self.repo.experiments.remove(
removed = self.repo.experiments.remove(
exp_names=self.args.experiment,
all_commits=self.args.all_commits,
rev=self.args.rev,
@@ -35,8 +36,10 @@ class CmdExperimentsRemove(CmdBase):
queue=self.args.queue,
git_remote=self.args.git_remote,
)
removed = ",".join(removed_list)
ui.write(f"Removed experiments: {removed}")
if removed:
ui.write(f"Removed experiments: {humanize.join(map(repr, removed))}")
else:
ui.write("No experiments to remove.")
return 0
+20 -44
View File
@@ -1,57 +1,32 @@
import argparse
import logging
from dvc.cli import completion
from dvc.cli.utils import append_doc_link
from dvc.commands.repro import CmdRepro
from dvc.commands.repro import add_arguments as add_repro_arguments
from dvc.exceptions import InvalidArgumentError
from dvc.ui import ui
logger = logging.getLogger(__name__)
class CmdExperimentsRun(CmdRepro):
def run(self):
from dvc.compare import show_metrics
if self.args.checkpoint_resume:
if self.args.reset:
raise InvalidArgumentError(
"--reset and --rev are mutually exclusive."
)
if not (self.args.queue or self.args.tmp_dir):
raise InvalidArgumentError(
"--rev can only be used in conjunction with "
"--queue or --temp."
)
if self.args.reset:
ui.write("Any existing checkpoints will be reset and re-run.")
results = self.repo.experiments.run(
self.repo.experiments.run(
name=self.args.name,
queue=self.args.queue,
run_all=self.args.run_all,
jobs=self.args.jobs,
params=self.args.set_param,
checkpoint_resume=self.args.checkpoint_resume,
reset=self.args.reset,
tmp_dir=self.args.tmp_dir,
machine=self.args.machine,
copy_paths=self.args.copy_paths,
message=self.args.message,
**self._common_kwargs,
)
if self.args.metrics and results:
metrics = self.repo.metrics.show(revs=list(results))
metrics.pop("workspace", None)
show_metrics(metrics)
return 0
def add_parser(experiments_subparsers, parent_parser):
EXPERIMENTS_RUN_HELP = "Run or resume an experiment."
experiments_run_parser = experiments_subparsers.add_parser(
"run",
@@ -61,22 +36,6 @@ def add_parser(experiments_subparsers, parent_parser):
formatter_class=argparse.RawDescriptionHelpFormatter,
)
_add_run_common(experiments_run_parser)
experiments_run_parser.add_argument(
"-r",
"--rev",
type=str,
dest="checkpoint_resume",
help=(
"Continue the specified checkpoint experiment. Can only be used "
"in conjunction with --queue or --temp."
),
metavar="<experiment_rev>",
).complete = completion.EXPERIMENT
experiments_run_parser.add_argument(
"--reset",
action="store_true",
help="Reset existing checkpoints and restart the experiment.",
)
experiments_run_parser.set_defaults(func=CmdExperimentsRun)
@@ -140,3 +99,20 @@ def _add_run_common(parser):
# )
# metavar="<name>",
)
parser.add_argument(
"-C",
"--copy-paths",
action="append",
default=[],
help=(
"List of ignored or untracked paths to copy into the temp directory."
" Only used if `--temp` or `--queue` is specified."
),
)
parser.add_argument(
"-m",
"--message",
type=str,
default=None,
help="Custom commit message to use when committing the experiment.",
)
+10 -4
View File
@@ -11,12 +11,12 @@ logger = logging.getLogger(__name__)
class CmdExperimentsSave(CmdBase):
def run(self):
try:
ref = self.repo.experiments.save(
name=self.args.name,
force=self.args.force,
include_untracked=self.args.include_untracked,
message=self.args.message,
)
except DvcException:
logger.exception("failed to save experiment")
@@ -36,7 +36,7 @@ class CmdExperimentsSave(CmdBase):
def add_parser(experiments_subparsers, parent_parser):
EXPERIMENTS_SAVE_HELP = "Save current workspace as a dvc experiment."
EXPERIMENTS_SAVE_HELP = "Save current workspace as an experiment."
save_parser = experiments_subparsers.add_parser(
"save",
parents=[parent_parser],
@@ -49,11 +49,10 @@ def add_parser(experiments_subparsers, parent_parser):
"--force",
action="store_true",
default=False,
help="Save even if hash value for dependencies/outputs changed.",
help="Replace experiment if it already exists.",
)
save_parser.add_argument(
"--json",
"--show-json",
action="store_true",
default=False,
help="Show output in JSON format.",
@@ -76,4 +75,11 @@ def add_parser(experiments_subparsers, parent_parser):
help="List of untracked paths to include in the experiment.",
metavar="<path>",
)
save_parser.add_argument(
"-M",
"--message",
type=str,
default=None,
help="Custom commit message to use when committing the experiment.",
)
save_parser.set_defaults(func=CmdExperimentsSave)
+42 -388
View File
@@ -1,20 +1,16 @@
import argparse
import logging
import os
import re
from collections import Counter, OrderedDict, defaultdict
from datetime import date, datetime
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Dict, Iterable
from funcy import lmap
from dvc.cli import completion
from dvc.cli.command import CmdBase
from dvc.cli.utils import append_doc_link
from dvc.commands.metrics import DEFAULT_PRECISION
from dvc.exceptions import DvcException, InvalidArgumentError
from dvc.exceptions import DvcException
from dvc.ui import ui
from dvc.utils.flatten import flatten
from dvc.utils.serialize import encode_exception
if TYPE_CHECKING:
@@ -28,269 +24,13 @@ FILL_VALUE_ERRORED = "!"
logger = logging.getLogger(__name__)
def _update_names(names, items):
for name, item in items:
item = item.get("data", {})
if isinstance(item, dict):
item = flatten(item)
names[name].update({key: None for key in item})
def _collect_names(all_experiments, **kwargs):
metric_names = defaultdict(dict)
param_names = defaultdict(dict)
deps_names = set()
for _, experiments in all_experiments.items():
for exp_data in experiments.values():
exp = exp_data.get("data", {})
_update_names(metric_names, exp.get("metrics", {}).items())
_update_names(param_names, exp.get("params", {}).items())
for dep_name in exp.get("deps", {}):
deps_names.add(dep_name)
return metric_names, param_names, sorted(deps_names)
experiment_types = {
"checkpoint_tip": "│ ╓",
"checkpoint_commit": "│ ╟",
"checkpoint_base": "├─╨",
"branch_commit": "├──",
"branch_base": "└──",
"baseline": "",
}
def _collect_rows(
base_rev,
experiments,
all_headers,
metric_headers,
param_headers,
metric_names,
param_names,
deps_names,
precision=DEFAULT_PRECISION,
sort_by=None,
sort_order=None,
fill_value=FILL_VALUE,
iso=False,
):
from scmrepo.git import Git
if sort_by:
sort_path, sort_name, sort_type = _sort_column(
sort_by, metric_names, param_names
)
reverse = sort_order == "desc"
experiments = _sort_exp(
experiments, sort_path, sort_name, sort_type, reverse
)
new_checkpoint = True
for i, (rev, results) in enumerate(experiments.items()):
fill_value = FILL_VALUE_ERRORED if results.get("error") else fill_value
row_dict = {k: fill_value for k in all_headers}
exp = results.get("data", {})
state = exp.get("status")
if state == "Success":
state = fill_value
is_baseline = rev == "baseline"
if is_baseline:
name_rev = base_rev[:7] if Git.is_sha(base_rev) else base_rev
else:
name_rev = rev[:7]
tip = exp.get("checkpoint_tip")
parent_rev = exp.get("checkpoint_parent", "")
parent_exp = experiments.get(parent_rev, {}).get("data", {})
parent_tip = parent_exp.get("checkpoint_tip")
parent = ""
if is_baseline:
typ = "baseline"
elif tip:
if tip == parent_tip:
typ = (
"checkpoint_tip" if new_checkpoint else "checkpoint_commit"
)
elif parent_rev == base_rev:
typ = "checkpoint_base"
else:
typ = "checkpoint_commit"
parent = parent_rev[:7]
elif i < len(experiments) - 1:
typ = "branch_commit"
else:
typ = "branch_base"
if not is_baseline:
new_checkpoint = not (tip and tip == parent_tip)
row_dict["Experiment"] = exp.get("name", "")
row_dict["rev"] = name_rev
row_dict["typ"] = typ
row_dict["Created"] = format_time(
exp.get("timestamp"), fill_value, iso
)
row_dict["parent"] = parent
row_dict["State"] = state
row_dict["Executor"] = exp.get("executor", fill_value)
_extend_row(
row_dict,
metric_names,
metric_headers,
exp.get("metrics", {}).items(),
precision,
fill_value=fill_value,
)
_extend_row(
row_dict,
param_names,
param_headers,
exp.get("params", {}).items(),
precision,
fill_value=fill_value,
)
for dep in deps_names:
hash_info = exp.get("deps", {}).get(dep, {}).get("hash")
if hash_info is not None:
hash_info = hash_info[:7]
row_dict[dep] = hash_info
yield list(row_dict.values())
def _sort_column(sort_by, metric_names, param_names):
path, _, sort_name = sort_by.rpartition(":")
matches = set()
if path:
if path in metric_names and sort_name in metric_names[path]:
matches.add((path, sort_name, "metrics"))
if path in param_names and sort_name in param_names[path]:
matches.add((path, sort_name, "params"))
else:
for path in metric_names:
if sort_name in metric_names[path]:
matches.add((path, sort_name, "metrics"))
for path in param_names:
if sort_name in param_names[path]:
matches.add((path, sort_name, "params"))
if len(matches) == 1:
return matches.pop()
if len(matches) > 1:
raise InvalidArgumentError(
"Ambiguous sort column '{}' matched '{}'".format(
sort_by,
", ".join([f"{path}:{name}" for path, name, _ in matches]),
)
)
raise InvalidArgumentError(f"Unknown sort column '{sort_by}'")
def _sort_exp(experiments, sort_path, sort_name, typ, reverse):
def _sort(item):
rev, exp = item
exp_data = exp.get("data", {})
tip = exp_data.get("checkpoint_tip")
if tip and tip != rev:
# Sort checkpoint experiments by tip commit
return _sort((tip, experiments[tip]))
data = exp_data.get(typ, {}).get(sort_path, {}).get("data", {})
val = flatten(data).get(sort_name)
return val is None, val
ret = OrderedDict()
if "baseline" in experiments:
ret["baseline"] = experiments.pop("baseline")
ret.update(sorted(experiments.items(), key=_sort, reverse=reverse))
return ret
def format_time(datetime_obj, fill_value=FILL_VALUE, iso=False):
if datetime_obj is None:
return fill_value
if iso:
return datetime_obj.isoformat()
if datetime_obj.date() == date.today():
fmt = "%I:%M %p"
else:
fmt = "%b %d, %Y"
return datetime_obj.strftime(fmt)
def _extend_row(row, names, headers, items, precision, fill_value=FILL_VALUE):
from dvc.compare import _format_field, with_value
for fname, data in items:
item = data.get("data", {})
item = flatten(item) if isinstance(item, dict) else {fname: item}
for name in names[fname]:
value = with_value(
item.get(name),
FILL_VALUE_ERRORED if data.get("error", None) else fill_value,
)
# wrap field data in ui.rich_text, otherwise rich may
# interpret unescaped braces from list/dict types as rich
# markup tags
value = ui.rich_text(str(_format_field(value, precision)))
if name in headers:
row[name] = value
else:
row[f"{fname}:{name}"] = value
def experiments_table(
all_experiments,
headers,
metric_headers,
metric_names,
param_headers,
param_names,
deps_names,
sort_by=None,
sort_order=None,
precision=DEFAULT_PRECISION,
fill_value=FILL_VALUE,
iso=False,
) -> "TabularData":
from funcy import lconcat
from dvc.compare import TabularData
all_headers = lconcat(headers, metric_headers, param_headers, deps_names)
td = TabularData(all_headers, fill_value=fill_value)
for base_rev, experiments in all_experiments.items():
rows = _collect_rows(
base_rev,
experiments,
all_headers,
metric_headers,
param_headers,
metric_names,
param_names,
deps_names,
sort_by=sort_by,
sort_order=sort_order,
precision=precision,
fill_value=fill_value,
iso=iso,
)
td.extend(rows)
return td
def prepare_exp_id(kwargs) -> "RichText":
exp_name = kwargs["Experiment"]
rev = kwargs["rev"]
@@ -314,52 +54,18 @@ def baseline_styler(typ):
return {"style": "bold"} if typ == "baseline" else {}
def show_experiments(
all_experiments,
def show_experiments( # noqa: C901
td: "TabularData",
headers: Dict[str, Iterable[str]],
keep=None,
drop=None,
pager=True,
csv=False,
markdown=False,
pcp=False,
**kwargs,
):
from funcy.seqs import flatten as flatten_list
metric_names, param_names, deps_names = _collect_names(all_experiments)
headers = [
"Experiment",
"rev",
"typ",
"Created",
"parent",
"State",
"Executor",
]
names = {**metric_names, **param_names}
counter = Counter(flatten_list([list(a.keys()) for a in names.values()]))
counter.update(headers)
metric_headers = _normalize_headers(metric_names, counter)
param_headers = _normalize_headers(param_names, counter)
td = experiments_table(
all_experiments,
headers,
metric_headers,
metric_names,
param_headers,
param_names,
deps_names,
kwargs.get("sort_by"),
kwargs.get("sort_order"),
kwargs.get("precision"),
kwargs.get("fill_value"),
kwargs.get("iso"),
)
if keep:
for col in td.keys():
for col in td.keys(): # noqa: SIM118
if re.match(keep, col):
td.protect(col)
@@ -371,16 +77,9 @@ def show_experiments(
if not csv:
merge_headers = ["Experiment", "rev", "typ", "parent"]
td.column("Experiment")[:] = map(
prepare_exp_id, td.as_dict(merge_headers)
)
td.column("Experiment")[:] = map(prepare_exp_id, td.as_dict(merge_headers))
td.drop(*merge_headers[1:])
headers = {
"metrics": metric_headers,
"params": param_headers,
"deps": deps_names,
}
styles = {
"Experiment": {"no_wrap": True, "header_style": "black on grey93"},
"Created": {"header_style": "black on grey93"},
@@ -405,51 +104,23 @@ def show_experiments(
}
)
if kwargs.get("only_changed", False) or pcp:
if kwargs.get("only_changed", False):
td.drop_duplicates("cols", ignore_empty=False)
cols_to_drop = set()
if drop is not None:
cols_to_drop = {col for col in td.keys() if re.match(drop, col)}
if pcp:
cols_to_drop.add("Created")
cols_to_drop = {col for col in td.keys() if re.match(drop, col)} # noqa: SIM118
td.drop(*cols_to_drop)
if pcp:
subset = {x for x in td.keys() if x != "Experiment"}
td.dropna(
"rows",
how="all",
subset=subset,
)
td.drop_duplicates("rows", subset=subset)
if "Experiment" in td:
td.column("Experiment")[:] = [
# remove tree characters
str(x).encode("ascii", "ignore").strip().decode()
for x in td.column("Experiment")
]
out = kwargs.get("out") or "dvc_plots"
output_file = os.path.join(out, "index.html")
ui.write(
td.to_parallel_coordinates(
output_path=os.path.abspath(output_file),
color_by=kwargs.get("sort_by") or "Experiment",
)
)
if kwargs.get("open"):
return ui.open_browser(output_file)
else:
td.render(
pager=pager,
borders="horizontals",
rich_table=True,
header_styles=styles,
row_styles=row_styles,
csv=csv,
markdown=markdown,
)
td.render(
pager=pager,
borders="horizontals",
rich_table=True,
header_styles=styles,
row_styles=row_styles,
csv=csv,
markdown=markdown,
)
def _normalize_headers(names, count):
@@ -468,8 +139,10 @@ def _format_json(item):
class CmdExperimentsShow(CmdBase):
def run(self):
from dvc.repo.experiments.show import tabulate
try:
all_experiments = self.repo.experiments.show(
exps = self.repo.experiments.show(
all_branches=self.args.all_branches,
all_tags=self.args.all_tags,
all_commits=self.args.all_commits,
@@ -480,38 +153,40 @@ class CmdExperimentsShow(CmdBase):
sha_only=self.args.sha,
param_deps=self.args.param_deps,
fetch_running=self.args.fetch_running,
force=self.args.force,
)
except DvcException:
logger.exception("failed to show experiments")
return 1
if self.args.json:
ui.write_json(all_experiments, default=_format_json)
ui.write_json([exp.dumpd() for exp in exps], default=_format_json)
else:
precision = (
self.args.precision or None
if self.args.csv
else DEFAULT_PRECISION
self.args.precision or None if self.args.csv else DEFAULT_PRECISION
)
fill_value = "" if self.args.csv else FILL_VALUE
iso = True if self.args.csv else False
iso = self.args.csv
td, headers = tabulate(
exps,
precision=precision,
fill_value=fill_value,
iso=iso,
sort_by=self.args.sort_by,
sort_order=self.args.sort_order,
)
show_experiments(
all_experiments,
td,
headers,
keep=self.args.keep,
drop=self.args.drop,
sort_by=self.args.sort_by,
sort_order=self.args.sort_order,
precision=precision,
fill_value=fill_value,
iso=iso,
pager=not self.args.no_pager,
csv=self.args.csv,
markdown=self.args.markdown,
only_changed=self.args.only_changed,
pcp=self.args.pcp,
out=self.args.out,
open=self.args.open,
)
return 0
@@ -580,10 +255,7 @@ def add_parser(experiments_subparsers, parent_parser):
)
experiments_show_parser.add_argument(
"--sort-order",
help=(
"Sort order to use with --sort-by."
" Defaults to ascending ('asc')."
),
help="Sort order to use with --sort-by. Defaults to ascending ('asc').",
choices=("asc", "desc"),
default="asc",
)
@@ -607,21 +279,18 @@ def add_parser(experiments_subparsers, parent_parser):
)
experiments_show_parser.add_argument(
"--json",
"--show-json",
action="store_true",
default=False,
help="Print output in JSON format instead of a human-readable table.",
)
experiments_show_parser.add_argument(
"--csv",
"--show-csv",
action="store_true",
default=False,
help="Print output in csv format instead of a human-readable table.",
)
experiments_show_parser.add_argument(
"--md",
"--show-md",
action="store_true",
default=False,
dest="markdown",
@@ -636,31 +305,16 @@ def add_parser(experiments_subparsers, parent_parser):
),
metavar="<n>",
)
experiments_show_parser.add_argument(
"--parallel-coordinates-plot",
"--pcp",
dest="pcp",
action="store_true",
default=False,
help="Generate a Parallel Coordinates Plot from the tabulated output.",
)
experiments_show_parser.add_argument(
"-o",
"--out",
default=None,
help="Destination folder to save the Parallel Coordinates Plot to",
metavar="<path>",
).complete = completion.DIR
experiments_show_parser.add_argument(
"--open",
action="store_true",
default=False,
help="Open the Parallel Coordinates Plot directly in the browser.",
)
experiments_show_parser.add_argument(
"--no-fetch",
dest="fetch_running",
action="store_false",
help=argparse.SUPPRESS,
)
experiments_show_parser.add_argument(
"-f",
"--force",
action="store_true",
help="Force re-collection of experiments instead of loading from exp cache.",
)
experiments_show_parser.set_defaults(func=CmdExperimentsShow)
+22 -12
View File
@@ -10,7 +10,7 @@ logger = logging.getLogger(__name__)
class CmdGC(CmdBase):
def run(self):
def run(self): # noqa: C901, PLR0912
from dvc.repo.gc import _validate_args
_validate_args(
@@ -22,6 +22,8 @@ class CmdGC(CmdBase):
workspace=self.args.workspace,
rev=self.args.rev,
num=self.args.num,
cloud=self.args.cloud,
not_in_remote=self.args.not_in_remote,
)
if self.args.rev:
@@ -40,17 +42,16 @@ class CmdGC(CmdBase):
elif self.args.all_tags:
msg += " and all git tags"
if self.args.commit_date:
msg += (
" and all git commits before date "
f"{self.args.commit_date}"
)
msg += f" and all git commits before date {self.args.commit_date}"
if self.args.rev:
msg += (
f" and last {self.args.num} commits from {self.args.rev}"
)
msg += f" and last {self.args.num} commits from {self.args.rev}"
if self.args.all_experiments:
msg += " and all experiments"
if self.args.not_in_remote:
msg += " that are present in the DVC remote"
if self.args.repos:
msg += " of the current and the following repos:"
@@ -79,6 +80,7 @@ class CmdGC(CmdBase):
workspace=self.args.workspace,
rev=self.args.rev,
num=self.args.num,
not_in_remote=self.args.not_in_remote,
)
return 0
@@ -162,12 +164,18 @@ def add_parser(subparsers, parent_parser):
default=False,
help="Keep data files for all experiments.",
)
gc_parser.add_argument(
"--not-in-remote",
action="store_true",
default=False,
help="Keep data files that are not present in the remote.",
)
gc_parser.add_argument(
"-c",
"--cloud",
action="store_true",
default=False,
help="Collect garbage in remote repository.",
help="Collect garbage in remote storage in addition to local cache.",
)
gc_parser.add_argument(
"-r",
@@ -198,9 +206,11 @@ def add_parser(subparsers, parent_parser):
dest="repos",
type=str,
nargs="*",
help="Keep data files required by these projects "
"in addition to the current one. "
"Useful if you share a single cache across repos.",
help=(
"Keep data files required by these projects "
"in addition to the current one. "
"Useful if you share a single cache across repos."
),
metavar="<paths>",
)
gc_parser.set_defaults(func=CmdGC)
+46 -15
View File
@@ -3,10 +3,9 @@ import logging
from dvc.cli import completion
from dvc.cli.command import CmdBaseNoRepo
from dvc.cli.utils import DictAction, append_doc_link
from dvc.exceptions import DvcException
from ..cli.utils import append_doc_link
logger = logging.getLogger(__name__)
@@ -15,14 +14,8 @@ class CmdGet(CmdBaseNoRepo):
from dvc.api import get_url
from dvc.ui import ui
try:
url = get_url(
self.args.path, repo=self.args.url, rev=self.args.rev
)
ui.write(url, force=True)
except DvcException:
logger.exception("failed to show URL")
return 1
url = get_url(self.args.path, repo=self.args.url, rev=self.args.rev)
ui.write(url, force=True)
return 0
@@ -34,6 +27,7 @@ class CmdGet(CmdBaseNoRepo):
def _get_file_from_repo(self):
from dvc.repo import Repo
from dvc.scm import CloneError
try:
Repo.get(
@@ -42,13 +36,18 @@ class CmdGet(CmdBaseNoRepo):
out=self.args.out,
rev=self.args.rev,
jobs=self.args.jobs,
force=self.args.force,
config=self.args.config,
remote=self.args.remote,
remote_config=self.args.remote_config,
)
return 0
except CloneError:
logger.exception("failed to get '%s'", self.args.path)
return 1
except DvcException:
logger.exception(
"failed to get '{}' from '{}'".format(
self.args.path, self.args.url
)
"failed to get '%s' from '%s'", self.args.path, self.args.url
)
return 1
@@ -84,8 +83,10 @@ def add_parser(subparsers, parent_parser):
get_parser.add_argument(
"--show-url",
action="store_true",
help="Print the storage location (URL) the target data would be "
"downloaded from, and exit.",
help=(
"Print the storage location (URL) the target data would be "
"downloaded from, and exit."
),
)
get_parser.add_argument(
"-j",
@@ -97,4 +98,34 @@ def add_parser(subparsers, parent_parser):
),
metavar="<number>",
)
get_parser.add_argument(
"-f",
"--force",
action="store_true",
default=False,
help="Override local file or folder if exists.",
)
get_parser.add_argument(
"--config",
type=str,
help=(
"Path to a config file that will be merged with the config "
"in the target repository."
),
)
get_parser.add_argument(
"--remote",
type=str,
help="Remote name to set as a default in the target repository.",
)
get_parser.add_argument(
"--remote-config",
type=str,
nargs="*",
action=DictAction,
help=(
"Remote config options to merge with a remote's config (default or one "
"specified by '--remote') in the target repository."
),
)
get_parser.set_defaults(func=CmdGet)
+14 -3
View File
@@ -3,10 +3,9 @@ import logging
from dvc.cli import completion
from dvc.cli.command import CmdBaseNoRepo
from dvc.cli.utils import append_doc_link
from dvc.exceptions import DvcException
from ..cli.utils import append_doc_link
logger = logging.getLogger(__name__)
@@ -15,7 +14,12 @@ class CmdGetUrl(CmdBaseNoRepo):
from dvc.repo import Repo
try:
Repo.get_url(self.args.url, out=self.args.out, jobs=self.args.jobs)
Repo.get_url(
self.args.url,
out=self.args.out,
jobs=self.args.jobs,
force=self.args.force,
)
return 0
except DvcException:
logger.exception("failed to get '%s'", self.args.url)
@@ -47,4 +51,11 @@ def add_parser(subparsers, parent_parser):
),
metavar="<number>",
)
get_parser.add_argument(
"-f",
"--force",
action="store_true",
default=False,
help="Override local file or folder if exists.",
)
get_parser.set_defaults(func=CmdGetUrl)
+4 -4
View File
@@ -64,15 +64,15 @@ class CmdPrePush(CmdHookBase):
class CmdMergeDriver(CmdHookBase):
def _run(self):
from dvc.dvcfile import Dvcfile
from dvc.dvcfile import load_file
from dvc.repo import Repo
dvc = Repo()
try:
ancestor = Dvcfile(dvc, self.args.ancestor, verify=False)
our = Dvcfile(dvc, self.args.our, verify=False)
their = Dvcfile(dvc, self.args.their, verify=False)
ancestor = load_file(dvc, self.args.ancestor, verify=False)
our = load_file(dvc, self.args.our, verify=False)
their = load_file(dvc, self.args.their, verify=False)
our.merge(ancestor, their, allowed=["add", "remove", "change"])
+39 -20
View File
@@ -3,7 +3,7 @@ import logging
from dvc.cli import completion
from dvc.cli.command import CmdBase
from dvc.cli.utils import append_doc_link
from dvc.cli.utils import DictAction, append_doc_link
from dvc.exceptions import DvcException
logger = logging.getLogger(__name__)
@@ -11,34 +11,35 @@ logger = logging.getLogger(__name__)
class CmdImport(CmdBase):
def run(self):
from dvc.scm import CloneError
try:
self.repo.imp(
self.args.url,
self.args.path,
out=self.args.out,
fname=self.args.file,
rev=self.args.rev,
no_exec=self.args.no_exec,
no_download=self.args.no_download,
desc=self.args.desc,
type=self.args.type,
labels=self.args.labels,
meta=self.args.meta,
jobs=self.args.jobs,
config=self.args.config,
remote=self.args.remote,
remote_config=self.args.remote_config,
)
except CloneError:
logger.exception("failed to import '%s'", self.args.path)
return 1
except DvcException:
logger.exception(
"failed to import '{}' from '{}'.".format(
self.args.path, self.args.url
)
"failed to import '%s' from '%s'.",
self.args.path,
self.args.url,
)
return 1
return 0
def add_parser(subparsers, parent_parser):
from .add import _add_annotating_args
IMPORT_HELP = (
"Download file or directory tracked by DVC or by Git "
"into the workspace, and track it."
@@ -70,11 +71,6 @@ def add_parser(subparsers, parent_parser):
help="Git revision (e.g. SHA, branch, tag)",
metavar="<commit>",
)
import_parser.add_argument(
"--file",
help="Specify name of the .dvc file this command will generate.",
metavar="<filename>",
)
no_download_exec_group = import_parser.add_mutually_exclusive_group()
no_download_exec_group.add_argument(
"--no-exec",
@@ -86,8 +82,10 @@ def add_parser(subparsers, parent_parser):
"--no-download",
action="store_true",
default=False,
help="Create .dvc file including target data hash value(s)"
" but do not actually download the file(s).",
help=(
"Create .dvc file including target data hash value(s)"
" but do not actually download the file(s)."
),
)
import_parser.add_argument(
"-j",
@@ -99,6 +97,27 @@ def add_parser(subparsers, parent_parser):
),
metavar="<number>",
)
_add_annotating_args(import_parser)
import_parser.add_argument(
"--config",
type=str,
help=(
"Path to a config file that will be merged with the config "
"in the target repository."
),
)
import_parser.add_argument(
"--remote",
type=str,
help="Remote name to set as a default in the target repository.",
)
import_parser.add_argument(
"--remote-config",
type=str,
nargs="*",
action=DictAction,
help=(
"Remote config options to merge with a remote's config (default or one "
"specified by '--remote') in the target repository."
),
)
import_parser.set_defaults(func=CmdImport)
+43 -48
View File
@@ -15,35 +15,28 @@ class CmdImportUrl(CmdBase):
self.repo.imp_url(
self.args.url,
out=self.args.out,
fname=self.args.file,
no_exec=self.args.no_exec,
no_download=self.args.no_download,
remote=self.args.remote,
to_remote=self.args.to_remote,
desc=self.args.desc,
type=self.args.type,
labels=self.args.labels,
meta=self.args.meta,
jobs=self.args.jobs,
force=self.args.force,
version_aware=self.args.version_aware,
)
except DvcException:
logger.exception(
"failed to import {}. You could also try downloading "
"it manually, and adding it with `dvc add`.".format(
self.args.url
)
(
"failed to import %s. You could also try downloading "
"it manually, and adding it with `dvc add`."
),
self.args.url,
)
return 1
return 0
def add_parser(subparsers, parent_parser):
from .add import _add_annotating_args
IMPORT_HELP = (
"Download or copy file from URL and take it under DVC control."
)
IMPORT_HELP = "Download or copy file from URL and take it under DVC control."
import_parser = subparsers.add_parser(
"import-url",
@@ -54,39 +47,22 @@ def add_parser(subparsers, parent_parser):
)
import_parser.add_argument(
"url",
help="Location of the data to download. Supported URLs:\n"
"/absolute/path/to/file/or/dir\n"
"relative/path/to/file/or/dir\n"
"C:\\\\path\\to\\file\\or\\dir\n"
"https://example.com/path/to/file\n"
"s3://bucket/key/path\n"
"gs://bucket/path/to/file/or/dir\n"
"hdfs://example.com/path/to/file\n"
"ssh://example.com/absolute/path/to/file/or/dir\n"
"remote://remote_name/path/to/file/or/dir (see `dvc remote`)",
help=(
"Location of the data to download. Supported URLs:\n"
"/absolute/path/to/file/or/dir\n"
"relative/path/to/file/or/dir\n"
"C:\\\\path\\to\\file\\or\\dir\n"
"https://example.com/path/to/file\n"
"s3://bucket/key/path\n"
"gs://bucket/path/to/file/or/dir\n"
"hdfs://example.com/path/to/file\n"
"ssh://example.com/absolute/path/to/file/or/dir\n"
"remote://remote_name/path/to/file/or/dir (see `dvc remote`)"
),
)
import_parser.add_argument(
"out", nargs="?", help="Destination path to put files to."
).complete = completion.DIR
import_parser.add_argument(
"--file",
help="Specify name of the .dvc file this command will generate.",
metavar="<filename>",
).complete = completion.DIR
no_download_exec_group = import_parser.add_mutually_exclusive_group()
no_download_exec_group.add_argument(
"--no-exec",
action="store_true",
default=False,
help="Only create .dvc file without actually importing target data.",
)
no_download_exec_group.add_argument(
"--no-download",
action="store_true",
default=False,
help="Create .dvc file including target data hash value(s)"
" but do not actually download the file(s).",
)
import_parser.add_argument(
"--to-remote",
action="store_true",
@@ -99,6 +75,22 @@ def add_parser(subparsers, parent_parser):
help="Remote storage to download to",
metavar="<name>",
)
no_download_exec_group = import_parser.add_mutually_exclusive_group()
no_download_exec_group.add_argument(
"--no-exec",
action="store_true",
default=False,
help="Only create .dvc file without actually importing target data.",
)
no_download_exec_group.add_argument(
"--no-download",
action="store_true",
default=False,
help=(
"Create .dvc file including target data hash value(s)"
" but do not actually download the file(s)."
),
)
import_parser.add_argument(
"-j",
"--jobs",
@@ -109,14 +101,17 @@ def add_parser(subparsers, parent_parser):
),
metavar="<number>",
)
import_parser.add_argument(
"-f",
"--force",
action="store_true",
default=False,
help="Override local file or folder if exists.",
)
import_parser.add_argument(
"--version-aware",
action="store_true",
default=False,
help=(
"Import using cloud versioning. Implied if the URL contains a "
"version ID."
),
help="Import using cloud versioning. Implied if the URL contains a version ID.",
)
_add_annotating_args(import_parser)
import_parser.set_defaults(func=CmdImportUrl)
+4 -4
View File
@@ -75,8 +75,9 @@ def add_parser(subparsers, parent_parser):
"--no-scm",
action="store_true",
default=False,
help="Initiate DVC in directory that is "
"not tracked by any SCM tool (e.g. Git).",
help=(
"Initiate DVC in directory that is not tracked by any SCM tool (e.g. Git)."
),
)
init_parser.add_argument(
"-f",
@@ -84,8 +85,7 @@ def add_parser(subparsers, parent_parser):
action="store_true",
default=False,
help=(
"Overwrite existing '.dvc/' directory. "
"This operation removes local cache."
"Overwrite existing '.dvc/' directory. This operation removes local cache."
),
)
init_parser.add_argument(
+4 -2
View File
@@ -31,7 +31,9 @@ def add_parser(subparsers, parent_parser):
"--use-pre-commit-tool",
action="store_true",
default=False,
help="Install DVC hooks using pre-commit "
"(https://pre-commit.com) if it is installed.",
help=(
"Install DVC hooks using pre-commit "
"(https://pre-commit.com) if it is installed."
),
)
install_parser.set_defaults(func=CmdInstall)
+27 -2
View File
@@ -3,7 +3,7 @@ import logging
from dvc.cli import completion
from dvc.cli.command import CmdBaseNoRepo
from dvc.cli.utils import append_doc_link
from dvc.cli.utils import DictAction, append_doc_link
from dvc.commands.ls.ls_colors import LsColors
from dvc.exceptions import DvcException
from dvc.ui import ui
@@ -34,6 +34,9 @@ class CmdList(CmdBaseNoRepo):
rev=self.args.rev,
recursive=self.args.recursive,
dvc_only=self.args.dvc_only,
config=self.args.config,
remote=self.args.remote,
remote_config=self.args.remote_config,
)
if self.args.json:
ui.write_json(entries)
@@ -71,7 +74,6 @@ def add_parser(subparsers, parent_parser):
)
list_parser.add_argument(
"--json",
"--show-json",
action="store_true",
help="Show output in JSON format.",
)
@@ -81,6 +83,29 @@ def add_parser(subparsers, parent_parser):
help="Git revision (e.g. SHA, branch, tag)",
metavar="<commit>",
)
list_parser.add_argument(
"--config",
type=str,
help=(
"Path to a config file that will be merged with the config "
"in the target repository."
),
)
list_parser.add_argument(
"--remote",
type=str,
help="Remote name to set as a default in the target repository.",
)
list_parser.add_argument(
"--remote-config",
type=str,
nargs="*",
action=DictAction,
help=(
"Remote config options to merge with a remote's config (default or one "
"specified by '--remote') in the target repository."
),
)
list_parser.add_argument(
"path",
nargs="?",
+1 -1
View File
@@ -20,7 +20,7 @@ class LsColors:
else:
self._codes[code] = color
def format(self, entry):
def format(self, entry): # noqa: A003
text = entry["path"]
if entry.get("isout", False) and "out" in self._codes:
+14 -32
View File
@@ -1,4 +1,5 @@
import argparse
from typing import Dict, List
from dvc.cli.command import CmdBase
from dvc.cli.utils import append_doc_link, fix_subparsers
@@ -6,7 +7,6 @@ from dvc.commands.config import CmdConfig
from dvc.compare import TabularData
from dvc.config import ConfigError
from dvc.exceptions import DvcException
from dvc.types import Dict, List
from dvc.ui import ui
from dvc.utils import format_link
@@ -18,7 +18,6 @@ class MachineDisabledError(ConfigError):
class CmdMachineConfig(CmdConfig):
def __init__(self, args):
super().__init__(args)
if not self.config["feature"].get("machine", False):
raise MachineDisabledError
@@ -163,20 +162,18 @@ class CmdMachineRename(CmdBase):
all_config = self.config.load_config_to_level(None)
if self.args.new in all_config.get("machine", {}):
raise ConfigError(
"Rename failed. Machine '{}' already exists.".format(
self.args.new
)
f"Rename failed. Machine '{self.args.new}' already exists."
)
ui.write(f"Rename machine '{self.args.name}' to '{self.args.new}'.")
def run(self):
self._check_before_rename()
with self.config.edit(self.args.level) as conf:
self._check_exists(conf)
conf["machine"][self.args.new] = conf["machine"][self.args.name]
try:
assert self.repo.machine
self.repo.machine.rename(self.args.name, self.args.new)
except DvcException as error:
del conf["machine"][self.args.new]
@@ -199,7 +196,7 @@ class CmdMachineDefault(CmdMachineConfig):
if self.args.name is None and not self.args.unset:
conf = self.config.read(self.args.level)
try:
print(conf["core"]["machine"])
ui.write(conf["core"]["machine"])
except KeyError:
ui.write("No default machine set")
return 1
@@ -208,9 +205,7 @@ class CmdMachineDefault(CmdMachineConfig):
if self.args.unset:
conf["core"].pop("machine", None)
else:
merged_conf = self.config.load_config_to_level(
self.args.level
)
merged_conf = self.config.load_config_to_level(self.args.level)
if (
self.args.name in conf["machine"]
or self.args.name in merged_conf["machine"]
@@ -218,8 +213,7 @@ class CmdMachineDefault(CmdMachineConfig):
conf["core"]["machine"] = self.args.name
else:
raise ConfigError(
"default machine must be present in machine "
"list."
"default machine must be present in machine list."
)
return 0
@@ -250,7 +244,6 @@ class CmdMachineStatus(CmdBase):
all_status: List[Dict],
td: TabularData,
):
if not all_status:
row = [
name,
@@ -309,7 +302,7 @@ class CmdMachineSsh(CmdBase):
return 0
def add_parser(subparsers, parent_parser):
def add_parser(subparsers, parent_parser): # noqa: PLR0915
from dvc.commands.config import parent_config_parser
machine_HELP = "Set up and manage cloud machines."
@@ -324,7 +317,7 @@ def add_parser(subparsers, parent_parser):
machine_subparsers = machine_parser.add_subparsers(
dest="cmd",
help="Use `dvc machine CMD --help` for " "command-specific help.",
help="Use `dvc machine CMD --help` for command-specific help.",
)
fix_subparsers(machine_subparsers)
@@ -342,8 +335,7 @@ def add_parser(subparsers, parent_parser):
"cloud",
help="Machine cloud. See full list of supported clouds at {}".format(
format_link(
"https://github.com/iterative/"
"terraform-provider-iterative#machine"
"https://github.com/iterative/terraform-provider-iterative#machine"
)
),
)
@@ -371,9 +363,7 @@ def add_parser(subparsers, parent_parser):
help=machine_DEFAULT_HELP,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
machine_default_parser.add_argument(
"name", nargs="?", help="Name of the machine"
)
machine_default_parser.add_argument("name", nargs="?", help="Name of the machine")
machine_default_parser.add_argument(
"-u",
"--unset",
@@ -413,9 +403,7 @@ def add_parser(subparsers, parent_parser):
formatter_class=argparse.RawDescriptionHelpFormatter,
)
machine_modify_parser.add_argument("name", help="Name of the machine")
machine_modify_parser.add_argument(
"option", help="Name of the option to modify."
)
machine_modify_parser.add_argument("option", help="Name of the option to modify.")
machine_modify_parser.add_argument(
"value", nargs="?", help="(optional) Value of the option."
)
@@ -448,9 +436,7 @@ def add_parser(subparsers, parent_parser):
help=machine_REMOVE_HELP,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
machine_remove_parser.add_argument(
"name", help="Name of the machine to remove."
)
machine_remove_parser.add_argument("name", help="Name of the machine to remove.")
machine_remove_parser.set_defaults(func=CmdMachineRemove)
machine_CREATE_HELP = "Create and start a machine instance."
@@ -461,14 +447,10 @@ def add_parser(subparsers, parent_parser):
help=machine_CREATE_HELP,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
machine_create_parser.add_argument(
"name", help="Name of the machine to create."
)
machine_create_parser.add_argument("name", help="Name of the machine to create.")
machine_create_parser.set_defaults(func=CmdMachineCreate)
machine_STATUS_HELP = (
"List the status of running instances for one/all machines."
)
machine_STATUS_HELP = "List the status of running instances for one/all machines."
machine_status_parser = machine_subparsers.add_parser(
"status",
parents=[parent_parser],
-4
View File
@@ -140,14 +140,12 @@ def add_parser(subparsers, parent_parser):
)
metrics_show_parser.add_argument(
"--json",
"--show-json",
action="store_true",
default=False,
help="Show output in JSON format.",
)
metrics_show_parser.add_argument(
"--md",
"--show-md",
action="store_true",
default=False,
dest="markdown",
@@ -223,14 +221,12 @@ def add_parser(subparsers, parent_parser):
)
metrics_diff_parser.add_argument(
"--json",
"--show-json",
action="store_true",
default=False,
help="Show output in JSON format.",
)
metrics_diff_parser.add_argument(
"--md",
"--show-md",
action="store_true",
default=False,
dest="markdown",
+2 -6
View File
@@ -14,9 +14,7 @@ class CmdMove(CmdBase):
try:
self.repo.move(self.args.src, self.args.dst)
except DvcException:
msg = "failed to move '{}' -> '{}'".format(
self.args.src, self.args.dst
)
msg = f"failed to move '{self.args.src}' -> '{self.args.dst}'"
logger.exception(msg)
return 1
return 0
@@ -40,7 +38,5 @@ def add_parser(subparsers, parent_parser):
move_parser.add_argument(
"src", help="Source path to a data file or directory."
).complete = completion.FILE
move_parser.add_argument(
"dst", help="Destination path."
).complete = completion.FILE
move_parser.add_argument("dst", help="Destination path.").complete = completion.FILE
move_parser.set_defaults(func=CmdMove)
+1 -3
View File
@@ -79,7 +79,7 @@ def add_parser(subparsers, parent_parser):
params_diff_parser.add_argument(
"b_rev",
nargs="?",
help=("New Git commit to compare (defaults to the current workspace)"),
help="New Git commit to compare (defaults to the current workspace)",
)
params_diff_parser.add_argument(
"--targets",
@@ -105,14 +105,12 @@ def add_parser(subparsers, parent_parser):
)
params_diff_parser.add_argument(
"--json",
"--show-json",
action="store_true",
default=False,
help="Show output in JSON format.",
)
params_diff_parser.add_argument(
"--md",
"--show-md",
action="store_true",
default=False,
dest="markdown",
+69 -59
View File
@@ -1,9 +1,9 @@
import argparse
import json
import logging
import os
from typing import TYPE_CHECKING, Dict, List, Optional
from funcy import first
from funcy import compact, first, get_in
from dvc.cli import completion
from dvc.cli.command import CmdBase
@@ -12,16 +12,51 @@ from dvc.exceptions import DvcException
from dvc.ui import ui
from dvc.utils import format_link
if TYPE_CHECKING:
from dvc.render.match import RendererWithErrors
logger = logging.getLogger(__name__)
def _show_json(renderers, split=False):
def _show_json(
renderers_with_errors: List["RendererWithErrors"],
split=False,
errors: Optional[Dict[str, Exception]] = None,
):
from dvc.render.convert import to_json
from dvc.utils.serialize import encode_exception
result = {
renderer.name: to_json(renderer, split) for renderer in renderers
}
ui.write_json(result)
all_errors: List[Dict] = []
data = {}
for renderer, src_errors, def_errors in renderers_with_errors:
name = renderer.name
data[name] = to_json(renderer, split)
all_errors.extend(
{
"name": name,
"rev": rev,
"source": source,
**encode_exception(e),
}
for rev, per_rev_src_errors in src_errors.items()
for source, e in per_rev_src_errors.items()
)
all_errors.extend(
{
"name": name,
"rev": rev,
**encode_exception(e),
}
for rev, e in def_errors.items()
)
# these errors are not tied to any renderers
errors = errors or {}
all_errors.extend({"rev": rev, **encode_exception(e)} for rev, e in errors.items())
ui.write_json(compact({"errors": all_errors, "data": data}), highlight=False)
def _adjust_vega_renderers(renderers):
@@ -78,12 +113,6 @@ class CmdPlots(CmdBase):
props = {p: getattr(self.args, p) for p in PLOT_PROPS}
return {k: v for k, v in props.items() if v is not None}
def _config_files(self):
config_files = None
if self.args.from_config:
config_files = {self.args.from_config}
return config_files
def _html_template_path(self):
html_template_path = self.args.html_template
if not html_template_path:
@@ -91,12 +120,11 @@ class CmdPlots(CmdBase):
"html_template", None
)
if html_template_path and not os.path.isabs(html_template_path):
html_template_path = os.path.join(
self.repo.dvc_dir, html_template_path
)
assert self.repo.dvc_dir
html_template_path = os.path.join(self.repo.dvc_dir, html_template_path)
return html_template_path
def run(self):
def run(self) -> int: # noqa: C901, PLR0911, PLR0912
from pathlib import Path
from dvc.render.match import match_defs_renderers
@@ -107,14 +135,11 @@ class CmdPlots(CmdBase):
logger.error("please specify a target for `--show-vega`")
return 1
if len(self.args.targets) > 1:
logger.error(
"you can only specify one target for `--show-vega`"
)
logger.error("you can only specify one target for `--show-vega`")
return 1
if self.args.json:
logger.error(
"'--show-vega' and '--json' are mutually exclusive "
"options."
"'--show-vega' and '--json' are mutually exclusive options."
)
return 1
@@ -122,37 +147,39 @@ class CmdPlots(CmdBase):
plots_data = self._func(
targets=self.args.targets,
props=self._props(),
config_files=self._config_files(),
)
if not plots_data:
if not plots_data and not self.args.json:
ui.error_write(
"No plots were loaded, "
"visualization file will not be created."
"No plots were loaded, visualization file will not be created."
)
out: str = self.args.out or self.repo.config.get("plots", {}).get(
"out_dir", "dvc_plots"
)
renderers_out = (
out if self.args.json else os.path.join(out, "static")
)
renderers = match_defs_renderers(
renderers_out = out if self.args.json else os.path.join(out, "static")
renderers_with_errors = match_defs_renderers(
data=plots_data,
out=renderers_out,
templates_dir=self.repo.plots.templates_dir,
)
if self.args.json:
_show_json(renderers, self.args.split)
errors = compact(
{
rev: get_in(data, ["definitions", "error"])
for rev, data in plots_data.items()
}
)
_show_json(renderers_with_errors, self.args.split, errors=errors)
return 0
renderers = [r.renderer for r in renderers_with_errors]
_adjust_vega_renderers(renderers)
if self.args.show_vega:
renderer = first(filter(lambda r: r.TYPE == "vega", renderers))
if renderer:
ui.write_json(json.loads(renderer.get_filled_template()))
ui.write_json(renderer.get_filled_template(as_string=False))
return 0
output_file: Path = (Path.cwd() / out).resolve() / "index.html"
@@ -161,7 +188,7 @@ class CmdPlots(CmdBase):
render_html(
renderers=renderers,
output_file=output_file,
template_path=self._html_template_path(),
html_template=self._html_template_path(),
)
ui.write(output_file.as_uri())
@@ -223,9 +250,8 @@ class CmdPlotsTemplates(CmdBase):
return 0
raise InvalidArgumentError(f"Unexpected template: {target}.")
else:
for template in TEMPLATES:
ui.write(template.DEFAULT_NAME)
for template in TEMPLATES:
ui.write(template.DEFAULT_NAME)
return 0
except DvcException:
@@ -251,8 +277,7 @@ def add_parser(subparsers, parent_parser):
fix_subparsers(plots_subparsers)
SHOW_HELP = (
"Generate plots from target files or from `plots`"
" definitions in `dvc.yaml`."
"Generate plots from target files or from `plots` definitions in `dvc.yaml`."
)
plots_show_parser = plots_subparsers.add_parser(
"show",
@@ -275,8 +300,7 @@ def add_parser(subparsers, parent_parser):
plots_show_parser.set_defaults(func=CmdPlotsShow)
PLOTS_DIFF_HELP = (
"Show multiple versions of a plot by overlaying them "
"in a single image."
"Show multiple versions of a plot by overlaying them in a single image."
)
plots_diff_parser = plots_subparsers.add_parser(
"diff",
@@ -334,9 +358,7 @@ def add_parser(subparsers, parent_parser):
)
plots_modify_parser.set_defaults(func=CmdPlotsModify)
TEMPLATES_HELP = (
"List built-in plots templates or show JSON specification for one."
)
TEMPLATES_HELP = "List built-in plots templates or show JSON specification for one."
plots_templates_parser = plots_subparsers.add_parser(
"templates",
parents=[parent_parser],
@@ -362,11 +384,8 @@ def _add_props_arguments(parser):
"--template",
nargs="?",
default=None,
help=(
"Special JSON or HTML schema file to inject with the data. "
"See {}".format(
format_link("https://man.dvc.org/plots#plot-templates")
)
help="Special JSON or HTML schema file to inject with the data. See {}".format(
format_link("https://man.dvc.org/plots#plot-templates")
),
metavar="<path>",
).complete = completion.FILE
@@ -383,9 +402,7 @@ def _add_props_arguments(parser):
default=None, # Use default None to distinguish when it's not used
help="Provided CSV or TSV datafile does not have a header.",
)
parser.add_argument(
"--title", default=None, metavar="<text>", help="Plot title."
)
parser.add_argument("--title", default=None, metavar="<text>", help="Plot title.")
parser.add_argument(
"--x-label", default=None, help="X axis label", metavar="<text>"
)
@@ -413,7 +430,6 @@ def _add_ui_arguments(parser):
)
parser.add_argument(
"--json",
"--show-json",
action="store_true",
default=False,
help=argparse.SUPPRESS,
@@ -433,9 +449,3 @@ def _add_ui_arguments(parser):
help="Custom HTML template for VEGA visualization.",
metavar="<path>",
)
parser.add_argument(
"--from-config",
default=None,
metavar="<path>",
help=argparse.SUPPRESS,
)
+1 -1
View File
@@ -26,7 +26,7 @@ def add_parser(subparsers, parent_parser):
queue_subparsers = queue_parser.add_subparsers(
dest="cmd",
help="Use `dvc queue CMD --help` to display " "command-specific help.",
help="Use `dvc queue CMD --help` to display command-specific help.",
)
fix_subparsers(queue_subparsers)
+13 -2
View File
@@ -11,13 +11,17 @@ class CmdQueueKill(CmdBase):
"""Kill exp task in queue."""
def run(self):
self.repo.experiments.celery_queue.kill(revs=self.args.task)
self.repo.experiments.celery_queue.kill(
revs=self.args.task, force=self.args.force
)
return 0
def add_parser(queue_subparsers, parent_parser):
QUEUE_KILL_HELP = "Kill actively running experiment queue tasks."
QUEUE_KILL_HELP = (
"Gracefully interrupt running experiment queue tasks (equivalent to Ctrl-C)"
)
queue_kill_parser = queue_subparsers.add_parser(
"kill",
parents=[parent_parser],
@@ -25,6 +29,13 @@ def add_parser(queue_subparsers, parent_parser):
help=QUEUE_KILL_HELP,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
queue_kill_parser.add_argument(
"-f",
"--force",
action="store_true",
default=False,
help="Forcefully and immediately kill running experiment queue tasks",
)
queue_kill_parser.add_argument(
"task",
nargs="*",
+1 -3
View File
@@ -34,9 +34,7 @@ def add_parser(queue_subparsers, parent_parser):
queue_logs_parser.add_argument(
"-e",
"--encoding",
help=(
"Text encoding for log output. Defaults to system locale encoding."
),
help="Text encoding for log output. Defaults to system locale encoding.",
metavar="<encoding>",
)
queue_logs_parser.add_argument(
-2
View File
@@ -28,7 +28,6 @@ class CmdQueueRemove(CmdBase):
)
def run(self):
self.check_arguments()
if self.args.all:
@@ -57,7 +56,6 @@ class CmdQueueRemove(CmdBase):
def add_parser(queue_subparsers, parent_parser):
QUEUE_REMOVE_HELP = "Remove queued and completed tasks from the queue."
queue_remove_parser = queue_subparsers.add_parser(
"remove",
+3 -11
View File
@@ -12,20 +12,15 @@ class CmdQueueStart(CmdBase):
"""Start exp queue workers."""
def run(self):
started = self.repo.experiments.celery_queue.start_workers(
self.args.jobs
)
started = self.repo.experiments.celery_queue.start_workers(self.args.jobs)
suffix = "s" if started > 1 else ""
ui.write(
f"Started '{started}' new experiments task queue worker{suffix}."
)
ui.write(f"Started '{started}' new experiments task queue worker{suffix}.")
return 0
def add_parser(queue_subparsers, parent_parser):
QUEUE_START_HELP = "Start the experiments task queue worker."
queue_start_parser = queue_subparsers.add_parser(
"start",
@@ -39,10 +34,7 @@ def add_parser(queue_subparsers, parent_parser):
"--jobs",
type=int,
default=1,
help=(
"Maximum number of concurrent queue workers to start. "
"Defaults to 1."
),
help="Maximum number of concurrent queue workers to start. Defaults to 1.",
metavar="<number>",
)
queue_start_parser.set_defaults(func=CmdQueueStart)
+9 -14
View File
@@ -1,33 +1,32 @@
import argparse
import logging
from typing import List, Mapping, Optional
from dvc.cli.command import CmdBase
from dvc.cli.utils import append_doc_link
from dvc.compare import TabularData
from dvc.ui import ui
from ..experiments.show import format_time
logger = logging.getLogger(__name__)
class CmdQueueStatus(CmdBase):
"""Show queue task and worker status."""
def run(self):
result: List[
Mapping[str, Optional[str]]
] = self.repo.experiments.celery_queue.status()
def run(self) -> int:
from dvc.repo.experiments.show import format_time
result = self.repo.experiments.celery_queue.status()
if result:
all_headers = ["Task", "Name", "Created", "Status"]
td = TabularData(all_headers)
for exp in result:
created = format_time(exp.get("timestamp"))
assert exp["rev"]
assert exp["status"]
td.append(
[
exp["rev"][:7],
exp.get("name", ""),
exp.get("name") or "",
created,
exp["status"],
]
@@ -38,9 +37,7 @@ class CmdQueueStatus(CmdBase):
ui.write()
worker_status = self.repo.experiments.celery_queue.worker_status()
active_count = len(
[name for name, task in worker_status.items() if task]
)
active_count = len([name for name, task in worker_status.items() if task])
idle_count = len(worker_status) - active_count
ui.write(f"Worker status: {active_count} active, {idle_count} idle")
@@ -49,9 +46,7 @@ class CmdQueueStatus(CmdBase):
def add_parser(queue_subparsers, parent_parser):
QUEUE_STATUS_HELP = (
"Show the status of experiments queue tasks and workers."
)
QUEUE_STATUS_HELP = "Show the status of experiments queue tasks and workers."
queue_status_parser = queue_subparsers.add_parser(
"status",
parents=[parent_parser],
-1
View File
@@ -26,7 +26,6 @@ class CmdQueueStop(CmdBase):
def add_parser(queue_subparsers, parent_parser):
QUEUE_STOP_HELP = "Stop all experiments task queue workers."
queue_stop_parser = queue_subparsers.add_parser(
"stop",
+6 -16
View File
@@ -95,9 +95,7 @@ class CmdRemoteDefault(CmdRemote):
if self.args.unset:
conf["core"].pop("remote", None)
else:
merged_conf = self.config.load_config_to_level(
self.args.level
)
merged_conf = self.config.load_config_to_level(self.args.level)
if (
self.args.name in conf["remote"]
or self.args.name in merged_conf["remote"]
@@ -129,9 +127,7 @@ class CmdRemoteRename(CmdRemote):
all_config = self.config.load_config_to_level(None)
if self.args.new in all_config.get("remote", {}):
raise ConfigError(
"Rename failed. Remote name '{}' already exists.".format(
{self.args.new}
)
f"Rename failed. Remote name {self.args.new!r} already exists."
)
with self.config.edit(self.args.level) as conf:
@@ -164,7 +160,7 @@ def add_parser(subparsers, parent_parser):
remote_subparsers = remote_parser.add_subparsers(
dest="cmd",
help="Use `dvc remote CMD --help` for " "command-specific help.",
help="Use `dvc remote CMD --help` for command-specific help.",
)
fix_subparsers(remote_subparsers)
@@ -208,9 +204,7 @@ def add_parser(subparsers, parent_parser):
help=REMOTE_DEFAULT_HELP,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
remote_default_parser.add_argument(
"name", nargs="?", help="Name of the remote"
)
remote_default_parser.add_argument("name", nargs="?", help="Name of the remote")
remote_default_parser.add_argument(
"-u",
"--unset",
@@ -229,9 +223,7 @@ def add_parser(subparsers, parent_parser):
formatter_class=argparse.RawDescriptionHelpFormatter,
)
remote_modify_parser.add_argument("name", help="Name of the remote")
remote_modify_parser.add_argument(
"option", help="Name of the option to modify."
)
remote_modify_parser.add_argument("option", help="Name of the option to modify.")
remote_modify_parser.add_argument(
"value", nargs="?", help="(optional) Value of the option."
)
@@ -262,9 +254,7 @@ def add_parser(subparsers, parent_parser):
help=REMOTE_REMOVE_HELP,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
remote_remove_parser.add_argument(
"name", help="Name of the remote to remove."
)
remote_remove_parser.add_argument("name", help="Name of the remote to remove.")
remote_remove_parser.set_defaults(func=CmdRemoteRemove)
REMOTE_RENAME_HELP = "Rename a DVC remote"
remote_rename_parser = remote_subparsers.add_parser(
+1 -2
View File
@@ -22,8 +22,7 @@ class CmdRemove(CmdBase):
def add_parser(subparsers, parent_parser):
REMOVE_HELP = (
"Remove stages from dvc.yaml and/or"
" stop tracking files or directories."
"Remove stages from dvc.yaml and/or stop tracking files or directories."
)
remove_parser = subparsers.add_parser(
"remove",
+41 -31
View File
@@ -10,20 +10,12 @@ class CmdRepro(CmdBase):
def run(self):
from dvc.ui import ui
stages = self.repo.reproduce(
**self._common_kwargs, **self._repro_kwargs
)
stages = self.repo.reproduce(**self._common_kwargs, **self._repro_kwargs)
if len(stages) == 0:
ui.write(CmdDataStatus.UP_TO_DATE_MSG)
else:
ui.write("Use `dvc push` to send your updates to remote storage.")
if self.args.metrics:
from dvc.compare import show_metrics
metrics = self.repo.metrics.show()
show_metrics(metrics)
return 0
@property
@@ -40,6 +32,8 @@ class CmdRepro(CmdBase):
"recursive": self.args.recursive,
"force_downstream": self.args.force_downstream,
"pull": self.args.pull,
"allow_missing": self.args.allow_missing,
"on_error": self.args.on_error,
}
@property
@@ -55,16 +49,14 @@ def add_arguments(repro_parser):
repro_parser.add_argument(
"targets",
nargs="*",
help=(
"""\
help="""\
Stages to reproduce. 'dvc.yaml' by default.
The targets can be path to a dvc.yaml file or `.dvc` file,
or a stage name from dvc.yaml file from
current working directory. To run a stage from dvc.yaml
from other directories, the target must be a path followed by colon `:`
and then the stage name name.
"""
),
""",
).complete = completion.DVCFILES_AND_STAGE
repro_parser.add_argument(
"-f",
@@ -85,16 +77,14 @@ and then the stage name name.
"--single-item",
action="store_true",
default=False,
help="Reproduce only single data item without recursive dependencies "
"check.",
help="Reproduce only single data item without recursive dependencies check.",
)
repro_parser.add_argument(
"-p",
"--pipeline",
action="store_true",
default=False,
help="Reproduce the whole pipeline that the specified targets "
"belong to.",
help="Reproduce the whole pipeline that the specified targets belong to.",
)
repro_parser.add_argument(
"-P",
@@ -110,13 +100,6 @@ and then the stage name name.
default=False,
help="Reproduce all stages in the specified directory.",
)
repro_parser.add_argument(
"-m",
"--metrics",
action="store_true",
default=False,
help="Show metrics after reproduction.",
)
repro_parser.add_argument(
"--downstream",
action="store_true",
@@ -127,8 +110,10 @@ and then the stage name name.
"--force-downstream",
action="store_true",
default=False,
help="Reproduce all descendants of a changed stage even if their "
"direct dependencies didn't change.",
help=(
"Reproduce all descendants of a changed stage even if their "
"direct dependencies didn't change."
),
)
repro_parser.add_argument(
"--pull",
@@ -139,19 +124,44 @@ and then the stage name name.
"from the run-cache."
),
)
repro_parser.add_argument(
"--allow-missing",
action="store_true",
default=False,
help=("Skip stages with missing data but no other changes."),
)
repro_parser.add_argument(
"--dry",
action="store_true",
default=False,
help="Only print the commands that would be executed without "
"actually executing.",
help=(
"Only print the commands that would be executed without actually executing."
),
)
repro_parser.add_argument(
"-k",
"--keep-going",
action="store_const",
default="fail",
const="keep-going",
dest="on_error",
help=(
"Continue executing, skipping stages having dependencies "
"on the failed stages"
),
)
repro_parser.add_argument(
"--ignore-errors",
action="store_const",
default="fail",
const="ignore",
dest="on_error",
help="Ignore errors from stages.",
)
def add_parser(subparsers, parent_parser):
REPRO_HELP = (
"Reproduce complete or partial pipelines by executing their stages."
)
REPRO_HELP = "Reproduce complete or partial pipelines by executing their stages."
repro_parser = subparsers.add_parser(
"repro",
parents=[parent_parser],
-100
View File
@@ -1,100 +0,0 @@
import argparse
import logging
from dvc.cli.command import CmdBase
from dvc.cli.utils import append_doc_link
from dvc.commands.stage import parse_cmd
from dvc.exceptions import DvcException
logger = logging.getLogger(__name__)
class CmdRun(CmdBase):
def run(self):
if not any(
[
self.args.deps,
self.args.outs,
self.args.outs_no_cache,
self.args.metrics,
self.args.metrics_no_cache,
self.args.plots,
self.args.plots_no_cache,
self.args.outs_persist,
self.args.outs_persist_no_cache,
self.args.checkpoints,
self.args.params,
self.args.command,
]
): # pragma: no cover
logger.error(
"too few arguments. Specify at least one: `-d`, `-o`, `-O`, "
"`-m`, `-M`, `-p`, `--plots`, `--plots-no-cache`, "
"`--outs-persist`, `--outs-persist-no-cache`, `command`."
)
return 1
kwargs = vars(self.args)
kwargs.update(
{
"cmd": parse_cmd(self.args.command),
"fname": kwargs.pop("file"),
"no_exec": (self.args.no_exec or bool(self.args.checkpoints)),
"run_cache": not kwargs.pop("no_run_cache"),
}
)
try:
self.repo.run(**kwargs)
except DvcException:
logger.exception("")
return 1
return 0
def add_parser(subparsers, parent_parser):
from dvc.commands.stage import _add_common_args
RUN_HELP = (
"Generate a dvc.yaml file from a command and execute the command."
)
run_parser = subparsers.add_parser(
"run",
parents=[parent_parser],
description=append_doc_link(RUN_HELP, "run"),
help=RUN_HELP,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
run_parser.add_argument("-n", "--name", help="Stage name.")
run_parser.add_argument(
"--file", metavar="<filename>", help=argparse.SUPPRESS
)
run_parser.add_argument(
"--single-stage",
action="store_true",
default=False,
help=argparse.SUPPRESS,
)
_add_common_args(run_parser)
run_parser.add_argument(
"--no-exec",
action="store_true",
default=False,
help="Only create dvc.yaml without actually running it.",
)
run_parser.add_argument(
"--no-commit",
action="store_true",
default=False,
help="Don't put files/directories into cache.",
)
run_parser.add_argument(
"--no-run-cache",
action="store_true",
default=False,
help=(
"Execute the command even if this stage has already been run "
"with the same command/dependencies/outputs/etc before."
),
)
run_parser.set_defaults(func=CmdRun)
+43 -33
View File
@@ -1,5 +1,6 @@
import argparse
import logging
from contextlib import contextmanager
from itertools import chain, filterfalse
from typing import TYPE_CHECKING, Dict, Iterable, List
@@ -44,9 +45,7 @@ def generate_description(stage: "Stage") -> str:
return "; ".join(desc)
def prepare_description(
stage: "Stage", max_length: int = MAX_TEXT_LENGTH
) -> str:
def prepare_description(stage: "Stage", max_length: int = MAX_TEXT_LENGTH) -> str:
desc = stage.short_description() or generate_description(stage)
return truncate_text(desc, max_length)
@@ -57,9 +56,9 @@ def prepare_stages_data(
max_length: int = MAX_TEXT_LENGTH,
) -> Dict[str, str]:
return {
stage.addressing: prepare_description(stage, max_length=max_length)
if description
else ""
stage.addressing: (
prepare_description(stage, max_length=max_length) if description else ""
)
for stage in stages
}
@@ -67,7 +66,7 @@ def prepare_stages_data(
class CmdStageList(CmdBase):
def _get_stages(self) -> Iterable["Stage"]:
if self.args.all:
stages: List["Stage"] = self.repo.index.stages # type: ignore
stages: List["Stage"] = self.repo.index.stages
logger.trace( # type: ignore[attr-defined]
"%d no. of stages found", len(stages)
)
@@ -75,9 +74,7 @@ class CmdStageList(CmdBase):
# removing duplicates while maintaining order
collected = chain.from_iterable(
self.repo.stage.collect(
target=target, recursive=self.args.recursive
)
self.repo.stage.collect(target=target, recursive=self.args.recursive)
for target in self.args.targets
)
return dict.fromkeys(collected).keys()
@@ -95,7 +92,7 @@ class CmdStageList(CmdBase):
stages = self._get_stages()
data = prepare_stages_data(stages, description=not self.args.name_only)
ui.table(data.items())
ui.table(list(data.items()))
return 0
@@ -123,8 +120,22 @@ def parse_cmd(commands: List[str]) -> str:
return " ".join(map(quote_argument, commands))
@contextmanager
def _disable_logging(highest_level=logging.CRITICAL):
previous_level = logging.root.manager.disable
logging.disable(highest_level)
try:
yield
finally:
logging.disable(previous_level)
class CmdStageAdd(CmdBase):
def run(self):
from dvc.repo import lock_repo
kwargs = vars(self.args)
kwargs.update(
{
@@ -132,7 +143,15 @@ class CmdStageAdd(CmdBase):
"params": parse_params(self.args.params),
}
)
self.repo.stage.add(**kwargs)
with self.repo.scm_context, lock_repo(self.repo):
with _disable_logging(logging.INFO):
stage = self.repo.stage.add(**kwargs)
logger.info("Added stage %r in %r", stage.addressing, stage.relpath)
if self.args.run:
stage.run()
stage.dump(update_pipeline=False)
return 0
@@ -173,39 +192,24 @@ def _add_common_args(parser):
"--outs-no-cache",
action="append",
default=[],
help="Declare output file or directory "
"(do not put into DVC cache).",
help="Declare output file or directory (do not put into DVC cache).",
metavar="<filename>",
).complete = completion.FILE
parser.add_argument(
"-c",
"--checkpoints",
action="append",
default=[],
help="Declare checkpoint output file or directory for 'dvc exp run'. "
"Not compatible with 'dvc repro'.",
metavar="<filename>",
).complete = completion.FILE
parser.add_argument(
"--external",
action="store_true",
default=False,
help="Allow outputs that are outside of the DVC repository.",
)
parser.add_argument(
"--outs-persist",
action="append",
default=[],
help="Declare output file or directory that will not be "
"removed upon repro.",
help="Declare output file or directory that will not be removed upon repro.",
metavar="<filename>",
)
parser.add_argument(
"--outs-persist-no-cache",
action="append",
default=[],
help="Declare output file or directory that will not be "
"removed upon repro (do not put into DVC cache).",
help=(
"Declare output file or directory that will not be "
"removed upon repro (do not put into DVC cache)."
),
metavar="<filename>",
)
parser.add_argument(
@@ -259,6 +263,12 @@ def _add_common_args(parser):
"This doesn't affect any DVC operations."
),
)
parser.add_argument(
"--run",
action="store_true",
default=False,
help="Execute the stage after generating it.",
)
parser.add_argument(
"command",
nargs=argparse.REMAINDER,
+1 -3
View File
@@ -81,9 +81,7 @@ class CmdDataStatus(CmdDataBase):
if not self.repo.index.stages:
ui.write(self.EMPTY_PROJECT_MSG)
elif self.args.cloud or self.args.remote:
remote = self.args.remote or self.repo.config["core"].get(
"remote"
)
remote = self.args.remote or self.repo.config["core"].get("remote")
ui.write(self.IN_SYNC_MSG.format(remote=remote))
else:
ui.write(self.UP_TO_DATE_MSG)
+4 -2
View File
@@ -60,8 +60,10 @@ def add_parser(subparsers, parent_parser):
"--no-download",
action="store_true",
default=False,
help="Update .dvc file git revision/hash value(s)"
" but do not download the file(s).",
help=(
"Update .dvc file git revision/hash value(s)"
" but do not download the file(s)."
),
)
update_parser.add_argument(
"--to-remote",
+1 -3
View File
@@ -21,9 +21,7 @@ class CmdVersion(CmdBaseNoRepo):
def add_parser(subparsers, parent_parser):
VERSION_HELP = (
"Display the DVC version and system/environment information."
)
VERSION_HELP = "Display the DVC version and system/environment information."
version_parser = subparsers.add_parser(
"version",
parents=[parent_parser],
+29 -65
View File
@@ -22,7 +22,6 @@ from typing import (
from funcy import reraise
if TYPE_CHECKING:
from dvc.types import StrPath
from dvc.ui.table import CellT
@@ -35,7 +34,7 @@ def with_value(value, default):
class TabularData(MutableSequence[Sequence["CellT"]]):
def __init__(self, columns: Sequence[str], fill_value: str = ""):
def __init__(self, columns: Sequence[str], fill_value: Optional[str] = ""):
self._columns: Dict[str, Column] = {name: Column() for name in columns}
self._keys: List[str] = list(columns)
self._fill_value = fill_value
@@ -64,9 +63,7 @@ class TabularData(MutableSequence[Sequence["CellT"]]):
def keys(self) -> List[str]:
return self._keys
def _iter_col_row(
self, row: Sequence["CellT"]
) -> Iterator[Tuple["CellT", Column]]:
def _iter_col_row(self, row: Sequence["CellT"]) -> Iterator[Tuple["CellT", Column]]:
for val, col in zip_longest(row, self.columns):
if col is None:
break
@@ -103,9 +100,7 @@ class TabularData(MutableSequence[Sequence["CellT"]]):
...
@overload
def __setitem__(
self, item: slice, value: Iterable[Sequence["CellT"]]
) -> None:
def __setitem__(self, item: slice, value: Iterable[Sequence["CellT"]]) -> None:
...
def __setitem__(self, item, value) -> None:
@@ -113,8 +108,7 @@ class TabularData(MutableSequence[Sequence["CellT"]]):
if isinstance(item, slice):
n = len(self.columns)
normalized_rows = (
chain(val, repeat(self._fill_value, n - len(val)))
for val in value
chain(val, repeat(self._fill_value, n - len(val))) for val in value
)
# we need to transpose those rows into columnar format
# as we work in terms of column-based arrays
@@ -166,24 +160,6 @@ class TabularData(MutableSequence[Sequence["CellT"]]):
writer.writerow(row)
return buff.getvalue()
def to_parallel_coordinates(
self, output_path: "StrPath", color_by: str = None
) -> "StrPath":
from dvc_render.html import render_html
from dvc_render.plotly import ParallelCoordinatesRenderer
render_html(
renderers=[
ParallelCoordinatesRenderer(
self.as_dict(),
color_by=color_by,
fill_value=self._fill_value,
)
],
output_file=output_path,
)
return output_path
def add_column(self, name: str) -> None:
self._columns[name] = Column([self._fill_value] * len(self))
self._keys.append(name)
@@ -208,14 +184,12 @@ class TabularData(MutableSequence[Sequence["CellT"]]):
ui.table(self, headers=self.keys(), **kwargs)
def as_dict(
self, cols: Iterable[str] = None
self, cols: Optional[Iterable[str]] = None
) -> Iterable[Dict[str, "CellT"]]:
keys = self.keys() if cols is None else set(cols)
return [
{k: self._columns[k][i] for k in keys} for i in range(len(self))
]
return [{k: self._columns[k][i] for k in keys} for i in range(len(self))]
def dropna(
def dropna( # noqa: C901, PLR0912
self,
axis: str = "rows",
how="any",
@@ -223,13 +197,10 @@ class TabularData(MutableSequence[Sequence["CellT"]]):
):
if axis not in ["rows", "cols"]:
raise ValueError(
f"Invalid 'axis' value {axis}."
"Choose one of ['rows', 'cols']"
f"Invalid 'axis' value {axis}.Choose one of ['rows', 'cols']"
)
if how not in ["any", "all"]:
raise ValueError(
f"Invalid 'how' value {how}." "Choose one of ['any', 'all']"
)
raise ValueError(f"Invalid 'how' value {how}. Choose one of ['any', 'all']")
match_line: Set = set()
match_any = True
@@ -244,8 +215,7 @@ class TabularData(MutableSequence[Sequence["CellT"]]):
if axis == "rows":
match_line.add(n_row)
break
else:
match_line.add(self.keys()[n_col])
match_line.add(self.keys()[n_col])
to_drop = match_line
if how == "all":
@@ -258,16 +228,12 @@ class TabularData(MutableSequence[Sequence["CellT"]]):
if axis == "rows":
for name in self.keys():
self._columns[name] = Column(
[
x
for n, x in enumerate(self._columns[name])
if n not in to_drop
]
[x for n, x in enumerate(self._columns[name]) if n not in to_drop]
)
else:
self.drop(*to_drop)
def drop_duplicates(
def drop_duplicates( # noqa: C901
self,
axis: str = "rows",
subset: Optional[Iterable[str]] = None,
@@ -275,8 +241,7 @@ class TabularData(MutableSequence[Sequence["CellT"]]):
):
if axis not in ["rows", "cols"]:
raise ValueError(
f"Invalid 'axis' value {axis}."
"Choose one of ['rows', 'cols']"
f"Invalid 'axis' value {axis}.Choose one of ['rows', 'cols']"
)
if axis == "cols":
@@ -324,12 +289,13 @@ def _normalize_float(val: float, precision: int):
def _format_field(
val: Any, precision: int = None, round_digits: bool = False
val: Any, precision: Optional[int] = None, round_digits: bool = False
) -> str:
def _format(_val):
if isinstance(_val, float) and precision:
func = round if round_digits else _normalize_float
return func(_val, precision)
if round_digits:
return round(_val, precision)
return _normalize_float(_val, precision)
if isinstance(_val, abc.Mapping):
return {k: _format(v) for k, v in _val.items()}
if isinstance(_val, list):
@@ -345,11 +311,11 @@ def diff_table(
old: bool = True,
no_path: bool = False,
show_changes: bool = True,
precision: int = None,
precision: Optional[int] = None,
round_digits: bool = False,
on_empty_diff: str = None,
a_rev: str = None,
b_rev: str = None,
on_empty_diff: Optional[str] = None,
a_rev: Optional[str] = None,
b_rev: Optional[str] = None,
) -> TabularData:
a_rev = a_rev or "HEAD"
b_rev = b_rev or "workspace"
@@ -361,9 +327,7 @@ def diff_table(
for item, change in sorted(diff_in_file.items()):
old_value = with_value(change.get("old"), fill_value)
new_value = with_value(change.get("new"), fill_value)
diff_value = with_value(
change.get("diff", on_empty_diff), fill_value
)
diff_value = with_value(change.get("diff", on_empty_diff), fill_value)
td.append(
[
fname,
@@ -387,18 +351,18 @@ def diff_table(
return td
def show_diff(
def show_diff( # noqa: PLR0913
diff,
title: str,
old: bool = True,
no_path: bool = False,
show_changes: bool = True,
precision: int = None,
precision: Optional[int] = None,
round_digits: bool = False,
on_empty_diff: str = None,
on_empty_diff: Optional[str] = None,
markdown: bool = False,
a_rev: str = None,
b_rev: str = None,
a_rev: Optional[str] = None,
b_rev: Optional[str] = None,
) -> None:
td = diff_table(
diff,
@@ -420,7 +384,7 @@ def metrics_table(
all_branches: bool = False,
all_tags: bool = False,
all_commits: bool = False,
precision: int = None,
precision: Optional[int] = None,
round_digits: bool = False,
):
from dvc.utils.diff import format_dict
@@ -460,7 +424,7 @@ def show_metrics(
all_branches: bool = False,
all_tags: bool = False,
all_commits: bool = False,
precision: int = None,
precision: Optional[int] = None,
round_digits: bool = False,
) -> None:
td = metrics_table(
+79 -40
View File
@@ -4,11 +4,18 @@ import os
import re
from contextlib import contextmanager
from functools import partial
from typing import TYPE_CHECKING, Dict, Optional
from funcy import cached_property, compact, memoize, re_find
from funcy import compact, memoize, re_find
from dvc.exceptions import DvcException, NotDvcRepoError
from .utils.objects import cached_property
if TYPE_CHECKING:
from dvc.fs import FileSystem
from dvc.types import DictStrAny, StrPath
logger = logging.getLogger(__name__)
@@ -72,9 +79,6 @@ class Config(dict):
ConfigError: thrown if config has an invalid format.
"""
APPNAME = "dvc"
APPAUTHOR = "iterative"
SYSTEM_LEVELS = ("system", "global")
REPO_LEVELS = ("repo", "local")
# In the order they shadow each other
@@ -84,7 +88,13 @@ class Config(dict):
CONFIG_LOCAL = "config.local"
def __init__(
self, dvc_dir=None, validate=True, fs=None, config=None
self,
dvc_dir: Optional["StrPath"] = None,
validate: bool = True,
fs: Optional["FileSystem"] = None,
config: Optional["DictStrAny"] = None,
remote: Optional[str] = None,
remote_config: Optional["DictStrAny"] = None,
): # pylint: disable=super-init-not-called
from dvc.fs import LocalFileSystem
@@ -92,31 +102,37 @@ class Config(dict):
self.wfs = LocalFileSystem()
self.fs = fs or self.wfs
if not dvc_dir:
try:
from dvc.repo import Repo
if dvc_dir:
self.dvc_dir = self.fs.path.abspath(dvc_dir)
self.dvc_dir = Repo.find_dvc_dir()
except NotDvcRepoError:
self.dvc_dir = None
else:
self.dvc_dir = self.fs.path.abspath(self.fs.path.realpath(dvc_dir))
self.load(
validate=validate, config=config, remote=remote, remote_config=remote_config
)
self.load(validate=validate, config=config)
@classmethod
def from_cwd(cls, fs: Optional["FileSystem"] = None, **kwargs):
from dvc.repo import Repo
try:
dvc_dir = Repo.find_dvc_dir(fs=fs)
except NotDvcRepoError:
dvc_dir = None
return cls(dvc_dir=dvc_dir, fs=fs, **kwargs)
@classmethod
def get_dir(cls, level):
from appdirs import site_config_dir, user_config_dir
from dvc.dirs import global_config_dir, system_config_dir
assert level in ("global", "system")
if level == "global":
return user_config_dir(cls.APPNAME, cls.APPAUTHOR)
return global_config_dir()
if level == "system":
return site_config_dir(cls.APPNAME, cls.APPAUTHOR)
return system_config_dir()
@cached_property
def files(self):
def files(self) -> Dict[str, str]:
files = {
level: os.path.join(self.get_dir(level), self.CONFIG)
for level in ("system", "global")
@@ -139,10 +155,16 @@ class Config(dict):
dvc.config.Config: config object.
"""
config_file = os.path.join(dvc_dir, Config.CONFIG)
open(config_file, "w+", encoding="utf-8").close()
return Config(dvc_dir)
with open(config_file, "w+", encoding="utf-8"):
return Config(dvc_dir)
def load(self, validate=True, config=None):
def load(
self,
validate: bool = True,
config: Optional["DictStrAny"] = None,
remote: Optional[str] = None,
remote_config: Optional["DictStrAny"] = None,
):
"""Loads config from all the config files.
Raises:
@@ -157,32 +179,50 @@ class Config(dict):
conf = self.validate(conf)
self.clear()
self.update(conf)
# Add resolved default cache.dir
if not self["cache"].get("dir") and self.dvc_dir:
self["cache"]["dir"] = os.path.join(self.dvc_dir, "cache")
if remote:
conf["core"]["remote"] = remote
if remote_config:
remote = remote or conf["core"].get("remote")
if not remote:
raise ValueError("Missing remote name")
merge(conf, {"remote": {remote: remote_config}})
self.update(conf)
def _get_fs(self, level):
# NOTE: this might be a Gitfs, which doesn't see things outside of
# the repo.
return self.fs if level == "repo" else self.wfs
def _load_config(self, level):
from configobj import ConfigObj
@staticmethod
def load_file(path, fs=None) -> dict:
from configobj import ConfigObj, ConfigObjError
from dvc.fs import localfs
fs = fs or localfs
with fs.open(path) as fobj:
try:
conf_obj = ConfigObj(fobj)
except UnicodeDecodeError as exc:
raise ConfigError(str(exc)) from exc
except ConfigObjError as exc:
raise ConfigError(str(exc)) from exc
return _parse_named(_lower_keys(conf_obj.dict()))
def _load_config(self, level):
filename = self.files[level]
fs = self._get_fs(level)
if fs.exists(filename):
with fs.open(filename) as fobj:
try:
conf_obj = ConfigObj(fobj)
except UnicodeDecodeError as exc:
raise ConfigError(str(exc)) from exc
else:
conf_obj = ConfigObj()
return _parse_named(_lower_keys(conf_obj.dict()))
try:
return self.load_file(filename, fs=fs)
except FileNotFoundError:
return {}
def _save_config(self, level, conf_dict):
from configobj import ConfigObj
@@ -278,7 +318,7 @@ class Config(dict):
return Schema(dirs_schema, extra=ALLOW_EXTRA)(conf)
def load_config_to_level(self, level=None):
merged_conf = {}
merged_conf: Dict = {}
for merge_level in self.LEVELS:
if merge_level == level:
break
@@ -324,7 +364,7 @@ class Config(dict):
def _parse_named(conf):
result = {"remote": {}, "machine": {}}
result: Dict[str, Dict] = {"remote": {}, "machine": {}}
for section, val in conf.items():
match = re_find(r'^\s*(remote|machine)\s*"(.*)"\s*$', section)
@@ -361,6 +401,5 @@ def merge(into, update):
def _lower_keys(data):
return {
k.lower(): _lower_keys(v) if isinstance(v, dict) else v
for k, v in data.items()
k.lower(): _lower_keys(v) if isinstance(v, dict) else v for k, v in data.items()
}
+60 -25
View File
@@ -1,8 +1,10 @@
import logging
import os
from urllib.parse import urlparse
from funcy import walk_values
from funcy import once, walk_values
from voluptuous import (
REMOVE_EXTRA,
All,
Any,
Coerce,
@@ -13,6 +15,8 @@ from voluptuous import (
Schema,
)
logger = logging.getLogger(__name__)
Bool = All(
Lower,
Any("true", "false"),
@@ -34,14 +38,12 @@ def supported_cache_type(types):
unsupported = set(types) - {"reflink", "hardlink", "symlink", "copy"}
if unsupported:
raise Invalid(
"Unsupported cache type(s): {}".format(", ".join(unsupported))
)
raise Invalid("Unsupported cache type(s): {}".format(", ".join(unsupported)))
return types
def Choices(*choices):
def Choices(*choices): # noqa: N802
"""Checks that value belongs to the specified set of values
Args:
@@ -51,7 +53,7 @@ def Choices(*choices):
return Any(*choices, msg="expected one of {}".format(", ".join(choices)))
def ByUrl(mapping):
def ByUrl(mapping): # noqa: N802
schemas = walk_values(Schema, mapping)
def validate(data):
@@ -60,7 +62,9 @@ def ByUrl(mapping):
parsed = urlparse(data["url"])
# Windows absolute paths should really have scheme == "" (local)
if os.name == "nt" and len(parsed.scheme) == 1 and parsed.netloc == "":
if os.name == "nt" and len(parsed.scheme) == 1 and not parsed.netloc:
return schemas[""](data)
if not parsed.netloc:
return schemas[""](data)
if parsed.scheme not in schemas:
raise Invalid(f"Unsupported URL type {parsed.scheme}://")
@@ -71,7 +75,28 @@ def ByUrl(mapping):
class RelPath(str):
pass
__slots__ = ()
class FeatureSchema(Schema):
def __init__(self, schema, required=False):
super().__init__(schema, required=required, extra=REMOVE_EXTRA)
@staticmethod
@once
def _log_deprecated(keys):
# only run this once per session
message = "%s config option%s unsupported"
paths = ", ".join(f"'feature.{key}'" for key in keys)
pluralize = " is" if len(keys) == 1 else "s are"
logger.warning(message, paths, pluralize)
def __call__(self, data):
ret = super().__call__(data)
extra_keys = data.keys() - ret.keys()
if extra_keys:
self._log_deprecated(sorted(extra_keys))
return ret
REMOTE_COMMON = {
@@ -97,6 +122,8 @@ HTTP_COMMON = {
"ask_password": Bool,
"ssl_verify": Any(Bool, str),
"method": str,
"connect_timeout": All(Coerce(float), Range(0, min_included=True)),
"read_timeout": All(Coerce(float), Range(0, min_included=True)),
Optional("verify", default=False): Bool,
}
WEBDAV_COMMON = {
@@ -104,6 +131,7 @@ WEBDAV_COMMON = {
"password": str,
"ask_password": Bool,
"token": str,
"custom_auth_header": str,
"cert_path": str,
"key_path": str,
"timeout": Coerce(int),
@@ -122,16 +150,17 @@ SCHEMA = {
Optional("autostage", default=False): Bool,
Optional("experiments"): Bool, # obsoleted
Optional("check_update", default=True): Bool,
"site_cache_dir": str,
"machine": Lower,
},
"cache": {
"local": str,
"s3": str,
"gs": str,
"hdfs": str,
"webhdfs": str,
"ssh": str,
"azure": str,
"local": str, # obsoleted
"s3": str, # obsoleted
"gs": str, # obsoleted
"hdfs": str, # obsoleted
"webhdfs": str, # obsoleted
"ssh": str, # obsoleted
"azure": str, # obsoleted
# This is for default local cache
"dir": str,
**LOCAL_COMMON,
@@ -186,6 +215,7 @@ SCHEMA = {
"timeout": Coerce(int),
"gss_auth": Bool,
"allow_agent": Bool,
"max_sessions": Coerce(int),
Optional("verify", default=False): Bool,
**REMOTE_COMMON,
},
@@ -245,19 +275,17 @@ SCHEMA = {
)
},
"state": {
"dir": str,
"dir": str, # obsoleted
"row_limit": All(Coerce(int), Range(1)), # obsoleted
"row_cleanup_quota": All(Coerce(int), Range(0, 100)), # obsoleted
},
"index": {
"dir": str,
"dir": str, # obsoleted
},
"machine": {
str: {
"cloud": All(Lower, Choices("aws", "azure")),
"region": All(
Lower, Choices("us-west", "us-east", "eu-west", "eu-north")
),
"region": All(Lower, Choices("us-west", "us-east", "eu-west", "eu-north")),
"image": str,
"spot": Bool,
"spot_price": Coerce(float),
@@ -270,11 +298,12 @@ SCHEMA = {
},
},
# section for experimental features
"feature": {
Optional("machine", default=False): Bool,
# enabled by default. It's of no use, kept for backward compatibility.
Optional("parametrization", default=True): Bool,
},
# only specified keys are validated, others get logged and then ignored/removed
"feature": FeatureSchema(
{
Optional("machine", default=False): Bool,
},
),
"plots": {
"html_template": str,
Optional("auto_open", default=False): Bool,
@@ -298,4 +327,10 @@ SCHEMA = {
"config_dir": str,
"config_name": str,
},
"studio": {
"token": str,
"url": str,
"repo_url": str,
Optional("offline", default=False): Bool,
},
}
+42 -19
View File
@@ -5,7 +5,7 @@ import logging
import os
import platform
import sys
from subprocess import Popen
from subprocess import Popen # nosec B404
from typing import List
from dvc.env import DVC_DAEMON
@@ -14,52 +14,74 @@ from dvc.utils import fix_env, is_binary
logger = logging.getLogger(__name__)
def _popen(cmd, **kwargs):
def _suppress_resource_warning(popen: Popen):
"""Sets the returncode to avoid ResourceWarning when popen is garbage collected."""
# only use for daemon processes.
# See https://bugs.python.org/issue38890.
popen.returncode = 0
def _popen(cmd, **kwargs) -> Popen:
prefix = [sys.executable]
if not is_binary():
main_entrypoint = os.path.join(
os.path.abspath(os.path.dirname(__file__)), "__main__.py"
)
prefix += [main_entrypoint]
return Popen(prefix + cmd, close_fds=True, shell=False, **kwargs)
return Popen(
prefix + cmd, close_fds=True, shell=False, **kwargs # nosec B603 # noqa: S603
)
def _spawn_windows(cmd, env):
from subprocess import (
CREATE_NEW_PROCESS_GROUP,
CREATE_NO_WINDOW,
STARTF_USESHOWWINDOW,
STARTUPINFO,
)
if sys.platform == "win32":
from subprocess import ( # nosec B404
CREATE_NEW_PROCESS_GROUP,
CREATE_NO_WINDOW,
STARTF_USESHOWWINDOW,
STARTUPINFO,
)
# https://stackoverflow.com/a/7006424
# https://bugs.python.org/issue41619
creationflags = CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW
# https://stackoverflow.com/a/7006424
# https://bugs.python.org/issue41619
creationflags = CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW
startupinfo = STARTUPINFO()
startupinfo.dwFlags |= STARTF_USESHOWWINDOW
startupinfo = STARTUPINFO()
startupinfo.dwFlags |= STARTF_USESHOWWINDOW
_popen(cmd, env=env, creationflags=creationflags, startupinfo=startupinfo)
popen = _popen(
cmd, env=env, creationflags=creationflags, startupinfo=startupinfo
)
_suppress_resource_warning(popen)
def _spawn_posix(cmd, env):
from dvc.cli import main
# `fork` will copy buffers, so we need to flush them before forking.
# Otherwise, we will get duplicated outputs.
if sys.stdout and not sys.stdout.closed:
sys.stdout.flush()
if sys.stderr and not sys.stderr.closed:
sys.stderr.flush()
# NOTE: using os._exit instead of sys.exit, because dvc built
# with PyInstaller has trouble with SystemExit exception and throws
# errors such as "[26338] Failed to execute script __main__"
try:
pid = os.fork() # pylint: disable=no-member
# pylint: disable-next=no-member
pid = os.fork() # type: ignore[attr-defined]
if pid > 0:
return
except OSError:
logger.exception("failed at first fork")
os._exit(1) # pylint: disable=protected-access
os.setsid() # pylint: disable=no-member
os.setsid() # type: ignore[attr-defined] # pylint: disable=no-member
try:
pid = os.fork() # pylint: disable=no-member
# pylint: disable-next=no-member
pid = os.fork() # type: ignore[attr-defined]
if pid > 0:
os._exit(0) # pylint: disable=protected-access
except OSError:
@@ -69,6 +91,7 @@ def _spawn_posix(cmd, env):
sys.stdin.close()
sys.stdout.close()
sys.stderr.close()
os.closerange(0, 3)
if platform.system() == "Darwin":
# workaround for MacOS bug
@@ -100,7 +123,7 @@ def daemon(args):
Args:
args (list): list of arguments to append to `dvc daemon` command.
"""
daemonize(["daemon", "-q"] + args)
daemonize(["daemon", "-q", *args])
def daemonize(cmd: List[str]):

Some files were not shown because too many files have changed in this diff Show More