Re: [Tutor] classes and the deepcopy function

2008-01-06 Thread Michael
Okay

Just when I think I am getting it you throw this in. So why does a 
become local to each variable but b seem global?

Michael

bob gailer wrote:
> Michael wrote:
>> Hi Michael
>>
>> Thanks for the quick reply, I think I get it. So becuase I did not 
>> declare them withing the init method using self they are shared by 
>> every object that is created, even completely brand new ones?
>>
>> Is it normal practice to declare your variables in a class? I notice 
>> that you don't have to, you can create them as you go, but i thought 
>> declaring and initialising them in the class would make it easier to 
>> understand and see what the class is for and should contain.
> And now for the rest of the story:
>
> class Foo:
>  a = 0
>  b = []
>
> f = Foo()
> f.a = 3
> f.b.append(1)
>
> g = Foo()
> g.a = 4
> g.b.append(2)
>
> print f.a, g.a # 3 4
> print f.b, g.b # [1, 2] [1, 2]
>
> [snip]
>

___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Program review

2008-01-06 Thread Ricardo Aráoz
Jeff Younker wrote:
> The procesar function is complicated.   It tries to do several things
> that that are better done elsewhere.  It needs to be broken up into
> several functions and methods.   This also clarifies and isolates the
> exception handling.
> 
>> def procesar(mensaje):
>>try :
> The enclosing try block isn't needed.  More on this later.
>>
>>try :
>>fIncl = open(mensaje.direcciones)
>>except Exception, e :
>>logging.error('Error!!! No pude abrir "%s" : %s',
>>mensaje.direcciones,
>>e.strerror)
>>raise
> 
> This is one function.  It has the argument filename.
>>
>>try :
>>fExcl = open(mensaje.excluidas)
>>except Exception, e :
>>logging.error('No pude abrir "%s" : %s',
>>mensaje.excluidas,
>>e.strerror)
>>fIncl.close()
>>raise
> 
> This is the same function with a different argument.
> 
>>
>>except : pass
>>else :
> 
> The outer exception block here does nothing.   If an exception
> is raised then the following code won't be executed anyway.
> 
>>mails = enumerate(
>>set(addr.strip() for addr in fIncl)
>>- set(excl.strip() for excl in fExcl))
>>fIncl.close()
>>fExcl.close()
> 

Maybe it is my poor understanding of exception handling. My intention
here is to open the first file, if error then report in logging and
finish normally, else open the 2nd file, if error then report in logging
close the 1st file and finish normally. If no error then process.

___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] classes and the deepcopy function

2008-01-06 Thread bob gailer
Michael wrote:
> Okay
>
> Just when I think I am getting it you throw this in. 
You're welcome.
> So why does a become local to each variable but b seem global?
>   
A better way to ask that is "why does a become an instance property but 
b remain a class property?"

f.a = 3

This is an assignment statement. It creates a property of the instance. The 
class property a is ignored.

f.b.append(1)

This is not an assignment. It references a property of the instance that does 
not exist, so Python goes up the inheritance hierarchy and finds the class 
property.

HTH


___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Program review

2008-01-06 Thread Kent Johnson
Ricardo Aráoz wrote:
> Jeff Younker wrote:

>> The enclosing try block isn't needed.  More on this later.

> Maybe it is my poor understanding of exception handling. My intention
> here is to open the first file, if error then report in logging and
> finish normally, else open the 2nd file, if error then report in logging
> close the 1st file and finish normally. If no error then process.

The code is correct for what you want to do. It does seem a bit awkward 
but it's hard to get much better and preserve the logging.

You could use 'return' instead of 'raise' and eliminate the outer try block.

You could put the duplicate code in a function (with raise):
def my_open(f):
 try :
 fIncl = open(f)
 except Exception, e :
 logging.error('Error!!! No pude abrir "%s" : %s',
 f,
 e.strerror)
 raise

but you would still need try/except in the calling function:

try :
 fIncl = my_open(mensaje.direcciones)
except:
 return
try :
 fExcl = my_open(mensaje.excluidas)
except:
 fIncl.close()
 return

It is safe to omit the close() in this situation - the file will be 
closed by the OS when the program terminates - so you could use a single 
try block:
try :
 fIncl = my_open(mensaje.direcciones)
 fExcl = my_open(mensaje.excluidas)
except:
 return

That is the only version I can come up with that seems significantly 
simpler than what you wrote.

Kent
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Program review

2008-01-06 Thread Ricardo Aráoz
Kent Johnson wrote:
> Ricardo Aráoz wrote:
>> Jeff Younker wrote:
> 
>>> The enclosing try block isn't needed.  More on this later.
> 
>> Maybe it is my poor understanding of exception handling. My intention
>> here is to open the first file, if error then report in logging and
>> finish normally, else open the 2nd file, if error then report in logging
>> close the 1st file and finish normally. If no error then process.
> 
> The code is correct for what you want to do. It does seem a bit awkward 
> but it's hard to get much better and preserve the logging.
> 

