Selbst erstellte Library lässt sich nicht importieren

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mallo321123
User
Beiträge: 11
Registriert: Mittwoch 12. April 2023, 14:16
Wohnort: 127.0.0.1

Hallo, ich bin gerade dabei ein projekt von mir in eine Library zu stopfen, aber irgend wie schaffe ich es nicht.
Ich kann die Library builden und installieren ohne probleme oder Fehlermeldungen zu bekommen, aber wenn ich sie im code verwenden will, geht nix.

Hier der Link zum Github: https://github.com/Mallo321123/Investspiel_library

Ich habe das projekt mit "python3 -m build" gebaut, und mit "pip install Investspiel_library/dist/investspielapi-0.1.0-py3-none-any.whl" installiert.
Sirius3
User
Beiträge: 18227
Registriert: Sonntag 21. Oktober 2012, 17:20

Mit den von Dir zur Verfügung gestellten Informationen würde ich sagen, Du machst irgendwo etwas falsch.
Mit "geht nix" kann halt niemand etwas anfangen.
Poste hier bitte den Code und die passende Fehlermeldung.
mallo321123
User
Beiträge: 11
Registriert: Mittwoch 12. April 2023, 14:16
Wohnort: 127.0.0.1

Hier ist die Fehlermeldung wenn ich die Library in einem Programm verwenden will:

Code: Alles auswählen

Traceback (most recent call last):
  File "/**/test/test.py", line 1, in <module>
    import investspielapi
ModuleNotFoundError: No module named 'investspielapi'
Benutzeravatar
__blackjack__
User
Beiträge: 13937
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@mallo321123: Dann gehört das ``pip`` wohl zu einem anderen Python als dem mit dem das Programm dann ausgeführt wird. Dazu gehört auch ob das in ein venv installiert wird und ob *das* dann auch aktiv ist bei der Programmausführung.

Das `venv` hat in dem Github-Repository nichts zu suchen. Das ``dist/``-Verzeichnis mit dem Wheel und dem Quelltext-Archiv auch nicht. In ein Repository gehören keine generierten Sachen, sondern nur Quelltext.

Pro Klasse ein Modul macht keinen Sinn, und man steckt auch nichts in eine Klasse das einfach eine Funktion sein könnte. Und schon gar nicht hat man ”Klassen” die *nur* aus solchen Funktionen bestehen. Das ist nicht Java sondern Python! 🙄
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
Sirius3
User
Beiträge: 18227
Registriert: Sonntag 21. Oktober 2012, 17:20

@mallo321123: Wenn Du das mit den Pfaden korrigiert hast, kommen die nächsten Probleme.
In Python gibt es eine Namenskonvention, dass Klassen mit Großen Anfangsbuchstaben geschrieben werden, Funktionen und Variablen aber komplett klein. Da Du Dich nicht an diese Konvention hältst, macht es das Lesen des Codes sehr schwierig.
buy, read und sell sind zum Großteil identisch. Du solltest nicht in jeder Klasse nochmal das Lesen Deiner Config-Dateien implementieren, sondern die Konfiguration sollte einmal gelesen werden und dann eventuell an die einzelnen Klassen als Argument übergeben werden.
Du importierst Module, die gar nicht existieren. read, calc, ... sind Submodule von investspielapi, müssen deshalb auch als Submodule importiert werden.
Du benutzt print und return für das Fehlerhandling, statt Exceptions. In `read` sind z.B. im Fehlerfall Variablen nicht definiert, was dann zu einem kryptischen Folgefehler führt. `return` ist keine Funktion, sollte also nicht wie eine solche geschrieben werden.
Die Funktion chart sollte also eher so aussehen:

Code: Alles auswählen

    def chart(self, name, time_range):
        url = self.stock_config[name][time_range]
        response = requests.get(url)
        response.raise_for_status()
        return response.json()
In `price` stückelst Du dann eine URL zusammen, die eigentlich Parameter enthält:

