@@ -59,7 +59,7 @@ private void AssignVariables(FromImportStatement node, IImportSearchResult impor
59
59
// TODO: warn this is not a good style per
60
60
// TODO: https://docs.python.org/3/faq/programming.html#what-are-the-best-practices-for-using-import-in-a-module
61
61
// TODO: warn this is invalid if not in the global scope.
62
- HandleModuleImportStar ( variableModule , imports is ImplicitPackageImport ) ;
62
+ HandleModuleImportStar ( variableModule , imports is ImplicitPackageImport , node . StartIndex ) ;
63
63
return ;
64
64
}
65
65
@@ -68,14 +68,16 @@ private void AssignVariables(FromImportStatement node, IImportSearchResult impor
68
68
if ( ! string . IsNullOrEmpty ( memberName ) ) {
69
69
var nameExpression = asNames [ i ] ?? names [ i ] ;
70
70
var variableName = nameExpression ? . Name ?? memberName ;
71
- var exported = variableModule . Analysis ? . GlobalScope . Variables [ memberName ] ?? variableModule . GetMember ( memberName ) ;
71
+ var variable = variableModule . Analysis ? . GlobalScope ? . Variables [ memberName ] ;
72
+ var exported = variable ?? variableModule . GetMember ( memberName ) ;
72
73
var value = exported ?? GetValueFromImports ( variableModule , imports as IImportChildrenSource , memberName ) ;
73
- Eval . DeclareVariable ( variableName , value , VariableSource . Import , nameExpression ) ;
74
+ // Do not allow imported variables to override local declarations
75
+ Eval . DeclareVariable ( variableName , value , VariableSource . Import , nameExpression , CanOverwriteVariable ( variableName , node . StartIndex ) ) ;
74
76
}
75
77
}
76
78
}
77
79
78
- private void HandleModuleImportStar ( PythonVariableModule variableModule , bool isImplicitPackage ) {
80
+ private void HandleModuleImportStar ( PythonVariableModule variableModule , bool isImplicitPackage , int importPosition ) {
79
81
if ( variableModule . Module == Module ) {
80
82
// from self import * won't define any new members
81
83
return ;
@@ -100,10 +102,31 @@ private void HandleModuleImportStar(PythonVariableModule variableModule, bool is
100
102
}
101
103
102
104
var variable = variableModule . Analysis ? . GlobalScope ? . Variables [ memberName ] ;
103
- Eval . DeclareVariable ( memberName , variable ?? member , VariableSource . Import ) ;
105
+ // Do not allow imported variables to override local declarations
106
+ Eval . DeclareVariable ( memberName , variable ?? member , VariableSource . Import , Eval . DefaultLocation , CanOverwriteVariable ( memberName , importPosition ) ) ;
104
107
}
105
108
}
106
109
110
+ private bool CanOverwriteVariable ( string name , int importPosition ) {
111
+ var v = Eval . CurrentScope . Variables [ name ] ;
112
+ if ( v == null ) {
113
+ return true ; // Variable does not exist
114
+ }
115
+ // Allow overwrite if import is below the variable. Consider
116
+ // x = 1
117
+ // x = 2
118
+ // from A import * # brings another x
119
+ // x = 3
120
+ var references = v . References . Where ( r => r . DocumentUri == Module . Uri ) . ToArray ( ) ;
121
+ if ( references . Length == 0 ) {
122
+ // No references to the variable in this file - the variable
123
+ // is imported from another module. OK to overwrite.
124
+ return true ;
125
+ }
126
+ var firstAssignmentPosition = references . Min ( r => r . Span . ToIndexSpan ( Ast ) . Start ) ;
127
+ return firstAssignmentPosition < importPosition ;
128
+ }
129
+
107
130
private IMember GetValueFromImports ( PythonVariableModule parentModule , IImportChildrenSource childrenSource , string memberName ) {
108
131
if ( childrenSource == null || ! childrenSource . TryGetChildImport ( memberName , out var childImport ) ) {
109
132
return Interpreter . UnknownType ;
0 commit comments