FAQ
Hi all you experts,

This has me beat. Has anyone any ideas about what might be going wrong?

This is code from within a windows service (hence no print statements -
no sys.stdout to print on!).

I am trying to trace through to find where the code is not working. No
stdout so I have to log to a file.

I have the following code fragments.

def log(message):
f = open('d:\logfile.txt','a')
f.write(message + "\n")
f.close()

from DelNotePrinter import DelNotePrinter

note the order of the above - log is defined before the import.
Later in the source I have

log('disPrint is:'+disPrint)
log('count is:'+count)
log(repr(DelNotePrinter))
printer = DelNotePrinter(disPrint,int(count))

The DelNotePrinter.py file cannot us log even though it is declared
as global. The code is...

# coding=utf8
# DelNotePrinter = code to print delivery notes
assorted imports removed for space reasons

class DelNotePrinter(object):
''' Print Delivery Note on A5 in portrait '''
def __init__(self,printer,copies):
''' create printer and painter '''
global font,sm,log
log('DelNotePrinter: starting')
self.printer = QPrinter(QPrinter.HighResolution)
etc

The file the log writes contains..
disPrint is:HP Deskjet 6940 series
count is:1
<class 'DelNotePrinter.DelNotePrinter'>

The > is followed by a newline and end of file! Where is the
DelNotePrinter: starting message?

If I replace the opening of __init__ with
global font,sm,log
f = open('d:\logfile.txt','a')
f.write('DelNotePrinter: starting' + "\n")
f.close()
self.printer = QPrinter(QPrinter.HighResolution)

then the message IS written to the log file.

I have read http://docs.python.org/reference/simple_stmts.html#global
very carefully and I still don't understand.

Regards

Ian

p.s. There are no trackbacks, no events on the event log, and no error
messages I have been able to find. When run as a script (not a service)
DelNotePrinter does produce the expected printout.

