grimp 3.2__tar.gz → 3.3__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 (43) hide show
  1. {grimp-3.2 → grimp-3.3}/PKG-INFO +2 -2
  2. {grimp-3.2 → grimp-3.3}/pyproject.toml +2 -2
  3. {grimp-3.2 → grimp-3.3}/rust/Cargo.lock +85 -18
  4. {grimp-3.2 → grimp-3.3}/rust/Cargo.toml +3 -2
  5. {grimp-3.2 → grimp-3.3}/rust/src/containers.rs +1 -2
  6. {grimp-3.2 → grimp-3.3}/rust/src/layers.rs +61 -47
  7. {grimp-3.2 → grimp-3.3}/rust/src/lib.rs +85 -49
  8. {grimp-3.2 → grimp-3.3}/rust/tests/large.rs +6 -6
  9. {grimp-3.2 → grimp-3.3}/src/grimp/__init__.py +1 -1
  10. {grimp-3.2 → grimp-3.3}/src/grimp/adaptors/filesystem.py +1 -1
  11. {grimp-3.2 → grimp-3.3}/README.rst +0 -0
  12. {grimp-3.2 → grimp-3.3}/rust/.cargo/config +0 -0
  13. {grimp-3.2 → grimp-3.3}/rust/src/dependencies.rs +0 -0
  14. {grimp-3.2 → grimp-3.3}/rust/src/importgraph.rs +0 -0
  15. {grimp-3.2 → grimp-3.3}/rust/tests/large_graph.json +0 -0
  16. {grimp-3.2 → grimp-3.3}/src/grimp/adaptors/__init__.py +0 -0
  17. {grimp-3.2 → grimp-3.3}/src/grimp/adaptors/_layers.py +0 -0
  18. {grimp-3.2 → grimp-3.3}/src/grimp/adaptors/caching.py +0 -0
  19. {grimp-3.2 → grimp-3.3}/src/grimp/adaptors/graph.py +0 -0
  20. {grimp-3.2 → grimp-3.3}/src/grimp/adaptors/importscanner.py +0 -0
  21. {grimp-3.2 → grimp-3.3}/src/grimp/adaptors/modulefinder.py +0 -0
  22. {grimp-3.2 → grimp-3.3}/src/grimp/adaptors/packagefinder.py +0 -0
  23. {grimp-3.2 → grimp-3.3}/src/grimp/adaptors/timing.py +0 -0
  24. {grimp-3.2 → grimp-3.3}/src/grimp/algorithms/__init__.py +0 -0
  25. {grimp-3.2 → grimp-3.3}/src/grimp/algorithms/shortest_path.py +0 -0
  26. {grimp-3.2 → grimp-3.3}/src/grimp/application/__init__.py +0 -0
  27. {grimp-3.2 → grimp-3.3}/src/grimp/application/config.py +0 -0
  28. {grimp-3.2 → grimp-3.3}/src/grimp/application/ports/__init__.py +0 -0
  29. {grimp-3.2 → grimp-3.3}/src/grimp/application/ports/caching.py +0 -0
  30. {grimp-3.2 → grimp-3.3}/src/grimp/application/ports/filesystem.py +0 -0
  31. {grimp-3.2 → grimp-3.3}/src/grimp/application/ports/graph.py +0 -0
  32. {grimp-3.2 → grimp-3.3}/src/grimp/application/ports/importscanner.py +0 -0
  33. {grimp-3.2 → grimp-3.3}/src/grimp/application/ports/modulefinder.py +0 -0
  34. {grimp-3.2 → grimp-3.3}/src/grimp/application/ports/packagefinder.py +0 -0
  35. {grimp-3.2 → grimp-3.3}/src/grimp/application/ports/timing.py +0 -0
  36. {grimp-3.2 → grimp-3.3}/src/grimp/application/usecases.py +0 -0
  37. {grimp-3.2 → grimp-3.3}/src/grimp/domain/__init__.py +0 -0
  38. {grimp-3.2 → grimp-3.3}/src/grimp/domain/analysis.py +0 -0
  39. {grimp-3.2 → grimp-3.3}/src/grimp/domain/valueobjects.py +0 -0
  40. {grimp-3.2 → grimp-3.3}/src/grimp/exceptions.py +0 -0
  41. {grimp-3.2 → grimp-3.3}/src/grimp/helpers.py +0 -0
  42. {grimp-3.2 → grimp-3.3}/src/grimp/main.py +0 -0
  43. {grimp-3.2 → grimp-3.3}/src/grimp/py.typed +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: grimp
