portable fortune program

Steve Holden sholden at holdenweb.com
Sun Apr 28 14:18:36 EDT 2002


"J.Jacob" <joost_jacob at hotmail.com> wrote in message
news:13285ea2.0204270857.2f34f8a4 at posting.google.com...
> I have always liked the unix fortune program.
> Unfortunately nowadays some *n.x's come without fortune,
> and sometimes I have to work with Windows.  I wanted to be
> able to do:
>     C:\mydirectory> python -c "import fortune; fortune.quote()"
> printing a nice quote to stdout.
> The fortune module has to be able to locate a file with
> the name 'allfortunes'.  And you want everything to be
> portable.  And working with python 1.5.2 too.
>
> The allfortunes file contains quotes separated by lines
> with a '%' as its first character.  I downloaded a couple
> of BSD fortune files and combined them into allfortunes.
> If you put the following fortune.py file with an
> allfortunes file into one of the directories in your
> sys.path, or in you current working directory, it will work.
>
> This is a first hack, it is slow, the allfortunes file is
> not compressed, so comments are elcome, maybe you can
> suggest improvements?  I was trying to put the allfortunes
> file into a compressed string at the end of the fortune.py
> file, so you do not need a separate file anymore, but I
> did not see a best way to do it.  Please let me know if it
> does not work with your python distribution.
>
> joost_jacob at hotmail.com
>
>
[Jacob's original program appears after these comments]

Jacob:

Well done! Utilities like this need to be more widely available. One of the
other problems you have solved (without realizing it, possibly) is that
Windows users can now get their fortune. I'm a strong believer that once
Windows users see how powerful open source applications are they'll be a lot
less worried about using GNU/Linux and the wonderful system tools that come
with them.

You have obviously already thought about speed: the more fortunes you have,
the more reading you do from filestore. With today's modern computers, and
infrequent fortune usage, this probably doesn't matter for many users. So,
you can just shrug your shoulders and ignore this suggestion, which has to
do with locating the individual fortunes with in the file. Alternatively,
you could ask yourself "If this were a fortune server on the web, how would
I give my server the best chances of scaling to 1,000 or 1,000,000 users?"
and start on a hunt for efficiency.

If there were a subsidiary data file (containing the starting position in
the file for each fortune in your original data file) you could try to read
this in, make a random choice from the resulting list of positions (using
choice(), as suggested by another poster), and only then use the fortunes
file. From there a single fortunes.seek()[1] will get you to the start of
the chosen fortune, and you can just read that one fortune and display it.

You might ask: "Where does the subsidiary data file come from?". The answer
is that your program will check for the presence of the fortune file as
always (no harm opening it right at the start, since you have to read it
later), and look in that directory for the subsidiary file. If no data file
is found, the program will attempt to create it if it doesn't already exist
(or if it's older than the fortune file). If you are on a Unix or cygwin
system you could use os.system()[2] and rely on the make(1)[4] command for
this portion of the process, at least at the start..

That way, as long as the file can be created it will be. You should be
careful to ensure your program still works even if it tries but cannot
create the file. This could happen if, say, only root could write into the
directory, and an ordinary user was running the program. Clearly it would be
a great idea to retain your existing code, or something very close to it, to
handle such exceptional circumstances.

What should the format of that file be? A pickle[3] containing a list of
(possibly) long integers would be simplest to create and use in Python.

If you wanted to use the Python source as a fortunes files, one way to do
this would simply be to build a list using code similar to the following
pseudo-code:

    fortunes = []
    fortunes.append("""I tell you three times it is 1""")
    fortunes.append("""We hold these 1s to be self-evident, that all men are
created equal, that they are endowed by their Creator with certain
unalienable Rights, that among these are Life, Liberty and the pursuit of
Happiness.""")
    fortunes.append("""A lie would have no sense unless the 1 were felt
dangerous.
- Alfred Adler""")
    fortunes.append("""The first and last thing required of genius is the
love of truth.
- Johann Wolfgang von Goethe""")

... and so on.

You can probably quite easily see how you could write a program to write
most of this code for you while reading to allfortunes file. Adding so much
code would, of course, make the Python module much bigger. If it were going
to be in continual use as a web server, then, you might want to write it as
some sort of long-running process that only has to start up once before
serving several thousand fortunes. That's getting a bit sophisticated,
though Python is easily capable of handling that sort of stuff[5].

I hope you don't in any way see this as critical of your efforts. As I said
at the start, I think your program is great. This being comp.lang.python you
may well see another set of postings with other, possibly even better, ideas
for improvement.

regards
--
[1]:    http://www.python.org/doc/current/lib/bltin-file-objects.html
[2]:    http://www.python.org/doc/current/lib/os-process.html
[3]:    http://www.python.org/doc/current/lib/module-pickle.html
        http://www.python.org/doc/current/lib/module-cPickle.html
[4]:    http://www.gnu.org/manual/make-3.79.1/html_mono/make.html#SEC1
[5]:    http://www.zope.com/

Steve Holden: http://www.holdenweb.com/ Python Web Programming:
http://pydish.holdenweb.com/pwp/

>
> # file fortune.py
> import random, os
>
> def randlistindex(yourlist):
>     "Return a random index number into yourlist"
>     return random.randint(0, len(yourlist)-1)
>
> def quote():
>     """
>     Return a quote <string> from file allfortunes,
>     assume the file allfortunes is located in the same
>     directory as this module."""
>     datafile = os.path.join(
>       os.path.dirname(__import__(__name__).__file__),
>       'allfortunes' )
>     quotesfile = open(datafile)
>     quoteslist, quote = [], ''
>     for s in quotesfile.readlines():
>         if s[0] == '%':
>             if quote:
>                 quoteslist.append(quote)
>                 quote = ''
>         else: quote = quote + s
>     if quote: quoteslist.append(quote)
>     print quoteslist[randlistindex(quoteslist)],






More information about the Python-list mailing list