This feed contains pages in the "python" category.

Bei StudiVZ hat man das klitzekleine Problem, dass man nur eine Benachrichtigungsmail bekommt, dass man eine Nachricht erhalten hat, aber nicht erfährt, was drin steht. Mit ein wenig Python und einem eigenen Mailserver (eventl auch ohne) kann man aber Abhilfe schaffen:

#!/usr/bin/python
from xml.dom.minidom import parse, parseString
from mechanize import Browser
import os, sys, smtplib

# args: SENDER TO ORIGTO

mail=sys.argv[3]
pw="studivzpassword"
to=sys.argv[2]
sendermail="postmaster@example.com"

process=False
origmsg=[]
preserve_headers=['From','To','Date','Subject','Content-Type','Content-Transfer-Encoding','MIME-Version']
inHeaders=True
for line in sys.stdin:
  line=line[:-1]
  if inHeaders:
    if line == '':
      inHeaders=False
      origmsg.append("")
    s = line.split(": ",1)
    if len(s) == 2:
      (name, value) = s
    else:
      continue
    if name in preserve_headers:
      origmsg.append(line)
    if name == "Subject" and "Neue Nachricht von " in value:
      process=True
    if name == "From" and "studiVZ Zentrale" in value:
      process=True
  else:
    origmsg.append(line)

if not process:
  server = smtplib.SMTP('localhost')
  server.sendmail(sendermail, to, "\r\n".join(origmsg))
  server.quit()
  sys.exit(0)

def getMessages(data, msgs={}):
  doc=parseString(data)
  for div in doc.getElementsByTagName('div'):
    if 'status_new' in div.getAttribute('class'):
      id=div.getAttribute('id')[4:]
      if not msgs.has_key(id):
        msgs[id]={}
      for subdiv in div.getElementsByTagName('div'):
        if 'body_text' in subdiv.getAttribute('class'):
          msgs[id]['content'] = ''
          for e in subdiv.childNodes:
            if e.nodeType == e.TEXT_NODE:
              msgs[id]['content'] += '> '+e.nodeValue.strip()
            if e.nodeName == 'br':
              msgs[id]['content'] += "\r\n"
        if 'fromName' in subdiv.getAttribute('class'):
          msgs[id]['sender'] = subdiv.getElementsByTagName("a")[0].firstChild.nodeValue.strip()
          msgs[id]['time'] = subdiv.getElementsByTagName("small")[0].firstChild.nodeValue.strip()
        if 'subject' in subdiv.getAttribute('class'):
          msgs[id]['subject'] = subdiv.getElementsByTagName('a')[0].firstChild.nodeValue.strip()
  return msgs

br = Browser()
res=br.open("http://www.studivz.net")
br.select_form(nr=0)
br['email']=mail
br['password']=pw
res2=br.submit()
res3=br.follow_link(text_regex=r'Nachrichtendienst')
res4=br.follow_link(text_regex=r'Inbox')
msgs=getMessages(res4.read())
toBeRead=[]
for (id,msg) in msgs.iteritems():
  if not msg.has_key('content'):
    toBeRead.append(id)
for id in toBeRead:
  resN=br.follow_link(url_regex=r'/Messages/Inbox/messageId/'+id+'/p/')
  msgs=getMessages(resN.read(),msgs)
res6=br.follow_link(text_regex='raus hier')
if len(msgs) > 0:
  server = smtplib.SMTP('localhost')
  for (id,msg) in msgs.iteritems():
    fromaddr = str(msg['sender'])+" <"+sendermail+">"
    mmsg = "From: %s\r\nTo: %s\r\n" % (fromaddr, to)
    mmsg += "Subject: [StudiVZ] %s\r\n" % msg['subject']
    mmsg += 'Content-Type: text/plain; charset="UTF-8"\r\n'
    mmsg += 'Content-Transfer-Encoding: 8bit\r\n'
    mmsg += 'X-StudiVZ-MsgId: %s\r\n' % id
    mmsg += '\r\n'
    mmsg += msg['sender'] + ' schrieb am ' + msg['time'] + ':\r\n'
    mmsg += msg['content']
    mmsg += '\r\n\r\n\t StudiVZ Nachrichten Mailing Robot'
    server.sendmail(fromaddr, to, mmsg)
  server.quit()

