gh-102511: Speed up os.path.splitroot() with native helpers (GH-118089) · python/cpython@10bb90e

GitHub

@@ -167,56 +167,76 @@ def splitdrive(p):

167167returndrive, root+tail

168168169169170-defsplitroot(p):

171-"""Split a pathname into drive, root and tail. The drive is defined

172- exactly as in splitdrive(). On Windows, the root may be a single path

173- separator or an empty string. The tail contains anything after the root.

174- For example:

175-176- splitroot('//server/share/') == ('//server/share', '/', '')

177- splitroot('C:/Users/Barney') == ('C:', '/', 'Users/Barney')

178- splitroot('C:///spam///ham') == ('C:', '/', '//spam///ham')

179- splitroot('Windows/notepad') == ('', '', 'Windows/notepad')

180- """

181-p=os.fspath(p)

182-ifisinstance(p, bytes):

183-sep=b'\\'

184-altsep=b'/'

185-colon=b':'

186-unc_prefix=b'\\\\?\\UNC\\'

187-empty=b''

188-else:

189-sep='\\'

190-altsep='/'

191-colon=':'

192-unc_prefix='\\\\?\\UNC\\'

193-empty=''

194-normp=p.replace(altsep, sep)

195-ifnormp[:1] ==sep:

196-ifnormp[1:2] ==sep:

197-# UNC drives, e.g. \\server\share or \\?\UNC\server\share

198-# Device drives, e.g. \\.\device or \\?\device

199-start=8ifnormp[:8].upper() ==unc_prefixelse2

200-index=normp.find(sep, start)

201-ifindex==-1:

202-returnp, empty, empty

203-index2=normp.find(sep, index+1)

204-ifindex2==-1:

205-returnp, empty, empty

206-returnp[:index2], p[index2:index2+1], p[index2+1:]

170+try:

171+fromntimport_path_splitroot_ex

172+exceptImportError:

173+defsplitroot(p):

174+"""Split a pathname into drive, root and tail. The drive is defined

175+ exactly as in splitdrive(). On Windows, the root may be a single path

176+ separator or an empty string. The tail contains anything after the root.

177+ For example:

178+179+ splitroot('//server/share/') == ('//server/share', '/', '')

180+ splitroot('C:/Users/Barney') == ('C:', '/', 'Users/Barney')

181+ splitroot('C:///spam///ham') == ('C:', '/', '//spam///ham')

182+ splitroot('Windows/notepad') == ('', '', 'Windows/notepad')

183+ """

184+p=os.fspath(p)

185+ifisinstance(p, bytes):

186+sep=b'\\'

187+altsep=b'/'

188+colon=b':'

189+unc_prefix=b'\\\\?\\UNC\\'

190+empty=b''

207191else:

208-# Relative path with root, e.g. \Windows

209-returnempty, p[:1], p[1:]

210-elifnormp[1:2] ==colon:

211-ifnormp[2:3] ==sep:

212-# Absolute drive-letter path, e.g. X:\Windows

213-returnp[:2], p[2:3], p[3:]

192+sep='\\'

193+altsep='/'

194+colon=':'

195+unc_prefix='\\\\?\\UNC\\'

196+empty=''

197+normp=p.replace(altsep, sep)

198+ifnormp[:1] ==sep:

199+ifnormp[1:2] ==sep:

200+# UNC drives, e.g. \\server\share or \\?\UNC\server\share

201+# Device drives, e.g. \\.\device or \\?\device

202+start=8ifnormp[:8].upper() ==unc_prefixelse2

203+index=normp.find(sep, start)

204+ifindex==-1:

205+returnp, empty, empty

206+index2=normp.find(sep, index+1)

207+ifindex2==-1:

208+returnp, empty, empty

209+returnp[:index2], p[index2:index2+1], p[index2+1:]

210+else:

211+# Relative path with root, e.g. \Windows

212+returnempty, p[:1], p[1:]

213+elifnormp[1:2] ==colon:

214+ifnormp[2:3] ==sep:

215+# Absolute drive-letter path, e.g. X:\Windows

216+returnp[:2], p[2:3], p[3:]

217+else:

218+# Relative path with drive, e.g. X:Windows

219+returnp[:2], empty, p[2:]

214220else:

215-# Relative path with drive, e.g. X:Windows

216-returnp[:2], empty, p[2:]

217-else:

218-# Relative path, e.g. Windows

219-returnempty, empty, p

221+# Relative path, e.g. Windows

222+returnempty, empty, p

223+else:

224+defsplitroot(p):

225+"""Split a pathname into drive, root and tail. The drive is defined

226+ exactly as in splitdrive(). On Windows, the root may be a single path

227+ separator or an empty string. The tail contains anything after the root.

228+ For example:

229+230+ splitroot('//server/share/') == ('//server/share', '/', '')

231+ splitroot('C:/Users/Barney') == ('C:', '/', 'Users/Barney')

232+ splitroot('C:///spam///ham') == ('C:', '/', '//spam///ham')

233+ splitroot('Windows/notepad') == ('', '', 'Windows/notepad')

234+ """

235+p=os.fspath(p)

236+ifisinstance(p, bytes):

237+drive, root, tail=_path_splitroot_ex(os.fsdecode(p))

238+returnos.fsencode(drive), os.fsencode(root), os.fsencode(tail)

239+return_path_splitroot_ex(p)

220240221241222242# Split a path in head (everything up to the last '/') and tail (the