Python 3.0a2 Released!
The second alpha release is out!
Python 3000 is getting real, real fast! :D
The second alpha release is out!
Python 3000 is getting real, real fast! :D
xkcd is great!
Yes, the first alpha release is out! :D
Congratulations to all python developers for this release!!!
Do you like mazes?
eriol@mornie:~$ python maze.py
+--+--+--+--+--+--+--+--+--+--+
| | | | |
+ + + +--+ + +--+ + + +
| | | | | | | |
+ + + +--+--+--+ +--+--+ +
| | | | | | |
+ + +--+ + +--+--+ + + +
| | | | | | |
+ + + +--+--+--+--+--+--+ +
| | | | |
+ +--+--+ + + +--+--+--+ +
| | | |
+--+--+--+--+--+--+--+--+--+--+
After reading this good article, I decided to wrote some code to generate a perfect maze :D
The result is here: maze.py
As you can see, Depth-First Search is not a complex algorithm:
def create(self):
cell_stack = []
while self.visited_cells < self.total_cells:
neighbors = self.find_neighbors_with_walls(self.current_cell)
if neighbors:
new_cell = random.choice(neighbors)
self.current_cell.destroy_wall(cell=new_cell)
cell_stack.append(self.current_cell)
self.current_cell = new_cell
self.visited_cells += 1
else:
self.current_cell = cell_stack.pop()
The first Python Conference in Italy will be held in Florence on June, the 9th and 10th.
If you love Python, you can't miss it! :)
Finally I had the time to add RSS feeds! I hope you enjoy them :)
I'm not going to show some code because the documentation of Django's syndication feed framework is very good!
The GNU/Linux User Group Catania meets the last thursday of every month. Usually a reminder is sent to mailing list by someone, but the other day a friend of mine started a «reminder contest».
I could not miss it :)
I wanted something unusual to set the timer, so I decided to use the Heaviside step function:
def u(t):
if t < 0: return 0
else: return 1
Obviously not a single unit step :)
def setTimer(t):
return u(t) - 0.5 * u(t-TOTAL_HOURS-3) - 0.25 * u(t-TOTAL_HOURS-1)
In this manner the reminder is more dynamic: I use the return value to change the display's frequency.
It's time to write the GUI part!
A shaped window is simply a pixmap where the background pixels are transparent.
An image is worth a thousand words.
Yes, the pizza is our window :)
class PReminder:
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_POPUP)
self.window.set_events(self.window.get_events() | gtk.gdk.BUTTON_PRESS_MASK)
self.window.connect("button_press_event", self.hide)
[...]
Using gtk.WINDOW_POPUP makes the window a popup so it will not have a titlebar. In addiction, the "button_press_event" signal is attached to self.hide callback to hide the reminder:
def hide(self, *args):
self.window.hide()
if self.timerShow:
gobject.source_remove(self.timerShow)
To masks out everything except for the image we have to use gtk.gdk.Window.shape_combine_mask:
self.window.shape_combine_mask(self.mask, 0, 0)
Changing the window itself as the time for the appointment approaches, can be useful.
def draw(self):
w = self.width, self.pangolayout.get_pixel_size()[0]
offset = (max(w) - min(w)) / 2.
if self.width < self.pangolayout.get_pixel_size()[0]:
offset = -offset
self.mask.draw_rectangle(self.bmgc,
True,
0, 0,
self.pieces * self.pixelpiece,
self.height)
textwidth = self.pangolayout.get_pixel_size()[0]
self.pixmap.draw_layout(self.bgc,
int(offset),
int(self.height / 2.),
self.pangolayout)
self.mask.draw_layout(self.wmgc,
int(offset),
int(self.height / 2.),
self.pangolayout)
self.image = gtk.Image()
self.image.set_from_pixmap(self.pixmap, self.mask)
self.image.show()
self.window.shape_combine_mask(self.mask, 0, 0)
We have to change only the mask to obtain the desired effect.
Checking for last thursday of every month can be done in few line of code using dateutil:
lastThursday = rrule.rrule(rrule.MONTHLY,
byweekday=rrule.TH(-1),
count=1)[0].date()
The complete checking method:
def check(self):
today = datetime.today()
lastThursday = rrule.rrule(rrule.MONTHLY,
byweekday=rrule.TH(-1),
count=1)[0].date()
if today.date() == lastThursday:
now = today.time()
if START_CHECK_HOUR <= now <= FINISH_CHECK_HOUR:
timerModulator = setTimer(now.hour - START_CHECK_HOUR.hour)
timer = int(timerModulator * 60 * 60 * 1000)
self.setText(DIPLAYING_TEXT)
self.setPiece(now.hour - START_CHECK_HOUR.hour)
self.show()
self.timerShow = gobject.timeout_add(AUTO_HIDE_AFTER * 1000,
self.hide)
else:
timer = CHECK_TIMER * 1000
self.timerID = gobject.timeout_add(timer, self.check)
You can download the complete source code here: preminder-0.1.zip
ctypes is a foreign function interface for Python. It allows to call functions in dlls/shared libraries and access and manipulate C data types in Python: you can use it to wrap libraries in pure Python. It is included in Python 2.5 standard library.
I want to code a funny example using it, so I will show how to make a snake game using libcaca.
libcaca is an ascii art library like AAlib, but it has some cool features:
First of all we have to load libcaca, I use Linux so I will call libcaca.so.0:
import ctypes as C
lcaca = C.cdll.LoadLibrary('libcaca.so.0')
Now you can access libcaca's functions from Python :)
Create canvas and display for our snake is very easy:
cv = lcaca.cucul_create_canvas(CANVAS_WIDTH, CANVAS_HEIGHT)
dp = lcaca.caca_create_display(cv)
lcaca.caca_set_display_title(dp, "snake.py - playing with ctypes and libcaca")
To get events from keyboard call caca_get_event:
lcaca.caca_get_event(dp, 0x0001, C.byref(event), 0)
Where event is a caca_event structure. We need it because if not null, it will be filled with information about the event received.
How define event? Simply like that:
class MOUSE(C.Structure):
_fields_ = [('x', C.c_uint),
('y', C.c_uint),
('button', C.c_uint)]
class RESIZE(C.Structure):
_fields_ = [('w', C.c_uint),
('h', C.c_uint)]
class KEY(C.Structure):
_fields_ = [('ch', C.c_uint),
('utf32', C.c_ulong),
('utf8', C.c_char_p * 8)]
class ev(C.Union):
_fields_ = [('type', C.c_uint),
('mouse', MOUSE),
('resize', RESIZE),
('key', KEY)]
event = ev()
Now we can code the snake class:
class Snake(object):
def __init__(self, center_point, length):
self.head = center_point
self.body = []
for y in xrange(self.head[1] + 1, self.head[1] + length + 1):
self.body.append((self.head[0], y))
def move(self, direction):
phead = tuple(self.head)
if direction == 'UP':
self.head[1] -=1
elif direction == 'DOWN':
self.head[1] +=1
elif direction == 'LEFT':
self.head[0] -=1
elif direction == 'RIGHT':
self.head[0] +=1
self.body = [phead] + self.body[:-1]
def grow(self):
self.body += [tuple(self.head)] * 2
def draw(self):
global cv
lcaca.cucul_set_color_ansi(cv, 0x05, 0x00)
for p in self.body:
lcaca.cucul_put_char(cv, p[0], p[1], ord('o'))
lcaca.cucul_set_color_ansi(cv, 0x02, 0x00)
lcaca.cucul_put_char(cv, self.head[0], self.head[1], ord('@'))
lcaca.caca_refresh_display(dp)
And the target class:
class Target(object):
def __init__(self):
self.total = 0
def random(self, width, height):
self.x = int(random.uniform(1, width))
self.y = int(random.uniform(1, height))
self.value = random.choice(range(1,10))
def sum(self):
self.total += self.value
def draw(self):
global cv
lcaca.cucul_set_color_ansi(cv, 0x03, 0x00)
lcaca.cucul_put_char(cv, self.x, self.y, ord(str(self.value)))
lcaca.caca_refresh_display(dp)
We are ready for the mainloop ;)
while True:
while lcaca.caca_get_event(dp, 0x0001, C.byref(event), 0):
if event.key.utf32 == 113: # 'q' pressed
sys.exit()
elif event.key.utf32 == UP:
d = 'UP'
elif event.key.utf32 == DOWN:
d = 'DOWN'
elif event.key.utf32 == LEFT:
d = 'LEFT'
elif event.key.utf32 == RIGHT:
d = 'RIGHT'
try:
s.move(d)
except NameError:
pass
if (tuple(s.head) in s.body[1:] or
not 0 < s.head[0] < CANVAS_WIDTH - 1 or
not 0 < s.head[1] < CANVAS_HEIGHT - 1):
print 'Game Over!'
print 'Total score:', t.total
sys.exit()
elif tuple(s.head) == (t.x, t.y):
t.sum()
t.random(CANVAS_WIDTH - 2, CANVAS_HEIGHT - 2)
s.grow()
lcaca.cucul_clear_canvas(cv)
draw_border()
s.draw()
t.draw()
time.sleep(0.1)
The complete example is here: snake.py
Update 2007/10/20:
Sam Hocevar pointed me about importance of checking caca_get_event's return value, otherwise from time to time invalid keys are read. Thank you, Sam!
At the end I made it!
Django is great! You can build your own blog in few minutes! :)
Many thanks to Sal Zeta for his help with this site's design!
Storing images into a database is not common, usually you store only the file name, but sometimes it can be useful. Think you must log the position of several objects on a map. You can store the map and the logs in different files, but if your users have to share map and logs and they are not geek people, it can be a serious problem.
Remember that, of course, store files into a database makes the storage space more expensive. However, if you have to store one or few files it's not a big problem :-)
Consider the following database schema:
CREATE TABLE map (
name varchar(20) NOT NULL PRIMARY KEY,
image_file blob NOT NULL
);
CREATE TABLE logs (
-- <your logs schema here>
);
Let's start to code:
import Image
import StringIO
from pysqlite2 import dbapi2 as sqlite
Storing an image into the database is very simple:
def storeInDatabase(cur, image_name, data):
cur.execute("INSERT INTO map (name, image_file) values (?, ?)",
(image_name, sqlite.Binary(data))
)
con.commit()
N.B. As said by Fredrik Lundh, SQLite 3.0 has a limitation of 1 MB for each row of data, and the database uses NUL bytes to separate columns in the storage.
Retrieve the previously image stored is simple too:
def retrieveFromDatabase(cur, image):
cur.execute("SELECT image_file FROM map WHERE name = ?", (image,))
img = cur.fetchone()[0]
return StringIO.StringIO(img)
I use StringIO.StringIO because cur.fetchone()[0] returns a buffer-object and I want a file-object instead ;)
You can test with:
if __name__ == '__main__':
IMAGE = 'Surf.jpg'
i = open(IMAGE, 'rb')
idata = i.read()
i.close()
con = sqlite.connect('blob.db')
cur = con.cursor()
try:
storeInDatabase(cur, image_name=IMAGE, data=idata)
except sqlite.IntegrityError:
print 'You have stored this map already'
img = retrieveFromDatabase(cur, IMAGE)
cur.close()
Image.open(img).show()
The whole example, blobexample.py
Today, when I arrived at home I saw a package on the table in the living room:
My first purchase on Amazon! :)