The Wayback Machine - https://web.archive.org/web/20150926085844/http://jugad2.blogspot.com/search/label/python
Showing posts with label python. Show all posts
Showing posts with label python. Show all posts

Saturday, September 19, 2015

Swapping two variables without using a third, 1) generically and 2) Pythonically


Image

By Vasudev Ram


One of the techniques taught in some beginners' programming courses, is how to swap the values of two variables, without using a third variable. It is sometimes given as an exercise to students. I remember it from an early course that I took.

[ If you don't know the solution, try it before reading on. Hint: Try it for two integers. No restrictions, other than not being allowed to use a third variable. ]
.
.
.
.
.
One solution to it, at least when the two variables contain integer values, is like this:

>>> a, b = 1, 2
>>> print a, b
1 2
>>> a = a + b
>>> a, b
(3, 2)
>>> b = a - b
>>> a, b
(3, 1)
>>> a = a - b
>>> print a, b
2 1
Of course, the above method will only work for numbers, i.e. at least, for integers; it might or not work for all pairs a and b when a and b are floating-point numbers. Why? (*)

Similarly, it will not work when a and b are strings or any other data type.

(*) One reason it may not work for all floats (only some - I need to check this), is because some float values cannot be represented exactly in a computer that uses binary representation of numbers.

So that was the generic way, above (to swap the values of two integer variables, without using a third temporary variable), which will work in most or all programming languages.

Python has another, Pythonic way (though it also works in some other languages, I guess). It's just:

a, b = b, a

which does a parallel assignment of a and b's old values to each other, without overwriting either.

Interestingly, this 2nd way, since it does not involve addition and subtraction (as in a + b and a - b), is more general. For example, we can swap the values of two function objects:
>>> def foo(): print "this is function foo"
...
>>> def bar(): print "this is function bar"
...
>>> foo()
this is function foo
>>>
>>> bar()
this is function bar
>>>
>>> foo
<function foo at 0x00000000029F09E8>
>>> bar
<function bar at 0x00000000029F0518>
>>>
>>> foo, bar = bar, foo
>>>
>>> foo()
this is function bar
>>> bar()
this is function foo
>>> foo
<function bar at 0x00000000029F0518>
>>> bar
<function foo at 0x00000000029F09E8>
Note that both calling the function, like foo(), and just entering its name at the Python shell, like foo, tell us that the name foo now refers to the original bar function object. And similarly the name bar now refers to the original foo function object.

And finally, to show what happens in the above function object swap, in a different way:
>>> id(foo), id(bar)
(43977192L, 43975960L)
>>> foo, bar = bar, foo
>>>
>>> id(foo), id(bar)
(43975960L, 43977192L)
After writing this post, I googled for "swapping two variables without using temp" and found an interesting hit:

Swap Two Variables Without Using a Temp Variable (With Math!)

which throws more light on this subject, showing other ways to do it, and also goes into the mathematical theory behind it (involving groups - the mathematical kind) - which I remember as a fun math topic from college, with many applications in the real world. I even got to know about quasigroups from that post ... whew!

Referring to the swapping of function objects above, coincidentally, just recently I came across a post by Ned Batchelder on a very related topic: names and values in Python. The exact meaning of (identifier) names and values in Python is not as obvious as it may seem at first, and is also somewhat different from the way these things work in other languages like C or Java. It has to do with concepts like binding names to values (and also unbinding and rebinding them). Here is his post, which he also presented as a video at PyCon 2015:

Python Names and Values

There is a link to the video in his post, and it is also embedded below:



- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new products and services I create.

Posts about Python  Posts about xtopdf

Contact Page

Tuesday, August 4, 2015

Converting numeric strings to integers with handrolled code


By Vasudev Ram

-

Image

A while ago, I was explaining to someone, how different data types such as numbers and strings are represented in a computer. That made me think of writing a simple program, called str_to_int.py, similar to Python's built-in int() function, to show them roughly what steps are involved in the process of converting a numeric string, such as '123', to an integer.

There are many different solutions possible for this task, and some may be more efficient or simpler than others, of course. This was just my first quick attempt at it (in Python, because I had no need to do it earlier, though I've done it before in assembly language and in C; in C it would be like the atoi() function in the C standard library). Note that this program does not handle all the cases that Python's int() does. It's just meant to show the basics of the process.

Here is the source code for str_to_int.py:
def str_to_int(s):
    ctr = i = 0
    for c in reversed(s):
        i += (ord(c) - 48) * (10 ** ctr)
        ctr += 1
    return i

print
for s in ('0', '1', '2', '3', '12', '123', '234', '456', '567'):
    i = str_to_int(s)
    print "s = {}, i = {} |".format(s, i),

print
print

for i in range(50):
    s = str(i)
    j = str_to_int(s)
    print "s = {}, j = {} |".format(s, j), 

And here is its output:
$ py str_to_int.py

s = 0, i = 0 | s = 1, i = 1 | s = 2, i = 2 | s = 3, i = 3 | s = 12, i = 12 | s =
 123, i = 123 | s = 234, i = 234 | s = 456, i = 456 | s = 567, i = 567 |

s = 0, j = 0 | s = 1, j = 1 | s = 2, j = 2 | s = 3, j = 3 | s = 4, j = 4 | s = 5
, j = 5 | s = 6, j = 6 | s = 7, j = 7 | s = 8, j = 8 | s = 9, j = 9 | s = 10, j
= 10 | s = 11, j = 11 | s = 12, j = 12 | s = 13, j = 13 | s = 14, j = 14 | s = 1
5, j = 15 | s = 16, j = 16 | s = 17, j = 17 | s = 18, j = 18 | s = 19, j = 19 |
s = 20, j = 20 | s = 21, j = 21 | s = 22, j = 22 | s = 23, j = 23 | s = 24, j =
24 | s = 25, j = 25 | s = 26, j = 26 | s = 27, j = 27 | s = 28, j = 28 | s = 29,
 j = 29 | s = 30, j = 30 | s = 31, j = 31 | s = 32, j = 32 | s = 33, j = 33 | s
= 34, j = 34 | s = 35, j = 35 | s = 36, j = 36 | s = 37, j = 37 | s = 38, j = 38
 | s = 39, j = 39 | s = 40, j = 40 | s = 41, j = 41 | s = 42, j = 42 | s = 43, j
 = 43 | s = 44, j = 44 | s = 45, j = 45 | s = 46, j = 46 | s = 47, j = 47 | s =
48, j = 48 | s = 49, j = 49 |

To get the documentation for int(), you can do this:
>>> print int.__doc__
which gives this as the output:
int(x=0) -> int or long
int(x, base=10) -> int or long

Convert a number or string to an integer, or return 0 if no arguments
are given.  If x is floating point, the conversion truncates towards zero.
If x is outside the integer range, the function returns a long instead.

If x is not a number or if base is given, then x must be a string or
Unicode object representing an integer literal in the given base.  The
literal can be preceded by '+' or '-' and be surrounded by whitespace.
The base defaults to 10.  Valid bases are 0 and 2-36.  Base 0 means to
interpret the base from the string as an integer literal.
>>> int('0b100', base=0)
4
Learn more about this overall topic at the Wikipedia article on numeral systems.
Also check out my earlier post about Bhaskaracharya and the man who found zero.

Kthxbye :)

Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new Python products or services that I create.

Posts about Python  Posts about xtopdf

Contact Page

Sunday, July 12, 2015

Cut the crap! An absolutely essential tool for writers

By Vasudev Ram


KEEP CALM

AND

BE CONCISE




Like anyone else, every now and then I hear people use redundant words words or phrases. Hey, I do it myself sometimes, but am trying to do less of it.

So one day recently, thinking about ways to help with this issue, I came up with the idea for this program, called "Cut the crap!".

You feed it a redundant word or phrase, and if it "knows" it, it spits out the concise (unredundant? dundant? :-) version. Think a Strunk-and-White-like Python bot.

So, here's the Python code for cut_the_crap.py, an absolutely essential tool for writers. The phrases and words are hardcoded as of now, in this first version, but you can easily modify the program to read them from any persistent store (such as a file or database), along with the concise substitutes:
# cut_the_crap.py
# Author: Vasudev Ram
# Purpose: Given a redundant word or phrase, emits a concise synonym.
# See Strunk and White, et al.

from string import lower
from random import randint

d = {
    'at this point in time':
    ['now', 'at present', 'at the moment', 'at this moment', 
    'currently', 'now', 'presently', 'right now'],
    'absolutely complete': ['complete'],
    'absolutely essential': ['essential', 'indispensable'],
    'actual experience': ['past experience', 'experience'],
    'as to whether': ['whether'],
    'try out': ['try']
}

def cut_the_crap(word):
    if word in d:
        words = d[word]
        i = randint(0, len(words) - 1)
        return words[i]
    else:
        return ""
        
def get_the_word():
    crap_word = raw_input("Enter your word (or type 'exit'): ")
    return crap_word

def main():
    word = get_the_word()
    while lower(word) != 'exit':
        right_word = cut_the_crap(word)
        if right_word != "":
            print "Cut the crap! Say:", right_word
        print
        word = get_the_word()
    print "Bye."

if __name__ == '__main__':
    main()
And here is a sample run, entering a few redundant words and phrases:
$ py cut_the_crap.py
Enter your word (or type 'exit'): at this point in time
Cut the crap! Say: at the moment

Enter your word (or type 'exit'): at this point in time
Cut the crap! Say: right now

Enter your word (or type 'exit'): at this point in time
Cut the crap! Say: now

Enter your word (or type 'exit'): as to whether
Cut the crap! Say: whether

Enter your word (or type 'exit'): absolutely essential
Cut the crap! Say: indispensable

Enter your word (or type 'exit'): absolutely essential
Cut the crap! Say: essential

Enter your word (or type 'exit'): try out
Cut the crap! Say: try

Enter your word (or type 'exit'): exit
Bye.
- Enjoy.

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new products or services that I create.

Posts about Python  Posts about xtopdf

Contact Page

Saturday, June 20, 2015

What is the meaning of this number? 3735928559

By Vasudev Ram



Image

Saw this tweet by Raymond Hettinger (@raymondh), Python core developer:

Pop quiz: Whenever you see the number 3735928559 in your output, there is probably an error in the code. What is special about this number?

So I took a guess: converted the number to hexadecimal:
>>> print hex(3735928559)
and sure enough, it printed out:
0xdeadbeefL
Here is the reverse conversion, from hexadecimal to decimal:
>>> print int('0xDEADBEEF', 16)
3735928559
Also see: hexspeak

How do you like that little critter at the top of the post?
I call him PyBug. Drawn impromptu, for this post, by:

- Yours truly,

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new products or services that I create.

Posts about Python  Posts about xtopdf

Contact Page


Wednesday, June 10, 2015

pygal, a Python SVG charting library

By Vasudev Ram



Image

I came across pygal recently. It is a Kozea project. They also have some other interesting projects, some of which are in Python. lxml is the only needed dependency for pygal.

I tried out a simple example from the pygal site, which generates a graph of Fibonacci numbers, and then enhanced it a bit to add a graph of a univariate quadratic function, which represents a parabola, in the same plot. The quadratic function I used was:

3x^2 + 2x + 4 (three x squared plus two x plus four)

[ Also check out:

Quadratic equations

and

the quadratic formula

if not known (or not remembered from high school mathematics :)

And speaking of quadratics (functions, formulae, equations and so on), also check out my earlier post:

Bhaskaracharya and the man who found zero, which briefly mentioned Brahmagupta, an ancient Indian mathematician, who is supposed to be the discoverer of the number zero, without which practically no modern science or technology (including computers and software :) would be possible. He also gave "the first explicit (although still not completely general) solution of the quadratic equation ax^2 + bx = c", according to the Wikipedia article about him, linked to in the previous sentence.

]

Here is the modified pygal example program, in test_pygal.py:
import pygal

bar_chart = pygal.Bar()
bar_chart.add('Fibonacci', [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55])
bar_chart.render_to_file('bar_chart.svg')

def quadratic(a, b, c, x):
    return a * x * x + b * x + c

bar_chart.add('Quadratic', [quadratic(3, 2, 4, x) for x in range(1, 10)])
bar_chart.render_to_file('bar_chart.svg')
I ran it with:
py test_pygal.py
[ Learn more about py here: py, the Python Launcher for Windows ]

And here is a screenshot of the output of running the test pygal program:

Image

You can intuitively see that if you drew a curve joining the tops of the green bars in the screenshot, it would approximate a parabola. Parabolas occur a lot in nature too, as do many other mathematical concepts or principles.

- Enjoy.

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new products or services that I create.

Posts about Python  Posts about xtopdf

Contact Page

Saturday, May 30, 2015

Moire with Spyre (a Python web framework)

By Vasudev Ram



Image

The image above is of Uppsala Cathedral, Sweden, with its spires.

From the Spyre site:

Spyre is a Web Application Framework for providing a simple user interface for Python data projects. It is by Adam Hajari

I had come across Spyre recently via this post by Ian Oszvald:

Data Science Deployed – Opening Keynote for PyConSE 2015. More about Ian Oszvald here.

So I installed Spyre with the command:
pip install dataspyre
which in turn installed NumPy, pandas and matplotlib, all of which went through okay, though I saw some compiler / linker error messages scroll by as some compilation of C modules was happening (as part of the installation).

Then I tried it out a little, this time just using one of the simple applications on the Spyre site, without any modifications, like I sometimes do.
from spyre import server

import matplotlib.pyplot as plt
import numpy as np

class SimpleSineApp(server.App):
    title = "Simple Sine App"
    inputs = [{ "input_type":"text",
                "variable_name":"freq",
                "value":5,
                "action_id":"sine_wave_plot"}]

    outputs = [{"output_type":"plot",
                "output_id":"sine_wave_plot",
                "on_page_load":True }]

    def getPlot(self, params):
        f = float(params['freq'])
        x = np.arange(0,2*np.pi,np.pi/150)
        y = np.sin(f*x)
        fig = plt.figure()
        splt1 = fig.add_subplot(1,1,1)
        splt1.plot(x,y)
        return fig

app = SimpleSineApp()
app.launch()
As you can see, the structure / model of the code for a Spyre app does not seem to be very similar to that of, say, a Flask or a Bottle app. But then, there is no reason that it should be.
Anyway, I ran this app with the command:

python simple_sine_example.py

and then browsed to:

http://127.0.0.1:8080/

where I then gave different values for the input parameter freq, to see what would happen. I found that running it with certain values of freq created interesting Moire patterns in the output; hence the title of this post.

Here are a few screenshots below that show those moire patterns:

With freq = 764:

Image

With freq = 472:

Image

With freq = 475:

Image

With freq = 479:

Image

Notice that in some cases, such as with the values of 472, 475 and 479 for freq, the small changes between those values results in significant changes in the output image. Not only that: for 472 and 479, the images are similar (look sine-wave-y), but for 475 (which is between the other two values), the image looks almost like straight vertical lines. (It isn't, of course; it's still a sine wave, but more compressed along the horizontal axis.) I've not analyzed the reason for this in detail; something to do with the periodicity of the sine function, is my rough guess, but I have seen similar phenomena when drawing other kinds of computer graphics on the screen; those also involved trigonometric functions such as sine and cosine.

Spyre away :)

