robotcode-robot 2.6.2__tar.gz → 2.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/PKG-INFO +2 -2
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/pyproject.toml +1 -1
- robotcode_robot-2.7.0/src/robotcode/robot/__version__.py +1 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/config/model.py +29 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/document_cache_helper.py +84 -11
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/import_resolver.py +20 -4
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/imports_manager.py +269 -154
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/namespace.py +24 -3
- robotcode_robot-2.6.2/src/robotcode/robot/__version__.py +0 -1
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/.gitignore +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/README.md +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/__init__.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/config/__init__.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/config/loader.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/config/utils.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/__init__.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/analyzer_result.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/data_cache.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/diagnostic_rules.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/diagnostics_modifier.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/entities.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/errors.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/keyword_finder.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/library_doc.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/model_helper.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/namespace_analyzer.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/project_index.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/scope_tree.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/semantic_analyzer/__init__.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/semantic_analyzer/analyzer.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/semantic_analyzer/enums.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/semantic_analyzer/model.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/semantic_analyzer/nodes.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/semantic_analyzer/run_keyword.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/semantic_analyzer/serialization.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/semantic_analyzer/variable_tokenizer.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/variable_scope.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/workspace_config.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/py.typed +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/utils/__init__.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/utils/ast.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/utils/markdownformatter.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/utils/match.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/utils/robot_patching.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/utils/robot_path.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/utils/stubs.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/utils/variables.py +0 -0
- {robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/utils/visitor.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: robotcode-robot
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.7.0
|
|
4
4
|
Summary: Support classes for RobotCode for handling Robot Framework projects.
|
|
5
5
|
Project-URL: Homepage, https://robotcode.io
|
|
6
6
|
Project-URL: Donate, https://opencollective.com/robotcode
|
|
@@ -26,7 +26,7 @@ Classifier: Topic :: Utilities
|
|
|
26
26
|
Classifier: Typing :: Typed
|
|
27
27
|
Requires-Python: >=3.10
|
|
28
28
|
Requires-Dist: platformdirs>=4.3
|
|
29
|
-
Requires-Dist: robotcode-core==2.
|
|
29
|
+
Requires-Dist: robotcode-core==2.7.0
|
|
30
30
|
Requires-Dist: robotframework>=5.0.0
|
|
31
31
|
Requires-Dist: tomli>=1.1.0; python_version < '3.11'
|
|
32
32
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.7.0"
|
|
@@ -2912,6 +2912,23 @@ class RobotBaseProfile(CommonOptions, CommonExtendOptions, RobotOptions, RobotEx
|
|
|
2912
2912
|
"""
|
|
2913
2913
|
)
|
|
2914
2914
|
|
|
2915
|
+
wrapper: Optional[List[Union[str, StringExpression]]] = field(
|
|
2916
|
+
description="""\
|
|
2917
|
+
Command prefix the test run is executed through (the actual
|
|
2918
|
+
`robotcode` command line is appended to it), e.g. to bring up the
|
|
2919
|
+
services, servers, mocks or session the tests need around them. For
|
|
2920
|
+
plain environment variables use `env` instead. The selected
|
|
2921
|
+
profile's `env` is applied first, so the wrapper can rely on it.
|
|
2922
|
+
|
|
2923
|
+
Examples:
|
|
2924
|
+
```toml
|
|
2925
|
+
[profiles.integration]
|
|
2926
|
+
wrapper = ["./with-test-services.sh"]
|
|
2927
|
+
# or a ready-made tool, e.g. ["xvfb-run", "-a"] for headless UI tests
|
|
2928
|
+
```
|
|
2929
|
+
""",
|
|
2930
|
+
)
|
|
2931
|
+
|
|
2915
2932
|
rebot: Optional[RebotProfile] = field(
|
|
2916
2933
|
description="""\
|
|
2917
2934
|
Options to be passed to _rebot_.
|
|
@@ -2979,6 +2996,18 @@ class RobotExtendBaseProfile(RobotBaseProfile):
|
|
|
2979
2996
|
alias="extend-env",
|
|
2980
2997
|
)
|
|
2981
2998
|
|
|
2999
|
+
extend_wrapper: Optional[List[Union[str, StringExpression]]] = field(
|
|
3000
|
+
description="""\
|
|
3001
|
+
Append extra entries to the `wrapper` command prefix.
|
|
3002
|
+
|
|
3003
|
+
Examples:
|
|
3004
|
+
```toml
|
|
3005
|
+
extend-wrapper = ["--some-flag"]
|
|
3006
|
+
```
|
|
3007
|
+
""",
|
|
3008
|
+
alias="extend-wrapper",
|
|
3009
|
+
)
|
|
3010
|
+
|
|
2982
3011
|
extend_paths: Union[str, List[str], None] = field(
|
|
2983
3012
|
description="""\
|
|
2984
3013
|
Append extra entries to the paths argument.
|
|
@@ -24,6 +24,7 @@ from robotcode.core.filewatcher import FileWatcherManagerBase
|
|
|
24
24
|
from robotcode.core.text_document import TextDocument
|
|
25
25
|
from robotcode.core.uri import Uri
|
|
26
26
|
from robotcode.core.utils.logging import LoggingDescriptor
|
|
27
|
+
from robotcode.core.utils.path import DiskInfo
|
|
27
28
|
from robotcode.core.workspace import Workspace, WorkspaceFolder
|
|
28
29
|
from robotcode.robot.diagnostics.diagnostics_modifier import (
|
|
29
30
|
DiagnosticModifiersConfig,
|
|
@@ -58,6 +59,18 @@ class UnknownFileTypeError(Exception):
|
|
|
58
59
|
pass
|
|
59
60
|
|
|
60
61
|
|
|
62
|
+
def _namespace_cache_key(source: str, document_type: Optional[DocumentType]) -> str:
|
|
63
|
+
"""Disk-cache entry name for a namespace.
|
|
64
|
+
|
|
65
|
+
Includes the document type because the same file can be analyzed both as
|
|
66
|
+
a suite (GENERAL) and as an imported resource (RESOURCE) — the results
|
|
67
|
+
must not overwrite each other. "\\n" as separator is impossible in Windows
|
|
68
|
+
paths and never appears in real-world POSIX paths (where it is technically
|
|
69
|
+
legal); the key is an opaque entry name and is never parsed back.
|
|
70
|
+
"""
|
|
71
|
+
return f"{source}\n{document_type.value if document_type is not None else ''}"
|
|
72
|
+
|
|
73
|
+
|
|
61
74
|
class _CacheEntry:
|
|
62
75
|
pass
|
|
63
76
|
|
|
@@ -438,11 +451,16 @@ class DocumentsCacheHelper:
|
|
|
438
451
|
imports_manager = self.get_imports_manager(document)
|
|
439
452
|
semantic_model_enabled = self._is_semantic_model_enabled(document)
|
|
440
453
|
|
|
454
|
+
# Capture the disk state before the model is parsed: this snapshot can
|
|
455
|
+
# only be older than the analyzed content, never newer, so anything
|
|
456
|
+
# persisted under it self-heals with a cache miss.
|
|
457
|
+
disk_info = document.disk_info
|
|
458
|
+
|
|
441
459
|
# --- Try disk cache (cold-start acceleration) ---
|
|
442
460
|
cache_namespaces = self.analysis_config.cache.cache_namespaces
|
|
443
|
-
if cache_namespaces and document.version is None:
|
|
461
|
+
if cache_namespaces and document.version is None and disk_info is not None:
|
|
444
462
|
result = self._try_load_cached_namespace(
|
|
445
|
-
source, document, document_type, imports_manager, semantic_model_enabled
|
|
463
|
+
source, document, document_type, imports_manager, semantic_model_enabled, disk_info
|
|
446
464
|
)
|
|
447
465
|
if result is not None:
|
|
448
466
|
return result
|
|
@@ -457,6 +475,13 @@ class DocumentsCacheHelper:
|
|
|
457
475
|
else:
|
|
458
476
|
model = self.get_model(document)
|
|
459
477
|
|
|
478
|
+
# The document may have been re-read from disk while the model was
|
|
479
|
+
# parsed; the captured snapshot then no longer describes the parsed
|
|
480
|
+
# content and must not label anything written during the build (the
|
|
481
|
+
# builder writes RESOURCE cache entries under this snapshot).
|
|
482
|
+
if disk_info is not None and document.disk_info != disk_info:
|
|
483
|
+
disk_info = None
|
|
484
|
+
|
|
460
485
|
languages, workspace_languages = self.build_languages_from_model(document, model)
|
|
461
486
|
builder = NamespaceBuilder(
|
|
462
487
|
imports_manager,
|
|
@@ -466,14 +491,20 @@ class DocumentsCacheHelper:
|
|
|
466
491
|
document_type,
|
|
467
492
|
languages,
|
|
468
493
|
workspace_languages,
|
|
494
|
+
disk_info=disk_info,
|
|
469
495
|
)
|
|
470
496
|
builder.set_semantic_model_enabled(semantic_model_enabled)
|
|
471
497
|
|
|
472
498
|
result = builder.build()
|
|
473
499
|
|
|
474
|
-
# Save to disk cache
|
|
475
|
-
|
|
476
|
-
|
|
500
|
+
# Save to disk cache — the re-checks in _namespace_is_cacheable catch
|
|
501
|
+
# a watcher re-read (disk_info) and a didOpen on another thread
|
|
502
|
+
# (version) that happened during the build.
|
|
503
|
+
if cache_namespaces and self._namespace_is_cacheable(document, disk_info):
|
|
504
|
+
assert disk_info is not None
|
|
505
|
+
self._save_namespace_to_cache(
|
|
506
|
+
source, document, document_type, result, imports_manager, disk_info, semantic_model_enabled
|
|
507
|
+
)
|
|
477
508
|
|
|
478
509
|
# Update the folder-scoped reference index
|
|
479
510
|
self.get_project_index(document).update_file(result.source, result)
|
|
@@ -491,6 +522,18 @@ class DocumentsCacheHelper:
|
|
|
491
522
|
experimental_config = self.workspace.get_configuration(ExperimentalConfig, document.uri)
|
|
492
523
|
return self.analysis_config.semantic_model or experimental_config.semantic_model
|
|
493
524
|
|
|
525
|
+
@staticmethod
|
|
526
|
+
def _namespace_is_cacheable(document: TextDocument, disk_info: Optional[DiskInfo]) -> bool:
|
|
527
|
+
"""Whether a namespace built from this document may be persisted.
|
|
528
|
+
|
|
529
|
+
Only when the analyzed content is the on-disk state: not an editor
|
|
530
|
+
buffer (version), backed by a trusted snapshot, and the document still
|
|
531
|
+
holds exactly that snapshot.
|
|
532
|
+
"""
|
|
533
|
+
return (
|
|
534
|
+
document.version is None and disk_info is not None and disk_info.trusted and document.disk_info == disk_info
|
|
535
|
+
)
|
|
536
|
+
|
|
494
537
|
def _try_load_cached_namespace(
|
|
495
538
|
self,
|
|
496
539
|
source: str,
|
|
@@ -498,10 +541,14 @@ class DocumentsCacheHelper:
|
|
|
498
541
|
document_type: Optional[DocumentType],
|
|
499
542
|
imports_manager: ImportsManager,
|
|
500
543
|
semantic_model_enabled: bool,
|
|
544
|
+
disk_info: DiskInfo,
|
|
501
545
|
) -> Optional[Namespace]:
|
|
502
546
|
"""Attempt to load a Namespace from the disk cache.
|
|
503
547
|
|
|
504
|
-
|
|
548
|
+
``disk_info`` is the snapshot of the document content the namespace
|
|
549
|
+
will represent; the cached entry is validated against it, not against
|
|
550
|
+
the current disk state. Returns None on cache miss or validation
|
|
551
|
+
failure.
|
|
505
552
|
"""
|
|
506
553
|
data_cache = imports_manager.data_cache
|
|
507
554
|
|
|
@@ -510,7 +557,9 @@ class DocumentsCacheHelper:
|
|
|
510
557
|
return None
|
|
511
558
|
|
|
512
559
|
try:
|
|
513
|
-
entry = data_cache.read_entry(
|
|
560
|
+
entry = data_cache.read_entry(
|
|
561
|
+
CacheSection.NAMESPACE, _namespace_cache_key(source, document_type), NamespaceMetaData, NamespaceData
|
|
562
|
+
)
|
|
514
563
|
except (SystemExit, KeyboardInterrupt):
|
|
515
564
|
raise
|
|
516
565
|
except BaseException as e:
|
|
@@ -536,7 +585,7 @@ class DocumentsCacheHelper:
|
|
|
536
585
|
)
|
|
537
586
|
return None
|
|
538
587
|
|
|
539
|
-
if not imports_manager.validate_namespace_meta(meta):
|
|
588
|
+
if not imports_manager.validate_namespace_meta(meta, disk_info):
|
|
540
589
|
self._logger.debug(
|
|
541
590
|
lambda: f"Cache miss for {source}: cached entry is stale, re-analyzing",
|
|
542
591
|
context_name="cache",
|
|
@@ -588,19 +637,43 @@ class DocumentsCacheHelper:
|
|
|
588
637
|
def _save_namespace_to_cache(
|
|
589
638
|
self,
|
|
590
639
|
source: str,
|
|
640
|
+
document: TextDocument,
|
|
641
|
+
document_type: Optional[DocumentType],
|
|
591
642
|
namespace: Namespace,
|
|
592
643
|
imports_manager: ImportsManager,
|
|
644
|
+
disk_info: DiskInfo,
|
|
593
645
|
semantic_model_enabled: bool,
|
|
594
646
|
) -> None:
|
|
595
|
-
"""Save a Namespace to the disk cache.
|
|
647
|
+
"""Save a Namespace to the disk cache.
|
|
648
|
+
|
|
649
|
+
``disk_info`` must be the snapshot captured before the namespace was
|
|
650
|
+
built; the entry is skipped when the namespace's state is not fully
|
|
651
|
+
trustworthy or the document changed in the meantime.
|
|
652
|
+
"""
|
|
596
653
|
try:
|
|
597
654
|
meta = imports_manager.build_namespace_meta(
|
|
598
|
-
source, namespace, semantic_model_enabled=semantic_model_enabled
|
|
655
|
+
source, namespace, disk_info, semantic_model_enabled=semantic_model_enabled
|
|
599
656
|
)
|
|
657
|
+
if meta is None:
|
|
658
|
+
self._logger.debug(
|
|
659
|
+
lambda: f"Skip caching namespace for {source}: state not trustworthy",
|
|
660
|
+
context_name="cache",
|
|
661
|
+
)
|
|
662
|
+
return
|
|
663
|
+
|
|
600
664
|
data = namespace.to_data()
|
|
601
665
|
|
|
666
|
+
# to_data() takes time — re-check that the document still holds
|
|
667
|
+
# exactly the content this namespace was built from.
|
|
668
|
+
if not self._namespace_is_cacheable(document, disk_info):
|
|
669
|
+
self._logger.debug(
|
|
670
|
+
lambda: f"Skip caching namespace for {source}: document changed during save",
|
|
671
|
+
context_name="cache",
|
|
672
|
+
)
|
|
673
|
+
return
|
|
674
|
+
|
|
602
675
|
data_cache = imports_manager.data_cache
|
|
603
|
-
data_cache.save_entry(CacheSection.NAMESPACE, source, meta, data)
|
|
676
|
+
data_cache.save_entry(CacheSection.NAMESPACE, _namespace_cache_key(source, document_type), meta, data)
|
|
604
677
|
except (SystemExit, KeyboardInterrupt):
|
|
605
678
|
raise
|
|
606
679
|
except BaseException as e:
|
{robotcode_robot-2.6.2 → robotcode_robot-2.7.0}/src/robotcode/robot/diagnostics/import_resolver.py
RENAMED
|
@@ -59,6 +59,12 @@ class ResolvedImports:
|
|
|
59
59
|
resources: Dict[str, ResourceEntry] = field(default_factory=dict)
|
|
60
60
|
variables_imports: Dict[str, VariablesEntry] = field(default_factory=dict)
|
|
61
61
|
|
|
62
|
+
# Metadata of each resolved dependency, captured together with its doc at
|
|
63
|
+
# resolve time (keys: "lib:{import_name}", "res:{source}", "var:{import_name}").
|
|
64
|
+
# A None value means the dependency was resolved but no trustworthy meta
|
|
65
|
+
# exists — namespaces built from it must not be persisted.
|
|
66
|
+
dependency_metas: Dict[str, Optional[Any]] = field(default_factory=dict)
|
|
67
|
+
|
|
62
68
|
|
|
63
69
|
class ImportResolver:
|
|
64
70
|
"""Resolves all imports for a Robot Framework file.
|
|
@@ -78,6 +84,7 @@ class ImportResolver:
|
|
|
78
84
|
|
|
79
85
|
__slots__ = (
|
|
80
86
|
"_base_dir",
|
|
87
|
+
"_dependency_metas",
|
|
81
88
|
"_diagnostics",
|
|
82
89
|
"_import_entries",
|
|
83
90
|
"_imports_manager",
|
|
@@ -115,6 +122,7 @@ class ImportResolver:
|
|
|
115
122
|
self._variables: Dict[str, Any] = {}
|
|
116
123
|
self._variables_dirty = True
|
|
117
124
|
self._source_hints: Dict[str, str] = {}
|
|
125
|
+
self._dependency_metas: Dict[str, Optional[Any]] = {}
|
|
118
126
|
|
|
119
127
|
def resolve(self, imports: Iterable[Import], *, source_hints: Optional[Dict[str, str]] = None) -> ResolvedImports:
|
|
120
128
|
"""Resolve all imports and return the result."""
|
|
@@ -129,6 +137,7 @@ class ImportResolver:
|
|
|
129
137
|
variables_imports=self._variables_imports,
|
|
130
138
|
import_entries=self._import_entries,
|
|
131
139
|
diagnostics=self._diagnostics,
|
|
140
|
+
dependency_metas=self._dependency_metas,
|
|
132
141
|
)
|
|
133
142
|
|
|
134
143
|
# ------------------------------------------------------------------
|
|
@@ -186,13 +195,14 @@ class ImportResolver:
|
|
|
186
195
|
):
|
|
187
196
|
for library in DEFAULT_LIBRARIES:
|
|
188
197
|
try:
|
|
189
|
-
library_doc = self._imports_manager.
|
|
198
|
+
library_doc, meta = self._imports_manager.get_libdoc_for_library_import_with_meta(
|
|
190
199
|
library,
|
|
191
200
|
(),
|
|
192
201
|
base_dir=self._base_dir,
|
|
193
202
|
sentinel=None,
|
|
194
203
|
variables=self._variables,
|
|
195
204
|
)
|
|
205
|
+
self._dependency_metas[f"lib:{library}"] = meta
|
|
196
206
|
entry = LibraryEntry(
|
|
197
207
|
name=library_doc.name,
|
|
198
208
|
import_name=library,
|
|
@@ -312,13 +322,14 @@ class ImportResolver:
|
|
|
312
322
|
def _import_library(self, imp: LibraryImport, base_dir: str, *, top_level: bool) -> None:
|
|
313
323
|
assert imp.name is not None
|
|
314
324
|
|
|
315
|
-
library_doc = self._imports_manager.
|
|
325
|
+
library_doc, meta = self._imports_manager.get_libdoc_for_library_import_with_meta(
|
|
316
326
|
imp.name,
|
|
317
327
|
imp.args,
|
|
318
328
|
base_dir=base_dir,
|
|
319
329
|
sentinel=self._sentinel,
|
|
320
330
|
variables=self._variables,
|
|
321
331
|
)
|
|
332
|
+
self._dependency_metas[f"lib:{imp.name}"] = meta
|
|
322
333
|
entry = LibraryEntry(
|
|
323
334
|
name=library_doc.name,
|
|
324
335
|
import_name=imp.name,
|
|
@@ -407,13 +418,17 @@ class ImportResolver:
|
|
|
407
418
|
if hint is not None and os.path.isfile(hint):
|
|
408
419
|
source_hint = hint
|
|
409
420
|
|
|
410
|
-
resource_doc = self._imports_manager.
|
|
421
|
+
resource_doc, meta = self._imports_manager.get_resource_doc_for_resource_import_with_meta(
|
|
411
422
|
imp.name,
|
|
412
423
|
base_dir,
|
|
413
424
|
sentinel=self._sentinel,
|
|
414
425
|
variables=self._variables,
|
|
415
426
|
source=source_hint,
|
|
416
427
|
)
|
|
428
|
+
if resource_doc.source is not None:
|
|
429
|
+
# setdefault: on re-imports of the same resource the meta captured
|
|
430
|
+
# with the first (analyzed) doc wins.
|
|
431
|
+
self._dependency_metas.setdefault(f"res:{resource_doc.source}", meta)
|
|
417
432
|
entry = ResourceEntry(
|
|
418
433
|
name=resource_doc.name,
|
|
419
434
|
import_name=imp.name,
|
|
@@ -535,13 +550,14 @@ class ImportResolver:
|
|
|
535
550
|
def _import_variables(self, imp: VariablesImport, base_dir: str, *, top_level: bool) -> None:
|
|
536
551
|
assert imp.name is not None
|
|
537
552
|
|
|
538
|
-
library_doc = self._imports_manager.
|
|
553
|
+
library_doc, meta = self._imports_manager.get_libdoc_for_variables_import_with_meta(
|
|
539
554
|
imp.name,
|
|
540
555
|
imp.args,
|
|
541
556
|
base_dir=base_dir,
|
|
542
557
|
sentinel=self._sentinel,
|
|
543
558
|
variables=self._variables,
|
|
544
559
|
)
|
|
560
|
+
self._dependency_metas[f"var:{imp.name}"] = meta
|
|
545
561
|
entry = VariablesEntry(
|
|
546
562
|
name=library_doc.name,
|
|
547
563
|
import_name=imp.name,
|