grimp 3.16__tar.gz → 3.17__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.16 → grimp-3.17}/PKG-INFO +1 -1
- {grimp-3.16 → grimp-3.17}/pyproject.toml +1 -1
- {grimp-3.16 → grimp-3.17}/rust/src/caching.rs +40 -10
- {grimp-3.16 → grimp-3.17}/rust/src/errors.rs +6 -0
- {grimp-3.16 → grimp-3.17}/rust/src/exceptions.rs +1 -0
- {grimp-3.16 → grimp-3.17}/rust/src/graph/graph_manipulation.rs +2 -1
- {grimp-3.16 → grimp-3.17}/rust/src/graph/mod.rs +35 -13
- {grimp-3.16 → grimp-3.17}/rust/src/import_parsing.rs +5 -0
- {grimp-3.16 → grimp-3.17}/rust/src/import_scanning.rs +6 -0
- {grimp-3.16 → grimp-3.17}/rust/src/lib.rs +2 -1
- {grimp-3.16 → grimp-3.17}/src/grimp/__init__.py +1 -1
- {grimp-3.16 → grimp-3.17}/src/grimp/adaptors/caching.py +6 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/application/graph.py +8 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/application/usecases.py +1 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/domain/valueobjects.py +4 -1
- {grimp-3.16 → grimp-3.17}/README.rst +0 -0
- {grimp-3.16 → grimp-3.17}/rust/Cargo.lock +0 -0
- {grimp-3.16 → grimp-3.17}/rust/Cargo.toml +0 -0
- {grimp-3.16 → grimp-3.17}/rust/build.rs +0 -0
- {grimp-3.16 → grimp-3.17}/rust/rust-toolchain.toml +0 -0
- {grimp-3.16 → grimp-3.17}/rust/src/filesystem.rs +0 -0
- {grimp-3.16 → grimp-3.17}/rust/src/graph/cycle_breakers.rs +0 -0
- {grimp-3.16 → grimp-3.17}/rust/src/graph/direct_import_queries.rs +0 -0
- {grimp-3.16 → grimp-3.17}/rust/src/graph/hierarchy_queries.rs +0 -0
- {grimp-3.16 → grimp-3.17}/rust/src/graph/higher_order_queries.rs +0 -0
- {grimp-3.16 → grimp-3.17}/rust/src/graph/import_chain_queries.rs +0 -0
- {grimp-3.16 → grimp-3.17}/rust/src/graph/pathfinding.rs +0 -0
- {grimp-3.16 → grimp-3.17}/rust/src/module_expressions.rs +0 -0
- {grimp-3.16 → grimp-3.17}/rust/src/module_finding.rs +0 -0
- {grimp-3.16 → grimp-3.17}/rust/tests/large.rs +0 -0
- {grimp-3.16 → grimp-3.17}/rust/tests/large_graph.json +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/adaptors/__init__.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/adaptors/filesystem.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/adaptors/modulefinder.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/adaptors/packagefinder.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/adaptors/timing.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/application/__init__.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/application/config.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/application/ports/__init__.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/application/ports/caching.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/application/ports/filesystem.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/application/ports/modulefinder.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/application/ports/packagefinder.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/application/ports/timing.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/application/scanning.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/domain/__init__.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/domain/analysis.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/exceptions.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/main.py +0 -0
- {grimp-3.16 → grimp-3.17}/src/grimp/py.typed +0 -0
|
@@ -75,17 +75,27 @@ impl<'a, 'py> FromPyObject<'a, 'py> for ImportsByModule {
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
/// The version of the data cache file format.
|
|
79
|
+
///
|
|
80
|
+
/// Bump this whenever the serialized structure changes. On read, a file with a
|
|
81
|
+
/// different (or missing) version is treated as a version mismatch and rebuilt,
|
|
82
|
+
/// rather than being mistaken for a corrupt file.
|
|
83
|
+
const CACHE_SCHEMA_VERSION: u32 = 2;
|
|
84
|
+
|
|
78
85
|
fn serialize_imports_by_module(
|
|
79
86
|
imports_by_module: &HashMap<Module, HashSet<DirectImport>>,
|
|
80
87
|
) -> String {
|
|
81
|
-
|
|
88
|
+
// Fields are ordered to match the `get_import_details` dict (`imported`, `is_lazy`,
|
|
89
|
+
// `line_number`, `line_contents`); `importer` is the map key.
|
|
90
|
+
let raw_map: HashMap<&str, Vec<(&str, bool, usize, &str)>> = imports_by_module
|
|
82
91
|
.iter()
|
|
83
92
|
.map(|(module, imports)| {
|
|
84
|
-
let imports_vec: Vec<(&str, usize, &str)> = imports
|
|
93
|
+
let imports_vec: Vec<(&str, bool, usize, &str)> = imports
|
|
85
94
|
.iter()
|
|
86
95
|
.map(|import| {
|
|
87
96
|
(
|
|
88
97
|
import.imported.as_str(),
|
|
98
|
+
import.is_lazy,
|
|
89
99
|
import.line_number,
|
|
90
100
|
import.line_contents.as_str(),
|
|
91
101
|
)
|
|
@@ -95,16 +105,33 @@ fn serialize_imports_by_module(
|
|
|
95
105
|
})
|
|
96
106
|
.collect();
|
|
97
107
|
|
|
98
|
-
serde_json::
|
|
108
|
+
let envelope = serde_json::json!({
|
|
109
|
+
"version": CACHE_SCHEMA_VERSION,
|
|
110
|
+
"imports_by_module": raw_map,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
serde_json::to_string(&envelope).expect("Failed to serialize to JSON")
|
|
99
114
|
}
|
|
100
115
|
|
|
101
116
|
pub fn parse_json_to_map(
|
|
102
117
|
json_str: &str,
|
|
103
118
|
filename: &str,
|
|
104
119
|
) -> GrimpResult<HashMap<Module, HashSet<DirectImport>>> {
|
|
105
|
-
|
|
120
|
+
// Parse into a generic value first, so we can distinguish genuinely corrupt
|
|
121
|
+
// JSON from a cache file written by a different format version (e.g. by an
|
|
122
|
+
// older Grimp). The latter should be silently rebuilt, not warned about.
|
|
123
|
+
let value: serde_json::Value = serde_json::from_str(json_str)
|
|
106
124
|
.map_err(|_| GrimpError::CorruptCache(filename.to_string()))?;
|
|
107
125
|
|
|
126
|
+
let version = value.get("version").and_then(|v| v.as_u64());
|
|
127
|
+
if version != Some(CACHE_SCHEMA_VERSION as u64) {
|
|
128
|
+
return Err(GrimpError::CacheVersionMismatch(filename.to_string()));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let raw_map: HashMap<String, Vec<(String, bool, usize, String)>> =
|
|
132
|
+
serde_json::from_value(value.get("imports_by_module").cloned().unwrap_or_default())
|
|
133
|
+
.map_err(|_| GrimpError::CorruptCache(filename.to_string()))?;
|
|
134
|
+
|
|
108
135
|
let mut parsed_map: HashMap<Module, HashSet<DirectImport>> = HashMap::new();
|
|
109
136
|
|
|
110
137
|
for (module_name, imports) in raw_map {
|
|
@@ -113,12 +140,15 @@ pub fn parse_json_to_map(
|
|
|
113
140
|
};
|
|
114
141
|
let import_set: HashSet<DirectImport> = imports
|
|
115
142
|
.into_iter()
|
|
116
|
-
.map(
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
143
|
+
.map(
|
|
144
|
+
|(imported, is_lazy, line_number, line_contents)| DirectImport {
|
|
145
|
+
importer: module_name.clone(),
|
|
146
|
+
imported,
|
|
147
|
+
line_number,
|
|
148
|
+
line_contents,
|
|
149
|
+
is_lazy,
|
|
150
|
+
},
|
|
151
|
+
)
|
|
122
152
|
.collect();
|
|
123
153
|
parsed_map.insert(module, import_set);
|
|
124
154
|
}
|
|
@@ -36,6 +36,9 @@ pub enum GrimpError {
|
|
|
36
36
|
|
|
37
37
|
#[error("Could not use corrupt cache file {0}.")]
|
|
38
38
|
CorruptCache(String),
|
|
39
|
+
|
|
40
|
+
#[error("Cache file {0} was written by a different version of Grimp.")]
|
|
41
|
+
CacheVersionMismatch(String),
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
pub type GrimpResult<T> = Result<T, GrimpError>;
|
|
@@ -55,6 +58,9 @@ impl From<GrimpError> for PyErr {
|
|
|
55
58
|
line_number, text, ..
|
|
56
59
|
} => PyErr::new::<exceptions::ParseError, _>((line_number, text)),
|
|
57
60
|
GrimpError::CorruptCache(_) => exceptions::CorruptCache::new_err(value.to_string()),
|
|
61
|
+
GrimpError::CacheVersionMismatch(_) => {
|
|
62
|
+
exceptions::CacheVersionMismatch::new_err(value.to_string())
|
|
63
|
+
}
|
|
58
64
|
}
|
|
59
65
|
}
|
|
60
66
|
}
|
|
@@ -6,6 +6,7 @@ create_exception!(_rustgrimp, ModuleNotPresent, PyException);
|
|
|
6
6
|
create_exception!(_rustgrimp, NoSuchContainer, PyException);
|
|
7
7
|
create_exception!(_rustgrimp, InvalidModuleExpression, PyException);
|
|
8
8
|
create_exception!(_rustgrimp, CorruptCache, PyException);
|
|
9
|
+
create_exception!(_rustgrimp, CacheVersionMismatch, PyException);
|
|
9
10
|
|
|
10
11
|
// We need to use here `pyclass(extends=PyException)` instead of `create_exception!`
|
|
11
12
|
// since the exception contains custom data. See:
|
|
@@ -120,6 +120,7 @@ impl Graph {
|
|
|
120
120
|
imported: ModuleToken,
|
|
121
121
|
line_number: u32,
|
|
122
122
|
line_contents: &str,
|
|
123
|
+
is_lazy: bool,
|
|
123
124
|
) {
|
|
124
125
|
self.imports
|
|
125
126
|
.entry(importer)
|
|
@@ -137,7 +138,7 @@ impl Graph {
|
|
|
137
138
|
self.import_details
|
|
138
139
|
.entry((importer, imported))
|
|
139
140
|
.or_default()
|
|
140
|
-
.insert(PyImportDetails::new(line_number, line_contents));
|
|
141
|
+
.insert(PyImportDetails::new(line_number, line_contents, is_lazy));
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
144
|
|
|
@@ -264,29 +264,45 @@ impl GraphWrapper {
|
|
|
264
264
|
Ok(self.get_visible_module_by_name(module)?.is_squashed())
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
-
#[pyo3(signature = (*, importer, imported, line_number=None, line_contents=None))]
|
|
267
|
+
#[pyo3(signature = (*, importer, imported, is_lazy=None, line_number=None, line_contents=None))]
|
|
268
268
|
pub fn add_import(
|
|
269
269
|
&mut self,
|
|
270
270
|
importer: &str,
|
|
271
271
|
imported: &str,
|
|
272
|
+
is_lazy: Option<bool>,
|
|
272
273
|
line_number: Option<u32>,
|
|
273
274
|
line_contents: Option<&str>,
|
|
274
|
-
) {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
self._graph
|
|
280
|
-
.add_detailed_import(importer, imported, line_number, line_contents)
|
|
281
|
-
}
|
|
282
|
-
(None, None) => {
|
|
275
|
+
) -> PyResult<()> {
|
|
276
|
+
match (line_number, line_contents, is_lazy) {
|
|
277
|
+
(None, None, None) => {
|
|
278
|
+
let importer = self._graph.get_or_add_module(importer).token();
|
|
279
|
+
let imported = self._graph.get_or_add_module(imported).token();
|
|
283
280
|
self._graph.add_import(importer, imported);
|
|
284
281
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
282
|
+
(Some(line_number), Some(line_contents), is_lazy) => {
|
|
283
|
+
let is_lazy = is_lazy.unwrap_or(false);
|
|
284
|
+
let importer = self._graph.get_or_add_module(importer).token();
|
|
285
|
+
let imported = self._graph.get_or_add_module(imported).token();
|
|
286
|
+
self._graph.add_detailed_import(
|
|
287
|
+
importer,
|
|
288
|
+
imported,
|
|
289
|
+
line_number,
|
|
290
|
+
line_contents,
|
|
291
|
+
is_lazy,
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
(_, _, Some(_is_lazy)) => {
|
|
295
|
+
return Err(PyValueError::new_err(
|
|
296
|
+
"You must provide line_number and line_contents when providing is_lazy.",
|
|
297
|
+
));
|
|
298
|
+
}
|
|
299
|
+
(_, _, None) => {
|
|
300
|
+
return Err(PyValueError::new_err(
|
|
301
|
+
"Expected line_number and line_contents, or neither.",
|
|
302
|
+
));
|
|
288
303
|
}
|
|
289
304
|
}
|
|
305
|
+
Ok(())
|
|
290
306
|
}
|
|
291
307
|
|
|
292
308
|
#[pyo3(signature = (*, importer, imported))]
|
|
@@ -402,6 +418,7 @@ impl GraphWrapper {
|
|
|
402
418
|
imported.name(),
|
|
403
419
|
import_details.line_number(),
|
|
404
420
|
import_details.line_contents(),
|
|
421
|
+
import_details.is_lazy(),
|
|
405
422
|
)
|
|
406
423
|
})
|
|
407
424
|
.sorted()
|
|
@@ -417,6 +434,7 @@ impl GraphWrapper {
|
|
|
417
434
|
"line_contents",
|
|
418
435
|
import_details.line_contents.into_py_any(py).unwrap(),
|
|
419
436
|
),
|
|
437
|
+
("is_lazy", import_details.is_lazy.into_py_any(py).unwrap()),
|
|
420
438
|
]
|
|
421
439
|
.into_py_dict(py)
|
|
422
440
|
.unwrap()
|
|
@@ -667,6 +685,7 @@ struct ImportDetails {
|
|
|
667
685
|
imported: String,
|
|
668
686
|
line_number: u32,
|
|
669
687
|
line_contents: String,
|
|
688
|
+
is_lazy: bool,
|
|
670
689
|
}
|
|
671
690
|
|
|
672
691
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, new)]
|
|
@@ -754,6 +773,9 @@ pub struct PyImportDetails {
|
|
|
754
773
|
|
|
755
774
|
#[getset(get_copy = "pub")]
|
|
756
775
|
interned_line_contents: DefaultSymbol,
|
|
776
|
+
|
|
777
|
+
#[getset(get_copy = "pub")]
|
|
778
|
+
is_lazy: bool,
|
|
757
779
|
}
|
|
758
780
|
|
|
759
781
|
impl PyImportDetails {
|
|
@@ -10,6 +10,7 @@ pub struct ImportedObject {
|
|
|
10
10
|
pub line_number: usize,
|
|
11
11
|
pub line_contents: String,
|
|
12
12
|
pub typechecking_only: bool,
|
|
13
|
+
pub is_lazy: bool,
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
impl ImportedObject {
|
|
@@ -18,12 +19,14 @@ impl ImportedObject {
|
|
|
18
19
|
line_number: usize,
|
|
19
20
|
line_contents: String,
|
|
20
21
|
typechecking_only: bool,
|
|
22
|
+
is_lazy: bool,
|
|
21
23
|
) -> Self {
|
|
22
24
|
Self {
|
|
23
25
|
name,
|
|
24
26
|
line_number,
|
|
25
27
|
line_contents,
|
|
26
28
|
typechecking_only,
|
|
29
|
+
is_lazy,
|
|
27
30
|
}
|
|
28
31
|
}
|
|
29
32
|
}
|
|
@@ -84,6 +87,7 @@ impl<'a> StatementVisitor<'a> for Visitor<'a> {
|
|
|
84
87
|
line_number.get(),
|
|
85
88
|
self.source_code.line_text(line_number).trim().to_string(),
|
|
86
89
|
self.typechecking_only,
|
|
90
|
+
import_stmt.is_lazy,
|
|
87
91
|
))
|
|
88
92
|
}
|
|
89
93
|
walk_stmt(self, stmt);
|
|
@@ -113,6 +117,7 @@ impl<'a> StatementVisitor<'a> for Visitor<'a> {
|
|
|
113
117
|
line_number.get(),
|
|
114
118
|
self.source_code.line_text(line_number).trim().to_string(),
|
|
115
119
|
self.typechecking_only,
|
|
120
|
+
import_from_stmt.is_lazy,
|
|
116
121
|
))
|
|
117
122
|
}
|
|
118
123
|
walk_stmt(self, stmt);
|
|
@@ -16,6 +16,7 @@ pub struct DirectImport {
|
|
|
16
16
|
pub imported: String,
|
|
17
17
|
pub line_number: usize,
|
|
18
18
|
pub line_contents: String,
|
|
19
|
+
pub is_lazy: bool,
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
impl<'a, 'py> FromPyObject<'a, 'py> for DirectImport {
|
|
@@ -26,12 +27,14 @@ impl<'a, 'py> FromPyObject<'a, 'py> for DirectImport {
|
|
|
26
27
|
let imported: String = ob.getattr("imported")?.getattr("name")?.extract()?;
|
|
27
28
|
let line_number: usize = ob.getattr("line_number")?.extract()?;
|
|
28
29
|
let line_contents: String = ob.getattr("line_contents")?.extract()?;
|
|
30
|
+
let is_lazy: bool = ob.getattr("is_lazy")?.extract()?;
|
|
29
31
|
|
|
30
32
|
Ok(DirectImport {
|
|
31
33
|
importer,
|
|
32
34
|
imported,
|
|
33
35
|
line_number,
|
|
34
36
|
line_contents,
|
|
37
|
+
is_lazy,
|
|
35
38
|
})
|
|
36
39
|
}
|
|
37
40
|
}
|
|
@@ -152,6 +155,7 @@ fn scan_for_imports_no_py_single_module(
|
|
|
152
155
|
imported: imported_module.name.to_string(),
|
|
153
156
|
line_number: imported_object.line_number,
|
|
154
157
|
line_contents: imported_object.line_contents,
|
|
158
|
+
is_lazy: imported_object.is_lazy,
|
|
155
159
|
});
|
|
156
160
|
}
|
|
157
161
|
None => {
|
|
@@ -165,6 +169,7 @@ fn scan_for_imports_no_py_single_module(
|
|
|
165
169
|
imported: imported_module,
|
|
166
170
|
line_number: imported_object.line_number,
|
|
167
171
|
line_contents: imported_object.line_contents,
|
|
172
|
+
is_lazy: imported_object.is_lazy,
|
|
168
173
|
});
|
|
169
174
|
}
|
|
170
175
|
}
|
|
@@ -196,6 +201,7 @@ fn to_py_direct_imports<'a>(
|
|
|
196
201
|
kwargs
|
|
197
202
|
.set_item("line_contents", &rust_import.line_contents)
|
|
198
203
|
.unwrap();
|
|
204
|
+
kwargs.set_item("is_lazy", rust_import.is_lazy).unwrap();
|
|
199
205
|
let py_direct_import = py_direct_import_class.call((), Some(&kwargs)).unwrap();
|
|
200
206
|
pyset.add(&py_direct_import).unwrap();
|
|
201
207
|
}
|
|
@@ -29,6 +29,7 @@ mod _rustgrimp {
|
|
|
29
29
|
|
|
30
30
|
#[pymodule_export]
|
|
31
31
|
use crate::exceptions::{
|
|
32
|
-
CorruptCache, InvalidModuleExpression, ModuleNotPresent,
|
|
32
|
+
CacheVersionMismatch, CorruptCache, InvalidModuleExpression, ModuleNotPresent,
|
|
33
|
+
NoSuchContainer, ParseError,
|
|
33
34
|
};
|
|
34
35
|
}
|
|
@@ -203,6 +203,12 @@ class Cache(AbstractCache):
|
|
|
203
203
|
except rust.CorruptCache:
|
|
204
204
|
logger.warning(f"Could not use corrupt cache file {data_cache_filename}.")
|
|
205
205
|
return {}
|
|
206
|
+
except rust.CacheVersionMismatch:
|
|
207
|
+
logger.info(
|
|
208
|
+
f"Cache file {data_cache_filename} was written by a different version of Grimp; "
|
|
209
|
+
"rebuilding."
|
|
210
|
+
)
|
|
211
|
+
return {}
|
|
206
212
|
|
|
207
213
|
logger.info(f"Used cache data file {data_cache_filename}.")
|
|
208
214
|
return imports_by_module
|
|
@@ -27,6 +27,7 @@ ImportTuple = tuple[str, str]
|
|
|
27
27
|
class DetailedImport(Import):
|
|
28
28
|
line_number: int
|
|
29
29
|
line_contents: str
|
|
30
|
+
is_lazy: bool
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
class ImportGraph:
|
|
@@ -138,10 +139,15 @@ class ImportGraph:
|
|
|
138
139
|
imported: str,
|
|
139
140
|
line_number: int | None = None,
|
|
140
141
|
line_contents: str | None = None,
|
|
142
|
+
is_lazy: bool | None = None,
|
|
141
143
|
) -> None:
|
|
142
144
|
"""
|
|
143
145
|
Add a direct import between two modules to the graph. If the modules are not already
|
|
144
146
|
present, they will be added to the graph.
|
|
147
|
+
|
|
148
|
+
Raises:
|
|
149
|
+
ValueError if only one of line_number and line_contents is supplied, or if
|
|
150
|
+
is_lazy is supplied without line_number and line_contents.
|
|
145
151
|
"""
|
|
146
152
|
self._cached_modules = None
|
|
147
153
|
self._rustgraph.add_import(
|
|
@@ -149,6 +155,7 @@ class ImportGraph:
|
|
|
149
155
|
imported=imported,
|
|
150
156
|
line_number=line_number,
|
|
151
157
|
line_contents=line_contents,
|
|
158
|
+
is_lazy=is_lazy,
|
|
152
159
|
)
|
|
153
160
|
|
|
154
161
|
def remove_import(self, *, importer: str, imported: str) -> None:
|
|
@@ -249,6 +256,7 @@ class ImportGraph:
|
|
|
249
256
|
'imported': 'mypackage.imported',
|
|
250
257
|
'line_number': 5,
|
|
251
258
|
'line_contents': 'from mypackage import imported',
|
|
259
|
+
'is_lazy': False,
|
|
252
260
|
},
|
|
253
261
|
(additional imports here)
|
|
254
262
|
]
|
|
@@ -55,9 +55,12 @@ class DirectImport:
|
|
|
55
55
|
imported: Module
|
|
56
56
|
line_number: int
|
|
57
57
|
line_contents: str
|
|
58
|
+
# Import in the form `lazy import` or `lazy from import`.
|
|
59
|
+
is_lazy: bool = False
|
|
58
60
|
|
|
59
61
|
def __str__(self) -> str:
|
|
60
|
-
|
|
62
|
+
lazy_label = ", lazy" if self.is_lazy else ""
|
|
63
|
+
return f"{self.importer} -> {self.imported} (l. {self.line_number}{lazy_label})"
|
|
61
64
|
|
|
62
65
|
|
|
63
66
|
@dataclass(frozen=True, order=True)
|
|
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
|