P.S. In other news, I was recently profiled in PyDev of the Week.

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new products or services that I create.

Posts about Python  Posts about xtopdf

Contact Page

Friday, May 22, 2015

Talk Python To Me podcast; Australia mandates text-based programming

By Vasudev Ram



Image

Today, for a change, a different kind of Python post, but one that I think will be interesting to my readers:

From the horse's, er, snake's mouth :)

Talk Python to Me "is a weekly podcast hosted by Michael Kennedy. The show covers a wide array of Python topics as well as many related topics (e.g. MongoDB, AngularJS, DevOps)."

The format is a casual 30 minute conversation with industry experts.

I just came across it today, and am checking out the site a bit. The site itself looks good, visually, I mean.

Some of the podcasts also have text transcripts.

I'm reading one of the transcripts, Transcript for Episode #8, of the conversation with Dr. James Curran:

Teaching Python at Grok Learning and Classrooms

Excerpt:

"James Curran is an associate professor in computer science at the University of Sidney and co-founder of Grok Learning, which you can find at groklearning.com. James has been teaching computer science to students and teachers for over a decade. In 2010 he was named one of Sidney magazines top 100 influential people for his work in computer science education."

(I guess the 'Sidney' spelling is due to an error in the automated or manual transcription of the podcast.)

Anyway, the transcript is interesting, since is about Python and/in education / training, which are both among my interests.

