Posts tagged ‘todos’

Pyjaco in a real app: Todos with local storage

I didn’t get the memo, but there appears to be a movement to demonstrate emerging web technologies with a simple todo list application, much as hello world is used to introduce programming languages.

In my last post, I introduced using jQuery with Pyjaco, the PYthon JAvascript COmpiler. Since then, I’ve made several contributions to the project and have been involved in diverse discussions with Pyjaco developers regarding the current and future status of the project. This post goes further by acting as a tutorial for writing a basic todos app using Pyjaco.

Pyjaco is alpha software. It is hard to write valid code, and harder to debug. I’ve managed to both lock up Firefox and hard crash it while using the Pyjaco library.

On the positive side, Pyjaco is under active, rapid development. The head developer, Christian Iversen is extremely responsive to both questions about Pyjaco, and to code contributions. This is a project with a lot of potential, and I see it as the current best bet for Python programmers hoping to avoid javascript one day in the future.

In spite of the hiccups, it is possible to generate a working javascript app using just Pyjaco. Here’s how.

Let’s start:

mkdir pyjados
cd pyjados
virtualenv2 venv --distribute --no-site-packages
source venv/bin/activate
pip install git+https://buchuki@github.com/buchuki/pyjaco.git@run_script

First we create a directory to work in and install a virtualenv. Pyjaco does not currently work with python 3, so in Arch Linux, I use the virtualenv2 command. We then activate the virtualenv and install the pyjaco package. Here I am installing from my personal fork, as it contains some changes for generating the built-in standard library that have not yet been merged upstream. You should normally install directly from chrivers’s git repository using pip install git+git://github.com/chrivers/pyjaco.git.

Now let’s create a basic HTML 5 page with jQuery loaded:

<!DOCTYPE html>
<html>
  <head>
    <title>PyJaco Todo List Example</title>
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
  </head>
  <body>
    <h1>PyJaco Todo List Example</h1> 
  </body>
</html>

We can load this in our web browser using a file:// URL. This is the only HTML page in our app, and it can be refreshed to load our changes as we work.

Pyjaco doesn’t simply translate Python into Javascript. Rather, it creates a basic standard library of Python-like objects that are utilized in the compiled javascript code. I wasn’t too keen on this idea when I first heard it, as it introduces a dependency that currently weighs in at 65K before minification and compression. While this is not a terribly heavy library, there are efforts under way to shrink the builtins or to dynamically generate it to contain only those builtins that your code actually touches. At any rate, we need to ensure this library is available to our code. First we generate the library:

pyjs.py --builtins=generate --output=py-builtins.js

pyjs.py is the name of the pyjaco command. It is expected to be renamed to pyjaco in the future. The --builtins=generate option tells pyjaco to generate the standard library, while the --output flag provides the filename for the new library file:

$ ls
index.html  py-builtins.js  venv

We then need to load this library in the head of our html file. Let’s also load the future pyjados.js script at this time:

  <head>
    <title>PyJaco Todo List Example</title>
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
    <script type="text/javascript" src="py-builtins.js"></script>
    <script type="text/javascript" src="pyjados.js"></script>
  </head>

Now, before we start coding the Python file that will be compiled to Javascript, I want to discuss what I consider to be the most confusing aspect of Pyjaco development. There are basically two types of variables in Pyjaco, Javascript variables, and Python variables. Javascript variables refer to “normal” variables that you would call in Javascript. These include alert, window, document and the like, as well as variables in third-party Javascript libraries, such as the ubiquitous jQuery. Further, any attributes on those objects are also Javascript variables, and the return value of any methods will also be Javascript variables.

Python variables, on the other hand, refer to any variables that you define in your Python source code. If you create a dict or a list, for example, it will be compiled to a list or dict object from the standard library we just generated. In the compiled script, of course these Python variables are represented by Javascript objects, but from the point of view of a Pyjaco coder, it is important to keep the two types of files separate. Almost all the bugs I have encountered in my Pyjaco code have been caused by confusing the two types of variables.