Yes, I guessed so.

> You could use 'return' instead of 'raise' and eliminate the outer try block.
> 
> You could put the duplicate code in a function (with raise):
> def my_open(f):
>  try :
>  fIncl = open(f)
>  except Exception, e :
>  logging.error('Error!!! No pude abrir "%s" : %s',
>  f,
>  e.strerror)
>  raise
> 
> but you would still need try/except in the calling function:
> 
> try :
>  fIncl = my_open(mensaje.direcciones)
> except:
>  return
> try :
>  fExcl = my_open(mensaje.excluidas)
> except:
>  fIncl.close()
>  return
> 

AND the code would have an added depth that gives me no real benefit,
which is why I chose to do it that way. So long as meaning is not
obscured by complicated or lengthy code I'd rather keep it shallow.


> It is safe to omit the close() in this situation - the file will be 
> closed by the OS when the program terminates - so you could use a single 
> try block:
> try :
>  fIncl = my_open(mensaje.direcciones)
>  fExcl = my_open(mensaje.excluidas)
> except:
>  return

True, I usually prefer to explicitly close the file anyway.
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Program review

2008-01-06 Thread Ricardo Aráoz
Ok, new version.
In procesar() I tried getting rid of the outer try block and having
'return' instead of 'raise' in the inner try blocks but I didn't like
the result. I'd rather have one more indent level but have only one exit
point from the function.
Redesigned class Mensaje so that it now includes a MIME message, I think
it simplifies the code and less attributes are going around, now
Correo.__init__() is simpler.
I was tempted to put 'messg = self.mensage.messg' as the first line of
Correo.enviar() so as to shorten things like
self.mensaje.messg.replace_header('To', addr) to
messg.replace_header('To', addr) but I didn't like it, I'd rather stress
the fact that 'messg' belongs to Correo's attribute 'mensaje'.

Here's the code (untested):

#!/usr/bin/env python

import time
import smtplib
import email
import ConfigParser
import logging

class Mensaje(object) :
def __init__(self) :
cfg = ConfigParser.ConfigParser()
try :
cfg.readfp(open('config.cfg'))
except Exception, e :
logging.error('No pude leer "config.cfg" : %s', e.strerror)

self.direcciones = cfg.get('Archivos', 'Direcciones')
self.excluidas = cfg.get('Archivos', 'Excluir')
self.cuantos = cfg.getint('Correo', 'MailsPorVez')
self.intervalo = cfg.getint('Correo', 'IntervaloEnSegundos')

try :
htmlFile = open(cfg.get('Archivos', 'Mensaje'))
self.html = htmlFile.read()
htmlFile.close()
except Exception, e :
logging.error('No pude leer "%s" : %s',
cfg.get('Archivos', 'Mensaje'),
e.strerror)

self.messg = email.MIMEMultipart.MIMEMultipart()
self.messg['From'] = cfg.get('Encabezados', 'De')
self.messg['To'] = ''
self.messg['Subject'] = cfg.get('Encabezados', 'Encabezado')
self.messg['Reply-To'] = cfg.get('Encabezados', 'ResponderA')
self.messg.preamble = 'This is a multi-part message in MIME format'
self.messg.attach(email.MIMEText.MIMEText(mensaje.html, 'html'))

self.Servidor = cfg.get('Correo', 'Servidor')
self.Usuario = cfg.get('Correo', 'Usuario')
self.Contra = cfg.get('Correo', 'Contrasenia')

class Correo(object) :
def __init__(self, mensaje) :
self.mensaje = mensaje
self.conexion = smtplib.SMTP()

def connect(self) :
try :
self.Conexion.connect(self.mensaje.servidor)
self.Conexion.set_debuglevel(False)
self.Conexion.ehlo()
self.Conexion.starttls()
self.Conexion.ehlo()
self.Conexion.login(self.mensaje.usuario, self.mensaje.contra)
return True
except :
logging.error('No me pude conectar al Servidor')
return False

def disconnect(self) :
self.Conexion.close()

def enviar(self, addr) :
self.mensaje.messg.replace_header('To', addr)
try :
self.Conexion.sendmail(self.mensaje.messg['From'],
self.mensaje.messg['To'],
self.mensaje.messg.as_string())
logging.info('Enviado a : %s', self.mensaje.messg['To'])
except SMTPRecipientsRefused :
logging.error('El destinatario fue rechazado por el servidor')
except SMTPHeloError :
logging.error('El servidor no respondio apropiadamente')
except SMTPSenderRefused :
logging.error('El From: fue rechazado por el servidor')
except SMTPDataError :
logging.error('El servidor respondio con un error desconocido')

