When I'm debugging Python I tend to sprinkle my code liberally with print statements. Trouble is, I forget which files I added those print statements to and have to waste a few minutes tracking them down. Time which could be better spent doing pretty much anything else.
Not sure why I didn't think of this before, but I hacked together something that automatically prints the file and line of the print statement next to the output.
Here's the code:
import inspect import sys import os class DebugPrint(object): def __init__(self, f): self.f = f def write(self, text): frame = inspect.currentframe() filename = frame.f_back.f_code.co_filename.rsplit(os.sep, 1)[-1] lineno = frame.f_back.f_lineno prefix = "[%s:%s] " % (filename, lineno) if text == os.linesep: self.f.write(text) else: self.f.write(prefix + text) if not isinstance(sys.stdout, DebugPrint): sys.stdout = DebugPrint(sys.stdout)
To use it, save it as ‘debugprint.py’ then imported it somewhere. That's all you need to do. Works on Python 2.7 and probably other 2.X Pythons.
Here's what happens if you do it from the console:
>>> import debugprint >>> print "Hello" [<stdin>:1] Hello
For print statements in your app, you will get something like:
“ Has anyone done for the email module, what @kennethreitz has done for http? i.e. make the api only as complex than it needs to be. #Python ”0
“ Maybe I should be a pro photographer. Let's face it, at 40 I'm going to struggle to maintain the fast paced life of a #Python engineer. ”0
Ben Timby has committed code to PyFilesystem that lets you expose any filesystem over FTP. We've had the ability to serve filesystems over SFTP (secure ftp) and XMLRPC for a while, but plain old FTP was a glaring omission–until now.
You can serve the current directory programatically with something like the following:
from fs.expose.ftp import serve_fs from fs.osfs import OSFS serve_fs(OSFS('.'), '127.0.0.1', 21)
The same functionality is also available to the fsserve command. The following is equivalent to the above code, but from the command line:
fsserve -t ftp .
You'll probably need root privileges (i.e. sudo) on Linux for these examples.
With the server running, you can browse the files on your home directory with an ftp client, or by typing “ftp://127.0.0.1” in to your browser. Any of the other supported filesystems can be served in the same way.
FTP has been around since the dawn of the internet, so just about any network enabled device will be able to access files exposed this way. It's a great way of creating a gateway to other filesystems. You could expose files stored on Amazon S3 for example.
You'll need to check out the latest code from SVN to try this out.
Update: Ben has posted more about this.
“ RT @worrp: Proof of concept Riak-backed virtual filesystem - https://t.co/EagEcjU9 #riak #python #pyfilesystem /cc @willmcgugan // Cool ”0
I made currency site available for testing today. See my previous post for the back-story, but in essence currency site is a virtual currency platform.
I sometimes object to the word virtual in ‘virtual currency’. Most of the money I possess is not in any physical form; it's merely a number stored in a database somewhere – and transactions occur without any kind of physical objects changing hands. So the word ‘virtual’ seems entirely redundant, since there's is no qualitative difference between virtual and ‘real’ money I can see. The only difference is the level of trust in the system.
But I digress. Currency site is a platform for virtual currencies, in that it is up to the users to create and manage currencies. The site just provides the tools. What currencies are used for is irrelevant as far as the platform is concerned. It could be for a house of students to manage the housework, or for a community to exchange goods and services. Regardless of what a currency is used for, there has to be a certain amount of trust in the system. The platform has to be reliable, in that you shouldn't be able to create currency without a valid transaction. Currency site is centralised, which makes that requirement simpler–the system keeps track of how much is owned, in the same way you trust banks to keep track of the money in your accounts.
The second level of trust is in the creator of the currency. The creator of the currency has the extra responsibility of defining how much of that currency is available at any one time. This is done by minting new currency. For instance, if the provider creates a currency and mints 1,000,000 virtual bucks then only 1,000,000 will ever be available to other users. It could be owned by a single person, or by a million people owning one virtual buck. Alternatively, since all currencies are divisible by 100, it could be that 100,000,000 people own 0.01 virtual bucks (a virtual cent?). However it is distributed there will be no more than one million virtual bucks in existence unless more is minted. A record of the currency mints is public, as well as information about how much currency exists and how much is in general circulation, which allows regular users to keep an eye on how the currency is managed.
From a techy side, currency site wasn't all that challenging. Sure it was a few months of part time work, but it was mostly user interface code. I wanted to make something that worked like online banking, but not as painful (I've never used an online banking system that didn't make me want to tear hair out). That was helped by using Twitter's bootstrap CSS framework, which creates an elegant user interface with simple markup.
There was only one piece of code that wasn't a straightforward as it appeared (and it was kind of fundamental). A currency site transaction basically involves subtracting a value from the source account and adding it to the destination account. In psuedo code, it is simply this:
if source_account.balance < amount: raise TransferError("Not enough currency") source_account.balance -= amount destination_account.balance += amount
In essence, that's all that is done, but things get more complex in the context of a web application where multiple transactions may occur simultaneously. For example, if an account A contains 30 virtual bucks and the owner attempts to send 20 virtual bucks to account B and simultaneously sends 20 virtual bucks to account C, one of those transactions has to fail – otherwise we may end up with a negative balances which is not allowed. The if statement checks if the account has enough currency, but if both those transactions occur simultaneously then they will both subtract 20 from the source account (leaving -10). Granted, this could only occurs in a small window of time, but there is no way to recover if it does.
I couldn't figure out how to handle this situation elegantly with the Django ORM, and I don't like resorting to custom SQL. Fortunately, the recent release of Django 1.4 came to the rescue with the addition of select_for_update, which does row level locking. Basically it allowed me to lock the two accounts objects so that no other process is permitted to modify them until the currency has been transferred. Another consideration is that the entire thing has to be done in a (database) transaction, since half a (currency) transaction could result in currency being subtracted from the source account without being added to the destination (in effect, disappearing currency from the system). To keep the currency consistent, the psuedo-code becomes:
begin_transaction() lock(source_account, destination_account) if source_account.balance < amount: raise TransferError("Not enough currency") source_account.balance -= amount destination_account.balance += amount commit_transaction()
I don't think there is much else in the code that is blog-worthy, although there is still plenty of features I'm thinking of adding. I'm considering allowing users to trade currencies, which might be interesting. I would also like to build an API, so users could pay for web content with virtual currency. A few more evenings of hacking in there I think…
If you would like to help with the testing then head on over to http://currency.willmcgugan.com/ (username: currency, password: reliance). If you let me know, I'll send you 100 beta bucks for your time. Bear in mind its in an early testing phase, so don't use it for anything serious – I'll be wiping the database before it goes live. I'd also be interested in suggestions for a proper domain name!