Re: Code critique please

2015-04-09 Thread Peter Otten
kai.pet...@gmail.com wrote:

> I just wrote this bit (coming from Pascal) 

> if (((xdim / 8) * ydim) + header) <> filesize:

Yeah, either Pascal or Barry Warsaw is your uncle ;)

https://www.python.org/dev/peps/pep-0401/

> and am wondering how seasoned
> Python programmers would have done the same? Anything terribly non-python?

> def RenderByte(draw, byte, x, y):

Please read PEP 8 for naming conventions etc.

The function at the core of your code

> def RenderByte(draw, byte, x, y):
> 
> blist = list(bin(byte).lstrip('0b')) # turn byte into list with 8
> elements,
> c = 0# each representing one bit
> for bit in blist:
> if bit:
> draw.point((x + c, y), fcolor)
> 
> c += 1
> return

can be fixed/micro-optimised, and if I were to do that I'd precreate a 
lookup table that maps every byte (i. e. value in the range 0...255) to a 
sequence of offsets 

lookup = [
(),  # for b"\x00" the inner loop is empty
(0),
(1),
(0, 1),
...
(0, 1, 2, 3, 4, 5, 6, 7), # for b"\xFF" the inner loop comprises 
  # all 8 bits
]
or to a 8x1 image, but my idea of a "seasoned Python programmer" will try to 
keep the big picture in mind -- and that is that handling individual 
bits/pixels in Python is inefficient. Therefore many libraries tend to offer 
an alternative that is both easier to use and faster.

In this case that's

   img = Image.frombytes("1", (width, height), data)
 
and with the extra comfort of reading the size from the EPD file

from PIL import Image
import struct

EPDFILE = "tmp.epd"
PNGFILE = "tmp.png"

class EPDError(Exception):
pass

with open(EPDFILE, "rb") as f:
header = f.read(16)
width, height, colordepth = struct.unpack("http://www.pervasivedisplays.com/_literature_112691/Developer_Guide_for_Demo_Kit

PS: I thought that Image.frombytes() was already pointed out to you, but I 
failed to find it in the archives. So there.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Code critique please

2015-04-08 Thread Jean-Michel Pichavant
- Original Message -
> From: "kai peters" 
> To: python-list@python.org
> Sent: Wednesday, 8 April, 2015 12:43:23 AM
> Subject: Code critique please
> 
> I just wrote this bit (coming from Pascal) and am wondering how
> seasoned Python programmers would have done the same? Anything
> terribly non-python?
> 
> As always, thanks for all input.
> 
> K
> 
> 
> 
> """
>  Creates a PNG image from EPD file
> """
> 
> import os, sys
> from PIL import Image, ImageFont, ImageDraw
> 
> #
> -
> def RenderByte(draw, byte, x, y):
> 
> blist = list(bin(byte).lstrip('0b')) # turn byte into list with 8
> elements,
> c = 0# each representing one bit
> for bit in blist:
> if bit:
> draw.point((x + c, y), fcolor)
> 
> c += 1
> return
> 
> #

Apart from what has been already said, you could rewrite your function 
RenderByte this way (untested):

def render_byte(draw, byte, x, y):
  for point in [(x+c, y) for (c, bit) in enumerate(bin(byte)[2:]) if int(bit)]:
draw.point(point, fcolor)


it involves important notions in the python language:
  - list comprehension, this is the  [...] part, where it combines filtering a 
list and applying a function to the values
  - slicing, bin(byte)[2:] returning the sequence stripped from its 2 first 
elements

Additional remarks : 
  - is fcolor defined ?
  - your test "if bit:" was probably wrong as it was testing either "0" or "1" 
which are both evaluated to True. In other words, bool("0") == True, bool(0) == 
False

Cheers,

JM


-- IMPORTANT NOTICE: 

The contents of this email and any attachments are confidential and may also be 
privileged. If you are not the intended recipient, please notify the sender 
immediately and do not disclose the contents to any other person, use it for 
any purpose, or store or copy the information in any medium. Thank you.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Code critique please

2015-04-08 Thread Robert Kern

On 2015-04-08 01:54, Mark Lawrence wrote:

On 07/04/2015 23:43, kai.pet...@gmail.com wrote:

I just wrote this bit (coming from Pascal) and am wondering how seasoned
Python programmers would have done the same? Anything terribly non-python?

As always, thanks for all input.

import os, sys
from PIL import Image, ImageFont, ImageDraw



As you've had plenty of answers I'll just say that PIL is pretty old now.  Are
you aware of the fork called Pillow? https://pillow.readthedocs.org/


Pillow uses the name "PIL" for its package name too, in the interest of being 
drop-in compatible.


https://pillow.readthedocs.org/porting-pil-to-pillow.html

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
 that is made terrible by our own mad attempt to interpret it as though it had
 an underlying truth."
  -- Umberto Eco

--
https://mail.python.org/mailman/listinfo/python-list


Re: Code critique please

2015-04-07 Thread Mark Lawrence

On 07/04/2015 23:43, kai.pet...@gmail.com wrote:

I just wrote this bit (coming from Pascal) and am wondering how seasoned Python 
programmers would have done the same? Anything terribly non-python?

As always, thanks for all input.

import os, sys
from PIL import Image, ImageFont, ImageDraw



As you've had plenty of answers I'll just say that PIL is pretty old 
now.  Are you aware of the fork called Pillow? 
https://pillow.readthedocs.org/


--
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

--
https://mail.python.org/mailman/listinfo/python-list


Re: Code critique please

2015-04-07 Thread kai . peters
On Tuesday, 7 April 2015 15:43:44 UTC-7, kai.p...@gmail.com  wrote:
> I just wrote this bit (coming from Pascal) and am wondering how seasoned 
> Python programmers would have done the same? Anything terribly non-python?
> 
> As always, thanks for all input.
> 
> K
> 
> 
> 
> """
>  Creates a PNG image from EPD file
> """
> 
> import os, sys
> from PIL import Image, ImageFont, ImageDraw
> 
> # 
> -
> def RenderByte(draw, byte, x, y):
> 
> blist = list(bin(byte).lstrip('0b')) # turn byte into list with 8 
> elements, 
> c = 0# each representing one bit
> for bit in blist:   
> if bit:
> draw.point((x + c, y), fcolor)
> 
> c += 1
> return
> 
> # 
> -
> def EPD_2_Image(edpfilename, imagefilename):
> 
> # get out of here if EPD file not present
> if not os.path.isfile(epdfilename):
> print 'file not found: ' + edpfilename
> return
> 
> # is this a valid EPD file?
> filesize = os.path.getsize(epdfilename)
> if (((xdim / 8) * ydim) + header) <> filesize:
> print 'incorrect file size: ' + edpfilename
> return
> 
> # blow old destination file away 
> if os.path.isfile(imagefilename):
> print 'deleting old dest. file: ' + imagefilename
> os.remove(imagefilename)
> 
> print 'processing...'
> 
> # set up PIL objects
> img  = Image.new('1', (xdim, ydim), bcolor)   # '1' = Bi-tonal image
> draw = ImageDraw.Draw(img)
> 
> # read entire EPD file into byte array (without the header)
> content = bytearray(open(epdfilename, 'rb').read())[16:] 
>  
> # image coord origin at top/left according to PIL documentation
> pos = 0
> for y in range(ydim): 
> x = 0
> for byte in range(xdim / 8):   # 8 pixels 'stuffed' into one byte
> RenderByte(draw, content[pos], x, y)
> pos += 1   
> x   += 8
> 
> img.save(imagefilename)   # format is inferred from given extension
> print 'done.'
> 
> return
> # 
> -
> 
> xdim   = 1024
> ydim   = 1280
> header = 16
> black  = 0
> white  = 1
> bcolor = black
> fcolor = white
> 
> epdfilename   = 'c:\\temp\\drawtest2.epd'
> imagefilename = 'c:\\temp\\drawtest2.png'
> 
> EPD_2_Image(epdfilename, imagefilename)


Thanks for taking the time to give such detailed suggestions - very much 
appreciated!

K
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Code critique please

2015-04-07 Thread Cameron Simpson

On 07Apr2015 15:43, kai.pet...@gmail.com  wrote:

I just wrote this bit (coming from Pascal) and am wondering how seasoned Python 
programmers would have done the same? Anything terribly non-python?

As always, thanks for all input.
K

"""
Creates a PNG image from EPD file
"""

import os, sys
from PIL import Image, ImageFont, ImageDraw

# -
def RenderByte(draw, byte, x, y):
   blist = list(bin(byte).lstrip('0b')) # turn byte into list with 8 elements,


Remark: .lstrip does not do what you think.
You want:

   blist = list(bin(byte)[2:]) # turn byte into list with 8 elements,

to skip over the leading "0b". Otherwise, with lstrip, consider what would 
happen with a low value byte, with multiple leading zeroes. (Actually, on 
reflection, you might get away with it - but probably not, and anyway would be 
fragile against changing the ordering of the bits.)


I'd be popping off the least or most siginificant bit myself with "&" and "<<" 
or ">>". It might be wordier, bit it would be more in keeping with the actual 
bitwise operations going on.



   c = 0# each representing one bit
   for bit in blist:
   if bit:
   draw.point((x + c, y), fcolor)
   c += 1


This might be more Pythonic written:

 for c, bit in enumerate(blist):

which will emit (0, b0), (1, b1) and so forth for bit 0, bit 1 etc (where bit 0 
is the leftmost from your list, etc). Avoids the "c = 0" and the "c += 1" and 
also makes your loop robust against adding control flows later which might skip 
the final "c += 1" at the end, even by accident.



   return


You generally do not need a trailing return with no value; it is implicit.


def EPD_2_Image(edpfilename, imagefilename):
   # get out of here if EPD file not present
   if not os.path.isfile(epdfilename):
   print 'file not found: ' + edpfilename
   return


Traditionally one would raise an exception instead of returning. Eg:

 if not os.path.isfile(epdfilename):
   raise ValueError("missing file: %r" % (epdfilename,))

and have the caller handle the issue. Similarly for all the other pre-checks 
below.


Also, it is normal for error messages to be directed to sys.stderr (this allows 
them to be logged independently of the program's normal output; for example the 
normal output might be sent to a file, but the error messages would continue to 
be displayed on screen). So were you to iussue a print statement (instead of an 
exception) you would write:


 print >>sys.stderr, 

or in Python 3:

 print(, file=sys.stderr)


   # is this a valid EPD file?
   filesize = os.path.getsize(epdfilename)
   if (((xdim / 8) * ydim) + header) <> filesize:
   print 'incorrect file size: ' + edpfilename
   return

   # blow old destination file away
   if os.path.isfile(imagefilename):
   print 'deleting old dest. file: ' + imagefilename
   os.remove(imagefilename)

   print 'processing...'

   # set up PIL objects
   img  = Image.new('1', (xdim, ydim), bcolor)   # '1' = Bi-tonal image
   draw = ImageDraw.Draw(img)

   # read entire EPD file into byte array (without the header)
   content = bytearray(open(epdfilename, 'rb').read())[16:]

   # image coord origin at top/left according to PIL documentation
   pos = 0
   for y in range(ydim):
   x = 0
   for byte in range(xdim / 8):   # 8 pixels 'stuffed' into one byte
   RenderByte(draw, content[pos], x, y)
   pos += 1
   x   += 8

   img.save(imagefilename)   # format is inferred from given extension
   print 'done.'

   return


Again, this "return" can be implicit.


# -

xdim   = 1024
ydim   = 1280
header = 16
black  = 0
white  = 1
bcolor = black
fcolor = white

epdfilename   = 'c:\\temp\\drawtest2.epd'
imagefilename = 'c:\\temp\\drawtest2.png'


Normally these values would be at the top of your program, and named in 
UPPER_CASE to indicate that they are like "constants" in other languages. So 
you might put this:


 XDIM   = 1024
 YDIM   = 1280
 HEADER_SIZE = 16
 BLACK  = 0
 WHITE  = 1
 BCOLOR = BLACK
 FCOLOR = WHITE

 EPD_FILENAME   = 'c:\\temp\\drawtest2.epd'
 IMAGE_FILENAME = 'c:\\temp\\drawtest2.png'

at the top of the script.

I notice you have a bare [16:] in your "content =" line. Should that not say 
"[HEADER_SIZE:]" ?



EPD_2_Image(epdfilename, imagefilename)


I tend to write things like this as thought they could become python modules 
for reuse. (Often they do; why write something twice?)


So the base of the script becomes like this:

if __name__ == '__main__':
 EPD_2_Image(EPD_FILENAME, IMAGE_FILENAME)

In this way, when you invoke the .py file directly __name__ is "__main__" and 
your function gets run. But it you move this all into a module which may be 
imported, __name__ will be the module name, an so not invoke the main function.  
The importing code can then do so as i

Re: Code critique please

2015-04-07 Thread Chris Kaynor
On Tue, Apr 7, 2015 at 3:43 PM,   wrote:
> I just wrote this bit (coming from Pascal) and am wondering how seasoned 
> Python programmers would have done the same? Anything terribly non-python?
>
> As always, thanks for all input.
>
> K
>
>
>
> """
>  Creates a PNG image from EPD file
> """
>
> import os, sys
> from PIL import Image, ImageFont, ImageDraw
>
> # 
> -
> def RenderByte(draw, byte, x, y):
>
> blist = list(bin(byte).lstrip('0b')) # turn byte into list with 8 
> elements,

A couple of comments on this line: lstrip strips based on characters,
and even without that, the 8 elements comment is not correct. bin()
only returns enough to hold the value without leading zeros, and the
lstrip will remove any leading zeros, even if it did produce them.

Additionally, if byte is outside the [0, 255] range, bin could produce
more than 8 elements. Your loop will work in any case, but it may
cause incorrect behavior, and in any case, the comment is wrong.

> c = 0# each representing one bit
> for bit in blist:
> if bit:
> draw.point((x + c, y), fcolor)
>
> c += 1

Rather than keeping a manual counter, this could be better written
using enumerate:

for c, bit in enumerate(blist):
if bit:
draw.point((x + c, y), fcolor)

> return

This return is unneeded. If a function falls off the end, it
implicitly has a bare "return" at its end. Note that a bare return (or
falling off the end) will cause the function to return None (all
functions have a return value).

>
> # 
> -
> def EPD_2_Image(edpfilename, imagefilename):
>
> # get out of here if EPD file not present
> if not os.path.isfile(epdfilename):
> print 'file not found: ' + edpfilename
> return
>
> # is this a valid EPD file?
> filesize = os.path.getsize(epdfilename)
> if (((xdim / 8) * ydim) + header) <> filesize:
> print 'incorrect file size: ' + edpfilename
> return

Both of these would probably be better as exceptions, rather than
prints. When running the function via a batch script, you can always
catch the exception and do something with it, while with a print, the
caller will have a hard time determining whether the function worked
or not. This could be important if you ever try to wrap this function
into a GUI (you may want a dialog rather than a command prompt
textural error, on stdout no less), or call the function with
batching, where you may want to report the failures via other means
(collect them all and include them in an e-mail report, for example).

For example, "raise OSError('file not found' + edpfilename)". Also, in
Python, the perfered dogma is "better to ask forgiveness than
permission" (aka, try the operation and let it fail if invalid),
rather than "look before you leap" (validate correct inputs, and fail
early). Basically, in this case, you could just remove the first check
(the second is probably worthwhile), and let the getsize fail if the
file does not exist.

Raising the exceptions will play better with batching (its easier to
detect errors and report them en-mass after processing). Avoiding LBYL
is generally useful for files in case other processes mess with them
after your check.

>
> # blow old destination file away
> if os.path.isfile(imagefilename):
> print 'deleting old dest. file: ' + imagefilename
> os.remove(imagefilename)

This is probably unneeded, and could cause issues with deleting the
file then failing out for various reasons. I generally prefer to leave
files intact until the last possible second. Thi sis nice if the code
fails for some reason.

>
> print 'processing...'
>
> # set up PIL objects
> img  = Image.new('1', (xdim, ydim), bcolor)   # '1' = Bi-tonal image
> draw = ImageDraw.Draw(img)
>
> # read entire EPD file into byte array (without the header)
> content = bytearray(open(epdfilename, 'rb').read())[16:]
>
> # image coord origin at top/left according to PIL documentation
> pos = 0
> for y in range(ydim):
> x = 0
> for byte in range(xdim / 8):   # 8 pixels 'stuffed' into one byte
> RenderByte(draw, content[pos], x, y)
> pos += 1
> x   += 8
>
> img.save(imagefilename)   # format is inferred from given extension
> print 'done.'
>
> return
> # 
> -
>
> xdim   = 1024
> ydim   = 1280
> header = 16
> black  = 0
> white  = 1
> bcolor = black
> fcolor = white

By convention, constants in Python are denoted by using all capital
letters with under scores.

>
> epdfilename   = 'c:\\temp\\drawtest2.epd'
> imagefilename = 'c:\\temp\\drawtest2.png'
>
> EPD_2_Image(epdfilename, imagefilename)
> --
> https://mail.python.org/mailman/listinfo/pyt

Re: Code critique please

2015-04-07 Thread Ian Kelly
On Tue, Apr 7, 2015 at 4:43 PM,   wrote:
> def RenderByte(draw, byte, x, y):

Python function and method names customarily use the
lowercase_with_underscores style.

> blist = list(bin(byte).lstrip('0b')) # turn byte into list with 8 
> elements,

There's no guarantee that the resulting list will have 8 elements
here. The result of bin() will use the minimum number of digits needed
to represent the value, which has nothing to do with the size of a
byte. If you want exactly 8, use str.zfill to add zeroes.

Also, lstrip('0b') will remove *all* occurrences of the characters '0'
and 'b' from the left of the string, not just the exact substring
'0b'. So for example, bin(0).lstrip('0b') would return the empty
string since all the characters in the string are either '0' or 'b'.

That said, all this string manipulation to convert from an int to a
list of bits smells a bit funky to me. I'd probably write a generator
to yield the bits from the number. Something like:

def bits(number, length=None):
if length is None:
length = number.bit_length()
for i in range(length):
yield (number >> i) & 1

Now you can iterate directly over bits(byte, 8), or if you really want
a list then you can call list(bits(byte, 8)).

> c = 0# each representing one bit
> for bit in blist:
> if bit:
> draw.point((x + c, y), fcolor)
>
> c += 1

Instead of incrementing c on each loop, use enumerate.

for c, bit in enumerate(blist):

> return

Not needed if you're not returning a value. It's perfectly okay to
just let execution "fall off" the end of the function.

> # get out of here if EPD file not present
> if not os.path.isfile(epdfilename):
> print 'file not found: ' + edpfilename

Recommend using print's function syntax for forward compatibility with Python 3:

print('file not found: ' + edpfilename)

Also consider doing "from __future__ import print_function" at the top
of the file so that print really is a function, although it doesn't
matter in this case.

> xdim   = 1024
> ydim   = 1280
> header = 16
> black  = 0
> white  = 1
> bcolor = black
> fcolor = white

Constants, particularly global ones, are conventionally
UPPERCASE_WITH_UNDERSCORES.

> EPD_2_Image(epdfilename, imagefilename)

If you use the construct

if __name__ == '__main__':
EPD_2_Image(epdfilename, imagefilename)

then the function will automatically be called when the file is
executed as a script, but it will also let you import the file from
other modules and call it on your own terms, should you ever desire to
do that.
-- 
https://mail.python.org/mailman/listinfo/python-list


Code critique please

2015-04-07 Thread kai . peters
I just wrote this bit (coming from Pascal) and am wondering how seasoned Python 
programmers would have done the same? Anything terribly non-python?

As always, thanks for all input.

K



"""
 Creates a PNG image from EPD file
"""

import os, sys
from PIL import Image, ImageFont, ImageDraw

# -
def RenderByte(draw, byte, x, y):

blist = list(bin(byte).lstrip('0b')) # turn byte into list with 8 elements, 
c = 0# each representing one bit
for bit in blist:   
if bit:
draw.point((x + c, y), fcolor)

c += 1
return

# -
def EPD_2_Image(edpfilename, imagefilename):

# get out of here if EPD file not present
if not os.path.isfile(epdfilename):
print 'file not found: ' + edpfilename
return

# is this a valid EPD file?
filesize = os.path.getsize(epdfilename)
if (((xdim / 8) * ydim) + header) <> filesize:
print 'incorrect file size: ' + edpfilename
return

# blow old destination file away 
if os.path.isfile(imagefilename):
print 'deleting old dest. file: ' + imagefilename
os.remove(imagefilename)

print 'processing...'

# set up PIL objects
img  = Image.new('1', (xdim, ydim), bcolor)   # '1' = Bi-tonal image
draw = ImageDraw.Draw(img)

# read entire EPD file into byte array (without the header)
content = bytearray(open(epdfilename, 'rb').read())[16:] 
 
# image coord origin at top/left according to PIL documentation
pos = 0
for y in range(ydim): 
x = 0
for byte in range(xdim / 8):   # 8 pixels 'stuffed' into one byte
RenderByte(draw, content[pos], x, y)
pos += 1   
x   += 8

img.save(imagefilename)   # format is inferred from given extension
print 'done.'

return
# -

xdim   = 1024
ydim   = 1280
header = 16
black  = 0
white  = 1
bcolor = black
fcolor = white

epdfilename   = 'c:\\temp\\drawtest2.epd'
imagefilename = 'c:\\temp\\drawtest2.png'

EPD_2_Image(epdfilename, imagefilename)
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Learning Python: Code critique please

2008-06-22 Thread William McBrine
On Sun, 22 Jun 2008 08:44:25 -0500, Saul Spatz wrote:

> macoovacany wrote:
>> http://macoovacany.wordpress.com/
> When I tried to run it, I got all kinds of syntax errors because of
> non-ASCII characters; namely, you have fancy left and right single and
> double quotes.

That's probably WordPress' doing.

-- 
09 F9 11 02 9D 74 E3 5B D8 41 56 C5 63 56 88 C0 -- pass it on
--
http://mail.python.org/mailman/listinfo/python-list


Re: Learning Python: Code critique please

2008-06-22 Thread Saul Spatz

macoovacany wrote:

http://macoovacany.wordpress.com/
When I tried to run it, I got all kinds of syntax errors because of 
non-ASCII characters; namely, you have fancy left and right single

and double quotes.  Once I replaced these with the ASCII equivalents,
it worked fine.  I suggest you use a plain ASCII text editor, like the
one that comes with IDLE.

HTH,
Saul
--
http://mail.python.org/mailman/listinfo/python-list


Re: Learning Python: Code critique please

2008-06-21 Thread macoovacany
http://macoovacany.wordpress.com/
--
http://mail.python.org/mailman/listinfo/python-list


Learning Python: Code critique please

2008-06-20 Thread macoovacany
Hello all,
   I'm trying to learn various programming languages (I did MATLAB at
uni), and have decided to start with Python. The programming exercises
are derived from Larry O'brien's http://www.knowing.net/
PermaLink,guid,f3b9ba36-848e-43f8-9caa-232ec216192d.aspx">15
Programming Exercises . First one is up with a couple of comments
of my own.

Any suggestions, corrections, things that I have done wrong, could do
better, etc, please feel free to post a comment.

Timbo
--
http://mail.python.org/mailman/listinfo/python-list