Neuling needs Help

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
parado
User
Beiträge: 4
Registriert: Freitag 17. Mai 2013, 15:22

Hallo zusammen :D
Ich hatte mich vor ca. einer Woche dazu entschlossen mir eine Programmier- oder Scriptsprache anzueignen, nach langem überlegen und stöbern nach Informationen habe ich mich dazu entschlossen, dass es Python werden soll.

Lange rede gar kein Sinn.
Hier mein erstes Script:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: iso-8859-1 -*-
import pycurl
import sys
import httplib2
from optparse import OptionParser

# Hier koennen default Variablen gesetzt werden damit man 
# sie nicht jedes mal beim start mit angeben muss.

# Ihr Box API-Token
# Zu finden im Box Control-Panel unter Account -> API-Zugriff
#def_token = ""

# Standard CloudLevel fuer neue Boxen setzen
# CloudLevel1: 20
# CloudLevel2: 21
# CloudLevel3: 22
# CloudLevel4: 23
# CloudLevel5: 24
#plan_id = ""

# ID der Box die genutzt wird, wenn keine beim start 
# angegeben wurde
box_id = ""

##################################################
######  Ab hier bitte nichts mehr editieren ######
##################################################

# httplib2 und pycurl Variablen
h = httplib2.Http(disable_ssl_certificate_validation=True)
c = pycurl.Curl()

# Script Startoptionen
parser = OptionParser("jb [Option] Wert")
parser.add_option("-t", dest="token", help="Box API-Token")
parser.add_option("-i", dest="box_id", help="ID der Box")
parser.add_option("-p", dest="plan_id", help="CloudLevel der Box")
parser.add_option("-s", "--status", action="store_true", dest="box_status",
                  help="Anzeige des Status der Box(en)")
parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
                  default=False, help="Textausgabe an die Console aktivieren")
(option, args) = parser.parse_args()

# Checken ob ein API-Token gesetzt ist und ob
# der Pageheader Status 200 (ok) liefert
try:
    option.token
except NameError:
    option.token = None
try:
    def_token
except NameError:
    def_token = None
print def_token
print option.token
if def_token == option.token is None:
    sys.exit("\nBitte den API-Token im Script oder beim Starten angeben")
if def_token is None:
    baseurl = "https://api.box.de/%s/v1.0/Boxes/" % (option.token)
    response, content = h.request(baseurl, 'HEAD')
else:
    baseurl = "https://api.box.de/%s/v1.0/Boxes/" % (def_token)
    response, content = h.request(baseurl, 'HEAD')

if response.status == 200:
    print "\nDie Box API ist erreichbar."
else:
    sys.exit("\nBitte einen richtigen API-Token setzten")

# Checken ob die ID der Box gesetzt wurde
if option.box_id:
    print("\nDie ID %s der Box wurde erfolgreich gesetzt." % option.box_id)
else:
    print "\nKeine Box-ID gesetzt"

# Ausgabe des Status der Box(en)
if option.box_status:
    if option.box_id is None:
        print "Status aller Boxen:\n"
        c.setopt(c.URL, baseurl)
        c.perform()
        c.close()
        print "\n"
    else:
        boxurl = baseurl + option.box_id
        print("Staus der Box mit der ID: " + option.box_id + "\n")
        c.setopt(c.URL, boxurl)
        c.perform()
        c.close()
        print "\n"
Pastebin:
http://www.python-forum.de/pastebin.php?mode=view&s=349

Das ganze funktioniert auch bis jetzt tadellos, sorry wenn es aus euerer sicht sicher ein wenig :oops: "unsauber" wirkt, wie gesagt ich habe heute die ersten Beispiele zu Python angesehen und einfach mal angefangen. :wink:

Über jeden Tipp wie man es besser machen kann bzw. gewisse Abschnitte besser ordnen, verpacken oder kürzen kann um einen sauberen Code zu erhalten bin ich sehr dankbar.
(ala guck dir zu den zeilen mal das und das an, ich erwarte keine fertige lösung!)

