grimp 3.7__tar.gz → 3.8__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.
- {grimp-3.7 → grimp-3.8}/PKG-INFO +1 -1
- {grimp-3.7 → grimp-3.8}/pyproject.toml +1 -1
- {grimp-3.7 → grimp-3.8}/rust/Cargo.lock +12 -12
- {grimp-3.7 → grimp-3.8}/rust/Cargo.toml +1 -1
- {grimp-3.7 → grimp-3.8}/src/grimp/__init__.py +1 -1
- {grimp-3.7 → grimp-3.8}/src/grimp/application/usecases.py +132 -20
- {grimp-3.7 → grimp-3.8}/src/grimp/exceptions.py +5 -0
- {grimp-3.7 → grimp-3.8}/README.rst +0 -0
- {grimp-3.7 → grimp-3.8}/rust/.cargo/config.toml +0 -0
- {grimp-3.7 → grimp-3.8}/rust/src/errors.rs +0 -0
- {grimp-3.7 → grimp-3.8}/rust/src/exceptions.rs +0 -0
- {grimp-3.7 → grimp-3.8}/rust/src/graph/direct_import_queries.rs +0 -0
- {grimp-3.7 → grimp-3.8}/rust/src/graph/graph_manipulation.rs +5 -5
- {grimp-3.7 → grimp-3.8}/rust/src/graph/hierarchy_queries.rs +0 -0
- {grimp-3.7 → grimp-3.8}/rust/src/graph/higher_order_queries.rs +0 -0
- {grimp-3.7 → grimp-3.8}/rust/src/graph/import_chain_queries.rs +0 -0
- {grimp-3.7 → grimp-3.8}/rust/src/graph/mod.rs +0 -0
- {grimp-3.7 → grimp-3.8}/rust/src/graph/pathfinding.rs +0 -0
- {grimp-3.7 → grimp-3.8}/rust/src/lib.rs +0 -0
- {grimp-3.7 → grimp-3.8}/rust/src/module_expressions.rs +0 -0
- {grimp-3.7 → grimp-3.8}/rust/tests/large.rs +0 -0
- {grimp-3.7 → grimp-3.8}/rust/tests/large_graph.json +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/adaptors/__init__.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/adaptors/caching.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/adaptors/filesystem.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/adaptors/graph.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/adaptors/importscanner.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/adaptors/modulefinder.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/adaptors/packagefinder.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/adaptors/timing.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/algorithms/__init__.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/algorithms/shortest_path.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/application/__init__.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/application/config.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/application/ports/__init__.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/application/ports/caching.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/application/ports/filesystem.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/application/ports/graph.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/application/ports/importscanner.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/application/ports/modulefinder.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/application/ports/packagefinder.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/application/ports/timing.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/domain/__init__.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/domain/analysis.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/domain/valueobjects.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/helpers.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/main.py +0 -0
- {grimp-3.7 → grimp-3.8}/src/grimp/py.typed +0 -0
{grimp-3.7 → grimp-3.8}/PKG-INFO
RENAMED
|
@@ -293,9 +293,9 @@ dependencies = [
|
|
|
293
293
|
|
|
294
294
|
[[package]]
|
|
295
295
|
name = "pyo3"
|
|
296
|
-
version = "0.
|
|
296
|
+
version = "0.24.1"
|
|
297
297
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
298
|
-
checksum = "
|
|
298
|
+
checksum = "17da310086b068fbdcefbba30aeb3721d5bb9af8db4987d6735b2183ca567229"
|
|
299
299
|
dependencies = [
|
|
300
300
|
"cfg-if",
|
|
301
301
|
"indoc",
|
|
@@ -311,9 +311,9 @@ dependencies = [
|
|
|
311
311
|
|
|
312
312
|
[[package]]
|
|
313
313
|
name = "pyo3-build-config"
|
|
314
|
-
version = "0.
|
|
314
|
+
version = "0.24.1"
|
|
315
315
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
316
|
-
checksum = "
|
|
316
|
+
checksum = "e27165889bd793000a098bb966adc4300c312497ea25cf7a690a9f0ac5aa5fc1"
|
|
317
317
|
dependencies = [
|
|
318
318
|
"once_cell",
|
|
319
319
|
"target-lexicon",
|
|
@@ -321,9 +321,9 @@ dependencies = [
|
|
|
321
321
|
|
|
322
322
|
[[package]]
|
|
323
323
|
name = "pyo3-ffi"
|
|
324
|
-
version = "0.
|
|
324
|
+
version = "0.24.1"
|
|
325
325
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
326
|
-
checksum = "
|
|
326
|
+
checksum = "05280526e1dbf6b420062f3ef228b78c0c54ba94e157f5cb724a609d0f2faabc"
|
|
327
327
|
dependencies = [
|
|
328
328
|
"libc",
|
|
329
329
|
"pyo3-build-config",
|
|
@@ -331,9 +331,9 @@ dependencies = [
|
|
|
331
331
|
|
|
332
332
|
[[package]]
|
|
333
333
|
name = "pyo3-macros"
|
|
334
|
-
version = "0.
|
|
334
|
+
version = "0.24.1"
|
|
335
335
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
336
|
-
checksum = "
|
|
336
|
+
checksum = "5c3ce5686aa4d3f63359a5100c62a127c9f15e8398e5fdeb5deef1fed5cd5f44"
|
|
337
337
|
dependencies = [
|
|
338
338
|
"proc-macro2",
|
|
339
339
|
"pyo3-macros-backend",
|
|
@@ -343,9 +343,9 @@ dependencies = [
|
|
|
343
343
|
|
|
344
344
|
[[package]]
|
|
345
345
|
name = "pyo3-macros-backend"
|
|
346
|
-
version = "0.
|
|
346
|
+
version = "0.24.1"
|
|
347
347
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
348
|
-
checksum = "
|
|
348
|
+
checksum = "f4cf6faa0cbfb0ed08e89beb8103ae9724eb4750e3a78084ba4017cbe94f3855"
|
|
349
349
|
dependencies = [
|
|
350
350
|
"heck",
|
|
351
351
|
"proc-macro2",
|
|
@@ -494,9 +494,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
|
|
494
494
|
|
|
495
495
|
[[package]]
|
|
496
496
|
name = "target-lexicon"
|
|
497
|
-
version = "0.
|
|
497
|
+
version = "0.13.2"
|
|
498
498
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
499
|
-
checksum = "
|
|
499
|
+
checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
|
|
500
500
|
|
|
501
501
|
[[package]]
|
|
502
502
|
name = "thiserror"
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Use cases handle application logic.
|
|
3
3
|
"""
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
from typing import Dict, Sequence, Set, Type, Union, cast, Iterable, Collection
|
|
6
|
+
import multiprocessing
|
|
7
|
+
import math
|
|
5
8
|
|
|
6
9
|
from ..application.ports import caching
|
|
7
10
|
from ..application.ports.filesystem import AbstractFileSystem
|
|
8
11
|
from ..application.ports.graph import ImportGraph
|
|
9
12
|
from ..application.ports.importscanner import AbstractImportScanner
|
|
10
|
-
from ..application.ports.modulefinder import AbstractModuleFinder, FoundPackage
|
|
13
|
+
from ..application.ports.modulefinder import AbstractModuleFinder, FoundPackage, ModuleFile
|
|
11
14
|
from ..application.ports.packagefinder import AbstractPackageFinder
|
|
12
15
|
from ..domain.valueobjects import DirectImport, Module
|
|
13
16
|
from .config import settings
|
|
@@ -17,6 +20,10 @@ class NotSupplied:
|
|
|
17
20
|
pass
|
|
18
21
|
|
|
19
22
|
|
|
23
|
+
# This is an arbitrary number, but setting it too low slows down our functional tests considerably.
|
|
24
|
+
MIN_NUMBER_OF_MODULES_TO_SCAN_USING_MULTIPROCESSING = 50
|
|
25
|
+
|
|
26
|
+
|
|
20
27
|
def build_graph(
|
|
21
28
|
package_name,
|
|
22
29
|
*additional_package_names,
|
|
@@ -106,7 +113,6 @@ def _scan_packages(
|
|
|
106
113
|
exclude_type_checking_imports: bool,
|
|
107
114
|
cache_dir: Union[str, Type[NotSupplied], None],
|
|
108
115
|
) -> Dict[Module, Set[DirectImport]]:
|
|
109
|
-
imports_by_module: Dict[Module, Set[DirectImport]] = {}
|
|
110
116
|
if cache_dir is not None:
|
|
111
117
|
cache_dir_if_supplied = cache_dir if cache_dir != NotSupplied else None
|
|
112
118
|
cache: caching.Cache = settings.CACHE_CLASS.setup(
|
|
@@ -116,24 +122,33 @@ def _scan_packages(
|
|
|
116
122
|
exclude_type_checking_imports=exclude_type_checking_imports,
|
|
117
123
|
cache_dir=cache_dir_if_supplied,
|
|
118
124
|
)
|
|
119
|
-
import_scanner: AbstractImportScanner = settings.IMPORT_SCANNER_CLASS(
|
|
120
|
-
file_system=file_system,
|
|
121
|
-
found_packages=found_packages,
|
|
122
|
-
include_external_packages=include_external_packages,
|
|
123
|
-
)
|
|
124
125
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
126
|
+
module_files_to_scan = {
|
|
127
|
+
module_file
|
|
128
|
+
for found_package in found_packages
|
|
129
|
+
for module_file in found_package.module_files
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
imports_by_module_file: Dict[ModuleFile, Set[DirectImport]] = {}
|
|
133
|
+
|
|
134
|
+
if cache_dir is not None:
|
|
135
|
+
imports_by_module_file.update(_read_imports_from_cache(module_files_to_scan, cache=cache))
|
|
136
|
+
|
|
137
|
+
remaining_module_files_to_scan = module_files_to_scan.difference(imports_by_module_file)
|
|
138
|
+
if remaining_module_files_to_scan:
|
|
139
|
+
imports_by_module_file.update(
|
|
140
|
+
_scan_imports(
|
|
141
|
+
remaining_module_files_to_scan,
|
|
142
|
+
file_system=file_system,
|
|
143
|
+
found_packages=found_packages,
|
|
144
|
+
include_external_packages=include_external_packages,
|
|
145
|
+
exclude_type_checking_imports=exclude_type_checking_imports,
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
imports_by_module: Dict[Module, Set[DirectImport]] = {
|
|
150
|
+
k.module: v for k, v in imports_by_module_file.items()
|
|
151
|
+
}
|
|
137
152
|
|
|
138
153
|
if cache_dir is not None:
|
|
139
154
|
cache.write(imports_by_module)
|
|
@@ -172,3 +187,100 @@ def _is_external(module: Module, found_packages: Set[FoundPackage]) -> bool:
|
|
|
172
187
|
module.is_descendant_of(package_module) or module == package_module
|
|
173
188
|
for package_module in package_modules
|
|
174
189
|
)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _read_imports_from_cache(
|
|
193
|
+
module_files: Iterable[ModuleFile], *, cache: caching.Cache
|
|
194
|
+
) -> Dict[ModuleFile, Set[DirectImport]]:
|
|
195
|
+
imports_by_module_file: Dict[ModuleFile, Set[DirectImport]] = {}
|
|
196
|
+
for module_file in module_files:
|
|
197
|
+
try:
|
|
198
|
+
direct_imports = cache.read_imports(module_file)
|
|
199
|
+
except caching.CacheMiss:
|
|
200
|
+
continue
|
|
201
|
+
else:
|
|
202
|
+
imports_by_module_file[module_file] = direct_imports
|
|
203
|
+
return imports_by_module_file
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _scan_imports(
|
|
207
|
+
module_files: Collection[ModuleFile],
|
|
208
|
+
*,
|
|
209
|
+
file_system: AbstractFileSystem,
|
|
210
|
+
found_packages: Set[FoundPackage],
|
|
211
|
+
include_external_packages: bool,
|
|
212
|
+
exclude_type_checking_imports: bool,
|
|
213
|
+
) -> Dict[ModuleFile, Set[DirectImport]]:
|
|
214
|
+
chunks = _create_chunks(module_files)
|
|
215
|
+
return _scan_chunks(
|
|
216
|
+
chunks,
|
|
217
|
+
file_system,
|
|
218
|
+
found_packages,
|
|
219
|
+
include_external_packages,
|
|
220
|
+
exclude_type_checking_imports,
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _create_chunks(module_files: Collection[ModuleFile]) -> tuple[tuple[ModuleFile, ...], ...]:
|
|
225
|
+
"""
|
|
226
|
+
Split the module files into chunks, each to be worked on by a separate OS process.
|
|
227
|
+
"""
|
|
228
|
+
module_files_tuple = tuple(module_files)
|
|
229
|
+
|
|
230
|
+
number_of_module_files = len(module_files_tuple)
|
|
231
|
+
n_chunks = _decide_number_of_of_processes(number_of_module_files)
|
|
232
|
+
chunk_size = math.ceil(number_of_module_files / n_chunks)
|
|
233
|
+
|
|
234
|
+
return tuple(
|
|
235
|
+
module_files_tuple[i * chunk_size : (i + 1) * chunk_size] for i in range(n_chunks)
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _decide_number_of_of_processes(number_of_module_files: int) -> int:
|
|
240
|
+
if number_of_module_files < MIN_NUMBER_OF_MODULES_TO_SCAN_USING_MULTIPROCESSING:
|
|
241
|
+
# Don't incur the overhead of multiprocessing.
|
|
242
|
+
return 1
|
|
243
|
+
return min(multiprocessing.cpu_count(), number_of_module_files)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def _scan_chunks(
|
|
247
|
+
chunks: Collection[Collection[ModuleFile]],
|
|
248
|
+
file_system: AbstractFileSystem,
|
|
249
|
+
found_packages: Set[FoundPackage],
|
|
250
|
+
include_external_packages: bool,
|
|
251
|
+
exclude_type_checking_imports: bool,
|
|
252
|
+
) -> Dict[ModuleFile, Set[DirectImport]]:
|
|
253
|
+
import_scanner: AbstractImportScanner = settings.IMPORT_SCANNER_CLASS(
|
|
254
|
+
file_system=file_system,
|
|
255
|
+
found_packages=found_packages,
|
|
256
|
+
include_external_packages=include_external_packages,
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
number_of_processes = len(chunks)
|
|
260
|
+
if number_of_processes == 1:
|
|
261
|
+
# No need to spawn a process if there's only one chunk.
|
|
262
|
+
[chunk] = chunks
|
|
263
|
+
return _scan_chunk(import_scanner, exclude_type_checking_imports, chunk)
|
|
264
|
+
else:
|
|
265
|
+
with multiprocessing.Pool(number_of_processes) as pool:
|
|
266
|
+
imports_by_module_file: Dict[ModuleFile, Set[DirectImport]] = {}
|
|
267
|
+
import_scanning_jobs = pool.starmap(
|
|
268
|
+
_scan_chunk,
|
|
269
|
+
[(import_scanner, exclude_type_checking_imports, chunk) for chunk in chunks],
|
|
270
|
+
)
|
|
271
|
+
for chunk_imports_by_module_file in import_scanning_jobs:
|
|
272
|
+
imports_by_module_file.update(chunk_imports_by_module_file)
|
|
273
|
+
return imports_by_module_file
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def _scan_chunk(
|
|
277
|
+
import_scanner: AbstractImportScanner,
|
|
278
|
+
exclude_type_checking_imports: bool,
|
|
279
|
+
chunk: Iterable[ModuleFile],
|
|
280
|
+
) -> Dict[ModuleFile, Set[DirectImport]]:
|
|
281
|
+
return {
|
|
282
|
+
module_file: import_scanner.scan_for_imports(
|
|
283
|
+
module_file.module, exclude_type_checking_imports=exclude_type_checking_imports
|
|
284
|
+
)
|
|
285
|
+
for module_file in chunk
|
|
286
|
+
}
|
|
@@ -62,6 +62,11 @@ class SourceSyntaxError(GrimpException):
|
|
|
62
62
|
other.text,
|
|
63
63
|
)
|
|
64
64
|
|
|
65
|
+
def __reduce__(self):
|
|
66
|
+
# Implement __reduce__ to make this exception pickleable,
|
|
67
|
+
# allowing it to be sent between processes.
|
|
68
|
+
return SourceSyntaxError, (self.filename, self.lineno, self.text)
|
|
69
|
+
|
|
65
70
|
|
|
66
71
|
class InvalidModuleExpression(GrimpException):
|
|
67
72
|
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -178,11 +178,6 @@ impl Graph {
|
|
|
178
178
|
})
|
|
179
179
|
.collect();
|
|
180
180
|
|
|
181
|
-
// Remove any descendants.
|
|
182
|
-
for descendant in descendants {
|
|
183
|
-
self.remove_module(descendant);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
181
|
// Add descendants and imports to parent module.
|
|
187
182
|
for imported in modules_imported_by_descendants {
|
|
188
183
|
self.add_import(module, imported);
|
|
@@ -192,6 +187,11 @@ impl Graph {
|
|
|
192
187
|
self.add_import(importer, module);
|
|
193
188
|
}
|
|
194
189
|
|
|
190
|
+
// Remove any descendants.
|
|
191
|
+
for descendant in descendants {
|
|
192
|
+
self.remove_module(descendant);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
195
|
self.mark_module_squashed(module);
|
|
196
196
|
}
|
|
197
197
|
}
|
|
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
|