__str__ und file.write

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.
mechanicalStore
User
Beiträge: 91
Registriert: Dienstag 29. Dezember 2009, 00:09

__blackjack__ hat geschrieben: Freitag 13. Mai 2022, 16:16 Es gibt da zwei Perspektiven. Der Rechner, für den ist immer eine ganze Zahl der Schlüssel und das Verknüpungskriterieum. Und keine Texte. Und wenn man Tabellen hat die in Beziehung stehen, dann sollten sie das auch über Fremdschlüssel tatsächlich tun. Und das Schema sollte auch sauber normalisiert sein.
Ich verstehe, bzw. akzeptiere das so. Dazu belese ich mich gerade hier: https://docs.sqlalchemy.org/en/14/orm/b ... ships.html
Nun frage ich mich allerdings, welche Beziehung da nötig ist. Eigentlich sollte es doch dann so aussehen:

Code: Alles auswählen

>> Tabelle Project:
id integer primary key
name text
netplan text
description text
children = relationship("Entry")

>> Tabelle Entry:
id integer primary key
project text
starttime timestamp
stoptime timestamp
project_id = Column(Integer, ForeignKey('project.id'))
Dann hätte ich eine 'One to many' Beziehung. Da diese über die eindeutigen IDs geht, könnte man alles Andere doch als Text belassen?! Ich könnte also an jedes Project-Object beliebig viele Entrys anhängen. Und je Project-Object die Zeiten (in Emtry) innerhalb eines Zeitraums abfragen. Aber kann ich damit auch z.B. nur über Entry laufen und die Zeiten (Projektunabhängig) eines Zeitraums ermitteln?

Und wozu wäre eine bidirektionale Richtung nötig? Den Sinn darin verstehe ich nicht ganz.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Dein `Entry` braucht kein `project` vom Typ TEXT mehr, denn die Informationen über das Projekt sind ja über die Beziehung aus dem Projekt verfügbar.

Ich würde das so machen (ungetestet):

Code: Alles auswählen

class Project(Base):
    __tablename__ = "project"

    id = Column(INTEGER, primary_key=True)
    name = Column(TEXT, nullable=False)
    netplan = Column(TEXT, nullable=False)
    description = Column(TEXT, nullable=True)

    # `entries` from `Entry`


class Entry(Base):
    __tablename__ = "entry"

    id = Column(INTEGER, primary_key=True)
    project_id = Column(INTEGER, ForeignKey(Project.id))
    start = Column(TIMESTAMP, nullable=False, default=DateTime.now)
    stop = Column(TIMESTAMP, nullable=True, default=None)

    project = relationship(Project, backref="entries")
Jetzt haben `Entry`-Objekte ein `project`-Attribut das zum Projekt zu dem Eintrag führt, und `Project`-Objekte haben ein `entries`-Attribut das zu allen Einträgen zu dem Projekt führt.

Code: Alles auswählen

#!/usr/bin/env python3
from datetime import datetime as DateTime, timedelta as TimeDelta

