import openpyxl schlägt fehlt

Probleme bei der Installation?
Antworten
tobi45f
User
Beiträge: 24
Registriert: Montag 22. Februar 2021, 14:31

Hallo zusammen,

ich habe ein Problem beim import von openpyxl bzw. beim Ausführen des Codes.
In VS Code läuft alles, wie es soll. Egal, ob ich F5 drücke oder über den grünen Play-Button. Mein Code läuft durch und er macht es. Der ausgewählte Interpreter ist Python 3.9.2 64bit.
Wenn ich aber das Skript aus dem Ordner heraus (Doppelklick) starten möchte, dann scheitert er bei "import openpyxl". Woher ich das weiß?

Code: Alles auswählen

from tkinter import messagebox
messagebox.showerror(title="Error Selektion", message="tkinter geht")

#import openpyxl
from openpyxl import load_workbook
messagebox.showerror(title="Error Selektion", message="openpyxl geht")
steht am anfang meines Codes. Das zweite Fenster von tkinter wird nicht mehr angezeigt, das Skript wird beendet. Wie gesagt, lustigerweise nicht, wenn ich es über VS Code starte. Ich habe sowohl import openpyxl und auch from openpyxl import ... versucht. Das Resultat war identisch.

Ich habe über "öffnen mit" zum Python 3.9 Ordner navigiert und da die korrekte Python 3.9 - python.exe und auch pythonw.exe ausgewählt und getestet. Leider ohne erfolg. Unter ..AppData\Local\Programs\Python\Python39\Lib\site-packages ist openpyxl installiert (3.0.6).

Wenn ich allerdings, das Skript per drag'n'drop auf die Python39\python(w).exe ziehe, dann läuft das Skript. Aber nicht über "öffnen mit 'damit'"? Ich versteh das nicht..

Hat jemand eine Idee, woran das liegen kann?

Grüße Tobias
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@tobi45f: Entweder hast Du noch ein anderes Python oder in VS-Code ein venv angelegt und nur in dem `openpyxl` installiert. Kannst Dir in VS-Code ja mal `sys.executable` anzeigen lassen, ob das der Interpreter ist, den Du erwartest.
“I am Dyslexic of Borg, Your Ass will be Laminated” — unknown
tobi45f
User
Beiträge: 24
Registriert: Montag 22. Februar 2021, 14:31

keine Ahnung, woran es jetzt wirklich lag, denn eigentlich sollte .py standardmäßig mit der richtigen Version geöffnet werden - aber scheinbar war das nicht der Fall. Ich habe die eine Version deinstalliert und jetzt geht es. Merkwürdig... und ja, openpyxl war nur in der einen Version installiert.
Hans888
User
Beiträge: 44
Registriert: Montag 10. Juni 2024, 08:58

Hallo zusammen ich habe über pip install openpyxl erfolgreich installiert.
Fehler
[{
"resource": "/c:/Meine Python Programme/TestExcel.py",
"owner": "_generated_diagnostic_collection_name_#1",
"code": {
"value": "reportMissingModuleSource",
"target": {
"$mid": 1,
"path": "/microsoft/pyright/blob/main/docs/configuration.md",
"scheme": "https",
"authority": "github.com",
"fragment": "reportMissingModuleSource"
}
},
"severity": 4,
"message": "Import \"openpyxl\" could not be resolved from source",
"source": "Pylance",
"startLineNumber": 1,
"startColumn": 6,
"endLineNumber": 1,
"endColumn": 14
}]
Bild

Diese Fehlermeldung erscheint.
Das Programm arbeitet und gibt in der Konsole Werte aus, aber in meine Excel Datei wird nichts geschrieben.
Hans888
User
Beiträge: 44
Registriert: Montag 10. Juni 2024, 08:58

Das wäre mein Code zum Testen am Anfang.

Code: Alles auswählen

from openpyxl import Workbook, load_workbook

wb = load_workbook("Bestellungen.xlsx")
ws = wb["Bestellungen"]


menge = ws["C2"].value
preis = ws["D2"].value

gesamtkosten = menge * preis

print("Preis ist: " + str(gesamtkosten) + "€")

ws["E2"].value = gesamtkosten
wb.save("Bestellungen.xlsx")
Benutzeravatar
Dennis89
User
Beiträge: 1503
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

wenn du über den Index einen Wert in die Zelle schreiben willst, dann ohne `value` :

Code: Alles auswählen

ws["E2"] = gesamtkosten
Die Fehlermeldung ist nicht von Python?