3
- Version: 3.2
3
+ Version: 3.3
4
4
  Classifier: Development Status :: 5 - Production/Stable
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: BSD License
@@ -8,7 +8,7 @@ module-name = "grimp._rustgrimp"
8
8
 
9
9
  [project]
10
10
  name = "grimp"
11
- version = "3.2"
11
+ version = "3.3"
12
12
  license = {text = "BSD 2-Clause License"}
13
13
  description = "Builds a queryable graph of the imports within one or more Python packages."
14
14
  authors = [
@@ -54,4 +54,4 @@ namespaces = false
54
54
 
55
55
  [tool.black]
56
56
  line-length = 99
57
- exclude = 'tests/assets/syntaxerrorpackage'
57
+ exclude = 'tests/assets/syntaxerrorpackage'
@@ -9,6 +9,7 @@ dependencies = [
9
9
  "log",
10
10
  "pyo3",
11
11
  "pyo3-log",
12
+ "rayon",
12
13
  "serde_json",
13
14
  ]
14
15
 
@@ -36,11 +37,48 @@ version = "1.0.0"
36
37
  source = "registry+https://github.com/rust-lang/crates.io-index"
37
38
  checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
38
39
 
40
+ [[package]]
41
+ name = "crossbeam-deque"
42
+ version = "0.8.5"
43
+ source = "registry+https://github.com/rust-lang/crates.io-index"
44
+ checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
45
+ dependencies = [
46
+ "crossbeam-epoch",
47
+ "crossbeam-utils",
48
+ ]
49
+
50
+ [[package]]
51
+ name = "crossbeam-epoch"
52
+ version = "0.9.18"
53
+ source = "registry+https://github.com/rust-lang/crates.io-index"
54
+ checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
55
+ dependencies = [
56
+ "crossbeam-utils",
57
+ ]
58
+
59
+ [[package]]
60
+ name = "crossbeam-utils"
61
+ version = "0.8.20"
62
+ source = "registry+https://github.com/rust-lang/crates.io-index"
63
+ checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
64
+
65
+ [[package]]
66
+ name = "either"
67
+ version = "1.12.0"
68
+ source = "registry+https://github.com/rust-lang/crates.io-index"
69
+ checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
70
+
71
+ [[package]]
72
+ name = "heck"
73
+ version = "0.4.1"
74
+ source = "registry+https://github.com/rust-lang/crates.io-index"
75
+ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
76
+
39
77
  [[package]]
40
78
  name = "indoc"
41
- version = "1.0.9"
79
+ version = "2.0.5"
42
80
  source = "registry+https://github.com/rust-lang/crates.io-index"
43
- checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306"
81
+ checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
44
82
 
45
83
  [[package]]
46
84
  name = "itoa"
@@ -108,6 +146,12 @@ dependencies = [
108
146
  "windows-targets",
109
147
  ]
110
148
 
149
+ [[package]]
150
+ name = "portable-atomic"
151
+ version = "1.6.0"
152
+ source = "registry+https://github.com/rust-lang/crates.io-index"
153
+ checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
154
+
111
155
  [[package]]
112
156
  name = "proc-macro2"
113
157
  version = "1.0.64"
@@ -119,15 +163,16 @@ dependencies = [
119
163
 
120
164
  [[package]]
121
165
  name = "pyo3"
122
- version = "0.19.1"
166
+ version = "0.21.2"
123
167
  source = "registry+https://github.com/rust-lang/crates.io-index"
124
- checksum = "ffb88ae05f306b4bfcde40ac4a51dc0b05936a9207a4b75b798c7729c4258a59"
168
+ checksum = "a5e00b96a521718e08e03b1a622f01c8a8deb50719335de3f60b3b3950f069d8"
125
169
  dependencies = [
126
170
  "cfg-if",
127
171
  "indoc",
128
172
  "libc",
129
173
  "memoffset",
130
174
  "parking_lot",
175
+ "portable-atomic",
131
176
  "pyo3-build-config",
132
177
  "pyo3-ffi",
133
178
  "pyo3-macros",
@@ -136,9 +181,9 @@ dependencies = [
136
181
 
137
182
  [[package]]
138
183
  name = "pyo3-build-config"
139
- version = "0.19.1"
184
+ version = "0.21.2"
140
185
  source = "registry+https://github.com/rust-lang/crates.io-index"
141
- checksum = "554db24f0b3c180a9c0b1268f91287ab3f17c162e15b54caaae5a6b3773396b0"
186
+ checksum = "7883df5835fafdad87c0d888b266c8ec0f4c9ca48a5bed6bbb592e8dedee1b50"
142
187
  dependencies = [
143
188
  "once_cell",
144
189
  "target-lexicon",
@@ -146,9 +191,9 @@ dependencies = [
146
191
 
147
192
  [[package]]
148
193
  name = "pyo3-ffi"
149
- version = "0.19.1"
194
+ version = "0.21.2"
150
195
  source = "registry+https://github.com/rust-lang/crates.io-index"
151
- checksum = "922ede8759e8600ad4da3195ae41259654b9c55da4f7eec84a0ccc7d067a70a4"
196
+ checksum = "01be5843dc60b916ab4dad1dca6d20b9b4e6ddc8e15f50c47fe6d85f1fb97403"
152
197
  dependencies = [
153
198
  "libc",
154
199
  "pyo3-build-config",
@@ -156,9 +201,9 @@ dependencies = [
156
201
 
157
202
  [[package]]
158
203
  name = "pyo3-log"
159
- version = "0.8.3"
204
+ version = "0.10.0"
160
205
  source = "registry+https://github.com/rust-lang/crates.io-index"
161
- checksum = "f47b0777feb17f61eea78667d61103758b243a871edc09a7786500a50467b605"
206
+ checksum = "2af49834b8d2ecd555177e63b273b708dea75150abc6f5341d0a6e1a9623976c"
162
207
  dependencies = [
163
208
  "arc-swap",
164
209
  "log",
@@ -167,9 +212,9 @@ dependencies = [
167
212
 
168
213
  [[package]]
169
214
  name = "pyo3-macros"
170
- version = "0.19.1"
215
+ version = "0.21.2"
171
216
  source = "registry+https://github.com/rust-lang/crates.io-index"
172
- checksum = "8a5caec6a1dd355964a841fcbeeb1b89fe4146c87295573f94228911af3cc5a2"
217
+ checksum = "77b34069fc0682e11b31dbd10321cbf94808394c56fd996796ce45217dfac53c"
173
218
  dependencies = [
174
219
  "proc-macro2",
175
220
  "pyo3-macros-backend",
@@ -179,11 +224,13 @@ dependencies = [
179
224
 
180
225
  [[package]]
181
226
  name = "pyo3-macros-backend"
182
- version = "0.19.1"
227
+ version = "0.21.2"
183
228
  source = "registry+https://github.com/rust-lang/crates.io-index"
184
- checksum = "e0b78ccbb160db1556cdb6fd96c50334c5d4ec44dc5e0a968d0a1208fa0efa8b"
229
+ checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c"
185
230
  dependencies = [
231
+ "heck",
186
232
  "proc-macro2",
233
+ "pyo3-build-config",
187
234
  "quote",
188
235
  "syn",
189
236
  ]
@@ -197,6 +244,26 @@ dependencies = [
197
244
  "proc-macro2",
198
245
  ]
199
246
 
247
+ [[package]]
248
+ name = "rayon"
249
+ version = "1.10.0"
250
+ source = "registry+https://github.com/rust-lang/crates.io-index"
251
+ checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
252
+ dependencies = [
253
+ "either",
254
+ "rayon-core",
255
+ ]
256
+
257
+ [[package]]
258
+ name = "rayon-core"
259
+ version = "1.12.1"
260
+ source = "registry+https://github.com/rust-lang/crates.io-index"
261
+ checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
262
+ dependencies = [
263
+ "crossbeam-deque",
264
+ "crossbeam-utils",
265
+ ]
266
+
200
267
  [[package]]
201
268
  name = "redox_syscall"
202
269
  version = "0.3.5"
@@ -243,9 +310,9 @@ checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
243
310
 
244
311
  [[package]]
245
312
  name = "syn"
246
- version = "1.0.109"
313
+ version = "2.0.32"
247
314
  source = "registry+https://github.com/rust-lang/crates.io-index"
248
- checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
315
+ checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
249
316
  dependencies = [
250
317
  "proc-macro2",
251
318
  "quote",
@@ -266,9 +333,9 @@ checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73"
266
333
 
267
334
  [[package]]
268
335
  name = "unindent"
269
- version = "0.1.11"
336
+ version = "0.2.3"
270
337
  source = "registry+https://github.com/rust-lang/crates.io-index"
271
- checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c"
338
+ checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
272
339
 
273
340
  [[package]]
274
341
  name = "windows-targets"
@@ -9,11 +9,12 @@ crate-type = ["cdylib", "rlib"]
9
9
 
10
10
  [dependencies]
11
11
  log = "0.4.19"
12
- pyo3-log = "0.8.3"
12
+ pyo3-log = "0.10.0"
13
13
  serde_json = "1.0.103"
14
+ rayon = "1.10"
14
15
 
15
16
  [dependencies.pyo3]
16
- version = "0.19.1"
17
+ version = "0.21.2"
17
18
 
18
19
  [features]
19
20
  extension-module = ["pyo3/extension-module"]
@@ -1,10 +1,9 @@
1
1
  use crate::importgraph::ImportGraph;
2
2
  use std::collections::HashSet;
3
3
 
4
-
5
4
  pub fn check_containers_exist<'a>(
6
5
  graph: &'a ImportGraph,
7
- containers: &'a HashSet<&'a str>,
6
+ containers: &'a HashSet<String>,
8
7
  ) -> Result<(), String> {
9
8
  for container in containers {
10
9
  if !graph.contains_module(container) {
@@ -2,47 +2,45 @@ use crate::dependencies::{PackageDependency, Route};
2
2
  use crate::importgraph::ImportGraph;
3
3
 
4
4
  use log::info;
5
+ use rayon::prelude::*;
5
6
  use std::collections::HashSet;
6
7
  use std::time::Instant;
7
8
 
8
9
  /// A group of layers at the same level in the layering.
9
10
  #[derive(PartialEq, Eq, Hash, Debug)]
10
- pub struct Level<'a> {
11
- pub layers: Vec<&'a str>,
11
+ pub struct Level {
12
+ pub layers: Vec<String>,
12
13
  pub independent: bool,
13
14
  }
14
15
 
15
16
  pub fn find_illegal_dependencies<'a>(
16
17
  graph: &'a ImportGraph,
17
18
  levels: &'a Vec<Level>,
18
- containers: &'a HashSet<&'a str>,
19
+ containers: &'a HashSet<String>,
19
20
  ) -> Vec<PackageDependency> {
20
- let mut dependencies: Vec<PackageDependency> = vec![];
21
21
  let layers = _layers_from_levels(levels);
22
22
 
23
- for (higher_layer_package, lower_layer_package, container) in
24
- _generate_module_permutations(graph, levels, containers)
25
- {
26
- // TODO: it's inefficient to do this for sibling layers, as we don't need
27
- // to clone and trim the graph for identical pairs.
28
- info!(
29
- "Searching for import chains from {} to {}...",
30
- lower_layer_package, higher_layer_package
31
- );
32
- let now = Instant::now();
33
- let dependency_or_none = _search_for_package_dependency(
34
- &higher_layer_package,
35
- &lower_layer_package,
36
- &layers,
37
- &container,
38
- graph,
39
- );
40
- _log_illegal_route_count(&dependency_or_none, now.elapsed().as_secs());
41
- if let Some(dependency) = dependency_or_none {
42
- dependencies.push(dependency);
43
- }
44
- }
45
- dependencies
23
+ _generate_module_permutations(graph, levels, containers)
24
+ .into_par_iter()
25
+ .filter_map(|(higher_layer_package, lower_layer_package, container)| {
26
+ // TODO: it's inefficient to do this for sibling layers, as we don't need
27
+ // to clone and trim the graph for identical pairs.
28
+ info!(
29
+ "Searching for import chains from {} to {}...",
30
+ lower_layer_package, higher_layer_package
31
+ );
32
+ let now = Instant::now();
33
+ let dependency_or_none = _search_for_package_dependency(
34
+ &higher_layer_package,
35
+ &lower_layer_package,
36
+ &layers,
37
+ &container,
38
+ graph,
39
+ );
40
+ _log_illegal_route_count(&dependency_or_none, now.elapsed().as_secs());
41
+ dependency_or_none
42
+ })
43
+ .collect()
46
44
  }
47
45
 
48
46
  /// Return every permutation of modules that exist in the graph
@@ -50,7 +48,7 @@ pub fn find_illegal_dependencies<'a>(
50
48
  fn _generate_module_permutations<'a>(
51
49
  graph: &'a ImportGraph,
52
50
  levels: &'a [Level],
53
- containers: &'a HashSet<&'a str>,
51
+ containers: &'a HashSet<String>,
54
52
  ) -> Vec<(String, String, Option<String>)> {
55
53
  let mut permutations: Vec<(String, String, Option<String>)> = vec![];
56
54
 
@@ -71,7 +69,7 @@ fn _generate_module_permutations<'a>(
71
69
  continue;
72
70
  }
73
71
 
74
- // Build the layers that mustn't import this higher layer.
72
+ // Build the layers that mustn't import this higher layer.
75
73
  // That includes:
76
74
  // * lower layers.
77
75
  // * sibling layers, if the layer is independent.
@@ -164,7 +162,7 @@ fn _search_for_package_dependency<'a>(
164
162
  fn _layers_from_levels<'a>(levels: &'a Vec<Level>) -> Vec<&'a str> {
165
163
  let mut layers: Vec<&str> = vec![];
166
164
  for level in levels {
167
- layers.extend(level.layers.iter());
165
+ layers.extend(level.layers.iter().map(|s| s.as_str()));
168
166
  }
169
167
  layers
170
168
  }
@@ -341,15 +339,19 @@ mod tests {
341
339
  let levels = vec![
342
340
  Level {
343
341
  independent: true,
344
- layers: vec!["high"],
342
+ layers: vec!["high".to_string()],
345
343
  },
346
344
  Level {
347
345
  independent: true,
348
- layers: vec!["mid_a", "mid_b", "mid_c"],
346
+ layers: vec![
347
+ "mid_a".to_string(),
348
+ "mid_b".to_string(),
349
+ "mid_c".to_string(),
350
+ ],
349
351
  },
350
352
  Level {
351
353
  independent: true,
352
- layers: vec!["low"],
354
+ layers: vec!["low".to_string()],
353
355
  },
354
356
  ];
355
357
  let containers = HashSet::new();
@@ -416,14 +418,14 @@ mod tests {
416
418
  let levels = vec![
417
419
  Level {
418
420
  independent: true,
419
- layers: vec!["high"],
421
+ layers: vec!["high".to_string()],
420
422
  },
421
423
  Level {
422
424
  independent: true,
423
- layers: vec!["low"],
425
+ layers: vec!["low".to_string()],
424
426
  },
425
427
  ];
426
- let containers = HashSet::from(["mypackage"]);
428
+ let containers = HashSet::from(["mypackage".to_string()]);
427
429
 
428
430
  let dependencies = find_illegal_dependencies(&graph, &levels, &containers);
429
431
 
@@ -473,18 +475,22 @@ mod tests {
473
475
  let levels = vec![
474
476
  Level {
475
477
  independent: true,
476
- layers: vec!["high"],
478
+ layers: vec!["high".to_string()],
477
479
  },
478
480
  Level {
479
481
  independent: true,
480
- layers: vec!["mid_a", "mid_b", "mid_c"],
482
+ layers: vec![
483
+ "mid_a".to_string(),
484
+ "mid_b".to_string(),
485
+ "mid_c".to_string(),
486
+ ],
481
487
  },
482
488
  Level {
483
489
  independent: true,
484
- layers: vec!["low"],
490
+ layers: vec!["low".to_string()],
485
491
  },
486
492
  ];
487
- let containers = HashSet::from(["mypackage"]);
493
+ let containers = HashSet::from(["mypackage".to_string()]);
488
494
 
489
495
  let perms = _generate_module_permutations(&graph, &levels, &containers);
490
496
 
@@ -593,18 +599,22 @@ mod tests {
593
599
  let levels = vec![
594
600
  Level {
595
601
  independent: true,
596
- layers: vec!["high"],
602
+ layers: vec!["high".to_string()],
597
603
  },
598
604
  Level {
599
605
  independent: false,
600
- layers: vec!["mid_a", "mid_b", "mid_c"],
606
+ layers: vec![
607
+ "mid_a".to_string(),
608
+ "mid_b".to_string(),
609
+ "mid_c".to_string(),
610
+ ],
601
611
  },
602
612
  Level {
603
613
  independent: true,
604
- layers: vec!["low"],
614
+ layers: vec!["low".to_string()],
605
615
  },
606
616
  ];
607
- let containers = HashSet::from(["mypackage"]);
617
+ let containers = HashSet::from(["mypackage".to_string()]);
608
618
 
609
619
  let perms = _generate_module_permutations(&graph, &levels, &containers);
610
620
 
@@ -663,15 +673,19 @@ mod tests {
663
673
  let levels = vec![
664
674
  Level {
665
675
  independent: true,
666
- layers: vec!["high"],
676
+ layers: vec!["high".to_string()],
667
677
  },
668
678
  Level {
669
679
  independent: true,
670
- layers: vec!["medium_a", "medium_b", "medium_c"],
680
+ layers: vec![
681
+ "medium_a".to_string(),
682
+ "medium_b".to_string(),
683
+ "medium_c".to_string(),
684
+ ],
671
685
  },
672
686
  Level {
673
687
  independent: true,
674
- layers: vec!["low"],
688
+ layers: vec!["low".to_string()],
675
689
  },
676
690
  ];
677
691
 
@@ -12,47 +12,79 @@ use log::info;
12
12
  use pyo3::create_exception;
13
13
  use pyo3::prelude::*;
14
14
  use pyo3::types::{PyDict, PyFrozenSet, PySet, PyString, PyTuple};
15
- use std::collections::HashSet;
15
+ use std::collections::{HashMap, HashSet};
16
16
 
17
17
  #[pymodule]
18
- fn _rustgrimp(_py: Python, m: &PyModule) -> PyResult<()> {
18
+ fn _rustgrimp(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
19
19
  pyo3_log::init();
20
20
 
21
21
  m.add_function(wrap_pyfunction!(find_illegal_dependencies, m)?)?;
22
- m.add("NoSuchContainer", _py.get_type::<NoSuchContainer>())?;
22
+ m.add("NoSuchContainer", py.get_type_bound::<NoSuchContainer>())?;
23
23
  Ok(())
24
24
  }
25
25
 
26
26
  create_exception!(_rustgrimp, NoSuchContainer, pyo3::exceptions::PyException);
27
27
 
28
28
  #[pyfunction]
29
- pub fn find_illegal_dependencies<'a>(
30
- py: Python<'a>,
31
- levels: &'a PyTuple,
32
- containers: &'a PySet,
33
- importeds_by_importer: &'a PyDict,
34
- ) -> PyResult<&'a PyTuple> {
29
+ pub fn find_illegal_dependencies<'py>(
30
+ py: Python<'py>,
31
+ levels: &Bound<'py, PyTuple>,
32
+ containers: &Bound<'py, PySet>,
33
+ importeds_by_importer: &Bound<'py, PyDict>,
34
+ ) -> PyResult<Bound<'py, PyTuple>> {
35
35
  info!("Using Rust to find illegal dependencies.");
36
- let graph = ImportGraph::new(importeds_by_importer.extract()?);
37
36
 
37
+ let importeds_by_importer_strings: HashMap<String, HashSet<String>> =
38
+ importeds_by_importer.extract()?;
39
+ let importeds_by_importer_strs = strings_to_strs_hashmap(&importeds_by_importer_strings);
40
+
41
+ let graph = ImportGraph::new(importeds_by_importer_strs);
38
42
  let levels_rust = rustify_levels(levels);
39
- let containers_rust: HashSet<&str> = containers.extract()?;
43
+ let containers_rust: HashSet<String> = containers.extract()?;
40
44
 
41
45
  if let Err(err) = check_containers_exist(&graph, &containers_rust) {
42
46
  return Err(NoSuchContainer::new_err(err));
43
47
  }
44
48
 
45
- let dependencies = layers::find_illegal_dependencies(&graph, &levels_rust, &containers_rust);
49
+ let dependencies = py.allow_threads(|| {
50
+ layers::find_illegal_dependencies(&graph, &levels_rust, &containers_rust)
51
+ });
46
52
 
47
53
  convert_dependencies_to_python(py, dependencies, &graph)
48
54
  }
49
55
 
50
- fn rustify_levels(levels_python: &PyTuple) -> Vec<Level> {
56
+ fn strings_to_strs_hashmap<'a>(
57
+ string_map: &'a HashMap<String, HashSet<String>>,
58
+ ) -> HashMap<&'a str, HashSet<&'a str>> {
59
+ let mut str_map: HashMap<&str, HashSet<&str>> = HashMap::new();
60
+
61
+ for (key, set) in string_map {
62
+ let mut str_set: HashSet<&str> = HashSet::new();
63
+ for item in set.iter() {
64
+ str_set.insert(item);
65
+ }
66
+ str_map.insert(key.as_str(), str_set);
67
+ }
68
+ str_map
69
+ }
70
+
71
+ fn rustify_levels<'a>(levels_python: &Bound<'a, PyTuple>) -> Vec<Level> {
51
72
  let mut rust_levels: Vec<Level> = vec![];
52
73
  for level_python in levels_python.into_iter() {
53
74
  let level_dict = level_python.downcast::<PyDict>().unwrap();
54
- let layers: HashSet<&str> = level_dict.get_item("layers").unwrap().extract().unwrap();
55
- let independent: bool = level_dict.get_item("independent").unwrap().extract().unwrap();
75
+ let layers: HashSet<String> = level_dict
76
+ .get_item("layers")
77
+ .unwrap()
78
+ .unwrap()
79
+ .extract()
80
+ .unwrap();
81
+
82
+ let independent: bool = level_dict
83
+ .get_item("independent")
84
+ .unwrap()
85
+ .unwrap()
86
+ .extract()
87
+ .unwrap();
56
88
  rust_levels.push(Level {
57
89
  independent,
58
90
  layers: layers.into_iter().collect(),
@@ -61,47 +93,47 @@ fn rustify_levels(levels_python: &PyTuple) -> Vec<Level> {
61
93
  rust_levels
62
94
  }
63
95
 
64
- fn convert_dependencies_to_python<'a>(
65
- py: Python<'a>,
96
+ fn convert_dependencies_to_python<'py>(
97
+ py: Python<'py>,
66
98
  dependencies: Vec<PackageDependency>,
67
99
  graph: &ImportGraph,
68
- ) -> PyResult<&'a PyTuple> {
69
- let mut python_dependencies: Vec<&PyDict> = vec![];
100
+ ) -> PyResult<Bound<'py, PyTuple>> {
101
+ let mut python_dependencies: Vec<Bound<'py, PyDict>> = vec![];
70
102
 
71
103
  for rust_dependency in dependencies {
72
- let python_dependency = PyDict::new(py);
104
+ let python_dependency = PyDict::new_bound(py);
73
105
  python_dependency.set_item("imported", graph.names_by_id[&rust_dependency.imported])?;
74
106
  python_dependency.set_item("importer", graph.names_by_id[&rust_dependency.importer])?;
75
- let mut python_routes: Vec<&PyDict> = vec![];
107
+ let mut python_routes: Vec<Bound<'py, PyDict>> = vec![];
76
108
  for rust_route in rust_dependency.routes {
77
- let route = PyDict::new(py);
78
- let heads: Vec<&PyString> = rust_route
109
+ let route = PyDict::new_bound(py);
110
+ let heads: Vec<Bound<'py, PyString>> = rust_route
79
111
  .heads
80
112
  .iter()
81
- .map(|i| PyString::new(py, graph.names_by_id[&i]))
113
+ .map(|i| PyString::new_bound(py, graph.names_by_id[&i]))
82
114
  .collect();
83
- route.set_item("heads", PyFrozenSet::new(py, &heads)?)?;
84
- let middle: Vec<&PyString> = rust_route
115
+ route.set_item("heads", PyFrozenSet::new_bound(py, &heads)?)?;
116
+ let middle: Vec<Bound<'py, PyString>> = rust_route
85
117
  .middle
86
118
  .iter()
87
- .map(|i| PyString::new(py, graph.names_by_id[&i]))
119
+ .map(|i| PyString::new_bound(py, graph.names_by_id[&i]))
88
120
  .collect();
89
- route.set_item("middle", PyTuple::new(py, &middle))?;
90
- let tails: Vec<&PyString> = rust_route
121
+ route.set_item("middle", PyTuple::new_bound(py, &middle))?;
122
+ let tails: Vec<Bound<'py, PyString>> = rust_route
91
123
  .tails
92
124
  .iter()
93
- .map(|i| PyString::new(py, graph.names_by_id[&i]))
125
+ .map(|i| PyString::new_bound(py, graph.names_by_id[&i]))
94
126
  .collect();
95
- route.set_item("tails", PyFrozenSet::new(py, &tails)?)?;
127
+ route.set_item("tails", PyFrozenSet::new_bound(py, &tails)?)?;
96
128
 
97
129
  python_routes.push(route);
98
130
  }
99
131
 
100
- python_dependency.set_item("routes", PyTuple::new(py, python_routes))?;
132
+ python_dependency.set_item("routes", PyTuple::new_bound(py, python_routes))?;
101
133
  python_dependencies.push(python_dependency)
102
134
  }
103
135
 
104
- Ok(PyTuple::new(py, python_dependencies))
136
+ Ok(PyTuple::new_bound(py, python_dependencies))
105
137
  }
106
138
 
107
139
  #[cfg(test)]
@@ -113,7 +145,7 @@ mod tests {
113
145
  macro_rules! pydict {
114
146
  ($py: ident, {$($k: expr => $v: expr),*, $(,)?}) => {
115
147
  {
116
- let dict = PyDict::new($py);
148
+ let dict = PyDict::new_bound($py);
117
149
  $(
118
150
  dict.set_item($k, $v)?;
119
151
  )*
@@ -126,7 +158,7 @@ mod tests {
126
158
  fn test_rustify_levels_no_sibling_layers() {
127
159
  pyo3::prepare_freethreaded_python();
128
160
  Python::with_gil(|py| -> PyResult<()> {
129
- let elements: Vec<&PyDict> = vec![
161
+ let elements = vec![
130
162
  pydict! (py, {
131
163
  "independent" => true,
132
164
  "layers" => HashSet::from(["high"]),
@@ -138,26 +170,26 @@ mod tests {
138
170
  pydict! (py, {
139
171
  "independent" => true,
140
172
  "layers" => HashSet::from(["low"]),
141
- })
173
+ }),
142
174
  ];
143
- let python_levels: &PyTuple = PyTuple::new(py, elements);
175
+ let python_levels = PyTuple::new_bound(py, elements);
144
176
 
145
- let result = rustify_levels(python_levels);
177
+ let result = rustify_levels(&python_levels);
146
178
 
147
179
  assert_eq!(
148
180
  result,
149
181
  vec![
150
182
  Level {
151
183
  independent: true,
152
- layers: vec!["high"]
184
+ layers: vec!["high".to_string()]
153
185
  },
154
186
  Level {
155
187
  independent: true,
156
- layers: vec!["medium"]
188
+ layers: vec!["medium".to_string()]
157
189
  },
158
190
  Level {
159
191
  independent: true,
160
- layers: vec!["low"]
192
+ layers: vec!["low".to_string()]
161
193
  }
162
194
  ]
163
195
  );
@@ -171,7 +203,7 @@ mod tests {
171
203
  fn test_rustify_levels_sibling_layers() {
172
204
  pyo3::prepare_freethreaded_python();
173
205
  Python::with_gil(|py| -> PyResult<()> {
174
- let elements: Vec<&PyDict> = vec![
206
+ let elements = vec![
175
207
  pydict! (py, {
176
208
  "independent" => true,
177
209
  "layers" => HashSet::from(["high"]),
@@ -187,11 +219,11 @@ mod tests {
187
219
  pydict! (py, {
188
220
  "independent" => true,
189
221
  "layers" => HashSet::from(["low"]),
190
- })
222
+ }),
191
223
  ];
192
- let python_levels: &PyTuple = PyTuple::new(py, elements);
224
+ let python_levels = PyTuple::new_bound(py, elements);
193
225
 
194
- let mut result = rustify_levels(python_levels);
226
+ let mut result = rustify_levels(&python_levels);
195
227
 
196
228
  for level in &mut result {
197
229
  level.layers.sort();
@@ -201,19 +233,23 @@ mod tests {
201
233
  vec![
202
234
  Level {
203
235
  independent: true,
204
- layers: vec!["high"]
236
+ layers: vec!["high".to_string()]
205
237
  },
206
238
  Level {
207
239
  independent: true,
208
- layers: vec!["blue", "green", "orange"]
240
+ layers: vec![
241
+ "blue".to_string(),
242
+ "green".to_string(),
243
+ "orange".to_string()
244
+ ]
209
245
  },
210
246
  Level {
211
247
  independent: false,
212
- layers: vec!["red", "yellow"]
248
+ layers: vec!["red".to_string(), "yellow".to_string()]
213
249
  },
214
250
  Level {
215
251
  independent: true,
216
- layers: vec!["low"]
252
+ layers: vec!["low".to_string()]
217
253
  }
218
254
  ]
219
255
  );
@@ -22,26 +22,26 @@ fn test_large_graph() {
22
22
  let levels = vec![
23
23
  Level {
24
24
  independent: true,
25
- layers: vec!["plugins"],
25
+ layers: vec!["plugins".to_string()],
26
26
  },
27
27
  Level {
28
28
  independent: true,
29
- layers: vec!["interfaces"],
29
+ layers: vec!["interfaces".to_string()],
30
30
  },
31
31
  Level {
32
32
  independent: true,
33
- layers: vec!["application"],
33
+ layers: vec!["application".to_string()],
34
34
  },
35
35
  Level {
36
36
  independent: true,
37
- layers: vec!["domain"],
37
+ layers: vec!["domain".to_string()],
38
38
  },
39
39
  Level {
40
40
  independent: true,
41
- layers: vec!["data"],
41
+ layers: vec!["data".to_string()],
42
42
  },
43
43
  ];
44
- let containers = HashSet::from(["mypackage"]);
44
+ let containers = HashSet::from(["mypackage".to_string()]);
45
45
 
46
46
  find_illegal_dependencies(&graph, &levels, &containers);
47
47
  }
@@ -1,4 +1,4 @@
1
- __version__ = "3.2"
1
+ __version__ = "3.3"
2
2
 
3
3
  from .application.ports.graph import DetailedImport, ImportGraph
4
4
  from .domain.analysis import PackageDependency, Route
@@ -18,7 +18,7 @@ class FileSystem(AbstractFileSystem):
18
18
  return os.path.dirname(filename)
19
19
 
20
20
  def walk(self, directory_name: str) -> Iterator[Tuple[str, List[str], List[str]]]:
21
- yield from os.walk(directory_name)
21
+ yield from os.walk(directory_name, followlinks=True)
22
22
 
23
23
  def join(self, *components: str) -> str:
24
24
  return os.path.join(*components)
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