473,402 Members | 2,050 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,402 software developers and data experts.

Passing options around your program

I have another question where I am not so much looking for a
solution but rather hoping to get some feedback on *which*
solutions people here consider good Pythonic ways to approach a
issue.

The situation is this: I am writing fairly large console scripts
in Python. They have quite a few command-line options, which lead
to configuration variables that are needed all over the program
(e.g. the "--verbose" option alone is used by just about every
function and method).

I am using optparse to handle the actual option parsing, so I
have a main function that contains:

opts,args = parser.parse_args()

My question in a nutshell is: what is the best way to make the
parsed options in 'opts' easily available to the rest of my
program?

- Having 'opts' trickle down by passing it as an explicit
parameter is the most flexible option. It allows me to easily
separate the options from the command-line parsing -- if I want
to call my script interactively or from a GUI instead, I can just
craft my own 'opts' object and pass that.

But on the other hand, I feel that the proliferation of 'opts'
parameters gets ugly, and does not do wonders for the readability
of the program.

- So especially for shorter scripts, a solution I've used is to
define a global config class, and transfer the options to it:

class Config:
pass

With in main():

for opt in vars(opts):
setattr(Config, opt, getattr(opts, opt))

or:

Config.cmd_opts = opts

Now every method that needs it can just call Config.verbose or
Config.cmd_opts.verbose or whatever.

A variant I have also used occasionally is to derive Config from
a Martelli Borg parent class with shared-state instances, so that
every function or class that needs access to the config
parameters can just instantiate its own 'local' Config() object.
I find this works nicely if the program is spread out over more
than one file.

- A third option I have seen mentioned (possibly even here on
c.l.p.), but have not actually tried yet, is that if you decide
to have something 'global' anyway, why not just use a module
instead of a class to store the options, so that every file can
do "import config" and then say "config.verbose" etc.
So, does anybody have any particular positive or negative
opinions on any of these approaches, and/or are there perhaps
possibilities I have overlooked?

Many thanks in advance for your feedback.

--
Leo Breebaart <le*@lspace.org>
May 7 '06 #1
7 1519
When I have done this, I've used the last option -- creating a "config"
module which can be imported wherever the configuration info is needed.
(This module also handles any config files and/or Windows registry
keys needed.) Using a Borg is a nice idea... but that ConfigBorg is
probably going to be in its own module, which will need to be imported
anyhow... so why not let sys.__import__() do your singleton-enforcement
for you?

Of course, I hesitate to claim anything that I do as being necessarily
related to "best practices", but what would Usenet be without swarms of
half-informed opinions? ;)

Jeff Shannon

May 7 '06 #2
Leo Breebaart wrote:
I have another question where I am not so much looking for a
solution but rather hoping to get some feedback on *which*
solutions people here consider good Pythonic ways to approach a
issue.

The situation is this: I am writing fairly large console scripts
in Python. They have quite a few command-line options, which lead
to configuration variables that are needed all over the program
(e.g. the "--verbose" option alone is used by just about every
function and method).


<SNIP>

One question I have is about the "--verbose" option.

If you're doing something that is equivalent to logging to <file |
console>, rather than continuing to pass the '--verbose' flag around,
why not just use the built-in logging facility to manage the extra
output?

By having the different modules call logging( <level>, "<message">)
throughout your programs, you only need to set the initial level from
where you're checking options (whether from command line or
configuration file) rather than having to pass the '--verbose' option
around.

May 7 '06 #3
"alisonken1" <al********@gmail.com> writes:
Leo Breebaart wrote:
I am writing fairly large console scripts in Python. They
have quite a few command-line options, which lead to
configuration variables that are needed all over the program
(e.g. the "--verbose" option alone is used by just about
every function and method).


<SNIP>

One question I have is about the "--verbose" option.

If you're doing something that is equivalent to logging to
<file | console>, rather than continuing to pass the
'--verbose' flag around, why not just use the built-in logging
facility to manage the extra output?