Dieses Script nimmt über STDIN eine Mail entgegen und erwartet als Argumente zuerst die Absendermailadresse, danach die Mailadresse, wo die Mail schlussendlich landen sollen und als drittes Argument die Mailadresse mit der man bei StudiVZ angemeldet ist. Man bindet dieses Script in Postfix analog zu den Autoreplies ein.

Posted Sun Mar 1 21:01:36 2009 Tags: python

Bei ein wenig Javaprogrammieren bot es sich an, Rekursion zu nutzen. Unerwarteterweise schmiss Java schon bei einer Rekursionstiefe von etwa 130-140 einen Stackoverflowerror. Das hat dann recht schnell den Spieltrieb geweckt, so kam folgendes Codeschnippselchen raus:

public class Rekursion {
    public static void main(String[] args) {
        System.out.println(test(0));
    }

    public static int test(int n) {
        System.out.println(n);
        return test(++n);
    }
}

Raus kam folgendes:

$ java Rekursion
0
1
2
[snip]
6882
Exception in thread "main" java.lang.StackOverflowError
    at java.lang.String.(String.java:637)
    at java.lang.Integer.toString(Integer.java:308)
    at java.lang.Integer.toString(Integer.java:116)
    at java.lang.String.valueOf(String.java:2932)
    at java.io.PrintStream.print(PrintStream.java:547)
    at java.io.PrintStream.println(PrintStream.java:686)
    at Rekursion.test(Rekursion.java:7)

Das kann Python doch bestimmt besser dachte ich mir, folgendes entstand:

def test(n):
    n+=1
    print n
    return test(n)
print test(0)

Raus kam das hier:

$ echo -e "def test(n):\n\tn+=1\n\tprint n\n\treturn test(n)\nprint test(0)" | python
1
2
3
4
5
6
...
999
Traceback (most recent call last):
  File "", line 5, in 
....
  File "", line 4, in test
RuntimeError: maximum recursion depth exceeded

Also Python kann zwar nicht mehr, aber nur weil es nicht will, also bringen wir es dazu, zu wollen :)

$ echo -e "import sys\nsys.setrecursionlimit(1000000)\ndef test(n):\n\tn+=1\n\tprint n\n\treturn test(n)\nprint test(0)" | python
1
2
3
4
5
6
7
8
...
20953
Segmentation fault
$

Aber offenbar wird Python dann ein wenig störrisch und verabschiedet sich komplett. Der Vollständigkeit halber bringt man Java auch nochmal dazu, ein wenig mehr zu wollen:

$ java -Xss128m Rekursion
0
1
2
3
....
2520128
2520129
2520130
2520131
Exception in thread "main" java.lang.StackOverflowError
    at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:517)
    at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:544)
    at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:252)
    at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:106)
    at java.io.OutputStreamWriter.write(OutputStreamWriter.java:190)
    at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:111)
    at java.io.PrintStream.write(PrintStream.java:476)
    at java.io.PrintStream.print(PrintStream.java:547)
    at java.io.PrintStream.println(PrintStream.java:686)
    at Rekursion.test(Rekursion.java:7)

Da kommt Java dann schlussendlich aber erheblich weiter. Allerdings wirft Python (sofern sich der Interpreter nicht komplett verabschiedet) einen weitaus spezifischeren und daher auch leichter fangbaren Fehler als Java. Trotzdem bleibt in diesem Falle als Ergebnis 1:0 für Java. (Probiert wurde das ganze auf einem Standard Ubuntu 8.04, Python: Python 2.5.2 (r252:60911, Jul 31 2008, 17:28:52), Sun Java: Java(TM) SE Runtime Environment (build 1.6.0_06-b02))

Posted Fri Aug 22 18:00:29 2008 Tags: python

Beim Wechsel des Jabberservers trifft man unweigerlich auf das Problem, dass man seine Kontakte transferieren muss. Dazu gibt es zwei Möglichkeiten: Selber abtippen oder das passende Pythonmodul suchen und ein kleines Script damit schreiben. Natürlich wählt man die letztere Möglichkeit, auch wenn es dreimal so lange dauert ;)

Hier also das Resultat:

 #!/usr/bin/python