An interesting point mentioned in the talk, is that Australia is mandating text-based computer programming in its schools, as opposed to only having visual programming with tools like Scratch. Methinks that is a good idea, since only being able to work with GUI's and no skill with text-based tools (such as text editors and the command line), is not a good thing, IMO. I've come across, and once interviewed (for a client), some Java "programmers" who could not write a simple Java program without reaching for Eclipse. What the hell. Not knocking Java. I'm sure there must be people like that for other languages too. [ Dons latest flame shield made of modern composites in advance ... :) ]

Dr. Curran on the topic:

"So we have done a lot of work with teaching students in seventh and eighth grade, and I think that that is the ideal zone in fact the Australian curriculum that I was just involved in writing has mandated that the kids will learn a text based programming language as opposed to something like visual language, like Scratch. So text based programming is mandated for year seventh and eighth, and Python I think is the ideal language to be teaching there."

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new products or services that I create.

Posts about Python  Posts about xtopdf

Contact Page

Wednesday, May 13, 2015

Python video: P is better than NP :)

By Vasudev Ram



Image

Another Raymond Hettinger Python video, both entertaining and informative. This one was at the recently concluded PyCon 2015 in Montreal.

Watch this video to find out how P is better than NP, and how to create adapters for code from other languages that has been ported to Python.

The video is also embedded below.



I originally saw the video via a link in this recent HN thread about Peter Norvig's Python IAQ, which I also tweeted about recently:

The Python IAQ: Infrequently Answered Questions (norvig.com)

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new products or services that I create.

Posts about Python  Posts about xtopdf

Contact Page


Friday, May 8, 2015

tabtospaces, utility to change tabs to spaces in Python files

By Vasudev Ram



Image

Near the end of a recent blog post:

asciiflow.com: Draw flowcharts online, in ASCII

, I showed how this small snippet of Python code can be used to make a Python program usable as a component in a Unix pipeline:
for lin in sys.stdin:
    sys.stdout.write(process(lin))

Image