The distinction between python and javascript variables introduces a couple of complications to writing Pyjaco compatible python code. First we need to flag all of our Javascript variables using a decorator on methods that access them. Second, we need to explicitly convert our variables between Javascript and Python any time we access one from the other. I’m told that this conversion can — and one day will — be done automatically by the pyjaco multiplexer, but in the meantime, we need to make it explicit. We do this by using two javascript functions supplied with the standard library we just generated, appropriately named js() and py(). You will see examples of these shortly.

When I finally figured out the distinction, my first thought was, “ok, let’s prefer to always work with python variables.” Therefore, in my initialization code, I tried jQ=py(jQuery). Unfortunately, jQuery is a rather large object, and the py function apparently recursively converts all attributes from javascript to python. I ended up with a stack overflow.

Now, let’s create our first python code and watch it compile to Javascript. Name the file pyjados.py:

def setup():
    print "Pyjados Hello World"
 
jQuery(js(setup));

First we write a python function named setup. This function is a python object. jQuery is a javascript object that expects a javascript object as input. Therefore, we wrap setup in a js() call and pass the result into the jQuery function. jQuery will now run setup when document.ready is fired.

Now we compile the code using the following command inside our activated virtualenv:

pyjs.py --watch pyjados.py --output pyjados.js

You’ll notice the command doesn’t exit. That is the --watch option at work. If you now make a change to pyjados.py and save it, it will automatically recompile it. The output file pyjados.js is regenerated each time. This is the file we included in our html file. So now, open that html file in a web browser using a file:// url. Make sure the Javascript console is displayed and reload the page. You should see the words “Pyjados Hello World” printed on the console. Pyjaco automatically compiles print statements into console.log output.