Gewöhne dir von Anfang an gleich an, sprechende Namen und Funktionen zu verwenden.
Es macht auch Sinn absolute Pfade zu verwenden und die dann als `Path`-Objekt anzugeben. Das kann man dann als Konstante deklarieren, dann muss man bei Änderungen, diese auch nur einmal im COde ändern.
Strings puzzelt man nicht mit + zusammen, sondern verwendet dafür `f` - Strings.

Code: Alles auswählen

#!/usr/bin/env python
from openpyxl import Workbook, load_workbook
from pathlib import Path

PATH_TO_ORDER_FILE = Path(__file__).parent / "Bestellungen.xlsx"


def main():
    workbook = load_workbook(PATH_TO_ORDER_FILE)
    worksheet = workbook["Bestellungen"]

    menge = worksheet["C2"].value
    preis = worksheet["D2"].value

    gesamtkosten = menge * preis

    print(f"Preis ist: {gesamtkosten} €")

    worksheet["E2"] = gesamtkosten
    workbook.save(PATH_TO_ORDER_FILE)


if __name__ == '__main__':
    main()
Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Hans888
User
Beiträge: 44
Registriert: Montag 10. Juni 2024, 08:58

@Dennis89
Wenn ich deinen code ausführe erhalte ich in der Konsole diese Nachricht:

"c:/Meine Python Programme/Internetexcel.py"
Preis ist: 6.9 €
PS C:\Meine Python Programme>

