Minor bug in tempfile module (possibly __doc__ error)

  • Thread starter James T. Dennis
  • Start date
J

James T. Dennis

Tonight I discovered something odd in the __doc__ for tempfile
as shipped with Python 2.4.4 and 2.5: it says:

This module also provides some data items to the user:

TMP_MAX - maximum number of names that will be tried before
giving up.
template - the default prefix for all temporary names.
You may change this to control the default prefix.

... which would lead one to think that the following code would work:

>>> import tempfile
>>> tempfile.template = 'mytest'
>>> tf = tempfile.NamedTemporaryFile() '/tmp/mytest-XXXXXX'

It doesn't.

In fact I realized, after reading through tempfile.py in /usr/lib/...
that the following also doesn't "work" like I'd expect:

# foo.py
tst = "foo"
def getTst(arg):
return "foo-%s" % arg


# bar.py
import foo
foo.tst = "bar"
print foo.getTst("testing")

foo-testing <<<----- NOT "bar-testing"

Now I would feel like a real idiot if I'd come across that in the
foo/bar case here ... because I clearly don't understand quite *why*
I can't "monkey patch" this value. I would ... but I don't.

First, I wouldn't have written code like this foo/bar stuff; except
to test my hypothesis about why changes to tempfile.template don't
actually affect the values seen by functions in the tempfile namespace.

