12 Commits

Author SHA1 Message Date
Olli Graf
61e8c85bbe Styling des "Passwort vergessen" Button. 2025-02-17 06:49:49 +01:00
Olli Graf
dac83ccbf9 requirements.txt 2025-02-16 14:41:07 +01:00
Olli Graf
4d2b58b744 Dateien zu Teil 29 2025-02-16 14:39:34 +01:00
6db74b04f5 „date_diff.py“ hinzufügen
Übernahme
2024-11-11 07:00:14 +00:00
060c235e3f Typo korrigiert. 2024-11-09 16:58:16 +01:00
Olli Graf
ea14cde427 Zwischen Commit 2024-11-09 10:21:36 +01:00
Olli Graf
fec0969d7f Verzeichnis für teil28 2024-10-25 14:03:27 +02:00
Olli Graf
af36c44e66 Code für Decorators 2024-10-25 14:01:47 +02:00
b913b2cb01 Dateien hochladen nach „decorator“
Decorator Sourcen
2024-10-18 05:01:01 +00:00
Olli Graf
37cbae2683 timer Decorator 2024-10-18 06:58:31 +02:00
Olli Graf
14d3064309 Inhaltsverzeichnis. 2024-10-14 16:10:32 +02:00
Olli Graf
fd50a8628c Teil 27: logging.config 2024-10-14 16:09:41 +02:00
43 changed files with 672 additions and 25 deletions

View File

@@ -31,5 +31,6 @@ CC-BY-SA Olli Graf
|24 | match| |24 | match|
|25 | reguläre Ausdrücke| |25 | reguläre Ausdrücke|
|26 | lambda Funktionen| |26 | lambda Funktionen|
|27 | __getattr__()| |27 | logging.config|
|28 | Decorators|

52
date_diff.py Normal file
View File

@@ -0,0 +1,52 @@
#! python
import sys
from datetime import datetime
def date_diff_in_days(date1, date2):
try:
# Konvertiere die übergebenen Datumsangaben in datetime-Objekte
if date1 == '$today':
print('date1 ist heutiges Datum')
date1_obj = datetime.today()
date1_obj = date1_obj.replace(hour=0,minute=0,second=0,microsecond=0)
else:
print(f'konvertiere erstes Datum {date1}')
date1_obj = datetime.strptime(date1, "%d.%m.%Y")
if date2 == '$today':
print('date2 ist heutiges Datum')
date2_obj = datetime.today()
date2_obj = date2_obj.replace(hour=0,minute=0,second=0,microsecond=0)
else:
print(f'konvertiere zweites Datum {date2}')
date2_obj = datetime.strptime(date2, "%d.%m.%Y")
print(f'konvertiere zweites Datum {date2}')
# Berechne die Differenz zwischen den beiden Datumsangaben
print(f'erstes Datum: {date1_obj}, zweites Datum: {date2_obj}')
diff = abs(date1_obj - date2_obj).days
return diff
except ValueError as e:
print("Fehler beim Parsen der Datumsangaben:", e)
return None
if __name__ == "__main__":
# Überprüfe, ob genau zwei Datumsangaben als Parameter übergeben wurden
print(f'Params: {sys.argv}')
print(f'Anzahl Param: {len(sys.argv)}')
if len(sys.argv) != 3:
print("Bitte geben Sie zwei Datumsangaben im Format YYYY-MM-DD als Kommandozeilenparameter ein.")
else:
date1 = sys.argv[1]
date2 = sys.argv[2]
# Berechne die Differenz in Tagen zwischen den beiden Datumsangaben
difference = date_diff_in_days(date1, date2)
if difference is not None:
if sys.argv[1] == '$today':
date1= 'heutigen Tag'
if sys.argv[2] == '$today':
date2= 'heutigen Tag'
print(f"Zwischen dem {date1} und dem {date2} liegen {difference} Tage.")

View File

@@ -0,0 +1,9 @@
---
version: "2.1"
services:
fibserver:
image: hans:5000/fibserver:1
container_name: fibserver
ports:
- 8085:8085
restart: unless-stopped

1
getattr/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
__pycache__

19
getattr/Kreis_getattr.py Normal file
View File

