[Tutor] file exception & behaviour (was: Getting caller name...)

spir denis.spir at free.fr
Sun Feb 14 14:30:51 CET 2010

On Sun, 14 Feb 2010 12:33:09 +0100
patrice laporte <zepangolin at gmail.com> wrote:

> 2010/2/13 Luke Paireepinart <rabidpoobear at gmail.com>
> >
> >
> > On Sat, Feb 13, 2010 at 9:56 AM, patrice laporte <zepangolin at gmail.com>wrote:
> >
> >>
> >> Hi,
> >>
> >> Being in an exeption of my own, I want to print the name of the caller,
> >> and I'm looking for a way to have it.
> >>
> >> Could you tell us exactly why you want to do this?  It seems sort of
> > strange.  Also couldn't you pass the caller as an argument to your function?
> >
> >
> Hi,
> I don't know if it's strange, maybe, so tell me why. Or maybe it's me....
> Maybe the fact I'm à pure C coder for a longtime prevent me from thinking in
> Python, maybe my brain is only capable of thinking and viewing in C..... and
> maybe there's an obvious way to solve my problem that I can't see yet... or
> maybe it's because I'm French, genetically programed to live in the past ?
> ... so this mailing list is my starting point to improve my Python
> understanding.
> And now, something different : what I want to do, and why.
> I got a class that takes a file name in its  __init__ method (it could be
> elsewhere, but why not here ?). Then, somewhere in that class, a method will
> do something with that file  name, such as "try to open that file".
> If the file do esn't exist, bing ! I got an exception "I/O Error n°2 : file
> doesn't exist".
> That's nice, I of course catch this exception, but it's not enough for the
> user : What file are we talking about ?  And how to tell the user  what is
> that file, and make him understand  he tell the app to use a file that
> doesn't exist ?
> And this is not enough for developer : where that error happened ? what
> class ? what method ?
> There is many solution, and mine is :
> - don't check for the existence of the file in __init__
> - don't use a default value for the file name parameter in __init__ : coder
> MUST provide it.
> - try/catch open(this_file_name) and if I got an IOErro exception, I
> re-raise my own exception with :
>    - the name of the class where that IOError occured
>    - the name of the method in that class that make that error occured
>    - the name of the file the method tried to opened
>    - some other info to help diagnostic
> Then my exception object can :
>    - log in a file dedicated to the team (so, just me for the moment)
>    - and/or log in a file dedicated to the user
> And then the app can popup a message box or something like that.
> Currently, I'm thinking about "how to get that class/method name", easily,
> and make something usefull with that.
> I don't want to write the name of the method and the class each time I need
> to use my exception class, and I don't want to modify that name each time
> I'm doing a refactoring operation : I just want to do something like :
>    except IOError, (errno, errmes):
>             raise myexceptioniwanttobenice ("IO Error %d -> %s ('%s')" %
> (errno, errmes, self.__csv) )
> And then I print somewhere a message like :
>           Error in csv2db.getColumnFromCsv : IO Error 2 -> No such file or
> directory ('toto')
> What I don't want is to write something like :
> except IOError, (errno, errmes):
>             raise myexceptioniwanttobenice ("cvs2db.getColumnFromCsv IO
> Error %d -> %s ('%s')" % (errno, errmes, self.__csv) )
> I don't want because it's to much to write, and if I change the class name,
> I don't want to rewrite all my call to change that name.
> So, I was looking for a way to retrieve :
> The name of the class the object that throw the exception belongs to
> The name of the method in that class
> And I finally found those recipe with the sys._getframe call.
> My first solution, currently, is (I didn't yet rewrite it with the solution
> with the traceback module) :
> class argError(Exception):
>     def __init__(self, callerClass, errorMessage):
>         self.__class   = callerClass.__class__.__name__
>         self.__method  = sys._getframe(1).f_code.co_name
>         self.__message = errorMessage
>     def __str__(self):
>         return "Error in %s.%s : %s" % (self.__class, self.__method,
> self.__message)
> And how I use it :
>        try:
>             f = open(self.__csv)
>         except IOError, (errno, errmes):
>             raise argError (self, "IO Error %d -> %s ('%s')" % (errno,
> errmes, self.__csv) )
> I now will :
> - rewrite it with the solution with traceback module
> - read about that module and find how to get rid of the need to pass "self"
> as an argument in the call "raise argError (*self*, "IO Error %d -> %s
> ('%s')" % (errno, errmes, self.__csv) )". That call enable me to get the
> name of the class.
> All of that is a way to me to experiment Python, I try a lot of thing to
> understand, and then I will make a choice.
> But now, it's time to lunch. Did I gave you enough information about what I
> want ?
> Patrice

First, here is a kind of implementation of your specification. I just wrote it because I had something similar in mind (a file proxy, not the special exception type) and a few time. But this is globally useless. See below more comments.

==========  code  ===============
#!/usr/bin/env python
# coding: utf-8

class FileError(Exception):
	NO_CALLER = "<unknown caller>"
	def __init__(self, name, info, caller=None):
		if caller is None:
			caller = FileError.NO_CALLER
		self.name, self.caller, self.info = name, caller, info
	def __str__(self):
		text = "File error in %s.\nTried to open non-existent file '%s'\n%s" \
				% (self.caller,self.name,self.info)
		logFile = open("error.log", 'w')
		return text

class File(object):
	NAME_MESSAGE = "A File must have a name."
	FILE_MESSAGE = "File '%s' is closed."
	def __init__(self, name=None):
		''' Init name. '''
		if name is None:
			raise ValueError(File.NAME_MESSAGE)
		self.name = name
		self.file = None
	def __str__(self):
		''' File output '''
		return "File '%s'" %self.name
	def open(self, mode = 'r', caller=None):
		''' (Try to) open actual file. '''
			self.file = open(self.name, mode)
		except IOError, e:
			raise FileError(self.name, str(e), caller)
		print "%s is open in mode '%s'." %(self,mode)
	def close(self):
		''' Close actual file. '''
		if self.file is None:
			message = File.FILE_MESSAGE %self.name
			raise ValueError(message)
		print "%s is closed." %self
	def __getattr__(self, key):
		''' Delegate file method to actual file. '''
		print "* method: %s" %key
		return getattr(self.file, key)
	def content(self):
		''' Close actual file. '''
		content = self.read()
		return content
	def writeContent(self, content):
		''' Close actual file. '''

def test():
	f = File("test.txt")
	print f
	for line in f.readlines(): print line.rstrip()
	print f.content()
	f.writeContent("foo bar baz")
	f = File("goo.txt")
	f.open('r', test)
========== output ===============
File 'test.txt'
File 'test.txt' is open in mode 'r'.
* method: readlines
File 'test.txt' is closed.
File 'test.txt' is open in mode 'r'.
* method: read
File 'test.txt' is closed.

File 'test.txt' is open in mode 'w'.
* method: write
File 'test.txt' is closed.
Traceback (most recent call last):
  File "__essai__.py", line 73, in <module>
  File "__essai__.py", line 72, in test
    f.open('r', test)
  File "__essai__.py", line 38, in open
    raise FileError(self.name, str(e), caller)
__main__.FileError: File error in <function test at 0xb76e0d4c>.
Tried to open non-existent file 'goo.txt'
[Errno 2] No such file or directory: 'goo.txt'

I think you do not need any special treatment of files to get all the info you need when errors occur. The file name and caller already appear in python error texts. In other words: FileError is useless:

def test2():
	f = file("goo.txt", 'r')
Traceback (most recent call last):
  File "__essai__.py", line 77, in <module>
  File "__essai__.py", line 76, in test2	**************
    f = file("goo.txt", 'r')
IOError: [Errno 2] No such file or directory: 'goo.txt'

But a file wrapper (or rather: a proxy) can be useful, i guess, to get a kind of "potential" File object type that behaves a bit differently, as illustrated above by transparent opening and closing in content() and writeContent() methods. (That's what I wanted to try, and I rather like it.)


PS: Les programmeurs français ne sont pas supposés avoir un capital de gènes différent, former une race à part; mais il me semble bien pourtant que toi & moi sommes des programmeurs python pas comme les autres.

la vita e estrany


More information about the Tutor mailing list