from xmpp import *
import sys
print "Daten des alten Accounts:\nServer: ",
server1 = sys.stdin.readline()
print "Port: ",
port1 = sys.stdin.readline()
print "Nick: ",
nick1 = sys.stdin.readline()
print "Password: ",
pass1 = sys.stdin.readline()
print "Daten des neuen Accounts:\nServer: ",
server2 = sys.stdin.readline()
print "Port: ",
port2 = sys.stdin.readline()
print "Nick: ",
nick2 = sys.stdin.readline()
print "Password: ",
pass2 = sys.stdin.readline()
server1 = server1[:-1]
server2 = server2[:-1]
port1 = port1[:-1]
port2 = port2[:-1]
nick1 = nick1[:-1]
nick2 = nick2[:-1]
pass1 = pass1[:-1]
pass2 = pass2[:-1]
print "Source-Server: "+nick1+"@"+server1+":"+port1+"."
cl1=Client(server1,debug=[])
if not cl1.connect(server=(server1,int(port1))):
     raise IOError('Can not connect first server.')
if not cl1.auth(nick1,pass1,'Account Moving Tool'):
     raise IOError('Can not auth with first server.')
cl1.sendInitPresence()
cl1.Roster.getRoster()
tobeadded=[]
buddies = cl1.Roster.getItems()
for b in buddies:
     print "Transfer "+b+"? [Yn]",
     if sys.stdin.readline()[0] not in ["n","N"]:
          tobeadded.append(b)
cl1.disconnect()
cl1=Client(server2,debug=[])
if not cl1.connect(server=(server2,int(port2))):
     raise IOError('Can not connect first server.')
if not cl1.auth(nick2,pass2,'Account Moving Tool'):
     raise IOError('Can not auth with first server.')
cl1.sendInitPresence()
for b in tobeadded:
     print "Adding: "+b
     cl1.Roster.Subscribe(b)
cl1.disconnect()

Gibt es auch zum Download.

Posted Thu Jan 17 23:58:39 2008 Tags: python

Ich beschäftige mich zur Zeit mit dem Rewrite von Fillplayer. Es sollte eine GUI mit GTK/Glade erhalten und die Daten in SQLite speichern. Nun zeigte sich das Problem, dass wenn in einem einfachen Callback die MP3-Sammlung durchsucht wurde, die GUI hing und das Programm abgestürzt schien. Das ist für mich natürlich nicht akzeptabel :) Die Lösung sind Threads, also quasi das Musiksammlung scannen in den Hintergrund zu verlegen. Leider ist das einfacher gesagt als getan. Das »threading« Modul scheint da aktuellste zu sein, also nahm ich das. Die ersten Versuche bestanden darin, das Scannen in eine seperate Funktion zu verlegen und als Thread zu starten:

from threading import Thread
t = Thread(target=scanfunction,args=('verzeichnis',))
t.start()

Dies führte dazu, dass die scanfunction immer nach dem beenden der GUI ausgeführt wurde, also nicht das war was ich wollte. ein zusätzliches t.join() führte die Funktion zwar zum richtigen Zeitpunkt aus, blockierte aber erwartungsgemäß wieder die GUI.

Durch Googlen und Stöbern in der PyGtk-Dokumentation bin ich dann auf die Funktionen gtk.gdk.threadsinit(), gtk.threadsenter() und gtk.threads_leave() gestoßen. Da ich nicht gleich das richtige Stück Dokumentation erwischte und die Dokumentation richtig interpretierte, ging ich fälschlicherweise davon aus, dass es sich hierbei um einen ganz anderen Ansatz handelte. Doch verschiedenste Experimente mit diesen drei Funktionen brachten keine Ergebnisse.

Nach weiterem Googeln, entdeckte ich dann in einem Code-Beispiel, wie das alles richtig zusammengehört:

gtk.gdk.threads_init() # Gtk threadingfähig machen
gtk.main()  # Mainloop starten
Thread(target=scanfunktion,args=('verzeichnis',)).start() # Thread starten
def scanfunction(verzeichnis):
    while busy:
        # mache irgendwas ganz aufwändiges
        gtk.threads_enter() # Beginne Bereich, in dem Code ausgeführt wird, auf den nur ein Thread zugreifen darf (zB GUI)
        xml.get_widget('progressbar').pulse()
        gtk.threads_leave() # Ende des Bereichs

Das sind nur die für Threads relevanten Bereiche. Den kompletten Code kann man im SVN einsehen.

Posted Mon Feb 20 23:28:41 2006 Tags: python