grimp 3.13__tar.gz → 3.14__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 (51) hide show
  1. {grimp-3.13 → grimp-3.14}/PKG-INFO +26 -10
  2. {grimp-3.13 → grimp-3.14}/README.rst +24 -7
  3. {grimp-3.13 → grimp-3.14}/pyproject.toml +3 -3
  4. {grimp-3.13 → grimp-3.14}/rust/Cargo.lock +192 -27
  5. {grimp-3.13 → grimp-3.14}/rust/Cargo.toml +3 -3
  6. grimp-3.14/rust/src/caching.rs +125 -0
  7. {grimp-3.13 → grimp-3.14}/rust/src/filesystem.rs +46 -18
  8. {grimp-3.13 → grimp-3.14}/rust/src/import_parsing.rs +1 -1
  9. {grimp-3.13 → grimp-3.14}/rust/src/import_scanning.rs +23 -4
  10. {grimp-3.13 → grimp-3.14}/rust/src/lib.rs +3 -0
  11. {grimp-3.13 → grimp-3.14}/rust/src/module_finding.rs +19 -2
  12. {grimp-3.13 → grimp-3.14}/src/grimp/__init__.py +1 -1
  13. {grimp-3.13 → grimp-3.14}/src/grimp/adaptors/caching.py +26 -37
  14. {grimp-3.13 → grimp-3.14}/src/grimp/adaptors/filesystem.py +3 -3
  15. grimp-3.14/src/grimp/adaptors/modulefinder.py +172 -0
  16. {grimp-3.13 → grimp-3.14}/src/grimp/adaptors/packagefinder.py +6 -14
  17. {grimp-3.13 → grimp-3.14}/src/grimp/application/graph.py +18 -17
  18. {grimp-3.13 → grimp-3.14}/src/grimp/application/ports/caching.py +9 -11
  19. {grimp-3.13 → grimp-3.14}/src/grimp/application/ports/filesystem.py +7 -5
  20. {grimp-3.13 → grimp-3.14}/src/grimp/application/ports/modulefinder.py +5 -4
  21. {grimp-3.13 → grimp-3.14}/src/grimp/application/ports/packagefinder.py +2 -2
  22. {grimp-3.13 → grimp-3.14}/src/grimp/application/scanning.py +3 -3
  23. {grimp-3.13 → grimp-3.14}/src/grimp/application/usecases.py +34 -25
  24. {grimp-3.13 → grimp-3.14}/src/grimp/domain/analysis.py +3 -3
  25. {grimp-3.13 → grimp-3.14}/src/grimp/domain/valueobjects.py +4 -5
  26. {grimp-3.13 → grimp-3.14}/src/grimp/exceptions.py +1 -4
  27. grimp-3.13/rust/src/caching.rs +0 -55
  28. grimp-3.13/src/grimp/adaptors/modulefinder.py +0 -109
  29. {grimp-3.13 → grimp-3.14}/rust/.cargo/config.toml +0 -0
  30. {grimp-3.13 → grimp-3.14}/rust/src/errors.rs +0 -0
  31. {grimp-3.13 → grimp-3.14}/rust/src/exceptions.rs +0 -0
  32. {grimp-3.13 → grimp-3.14}/rust/src/graph/cycle_breakers.rs +0 -0
  33. {grimp-3.13 → grimp-3.14}/rust/src/graph/direct_import_queries.rs +0 -0
  34. {grimp-3.13 → grimp-3.14}/rust/src/graph/graph_manipulation.rs +0 -0
  35. {grimp-3.13 → grimp-3.14}/rust/src/graph/hierarchy_queries.rs +0 -0
  36. {grimp-3.13 → grimp-3.14}/rust/src/graph/higher_order_queries.rs +0 -0
  37. {grimp-3.13 → grimp-3.14}/rust/src/graph/import_chain_queries.rs +0 -0
  38. {grimp-3.13 → grimp-3.14}/rust/src/graph/mod.rs +0 -0
  39. {grimp-3.13 → grimp-3.14}/rust/src/graph/pathfinding.rs +0 -0
  40. {grimp-3.13 → grimp-3.14}/rust/src/module_expressions.rs +0 -0
  41. {grimp-3.13 → grimp-3.14}/rust/tests/large.rs +0 -0
  42. {grimp-3.13 → grimp-3.14}/rust/tests/large_graph.json +0 -0
  43. {grimp-3.13 → grimp-3.14}/src/grimp/adaptors/__init__.py +0 -0
  44. {grimp-3.13 → grimp-3.14}/src/grimp/adaptors/timing.py +0 -0
  45. {grimp-3.13 → grimp-3.14}/src/grimp/application/__init__.py +0 -0
  46. {grimp-3.13 → grimp-3.14}/src/grimp/application/config.py +0 -0
  47. {grimp-3.13 → grimp-3.14}/src/grimp/application/ports/__init__.py +0 -0
  48. {grimp-3.13 → grimp-3.14}/src/grimp/application/ports/timing.py +0 -0
  49. {grimp-3.13 → grimp-3.14}/src/grimp/domain/__init__.py +0 -0
  50. {grimp-3.13 → grimp-3.14}/src/grimp/main.py +0 -0
  51. {grimp-3.13 → grimp-3.14}/src/grimp/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: grimp