Mein Problem:
Momentan habe ich für token, plan_id & box_id jeweils zwei Variablen, was mir stinkt und besser zu lösen sein muss.
Die einen Variablen kann man im script selbst festlegen die anderen werden per command line übergeben.

Meine Frage: Wie bekomme ich es hin das ich die Variablen im Script setzen kann, die aber vom OptionParser überschrieben werden kann, oder evtl. eine ganz andere lösung?
Hauptsache ich komme von den vorhandenen 6 variablen auf die eigentlich notwendigen 3
Ist das evtl. mit einer Funktion lösbar?

Code: Alles auswählen

print options
ergibt
{'token': 'dfjhxgfjgdfjdfjhdfjdfjgf', 'box_id': '77753', 'plan_id': None, 'verbose': False, 'box_status': True}

Es würde mir ja schon reichen wenn ich innerhalb dieser Kette(?oder wie nennt man das ding) Daten ersetzen kann, ich bekomme nur nicht raus wie!

Frage:
Im Abschnitt
# Checken ob ein API-Token gesetzt ist und ob
# der Pageheader Status 200 (ok) liefert
wird ja eigentlich nur geprüft ob ein Token gesetzt ist, die baseurl wird gebastelt & der HEAD status überprüft. da ich das vermutlich öfter in dem script brauchen werde kann man das nicht irgendwie als funktion lösen oder es zumindest vereinfachen?

Danke schonmal für jegliche Hilfe
Gruß Chris
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@parado: »parser.add_option« kennt default-Werte. Da Du die aber sowieso immer »None« setzt, ist das der Default der default-Werte. Die default-Werte werden in »options« geschrieben, wenn die Option nicht gesetzt wird.

Übrigens:

Code: Alles auswählen

if def_token == option.token is None:
wird nie erfüllt, da »def_token == option.token« entweder »True« oder »False« ist und damit nie »None«.

Edit: ich wurde eines besseren belehrt:

Code: Alles auswählen

>>> None == None is None
True
aber

Code: Alles auswählen

>>> None == (None is None)
False
>>> (None == None) is None
False
:| :? :x :K

Edit2: ah, jetzt wird's klar.

Code: Alles auswählen

None == None is None
sind zwei Vergleichsoperatoren, die gekettet werden, was äquivalent ist zu

Code: Alles auswählen

None == None and None is None
Werd ich mir merken.
parado
User
Beiträge: 4
Registriert: Freitag 17. Mai 2013, 15:22

Bin jetzt leicht verwirrt :D also funtioniert mein "Beispiel"!?

Zumindest schien es so als ich es Probiert habe!
Danke erstmal Sirius3

EDIT: Ok, habs gerafft, die Frage hat sich erübrigt!
EDIT2: »parser.add_option« kennt default Werte (Ich weiß!): Werde mal versuchen ob ich den default wert aus den obrigen Variablen lesen kann & die darein bekomme wenn sie nicht None sind, denn sonst hätte ich ein neues Problem. :D

Code: Alles auswählen

parser.add_option("-i", dest="box_id", default=*********, help="ID der JiffyBox")
evtl. jemand eine idee wich ich an der Stelle default=********* eine die Variable "def_box_id" auslesen lassen kann?
BlackJack

@parado: Im Style Guide for Python Code gibt es ein paar Richtlinien was die Quelltextformatierung und die Namenskonventionen betrifft. Konstanten werden beispielsweise komplett mit Grossbuchstaben benannt. Dann kannst Du dafür auch den gleichen Namen verwenden wie für die Option, denn Python unterscheided ja Gross- und Kleinschreibung.

Es wäre einfacher die Konstanten auch grundsätzlich immer zu definieren, also gleich auf `None` zu setzen, statt später mit einem ``except NameError:`` zu testen ob es den Namen gibt und dann erst gegebenenfalls an `None` zu binden.