@@ -0,0 +1,19 @@
from math import pi as pi
class Kreis_getattr:
def __init__(self, radius):
self.radius = radius
self.operators ={
'durchmesser': lambda x: self.radius * 2,
'umfang': lambda x: self.durchmesser * pi,
'flaeche': lambda x: self.radius**2 *pi
}
def __getattr__(self, name):
if name not in self.operators:
raise TypeError(f'unbekannte Operation {name}')
return self.operators[name](0)

View File

@@ -1,20 +0,0 @@
from math import pi as pi
class Kreis_gettattr:
def __init__(self, radius):
self.radius = radius
self.operators ={
'durchmesser': lambda x: self.radius * 2
'umfang': lambda x: self.durchmesser * pi
'flaeche': lambda: x: self.radius**2 *pi
}
def __getattr(self, name):
if name not in self.operators:
raise TypeError(f'unbekannte Operation {name}')
return {
} [name]

2
teil13/.gitignore vendored
View File

@@ -1,2 +1,2 @@
./__pycache__ __pycache__
./network/__pycache__/* ./network/__pycache__/*

View File

@@ -1,3 +1,6 @@
example.py example.py
ex2.py ex2.py
*.log *.log
__pycache__
db.ini

10
teil27/JSONFormatter.py Normal file
View File

@@ -0,0 +1,10 @@
import logging
import logging.config
import json
ATTR_TO_JSON = ['created', 'filename', 'funcName', 'levelname', 'lineno', 'module', 'msecs', 'msg', 'name', 'pathname', 'process', 'processName', 'relativeCreated', 'thread', 'threadName']
class JsonFormatter:
def format(self, record):
obj = {attr: getattr(record, attr)
for attr in ATTR_TO_JSON}
return json.dumps(obj, indent=4)

8
teil27/db.ini.sample Normal file
View File

@@ -0,0 +1,8 @@
[pidb]
host=database
user=piuser
password=<passwort>
database=pidb

75
teil27/dbhandler.py Normal file
View File

@@ -0,0 +1,75 @@
# Datei dbhandler.py
import mysql.connector
import datetime
import configparser
import logging
from logging import config
import json
class DBHandler(logging.Handler):
def __init__(self):
logging.Handler.__init__(self)
# Datenbank Konfiguration lesen
confparser = configparser.ConfigParser()
confparser.read('db.ini')
# Verbindung zur DB herstellen
self.connection= mysql.connector.connect(host=confparser['pidb']['host'],user = confparser['pidb']['user'],password = confparser['pidb']['password'],database = confparser['pidb']['database'])
# Tabelle anlegen, falls noch keine existiert.
self.connection.cursor().execute('''CREATE TABLE IF NOT EXISTS logs (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
zeit VARCHAR(50),
level VARCHAR(8),
message VARCHAR(40),
logger_name VARCHAR(25),
filename VARCHAR(60),
line INTEGER)''')
self.connection.commit()
# Bei Löschung der Klasseninstanz, Connection schliessen
def __del__(self):
if self.connection != None:
self.connection.close()
self.connection = None
# LogRecord in die DB schreiben
def emit(self, record):
try:
# Log-Daten in ein Tupel extrahieren
log_entry = (datetime.datetime.utcnow().isoformat(),
record.levelname,
record.getMessage(),
record.name,
record.pathname,
record.lineno)
# Log in die Datenbank einfügen
cursor = self.connection.cursor()
cursor.execute('''INSERT INTO logs (zeit, level, message, logger_name, filename, line)
VALUES (%s, %s, %s, %s, %s, %s)''', log_entry)
self.connection.commit()
cursor.close()
except Exception as e:
# im Fehlerfall den LogRecord nach "oben" weiterreichen.
self.handleError(record)
# Config aus JSON Datei laden und setzen
with open('handler_config.json') as file_config:
config.dictConfig(json.load(file_config))
# Logging testen
def testlogging():
print('testlogging() aufgerufen.')
logging.debug('Diese Zeile wird ausgefiltert.')
logging.debug('DEBUG/Druckdaten werden gesendet.')
logging.info('INFO/Es werden 2 Seiten gedruckt')
logging.debug('Diese Zeile wird auch ausgefiltert.')
logging.warning('WARN/nicht genügend Papier im Drucker')
logging.error('ERROR/Drucker nicht gefunden.')
logging.critical('CRITICAL/Drucker brennt')
if __name__ == '__main__':
testlogging()

View File

@@ -1,7 +1,19 @@
#encoding: utf-8
import logging import logging
from logging import config from logging import config
import json import json
import random import random
import JSONFormatter
#JSON Formatter
ATTR_TO_JSON = ['created', 'filename', 'funcName', 'levelname', 'lineno', 'module', 'msecs', 'msg', 'name', 'pathname', 'process', 'processName', 'relativeCreated', 'thread', 'threadName']
class JsonFormatter:
def format(self, record):
obj = {attr: getattr(record, attr)
for attr in ATTR_TO_JSON}
return json.dumps(obj, indent=4)
#CustomFilter
class HalloweenFilter(logging.Filter): class HalloweenFilter(logging.Filter):
@@ -14,7 +26,7 @@ class HalloweenFilter(logging.Filter):
# Der Unsichtbare soll keine Spuren im Logfile hinterlassen. # Der Unsichtbare soll keine Spuren im Logfile hinterlassen.
return record.getMessage().lower().find('unsichtbar') == -1 return record.getMessage().lower().find('unsichtbar') == -1
visitors = ['Werwolf','Gespenst','Hexe','Unsichtbarer','Vampir','Dämon','Gorilla','Hulk','Mumie'] visitors = ['Werwolf','Gespenst','Hexe','Unsichtbarer','Vampir','Dämon','Gorilla','Monster','Mumie']
treats = ['Bonbons','Twinkies','Lollis','Schokoladen','Kuchen', 'Äpfel'] treats = ['Bonbons','Twinkies','Lollis','Schokoladen','Kuchen', 'Äpfel']

View File

@@ -9,6 +9,9 @@
"std_out":{ "std_out":{
"format": "%(asctime)s : %(levelname)s : %(lineno)d : %(message)s", "format": "%(asctime)s : %(levelname)s : %(lineno)d : %(message)s",
"datefmt":"%I:%M:%S %d.%m.%Y" "datefmt":"%I:%M:%S %d.%m.%Y"
},
"json": {
"()": "__main__.JsonFormatter"
} }
}, },
"handlers":{ "handlers":{
@@ -18,7 +21,7 @@
"level": "DEBUG" "level": "DEBUG"
}, },
"file":{ "file":{
"formatter":"std_out", "formatter":"json",
"class":"logging.FileHandler", "class":"logging.FileHandler",
"level":"DEBUG", "level":"DEBUG",
"filename" : "halloween.log", "filename" : "halloween.log",

View File

@@ -0,0 +1,33 @@
{
"version":1,
"formatters":{
"std_out":{
"format": "%(asctime)s : %(levelname)s : %(module)s : %(funcName)s : %(lineno)d : (Process Details : (%(process)d, %(processName)s), Thread Details : (%(thread)d, %(threadName)s))\nLog : %(message)s",
"datefmt":"%d-%m-%Y %I:%M:%S"
}
},
"handlers":{
"console":{
"formatter": "std_out",
"class": "logging.StreamHandler",
"level": "DEBUG"
},
"db":{
"formatter": "std_out",
"()": "__main__.DBHandler",
"level": "DEBUG"
},
"file":{
"formatter":"std_out",
"class":"logging.FileHandler",
"level":"DEBUG",
"filename" : "raspithek.log"
}
},
"root":{
"handlers":["console","file","db"],
"level": "DEBUG"
}
}

1
teil28/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
__pycache__

25
teil28/classdecor.py Normal file
View File

@@ -0,0 +1,25 @@
# Datei: classdecor.py
def addrepr(cls):
# Universelle __repr__ Methode
def __repr__(self):
return f"{cls.__name__}({self.__dict__})"
cls.__repr__ = __repr__
return cls
@addrepr
class Fahrzeug():
def __init__(self,farbe,typ):
self.typ = typ
self.farbe = farbe
f1 = Fahrzeug('grau','VW')
f2 = Fahrzeug('rot','Ferrari')
print(f'{f1}')
print(f'{f2}')

13
teil28/counter.py Normal file
View File

@@ -0,0 +1,13 @@
#Datei: counter.py
def counter(func):
func.count = 0
def wrapper(*args, **kwargs):
func.count = func.count +1
print(f'{func.__name__} wurde {func.count}-mal aufgerufen.')
result = func(*args,**kwargs)
return result
wrapper.count = 0
return wrapper

16
teil28/fib.py Normal file
View File

@@ -0,0 +1,16 @@
#Datei: fib.py
import functools
import sys
from counter import counter
#@functools.cache
@counter
def fib(n):
if n in [0,1]:
return n
else:
return fib(n-1) + fib(n-2)

16
teil28/func_param.py Normal file
View File

@@ -0,0 +1,16 @@
# Datei: func_param.py
def add(x, y):
return x + y
def mul(x,y):
return x * y
def calculate(func, x, y):
return func(x, y)
result = calculate(add, 4, 6) # Aufruf von calculate mit add Funktion als Parameter
print(result) # Ausgabe ist 10
result = calculate(mul, 4, 6) # Aufruf von calculate mit add Funktion als Parameter
print(result) # Ausgabe ist 24

12
teil28/nested_function.py Normal file
View File

@@ -0,0 +1,12 @@
#Datei: nested_function.py
def print_message(message):
print('Umgebende Funktion')
def inner_function():
print('Eingebettete Funktion')
print(message)
inner_function()
print_message("Irgendein Text")

20
teil28/pass_func.py Normal file
View File

@@ -0,0 +1,20 @@
def make_pretty(func):
# define the inner function
def inner():
# add some additional behavior to decorated function
print("Dies ist die innere Funktion.")
# call original function
func()
# return the inner function
return inner
# define ordinary function
def ordinary():
print("Dies ist die ordinary() Funktion.")
# decorate the ordinary function
decorated_func = make_pretty(ordinary)
# call the decorated function
decorated_func()

17
teil28/reverse.py Normal file
View File

@@ -0,0 +1,17 @@
def reverse_decorator(func):
def wrapper(text):
make_reverse = "".join(reversed(text))
return func(make_reverse)
return wrapper
@reverse_decorator
def format_message(text):
return f'Text: {text}'
print(format_message('Hallo'))

21
teil28/simpledecorator.py Normal file
View File

@@ -0,0 +1,21 @@
def make_pretty(func):
# define the inner function
def inner():
# add some additional behavior to decorated function
print("I got decorated")
# call original function
func()
# return the inner function
return inner
# define ordinary function
@make_pretty
def ordinary():
print("I am ordinary")
# decorate the ordinary function
decorated_func = make_pretty(ordinary)
# call the decorated function
ordinary()

20
teil28/static.py Normal file
View File

@@ -0,0 +1,20 @@
# Datei static.py
class Math():
@staticmethod
def add(x,y):
return x+y
@staticmethod
def sub(x,y):
return x-y
@staticmethod
def mul(x,y):
return x*y
print(f'Add: {Math.add(3,2)}')
print(f'Sub: {Math.sub(3,2)}')
print(f'Mul: {Math.mul(3,2)}')

28
teil28/timer.py Normal file
View File

@@ -0,0 +1,28 @@
#Datei: timer.py
from fib import fib
from counter import counter
import time
import sys
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args,**kwargs)
end_time = time.time()
print(f'Methode {func.__name__} - Laufzeit {end_time - start_time:.4f}s')
return result
return wrapper
@timer
def summe(n):
return f"Summe: {sum(range(n))}"
@timer
def calc_fib(n):
return fib(n)
print(summe(1000000))
print(calc_fib(int(sys.argv[1])))

4
teil29/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
# created by virtualenv automatically
bin
lib

30
teil29/handleButton.py Executable file
View File

@@ -0,0 +1,30 @@
#! /usr/bin/python
#Datei: handleButton.py
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Button Signal")
button = QPushButton("Bitte klicken")
button.setCheckable(True)
button.clicked.connect(self.handle_button_click)
# Set the central widget of the Window.
self.setCentralWidget(button)
def handle_button_click(self):
print("Button geklickt")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

36
teil29/lineedit.py Executable file
View File

@@ -0,0 +1,36 @@
#! /usr/bin/python
#Datei: lineEdit.py
from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel, QLineEdit, QVBoxLayout, QWidget
import sys
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Eingabe mit LineEdit")
self.label = QLabel()
self.input = QLineEdit()
self.input.textChanged.connect(self.label.setText)
layout = QVBoxLayout()
layout.addWidget(self.input)
layout.addWidget(self.label)
container = QWidget()
container.setLayout(layout)
# Set the central widget of the Window.
self.setCentralWidget(container)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

78
teil29/login.py Executable file
View File

@@ -0,0 +1,78 @@
#! /usr/bin/python
#Datei: lineEdit.py
from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel, QLineEdit, QPushButton, QGridLayout, QWidget
from PyQt6.QtGui import QPixmap
import sys
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Login")
layout = QGridLayout()
layout.setContentsMargins(20, 20, 20, 20)
layout.setSpacing(10)
self.user_logo_pixmap =QPixmap('./user.jpg')
self.user_logo_label = QLabel()
self.user_logo_label.setPixmap(self.user_logo_pixmap)
layout.addWidget(self.user_logo_label,1,1)
self.user_label = QLabel('Username:')
self.password_label = QLabel('Passwort:')
self.username_input = QLineEdit()
self.password_input = QLineEdit()
self.password_input.setEchoMode(QLineEdit.EchoMode.Password)
layout.addWidget(self.user_label,2,0)
layout.addWidget(self.username_input,2,1,1,2)
layout.addWidget(self.password_label,3,0)
layout.addWidget(self.password_input,3,1,1,2)
#Buttons
self.register_button = QPushButton("Register")
layout.addWidget(self.register_button, 4, 1)
self.login_button = QPushButton("Login")
self.login_button.clicked.connect(self.handle_login_button)
self.register_button.clicked.connect(self.handle_register_button)
layout.addWidget(self.login_button, 4, 2)
# Password vergessen
self.forgot_pw_button = QPushButton('Passwort vergessen')
self.forgot_pw_button.setStyleSheet('QPushButton {background-color: #A3C1DA; color: blue;}')
layout.addWidget(self.forgot_pw_button,5,2)
container = QWidget()
container.setLayout(layout)
# Set the central widget of the Window.
self.setCentralWidget(container)
def handle_register_button(self):
print('Register Button')
def handle_login_button(self):
print(f'Login mit {self.username_input.text()} and {self.password_input.text()}')
def handle_forgot_pw_button(self):
print('Forgot PW')
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

26
teil29/mainwindow.py Executable file
View File

@@ -0,0 +1,26 @@
#! /usr/bin/python
#Datei: mainwindows.py
import sys
from PyQt6.QtCore import QSize, Qt
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton
# Subclass QMainWindow to customize your application's main window
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
button = QPushButton("Bitte klicken")
# Set the central widget of the Window.
self.setCentralWidget(button)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

12
teil29/pushbutton.py Executable file
View File

@@ -0,0 +1,12 @@
#! /usr/bin/python
#Datei: pushbutton.py
import sys
from PyQt6.QtWidgets import QApplication, QPushButton
app = QApplication(sys.argv)
window = QPushButton("Bitte klicken")
window.show()
app.exec()

8
teil29/pyvenv.cfg Normal file
View File

@@ -0,0 +1,8 @@
home = /usr/bin
implementation = CPython
version_info = 3.11.2.final.0
virtualenv = 20.17.1+ds
include-system-site-packages = false
base-prefix = /usr
base-exec-prefix = /usr
base-executable = /usr/bin/python3

5
teil29/requirements.txt Normal file
View File

@@ -0,0 +1,5 @@
numpy==2.2.3
opencv-python==4.11.0.86
PyQt6==6.8.1
PyQt6-Qt6==6.8.2
PyQt6_sip==13.10.0

30
teil29/sizewindow.py Executable file
View File

@@ -0,0 +1,30 @@
#! /usr/bin/python
# Datei: sizewindow.py
import sys
from PyQt6.QtCore import QSize, Qt
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton
# abgeleitet von QMainWindow können wir unser GUI besser einstellen und
# z.B. die Dimensionen des Fensters ändern.
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Fenstergröße")
button = QPushButton("Bitte klicken")
self.setFixedSize(QSize(400, 300))
# der Button sitzt als zentrales Widget im Fenster.
self.setCentralWidget(button)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

BIN
teil29/user.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

23
teil29/window.py Executable file
View File

@@ -0,0 +1,23 @@
#! /usr/bin/python
#Datei: window.py
# Die benötigten Qt Widgets
from PyQt6.QtWidgets import QApplication, QWidget
# Für die Kommandozeilenparameter
import sys
# QTApplication instanziieren. Die Kommandozeilenparameter geben wir
# mit.
app = QApplication(sys.argv)
# Window Widget erzeugen
window = QWidget()
window.show() # Das Fenster muss immer manuell angzeigt werden.
# Wvent-Loop starten.
app.exec()
# So lang die Event-Loop läuft kommen wir hier nicht hin,
# sie kann durch den "Schließen" Button des Fensters unterbrochen werden.