@@ -152,75 +152,76 @@ impl InstalledPackages {
152
152
path : & Path ,
153
153
dist_info : & InstalledDist ,
154
154
) -> bool {
155
- // In most cases, there is no other distribution of the same name in path.
156
- let Some ( existing) = by_name
157
- . get ( dist_info. name ( ) )
158
- . into_iter ( )
159
- . flatten ( )
160
- . find_map ( |dist_id| distributions[ * dist_id] . as_ref ( ) )
161
- else {
155
+ let Some ( existing_ids) = by_name. get ( dist_info. name ( ) ) else {
162
156
return false ;
163
157
} ;
158
+ // In most cases, there is no other distribution of the same name in path.
159
+ for existing_id in existing_ids {
160
+ let Some ( existing) = distributions[ * existing_id] . as_ref ( ) else {
161
+ continue ;
162
+ } ;
164
163
165
- // Ignore duplicate paths in `sys.path`
166
- if existing == dist_info {
167
- return true ;
168
- }
164
+ // Ignore duplicate paths in `sys.path`
165
+ if existing == dist_info {
166
+ return true ;
167
+ }
169
168
170
- // On fedora, purelib and platlib in a venv are `.venv/lib` and `.venv/lib64`,
171
- // with `.venv/lib64` being a symlink to `.venv/lib`. We have to deduplicate
172
- // access across this symlink, such as:
173
- // * `.venv/lib/python3.13/site-packages/foo-1.0.0.dist-info`
174
- // * `.venv/lib64/python3.13/site-packages/foo-1.0.0.dist-info`
175
- if is_same_file ( existing. path ( ) , dist_info. path ( ) ) . unwrap_or ( false ) {
176
- return true ;
177
- }
169
+ // On fedora, purelib and platlib in a venv are `.venv/lib` and `.venv/lib64`,
170
+ // with `.venv/lib64` being a symlink to `.venv/lib`. We have to deduplicate
171
+ // access across this symlink, such as:
172
+ // * `.venv/lib/python3.13/site-packages/foo-1.0.0.dist-info`
173
+ // * `.venv/lib64/python3.13/site-packages/foo-1.0.0.dist-info`
174
+ if is_same_file ( existing. path ( ) , dist_info. path ( ) ) . unwrap_or ( false ) {
175
+ return true ;
176
+ }
178
177
179
- // egg-info directories are special: We may see them twice, once as dist-info
180
- // directory, and then again as egg-info directory in a subdirectory of the
181
- // package of the same name, linked from the `sys.path` entry added by the
182
- // editable. If they both point to the same path, we want to only consider the
183
- // dist-info that already covers the package.
184
- if let InstalledDist :: EggInfoDirectory ( InstalledEggInfoDirectory {
185
- base_path : Some ( base_path) ,
186
- ..
187
- } ) = & dist_info
188
- {
189
- if let InstalledDist :: Url ( InstalledDirectUrlDist { url, .. } ) = existing {
190
- if !is_same_file ( url. path ( ) , base_path) . unwrap_or ( false ) {
191
- debug ! (
192
- "Ignoring already processed egg-info at: `{}`" ,
193
- path. user_display( )
194
- ) ;
195
- return true ;
178
+ // egg-info directories are special: We may see them twice, once as dist-info
179
+ // directory, and then again as egg-info directory in a subdirectory of the
180
+ // package of the same name, linked from the `sys.path` entry added by the
181
+ // editable. If they both point to the same path, we want to only consider the
182
+ // dist-info that already covers the package.
183
+ if let InstalledDist :: EggInfoDirectory ( InstalledEggInfoDirectory {
184
+ base_path : Some ( base_path) ,
185
+ ..
186
+ } ) = & dist_info
187
+ {
188
+ if let InstalledDist :: Url ( InstalledDirectUrlDist { url, .. } ) = existing {
189
+ if !is_same_file ( url. path ( ) , base_path) . unwrap_or ( false ) {
190
+ debug ! (
191
+ "Ignoring already processed egg-info at: `{}`" ,
192
+ path. user_display( )
193
+ ) ;
194
+ return true ;
195
+ }
196
196
}
197
197
}
198
- }
199
198
200
- // It can be valid to shadow packages, but two different distributions for the
201
- // same package name in the same directory should never happen, see e.g.
202
- // https://github.com/astral-sh/uv/issues/11648. In this case, it is not clear
203
- // of which version the module that Python will pick up is. We must keep both
204
- // to remove both.
205
- if !is_same_file (
206
- existing. path ( ) . parent ( ) . unwrap_or ( Path :: new ( "" ) ) ,
207
- dist_info. path ( ) . parent ( ) . unwrap_or ( Path :: new ( "" ) ) ,
208
- )
209
- . unwrap_or ( false )
210
- {
211
- debug ! (
212
- "The package `{}` has multiple installed distributions:\n \
213
- - version {} at `{}`\n \
214
- - version {} at `{}`",
215
- dist_info. name( ) ,
216
- existing. version( ) ,
217
- existing. path( ) . user_display( ) ,
218
- dist_info. version( ) ,
219
- dist_info. path( ) . user_display( ) ,
220
- ) ;
199
+ // It can be valid to shadow packages, but two different distributions for the
200
+ // same package name in the same directory should never happen, see e.g.
201
+ // https://github.com/astral-sh/uv/issues/11648. In this case, it is not clear
202
+ // of which version the module that Python will pick up is. We must keep both
203
+ // to remove both.
204
+ if !is_same_file (
205
+ existing. path ( ) . parent ( ) . unwrap_or ( Path :: new ( "" ) ) ,
206
+ dist_info. path ( ) . parent ( ) . unwrap_or ( Path :: new ( "" ) ) ,
207
+ )
208
+ . unwrap_or ( false )
209
+ {
210
+ debug ! (
211
+ "The package `{}` has multiple installed distributions:\n \
212
+ - version {} at `{}`\n \
213
+ - version {} at `{}`",
214
+ dist_info. name( ) ,
215
+ existing. version( ) ,
216
+ existing. path( ) . user_display( ) ,
217
+ dist_info. version( ) ,
218
+ dist_info. path( ) . user_display( ) ,
219
+ ) ;
220
+ // We can't skip distributions even if they are inexact duplicates as we must
221
+ // uninstall them, so we continue to the `false` return.
222
+ }
221
223
}
222
224
223
- // We can't skip duplicate distributions as we must uninstall them
224
225
false
225
226
}
226
227
0 commit comments