depkeeper 0.1.0__py3-none-any.whl
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.
- depkeeper/__init__.py +32 -0
- depkeeper/__main__.py +45 -0
- depkeeper/__version__.py +12 -0
- depkeeper/cli.py +169 -0
- depkeeper/commands/__init__.py +0 -0
- depkeeper/commands/check.py +604 -0
- depkeeper/commands/update.py +651 -0
- depkeeper/config.py +289 -0
- depkeeper/constants.py +104 -0
- depkeeper/context.py +42 -0
- depkeeper/core/__init__.py +27 -0
- depkeeper/core/checker.py +458 -0
- depkeeper/core/data_store.py +645 -0
- depkeeper/core/dependency_analyzer.py +1011 -0
- depkeeper/core/parser.py +1138 -0
- depkeeper/exceptions.py +218 -0
- depkeeper/models/__init__.py +23 -0
- depkeeper/models/conflict.py +151 -0
- depkeeper/models/package.py +371 -0
- depkeeper/models/requirement.py +148 -0
- depkeeper/utils/__init__.py +100 -0
- depkeeper/utils/console.py +238 -0
- depkeeper/utils/filesystem.py +324 -0
- depkeeper/utils/http.py +267 -0
- depkeeper/utils/logger.py +146 -0
- depkeeper/utils/version_utils.py +92 -0
- depkeeper-0.1.0.dist-info/LICENSE +201 -0
- depkeeper-0.1.0.dist-info/METADATA +223 -0
- depkeeper-0.1.0.dist-info/RECORD +32 -0
- depkeeper-0.1.0.dist-info/WHEEL +5 -0
- depkeeper-0.1.0.dist-info/entry_points.txt +2 -0
- depkeeper-0.1.0.dist-info/top_level.txt +1 -0
depkeeper/__init__.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
depkeeper — modern Python dependency management for requirements.txt.
|
|
3
|
+
|
|
4
|
+
depkeeper is an intelligent dependency management tool that helps developers
|
|
5
|
+
keep their ``requirements.txt`` files up to date, secure, and conflict-free.
|
|
6
|
+
|
|
7
|
+
Quick start
|
|
8
|
+
-----------
|
|
9
|
+
Check for available updates::
|
|
10
|
+
|
|
11
|
+
$ depkeeper check
|
|
12
|
+
|
|
13
|
+
Update packages to newer versions::
|
|
14
|
+
|
|
15
|
+
$ depkeeper update
|
|
16
|
+
|
|
17
|
+
Programmatic usage::
|
|
18
|
+
|
|
19
|
+
>>> from depkeeper.core.parser import RequirementsParser
|
|
20
|
+
>>> from depkeeper.core.checker import VersionChecker
|
|
21
|
+
>>> parser = RequirementsParser()
|
|
22
|
+
>>> requirements = parser.parse_file("requirements.txt")
|
|
23
|
+
|
|
24
|
+
For more information, see:
|
|
25
|
+
https://rahulkaushal04.github.io/depkeeper/
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
from depkeeper.__version__ import __version__
|
|
31
|
+
|
|
32
|
+
__all__ = ["__version__"]
|
depkeeper/__main__.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module entry point for depkeeper.
|
|
3
|
+
|
|
4
|
+
This file enables execution via ``python -m depkeeper`` and delegates
|
|
5
|
+
control to the main CLI implementation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def main() -> int:
|
|
14
|
+
"""Entry point for ``python -m depkeeper``.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
Exit code:
|
|
18
|
+
0 Success
|
|
19
|
+
1 Import or runtime error
|
|
20
|
+
130 Interrupted by user
|
|
21
|
+
"""
|
|
22
|
+
try:
|
|
23
|
+
from depkeeper.cli import main as cli_main
|
|
24
|
+
except ImportError as exc:
|
|
25
|
+
_print_startup_error(exc)
|
|
26
|
+
return 1
|
|
27
|
+
|
|
28
|
+
return cli_main()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _print_startup_error(exc: ImportError) -> None:
|
|
32
|
+
"""Print a helpful error message if the CLI cannot be imported."""
|
|
33
|
+
try:
|
|
34
|
+
from depkeeper.__version__ import __version__
|
|
35
|
+
|
|
36
|
+
sys.stderr.write(f"depkeeper version: {__version__}\n")
|
|
37
|
+
except Exception:
|
|
38
|
+
sys.stderr.write("depkeeper version: <unknown>\n")
|
|
39
|
+
|
|
40
|
+
sys.stderr.write("\n")
|
|
41
|
+
sys.stderr.write(f"ImportError: {exc}\n")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
if __name__ == "__main__":
|
|
45
|
+
sys.exit(main())
|
depkeeper/__version__.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Version information for depkeeper.
|
|
3
|
+
|
|
4
|
+
This module exposes the canonical version string for the depkeeper
|
|
5
|
+
package. It is intentionally isolated to avoid import cycles and to
|
|
6
|
+
allow tools (CLI, packaging, docs) to query the version reliably.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
#: Current depkeeper version (PEP 440 compliant).
|
|
12
|
+
__version__: str = "0.1.0"
|
depkeeper/cli.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Command-line interface for depkeeper.
|
|
3
|
+
|
|
4
|
+
This module provides the main CLI entry point and handles global options,
|
|
5
|
+
configuration loading, and command registration.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
import logging
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Optional
|
|
15
|
+
|
|
16
|
+
import click
|
|
17
|
+
|
|
18
|
+
from depkeeper.config import load_config
|
|
19
|
+
from depkeeper.__version__ import __version__
|
|
20
|
+
from depkeeper.context import DepKeeperContext
|
|
21
|
+
from depkeeper.exceptions import ConfigError, DepKeeperError
|
|
22
|
+
from depkeeper.utils.logger import get_logger, setup_logging
|
|
23
|
+
from depkeeper.utils.console import print_error, print_warning
|
|
24
|
+
|
|
25
|
+
logger = get_logger("cli")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@click.group(context_settings={"help_option_names": ["-h", "--help"]})
|
|
29
|
+
@click.option(
|
|
30
|
+
"--config",
|
|
31
|
+
"-c",
|
|
32
|
+
type=click.Path(exists=True, dir_okay=False, path_type=Path),
|
|
33
|
+
help="Path to configuration file.",
|
|
34
|
+
envvar="DEPKEEPER_CONFIG",
|
|
35
|
+
)
|
|
36
|
+
@click.option(
|
|
37
|
+
"--verbose",
|
|
38
|
+
"-v",
|
|
39
|
+
count=True,
|
|
40
|
+
help="Increase verbosity (can be repeated: -v, -vv).",
|
|
41
|
+
)
|
|
42
|
+
@click.option(
|
|
43
|
+
"--color/--no-color",
|
|
44
|
+
default=True,
|
|
45
|
+
help="Enable or disable colored output.",
|
|
46
|
+
envvar="DEPKEEPER_COLOR",
|
|
47
|
+
)
|
|
48
|
+
@click.version_option(
|
|
49
|
+
version=__version__,
|
|
50
|
+
prog_name="depkeeper",
|
|
51
|
+
message="%(prog)s %(version)s",
|
|
52
|
+
)
|
|
53
|
+
@click.pass_context
|
|
54
|
+
def cli(
|
|
55
|
+
ctx: click.Context,
|
|
56
|
+
config: Optional[Path],
|
|
57
|
+
verbose: int,
|
|
58
|
+
color: bool,
|
|
59
|
+
) -> None:
|
|
60
|
+
"""depkeeper — modern dependency management for requirements.txt files.
|
|
61
|
+
|
|
62
|
+
\b
|
|
63
|
+
Available commands:
|
|
64
|
+
depkeeper check Check for available updates
|
|
65
|
+
depkeeper update Update packages to newer versions
|
|
66
|
+
|
|
67
|
+
\b
|
|
68
|
+
Examples:
|
|
69
|
+
depkeeper check
|
|
70
|
+
depkeeper update
|
|
71
|
+
depkeeper -v check
|
|
72
|
+
|
|
73
|
+
Use ``depkeeper COMMAND --help`` for command-specific options.
|
|
74
|
+
"""
|
|
75
|
+
_configure_logging(verbose)
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
loaded_config = load_config(config)
|
|
79
|
+
except ConfigError as exc:
|
|
80
|
+
print_error(str(exc))
|
|
81
|
+
raise SystemExit(1) from exc
|
|
82
|
+
|
|
83
|
+
depkeeper_ctx = DepKeeperContext()
|
|
84
|
+
depkeeper_ctx.config_path = config or (
|
|
85
|
+
loaded_config.source_path if loaded_config.source_path else None
|
|
86
|
+
)
|
|
87
|
+
depkeeper_ctx.color = color
|
|
88
|
+
depkeeper_ctx.verbose = verbose
|
|
89
|
+
depkeeper_ctx.config = loaded_config
|
|
90
|
+
ctx.obj = depkeeper_ctx
|
|
91
|
+
|
|
92
|
+
# Respect NO_COLOR for downstream libraries
|
|
93
|
+
if color:
|
|
94
|
+
os.environ.pop("NO_COLOR", None)
|
|
95
|
+
else:
|
|
96
|
+
os.environ["NO_COLOR"] = "1"
|
|
97
|
+
|
|
98
|
+
logger.debug("depkeeper v%s", __version__)
|
|
99
|
+
logger.debug("Config path: %s", depkeeper_ctx.config_path)
|
|
100
|
+
if loaded_config.source_path:
|
|
101
|
+
logger.debug("Loaded configuration: %s", loaded_config.to_log_dict())
|
|
102
|
+
logger.debug("Verbosity: %s | Color: %s", verbose, color)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _configure_logging(verbose: int) -> None:
|
|
106
|
+
"""Configure logging level based on verbosity flags."""
|
|
107
|
+
if verbose <= 0:
|
|
108
|
+
level = logging.WARNING
|
|
109
|
+
elif verbose == 1:
|
|
110
|
+
level = logging.INFO
|
|
111
|
+
else:
|
|
112
|
+
level = logging.DEBUG
|
|
113
|
+
|
|
114
|
+
setup_logging(level=level)
|
|
115
|
+
logger.debug("Logging initialized at %s level", logging.getLevelName(level))
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# Register CLI subcommands
|
|
119
|
+
try:
|
|
120
|
+
from depkeeper.commands.check import check
|
|
121
|
+
from depkeeper.commands.update import update
|
|
122
|
+
|
|
123
|
+
cli.add_command(check)
|
|
124
|
+
cli.add_command(update)
|
|
125
|
+
|
|
126
|
+
except ImportError as exc:
|
|
127
|
+
sys.stderr.write(f"FATAL: Failed to import CLI commands: {exc}\n")
|
|
128
|
+
sys.exit(1)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def main() -> int:
|
|
132
|
+
"""Main entry point for the depkeeper CLI.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Exit code:
|
|
136
|
+
0 Success
|
|
137
|
+
1 Unhandled or application error
|
|
138
|
+
2 Usage error (Click)
|
|
139
|
+
130 Interrupted by user (Ctrl+C)
|
|
140
|
+
"""
|
|
141
|
+
try:
|
|
142
|
+
cli(standalone_mode=False)
|
|
143
|
+
return 0
|
|
144
|
+
|
|
145
|
+
except click.ClickException as exc:
|
|
146
|
+
exc.show()
|
|
147
|
+
return exc.exit_code
|
|
148
|
+
|
|
149
|
+
except DepKeeperError as exc:
|
|
150
|
+
print_error(str(exc))
|
|
151
|
+
logger.debug(
|
|
152
|
+
"DepKeeperError details: %s",
|
|
153
|
+
exc.details or "<none>",
|
|
154
|
+
exc_info=True,
|
|
155
|
+
)
|
|
156
|
+
return 1
|
|
157
|
+
|
|
158
|
+
except KeyboardInterrupt:
|
|
159
|
+
print_warning("\nOperation cancelled by user")
|
|
160
|
+
return 130
|
|
161
|
+
|
|
162
|
+
except Exception as exc:
|
|
163
|
+
print_error(f"Unexpected error: {exc}")
|
|
164
|
+
logger.exception("Unhandled exception in CLI")
|
|
165
|
+
return 1
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
if __name__ == "__main__":
|
|
169
|
+
sys.exit(main())
|
|
File without changes
|