Today I saw Raymond Hettinger (@raymondh)'s tweet about the -t and -tt command line options of Python:
#python tip: In Python 2, the -tt option raises an error when you foolishly mix spaces and tabs. In Python 3, that is always an error.
That made me think of writing a simple Python 2 tool to change the tabs in a Python file to spaces. Yes, I know it can be easily done in Unix or Windix [1] with any of sed / awk / tr etc. That's not the point. So here is tabtospaces.py:
import sys
for lin in sys.stdin:
    sys.stdout.write(lin.replace("\t", "    "))
[ Note: this code converts each tab into 4 spaces. It can be parameterized by passing a command-line option that specifies the number of spaces, such as 4 or 8, and then replacing each tab with that many spaces. Also note that I have not tested the program on many sets of data, just one for now. ]

I created a simple Python file, test1.py, that has mixed tabs and spaces to use as input to tabtospaces.py. Then I ran the following commands:
$ py -tt test1.py
  File "test1.py", line 4
    print arg,
              ^
TabError: inconsistent use of tabs and spaces in indentation

$ py tabtospaces.py < test1.py > test2.py

$ py -tt test2.py
0 1 2 3 4 5 6 7 8 9
which shows that tabtospaces.py does convert the tabs to spaces.

And you can see from this diff that the original test1.py and the test2.py generated by tabtospaces.py, differ only in the use of tabs vs. spaces:
$ fc /l test1.py test2.py
Comparing files test1.py and TEST2.PY
***** test1.py
    for arg in args:
                print arg,

***** TEST2.PY
    for arg in args:
        print arg,

*****

[1] Windix is the latest upcoming Unix-compatible OS from M$, due Real Soon Now. You heard it here first - TM.

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new software products or info-products that I create.

Posts about Python  Posts about xtopdf

Contact Page

Friday, May 1, 2015

Can a Python data structure reference itself?

By Vasudev Ram



Image

As part of some Python work, I was tinkering with the built-in globals() function of Python, when I noticed this:
>>> g = globals()
>>> g
{'a': 'A', 'A': 'C', 'C': 4, 'b': 'a', 'g': {...}, '__builtins__': <
module '__builtin__' (built-in)>, 'k': '__doc__', '__package__': None, '__name__
': '__main__', '__doc__': None}
>>> # The variable g seems to have got stored inside of itself!
>>> id(g)
31298152L
>>> id(globals())
31298152L
>>> g['g'] == g
True
>>> g['g']['g'] == g
True
>>> g['g']['g']['g'] == g
True
>>> id(g['g']['g']['g']) == id(g)
True
The above does make a kind of sense, when you remember that the globals() function returns a dict representing the current global symbol table, i.e. all the currently defined attributes (objects) in the global scope.

So when I said g = globals(), the variable g got created in the global scope; so when I next print g, it should contain g itself, i.e. g (a list) contains itself as a list item (of g).

But on further thought, it seems like this should depend on the order of the evaluation of the statement g = globals():

Case 1) If the variable g is created first (and hence the global symbol table now contains it), and if only after that is the globals() function called, and its return value assigned to g, then things should work as shown in the above interpreter output.

Case 2) But if the evaluation works in a different order, i.e. the globals() function is first called (before the variable g is created), then at this point its return value (the dict) should not contain the item with key 'g' (and value g), and it is this dict that should get assigned to the variable g. Hence when we print g, we should not see g again within it.

Considering the above output, it seems like Case 1 is what actually happens. Also, I realized that if the globals() function is returning a copy of the dict that represents the global state, the above output should not work. But it seems to be returning the original dict itself, as shown by this:
>>> id(g) == id(globals())
True
To explore this further, I thought of trying to create a similar self-referential structure, but without using globals():
lis = []
lis.append(1)
print 'lis:', lis
print 'id(lis):', id(lis)
lis.append(lis)
print 'lis:', lis
print 'id(lis):', id(lis)
print 'id(lis[1]):', id(lis[1])
print lis == lis[1]
print lis[1] == lis[1][1]
And the output again seems to indicate that the list lis now references itself, that is, contains itself as an item.

I then thought of testing my Python function to flatten an arbitrarily nested list, with the above definition of lis, as the input argument. As expected, it terminated with a run-time error about recursion limit exceeded. See the post linked in the previous sentence for the flatten function - and some variations on it, in the comments on that post.

I'll write more about this in a following post, after fixing the flatten function to handle this case. On first thought, the fix seems straightforward: at any level in the recursion, check if id(lis) == id(lis[i]) - for any i, and if so terminate with an error about this being a self-referential list - but I'll write and test it first, then blog the results.

The more interesting question is whether this is a known Python feature, or an undocumented one (seems unlikely), or a bug (unlikely), and also whether similar behavior exists in other languages. Interested to hear what others think / know about this.

Update:

I looked in the official Python Language Reference, at the Section 3. Data model:

https://docs.python.org/2/reference/datamodel.html

and saw this excerpt:

[ CPython implementation detail: CPython currently uses a reference-counting scheme with (optional) delayed detection of cyclically linked garbage, which collects most objects as soon as they become unreachable, but is not guaranteed to collect garbage containing circular references. ]

Not sure whether it is relevant to the topic at hand, since, on the one hand, it uses the words "cyclically linked", but on the other, it says "garbage collection".

The image at the top of the post is of an ouroboros, which is "ancient symbol depicting a serpent or dragon eating its own tail", according to Wikipedia. Sort of appropriate, I guess, because Python :)

- Vasudev Ram - Online Python and Linux training and programming

Dancing Bison Enterprises

Signup to hear about new products or services that I create.

Posts about Python  Posts about xtopdf

Contact Page

Sunday, April 26, 2015

pyvim, an experimental pure Python vim clone

By Vasudev Ram



Image

Saw this via Twitter:

pyvim, a pure Python vim clone, by Jonathan Slenders from Belgium.

It's new and experimental, so will not have a lot of features, and may have some bugs.

I tried it out briefly after installing it with:
pip install pyvim
(That's all there is to it. It's location even got added to my PATH.)

Here is a screenshot of me editing a file in pyvim:

Image

And here is a screenshot of running pyvim without specifying a filename, i.e. editing a new file (same image as the one at the top of this post, except that the one at the top links to the pyvim site on Github):

Image

