1212_os_alt_seps : list [str ] = list (
1313 sep for sep in [os .sep , os .path .altsep ] if sep is not None and sep != "/"
1414)
15+ # https://chrisdenton.github.io/omnipath/Special%20Dos%20Device%20Names.html
1516_windows_device_files = {
16- "CON" ,
17- "PRN" ,
1817 "AUX" ,
18+ "CON" ,
19+ "CONIN$" ,
20+ "CONOUT$" ,
21+ * (f"COM{ c } " for c in "123456789¹²³" ),
22+ * (f"LPT{ c } " for c in "123456789¹²³" ),
1923 "NUL" ,
20- * (f"COM{ i } " for i in range (10 )),
21- * (f"LPT{ i } " for i in range (10 )),
24+ "PRN" ,
2225}
2326
2427
@@ -148,8 +151,12 @@ def safe_join(directory: str, *pathnames: str) -> str | None:
148151 base directory.
149152 :return: A safe path, otherwise ``None``.
150153
154+ .. versionchanged:: 3.1.5
155+ More special device names, regardless of extension or trailing spaces,
156+ are not allowed on Windows.
157+
151158 .. versionchanged:: 3.1.4
152- Special device names are disallowed on Windows.
159+ Special device names are not allowed on Windows.
153160 """
154161 if not directory :
155162 # Ensure we end up with ./path if directory="" is given,
@@ -166,7 +173,7 @@ def safe_join(directory: str, *pathnames: str) -> str | None:
166173 any (sep in filename for sep in _os_alt_seps )
167174 or (
168175 os .name == "nt"
169- and os . path . splitext ( filename )[0 ].upper () in _windows_device_files
176+ and filename . partition ( "." )[0 ]. strip () .upper () in _windows_device_files
170177 )
171178 or os .path .isabs (filename )
172179 # ntpath.isabs doesn't catch this on Python < 3.11
0 commit comments