drupal-scout 3.0.2__tar.gz → 3.1.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 (48) hide show
  1. {drupal_scout-3.0.2/drupal_scout.egg-info → drupal_scout-3.1.0}/PKG-INFO +19 -8
  2. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/README.md +18 -7
  3. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/application.py +155 -65
  4. drupal_scout-3.1.0/drupal_scout/deep_scan.py +344 -0
  5. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/exceptions.py +7 -2
  6. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/formatters/formatter.py +2 -0
  7. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/formatters/formatterfactory.py +4 -4
  8. drupal_scout-3.1.0/drupal_scout/formatters/jsonformatter.py +56 -0
  9. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/formatters/suggestformatter.py +14 -10
  10. drupal_scout-3.1.0/drupal_scout/formatters/tableformatter.py +199 -0
  11. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/mcp_server.py +36 -21
  12. drupal_scout-3.1.0/drupal_scout/module.py +43 -0
  13. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/output.py +36 -16
  14. drupal_scout-3.1.0/drupal_scout/tests/conftest.py +121 -0
  15. drupal_scout-3.1.0/drupal_scout/tests/test_application.py +1030 -0
  16. drupal_scout-3.1.0/drupal_scout/tests/test_deep_scan.py +346 -0
  17. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/tests/test_exceptions.py +17 -7
  18. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/tests/test_formatterfactory.py +5 -5
  19. drupal_scout-3.1.0/drupal_scout/tests/test_jsonformatter.py +142 -0
  20. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/tests/test_mcp_server.py +141 -17
  21. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/tests/test_suggestformatter.py +26 -26
  22. drupal_scout-3.1.0/drupal_scout/tests/test_tableformatter.py +157 -0
  23. drupal_scout-3.1.0/drupal_scout/tests/test_worker.py +462 -0
  24. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/tests/test_workers_manager.py +22 -8
  25. drupal_scout-3.1.0/drupal_scout/worker.py +270 -0
  26. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/workers_manager.py +24 -9
  27. {drupal_scout-3.0.2 → drupal_scout-3.1.0/drupal_scout.egg-info}/PKG-INFO +19 -8
  28. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout.egg-info/SOURCES.txt +2 -0
  29. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/pyproject.toml +1 -1
  30. drupal_scout-3.0.2/drupal_scout/formatters/jsonformatter.py +0 -39
  31. drupal_scout-3.0.2/drupal_scout/formatters/tableformatter.py +0 -50
  32. drupal_scout-3.0.2/drupal_scout/module.py +0 -18
  33. drupal_scout-3.0.2/drupal_scout/tests/conftest.py +0 -20
  34. drupal_scout-3.0.2/drupal_scout/tests/test_application.py +0 -668
  35. drupal_scout-3.0.2/drupal_scout/tests/test_jsonformatter.py +0 -101
  36. drupal_scout-3.0.2/drupal_scout/tests/test_tableformatter.py +0 -78
  37. drupal_scout-3.0.2/drupal_scout/tests/test_worker.py +0 -360
  38. drupal_scout-3.0.2/drupal_scout/worker.py +0 -158
  39. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/LICENSE.txt +0 -0
  40. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/bin/drupal-scout +0 -0
  41. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/__init__.py +0 -0
  42. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/formatters/__init__.py +0 -0
  43. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout/tests/__init__.py +0 -0
  44. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout.egg-info/dependency_links.txt +0 -0
  45. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout.egg-info/entry_points.txt +0 -0
  46. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout.egg-info/requires.txt +0 -0
  47. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/drupal_scout.egg-info/top_level.txt +0 -0
  48. {drupal_scout-3.0.2 → drupal_scout-3.1.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drupal-scout
3
- Version: 3.0.2
3
+ Version: 3.1.0
4
4
  Summary: Scout out for transitive versions of Drupal modules for the upgrade of the core.
5
5
  Author-email: "Andrew [R-Tech] Tsyhaniuk" <in0mad91@gmail.com>
6
6
  License: MIT License
@@ -127,6 +127,8 @@ drupal-scout [-h] [-v] [-d DIRECTORY] [-n] [-l LIMIT] [-f {table,json,suggest}]
127
127
  - `-s, --save-dump`: Use with `--format suggest` to save the suggested `composer.json` to disk.
128
128
  - `-c CORE, --core CORE`: Optional Drupal core version override (e.g., `10.0.0`).
129
129
  - `-m MODULES [MODULES ...], --modules MODULES [MODULES ...]`: Scan only specific modules, skipping full project discovery.
130
+ - `--deep-scan[=MODE]`: Perform a read-only local deep scan for global or targeted scans. Optional mode: `all` (default, Git + Patches), `patches` (Composer patches only), or `git` (Git index + history only).
131
+
130
132
 
131
133
  ### Subcommands
132
134
 
@@ -146,22 +148,31 @@ Or with `uvx`:
146
148
  uvx --from drupal-scout drupal-scout-mcp
147
149
  ```
148
150
 
149
- ### Targeted Scan Examples
151
+ ### Deep Scan & Audit Examples
152
+
153
+ Perform a complete deep scan across all project modules (global scan):
154
+
155
+ ```bash
156
+ drupal-scout --deep-scan
157
+ ```
150
158
 
151
- Scan one specific module with an explicit core version:
159
+ Perform a Composer patch-only scan:
152
160
 
153
161
  ```bash
154
- drupal-scout --core 10.0.0 --modules drupal/webform
162
+ drupal-scout --deep-scan=patches
155
163
  ```
156
164
 
157
- Scan multiple modules and output JSON:
165
+ Perform a Git audit scan for targeted modules:
158
166
 
159
167
  ```bash
160
- drupal-scout --core 10.0.0 --modules drupal/webform drupal/ctools --format json
168
+ drupal-scout --directory /path/to/drupal --modules drupal/webform drupal/workbench --deep-scan=git
161
169
  ```
162
170
 
163
- Scan modules with auto-detected core from a local directory:
171
+ Perform a deep scan and output JSON:
164
172
 
165
173
  ```bash
166
- drupal-scout --directory /path/to/drupal --modules drupal/webform
174
+ drupal-scout --directory /path/to/drupal --deep-scan --format json
167
175
  ```
176
+
177
+
178
+
@@ -69,6 +69,8 @@ drupal-scout [-h] [-v] [-d DIRECTORY] [-n] [-l LIMIT] [-f {table,json,suggest}]
69
69
  - `-s, --save-dump`: Use with `--format suggest` to save the suggested `composer.json` to disk.
70
70
  - `-c CORE, --core CORE`: Optional Drupal core version override (e.g., `10.0.0`).
71
71
  - `-m MODULES [MODULES ...], --modules MODULES [MODULES ...]`: Scan only specific modules, skipping full project discovery.
72
+ - `--deep-scan[=MODE]`: Perform a read-only local deep scan for global or targeted scans. Optional mode: `all` (default, Git + Patches), `patches` (Composer patches only), or `git` (Git index + history only).
73
+
72
74
 
73
75
  ### Subcommands
74
76
 
@@ -88,22 +90,31 @@ Or with `uvx`:
88
90
  uvx --from drupal-scout drupal-scout-mcp
89
91
  ```
90
92
 
91
- ### Targeted Scan Examples
93
+ ### Deep Scan & Audit Examples
94
+
95
+ Perform a complete deep scan across all project modules (global scan):
96
+
97
+ ```bash
98
+ drupal-scout --deep-scan
99
+ ```
92
100
 
93
- Scan one specific module with an explicit core version:
101
+ Perform a Composer patch-only scan:
94
102
 
95
103
  ```bash
96
- drupal-scout --core 10.0.0 --modules drupal/webform
104
+ drupal-scout --deep-scan=patches
97
105
  ```
98
106
 
99
- Scan multiple modules and output JSON:
107
+ Perform a Git audit scan for targeted modules:
100
108
 
101
109
  ```bash
102
- drupal-scout --core 10.0.0 --modules drupal/webform drupal/ctools --format json
110
+ drupal-scout --directory /path/to/drupal --modules drupal/webform drupal/workbench --deep-scan=git
103
111
  ```
104
112
 
105
- Scan modules with auto-detected core from a local directory:
113
+ Perform a deep scan and output JSON:
106
114
 
107
115
  ```bash
108
- drupal-scout --directory /path/to/drupal --modules drupal/webform
116
+ drupal-scout --directory /path/to/drupal --deep-scan --format json
109
117
  ```
118
+
119
+
120
+
@@ -1,14 +1,16 @@
1
- from sys import exit
2
- import asyncio
3
1
  import json
4
2
  import os
5
3
  from argparse import ArgumentParser
4
+ from sys import exit
5
+
6
6
  import jq
7
- from .formatters.formatterfactory import FormatterFactory
7
+
8
+ from .deep_scan import audit_modules_async
8
9
  from .exceptions import *
10
+ from .formatters.formatterfactory import FormatterFactory
9
11
  from .module import Module
10
- from .workers_manager import WorkersManager
11
12
  from .output import ConsoleOutputHandler, logger
13
+ from .workers_manager import WorkersManager
12
14
 
13
15
 
14
16
  class Application:
@@ -19,7 +21,9 @@ class Application:
19
21
  def __init__(self, output_handler=None):
20
22
  self.output = output_handler or ConsoleOutputHandler()
21
23
  self.__modules = {}
22
- self.__drupal_core_version = "8.8" # default and minimal supported Drupal core version for upgrade
24
+ self.__drupal_core_version = (
25
+ "8.8" # default and minimal supported Drupal core version for upgrade
26
+ )
23
27
 
24
28
  @property
25
29
  def modules(self) -> dict:
@@ -61,7 +65,11 @@ class Application:
61
65
  # Full environment scan
62
66
  await self._run_environment_scan(args)
63
67
 
64
- except (ComposerV1Exception, DirectoryNotFoundException, NoComposerJSONFileException) as e:
68
+ except (
69
+ ComposerV1Exception,
70
+ DirectoryNotFoundException,
71
+ NoComposerJSONFileException,
72
+ ) as e:
65
73
  logger.warning(e.message)
66
74
  exit(1)
67
75
 
@@ -90,10 +98,17 @@ class Application:
90
98
  current_core=self.__drupal_core_version,
91
99
  use_lock_version=use_lock_version,
92
100
  concurrency_limit=args.limit,
93
- output=self.output
101
+ output=self.output,
94
102
  )