Good point. It's not a real conscious decision, and I have one or
two other projects lying around where I do in fact use logging. I
think the main reason why I am not using it by default is
because, when all is said and done, it still comes easier to me
to resort to guarded print statements then to set up and use the
logging machinery.

This may well be a false economy in the long run, but it is
nevertheless how I perceive it in day-to-day programming.

(Related to this is that while I found e.g. the optparse
documentation very clear and relevant to my needs, the logging
documentation and examples, while readable, just never seem to
relate to what I actually need. This is not a complaint -- just
a subjective observation.)

But you are right. Especially for the larger projects I really
should bite the bullet and start using the logging module.

--
Leo Breebaart <le*@lspace.org>
May 8 '06 #4
Leo Breebaart enlightened us with:
I think the main reason why I am not using it by default is because,
when all is said and done, it still comes easier to me to resort to
guarded print statements then to set up and use the logging
machinery.


The logging "machinery" isn't that huge nor is it difficult to set up:

==================================================
import logging

logging.basicConfig()
log = logging.getLogger('your.module.name')
==================================================

and that's all there is to it.

Sybren
--
The problem with the world is stupidity. Not saying there should be a
capital punishment for stupidity, but why don't we just take the
safety labels off of everything and let the problem solve itself?
Frank Zappa
May 8 '06 #5
Sybren Stuvel <sy*******@YOURthirdtower.com.imagination> writes:
Leo Breebaart enlightened us with:

I think the main reason why I am not using [logging] by
default is because, when all is said and done, it still comes
easier to me to resort to guarded print statements then to
set up and use the logging machinery.


The logging "machinery" isn't that huge nor is it difficult to set up:

==================================================
import logging

logging.basicConfig()
log = logging.getLogger('your.module.name')
==================================================

and that's all there is to it.


I did say: "it comes easier *to me*" -- I am aware that my own
tastes, which may not be shared by others, or be entirely
logical, feature into this.