The really interesting thing about the editor being written in Python, is that, as they say, it may later be possible to script the editor in Python:

"Further, when the project develops, it should also become possible to write extensions in Python, and use Python as a scripting language. (Instead of vimscript, for instance.)"

Speaking of vim, if you are new to vim or vi (vim's predecessor), you may like to check out my vi quickstart tutorial, first published in Linux For You magazine. I first wrote the tutorial at the request of some Windows sysadmin friends who were transitioning to Linux, and they told me that it helped them to come up to speed with vi quickly, for basic text editing tasks. I then sent it to Linux For You as an article proposal and they published it.

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new products or services that I create.

Posts about Python  Posts about xtopdf

Contact Page

Sunday, April 19, 2015

asciiflow.com: Draw flowcharts online, in ASCII

By Vasudev Ram


Image

Saw this today: asciiflow.com

asciiflow.com is a site that allows you to draw flowcharts online, on their site, using the metaphor of a drag-and-drop paint program like MS Paint, but the flowcharts are drawn entirely using ASCII characters.

I tried it out a bit. Innovative.

One point is that to save the flowchart, it requires access to your Google Drive account.

The image at the top of this page, is of a flowchart that I created with asciiflow.com. I did not use the Save feature, but instead took a screenshot and saved it as a PNG file (using MS Paint, ha ha). The flowchart shows a diagram that illustrates the concept of a UNIX command pipeline, where the standard output of a preceding program becomes the standard input of a succeeding one (in the pipeline). (How's that for using web-based and Windows software to illustrate something about UNIX? :)

For another example of the innovative use of ASCII characters, check out this post I wrote somewhat recently, about the Python library called PrettyTable, which lets you generate visually appealing tables of data, bordered and boxed by ASCII characters:

PrettyTable to PDF is pretty easy with xtopdf

Also, since we're talking about standard input and output and UNIX pipelines, these two posts may be of interest:

1) [xtopdf] PDFWriter can create PDF from standard input

(The post at the above link also has an example of eating your own dog food.)

2) Print selected text pages to PDF with Python, selpg and xtopdf on Linux

Generalizing from a fragment of code in post 1) above, I'll also note that making a Python program usable as a component of a UNIX pipeline, can, in some cases, be as simple as having something like this in your code:
import sys
# ...
    for lin in sys.stdin:
        lin = process(lin)
        sys.stdout.write(lin)
which could be shortened to:
for lin in sys.stdin:
    sys.stdout.write(process(lin))
Due to this (being able to easily make a Python program into a component of a UNIX pipeline), you can do things like this (and more):

$ foo | bar | baz

where foo may be a built-in UNIX command (a filter) or a shell script, bar may be (for example) a Perl program that leverages some powerful Perl features, and baz may be a Python program that leverages some powerful Python features, thereby leveraging the UNIX philosophy concept of writing small programs, each of which do one thing well, or in this case, leveraging the features of different languages (each of which may do some things better than others), to write individual components in those respective languages. The possibilities are limitless ...

- Enjoy.

- Vasudev Ram - Online Python and Linux training;
freelance Python programming

Dancing Bison Enterprises

Signup to hear about new software products that I create.

Posts about Python  Posts about xtopdf

Contact Page

Friday, April 10, 2015

A four line Python quine

By Vasudev Ram



Image

Something that happened today made me think of writing a quine, in Python.

A four line Python quine;
how's that for a rhyme?
# Not so good.

A four line Python quine;
Yes, this one is mine.
# Ah, better.

A four line Python quine;
Sure, this too is mine.
# So-so.

A four line Python quine;
Can you stretch that to nine?
# It may not be worth my time.

A four line Python quine;
Hello, sir, rise and shine!

Of course, since the quine prints itself (by definition) when run, I don't need to show the code separately from the output:
$ python quine.py
import sys
with open(sys.argv[0]) as program:
    for line in program:
        sys.stdout.write(line)
Let's check that it works right:
$ python quine.py > pq.py
$ fc /l quine.py pq.py
Comparing files quine.py and PQ.PY
FC: no differences encountered
The quine could be shortened to:
import sys
with open(sys.argv[0]) as p:
    for l in p:
        sys.stdout.write(l)
I'm sure someone can come up with a shorter quine; is it thine? but this was my first time writing one, and I had fun :)

- Enjoy.

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new products or services from me.

Posts about Python  Posts about xtopdf

Contact Page

Monday, March 30, 2015

dunderdoc, a simple Python introspection utility

By Vasudev Ram

Image

While browsing Python documentation, I came up with the idea of this small Python introspection utility.

It prints the __doc__ attribute (the docstring) of each item in a list of names given as argument to it. So I called the function 'dunderdoc()' - because it is an informal convention in the Python community to call attributes such as __name__, that begin and end with a double underscore, dunder-name, and so on.

Here is the code for dunderdoc.py:

"""
dunderdoc.py
A Python function to print the .__doc__ attribute (i.e. the docstring) 
of each item in a list of names given as the argument.
The function is called dunderdoc because it is an informal convention 
in the Python community to call attributes such as __name__, that begin 
and end with a double underscore, dunder-name, and so on.
Author: Vasudev Ram - http://www.dancingbison.com
Copyright 2015 Vasudev Ram
"""

def dunderdoc(names):
    for name in names:
        print '-' * 72
        print name + '.__doc__:'
        print eval(name).__doc__
    print '-' * 72

# Call dunderdoc() on some basic objects:

a = 1 # an integer
b = 'abc' # a string
c = False # a boolean
d = () # a tuple
e = [] # a list
f = {} # a dict
g = set() # a set

dunderdoc(('a', 'b', 'c', 'd', 'e', 'f', 'g'))

# Call dunderdoc() on some user-defined objects:

class Foo(object):
    """
    A class that implements Foo instances.
    """

def bar(args):
    """
    A function that implements bar functionality.
    """

dunderdoc(['Foo', 'bar'])

And here is the output of running dunderdoc.py with the example calls to the dunderdoc() function:
------------------------------------------------------------------------
a.__doc__:
int(x=0) -> int or long
int(x, base=10) -> int or long

Convert a number or string to an integer, or return 0 if no arguments
are given.  If x is floating point, the conversion truncates towards zero.
If x is outside the integer range, the function returns a long instead.