95
103
  await workers_manager.run()
96
104
 
105
+ deep_scan_mode = getattr(args, "deep_scan", None)
106
+ if deep_scan_mode:
107
+ mode_str = "all" if deep_scan_mode is True else str(deep_scan_mode)
108
+ await audit_modules_async(
109
+ list(self.__modules.values()), args.directory, mode=mode_str
110
+ )
111
+
97
112
  formatter = FormatterFactory.get_formatter(args)
98
113
  if formatter:
99
114
  self.output.print(formatter.format(list(self.__modules.values())))
@@ -124,7 +139,9 @@ class Application:
124
139
  """Scan all modules discovered from the Drupal project's composer files."""
125
140
  # check if the directory exists and whether the composer.json file exists in it
126
141
  if not os.path.isdir(args.directory):
127
- raise DirectoryNotFoundException("The directory {} does not exist.".format(args.directory))
142
+ raise DirectoryNotFoundException(
143
+ f"The directory {args.directory} does not exist."
144
+ )
128
145
 
129
146
  # check if the directory contains the composer.json file
130
147
  if not os.path.isfile(os.path.join(args.directory, "composer.json")):
@@ -141,10 +158,14 @@ class Application:
141
158
  self.get_required_modules(args)
142
159
 
143
160
  if len(self.__modules) > 0:
144
- if not args.no_lock and os.path.isfile(os.path.join(args.directory, "composer.lock")):
161
+ if not args.no_lock and os.path.isfile(
162
+ os.path.join(args.directory, "composer.lock")
163
+ ):
145
164
  self.determine_module_versions(args)
146
165
  elif args.no_lock:
147
- logger.warning("The composer.lock file was not used to determine the installed versions of the modules.")
166
+ logger.warning(
167
+ "The composer.lock file was not used to determine the installed versions of the modules."
168
+ )
148
169
  logger.warning(
149
170
  "The only Drupal core version will be use to determine the transitive versions of the modules."
150
171
  )
@@ -155,14 +176,22 @@ class Application:
155
176
  current_core=self.__drupal_core_version,
156
177
  use_lock_version=not args.no_lock,
157
178
  concurrency_limit=args.limit,
158
- output=self.output
179
+ output=self.output,
159
180
  )
160
181
  await workers_manager.run()
161
182
 
183
+ deep_scan_mode = getattr(args, "deep_scan", None)
184
+ if deep_scan_mode:
185
+ mode_str = "all" if deep_scan_mode is True else str(deep_scan_mode)
186
+ await audit_modules_async(
187
+ list(self.__modules.values()), args.directory, mode=mode_str
188
+ )
189
+
162
190
  # output the results