In der Excel Datei wird nichts eingetragen. :(

Ich habe gelsen es gibt da irgendwas mit read und write only.
Kann es sein, dass bei mir etwas falsch eingestellt ist und wie stelle ich es um?
Benutzeravatar
sparrow
User
Beiträge: 4501
Registriert: Freitag 17. April 2009, 10:28

Das Programm funktioniert korrekt.
Wenn es eine "c:/Meine Python Programme/Bestellungen.xlsx" gibt und darin ein Tabellenblatt "Bestellungen" wird in E2 das Ergebnis von C2*D2 eingetragen.
Ich tippe darauf, dass du eine andere Datei anschaust und nicht die geänderte.
Benutzeravatar
grubenfox
User
Beiträge: 593
Registriert: Freitag 2. Dezember 2022, 15:49

oder während des Programmlaufs ist die Datei noch in Excel geöffnet. Das führt im Zweifel auch zu Problemen, aber sollte meiner Meinung nach eher zum Programmabbruch durch eine Exception führen.
Hans888
User
Beiträge: 44
Registriert: Montag 10. Juni 2024, 08:58

Das Problem ist, es wird die Datei automatisch in folgender Pfad angelegt:
C:\VTRoot\HarddiskVolume3\Meine Python Programme\
Habe das nur durch einen Zufall gefunden.

Warum das nicht, wie bei allen andern, gleich in den Ordner gespeichert wird, weis ich nicht.
Benutzeravatar
sparrow
User
Beiträge: 4501
Registriert: Freitag 17. April 2009, 10:28

Da musst du wohl deine Antivirensoftware fragen.
Hans888
User
Beiträge: 44
Registriert: Montag 10. Juni 2024, 08:58

Wie meinst du das?
Antivieren Software hab ich mal gecheckt.
Jetzt wird es zwar in den Pfad kopiert, aber nur in den ersten Order :(

Warum wird beim Speichern nur in den Ordner c:/Meine Python Programme/ gespeichert.?

Code: Alles auswählen

from tkinter import *
from tkinter import filedialog

root = Tk()
root.title("Test")
root.geometry("500x450")

def open_txt():
    text_file = filedialog.askopenfilename(initialdir="C:/Meine Python Programme/Text speichern/3 Code", title="Open Text File", filetypes=(("Text Files", "*.txt"), ))
    text_file = open(text_file, "r")
    stuff = text_file.read()
    
    my_text.insert(END, stuff)
    text_file.close()

def save_text():
    text_file = open("Gesamtliste.txt", "w")
    text_file.write(my_text.get(1.0, END))



my_text = Text(root, width=40, height=10, font=("Helvetica", 16))
my_text.pack(pady=20)

open_button = Button(root, text="Öffen Text File", command=open_txt)
open_button.pack(pady=20)

save_button = Button(root, text="Save File", command=save_text)
save_button.pack(pady=20)



root.mainloop()
Benutzeravatar
grubenfox
User
Beiträge: 593
Registriert: Freitag 2. Dezember 2022, 15:49

wahrscheinlich weil bei 'save_text()' kein Pfad vorgegeben ist. Was sagt denn ein

Code: Alles auswählen

print(os.getcwd())
wenn man das in

Code: Alles auswählen

def save_text():
einfügt?
Hans888
User
Beiträge: 44
Registriert: Montag 10. Juni 2024, 08:58

NameError: name 'os' is not defined. Did you forget to import 'os'

Das kommt als Error wenn ich print(os.getcwd()) dazuschreibe.

Wenn ich in Zeile 2 import os schreibe, und dann den Code ergänze, sehe ich weder auf der Console noch auf dem Label etwas?

Code: Alles auswählen

def save_text():
    text_file = open("Gesamtliste.txt", "w")
    text_file.write(my_text.get(1.0, END))
    print(os.getcwd())
Bin noch blutiger Anfänger sry falls ich da was nicht weis oder falsch mache :(
Sirius3
User
Beiträge: 18216
Registriert: Sonntag 21. Oktober 2012, 17:20

Die Fehlermeldung sagt deutlich, dass man `os` importieren muss.
Jeder Prozess hat ein aktuelles Arbeitsverzeichnis, auf das sich relative Dateipfade beziehen. Wenn Du ein Programm startest, legst Du dieses Verzeichnis fest.
Ansonsten gilt, keine *-Importe, keine globalen Variablen und kein ausführbarer Code auf oberster Ebene.
Bei open_text fehlt ein e. Dateien öffnet nun mit with, damit sie auch verlässlich wieder geschlossen werden.

Code: Alles auswählen

import tkinter as tk
from tkinter import filedialog
from functools import partial

def open_text(text_field):
    text_file = filedialog.askopenfilename(initialdir="C:/Meine Python Programme/Text speichern/3 Code", title="Open Text File", filetypes=(("Text Files", "*.txt"), ))
    with open(text_file, "r", encoding="utf8") as file:
        stuff = file.read()
    
    text_field.insert(tk.END, stuff)

def save_text(text_field):
    with open("Gesamtliste.txt", "w", encoding="utf8") as file:
        file.write(text_field.get(1.0, tk.END))

def main():
    root = tk.Tk()
    root.title("Test")
    root.geometry("500x450")

    my_text = tk.Text(root, 
        width=40, height=10,
        font=("Helvetica", 16))
    my_text.pack(pady=20)
    tk.Button(root, text="Öffen Text File",
        command=partiall(open_text, my_text)
    ).pack(pady=20)
    tk.Button(root, text="Save File",
        command=partial(save_text, my_text)
    ).pack(pady=20)
    root.mainloop()

if __name__ == "__main__":
    main()
Hans888
User
Beiträge: 44
Registriert: Montag 10. Juni 2024, 08:58

Danke für die Hilfe mit dem Befehl partial, kann man auf einmal mehrere Variablen gelichzeitig etwas zuweisen?
Hab ich das richtig verstanden?
Benutzeravatar
Dennis89
User
Beiträge: 1503
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

das hast du falsch verstanden. `open_text` benötigt ein Argument. Dass ist das was nach `def open_text` in der Klammer steht.
Im "Normalfall" wenn du die Funktion aufrufst, würdest du schreiben `open_text(my_text)` und dann wird die Funktion ausgeführt. Wenn du aber eine Funktion an einen Button zuweist, dann darfst du kein Klammerpaar hinter den Funktionsname schreiben, weil die Funktion dann gleich ausgeführt wird, wenn der Python-Interpreter die Zeile zum ersten mal "sieht" und nicht erst wenn der Button gedrückt wird. Mit `partial` kannst du nun eine Funktion mit Argument angeben, ohne dass die gleich ausgeführt wird.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Hans888
User
Beiträge: 44
Registriert: Montag 10. Juni 2024, 08:58

Ah ok das klingt einfacher zu verstehen für mich, danke für die Erklärung und Hilfe.
Hans888
User
Beiträge: 44
Registriert: Montag 10. Juni 2024, 08:58

@Sirius3,

vorab Danke für deine Unterstützung.
Ich hoffe es ist in Ordnung, wenn ich dir eine PM sende, da du mir schon ein paar mal weiter geholfen hast.

Das mit den *-Importen hab ich nicht gewusst, jetzt aber zur Kentniss genommen.

Warum wird in den Anfänger Tutorials, egal welche, ich habe jetzt schon ein paar durch, immer in der obersten Ebene ausführbare Codes und globale Variablen angewendet?
Durch die Videos, dachte ich globale Variablen setzt man immer am Anfang.

Der Code von dir besteht nur noch aus Funktionen(wenn ich es richtig gelernt habe heißt es so).
Ist das generell besser?

Diesen Befehl hab ich noch nie gesehen:
from functools import partial
Das ist mir jetzt am Anafang zu komplex.
Hab gerade gelsen was das macht und ich muss sagen, ich verstehe mit Glück die Hälfte^^.

CODE: ALLES AUSWÄHLEN

import tkinter as tk
from tkinter import filedialog
from functools import partial

def open_text(text_field):
text_file = filedialog.askopenfilename(initialdir="C:/Meine Python Programme/Text speichern/3 Code", title="Open Text File", filetypes=(("Text Files", "*.txt"), ))
with open(text_file, "r", encoding="utf8") as file:
stuff = file.read()

text_field.insert(tk.END, stuff)

def save_text(text_field):
with open("Gesamtliste.txt", "w", encoding="utf8") as file:
file.write(text_field.get(1.0, tk.END))

def main():
root = tk.Tk()
root.title("Test")
root.geometry("500x450")

my_text = tk.Text(root,
width=40, height=10,
font=("Helvetica", 16))
my_text.pack(pady=20)
tk.Button(root, text="Öffen Text File",
command=partiall(open_text, my_text)
).pack(pady=20)
tk.Button(root, text="Save File",
command=partial(save_text, my_text)
).pack(pady=20)
root.mainloop()

if __name__ == "__main__":
main()
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Hans888: Videos bei Youtube kann jeder erstellen, da gibt's keine Qualitätskontrolle was die Inhalte betrifft. Viele Tutorials sind von Leuten die selber gerade mal mit Python angefangen haben. Teilweise ohne Vorerfahrung, teilweise mit Vorerfahrung in anderen Programmiersprachen, wo dann Gewohnheiten und Vorgehensweisen in Python übernommen werden die dort anders gehandhabt werden. Und dann gibt es halt auch einfach schlechte Programmierer, die zwar etwas funktionierendes basteln, das aber handwerklich nicht gut ist.

Es gibt auch noch den Unterschied zwischen „Ich zeige jetzt mal wie Konstrukt XY“ funktioniert, und „Ich schreibe ein echtes Programm“. Wenn man nur zeigen will wie ein bestimmtes Syntax-Konstrukt funktioniert und das in ein paar Zeilen Code geht, dann muss man da nicht unbedingt eine Funktion drum herum schreiben, wie man das in einem Programm machen würde.

Zuguterletzt gibt es Leute die zwischen ”Skripten” und ”Programmen” unterscheiden und es bei ersterem in Ordnung finden, das ohne Funktionen mit Code auf Modulebene zu schreiben. Bin ich kein Fan von, weil diese Unterscheidung sehr schwammig ist, und Code die Tendenz hat zu wachsen und irgendwann müsste man dann doch Funktionen einführen. Auf der anderen Seite macht es so gut wie gar keine Arbeit einfach immer mit einer `main()`-Funktion anzufangen und schon muss man sich gar keine Gedanken mehr darüber machen ob das nun ein ”Skript” oder ein ”Programm” ist, was man da gerade schreiben will.

Ich würde sagen kein Code auf Modulebene, der nicht dazu da ist Konstanten, Funktionen, und Klassen zu definieren, also ”nur Funktionen” ist generell besser. Man kann das Modul dann importieren, ohne dass das Programm abläuft. Zum Beispiel zur Fehlersuche interaktiv in einer Python-Shell, oder für automatisierte Tests aus einem anderen Modul heraus. Ausserdem gibt es noch nützliche Werkzeuge die erwarten, dass man ein Modul importieren kann, ohne das mehr passiert als die Definition von Konstanten, Funktionen, und Klassen. Beispielsweise welche die Dokumentation aus Docstrings erstellen. Mindestens ein Modul aus der Standardbibliothek (`multiprocessing`) erwartet das auch, damit es unter allen Betriebssystemen funktioniert.

Wenn Dir `functools.partial()` zu komplex ist, dann sind Dir „Closures“ zu komplex, und damit im Grunde auch Klassen. Mindestens eines davon, in der Praxis oft beides, braucht man für die GUI-Programmierung.
“I am Dyslexic of Borg, Your Ass will be Laminated” — unknown
Antworten