Search Discussions

  • Bruno Desthuilliers at Sep 7, 2010 at 10:50 am

    Ian Hobson a ?crit :
    Hi all you experts,

    This has me beat. Has anyone any ideas about what might be going wrong?

    This is code from within a windows service (hence no print statements -
    no sys.stdout to print on!).

    I am trying to trace through to find where the code is not working. No
    stdout so I have to log to a file.
    Then you'd be better using the logging module from the stdlib. And FWIW,
    you should try to make you code testable in a non-service context...
    I have the following code fragments.

    def log(message):
    f = open('d:\logfile.txt','a')
    f.write(message + "\n")
    f.close()

    from DelNotePrinter import DelNotePrinter
    <OT>
    The convention is to use all_lower_names for modules - having modules
    and classes with the same (case-sensitive) name can be very misleading.
    </OT>
    note the order of the above - log is defined before the import.
    And ? Do you think it will affect the imported module in any way ? Like,
    say, magically "inject" your log function in the DelNotePrinter module ?-)

    Later in the source Where ?
    I have

    log('disPrint is:'+disPrint)
    log('count is:'+count)
    Do yourself a favor and learn string formating...
    log(repr(DelNotePrinter))
    printer = DelNotePrinter(disPrint,int(count))
    The DelNotePrinter.py file cannot us log even though it is declared
    as global.
    In Python, "global" means "module-level", and it's only necessary when
    you want to rebind a module-level name from within a function or method.

    The code is...
    # coding=utf8
    # DelNotePrinter = code to print delivery notes
    assorted imports removed for space reasons
    Some of these imports surely explain why you don't just get a NameError
    when trying to call log() - wild guess : you have some "from xxx import
    *" statement that does import another callable named 'log'.
    class DelNotePrinter(object):
    ''' Print Delivery Note on A5 in portrait '''
    def __init__(self,printer,copies):
    ''' create printer and painter '''
    global font,sm,log
    log('DelNotePrinter: starting')
    self.printer = QPrinter(QPrinter.HighResolution)
    If you want to access a name (function, class, whatever) defined in
    another module, you have to explicitely import it.
    The file the log writes contains..
    disPrint is:HP Deskjet 6940 series
    count is:1
    <class 'DelNotePrinter.DelNotePrinter'>

    The > is followed by a newline and end of file! Where is the
    DelNotePrinter: starting message?
    We can't tell - but you can get at least some hint, cf below
    If I replace the opening of __init__ with
    global font,sm,log
    f = open('d:\logfile.txt','a')
    f.write('DelNotePrinter: starting' + "\n")
    f.close()
    self.printer = QPrinter(QPrinter.HighResolution)

    then the message IS written to the log file.
    Obviously, yes. Now please add this to your code:

    class DelNotePrinter(object):
    ''' Print Delivery Note on A5 in portrait '''
    def __init__(self,printer,copies):
    ''' create printer and painter '''
    global font,sm,log
    f = open('d:\logfile.txt','a')
    f.write('DelNotePrinter: starting' + "\n")

    # check what "log" is bound to in the currrent namespace
    f.write(
    "DelNotePrinter : log is '%s' from '%s'" % (
    log, log.__module__
    ))
    f.close()
    self.printer = QPrinter(QPrinter.HighResolution)

    I have read http://docs.python.org/reference/simple_stmts.html#global
    very carefully and I still don't understand.
    The statement definition makes no sense if you don't understand
    namespaces and bindings:

    http://docs.python.org/reference/executionmodel.html#naming-and-binding
  • Ian at Sep 7, 2010 at 2:00 pm
    Hi Bruno,

    Thanks for your quick response. I still do not understand.
    On 07/09/2010 11:50, Bruno Desthuilliers wrote:
    Ian Hobson a ?crit :
    Hi all you experts,

    This has me beat. Has anyone any ideas about what might be going wrong?

    This is code from within a windows service (hence no print statements
    - no sys.stdout to print on!).

    I am trying to trace through to find where the code is not working.
    No stdout so I have to log to a file.
    Then you'd be better using the logging module from the stdlib. And
    FWIW, you should try to make you code testable in a non-service
    context...
    Thanks for the tip. "Batteries included" means there are so many
    batteries you miss some.

    The Module I am trying to use works perfectly as a free standing routine.
    I have the following code fragments.

    def log(message):
    f = open('d:\logfile.txt','a')
    f.write(message + "\n")
    f.close()

    from DelNotePrinter import DelNotePrinter
    <OT>
    The convention is to use all_lower_names for modules - having modules
    and classes with the same (case-sensitive) name can be very misleading.
    </OT>
    The convention is a good one.
    note the order of the above - log is defined before the import.
    And ? Do you think it will affect the imported module in any way ?
    Like, say, magically "inject" your log function in the DelNotePrinter
    module ?-)
    Just that log is defined before the global log is encountered to that if
    the compiler needed to set up a link at compile time it was able to do so.
    Later in the source
    Where ?
    About 350 lines further down.
    I have

    log('disPrint is:'+disPrint)
    log('count is:'+count)
    Do yourself a favor and learn string formating...
    Agreed. :) - These are debug statements to discover what is going on.

    I have had so much trouble with problems NOT being reported, that I
    avoid anything that I am not 100% sure must work.
    log(repr(DelNotePrinter))
    printer = DelNotePrinter(disPrint,int(count))
    The DelNotePrinter.py file cannot us log even though it is declared
    as global.
    In Python, "global" means "module-level", and it's only necessary when
    you want to rebind a module-level name from within a function or method.
    Exactly! I want to bind the name log to the function I wrote.
    So I carefully placed log in global scope and told the compiler that
    when I referred to log I meant the global one I wrote.
    I expected that to bind log to the function I wrote.
    The compiler did not complain it was undefined (which would have caused
    a trackback on the Event log).

    But neither was the routine called. :(

    I still don't understand what is going wrong.
    The code is...
    # coding=utf8
    # DelNotePrinter = code to print delivery notes
    assorted imports removed for space reasons
    Some of these imports surely explain why you don't just get a
    NameError when trying to call log() - wild guess : you have some "from
    xxx import *" statement that does import another callable named 'log'.
    I don't think so. The lines are

    import sys
    import datetime
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *
    from DataBaseClass import DataBase

    I know all PyQt classes begin with Q. Database I wrote, and it has no
    log in it.
    class DelNotePrinter(object):
    ''' Print Delivery Note on A5 in portrait '''
    def __init__(self,printer,copies):
    ''' create printer and painter '''
    global font,sm,log
    log('DelNotePrinter: starting')
    self.printer = QPrinter(QPrinter.HighResolution)
    If you want to access a name (function, class, whatever) defined in
    another module, you have to explicitely import it.
    The file the log writes contains..
    disPrint is:HP Deskjet 6940 series
    count is:1
    <class 'DelNotePrinter.DelNotePrinter'>

    The > is followed by a newline and end of file! Where is the
    DelNotePrinter: starting message?
    We can't tell - but you can get at least some hint, cf below
    If I replace the opening of __init__ with
    global font,sm,log
    f = open('d:\logfile.txt','a')
    f.write('DelNotePrinter: starting' + "\n")
    f.close()
    self.printer = QPrinter(QPrinter.HighResolution)

    then the message IS written to the log file.
    Obviously, yes. Now please add this to your code:

    class DelNotePrinter(object):
    ''' Print Delivery Note on A5 in portrait '''
    def __init__(self,printer,copies):
    ''' create printer and painter '''
    global font,sm,log
    f = open('d:\logfile.txt','a')
    f.write('DelNotePrinter: starting' + "\n")

    # check what "log" is bound to in the currrent namespace
    f.write(
    "DelNotePrinter : log is '%s' from '%s'" % (
    log, log.__module__
    ))
    f.close()
    self.printer = QPrinter(QPrinter.HighResolution)
    I tried that (using copy/paste) and got no output! So I modified is
    slightly to

    global log
    f = open('d:\logfile.txt','a')
    f.write("test message\n")
    f.write(
    "DelNotePrinter : log is '%s' from '%s'" % (
    log, log.__module__
    ))
    f.close()
    self.printer = QPrinter(QPrinter.HighResolution)

    I get my "test message" and then nothing. When I close the service, the
    next
    log message comes from the closing code.

    There are no errors reported, no messages, no Event log entries and
    nothing further happens. Its as if the thread died.
    I have read http://docs.python.org/reference/simple_stmts.html#global
    very carefully and I still don't understand.
    The statement definition makes no sense if you don't understand
    namespaces and bindings:

    http://docs.python.org/reference/executionmodel.html#naming-and-binding
    Thanks for the pointer. What a truly execrable piece of writing - full
    of over-long sentences and multiple subordinate clauses. It routinely
    uses terms before definition, and sometimes without definition. It is
    astonishingly bad.

    The third sentence reads "Each occurrence of a name in the program text
    refers to the /binding/ of that name established in the innermost
    function block containing the use." What does that mean? It appears to
    mean that it is the assignment in the innermost function block that
    binds for all uses, not the first, not module blocks, not class blocks
    and not code blocks - but the innermost function block. That might be
    correct, but somehow I doubt it, for it would mean that earlier bindings
    are ignored or invalidated or not used or something - even if the inner
    block is not executed.

    I am not stupid and English is my mother tongue, and I have read that
    page many times. The implications of the passage are still opaque to me.

    How can I call a global function placed at the top of the source. Do I
    really have to move a 4 line function into its own file and import it
    again and again and again?

    Regards

    Ian
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: <http://mail.python.org/pipermail/python-list/attachments/20100907/12dd0ce4/attachment.html>
  • Rami Chowdhury at Sep 7, 2010 at 7:54 pm
    Hi Ian,
    On Tue, Sep 7, 2010 at 20:00, Ian wrote:

    On 07/09/2010 11:50, Bruno Desthuilliers wrote:

    note the order of the above - log is defined before the import.

    And ? Do you think it will affect the imported module in any way ? Like,
    say, magically "inject" your log function in the DelNotePrinter module ?-)

    Just that log is defined before the global log is encountered to that if
    the compiler needed to set up a link at compile time it was able to do so.
    I think I see where you're going wrong -- this bit me too when I was
    learning Python, having come from PHP. Unlike PHP, when you import a module
    in Python it does *not* inherit the importing module's namespace. So the
    "log" function you're accessing in DelNotePrinter.py is not the one you
    defined above the import statement.

    In Python, "global" means "module-level", and it's only necessary when you
    want to rebind a module-level name from within a function or method.

    Exactly! I want to bind the name log to the function I wrote.
    As Bruno pointed out, the "global" statement is only necessary if you want
    to "rebind" a name -- i.e. if you want to modify how an object appears to
    the global scope. It's not necessary if you simply want to call a function.

    I have read http://docs.python.org/reference/simple_stmts.html#globalvery carefully and I still don't understand.


    The statement definition makes no sense if you don't understand namespaces
    and bindings:

    http://docs.python.org/reference/executionmodel.html#naming-and-binding

    Thanks for the pointer. What a truly execrable piece of writing - full of
    over-long sentences and multiple subordinate clauses. It routinely uses
    terms before definition, and sometimes without definition. It is
    astonishingly bad.
    Perhaps you could help rewrite it? I'm sure the maintainers would be very
    happy to get a documentation patch.

    The third sentence reads "Each occurrence of a name in the program text
    refers to the *binding* of that name established in the innermost function
    block containing the use." What does that mean? It appears to mean that it
    is the assignment in the innermost function block that binds for all uses,
    not the first, not module blocks, not class blocks and not code blocks - but
    the innermost function block. That might be correct, but somehow I doubt it,
    for it would mean that earlier bindings are ignored or invalidated or not
    used or something - even if the inner block is not executed.

    I am not stupid and English is my mother tongue, and I have read that page
    many times. The implications of the passage are still opaque to me.

    How can I call a global function placed at the top of the source. Do I
    really have to move a 4 line function into its own file and import it again
    and again and again?
    The short answer is yes. If you have this and similar functions that you
    call from various modules, then it's ideal to put them in a utility module
    of their own. However, as imported modules are cached in Python, this isn't
    as expensive as you might think if you are more used to other languages.

    --
    Rami Chowdhury
    "Never assume malice when stupidity will suffice." -- Hanlon's Razor
    408-597-7068 (US) / 07875-841-046 (UK) / 0189-245544 (BD)
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: <http://mail.python.org/pipermail/python-list/attachments/20100908/339038b5/attachment.html>
  • Ian at Sep 7, 2010 at 9:50 pm
    Hi Rami, Stefan, Bruno.

    First a big thanks for your replies.
    On 07/09/2010 20:54, Rami Chowdhury wrote:
    Hi Ian,

    I think I see where you're going wrong -- this bit me too when I was
    learning Python, having come from PHP. Unlike PHP, when you import a
    module in Python it does *not* inherit the importing module's
    namespace. So the "log" function you're accessing in DelNotePrinter.py
    is not the one you defined above the import statement.
    Hmm. My php background shows that much. Huh? :) I guess so.
    Thanks for the pointer. What a truly execrable piece of writing -
    full of over-long sentences and multiple subordinate clauses. It
    routinely uses terms before definition, and sometimes without
    definition. It is astonishingly bad.


    Perhaps you could help rewrite it? I'm sure the maintainers would be
    very happy to get a documentation patch.
    I would be happy to re-write it but I do need to understand the subject
    better before that can happen. Clear and wrong will not help anyone. :)
    Do I really have to move a 4 line function into its own file and
    import it again and again and again?


    The short answer is yes. If you have this and similar functions that
    you call from various modules, then it's ideal to put them in a
    utility module of their own. However, as imported modules are cached
    in Python, this isn't as expensive as you might think if you are more
    used to other languages.
    OK. Now I understand the need, the solution is easy.

    My first exploration of the wonders of writing windows services has had
    five things wrong with it:
    1) Its windows - spit, crash, complicated, can't start a command
    line with elevated permissions, nash teeth, rip hair out.
    2) Its services - so no stdout, or stderr, errors not reported, no
    "current directory" - burn and crash programming all over again. Deep joy!
    3) pythonservice.exe - so module not called __main__ and
    initialisation not performed (unseen - see 2) - More fun.
    4) multi-threading - I got really confused from this example
    http://docs.python.org/library/multiprocessing.html#exchanging-objects-between-processes
    becasue I got the wrong sort of Queue, so it stalled when it failed to
    call task_done() (there isn't such a method - but no error reported
    see 2).
    5) Names pipes. The latest is that writing - yes writing - to the
    named pipe causes the reader to fail with
    (232, 'ConnectNamedPipe', 'The pipe is being closed.') if I write
    using php - yet I can write with python no trouble.

    There are down sides to "batteries included". When there are so many
    batteries, it can be hard to know if what you have is "good enough" or
    should you search for a more suitable one. Logging would have helped me
    a lot (assuming it would work in service environment with the
    permissions it would have had - a serious assumption). If it failed, it
    would have failed and hidden the problem.

    Oh to get on to proper GUI programming with python and PyQt! The next
    project. Wey Hey!

    Thanks again

    Ian




    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: <http://mail.python.org/pipermail/python-list/attachments/20100907/b4085f72/attachment.html>
  • Bruno Desthuilliers at Sep 7, 2010 at 1:58 pm
    Ian Hobson a ?crit :
    (snip)

    you may also want to read the recent "using modules" thread...
  • Stefan Schwarzer at Sep 7, 2010 at 8:01 pm
    Hi Ian,
    On 2010-09-07 12:18, Ian Hobson wrote:
    f = open('d:\logfile.txt','a')
    Just a note: Using a backslash in a non-raw string will get
    you in trouble as soon as the backslash is followed by a
    character which makes a special character sequence, like "\n".
    For example,

    f = open('d:\nice_filename.txt', 'a')

    will give surprising results. :-) Either double the
    backslash, use a raw string, or, in the special case of
    file system paths, possibly use a forward slash.

    Stefan

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedSep 7, '10 at 10:18a
activeSep 7, '10 at 9:50p
posts7
users5
websitepython.org

People

Translate

site design / logo © 2022 Grokbase