163
191
  formatter = FormatterFactory.get_formatter(args)
164
192
  if formatter:
165
193
  self.output.print(formatter.format(list(self.__modules.values())))
194
+
166
195
  else:
167
196
  logger.warning("No modules were found in the composer.json file.")
168
197
 
@@ -178,14 +207,14 @@ class Application:
178
207
  "-v",
179
208
  "--version",
180
209
  action="version",
181
- version="drupal-scout {}".format(self.get_version())
210
+ version=f"drupal-scout {self.get_version()}",
182
211
  )
183
212
  parser.add_argument(
184
213
  "-d",
185
214
  "--directory",
186
215
  help="The directory of the Drupal installation.",
187
216
  type=str,
188
- default="."
217
+ default=".",
189
218
  )
190
219
  # special argument to support the composer.lock file
191
220
  parser.add_argument(
@@ -193,15 +222,15 @@ class Application:
193
222
  "--no-lock",
194
223
  help="Do not use the composer.lock file to determine the installed versions of the modules.",
195
224
  action="store_true",
196
- default=False
225
+ default=False,
197
226
  )
198
227
  parser.add_argument(
199
228
  "-l",
200
229
  "--limit",
201
230
  help="Maximum number of concurrent network requests. This prevents overwhelming the upstream API "
202
- "and hitting rate limits. Default: 10.",
231
+ "and hitting rate limits. Default: 10.",
203
232
  type=int,
204
- default=10
233
+ default=10,
205
234
  )
206
235
 
207
236
  # "table" format is for human-readable output in the console
@@ -213,39 +242,51 @@ class Application:
213
242
  "--format",
214
243
  help="The output format. By default, the application will use the table format.",
215
244
  choices=["table", "json", "suggest"],
216
- default="table"
245
+ default="table",
217
246
  )
218
247
 
219
248
  # the following argument is only available for the "suggest" format
220
249
  parser.add_argument(
221
- '-s',
222
- '--save-dump',
223
- help='Use in pair with --format suggest to dump the suggested composer.json file to the specified path.',
250
+ "-s",
251
+ "--save-dump",
252
+ help="Use in pair with --format suggest to dump the suggested composer.json file to the specified path.",
224
253
  default=False,
225
- action='store_true'
254
+ action="store_true",
226
255
  )
227
256
 
228
257
  parser.add_argument(
229
- '-c',
230
- '--core',
231
- help='Optional Drupal core version override for targeted module scans (e.g. 10.0.0). '
232
- 'If omitted, the core version is auto-detected from composer.lock/composer.json in --directory.',
258
+ "-c",
259
+ "--core",
260
+ help="Optional Drupal core version override for targeted module scans (e.g. 10.0.0). "
261
+ "If omitted, the core version is auto-detected from composer.lock/composer.json in --directory.",
233
262
  type=str,
234
- default=None
263
+ default=None,
235
264
  )
236
265
 
237
266
  parser.add_argument(
238
- '-m',
239
- '--modules',
240
- nargs='+',
241
- help='One or more specific Drupal module names to scan (e.g. drupal/webform drupal/ctools). '
242
- 'When provided, the full environment scan is skipped. The tool still uses composer.lock from '
243
- '--directory for installed-version protection when available.',
244
- default=[]
267
+ "-m",
268
+ "--modules",
269
+ nargs="+",
270
+ help="One or more specific Drupal module names to scan (e.g. drupal/webform drupal/ctools). "
271
+ "When provided, the full environment scan is skipped. The tool still uses composer.lock from "
272
+ "--directory for installed-version protection when available.",
273
+ default=[],
274
+ )
275
+
276
+ parser.add_argument(
277
+ "--deep-scan",
278
+ dest="deep_scan",
279
+ nargs="?",
280
+ const="all",
281
+ default=None,
282
+ choices=["all", "patches", "git"],
283
+ help="Perform a read-only local deep scan (Git index, commit history, and Composer patches). Optional mode: all (default), patches, git.",
245
284
  )
246
285
 
247
286
  subparsers = parser.add_subparsers(dest="command")