Secondly, the author(s) of the tempfile module apparently didn't
understand this either. And no one else even noticed that the __doc__
is wrong (or at least misleading -- since the only way I can see to
change tempfile.template is to edit the .py file!

So, I don't feel like an idiot. But I am curious ...

... why can't I change that value in that other namespace? Is it
a closure? (Or like a closure?) Where is this particular aspect
of the import/namespace semantics documented?
 
M

Marc 'BlackJack' Rintsch

Tonight I discovered something odd in the __doc__ for tempfile
as shipped with Python 2.4.4 and 2.5: it says:

This module also provides some data items to the user:

TMP_MAX - maximum number of names that will be tried before
giving up.
template - the default prefix for all temporary names.
You may change this to control the default prefix.

... which would lead one to think that the following code would work:

>>> import tempfile
>>> tempfile.template = 'mytest'
>>> tf = tempfile.NamedTemporaryFile()
'/tmp/mytest-XXXXXX'

It doesn't.

The source says:

__all__ = [
"NamedTemporaryFile", "TemporaryFile", # high level safe interfaces
"mkstemp", "mkdtemp", # low level safe interfaces
"mktemp", # deprecated unsafe interface
"TMP_MAX", "gettempprefix", # constants
"tempdir", "gettempdir"
]

Maybe the doc should be clearer in saying "constants" too.
Secondly, the author(s) of the tempfile module apparently didn't
understand this either. And no one else even noticed that the __doc__
is wrong (or at least misleading -- since the only way I can see to
change tempfile.template is to edit the .py file!

You can change it by simply assigning to the name:

In [15]: tempfile.template = 'spam'

In [16]: tempfile.template
Out[16]: 'spam'

If you want to change the outcome of the functions and objects then simply
give the prefix as argument.

In [21]: tempfile.mktemp(prefix='eggs')
Out[21]: '/tmp/eggsBqiqZD'

In [22]: a = tempfile.NamedTemporaryFile(prefix='eric')

In [23]: a.name
Out[23]: '/tmp/ericHcns14'
... why can't I change that value in that other namespace? Is it
a closure? (Or like a closure?) Where is this particular aspect
of the import/namespace semantics documented?

You *can* change it, but it is not used by the code in that module.

Ciao,
Marc 'BlackJack' Rintsch
 
D

Dennis Lee Bieber

In fact I realized, after reading through tempfile.py in /usr/lib/...
that the following also doesn't "work" like I'd expect:
No idea of the tempfile problem, but...
# foo.py
tst = "foo"
def getTst(arg):
return "foo-%s" % arg

This return is using a literal "foo-". Change it to

return "%s-%s" % (tst, arg)

and try again.
# bar.py
import foo
foo.tst = "bar"
print foo.getTst("testing")

foo-testing <<<----- NOT "bar-testing"
Just what I would expect when returning a string literal, and not a
variable reference.

--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
J

James T. Dennis

Dennis Lee Bieber said:
No idea of the tempfile problem, but...
This return is using a literal "foo-". Change it to
return "%s-%s" % (tst, arg)

Sorry that was a retyping bug in my posting ... not in
my sample code which was on another system.
and try again.

Try it yourself. As I said ... the value of tst in your
name space will be changed, but the value returned by functions
in the imported module will still use the old value!
 
J

James T. Dennis

The source says:
__all__ = [
"NamedTemporaryFile", "TemporaryFile", # high level safe interfaces
"mkstemp", "mkdtemp", # low level safe interfaces
"mktemp", # deprecated unsafe interface
"TMP_MAX", "gettempprefix", # constants
"tempdir", "gettempdir"
]
Maybe the doc should be clearer in saying "constants" too.
You can change it by simply assigning to the name:
In [15]: tempfile.template = 'spam'
In [16]: tempfile.template
Out[16]: 'spam'

I know you can change it. But changing it in your namespace
doesn't change the results returned by the functions called
from the module.
If you want to change the outcome of the functions and objects then simply
give the prefix as argument.

I know how to provide the prefix arguments and that was
never the issue.

The issue was twofold:

The docs are wrong (or at least confusing/misleading)

I don't quite understand how this name/variable in
my namespace (__main__) is able to change the value
while the functions in the module still hold the old
value.
 
M

Marc 'BlackJack' Rintsch

Marc 'BlackJack' Rintsch said:
In <1178693438.689184@smirk>, James T. Dennis wrote:
You can change it by simply assigning to the name:
In [15]: tempfile.template = 'spam'
In [16]: tempfile.template
Out[16]: 'spam'

I know you can change it. But changing it in your namespace
doesn't change the results returned by the functions called
from the module.

I'm not changing it in my namespace but in the namespace of the `tempfile`
module.
I don't quite understand how this name/variable in
my namespace (__main__) is able to change the value
while the functions in the module still hold the old
value.

Default arguments are evaluated *once* when the ``def`` is executed and
not at every function call.

Ciao,
Marc 'BlackJack' Rintsch
 
M

Marc Christiansen

James T. Dennis said:
In fact I realized, after reading through tempfile.py in /usr/lib/...
that the following also doesn't "work" like I'd expect:

# foo.py
tst = "foo"
def getTst(arg): If I change this line:
return "foo-%s" % arg
to:
return "%s-%s" % (tst, arg)
# bar.py
import foo
foo.tst = "bar"
print foo.getTst("testing")

foo-testing <<<----- NOT "bar-testing"
Then "python bar.py" prints "bar-testing".

0:tolot@jupiter:/tmp> cat foo.py
tst = "foo"
def getTst(arg):
return "%s-%s" % (tst,arg)
0:tolot@jupiter:/tmp> cat bar.py
import foo
foo.tst = "bar"
print foo.getTst("testing")
0:tolot@jupiter:/tmp> python bar.py
bar-testing

And regarding the tempfile.template problem, this looks like a bug.
Because all functions in tempfile taking a prefix argument use "def
function(... , prefix=template, ...)", only the value of template at
import time matters.

AdiaÅ­, Marc
 
J

James T. Dennis

Marc Christiansen said:
to:
return "%s-%s" % (tst, arg)
Then "python bar.py" prints "bar-testing".
0:tolot@jupiter:/tmp> cat foo.py
tst = "foo"
def getTst(arg):
return "%s-%s" % (tst,arg)
0:tolot@jupiter:/tmp> cat bar.py
import foo
foo.tst = "bar"
print foo.getTst("testing")
0:tolot@jupiter:/tmp> python bar.py
bar-testing
And regarding the tempfile.template problem, this looks like a bug.
Because all functions in tempfile taking a prefix argument use "def
function(... , prefix=template, ...)", only the value of template at
import time matters.
Adia?, Marc

I suppose my real sample code was def getTst(arg=tst):

Oddly I've never come across that (the fact that defaulted arguments are
evaluated during function definition) in my own coding and I guess there
are two reasons for that: I try to avoid global variables and I usually
use defaulted variables of the form:

def (foo=None):
if foo is None:
foo = self.default_foo
 
D

Dennis Lee Bieber

Sorry that was a retyping bug in my posting ... not in
my sample code which was on another system.


Try it yourself. As I said ... the value of tst in your
name space will be changed, but the value returned by functions
in the imported module will still use the old value!

Works for me...

# foo.py

tst = "foo"

def getTst(arg):
return "%s-%s" % (tst, arg)
-=-=-=-=-
# bar.py

import foo

print foo.getTst("Before assignment")

foo.tst = "bar"

print foo.getTst("After assignment")
-=-=-=-=-
pythonw -u "bar.py"
foo-Before assignment
bar-After assignment
Exit code: 0
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,021
Latest member
AkilahJaim

Latest Threads

Top