Code: Alles auswählen

    def price(self, name):
        url = self.generall_config["get"]["url"]
        parameters = {
            "portfolio_id": self.portfolioid,
            "exchange":  self.trade_config[name]["type"],
            "ticker": self.trade_config[name]["ticker"],
        }
        response = requests.get(url, cookies=self.cookie, params=parameters)
        response.raise_for_status()
        return response.json()["StockRateInGameCurrency"]
Buy und Sell sind so ähnlich, dass man sie am besten in eine Klasse packt:

Code: Alles auswählen

class Sell:
    def __init__(self, config, trade_config, stock_config, generall_config):
        self.trade_config = trade_config
        self.stock_config = stock_config
        self.generall_config = generall_config
        
        self.portfolioid = config.portfolioid
        self.cookie = config.cookie_full

    def _buy_or_sell(self, name, parameters)
        url = self.generall_config["post"]["url"]
        headers = {
            "Cookie": str(self.cookie)
        }
        exchange = self.trade_config[name]["type"]

        parameters.update({
            'PortfolioId': int(self.portfolioid),
            'Exchange': exchange,
            'Ticker': self.trade_config[name]["ticker"],
            'DoEnqueue': False
        })
            
        value = {
            'rq': json.dumps(parameters)
        }
        response = requests.post(url, headers=headers, data=value)
        response.raise_for_status()
        return response

    def sell_count(self, amount, name):
        if amount > self.quant(name):
            raise RuntimeError("not enouth in stock")
        return self._buy_or_sell(name, {
            'SellQuantity': amount,
        })

    def sell_price(self, money, name):
        amount = self.calc_count(name, money)
        return self.count(amount, name)

    def sell_all(self, name):
        amount = self.quant(name)
        return self.count(amount, name)


    def buy_price(self, money, name):
        if money > self.ballance():
            return("not enouth money")
        return self._buy_or_sell(name, {
            'BuyWithAmount': money,
        })
                      
    def buy_count(self, count, name):
        money = self.calc_price(name, count)
        return self.buy_price(money, name)
            
    def buy_all(self, name):
        amount = self.quant(name)
        return self._buy_or_sell(name, {
            'SellQuantity': amount,
        })

    ... # hier noch die Methoden aus read und calc
wobei hier auch noch die Methoden der `read`-Klasse und die calc-Funktioen dazugehören, weil ohne eine konkrete Instanz funktionieren die sowieso nicht.
mallo321123
User
Beiträge: 11
Registriert: Mittwoch 12. April 2023, 14:16
Wohnort: 127.0.0.1

__blackjack__ hat geschrieben: Montag 17. Juni 2024, 12:28 @mallo321123: Dann gehört das ``pip`` wohl zu einem anderen Python als dem mit dem das Programm dann ausgeführt wird. Dazu gehört auch ob das in ein venv installiert wird und ob *das* dann auch aktiv ist bei der Programmausführung.

Das `venv` hat in dem Github-Repository nichts zu suchen. Das ``dist/``-Verzeichnis mit dem Wheel und dem Quelltext-Archiv auch nicht. In ein Repository gehören keine generierten Sachen, sondern nur Quelltext.

Pro Klasse ein Modul macht keinen Sinn, und man steckt auch nichts in eine Klasse das einfach eine Funktion sein könnte. Und schon gar nicht hat man ”Klassen” die *nur* aus solchen Funktionen bestehen. Das ist nicht Java sondern Python! 🙄
Ok, danke für die Infos, ich werd's mir noch mal anschauen. Ist halt mein erster versuch, und ich hab mich an eine Anleitung im Internet gehalten.
mallo321123
User
Beiträge: 11
Registriert: Mittwoch 12. April 2023, 14:16
Wohnort: 127.0.0.1

@Sirius3
Auch dir, danke für die ganzen tipps. Ich habe jetzt mal versucht so viele und so gut wie ich konnte anzuwenden.

Ich habe jetzt auch herausgefunden, warum ich die Library nicht Importen kann. Ich hatte im VScode den falschen Interpreter ausgewählt. Ich weis nicht wich ich dass geschaft habe, aber jetzt findet er zumindest was er finden soll.