from dateutil.relativedelta import relativedelta
from sqlalchemy import (
    INTEGER,
    TEXT,
    TIMESTAMP,
    Column,
    ForeignKey,
    create_engine,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker

Base = declarative_base()
Session = sessionmaker()


class Project(Base):
    __tablename__ = "project"

    id = Column(INTEGER, primary_key=True)
    name = Column(TEXT, nullable=False, unique=True)
    netplan = Column(TEXT, nullable=False)
    description = Column(TEXT, nullable=True)

    # `entries` from `Entry`


class Entry(Base):
    __tablename__ = "entry"

    id = Column(INTEGER, primary_key=True)
    project_id = Column(INTEGER, ForeignKey(Project.id))
    start = Column(TIMESTAMP, nullable=False, default=DateTime.now)
    stop = Column(TIMESTAMP, nullable=True, default=None)

    project = relationship(Project, backref="entries")


def print_entry(entry):
    print(
        f"{entry.project.name} on {entry.start.date()} from"
        f" {entry.start.time()} to {entry.stop.time()}."
    )


def main():
    engine = create_engine("sqlite:///:memory:")
    Base.metadata.create_all(engine)
    session = Session(bind=engine)
    #
    # Beispieldaten erzeugen von denen einige im März und einige im April
    # liegen.
    #
    one_hour = TimeDelta(hours=1)
    for i in range(5):
        start = DateTime(2022, 3, 30, 10, 42, 23) + TimeDelta(days=i)
        project = Project(name=f"Projekt {i}", netplan="<netplan>")
        session.add(Entry(project=project, start=start, stop=start + one_hour))
    #
    # Dem zuletzt erzeugten Projekt noch weitere Zeiteinträge im Mai hinzufügen.
    #
    for i in range(3):
        start = DateTime(2022, 5, 1, 13, 47, 11) + TimeDelta(days=i)
        project.entries.append(Entry(start=start, stop=start + one_hour))

    session.commit()
    #
    # Alle Einträge im April abfragen.
    #
    start = DateTime(2022, 4, 1)
    for entry in (
        session.query(Entry)
        .filter(Entry.start.between(start, start + relativedelta(months=1)))
        .order_by(Entry.start)
    ):
        print_entry(entry)

    print()
    #
    # Alle Einträge vom Projekt mit dem Namen "Projekt 4" abfragen.
    #
    for entry in (
        session.query(Project).filter_by(name="Projekt 4").one().entries
    ):
        print_entry(entry)


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
mechanicalStore
User
Beiträge: 91
Registriert: Dienstag 29. Dezember 2009, 00:09

__blackjack__ hat geschrieben: Samstag 14. Mai 2022, 11:26 Dein `Entry` braucht kein `project` vom Typ TEXT mehr, denn die Informationen über das Projekt sind ja über die Beziehung aus dem Projekt verfügbar.
Ja, ist mir im Nachhinein auch aufgefallen.
__blackjack__ hat geschrieben: Samstag 14. Mai 2022, 11:26 Ich würde das so machen (ungetestet):

Code: Alles auswählen

class Project(Base):
    __tablename__ = "project"
	...
Ich war auch schon am rumprobieren, aber danke für Deinen Vorgriff. Meine Version war etwas umständlicher. Zur Info, das ungetestet funktioniert auf Anhieb. :D
__blackjack__ hat geschrieben: Samstag 14. Mai 2022, 11:26 Jetzt haben `Entry`-Objekte ein `project`-Attribut das zum Projekt zu dem Eintrag führt, und `Project`-Objekte haben ein `entries`-Attribut das zu allen Einträgen zu dem Projekt führt.
Wobei 'entries' - wieder mal - auf 'magische Weise' in Project landet, da es ja in Entry deklariert ist, richtig?!

Anderes Thema; eigentlich arbeite ich privat mit einem Betriebssystem, genannt Linux. In der Firma habe ich leider kein Betriebssystem, sondern nur Windows. Daher probiere ich im Moment auf meiner (privaten) Windows-Maschine herum. Wollte WX testen. Das haut mir bei 'pip install' alles um die Ohren (eigentlich habe ich das nicht anders erwartet....). Da ich hier schon lange mit lese, weiß ich. dass es unerwünscht ist, eine Latte von Fehlermeldungen zu posten, ohne selbst mal zu analysieren, was los ist. Das habe ich versucht, komme aber nicht drauf.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Weiss nicht, woher du diesen Eindruck hast. Wir sind nicht Fehlermeldungophob.
mechanicalStore
User
Beiträge: 91
Registriert: Dienstag 29. Dezember 2009, 00:09

__deets__ hat geschrieben: Samstag 14. Mai 2022, 17:40 Weiss nicht, woher du diesen Eindruck hast. Wir sind nicht Fehlermeldungophob.
Der Eindruck erweckt sich von: 'wir machen nicht Deine Hausaufgaben' - 'was hast Du bisher selbst versucht' - 'in der Fehlermeldung steht doch ganz klar, wo das Problem ist' - 'Offene Briefe an Neulinge' - usw.

Ich verstehe das vollkommen, wirklich!!!!

Und daher - und gerade deshalb, weil hier ein hohes Maß an Hilfe erbracht wird (in der freien Wirtschaft würde das viel Geld kosten!), möchte ich halt nichts überstrapazieren. Ich bin echt froh und dankbar, wie das hier läuft. Auch bin ich der Meinung, selbst viel zu tun und auf keine Lösungen zu warten (auch wenn die dankenswerter Weise immer wieder präsentiert werden), und stattdessen lieber die Themen zu diskutieren, um auf den Punkt zu kommen. Daher möchte ich das nicht überstrapazieren, es ist mir zu viel wert, das zu gefährden!
Dennoch, ich poste das halt jetzt mal - aufgrund Deiner Antwort, die das jetzt suggeriert.
Zu erwähnen ist, dass hier 'Windows 10 Home, 64 Bit', 'Python 3.10.4, 64 Bit' und Visual Studio 2019 (inkl. C++ Compiler) installiert ist, 'eigentlich' ist also alle Voraussetzung gegeben:

Code: Alles auswählen

pip install -U wxPython

Collecting wxPython
  Using cached wxPython-4.1.1.tar.gz (66.0 MB)
  Preparing metadata (setup.py) ... done
Requirement already satisfied: pillow in c:\users\*****\appdata\local\programs\python\python310\lib\site-packages (from wxPython) (9.1.0)
Requirement already satisfied: six in c:\users\*****\appdata\local\programs\python\python310\lib\site-packages (from wxPython) (1.16.0)
Requirement already satisfied: numpy in c:\users\*****\appdata\local\programs\python\python310\lib\site-packages (from wxPython) (1.22.3)
Building wheels for collected packages: wxPython
  Building wheel for wxPython (setup.py) ... error
  error: subprocess-exited-with-error

  × python setup.py bdist_wheel did not run successfully.
  │ exit code: 1
  ╰─> [51 lines of output]
      C:\Users\*****\AppData\Local\Programs\Python\Python310\lib\site-packages\setuptools\dist.py:717: UserWarning: Usage of dash-separated 'license-file' will not be supported in future versions. Please use the underscore name 'license_file' instead
        warnings.warn(
      C:\Users\*****\AppData\Local\Programs\Python\Python310\lib\site-packages\setuptools\dist.py:294: DistDeprecationWarning: use_2to3 is ignored.
        warnings.warn(f"{attr} is ignored.", DistDeprecationWarning)
      running bdist_wheel
      running build
      C:\Users\*****\AppData\Local\Temp\pip-install-1wdf6n5b\wxpython_90a34763b78149f7bf1edcb011dfb0e0\build.py:41: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives
        from distutils.dep_util import newer, newer_group
      Will build using: "C:\Users\*****\AppData\Local\Programs\Python\Python310\python.exe"
      3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)]
      Python's architecture is 64bit
      cfg.VERSION: 4.1.1

      Running command: build
      Running command: build_wx
      Command '"C:\Users\*****\AppData\Local\Programs\Python\Python310\python.exe" -c "import setuptools, distutils.msvc9compiler as msvc; mc = msvc.MSVCCompiler(); mc.initialize(); print(mc.cc)"' failed with exit code 1.
      Traceback (most recent call last):

        File "<string>", line 1, in <module>

        File "C:\Users\*****\AppData\Local\Programs\Python\Python310\lib\distutils\msvc9compiler.py", line 371, in initialize

          vc_env = query_vcvarsall(VERSION, plat_spec)

        File "C:\Users\*****\AppData\Local\Programs\Python\Python310\lib\site-packages\setuptools\msvc.py", line 140, in msvc9_query_vcvarsall

          return EnvironmentInfo(arch, ver).return_env()

        File "C:\Users\*****\AppData\Local\Programs\Python\Python310\lib\site-packages\setuptools\msvc.py", line 1740, in return_env

          [self.VCIncludes,

        File "C:\Users\*****\AppData\Local\Programs\Python\Python310\lib\site-packages\setuptools\msvc.py", line 1282, in VCIncludes

          return [join(self.si.VCInstallDir, 'Include'),

        File "C:\Users\*****\AppData\Local\Programs\Python\Python310\lib\site-packages\setuptools\msvc.py", line 840, in VCInstallDir

          raise distutils.errors.DistutilsPlatformError(msg)

      distutils.errors.DistutilsPlatformError: Microsoft Visual C++ 14.2 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/
      Finished command: build_wx (0.296s)
      Finished command: build (0.296s)
      WARNING: Building this way assumes that all generated files have been
      generated already.  If that is not the case then use build.py directly
      to generate the source and perform the build stage.  You can use
      --skip-build with the bdist_* or install commands to avoid this
      message and the wxWidgets and Phoenix build steps in the future.

      "C:\Users\*****\AppData\Local\Programs\Python\Python310\python.exe" -u build.py build
      Command '"C:\Users\*****\AppData\Local\Programs\Python\Python310\python.exe" -u build.py build' failed with exit code 1.
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for wxPython
  Running setup.py clean for wxPython
Failed to build wxPython
Installing collected packages: wxPython
  Running setup.py install for wxPython ... error
  error: subprocess-exited-with-error

  × Running setup.py install for wxPython did not run successfully.
  │ exit code: 1
  ╰─> [51 lines of output]
      C:\Users\*****\AppData\Local\Programs\Python\Python310\lib\site-packages\setuptools\dist.py:717: UserWarning: Usage of dash-separated 'license-file' will not be supported in future versions. Please use the underscore name 'license_file' instead
        warnings.warn(
      C:\Users\*****\AppData\Local\Programs\Python\Python310\lib\site-packages\setuptools\dist.py:294: DistDeprecationWarning: use_2to3 is ignored.
        warnings.warn(f"{attr} is ignored.", DistDeprecationWarning)
      running install
      running build
      C:\Users\*****\AppData\Local\Temp\pip-install-1wdf6n5b\wxpython_90a34763b78149f7bf1edcb011dfb0e0\build.py:41: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives
        from distutils.dep_util import newer, newer_group
      Will build using: "C:\Users\*****\AppData\Local\Programs\Python\Python310\python.exe"
      3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)]
      Python's architecture is 64bit
      cfg.VERSION: 4.1.1

      Running command: build
      Running command: build_wx
      Command '"C:\Users\*****\AppData\Local\Programs\Python\Python310\python.exe" -c "import setuptools, distutils.msvc9compiler as msvc; mc = msvc.MSVCCompiler(); mc.initialize(); print(mc.cc)"' failed with exit code 1.
      Traceback (most recent call last):

        File "<string>", line 1, in <module>

        File "C:\Users\*****\AppData\Local\Programs\Python\Python310\lib\distutils\msvc9compiler.py", line 371, in initialize

          vc_env = query_vcvarsall(VERSION, plat_spec)

        File "C:\Users\*****\AppData\Local\Programs\Python\Python310\lib\site-packages\setuptools\msvc.py", line 140, in msvc9_query_vcvarsall

          return EnvironmentInfo(arch, ver).return_env()

        File "C:\Users\*****\AppData\Local\Programs\Python\Python310\lib\site-packages\setuptools\msvc.py", line 1740, in return_env

          [self.VCIncludes,

        File "C:\Users\*****\AppData\Local\Programs\Python\Python310\lib\site-packages\setuptools\msvc.py", line 1282, in VCIncludes

          return [join(self.si.VCInstallDir, 'Include'),

        File "C:\Users\*****\AppData\Local\Programs\Python\Python310\lib\site-packages\setuptools\msvc.py", line 840, in VCInstallDir

          raise distutils.errors.DistutilsPlatformError(msg)

      distutils.errors.DistutilsPlatformError: Microsoft Visual C++ 14.2 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/
      Finished command: build_wx (0.252s)
      Finished command: build (0.252s)
      WARNING: Building this way assumes that all generated files have been
      generated already.  If that is not the case then use build.py directly
      to generate the source and perform the build stage.  You can use
      --skip-build with the bdist_* or install commands to avoid this
      message and the wxWidgets and Phoenix build steps in the future.

      "C:\Users\*****\AppData\Local\Programs\Python\Python310\python.exe" -u build.py build
      Command '"C:\Users\*****\AppData\Local\Programs\Python\Python310\python.exe" -u build.py build' failed with exit code 1.
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
error: legacy-install-failure

× Encountered error while trying to install package.
╰─> wxPython

note: This is an issue with the package mentioned above, not pip.
hint: See above for output from the failure.
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

wxPython hat (noch?) keine Wheels für 3.10: https://pypi.org/project/wxPython/#files Einfachster Workaround ist, einfach zusätzlich 3.9 zu installieren, dann muss man nichts selber kompilieren.

Falls du selber kompilieren willst: Muss man unter Windows nicht diesen MSVC Command Prompt benutzen, damit die Umgebungsvariablen alle richtig gesetzt werden? Hast du das gemacht?
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@mechanicalStore: Muss es denn unbedingt Python 3.10 sein? Wenn ich in den Package Index schaue scheint es für Python 3.6 bis Python 3.9 vorkompiliertes zu geben.

Das wäre so generell ein Hinweis für Windows-Nutzer nicht die neueste Python-Version zu verwenden wenn man Pakete braucht für die nativer Code compiliert werden muss.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
mechanicalStore
User
Beiträge: 91
Registriert: Dienstag 29. Dezember 2009, 00:09

@narpfel: Ja, im Developer Command Prompt.
@ __blackjack__: Habe 3.10 völlig unbedarft installiert, frei nach dem Motto, das neueste (stable) muss das Beste sein.

Werde es mal mit 3.9 testen, danke für die Hinweise.
Das wäre so generell ein Hinweis für Windows-Nutzer nicht die neueste Python-Version zu verwenden wenn man Pakete braucht für die nativer Code compiliert werden muss.
Ich bin kein Windows-Nutzer (in dem Anwendungsfall gezwungenermaßen). :D
mechanicalStore
User
Beiträge: 91
Registriert: Dienstag 29. Dezember 2009, 00:09

Unter Python 3.9 funktioniert die Installation von wx.

Danke Euch !!
Antworten