If x is not a number or if base is given, then x must be a string or
Unicode object representing an integer literal in the given base.  The
literal can be preceded by '+' or '-' and be surrounded by whitespace.
The base defaults to 10.  Valid bases are 0 and 2-36.  Base 0 means to
interpret the base from the string as an integer literal.
>>> int('0b100', base=0)
4
------------------------------------------------------------------------
b.__doc__:
str(object='') -> string

Return a nice string representation of the object.
If the argument is a string, the return value is the same object.
------------------------------------------------------------------------
c.__doc__:
bool(x) -> bool

Returns True when the argument x is true, False otherwise.
The builtins True and False are the only two instances of the class bool.
The class bool is a subclass of the class int, and cannot be subclassed.
------------------------------------------------------------------------
d.__doc__:
tuple() -> empty tuple
tuple(iterable) -> tuple initialized from iterable's items

If the argument is a tuple, the return value is the same object.
------------------------------------------------------------------------
e.__doc__:
list() -> new empty list
list(iterable) -> new list initialized from iterable's items
------------------------------------------------------------------------
f.__doc__:
dict() -> new empty dictionary
dict(mapping) -> new dictionary initialized from a mapping object's
    (key, value) pairs
dict(iterable) -> new dictionary initialized as if via:
    d = {}
    for k, v in iterable:
        d[k] = v
dict(**kwargs) -> new dictionary initialized with the name=value pairs
    in the keyword argument list.  For example:  dict(one=1, two=2)
------------------------------------------------------------------------
g.__doc__:
set() -> new empty set object
set(iterable) -> new set object

Build an unordered collection of unique elements.
------------------------------------------------------------------------
------------------------------------------------------------------------
Foo.__doc__:

    A class that implements Foo instances.
    
------------------------------------------------------------------------
bar.__doc__:

    A function that implements bar functionality.
    
------------------------------------------------------------------------

The image at the top of the post is of Auguste Rodin's Le Penseur (The Thinker).

- Enjoy.

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new products that I create.

Posts about Python  Posts about xtopdf

Contact Page

Friday, March 27, 2015

Which which is which?

By Vasudev Ram

Recently I had blogged about which.py, a simple Python program that I wrote, here:

A simple UNIX-like 'which' command in Python

I also posted the same program on ActiveState Code:

A UNIX-like "which" command for Python (Python recipe)

A reader there, Hongxu Chen, pointed out that my which.py actually implemented the variant "which -a", that is, the UNIX which with the -a (or -all) option included. This variant displays not just the first full pathname of an occurrence of the searched-for name in the PATH (environment variable), but all such occurrences, in any directory in the PATH. That was not what I had intended. It was a bug. I had intended it to only show the first occurrence.

So I rewrote the program to fix that bug, and also implemented the -a option properly - i.e. when -a (or its long form, --all, is given, find all occurrences, otherwise only find the first. Here is the new version:
from __future__ import print_function

# which.py
# A minimal version of the UNIX which utility, in Python.
# Also implements the -a or --all option.
# Author: Vasudev Ram - www.dancingbison.com
# Copyright 2015 Vasudev Ram - http://www.dancingbison.com

import sys
import os
import os.path
import stat

def usage():
    sys.stderr.write("Usage: python which.py [ -a | --all ] name ...\n") 
    sys.stderr.write("or: which.py [ -a | --all ] name ...\n") 

def which(name, all):
    for path in os.getenv("PATH").split(os.path.pathsep):
        full_path = path + os.sep + name
        if os.path.exists(full_path):
            print(full_path)
            if not all:
                break

def main():
    if len(sys.argv) < 2:
        usage()
        sys.exit(1)
    if sys.argv[1] in ('-a', '--all'):
        # Print all matches in PATH.
        for name in sys.argv[2:]:
            which(name, True)
    else:
        # Stop after printing first match in PATH.
        for name in sys.argv[1:]:
            which(name, False)

if "__main__" == __name__:
        main()
I tested it some and it seems to be working okay both with and without the -a option now. After more testing, I'll upload it to my Bitbucket account.

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new software or info products that I create.

Posts about Python  Posts about xtopdf

Contact Page

Friday, March 20, 2015

A simple UNIX-like "which" command in Python

By Vasudev Ram



Image

UNIX users are familiar with the which command. Given an argument called name, it checks the system PATH environment variable, to see whether that name exists (as a file) in any of the directories specified in the PATH. (The directories in the PATH are colon-separated on UNIX and semicolon-separated on Windows.)

I'd written a Windows-specific version of the which command some time ago, in C.

Today I decided to write a simple version of the which command in Python. In the spirit of YAGNI and incremental development, I tried to resist the temptation to add more features too early; but I did give in once and add the exit code stuff near the end :)

Here is the code for which.py:
from __future__ import print_function

# which.py
# A minimal version of the UNIX which utility, in Python.
# Author: Vasudev Ram - www.dancingbison.com
# Copyright 2015 Vasudev Ram - http://www.dancingbison.com

import sys
import os
import os.path
import stat

def usage():
    sys.stderr.write("Usage: python which.py name\n") 
    sys.stderr.write("or: which.py name\n") 

def which(name):
    found = 0 
    for path in os.getenv("PATH").split(os.path.pathsep):
        full_path = path + os.sep + name
        if os.path.exists(full_path):
            """
            if os.stat(full_path).st_mode & stat.S_IXUSR:
                found = 1
                print(full_path)
            """
            found = 1
            print(full_path)
    # Return a UNIX-style exit code so it can be checked by calling scripts.
    # Programming shortcut to toggle the value of found: 1 => 0, 0 => 1.
    sys.exit(1 - found)

def main():
    if len(sys.argv) != 2:
        usage()
        sys.exit(1)
    which(sys.argv[1])

if "__main__" == __name__:
        main()
And here are a few examples of using the command:

(Note: the tests are done on Windows, though the command prompt is a $ sign (UNIX default); I just set it to that because I like $'s and UNIX :)

$ which vim
\vim

$ which vim.exe
C:\Ch\bin\vim.exe

$ set PATH | grep -i vim73

$ addpath c:\vim\vim73

$ which.py vim.exe
C:\Ch\bin\vim.exe

c:\vim\vim73\vim.exe
$ which metapad.exe
C:\util\metapad.exe

$ which pscp.exe
C:\util\pscp.exe
C:\Ch\bin\pscp.exe

$ which dostounix.exe
C:\util\dostounix.exe

$ which pythonw.exe
C:\Python278\pythonw.exe
D:\Anaconda-2.1.0-64\pythonw.exe

# Which which is which? All four combinations:

$ which which
.\which

$ which.py which
.\which

$ which which.py
.\which.py

$ which.py which.py
.\which.py

As you can see, calling the which Python command with different arguments, gives various results, including sometimes finding one instance of vim.exe and sometimes two instances, depending on the values in the PATH variable (which I changed, using my addpath.bat script, to add the \vim\vim73 directory to it).

Also, it works when invoked either as which.py or just which.

I'll discuss my interpretation of these variations in an upcoming post - including a variation that uses os.stat(full_path).st_mode - see the commented part of the code under the line:

if os.path.exists(full_path):

Meanwhile, did you know that YAGNI was written about much before agile was a thing? IIRC, I've seen it described in either Kernighan and Ritchie (The C Programming Language) or in Kernighan and Pike (The UNIX Programming Environment). It could be possibly be older than that, say from the mainframe era.

Finally, as I was adding labels to this blog post, Blogger showed me "pywhich" as a label, after I typed "which" in the labels box. That reminded me that I had written another post earlier about a Python which utility (not by me), so I found it on my blog by typing in this URL:

http://jugad2.blogspot.in/search/label/pywhich

which finds all posts on my blog with the label 'pywhich' (and the same approach works for any other label); the resulting post is:

pywhich, like the Unix which tool, for Python modules.

- Enjoy.

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new products that I create.

Posts about Python  Posts about xtopdf

Contact Page

Wednesday, March 11, 2015

ASCII Table to PDF with xtopdf

By Vasudev Ram

Recently, I had the need for an ASCII table lookup, which I searched for and found, thanks to the folks here:

www.ascii-code.com

That gave me the idea of writing a simple program to generate an ASCII table in PDF. Here is the code for a part of that table - the first 32 (0 to 31) ASCII characters, which are the control characters:

# ASCIITableToPDF.py
# Author: Vasudev Ram - http://www.dancingbison.com
# Demo program to show how to generate an ASCII table as PDF,
# using the xtopdf toolkit for PDF creation from Python.
# Generates a PDF file with information about the 
# first 32 ASCII codes, i.e. the control characters.
# Based on the ASCII Code table at http://www.ascii-code.com/

import sys
from PDFWriter import PDFWriter

# Define the header information.
column_names = ['DEC', 'OCT', 'HEX', 'BIN', 'Symbol', 'Description']
column_widths = [4, 6, 4, 10, 7, 20]

# Define the ASCII control character information.
ascii_control_characters = \
"""
0    000    00    00000000    NUL    �         Null char
1    001    01    00000001    SOH             Start of Heading
2    002    02    00000010    STX             Start of Text
3    003    03    00000011    ETX             End of Text
4    004    04    00000100    EOT             End of Transmission
5    005    05    00000101    ENQ             Enquiry
6    006    06    00000110    ACK             Acknowledgment
7    007    07    00000111    BEL             Bell
8    010    08    00001000    BS             Back Space
9    011    09    00001001    HT    	         Horizontal Tab
10    012    0A    00001010    LF    
         Line Feed
11    013    0B    00001011    VT             Vertical Tab
12    014    0C    00001100    FF             Form Feed
13    015    0D    00001101    CR    
         Carriage Return
14    016    0E    00001110    SO             Shift Out / X-On
15    017    0F    00001111    SI             Shift In / X-Off
16    020    10    00010000    DLE             Data Line Escape
17    021    11    00010001    DC1             Device Control 1 (oft. XON)
18    022    12    00010010    DC2             Device Control 2
19    023    13    00010011    DC3             Device Control 3 (oft. XOFF)
20    024    14    00010100    DC4             Device Control 4
21    025    15    00010101    NAK             Negative Acknowledgement
22    026    16    00010110    SYN             Synchronous Idle
23    027    17    00010111    ETB             End of Transmit Block
24    030    18    00011000    CAN             Cancel
25    031    19    00011001    EM             End of Medium
26    032    1A    00011010    SUB             Substitute
27    033    1B    00011011    ESC             Escape
28    034    1C    00011100    FS             File Separator
29    035    1D    00011101    GS             Group Separator
30    036    1E    00011110    RS             Record Separator
31    037    1F    00011111    US             Unit Separator
"""

# Create and set some of the fields of a PDFWriter instance.
pw = PDFWriter("ASCII-Table.pdf")
pw.setFont("Courier", 12)
pw.setHeader("ASCII Control Characters - 0 to 31")
pw.setFooter("Generated by xtopdf: http://slid.es/vasudevram/xtopdf")

# Write the column headings to the output.
column_headings = [ str(val).ljust(column_widths[idx]) \
    for idx, val in enumerate(column_names) ]
pw.writeLine(' '.join(column_headings))

# Split the string into lines, omitting the first and last empty lines.
for line in ascii_control_characters.split('\n')[1:-1]:

    # Split the line into space-delimited fields.
    lis = line.split()

    # Join the words of the Description back into one field, 
    # since it was split due to having internal spaces.
    lis2 = lis[0:5] + [' '.join(lis[6:])]

    # Write the column data to the output.
    lis3 = [ str(val).ljust(column_widths[idx]) \
        for idx, val in enumerate(lis2) ]
    pw.writeLine(' '.join(lis3))

pw.close()
Discerning readers will notice the effect of some of the said control characters on the displayed program code :)

You can run the program with:
python ASCIITableToPDF.py
or
py ASCIITableToPDF.py
or
./ASCIITableToPDF.py
or
ASCIITableToPDF.py
Figuring what needs to be done for each of the above methods of invocation to work, is (as they say in computer textbooks), left as an exercise for the reader :)

(There is a bit of subtlety involved, at least for beginners, particularly if you want to do it on both Linux and Windows.)

And here is a screenshot of the PDF output of the program:

Image

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new products or services from me.

Posts about Python  Posts about xtopdf

Contact Page

Saturday, March 7, 2015

PDFCrowd and its HTML to PDF API (for Python and other languages)

By Vasudev Ram


PDFcrowd is a web service that I came across recently. It allows users to convert HTML content to PDF. This can be done both via the PDFcrowd site - by entering either the content or the URL of an HTML page to be converted to PDF - or via the PDFcrowd API, which has support for multiple programming languages, including for Python. I tried multiple approaches, and all worked fairly well.

A slightly modified version of a simple PDFcrowd API example from their site, is shown below.

# Demo program to show how to use the PDFcrowd API
# to convert HTML content to PDF.
# Author: Vasudev Ram - www.dancingbison.com

import pdfcrowd

try:
    # create an API client instance
    # Dummy credentials used; to actually run the program, enter your own.
    client = pdfcrowd.Client("user_name", "api_key")
    client.setAuthor('author_name')
    # Dummy credentials used; to actually run the program, enter your own.
    client.setUserPassword('user_password')

    # Convert a web page and store the generated PDF in a file.
    pdf = client.convertURI('http://www.dancingbison.com')
    with open('dancingbison.pdf', 'wb') as output_file:
        output_file.write(pdf)
    
    # Convert a web page and store the generated PDF in a file.
    pdf = client.convertURI('http://jugad2.blogspot.in/p/about-vasudev-ram.html')
    with open('jugad2-about-vasudevram.pdf', 'wb') as output_file:
        output_file.write(pdf)

    # convert an HTML string and save the result to a file
    output_file = open('html.pdf', 'wb')
    html = "My Small HTML File
"
    client.convertHtml(html, output_file)
    output_file.close()

except pdfcrowd.Error, why:
    print 'Failed:', why
I used three calls to the API. For the first two calls, the inputs were: 1) my web site, 2) the about page of my blog.

Screenshots of the results of those two calls are below. You can see that they correspond closely to the originals.

Screenshot of generated PDF of dancingbison.com site


Image

Screenshot of generated PDF of About Vasudev Ram page on jugad2.blogspot.com blog


Image

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new Python or PDF related products created by me.

Posts about Python  Posts about xtopdf

Contact Page

Sunday, March 1, 2015

pip now installed with Python 2.7.9

By Vasudev Ram


In Python 2.7.9, pip (the Python package installer tool) will now be installed automatically.

Read it via a tweet and then verified it via this link:

Installing Python Modules

and also this one:

pip included with Python

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new products or services from me.

Posts about Python  Posts about xtopdf

Contact Page


Wednesday, February 25, 2015

Publish SQLite data to PDF using named tuples

By Vasudev Ram

Image

Some time ago I had written this post:

Publishing SQLite data to PDF is easy with xtopdf.

It showed how to get data from an SQLite (Wikipedia) database and write it to PDF, using xtopdf, my open source PDF creation library for Python.

Today I was browsing the Python standard library docs, and so thought of modifying that program to use the namedtuple data type from the collections module of Python, which is described as implementing "High-performance container datatypes". The collections module was introduced in Python 2.4.
Here is a modified version of that program, SQLiteToPDF.py, called SQLiteToPDFWithNamedTuples.py, that uses named tuples:
# SQLiteToPDFWithNamedTuples.py
# Author: Vasudev Ram - http://www.dancingbison.com
# SQLiteToPDFWithNamedTuples.py is a program to demonstrate how to read 
# SQLite database data and convert it to PDF. It uses the Python
# data structure called namedtuple from the collections module of 
# the Python standard library.

from __future__ import print_function
import sys
from collections import namedtuple
import sqlite3
from PDFWriter import PDFWriter

# Helper function to output a string to both screen and PDF.
def print_and_write(pw, strng):
    print(strng)
    pw.writeLine(strng)

try:

    # Create the stocks database.
    conn = sqlite3.connect('stocks.db')
    # Get a cursor to it.
    curs = conn.cursor()

    # Create the stocks table.
    curs.execute('''DROP TABLE IF EXISTS stocks''')
    curs.execute('''CREATE TABLE stocks
                 (date text, trans text, symbol text, qty real, price real)''')

    # Insert a few rows of data into the stocks table.
    curs.execute("INSERT INTO stocks VALUES ('2006-01-05', 'BUY', 'RHAT', 100, 25.1)")
    curs.execute("INSERT INTO stocks VALUES ('2007-02-06', 'SELL', 'ORCL', 200, 35.2)")
    curs.execute("INSERT INTO stocks VALUES ('2008-03-07', 'HOLD', 'IBM', 300, 45.3)")
    conn.commit()

    # Create a namedtuple to represent stock rows.
    StockRecord = namedtuple('StockRecord', 'date, trans, symbol, qty, price')

    # Run the query to get the stocks data.
    curs.execute("SELECT date, trans, symbol, qty, price FROM stocks")

    # Create a PDFWriter and set some of its fields.
    pw = PDFWriter("stocks.pdf")
    pw.setFont("Courier", 12)
    pw.setHeader("SQLite data to PDF with named tuples")
    pw.setFooter("Generated by xtopdf - https://bitbucket.org/vasudevram/xtopdf")

    # Write header info.
    hdr_flds = [ str(hdr_fld).rjust(10) + " " for hdr_fld in StockRecord._fields ]
    hdr_fld_str = ''.join(hdr_flds)
    print_and_write(pw, '=' * len(hdr_fld_str))
    print_and_write(pw, hdr_fld_str)
    print_and_write(pw, '-' * len(hdr_fld_str))

    # Now loop over the fetched data and write it to PDF.
    # Map the StockRecord namedtuple's _make class method
    # (that creates a new instance) to all the rows fetched.
    for stock in map(StockRecord._make, curs.fetchall()):
        row = [ str(col).rjust(10) + " " for col in (stock.date, \
        stock.trans, stock.symbol, stock.qty, stock.price) ]
        # Above line can instead be written more simply as:
        # row = [ str(col).rjust(10) + " " for col in stock ]
        row_str = ''.join(row)
        print_and_write(pw, row_str)

    print_and_write(pw, '=' * len(hdr_fld_str))

except Exception as e:
    print("ERROR: Caught exception: " + e.message)
    sys.exit(1)

finally:
    pw.close()
    conn.close()

This time I've imported print_function so that I can use print as a function instead of as a statement.

Here's a screenshot of the PDF output in Foxit PDF Reader:

Image

- Vasudev Ram - Online Python training and programming

Dancing Bison Enterprises

Signup to hear about new products or services from me.

Posts about Python  Posts about xtopdf

Contact Page