@@ -168,8 +168,6 @@ def _create_file(self, source, metakeys):
168168 try :
169169 source = os .fspath (source )
170170 except TypeError :
171- if not isinstance (source , WritablePath ):
172- raise
173171 super ()._create_file (source , metakeys )
174172 else :
175173 copyfile (source , os .fspath (self ._path ))
@@ -544,8 +542,31 @@ def with_name(self, name):
544542 tail [- 1 ] = name
545543 return self ._from_parsed_parts (self .drive , self .root , tail )
546544
547- with_stem = JoinablePath .with_stem
548- with_suffix = JoinablePath .with_suffix
545+
546+ def with_stem (self , stem ):
547+ """Return a new path with the stem changed."""
548+ suffix = self .suffix
549+ if not suffix :
550+ return self .with_name (stem )
551+ elif not stem :
552+ # If the suffix is non-empty, we can't make the stem empty.
553+ raise ValueError (f"{ self !r} has a non-empty suffix" )
554+ else :
555+ return self .with_name (stem + suffix )
556+
557+ def with_suffix (self , suffix ):
558+ """Return a new path with the file suffix changed. If the path
559+ has no suffix, add given suffix. If the given suffix is an empty
560+ string, remove the suffix from the path.
561+ """
562+ stem = self .stem
563+ if not stem :
564+ # If the stem is empty, we can't make the suffix non-empty.
565+ raise ValueError (f"{ self !r} has an empty name" )
566+ elif suffix and not suffix .startswith ('.' ):
567+ raise ValueError (f"Invalid suffix { suffix !r} " )
568+ else :
569+ return self .with_name (stem + suffix )
549570
550571 @property
551572 def stem (self ):
@@ -1162,8 +1183,36 @@ def replace(self, target):
11621183 _copy_reader = property (_LocalCopyReader )
11631184 _copy_writer = property (_LocalCopyWriter )
11641185
1165- copy = ReadablePath .copy
1166- copy_into = ReadablePath .copy_into
1186+ def copy (self , target , follow_symlinks = True , dirs_exist_ok = False ,
1187+ preserve_metadata = False ):
1188+ """
1189+ Recursively copy this file or directory tree to the given destination.
1190+ """
1191+ if not hasattr (target , '_copy_writer' ):
1192+ target = self .with_segments (target )
1193+
1194+ # Delegate to the target path's CopyWriter object.
1195+ try :
1196+ create = target ._copy_writer ._create
1197+ except AttributeError :
1198+ raise TypeError (f"Target is not writable: { target } " ) from None
1199+ return create (self , follow_symlinks , dirs_exist_ok , preserve_metadata )
1200+
1201+ def copy_into (self , target_dir , * , follow_symlinks = True ,
1202+ dirs_exist_ok = False , preserve_metadata = False ):
1203+ """
1204+ Copy this file or directory tree into the given existing directory.
1205+ """
1206+ name = self .name
1207+ if not name :
1208+ raise ValueError (f"{ self !r} has an empty name" )
1209+ elif hasattr (target_dir , '_copy_writer' ):
1210+ target = target_dir / name
1211+ else :
1212+ target = self .with_segments (target_dir , name )
1213+ return self .copy (target , follow_symlinks = follow_symlinks ,
1214+ dirs_exist_ok = dirs_exist_ok ,
1215+ preserve_metadata = preserve_metadata )
11671216
11681217 def move (self , target ):
11691218 """
0 commit comments