Seite 1 von 2
Type Error bei Verwendung mehrer Menüs
Verfasst: Mittwoch 19. Juni 2019, 13:44
von TheBombTuber
Hallo ich habe eine Anwendung geschrieben in welcher ich mittels eines Menüs verschiedene Funktionen aufrufen lasse.
Ich möchte diese Anwendung nun mit Untermenüs ausstatten aber erhalte immer den folgenden Fehler:
TypeError: handle_con_menu() missing 1 required positional argument: 'conmenu'
Hier der Code mit welchem ich rumprobiert habe:
Code: Alles auswählen
import os
import time
import sys
def quit_entry():
sys.exit()
def handle_menu(menu):
os.system('cls')
while True:
try:
for index, item in enumerate(menu, 1):
print("{} {}".format(index, item[0]))
choice = int(input("Ihre Wahl? ")) - 1
if 0 <= choice < len(menu):
menu[choice][1]()
else:
print("Bitte nur Zahlen im Bereich 1 - {} eingeben".format(len(menu)))
time.sleep(1)
os.system('cls')
except ValueError:
print("Bitte keine Buchstaben sondern nur Zahlen im Bereich 1 - {} eingeben".format(len(menu)))
time.sleep(2)
os.system('cls')
def handle_menu2(menu2):
os.system('cls')
while True:
try:
for index, item in enumerate(menu2, 1):
print("{} {}".format(index, item[0]))
choice = int(input("Ihre Wahl? ")) - 1
if 0 <= choice < len(menu2):
menu2[choice][1]()
else:
print("Bitte nur Zahlen im Bereich 1 - {} eingeben".format(len(menu2)))
time.sleep(1)
os.system('cls')
except ValueError:
print("Bitte keine Buchstaben sondern nur Zahlen im Bereich 1 - {} eingeben".format(len(menu2)))
time.sleep(2)
os.system('cls')
menu = [
["Informationen", handle_menu2],
["Programm beenden", quit_entry],
]
menu2 = [
["Zurück", handle_menu],
["Programm beenden", quit_entry],
]
handle_menu(menu)
handle_menu2(menu2)
Wo genau ist der Fehler? Ich sage doch eigentlich nur, dass bei entsprechender Eingabe das anderen Menü aufgerufen werden soll.
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Mittwoch 19. Juni 2019, 13:48
von noisefloor
Hallo,
da im gezeigten Code gar keinen Funktion `handle_con_menu()` existiert und auch die Variable 'conmenu` nicht existiert, kann der Fehler da eigentlich gar nicht auftreten.
Gruß, noisefloor
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Mittwoch 19. Juni 2019, 13:58
von TheBombTuber
noisefloor hat geschrieben: Mittwoch 19. Juni 2019, 13:48
Hallo,
da im gezeigten Code gar keinen Funktion `handle_con_menu()` existiert und auch die Variable 'conmenu` nicht existiert, kann der Fehler da eigentlich gar nicht auftreten.
Gruß, noisefloor
hatte die Fehlermeldung noch von einem anderen versuch in der ZA gehabt ist mir leider nicht aufgefallen.
hier die Fehlermeldung zu dem gezeigten code
TypeError: handle_menu2() missing 1 required positional argument: 'menu2'
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Mittwoch 19. Juni 2019, 14:16
von Sirius3
Und was wundert Dich das jetzt? Du rufst in Zeile 18 die Funktion handle_menu2 ohne Argumente auf, es werden aber 1 erwartet.
functools.partial hilft da weiter.
`handle_menu` und `handle_menu2` sind identisch, das zweite kann also weg.
os.system sollte man nicht mehr verwenden. Der Aufruf von cls ist nicht systemunabhängig. Gerade bei solchen Dingen sollte man das also in eine Funktion auslagern, dass man im Zweifel nur an einer Stelle etwas anpassen muß. Oder am besten ganz weglassen, weil Programme, die mir meinen Bildschirminhalt zerstören sofort bei mir rausfliegen.
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Mittwoch 19. Juni 2019, 14:17
von __blackjack__
@TheBombTuber: Und wo tritt dieser Fehler auf? Bitte immer den gesamten Traceback zeigen und nicht nur die letzte Zeile.
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Mittwoch 19. Juni 2019, 15:15
von TheBombTuber
__blackjack__ hat geschrieben: Mittwoch 19. Juni 2019, 14:17
@TheBombTuber: Und wo tritt dieser Fehler auf? Bitte immer den gesamten Traceback zeigen und nicht nur die letzte Zeile.
@blackjack: Hier ist der gesamte Traceback
Code: Alles auswählen
(most recent call last):
File "<ipython-input-13-1ebcaf7c99f2>", line 1, in <module>
runfile('C:/Users/cpohlmann/.spyder-py3/temp.py', wdir='C:/Users/cpohlmann/.spyder-py3')
File "C:\Users\cpohlmann\AppData\Local\Continuum\anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 827, in runfile
execfile(filename, namespace)
File "C:\Users\cpohlmann\AppData\Local\Continuum\anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 110, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "C:/Users/cpohlmann/.spyder-py3/temp.py", line 59, in <module>
handle_menu(menu)
File "C:/Users/cpohlmann/.spyder-py3/temp.py", line 18, in handle_menu
menu[choice][1]()
TypeError: handle_menu2() missing 1 required positional argument: 'menu2'
Sirius3 hat geschrieben: Mittwoch 19. Juni 2019, 14:16
Und was wundert Dich das jetzt? Du rufst in Zeile 18 die Funktion handle_menu2 ohne Argumente auf, es werden aber 1 erwartet.
functools.partial hilft da weiter.
`handle_menu` und `handle_menu2` sind identisch, das zweite kann also weg.
os.system sollte man nicht mehr verwenden. Der Aufruf von cls ist nicht systemunabhängig. Gerade bei solchen Dingen sollte man das also in eine Funktion auslagern, dass man im Zweifel nur an einer Stelle etwas anpassen muß. Oder am besten ganz weglassen, weil Programme, die mir meinen Bildschirminhalt zerstören sofort bei mir rausfliegen.
@Sirius3: Danke für das Feedback ich werde mir functools einmal anschauen.
`handle_menu` und `handle_menu2` sind gleich weil ich mit denen am rumprobieren bin.
Wieso system('cls') durch eine extra Funktion ersetzen? Und wie müsste eine solche Funktion dann aussehen?
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Mittwoch 19. Juni 2019, 15:20
von __blackjack__
@TheBombTuber: Wieso ``system('cls')`` durch eine extra Funktion ersetzen steht da schon: Das ist so nicht systemunabhängig. Wenn man das Systemunabhängig machen möchte, braucht man da eine Fallunterscheidung, und die will man ja nicht immer und immer wieder in den Code schreiben. Noch wichtiger ist aber der letzte Satz: Weglassen den Unsinn. Oder durch eine richtige Textoberfläche ersetzen die am Ende den alten Inhalt wiederherstellt.
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Mittwoch 19. Juni 2019, 19:35
von TheBombTuber
__blackjack__ hat geschrieben: Mittwoch 19. Juni 2019, 15:20
@TheBombTuber: Wieso ``system('cls')`` durch eine extra Funktion ersetzen steht da schon: Das ist so nicht systemunabhängig. Wenn man das Systemunabhängig machen möchte, braucht man da eine Fallunterscheidung, und die will man ja nicht immer und immer wieder in den Code schreiben. Noch wichtiger ist aber der letzte Satz: Weglassen den Unsinn. Oder durch eine richtige Textoberfläche ersetzen die am Ende den alten Inhalt wiederherstellt.
@blackjack war in dem Moment etwas verpeilt hatte erst nicht verstanden was mit Systemunabhängig gemeint war.
Hast du für mich zufällig eine Quelle in der ich nachlesen kann wie ich system('cls') in einer Konsolenanwendung sauber ersetzen kann?
Da ich dies in meinem eigentlichen Code sehr häufig verwende, würde ich es gerne gleich vernünftig ersetzen.
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Mittwoch 19. Juni 2019, 23:26
von __blackjack__
Wie gesagt, am besten gar nicht machen. Ansonsten würde ich das nicht selbst programmieren sondern etwas fertiges nehmen. So spontan würde mir `click` einfallen. Das macht auch das richtige – nämlich nichts – wenn die Standardausgabe kein Terminal ist. `click` ist allerdings hauptsächlich für eine API mit Argumenten/Optionen. Falls Dein(e) Programm(e) interaktiver sind, könntest Du Dir beispielsweise `prompt_toolkit` anschauen.
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Donnerstag 20. Juni 2019, 08:04
von TheBombTuber
__blackjack__ hat geschrieben: Mittwoch 19. Juni 2019, 23:26
Wie gesagt, am besten gar nicht machen. Ansonsten würde ich das nicht selbst programmieren sondern etwas fertiges nehmen. So spontan würde mir `click` einfallen. Das macht auch das richtige – nämlich nichts – wenn die Standardausgabe kein Terminal ist. `click` ist allerdings hauptsächlich für eine API mit Argumenten/Optionen. Falls Dein(e) Programm(e) interaktiver sind, könntest Du Dir beispielsweise `prompt_toolkit` anschauen.
@blackjack Danke für den Tip 'prompt_toolkit' sieht extrem vielversprechend aus.
Ist dann auch eine gute Möglichkeit meinen jetzigen Code neu aufzubauen und zu strukturieren.
Denn momentan sieht man ihm sehr an, dass ich da immer wieder sachen zwischengeschmissen habe.
Hier einmal mein Code
PS: Bitte nicht wundern die Pfade musste ich herauskürzen
Code: Alles auswählen
# -*- coding: utf-8 -*-
"""
Spyder Editor
Bereinigung
"""
import shutil
import os
import time
import win32api
import win32con
import sys
import subprocess
from datetime import datetime
benutzer = os.getlogin()
path_cache = os.environ['K_PATH'] + ""
path_temp = "C:\\Users\\" + benutzer + ""
path_Logfile = ("C:\\Users\\" + benutzer + "\\Desktop\\LogFile_bereinigung")
Logfile = (path_Logfile + "\\LogFile.txt")
if not os.path.exists(path_Logfile):
os.mkdir(path_Logfile)
Logfile = open(Logfile,"a")
else:
Logfile = open(Logfile,"a")
def updateinfo():
print("Kommt noch")
input()
def info():
os.system("cls")
print("""Bei Ausführung der Bereinigung werden bestimmte prozesse beendet.
\nDaher ist es wichtig alle Daten vorab zu Speichern!!!\nDer Rechner wird nach Abschluss der Bereinigung neu gestartet!!!!
\nUm in das Menü zurückzukehren drücken Sie bitte Enter""")
input()
os.system("cls")
def groß_entry():
os.system("cls")
Logfile.write("********** Logentry " + str(datetime.now().strftime("%d-%m-%Y %H-%M-%S")) + " **********\n")
for i in range(10,0,-1):
sys.stdout.write("Die Bereinigung startet in " + str(i)+' ' + "Sekunden\nUm die Bereinigung abzubrechen drücken Sie STRG+C")
time.sleep(1)
sys.stdout.flush()
os.system("cls")
os.system("taskkill /f /im javaw.exe")
os.system("taskkill /f /im perl.exe")
os.system("taskkill /f /im java.exe")
time.sleep(0.1)
if os.path.exists(path_cache):
try:
for root, dirs, files in os.walk(path_cache, topdown=True):
for name in files:
win32api.SetFileAttributes(os.path.join(root, name), win32con.FILE_ATTRIBUTE_NORMAL)
for filename in os.listdir(path_cache):
print(os.path.join(path_cache, filename) + " wird gelöscht")
time.sleep(1)
shutil.rmtree(os.path.join(path_cache, filename))
Logfile.write(os.path.join(path_cache, filename) + " wurde gelöscht\n")
except PermissionError as cache_error:
os.system("cls")
print("Es werden Administratorrechte benötigt\nBitte schauen Sie, für mehr Details, in das Logfile\n\nUm in das Menü zurück zu kehren bitte Enter drücken")
Logfile.write("*******ERROR*******\nDatei {0}: konnte nicht gelöscht werden\n{1}\n*******ERROR*******\n".format(str(os.path.join(path_cache, filename)), str(cache_error)))
print("Zum fortfahren bitte Enter drücken")
input()
try:
for filename in os.listdir(path_temp):
if filename.startswith('.abc'):
print(os.path.join(path_temp, filename) + " wird gelöscht")
os.remove(os.path.join(path_temp, filename))
Logfile.write(os.path.join(path_temp, filename) + " wurde gelöscht\n")
if filename.startswith('.xyz'):
print(os.path.join(path_temp, filename) + " wird gelöscht")
os.remove(os.path.join(path_temp, filename))
Logfile.write(os.path.join(path_temp, filename) + " wurde gelöscht\n")
if filename.startswith('xyz'):
print(os.path.join(path_temp, filename) + " wird gelöscht")
os.remove(os.path.join(path_temp, filename))
Logfile.write(os.path.join(path_temp, filename) + " wurde gelöscht\n")
for path in["C:\\Users\\" + benutzer + "",
"C:\\Users\\" + benutzer + "",
"C:\\Users\\" + benutzer + "",
"C:\\Users\\" + benutzer + "",
"C:\\Users\\" + benutzer + "",
"C:\\Users\\" + benutzer + "",
os.environ['K_PATH'] ,]:
if os.path.exists(path):
win32api.SetFileAttributes(path, win32con.FILE_ATTRIBUTE_NORMAL)
print(path + " wird entfernt")
time.sleep(0.5)
shutil.rmtree(path)
Logfile.write(path + " wurde entfernt" + "\n")
print("Der Rechner wird in kürze neu gestartet!!!!")
subprocess.call(["shutdown", "/r"])
Logfile.close()
os.system("cls")
except PermissionError as temp_file_error:
Logfile.write("*******ERROR*******\nDatei {0}: konnte nicht gelöscht werden\n{1}\n*******ERROR*******\n".format(str(path), str(temp_file_error)))
print("Es werden Administratorrechte benötigt\nBitte schauen Sie, für mehr Details, in das Logfile\n\nUm in das Menü zurück zu kehren bitte Enter drücken")
Logfile.close()
input()
os.system("cls")
def shutdown_cancel():
os.system("cls")
subprocess.call(["shutdown", "/a"])
os.system("cls")
print("Der Neustart wird abgebrochen")
print("Sie kehren zurück ins Menü")
time.sleep(1)
os.system("cls")
def quit_entry():
os.system("cls")
print("Programm wird beendet")
time.sleep(1)
sys.exit()
def handle_menu(menu):
while True:
try:
for index, item in enumerate(menu, 1):
print("{} {}".format(index, item[0]))
choice = int(input("Ihre Wahl? ")) - 1
if 0 <= choice < len(menu):
menu[choice][1]()
else:
print("Bitte nur Zahlen im Bereich 1 - {} eingeben".format(len(menu)))
time.sleep(1)
os.system('cls')
except ValueError:
print("Bitte keine Buchstaben sondern nur Zahlen im Bereich 1 - {} eingeben".format(len(menu)))
time.sleep(2)
os.system('cls')
menu = [
["Informationen", info],
["Bereinigung", groß_entry],
["NEUSTART abbrechen", shutdown_cancel],
["Programm beenden", quit_entry],
]
handle_menu(menu)
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Donnerstag 20. Juni 2019, 11:26
von Sirius3
Pfade setzt man nicht mit + zusammen, sondern nutzt die Bibliothek pathlib:
Code: Alles auswählen
from pathlib import Path
LOGFILE = Path.home() / "Desktop" / "LogFile_bereinigung" / "LogFile.txt"
Konstanten schreibt man komplett GROSS.
Wenn in einem if-Block das selbe wie im else-Block steht, dann kann man es auch danach schreiben.
Wenn Du Pfade erstellen willst, geht das auch mit Path aus pathlib:
os.system sollte nicht verwendet werden, stattdessen subprocess.run.
Innerhalb der for-Schleife des try-Blocks hast Du drei if-Blöcke, die identisch sind und daher zu einem zusammengefasst werden können. startswith kann auch mehrere Vergleiche gleichzeitig machen, wenn man als Argument ein Tuple benutzt.
Das mehrfache Zusammensetzen des Pfades mit os.path.join sollte man nicht machen, sondern den gesamten Pfad einmal ermitteln und in einer Variable merken. Statt listdir besser Path.iterdir verwenden, dann bekommst Du schon Path-Objekte mit vollem Pfad.
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Freitag 21. Juni 2019, 06:00
von TheBombTuber
Sirius3 hat geschrieben: Donnerstag 20. Juni 2019, 11:26
Pfade setzt man nicht mit + zusammen, sondern nutzt die Bibliothek pathlib:
Code: Alles auswählen
from pathlib import Path
LOGFILE = Path.home() / "Desktop" / "LogFile_bereinigung" / "LogFile.txt"
Konstanten schreibt man komplett GROSS.
Wenn in einem if-Block das selbe wie im else-Block steht, dann kann man es auch danach schreiben.
Wenn Du Pfade erstellen willst, geht das auch mit Path aus pathlib:
os.system sollte nicht verwendet werden, stattdessen subprocess.run.
Innerhalb der for-Schleife des try-Blocks hast Du drei if-Blöcke, die identisch sind und daher zu einem zusammengefasst werden können. startswith kann auch mehrere Vergleiche gleichzeitig machen, wenn man als Argument ein Tuple benutzt.
Das mehrfache Zusammensetzen des Pfades mit os.path.join sollte man nicht machen, sondern den gesamten Pfad einmal ermitteln und in einer Variable merken. Statt listdir besser Path.iterdir verwenden, dann bekommst Du schon Path-Objekte mit vollem Pfad.
@Sirius3 danke für die Hinweise werde ich beachten.
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Freitag 21. Juni 2019, 13:25
von TheBombTuber
@Sirius3 Ich habe mich nun daran gemacht meinen Code umzustrukturieren aber stoße dabei auf ein Problem mit 'pathlib'
Wenn ich folgendes versuche:
Code: Alles auswählen
from pathlib import Path
TEMP_PATH = Path.home() / "AppData" / "local" / "Temp"
TEMP_NAMES = (".connect", ".startpdm", "tcic")
for filename in Path.iterdir(TEMP_PATH):
if filename.startswith(TEMP_NAMES):
print(filename)
Bekomme ich immer diesen Fehler:
Code: Alles auswählen
Traceback (most recent call last):
File "<ipython-input-12-1ebcaf7c99f2>", line 1, in <module>
runfile('C:/Users/cpohlmann/.spyder-py3/temp.py', wdir='C:/Users/cpohlmann/.spyder-py3')
File "C:\Users\cpohlmann\AppData\Local\Continuum\anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 827, in runfile
execfile(filename, namespace)
File "C:\Users\cpohlmann\AppData\Local\Continuum\anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 110, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "C:/Users/cpohlmann/.spyder-py3/temp.py", line 9, in <module>
if filename.startswith(TEMP_NAMES):
AttributeError: 'WindowsPath' object has no attribute 'startswith'
Was mache ich falsch?
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Freitag 21. Juni 2019, 13:28
von __deets__
Zu denken ein Path-Objekt sei ein String. Hier stehen alle Methoden und Properties, die ein Path-Objekt kennt:
https://docs.python.org/3/library/pathl ... properties
Du musst wohl eher auf
https://docs.python.org/3/library/pathl ... ePath.name zugreifen, und das testen.
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Freitag 21. Juni 2019, 13:41
von TheBombTuber
@deets = danke für den Tipp
Habe es nun folgendermaßen umgebaut:
Code: Alles auswählen
from pathlib import Path
TEMP_PATH = Path.home() / "AppData" / "local" / "Temp"
TEMP_NAMES = (".connect", ".startpdm", "tcic")
for OBJECT in Path.iterdir(TEMP_PATH):
FILENAME = Path (OBJECT).name
if FILENAME.startswith(TEMP_NAMES):
print(FILENAME)
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Freitag 21. Juni 2019, 13:44
von Sirius3
Komplett großgeschrieben Variablennamen sind nach Konvention Konstanten. OBJECT ist auch ein bescheidener Name, da alles ein Objekt ist. OBJEKT ist schon ein Path-Objekt, das nochmal in eins zu konvertieren, ist unsinnig.
Code: Alles auswählen
for filepath in Path.iterdir(TEMP_PATH):
if filepath.name.startswith(TEMP_NAMES):
print(filepath)
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Freitag 21. Juni 2019, 13:45
von __blackjack__
@TheBombTuber: `OBJECT` und `FILENAME` sollten nicht gross geschrieben werden, das sind ja keine Konstanten. `OBJECT` ist auch ein bisschen *sehr* generisch, denn in Python ist *alles* ein Objekt das man an einen Namen binden kann. Zudem ist `object` klein geschrieben schon der Name des eingebauten Grunddatentyps `object`.
Es macht auch nicht wirklich Sinn `Path` mit `OBJECT` aufzurufen, denn `OBJECT` ist ja bereits ein `Path`-Objekt.
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Freitag 21. Juni 2019, 13:51
von __deets__
Schoen das es klappt. Aber es gibt eine Menge zu meckern:
- GROSSBUCHSTABENSINDNURFUERKONSTANTENAUFMODULEBENEUNDNICHTFUERVARIABLEN. Also nicht OBJECT, nicht FILENAME. Sondern wenn object und filename (aber siehe gleich).
- object ist (auch kleingeschrieben) ein ganz doofer Name. Was ist denn bitte kein Objekt? Warum nicht einfach temp_file?
- Path(OBJECT).name ist cargo-cult. Das Ergebnis von iterdir sind schon Path-Objekte.
- .name nochmal an eine eigene Variable zuzuweisen ist ein bisschen ueberfluessig.
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Montag 24. Juni 2019, 07:04
von TheBombTuber
Danke an alle für die Hinweise.
Ich muss mich noch daran gewöhnen die Namenskonventionen genauer einzuhalten, aber ich versuche mein bestes.
Schlussendlich habe ich folgendes Ergebnis:
Code: Alles auswählen
for temp_files in Path.iterdir(TEMP_PATH):
if (temp_files.name).startswith(TEMP_NAMES):
print(temp_files, "wird entfernt")
shutil.rmtree(TEMP_PATH,temp_files)
Re: Type Error bei Verwendung mehrer Menüs
Verfasst: Montag 24. Juni 2019, 07:15
von __blackjack__
@TheBombTuber: `Path.iterdir()` auf der Klasse aufzurufen ist komisch/falsch.
Die Klammern um `temp_files.name` sind überflüssig.
Der `shutil.rmtree()`-Aufruf bekommt falsche Argumente.