3
- Version: 3.13
3
+ Version: 3.14
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,6 @@ Classifier: Operating System :: Unix
8
8
  Classifier: Operating System :: POSIX
9
9
  Classifier: Operating System :: Microsoft :: Windows
10
10
  Classifier: Programming Language :: Python
11
- Classifier: Programming Language :: Python :: 3.9
12
11
  Classifier: Programming Language :: Python :: 3.10
13
12
  Classifier: Programming Language :: Python :: 3.11
14
13
  Classifier: Programming Language :: Python :: 3.12
@@ -23,7 +22,7 @@ License-File: AUTHORS.rst
23
22
  Summary: Builds a queryable graph of the imports within one or more Python packages.
24
23
  Author-email: David Seddon <david@seddonym.me>
25
24
  License: BSD 2-Clause License
26
- Requires-Python: >=3.9
25
+ Requires-Python: >=3.10
27
26
  Description-Content-Type: text/x-rst; charset=UTF-8
28
27
  Project-URL: Documentation, https://grimp.readthedocs.io/
29
28
  Project-URL: Source-code, https://github.com/python-grimp/grimp/
@@ -144,20 +143,37 @@ You may analyse multiple root packages. To do this, pass each package name as a
144
143
  Namespace packages
145
144
  ------------------
146
145
 
147
- Graphs can also be built from `portions`_ of `namespace packages`_. To do this, provide the portion name, rather than the namespace name::
148
-
149
- >>> graph = grimp.build_graph('somenamespace.foo')
146
+ Graphs can be built either from `namespace packages`_ or from their `portions`_.
150
147
 
151
148
  What's a namespace package?
152
149
  ###########################
153
150
 
154
- Namespace packages are a Python feature allows subpackages to be distributed independently, while still importable under a shared namespace. This is, for example, used by `the Python client for Google's Cloud Logging API`_. When installed, it is importable in Python as ``google.cloud.logging``. The parent packages ``google`` and ``google.cloud`` are both namespace packages, while ``google.cloud.logging`` is known as the 'portion'. Other portions in the same namespace can be installed separately, for example ``google.cloud.secretmanager``.
151
+ Namespace packages are a Python feature allows subpackages to be distributed independently, while
152
+ still importable under a shared namespace.
153
+
154
+ This is used by
155
+ `the Python client for Google's Cloud Logging API`_, for example. When installed, it is importable
156
+ in Python as ``google.cloud.logging``. The parent packages ``google`` and ``google.cloud`` are both namespace
157
+ packages, while ``google.cloud.logging`` is known as the 'portion'. Other portions in the same
158
+ namespace can be installed separately, for example ``google.cloud.secretmanager``.
159
+
160
+ Examples::
161
+
162
+ # In this one, the portion is supplied. Neither "google" nor "google.cloud"
163
+ # will appear in the graph.
164
+ >>> graph = grimp.build_graph("google.cloud.logging")
165
+
166
+ # In this one, a namespace is supplied.
167
+ # Neither "google" nor "google.cloud" will appear in the graph,
168
+ # as will other installed packages under the "google" namespace such
169
+ # as "google.auth".
170
+ >>> graph = grimp.build_graph("google")
155
171
 
156
- Grimp expects the package name passed to ``build_graph`` to be a portion, rather than a namespace package. So in the case of the example above, the graph should be built like so::
172
+ # This one supplies a subnamespace of "google" - it will include
173
+ # "google.cloud.logging" and "google.cloud.secretmanager" but not "google.auth".
174
+ >>> graph = grimp.build_graph("google.cloud")
157
175
 
158
- >>> graph = grimp.build_graph('google.cloud.logging')
159
176
 
160
- If, instead, a namespace package is passed (e.g. ``grimp.build_graph('google.cloud')``), Grimp will raise ``NamespacePackageEncountered``.
161
177
 
162
178
  .. _portions: https://docs.python.org/3/glossary.html#term-portion
163
179
  .. _namespace packages: https://docs.python.org/3/glossary.html#term-namespace-package
@@ -114,20 +114,37 @@ You may analyse multiple root packages. To do this, pass each package name as a
114
114
  Namespace packages
115
115
  ------------------
116
116
 
117
- Graphs can also be built from `portions`_ of `namespace packages`_. To do this, provide the portion name, rather than the namespace name::
118
-
119
- >>> graph = grimp.build_graph('somenamespace.foo')
117
+ Graphs can be built either from `namespace packages`_ or from their `portions`_.
120
118
 
121
119
  What's a namespace package?
122
120
  ###########################
123
121
 
124
- Namespace packages are a Python feature allows subpackages to be distributed independently, while still importable under a shared namespace. This is, for example, used by `the Python client for Google's Cloud Logging API`_. When installed, it is importable in Python as ``google.cloud.logging``. The parent packages ``google`` and ``google.cloud`` are both namespace packages, while ``google.cloud.logging`` is known as the 'portion'. Other portions in the same namespace can be installed separately, for example ``google.cloud.secretmanager``.
122
+ Namespace packages are a Python feature allows subpackages to be distributed independently, while
123
+ still importable under a shared namespace.
124
+
125
+ This is used by
126
+ `the Python client for Google's Cloud Logging API`_, for example. When installed, it is importable
127
+ in Python as ``google.cloud.logging``. The parent packages ``google`` and ``google.cloud`` are both namespace
128
+ packages, while ``google.cloud.logging`` is known as the 'portion'. Other portions in the same
129
+ namespace can be installed separately, for example ``google.cloud.secretmanager``.
130
+
131
+ Examples::
132
+
133
+ # In this one, the portion is supplied. Neither "google" nor "google.cloud"
134
+ # will appear in the graph.
135
+ >>> graph = grimp.build_graph("google.cloud.logging")
136
+
137
+ # In this one, a namespace is supplied.
138
+ # Neither "google" nor "google.cloud" will appear in the graph,
139
+ # as will other installed packages under the "google" namespace such
140
+ # as "google.auth".
141
+ >>> graph = grimp.build_graph("google")
125
142
 
126
- Grimp expects the package name passed to ``build_graph`` to be a portion, rather than a namespace package. So in the case of the example above, the graph should be built like so::
143
+ # This one supplies a subnamespace of "google" - it will include
144
+ # "google.cloud.logging" and "google.cloud.secretmanager" but not "google.auth".
145
+ >>> graph = grimp.build_graph("google.cloud")
127
146
 
128
- >>> graph = grimp.build_graph('google.cloud.logging')
129
147
 
130
- If, instead, a namespace package is passed (e.g. ``grimp.build_graph('google.cloud')``), Grimp will raise ``NamespacePackageEncountered``.
131
148
 
132
149
  .. _portions: https://docs.python.org/3/glossary.html#term-portion
133
150
  .. _namespace packages: https://docs.python.org/3/glossary.html#term-namespace-package
@@ -8,13 +8,13 @@ module-name = "grimp._rustgrimp"
8
8
 
9
9
  [project]
10
10
  name = "grimp"
11
- version = "3.13"
11
+ version = "3.14"
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 = [
15
15
  {name = "David Seddon", email = "david@seddonym.me"},
16
16
  ]
17
- requires-python = ">=3.9"
17
+ requires-python = ">=3.10"
18
18
  dependencies = [
19
19
  "typing-extensions>=3.10.0.0",
20
20
  ]
@@ -26,7 +26,6 @@ classifiers = [
26
26
  "Operating System :: POSIX",
27
27
  "Operating System :: Microsoft :: Windows",
28
28
  "Programming Language :: Python",
29
- "Programming Language :: Python :: 3.9",
30
29
  "Programming Language :: Python :: 3.10",
31
30
  "Programming Language :: Python :: 3.11",
32
31
  "Programming Language :: Python :: 3.12",
@@ -61,6 +60,7 @@ dev = [
61
60
  "requests==2.32.3",
62
61
  "sqlalchemy==2.0.35",
63
62
  "google-cloud-audit-log==0.3.0",
63
+ "pyupgrade>=3.21.0",
64
64
  ]
65
65
  docs = [
66
66
  "sphinx>=7.4.7",
@@ -12,7 +12,7 @@ dependencies = [
12
12
  "encoding_rs",
13
13
  "getset",
14
14
  "indexmap 2.11.0",
15
- "itertools 0.14.0",
15
+ "itertools",
16
16
  "parameterized",
17
17
  "pyo3",
18
18
  "rayon",
@@ -20,7 +20,7 @@ dependencies = [
20
20
  "ruff_python_ast",
21
21
  "ruff_python_parser",
22
22
  "ruff_source_file",
23
- "rustc-hash 2.1.1",
23
+ "rustc-hash",
24
24
  "serde",
25
25
  "serde_json",
26
26
  "serde_yaml",
@@ -40,6 +40,36 @@ dependencies = [
40
40
  "memchr",
41
41
  ]
42
42
 
43
+ [[package]]
44
+ name = "attribute-derive"
45
+ version = "0.10.5"
46
+ source = "registry+https://github.com/rust-lang/crates.io-index"
47
+ checksum = "05832cdddc8f2650cc2cc187cc2e952b8c133a48eb055f35211f61ee81502d77"
48
+ dependencies = [
49
+ "attribute-derive-macro",
50
+ "derive-where",
51
+ "manyhow",
52
+ "proc-macro2",
53
+ "quote",
54
+ "syn",
55
+ ]
56
+
57
+ [[package]]
58
+ name = "attribute-derive-macro"
59
+ version = "0.10.5"
60
+ source = "registry+https://github.com/rust-lang/crates.io-index"
61
+ checksum = "0a7cdbbd4bd005c5d3e2e9c885e6fa575db4f4a3572335b974d8db853b6beb61"
62
+ dependencies = [
63
+ "collection_literals",
64
+ "interpolator",
65
+ "manyhow",
66
+ "proc-macro-utils",
67
+ "proc-macro2",
68
+ "quote",
69
+ "quote-use",
70
+ "syn",
71
+ ]
72
+
43
73
  [[package]]
44
74
  name = "autocfg"
45
75
  version = "1.5.0"
@@ -69,12 +99,41 @@ dependencies = [
69
99
  "serde",
70
100
  ]
71
101
 
102
+ [[package]]
103
+ name = "castaway"
104
+ version = "0.2.4"
105
+ source = "registry+https://github.com/rust-lang/crates.io-index"
106
+ checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
107
+ dependencies = [
108
+ "rustversion",
109
+ ]
110
+
72
111
  [[package]]
73
112
  name = "cfg-if"
74
113
  version = "1.0.3"
75
114
  source = "registry+https://github.com/rust-lang/crates.io-index"
76
115
  checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
77
116
 
117
+ [[package]]
118
+ name = "collection_literals"
119
+ version = "1.0.3"
120
+ source = "registry+https://github.com/rust-lang/crates.io-index"
121
+ checksum = "2550f75b8cfac212855f6b1885455df8eaee8fe8e246b647d69146142e016084"
122
+
123
+ [[package]]
124
+ name = "compact_str"
125
+ version = "0.9.0"
126
+ source = "registry+https://github.com/rust-lang/crates.io-index"
127
+ checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a"
128
+ dependencies = [
129
+ "castaway",
130
+ "cfg-if",
131
+ "itoa",
132
+ "rustversion",
133
+ "ryu",
134
+ "static_assertions",
135
+ ]
136
+
78
137
  [[package]]
79
138
  name = "const_format"
80
139
  version = "0.2.34"
@@ -131,6 +190,17 @@ dependencies = [
131
190
  "syn",
132
191
  ]
133
192
 
193
+ [[package]]
194
+ name = "derive-where"
195
+ version = "1.6.0"
196
+ source = "registry+https://github.com/rust-lang/crates.io-index"
197
+ checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f"
198
+ dependencies = [
199
+ "proc-macro2",
200
+ "quote",
201
+ "syn",
202
+ ]
203
+
134
204
  [[package]]
135
205
  name = "either"
136
206
  version = "1.15.0"
@@ -158,6 +228,29 @@ version = "0.1.5"
158
228
  source = "registry+https://github.com/rust-lang/crates.io-index"
159
229
  checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
160
230
 
231
+ [[package]]
232
+ name = "get-size-derive2"
233
+ version = "0.7.3"
234
+ source = "registry+https://github.com/rust-lang/crates.io-index"
235
+ checksum = "ab21d7bd2c625f2064f04ce54bcb88bc57c45724cde45cba326d784e22d3f71a"
236
+ dependencies = [
237
+ "attribute-derive",
238
+ "quote",
239
+ "syn",
240
+ ]
241
+
242
+ [[package]]
243
+ name = "get-size2"
244
+ version = "0.7.3"
245
+ source = "registry+https://github.com/rust-lang/crates.io-index"
246
+ checksum = "879272b0de109e2b67b39fcfe3d25fdbba96ac07e44a254f5a0b4d7ff55340cb"
247
+ dependencies = [
248
+ "compact_str",
249
+ "get-size-derive2",
250
+ "hashbrown 0.16.1",
251
+ "smallvec",
252
+ ]
253
+
161
254
  [[package]]
162
255
  name = "getopts"
163
256
  version = "0.2.24"
@@ -205,6 +298,12 @@ dependencies = [
205
298
  "foldhash",
206
299
  ]
207
300
 
301
+ [[package]]
302
+ name = "hashbrown"
303
+ version = "0.16.1"
304
+ source = "registry+https://github.com/rust-lang/crates.io-index"
305
+ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
306
+
208
307
  [[package]]
209
308
  name = "heck"
210
309
  version = "0.5.0"
@@ -237,6 +336,12 @@ version = "2.0.6"
237
336
  source = "registry+https://github.com/rust-lang/crates.io-index"
238
337
  checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
239
338
 
339
+ [[package]]
340
+ name = "interpolator"
341
+ version = "0.5.0"
342
+ source = "registry+https://github.com/rust-lang/crates.io-index"
343
+ checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8"
344
+
240
345
  [[package]]
241
346
  name = "is-macro"
242
347
  version = "0.3.7"
@@ -249,15 +354,6 @@ dependencies = [
249
354
  "syn",
250
355
  ]
251
356
 
252
- [[package]]
253
- name = "itertools"
254
- version = "0.13.0"
255
- source = "registry+https://github.com/rust-lang/crates.io-index"
256
- checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
257
- dependencies = [
258
- "either",
259
- ]
260
-
261
357
  [[package]]
262
358
  name = "itertools"
263
359
  version = "0.14.0"
@@ -285,6 +381,29 @@ version = "0.4.28"
285
381
  source = "registry+https://github.com/rust-lang/crates.io-index"
286
382
  checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
287
383
 
384
+ [[package]]
385
+ name = "manyhow"
386
+ version = "0.11.4"
387
+ source = "registry+https://github.com/rust-lang/crates.io-index"
388
+ checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587"
389
+ dependencies = [
390
+ "manyhow-macros",
391
+ "proc-macro2",
392
+ "quote",
393
+ "syn",
394
+ ]
395
+
396
+ [[package]]
397
+ name = "manyhow-macros"
398
+ version = "0.11.4"
399
+ source = "registry+https://github.com/rust-lang/crates.io-index"
400
+ checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495"
401
+ dependencies = [
402
+ "proc-macro-utils",
403
+ "proc-macro2",
404
+ "quote",
405
+ ]
406
+
288
407
  [[package]]
289
408
  name = "memchr"
290
409
  version = "2.7.5"
@@ -402,6 +521,17 @@ dependencies = [
402
521
  "syn",
403
522
  ]
404
523
 
524
+ [[package]]
525
+ name = "proc-macro-utils"
526
+ version = "0.10.0"
527
+ source = "registry+https://github.com/rust-lang/crates.io-index"
528
+ checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071"
529
+ dependencies = [
530
+ "proc-macro2",
531
+ "quote",
532
+ "smallvec",
533
+ ]
534
+
405
535
  [[package]]
406
536
  name = "proc-macro2"
407
537
  version = "1.0.101"
@@ -481,6 +611,28 @@ dependencies = [
481
611
  "proc-macro2",
482
612
  ]
483
613
 
614
+ [[package]]
615
+ name = "quote-use"
616
+ version = "0.8.4"
617
+ source = "registry+https://github.com/rust-lang/crates.io-index"
618
+ checksum = "9619db1197b497a36178cfc736dc96b271fe918875fbf1344c436a7e93d0321e"
619
+ dependencies = [
620
+ "quote",
621
+ "quote-use-macros",
622
+ ]
623
+
624
+ [[package]]
625
+ name = "quote-use-macros"
626
+ version = "0.8.4"
627
+ source = "registry+https://github.com/rust-lang/crates.io-index"
628
+ checksum = "82ebfb7faafadc06a7ab141a6f67bcfb24cb8beb158c6fe933f2f035afa99f35"
629
+ dependencies = [
630
+ "proc-macro-utils",
631
+ "proc-macro2",
632
+ "quote",
633
+ "syn",
634
+ ]
635
+
484
636
  [[package]]
485
637
  name = "rand"
486
638
  version = "0.8.5"
@@ -563,31 +715,36 @@ checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
563
715
  [[package]]
564
716
  name = "ruff_python_ast"
565
717
  version = "0.0.0"
566
- source = "git+https://github.com/astral-sh/ruff.git?tag=v0.4.10#b54922fd7394c36cdc390fd21aaee99206ebc361"
718
+ source = "git+https://github.com/astral-sh/ruff.git?tag=0.14.8#9d4f1c6ae24b75642a586531f4c668213fbac3fb"
567
719
  dependencies = [
568
720
  "aho-corasick",
569
721
  "bitflags",
722
+ "compact_str",
723
+ "get-size2",
570
724
  "is-macro",
571
- "itertools 0.13.0",
572
- "once_cell",
725
+ "itertools",
726
+ "memchr",
573
727
  "ruff_python_trivia",
574
728
  "ruff_source_file",
575
729
  "ruff_text_size",
576
- "rustc-hash 1.1.0",
730
+ "rustc-hash",
731
+ "thiserror",
577
732
  ]
578
733
 
579
734
  [[package]]
580
735
  name = "ruff_python_parser"
581
736
  version = "0.0.0"
582
- source = "git+https://github.com/astral-sh/ruff.git?tag=v0.4.10#b54922fd7394c36cdc390fd21aaee99206ebc361"
737
+ source = "git+https://github.com/astral-sh/ruff.git?tag=0.14.8#9d4f1c6ae24b75642a586531f4c668213fbac3fb"
583
738
  dependencies = [
584
739
  "bitflags",
585
740
  "bstr",
741
+ "compact_str",
742
+ "get-size2",
586
743
  "memchr",
587
744
  "ruff_python_ast",
588
745
  "ruff_python_trivia",
589
746
  "ruff_text_size",
590
- "rustc-hash 1.1.0",
747
+ "rustc-hash",
591
748
  "static_assertions",
592
749
  "unicode-ident",
593
750
  "unicode-normalization",
@@ -597,9 +754,9 @@ dependencies = [
597
754
  [[package]]
598
755
  name = "ruff_python_trivia"
599
756
  version = "0.0.0"
600
- source = "git+https://github.com/astral-sh/ruff.git?tag=v0.4.10#b54922fd7394c36cdc390fd21aaee99206ebc361"
757
+ source = "git+https://github.com/astral-sh/ruff.git?tag=0.14.8#9d4f1c6ae24b75642a586531f4c668213fbac3fb"
601
758
  dependencies = [
602
- "itertools 0.13.0",
759
+ "itertools",
603
760
  "ruff_source_file",
604
761
  "ruff_text_size",
605
762
  "unicode-ident",
@@ -608,29 +765,31 @@ dependencies = [
608
765
  [[package]]
609
766
  name = "ruff_source_file"
610
767
  version = "0.0.0"
611
- source = "git+https://github.com/astral-sh/ruff.git?tag=v0.4.10#b54922fd7394c36cdc390fd21aaee99206ebc361"
768
+ source = "git+https://github.com/astral-sh/ruff.git?tag=0.14.8#9d4f1c6ae24b75642a586531f4c668213fbac3fb"
612
769
  dependencies = [
613
770
  "memchr",
614
- "once_cell",
615
771
  "ruff_text_size",
616
772
  ]
617
773
 
618
774
  [[package]]
619
775
  name = "ruff_text_size"
620
776
  version = "0.0.0"
621
- source = "git+https://github.com/astral-sh/ruff.git?tag=v0.4.10#b54922fd7394c36cdc390fd21aaee99206ebc361"
777
+ source = "git+https://github.com/astral-sh/ruff.git?tag=0.14.8#9d4f1c6ae24b75642a586531f4c668213fbac3fb"
778
+ dependencies = [
779
+ "get-size2",
780
+ ]
622
781
 
623
782
  [[package]]
624
783
  name = "rustc-hash"
625
- version = "1.1.0"
784
+ version = "2.1.1"
626
785
  source = "registry+https://github.com/rust-lang/crates.io-index"
627
- checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
786
+ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
628
787
 
629
788
  [[package]]
630
- name = "rustc-hash"
631
- version = "2.1.1"
789
+ name = "rustversion"
790
+ version = "1.0.22"
632
791
  source = "registry+https://github.com/rust-lang/crates.io-index"
633
- checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
792
+ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
634
793
 
635
794
  [[package]]
636
795
  name = "ryu"
@@ -698,6 +857,12 @@ dependencies = [
698
857
  "version_check",
699
858
  ]
700
859
 
860
+ [[package]]
861
+ name = "smallvec"
862
+ version = "1.15.1"
863
+ source = "registry+https://github.com/rust-lang/crates.io-index"
864
+ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
865
+
701
866
  [[package]]
702
867
  name = "static_assertions"
703
868
  version = "1.1.0"
@@ -21,9 +21,9 @@ rustc-hash = "2.1.1"
21
21
  indexmap = "2.11.0"
22
22
  regex = "1.11.2"
23
23
  const_format = "0.2.34"
24
- ruff_python_parser = { git = "https://github.com/astral-sh/ruff.git", tag = "v0.4.10" }
25
- ruff_python_ast = { git = "https://github.com/astral-sh/ruff.git", tag = "v0.4.10" }
26
- ruff_source_file = { git = "https://github.com/astral-sh/ruff.git", tag = "v0.4.10" }
24
+ ruff_python_parser = { git = "https://github.com/astral-sh/ruff.git", tag = "0.14.8" }
25
+ ruff_python_ast = { git = "https://github.com/astral-sh/ruff.git", tag = "0.14.8" }
26
+ ruff_source_file = { git = "https://github.com/astral-sh/ruff.git", tag = "0.14.8" }
27
27
  serde = { version = "1.0", features = ["derive"] }
28
28
  serde_json = "1.0.137"
29
29
  serde_yaml = "0.9"
@@ -0,0 +1,125 @@
1
+ use crate::errors::{GrimpError, GrimpResult};
2
+ use crate::filesystem::get_file_system_boxed;
3
+ use crate::import_scanning::{DirectImport, imports_by_module_to_py};
4
+ use crate::module_finding::Module;
5
+ use pyo3::types::PyAnyMethods;
6
+ use pyo3::types::{PyDict, PySet};
7
+ use pyo3::types::{PyDictMethods, PySetMethods};
8
+ use pyo3::{Bound, FromPyObject, PyAny, PyResult, Python, pyfunction};
9
+ use std::collections::{HashMap, HashSet};
10
+
11
+ /// Writes the cache file containing all the imports for a given package.
12
+ /// Args:
13
+ /// - filename: str
14
+ /// - imports_by_module: dict[Module, Set[DirectImport]]
15
+ /// - file_system: The file system interface to use. (A BasicFileSystem.)
16
+ #[pyfunction]
17
+ pub fn write_cache_data_map_file<'py>(
18
+ filename: &str,
19
+ imports_by_module: Bound<'py, PyDict>,
20
+ file_system: Bound<'py, PyAny>,
21
+ ) -> PyResult<()> {
22
+ let mut file_system_boxed = get_file_system_boxed(&file_system)?;
23
+
24
+ let ImportsByModule(imports_by_module_rust) = imports_by_module.extract()?;
25
+
26
+ let file_contents = serialize_imports_by_module(&imports_by_module_rust);
27
+
28
+ file_system_boxed.write(filename, &file_contents)?;
29
+
30
+ Ok(())
31
+ }
32
+
33
+ /// Reads the cache file containing all the imports for a given package.
34
+ /// Args:
35
+ /// - filename: str
36
+ /// - file_system: The file system interface to use. (A BasicFileSystem.)
37
+ /// Returns Dict[Module, Set[DirectImport]]
38
+ #[pyfunction]
39
+ pub fn read_cache_data_map_file<'py>(
40
+ py: Python<'py>,
41
+ filename: &str,
42
+ file_system: Bound<'py, PyAny>,
43
+ ) -> PyResult<Bound<'py, PyDict>> {
44
+ let file_system_boxed = get_file_system_boxed(&file_system)?;
45
+
46
+ let file_contents = file_system_boxed.read(filename)?;
47
+
48
+ let imports_by_module = parse_json_to_map(&file_contents, filename)?;
49
+
50
+ Ok(imports_by_module_to_py(py, imports_by_module))
51
+ }
52
+
53
+ /// A newtype wrapper for HashMap<Module, HashSet<DirectImport>> that implements FromPyObject.
54
+ pub struct ImportsByModule(pub HashMap<Module, HashSet<DirectImport>>);
55
+
56
+ impl<'py> FromPyObject<'py> for ImportsByModule {
57
+ fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
58
+ let py_dict = ob.downcast::<PyDict>()?;
59
+ let mut imports_by_module_rust = HashMap::new();
60
+
61
+ for (py_key, py_value) in py_dict.iter() {
62
+ let module: Module = py_key.extract()?;
63
+ let py_set = py_value.downcast::<PySet>()?;
64
+ let mut hashset: HashSet<DirectImport> = HashSet::new();
65
+ for element in py_set.iter() {
66
+ let direct_import: DirectImport = element.extract()?;
67
+ hashset.insert(direct_import);
68
+ }
69
+ imports_by_module_rust.insert(module, hashset);
70
+ }
71
+
72
+ Ok(ImportsByModule(imports_by_module_rust))
73
+ }
74
+ }
75
+
76
+ fn serialize_imports_by_module(
77
+ imports_by_module: &HashMap<Module, HashSet<DirectImport>>,
78
+ ) -> String {
79
+ let raw_map: HashMap<&str, Vec<(&str, usize, &str)>> = imports_by_module
80
+ .iter()
81
+ .map(|(module, imports)| {
82
+ let imports_vec: Vec<(&str, usize, &str)> = imports
83
+ .iter()
84
+ .map(|import| {
85
+ (
86
+ import.imported.as_str(),
87
+ import.line_number,
88
+ import.line_contents.as_str(),
89
+ )
90
+ })
91
+ .collect();
92
+ (module.name.as_str(), imports_vec)
93
+ })
94
+ .collect();
95
+
96
+ serde_json::to_string(&raw_map).expect("Failed to serialize to JSON")
97
+ }
98
+
99
+ pub fn parse_json_to_map(
100
+ json_str: &str,
101
+ filename: &str,
102
+ ) -> GrimpResult<HashMap<Module, HashSet<DirectImport>>> {
103
+ let raw_map: HashMap<String, Vec<(String, usize, String)>> = serde_json::from_str(json_str)
104
+ .map_err(|_| GrimpError::CorruptCache(filename.to_string()))?;
105
+
106
+ let mut parsed_map: HashMap<Module, HashSet<DirectImport>> = HashMap::new();
107
+
108
+ for (module_name, imports) in raw_map {
109
+ let module = Module {
110
+ name: module_name.clone(),
111
+ };
112
+ let import_set: HashSet<DirectImport> = imports
113
+ .into_iter()
114
+ .map(|(imported, line_number, line_contents)| DirectImport {
115
+ importer: module_name.clone(),
116
+ imported,
117
+ line_number,
118
+ line_contents,
119
+ })
120
+ .collect();
121
+ parsed_map.insert(module, import_set);
122
+ }
123
+
124
+ Ok(parsed_map)
125
+ }