248
- info_parser = subparsers.add_parser('info', help='Diagnostic information about the tool and environment')
287
+ subparsers.add_parser(
288
+ "info", help="Diagnostic information about the tool and environment"
289
+ )
249
290
 
250
291
  return parser
251
292
 
@@ -256,14 +297,16 @@ class Application:
256
297
  """
257
298
  import importlib.metadata
258
299
  import re
259
-
300
+
260
301
  try:
261
- return importlib.metadata.version('drupal-scout')
302
+ return importlib.metadata.version("drupal-scout")
262
303
  except importlib.metadata.PackageNotFoundError:
263
304
  try:
264
305
  # relative path to find pyproject.toml in the source tree
265
306
  current_dir = os.path.dirname(os.path.abspath(__file__))
266
- pyproject_path = os.path.join(os.path.dirname(current_dir), "pyproject.toml")
307
+ pyproject_path = os.path.join(
308
+ os.path.dirname(current_dir), "pyproject.toml"
309
+ )
267
310
  with open(pyproject_path, "r") as f:
268
311
  content = f.read()
269
312
  match = re.search(r'version\s*=\s*"([^"]+)"', content)
@@ -281,30 +324,55 @@ class Application:
281
324
 
282
325
  version = self.get_version()
283
326
 
284
-
285
327
  jq_status = "NOT FOUND OR NOT FUNCTIONAL"
286
328
  try:
287
- subprocess.run(["jq", "--version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
329
+ subprocess.run(
330
+ ["jq", "--version"],
331
+ stdout=subprocess.DEVNULL,
332
+ stderr=subprocess.DEVNULL,
333
+ check=True,
334
+ )
288
335
  jq_status = "FOUND and FUNCTIONAL"
289
336
  except (subprocess.SubprocessError, FileNotFoundError):
290
337
  pass
291
338
 
292
- composer_json_str = "DETECTED" if os.path.isfile(os.path.join(args.directory, "composer.json")) else "NOT DETECTED"
293
- composer_lock_str = "DETECTED" if os.path.isfile(os.path.join(args.directory, "composer.lock")) else "NOT DETECTED"
294
-
339
+ composer_json_str = (
340
+ "DETECTED"
341
+ if os.path.isfile(os.path.join(args.directory, "composer.json"))
342
+ else "NOT DETECTED"
343
+ )
344
+ composer_lock_str = (
345
+ "DETECTED"
346
+ if os.path.isfile(os.path.join(args.directory, "composer.lock"))
347
+ else "NOT DETECTED"
348
+ )
349
+
295
350
  composer2_status_str = "DETECTED" if self.is_composer2(args) else "NOT DETECTED"
296
-
351
+
297
352
  core_version = "[Unknown]"
298
353
  if composer_json_str == "DETECTED":
299
354
  try:
300
355
  if composer_lock_str == "DETECTED":
301
- args_mock = type('Args', (object,), {"no_lock": False, "directory": args.directory})()
356
+ args_mock = type(
357
+ "Args",
358
+ (object,),
359
+ {"no_lock": False, "directory": args.directory},
360
+ )()
302
361
  else:
303
- args_mock = type('Args', (object,), {"no_lock": True, "directory": args.directory})()
304
-
362
+ args_mock = type(
363
+ "Args",
364
+ (object,),
365
+ {"no_lock": True, "directory": args.directory},
366
+ )()
367
+
305
368
  # Use contextlib for cleaner stream suppression
306
- import contextlib, io
307
- with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()):
369
+ import contextlib
370
+ import io
371
+
372
+ with (
373
+ contextlib.redirect_stdout(io.StringIO()),
374
+ contextlib.redirect_stderr(io.StringIO()),
375
+ ):
308
376
  self.determine_drupal_core_version(args_mock)
309
377
  # Use public property to avoid __ direct access if possible
310
378
  core_version = self.drupal_core_version
@@ -317,7 +385,7 @@ class Application:
317
385
  "composer.json": composer_json_str,
318
386
  "composer.lock": composer_lock_str,
319
387
  "Composer 2": composer2_status_str,
320
- "Drupal Core Version": core_version
388
+ "Drupal Core Version": core_version,
321
389
  }
322
390
  self.output.render_info_table(f"Drupal Scout v{version} Status", status_data)
323
391
 
@@ -331,10 +399,11 @@ class Application:
331
399
  """