def procesar(mensaje):
try :
try :
fIncl = open(mensaje.direcciones)
except Exception, e :
logging.error('Error!!! No pude abrir "%s" : %s',
mensaje.direcciones,
e.strerror)
raise
try :
fExcl = open(mensaje.excluidas)
except Exception, e :
logging.error('No pude abrir "%s" : %s',
mensaje.excluidas,
e.strerror)
fIncl.close()
raise
except : pass
else :
mails = enumerate(
set(addr.strip() for addr in fIncl)
- set(excl.strip() for excl in fExcl))
fIncl.close()
fExcl.close()
miCorreo = Correo(mensaje)
miCorreo.connect()
empiezo = time.clock()
for nro, addr in mails :
if nro%mensaje.cuantos == 0 and nro > 0 :
miCorreo.disconnect()
time.sleep(mensaje.intervalo - (time.clock() - empiezo))
if not miCorreo.connect() :
logging.info('Terminando')
return
empiezo = time.clock()
miCorreo.enviar(addr)
miCorreo.disconnect()


if __nam

Re: [Tutor] Program review

2008-01-06 Thread Ricardo Aráoz
Jeff Johnson wrote:
> I would like to "butt" in here and mention that this is some of the most 
> useful information I have seen!  I am a programmer of 25 years that is 
> new to Python.  This type of back and forth dialog on actual production 
> code is extremely useful to learning the language.  I have done this 
> with Ed Leafe with Dabo and it has helped a lot.
> 
> Keep it up!
> 
> Jeff
> 

Guys, I really learned with this exercise (and my code was improved). I
got to think how good it would be to have one or two ongoing small
projects where we contribute code and the code is criticized and
enhanced by our community. We could agree on a subject, someone could
volunteer to give it a try (if the subject is big enough then many could
volunteer with different parts of the whole) then post the code so that
it can be viewed and reviewed by the rest. We could learn a lot and we
might end up with some useful pieces of code.
What do you think?

Ricardo
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


[Tutor] locating python scripts

2008-01-06 Thread max baseman
hey i just have a small question, doesn't have much to do with  
programing but it has to do with python.
anyways Im running a apple computer  version 10.4 and have been  
keeping my scripts in the user folder i was wondering where and how i  
can change the files that python looks in when looking for programs i  
would like to make it so that i can have separate folders in the user  
folder for different projects
any help would be great
thanks 
   
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Program review

2008-01-06 Thread Ricardo Aráoz
Ok, now the "tested" version (has been corrected) :

#!/usr/bin/env python

import time
import smtplib
import email
import ConfigParser
import logging

class Mensaje(object) :
def __init__(self) :
cfg = ConfigParser.ConfigParser()
try :
cfg.readfp(open('config.cfg'))
except Exception, e :
logging.error('No pude leer "config.cfg" : %s', e.strerror)

self.direcciones = cfg.get('Archivos', 'Direcciones')
self.excluidas = cfg.get('Archivos', 'Excluir')
self.cuantos = cfg.getint('Correo', 'MailsPorVez')
self.intervalo = cfg.getint('Correo', 'IntervaloEnSegundos')

try :
htmlFile = open(cfg.get('Archivos', 'Mensaje'))
htmlMessage = htmlFile.read()
htmlFile.close()
except Exception, e :
logging.error('No pude leer "%s" : %s',
cfg.get('Archivos', 'Mensaje'),
e.strerror)

self.messg = email.MIMEMultipart.MIMEMultipart()
self.messg['From'] = cfg.get('Encabezados', 'De')
self.messg['To'] = ''
self.messg['Subject'] = cfg.get('Encabezados', 'Encabezado')
self.messg['Reply-To'] = cfg.get('Encabezados', 'ResponderA')
self.messg.preamble = 'This is a multi-part message in MIME format'
self.messg.attach(email.MIMEText.MIMEText(htmlMessage, 'html'))

self.servidor = cfg.get('Correo', 'Servidor')
self.usuario = cfg.get('Correo', 'Usuario')
self.contra = cfg.get('Correo', 'Contrasenia')

class Correo(object) :
def __init__(self, mensaje) :
self.mensaje = mensaje
self.conexion = smtplib.SMTP()

def connect(self) :
try :
self.conexion.connect(self.mensaje.servidor)
self.conexion.set_debuglevel(False)
self.conexion.ehlo()
self.conexion.starttls()
self.conexion.ehlo()
self.conexion.login(self.mensaje.usuario, self.mensaje.contra)
return True
except :
logging.error('No me pude conectar al Servidor')
return False

