qgis-plugin-dev-tools 0.6.2__tar.gz → 0.8.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.
Files changed (44) hide show
  1. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/CHANGELOG.md +11 -0
  2. {qgis-plugin-dev-tools-0.6.2/src/qgis_plugin_dev_tools.egg-info → qgis_plugin_dev_tools-0.8.0}/PKG-INFO +23 -1
  3. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/README.md +11 -0
  4. qgis_plugin_dev_tools-0.8.0/pyproject.toml +71 -0
  5. qgis_plugin_dev_tools-0.8.0/setup.py +3 -0
  6. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/__init__.py +1 -1
  7. qgis_plugin_dev_tools-0.8.0/src/qgis_plugin_dev_tools/build/packaging.py +192 -0
  8. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/build/rewrite_imports.py +3 -4
  9. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/cli/__init__.py +10 -7
  10. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/config/__init__.py +9 -6
  11. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/config/dotenv.py +15 -9
  12. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/config/pyproject.py +4 -3
  13. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/publish/__init__.py +5 -3
  14. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/start/__init__.py +2 -2
  15. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/start/bootstrap/__init__.py +3 -3
  16. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/start/bootstrap/template.py +27 -29
  17. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/start/config.py +7 -5
  18. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/start/daemon_server.py +3 -2
  19. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/start/launch.py +12 -0
  20. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/utils/distributions.py +33 -11
  21. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0/src/qgis_plugin_dev_tools.egg-info}/PKG-INFO +23 -1
  22. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/test/test_build.py +23 -30
  23. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/test/test_read_distributions.py +4 -6
  24. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/test/test_read_dotenv.py +28 -12
  25. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/test/test_read_pyproject.py +20 -11
  26. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/test/test_rewrite_imports.py +1 -4
  27. qgis-plugin-dev-tools-0.6.2/pyproject.toml +0 -13
  28. qgis-plugin-dev-tools-0.6.2/setup.py +0 -3
  29. qgis-plugin-dev-tools-0.6.2/src/qgis_plugin_dev_tools/build/packaging.py +0 -202
  30. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/LICENSE +0 -0
  31. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/MANIFEST.in +0 -0
  32. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/setup.cfg +0 -0
  33. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/__main__.py +0 -0
  34. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/build/__init__.py +0 -0
  35. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/build/changelog_parser.py +0 -0
  36. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/build/distribution.py +0 -0
  37. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/build/metadata.py +0 -0
  38. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/py.typed +0 -0
  39. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools/utils/__init__.py +0 -0
  40. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools.egg-info/SOURCES.txt +0 -0
  41. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools.egg-info/dependency_links.txt +0 -0
  42. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools.egg-info/entry_points.txt +0 -0
  43. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools.egg-info/requires.txt +0 -0
  44. {qgis-plugin-dev-tools-0.6.2 → qgis_plugin_dev_tools-0.8.0}/src/qgis_plugin_dev_tools.egg-info/top_level.txt +0 -0
@@ -4,6 +4,15 @@ 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.8.0] - 2024-08-23
8
+
9
+ - Feat: Add locale and ui ini options to be able to further customize development environment
10
+
11
+ ## [0.7.0] - 2024-05-21
12
+
13
+ - Fix: Bundle contents by parsing pep-compliant distribution file catalog instead of possibly missing tool-specific top-level.txt
14
+ - Feat: Allow disabling auto-loaded entrypoint plugins
15
+
7
16
  ## [0.6.2] - 2023-09-27
8
17
 
9
18
  - Fix: Fix issues with bundling requirements of the requirements recursively
@@ -66,3 +75,5 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
75
  [0.6.0]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.6.0
67
76
  [0.6.1]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.6.1
68
77
  [0.6.2]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.6.2
78
+ [0.7.0]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.7.0
79
+ [0.8.0]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.8.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qgis-plugin-dev-tools
3
- Version: 0.6.2
3
+ Version: 0.8.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
@@ -113,6 +113,8 @@ By default config is read from `pyproject.toml` and runtime config from `.env` i
113
113
  QGIS_EXECUTABLE_PATH= # path to qgis-bin/qgis-bin-ltr or .exe equivalents, necessary
114
114
  # DEBUGGER_LIBRARY= # debugpy/pydevd to start a debugger on init, library must be installed to the environment
115
115
  # DEVELOPMENT_PROFILE_NAME= # name of the profile that qgis is launched with, otherwise uses default
