1- # from jaraco.path 3.7
1+ # from jaraco.path 3.7.2
2+
3+ from __future__import annotations
24
35import functools
46import pathlib
5- from typing import Dict ,Protocol ,Union
6- from typing import runtime_checkable
7+ from collections .abc import Mapping
8+ from typing import TYPE_CHECKING ,Protocol ,Union ,runtime_checkable
9+
10+ if TYPE_CHECKING :
11+ from typing_extensions import Self
712
813
914class Symlink (str ):
@@ -12,29 +17,25 @@ class Symlink(str):
1217 """
1318
1419
15- FilesSpec = Dict [str ,Union [str ,bytes ,Symlink ,'FilesSpec' ]]# type: ignore
20+ FilesSpec = Mapping [str ,Union [str ,bytes ,Symlink ,'FilesSpec' ]]
1621
1722
1823@runtime_checkable
1924class TreeMaker (Protocol ):
20- def __truediv__ (self ,* args ,** kwargs ): ...# pragma: no cover
21-
22- def mkdir (self ,** kwargs ): ...# pragma: no cover
23-
24- def write_text (self ,content ,** kwargs ): ...# pragma: no cover
25-
26- def write_bytes (self ,content ): ...# pragma: no cover
27-
28- def symlink_to (self ,target ): ...# pragma: no cover
25+ def __truediv__ (self ,other ,/ )-> Self : ...
26+ def mkdir (self ,* ,exist_ok )-> object : ...
27+ def write_text (self ,content ,/ ,* ,encoding )-> object : ...
28+ def write_bytes (self ,content ,/ )-> object : ...
29+ def symlink_to (self ,target ,/ )-> object : ...
2930
3031
31- def _ensure_tree_maker (obj :Union [ str , TreeMaker ] )-> TreeMaker :
32- return obj if isinstance (obj ,TreeMaker )else pathlib .Path (obj )# type: ignore
32+ def _ensure_tree_maker (obj :str | TreeMaker )-> TreeMaker :
33+ return obj if isinstance (obj ,TreeMaker )else pathlib .Path (obj )
3334
3435
3536def build (
3637spec :FilesSpec ,
37- prefix :Union [ str , TreeMaker ] = pathlib .Path (),# type: ignore
38+ prefix :str | TreeMaker = pathlib .Path (),
3839):
3940"""
4041 Build a set of files/directories, as described by the spec.
@@ -66,23 +67,24 @@ def build(
6667
6768
6869@functools .singledispatch
69- def create (content :Union [ str , bytes , FilesSpec ] ,path ) :
70+ def create (content :str | bytes | FilesSpec ,path : TreeMaker ) -> None :
7071path .mkdir (exist_ok = True )
71- build (content ,prefix = path )# type: ignore
72+ # Mypy only looks at the signature of the main singledispatch method. So it must contain the complete Union
73+ build (content ,prefix = path )# type: ignore[arg-type] # python/mypy#11727
7274
7375
7476@create .register
75- def _ (content :bytes ,path ) :
77+ def _ (content :bytes ,path : TreeMaker ) -> None :
7678path .write_bytes (content )
7779
7880
7981@create .register
80- def _ (content :str ,path ) :
82+ def _ (content :str ,path : TreeMaker ) -> None :
8183path .write_text (content ,encoding = 'utf-8' )
8284
8385
8486@create .register
85- def _ (content :Symlink ,path ) :
87+ def _ (content :Symlink ,path : TreeMaker ) -> None :
8688path .symlink_to (content )
8789
8890