dfsync 0.4.7__tar.gz → 0.4.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dfsync-0.4.7 → dfsync-0.4.9}/PKG-INFO +2 -2
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/distribution.py +50 -8
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/filters.py +19 -6
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/kube_credentials.py +3 -1
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/monitor.py +67 -11
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/test_dfsync.py +0 -4
- dfsync-0.4.9/dfsync/test_distribution.py +30 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/test_kube_credentials.py +17 -4
- {dfsync-0.4.7 → dfsync-0.4.9}/pyproject.toml +3 -2
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/__init__.py +0 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/backends/__init__.py +0 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/backends/kube.py +0 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/backends/kube_exec.py +0 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/backends/rsync.py +0 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/char_ui.py +0 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/chcli.py +0 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/check_dns.py +0 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/cli.py +0 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/config.py +0 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/diffui.py +0 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/exp.py +0 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/lib.py +0 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/test_lib.py +0 -0
- {dfsync-0.4.7 → dfsync-0.4.9}/dfsync/transactions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dfsync
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.9
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Mihai Balint
|
|
6
6
|
Author-email: balint.mihai@gmail.com
|
|
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.10
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
-
Requires-Dist: black (==
|
|
14
|
+
Requires-Dist: black (==24.3.0)
|
|
15
15
|
Requires-Dist: click (>=8,<9)
|
|
16
16
|
Requires-Dist: click-default-group (>=1.2.2,<2.0.0)
|
|
17
17
|
Requires-Dist: gitpython (>=3.1.14,<4.0.0)
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import click
|
|
1
2
|
import json
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
2
5
|
import urllib.request
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
3
8
|
from dfsync.lib import ControlledThreadedOperation
|
|
4
9
|
|
|
5
10
|
|
|
@@ -8,14 +13,14 @@ def get_package_version(package_name):
|
|
|
8
13
|
from importlib.metadata import version
|
|
9
14
|
|
|
10
15
|
return version(package_name)
|
|
11
|
-
except:
|
|
16
|
+
except Exception:
|
|
12
17
|
pass
|
|
13
18
|
|
|
14
19
|
try:
|
|
15
20
|
import pkg_resources
|
|
16
21
|
|
|
17
22
|
return pkg_resources.get_distribution(package_name).version
|
|
18
|
-
except:
|
|
23
|
+
except Exception:
|
|
19
24
|
pass
|
|
20
25
|
|
|
21
26
|
return None
|
|
@@ -41,7 +46,7 @@ def get_latest_version():
|
|
|
41
46
|
raise ValueError("No version visible on github")
|
|
42
47
|
|
|
43
48
|
return versions[0]
|
|
44
|
-
except Exception
|
|
49
|
+
except Exception:
|
|
45
50
|
return get_installed_version()
|
|
46
51
|
|
|
47
52
|
|
|
@@ -52,7 +57,7 @@ def parse_version(version_str):
|
|
|
52
57
|
for part in version_str.split("."):
|
|
53
58
|
try:
|
|
54
59
|
parsed_version.append(int(part))
|
|
55
|
-
except:
|
|
60
|
+
except Exception:
|
|
56
61
|
parsed_version.append(part)
|
|
57
62
|
return parsed_version
|
|
58
63
|
|
|
@@ -80,15 +85,52 @@ class AsyncVersionChecker(ControlledThreadedOperation):
|
|
|
80
85
|
self.installed = get_installed_version()
|
|
81
86
|
self.latest = get_latest_version()
|
|
82
87
|
self.installed_is_older = is_older_version(self.installed, self.latest)
|
|
88
|
+
self._is_install_editable = is_installed_in_editable_mode("dfsync")
|
|
83
89
|
self._cta_count = 0
|
|
84
90
|
self.stop()
|
|
85
91
|
|
|
86
92
|
@property
|
|
87
|
-
def
|
|
93
|
+
def should_emit_update_warning(self):
|
|
88
94
|
return self.is_completed and self.installed_is_older and self._cta_count < 1
|
|
89
95
|
|
|
90
|
-
def
|
|
96
|
+
def set_emitted_update_warning(self):
|
|
91
97
|
self._cta_count += 1
|
|
92
98
|
|
|
93
|
-
def
|
|
94
|
-
|
|
99
|
+
def get_update_warning(self):
|
|
100
|
+
if self._is_install_editable:
|
|
101
|
+
return f"dfsync ver. {self.latest} is available, please update! ({self.installed} is installed)"
|
|
102
|
+
else:
|
|
103
|
+
return f"dfsync ver. {self.latest} is available ({self.installed} is installed), please update using `dfsync self-update`"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _read_editable_location_from_pip_show_output(out: str) -> Optional[str]:
|
|
107
|
+
editable_label = "Editable project location: "
|
|
108
|
+
site_packages_label = "site-packages"
|
|
109
|
+
site_packages_lines = []
|
|
110
|
+
|
|
111
|
+
for line in out.split("\n"):
|
|
112
|
+
if line.startswith("Location: "):
|
|
113
|
+
continue
|
|
114
|
+
if line.startswith(editable_label):
|
|
115
|
+
return line[len(editable_label) :].strip()
|
|
116
|
+
if site_packages_label in line:
|
|
117
|
+
site_packages_lines.append(line)
|
|
118
|
+
|
|
119
|
+
return "UNKNOWN-EDITABLE-LOCATION" if len(site_packages_lines) > 0 else None
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def is_installed_in_editable_mode(package_name: str) -> bool:
|
|
123
|
+
try:
|
|
124
|
+
out = subprocess.check_output([sys.executable, "-m", "pip", "show", "-f", package_name]).decode()
|
|
125
|
+
editable_location = _read_editable_location_from_pip_show_output(out)
|
|
126
|
+
return editable_location is not None
|
|
127
|
+
except Exception:
|
|
128
|
+
return False
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def update_package(package_name: str):
|
|
132
|
+
click.echo(f"Running {sys.executable} -m pip install --upgrade {package_name}")
|
|
133
|
+
try:
|
|
134
|
+
subprocess.check_call([sys.executable, "-m", "pip", "install", "--upgrade", package_name])
|
|
135
|
+
except Exception as e:
|
|
136
|
+
click.echo(f"Failed to update {package_name}: {e}")
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import black
|
|
1
|
+
import black
|
|
2
|
+
import fnmatch
|
|
2
3
|
import os.path
|
|
3
4
|
import git.exc
|
|
4
5
|
import subprocess
|
|
@@ -111,6 +112,10 @@ class UntrackedGitFilesFilter(LoggingFilter):
|
|
|
111
112
|
self._repos = {}
|
|
112
113
|
self._is_repo_initialized = {}
|
|
113
114
|
self._untracked_and_ignored_files = {}
|
|
115
|
+
self._should_filter_untracked_files = True
|
|
116
|
+
|
|
117
|
+
def set_should_filter_untracked_files(self, should_filter_untracked_files: bool = True):
|
|
118
|
+
self._should_filter_untracked_files = should_filter_untracked_files
|
|
114
119
|
|
|
115
120
|
def get_untracked_and_ignored_files(self):
|
|
116
121
|
flat_files = []
|
|
@@ -175,13 +180,17 @@ class UntrackedGitFilesFilter(LoggingFilter):
|
|
|
175
180
|
self._ignore(src_file_path, "GIT repo internals")
|
|
176
181
|
return True
|
|
177
182
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
return True
|
|
183
|
+
if self._should_filter_untracked_files and self._is_untracked_file(repo, src_abs_path):
|
|
184
|
+
self._ignore(src_file_path, "Untracked GIT file")
|
|
185
|
+
return True
|
|
186
|
+
|
|
183
187
|
return False
|
|
184
188
|
|
|
189
|
+
def _is_untracked_file(self, repo, src_abs_path):
|
|
190
|
+
return any(
|
|
191
|
+
src_abs_path == os.path.join(repo.working_dir, rel_file_path) for rel_file_path in repo.untracked_files
|
|
192
|
+
)
|
|
193
|
+
|
|
185
194
|
|
|
186
195
|
USER_FILTERS = [EmacsBufferFilter(), PythonBlackFilter()]
|
|
187
196
|
GIT_FILTER = UntrackedGitFilesFilter()
|
|
@@ -215,3 +224,7 @@ def add_user_filter(f: LoggingFilter):
|
|
|
215
224
|
|
|
216
225
|
def add_user_ignored_patterns_filter(patterns: [str]):
|
|
217
226
|
add_user_filter(UserConfigFilter(patterns))
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def set_ignore_untracked_files(should_ignore_untracked_files: bool):
|
|
230
|
+
GIT_FILTER.set_should_filter_untracked_files(should_ignore_untracked_files)
|
|
@@ -77,14 +77,16 @@ def update_local_kube_config(new_kube_credentials):
|
|
|
77
77
|
credentials_yaml = yaml.dump(credentials)
|
|
78
78
|
with open(f"{LOCAL_CREDENTIALS_FILE}.new", "w") as f:
|
|
79
79
|
f.write(credentials_yaml)
|
|
80
|
+
os.chmod(f"{LOCAL_CREDENTIALS_FILE}.new", 0o600)
|
|
80
81
|
|
|
81
82
|
if os.path.isfile(LOCAL_CREDENTIALS_FILE):
|
|
82
83
|
if os.path.isfile(f"{LOCAL_CREDENTIALS_FILE}.old"):
|
|
83
84
|
os.remove(f"{LOCAL_CREDENTIALS_FILE}.old")
|
|
84
85
|
os.rename(f"{LOCAL_CREDENTIALS_FILE}", f"{LOCAL_CREDENTIALS_FILE}.old")
|
|
86
|
+
os.chmod(f"{LOCAL_CREDENTIALS_FILE}.old", 0o600)
|
|
85
87
|
|
|
86
88
|
os.rename(f"{LOCAL_CREDENTIALS_FILE}.new", f"{LOCAL_CREDENTIALS_FILE}")
|
|
87
|
-
|
|
89
|
+
os.chmod(LOCAL_CREDENTIALS_FILE, 0o600)
|
|
88
90
|
return credentials_yaml
|
|
89
91
|
|
|
90
92
|
|
|
@@ -12,9 +12,16 @@ from functools import partial
|
|
|
12
12
|
from watchdog.observers import Observer
|
|
13
13
|
from watchdog.events import FileSystemEventHandler
|
|
14
14
|
|
|
15
|
+
import dfsync.filters as filters
|
|
15
16
|
from dfsync.backends import rsync_backend, kube_backend
|
|
16
|
-
from dfsync.distribution import
|
|
17
|
-
|
|
17
|
+
from dfsync.distribution import (
|
|
18
|
+
get_installed_version,
|
|
19
|
+
get_latest_version,
|
|
20
|
+
is_older_version,
|
|
21
|
+
AsyncVersionChecker,
|
|
22
|
+
is_installed_in_editable_mode,
|
|
23
|
+
update_package,
|
|
24
|
+
)
|
|
18
25
|
from dfsync.config import read_config
|
|
19
26
|
from dfsync.char_ui import KeyController
|
|
20
27
|
from dfsync.kube_credentials import contextualize_kube_credentials, update_local_kube_config, normalized_k8s_url
|
|
@@ -47,7 +54,7 @@ class FileChangedEventHandler(ControlledThreadedOperation, FileSystemEventHandle
|
|
|
47
54
|
**kwargs,
|
|
48
55
|
):
|
|
49
56
|
super().__init__()
|
|
50
|
-
self.filters = [*ALL_FILTERS]
|
|
57
|
+
self.filters = [*filters.ALL_FILTERS]
|
|
51
58
|
|
|
52
59
|
self.backend = backend
|
|
53
60
|
self.backend_options = kwargs
|
|
@@ -253,12 +260,50 @@ def main():
|
|
|
253
260
|
|
|
254
261
|
@main.command()
|
|
255
262
|
def version():
|
|
263
|
+
"""
|
|
264
|
+
Print the currently installed version
|
|
265
|
+
"""
|
|
266
|
+
_version()
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def _version():
|
|
256
270
|
installed_version = get_installed_version()
|
|
257
271
|
click.echo(f"{installed_version}")
|
|
258
272
|
|
|
259
273
|
latest_version = get_latest_version()
|
|
260
|
-
if is_older_version(installed_version, latest_version):
|
|
261
|
-
|
|
274
|
+
if not is_older_version(installed_version, latest_version):
|
|
275
|
+
return
|
|
276
|
+
elif is_installed_in_editable_mode("dfsync"):
|
|
277
|
+
click.echo(f"Latest version is {latest_version}, please update!")
|
|
278
|
+
else:
|
|
279
|
+
click.echo(f"Latest version is {latest_version}, please update using `dfsync self-update`")
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
@main.command(name="help", context_settings=dict(ignore_unknown_options=True))
|
|
283
|
+
@click.option("--help", is_flag=True, default=False, hidden=True)
|
|
284
|
+
def help(help):
|
|
285
|
+
"""
|
|
286
|
+
Print the usage/help for dfsync
|
|
287
|
+
"""
|
|
288
|
+
with click.Context(sync, info_name="dfsync") as ctx:
|
|
289
|
+
click.echo(sync.get_help(ctx))
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
@main.command()
|
|
293
|
+
def self_update():
|
|
294
|
+
"""
|
|
295
|
+
Update dfsync to the latest version published on pypi
|
|
296
|
+
"""
|
|
297
|
+
latest_version = get_latest_version()
|
|
298
|
+
installed_version = get_installed_version()
|
|
299
|
+
if not is_older_version(installed_version, latest_version):
|
|
300
|
+
click.echo(f"The latest version is already installed: {installed_version}")
|
|
301
|
+
return
|
|
302
|
+
elif is_installed_in_editable_mode("dfsync"):
|
|
303
|
+
click.echo("dfsync is installed in editable mode, please update manually")
|
|
304
|
+
return
|
|
305
|
+
else:
|
|
306
|
+
update_package("dfsync")
|
|
262
307
|
|
|
263
308
|
|
|
264
309
|
@main.command()
|
|
@@ -278,11 +323,15 @@ def import_kube_host(kube_host=None, credentials=None):
|
|
|
278
323
|
@main.command()
|
|
279
324
|
@click.argument("source", nargs=-1)
|
|
280
325
|
@click.argument("destination", default="", nargs=1)
|
|
281
|
-
@click.option("--supervisor
|
|
326
|
+
@click.option("--supervisor", is_flag=True, default=False, help="Try to install supervisor in container")
|
|
282
327
|
@click.option("--kube-host", default=None, help="Kubernetes api host server address/hostname", type=str)
|
|
283
328
|
@click.option("--pod-timeout", default=30, help="Pod reconfiguration timeout (default is 30 seconds)", type=int)
|
|
284
329
|
@click.option("--full-sync/--no-full-sync", default=True, help="On startup, sync all files to destination", type=bool)
|
|
285
|
-
|
|
330
|
+
@click.option("--version", is_flag=True, default=False, help="Print the currently installed version")
|
|
331
|
+
@click.option(
|
|
332
|
+
"--sync-git-untracked", is_flag=True, default=False, help="Sync git-untracked files instead of ignoring them"
|
|
333
|
+
)
|
|
334
|
+
def sync(source, destination, supervisor, kube_host, pod_timeout, full_sync, version, sync_git_untracked):
|
|
286
335
|
"""
|
|
287
336
|
Watches a folder for changes and propagates all file changes to a destination.
|
|
288
337
|
|
|
@@ -322,7 +371,14 @@ def sync(source, destination, supervisor, kube_host, pod_timeout, full_sync):
|
|
|
322
371
|
|
|
323
372
|
paths = ["."] if len(source) == 0 else source
|
|
324
373
|
config = read_config(destination, *paths)
|
|
325
|
-
add_user_ignored_patterns_filter(config.ignore_files)
|
|
374
|
+
filters.add_user_ignored_patterns_filter(config.ignore_files)
|
|
375
|
+
|
|
376
|
+
if sync_git_untracked:
|
|
377
|
+
filters.set_ignore_untracked_files(False)
|
|
378
|
+
|
|
379
|
+
if version:
|
|
380
|
+
_version()
|
|
381
|
+
return
|
|
326
382
|
|
|
327
383
|
destination_dir = destination
|
|
328
384
|
if len(source) == 0 and config.destination and not has_destination_optics(destination):
|
|
@@ -419,9 +475,9 @@ def sync(source, destination, supervisor, kube_host, pod_timeout, full_sync):
|
|
|
419
475
|
no_errors = False
|
|
420
476
|
break
|
|
421
477
|
with controller.getch_lock():
|
|
422
|
-
if checker.
|
|
423
|
-
checker.
|
|
424
|
-
click.echo(checker.
|
|
478
|
+
if checker.should_emit_update_warning:
|
|
479
|
+
checker.set_emitted_update_warning()
|
|
480
|
+
click.echo(checker.get_update_warning())
|
|
425
481
|
controller.raise_exceptions()
|
|
426
482
|
|
|
427
483
|
except KeyboardInterrupt:
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from dfsync.distribution import is_installed_in_editable_mode, get_package_version, update_package
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_is_installed_in_editable_mode():
|
|
6
|
+
assert is_installed_in_editable_mode("dfsync") is True
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_is_installed_in_editable_mode_missing_package():
|
|
10
|
+
assert is_installed_in_editable_mode("does-not-exist") is False
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_is_installed_in_editable_mode_required_and_installed_package():
|
|
14
|
+
assert pytest is not None, "pytest must be installed"
|
|
15
|
+
assert is_installed_in_editable_mode("pytest") is False
|
|
16
|
+
|
|
17
|
+
assert is_installed_in_editable_mode("click") is False
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_update_package():
|
|
21
|
+
tqdm_version = get_package_version("tqdm")
|
|
22
|
+
|
|
23
|
+
update_package("tqdm==4.66.2")
|
|
24
|
+
assert get_package_version("tqdm") == "4.66.2"
|
|
25
|
+
|
|
26
|
+
update_package("tqdm==4.66.0")
|
|
27
|
+
assert get_package_version("tqdm") == "4.66.0"
|
|
28
|
+
|
|
29
|
+
update_package(f"tqdm=={tqdm_version}")
|
|
30
|
+
assert get_package_version("tqdm") == tqdm_version
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import os
|
|
1
2
|
import pytest
|
|
2
|
-
import yaml
|
|
3
3
|
import tempfile
|
|
4
|
+
import yaml
|
|
4
5
|
|
|
5
6
|
from dfsync.kube_credentials import update_local_kube_config, normalized_k8s_url
|
|
6
7
|
|
|
@@ -12,7 +13,7 @@ def mock_kube_credentials(mocker):
|
|
|
12
13
|
return temp.name
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
def
|
|
16
|
+
def test_update_missing_kube_config_and_check_permissions(mock_kube_credentials):
|
|
16
17
|
new_kube_credentials = {
|
|
17
18
|
"clusters": [{"cluster": {"server": "test_server"}, "name": "test_cluster"}],
|
|
18
19
|
"contexts": [{"context": {"cluster": "test_cluster", "user": "test_user"}, "name": "test_context"}],
|
|
@@ -23,6 +24,9 @@ def test_update_missing_kube_config(mock_kube_credentials):
|
|
|
23
24
|
assert "test_context" in result
|
|
24
25
|
assert "test_user" in result
|
|
25
26
|
|
|
27
|
+
# Check file permissions
|
|
28
|
+
assert oct(os.stat(mock_kube_credentials).st_mode)[-3:] == "600"
|
|
29
|
+
|
|
26
30
|
|
|
27
31
|
def test_update_empty_kube_config(mock_kube_credentials):
|
|
28
32
|
with open(mock_kube_credentials, "wb") as f:
|
|
@@ -53,6 +57,15 @@ def test_update_empty_kube_config(mock_kube_credentials):
|
|
|
53
57
|
assert credentials["users"][0]["user"]["username"] == "test_username"
|
|
54
58
|
assert credentials["users"][0]["user"]["password"] == "test_password"
|
|
55
59
|
|
|
60
|
+
# Verify that the old file was saved
|
|
61
|
+
with open(f"{mock_kube_credentials}.old", "r") as f:
|
|
62
|
+
credentials = yaml.safe_load(f)
|
|
63
|
+
assert credentials == empty_config
|
|
64
|
+
|
|
65
|
+
# Check file permissions for both old and new config file
|
|
66
|
+
assert oct(os.stat(mock_kube_credentials).st_mode)[-3:] == "600"
|
|
67
|
+
assert oct(os.stat(f"{mock_kube_credentials}.old").st_mode)[-3:] == "600"
|
|
68
|
+
|
|
56
69
|
|
|
57
70
|
def test_update_existing_kube_config(mock_kube_credentials):
|
|
58
71
|
with open(mock_kube_credentials, "wb") as f:
|
|
@@ -103,5 +116,5 @@ def test_normalized_k8s_url():
|
|
|
103
116
|
assert normalized_k8s_url("192.168.0.123:6443") == "https://192.168.0.123:6443"
|
|
104
117
|
with pytest.raises(ValueError):
|
|
105
118
|
normalized_k8s_url("")
|
|
106
|
-
|
|
107
|
-
|
|
119
|
+
|
|
120
|
+
assert normalized_k8s_url(None) is None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "dfsync"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.9"
|
|
4
4
|
description = ""
|
|
5
5
|
authors = ["Mihai Balint <balint.mihai@gmail.com>"]
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ toml = "^0.10.2"
|
|
|
14
14
|
tenacity = "^8.0.1"
|
|
15
15
|
click-default-group = "^1.2.2"
|
|
16
16
|
paramiko = {version = "^3.2.0", extras = ["invoke"]}
|
|
17
|
-
black = "
|
|
17
|
+
black = "24.3.0"
|
|
18
18
|
|
|
19
19
|
[tool.poetry.dev-dependencies]
|
|
20
20
|
pytest = "^7.4"
|
|
@@ -23,6 +23,7 @@ ipython = "^8"
|
|
|
23
23
|
ipdb = "^0.13"
|
|
24
24
|
flake8 = "^4.0.1"
|
|
25
25
|
pycodestyle = "^2.8.0"
|
|
26
|
+
tqdm = "4.66.0"
|
|
26
27
|
|
|
27
28
|
[tool.black]
|
|
28
29
|
line-length = 120
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|