Wenn man dann noch den Code in eine Funktion steckt, kann man sich den Kommentar ab wo man nichts mehr editieren soll, sparen, denn wer statt Konstanten den Code *in* einer Funktion anpasst, der hätte sich auch von einem Kommentar davon nicht aufhalten lassen. ;-)

Die ``-p``-Option wird vom Programm überhaupt nicht verwendet‽ Genauso die ``-v``/``--verbose``-Option.

Wenn man Variablen nicht `h` oder `c` nennt, dann muss man keinen Kommentar schreiben, der erklärt wofür die Namen *eigentlich* stehen, und wenn man im weiteren Programm diese Namen findet und nicht sicher ist wofür sie stehen, muss man nicht anfangen nach einem Kommentar zu suchen, der sie erklärt. Wobei nach so kurzen Namen zu suchen noch einmal ein Problem für sich sein kann. Auch sollte man Namen nicht zig Zeilen vor der ersten Verwendung an einen Wert binden. Es ist übersichtlicher und verständlicher wenn man eine Definition nicht erst lange suchen muss.

Für Werte die man zwar aus formalen Gründen an einen Namen binden muss, aber später überhaupt nicht verwendet, gibt es die Konvention einen einfachen Unterstrich als Namen zu verwenden. Etwas weniger verbreitet ist ein führender Unterstrich vor dem Namen um zu signalisieren, dass es Absicht ist, dass dieser Wert nicht verwendet wird. Das Betrifft zum Beispiel `content` beim Ergebnis vom `request()`-Aufruf.

``print`` ist in Python 2.x keine Funktion, also sollte man es nicht so schreiben als wäre es eine. Da gehören keine Klammern um die „Argumente”.