Having said that, I do think it's also not *quite* as trivial as
you claim. In order to duplicate what I already have ("if config.verbose:
print msg"), I probably need to log at the DEBUG level, and I
need to change the format so that that output looks like the
'print' output (no timestamping cruft etc.)

Okay, you say, that's still easy. It's just:

logging.basicConfig(level=logging.DEBUG,
format='%(message)s')

logging.debug('A debug message')

And that's true, but I did have to go and look this up, and I
made a couple of false starts first. I can only repeat that the
workings of the logging framework are rarely intuitive to me.

Also, assume that I have set it up as above. Now I want certain
other print statements to go to sys.stderr alone. If I understand
the docs correctly (possibly I don't), the way to do this is to
start attaching explicit StreamHandlers and whatnot. Whereas with
print, I can say "print >>sys.stderr, msg".

I know that it won't take much for a script to become so complex
that the extra stuff logging buys you vastly overpowers the
convenience of the print statements. I have just not needed that
often enough for it to become second nature to use in smaller
scripts as well.

--
Leo Breebaart <le*@lspace.org>
May 8 '06 #6
Leo Breebaart enlightened us with:
Okay, you say, that's still easy. It's just:

logging.basicConfig(level=logging.DEBUG,
format='%(message)s')
I always use a separate logger, as per my example. That would then
just require an additional line:

log.setLeveL(logging.DEBUG)
And that's true, but I did have to go and look this up, and I made a
couple of false starts first. I can only repeat that the workings of
the logging framework are rarely intuitive to me.
If you're just writing software for yourself, that's fine. If you want
to share your software, things that are intuitive to you might not be
to others. In such a case (and usually software is going to be shared
at some point or another) it's generally a good idea to spend a few
minutes learning how to use such a system, because then other people
will see your code using things they are already familiar with.

Reusing other people's code instead of writing your own logging, also
means that other people will fix bugs for you.
I know that it won't take much for a script to become so complex
that the extra stuff logging buys you vastly overpowers the
convenience of the print statements. I have just not needed that
often enough for it to become second nature to use in smaller
scripts as well.


I don't use the logging module in small scripts either, but as soon as
it gets over 100 lines, I do. It's quite easy to get it going, once
you get the hang of it.

Sybren
--
The problem with the world is stupidity. Not saying there should be a
capital punishment for stupidity, but why don't we just take the
safety labels off of everything and let the problem solve itself?
Frank Zappa
May 8 '06 #7

Leo Breebaart wrote:

<SNIP>
Also, assume that I have set it up as above. Now I want certain
other print statements to go to sys.stderr alone. If I understand
the docs correctly (possibly I don't), the way to do this is to
start attaching explicit StreamHandlers and whatnot. Whereas with
print, I can say "print >>sys.stderr, msg".

<SNIP>

Something else to consider, every time your script calls "print
sys.stderr, msg", it is making another file open request.


I've run across situations where this format will actually cause a
system to return "too many open files" error.

As was pointed out earlier, it's much easier to learn how to use the
logging facility and create a default stdout logger as well as a
secondary stderr logger that only maintains one file handle than to try
to find out where you're getting some errors that are not script errors
but system limit errors.

The other nice aspect of using the logging facility is the availability
of changing the logger to save output to a file or stdout/stderr than
to try and go through a more-than-one-file program.

It's easy to learn how to redirect stdout/stderr within a script, but
it's usually more flexible to use the logging facility that's already
been included. Before the logging module was included in the library, I
usually ended up writing my own logging module to do the same thing.
Especially since the logger allows you to specify levels.

For example, I typically have my logging facility setup as follows:

10 - Very basic logging - typically main routine changes
20 - Log imports
30 - Log class instantiation
40 - Log module calls
50 - Log function calls

The other aspect of using the logging facility, you can also define
your own in-between log levels:

51 - Entering function
52 - Exiting function
53 - Function sub-routines
60 - Everyhing under the sun

As part of the configParser options:
-v : Increment logging level by 1 level for every -v option on command
line
-loglevel=<level> : Specify log level
-logfile=<filename> : File to save stdout messages
-errfile=<filename> : File to save stderr messages

Once you get used to the logging module, it's hard to go back to using
file redirects and the <sometimes> system limits troubleshooting in
larger programs.

May 8 '06 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Chris | last post by:
I'm trying to come up with a not-so-ugly manner of passing many command-line options between modules. I have a Steering.py file, which contains my main() and handles the getopts getting of...
6
by: Garma | last post by:
According to what I have learnt so far, instantiating global objects should be the last resort. Is there any reasons why so? Sometimes some objects or their pointers have to be shared among...
58
by: jr | last post by:
Sorry for this very dumb question, but I've clearly got a long way to go! Can someone please help me pass an array into a function. Here's a starting point. void TheMainFunc() { // Body of...
3
by: Simon Harvey | last post by:
Hi, In my application I get lots of different sorts of information from databases. As such, a lot of information is stored in DataSets and DataTable objects. Up until now, I have been passing...
3
by: Lee | last post by:
Hi All How can I pass options from one webpage into another webpage. When the user clicks on the hyperlink I want them to be go to the next page but I need to pass in a number that the next...
28
by: Skeets | last post by:
i'm passing session and hidden variables between pages. not to mention post values. i'm a little concerned that someone with sufficient knowledge could spoof these vlaues and manipulate the...
5
by: Chris Hieronymus | last post by:
Hi, I have a bunch of x-y data contained in an array. I would like to plot the data using an external program (psxy in GMT). The plotting program takes x-y couples as standard input. ...
5
by: Markus Ernst | last post by:
Hello A class that composes the output of shop-related data gets some info from the main shop class. Now I wonder whether it is faster to store the info in the output class or get it from the...
1
by: Harold Fellermann | last post by:
Dear list, I looked through the list but could not find any solutions for my current problem. Within my program, I am importing a module via __import__(module_name,globals(),locals()) and I...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.