332
400
  # check whether the vendor directory exists and has a composer/platform_check.php file
333
401
  # because this clue is only available in Composer 2
334
- if os.path.isdir(os.path.join(args.directory, "vendor")):
335
- if os.path.isfile(os.path.join(args.directory, "vendor", "composer", "platform_check.php")):
336
- return True
337
- return False
402
+ return os.path.isdir(
403
+ os.path.join(args.directory, "vendor")
404
+ ) and os.path.isfile(
405
+ os.path.join(args.directory, "vendor", "composer", "platform_check.php")
406
+ )
338
407
 
339
408
  def determine_drupal_core_version(self, args):
340
409
  """
@@ -346,8 +415,13 @@ class Application:
346
415
  if not args.no_lock:
347
416
  with open(os.path.join(args.directory, "composer.lock"), "r") as f:
348
417
  composer_lock = json.load(f)
349
- self.__drupal_core_version = jq.compile(".packages[] | select(.name == \"drupal/core\") | .version") \
350
- .input(composer_lock).first()
418
+ self.__drupal_core_version = (
419
+ jq.compile(
420
+ '.packages[] | select(.name == "drupal/core") | .version'
421
+ )
422
+ .input(composer_lock)
423
+ .first()
424
+ )
351
425
  else:
352
426
  with open(os.path.join(args.directory, "composer.json"), "r") as f:
353
427
  composer_json = json.load(f)
@@ -355,12 +429,18 @@ class Application:
355
429
  # or within the "drupal/core-recommended" requirement
356
430
  if "drupal/core" in composer_json["require"]:
357
431
  # clear special characters from the version
358
- self.__drupal_core_version = composer_json["require"]["drupal/core"] \
359
- .replace("^", "").replace("~", "")
432
+ self.__drupal_core_version = (
433
+ composer_json["require"]["drupal/core"]
434
+ .replace("^", "")
435
+ .replace("~", "")
436
+ )
360
437
  elif "drupal/core-recommended" in composer_json["require"]:
361
438
  # clear special characters from the version
362
- self.__drupal_core_version = composer_json["require"]["drupal/core-recommended"] \
363
- .replace("^", "").replace("~", "")
439
+ self.__drupal_core_version = (
440
+ composer_json["require"]["drupal/core-recommended"]
441
+ .replace("^", "")
442
+ .replace("~", "")
443
+ )
364
444
  logger.warning("The Drupal core version is: " + self.__drupal_core_version)
365
445
 
366
446
  def get_required_modules(self, args):
@@ -374,8 +454,14 @@ class Application:
374
454
  with open(os.path.join(args.directory, "composer.json"), "r") as f:
375
455
  composer_json = json.load(f)
376
456
  # load required modules, but only with drupal/* prefix and exclude modules with drupal/core prefix
377
- found_modules = jq.compile(".require | keys | map(select(startswith(\"drupal/\"))) | map(select("
378
- "startswith(\"drupal/core\") | not))").input(composer_json).first()
457
+ found_modules = (
458
+ jq.compile(
459
+ '.require | keys | map(select(startswith("drupal/"))) | map(select('
460
+ 'startswith("drupal/core") | not))'
461
+ )
462
+ .input(composer_json)
463
+ .first()
464
+ )
379
465
  for module in found_modules:
380
466
  self.__modules[module] = Module(module)
381
467
 
@@ -392,16 +478,20 @@ class Application:
392
478
 
393
479
  with open(os.path.join(args.directory, "composer.lock"), "r") as f:
394
480
  composer_lock = json.load(f)
395
- for module_name in self.__modules.keys():
481
+ for module_name in self.__modules:
396
482
  module = self.__modules.get(module_name)
397
483
  if module is None:
398
484
  continue
399
485
  # look for the module with name in the packages array
400
486
  module_version = None
401
487
  try:
402
- module_version = jq.compile(
403
- ".packages | map(select(.name == \"{}\")) | .[].version".format(module.name)) \
404
- .input(composer_lock).first()
488
+ module_version = (
489
+ jq.compile(
490
+ f'.packages | map(select(.name == "{module.name}")) | .[].version'
491
+ )
492
+ .input(composer_lock)
493
+ .first()
494
+ )
405
495
  except StopIteration:
406
496
  module_version = None
407
497
  # save the module name and version in the versioned_modules array