11import collections
2- import operator
2+ import itertools
33import pathlib
4+ import operator
45import zipfile
56
67from . import abc
78
8- from ._itertools import unique_everseen
9+ from ._itertools import only
910
1011
1112def remove_duplicates (items ):
@@ -41,8 +42,10 @@ def open_resource(self, resource):
4142 raise FileNotFoundError (exc .args [0 ])
4243
4344 def is_resource (self , path ):
44- # workaround for `zipfile.Path.is_file` returning true
45- # for non-existent paths.
45+ """
46+ Workaround for `zipfile.Path.is_file` returning true
47+ for non-existent paths.
48+ """
4649 target = self .files ().joinpath (path )
4750 return target .is_file () and target .exists ()
4851
@@ -67,8 +70,10 @@ def __init__(self, *paths):
6770 raise NotADirectoryError ('MultiplexedPath only supports directories' )
6871
6972 def iterdir (self ):
70- files = (file for path in self ._paths for file in path .iterdir ())
71- return unique_everseen (files , key = operator .attrgetter ('name' ))
73+ children = (child for path in self ._paths for child in path .iterdir ())
74+ by_name = operator .attrgetter ('name' )
75+ groups = itertools .groupby (sorted (children , key = by_name ), key = by_name )
76+ return map (self ._follow , (locs for name , locs in groups ))
7277
7378 def read_bytes (self ):
7479 raise FileNotFoundError (f'{ self } is not a file' )
@@ -90,6 +95,25 @@ def joinpath(self, *descendants):
9095 # Just return something that will not exist.
9196 return self ._paths [0 ].joinpath (* descendants )
9297
98+ @classmethod
99+ def _follow (cls , children ):
100+ """
101+ Construct a MultiplexedPath if needed.
102+
103+ If children contains a sole element, return it.
104+ Otherwise, return a MultiplexedPath of the items.
105+ Unless one of the items is not a Directory, then return the first.
106+ """
107+ subdirs , one_dir , one_file = itertools .tee (children , 3 )
108+
109+ try :
110+ return only (one_dir )
111+ except ValueError :
112+ try :
113+ return cls (* subdirs )
114+ except NotADirectoryError :
115+ return next (one_file )
116+
93117 def open (self , * args , ** kwargs ):
94118 raise FileNotFoundError (f'{ self } is not a file' )
95119
0 commit comments