Transparent class Attribute mapping to DB in Python

I’ve spend some time to create a construct in python which allows me to transparently map an CouchDB (or any other document based database) document to a Class. For example a User class or later called Model should give access trough class attributes to the fields of the document. For that i had to manipulate getattr whit the help of a decorator. I had to deal with several issues till i got the perfect construct. StackOverflow helped me to find the way in this and this post.

This is a good example to understand how decorators in Python do work. The code here does simply demonstrate how the decorator works.

# should later connect to a read remote datasource
class Connector(object):
 data = {"emailAddress":"jackbauer@ctu.org", "lastName":"Bauer"}
 def readvar(self, var):
  return self.data[var]
 
# This is the Decorator
class DocumentDB(object):
 def __init__(self,connector):
  self.connector = connector
 def __call__(self, *args, **kargs):
  _c = self.connector # _c needs to be set to make the connector accessible for Transparent Attribute
  class TransparentAttribute(args[0]):
   def __getattr__(self, attrname):
    try:
     return _c.readvar(attrname)
    except:
     # If the field does not exist at the datasource, return the attribute from the object
     return getattr(args[0], attrname)
  return TransparentAttribute
 
c = Connector()
@DocumentDB(c)
class User(object):
 username = "JackBauer"
 def doSomething(self):
  print "I'am Jack bauer"
 def doSomethingElse(self):
  pass
 
u = User()
u.doSomething()
print u.emailAddress # Field from the Datasource
print u.lastName       # Field from the Datasource
print u.username

There was another way suggested on Stackoverflow to use Metaclasses. My personal opinion in this case is to use the decorator. Metaclasses does make sense if you work with databases in a classical sense where the fields are all known. Documents my be slightly different from each other. So their form would have to get interpreted on each attribute access or either the attributes are dynamically mapped.

Feelfree to comment this example!

Tagged: , , , , ,

Python and SQLAlchemy 0.8 example

There is this great ORM framework SQLAlchemy for Pyhton. With an ORM you are able to map Objects on Database Tables.

SQLAlchemy is really great, but if you want to use it in an more integrated way, to build for example an MVC based application, its a bit hard, especially if you get in touch with SQLAlchemy for the first time. To make it more easier for other people to build an base architecture i’ve created this example.

(This example is based on this tutorial.)

from sqlalchemy import create_engine, ForeignKey
 
from sqlalchemy import Column, Date, Integer, String
 
from sqlalchemy.ext.declarative import declarative_base
 
from sqlalchemy.orm import relationship, backref
 
from sqlalchemy.orm import sessionmaker
 
import datetime
 
Base = declarative_base()
 
class Singleton(object):
 
    '''
 
    Singelton class
 
    '''
 
    def __init__(self, decorated):
 
        self._decorated = decorated
 
    def instance(self, *args, **kwargs):
 
        try:
 
            return self._instance
 
        except AttributeError:
 
            self._instance = self._decorated(*args, **kwargs)
 
            return self._instance
 
    def __call__(self, *args, **kwargs):
 
        raise TypeError('Singletons must be accessed through the `Instance` method.')
 
@Singleton
 
class Db(object):
 
    '''
 
    The DB Class should only exits once, thats why it has the @Singleton decorator.
 
    To Create an instance you have to use the instance method:
 
        db = Db.instance()
 
    '''
 
    engine = None
 
    session = None
 
    def __init__(self):
 
        self.engine = create_engine('sqlite:////tmp/funnydatabase.db', echo=True)
 
        Session = sessionmaker(bind=self.engine)
 
        self.session = Session()
 
        ## Create all Tables
 
        Base.metadata.create_all(self.engine)
 
    def instance(self, *args, **kwargs): 
 
        '''
 
        Dummy method, cause several IDEs can not handel singeltons in Python
 
        '''
 
        pass
 
class Model():
 
    '''
 
    This is a baseclass with delivers all basic database operations
 
    '''
 
    def save(self):
 
        db = Db.instance()
 
        db.session.add(self)
 
        db.session.commit()
 
    def saveMultiple(self, objects = []):
 
        db = Db.instance()
 
        db.session.add_all(objects)
 
        db.session.commit()
 
    def update(self):
 
        db = Db.instance()
 
        db.session.commit()
 
    def delete(self):
 
        db = Db.instance()
 
        db.session.delete(self)
 
        db.session.commit()
 
    def queryObject(self):
 
        db = Db.instance()
 
        return db.session.query(self.__class__)
 
class Artist(Model,Base):
 
    """"""
 
    __tablename__ = "artists"
 
    id = Column(Integer, primary_key=True)
 
    name = Column(String)  
 
class Album(Model,Base):
 
    """"""
 
    __tablename__ = "albums"
 
    id = Column(Integer, primary_key=True)
 
    title = Column(String)
 
    release_date = Column(Date)
 
    publisher = Column(String)
 
    media_type = Column(String)
 
    artist_id = Column(Integer, ForeignKey("artists.id"))
 
    artist = relationship("Artist", backref=backref("albums", order_by=id))
 