116
+ # QGIS_LOCALE= # locale code of QGIS, otherwise uses default
117
+ # QGIS_GUI_INI= # path to ini file containing QGIS UI customizations
116
118
 
117
119
  # any other variables are added to the runtime QGIS environment
118
120
  # SOMETHING=something
@@ -135,6 +137,15 @@ Development mode also enables using and developing multiple plugins easily if ce
135
137
 
136
138
  Extra plugins are loaded on launch and reloaded together with the main plugin if [Plugin Reloader] is used.
137
139
 
140
+ You can disable plugin auto-load by using `pyproject.toml` configuration (for example when using a dependency, that also provides a plugin entrypoint):
141
+
142
+ ```toml
143
+ [tool.qgis_plugin_dev_tools]
144
+ disabled_extra_plugins = [
145
+ "unwanted_plugin_package_name",
146
+ ]
147
+ ```
148
+
138
149
  ## Development of qgis-plugin-dev-tools
139
150
 
140
151
  See [development readme](./DEVELOPMENT.md).
@@ -156,6 +167,15 @@ All notable changes to this project will be documented in this file.
156
167
 
157
168
  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
169
 
170
+ ## [0.8.0] - 2024-08-23
171
+
172
+ - Feat: Add locale and ui ini options to be able to further customize development environment
173
+
174
+ ## [0.7.0] - 2024-05-21
175
+
176
+ - Fix: Bundle contents by parsing pep-compliant distribution file catalog instead of possibly missing tool-specific top-level.txt
177
+ - Feat: Allow disabling auto-loaded entrypoint plugins
178
+
159
179
  ## [0.6.2] - 2023-09-27
160
180
 
161
181
  - Fix: Fix issues with bundling requirements of the requirements recursively
@@ -218,3 +238,5 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
218
238
  [0.6.0]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.6.0
219
239
  [0.6.1]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.6.1
220
240
  [0.6.2]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.6.2
241
+ [0.7.0]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.7.0
242
+ [0.8.0]: https://github.com/nlsfi/qgis-plugin-dev-tools/releases/tag/v0.8.0
@@ -83,6 +83,8 @@ By default config is read from `pyproject.toml` and runtime config from `.env` i
83
83
  QGIS_EXECUTABLE_PATH= # path to qgis-bin/qgis-bin-ltr or .exe equivalents, necessary
84
84
  # DEBUGGER_LIBRARY= # debugpy/pydevd to start a debugger on init, library must be installed to the environment
85
85
  # DEVELOPMENT_PROFILE_NAME= # name of the profile that qgis is launched with, otherwise uses default
86
+ # QGIS_LOCALE= # locale code of QGIS, otherwise uses default
87
+ # QGIS_GUI_INI= # path to ini file containing QGIS UI customizations
86
88
 
87
89
  # any other variables are added to the runtime QGIS environment
88
90
  # SOMETHING=something
@@ -105,6 +107,15 @@ Development mode also enables using and developing multiple plugins easily if ce
105
107
 
106
108
  Extra plugins are loaded on launch and reloaded together with the main plugin if [Plugin Reloader] is used.
107
109
 
110
+ You can disable plugin auto-load by using `pyproject.toml` configuration (for example when using a dependency, that also provides a plugin entrypoint):
111
+
112
+ ```toml
113
+ [tool.qgis_plugin_dev_tools]
114
+ disabled_extra_plugins = [
115
+ "unwanted_plugin_package_name",
116
+ ]
117
+ ```
118
+
108
119
  ## Development of qgis-plugin-dev-tools
109
120
 
110
121
  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,3 @@
1
+ from setuptools import setup
2
+
3
+ setup()
@@ -20,7 +20,7 @@
20
20
  import logging
21
21
  import sys
22
22
 
23
- __version__ = "0.6.2"
23
+ __version__ = "0.8.0"
24
24
 
25
25
  LOGGER = logging.getLogger(__name__)
26
26
  _handler = logging.StreamHandler(sys.stdout)
