@@ -31,7 +31,7 @@ def __init__(
31
31
if installed_packages is None :
32
32
installed_packages = []
33
33
34
- self ._installed_packages = installed_packages
34
+ self ._installed_packages = { pkg . name : pkg for pkg in installed_packages }
35
35
self ._root_package = root_package
36
36
self ._marker_env = marker_env
37
37
self ._groups = groups
@@ -102,51 +102,40 @@ def calculate_operations(
102
102
if not is_unsolicited_extra :
103
103
relevant_result_packages .add (result_package .name )
104
104
105
- installed = False
106
- for installed_package in self ._installed_packages :
107
- if result_package .name == installed_package .name :
108
- installed = True
109
-
110
- # Extras that were not requested are always uninstalled.
111
- if is_unsolicited_extra :
112
- pending_extra_uninstalls .append (installed_package )
113
-
114
- # We have to perform an update if the version or another
115
- # attribute of the package has changed (source type, url, ref, ...).
116
- elif result_package .version != installed_package .version or (
117
- (
118
- # This has to be done because installed packages cannot
119
- # have type "legacy". If a package with type "legacy"
120
- # is installed, the installed package has no source_type.
121
- # Thus, if installed_package has no source_type and
122
- # the result_package has source_type "legacy" (negation of
123
- # the following condition), update must not be performed.
124
- # This quirk has the side effect that when switching
125
- # from PyPI to legacy (or vice versa),
126
- # no update is performed.
127
- installed_package .source_type
128
- or result_package .source_type != "legacy"
129
- )
130
- and not result_package .is_same_package_as (installed_package )
131
- ):
132
- operations .append (
133
- Update (
134
- installed_package ,
135
- result_package ,
136
- priority = priorities [result_package ],
137
- )
138
- )
139
- else :
140
- operations .append (
141
- Install (result_package ).skip ("Already installed" )
105
+ if installed_package := self ._installed_packages .get (result_package .name ):
106
+ # Extras that were not requested are always uninstalled.
107
+ if is_unsolicited_extra :
108
+ pending_extra_uninstalls .append (installed_package )
109
+
110
+ # We have to perform an update if the version or another
111
+ # attribute of the package has changed (source type, url, ref, ...).
112
+ elif result_package .version != installed_package .version or (
113
+ (
114
+ # This has to be done because installed packages cannot
115
+ # have type "legacy". If a package with type "legacy"
116
+ # is installed, the installed package has no source_type.
117
+ # Thus, if installed_package has no source_type and
118
+ # the result_package has source_type "legacy" (negation of
119
+ # the following condition), update must not be performed.
120
+ # This quirk has the side effect that when switching
121
+ # from PyPI to legacy (or vice versa),
122
+ # no update is performed.
123
+ installed_package .source_type
124
+ or result_package .source_type != "legacy"
125
+ )
126
+ and not result_package .is_same_package_as (installed_package )
127
+ ):
128
+ operations .append (
129
+ Update (
130
+ installed_package ,
131
+ result_package ,
132
+ priority = priorities [result_package ],
142
133
)
134
+ )
135
+ else :
136
+ operations .append (Install (result_package ).skip ("Already installed" ))
143
137
144
- break
145
-
146
- if not (
147
- installed
148
- or (skip_directory and result_package .source_type == "directory" )
149
- ):
138
+ elif not (skip_directory and result_package .source_type == "directory" ):
150
139
op = Install (result_package , priority = priorities [result_package ])
151
140
if is_unsolicited_extra :
152
141
op .skip ("Not required" )
@@ -161,21 +150,23 @@ def calculate_operations(
161
150
162
151
if with_uninstalls :
163
152
for current_package in self ._current_packages :
164
- found = current_package .name in (relevant_result_packages | uninstalls )
165
-
166
- if not found :
167
- for installed_package in self ._installed_packages :
168
- if installed_package .name == current_package .name :
169
- uninstalls .add (installed_package .name )
170
- if installed_package .name not in system_site_packages :
171
- operations .append (Uninstall (installed_package ))
153
+ if current_package .name not in (
154
+ relevant_result_packages | uninstalls
155
+ ) and (
156
+ installed_package := self ._installed_packages .get (
157
+ current_package .name
158
+ )
159
+ ):
160
+ uninstalls .add (installed_package .name )
161
+ if installed_package .name not in system_site_packages :
162
+ operations .append (Uninstall (installed_package ))
172
163
173
164
if synchronize :
174
165
# We preserve pip when not managed by poetry, this is done to avoid
175
166
# externally managed virtual environments causing unnecessary removals.
176
167
preserved_package_names = {"pip" } - relevant_result_packages
177
168
178
- for installed_package in self ._installed_packages :
169
+ for installed_package in self ._installed_packages . values () :
179
170
if installed_package .name in uninstalls :
180
171
continue
181
172
0 commit comments