Ich habe jetzt aber ein anderes Problem, wenn ich eine config verwenden will, bekomme ich einen KeyError, obwohl der Key vorhanden ist, übersehe ich da was?

Code: Alles auswählen

Traceback (most recent call last):
  File "/***/test/test.py", line 14, in <module>
    trade.buy_price(1000, "etherium")
  File "/***/.local/lib/python3.10/site-packages/investspielapi/Trade.py", line 59, in buy_price
    if money > self.ballance():
  File "/***/.local/lib/python3.10/site-packages/investspielapi/Trade.py", line 100, in ballance
    name = self.generall_config["get"]["example"]
  File "/usr/lib/python3.10/configparser.py", line 965, in __getitem__
    raise KeyError(key)
KeyError: 'get'
Benutzeravatar
__blackjack__
User
Beiträge: 13937
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@mallo321123: Wurde die Konfigurationsdatei denn überhaupt geladen? Also ich meine nicht ob Du das glaubst, sondern ob das *tatsächlich* passiert ist. Du hast da *verschiedene* und *relative* Pfadangaben in dem Quelltext und `configparser` löst keine Ausnahme aus wenn eine Datei nicht gefunden wurde, sondern lädt dann einfach nicht.

Das mit den relativen Pfadangaben ist ein Problem.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
mallo321123
User
Beiträge: 11
Registriert: Mittwoch 12. April 2023, 14:16
Wohnort: 127.0.0.1

https://github.com/Mallo321123/Investspiel_library

Naja, in der Config.py lese ich in der __init__ die config aus, und speichere sie in self.

Code: Alles auswählen

class Config:
    def __init__(self, cookieconsent, ssid, cookie, portfolioid):
        self.portfolioid = portfolioid
        
        self.cookie = {
            "CookieConsent": cookieconsent,
            "EQSESSID": ssid
        }
        
        self.cookie_full = cookie
        self.stock_config = configparser.ConfigParser()
        self.stock_config.read('config/stock.conf')
        self.generall_config = configparser.ConfigParser()
        self.generall_config.read('config/generall.conf')
        self.trade_config = configparser.ConfigParser()
        self.trade_config.read('config/trade.conf')
in meinem test Programm führe ich dann vollgendes aus:

Code: Alles auswählen

conf = Config(cookieconsent, ssid, cookie, 517566)
trade = Trade(conf)
da sollte ja eigentlich die config mitkommen? Oder verstehe ich hier was Falsch?
Benutzeravatar
__blackjack__
User
Beiträge: 13937
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@mallo321123: Da sind `read()`-Aufrufe mit relativen Pfadangaben. Die beziehen sich auf das aktuelle Arbeitsverzeichnis des Prozesses — was immer *das* auch ist! Wir wissen es nicht. Du vielleicht auch nicht. Und die `read()`-Aufrufe machen einfach gar nichts wenn die angegebene Datei nicht existiert. Und genau das scheint ja zu passieren.

Du musst entweder sicherstellen das diese Dateien relativ zum Arbeitsverzeichnis des Prozesses tatsächlich existieren, das heisst das Programm aus dem richtigen Verzeichnis heraus starten. Oder die Angaben der Pfade dort in der Methode entsprechend anpassen.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
mallo321123
User
Beiträge: 11
Registriert: Mittwoch 12. April 2023, 14:16
Wohnort: 127.0.0.1

Na, dass erklärt einiges. Kann ich irgend wie die config dateien in die Library hinzufügen?
mallo321123
User
Beiträge: 11
Registriert: Mittwoch 12. April 2023, 14:16
Wohnort: 127.0.0.1

Habs hinbekommen die configs mit einzubauen. Sind jetzt nur noch kleine probleme
mallo321123
User
Beiträge: 11
Registriert: Mittwoch 12. April 2023, 14:16
Wohnort: 127.0.0.1

Jetzt geht alles, vielen dank euch beiden für die Hilfe!!
Antworten