def disconnect(self) :
self.conexion.close()

def enviar(self, addr) :
self.mensaje.messg.replace_header('To', addr)
try :
self.conexion.sendmail(self.mensaje.messg['From'],
self.mensaje.messg['To'],
self.mensaje.messg.as_string())
logging.info('Enviado a : %s', self.mensaje.messg['To'])
except smtplib.SMTPRecipientsRefused :
logging.error('El destinatario fue rechazado por el servidor')
except smtplib.SMTPHeloError :
logging.error('El servidor no respondio apropiadamente')
except smtplib.SMTPSenderRefused :
logging.error('El From: fue rechazado por el servidor')
except smtplib.SMTPDataError :
logging.error('El servidor respondio con un error desconocido')

def procesar(mensaje):
try :
try :
fIncl = open(mensaje.direcciones)
except Exception, e :
logging.error('Error!!! No pude abrir "%s" : %s',
mensaje.direcciones,
e.strerror)
raise
try :
fExcl = open(mensaje.excluidas)
except Exception, e :
logging.error('No pude abrir "%s" : %s',
mensaje.excluidas,
e.strerror)
fIncl.close()
raise
except : pass
else :
mails = enumerate(
set(addr.strip() for addr in fIncl)
- set(excl.strip() for excl in fExcl))
fIncl.close()
fExcl.close()
miCorreo = Correo(mensaje)
if miCorreo.connect() :
empiezo = time.clock()
for nro, addr in mails :
if nro%mensaje.cuantos == 0 and nro > 0 :
miCorreo.disconnect()
time.sleep(mensaje.intervalo - (time.clock() - empiezo))
if not miCorreo.connect() :
logging.info('Terminando')
return
empiezo = time.clock()
miCorreo.enviar(addr)
miCorreo.disconnect()


if __name__ == '__main__' :
logging.basicConfig(level=logging.INFO,
format='%(asctime)s %(levelname)-8s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S',

filename=time.strftime('informe-%Y-%m-%d-%H-%M-%S.log'),
filemode='w')
procesar(Mensaje())
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] locating python scripts

2008-01-06 Thread Brendan Rankin
max baseman  gmail.com> writes:

> 
> hey i just have a small question, doesn't have much to do with  
> programing but it has to do with python.
> anyways Im running a apple computer  version 10.4 and have been  
> keeping my scripts in the user folder i was wondering where and how i  
> can change the files that python looks in when looking for programs i  
> would like to make it so that i can have separate folders in the user  
> folder for different projects
> any help would be great
> thanks 
> 
> ___
> Tutor maillist  -  Tutor  python.org
> http://mail.python.org/mailman/listinfo/tutor
> 
> 

I've always just added paths to the PYTHONPATH environment variable.  It's value
is now:

/home/brendan/scripts/Python:/home/brendan/lib/python:.

This is on Linux, but I don't see why it shouldn't work identically on OSX.

Cheers,

- Brendan


___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Program review

2008-01-06 Thread Jeff Younker
>
> Maybe it is my poor understanding of exception handling. My intention
> here is to open the first file, if error then report in logging and
> finish normally, else open the 2nd file, if error then report in  
> logging
> close the 1st file and finish normally. If no error then process.
>

Right, but it helps to break up the error handling and the cleanup.
Right now the error reporting exception handlers are intermixed
with your cleanup error handlers.  Separating them makes the code
clearer.

def open_file(filename):
  try :
  return open(filename)
  except Exception:
  logging.error('No pude abrir "%s"' % filename, exec_info=True)
  raise

# Goes into configuration class
def mails(self):
   fIncl = open_file(self.direcciones)
   try:
  fExcl = open_file(self.excluidas)
  try:
  return enumerate(
  set(addr.strip() for addr in fIncl)
  - set(excl.strip() for excl in fExcl))
  finally:
   fExcl.close()
   finally:
fIncl.close()

Or if you're using python 2.5 then you can use with statements:

from __future__ import with_statements
from contextlib import closing
...
def mails(self):
 with closing(open_file(self.direcciones)) as fIncl:
with closing(open_file(self.excluidas)) as fExcl:
return enumerate(
set(addr.strip() for addr in fIncl)
- set(excl.strip() for excl in fExcl))

> close the 1st file and finish normally. If no error then process.

If an exception is raised then the code terminates right there and
then.   So, if procesar is written as:

def procesar(mensaje):
  mails = mensaje.mails()
  miCorreo = Correo(mensaje)
  

then if mensaje.mails() raises an exception then the code
terminates immediately, and the body of Correo will only be
executed if there is no error.

As you have it written it terminates, but it also silently consumes the
exception.  If something goes wrong with your program then there is
no way of diagnosing the problem because the failure cause is never
reported.

-jeff
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor