qgis-plugin-dev-tools 0.6.2__tar.gz → 0.7.0__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.
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/CHANGELOG.md +6 -0
- {qgis-plugin-dev-tools-0.6.2/src/qgis_plugin_dev_tools.egg-info → qgis_plugin_dev_tools-0.7.0}/PKG-INFO +16 -1
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/README.md +9 -0
- qgis_plugin_dev_tools-0.7.0/pyproject.toml +71 -0
- qgis_plugin_dev_tools-0.7.0/setup.py +3 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/__init__.py +1 -1
- qgis_plugin_dev_tools-0.7.0/src/qgis_plugin_dev_tools/build/packaging.py +192 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/build/rewrite_imports.py +3 -4
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/cli/__init__.py +8 -7
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/config/__init__.py +9 -6
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/config/dotenv.py +8 -8
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/config/pyproject.py +4 -3
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/publish/__init__.py +5 -3
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/start/__init__.py +0 -2
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/start/bootstrap/__init__.py +3 -3
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/start/bootstrap/template.py +27 -29
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/start/config.py +5 -5
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/start/daemon_server.py +3 -2
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/utils/distributions.py +33 -11
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0/src/qgis_plugin_dev_tools.egg-info}/PKG-INFO +16 -1
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/test/test_build.py +19 -18
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/test/test_read_distributions.py +4 -4
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/test/test_read_dotenv.py +26 -12
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/test/test_read_pyproject.py +20 -11
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/test/test_rewrite_imports.py +1 -4
- qgis-plugin-dev-tools-0.6.2/pyproject.toml +0 -13
- qgis-plugin-dev-tools-0.6.2/setup.py +0 -3
- qgis-plugin-dev-tools-0.6.2/src/qgis_plugin_dev_tools/build/packaging.py +0 -202
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/LICENSE +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/MANIFEST.in +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/setup.cfg +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/__main__.py +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/build/__init__.py +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/build/changelog_parser.py +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/build/distribution.py +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/build/metadata.py +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/py.typed +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/start/launch.py +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools/utils/__init__.py +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools.egg-info/SOURCES.txt +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools.egg-info/dependency_links.txt +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools.egg-info/entry_points.txt +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools.egg-info/requires.txt +0 -0
- {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.7.0}/src/qgis_plugin_dev_tools.egg-info/top_level.txt +0 -0
|
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.7.0] - 2024-05-21
|
|
8
|
+
|
|
9
|
+
- Fix: Bundle contents by parsing pep-compliant distribution file catalog instead of possibly missing tool-specific top-level.txt
|
|
10
|
+
- Feat: Allow disabling auto-loaded entrypoint plugins
|
|
11
|
+
|
|
7
12
|
## [0.6.2] - 2023-09-27
|
|
8
13
|
|
|
9
14
|
- Fix: Fix issues with bundling requirements of the requirements recursively
|
|
@@ -66,3 +71,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
|
66
71
|
[0.6.0]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.6.0
|
|
67
72
|
[0.6.1]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.6.1
|
|
68
73
|
[0.6.2]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.6.2
|
|
74
|
+
[0.7.0]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.7.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: qgis-plugin-dev-tools
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: QGIS plugin development and packaging tools, which make managing runtime dependencies easy.
|
|
5
5
|
Home-page: https://github.com/nlsfi/qgis-plugin-dev-tools
|
|
6
6
|
Author: National Land Survey of Finland
|
|
@@ -135,6 +135,15 @@ Development mode also enables using and developing multiple plugins easily if ce
|
|
|
135
135
|
|
|
136
136
|
Extra plugins are loaded on launch and reloaded together with the main plugin if [Plugin Reloader] is used.
|
|
137
137
|
|
|
138
|
+
You can disable plugin auto-load by using `pyproject.toml` configuration (for example when using a dependency, that also provides a plugin entrypoint):
|
|
139
|
+
|
|
140
|
+
```toml
|
|
141
|
+
[tool.qgis_plugin_dev_tools]
|
|
142
|
+
disabled_extra_plugins = [
|
|
143
|
+
"unwanted_plugin_package_name",
|
|
144
|
+
]
|
|
145
|
+
```
|
|
146
|
+
|
|
138
147
|
## Development of qgis-plugin-dev-tools
|
|
139
148
|
|
|
140
149
|
See [development readme](./DEVELOPMENT.md).
|
|
@@ -156,6 +165,11 @@ All notable changes to this project will be documented in this file.
|
|
|
156
165
|
|
|
157
166
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
158
167
|
|
|
168
|
+
## [0.7.0] - 2024-05-21
|
|
169
|
+
|
|
170
|
+
- Fix: Bundle contents by parsing pep-compliant distribution file catalog instead of possibly missing tool-specific top-level.txt
|
|
171
|
+
- Feat: Allow disabling auto-loaded entrypoint plugins
|
|
172
|
+
|
|
159
173
|
## [0.6.2] - 2023-09-27
|
|
160
174
|
|
|
161
175
|
- Fix: Fix issues with bundling requirements of the requirements recursively
|
|
@@ -218,3 +232,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
|
218
232
|
[0.6.0]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.6.0
|
|
219
233
|
[0.6.1]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.6.1
|
|
220
234
|
[0.6.2]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.6.2
|
|
235
|
+
[0.7.0]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.7.0
|
|
@@ -105,6 +105,15 @@ Development mode also enables using and developing multiple plugins easily if ce
|
|
|
105
105
|
|
|
106
106
|
Extra plugins are loaded on launch and reloaded together with the main plugin if [Plugin Reloader] is used.
|
|
107
107
|
|
|
108
|
+
You can disable plugin auto-load by using `pyproject.toml` configuration (for example when using a dependency, that also provides a plugin entrypoint):
|
|
109
|
+
|
|
110
|
+
```toml
|
|
111
|
+
[tool.qgis_plugin_dev_tools]
|
|
112
|
+
disabled_extra_plugins = [
|
|
113
|
+
"unwanted_plugin_package_name",
|
|
114
|
+
]
|
|
115
|
+
```
|
|
116
|
+
|
|
108
117
|
## Development of qgis-plugin-dev-tools
|
|
109
118
|
|
|
110
119
|
See [development readme](./DEVELOPMENT.md).
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
[tool.ruff]
|
|
2
|
+
ignore = [
|
|
3
|
+
"ANN101", # Missing type annotation for self in method
|
|
4
|
+
]
|
|
5
|
+
line-length = 88
|
|
6
|
+
|
|
7
|
+
# List of all rules https://docs.astral.sh/ruff/rules/
|
|
8
|
+
select = [
|
|
9
|
+
"ANN", # flake8-annotations
|
|
10
|
+
"B", # flake8-bugbear
|
|
11
|
+
"C", # flake8-comprehensions
|
|
12
|
+
"C90", # flake8, mccabe
|
|
13
|
+
"E", # flake8, pycodestyle
|
|
14
|
+
"F", # flake8, Pyflakes
|
|
15
|
+
"I", # isort
|
|
16
|
+
"INP", # flake8-no-pep420
|
|
17
|
+
"N", # pep8-naming
|
|
18
|
+
"PIE", # flake8-pie
|
|
19
|
+
"PGH", # pygrep-hooks
|
|
20
|
+
"PL", # pylint
|
|
21
|
+
"PT", # flake8-pytest-style
|
|
22
|
+
"RUF", # Ruff-specific rules
|
|
23
|
+
"SIM", # flake8-simplify
|
|
24
|
+
"T", # flake8-print
|
|
25
|
+
"ICN", # flake8-import-conventions
|
|
26
|
+
"TCH", # flake8-type-checking
|
|
27
|
+
"TID", # flake8-tidy-imports
|
|
28
|
+
"W", # flake8, pycodestyle
|
|
29
|
+
"UP", # pyupgrade
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
# Avoiding flagging (and removing) `SC200` from any `# noqa`
|
|
33
|
+
# directives, despite Ruff's lack of support for `flake8-spellcheck`.
|
|
34
|
+
external = ["SC200"]
|
|
35
|
+
|
|
36
|
+
target-version = "py39"
|
|
37
|
+
|
|
38
|
+
[tool.ruff.flake8-tidy-imports]
|
|
39
|
+
ban-relative-imports = "all"
|
|
40
|
+
|
|
41
|
+
[tool.ruff.per-file-ignores]
|
|
42
|
+
"test*" = [
|
|
43
|
+
"INP001",
|
|
44
|
+
"ANN201", # Missing return type annotation for public function
|
|
45
|
+
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
|
|
46
|
+
"PLR2004", # Magic value used in comparison, consider replacing {value} with a constant variable
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
[tool.flake8]
|
|
51
|
+
max-line-length = 88
|
|
52
|
+
spellcheck-targets = "names"
|
|
53
|
+
dictionaries = "en_US,python,technical"
|
|
54
|
+
extend-ignore = [
|
|
55
|
+
"E203", # whitespace before ':'
|
|
56
|
+
"E501", # line length (checked by ruff now, possible mismatches)
|
|
57
|
+
]
|
|
58
|
+
per-file-ignores = [
|
|
59
|
+
"test/*:INP001,SC200",
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
[tool.mypy]
|
|
63
|
+
follow_imports = "normal"
|
|
64
|
+
show_column_numbers = true
|
|
65
|
+
|
|
66
|
+
[tool.pytest.ini_options]
|
|
67
|
+
minversion = "6.0"
|
|
68
|
+
|
|
69
|
+
[build-system]
|
|
70
|
+
requires = ["setuptools"]
|
|
71
|
+
build-backend = "setuptools.build_meta"
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Copyright (C) 2022 National Land Survey of Finland
|
|
2
|
+
# (https://www.maanmittauslaitos.fi/en).
|
|
3
|
+
#
|
|
4
|
+
#
|
|
5
|
+
# This file is part of qgis-plugin-dev-tools.
|
|
6
|
+
#
|
|
7
|
+
# qgis-plugin-dev-tools is free software: you can redistribute it and/or
|
|
8
|
+
# modify it under the terms of the GNU General Public License as published
|
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
# (at your option) any later version.
|
|
11
|
+
#
|
|
12
|
+
# qgis-plugin-dev-tools is distributed in the hope that it will be
|
|
13
|
+
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
14
|
+
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
# GNU General Public License for more details.
|
|
16
|
+
#
|
|
17
|
+
# You should have received a copy of the GNU General Public License
|
|
18
|
+
# along with qgis-plugin-dev-tools. If not, see <https://www.gnu.org/licenses/>.
|
|
19
|
+
|
|
20
|
+
import logging
|
|
21
|
+
import shutil
|
|
22
|
+
import sys
|
|
23
|
+
from importlib_metadata import Distribution
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
from qgis_plugin_dev_tools.build.rewrite_imports import (
|
|
27
|
+
rewrite_imports_in_source_file,
|
|
28
|
+
insert_as_first_import,
|
|
29
|
+
)
|
|
30
|
+
from qgis_plugin_dev_tools.config import DevToolsConfig
|
|
31
|
+
from qgis_plugin_dev_tools.utils.distributions import get_distribution_top_level_names
|
|
32
|
+
|
|
33
|
+
IGNORED_FILES = shutil.ignore_patterns("__pycache__", "*.pyc", "*.pyi")
|
|
34
|
+
LOGGER = logging.getLogger(__name__)
|
|
35
|
+
|
|
36
|
+
VENDOR_PATH_APPEND_SCRIPT = """
|
|
37
|
+
import sys
|
|
38
|
+
from pathlib import Path
|
|
39
|
+
|
|
40
|
+
sys.path.append(Path(__file__).parent.resolve().as_posix())
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def copy_plugin_code(
|
|
45
|
+
dev_tools_config: DevToolsConfig, build_directory_path: Path
|
|
46
|
+
) -> None:
|
|
47
|
+
LOGGER.debug(
|
|
48
|
+
"copying %s to build directory",
|
|
49
|
+
dev_tools_config.plugin_package_path.resolve(),
|
|
50
|
+
)
|
|
51
|
+
shutil.copytree(
|
|
52
|
+
src=dev_tools_config.plugin_package_path,
|
|
53
|
+
dst=build_directory_path / dev_tools_config.plugin_package_name,
|
|
54
|
+
ignore=IGNORED_FILES,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def copy_runtime_requirements(
|
|
59
|
+
dev_tools_config: DevToolsConfig,
|
|
60
|
+
build_directory_path: Path,
|
|
61
|
+
) -> None:
|
|
62
|
+
if len(dev_tools_config.runtime_distributions) == 0:
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
plugin_package_name = dev_tools_config.plugin_package_name
|
|
66
|
+
vendor_path = build_directory_path / plugin_package_name / "_vendor"
|
|
67
|
+
|
|
68
|
+
vendor_path.mkdir(parents=True)
|
|
69
|
+
vendor_init_file = vendor_path / "__init__.py"
|
|
70
|
+
vendor_init_file.touch()
|
|
71
|
+
|
|
72
|
+
if dev_tools_config.append_distributions_to_path:
|
|
73
|
+
vendor_init_file.write_text(VENDOR_PATH_APPEND_SCRIPT)
|
|
74
|
+
insert_as_first_import(
|
|
75
|
+
build_directory_path / plugin_package_name / "__init__.py",
|
|
76
|
+
f"{plugin_package_name}._vendor",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
vendored_runtime_top_level_names: list[str] = []
|
|
80
|
+
|
|
81
|
+
for vendored_distribution in (
|
|
82
|
+
dev_tools_config.runtime_distributions
|
|
83
|
+
+ dev_tools_config.extra_runtime_distributions
|
|
84
|
+
):
|
|
85
|
+
# if a recursively found dependency is provided by system packages,
|
|
86
|
+
# assume it does not have to be bundled (this is possibly dangerous,
|
|
87
|
+
# if build is made on a different system package set than runtime)
|
|
88
|
+
if (
|
|
89
|
+
vendored_distribution in dev_tools_config.extra_runtime_distributions
|
|
90
|
+
and Path(
|
|
91
|
+
vendored_distribution._path, # type: ignore
|
|
92
|
+
).is_relative_to(Path(sys.base_prefix))
|
|
93
|
+
):
|
|
94
|
+
LOGGER.warning(
|
|
95
|
+
"skipping recursively found runtime requirement %s "
|
|
96
|
+
"because it is included in system packages",
|
|
97
|
+
vendored_distribution.name,
|
|
98
|
+
)
|
|
99
|
+
continue
|
|
100
|
+
|
|
101
|
+
# don't vendor plugin package, but allow to vendor other packages provided
|
|
102
|
+
# from plugin distribution. if "-e ." installs "my-plugin-name" distribution
|
|
103
|
+
# containing my_plugin & my_util_package top level packages, bundling is only
|
|
104
|
+
# needed for my_util_package
|
|
105
|
+
dist_top_level_names = get_distribution_top_level_names(vendored_distribution)
|
|
106
|
+
dist_top_level_names.discard(plugin_package_name)
|
|
107
|
+
|
|
108
|
+
LOGGER.debug(
|
|
109
|
+
"bundling runtime requirement %s with top level names %s",
|
|
110
|
+
vendored_distribution.name,
|
|
111
|
+
dist_top_level_names,
|
|
112
|
+
)
|
|
113
|
+
_copy_distribution_files(
|
|
114
|
+
vendored_distribution,
|
|
115
|
+
dist_top_level_names,
|
|
116
|
+
vendor_path,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
vendored_runtime_top_level_names.extend(dist_top_level_names)
|
|
120
|
+
|
|
121
|
+
if not dev_tools_config.append_distributions_to_path:
|
|
122
|
+
for package_name in vendored_runtime_top_level_names:
|
|
123
|
+
LOGGER.debug("rewriting imports for %s", package_name)
|
|
124
|
+
|
|
125
|
+
py_files = list((build_directory_path / plugin_package_name).rglob("*.py"))
|
|
126
|
+
ui_files = list((build_directory_path / plugin_package_name).rglob("*.ui"))
|
|
127
|
+
|
|
128
|
+
for source_file in py_files + ui_files:
|
|
129
|
+
rewrite_imports_in_source_file(
|
|
130
|
+
source_file,
|
|
131
|
+
rewritten_package_name=package_name,
|
|
132
|
+
container_package_name=f"{plugin_package_name}._vendor",
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _copy_distribution_files(
|
|
137
|
+
distribution: Distribution,
|
|
138
|
+
top_level_names: set[str],
|
|
139
|
+
target_root_path: Path,
|
|
140
|
+
) -> None:
|
|
141
|
+
if (file_paths := distribution.files) is None:
|
|
142
|
+
LOGGER.warning("could not resolve %s contents to bundle", distribution.name)
|
|
143
|
+
return
|
|
144
|
+
|
|
145
|
+
# bundle metadata directory first
|
|
146
|
+
distribution_metadata_path = Path(distribution._path) # type: ignore
|
|
147
|
+
LOGGER.debug(
|
|
148
|
+
"copying %s to build directory",
|
|
149
|
+
distribution_metadata_path.resolve(),
|
|
150
|
+
)
|
|
151
|
+
shutil.copytree(
|
|
152
|
+
src=distribution_metadata_path,
|
|
153
|
+
dst=target_root_path / distribution_metadata_path.name,
|
|
154
|
+
ignore=IGNORED_FILES,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
directories_to_bundle = {
|
|
158
|
+
top_directory_name
|
|
159
|
+
for file_path in file_paths
|
|
160
|
+
if len(file_path.parts) > 1
|
|
161
|
+
and (top_directory_name := file_path.parts[0]) in top_level_names
|
|
162
|
+
}
|
|
163
|
+
files_to_bundle = {
|
|
164
|
+
file_path
|
|
165
|
+
for file_path in file_paths
|
|
166
|
+
if len(file_path.parts) == 1 and file_path.stem in top_level_names
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
record_root_path = distribution_metadata_path.parent
|
|
170
|
+
|
|
171
|
+
for directory_path in directories_to_bundle:
|
|
172
|
+
original_path = record_root_path / directory_path
|
|
173
|
+
new_path = target_root_path / directory_path
|
|
174
|
+
|
|
175
|
+
LOGGER.debug("copying %s to build directory", original_path.resolve())
|
|
176
|
+
|
|
177
|
+
shutil.copytree(
|
|
178
|
+
src=original_path,
|
|
179
|
+
dst=new_path,
|
|
180
|
+
ignore=IGNORED_FILES,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
for file_path in files_to_bundle:
|
|
184
|
+
original_path = record_root_path / file_path
|
|
185
|
+
new_path = target_root_path / file_path
|
|
186
|
+
|
|
187
|
+
LOGGER.debug("copying %s to build directory", original_path.resolve())
|
|
188
|
+
|
|
189
|
+
shutil.copy(
|
|
190
|
+
src=original_path,
|
|
191
|
+
dst=new_path,
|
|
192
|
+
)
|
|
@@ -19,7 +19,7 @@ class SpecialImportRewriter(ast.NodeTransformer):
|
|
|
19
19
|
_replaced_imported_names: Dict[str, str] = field(default_factory=dict, init=False)
|
|
20
20
|
|
|
21
21
|
# collect the found imported names to replace the references also
|
|
22
|
-
def visit_Import(self, node: ast.Import) -> Any: # noqa N802
|
|
22
|
+
def visit_Import(self, node: ast.Import) -> Any: # noqa: N802
|
|
23
23
|
for alias in node.names:
|
|
24
24
|
if alias.name.startswith(f"{self.from_module}.") and alias.asname is None:
|
|
25
25
|
old_module_name = alias.name
|
|
@@ -33,7 +33,7 @@ class SpecialImportRewriter(ast.NodeTransformer):
|
|
|
33
33
|
return node
|
|
34
34
|
|
|
35
35
|
# check the attributes for an imported module name reference
|
|
36
|
-
def visit_Attribute(self, node: ast.Attribute) -> Any: # noqa N802
|
|
36
|
+
def visit_Attribute(self, node: ast.Attribute) -> Any: # noqa: N802
|
|
37
37
|
attribute_name = ast.unparse(node)
|
|
38
38
|
if attribute_name in self._replaced_imported_names:
|
|
39
39
|
replaced_name = self._replaced_imported_names[attribute_name]
|
|
@@ -42,7 +42,7 @@ class SpecialImportRewriter(ast.NodeTransformer):
|
|
|
42
42
|
return self.generic_visit(node)
|
|
43
43
|
|
|
44
44
|
# this will only handle sys.modules['something'] replace
|
|
45
|
-
def visit_Subscript(self, node: ast.Subscript) -> Any: # noqa N802
|
|
45
|
+
def visit_Subscript(self, node: ast.Subscript) -> Any: # noqa: N802
|
|
46
46
|
if (
|
|
47
47
|
ast.unparse(node.value) == "sys.modules"
|
|
48
48
|
and isinstance(node.slice, ast.Constant)
|
|
@@ -69,7 +69,6 @@ def rewrite_imports_in_source_file(
|
|
|
69
69
|
f'sys.modules["{rewritten_package_name}.',
|
|
70
70
|
]
|
|
71
71
|
if any(special in contents for special in specials):
|
|
72
|
-
|
|
73
72
|
# hold on to the original for license comments
|
|
74
73
|
# since comments are lost with ast parse+unparse
|
|
75
74
|
orig_file = source_file.with_name(source_file.name + "_original")
|
|
@@ -21,7 +21,7 @@ import argparse
|
|
|
21
21
|
import logging
|
|
22
22
|
import sys
|
|
23
23
|
from pathlib import Path
|
|
24
|
-
from typing import
|
|
24
|
+
from typing import Optional
|
|
25
25
|
|
|
26
26
|
from importlib_metadata import entry_points
|
|
27
27
|
|
|
@@ -32,14 +32,12 @@ from qgis_plugin_dev_tools.config.dotenv import read_dotenv_configs
|
|
|
32
32
|
from qgis_plugin_dev_tools.publish import publish_plugin_zip_file
|
|
33
33
|
from qgis_plugin_dev_tools.start import launch_development_qgis
|
|
34
34
|
from qgis_plugin_dev_tools.start.config import DevelopmentModeConfig
|
|
35
|
-
from qgis_plugin_dev_tools.utils.distributions import
|
|
36
|
-
get_distribution_top_level_package_names,
|
|
37
|
-
)
|
|
35
|
+
from qgis_plugin_dev_tools.utils.distributions import get_distribution_top_level_names
|
|
38
36
|
|
|
39
37
|
LOGGER = logging.getLogger(__name__)
|
|
40
38
|
|
|
41
39
|
|
|
42
|
-
def start(dotenv_file_paths:
|
|
40
|
+
def start(dotenv_file_paths: list[Path]) -> None:
|
|
43
41
|
# TODO: allow choosing pyproject file from cli?
|
|
44
42
|
dev_tools_config = DevToolsConfig.from_pyproject_config(Path("pyproject.toml"))
|
|
45
43
|
# TODO: allow setting debugger flag from cli?
|
|
@@ -63,13 +61,16 @@ def start(dotenv_file_paths: List[Path]) -> None:
|
|
|
63
61
|
plugin_dependency_package_names=[
|
|
64
62
|
name
|
|
65
63
|
for dist in dev_tools_config.runtime_distributions
|
|
66
|
-
for name in
|
|
64
|
+
for name in get_distribution_top_level_names(dist)
|
|
67
65
|
],
|
|
68
66
|
debugger_library=dotenv_config.DEBUGGER_LIBRARY,
|
|
69
67
|
extra_plugin_package_names=[
|
|
70
68
|
entry_point.name
|
|
71
69
|
for entry_point in entry_points_found_from_python_env
|
|
72
|
-
if
|
|
70
|
+
if (
|
|
71
|
+
entry_point.name != dev_tools_config.plugin_package_name
|
|
72
|
+
and entry_point.name not in dev_tools_config.disabled_extra_plugins
|
|
73
|
+
)
|
|
73
74
|
],
|
|
74
75
|
)
|
|
75
76
|
)
|
|
@@ -21,7 +21,6 @@ from collections import ChainMap
|
|
|
21
21
|
from enum import Enum, auto
|
|
22
22
|
from importlib.util import find_spec
|
|
23
23
|
from pathlib import Path
|
|
24
|
-
from typing import List
|
|
25
24
|
|
|
26
25
|
from importlib_metadata import Distribution, distribution
|
|
27
26
|
from packaging.requirements import Requirement
|
|
@@ -39,25 +38,27 @@ class VersionNumberSource(Enum):
|
|
|
39
38
|
try:
|
|
40
39
|
return VersionNumberSource[config_value.upper()]
|
|
41
40
|
except KeyError:
|
|
42
|
-
raise ValueError(f"{config_value=} is not a valid value")
|
|
41
|
+
raise ValueError(f"{config_value=} is not a valid value") from None
|
|
43
42
|
|
|
44
43
|
|
|
45
44
|
class DevToolsConfig:
|
|
46
45
|
plugin_package_name: str
|
|
47
46
|
plugin_package_path: Path
|
|
48
|
-
runtime_distributions:
|
|
47
|
+
runtime_distributions: list[Distribution]
|
|
49
48
|
changelog_file_path: Path
|
|
50
49
|
append_distributions_to_path: bool
|
|
51
50
|
version_number_source: VersionNumberSource
|
|
51
|
+
disabled_extra_plugins: list[str]
|
|
52
52
|
|
|
53
|
-
def __init__(
|
|
53
|
+
def __init__( # noqa: PLR0913
|
|
54
54
|
self,
|
|
55
55
|
plugin_package_name: str,
|
|
56
|
-
runtime_requires:
|
|
56
|
+
runtime_requires: list[str],
|
|
57
57
|
changelog_file_path: Path,
|
|
58
58
|
append_distributions_to_path: bool,
|
|
59
59
|
auto_add_recursive_runtime_dependencies: bool,
|
|
60
|
-
version_number_source: VersionNumberSource
|
|
60
|
+
version_number_source: VersionNumberSource,
|
|
61
|
+
disabled_extra_plugins: list[str],
|
|
61
62
|
) -> None:
|
|
62
63
|
plugin_package_spec = find_spec(plugin_package_name)
|
|
63
64
|
if plugin_package_spec is None or plugin_package_spec.origin is None:
|
|
@@ -75,6 +76,7 @@ class DevToolsConfig:
|
|
|
75
76
|
self.append_distributions_to_path = append_distributions_to_path
|
|
76
77
|
self.version_number_source = version_number_source
|
|
77
78
|
self.extra_runtime_distributions = []
|
|
79
|
+
self.disabled_extra_plugins = disabled_extra_plugins
|
|
78
80
|
|
|
79
81
|
if auto_add_recursive_runtime_dependencies:
|
|
80
82
|
# Add the requirements of the distributions as well
|
|
@@ -109,4 +111,5 @@ class DevToolsConfig:
|
|
|
109
111
|
version_number_source=VersionNumberSource.from_config_value(
|
|
110
112
|
pyproject_config.version_number_source
|
|
111
113
|
),
|
|
114
|
+
disabled_extra_plugins=pyproject_config.disabled_extra_plugins,
|
|
112
115
|
)
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
|
|
20
20
|
import logging
|
|
21
21
|
from pathlib import Path
|
|
22
|
-
from typing import
|
|
22
|
+
from typing import Optional
|
|
23
23
|
|
|
24
24
|
from dotenv import dotenv_values
|
|
25
25
|
|
|
26
26
|
LOGGER = logging.getLogger(__name__)
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
class DotenvConfig:
|
|
29
|
+
class DotenvConfig:
|
|
30
30
|
"""
|
|
31
31
|
Expected structure for the config keys in the .env.
|
|
32
32
|
"""
|
|
@@ -34,14 +34,14 @@ class DotenvConfig: # noqa SIM119
|
|
|
34
34
|
QGIS_EXECUTABLE_PATH: Path
|
|
35
35
|
DEBUGGER_LIBRARY: Optional[str]
|
|
36
36
|
DEVELOPMENT_PROFILE_NAME: Optional[str]
|
|
37
|
-
runtime_environment:
|
|
37
|
+
runtime_environment: dict[str, str]
|
|
38
38
|
|
|
39
39
|
def __init__(
|
|
40
40
|
self,
|
|
41
41
|
*,
|
|
42
|
-
QGIS_EXECUTABLE_PATH: str, # noqa N803
|
|
43
|
-
DEBUGGER_LIBRARY: Optional[str] = None, # noqa N803
|
|
44
|
-
DEVELOPMENT_PROFILE_NAME: Optional[str] = None, # noqa N803
|
|
42
|
+
QGIS_EXECUTABLE_PATH: str, # noqa: N803
|
|
43
|
+
DEBUGGER_LIBRARY: Optional[str] = None, # noqa: N803
|
|
44
|
+
DEVELOPMENT_PROFILE_NAME: Optional[str] = None, # noqa: N803
|
|
45
45
|
**other_vars: str,
|
|
46
46
|
) -> None:
|
|
47
47
|
self.QGIS_EXECUTABLE_PATH = Path(QGIS_EXECUTABLE_PATH)
|
|
@@ -54,7 +54,7 @@ class DotenvConfig: # noqa SIM119
|
|
|
54
54
|
self.runtime_environment = other_vars
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
def read_dotenv_configs(dotenv_file_paths:
|
|
57
|
+
def read_dotenv_configs(dotenv_file_paths: list[Path]) -> DotenvConfig:
|
|
58
58
|
config = {}
|
|
59
59
|
for dotenv_file_path in dotenv_file_paths:
|
|
60
60
|
LOGGER.debug("reading config from %s", dotenv_file_path.resolve())
|
|
@@ -62,4 +62,4 @@ def read_dotenv_configs(dotenv_file_paths: List[Path]) -> DotenvConfig:
|
|
|
62
62
|
try:
|
|
63
63
|
return DotenvConfig(**{k: v for k, v in config.items() if v})
|
|
64
64
|
except (KeyError, TypeError) as e:
|
|
65
|
-
raise ValueError(f"dev tools config invalid in .env: {e}")
|
|
65
|
+
raise ValueError(f"dev tools config invalid in .env: {e}") from e
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
import logging
|
|
21
21
|
from dataclasses import dataclass, field
|
|
22
22
|
from pathlib import Path
|
|
23
|
-
from typing import
|
|
23
|
+
from typing import Literal, Union
|
|
24
24
|
|
|
25
25
|
import tomli
|
|
26
26
|
|
|
@@ -36,12 +36,13 @@ class PyprojectConfig:
|
|
|
36
36
|
DEV_TOOLS_SECTION_LOCATOR = "qgis_plugin_dev_tools"
|
|
37
37
|
|
|
38
38
|
plugin_package_name: str
|
|
39
|
-
runtime_requires:
|
|
39
|
+
runtime_requires: list[str] = field(default_factory=list)
|
|
40
40
|
use_dangerous_vendor_sys_path_append: bool = False
|
|
41
41
|
auto_add_recursive_runtime_dependencies: bool = False
|
|
42
42
|
version_number_source: Union[
|
|
43
43
|
Literal["changelog"], Literal["distribution"]
|
|
44
44
|
] = "changelog"
|
|
45
|
+
disabled_extra_plugins: list[str] = field(default_factory=list)
|
|
45
46
|
|
|
46
47
|
def __post_init__(self) -> None:
|
|
47
48
|
if self.version_number_source not in ["changelog", "distribution"]:
|
|
@@ -60,4 +61,4 @@ def read_pyproject_config(pyproject_file_path: Path) -> PyprojectConfig:
|
|
|
60
61
|
]
|
|
61
62
|
return PyprojectConfig(**dev_tools_configuration)
|
|
62
63
|
except (KeyError, TypeError) as e:
|
|
63
|
-
raise ValueError(f"dev tools config invalid in pyproject.toml: {e}")
|
|
64
|
+
raise ValueError(f"dev tools config invalid in pyproject.toml: {e}") from e
|
|
@@ -4,13 +4,15 @@ import logging
|
|
|
4
4
|
import os
|
|
5
5
|
from base64 import b64encode
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import
|
|
7
|
+
from typing import cast
|
|
8
8
|
from uuid import uuid4
|
|
9
9
|
|
|
10
10
|
import requests
|
|
11
11
|
|
|
12
12
|
LOGGER = logging.getLogger(__name__)
|
|
13
13
|
|
|
14
|
+
HTTP_STATUS_CODE_OK = 200
|
|
15
|
+
|
|
14
16
|
|
|
15
17
|
def publish_plugin_zip_file(plugin_zip_file_path: Path) -> None:
|
|
16
18
|
username = os.environ.get("QPDT_PUBLISH_USERNAME")
|
|
@@ -51,7 +53,7 @@ def publish_plugin_zip_file(plugin_zip_file_path: Path) -> None:
|
|
|
51
53
|
response.text,
|
|
52
54
|
)
|
|
53
55
|
|
|
54
|
-
if response.status_code !=
|
|
56
|
+
if response.status_code != HTTP_STATUS_CODE_OK:
|
|
55
57
|
raise Exception(
|
|
56
58
|
"QGIS plugin repository plugin upload "
|
|
57
59
|
f"HTTP request failed with status {response.status_code}"
|
|
@@ -62,7 +64,7 @@ def publish_plugin_zip_file(plugin_zip_file_path: Path) -> None:
|
|
|
62
64
|
f"request returned error response {response.json().get('error')}"
|
|
63
65
|
)
|
|
64
66
|
|
|
65
|
-
plugin_id, version_id = cast(
|
|
67
|
+
plugin_id, version_id = cast(dict[str, tuple[int, int]], response.json()).get(
|
|
66
68
|
"result", (None, None)
|
|
67
69
|
)
|
|
68
70
|
|
|
@@ -32,13 +32,11 @@ def launch_development_qgis(
|
|
|
32
32
|
) -> None:
|
|
33
33
|
LOGGER.info("starting daemon server")
|
|
34
34
|
with start_daemon_server() as (port, handle_single_request):
|
|
35
|
-
|
|
36
35
|
LOGGER.info("creating a bootstrap file")
|
|
37
36
|
with create_bootstrap_file(
|
|
38
37
|
development_mode_config,
|
|
39
38
|
port,
|
|
40
39
|
) as bootstrap_file_path:
|
|
41
|
-
|
|
42
40
|
LOGGER.info("launching qgis")
|
|
43
41
|
launch_qgis_with_bootstrap_script(
|
|
44
42
|
development_mode_config.qgis_executable_path,
|
|
@@ -21,11 +21,11 @@ import dataclasses
|
|
|
21
21
|
import logging
|
|
22
22
|
import pickle
|
|
23
23
|
import sys
|
|
24
|
+
from collections.abc import Generator
|
|
24
25
|
from contextlib import contextmanager
|
|
25
26
|
from importlib import resources
|
|
26
27
|
from pathlib import Path
|
|
27
28
|
from tempfile import TemporaryDirectory
|
|
28
|
-
from typing import Generator
|
|
29
29
|
|
|
30
30
|
from qgis_plugin_dev_tools.start.bootstrap.template import BootstrapConfig
|
|
31
31
|
from qgis_plugin_dev_tools.start.config import DevelopmentModeConfig
|
|
@@ -44,10 +44,10 @@ def create_bootstrap_file(
|
|
|
44
44
|
runtime_environment=development_mode_configuration.runtime_environment,
|
|
45
45
|
plugin_package_path=development_mode_configuration.plugin_package_path,
|
|
46
46
|
plugin_package_name=development_mode_configuration.plugin_package_name,
|
|
47
|
-
plugin_dependency_package_names=development_mode_configuration.plugin_dependency_package_names,
|
|
47
|
+
plugin_dependency_package_names=development_mode_configuration.plugin_dependency_package_names,
|
|
48
48
|
debugger_library=development_mode_configuration.debugger_library,
|
|
49
49
|
bootstrap_python_executable_path=Path(sys.executable),
|
|
50
|
-
extra_plugin_package_names=development_mode_configuration.extra_plugin_package_names,
|
|
50
|
+
extra_plugin_package_names=development_mode_configuration.extra_plugin_package_names,
|
|
51
51
|
)
|
|
52
52
|
|
|
53
53
|
LOGGER.debug("using bootstrap config:\n%s", bootstrap_config)
|