Before we start implementing our Todo list, let’s look at an example of accessing a javascript variable inside a function. Change setup.py to utilize alert, as follows:

 
@JSVar("alert")
def setup():
    alert(js("Pyjados Hello Alert")
 
jQuery(js(setup));

Did you look closely at that code? There is a missing close bracket on the alert line. You’ll see the syntax error in your console where pyjs.py is watching the compiled code. Add the bracket and let it automatically recompile itself:

 
@JSVar("alert")
def setup():
    alert(js("Pyjados Hello Alert"))
 
jQuery(js(setup));

Let’s analyze this snippet. First, notice how we told the compiler that alert is a Javascript variable when used inside setup(). This is a bit odd, since the JSVar decorator is never actually imported into the namespace. This is a bit of magic in the Pyjaco compiler, just pretend it has been imported.

Second, notice that since alert has been flagged as a JSVar, it must accept a Javascript variable. However, the string “Pyjados Hello Alert” is a Python variable. Therefore, we convert it using js() as we pass it into the alert call.

Now let’s prepare to create some working todo-list code. Start by adding a form for submitting todos and a list to render the todos to the html body:

  <body>
    <h1>PyJaco Todo List Example</h1> 
    <form id="add_todo_form">
      <input type="text" id="add_box" placeholder="Add Todo", autofocus="autofocus">
      <button id="add_button">Add Todo</button>
    </form>
    <ul id="todo_items"></ul>
  </body> 

Nothing too exciting here. Note the ids on the elements, since we’ll be utilizing these from Pyjaco using jQuery selectors.

Now back into the python file. Let’s create a class to manage the various todo elements:

class TodosApp:
    @JSVar("jQuery", "js_add_form")
    def __init__(self):
        js_add_form = jQuery(js("#add_todo_form"))
        js_add_form.submit(js(self.add_todo))
 
    def add_todo(self, event):
        print "form submitted"
        return js(False)
 
def setup():
    todo_app = TodosApp()
 
jQuery(js(setup));

The __init__ function hooks up the form’s submit button to a method on the object. Notice that we need to flag not just jQuery, but also js_add_form as a javascript variable. Pyjaco does not (currently) know that a javascript variable is returned when calling a method on an existing javascript variable. I like to add the js_ prefix to variable names to help remind myself that this is a javascript variable.

In an ideal world, we could convert this variable to a Python variable using py(), but as noted earlier, calling py on a jQuery object results in a stack overflow or browser crash.

Also pay attention to the way we wrap the self.add_todo method name in a js() call when we pass it into the submit handler. The submit method is a javascript function expecting a javascript object.

The def add_todo method has its single parameter flagged as a @JSVar, since the method is being called internally by jQuery when the event occurs. We also wrap the False return value (to prevent event propogation on the submit handler) in a js() call so that jQuery recognizes it as a javascript false rather than a (true) object named False.

Try the code. Ensure the compiler recompiled it, and reload the html file. Enter some characters into the text box and use the Enter key or the Add Todo button to submit the form. The words form submitted should be displayed in the javascript console.

Now let’s actually store and render a newly added todo. The todos are stored in memory in a python dict object. Initialize this object by adding the following two lines of code to the end of __init__:

    self.todos = {}
    self.next_id = 1

And rewrite add_todo as follows as well as a new method named render

    @JSVar("event", "js_add_box")
    def add_todo(self, js_event):
        js_add_box = jQuery(js("#add_box"))
        self.todos[self.next_id] = py(js_add_box.val())
        js_add_box.val('')
        js_add_box.focus()
        self.next_id += 1
        self.render()
        return js(False)
 
    @JSVar("js_todo_items")
    def render(self):
        js_todo_items = jQuery(js("#todo_items"))
        js_todo_items.html("")
        for id, todo in sorted(self.todos.items()):
            js_todo_items.append(js('<li>%s</li>' % (id, todo)))

Note that the todos dict is a Python object, so when we insert the value of the js_add_box into it, we must convert it from a javascript object using py(). Also note how, because we are writing in a python function, manipulating the python value self.next_id requires no conversion, and calling the python function self.render is also clean.

In the render function itself, I think it’s pretty cool that string formatting using % is supported by pyjaco (as an aside, the str.format method introduced in python 2.6 is not yet available) and that the python sorted() function is available. Note also how we can loop over items() on the self.todos dictionary just as if we were using a normal python dictionary.

Now let’s add the ability to complete todos. Let’s start by adding a template string as a class variable, and use that string inside the render function. This illustrates that pyjaco supports class variables:

class TodosApp:
    list_item_template = """<li>
    %(text)s
    </li>"""

and we change the for loop in render to:

        for id, todo in sorted(self.todos.items()):
            js_todo_items.append(js(TodosApp.list_item_template % {
                "id": id,
                "text": todo}))

Reload the page again and notice how checkboxes have been displayed beside each todo. The next step is to make clicking these boxes actually complete the todos. We add a couple lines to our __init__ method to connect a live click event to the checkbox items, which now looks like this:

    @JSVar("jQuery", "js_add_form", "js_checkbox")
    def __init__(self):
        js_add_form = jQuery(js("#add_todo_form"))
        js_add_form.submit(js(self.add_todo))
        js_checkbox = jQuery(js("input[type=checkbox]"))
        js_checkbox.live("click", js(self.complete_todo))
        self.todos = {}
        self.next_id = 1

Don’t forget to add js_checkbox to the JSVar decorator.

The complete_todo method looks like this:

    @JSVar("event", "jQuery", "todo_item")
    def complete_todo(self, event):
        todo_item = jQuery(event.target).parent()
        id = int(py(todo_item.attr("id"))[5:])
        del self.todos[id]
        todo_item.delay(1500).fadeOut("slow")

The first line is using exclusively javascript arguments, and returns the <li> element containing the checkbox that was clicked. The id = line converts the javascript string id attribute of this element (which looks like “todo_5“, as defined in list_item_template) into the python integer id of the todo. The remaining lines simply remove that todo from the internal list and from the DOM, after a 1.5 second delay.

In fact, we now have a fully functional todo list that allows adding todos and checking them off. Now, as a bonus, let’s try hooking this up to the HTML 5 localStorage object so that the list is maintained across page reloads. We start by adding a store() method to our class:

    @JSVar("localStorage", "JSON")
    def store(self):
        localStorage.setItem("todolist", JSON.stringify(js(self.todos)))

The main line of code is easiest to read from the inside out. First we convert the self.todos dict to a normal javascript object using the js() function. Then we call JSON.stringify on this object to create a string suitable for insertion into localStorage.

Now add this call to the end of the two methods that manipulate the todo list, add_todo and complete_todo:

        self.store()

.

Refresh the page, add a couple todos, and inspect the localStorage object in your console. You should see the stringified dict in the todolist value.

Now all we have to do is ensure the self.todos dict is loaded from localStorage when the app is initialized. Add the following to the end of the __init__ method (make sure to add js_stored_todos to the JSVars decorator):

        js_stored_todos = localStorage.getItem("todolist")
 
        if js_stored_todos:
            stored_dict = dict(py(JSON.parse(js_stored_todos)))
            self.todos = dict([(int(i), stored_dict[i]) for i in stored_dict.keys()])
            self.next_id = max(self.todos.keys()) + 1
 
        self.render()

Note that calling py() on the output of JSON.parse creates a python object, not a python dict. The code is therefore wrapped in a call to dict(), which converts the object to a dictionary.

Unfortunately, the resultant dict contains keys that are strings, whereas our original dict used integer keys. So a pure-python list comprehension is used to convert the dictionary to one with integer keys. This line is a bit hard to read, but I wanted to include it to demonstrate that Pyjaco can parse list comprehensions. Finally, we set self.next_id using the python max() call, which Pyjaco also automatically translates into javascript.

Try it out. Load the pyjados HTML file, add some todos, check a few of them off, then close and reload the web browser. Your todos will be stored!

I hope you’ve enjoyed this introduction to Pyjaco. It is a nice tool with a lot of potential. Currently, I find writing Pyjaco code to be approximately equally tedious to writing Javascript code. However, I feel that as I learn the ins and outs of Pyjaco, and as the developers continue to refine and improve the compiler, Pyjaco may one day be a perfectly viable alternative to writing pure Javascript or to the rather too Ruby-esque, but otherwise excellent Coffeescript.

I can’t use CoffeeScript

I had some space between wrapping up my last contract on December 20, and starting my new job on January 16. I decided it was finally time to build a simple task management system, something I’ve attempted to do and never finished several times before. I currently use RememberTheMilk, which is a lovely service, but I don’t like paying them for mobile access. Further, even though I trust this small company, I see no reason to share intimate information about the tasks I accomplish every day with them. My long term goal is to pull as much of my personal data out of the cloud as I possibly can. This project is a step towards that goal.

There are numerous open source task manager apps out there that I’m sure would suit my not-too-exotic tastes. However, I also wanted to take this opportunity to learn a bunch of new technologies for an offline-enabled and mobile-enabled web application.

Therefore, I’ve spent most of my vacation time so far researching some technologies I haven’t had a chance to explore in the past year. JQuery Mobile was at the top of the list. I think it’s a lovely framework and I expect to continue using it.

I also wanted to try out CoffeeScript, as I’ve always hated writing Javascript, and I wanted to use some sort of client-side ORM for localstorage. I looked at backbone.js, but was more attracted to Spine.js. I have spent three days studying and playing with these two technologies. I am still undecided about Spine.js, but I have come to the conclusion that CoffeeScript is not for me.

I understand all the hype around the project. JavaScript really does suck. And CoffeeScript does suck less, it has pretty language features and it is much more succinct than JavaScript. I can imagine a lot of people being really excited about CofeeScript, especially Ruby and PERL programmers, and possibly even php programmers.

But not Python programmers. I tried to learn Ruby several times, and each time I was left with a foul taste in my mouth. It’s not a bad language, it just doesn’t fit in well with my personal philosophy. My personal philosophy happens to coincide almost exactly with the Zen Of Python. I chose Python because it matched my philosophy… not the other way around.

Like Ruby and PERL, CoffeeScript violently violates what I consider the most important rule of Python: “There should be one — and preferably only one — obvious way to do it.” I’m not going to argue why this is a good idea, I understand that some programmers prefer the “even if I don’t understand it, I can write code that will probably work” paradigm that Ruby promotes.

The simple truth is, writing CoffeeScript leaves me feeling like I’ve done something dirty, no less dirty than writing JavaScript. There is no incentive for me to add a layer of complexity (the CoffeeScript to JavaScript compile step) to my code when I know my code is going to be “ugly” either way.

CoffeeScript is a wonderful idea. It’s far better than JavaScript. It’s just not good enough. Luckily, the Python community is already working on pythonic answers, including the evilly poorly documented pyjaco and the less-than-well maintained pyvascript and pyjamas projects. I hope one of these or a new upstart will soon gain community momentum so frontend development is no longer painful.

Managing my TODOs in 2010

Last May I wrote an article on my ideal todo list. I implemented it in offline-enabled format, but never got around to writing the server-side code and it didn’t get used. I’ve been using a paper-based day book effectively all year, but the book is filled up.

Today, starting a new year, I needed something quick to manage my todos. I’m on a bad internet connection, and don’t want a web-based app; even offline enabled apps are quirky. I decided to write something quick and dirty using the command line. Half an hour later, this is what I have:

  • All my todos are stored in text files in one directory.
  • Each textfile contains the things I want to accomplish in one day, named after that day in 2010-01-31 format so they show up in sorted order.
  • I edit the files in my favourite text editor and put a “*” beside ones I’ve completed.
  • I wrote some scripts to easily open “relative” names such as TODAY, YESTERDAY, TOMORROW, and TWODAYS side by side.
  • I named each script starting with a 1 so that they show up at the beginning of the listing. This is useful in gui file managers as I can double click those scripts to open them.
  • I don’t actually use gui file managers much, but I put a link to this one on my desktop with a fancy icon so I don’t forget my tasks.
  • When I opened the directory in nautilus, I discovered that I can zoom in on the files, and actually read their contents without opening them. I switched it to compact view so I can fit more TODOs in one screen.
  • I’ll probably have one extra text file for “things that need to be done eventually.”
  • I haven’t really tested it, but I intend to use it for the next week and revise it as necessary. I may have to whip up a web.py server to give a simple interface to it from my phone, or maybe ConnectBot will suffice. It’s not important at the moment, I don’t take the phone anywhere due to a complete lack of coverage.

    If it seems to be working as well as the daybook did last year, I’ll keep it up. If I tend to forget to use it, like other electronic solutions I’ve tried, I’ll get a new daybook.

    What little code there is, I’ve posted to github.

Offline Enabled Webapps And Open Source

I’m currently working on a rather simple Todo list application intended to meet the requirements I outlined earlier. I’m developing this as an offline-enabled webapp and while I haven’t gotten very far (don’t try it, it barely satisfies the most elemental requirements), I have some interesting observations to make:

First, the app is currently 100% Javascript. Its wrapped in a Django project because I’m going to have to make it online enabled at some point, but I wrote this app from the ground up to run in offline mode. This is a huge departure from traditional web 2.0 development (as of now, web 2.0 is to be considered ‘traditional’), where logic is mostly stored on the server and an ugly mess of ajax calls run that business logic on different events. Instead, I have a Javascript app that is surprisingly elegant. MVC under this architecture is basically SQLite (model), XHTML/CSS (view), and javascript (controller). Then I will have a workerpool to sync up with the server in the background.

As a result, the entire code-base for this app is being served to the web browser. So if you personally want to hack this app, you can download the source files from the browser. Basically, I can’t release this app as closed source. I could put a license on it forbidding you to modify or redistribute it, but you can still read the code; the source is open.

Of course, that’s not a problem for me, as I release most of my code as open source and its already up on github. But it could kill corporate migration toward offline-enabled web 3.0. Because while its one thing to keep your trade secrets locked up on the server and provide a few incoherent javascript calls that interact with that API, it is a completely different beast to put your entire app available for download as a .js file.

I suspect the open source movement has gained enough momentum that any companies who have these fears will simply be put out of business by more modern outfits that will spring up to take their place. Otherwise, either web 3.0 will fail to grab market share, or somebody will come up with a way to ‘compile’ javascript into a standards compliant byte-code so they can pretend nobody can reverse engineer their app. This would be a damn shame as its a politically-motivated technically useless layer of complexity on a web based architecture that I am finally happy to be working with.

Todo List

I’ve spent a lot of time thinking about the proper way to design a calendar and to-do list application.  The irony: I never got around to putting ‘write to-do list application’ on my to-do list.

The best to-do list I’ve seen was designed by Kim Hoyer with input from myself and another developer. Its part of Kim’s proprietary Pursuits XRM System, a comprehensive sales and company management system. Oprius also has a terrific to-do and appointment management system. Google’s Calendar, on the other hand, seems to have done everything all wrong, by my standards.

I’ve read about several of the web-based options and discarded them for various reasons, usually too much complexity. Remember The Milk is a notable exception in that its complexities can be easily ignored. However, its still due-date based, and that’s not the way I work.

Stephen Covey’s well-known ‘The Seven Habits of Highly Effective People’ describes a slightly over-engineered, but otherwise workable paper-based to-do system that really jives with the way I think.

I’ve tried numerous solutions and always fall back to writing stuff on a scrap of paper. I’ve been actively monitoring exactly how I really do things (instead of trying to imagine how I should do things) in the 5.5 months since getting a day-book for Christmas. I’m ready to design a to-do list. I’d probably have sat down and started coding by now if I didn’t have this blog thingy to lay out some ideas. Just a little groundwork.

Day-oriented, not due-date oriented

When I plan what I want to do, its always about what I want to do today. I don’t care that the due date of a task is in two weeks, I care only about choosing whether I am or am not working on that task today. When I’m done working on the task today, I cross it off my todo list, even if the task isn’t complete. If its not complete, I add a NEW task for the next day. Its good to break big tasks into bite-sized sub-tasks, but often I just write the same task down for each day that I work on it.

Only plan a few days in advance

I need to be able to add, reorder, and move tasks between all days, but typically I won’t have tasks listed for something more than a week in advance. Unless I’m specifically meeting someone or planning a vacation, I don’t have stuff filled out for two months from now.

Area for planned but scheduled tasks

I currently add tasks I intend to do in the future for other days and then ‘move’ them by crossing out and rewriting under another day. This is suboptimal. I want a separate section for tasks that I don’t want to forget. It needs to be easy to move them into a specific day.

Recurring Tasks Suck

Most of the tasks I do on a recurring basis don’t happen at the same date and time each week. I just know I need to do them once a week. Having them auto occur makes me easily ignore them.

Instead, I need an area (possibly same area from previous point) to store tasks that I do repeatedly. These would be generic tasks and whenever I need to put one on a specific date I can just select it and add a date.

Super minimalist

I don’t need to attach much info to a task. I don’t need priorities, descriptions, notes, durations, locations, contacts. This shit clogs up the interface and the task name itself usually helps me recall all I need to remember about this stuff. Maybe if I was a sales person with 90 contacts per day that I can’t remember their names and faces I’d need those details, but in my life, its just extra cruft.

Task Ordering

On any given day, I want the completed tasks at the bottom of the list. Uncompleted tasks are at the top in a semi-ordered fashion. Currently when I sit down at my daybook, I cross out the last item I did and pick another one based on my current priorities. Sometimes I draw numbers beside them to note the next three things I’m going to do. In software, I want to use either drag and drop or tap-to-raise to easily order the next few things I plan to do. When I finish one, I want it to be easy to change my mind about what I’m doing next. Keep it agile!

My Phone

I expect I would make this a web app in the long run so I can access it anywhere, but I definitely need to be able to access it on my phone (Android Dev Phone). Since I want to play with the android APIs anyway, my first attempt is going to be for Android. Later I’ll tie it up to a mobile-oriented webapp similar to Choncho.