flet-cli 0.84.0.dev0__tar.gz → 0.85.0.dev0__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.
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/PKG-INFO +2 -2
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/pyproject.toml +2 -2
- flet_cli-0.85.0.dev0/src/flet_cli/utils/project_dependencies.py +133 -0
- flet_cli-0.85.0.dev0/src/flet_cli/version.py +1 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli.egg-info/PKG-INFO +2 -2
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli.egg-info/SOURCES.txt +2 -1
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli.egg-info/requires.txt +1 -1
- flet_cli-0.85.0.dev0/tests/test_project_dependencies.py +241 -0
- flet_cli-0.84.0.dev0/src/flet_cli/utils/project_dependencies.py +0 -133
- flet_cli-0.84.0.dev0/src/flet_cli/version.py +0 -1
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/README.md +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/setup.cfg +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/__pyinstaller/__init__.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/__pyinstaller/config.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/__pyinstaller/hook-flet.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/__pyinstaller/macos_utils.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/__pyinstaller/rthooks/pyi_rth_localhost_fletd.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/__pyinstaller/utils.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/__pyinstaller/win_utils.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/cli.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/commands/base.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/commands/build.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/commands/build_base.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/commands/create.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/commands/debug.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/commands/devices.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/commands/doctor.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/commands/emulators.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/commands/flutter_base.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/commands/options.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/commands/pack.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/commands/publish.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/commands/run.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/commands/serve.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/utils/android_sdk.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/utils/cli.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/utils/distros.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/utils/flutter.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/utils/hash_stamp.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/utils/jdk.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/utils/merge.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/utils/plist.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/utils/processes.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli/utils/pyproject_toml.py +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli.egg-info/dependency_links.txt +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli.egg-info/entry_points.txt +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/src/flet_cli.egg-info/top_level.txt +0 -0
- {flet_cli-0.84.0.dev0 → flet_cli-0.85.0.dev0}/tests/test_plist.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flet-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.85.0.dev0
|
|
4
4
|
Summary: Flet CLI
|
|
5
5
|
Author-email: "Appveyor Systems Inc." <hello@flet.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -9,7 +9,7 @@ Project-URL: Repository, https://github.com/flet-dev/flet
|
|
|
9
9
|
Project-URL: Documentation, https://flet.dev/docs
|
|
10
10
|
Requires-Python: >=3.10
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
|
-
Requires-Dist: flet==0.
|
|
12
|
+
Requires-Dist: flet==0.85.0.dev0
|
|
13
13
|
Requires-Dist: watchdog>=4.0.0
|
|
14
14
|
Requires-Dist: packaging>=25.0
|
|
15
15
|
Requires-Dist: qrcode>=7.4.2
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "flet-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.85.0.dev0"
|
|
4
4
|
description = "Flet CLI"
|
|
5
5
|
authors = [{ name = "Appveyor Systems Inc.", email = "hello@flet.dev" }]
|
|
6
6
|
license = "Apache-2.0"
|
|
7
7
|
readme = "README.md"
|
|
8
8
|
requires-python = ">=3.10"
|
|
9
9
|
dependencies = [
|
|
10
|
-
"flet==0.
|
|
10
|
+
"flet==0.85.0.dev0",
|
|
11
11
|
"watchdog >=4.0.0",
|
|
12
12
|
"packaging >=25.0",
|
|
13
13
|
"qrcode >=7.4.2",
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""Convert a pyproject.toml file to a requirements.txt file."""
|
|
2
|
+
|
|
3
|
+
# Based on: https://pypi.org/project/toml-to-requirements/
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from typing import Any, Optional
|
|
7
|
+
|
|
8
|
+
from packaging.requirements import Requirement
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _windows_safe(req_str: str) -> str:
|
|
12
|
+
"""Insert a space before bare `<` or `>` so Windows cmd.exe does not
|
|
13
|
+
interpret them as shell redirection when the string is passed via `-r`
|
|
14
|
+
to a `.BAT` subprocess."""
|
|
15
|
+
return re.sub(r"(?<=[^ ])([<>])", r" \1", req_str)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _poetry_version_to_pep440(version: str) -> str:
|
|
19
|
+
"""Convert a Poetry version constraint to PEP 440 syntax.
|
|
20
|
+
|
|
21
|
+
- `^1.2.3` → `>=1.2.3`
|
|
22
|
+
- `~1.2.3` → `~=1.2.3` (`~=` passes through unchanged)
|
|
23
|
+
- `*` → `""` (no constraint)
|
|
24
|
+
- `1.2.3` (bare version) → `==1.2.3`
|
|
25
|
+
- Anything else is returned as-is (already PEP 440).
|
|
26
|
+
"""
|
|
27
|
+
version = version.replace(" ", "")
|
|
28
|
+
if not version or version == "*":
|
|
29
|
+
return ""
|
|
30
|
+
if version.startswith("^"):
|
|
31
|
+
return f">={version[1:]}"
|
|
32
|
+
if version.startswith("~") and not version.startswith("~="):
|
|
33
|
+
return f"~={version[1:]}"
|
|
34
|
+
# Bare version number → pin with ==
|
|
35
|
+
if version[0].isdigit():
|
|
36
|
+
return f"=={version}"
|
|
37
|
+
return version
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _poetry_dep_to_pep508(name: str, value: Any) -> str:
|
|
41
|
+
"""Convert a single Poetry dependency entry to a PEP 508 requirement string."""
|
|
42
|
+
suffix = ""
|
|
43
|
+
|
|
44
|
+
if isinstance(value, dict):
|
|
45
|
+
version = value.get("version")
|
|
46
|
+
if version:
|
|
47
|
+
specifier = _poetry_version_to_pep440(version)
|
|
48
|
+
markers = value.get("markers")
|
|
49
|
+
if markers is not None:
|
|
50
|
+
suffix = f"; {markers}"
|
|
51
|
+
if specifier:
|
|
52
|
+
return f"{name}{specifier}{suffix}"
|
|
53
|
+
return f"{name}{suffix}"
|
|
54
|
+
|
|
55
|
+
git_url = value.get("git")
|
|
56
|
+
if git_url:
|
|
57
|
+
url = f"git+{git_url}" if not git_url.startswith("git@") else git_url
|
|
58
|
+
rev = value.get("branch") or value.get("rev") or value.get("tag")
|
|
59
|
+
if rev:
|
|
60
|
+
url = f"{url}@{rev}"
|
|
61
|
+
subdirectory = value.get("subdirectory")
|
|
62
|
+
if subdirectory:
|
|
63
|
+
url = f"{url}#subdirectory={subdirectory}"
|
|
64
|
+
markers = value.get("markers")
|
|
65
|
+
if markers is not None:
|
|
66
|
+
suffix = f"; {markers}"
|
|
67
|
+
return f"{name} @ {url}{suffix}"
|
|
68
|
+
|
|
69
|
+
path = value.get("path")
|
|
70
|
+
if path:
|
|
71
|
+
return path
|
|
72
|
+
|
|
73
|
+
url = value.get("url")
|
|
74
|
+
if url:
|
|
75
|
+
return url
|
|
76
|
+
|
|
77
|
+
raise ValueError(f"Unsupported dependency specification: {name} = {value}")
|
|
78
|
+
|
|
79
|
+
# String value
|
|
80
|
+
specifier = _poetry_version_to_pep440(value)
|
|
81
|
+
if specifier:
|
|
82
|
+
return f"{name}{specifier}"
|
|
83
|
+
return name
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def get_poetry_dependencies(
|
|
87
|
+
poetry_dependencies: Optional[dict[str, Any]] = None,
|
|
88
|
+
) -> Optional[list[str]]:
|
|
89
|
+
"""
|
|
90
|
+
Convert Poetry dependency declarations into pip-style requirement strings.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
poetry_dependencies: Value from `tool.poetry.dependencies`.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
Sorted requirement strings or `None` when `poetry_dependencies` is `None`.
|
|
97
|
+
"""
|
|
98
|
+
if poetry_dependencies is None:
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
dependencies: set[str] = {
|
|
102
|
+
_windows_safe(_poetry_dep_to_pep508(dep, ver))
|
|
103
|
+
for dep, ver in poetry_dependencies.items()
|
|
104
|
+
if dep != "python"
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return sorted(dependencies)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def get_project_dependencies(
|
|
111
|
+
project_dependencies: Optional[list[str]] = None,
|
|
112
|
+
) -> Optional[list[str]]:
|
|
113
|
+
"""
|
|
114
|
+
Normalize PEP 621 `project.dependencies` into a sorted unique list.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
project_dependencies: Value from `project.dependencies`.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Sorted dependency strings, or `None` when input is `None`.
|
|
121
|
+
"""
|
|
122
|
+
if project_dependencies is None:
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
dependencies: set[str] = set()
|
|
126
|
+
for dep in project_dependencies:
|
|
127
|
+
try:
|
|
128
|
+
req = Requirement(dep)
|
|
129
|
+
dependencies.add(_windows_safe(str(req)))
|
|
130
|
+
except Exception:
|
|
131
|
+
dependencies.add(_windows_safe(dep))
|
|
132
|
+
|
|
133
|
+
return sorted(dependencies)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "0.85.0.dev0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flet-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.85.0.dev0
|
|
4
4
|
Summary: Flet CLI
|
|
5
5
|
Author-email: "Appveyor Systems Inc." <hello@flet.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -9,7 +9,7 @@ Project-URL: Repository, https://github.com/flet-dev/flet
|
|
|
9
9
|
Project-URL: Documentation, https://flet.dev/docs
|
|
10
10
|
Requires-Python: >=3.10
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
|
-
Requires-Dist: flet==0.
|
|
12
|
+
Requires-Dist: flet==0.85.0.dev0
|
|
13
13
|
Requires-Dist: watchdog>=4.0.0
|
|
14
14
|
Requires-Dist: packaging>=25.0
|
|
15
15
|
Requires-Dist: qrcode>=7.4.2
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""Tests for project_dependencies module."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from flet_cli.utils.project_dependencies import (
|
|
6
|
+
get_poetry_dependencies,
|
|
7
|
+
get_project_dependencies,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
# ---------------------------------------------------------------------------
|
|
11
|
+
# get_poetry_dependencies
|
|
12
|
+
# ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestGetPoetryDependencies:
|
|
16
|
+
def test_none_returns_none(self):
|
|
17
|
+
assert get_poetry_dependencies(None) is None
|
|
18
|
+
|
|
19
|
+
def test_empty_dict(self):
|
|
20
|
+
assert get_poetry_dependencies({}) == []
|
|
21
|
+
|
|
22
|
+
def test_python_excluded(self):
|
|
23
|
+
assert get_poetry_dependencies({"python": "^3.10"}) == []
|
|
24
|
+
|
|
25
|
+
def test_exact_version(self):
|
|
26
|
+
result = get_poetry_dependencies({"packaging": "26.0"})
|
|
27
|
+
assert result == ["packaging==26.0"]
|
|
28
|
+
|
|
29
|
+
def test_caret(self):
|
|
30
|
+
result = get_poetry_dependencies({"urllib3": "^2.6.0"})
|
|
31
|
+
assert result == ["urllib3 >=2.6.0"]
|
|
32
|
+
|
|
33
|
+
def test_tilde(self):
|
|
34
|
+
result = get_poetry_dependencies({"setuptools": "~82.0.0"})
|
|
35
|
+
assert result == ["setuptools~=82.0.0"]
|
|
36
|
+
|
|
37
|
+
def test_tilde_equals_passthrough(self):
|
|
38
|
+
result = get_poetry_dependencies({"setuptools": "~=82.0.0"})
|
|
39
|
+
assert result == ["setuptools~=82.0.0"]
|
|
40
|
+
|
|
41
|
+
def test_wildcard(self):
|
|
42
|
+
result = get_poetry_dependencies({"boto3": "*"})
|
|
43
|
+
assert result == ["boto3"]
|
|
44
|
+
|
|
45
|
+
def test_less_than(self):
|
|
46
|
+
result = get_poetry_dependencies({"chardet": "<6"})
|
|
47
|
+
assert result == ["chardet <6"]
|
|
48
|
+
|
|
49
|
+
def test_less_than_equal(self):
|
|
50
|
+
result = get_poetry_dependencies({"requests": "<=2.32.4"})
|
|
51
|
+
assert result == ["requests <=2.32.4"]
|
|
52
|
+
|
|
53
|
+
def test_greater_than_equal(self):
|
|
54
|
+
result = get_poetry_dependencies({"certifi": ">=2026.1.4"})
|
|
55
|
+
assert result == ["certifi >=2026.1.4"]
|
|
56
|
+
|
|
57
|
+
def test_range_constraint(self):
|
|
58
|
+
result = get_poetry_dependencies({"pydantic": ">=2.9.0,<3.0.0"})
|
|
59
|
+
# _windows_safe ensures spaces before < and >
|
|
60
|
+
assert "pydantic" in result[0]
|
|
61
|
+
assert " >=" in result[0]
|
|
62
|
+
assert " <" in result[0]
|
|
63
|
+
|
|
64
|
+
def test_not_equal_combined(self):
|
|
65
|
+
result = get_poetry_dependencies({"pandas": ">=2.3,!=2.3.3"})
|
|
66
|
+
assert "pandas" in result[0]
|
|
67
|
+
assert " >=" in result[0]
|
|
68
|
+
assert "!=" in result[0]
|
|
69
|
+
|
|
70
|
+
def test_spaces_in_version_stripped(self):
|
|
71
|
+
result = get_poetry_dependencies({"chardet": " < 6 "})
|
|
72
|
+
assert result == ["chardet <6"]
|
|
73
|
+
|
|
74
|
+
def test_dict_version(self):
|
|
75
|
+
result = get_poetry_dependencies(
|
|
76
|
+
{"scipy": {"version": "^1.16", "optional": True}}
|
|
77
|
+
)
|
|
78
|
+
assert result == ["scipy >=1.16"]
|
|
79
|
+
|
|
80
|
+
def test_dict_version_with_markers(self):
|
|
81
|
+
result = get_poetry_dependencies(
|
|
82
|
+
{"pywin32": {"version": ">=310", "markers": "sys_platform == 'win32'"}}
|
|
83
|
+
)
|
|
84
|
+
assert result == ["pywin32 >=310; sys_platform == 'win32'"]
|
|
85
|
+
|
|
86
|
+
def test_dict_git(self):
|
|
87
|
+
result = get_poetry_dependencies(
|
|
88
|
+
{"numpy": {"git": "https://github.com/numpy/numpy.git", "branch": "main"}}
|
|
89
|
+
)
|
|
90
|
+
assert result == ["numpy @ git+https://github.com/numpy/numpy.git@main"]
|
|
91
|
+
|
|
92
|
+
def test_dict_git_ssh(self):
|
|
93
|
+
result = get_poetry_dependencies(
|
|
94
|
+
{"mylib": {"git": "git@github.com:org/repo.git", "tag": "v1.0"}}
|
|
95
|
+
)
|
|
96
|
+
assert result == ["mylib @ git@github.com:org/repo.git@v1.0"]
|
|
97
|
+
|
|
98
|
+
def test_dict_git_subdirectory(self):
|
|
99
|
+
result = get_poetry_dependencies(
|
|
100
|
+
{
|
|
101
|
+
"mylib": {
|
|
102
|
+
"git": "https://github.com/org/mono.git",
|
|
103
|
+
"branch": "main",
|
|
104
|
+
"subdirectory": "packages/mylib",
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
assert "subdirectory=packages/mylib" in result[0]
|
|
109
|
+
|
|
110
|
+
def test_dict_path(self):
|
|
111
|
+
result = get_poetry_dependencies({"mylib": {"path": "../mylib"}})
|
|
112
|
+
assert result == ["../mylib"]
|
|
113
|
+
|
|
114
|
+
def test_dict_url(self):
|
|
115
|
+
result = get_poetry_dependencies(
|
|
116
|
+
{"mylib": {"url": "https://example.com/mylib.tar.gz"}}
|
|
117
|
+
)
|
|
118
|
+
assert result == ["https://example.com/mylib.tar.gz"]
|
|
119
|
+
|
|
120
|
+
def test_dict_unsupported_raises(self):
|
|
121
|
+
with pytest.raises(ValueError, match="Unsupported"):
|
|
122
|
+
get_poetry_dependencies({"bad": {"extras": ["foo"]}})
|
|
123
|
+
|
|
124
|
+
def test_sorted_output(self):
|
|
125
|
+
result = get_poetry_dependencies({"zlib": "1.0", "aiohttp": "3.0"})
|
|
126
|
+
assert result == ["aiohttp==3.0", "zlib==1.0"]
|
|
127
|
+
|
|
128
|
+
def test_multiple_deps(self):
|
|
129
|
+
deps = {
|
|
130
|
+
"python": "^3.10",
|
|
131
|
+
"boto3": "*",
|
|
132
|
+
"chardet": "<6",
|
|
133
|
+
"packaging": "26.0",
|
|
134
|
+
}
|
|
135
|
+
result = get_poetry_dependencies(deps)
|
|
136
|
+
assert "boto3" in result
|
|
137
|
+
assert any("chardet" in r for r in result)
|
|
138
|
+
assert any("packaging" in r for r in result)
|
|
139
|
+
# python should be excluded
|
|
140
|
+
assert not any("python" in r for r in result)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# ---------------------------------------------------------------------------
|
|
144
|
+
# get_project_dependencies
|
|
145
|
+
# ---------------------------------------------------------------------------
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class TestGetProjectDependencies:
|
|
149
|
+
def test_none_returns_none(self):
|
|
150
|
+
assert get_project_dependencies(None) is None
|
|
151
|
+
|
|
152
|
+
def test_empty_list(self):
|
|
153
|
+
assert get_project_dependencies([]) == []
|
|
154
|
+
|
|
155
|
+
def test_simple_dep(self):
|
|
156
|
+
result = get_project_dependencies(["boto3"])
|
|
157
|
+
assert result == ["boto3"]
|
|
158
|
+
|
|
159
|
+
def test_exact_version(self):
|
|
160
|
+
result = get_project_dependencies(["packaging==26.0"])
|
|
161
|
+
assert result == ["packaging==26.0"]
|
|
162
|
+
|
|
163
|
+
def test_gte(self):
|
|
164
|
+
result = get_project_dependencies(["flet>=0.82.0"])
|
|
165
|
+
assert result == ["flet >=0.82.0"]
|
|
166
|
+
|
|
167
|
+
def test_lt_gets_space(self):
|
|
168
|
+
result = get_project_dependencies(["chardet<6"])
|
|
169
|
+
assert result == ["chardet <6"]
|
|
170
|
+
|
|
171
|
+
def test_lte_gets_space(self):
|
|
172
|
+
result = get_project_dependencies(["requests<=2.32.4"])
|
|
173
|
+
assert result == ["requests <=2.32.4"]
|
|
174
|
+
|
|
175
|
+
def test_gt_gets_space(self):
|
|
176
|
+
result = get_project_dependencies(["chardet>3"])
|
|
177
|
+
assert result == ["chardet >3"]
|
|
178
|
+
|
|
179
|
+
def test_combined_constraints(self):
|
|
180
|
+
result = get_project_dependencies(["pydantic>=2.9.0,<3.0.0"])
|
|
181
|
+
assert len(result) == 1
|
|
182
|
+
dep = result[0]
|
|
183
|
+
assert "pydantic" in dep
|
|
184
|
+
assert " <" in dep or " >" in dep
|
|
185
|
+
|
|
186
|
+
def test_not_equal(self):
|
|
187
|
+
result = get_project_dependencies(["pandas>=2.3,!=2.3.3"])
|
|
188
|
+
assert len(result) == 1
|
|
189
|
+
assert " >=" in result[0]
|
|
190
|
+
assert "!=" in result[0]
|
|
191
|
+
|
|
192
|
+
def test_compatible_release(self):
|
|
193
|
+
result = get_project_dependencies(["setuptools~=82.0.0"])
|
|
194
|
+
assert result == ["setuptools~=82.0.0"]
|
|
195
|
+
|
|
196
|
+
def test_extras(self):
|
|
197
|
+
result = get_project_dependencies(["uvicorn[standard]>=0.42.0"])
|
|
198
|
+
dep = result[0]
|
|
199
|
+
assert "uvicorn" in dep
|
|
200
|
+
assert "[standard]" in dep
|
|
201
|
+
assert " >=" in dep
|
|
202
|
+
|
|
203
|
+
def test_markers_preserved(self):
|
|
204
|
+
result = get_project_dependencies(['pywin32>=310; sys_platform == "win32"'])
|
|
205
|
+
assert len(result) == 1
|
|
206
|
+
assert "sys_platform" in result[0]
|
|
207
|
+
assert "win32" in result[0]
|
|
208
|
+
assert " >=" in result[0]
|
|
209
|
+
|
|
210
|
+
def test_url_dep(self):
|
|
211
|
+
result = get_project_dependencies(
|
|
212
|
+
["numpy @ git+https://github.com/numpy/numpy.git@main"]
|
|
213
|
+
)
|
|
214
|
+
assert len(result) == 1
|
|
215
|
+
assert "git+https://github.com/numpy/numpy.git@main" in result[0]
|
|
216
|
+
|
|
217
|
+
def test_extra_spaces_normalized(self):
|
|
218
|
+
result = get_project_dependencies(["chardet < 6"])
|
|
219
|
+
assert result == ["chardet <6"]
|
|
220
|
+
|
|
221
|
+
def test_sorted_and_deduplicated(self):
|
|
222
|
+
result = get_project_dependencies(["zlib>=1.0", "aiohttp>=3.0", "zlib>=1.0"])
|
|
223
|
+
assert result[0].startswith("aiohttp")
|
|
224
|
+
assert len(result) == 2
|
|
225
|
+
|
|
226
|
+
def test_downstream_compatible(self):
|
|
227
|
+
"""Output must be parseable by packaging.requirements.Requirement,
|
|
228
|
+
since build_base.py does Requirement(dep).name on our output."""
|
|
229
|
+
from packaging.requirements import Requirement
|
|
230
|
+
|
|
231
|
+
deps = [
|
|
232
|
+
"flet>=0.82.0",
|
|
233
|
+
"chardet<6",
|
|
234
|
+
"pydantic>=2.9.0,<3.0.0",
|
|
235
|
+
'pywin32>=310; sys_platform == "win32"',
|
|
236
|
+
"uvicorn[standard]>=0.42.0",
|
|
237
|
+
]
|
|
238
|
+
result = get_project_dependencies(deps)
|
|
239
|
+
for dep in result:
|
|
240
|
+
req = Requirement(dep)
|
|
241
|
+
assert req.name # must parse without error
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
"""Convert a pyproject.toml file to a requirements.txt file."""
|
|
2
|
-
|
|
3
|
-
# Based on: https://pypi.org/project/toml-to-requirements/
|
|
4
|
-
|
|
5
|
-
from typing import Any, Optional
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def get_poetry_dependencies(
|
|
9
|
-
poetry_dependencies: Optional[dict[str, Any]] = None,
|
|
10
|
-
) -> Optional[list[str]]:
|
|
11
|
-
"""
|
|
12
|
-
Convert Poetry dependency declarations into pip-style requirement strings.
|
|
13
|
-
|
|
14
|
-
Args:
|
|
15
|
-
poetry_dependencies: Value from `tool.poetry.dependencies`.
|
|
16
|
-
|
|
17
|
-
Returns:
|
|
18
|
-
Sorted requirement strings or `None` when `poetry_dependencies` is `None`.
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
if poetry_dependencies is None:
|
|
22
|
-
return None
|
|
23
|
-
|
|
24
|
-
def format_dependency_version(dependency_name: str, dependency_value: Any):
|
|
25
|
-
"""
|
|
26
|
-
Format a single Poetry dependency entry as a requirement specifier.
|
|
27
|
-
|
|
28
|
-
Supports version constraints, git dependencies (including branch/rev/tag
|
|
29
|
-
and subdirectory), path/url dependencies, and optional environment markers.
|
|
30
|
-
|
|
31
|
-
Args:
|
|
32
|
-
dependency_name: Dependency key in Poetry configuration.
|
|
33
|
-
dependency_value: String or mapping that describes the dependency.
|
|
34
|
-
|
|
35
|
-
Returns:
|
|
36
|
-
A requirement string consumable by pip-style tooling.
|
|
37
|
-
|
|
38
|
-
Raises:
|
|
39
|
-
ValueError: If the dependency mapping uses an unsupported shape.
|
|
40
|
-
"""
|
|
41
|
-
|
|
42
|
-
sep = "@"
|
|
43
|
-
value = ""
|
|
44
|
-
suffix = ""
|
|
45
|
-
|
|
46
|
-
if isinstance(dependency_value, dict):
|
|
47
|
-
version = dependency_value.get("version")
|
|
48
|
-
if version:
|
|
49
|
-
sep = "=="
|
|
50
|
-
value = version
|
|
51
|
-
else:
|
|
52
|
-
git_url = dependency_value.get("git")
|
|
53
|
-
if git_url:
|
|
54
|
-
value = (
|
|
55
|
-
f"git+{git_url}" if not git_url.startswith("git@") else git_url
|
|
56
|
-
)
|
|
57
|
-
rev = (
|
|
58
|
-
dependency_value.get("branch")
|
|
59
|
-
or dependency_value.get("rev")
|
|
60
|
-
or dependency_value.get("tag")
|
|
61
|
-
)
|
|
62
|
-
if rev:
|
|
63
|
-
value = f"{value}@{rev}"
|
|
64
|
-
subdirectory = dependency_value.get("subdirectory")
|
|
65
|
-
if subdirectory:
|
|
66
|
-
value = f"{value}#subdirectory={subdirectory}"
|
|
67
|
-
else:
|
|
68
|
-
path = dependency_value.get("path")
|
|
69
|
-
if path:
|
|
70
|
-
value = path
|
|
71
|
-
dependency_name = ""
|
|
72
|
-
sep = ""
|
|
73
|
-
else:
|
|
74
|
-
url = dependency_value.get("url")
|
|
75
|
-
if url:
|
|
76
|
-
value = url
|
|
77
|
-
dependency_name = ""
|
|
78
|
-
sep = ""
|
|
79
|
-
else:
|
|
80
|
-
raise ValueError(
|
|
81
|
-
"Unsupported dependency specification: "
|
|
82
|
-
f"{dependency_name} = {dependency_value}"
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
# markers - common for all
|
|
86
|
-
markers = dependency_value.get("markers")
|
|
87
|
-
if markers is not None:
|
|
88
|
-
suffix = f";{markers}"
|
|
89
|
-
else:
|
|
90
|
-
value = dependency_value
|
|
91
|
-
sep = "=="
|
|
92
|
-
|
|
93
|
-
if value.startswith("^"):
|
|
94
|
-
sep = ">="
|
|
95
|
-
value = value[1:]
|
|
96
|
-
elif value.startswith("~"):
|
|
97
|
-
sep = "~="
|
|
98
|
-
value = value[1:]
|
|
99
|
-
return f"{dependency_name}~={value[1:]}"
|
|
100
|
-
elif "<" in value or ">" in value:
|
|
101
|
-
sep = ""
|
|
102
|
-
value = value.replace(" ", "")
|
|
103
|
-
|
|
104
|
-
return f"{dependency_name}{sep}{value}{suffix}"
|
|
105
|
-
|
|
106
|
-
dependencies: set[str] = {
|
|
107
|
-
format_dependency_version(dependency, version)
|
|
108
|
-
for dependency, version in poetry_dependencies.items()
|
|
109
|
-
if dependency != "python"
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return sorted(dependencies)
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def get_project_dependencies(
|
|
116
|
-
project_dependencies: Optional[dict[str, Any]] = None,
|
|
117
|
-
) -> Optional[list[str]]:
|
|
118
|
-
"""
|
|
119
|
-
Normalize PEP 621 `project.dependencies` into a sorted unique list.
|
|
120
|
-
|
|
121
|
-
Args:
|
|
122
|
-
project_dependencies: Value from `project.dependencies`.
|
|
123
|
-
|
|
124
|
-
Returns:
|
|
125
|
-
Sorted dependency strings, or `None` when input is `None`.
|
|
126
|
-
"""
|
|
127
|
-
|
|
128
|
-
if project_dependencies is None:
|
|
129
|
-
return None
|
|
130
|
-
|
|
131
|
-
dependencies = set(project_dependencies)
|
|
132
|
-
|
|
133
|
-
return sorted(dependencies)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
version = "0.84.0.dev0"
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|