Die Attribute von ParameterBundle sind teilweise falsch typisiert. source und target sind Strings, keine Path-Objekte.
Funktionen sollten nach Tätigkeiten benannt sein, und komplett klein geschrieben werden, Path_str hält sich nicht daran.
Die Funktion an sich ist aber auch überflüssig, bzw. macht wohl an einigen Stellen im Zweifel etwas falsch, weil None-Werten nicht erwartet werden.
In `extend_path_by_prefix_timestamp` ist die Behandlung des Sonderfalls, dass path.name leer ist mit dem Sonderfall dass Path == "." ist, vermischt. Das kann man klarer schreiben:
Code: Alles auswählen
def extend_path_by_prefix_timestamp(path, prefix, timestamp):
if prefix is None:
prefix = ""
if path == Path("."):
new_path = Path(prefix + timestamp)
else:
new_path = path.with_name(prefix + path.name + timestamp)
return new_path
Da aber in `create_copy_items` der Fall path="." ausgeschlossen ist, vereinfacht sich die Funktion so stark, dass es eigentlich gar keine eigene Funktion braucht.
In `create_copy_items` sollten source_item und target_item schon Path-Objekte sein. extfolder sollte dementsprechend schon als Path-Objekt übergeben werden und nicht erst innerhalb der Funktion umgewandelt werden, denn das ist etwas undurchsichtig. Von args wird dann nur prefix und von params nur folder_timestamp verwendet, so dass man beides auch direkt übergeben kann.
Code: Alles auswählen
def create_copy_items(source_items, extfolder, prefix, folder_timestamp):
copy_items = []
if prefix is None:
prefix = ""
for source_path, target_path in source_items:
if source_path == Path("."):
if prefix:
print(f"--prefix {prefix} ignored")
target_new = Path(f"_home{folder_timestamp}")
else:
target_new = target_path.with_name(prefix + path.name + folder_timestamp)
copy_items.append((extfolder / source_path, extfolder / target_new))
return copy_items
Für `copy_list` wird jetzt ja auch schon das richtige extfolder übergeben, so dass sich die Dopplung des Codes für die Umwandlung erübrigt.
Eine Liste, die übergeben wird, um sie dann zu ändern, sollte nicht wieder als Rückgabewert zurückgegeben werden. Das verwirrt nur, ob wirklich die selbe Liste verwendet wird?
Es ist komisch, dass Du erst die Path-Objekte aus source ihres Pfades beraubst, um sie dann wieder an source zu binden.
Dieses `if member in prefix` verstehe ich nicht. Welchen Einfluß sollte ein Präfix auf die members haben?
`continue` sollte man vermeiden, weil es den Programmablauf undurchsichtig macht, vor allem, wenn continue in tief verschachtelten if-Abfragen auftaucht.
Die Sache mit den copy_items verstehe ich auch nicht ganz. Es sollen explizit angegebene einzelne Dateien nicht sofort kopiert werden. Aber dann kann man sie einfach schon in der done_list vormerken.
Dieses unnötige None-Tuple in done_list gehört weg. Man sollte nicht einfach nur, weil irgendwo anders etwas anderes erwartet wird, eine komplizierte Datenstruktur erzeugen, sondern die Stelle, wo es die Probleme gibt, beheben. done_list wäre dann auch besser ein Set.
Code: Alles auswählen
def copy_list(source, target, pathes_done, extfolder, prefix, args):
if not source.exists():
print(f"{source} not found")
return
members = list(source.iterdir())
if not members:
print(f"No members found in {source}")
return
if args.verbose:
print(f"\nSource: {source}\nTarget: {target}\nCopy following members: {', '.join(m.name for m in members)}")
else:
print(f"\nProcessing: {source}")
proceed = input("Proceed Y/(N) : ").upper() if args.wait else "Y"
if proceed != "Y":
return
if not target.exists():
target.mkdir(parents=True, exist_ok=True)
print(f"{target} created")
copied_count = 0
for source_member in members:
target_member = target / source_member.name
if args.excludetar and ".tar" in source_member.suffixes:
pass
elif source_member.is_dir():
if args.notrecursive:
pass
elif source_member in pathes_done:
pass
elif not args.backupdouble and source == extfolder and source_member.name.startswith("_home"):
pass
else:
copy_list(source_member, target_member, pathes_done, extfolder, prefix, args)
else:
shutil.copyfile(source_member, target_member)
if args.verbose:
print(f"{source_member.name} copied from {source.relative_to(extfolder)} to {target.relative_to(extfolder)}")
copied_count += 1
if copied_count > 0:
print(f"{copied_count} members copied")
if not args.homedouble:
pathes_done.add(source)
pathes_done.add(target)
Und hier der Rest, entsprechend angepasst:
Code: Alles auswählen
def parse_args():
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("-f", "--file", help="Filename for PDS")
parser.add_argument("-p", "--prefix", help="Prefix added before target")
parser.add_argument("-v", "--verbose", action="store_true", help="Report every single copy")
parser.add_argument("-w", "--wait", action="store_true", help="Ask before copy")
parser.add_argument("-i", "--source", help="Single Source folder, may be .")
parser.add_argument("-o", "--target", help="Single Target folder")
parser.add_argument("-e", "--extfolder", help="Extern (start) folder set if not root by default")
parser.add_argument("-r", "--notrecursive", action="store_true", help="Do not copy subdirectories")
parser.add_argument("-d", "--homedouble", action="store_true", help="Allow double copy of folders in home")
parser.add_argument("-b", "--backupdouble", action="store_true", help="Allow also backup of _home")
parser.add_argument("-t", "--notimestamp", action="store_true", help="Do not Add Timestamp to folder (not advised!)")
parser.add_argument("-x", "--excludetar", action="store_true", help="Do not store (old) .tar files in new backup")
args = parser.parse_args()
if args.file and args.source:
parser.error("You cannot use --file and --source at the same time")
if not args.prefix and args.notimestamp:
parser.error("--notimestamp without --prefix not allowed.")
if args.source is None:
if args.target:
target = None
print(f"--target {args.target} ignored")
input_file = Path(args.file if args.file else "copylist.txt")
source = target = None
else:
source = Path(args.source)
target = Path(args.target if args.target else args.source)
folder_timestamp = "" if args.notimestamp else f"_d{datetime.now():%Y%m%d_t%H%M%S}"
return args, source, target, folder_timestamp, input_file
def main():
print("\npycopy start\n")
args, source, target, folder_timestamp, input_file = parse_args()
extfolder = Path(".") if args.extfolder is None else Path(args.extfolder)
prefix = "" if args.prefix is None else args.prefix
if source:
source_items = [ (source, target) ]
else:
source_items = read_source_file(input_file)
copy_items = create_copy_items(source_items, extfolder, prefix, folder_timestamp)
pathes_done = {
source for source, target in copy_items
}
for source,target in copy_items:
copy_list(source, target, pathes_done, extfolder, prefix, args)
print("\npycopy done\n")
if __name__ == "__main__":
main()