###### HERE STARTS THE PROGRAM ######
 
## Initialize the whole Database.
 
db = Db.instance()
 
## Create an artist
 
new_artist = Artist("Kittie")
 
new_artist.albums = [Album("I've Failed You", 
 
                           datetime.date(1988,12,01),
 
                           "Blubb", "CD")]
 
## add more albums
 
more_albums = [Album("Album 2",
 
                     datetime.date(1990,07,31),
 
                     "Blobb", "CD"),
 
               Album("Album 3", 
 
                     datetime.date(1999,11,16),
 
                     "Blebb", "CD")]
 
new_artist.albums.extend(more_albums)
 
## Adding The new Artist to the DB
 
new_artist.save()
 
## Query for an artist
 
x = Artist()
 
qo = x.queryObject()
 
y = qo.filter(Artist.name=="Kittie").first()
 
## Delete the Artist
 
if y: y.delete()
 
## Add severall Artists
 
x.saveMultiple([
 
    Artist("Stone Sour"),
 
    Artist("Metallica"),
 
    Artist("Porcupine Tree")
 
    ])
Tagged: , , , ,

Encrypt and Decrypt asymmetric in python (RSA)

Accessing OpenSSL functionalities in Python is extremely easy. The following example shows how to encrypt an text with an public key and decrypt it with the private key in only 5 lines of code.

First you need the thirdparty Library M2Crypto installed on your system.

easy_install m2crypto

After that you should be able to use the library in any IDE to write the following short program:

from M2Crypto import RSA, X509
 
import base64
 
certificate = "xxx" # Your Certificate
 
privatekey = "xxx" # Your Privatekey.
 
data = "Python is awesome!"
 
# putting the certificate and the privatekey together
 
pem = "%s%s" % (certificate, privatekey)
 
# Create an X509 Object out of the Certificate
 
x509 = X509.load_cert_string(pem, X509.FORMAT_PEM)
 
# Extract the Public Key from the Certificate
 
publickey =  x509.get_pubkey().get_rsa().as_pem()
 
# Create an RSA Object which represents an Keyring with both publich/private-keys
 
rsa = RSA.load_key_string("%s%s" % (publickey, pem))
 
# encrypt
 
x = base64.b64encode(rsa.public_encrypt(data, 1))
 
# decrypt
 
y = rsa.private_decrypt(base64.b64decode(x), 1)
 
print "%s\n-----------\n%s" % (x,y)

Thats all. Even an non coder should be able to understand those steps.

Tagged: , , , ,

Permutation of a word to create unique brand names

Do you know that? You have a great idea for a new cool product and now you need an name for it and all cool names you can imagine are already taken or at least the .com/.net TLD names are taken.

Why do not use an permutation of your favorite name? As en example you would like to name your Product “Cool”. There are many combinations of the letters: colo oolc looc and so on…

With the following 3 lines of Python code are you able to get a list of all possible combinations:

 
import itertools
 
 
 
word = "cool"
 
for x in set(itertools.permutations(word, len(word))): print "".join(x)

Have fun :)

Tagged: , , , ,

Posfix and SASL Unix Auth

/etc/postfix/main.cf

Configure the Postfix MTA to support SASL

smtpd_sasl_auth_enable = yes
smtpd_sasl_authenticated_header = no
smtpd_sasl_exceptions_networks =
smtpd_sasl_local_domain =
smtpd_sasl_path = smtpd
smtpd_sasl_security_options = noanonymous
smtpd_sasl_tls_security_options = noanonymous
smtpd_sasl_type = cyrus

/etc/postfix/master.cf

Disable the run of the Postfix MTA in a chroot environment

smtp inet n - n - - smtpd

/etc/postfix/sasl/smtpd.conf

Tell Postfix where he finds the saselauthd socket file

pwcheck_method: saslauthd
saslauthd_path: /var/run/saslauthd/mux
mech_list: PLAIN LOGIN

/etc/pam.d/smtp

Configure PAM to support local unix Authentication for the SMTP Deamon

auth required pam_unix.so
account required pam_unix.so
password required pam_unix.so
session required pam_unix.so

Finally be sure saslauthd is running and is pointing to the right directory

/usr/sbin/saslauthd -a pam -c -m /var/run/saslauthd -n 5

Here a Python Script to Test the Auth

#!/usr/bin/python
 
import argparse
import smtplib
 
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Tests SASL')
    parser.add_argument('--username', '-u', dest='username', action='store', help='Username')
    parser.add_argument('--password', '-p', dest='password', action='store', help='Password')
    parser.add_argument('--host', '-H', dest='host', action='store', help='SMTP Hostname')
    parser.add_argument('--port', '-P', dest='port', action='store', help='SMTP Port', default='25')
 
    args = parser.parse_args()
 
    server = smtplib.SMTP(args.host, int(args.port))
    server.set_debuglevel(1)
    server.ehlo()
    server.starttls()
    server.ehlo()
    server.login(args.username, args.password)
    server.quit()
 
    exit(0)
Tagged: , , , , ,