Etwas aufgeräumt könnte das so aussehen (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python
import httplib2
import sys
from optparse import OptionParser
import pycurl

# Hier koennen default Variablen gesetzt werden damit man 
# sie nicht jedes mal beim start mit angeben muss.

# Ihr Box API-Token
# Zu finden im Box Control-Panel unter Account -> API-Zugriff
TOKEN = ''

# Standard CloudLevel fuer neue Boxen setzen
# CloudLevel1: 20
# CloudLevel2: 21
# CloudLevel3: 22
# CloudLevel4: 23
# CloudLevel5: 24
PLAN_ID = None  # TODO Unused!

# ID der Box die genutzt wird, wenn keine beim start 
# angegeben wurde
BOX_ID = ''


def main():
    parser = OptionParser('jb [Option] Wert')
    parser.add_option('-t', dest='token', default=TOKEN, help='Box API-Token')
    parser.add_option('-i', dest='box_id', default=BOX_ID, help='ID der Box')
    # 
    # TODO Unused option.
    # 
    parser.add_option(
        '-p', dest='plan_id', default=PLAN_ID, help='CloudLevel der Box'
    )
    parser.add_option('-s', '--status', action='store_true', dest='box_status',
                      help='Anzeige des Status der Box(en)')
    # 
    # TODO Unused option.
    # 
    parser.add_option(
        '-v', '--verbose', action='store_true', dest='verbose', default=False,
        help='Textausgabe an die Konsole aktivieren'
    )
    option, _args = parser.parse_args()
    print option.token
    if not option.token:
        sys.exit('\nBitte den API-Token im Script oder beim Starten angeben')
    # 
    # Checken ob ein API-Token gesetzt ist und ob der Pageheader
    # Status 200 (ok) liefert.
    # 
    http = httplib2.Http(disable_ssl_certificate_validation=True)
    baseurl = 'https://api.box.de/{0}/v1.0/Boxes/'.format(option.token)
    response, _content = http.request(baseurl, 'HEAD')
    if response.status == 200:
        print '\nDie Box API ist erreichbar.'
    else:
        sys.exit('\nBitte einen richtigen API-Token setzten')
    # 
    # Checken ob die ID der Box gesetzt wurde.
    # 
    if option.box_id:
        print '\nDie ID {0} der Box wurde erfolgreich gesetzt.'.format(
            option.box_id
        )
    else:
        print '\nKeine Box-ID gesetzt'
    # 
    # Ausgabe des Status der Box(en).
    # 
    if option.box_status:
        curl = pycurl.Curl()
        print 'Status {0}:\n'.format(
            'der Box mit der ID ' + option.box_id
                if option.box_id else 'aller Boxen'
        )
        curl.setopt(curl.URL, baseurl + option.box_id)
        curl.perform()
        curl.close()
        print '\n'


if __name__ == '__main__':
    main()
Ich würde überlegen ob man wirklich zwei verschiedene Module für den Webseitenzugriff braucht und ob das wirklich *diese* beiden sein müssen. `requests` ist eine sehr schöne HTTP-Bibliothek, die nur die Standardbibliothek als Abhängigkeit hat.
parado
User
Beiträge: 4
Registriert: Freitag 17. Mai 2013, 15:22

Danke im besonderern für folgende Anmerkung:
Für Werte die man zwar aus formalen Gründen an einen Namen binden muss, aber später überhaupt nicht verwendet, gibt es die Konvention einen einfachen Unterstrich als Namen zu verwenden. Etwas weniger verbreitet ist ein führender Unterstrich vor dem Namen um zu signalisieren, dass es Absicht ist, dass dieser Wert nicht verwendet wird. Das Betrifft zum Beispiel `content` beim Ergebnis vom `request()`-Aufruf.
Dazu werde ich mehr Infos suchen!

Etwas aufgeräumt könnte das so aussehen (ungetestet): (danke auch hier!)
.........................................
Für das Beispiel danke ich dir ohnehin schonmal!

Ich würde überlegen ob man wirklich zwei verschiedene Module für den Webseitenzugriff braucht und ob das wirklich *diese* beiden sein müssen. `requests` ist eine sehr schöne HTTP-Bibliothek, die nur die Standardbibliothek als Abhängigkeit hat.

Wie gesagt vor heute habe ich mir keinen Py Code angesehen gelesen oder versucht zu verstehen! Du hast wohl in den meisten, wenn nicht allen Punkten recht, & ich danke dir sehr, es wird mich weiterbringen! Ich bin aber auch Stolz darauf, egal wie gimpig der Code aussieht, das Sript am ersten Tag, so weit zum laufen gebracht zu haben!
Ehrlich, dass habe ich selbst nicht erwartet... :shock:

Auch wenn ich keinen Zweifel daran habe das fast alles einer Verbesserung bedarf!

Samstag melde ich mich sicher nochmal :P

Danke Chris

EDIT: Ich will auch niemanden auf den Schlips treten, aber wenn man relevante Infos Highlighten oder verlinken würde, könnte es dem Anfäger oft Hilfe zur Suche leisten!
Oft wissen wir einfach nicht wonach wir suchen müssen!

Ich kenne es sehr gut aus Gebieten wo ich Ahnung habe! Was ich als logisch ansehe, fällt neulingen nicht ein!

Es geht darum zu wissen was man sucht, was nicht immer einfach ist :D
parado
User
Beiträge: 4
Registriert: Freitag 17. Mai 2013, 15:22

Ich würde überlegen ob man wirklich zwei verschiedene Module für den Webseitenzugriff braucht und ob das wirklich *diese* beiden sein müssen. `requests` ist eine sehr schöne HTTP-Bibliothek, die nur die Standardbibliothek als Abhängigkeit hat.
Danke für die Info, da hatte ich nicht drüber nachgedacht!
Ich hab jetzt erstmal mal alles auf pycurl umgeschrieben und selbstverständlich den import für httplib2 enfernt... Ich werde mir requests nochmal genauer ansehen!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

pycurl ist halt eventuell ein Problem, da es als Dependency curl hat was man auf dem System erst nachinstallieren muss, wohingegen requests keine nicht-Python Dependencies hat und auch für Python 3.x verfügbar ist.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten