Thursday, 27 November 2008

Rails tip - how to see clearly the templates rendered for a query?

Not *that* inventive, but I somehow didn't think of it before:

tail -f log/development.log | grep Rendered

Wednesday, 8 October 2008

Getting svn:externals to work with git-svn and... Leopard

There IS a simple solution to work conveniently in git-svn with repository that has svn:externals set. You can clone all repositories to seperate trees, and instead of watching svn:externals, make hard links to the trees you need (remember to ignore them in git). The problem is you can't have hard links to directories... unless you're using OS X Leopard (they implemented it in order to get Time Machine to work).

This ability isn't exposed to the command line (ln makes an explicit check to prevent you from doing that), but the code to have it working(scroll down to listing 4) is trivial.

Update: When working with hard-linked directories, remember to be careful when unlinking them: rm wouldn't unlink the directory unless provided with "-r" option, which deletes everything recursively, leaving other hard links to that directory empty.

Tuesday, 23 September 2008

Harness the power of wget

I finally invested enough time in reading wget's man page to be able to download file hierarchies exposed through http file server. The magic command is:
wget -r -np -nH --cut-dirs=2 http://example.com/some/nested/directory
The switches mean:

-r
turns of recursive download
-np
no-parent - only links to files below in the hierarchy are followed
-nH
no-host - doesn't dump the files into directory named after host name
--cut-dirs=2
in addition to skipping host name skips also 2 topmost directories. In the example instead of some/nestes/directory the files are put straight into directory

Wednesday, 21 May 2008

Getting fresh datastore while testing GAE apps

If you want to find out how to test you GAE apps, check out these two URLs first:
http://groups.google.com/group/google-appengine/msg/9132b44026040498
http://farmdev.com/thoughts/45/testing-google-app-engine-sites/

I want to show you how to clear the datastore quickly (yep, only that :>):


from google.appengine.api import apiproxy_stub_map

def clear_datastore():
datastore = apiproxy_stub_map.apiproxy.GetStub('datastore_v3')
datastore.Clear()

Tuesday, 29 April 2008

Outputting pdfs with google app engine

It's child easy, but not googleable yet. I used reportlab - a handy, pure-python pdf library. Here are the steps:

  1. Checkout reportlab into your app directory
    svn co http://www.reportlab.co.uk/svn/public/reportlab/trunk \
    reportlab
  2. Write some pdf-generation code, like
    import wsgiref.handlers

    from google.appengine.ext import webapp

    from reportlab.pdfgen import canvas


    class MainPage(webapp.RequestHandler):

    def get(self):
    self.response.headers['Content-Type'] = 'application/pdf'
    p = canvas.Canvas(self.response.out)
    p.drawString(100, 750, "Hey, it's easy!.")

    p.showPage()
    p.save()



    def main():
    application = webapp.WSGIApplication([('/', MainPage)], debug=True)
    wsgiref.handlers.CGIHandler().run(application)

    if __name__ == "__main__":
    main()
    The key is the canvas instantiation. The constructor takes a file-like object and writes into it. You might have noticed that the code is heavily inspired by this tutorial. The only difference is the creation of canvas.
  3. That's it. See? I said it was easy. You can run the dev_appserver or upload it to Google in order to see the results.

Thursday, 13 March 2008

At PyCon


Yaaaay, after 9h flight, finally here.

Saturday, 16 February 2008

Brand new blog engine without a single line of code

Having investigated the new Google D&S forms feature, I decided to create a proof-of-concept blog application (OK - calling it an application is a *bit* an overstatement). It has some basic features, like form for entering entries and a feed. I doesn't have a site and is pretty much crippled. Still, quite good for 0 lines of code.

Here's the feed

And here's the new entry form. Feel free to post.

Sunday, 3 February 2008

Implementing Arc's function-negation operator in Python

Hey look! This guy implemented Arc's function-negation operator in Chicken. And he claims to be a Pythoneer, traitor ;-) !

I just investigated the possibilities of doing more or less the same thing in Python. Of course: you can't change the syntax, and you can't change default function's behaviour (which is not having "~" operator implemented). Or can't you?

Let's start with something more explicit for a moment. Nothing prevents us from creating a callable decorator that implements __invert__ something like this:

class invertible:

def __init__(self, foo):
self.foo = foo

def __call__(self, *args, **kwargs):
return self.foo(*args, **kwargs)

def __invert__(self):
def wrapper(*args, **kwargs):
return not self.foo(*args, **kwargs)
return wrapper
Implementing __init__ enables us to call invertible() with an argument, and implementing __call__ makes the instances of our class callable. These two work together in a way that an ordinary decorator works: It's a callable, that takes a callable and returns another callable - easy, huh?
Implementing __invert__ lets us use the "~" operator on the instances of our class, like this:
truth = invertible(lambda: True)
not_truth = ~truth
assert truth()
assert not not_truth()
This implementation, even though it's easy, is not finished yet. The inverted value is a regular function, which means, that we couldn't invert it again. The easy solution to that is decorating the wrapper:
class invertible:
# ...
def __invert__(self):
@invertible
def wrapper(*args, **kwargs):
return not self.foo(*args, **kwargs)
return wrapper
But this would cause the wrappers to accumulate on inverting. We can also check explicitly if we get an invertible on input and set a switch on each instance
class invertible:

def __init__(self, foo):
self.foo = foo
self.inverted = False

def __call__(self, *args, **kwargs):
if self.inverted:
return not self.foo(*args, **kwargs)
else:
return self.foo(*args, **kwargs)

def __invert__(self):
ret = invertible(self.foo)
ret.inverted = (not self.inverted)
return ret
Now, with the decorator ready, you can do some *evil* magic with frames and namespaces in order to decorate everything in scope, but I'm leaving it as an exercise to readers ;P

Tuesday, 29 January 2008

antigravity imported



The first Cracow Python meetup was a huge success! With over 60 people turning up (some of them having travelled up to 3 hours(!) to get there), four presentations, and plans for next event in mind. What's even better - there are going to be three of us now to organise the next meetings. What's even *more* than better - the lectures from now on will be recorded and streamed live. Unfortunately - most of them will be in polish, but foreign speakers are also very welcome, so don't hesitate and come to Cracow! The following meetup takes place on the 21st of February.

And here are the photos.

Thursday, 24 January 2008

The Longest Journey

The problem

Running all the tests for our rails app took around 2 minutes on other machines and over 15 on mine.

The solution

Remove all network locations from System Preferences and put them back again.

The journey

I reduced the problem to a single test case with a single test method with a single line. Having no idea how exactly Rails Does Stuff, I ended up putting parts of debug output and tracing rails' inner paths this way. I got to before_filters, then spotted the filter that caused the problem - it was the "black-list" check (provided by a plugin). Obviously, it was a single line of the file: the url resolution.

Now, I was scared - it couldn't be ruby's fault! Fortunately, it wasn't: analogous python library was slow as well. Actually they didn't work at all. Even pinging a non-existent url took 7secs, and on ALL other machines (running various OS's) it took an instant. The guys from #ruby channel at freenode were helping me for around 2 hours (thanks a lot!), but still nothing seemed to fix the problem. I got pretty convinced, however, that my problem was caused by a bug in Leopard's TCP/IP implementation. Feeling a bit more firmly in the topic, I started searching in forums. And there it was: on the ruby forum. I followed the most crazy tip and found out why it was the last message in the thread.



P.S. Blogger provides an OpenID for its users! My way of celebrating the fact was signing up on djangopeople.net (great site btw!)
P.S.2 Ola Bini run recently into the same problem, and put some more knowledge and investigation in solving it.

Thursday, 17 January 2008

My hobby 2:

Using sick aliases for common methods

irb(main):003:0> def putse *args
irb(main):004:1> puts args
irb(main):005:1> end
=> nil
irb(main):006:0> putse "lol"
lol
=> nil
irb(main):007:0>

My hobby:

Using rails' to_sentence method in my debug output.

Friday, 11 January 2008

It is happening! Cracow python community.


Driven mad by insanely active ruby community in Cracow, I decided to take the matter into my own hands and get pythonistas to meet. I was surprised by how easy it seems to be - the room is provided by my university, blogger helped me create something other people could link to (sorry - it's polish only), I found programmers who have something to say and asked couple of news sites and blogs to announce the event. Let's hope everything will go as planned.

Photo by Pete Reed

Sunday, 6 January 2008

Selenium testing in spite of browser differences

If you're using Selenium table tests for functional testing of your web app, you could have tried testing for browser specific issues. I used selenium vars for that (here in rsel format).

store_eval "if(navigator.userAgent.toLowerCase().indexOf('safari')\
!= -1){'some_locator';} \
else {'some other locator';}",
'specific_part'
assert_element_present '//div//${specific_part}'


*But* most probably, there should be a better way to do this. We used the trick above to look for specific inline style, which is handled differently in safari and firefox ( a space added after a semicolon in safari). We eventually found assert_element_visible.