@@ -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 List, Optional
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: List[Path]) -> None:
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?
@@ -56,6 +54,8 @@ def start(dotenv_file_paths: List[Path]) -> None:
56
54
  DevelopmentModeConfig(
57
55
  qgis_executable_path=dotenv_config.QGIS_EXECUTABLE_PATH,
58
56
  profile_name=dotenv_config.DEVELOPMENT_PROFILE_NAME,
57
+ locale=dotenv_config.QGIS_LOCALE,
58
+ ui_ini=dotenv_config.QGIS_GUI_INI,
59
59
  runtime_environment=dotenv_config.runtime_environment,
60
60
  runtime_library_paths=[Path(p) for p in sys.path],
61
61
  plugin_package_path=dev_tools_config.plugin_package_path,
@@ -63,13 +63,16 @@ def start(dotenv_file_paths: List[Path]) -> None:
63
63
  plugin_dependency_package_names=[
64
64
  name
65
65
  for dist in dev_tools_config.runtime_distributions
66
- for name in get_distribution_top_level_package_names(dist)
66
+ for name in get_distribution_top_level_names(dist)
67
67
  ],
68
68
  debugger_library=dotenv_config.DEBUGGER_LIBRARY,
69
69
  extra_plugin_package_names=[
70
70
  entry_point.name
71
71
  for entry_point in entry_points_found_from_python_env
72
- if entry_point.name != dev_tools_config.plugin_package_name
72
+ if (
73
+ entry_point.name != dev_tools_config.plugin_package_name
74
+ and entry_point.name not in dev_tools_config.disabled_extra_plugins
75
+ )
73
76
  ],
74
77
  )
75
78
  )
@@ -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: List[Distribution]
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: List[str],
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 = VersionNumberSource.CHANGELOG,
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 Dict, List, Optional
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: # noqa SIM119
29
+ class DotenvConfig:
30
30
  """
31
31
  Expected structure for the config keys in the .env.
32
32
  """
@@ -34,14 +34,18 @@ 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: Dict[str, str]
37
+ QGIS_LOCALE: Optional[str]
38
+ QGIS_GUI_INI: Optional[str]
39
+ runtime_environment: dict[str, str]
38
40
 
39
- def __init__(
41
+ def __init__( # noqa: PLR0913
40
42
  self,
41
43
  *,
42
- QGIS_EXECUTABLE_PATH: str, # noqa N803
43
- DEBUGGER_LIBRARY: Optional[str] = None, # noqa N803
44
- DEVELOPMENT_PROFILE_NAME: Optional[str] = None, # noqa N803
44
+ QGIS_EXECUTABLE_PATH: str, # noqa: N803
45
+ DEBUGGER_LIBRARY: Optional[str] = None, # noqa: N803
46
+ DEVELOPMENT_PROFILE_NAME: Optional[str] = None, # noqa: N803
47
+ QGIS_LOCALE: Optional[str] = None, # noqa: N803
48
+ QGIS_GUI_INI: Optional[str] = None, # noqa: N803
45
49
  **other_vars: str,
46
50
  ) -> None:
47
51
  self.QGIS_EXECUTABLE_PATH = Path(QGIS_EXECUTABLE_PATH)
@@ -51,10 +55,12 @@ class DotenvConfig: # noqa SIM119
51
55
  )
52
56
  self.DEBUGGER_LIBRARY = DEBUGGER_LIBRARY
53
57
  self.DEVELOPMENT_PROFILE_NAME = DEVELOPMENT_PROFILE_NAME
58
+ self.QGIS_LOCALE = QGIS_LOCALE
59
+ self.QGIS_GUI_INI = QGIS_GUI_INI
54
60
  self.runtime_environment = other_vars
55
61
 
56
62
 
57
- def read_dotenv_configs(dotenv_file_paths: List[Path]) -> DotenvConfig:
63
+ def read_dotenv_configs(dotenv_file_paths: list[Path]) -> DotenvConfig:
58
64
  config = {}
59
65
  for dotenv_file_path in dotenv_file_paths:
60
66
  LOGGER.debug("reading config from %s", dotenv_file_path.resolve())
@@ -62,4 +68,4 @@ def read_dotenv_configs(dotenv_file_paths: List[Path]) -> DotenvConfig:
62
68
  try:
63
69
  return DotenvConfig(**{k: v for k, v in config.items() if v})
64
70
  except (KeyError, TypeError) as e:
65
- raise ValueError(f"dev tools config invalid in .env: {e}")
71
+ 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 List, Literal, Union
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: List[str] = field(default_factory=list)
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 Dict, Tuple, cast
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 != 200:
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(Dict[str, Tuple[int, int]], response.json()).get(
67
+ plugin_id, version_id = cast(dict[str, tuple[int, int]], response.json()).get(
66
68
  "result", (None, None)
67
69
  )
68
70
 
@@ -32,18 +32,18 @@ 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,
45
43
  bootstrap_file_path,
46
44
  development_mode_config.profile_name,
45
+ development_mode_config.locale,
46
+ development_mode_config.ui_ini,
47
47
  )
48
48
 
49
49
  LOGGER.info("waiting for qgis to connect")